]> git.saurik.com Git - apple/system_cmds.git/blob - kdprof/TraceFileAction.cpp
system_cmds-671.10.3.tar.gz
[apple/system_cmds.git] / kdprof / TraceFileAction.cpp
1 //
2 // TraceFileAction.cpp
3 // kdprof
4 //
5 // Created by James McIlree on 4/15/13.
6 // Copyright (c) 2013 Apple. All rights reserved.
7 //
8
9 #include "global.h"
10
11 #if 0
12 template <typename SIZE>
13 static void execute_arch_specific(Globals& globals, std::string path)
14 {
15 //
16 // Trace file looks roughly like:
17 //
18 // RAW_header
19 // threadmap[thread_count]
20 // wasted-space-to-align-to-next-4096-byte-boundary
21 // KDEvents[]
22 //
23
24 MappedFile trace_data(path.c_str());
25 if (TraceDataHeader<SIZE>* header = reinterpret_cast<TraceDataHeader<SIZE>*>(trace_data.address())) {
26
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;
32
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
39 // offset.
40
41 threadmap_count = header->version();
42 threadmap = reinterpret_cast<KDThreadMapEntry<SIZE>*>(trace_data.address() + 4);
43
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);
47 } else {
48 //
49 // RAW_VERSION1
50 //
51 threadmap_count = header->thread_count();
52 threadmap = reinterpret_cast<KDThreadMapEntry<SIZE>*>(trace_data.address() + sizeof(TraceDataHeader<SIZE>));
53
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;
58
59 //
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.
63 //
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;
69 }
70 }
71
72 // Event data starts at the next PAGE alignment boundary.
73 //
74 // Hmm, this could be pretty awful in iOS...
75 //
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);
79 }
80
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");
85 }
86 event_count /= sizeof(KDEvent<SIZE>);
87
88 std::vector<KDCPUMapEntry> default_cpumap;
89
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-???");
94 }
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-???");
98 }
99
100 cpumap = default_cpumap.data();
101 cpumap_count = (uint32_t)default_cpumap.size();
102 }
103
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();
113 });
114 }
115
116 Machine<SIZE> machine(cpumap, cpumap_count, threadmap, threadmap_count, events, event_count);
117
118 if (!machine.lost_events()) {
119 if (globals.should_zero_base_timestamps() && event_count) {
120 globals.set_beginning_of_time(events[0].timestamp());
121 } else {
122 globals.set_beginning_of_time(AbsTime(0));
123 }
124
125 if (!globals.is_timebase_set()) {
126 if (machine.is_ios()) {
127 globals.set_timebase({ 125, 3 }, false);
128 } else {
129 globals.set_timebase({ 1, 1 }, false);
130 }
131 }
132
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);
136 }
137
138 if (globals.should_print_events()) {
139 print_machine_events(globals, machine);
140 }
141
142 if (globals.should_print_summary()) {
143 print_machine_summary(globals, machine);
144 }
145
146 if (globals.should_print_csv_summary()) {
147 print_machine_csv_summary(globals, machine);
148 }
149
150 if (globals.should_print_process_start_stop_timestamps()) {
151 print_process_start_stop_timestamps(globals, machine);
152 }
153 } else {
154 log_msg(ASL_LEVEL_WARNING, "The trace data indicates that events were lost, the file cannot be processed\n");
155 }
156 } else {
157 log_msg(ASL_LEVEL_ERR, "Unable to read from %s\n", path.c_str());
158 exit(1);
159 }
160 }
161
162 void TraceFileAction::execute(Globals& globals) {
163 if (globals.is_kernel_size_set()) {
164 try {
165 if (globals.kernel_size() == KernelSize::k32)
166 execute_arch_specific<Kernel32>(globals, _path);
167 else
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");
173 }
174 } else {
175 // Try em both!
176 try {
177 execute_arch_specific<Kernel64>(globals, _path);
178 } catch (Exception& e) {
179 execute_arch_specific<Kernel32>(globals, _path);
180 }
181 }
182 }
183
184 #endif
185
186 template <typename SIZE>
187 static void execute_arch_specific(Globals& globals, TraceFile& file, std::string& path)
188 {
189 Machine<SIZE> machine(file);
190
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());
194 } else {
195 globals.set_beginning_of_time(AbsTime(0));
196 }
197
198 if (!globals.is_timebase_set()) {
199 if (machine.is_ios()) {
200 globals.set_timebase({ 125, 3 }, false);
201 } else {
202 globals.set_timebase({ 1, 1 }, false);
203 }
204 }
205
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());
209 }
210
211 if (globals.should_print_events()) {
212 print_machine_events(globals, machine);
213 }
214
215 if (globals.should_print_summary()) {
216 print_machine_summary(globals, machine);
217 }
218
219 if (globals.should_print_csv_summary()) {
220 print_machine_csv_summary(globals, machine);
221 }
222
223 if (globals.should_print_process_start_stop_timestamps()) {
224 print_process_start_stop_timestamps(globals, machine);
225 }
226 } else {
227 log_msg(ASL_LEVEL_WARNING, "The trace data indicates that events were lost, the file cannot be processed\n");
228 }
229 }
230
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()) {
234 try {
235 if (globals.kernel_size() == KernelSize::k32)
236 execute_arch_specific<Kernel32>(globals, file, _path);
237 else
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");
243 }
244 } else {
245 if (file.is_valid()) {
246 if (file.is_64_bit()) {
247 execute_arch_specific<Kernel64>(globals, file, _path);
248 } else {
249 execute_arch_specific<Kernel32>(globals, file, _path);
250 }
251 } else {
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());
254 } else {
255 log_msg(ASL_LEVEL_ERR, "%s does not appear to be a valid trace file\n", _path.c_str());
256 }
257 }
258 }
259 }
260