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
3 // found in the LICENSE file.
5 #include "base/debug/trace_event_impl.h"
10 #include "base/debug/leak_annotations.h"
11 #include "base/debug/trace_event.h"
12 #include "base/format_macros.h"
13 #include "base/lazy_instance.h"
14 #include "base/memory/singleton.h"
15 #include "base/process_util.h"
16 #include "base/stl_util.h"
17 #include "base/stringprintf.h"
18 #include "base/string_tokenizer.h"
19 #include "base/string_util.h"
20 #include "base/sys_info.h"
21 #include "base/third_party/dynamic_annotations/dynamic_annotations.h"
22 #include "base/threading/platform_thread.h"
23 #include "base/threading/thread_local.h"
24 #include "base/time.h"
25 #include "base/utf_string_conversions.h"
28 #include "base/debug/trace_event_win.h"
31 class DeleteTraceLogForTesting
{
33 static void Delete() {
34 Singleton
<base::debug::TraceLog
,
35 StaticMemorySingletonTraits
<base::debug::TraceLog
> >::OnExit(0);
42 // Controls the number of trace events we will buffer in-memory
43 // before throwing them away.
44 const size_t kTraceEventBufferSize
= 500000;
45 const size_t kTraceEventBatchSize
= 1000;
47 #define TRACE_EVENT_MAX_CATEGORIES 100
51 // Parallel arrays g_categories and g_category_enabled are separate so that
52 // a pointer to a member of g_category_enabled can be easily converted to an
53 // index into g_categories. This allows macros to deal only with char enabled
54 // pointers from g_category_enabled, and we can convert internally to determine
55 // the category name from the char enabled pointer.
56 const char* g_categories
[TRACE_EVENT_MAX_CATEGORIES
] = {
57 "tracing already shutdown",
58 "tracing categories exhausted; must increase TRACE_EVENT_MAX_CATEGORIES",
61 // The enabled flag is char instead of bool so that the API can be used from C.
62 unsigned char g_category_enabled
[TRACE_EVENT_MAX_CATEGORIES
] = { 0 };
63 const int g_category_already_shutdown
= 0;
64 const int g_category_categories_exhausted
= 1;
65 const int g_category_metadata
= 2;
66 int g_category_index
= 3; // skip initial 3 categories
68 // The most-recently captured name of the current thread
69 LazyInstance
<ThreadLocalPointer
<const char> >::Leaky
70 g_current_thread_name
= LAZY_INSTANCE_INITIALIZER
;
74 ////////////////////////////////////////////////////////////////////////////////
78 ////////////////////////////////////////////////////////////////////////////////
82 size_t GetAllocLength(const char* str
) { return str
? strlen(str
) + 1 : 0; }
84 // Copies |*member| into |*buffer|, sets |*member| to point to this new
85 // location, and then advances |*buffer| by the amount written.
86 void CopyTraceEventParameter(char** buffer
,
90 size_t written
= strlcpy(*buffer
, *member
, end
- *buffer
) + 1;
91 DCHECK_LE(static_cast<int>(written
), end
- *buffer
);
99 TraceEvent::TraceEvent()
101 category_enabled_(NULL
),
104 phase_(TRACE_EVENT_PHASE_BEGIN
),
106 arg_names_
[0] = NULL
;
107 arg_names_
[1] = NULL
;
108 memset(arg_values_
, 0, sizeof(arg_values_
));
111 TraceEvent::TraceEvent(int thread_id
,
114 const unsigned char* category_enabled
,
116 unsigned long long id
,
118 const char** arg_names
,
119 const unsigned char* arg_types
,
120 const unsigned long long* arg_values
,
122 : timestamp_(timestamp
),
124 category_enabled_(category_enabled
),
126 thread_id_(thread_id
),
129 // Clamp num_args since it may have been set by a third_party library.
130 num_args
= (num_args
> kTraceMaxNumArgs
) ? kTraceMaxNumArgs
: num_args
;
132 for (; i
< num_args
; ++i
) {
133 arg_names_
[i
] = arg_names
[i
];
134 arg_values_
[i
].as_uint
= arg_values
[i
];
135 arg_types_
[i
] = arg_types
[i
];
137 for (; i
< kTraceMaxNumArgs
; ++i
) {
138 arg_names_
[i
] = NULL
;
139 arg_values_
[i
].as_uint
= 0u;
140 arg_types_
[i
] = TRACE_VALUE_TYPE_UINT
;
143 bool copy
= !!(flags
& TRACE_EVENT_FLAG_COPY
);
144 size_t alloc_size
= 0;
146 alloc_size
+= GetAllocLength(name
);
147 for (i
= 0; i
< num_args
; ++i
) {
148 alloc_size
+= GetAllocLength(arg_names_
[i
]);
149 if (arg_types_
[i
] == TRACE_VALUE_TYPE_STRING
)
150 arg_types_
[i
] = TRACE_VALUE_TYPE_COPY_STRING
;
154 bool arg_is_copy
[kTraceMaxNumArgs
];
155 for (i
= 0; i
< num_args
; ++i
) {
156 // We only take a copy of arg_vals if they are of type COPY_STRING.
157 arg_is_copy
[i
] = (arg_types_
[i
] == TRACE_VALUE_TYPE_COPY_STRING
);
159 alloc_size
+= GetAllocLength(arg_values_
[i
].as_string
);
163 parameter_copy_storage_
= new base::RefCountedString
;
164 parameter_copy_storage_
->data().resize(alloc_size
);
165 char* ptr
= string_as_array(¶meter_copy_storage_
->data());
166 const char* end
= ptr
+ alloc_size
;
168 CopyTraceEventParameter(&ptr
, &name_
, end
);
169 for (i
= 0; i
< num_args
; ++i
)
170 CopyTraceEventParameter(&ptr
, &arg_names_
[i
], end
);
172 for (i
= 0; i
< num_args
; ++i
) {
174 CopyTraceEventParameter(&ptr
, &arg_values_
[i
].as_string
, end
);
176 DCHECK_EQ(end
, ptr
) << "Overrun by " << ptr
- end
;
180 TraceEvent::~TraceEvent() {
184 void TraceEvent::AppendValueAsJSON(unsigned char type
,
185 TraceEvent::TraceValue value
,
187 std::string::size_type start_pos
;
189 case TRACE_VALUE_TYPE_BOOL
:
190 *out
+= value
.as_bool
? "true" : "false";
192 case TRACE_VALUE_TYPE_UINT
:
193 StringAppendF(out
, "%" PRIu64
, static_cast<uint64
>(value
.as_uint
));
195 case TRACE_VALUE_TYPE_INT
:
196 StringAppendF(out
, "%" PRId64
, static_cast<int64
>(value
.as_int
));
198 case TRACE_VALUE_TYPE_DOUBLE
:
199 StringAppendF(out
, "%f", value
.as_double
);
201 case TRACE_VALUE_TYPE_POINTER
:
202 // JSON only supports double and int numbers.
203 // So as not to lose bits from a 64-bit pointer, output as a hex string.
204 StringAppendF(out
, "\"%" PRIx64
"\"", static_cast<uint64
>(
205 reinterpret_cast<intptr_t>(
208 case TRACE_VALUE_TYPE_STRING
:
209 case TRACE_VALUE_TYPE_COPY_STRING
:
211 start_pos
= out
->size();
212 *out
+= value
.as_string
? value
.as_string
: "NULL";
213 // insert backslash before special characters for proper json format.
214 while ((start_pos
= out
->find_first_of("\\\"", start_pos
)) !=
216 out
->insert(start_pos
, 1, '\\');
217 // skip inserted escape character and following character.
223 NOTREACHED() << "Don't know how to print this value";
228 void TraceEvent::AppendEventsAsJSON(const std::vector
<TraceEvent
>& events
,
232 for (size_t i
= 0; i
< count
&& start
+ i
< events
.size(); ++i
) {
235 events
[i
+ start
].AppendAsJSON(out
);
239 void TraceEvent::AppendAsJSON(std::string
* out
) const {
240 int64 time_int64
= timestamp_
.ToInternalValue();
241 int process_id
= TraceLog::GetInstance()->process_id();
242 // Category name checked at category creation time.
243 DCHECK(!strchr(name_
, '"'));
245 "{\"cat\":\"%s\",\"pid\":%i,\"tid\":%i,\"ts\":%" PRId64
","
246 "\"ph\":\"%c\",\"name\":\"%s\",\"args\":{",
247 TraceLog::GetCategoryName(category_enabled_
),
254 // Output argument names and values, stop at first NULL argument name.
255 for (int i
= 0; i
< kTraceMaxNumArgs
&& arg_names_
[i
]; ++i
) {
259 *out
+= arg_names_
[i
];
261 AppendValueAsJSON(arg_types_
[i
], arg_values_
[i
], out
);
265 // If id_ is set, print it out as a hex string so we don't loose any
266 // bits (it might be a 64-bit pointer).
267 if (flags_
& TRACE_EVENT_FLAG_HAS_ID
)
268 StringAppendF(out
, ",\"id\":\"%" PRIx64
"\"", static_cast<uint64
>(id_
));
272 ////////////////////////////////////////////////////////////////////////////////
276 ////////////////////////////////////////////////////////////////////////////////
278 TraceResultBuffer::OutputCallback
279 TraceResultBuffer::SimpleOutput::GetCallback() {
280 return base::Bind(&SimpleOutput::Append
, base::Unretained(this));
283 void TraceResultBuffer::SimpleOutput::Append(
284 const std::string
& json_trace_output
) {
285 json_output
+= json_trace_output
;
288 TraceResultBuffer::TraceResultBuffer() : append_comma_(false) {
291 TraceResultBuffer::~TraceResultBuffer() {
294 void TraceResultBuffer::SetOutputCallback(
295 const OutputCallback
& json_chunk_callback
) {
296 output_callback_
= json_chunk_callback
;
299 void TraceResultBuffer::Start() {
300 append_comma_
= false;
301 output_callback_
.Run("[");
304 void TraceResultBuffer::AddFragment(const std::string
& trace_fragment
) {
306 output_callback_
.Run(",");
307 append_comma_
= true;
308 output_callback_
.Run(trace_fragment
);
311 void TraceResultBuffer::Finish() {
312 output_callback_
.Run("]");
315 ////////////////////////////////////////////////////////////////////////////////
319 ////////////////////////////////////////////////////////////////////////////////
321 TraceLog::NotificationHelper::NotificationHelper(TraceLog
* trace_log
)
322 : trace_log_(trace_log
),
326 TraceLog::NotificationHelper::~NotificationHelper() {
329 void TraceLog::NotificationHelper::AddNotificationWhileLocked(
331 if (trace_log_
->notification_callback_
.is_null())
333 if (notification_
== 0)
334 callback_copy_
= trace_log_
->notification_callback_
;
335 notification_
|= notification
;
338 void TraceLog::NotificationHelper::SendNotificationIfAny() {
340 callback_copy_
.Run(notification_
);
344 TraceLog
* TraceLog::GetInstance() {
345 return Singleton
<TraceLog
, StaticMemorySingletonTraits
<TraceLog
> >::get();
350 dispatching_to_observer_list_(false),
351 watch_category_(NULL
) {
352 // Trace is enabled or disabled on one thread while other threads are
353 // accessing the enabled flag. We don't care whether edge-case events are
354 // traced or not, so we allow races on the enabled flag to keep the trace
356 // TODO(jbates): ANNOTATE_BENIGN_RACE_SIZED crashes windows TSAN bots:
357 // ANNOTATE_BENIGN_RACE_SIZED(g_category_enabled, sizeof(g_category_enabled),
358 // "trace_event category enabled");
359 for (int i
= 0; i
< TRACE_EVENT_MAX_CATEGORIES
; ++i
) {
360 ANNOTATE_BENIGN_RACE(&g_category_enabled
[i
],
361 "trace_event category enabled");
363 #if defined(OS_NACL) // NaCl shouldn't expose the process id.
366 SetProcessID(static_cast<int>(base::GetCurrentProcId()));
370 TraceLog::~TraceLog() {
373 const unsigned char* TraceLog::GetCategoryEnabled(const char* name
) {
374 TraceLog
* tracelog
= GetInstance();
376 DCHECK(!g_category_enabled
[g_category_already_shutdown
]);
377 return &g_category_enabled
[g_category_already_shutdown
];
379 return tracelog
->GetCategoryEnabledInternal(name
);
382 const char* TraceLog::GetCategoryName(const unsigned char* category_enabled
) {
383 // Calculate the index of the category by finding category_enabled in
384 // g_category_enabled array.
385 uintptr_t category_begin
= reinterpret_cast<uintptr_t>(g_category_enabled
);
386 uintptr_t category_ptr
= reinterpret_cast<uintptr_t>(category_enabled
);
387 DCHECK(category_ptr
>= category_begin
&&
388 category_ptr
< reinterpret_cast<uintptr_t>(g_category_enabled
+
389 TRACE_EVENT_MAX_CATEGORIES
)) <<
390 "out of bounds category pointer";
391 uintptr_t category_index
=
392 (category_ptr
- category_begin
) / sizeof(g_category_enabled
[0]);
393 return g_categories
[category_index
];
396 static void EnableMatchingCategory(int category_index
,
397 const std::vector
<std::string
>& patterns
,
398 unsigned char matched_value
,
399 unsigned char unmatched_value
) {
400 std::vector
<std::string
>::const_iterator ci
= patterns
.begin();
401 bool is_match
= false;
402 for (; ci
!= patterns
.end(); ++ci
) {
403 is_match
= MatchPattern(g_categories
[category_index
], ci
->c_str());
407 g_category_enabled
[category_index
] = is_match
?
408 matched_value
: unmatched_value
;
411 // Enable/disable each category based on the category filters in |patterns|.
412 // If the category name matches one of the patterns, its enabled status is set
413 // to |matched_value|. Otherwise its enabled status is set to |unmatched_value|.
414 static void EnableMatchingCategories(const std::vector
<std::string
>& patterns
,
415 unsigned char matched_value
,
416 unsigned char unmatched_value
) {
417 for (int i
= 0; i
< g_category_index
; i
++)
418 EnableMatchingCategory(i
, patterns
, matched_value
, unmatched_value
);
421 const unsigned char* TraceLog::GetCategoryEnabledInternal(const char* name
) {
422 AutoLock
lock(lock_
);
423 DCHECK(!strchr(name
, '"')) << "Category names may not contain double quote";
425 unsigned char* category_enabled
= NULL
;
426 // Search for pre-existing category matching this name
427 for (int i
= 0; i
< g_category_index
; i
++) {
428 if (strcmp(g_categories
[i
], name
) == 0) {
429 category_enabled
= &g_category_enabled
[i
];
434 if (!category_enabled
) {
435 // Create a new category
436 DCHECK(g_category_index
< TRACE_EVENT_MAX_CATEGORIES
) <<
437 "must increase TRACE_EVENT_MAX_CATEGORIES";
438 if (g_category_index
< TRACE_EVENT_MAX_CATEGORIES
) {
439 int new_index
= g_category_index
++;
440 // Don't hold on to the name pointer, so that we can create categories
441 // with strings not known at compile time (this is required by
443 const char* new_name
= base::strdup(name
);
444 ANNOTATE_LEAKING_OBJECT_PTR(new_name
);
445 g_categories
[new_index
] = new_name
;
446 DCHECK(!g_category_enabled
[new_index
]);
448 // Note that if both included and excluded_categories are empty, the
449 // else clause below excludes nothing, thereby enabling this category.
450 if (!included_categories_
.empty()) {
451 EnableMatchingCategory(new_index
, included_categories_
,
452 CATEGORY_ENABLED
, 0);
454 EnableMatchingCategory(new_index
, excluded_categories_
,
455 0, CATEGORY_ENABLED
);
458 g_category_enabled
[new_index
] = 0;
460 category_enabled
= &g_category_enabled
[new_index
];
462 category_enabled
= &g_category_enabled
[g_category_categories_exhausted
];
465 #if defined(OS_ANDROID)
466 ApplyATraceEnabledFlag(category_enabled
);
468 return category_enabled
;
471 void TraceLog::GetKnownCategories(std::vector
<std::string
>* categories
) {
472 AutoLock
lock(lock_
);
473 for (int i
= 0; i
< g_category_index
; i
++)
474 categories
->push_back(g_categories
[i
]);
477 void TraceLog::SetEnabled(const std::vector
<std::string
>& included_categories
,
478 const std::vector
<std::string
>& excluded_categories
) {
479 AutoLock
lock(lock_
);
483 if (dispatching_to_observer_list_
) {
485 "Cannot manipulate TraceLog::Enabled state from an observer.";
489 dispatching_to_observer_list_
= true;
490 FOR_EACH_OBSERVER(EnabledStateChangedObserver
, enabled_state_observer_list_
,
491 OnTraceLogWillEnable());
492 dispatching_to_observer_list_
= false;
494 logged_events_
.reserve(1024);
496 included_categories_
= included_categories
;
497 excluded_categories_
= excluded_categories
;
498 // Note that if both included and excluded_categories are empty, the else
499 // clause below excludes nothing, thereby enabling all categories.
500 if (!included_categories_
.empty())
501 EnableMatchingCategories(included_categories_
, CATEGORY_ENABLED
, 0);
503 EnableMatchingCategories(excluded_categories_
, 0, CATEGORY_ENABLED
);
506 void TraceLog::SetEnabled(const std::string
& categories
) {
507 std::vector
<std::string
> included
, excluded
;
508 // Tokenize list of categories, delimited by ','.
509 StringTokenizer
tokens(categories
, ",");
510 while (tokens
.GetNext()) {
511 bool is_included
= true;
512 std::string category
= tokens
.token();
513 // Excluded categories start with '-'.
514 if (category
.at(0) == '-') {
515 // Remove '-' from category string.
516 category
= category
.substr(1);
520 included
.push_back(category
);
522 excluded
.push_back(category
);
524 SetEnabled(included
, excluded
);
527 void TraceLog::GetEnabledTraceCategories(
528 std::vector
<std::string
>* included_out
,
529 std::vector
<std::string
>* excluded_out
) {
530 AutoLock
lock(lock_
);
532 *included_out
= included_categories_
;
533 *excluded_out
= excluded_categories_
;
537 void TraceLog::SetDisabled() {
538 AutoLock
lock(lock_
);
542 if (dispatching_to_observer_list_
) {
544 << "Cannot manipulate TraceLog::Enabled state from an observer.";
548 dispatching_to_observer_list_
= true;
549 FOR_EACH_OBSERVER(EnabledStateChangedObserver
, enabled_state_observer_list_
,
550 OnTraceLogWillDisable());
551 dispatching_to_observer_list_
= false;
554 included_categories_
.clear();
555 excluded_categories_
.clear();
556 watch_category_
= NULL
;
557 watch_event_name_
= "";
558 for (int i
= 0; i
< g_category_index
; i
++)
559 g_category_enabled
[i
] = 0;
560 AddThreadNameMetadataEvents();
561 #if defined(OS_ANDROID)
562 AddClockSyncMetadataEvents();
566 void TraceLog::SetEnabled(bool enabled
) {
568 SetEnabled(std::vector
<std::string
>(), std::vector
<std::string
>());
573 void TraceLog::AddEnabledStateObserver(EnabledStateChangedObserver
* listener
) {
574 enabled_state_observer_list_
.AddObserver(listener
);
577 void TraceLog::RemoveEnabledStateObserver(
578 EnabledStateChangedObserver
* listener
) {
579 enabled_state_observer_list_
.RemoveObserver(listener
);
582 float TraceLog::GetBufferPercentFull() const {
583 return (float)((double)logged_events_
.size()/(double)kTraceEventBufferSize
);
586 void TraceLog::SetNotificationCallback(
587 const TraceLog::NotificationCallback
& cb
) {
588 AutoLock
lock(lock_
);
589 notification_callback_
= cb
;
592 void TraceLog::Flush(const TraceLog::OutputCallback
& cb
) {
593 std::vector
<TraceEvent
> previous_logged_events
;
595 AutoLock
lock(lock_
);
596 previous_logged_events
.swap(logged_events_
);
600 i
< previous_logged_events
.size();
601 i
+= kTraceEventBatchSize
) {
602 scoped_refptr
<RefCountedString
> json_events_str_ptr
=
603 new RefCountedString();
604 TraceEvent::AppendEventsAsJSON(previous_logged_events
,
606 kTraceEventBatchSize
,
607 &(json_events_str_ptr
->data()));
608 cb
.Run(json_events_str_ptr
);
612 void TraceLog::AddTraceEvent(char phase
,
613 const unsigned char* category_enabled
,
615 unsigned long long id
,
617 const char** arg_names
,
618 const unsigned char* arg_types
,
619 const unsigned long long* arg_values
,
620 unsigned char flags
) {
623 #if defined(OS_ANDROID)
624 SendToATrace(phase
, GetCategoryName(category_enabled
), name
,
625 num_args
, arg_names
, arg_types
, arg_values
);
628 TimeTicks now
= TimeTicks::NowFromSystemTraceTime() - time_offset_
;
629 NotificationHelper
notifier(this);
631 AutoLock
lock(lock_
);
632 if (*category_enabled
!= CATEGORY_ENABLED
)
634 if (logged_events_
.size() >= kTraceEventBufferSize
)
637 int thread_id
= static_cast<int>(PlatformThread::CurrentId());
639 const char* new_name
= PlatformThread::GetName();
640 // Check if the thread name has been set or changed since the previous
641 // call (if any), but don't bother if the new name is empty. Note this will
642 // not detect a thread name change within the same char* buffer address: we
643 // favor common case performance over corner case correctness.
644 if (new_name
!= g_current_thread_name
.Get().Get() &&
645 new_name
&& *new_name
) {
646 g_current_thread_name
.Get().Set(new_name
);
647 base::hash_map
<int, std::string
>::iterator existing_name
=
648 thread_names_
.find(thread_id
);
649 if (existing_name
== thread_names_
.end()) {
650 // This is a new thread id, and a new name.
651 thread_names_
[thread_id
] = new_name
;
653 // This is a thread id that we've seen before, but potentially with a
655 std::vector
<base::StringPiece
> existing_names
;
656 Tokenize(existing_name
->second
, ",", &existing_names
);
657 bool found
= std::find(existing_names
.begin(),
658 existing_names
.end(),
659 new_name
) != existing_names
.end();
661 existing_name
->second
.push_back(',');
662 existing_name
->second
.append(new_name
);
667 if (flags
& TRACE_EVENT_FLAG_MANGLE_ID
)
668 id
^= process_id_hash_
;
670 logged_events_
.push_back(
671 TraceEvent(thread_id
,
672 now
, phase
, category_enabled
, name
, id
,
673 num_args
, arg_names
, arg_types
, arg_values
,
676 if (logged_events_
.size() == kTraceEventBufferSize
)
677 notifier
.AddNotificationWhileLocked(TRACE_BUFFER_FULL
);
679 if (watch_category_
== category_enabled
&& watch_event_name_
== name
)
680 notifier
.AddNotificationWhileLocked(EVENT_WATCH_NOTIFICATION
);
683 notifier
.SendNotificationIfAny();
686 void TraceLog::AddTraceEventEtw(char phase
,
691 TraceEventETWProvider::Trace(name
, phase
, id
, extra
);
693 INTERNAL_TRACE_EVENT_ADD(phase
, "ETW Trace Event", name
,
694 TRACE_EVENT_FLAG_COPY
, "id", id
, "extra", extra
);
697 void TraceLog::AddTraceEventEtw(char phase
,
700 const std::string
& extra
)
703 TraceEventETWProvider::Trace(name
, phase
, id
, extra
);
705 INTERNAL_TRACE_EVENT_ADD(phase
, "ETW Trace Event", name
,
706 TRACE_EVENT_FLAG_COPY
, "id", id
, "extra", extra
);
709 void TraceLog::SetWatchEvent(const std::string
& category_name
,
710 const std::string
& event_name
) {
711 const unsigned char* category
= GetCategoryEnabled(category_name
.c_str());
712 int notify_count
= 0;
714 AutoLock
lock(lock_
);
715 watch_category_
= category
;
716 watch_event_name_
= event_name
;
718 // First, search existing events for watch event because we want to catch it
719 // even if it has already occurred.
720 for (size_t i
= 0u; i
< logged_events_
.size(); ++i
) {
721 if (category
== logged_events_
[i
].category_enabled() &&
722 strcmp(event_name
.c_str(), logged_events_
[i
].name()) == 0) {
728 // Send notification for each event found.
729 for (int i
= 0; i
< notify_count
; ++i
) {
730 NotificationHelper
notifier(this);
732 notifier
.AddNotificationWhileLocked(EVENT_WATCH_NOTIFICATION
);
734 notifier
.SendNotificationIfAny();
738 void TraceLog::CancelWatchEvent() {
739 AutoLock
lock(lock_
);
740 watch_category_
= NULL
;
741 watch_event_name_
= "";
744 void TraceLog::AddThreadNameMetadataEvents() {
745 lock_
.AssertAcquired();
746 for(base::hash_map
<int, std::string
>::iterator it
= thread_names_
.begin();
747 it
!= thread_names_
.end();
749 if (!it
->second
.empty()) {
751 const char* arg_name
= "name";
752 unsigned char arg_type
;
753 unsigned long long arg_value
;
754 trace_event_internal::SetTraceValue(it
->second
, &arg_type
, &arg_value
);
755 logged_events_
.push_back(
756 TraceEvent(it
->first
,
757 TimeTicks(), TRACE_EVENT_PHASE_METADATA
,
758 &g_category_enabled
[g_category_metadata
],
759 "thread_name", trace_event_internal::kNoEventId
,
760 num_args
, &arg_name
, &arg_type
, &arg_value
,
761 TRACE_EVENT_FLAG_NONE
));
766 void TraceLog::DeleteForTesting() {
767 DeleteTraceLogForTesting::Delete();
770 void TraceLog::Resurrect() {
771 StaticMemorySingletonTraits
<TraceLog
>::Resurrect();
774 void TraceLog::SetProcessID(int process_id
) {
775 process_id_
= process_id
;
776 // Create a FNV hash from the process ID for XORing.
777 // See http://isthe.com/chongo/tech/comp/fnv/ for algorithm details.
778 unsigned long long offset_basis
= 14695981039346656037ull;
779 unsigned long long fnv_prime
= 1099511628211ull;
780 unsigned long long pid
= static_cast<unsigned long long>(process_id_
);
781 process_id_hash_
= (offset_basis
^ pid
) * fnv_prime
;
784 void TraceLog::SetTimeOffset(TimeDelta offset
) {
785 time_offset_
= offset
;