1 : // Copyright 2012 Google Inc.
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 : class TraceFileDumper : public ParseEventHandler {
39 m : public:
40 m : explicit TraceFileDumper(FILE* file)
41 m : : file_(file ? file : stdout),
42 m : indentation_("") {
43 m : }
44 :
45 m : void PrintFunctionEvent(const char* event_type,
46 m : base::Time time,
47 m : DWORD process_id,
48 m : DWORD thread_id,
49 m : const TraceEnterExitEventData* data) {
50 m : DCHECK(event_type != NULL);
51 m : DCHECK(data != NULL);
52 m : DCHECK(data->function != NULL);
53 m : ::fprintf(file_,
54 m : "[%012lld] %s%s: process-id=%d; thread-id=%d; address=0x%08X\n",
55 m : time.ToInternalValue(),
56 m : indentation_,
57 m : event_type,
58 m : process_id,
59 m : thread_id,
60 m : data->function);
61 m : }
62 :
63 m : void PrintModuleEvent(const char* event_type,
64 m : base::Time time,
65 m : DWORD process_id,
66 m : DWORD thread_id,
67 m : const TraceModuleData* data) {
68 m : DCHECK(event_type != NULL);
69 m : DCHECK(data != NULL);
70 m : DCHECK(data->module_base_addr != NULL);
71 m : ::fprintf(file_,
72 m : "[%012lld] %s: process-id=%d; thread-id=%d;"
73 m : " module-name='%ls';"
74 m : " module-addr=0x%08X; module-size=%d\n",
75 m : time.ToInternalValue(),
76 m : event_type,
77 m : process_id,
78 m : thread_id,
79 m : data->module_name,
80 m : data->module_base_addr,
81 m : data->module_base_size);
82 m : }
83 :
84 m : void PrintOsVersionInfo(base::Time time,
85 m : const OSVERSIONINFOEX& os_version_info) {
86 m : ::fprintf(file_,
87 m : "[%012lld] %sOsVersionInfo: platform_id=%d; product_type=%d; "
88 m : "version=%d.%d; build=%d; service_pack=%d.%d\n",
89 m : time.ToInternalValue(),
90 m : indentation_,
91 m : os_version_info.dwPlatformId,
92 m : os_version_info.wProductType,
93 m : os_version_info.dwMajorVersion,
94 m : os_version_info.dwMinorVersion,
95 m : os_version_info.dwBuildNumber,
96 m : os_version_info.wServicePackMajor,
97 m : os_version_info.wServicePackMinor);
98 m : }
99 :
100 m : void PrintSystemInfo(base::Time time, const SYSTEM_INFO& system_info) {
101 m : ::fprintf(file_,
102 m : "[%012lld] %sSystemInfo: cpu_arch=%d; cpu_count=%d; "
103 m : "cpu_level=%d; cpu_rev=%d\n",
104 m : time.ToInternalValue(),
105 m : indentation_,
106 m : system_info.wProcessorArchitecture,
107 m : system_info.dwNumberOfProcessors,
108 m : system_info.wProcessorLevel,
109 m : system_info.wProcessorRevision);
110 m : }
111 :
112 m : void PrintMemoryStatus(base::Time time, const MEMORYSTATUSEX& memory_status) {
113 m : ::fprintf(file_,
114 m : "[%012lld] %sMemoryStatus: load=%d; total_phys=%lld; "
115 m : "avail_phys=%lld\n",
116 m : time.ToInternalValue(),
117 m : indentation_,
118 m : memory_status.dwMemoryLoad,
119 m : memory_status.ullTotalPhys,
120 m : memory_status.ullAvailPhys);
121 m : }
122 :
123 m : void PrintEnvironmentString(base::Time time,
124 m : const std::wstring& key,
125 m : const std::wstring& value) {
126 m : ::fprintf(file_,
127 m : "[%012lld] %sEnvironment: %ls=%ls\n",
128 m : time.ToInternalValue(),
129 m : indentation_,
130 m : key.c_str(),
131 m : value.c_str());
132 m : }
133 :
134 m : void PrintEnvironmentStrings(base::Time time,
135 m : const TraceEnvironmentStrings& env_strings) {
136 m : for (size_t i = 0; i < env_strings.size(); ++i)
137 m : PrintEnvironmentString(time, env_strings[i].first, env_strings[i].second);
138 m : }
139 :
140 m : virtual void OnProcessStarted(base::Time time,
141 m : DWORD process_id,
142 m : const TraceSystemInfo* data) {
143 m : ::fprintf(file_,
144 m : "[%012lld] OnProcessStarted: process-id=%d\n",
145 m : time.ToInternalValue(),
146 m : process_id);
147 :
148 m : if (data == NULL)
149 m : return;
150 :
151 m : indentation_ = " ";
152 m : PrintOsVersionInfo(time, data->os_version_info);
153 m : PrintSystemInfo(time, data->system_info);
154 m : PrintMemoryStatus(time, data->memory_status);
155 m : PrintEnvironmentStrings(time, data->environment_strings);
156 m : indentation_ = "";
157 m : }
158 :
159 m : virtual void OnProcessEnded(base::Time time, DWORD process_id) {
160 m : ::fprintf(file_,
161 m : "[%012lld] OnProcessEnded: process-id=%d\n",
162 m : time.ToInternalValue(),
163 m : process_id);
164 m : }
165 :
166 m : virtual void OnFunctionEntry(base::Time time,
167 m : DWORD process_id,
168 m : DWORD thread_id,
169 m : const TraceEnterExitEventData* data) {
170 m : PrintFunctionEvent("OnFunctionEntry", time, process_id, thread_id, data);
171 m : }
172 :
173 m : virtual void OnFunctionExit(base::Time time,
174 m : DWORD process_id,
175 m : DWORD thread_id,
176 m : const TraceEnterExitEventData* data) {
177 m : PrintFunctionEvent("OnFunctionEntry", time, process_id, thread_id, data);
178 m : }
179 :
180 m : virtual void OnBatchFunctionEntry(base::Time time,
181 m : DWORD process_id,
182 m : DWORD thread_id,
183 m : const TraceBatchEnterData* data) {
184 m : DCHECK(data != NULL);
185 m : DCHECK_EQ(thread_id, data->thread_id);
186 m : ::fprintf(file_,
187 m : "[%012lld] OnBatchFunctionEntry: " \
188 m : "process-id=%d; thread-id=%d; num-calls=%d\n",
189 m : time.ToInternalValue(),
190 m : process_id,
191 m : thread_id,
192 m : data->num_calls);
193 :
194 : // Explode the batch event into individual function entry events.
195 m : TraceEnterExitEventData new_data = {};
196 m : indentation_ = " ";
197 m : for (size_t i = 0; i < data->num_calls; ++i) {
198 m : new_data.function = data->calls[i].function;
199 m : OnFunctionEntry(base::Time::FromInternalValue(data->calls[i].tick_count),
200 m : process_id,
201 m : thread_id,
202 m : &new_data);
203 m : }
204 m : indentation_ = "";
205 m : }
206 :
207 m : virtual void OnProcessAttach(base::Time time,
208 m : DWORD process_id,
209 m : DWORD thread_id,
210 m : const TraceModuleData* data) {
211 m : PrintModuleEvent("OnProcessAttach", time, process_id, thread_id, data);
212 m : }
213 :
214 m : virtual void OnProcessDetach(base::Time time,
215 m : DWORD process_id,
216 m : DWORD thread_id,
217 m : const TraceModuleData* data) {
218 m : PrintModuleEvent("OnProcessDetach", time, process_id, thread_id, data);
219 m : }
220 :
221 m : virtual void OnThreadAttach(base::Time time,
222 m : DWORD process_id,
223 m : DWORD thread_id,
224 m : const TraceModuleData* data) {
225 m : PrintModuleEvent("OnThreadAttach", time, process_id, thread_id, data);
226 m : }
227 :
228 m : virtual void OnThreadDetach(base::Time time,
229 m : DWORD process_id,
230 m : DWORD thread_id,
231 m : const TraceModuleData* data) {
232 m : PrintModuleEvent("OnThreadDetach", time, process_id, thread_id, data);
233 m : }
234 :
235 m : virtual void OnInvocationBatch(base::Time time,
236 m : DWORD process_id,
237 m : DWORD thread_id,
238 m : size_t num_invocations,
239 m : const TraceBatchInvocationInfo* data) {
240 m : DCHECK(data != NULL);
241 m : ::fprintf(file_,
242 m : "OnInvocationBatch: process-id=%d; thread-id=%d;\n",
243 m : process_id,
244 m : thread_id);
245 m : for (size_t i = 0; i < num_invocations; ++i) {
246 m : ::fprintf(file_,
247 m : " caller=0x%08X; function=0x%08X; num-calls=%d;\n"
248 m : " cycles-min=%lld; cycles-max=%lld; cycles-sum=%lld\n",
249 m : data->invocations[i].caller,
250 m : data->invocations[i].function,
251 m : data->invocations[i].num_calls,
252 m : data->invocations[i].cycles_min,
253 m : data->invocations[i].cycles_max,
254 m : data->invocations[i].cycles_sum);
255 m : }
256 m : }
257 :
258 m : virtual void OnThreadName(base::Time time,
259 m : DWORD process_id,
260 m : DWORD thread_id,
261 m : const base::StringPiece& thread_name) OVERRIDE {
262 m : ::fprintf(file_, "OnThreadName: process-id=%d; thread-id=%d;\n"
263 m : " name=%s\n",
264 m : process_id, thread_id, thread_name.as_string().c_str());
265 m : }
266 :
267 m : virtual void OnBasicBlockFrequency(
268 m : base::Time time,
269 m : DWORD process_id,
270 m : DWORD thread_id,
271 m : const TraceBasicBlockFrequencyData* data) OVERRIDE {
272 m : DCHECK(data != NULL);
273 m : ::fprintf(file_,
274 m : "OnBasicBlockFrequency: process-id=%d; thread-id=%d;\n"
275 m : " module-base-addr=0x%08X; module-base-size=%d\n"
276 m : " module-checksum=0x%08X; module-time-date-stamp=0x%08X\n"
277 m : " frequency-size=%d; basic-block-count=%d\n",
278 m : data->module_base_addr,
279 m : data->module_base_size,
280 m : data->module_checksum,
281 m : data->module_time_date_stamp,
282 m : data->frequency_size,
283 m : data->num_basic_blocks);
284 m : }
285 :
286 m : private:
287 m : FILE* file_;
288 m : const char* indentation_;
289 :
290 m : DISALLOW_COPY_AND_ASSIGN(TraceFileDumper);
291 m : };
292 :
293 m : bool DumpTraceFiles(FILE* out_file, const std::vector<FilePath>& file_paths) {
294 m : Parser parser;
295 m : TraceFileDumper dumper(out_file);
296 m : if (!parser.Init(&dumper))
297 m : return false;
298 :
299 m : std::vector<FilePath>::const_iterator iter = file_paths.begin();
300 m : for (; iter != file_paths.end(); ++iter) {
301 m : if (!parser.OpenTraceFile(*iter))
302 m : return false;
303 m : }
304 :
305 m : return parser.Consume() && !parser.error_occurred();
306 m : }
307 :
308 m : } // namespace
309 :
310 m : int main(int argc, const char** argv) {
311 m : base::AtExitManager at_exit_manager;
312 m : CommandLine::Init(argc, argv);
313 :
314 m : if (!logging::InitLogging(
315 m : L"",
316 m : logging::LOG_ONLY_TO_SYSTEM_DEBUG_LOG,
317 m : logging::DONT_LOCK_LOG_FILE,
318 m : logging::APPEND_TO_OLD_LOG_FILE,
319 m : logging::ENABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS)) {
320 m : return 1;
321 m : }
322 :
323 m : CommandLine* cmd_line = CommandLine::ForCurrentProcess();
324 m : CHECK(cmd_line != NULL);
325 :
326 m : std::vector<FilePath> trace_file_paths;
327 m : for (size_t i = 0; i < cmd_line->GetArgs().size(); ++i)
328 m : trace_file_paths.push_back(FilePath(cmd_line->GetArgs()[i]));
329 :
330 m : if (trace_file_paths.empty()) {
331 m : LOG(ERROR) << "No trace file paths specified.";
332 :
333 m : ::fprintf(stderr,
334 m : "Usage: %ls [--out=OUTPUT] TRACE_FILE(s)...\n\n",
335 m : cmd_line->GetProgram().value().c_str());
336 m : return 1;
337 m : }
338 :
339 m : FilePath out_file_path(cmd_line->GetSwitchValuePath("out"));
340 m : file_util::ScopedFILE out_file;
341 m : if (!out_file_path.empty()) {
342 m : out_file.reset(file_util::OpenFile(out_file_path, "w"));
343 m : if (out_file.get() == NULL) {
344 m : LOG(ERROR) << "Failed to open output file: '" << out_file_path.value()
345 m : << "'.";
346 m : return 1;
347 m : }
348 m : }
349 :
350 m : if (!DumpTraceFiles(out_file.get(), trace_file_paths)) {
351 m : LOG(ERROR) << "Failed to dump trace files.";
352 m : return 1;
353 m : }
354 :
355 m : return 0;
356 m : }
|