]>
git.saurik.com Git - apple/system_cmds.git/blob - kdprof/TraceFileAction.cpp
5 // Created by James McIlree on 4/15/13.
6 // Copyright (c) 2013 Apple. All rights reserved.
12 template < typename SIZE
>
13 static void execute_arch_specific ( Globals
& globals
, std :: string path
)
16 // Trace file looks roughly like:
19 // threadmap[thread_count]
20 // wasted-space-to-align-to-next-4096-byte-boundary
24 MappedFile
trace_data ( path
. c_str ());
25 if ( TraceDataHeader
< SIZE
>* header
= reinterpret_cast < TraceDataHeader
< SIZE
>*>( trace_data
. address ())) {
27 KDThreadMapEntry
< SIZE
>* threadmap
= NULL
;
28 uint32_t threadmap_count
= 0 ;
29 KDCPUMapEntry
* cpumap
= NULL
;
30 uint32_t cpumap_count
= 0 ;
31 KDEvent
< SIZE
>* events
= NULL
;
33 if ( header
-> version () != RAW_VERSION1
) {
34 // If the header is not a RAW_VERSION1, we must assume it is a
35 // RAW_VERSION0. The difficulty here is that RAW_VERSION0 consists
36 // of 4 bytes, which are the thread_count. We can't do much
37 // sanity checking. The first four bytes are already read into
38 // the existing header, reuse them. We must also reset the file
41 threadmap_count
= header
-> version ();
42 threadmap
= reinterpret_cast < KDThreadMapEntry
< SIZE
>*>( trace_data
. address () + 4 );
44 // Event data starts immediately following the threadmap
45 size_t offset
= 4 + threadmap_count
* sizeof ( KDThreadMapEntry
< SIZE
>);
46 events
= reinterpret_cast < KDEvent
< SIZE
>*>( trace_data
. address () + offset
);
51 threadmap_count
= header
-> thread_count ();
52 threadmap
= reinterpret_cast < KDThreadMapEntry
< SIZE
>*>( trace_data
. address () + sizeof ( TraceDataHeader
< SIZE
>));
54 size_t threadmap_size_in_bytes
= threadmap_count
* sizeof ( KDThreadMapEntry
< SIZE
>);
55 size_t offset_to_event_data
= ( sizeof ( TraceDataHeader
< SIZE
>) + threadmap_size_in_bytes
+ 4095 ) & ~ 4095 ;
56 size_t offset_to_cpumap_data
= sizeof ( TraceDataHeader
< SIZE
>) + threadmap_size_in_bytes
;
57 size_t cpumap_bytes
= offset_to_event_data
- offset_to_cpumap_data
;
60 // In a RAW_VERSION1, there *may* be a cpumap.
61 // If it exists, it will be between the header and the page aligned offset
62 // that event data begins at.
64 if ( cpumap_bytes
> sizeof ( kd_cpumap_header
) + sizeof ( kd_cpumap
)) {
65 kd_cpumap_header
* cpumap_header
= reinterpret_cast < kd_cpumap_header
*>( trace_data
. address () + offset_to_cpumap_data
);
66 if ( cpumap_header
-> version_no
== RAW_VERSION1
) {
67 cpumap
= ( KDCPUMapEntry
*)& cpumap_header
[ 1 ];
68 cpumap_count
= cpumap_header
-> cpu_count
;
72 // Event data starts at the next PAGE alignment boundary.
74 // Hmm, this could be pretty awful in iOS...
76 // Kernel page size is 4k. Userspace page size is 16kb in 64b.
77 // Kernel writes the data. Unless the kernel call fails, then userspace writes the data. Blech.
78 events
= reinterpret_cast < KDEvent
< SIZE
>*>( trace_data
. address () + offset_to_event_data
);
81 uintptr_t event_count
= ( uintptr_t ) trace_data
. size () - ( reinterpret_cast < uintptr_t >( events
) - reinterpret_cast < uintptr_t >( trace_data
. address ()));
82 if ( event_count
% sizeof ( KDEvent
< SIZE
>) != 0 ) {
83 // We're probably looking at the wrong k32/k64. Throw and try the other size.
84 THROW ( "Bytes in file does not match an even multiple of Event struct" );
86 event_count
/= sizeof ( KDEvent
< SIZE
>);
88 std :: vector
< KDCPUMapEntry
> default_cpumap
;
90 if ( cpumap
== NULL
|| cpumap_count
== 0 ) {
91 // No cpumap found, we need to fake one up using the default values.
92 for ( uint32_t i
= 0 ; i
< globals
. cpu_count (); ++ i
) {
93 default_cpumap
. emplace_back ( i
, 0 , "AP-???" );
95 uint32_t iop_limit
= globals
. cpu_count () + globals
. iop_count ();
96 for ( uint32_t i
= globals
. cpu_count (); i
< iop_limit
; ++ i
) {
97 default_cpumap
. emplace_back ( i
, KDBG_CPUMAP_IS_IOP
, "IOP-???" );
100 cpumap
= default_cpumap
. data ();
101 cpumap_count
= ( uint32_t ) default_cpumap
. size ();
104 // IOP's have been producing .trace files with out of order events.
105 // This is a hack fix to work around that. It costs a full copy of the data!
106 MemoryBuffer
< KDEvent
< SIZE
>> presorted_events
;
107 if ( globals
. should_presort_events () && event_count
) {
108 presorted_events
. set_capacity ( event_count
);
109 memcpy ( presorted_events
. data (), events
, event_count
* sizeof ( KDEvent
< SIZE
>));
110 events
= presorted_events
. data ();
111 std :: sort ( events
, events
+ event_count
, []( KDEvent
< SIZE
> const & p0
, KDEvent
< SIZE
> const & p1
) -> bool {
112 return p0
. timestamp () < p1
. timestamp ();
116 Machine
< SIZE
> machine ( cpumap
, cpumap_count
, threadmap
, threadmap_count
, events
, event_count
);
118 if (! machine
. lost_events ()) {
119 if ( globals
. should_zero_base_timestamps () && event_count
) {
120 globals
. set_beginning_of_time ( events
[ 0 ]. timestamp ());
122 globals
. set_beginning_of_time ( AbsTime ( 0 ));
125 if (! globals
. is_timebase_set ()) {
126 if ( machine
. is_ios ()) {
127 globals
. set_timebase ({ 125 , 3 }, false );
129 globals
. set_timebase ({ 1 , 1 }, false );
133 if ( globals
. is_verbose ()) {
134 dprintf ( globals
. output_fd (), " \n %s \n " , path
. c_str ());
135 print_verbose_machine_info ( globals
, machine
, threadmap_count
, ( default_cpumap
. empty ()) ? cpumap_count
: 0 );
138 if ( globals
. should_print_events ()) {
139 print_machine_events ( globals
, machine
);
142 if ( globals
. should_print_summary ()) {
143 print_machine_summary ( globals
, machine
);
146 if ( globals
. should_print_csv_summary ()) {
147 print_machine_csv_summary ( globals
, machine
);
150 if ( globals
. should_print_process_start_stop_timestamps ()) {
151 print_process_start_stop_timestamps ( globals
, machine
);
154 log_msg ( ASL_LEVEL_WARNING
, "The trace data indicates that events were lost, the file cannot be processed \n " );
157 log_msg ( ASL_LEVEL_ERR
, "Unable to read from %s \n " , path
. c_str ());
162 void TraceFileAction :: execute ( Globals
& globals
) {
163 if ( globals
. is_kernel_size_set ()) {
165 if ( globals
. kernel_size () == KernelSize :: k32
)
166 execute_arch_specific
< Kernel32
>( globals
, _path
);
168 execute_arch_specific
< Kernel64
>( globals
, _path
);
169 } catch ( Exception
& e
) {
170 log_msg ( ASL_LEVEL_ERR
, "An exception was raised: %s " , e
. what ());
171 log_msg ( ASL_LEVEL_ERR
, "An explicit kernel size was set, you may want to try not forcing the size to a single value \n " );
172 log_msg ( ASL_LEVEL_ERR
, "You may also want to check the number of cpus and iops configured if the file is from a device and does not have a cpumap \n " );
177 execute_arch_specific
< Kernel64
>( globals
, _path
);
178 } catch ( Exception
& e
) {
179 execute_arch_specific
< Kernel32
>( globals
, _path
);
186 template < typename SIZE
>
187 static void execute_arch_specific ( Globals
& globals
, TraceFile
& file
, std :: string
& path
)
189 Machine
< SIZE
> machine ( file
);
191 if (! machine
. lost_events ()) {
192 if ( globals
. should_zero_base_timestamps () && machine
. event_count ()) {
193 globals
. set_beginning_of_time ( machine
. events ()[ 0 ]. timestamp ());
195 globals
. set_beginning_of_time ( AbsTime ( 0 ));
198 if (! globals
. is_timebase_set ()) {
199 if ( machine
. is_ios ()) {
200 globals
. set_timebase ({ 125 , 3 }, false );
202 globals
. set_timebase ({ 1 , 1 }, false );
206 if ( globals
. is_verbose ()) {
207 dprintf ( globals
. output_fd (), " \n %s \n " , path
. c_str ());
208 print_verbose_machine_info ( globals
, machine
, file
. threadmap_count (), file
. cpumap_count ());
211 if ( globals
. should_print_events ()) {
212 print_machine_events ( globals
, machine
);
215 if ( globals
. should_print_summary ()) {
216 print_machine_summary ( globals
, machine
);
219 if ( globals
. should_print_csv_summary ()) {
220 print_machine_csv_summary ( globals
, machine
);
223 if ( globals
. should_print_process_start_stop_timestamps ()) {
224 print_process_start_stop_timestamps ( globals
, machine
);
227 log_msg ( ASL_LEVEL_WARNING
, "The trace data indicates that events were lost, the file cannot be processed \n " );
231 void TraceFileAction :: execute ( Globals
& globals
) {
232 TraceFile
file ( _path
. c_str (), globals
. should_presort_events (), globals
. cpu_count (), globals
. iop_count ());
233 if ( globals
. is_kernel_size_set ()) {
235 if ( globals
. kernel_size () == KernelSize :: k32
)
236 execute_arch_specific
< Kernel32
>( globals
, file
, _path
);
238 execute_arch_specific
< Kernel64
>( globals
, file
, _path
);
239 } catch ( Exception
& e
) {
240 log_msg ( ASL_LEVEL_ERR
, "An exception was raised: %s " , e
. what ());
241 log_msg ( ASL_LEVEL_ERR
, "An explicit kernel size was set, you may want to try not forcing the size to a single value \n " );
242 log_msg ( ASL_LEVEL_ERR
, "You may also want to check the number of cpus and iops configured if the file is from a device and does not have a cpumap \n " );
245 if ( file
. is_valid ()) {
246 if ( file
. is_64_bit ()) {
247 execute_arch_specific
< Kernel64
>( globals
, file
, _path
);
249 execute_arch_specific
< Kernel32
>( globals
, file
, _path
);
252 if ( file
. mmap_failed ()) {
253 log_msg ( ASL_LEVEL_ERR
, "Unable to mmap %s , it may exceed this devices memory limits \n " , _path
. c_str ());
255 log_msg ( ASL_LEVEL_ERR
, " %s does not appear to be a valid trace file \n " , _path
. c_str ());