| Index: base/debug/activity_tracker.cc
|
| diff --git a/base/debug/activity_tracker.cc b/base/debug/activity_tracker.cc
|
| index deb17179904c532642c29bdfc85100628613b079..9291e16991bf3723ac6d780760a257e437cae7cb 100644
|
| --- a/base/debug/activity_tracker.cc
|
| +++ b/base/debug/activity_tracker.cc
|
| @@ -12,6 +12,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"
|
| @@ -40,8 +41,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());
|
|
|
| @@ -63,6 +64,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() {
|
| + 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);
|
| @@ -287,7 +346,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);
|
| @@ -1049,6 +1107,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,
|
| @@ -1209,6 +1280,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)
|
| @@ -1228,7 +1310,7 @@ GlobalActivityTracker::GlobalActivityTracker(
|
| kUserDataSize,
|
| kCachedUserDataMemories,
|
| /*make_iterable=*/false),
|
| - user_data_(
|
| + global_data_(
|
| allocator_->GetAsArray<char>(
|
| allocator_->Allocate(kGlobalDataSize, kTypeIdGlobalDataRecord),
|
| kTypeIdGlobalDataRecord,
|
| @@ -1244,7 +1326,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() {
|
|
|