Chromium Code Reviews| Index: base/debug/trace_event_impl.cc |
| diff --git a/base/debug/trace_event_impl.cc b/base/debug/trace_event_impl.cc |
| index 0f520b922de6a93e53b09ec0a57534b7190e367a..36e665d4f1e520f65d078d50ff403d60c550d6ec 100644 |
| --- a/base/debug/trace_event_impl.cc |
| +++ b/base/debug/trace_event_impl.cc |
| @@ -67,6 +67,7 @@ const char* g_categories[TRACE_EVENT_MAX_CATEGORIES] = { |
| "tracing categories exhausted; must increase TRACE_EVENT_MAX_CATEGORIES", |
| "__metadata", |
| }; |
| + |
| // The enabled flag is char instead of bool so that the API can be used from C. |
| unsigned char g_category_enabled[TRACE_EVENT_MAX_CATEGORIES] = { 0 }; |
| const int g_category_already_shutdown = 0; |
| @@ -81,6 +82,123 @@ LazyInstance<ThreadLocalPointer<const char> >::Leaky |
| g_current_thread_name = LAZY_INSTANCE_INITIALIZER; |
| const char kRecordUntilFull[] = "record-until-full"; |
| +const char kRecordContinuously[] = "record-continuously"; |
| + |
| +class TraceBufferRingBuffer : public TraceBuffer { |
| + public: |
| + TraceBufferRingBuffer() |
| + : logged_events_newest_(0), |
| + logged_events_oldest_(0) { |
| + } |
| + |
| + ~TraceBufferRingBuffer() {} |
| + |
| + void AddEvent(const TraceEvent& event) OVERRIDE { |
| + if (logged_events_newest_ < logged_events_.size()) |
| + logged_events_[logged_events_newest_] = event; |
| + else |
| + logged_events_.push_back(event); |
| + |
| + logged_events_newest_++; |
| + if (logged_events_newest_ >= kTraceEventBufferSize) |
| + logged_events_newest_ = 0; |
| + if (logged_events_newest_ == logged_events_oldest_) { |
| + logged_events_oldest_++; |
| + if (logged_events_oldest_ >= kTraceEventBufferSize) { |
| + logged_events_oldest_ = 0; |
| + } |
| + } |
| + } |
| + |
| + bool HasMoreEvents() const OVERRIDE { |
| + return logged_events_oldest_ != logged_events_newest_; |
| + } |
| + |
| + const TraceEvent& NextEvent() OVERRIDE { |
| + DCHECK(HasMoreEvents()); |
| + |
| + int cur = logged_events_oldest_; |
|
jar (doing other things)
2013/03/13 18:42:30
nit: avoid abreviations such as |cur| which I'm gu
dsinclair
2013/03/13 19:27:27
Done.
|
| + logged_events_oldest_++; |
| + if (logged_events_oldest_ >= kTraceEventBufferSize) |
| + logged_events_oldest_ = 0; |
| + return logged_events_[cur]; |
| + } |
| + |
| + bool IsFull() const OVERRIDE { |
| + return false; |
| + } |
| + |
| + size_t CountEnabledByName(const unsigned char* category, |
| + const std::string& event_name) const OVERRIDE { |
| + size_t notify_count = 0; |
| + size_t idx = logged_events_oldest_; |
| + while (true) { |
| + if (idx == logged_events_newest_) |
| + break; |
|
jar (doing other things)
2013/03/13 18:42:30
nit: How about replacing last three lines with:
wh
dsinclair
2013/03/13 19:27:27
Done.
|
| + |
| + if (category == logged_events_[idx].category_enabled() && |
| + strcmp(event_name.c_str(), logged_events_[idx].name()) == 0) { |
| + ++notify_count; |
| + } |
| + |
| + idx++; |
| + if (idx >= kTraceEventBufferSize) |
| + idx = 0; |
| + } |
| + return notify_count; |
| + } |
| + |
| + private: |
| + uint32 logged_events_newest_; |
|
jar (doing other things)
2013/03/13 18:42:30
nit: This is not really the index of the newest, b
dsinclair
2013/03/13 19:27:27
Done.
|
| + uint32 logged_events_oldest_; |
|
jar (doing other things)
2013/03/13 18:42:30
nit: Since this points to a singular event, better
dsinclair
2013/03/13 19:27:27
Done.
|
| + |
| + DISALLOW_COPY_AND_ASSIGN(TraceBufferRingBuffer); |
| +}; |
| + |
| +class TraceBufferVector : public TraceBuffer { |
| + public: |
| + TraceBufferVector() : current_iteration_index_(0) { |
| + } |
| + |
| + ~TraceBufferVector() { |
| + } |
| + |
| + void AddEvent(const TraceEvent& event) OVERRIDE { |
| + // Note, we don't check IsFull here as the code to add the metadata |
| + // will do an AddEvent, if the buffer is full we'd lose the metadata. |
|
jar (doing other things)
2013/03/13 18:42:30
nit: "AddEvent, if the" --> "AddEvent. If the"
I
dsinclair
2013/03/13 19:27:27
Clarified the comment.
|
| + logged_events_.push_back(event); |
| + } |
| + |
| + bool HasMoreEvents() const OVERRIDE { |
| + return current_iteration_index_ < Size(); |
| + } |
| + |
| + const TraceEvent& NextEvent() OVERRIDE { |
| + DCHECK(HasMoreEvents()); |
| + return logged_events_[current_iteration_index_++]; |
| + } |
| + |
| + bool IsFull() const OVERRIDE { |
| + return Size() == kTraceEventBufferSize; |
|
jar (doing other things)
2013/03/13 18:42:30
I'm not clear on the meaning, given that you push
dsinclair
2013/03/13 19:27:27
Done.
|
| + } |
| + |
| + size_t CountEnabledByName(const unsigned char* category, |
| + const std::string& event_name) const OVERRIDE { |
| + size_t notify_count = 0; |
| + for (size_t idx = 0; idx < logged_events_.size(); idx++) { |
|
jar (doing other things)
2013/03/13 18:42:30
nit: Rather than abbreviate |idx|, use |index|, or
dsinclair
2013/03/13 19:27:27
Done.
|
| + if (category == logged_events_[idx].category_enabled() && |
| + strcmp(event_name.c_str(), logged_events_[idx].name()) == 0) { |
| + ++notify_count; |
| + } |
| + } |
| + return notify_count; |
| + } |
| + |
| + private: |
| + size_t current_iteration_index_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(TraceBufferVector); |
| +}; |
| } // namespace |
| @@ -238,17 +356,6 @@ void TraceEvent::AppendValueAsJSON(unsigned char type, |
| } |
| } |
| -void TraceEvent::AppendEventsAsJSON(const std::vector<TraceEvent>& events, |
| - size_t start, |
| - size_t count, |
| - std::string* out) { |
| - for (size_t i = 0; i < count && start + i < events.size(); ++i) { |
| - if (i > 0) |
| - *out += ","; |
| - events[i + start].AppendAsJSON(out); |
| - } |
| -} |
| - |
| void TraceEvent::AppendAsJSON(std::string* out) const { |
| int64 time_int64 = timestamp_.ToInternalValue(); |
| int process_id = TraceLog::GetInstance()->process_id(); |
| @@ -284,6 +391,19 @@ void TraceEvent::AppendAsJSON(std::string* out) const { |
| //////////////////////////////////////////////////////////////////////////////// |
| // |
| +// TraceBuffer |
| +// |
| +//////////////////////////////////////////////////////////////////////////////// |
| + |
| +TraceBuffer::TraceBuffer() { |
| + logged_events_.reserve(1024); |
| +} |
| + |
| +TraceBuffer::~TraceBuffer() { |
| +} |
| + |
| +//////////////////////////////////////////////////////////////////////////////// |
| +// |
| // TraceResultBuffer |
| // |
| //////////////////////////////////////////////////////////////////////////////// |
| @@ -511,15 +631,13 @@ TraceLog::Options TraceLog::TraceOptionsFromString(const std::string& options) { |
| ++iter) { |
| if (*iter == kRecordUntilFull) { |
| ret |= RECORD_UNTIL_FULL; |
| + } else if (*iter == kRecordContinuously) { |
| + ret |= RECORD_CONTINUOUSLY; |
| } else { |
| NOTREACHED(); // Unknown option provided. |
| } |
| } |
| - // Check to see if any RECORD_* options are set, and if none, then provide |
| - // a default. |
| - // TODO(dsinclair): Remove this comment when we have more then one RECORD_* |
| - // flag and the code's structure is then sensible. |
| - if (!(ret & RECORD_UNTIL_FULL)) |
| + if (!(ret & RECORD_UNTIL_FULL) && !(ret & RECORD_CONTINUOUSLY)) |
| ret |= RECORD_UNTIL_FULL; // Default when no options are specified. |
| return static_cast<Options>(ret); |
| @@ -527,6 +645,7 @@ TraceLog::Options TraceLog::TraceOptionsFromString(const std::string& options) { |
| TraceLog::TraceLog() |
| : enable_count_(0), |
| + logged_events_(NULL), |
| dispatching_to_observer_list_(false), |
| watch_category_(NULL), |
| trace_options_(RECORD_UNTIL_FULL), |
| @@ -547,6 +666,8 @@ TraceLog::TraceLog() |
| #else |
| SetProcessID(static_cast<int>(GetCurrentProcId())); |
| #endif |
| + |
| + logged_events_.reset(GetTraceBuffer()); |
| } |
| TraceLog::~TraceLog() { |
| @@ -682,7 +803,11 @@ void TraceLog::SetEnabled(const std::vector<std::string>& included_categories, |
| } |
| return; |
| } |
| - trace_options_ = options; |
| + |
| + if (options != trace_options_) { |
| + trace_options_ = options; |
| + logged_events_.reset(GetTraceBuffer()); |
| + } |
| if (dispatching_to_observer_list_) { |
| DLOG(ERROR) << |
| @@ -695,7 +820,6 @@ void TraceLog::SetEnabled(const std::vector<std::string>& included_categories, |
| OnTraceLogWillEnable()); |
| dispatching_to_observer_list_ = false; |
| - logged_events_.reserve(1024); |
| included_categories_ = included_categories; |
| excluded_categories_ = excluded_categories; |
| // Note that if both included and excluded_categories are empty, the else |
| @@ -811,7 +935,7 @@ void TraceLog::RemoveEnabledStateObserver( |
| } |
| float TraceLog::GetBufferPercentFull() const { |
| - return (float)((double)logged_events_.size()/(double)kTraceEventBufferSize); |
| + return (float)((double)logged_events_->Size()/(double)kTraceEventBufferSize); |
| } |
| void TraceLog::SetNotificationCallback( |
| @@ -820,27 +944,43 @@ void TraceLog::SetNotificationCallback( |
| notification_callback_ = cb; |
| } |
| +TraceBuffer* TraceLog::GetTraceBuffer() { |
| + if (trace_options_ & RECORD_CONTINUOUSLY) |
| + return new TraceBufferRingBuffer(); |
| + return new TraceBufferVector(); |
| +} |
| + |
| void TraceLog::SetEventCallback(EventCallback cb) { |
| AutoLock lock(lock_); |
| event_callback_ = cb; |
| }; |
| void TraceLog::Flush(const TraceLog::OutputCallback& cb) { |
| - std::vector<TraceEvent> previous_logged_events; |
| + scoped_ptr<TraceBuffer> previous_logged_events; |
| { |
| AutoLock lock(lock_); |
| previous_logged_events.swap(logged_events_); |
| + logged_events_.reset(GetTraceBuffer()); |
| } // release lock |
| - for (size_t i = 0; |
| - i < previous_logged_events.size(); |
| - i += kTraceEventBatchSize) { |
| + while (true) { |
| + if (!previous_logged_events->HasMoreEvents()) |
|
jar (doing other things)
2013/03/13 18:42:30
nit: again, why not put test into while()
dsinclair
2013/03/13 19:27:27
Done.
|
| + break; |
| + |
| scoped_refptr<RefCountedString> json_events_str_ptr = |
| new RefCountedString(); |
| - TraceEvent::AppendEventsAsJSON(previous_logged_events, |
| - i, |
| - kTraceEventBatchSize, |
| - &(json_events_str_ptr->data())); |
| + |
| + for (size_t i = 0; i < kTraceEventBatchSize; ++i) { |
| + if (i > 0) |
| + *(&(json_events_str_ptr->data())) += ","; |
| + |
| + previous_logged_events->NextEvent().AppendAsJSON( |
| + &(json_events_str_ptr->data())); |
| + |
| + if (!previous_logged_events->HasMoreEvents()) |
| + break; |
| + } |
| + |
| cb.Run(json_events_str_ptr); |
| } |
| } |
| @@ -889,7 +1029,7 @@ void TraceLog::AddTraceEventWithThreadIdAndTimestamp( |
| AutoLock lock(lock_); |
| if (*category_enabled != CATEGORY_ENABLED) |
| return; |
| - if (logged_events_.size() >= kTraceEventBufferSize) |
| + if (logged_events_->IsFull()) |
| return; |
| const char* new_name = ThreadIdNameManager::GetInstance()-> |
| @@ -925,13 +1065,12 @@ void TraceLog::AddTraceEventWithThreadIdAndTimestamp( |
| if (flags & TRACE_EVENT_FLAG_MANGLE_ID) |
| id ^= process_id_hash_; |
| - logged_events_.push_back( |
| - TraceEvent(thread_id, |
| - now, phase, category_enabled, name, id, |
| - num_args, arg_names, arg_types, arg_values, |
| - flags)); |
| + logged_events_->AddEvent(TraceEvent(thread_id, |
| + now, phase, category_enabled, name, id, |
| + num_args, arg_names, arg_types, arg_values, |
| + flags)); |
| - if (logged_events_.size() == kTraceEventBufferSize) |
| + if (logged_events_->IsFull()) |
| notifier.AddNotificationWhileLocked(TRACE_BUFFER_FULL); |
| if (watch_category_ == category_enabled && watch_event_name_ == name) |
| @@ -980,14 +1119,9 @@ void TraceLog::SetWatchEvent(const std::string& category_name, |
| watch_category_ = category; |
| watch_event_name_ = event_name; |
| - // First, search existing events for watch event because we want to catch it |
| - // even if it has already occurred. |
| - for (size_t i = 0u; i < logged_events_.size(); ++i) { |
| - if (category == logged_events_[i].category_enabled() && |
| - strcmp(event_name.c_str(), logged_events_[i].name()) == 0) { |
| - ++notify_count; |
| - } |
| - } |
| + // First, search existing events for watch event because we want to catch |
| + // it even if it has already occurred. |
| + notify_count = logged_events_->CountEnabledByName(category, event_name); |
| } // release lock |
| // Send notification for each event found. |
| @@ -1017,13 +1151,12 @@ void TraceLog::AddThreadNameMetadataEvents() { |
| unsigned char arg_type; |
| unsigned long long arg_value; |
| trace_event_internal::SetTraceValue(it->second, &arg_type, &arg_value); |
| - logged_events_.push_back( |
| - TraceEvent(it->first, |
| - TimeTicks(), TRACE_EVENT_PHASE_METADATA, |
| - &g_category_enabled[g_category_metadata], |
| - "thread_name", trace_event_internal::kNoEventId, |
| - num_args, &arg_name, &arg_type, &arg_value, |
| - TRACE_EVENT_FLAG_NONE)); |
| + logged_events_->AddEvent(TraceEvent(it->first, |
|
nduca
2013/03/13 17:04:40
a nice followup would maybe be to initialize inpla
dsinclair
2013/03/13 19:27:27
Ack.
|
| + TimeTicks(), TRACE_EVENT_PHASE_METADATA, |
| + &g_category_enabled[g_category_metadata], |
| + "thread_name", trace_event_internal::kNoEventId, |
| + num_args, &arg_name, &arg_type, &arg_value, |
| + TRACE_EVENT_FLAG_NONE)); |
| } |
| } |
| } |