1 : // Copyright 2012 Google Inc. All Rights Reserved.
2 : //
3 : // Licensed under the Apache License, Version 2.0 (the "License");
4 : // you may not use this file except in compliance with the License.
5 : // You may obtain a copy of the License at
6 : //
7 : // http://www.apache.org/licenses/LICENSE-2.0
8 : //
9 : // Unless required by applicable law or agreed to in writing, software
10 : // distributed under the License is distributed on an "AS IS" BASIS,
11 : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : // See the License for the specific language governing permissions and
13 : // limitations under the License.
14 :
15 : #include <windows.h> // NOLINT
16 : #include <stdio.h>
17 : #include <vector>
18 :
19 : #include "base/at_exit.h"
20 : #include "base/command_line.h"
21 : #include "base/file_path.h"
22 : #include "base/file_util.h"
23 : #include "base/logging.h"
24 : #include "base/threading/simple_thread.h"
25 : #include "base/win/event_trace_consumer.h"
26 : #include "base/win/event_trace_controller.h"
27 : #include "base/win/scoped_handle.h"
28 : #include "base/win/windows_version.h"
29 : #include "syzygy/trace/parse/parser.h"
30 : #include "syzygy/trace/service/service.h"
31 :
32 m : namespace {
33 :
34 m : using trace::parser::Parser;
35 m : using trace::parser::ParseEventHandler;
36 m : using trace::parser::ModuleInformation;
37 :
38 m : const char* GetIndexedDataTypeStr(uint8 data_type) {
39 m : const char* ret = NULL;
40 m : switch (data_type) {
41 m : case TraceIndexedFrequencyData::BASIC_BLOCK:
42 m : ret = "basic-block entry counts";
43 m : break;
44 m : case TraceIndexedFrequencyData::JUMP_TABLE:
45 m : ret = "jump-table case counts";
46 m : break;
47 m : default:
48 m : NOTREACHED();
49 m : break;
50 m : }
51 m : return ret;
52 m : }
53 :
54 m : class TraceFileDumper : public ParseEventHandler {
55 m : public:
56 m : explicit TraceFileDumper(FILE* file)
57 m : : file_(file ? file : stdout),
58 m : indentation_("") {
59 m : }
60 :
61 m : void PrintFunctionEvent(const char* event_type,
62 m : base::Time time,
63 m : DWORD process_id,
64 m : DWORD thread_id,
65 m : const TraceEnterExitEventData* data) {
66 m : DCHECK(event_type != NULL);
67 m : DCHECK(data != NULL);
68 m : DCHECK(data->function != NULL);
69 m : ::fprintf(file_,
70 m : "[%012lld] %s%s: process-id=%d; thread-id=%d; address=0x%08X\n",
71 m : time.ToInternalValue(),
72 m : indentation_,
73 m : event_type,
74 m : process_id,
75 m : thread_id,
76 m : data->function);
77 m : }
78 :
79 m : void PrintModuleEvent(const char* event_type,
80 m : base::Time time,
81 m : DWORD process_id,
82 m : DWORD thread_id,
83 m : const TraceModuleData* data) {
84 m : DCHECK(event_type != NULL);
85 m : DCHECK(data != NULL);
86 m : DCHECK(data->module_base_addr != NULL);
87 m : ::fprintf(file_,
88 m : "[%012lld] %s: process-id=%d; thread-id=%d;"
89 m : " module-name='%ls';"
90 m : " module-addr=0x%08X; module-size=%d\n",
91 m : time.ToInternalValue(),
92 m : event_type,
93 m : process_id,
94 m : thread_id,
95 m : data->module_name,
96 m : data->module_base_addr,
97 m : data->module_base_size);
98 m : }
99 :
100 m : void PrintOsVersionInfo(base::Time time,
101 m : const OSVERSIONINFOEX& os_version_info) {
102 m : ::fprintf(file_,
103 m : "[%012lld] %sOsVersionInfo: platform_id=%d; product_type=%d; "
104 m : "version=%d.%d; build=%d; service_pack=%d.%d\n",
105 m : time.ToInternalValue(),
106 m : indentation_,
107 m : os_version_info.dwPlatformId,
108 m : os_version_info.wProductType,
109 m : os_version_info.dwMajorVersion,
110 m : os_version_info.dwMinorVersion,
111 m : os_version_info.dwBuildNumber,
112 m : os_version_info.wServicePackMajor,
113 m : os_version_info.wServicePackMinor);
114 m : }
115 :
116 m : void PrintSystemInfo(base::Time time, const SYSTEM_INFO& system_info) {
117 m : ::fprintf(file_,
118 m : "[%012lld] %sSystemInfo: cpu_arch=%d; cpu_count=%d; "
119 m : "cpu_level=%d; cpu_rev=%d\n",
120 m : time.ToInternalValue(),
121 m : indentation_,
122 m : system_info.wProcessorArchitecture,
123 m : system_info.dwNumberOfProcessors,
124 m : system_info.wProcessorLevel,
125 m : system_info.wProcessorRevision);
126 m : }
127 :
128 m : void PrintMemoryStatus(base::Time time, const MEMORYSTATUSEX& memory_status) {
129 m : ::fprintf(file_,
130 m : "[%012lld] %sMemoryStatus: load=%d; total_phys=%lld; "
131 m : "avail_phys=%lld\n",
132 m : time.ToInternalValue(),
133 m : indentation_,
134 m : memory_status.dwMemoryLoad,
135 m : memory_status.ullTotalPhys,
136 m : memory_status.ullAvailPhys);
137 m : }
138 :
139 m : void PrintEnvironmentString(base::Time time,
140 m : const std::wstring& key,
141 m : const std::wstring& value) {
142 m : ::fprintf(file_,
143 m : "[%012lld] %sEnvironment: %ls=%ls\n",
144 m : time.ToInternalValue(),
145 m : indentation_,
146 m : key.c_str(),
147 m : value.c_str());
148 m : }
149 :
150 m : void PrintEnvironmentStrings(base::Time time,
151 m : const TraceEnvironmentStrings& env_strings) {
152 m : for (size_t i = 0; i < env_strings.size(); ++i)
153 m : PrintEnvironmentString(time, env_strings[i].first, env_strings[i].second);
154 m : }
155 :
156 m : virtual void OnProcessStarted(base::Time time,
157 m : DWORD process_id,
158 m : const TraceSystemInfo* data) {
159 m : ::fprintf(file_,
160 m : "[%012lld] OnProcessStarted: process-id=%d\n",
161 m : time.ToInternalValue(),
162 m : process_id);
163 :
164 m : if (data == NULL)
165 m : return;
166 :
167 m : indentation_ = " ";
168 m : PrintOsVersionInfo(time, data->os_version_info);
169 m : PrintSystemInfo(time, data->system_info);
170 m : PrintMemoryStatus(time, data->memory_status);
171 m : PrintEnvironmentStrings(time, data->environment_strings);
172 m : indentation_ = "";
173 m : }
174 :
175 m : virtual void OnProcessEnded(base::Time time, DWORD process_id) {
176 m : ::fprintf(file_,
177 m : "[%012lld] OnProcessEnded: process-id=%d\n",
178 m : time.ToInternalValue(),
179 m : process_id);
180 m : }
181 :
182 m : virtual void OnFunctionEntry(base::Time time,
183 m : DWORD process_id,
184 m : DWORD thread_id,
185 m : const TraceEnterExitEventData* data) {
186 m : PrintFunctionEvent("OnFunctionEntry", time, process_id, thread_id, data);
187 m : }
188 :
189 m : virtual void OnFunctionExit(base::Time time,
190 m : DWORD process_id,
191 m : DWORD thread_id,
192 m : const TraceEnterExitEventData* data) {
193 m : PrintFunctionEvent("OnFunctionEntry", time, process_id, thread_id, data);
194 m : }
195 :
196 m : virtual void OnBatchFunctionEntry(base::Time time,
197 m : DWORD process_id,
198 m : DWORD thread_id,
199 m : const TraceBatchEnterData* data) {
200 m : DCHECK(data != NULL);
201 m : DCHECK_EQ(thread_id, data->thread_id);
202 m : ::fprintf(file_,
203 m : "[%012lld] OnBatchFunctionEntry: " \
204 m : "process-id=%d; thread-id=%d; num-calls=%d\n",
205 m : time.ToInternalValue(),
206 m : process_id,
207 m : thread_id,
208 m : data->num_calls);
209 :
210 : // Explode the batch event into individual function entry events.
211 m : TraceEnterExitEventData new_data = {};
212 m : indentation_ = " ";
213 m : for (size_t i = 0; i < data->num_calls; ++i) {
214 m : new_data.function = data->calls[i].function;
215 m : OnFunctionEntry(time, process_id, thread_id, &new_data);
216 m : }
217 m : indentation_ = "";
218 m : }
219 :
220 m : virtual void OnProcessAttach(base::Time time,
221 m : DWORD process_id,
222 m : DWORD thread_id,
223 m : const TraceModuleData* data) {
224 m : PrintModuleEvent("OnProcessAttach", time, process_id, thread_id, data);
225 m : }
226 :
227 m : virtual void OnProcessDetach(base::Time time,
228 m : DWORD process_id,
229 m : DWORD thread_id,
230 m : const TraceModuleData* data) {
231 m : PrintModuleEvent("OnProcessDetach", time, process_id, thread_id, data);
232 m : }
233 :
234 m : virtual void OnThreadAttach(base::Time time,
235 m : DWORD process_id,
236 m : DWORD thread_id,
237 m : const TraceModuleData* data) {
238 m : PrintModuleEvent("OnThreadAttach", time, process_id, thread_id, data);
239 m : }
240 :
241 m : virtual void OnThreadDetach(base::Time time,
242 m : DWORD process_id,
243 m : DWORD thread_id,
244 m : const TraceModuleData* data) {
245 m : PrintModuleEvent("OnThreadDetach", time, process_id, thread_id, data);
246 m : }
247 :
248 m : virtual void OnInvocationBatch(base::Time time,
249 m : DWORD process_id,
250 m : DWORD thread_id,
251 m : size_t num_invocations,
252 m : const TraceBatchInvocationInfo* data) {
253 m : DCHECK(data != NULL);
254 m : ::fprintf(file_,
255 m : "OnInvocationBatch: process-id=%d; thread-id=%d;\n",
256 m : process_id,
257 m : thread_id);
258 m : for (size_t i = 0; i < num_invocations; ++i) {
259 m : ::fprintf(file_,
260 m : " caller=0x%08X; function=0x%08X; num-calls=%d;\n"
261 m : " cycles-min=%lld; cycles-max=%lld; cycles-sum=%lld\n",
262 m : data->invocations[i].caller,
263 m : data->invocations[i].function,
264 m : data->invocations[i].num_calls,
265 m : data->invocations[i].cycles_min,
266 m : data->invocations[i].cycles_max,
267 m : data->invocations[i].cycles_sum);
268 m : }
269 m : }
270 :
271 m : virtual void OnThreadName(base::Time time,
272 m : DWORD process_id,
273 m : DWORD thread_id,
274 m : const base::StringPiece& thread_name) OVERRIDE {
275 m : ::fprintf(file_, "OnThreadName: process-id=%d; thread-id=%d;\n"
276 m : " name=%s\n",
277 m : process_id, thread_id, thread_name.as_string().c_str());
278 m : }
279 :
280 m : virtual void OnIndexedFrequency(
281 m : base::Time time,
282 m : DWORD process_id,
283 m : DWORD thread_id,
284 m : const TraceIndexedFrequencyData* data) OVERRIDE {
285 m : DCHECK(data != NULL);
286 m : ::fprintf(file_,
287 m : "OnIndexedFrequency: process-id=%d; thread-id=%d;\n"
288 m : " module-base-addr=0x%08X; module-base-size=%d\n"
289 m : " module-checksum=0x%08X; module-time-date-stamp=0x%08X\n"
290 m : " frequency-size=%d; data-type=%s; num-entries=%d\n",
291 m : process_id,
292 m : thread_id,
293 m : data->module_base_addr,
294 m : data->module_base_size,
295 m : data->module_checksum,
296 m : data->module_time_date_stamp,
297 m : data->frequency_size,
298 m : GetIndexedDataTypeStr(data->data_type),
299 m : data->num_entries);
300 m : }
301 :
302 m : private:
303 m : FILE* file_;
304 m : const char* indentation_;
305 :
306 m : DISALLOW_COPY_AND_ASSIGN(TraceFileDumper);
307 m : };
308 :
309 m : bool DumpTraceFiles(FILE* out_file, const std::vector<FilePath>& file_paths) {
310 m : Parser parser;
311 m : TraceFileDumper dumper(out_file);
312 m : if (!parser.Init(&dumper))
313 m : return false;
314 :
315 m : std::vector<FilePath>::const_iterator iter = file_paths.begin();
316 m : for (; iter != file_paths.end(); ++iter) {
317 m : if (!parser.OpenTraceFile(*iter))
318 m : return false;
319 m : }
320 :
321 m : return parser.Consume() && !parser.error_occurred();
322 m : }
323 :
324 m : } // namespace
325 :
326 m : int main(int argc, const char** argv) {
327 m : base::AtExitManager at_exit_manager;
328 m : CommandLine::Init(argc, argv);
329 :
330 m : if (!logging::InitLogging(
331 m : L"",
332 m : logging::LOG_ONLY_TO_SYSTEM_DEBUG_LOG,
333 m : logging::DONT_LOCK_LOG_FILE,
334 m : logging::APPEND_TO_OLD_LOG_FILE,
335 m : logging::ENABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS)) {
336 m : return 1;
337 m : }
338 :
339 m : CommandLine* cmd_line = CommandLine::ForCurrentProcess();
340 m : CHECK(cmd_line != NULL);
341 :
342 m : std::vector<FilePath> trace_file_paths;
343 m : for (size_t i = 0; i < cmd_line->GetArgs().size(); ++i)
344 m : trace_file_paths.push_back(FilePath(cmd_line->GetArgs()[i]));
345 :
346 m : if (trace_file_paths.empty()) {
347 m : LOG(ERROR) << "No trace file paths specified.";
348 :
349 m : ::fprintf(stderr,
350 m : "Usage: %ls [--out=OUTPUT] TRACE_FILE(s)...\n\n",
351 m : cmd_line->GetProgram().value().c_str());
352 m : return 1;
353 m : }
354 :
355 m : FilePath out_file_path(cmd_line->GetSwitchValuePath("out"));
356 m : file_util::ScopedFILE out_file;
357 m : if (!out_file_path.empty()) {
358 m : out_file.reset(file_util::OpenFile(out_file_path, "w"));
359 m : if (out_file.get() == NULL) {
360 m : LOG(ERROR) << "Failed to open output file: '" << out_file_path.value()
361 m : << "'.";
362 m : return 1;
363 m : }
364 m : }
365 :
366 m : if (!DumpTraceFiles(out_file.get(), trace_file_paths)) {
367 m : LOG(ERROR) << "Failed to dump trace files.";
368 m : return 1;
369 m : }
370 :
371 m : return 0;
372 m : }
|