Chromium Code Reviews| Index: base/debug/activity_tracker.cc |
| diff --git a/base/debug/activity_tracker.cc b/base/debug/activity_tracker.cc |
| index 9835b2383b20a2d82de400677016a6927142a822..b8bc5490220017cb6a3398761df4e23c6ab9dd4b 100644 |
| --- a/base/debug/activity_tracker.cc |
| +++ b/base/debug/activity_tracker.cc |
| @@ -13,6 +13,7 @@ |
| #include "base/files/file.h" |
| #include "base/files/file_path.h" |
| #include "base/files/memory_mapped_file.h" |
| +#include "base/lazy_instance.h" |
| #include "base/logging.h" |
| #include "base/memory/ptr_util.h" |
| #include "base/metrics/field_trial.h" |
| @@ -41,8 +42,8 @@ const int kMinStackDepth = 2; |
| // The amount of memory set aside for holding arbitrary user data (key/value |
| // pairs) globally or associated with ActivityData entries. |
| -const size_t kUserDataSize = 1024; // bytes |
| -const size_t kGlobalDataSize = 4096; // bytes |
| +const size_t kUserDataSize = 1 << 10; // 1 KiB |
| +const size_t kGlobalDataSize = 16 << 10; // 16 KiB |
| const size_t kMaxUserDataNameLength = |
| static_cast<size_t>(std::numeric_limits<uint8_t>::max()); |
| @@ -64,6 +65,64 @@ union ThreadRef { |
| #endif |
| }; |
| +// A class to collect field-trial information and dump it to a global |
| +// tracker. If no GlobalActivityTracker exists, the information is held |
| +// locally for dumping later. |
| +class FieldTrialRecorder { |
| + public: |
| + FieldTrialRecorder() : enabled_(true) {} |
| + ~FieldTrialRecorder() {} |
| + |
| + void Disable() { |
| + enabled_.store(false, std::memory_order_relaxed); |
| + AutoLock lock(trial_group_lock_); |
| + trial_group_map_.clear(); |
| + } |
| + |
| + void DumpCollectedActivity() { |
|
Alexei Svitkine (slow)
2017/02/07 19:28:10
Thinking about this more, I think we can simplify
bcwhite
2017/02/07 21:18:03
Done.
|
| + DCHECK(GlobalActivityTracker::Get()); |
| + |
| + // OnFieldTrialGroupFinalized will insert into trial_group_map_ if the |
| + // global tracker goes away. Be safe and move its contents to a local |
| + // variable first. |
| + std::map<std::string, std::string> collected; |
| + { |
| + AutoLock lock(trial_group_lock_); |
| + collected.swap(trial_group_map_); |
| + } |
| + |
| + // Store collected information to the global tracker. |
| + for (const auto& kv : collected) |
| + Record(kv.first, kv.second); |
| + } |
| + |
| + void Record(const std::string& trial_name, const std::string& group_name) { |
| + if (!enabled_.load(std::memory_order_relaxed)) |
| + return; |
| + |
| + const std::string key = std::string("FieldTrial.") + trial_name; |
| + |
| + GlobalActivityTracker* tracker = GlobalActivityTracker::Get(); |
| + if (tracker) { |
| + // global_data is thread-safe. |
| + tracker->global_data().SetString(key, group_name); |
| + } else { |
| + AutoLock lock(trial_group_lock_); |
| + trial_group_map_.insert(std::make_pair(key, group_name)); |
| + } |
| + } |
| + |
| + private: |
| + std::atomic<bool> enabled_; |
| + std::map<std::string, std::string> trial_group_map_; |
| + Lock trial_group_lock_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(FieldTrialRecorder); |
| +}; |
| + |
| +LazyInstance<FieldTrialRecorder>::Leaky g_field_trial_recorder = |
| + LAZY_INSTANCE_INITIALIZER; |
| + |
| // Determines the previous aligned index. |
| size_t RoundDownToAlignment(size_t index, size_t alignment) { |
| return index & (0 - alignment); |
| @@ -288,7 +347,6 @@ void ActivityUserData::Set(StringPiece name, |
| ValueType type, |
| const void* memory, |
| size_t size) { |
| - DCHECK(thread_checker_.CalledOnValidThread()); |
| DCHECK_GE(std::numeric_limits<uint8_t>::max(), name.length()); |
| size = std::min(std::numeric_limits<uint16_t>::max() - (kMemoryAlignment - 1), |
| size); |
| @@ -1056,6 +1114,19 @@ ActivityUserData& GlobalActivityTracker::ScopedThreadActivity::user_data() { |
| return *user_data_; |
| } |
| +GlobalActivityTracker::GlobalUserData::GlobalUserData(void* memory, size_t size) |
| + : ActivityUserData(memory, size) {} |
| + |
| +GlobalActivityTracker::GlobalUserData::~GlobalUserData() {} |
| + |
| +void GlobalActivityTracker::GlobalUserData::Set(StringPiece name, |
| + ValueType type, |
| + const void* memory, |
| + size_t size) { |
| + AutoLock lock(data_lock_); |
| + ActivityUserData::Set(name, type, memory, size); |
| +} |
| + |
| GlobalActivityTracker::ManagedActivityTracker::ManagedActivityTracker( |
| PersistentMemoryAllocator::Reference mem_reference, |
| void* base, |
| @@ -1216,6 +1287,17 @@ void GlobalActivityTracker::RecordModuleInfo(const ModuleInfo& info) { |
| modules_.insert(std::make_pair(info.file, record)); |
| } |
| +// static |
| +void GlobalActivityTracker::RecordFieldTrial(const std::string& trial_name, |
| + const std::string& group_name) { |
| + g_field_trial_recorder.Get().Record(trial_name, group_name); |
| +} |
| + |
| +// static |
| +void GlobalActivityTracker::DisableFieldTrialRecording() { |
| + g_field_trial_recorder.Get().Disable(); |
| +} |
| + |
| GlobalActivityTracker::GlobalActivityTracker( |
| std::unique_ptr<PersistentMemoryAllocator> allocator, |
| int stack_depth) |
| @@ -1235,7 +1317,7 @@ GlobalActivityTracker::GlobalActivityTracker( |
| kUserDataSize, |
| kCachedUserDataMemories, |
| /*make_iterable=*/false), |
| - user_data_( |
| + global_data_( |
| allocator_->GetAsArray<char>( |
| allocator_->Allocate(kGlobalDataSize, kTypeIdGlobalDataRecord), |
| kTypeIdGlobalDataRecord, |
| @@ -1251,7 +1333,11 @@ GlobalActivityTracker::GlobalActivityTracker( |
| // The global records must be iterable in order to be found by an analyzer. |
| allocator_->MakeIterable(allocator_->GetAsReference( |
| - user_data_.GetBaseAddress(), kTypeIdGlobalDataRecord)); |
| + global_data_.GetBaseAddress(), kTypeIdGlobalDataRecord)); |
| + |
| + // Enable tracking (if not done previously) and dump previously collected |
| + // field-trial information to this global tracker. |
| + g_field_trial_recorder.Get().DumpCollectedActivity(); |
| } |
| GlobalActivityTracker::~GlobalActivityTracker() { |