| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "base/trace_event/trace_event_memory.h" | 5 #include "base/trace_event/trace_event_memory.h" |
| 6 | 6 |
| 7 #include "base/debug/leak_annotations.h" | 7 #include "base/debug/leak_annotations.h" |
| 8 #include "base/lazy_instance.h" | 8 #include "base/lazy_instance.h" |
| 9 #include "base/location.h" | 9 #include "base/location.h" |
| 10 #include "base/logging.h" | 10 #include "base/logging.h" |
| 11 #include "base/memory/scoped_ptr.h" | 11 #include "base/memory/scoped_ptr.h" |
| 12 #include "base/single_thread_task_runner.h" | 12 #include "base/single_thread_task_runner.h" |
| 13 #include "base/strings/string_number_conversions.h" | 13 #include "base/strings/string_number_conversions.h" |
| 14 #include "base/strings/string_split.h" |
| 14 #include "base/strings/string_util.h" | 15 #include "base/strings/string_util.h" |
| 15 #include "base/threading/thread_local_storage.h" | 16 #include "base/threading/thread_local_storage.h" |
| 16 #include "base/trace_event/trace_event.h" | 17 #include "base/trace_event/trace_event.h" |
| 17 | 18 |
| 18 namespace base { | 19 namespace base { |
| 19 namespace trace_event { | 20 namespace trace_event { |
| 20 | 21 |
| 21 namespace { | 22 namespace { |
| 22 | 23 |
| 23 // Maximum number of nested TRACE_EVENT scopes to record. Must be less than | 24 // Maximum number of nested TRACE_EVENT scopes to record. Must be less than |
| (...skipping 287 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 311 // | 312 // |
| 312 // Skip input after MAPPED_LIBRARIES. | 313 // Skip input after MAPPED_LIBRARIES. |
| 313 std::string input_string; | 314 std::string input_string; |
| 314 const char* mapped_libraries = strstr(input, "MAPPED_LIBRARIES"); | 315 const char* mapped_libraries = strstr(input, "MAPPED_LIBRARIES"); |
| 315 if (mapped_libraries) { | 316 if (mapped_libraries) { |
| 316 input_string.assign(input, mapped_libraries - input); | 317 input_string.assign(input, mapped_libraries - input); |
| 317 } else { | 318 } else { |
| 318 input_string.assign(input); | 319 input_string.assign(input); |
| 319 } | 320 } |
| 320 | 321 |
| 321 std::vector<std::string> lines; | 322 std::vector<std::string> lines = base::SplitString( |
| 322 size_t line_count = Tokenize(input_string, "\n", &lines); | 323 input_string, "\n", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY); |
| 323 if (line_count == 0) { | 324 if (lines.empty()) { |
| 324 DLOG(WARNING) << "No lines found"; | 325 DLOG(WARNING) << "No lines found"; |
| 325 return; | 326 return; |
| 326 } | 327 } |
| 327 | 328 |
| 328 // Handle the initial summary line. | 329 // Handle the initial summary line. |
| 329 output->append("["); | 330 output->append("["); |
| 330 AppendHeapProfileTotalsAsTraceFormat(lines[0], output); | 331 AppendHeapProfileTotalsAsTraceFormat(lines[0], output); |
| 331 | 332 |
| 332 // Handle the following stack trace lines. | 333 // Handle the following stack trace lines. |
| 333 for (size_t i = 1; i < line_count; ++i) { | 334 for (size_t i = 1; i < lines.size(); i++) |
| 334 const std::string& line = lines[i]; | 335 AppendHeapProfileLineAsTraceFormat(lines[i], output); |
| 335 AppendHeapProfileLineAsTraceFormat(line, output); | |
| 336 } | |
| 337 output->append("]\n"); | 336 output->append("]\n"); |
| 338 } | 337 } |
| 339 | 338 |
| 340 void AppendHeapProfileTotalsAsTraceFormat(const std::string& line, | 339 void AppendHeapProfileTotalsAsTraceFormat(const std::string& line, |
| 341 std::string* output) { | 340 std::string* output) { |
| 342 // This is what a line looks like: | 341 // This is what a line looks like: |
| 343 // heap profile: 357: 55227 [ 14653: 2624014] @ heapprofile | 342 // heap profile: 357: 55227 [ 14653: 2624014] @ heapprofile |
| 344 // | 343 // |
| 345 // The numbers represent total allocations since profiling was enabled. | 344 // The numbers represent total allocations since profiling was enabled. |
| 346 // From the example above: | 345 // From the example above: |
| 347 // 357 = Outstanding allocations (mallocs - frees) | 346 // 357 = Outstanding allocations (mallocs - frees) |
| 348 // 55227 = Outstanding bytes (malloc bytes - free bytes) | 347 // 55227 = Outstanding bytes (malloc bytes - free bytes) |
| 349 // 14653 = Total allocations (mallocs) | 348 // 14653 = Total allocations (mallocs) |
| 350 // 2624014 = Total bytes (malloc bytes) | 349 // 2624014 = Total bytes (malloc bytes) |
| 351 std::vector<std::string> tokens; | 350 std::vector<std::string> tokens = base::SplitString( |
| 352 Tokenize(line, " :[]@", &tokens); | 351 line, " :[]@", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY); |
| 353 if (tokens.size() < 4) { | 352 if (tokens.size() < 4) { |
| 354 DLOG(WARNING) << "Invalid totals line " << line; | 353 DLOG(WARNING) << "Invalid totals line " << line; |
| 355 return; | 354 return; |
| 356 } | 355 } |
| 357 DCHECK_EQ(tokens[0], "heap"); | 356 DCHECK_EQ(tokens[0], "heap"); |
| 358 DCHECK_EQ(tokens[1], "profile"); | 357 DCHECK_EQ(tokens[1], "profile"); |
| 359 output->append("{\"current_allocs\": "); | 358 output->append("{\"current_allocs\": "); |
| 360 output->append(tokens[2]); | 359 output->append(tokens[2]); |
| 361 output->append(", \"current_bytes\": "); | 360 output->append(", \"current_bytes\": "); |
| 362 output->append(tokens[3]); | 361 output->append(tokens[3]); |
| 363 output->append(", \"trace\": \"\"}"); | 362 output->append(", \"trace\": \"\"}"); |
| 364 } | 363 } |
| 365 | 364 |
| 366 bool AppendHeapProfileLineAsTraceFormat(const std::string& line, | 365 bool AppendHeapProfileLineAsTraceFormat(const std::string& line, |
| 367 std::string* output) { | 366 std::string* output) { |
| 368 // This is what a line looks like: | 367 // This is what a line looks like: |
| 369 // 68: 4195 [ 1087: 98009] @ 0x7fa7fa9b9ba0 0x7fa7f4b3be13 | 368 // 68: 4195 [ 1087: 98009] @ 0x7fa7fa9b9ba0 0x7fa7f4b3be13 |
| 370 // | 369 // |
| 371 // The numbers represent allocations for a particular stack trace since | 370 // The numbers represent allocations for a particular stack trace since |
| 372 // profiling was enabled. From the example above: | 371 // profiling was enabled. From the example above: |
| 373 // 68 = Outstanding allocations (mallocs - frees) | 372 // 68 = Outstanding allocations (mallocs - frees) |
| 374 // 4195 = Outstanding bytes (malloc bytes - free bytes) | 373 // 4195 = Outstanding bytes (malloc bytes - free bytes) |
| 375 // 1087 = Total allocations (mallocs) | 374 // 1087 = Total allocations (mallocs) |
| 376 // 98009 = Total bytes (malloc bytes) | 375 // 98009 = Total bytes (malloc bytes) |
| 377 // | 376 // |
| 378 // 0x7fa7fa9b9ba0 0x7fa7f4b3be13 = Stack trace represented as pointers to | 377 // 0x7fa7fa9b9ba0 0x7fa7f4b3be13 = Stack trace represented as pointers to |
| 379 // static strings from trace event categories | 378 // static strings from trace event categories |
| 380 // and names. | 379 // and names. |
| 381 std::vector<std::string> tokens; | 380 std::vector<std::string> tokens = base::SplitString( |
| 382 Tokenize(line, " :[]@", &tokens); | 381 line, " :[]@", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY); |
| 383 // It's valid to have no stack addresses, so only require 4 tokens. | 382 // It's valid to have no stack addresses, so only require 4 tokens. |
| 384 if (tokens.size() < 4) { | 383 if (tokens.size() < 4) { |
| 385 DLOG(WARNING) << "Invalid line " << line; | 384 DLOG(WARNING) << "Invalid line " << line; |
| 386 return false; | 385 return false; |
| 387 } | 386 } |
| 388 // Don't bother with stacks that have no current allocations. | 387 // Don't bother with stacks that have no current allocations. |
| 389 if (tokens[0] == "0") | 388 if (tokens[0] == "0") |
| 390 return false; | 389 return false; |
| 391 output->append(",\n"); | 390 output->append(",\n"); |
| 392 output->append("{\"current_allocs\": "); | 391 output->append("{\"current_allocs\": "); |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 428 if (!base::HexStringToUInt64(hex_address, &address)) | 427 if (!base::HexStringToUInt64(hex_address, &address)) |
| 429 return "error"; | 428 return "error"; |
| 430 if (!address) | 429 if (!address) |
| 431 return "null"; | 430 return "null"; |
| 432 // Note that this cast handles 64-bit to 32-bit conversion if necessary. | 431 // Note that this cast handles 64-bit to 32-bit conversion if necessary. |
| 433 return reinterpret_cast<const char*>(address); | 432 return reinterpret_cast<const char*>(address); |
| 434 } | 433 } |
| 435 | 434 |
| 436 } // namespace trace_event | 435 } // namespace trace_event |
| 437 } // namespace base | 436 } // namespace base |
| OLD | NEW |