| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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_impl.h" | 5 #include "base/trace_event/trace_event_impl.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <cmath> | 8 #include <cmath> |
| 9 | 9 |
| 10 #include "base/base_switches.h" | 10 #include "base/base_switches.h" |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 54 | 54 |
| 55 namespace base { | 55 namespace base { |
| 56 namespace trace_event { | 56 namespace trace_event { |
| 57 | 57 |
| 58 namespace { | 58 namespace { |
| 59 | 59 |
| 60 // The overhead of TraceEvent above this threshold will be reported in the | 60 // The overhead of TraceEvent above this threshold will be reported in the |
| 61 // trace. | 61 // trace. |
| 62 const int kOverheadReportThresholdInMicroseconds = 50; | 62 const int kOverheadReportThresholdInMicroseconds = 50; |
| 63 | 63 |
| 64 // String options that can be used to initialize TraceOptions. | |
| 65 const char kRecordUntilFull[] = "record-until-full"; | |
| 66 const char kRecordContinuously[] = "record-continuously"; | |
| 67 const char kRecordAsMuchAsPossible[] = "record-as-much-as-possible"; | |
| 68 const char kTraceToConsole[] = "trace-to-console"; | |
| 69 const char kEnableSampling[] = "enable-sampling"; | |
| 70 const char kEnableSystrace[] = "enable-systrace"; | |
| 71 const char kEnableArgumentFilter[] = "enable-argument-filter"; | |
| 72 | |
| 73 // Controls the number of trace events we will buffer in-memory | 64 // Controls the number of trace events we will buffer in-memory |
| 74 // before throwing them away. | 65 // before throwing them away. |
| 75 const size_t kTraceBufferChunkSize = TraceBufferChunk::kTraceBufferChunkSize; | 66 const size_t kTraceBufferChunkSize = TraceBufferChunk::kTraceBufferChunkSize; |
| 76 const size_t kTraceEventVectorBigBufferChunks = | 67 const size_t kTraceEventVectorBigBufferChunks = |
| 77 512000000 / kTraceBufferChunkSize; | 68 512000000 / kTraceBufferChunkSize; |
| 78 const size_t kTraceEventVectorBufferChunks = 256000 / kTraceBufferChunkSize; | 69 const size_t kTraceEventVectorBufferChunks = 256000 / kTraceBufferChunkSize; |
| 79 const size_t kTraceEventRingBufferChunks = kTraceEventVectorBufferChunks / 4; | 70 const size_t kTraceEventRingBufferChunks = kTraceEventVectorBufferChunks / 4; |
| 80 const size_t kTraceEventBufferSizeInBytes = 100 * 1024; | 71 const size_t kTraceEventBufferSizeInBytes = 100 * 1024; |
| 81 // Can store results for 30 seconds with 1 ms sampling interval. | 72 // Can store results for 30 seconds with 1 ms sampling interval. |
| 82 const size_t kMonitorTraceEventBufferChunks = 30000 / kTraceBufferChunkSize; | 73 const size_t kMonitorTraceEventBufferChunks = 30000 / kTraceBufferChunkSize; |
| 83 // ECHO_TO_CONSOLE needs a small buffer to hold the unfinished COMPLETE events. | 74 // ECHO_TO_CONSOLE needs a small buffer to hold the unfinished COMPLETE events. |
| 84 const size_t kEchoToConsoleTraceEventBufferChunks = 256; | 75 const size_t kEchoToConsoleTraceEventBufferChunks = 256; |
| 85 | 76 |
| 86 const int kThreadFlushTimeoutMs = 3000; | 77 const int kThreadFlushTimeoutMs = 3000; |
| 87 | 78 |
| 88 #if !defined(OS_NACL) | 79 #if !defined(OS_NACL) |
| 89 // These categories will cause deadlock when ECHO_TO_CONSOLE. crbug.com/325575. | 80 // These categories will cause deadlock when ECHO_TO_CONSOLE. crbug.com/325575. |
| 90 const char kEchoToConsoleCategoryFilter[] = "-ipc,-task"; | 81 const char kEchoToConsoleCategoryFilter[] = "-ipc,-task"; |
| 91 #endif | 82 #endif |
| 92 | 83 |
| 93 const char kSyntheticDelayCategoryFilterPrefix[] = "DELAY("; | |
| 94 | |
| 95 #define MAX_CATEGORY_GROUPS 100 | 84 #define MAX_CATEGORY_GROUPS 100 |
| 96 | 85 |
| 97 // Parallel arrays g_category_groups and g_category_group_enabled are separate | 86 // Parallel arrays g_category_groups and g_category_group_enabled are separate |
| 98 // so that a pointer to a member of g_category_group_enabled can be easily | 87 // so that a pointer to a member of g_category_group_enabled can be easily |
| 99 // converted to an index into g_category_groups. This allows macros to deal | 88 // converted to an index into g_category_groups. This allows macros to deal |
| 100 // only with char enabled pointers from g_category_group_enabled, and we can | 89 // only with char enabled pointers from g_category_group_enabled, and we can |
| 101 // convert internally to determine the category name from the char enabled | 90 // convert internally to determine the category name from the char enabled |
| 102 // pointer. | 91 // pointer. |
| 103 const char* g_category_groups[MAX_CATEGORY_GROUPS] = { | 92 const char* g_category_groups[MAX_CATEGORY_GROUPS] = { |
| 104 "toplevel", | 93 "toplevel", |
| (...skipping 878 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 983 : bucket(bucket), | 972 : bucket(bucket), |
| 984 bucket_name(name), | 973 bucket_name(name), |
| 985 callback(callback) { | 974 callback(callback) { |
| 986 } | 975 } |
| 987 | 976 |
| 988 TraceBucketData::~TraceBucketData() { | 977 TraceBucketData::~TraceBucketData() { |
| 989 } | 978 } |
| 990 | 979 |
| 991 //////////////////////////////////////////////////////////////////////////////// | 980 //////////////////////////////////////////////////////////////////////////////// |
| 992 // | 981 // |
| 993 // TraceOptions | |
| 994 // | |
| 995 //////////////////////////////////////////////////////////////////////////////// | |
| 996 | |
| 997 bool TraceOptions::SetFromString(const std::string& options_string) { | |
| 998 record_mode = RECORD_UNTIL_FULL; | |
| 999 enable_sampling = false; | |
| 1000 enable_systrace = false; | |
| 1001 | |
| 1002 std::vector<std::string> split; | |
| 1003 std::vector<std::string>::iterator iter; | |
| 1004 base::SplitString(options_string, ',', &split); | |
| 1005 for (iter = split.begin(); iter != split.end(); ++iter) { | |
| 1006 if (*iter == kRecordUntilFull) { | |
| 1007 record_mode = RECORD_UNTIL_FULL; | |
| 1008 } else if (*iter == kRecordContinuously) { | |
| 1009 record_mode = RECORD_CONTINUOUSLY; | |
| 1010 } else if (*iter == kTraceToConsole) { | |
| 1011 record_mode = ECHO_TO_CONSOLE; | |
| 1012 } else if (*iter == kRecordAsMuchAsPossible) { | |
| 1013 record_mode = RECORD_AS_MUCH_AS_POSSIBLE; | |
| 1014 } else if (*iter == kEnableSampling) { | |
| 1015 enable_sampling = true; | |
| 1016 } else if (*iter == kEnableSystrace) { | |
| 1017 enable_systrace = true; | |
| 1018 } else if (*iter == kEnableArgumentFilter) { | |
| 1019 enable_argument_filter = true; | |
| 1020 } else { | |
| 1021 return false; | |
| 1022 } | |
| 1023 } | |
| 1024 return true; | |
| 1025 } | |
| 1026 | |
| 1027 std::string TraceOptions::ToString() const { | |
| 1028 std::string ret; | |
| 1029 switch (record_mode) { | |
| 1030 case RECORD_UNTIL_FULL: | |
| 1031 ret = kRecordUntilFull; | |
| 1032 break; | |
| 1033 case RECORD_CONTINUOUSLY: | |
| 1034 ret = kRecordContinuously; | |
| 1035 break; | |
| 1036 case ECHO_TO_CONSOLE: | |
| 1037 ret = kTraceToConsole; | |
| 1038 break; | |
| 1039 case RECORD_AS_MUCH_AS_POSSIBLE: | |
| 1040 ret = kRecordAsMuchAsPossible; | |
| 1041 break; | |
| 1042 default: | |
| 1043 NOTREACHED(); | |
| 1044 } | |
| 1045 if (enable_sampling) | |
| 1046 ret = ret + "," + kEnableSampling; | |
| 1047 if (enable_systrace) | |
| 1048 ret = ret + "," + kEnableSystrace; | |
| 1049 if (enable_argument_filter) | |
| 1050 ret = ret + "," + kEnableArgumentFilter; | |
| 1051 return ret; | |
| 1052 } | |
| 1053 | |
| 1054 //////////////////////////////////////////////////////////////////////////////// | |
| 1055 // | |
| 1056 // TraceLog | 982 // TraceLog |
| 1057 // | 983 // |
| 1058 //////////////////////////////////////////////////////////////////////////////// | 984 //////////////////////////////////////////////////////////////////////////////// |
| 1059 | 985 |
| 1060 class TraceLog::ThreadLocalEventBuffer | 986 class TraceLog::ThreadLocalEventBuffer |
| 1061 : public MessageLoop::DestructionObserver { | 987 : public MessageLoop::DestructionObserver { |
| 1062 public: | 988 public: |
| 1063 ThreadLocalEventBuffer(TraceLog* trace_log); | 989 ThreadLocalEventBuffer(TraceLog* trace_log); |
| 1064 ~ThreadLocalEventBuffer() override; | 990 ~ThreadLocalEventBuffer() override; |
| 1065 | 991 |
| (...skipping 1358 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2424 } | 2350 } |
| 2425 | 2351 |
| 2426 void TraceLog::SetCurrentThreadBlocksMessageLoop() { | 2352 void TraceLog::SetCurrentThreadBlocksMessageLoop() { |
| 2427 thread_blocks_message_loop_.Set(true); | 2353 thread_blocks_message_loop_.Set(true); |
| 2428 if (thread_local_event_buffer_.Get()) { | 2354 if (thread_local_event_buffer_.Get()) { |
| 2429 // This will flush the thread local buffer. | 2355 // This will flush the thread local buffer. |
| 2430 delete thread_local_event_buffer_.Get(); | 2356 delete thread_local_event_buffer_.Get(); |
| 2431 } | 2357 } |
| 2432 } | 2358 } |
| 2433 | 2359 |
| 2434 bool CategoryFilter::IsEmptyOrContainsLeadingOrTrailingWhitespace( | |
| 2435 const std::string& str) { | |
| 2436 return str.empty() || | |
| 2437 str.at(0) == ' ' || | |
| 2438 str.at(str.length() - 1) == ' '; | |
| 2439 } | |
| 2440 | |
| 2441 CategoryFilter::CategoryFilter(const std::string& filter_string) { | |
| 2442 if (!filter_string.empty()) | |
| 2443 Initialize(filter_string); | |
| 2444 else | |
| 2445 Initialize(CategoryFilter::kDefaultCategoryFilterString); | |
| 2446 } | |
| 2447 | |
| 2448 CategoryFilter::CategoryFilter() { | |
| 2449 Initialize(CategoryFilter::kDefaultCategoryFilterString); | |
| 2450 } | |
| 2451 | |
| 2452 CategoryFilter::CategoryFilter(const CategoryFilter& cf) | |
| 2453 : included_(cf.included_), | |
| 2454 disabled_(cf.disabled_), | |
| 2455 excluded_(cf.excluded_), | |
| 2456 delays_(cf.delays_) { | |
| 2457 } | |
| 2458 | |
| 2459 CategoryFilter::~CategoryFilter() { | |
| 2460 } | |
| 2461 | |
| 2462 CategoryFilter& CategoryFilter::operator=(const CategoryFilter& rhs) { | |
| 2463 if (this == &rhs) | |
| 2464 return *this; | |
| 2465 | |
| 2466 included_ = rhs.included_; | |
| 2467 disabled_ = rhs.disabled_; | |
| 2468 excluded_ = rhs.excluded_; | |
| 2469 delays_ = rhs.delays_; | |
| 2470 return *this; | |
| 2471 } | |
| 2472 | |
| 2473 void CategoryFilter::Initialize(const std::string& filter_string) { | |
| 2474 // Tokenize list of categories, delimited by ','. | |
| 2475 StringTokenizer tokens(filter_string, ","); | |
| 2476 // Add each token to the appropriate list (included_,excluded_). | |
| 2477 while (tokens.GetNext()) { | |
| 2478 std::string category = tokens.token(); | |
| 2479 // Ignore empty categories. | |
| 2480 if (category.empty()) | |
| 2481 continue; | |
| 2482 // Synthetic delays are of the form 'DELAY(delay;option;option;...)'. | |
| 2483 if (category.find(kSyntheticDelayCategoryFilterPrefix) == 0 && | |
| 2484 category.at(category.size() - 1) == ')') { | |
| 2485 category = category.substr( | |
| 2486 strlen(kSyntheticDelayCategoryFilterPrefix), | |
| 2487 category.size() - strlen(kSyntheticDelayCategoryFilterPrefix) - 1); | |
| 2488 size_t name_length = category.find(';'); | |
| 2489 if (name_length != std::string::npos && name_length > 0 && | |
| 2490 name_length != category.size() - 1) { | |
| 2491 delays_.push_back(category); | |
| 2492 } | |
| 2493 } else if (category.at(0) == '-') { | |
| 2494 // Excluded categories start with '-'. | |
| 2495 // Remove '-' from category string. | |
| 2496 category = category.substr(1); | |
| 2497 excluded_.push_back(category); | |
| 2498 } else if (category.compare(0, strlen(TRACE_DISABLED_BY_DEFAULT("")), | |
| 2499 TRACE_DISABLED_BY_DEFAULT("")) == 0) { | |
| 2500 disabled_.push_back(category); | |
| 2501 } else { | |
| 2502 included_.push_back(category); | |
| 2503 } | |
| 2504 } | |
| 2505 } | |
| 2506 | |
| 2507 void CategoryFilter::WriteString(const StringList& values, | |
| 2508 std::string* out, | |
| 2509 bool included) const { | |
| 2510 bool prepend_comma = !out->empty(); | |
| 2511 int token_cnt = 0; | |
| 2512 for (StringList::const_iterator ci = values.begin(); | |
| 2513 ci != values.end(); ++ci) { | |
| 2514 if (token_cnt > 0 || prepend_comma) | |
| 2515 StringAppendF(out, ","); | |
| 2516 StringAppendF(out, "%s%s", (included ? "" : "-"), ci->c_str()); | |
| 2517 ++token_cnt; | |
| 2518 } | |
| 2519 } | |
| 2520 | |
| 2521 void CategoryFilter::WriteString(const StringList& delays, | |
| 2522 std::string* out) const { | |
| 2523 bool prepend_comma = !out->empty(); | |
| 2524 int token_cnt = 0; | |
| 2525 for (StringList::const_iterator ci = delays.begin(); | |
| 2526 ci != delays.end(); ++ci) { | |
| 2527 if (token_cnt > 0 || prepend_comma) | |
| 2528 StringAppendF(out, ","); | |
| 2529 StringAppendF(out, "%s%s)", kSyntheticDelayCategoryFilterPrefix, | |
| 2530 ci->c_str()); | |
| 2531 ++token_cnt; | |
| 2532 } | |
| 2533 } | |
| 2534 | |
| 2535 std::string CategoryFilter::ToString() const { | |
| 2536 std::string filter_string; | |
| 2537 WriteString(included_, &filter_string, true); | |
| 2538 WriteString(disabled_, &filter_string, true); | |
| 2539 WriteString(excluded_, &filter_string, false); | |
| 2540 WriteString(delays_, &filter_string); | |
| 2541 return filter_string; | |
| 2542 } | |
| 2543 | |
| 2544 bool CategoryFilter::IsCategoryGroupEnabled( | |
| 2545 const char* category_group_name) const { | |
| 2546 // TraceLog should call this method only as part of enabling/disabling | |
| 2547 // categories. | |
| 2548 | |
| 2549 bool had_enabled_by_default = false; | |
| 2550 DCHECK(category_group_name); | |
| 2551 CStringTokenizer category_group_tokens( | |
| 2552 category_group_name, category_group_name + strlen(category_group_name), | |
| 2553 ","); | |
| 2554 while (category_group_tokens.GetNext()) { | |
| 2555 std::string category_group_token = category_group_tokens.token(); | |
| 2556 // Don't allow empty tokens, nor tokens with leading or trailing space. | |
| 2557 DCHECK(!CategoryFilter::IsEmptyOrContainsLeadingOrTrailingWhitespace( | |
| 2558 category_group_token)) | |
| 2559 << "Disallowed category string"; | |
| 2560 if (IsCategoryEnabled(category_group_token.c_str())) { | |
| 2561 return true; | |
| 2562 } | |
| 2563 if (!MatchPattern(category_group_token.c_str(), | |
| 2564 TRACE_DISABLED_BY_DEFAULT("*"))) | |
| 2565 had_enabled_by_default = true; | |
| 2566 } | |
| 2567 // Do a second pass to check for explicitly disabled categories | |
| 2568 // (those explicitly enabled have priority due to first pass). | |
| 2569 category_group_tokens.Reset(); | |
| 2570 bool category_group_disabled = false; | |
| 2571 while (category_group_tokens.GetNext()) { | |
| 2572 std::string category_group_token = category_group_tokens.token(); | |
| 2573 for (StringList::const_iterator ci = excluded_.begin(); | |
| 2574 ci != excluded_.end(); ++ci) { | |
| 2575 if (MatchPattern(category_group_token.c_str(), ci->c_str())) { | |
| 2576 // Current token of category_group_name is present in excluded_list. | |
| 2577 // Flag the exclusion and proceed further to check if any of the | |
| 2578 // remaining categories of category_group_name is not present in the | |
| 2579 // excluded_ list. | |
| 2580 category_group_disabled = true; | |
| 2581 break; | |
| 2582 } | |
| 2583 // One of the category of category_group_name is not present in | |
| 2584 // excluded_ list. So, it has to be included_ list. Enable the | |
| 2585 // category_group_name for recording. | |
| 2586 category_group_disabled = false; | |
| 2587 } | |
| 2588 // One of the categories present in category_group_name is not present in | |
| 2589 // excluded_ list. Implies this category_group_name group can be enabled | |
| 2590 // for recording, since one of its groups is enabled for recording. | |
| 2591 if (!category_group_disabled) | |
| 2592 break; | |
| 2593 } | |
| 2594 // If the category group is not excluded, and there are no included patterns | |
| 2595 // we consider this category group enabled, as long as it had categories | |
| 2596 // other than disabled-by-default. | |
| 2597 return !category_group_disabled && | |
| 2598 included_.empty() && had_enabled_by_default; | |
| 2599 } | |
| 2600 | |
| 2601 bool CategoryFilter::IsCategoryEnabled(const char* category_name) const { | |
| 2602 StringList::const_iterator ci; | |
| 2603 | |
| 2604 // Check the disabled- filters and the disabled-* wildcard first so that a | |
| 2605 // "*" filter does not include the disabled. | |
| 2606 for (ci = disabled_.begin(); ci != disabled_.end(); ++ci) { | |
| 2607 if (MatchPattern(category_name, ci->c_str())) | |
| 2608 return true; | |
| 2609 } | |
| 2610 | |
| 2611 if (MatchPattern(category_name, TRACE_DISABLED_BY_DEFAULT("*"))) | |
| 2612 return false; | |
| 2613 | |
| 2614 for (ci = included_.begin(); ci != included_.end(); ++ci) { | |
| 2615 if (MatchPattern(category_name, ci->c_str())) | |
| 2616 return true; | |
| 2617 } | |
| 2618 | |
| 2619 return false; | |
| 2620 } | |
| 2621 | |
| 2622 bool CategoryFilter::HasIncludedPatterns() const { | |
| 2623 return !included_.empty(); | |
| 2624 } | |
| 2625 | |
| 2626 void CategoryFilter::Merge(const CategoryFilter& nested_filter) { | |
| 2627 // Keep included patterns only if both filters have an included entry. | |
| 2628 // Otherwise, one of the filter was specifying "*" and we want to honour the | |
| 2629 // broadest filter. | |
| 2630 if (HasIncludedPatterns() && nested_filter.HasIncludedPatterns()) { | |
| 2631 included_.insert(included_.end(), | |
| 2632 nested_filter.included_.begin(), | |
| 2633 nested_filter.included_.end()); | |
| 2634 } else { | |
| 2635 included_.clear(); | |
| 2636 } | |
| 2637 | |
| 2638 disabled_.insert(disabled_.end(), | |
| 2639 nested_filter.disabled_.begin(), | |
| 2640 nested_filter.disabled_.end()); | |
| 2641 excluded_.insert(excluded_.end(), | |
| 2642 nested_filter.excluded_.begin(), | |
| 2643 nested_filter.excluded_.end()); | |
| 2644 delays_.insert(delays_.end(), | |
| 2645 nested_filter.delays_.begin(), | |
| 2646 nested_filter.delays_.end()); | |
| 2647 } | |
| 2648 | |
| 2649 void CategoryFilter::Clear() { | |
| 2650 included_.clear(); | |
| 2651 disabled_.clear(); | |
| 2652 excluded_.clear(); | |
| 2653 } | |
| 2654 | |
| 2655 const CategoryFilter::StringList& | |
| 2656 CategoryFilter::GetSyntheticDelayValues() const { | |
| 2657 return delays_; | |
| 2658 } | |
| 2659 | |
| 2660 } // namespace trace_event | 2360 } // namespace trace_event |
| 2661 } // namespace base | 2361 } // namespace base |
| 2662 | 2362 |
| 2663 namespace trace_event_internal { | 2363 namespace trace_event_internal { |
| 2664 | 2364 |
| 2665 ScopedTraceBinaryEfficient::ScopedTraceBinaryEfficient( | 2365 ScopedTraceBinaryEfficient::ScopedTraceBinaryEfficient( |
| 2666 const char* category_group, const char* name) { | 2366 const char* category_group, const char* name) { |
| 2667 // The single atom works because for now the category_group can only be "gpu". | 2367 // The single atom works because for now the category_group can only be "gpu". |
| 2668 DCHECK_EQ(strcmp(category_group, "gpu"), 0); | 2368 DCHECK_EQ(strcmp(category_group, "gpu"), 0); |
| 2669 static TRACE_EVENT_API_ATOMIC_WORD atomic = 0; | 2369 static TRACE_EVENT_API_ATOMIC_WORD atomic = 0; |
| (...skipping 12 matching lines...) Expand all Loading... |
| 2682 } | 2382 } |
| 2683 | 2383 |
| 2684 ScopedTraceBinaryEfficient::~ScopedTraceBinaryEfficient() { | 2384 ScopedTraceBinaryEfficient::~ScopedTraceBinaryEfficient() { |
| 2685 if (*category_group_enabled_) { | 2385 if (*category_group_enabled_) { |
| 2686 TRACE_EVENT_API_UPDATE_TRACE_EVENT_DURATION(category_group_enabled_, | 2386 TRACE_EVENT_API_UPDATE_TRACE_EVENT_DURATION(category_group_enabled_, |
| 2687 name_, event_handle_); | 2387 name_, event_handle_); |
| 2688 } | 2388 } |
| 2689 } | 2389 } |
| 2690 | 2390 |
| 2691 } // namespace trace_event_internal | 2391 } // namespace trace_event_internal |
| OLD | NEW |