From 04511cb6300db2b3cf886bb7d147e1ae72fb8ce6 Mon Sep 17 00:00:00 2001 From: ruuda Date: Thu, 26 Nov 2015 08:29:51 -0800 Subject: Remove memory category from chrome://tracing The tcmalloc heap profiler will be replaced with the heap profiler in memory-infra. This removes the old "memory" category in chrome://tracing. (For now, the checkbox still exists in the UI.) A few places still reference the heap profiling functionality of tcmalloc. This is left untouched. Related trace viewer issues: https://github.com/catapult-project/catapult/issues/1050 https://github.com/catapult-project/catapult/issues/1804 BUG=560300, 524631 TBR=brettw Review URL: https://codereview.chromium.org/1468883003 Cr-Commit-Position: refs/heads/master@{#361903} --- base/trace_event/BUILD.gn | 3 - base/trace_event/common/trace_event_common.h | 20 +- base/trace_event/trace_event.gypi | 3 - base/trace_event/trace_event.h | 1 - base/trace_event/trace_event_memory.cc | 438 ------------------------ base/trace_event/trace_event_memory.h | 171 --------- base/trace_event/trace_event_memory_unittest.cc | 236 ------------- 7 files changed, 3 insertions(+), 869 deletions(-) delete mode 100644 base/trace_event/trace_event_memory.cc delete mode 100644 base/trace_event/trace_event_memory.h delete mode 100644 base/trace_event/trace_event_memory_unittest.cc (limited to 'base/trace_event') diff --git a/base/trace_event/BUILD.gn b/base/trace_event/BUILD.gn index 07d28fe..f0e90a7 100644 --- a/base/trace_event/BUILD.gn +++ b/base/trace_event/BUILD.gn @@ -53,8 +53,6 @@ source_set("trace_event") { "trace_event_etw_export_win.h", "trace_event_impl.cc", "trace_event_impl.h", - "trace_event_memory.cc", - "trace_event_memory.h", "trace_event_memory_overhead.cc", "trace_event_memory_overhead.h", "trace_event_synthetic_delay.cc", @@ -127,7 +125,6 @@ source_set("trace_event_unittests") { "trace_config_memory_test_util.h", "trace_config_unittest.cc", "trace_event_argument_unittest.cc", - "trace_event_memory_unittest.cc", "trace_event_synthetic_delay_unittest.cc", "trace_event_system_stats_monitor_unittest.cc", "trace_event_unittest.cc", diff --git a/base/trace_event/common/trace_event_common.h b/base/trace_event/common/trace_event_common.h index cae3670..72202f3 100644 --- a/base/trace_event/common/trace_event_common.h +++ b/base/trace_event/common/trace_event_common.h @@ -203,40 +203,26 @@ // - category and name strings must have application lifetime (statics or // literals). They may not include " chars. #define TRACE_EVENT0(category_group, name) \ - INTERNAL_TRACE_MEMORY(category_group, name) \ INTERNAL_TRACE_EVENT_ADD_SCOPED(category_group, name) #define TRACE_EVENT_WITH_FLOW0(category_group, name, bind_id, flow_flags) \ - INTERNAL_TRACE_MEMORY(category_group, name) \ INTERNAL_TRACE_EVENT_ADD_SCOPED_WITH_FLOW(category_group, name, bind_id, \ flow_flags) #define TRACE_EVENT1(category_group, name, arg1_name, arg1_val) \ - INTERNAL_TRACE_MEMORY(category_group, name) \ INTERNAL_TRACE_EVENT_ADD_SCOPED(category_group, name, arg1_name, arg1_val) #define TRACE_EVENT_WITH_FLOW1(category_group, name, bind_id, flow_flags, \ arg1_name, arg1_val) \ - INTERNAL_TRACE_MEMORY(category_group, name) \ INTERNAL_TRACE_EVENT_ADD_SCOPED_WITH_FLOW(category_group, name, bind_id, \ flow_flags, arg1_name, arg1_val) #define TRACE_EVENT2(category_group, name, arg1_name, arg1_val, arg2_name, \ arg2_val) \ - INTERNAL_TRACE_MEMORY(category_group, name) \ INTERNAL_TRACE_EVENT_ADD_SCOPED(category_group, name, arg1_name, arg1_val, \ arg2_name, arg2_val) #define TRACE_EVENT_WITH_FLOW2(category_group, name, bind_id, flow_flags, \ arg1_name, arg1_val, arg2_name, arg2_val) \ - INTERNAL_TRACE_MEMORY(category_group, name) \ INTERNAL_TRACE_EVENT_ADD_SCOPED_WITH_FLOW(category_group, name, bind_id, \ flow_flags, arg1_name, arg1_val, \ arg2_name, arg2_val) -// Records events like TRACE_EVENT2 but uses |memory_tag| for memory tracing. -// Use this where |name| is too generic to accurately aggregate allocations. -#define TRACE_EVENT_WITH_MEMORY_TAG2(category, name, memory_tag, arg1_name, \ - arg1_val, arg2_name, arg2_val) \ - INTERNAL_TRACE_MEMORY(category, memory_tag) \ - INTERNAL_TRACE_EVENT_ADD_SCOPED(category, name, arg1_name, arg1_val, \ - arg2_name, arg2_val) - // UNSHIPPED_TRACE_EVENT* are like TRACE_EVENT* except that they are not // included in official builds. @@ -310,9 +296,9 @@ arg2_name, arg2_val) #define TRACE_EVENT_INSTANT_WITH_TIMESTAMP0(category_group, name, scope, \ - timestamp) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \ - TRACE_EVENT_PHASE_INSTANT, category_group, name, 0, 0, timestamp, \ + timestamp) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \ + TRACE_EVENT_PHASE_INSTANT, category_group, name, 0, 0, timestamp, \ TRACE_EVENT_FLAG_NONE | scope) // Syntactic sugars for the sampling tracing in the main thread. diff --git a/base/trace_event/trace_event.gypi b/base/trace_event/trace_event.gypi index ca37015..0c43ae1 100644 --- a/base/trace_event/trace_event.gypi +++ b/base/trace_event/trace_event.gypi @@ -53,8 +53,6 @@ 'trace_event/trace_event_etw_export_win.h', 'trace_event/trace_event_impl.cc', 'trace_event/trace_event_impl.h', - 'trace_event/trace_event_memory.cc', - 'trace_event/trace_event_memory.h', 'trace_event/trace_event_memory_overhead.cc', 'trace_event/trace_event_memory_overhead.h', 'trace_event/trace_event_synthetic_delay.cc', @@ -83,7 +81,6 @@ 'trace_event/trace_config_memory_test_util.h', 'trace_event/trace_config_unittest.cc', 'trace_event/trace_event_argument_unittest.cc', - 'trace_event/trace_event_memory_unittest.cc', 'trace_event/trace_event_synthetic_delay_unittest.cc', 'trace_event/trace_event_system_stats_monitor_unittest.cc', 'trace_event/trace_event_unittest.cc', diff --git a/base/trace_event/trace_event.h b/base/trace_event/trace_event.h index 14448e2..7a2a656 100644 --- a/base/trace_event/trace_event.h +++ b/base/trace_event/trace_event.h @@ -14,7 +14,6 @@ #include "base/atomicops.h" #include "base/time/time.h" #include "base/trace_event/common/trace_event_common.h" -#include "base/trace_event/trace_event_memory.h" #include "base/trace_event/trace_event_system_stats_monitor.h" #include "base/trace_event/trace_log.h" #include "build/build_config.h" diff --git a/base/trace_event/trace_event_memory.cc b/base/trace_event/trace_event_memory.cc deleted file mode 100644 index 187bf74..0000000 --- a/base/trace_event/trace_event_memory.cc +++ /dev/null @@ -1,438 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/trace_event/trace_event_memory.h" - -#include - -#include "base/debug/leak_annotations.h" -#include "base/lazy_instance.h" -#include "base/location.h" -#include "base/logging.h" -#include "base/memory/scoped_ptr.h" -#include "base/single_thread_task_runner.h" -#include "base/strings/string_number_conversions.h" -#include "base/strings/string_split.h" -#include "base/strings/string_util.h" -#include "base/threading/thread_local_storage.h" -#include "base/trace_event/trace_event.h" - -namespace base { -namespace trace_event { - -namespace { - -// Maximum number of nested TRACE_EVENT scopes to record. Must be less than -// or equal to HeapProfileTable::kMaxStackDepth / 2 because we record two -// entries on the pseudo-stack per scope. -const size_t kMaxScopeDepth = 16; - -///////////////////////////////////////////////////////////////////////////// -// Holds a memory dump until the tracing system needs to serialize it. -class MemoryDumpHolder : public base::trace_event::ConvertableToTraceFormat { - public: - // Takes ownership of dump, which must be a JSON string, allocated with - // malloc() and NULL terminated. - explicit MemoryDumpHolder(char* dump) : dump_(dump) {} - - // base::trace_event::ConvertableToTraceFormat overrides: - void AppendAsTraceFormat(std::string* out) const override { - AppendHeapProfileAsTraceFormat(dump_, out); - } - - private: - ~MemoryDumpHolder() override { free(dump_); } - - char* dump_; - - DISALLOW_COPY_AND_ASSIGN(MemoryDumpHolder); -}; - -///////////////////////////////////////////////////////////////////////////// -// Records a stack of TRACE_MEMORY events. One per thread is required. -struct TraceMemoryStack { - TraceMemoryStack() : scope_depth(0) { - memset(scope_data, 0, kMaxScopeDepth * sizeof(scope_data[0])); - } - - // Depth of the currently nested TRACE_EVENT scopes. Allowed to be greater - // than kMaxScopeDepth so we can match scope pushes and pops even if we don't - // have enough space to store the EventData. - size_t scope_depth; - - // Stack of categories and names. - ScopedTraceMemory::ScopeData scope_data[kMaxScopeDepth]; -}; - -// Pointer to a TraceMemoryStack per thread. -base::ThreadLocalStorage::StaticSlot tls_trace_memory_stack = TLS_INITIALIZER; - -// Clean up memory pointed to by our thread-local storage. -void DeleteStackOnThreadCleanup(void* value) { - TraceMemoryStack* stack = static_cast(value); - delete stack; -} - -// Initializes the thread-local TraceMemoryStack pointer. -void InitThreadLocalStorage() { - if (tls_trace_memory_stack.initialized()) - return; - // Initialize the thread-local storage key. - tls_trace_memory_stack.Initialize(&DeleteStackOnThreadCleanup); -} - -// Clean up thread-local-storage in the main thread. -void CleanupThreadLocalStorage() { - if (!tls_trace_memory_stack.initialized()) - return; - TraceMemoryStack* stack = - static_cast(tls_trace_memory_stack.Get()); - delete stack; - tls_trace_memory_stack.Set(NULL); - // Intentionally do not release the thread-local-storage key here, that is, - // do not call tls_trace_memory_stack.Free(). Other threads have lazily - // created pointers in thread-local-storage via GetTraceMemoryStack() below. - // Those threads need to run the DeleteStack() destructor function when they - // exit. If we release the key the destructor will not be called and those - // threads will not clean up their memory. -} - -// Returns the thread-local trace memory stack for the current thread, creating -// one if needed. Returns NULL if the thread-local storage key isn't -// initialized, which indicates that heap profiling isn't running. -TraceMemoryStack* GetTraceMemoryStack() { - TraceMemoryStack* stack = - static_cast(tls_trace_memory_stack.Get()); - // Lazily initialize TraceMemoryStack objects for new threads. - if (!stack) { - stack = new TraceMemoryStack; - tls_trace_memory_stack.Set(stack); - } - return stack; -} - -// Returns a "pseudo-stack" of pointers to trace event categories and names. -// Because tcmalloc stores one pointer per stack frame this converts N nested -// trace events into N * 2 pseudo-stack entries. Thus this macro invocation: -// TRACE_EVENT0("category1", "name1"); -// TRACE_EVENT0("category2", "name2"); -// becomes this pseudo-stack: -// stack_out[0] = "category1" -// stack_out[1] = "name1" -// stack_out[2] = "category2" -// stack_out[3] = "name2" -// Returns int instead of size_t to match the signature required by tcmalloc. -int GetPseudoStack(int skip_count_ignored, void** stack_out) { - // If the tracing system isn't fully initialized, just skip this allocation. - // Attempting to initialize will allocate memory, causing this function to - // be called recursively from inside the allocator. - if (!tls_trace_memory_stack.initialized() || !tls_trace_memory_stack.Get()) - return 0; - TraceMemoryStack* stack = - static_cast(tls_trace_memory_stack.Get()); - // Copy at most kMaxScopeDepth scope entries. - const size_t count = std::min(stack->scope_depth, kMaxScopeDepth); - // Notes that memcpy() works for zero bytes. - memcpy(stack_out, - stack->scope_data, - count * sizeof(stack->scope_data[0])); - // Each item in the trace event stack contains both name and category so tell - // tcmalloc that we have returned |count| * 2 stack frames. - return static_cast(count * 2); -} - -} // namespace - -////////////////////////////////////////////////////////////////////////////// - -TraceMemoryController::TraceMemoryController( - scoped_refptr task_runner, - HeapProfilerStartFunction heap_profiler_start_function, - HeapProfilerStopFunction heap_profiler_stop_function, - GetHeapProfileFunction get_heap_profile_function) - : task_runner_(std::move(task_runner)), - heap_profiler_start_function_(heap_profiler_start_function), - heap_profiler_stop_function_(heap_profiler_stop_function), - get_heap_profile_function_(get_heap_profile_function), - weak_factory_(this) { - // Force the "memory" category to show up in the trace viewer. - TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("memory"), "init"); - // Watch for the tracing system being enabled. - TraceLog::GetInstance()->AddEnabledStateObserver(this); -} - -TraceMemoryController::~TraceMemoryController() { - if (dump_timer_.IsRunning()) - StopProfiling(); - TraceLog::GetInstance()->RemoveEnabledStateObserver(this); -} - -// base::trace_event::TraceLog::EnabledStateChangedObserver overrides: -void TraceMemoryController::OnTraceLogEnabled() { - // Check to see if tracing is enabled for the memory category. - bool enabled; - TRACE_EVENT_CATEGORY_GROUP_ENABLED(TRACE_DISABLED_BY_DEFAULT("memory"), - &enabled); - if (!enabled) - return; - DVLOG(1) << "OnTraceLogEnabled"; - task_runner_->PostTask(FROM_HERE, - base::Bind(&TraceMemoryController::StartProfiling, - weak_factory_.GetWeakPtr())); -} - -void TraceMemoryController::OnTraceLogDisabled() { - // The memory category is always disabled before OnTraceLogDisabled() is - // called, so we cannot tell if it was enabled before. Always try to turn - // off profiling. - DVLOG(1) << "OnTraceLogDisabled"; - task_runner_->PostTask(FROM_HERE, - base::Bind(&TraceMemoryController::StopProfiling, - weak_factory_.GetWeakPtr())); -} - -void TraceMemoryController::StartProfiling() { - // Watch for the tracing framework sending enabling more than once. - if (dump_timer_.IsRunning()) - return; - DVLOG(1) << "Starting trace memory"; - InitThreadLocalStorage(); - ScopedTraceMemory::set_enabled(true); - // Call ::HeapProfilerWithPseudoStackStart(). - heap_profiler_start_function_(&GetPseudoStack); - const int kDumpIntervalSeconds = 5; - dump_timer_.Start(FROM_HERE, - TimeDelta::FromSeconds(kDumpIntervalSeconds), - base::Bind(&TraceMemoryController::DumpMemoryProfile, - weak_factory_.GetWeakPtr())); -} - -void TraceMemoryController::DumpMemoryProfile() { - // Don't trace allocations here in the memory tracing system. - INTERNAL_TRACE_MEMORY(TRACE_DISABLED_BY_DEFAULT("memory"), - TRACE_MEMORY_IGNORE); - - DVLOG(1) << "DumpMemoryProfile"; - // MemoryDumpHolder takes ownership of this string. See GetHeapProfile() in - // tcmalloc for details. - char* dump = get_heap_profile_function_(); - const int kSnapshotId = 1; - TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID( - TRACE_DISABLED_BY_DEFAULT("memory"), - "memory::Heap", - kSnapshotId, - scoped_refptr(new MemoryDumpHolder(dump))); -} - -void TraceMemoryController::StopProfiling() { - // Watch for the tracing framework sending disabled more than once. - if (!dump_timer_.IsRunning()) - return; - DVLOG(1) << "Stopping trace memory"; - dump_timer_.Stop(); - ScopedTraceMemory::set_enabled(false); - CleanupThreadLocalStorage(); - // Call ::HeapProfilerStop(). - heap_profiler_stop_function_(); -} - -bool TraceMemoryController::IsTimerRunningForTest() const { - return dump_timer_.IsRunning(); -} - -///////////////////////////////////////////////////////////////////////////// - -// static -bool ScopedTraceMemory::enabled_ = false; - -void ScopedTraceMemory::Initialize(const char* category, const char* name) { - DCHECK(enabled_); - // Get our thread's copy of the stack. - TraceMemoryStack* trace_memory_stack = GetTraceMemoryStack(); - const size_t index = trace_memory_stack->scope_depth; - // Don't record data for deeply nested scopes, but continue to increment - // |stack_depth| so we can match pushes and pops. - if (index < kMaxScopeDepth) { - ScopeData& event = trace_memory_stack->scope_data[index]; - event.category = category; - event.name = name; - } - trace_memory_stack->scope_depth++; -} - -void ScopedTraceMemory::Destroy() { - DCHECK(enabled_); - // Get our thread's copy of the stack. - TraceMemoryStack* trace_memory_stack = GetTraceMemoryStack(); - // The tracing system can be turned on with ScopedTraceMemory objects - // allocated on the stack, so avoid potential underflow as they are destroyed. - if (trace_memory_stack->scope_depth > 0) - trace_memory_stack->scope_depth--; -} - -// static -void ScopedTraceMemory::InitForTest() { - InitThreadLocalStorage(); - enabled_ = true; -} - -// static -void ScopedTraceMemory::CleanupForTest() { - enabled_ = false; - CleanupThreadLocalStorage(); -} - -// static -int ScopedTraceMemory::GetStackDepthForTest() { - TraceMemoryStack* stack = GetTraceMemoryStack(); - return static_cast(stack->scope_depth); -} - -// static -ScopedTraceMemory::ScopeData ScopedTraceMemory::GetScopeDataForTest( - int stack_index) { - TraceMemoryStack* stack = GetTraceMemoryStack(); - return stack->scope_data[stack_index]; -} - -///////////////////////////////////////////////////////////////////////////// - -void AppendHeapProfileAsTraceFormat(const char* input, std::string* output) { - // Heap profile output has a header total line, then a list of stacks with - // memory totals, like this: - // - // heap profile: 357: 55227 [ 14653: 2624014] @ heapprofile - // 95: 40940 [ 649: 114260] @ 0x7fa7f4b3be13 - // 77: 32546 [ 742: 106234] @ - // 68: 4195 [ 1087: 98009] @ 0x7fa7fa9b9ba0 0x7fa7f4b3be13 - // - // MAPPED_LIBRARIES: - // 1be411fc1000-1be4139e4000 rw-p 00000000 00:00 0 - // 1be4139e4000-1be4139e5000 ---p 00000000 00:00 0 - // ... - // - // Skip input after MAPPED_LIBRARIES. - std::string input_string; - const char* mapped_libraries = strstr(input, "MAPPED_LIBRARIES"); - if (mapped_libraries) { - input_string.assign(input, mapped_libraries - input); - } else { - input_string.assign(input); - } - - std::vector lines = base::SplitString( - input_string, "\n", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY); - if (lines.empty()) { - DLOG(WARNING) << "No lines found"; - return; - } - - // Handle the initial summary line. - output->append("["); - AppendHeapProfileTotalsAsTraceFormat(lines[0], output); - - // Handle the following stack trace lines. - for (size_t i = 1; i < lines.size(); i++) - AppendHeapProfileLineAsTraceFormat(lines[i], output); - output->append("]\n"); -} - -void AppendHeapProfileTotalsAsTraceFormat(const std::string& line, - std::string* output) { - // This is what a line looks like: - // heap profile: 357: 55227 [ 14653: 2624014] @ heapprofile - // - // The numbers represent total allocations since profiling was enabled. - // From the example above: - // 357 = Outstanding allocations (mallocs - frees) - // 55227 = Outstanding bytes (malloc bytes - free bytes) - // 14653 = Total allocations (mallocs) - // 2624014 = Total bytes (malloc bytes) - std::vector tokens = base::SplitString( - line, " :[]@", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY); - if (tokens.size() < 4) { - DLOG(WARNING) << "Invalid totals line " << line; - return; - } - DCHECK_EQ(tokens[0], "heap"); - DCHECK_EQ(tokens[1], "profile"); - output->append("{\"current_allocs\": "); - output->append(tokens[2]); - output->append(", \"current_bytes\": "); - output->append(tokens[3]); - output->append(", \"trace\": \"\"}"); -} - -bool AppendHeapProfileLineAsTraceFormat(const std::string& line, - std::string* output) { - // This is what a line looks like: - // 68: 4195 [ 1087: 98009] @ 0x7fa7fa9b9ba0 0x7fa7f4b3be13 - // - // The numbers represent allocations for a particular stack trace since - // profiling was enabled. From the example above: - // 68 = Outstanding allocations (mallocs - frees) - // 4195 = Outstanding bytes (malloc bytes - free bytes) - // 1087 = Total allocations (mallocs) - // 98009 = Total bytes (malloc bytes) - // - // 0x7fa7fa9b9ba0 0x7fa7f4b3be13 = Stack trace represented as pointers to - // static strings from trace event categories - // and names. - std::vector tokens = base::SplitString( - line, " :[]@", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY); - // It's valid to have no stack addresses, so only require 4 tokens. - if (tokens.size() < 4) { - DLOG(WARNING) << "Invalid line " << line; - return false; - } - // Don't bother with stacks that have no current allocations. - if (tokens[0] == "0") - return false; - output->append(",\n"); - output->append("{\"current_allocs\": "); - output->append(tokens[0]); - output->append(", \"current_bytes\": "); - output->append(tokens[1]); - output->append(", \"trace\": \""); - - // Convert pairs of "stack addresses" into category and name strings. - const std::string kSingleQuote = "'"; - for (size_t t = 4; t < tokens.size(); t += 2) { - // Casting strings into pointers is ugly but otherwise tcmalloc would need - // to gain a special output serializer just for pseudo-stacks. - const char* trace_category = StringFromHexAddress(tokens[t]); - DCHECK_LT(t + 1, tokens.size()); - const char* trace_name = StringFromHexAddress(tokens[t + 1]); - - // TODO(jamescook): Report the trace category and name separately to the - // trace viewer and allow it to decide what decorations to apply. For now - // just hard-code a decoration for posted tasks (toplevel). - std::string trace_string(trace_name); - if (!strcmp(trace_category, "toplevel")) - trace_string.append("->PostTask"); - - // Some trace name strings have double quotes, convert them to single. - ReplaceChars(trace_string, "\"", kSingleQuote, &trace_string); - - output->append(trace_string); - - // Trace viewer expects a trailing space. - output->append(" "); - } - output->append("\"}"); - return true; -} - -const char* StringFromHexAddress(const std::string& hex_address) { - uint64 address = 0; - if (!base::HexStringToUInt64(hex_address, &address)) - return "error"; - if (!address) - return "null"; - // Note that this cast handles 64-bit to 32-bit conversion if necessary. - return reinterpret_cast(address); -} - -} // namespace trace_event -} // namespace base diff --git a/base/trace_event/trace_event_memory.h b/base/trace_event/trace_event_memory.h deleted file mode 100644 index 7088080..0000000 --- a/base/trace_event/trace_event_memory.h +++ /dev/null @@ -1,171 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_TRACE_EVENT_TRACE_EVENT_MEMORY_H_ -#define BASE_TRACE_EVENT_TRACE_EVENT_MEMORY_H_ - -#include "base/base_export.h" -#include "base/gtest_prod_util.h" -#include "base/memory/ref_counted.h" -#include "base/memory/weak_ptr.h" -#include "base/timer/timer.h" -#include "base/trace_event/trace_log.h" - -// TODO(jamescook): Windows support for memory tracing. -#if !defined(NO_TCMALLOC) && !defined(OS_NACL) && \ - (defined(OS_LINUX) || defined(OS_ANDROID)) -#define TCMALLOC_TRACE_MEMORY_SUPPORTED 1 -#endif - -namespace base { - -class SingleThreadTaskRunner; - -namespace trace_event { - -// Watches for chrome://tracing to be enabled or disabled. When tracing is -// enabled, also enables tcmalloc heap profiling. This class is the preferred -// way to turn trace-base heap memory profiling on and off. -class BASE_EXPORT TraceMemoryController - : public TraceLog::EnabledStateObserver { - public: - typedef int (*StackGeneratorFunction)(int skip_count, void** stack); - typedef void (*HeapProfilerStartFunction)(StackGeneratorFunction callback); - typedef void (*HeapProfilerStopFunction)(); - typedef char* (*GetHeapProfileFunction)(); - - // |task_runner| must be a task runner for the primary thread for the client - // process, e.g. the UI thread in a browser. The function pointers must be - // pointers to tcmalloc heap profiling functions; by avoiding direct calls to - // these functions we avoid a dependency on third_party/tcmalloc from base. - TraceMemoryController(scoped_refptr task_runner, - HeapProfilerStartFunction heap_profiler_start_function, - HeapProfilerStopFunction heap_profiler_stop_function, - GetHeapProfileFunction get_heap_profile_function); - ~TraceMemoryController() override; - - // base::trace_event::TraceLog::EnabledStateChangedObserver overrides: - void OnTraceLogEnabled() override; - void OnTraceLogDisabled() override; - - // Starts heap memory profiling. - void StartProfiling(); - - // Captures a heap profile. - void DumpMemoryProfile(); - - // If memory tracing is enabled, dumps a memory profile to the tracing system. - void StopProfiling(); - - private: - FRIEND_TEST_ALL_PREFIXES(TraceMemoryTest, TraceMemoryController); - - bool IsTimerRunningForTest() const; - - // Ensures the observer starts and stops tracing on the primary thread. - scoped_refptr task_runner_; - - // Pointers to tcmalloc heap profiling functions. Allows this class to use - // tcmalloc functions without introducing a dependency from base to tcmalloc. - HeapProfilerStartFunction heap_profiler_start_function_; - HeapProfilerStopFunction heap_profiler_stop_function_; - GetHeapProfileFunction get_heap_profile_function_; - - // Timer to schedule memory profile dumps. - RepeatingTimer dump_timer_; - - WeakPtrFactory weak_factory_; - - DISALLOW_COPY_AND_ASSIGN(TraceMemoryController); -}; - -////////////////////////////////////////////////////////////////////////////// - -// A scoped context for memory tracing. Pushes the name onto a stack for -// recording by tcmalloc heap profiling. -class BASE_EXPORT ScopedTraceMemory { - public: - struct ScopeData { - const char* category; - const char* name; - }; - - // Memory for |category| and |name| must be static, for example, literal - // strings in a TRACE_EVENT macro. - ScopedTraceMemory(const char* category, const char* name) { - if (!enabled_) - return; - Initialize(category, name); - } - ~ScopedTraceMemory() { - if (!enabled_) - return; - Destroy(); - } - - // Enables the storing of trace names on a per-thread stack. - static void set_enabled(bool enabled) { enabled_ = enabled; } - - // Testing interface: - static void InitForTest(); - static void CleanupForTest(); - static int GetStackDepthForTest(); - static ScopeData GetScopeDataForTest(int stack_index); - - private: - void Initialize(const char* category, const char* name); - void Destroy(); - - static bool enabled_; - DISALLOW_COPY_AND_ASSIGN(ScopedTraceMemory); -}; - -////////////////////////////////////////////////////////////////////////////// - -// Converts tcmalloc's heap profiler data with pseudo-stacks in |input| to -// trace event compatible JSON and appends to |output|. Visible for testing. -BASE_EXPORT void AppendHeapProfileAsTraceFormat(const char* input, - std::string* output); - -// Converts the first |line| of heap profiler data, which contains totals for -// all allocations in a special format, into trace event compatible JSON and -// appends to |output|. Visible for testing. -BASE_EXPORT void AppendHeapProfileTotalsAsTraceFormat(const std::string& line, - std::string* output); - -// Converts a single |line| of heap profiler data into trace event compatible -// JSON and appends to |output|. Returns true if the line was valid and has a -// non-zero number of current allocations. Visible for testing. -BASE_EXPORT bool AppendHeapProfileLineAsTraceFormat(const std::string& line, - std::string* output); - -// Returns a pointer to a string given its hexadecimal address in |hex_address|. -// Handles both 32-bit and 64-bit addresses. Returns "null" for null pointers -// and "error" if |address| could not be parsed. Visible for testing. -BASE_EXPORT const char* StringFromHexAddress(const std::string& hex_address); - -} // namespace trace_event -} // namespace base - -// Make local variables with unique names based on the line number. Note that -// the extra level of redirection is needed. -#define INTERNAL_TRACE_MEMORY_ID3(line) trace_memory_unique_##line -#define INTERNAL_TRACE_MEMORY_ID2(line) INTERNAL_TRACE_MEMORY_ID3(line) -#define INTERNAL_TRACE_MEMORY_ID INTERNAL_TRACE_MEMORY_ID2(__LINE__) - -// This is the core macro that adds a scope to each TRACE_EVENT location. -// It generates a unique local variable name using the macros above. -#if defined(TCMALLOC_TRACE_MEMORY_SUPPORTED) -#define INTERNAL_TRACE_MEMORY(category, name) \ - base::trace_event::ScopedTraceMemory INTERNAL_TRACE_MEMORY_ID(category, name); -#else -#define INTERNAL_TRACE_MEMORY(category, name) -#endif // defined(TRACE_MEMORY_SUPPORTED) - -// A special trace name that allows us to ignore memory allocations inside -// the memory dump system itself. The allocations are recorded, but the -// visualizer skips them. Must match the value in heap.js. -#define TRACE_MEMORY_IGNORE "trace-memory-ignore" - -#endif // BASE_TRACE_EVENT_TRACE_EVENT_MEMORY_H_ diff --git a/base/trace_event/trace_event_memory_unittest.cc b/base/trace_event/trace_event_memory_unittest.cc deleted file mode 100644 index 781a054..0000000 --- a/base/trace_event/trace_event_memory_unittest.cc +++ /dev/null @@ -1,236 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/trace_event/trace_event_memory.h" - -#include -#include - -#include "base/trace_event/trace_event_impl.h" -#include "testing/gtest/include/gtest/gtest.h" - -#if defined(TCMALLOC_TRACE_MEMORY_SUPPORTED) -#include "third_party/tcmalloc/chromium/src/gperftools/heap-profiler.h" -#endif - -namespace base { -namespace trace_event { - -// Tests for the trace event memory tracking system. Exists as a class so it -// can be a friend of TraceMemoryController. -class TraceMemoryTest : public testing::Test { - public: - TraceMemoryTest() {} - ~TraceMemoryTest() override {} - - private: - DISALLOW_COPY_AND_ASSIGN(TraceMemoryTest); -}; - -////////////////////////////////////////////////////////////////////////////// - -#if defined(TCMALLOC_TRACE_MEMORY_SUPPORTED) - -TEST_F(TraceMemoryTest, TraceMemoryController) { - MessageLoop message_loop; - - // Start with no observers of the TraceLog. - EXPECT_EQ(0u, TraceLog::GetInstance()->GetObserverCountForTest()); - - // Creating a controller adds it to the TraceLog observer list. - scoped_ptr controller(new TraceMemoryController( - message_loop.task_runner(), ::HeapProfilerWithPseudoStackStart, - ::HeapProfilerStop, ::GetHeapProfile)); - EXPECT_EQ(1u, TraceLog::GetInstance()->GetObserverCountForTest()); - EXPECT_TRUE( - TraceLog::GetInstance()->HasEnabledStateObserver(controller.get())); - - // By default the observer isn't dumping memory profiles. - EXPECT_FALSE(controller->IsTimerRunningForTest()); - - // Simulate enabling tracing. - controller->StartProfiling(); - message_loop.RunUntilIdle(); - EXPECT_TRUE(controller->IsTimerRunningForTest()); - - // Simulate disabling tracing. - controller->StopProfiling(); - message_loop.RunUntilIdle(); - EXPECT_FALSE(controller->IsTimerRunningForTest()); - - // Deleting the observer removes it from the TraceLog observer list. - controller.reset(); - EXPECT_EQ(0u, TraceLog::GetInstance()->GetObserverCountForTest()); -} - -TEST_F(TraceMemoryTest, ScopedTraceMemory) { - ScopedTraceMemory::InitForTest(); - - // Start with an empty stack. - EXPECT_EQ(0, ScopedTraceMemory::GetStackDepthForTest()); - - { - // Push an item. - ScopedTraceMemory scope1("cat1", "name1"); - EXPECT_EQ(1, ScopedTraceMemory::GetStackDepthForTest()); - EXPECT_EQ("cat1", ScopedTraceMemory::GetScopeDataForTest(0).category); - EXPECT_EQ("name1", ScopedTraceMemory::GetScopeDataForTest(0).name); - - { - // One more item. - ScopedTraceMemory scope2("cat2", "name2"); - EXPECT_EQ(2, ScopedTraceMemory::GetStackDepthForTest()); - EXPECT_EQ("cat2", ScopedTraceMemory::GetScopeDataForTest(1).category); - EXPECT_EQ("name2", ScopedTraceMemory::GetScopeDataForTest(1).name); - } - - // Ended scope 2. - EXPECT_EQ(1, ScopedTraceMemory::GetStackDepthForTest()); - } - - // Ended scope 1. - EXPECT_EQ(0, ScopedTraceMemory::GetStackDepthForTest()); - - ScopedTraceMemory::CleanupForTest(); -} - -void TestDeepScopeNesting(int current, int depth) { - EXPECT_EQ(current, ScopedTraceMemory::GetStackDepthForTest()); - ScopedTraceMemory scope("category", "name"); - if (current < depth) - TestDeepScopeNesting(current + 1, depth); - EXPECT_EQ(current + 1, ScopedTraceMemory::GetStackDepthForTest()); -} - -TEST_F(TraceMemoryTest, DeepScopeNesting) { - ScopedTraceMemory::InitForTest(); - - // Ensure really deep scopes don't crash. - TestDeepScopeNesting(0, 100); - - ScopedTraceMemory::CleanupForTest(); -} - -#endif // defined(TRACE_MEMORY_SUPPORTED) - -///////////////////////////////////////////////////////////////////////////// - -TEST_F(TraceMemoryTest, AppendHeapProfileTotalsAsTraceFormat) { - // Empty input gives empty output. - std::string empty_output; - AppendHeapProfileTotalsAsTraceFormat("", &empty_output); - EXPECT_EQ("", empty_output); - - // Typical case. - const char input[] = - "heap profile: 357: 55227 [ 14653: 2624014] @ heapprofile"; - const std::string kExpectedOutput = - "{\"current_allocs\": 357, \"current_bytes\": 55227, \"trace\": \"\"}"; - std::string output; - AppendHeapProfileTotalsAsTraceFormat(input, &output); - EXPECT_EQ(kExpectedOutput, output); -} - -TEST_F(TraceMemoryTest, AppendHeapProfileLineAsTraceFormat) { - // Empty input gives empty output. - std::string empty_output; - EXPECT_FALSE(AppendHeapProfileLineAsTraceFormat("", &empty_output)); - EXPECT_EQ("", empty_output); - - // Invalid input returns false. - std::string junk_output; - EXPECT_FALSE(AppendHeapProfileLineAsTraceFormat("junk", &junk_output)); - - // Input with normal category and name entries. - const char kCategory[] = "category"; - const char kName[] = "name"; - std::ostringstream input; - input << " 68: 4195 [ 1087: 98009] @ " << &kCategory << " " - << &kName; - const std::string kExpectedOutput = - ",\n" - "{" - "\"current_allocs\": 68, " - "\"current_bytes\": 4195, " - "\"trace\": \"name \"" - "}"; - std::string output; - EXPECT_TRUE( - AppendHeapProfileLineAsTraceFormat(input.str().c_str(), &output)); - EXPECT_EQ(kExpectedOutput, output); - - // Input with with the category "toplevel". - // TODO(jamescook): Eliminate this special case and move the logic to the - // trace viewer code. - const char kTaskCategory[] = "toplevel"; - const char kTaskName[] = "TaskName"; - std::ostringstream input2; - input2 << " 68: 4195 [ 1087: 98009] @ " << &kTaskCategory << " " - << &kTaskName; - const std::string kExpectedOutput2 = - ",\n" - "{" - "\"current_allocs\": 68, " - "\"current_bytes\": 4195, " - "\"trace\": \"TaskName->PostTask \"" - "}"; - std::string output2; - EXPECT_TRUE( - AppendHeapProfileLineAsTraceFormat(input2.str().c_str(), &output2)); - EXPECT_EQ(kExpectedOutput2, output2); - - // Zero current allocations is skipped. - std::ostringstream zero_input; - zero_input << " 0: 0 [ 1087: 98009] @ " << &kCategory << " " - << &kName; - std::string zero_output; - EXPECT_FALSE(AppendHeapProfileLineAsTraceFormat(zero_input.str().c_str(), - &zero_output)); - EXPECT_EQ("", zero_output); -} - -TEST_F(TraceMemoryTest, AppendHeapProfileAsTraceFormat) { - // Empty input gives empty output. - std::string empty_output; - AppendHeapProfileAsTraceFormat("", &empty_output); - EXPECT_EQ("", empty_output); - - // Typical case. - const char input[] = - "heap profile: 357: 55227 [ 14653: 2624014] @ heapprofile\n" - " 95: 40940 [ 649: 114260] @\n" - " 77: 32546 [ 742: 106234] @ 0x0 0x0\n" - " 0: 0 [ 132: 4236] @ 0x0\n" - "\n" - "MAPPED_LIBRARIES:\n" - "1be411fc1000-1be4139e4000 rw-p 00000000 00:00 0\n" - "1be4139e4000-1be4139e5000 ---p 00000000 00:00 0\n"; - const std::string kExpectedOutput = - "[{" - "\"current_allocs\": 357, " - "\"current_bytes\": 55227, " - "\"trace\": \"\"},\n" - "{\"current_allocs\": 95, " - "\"current_bytes\": 40940, " - "\"trace\": \"\"},\n" - "{\"current_allocs\": 77, " - "\"current_bytes\": 32546, " - "\"trace\": \"null \"" - "}]\n"; - std::string output; - AppendHeapProfileAsTraceFormat(input, &output); - EXPECT_EQ(kExpectedOutput, output); -} - -TEST_F(TraceMemoryTest, StringFromHexAddress) { - EXPECT_STREQ("null", StringFromHexAddress("0x0")); - EXPECT_STREQ("error", StringFromHexAddress("not an address")); - const char kHello[] = "hello"; - std::ostringstream hex_address; - hex_address << &kHello; - EXPECT_STREQ(kHello, StringFromHexAddress(hex_address.str())); -} - -} // namespace trace_event -} // namespace base -- cgit v1.1