diff --git a/content/browser/browser_main_loop.cc b/content/browser/browser_main_loop.cc index 5aa05675e33cc8..bf3da73101f984 100644 --- a/content/browser/browser_main_loop.cc +++ b/content/browser/browser_main_loop.cc @@ -71,6 +71,7 @@ #include "net/ssl/ssl_config_service.h" #include "ipc/mojo/scoped_ipc_support.h" #include "skia/ext/skia_memory_dump_provider.h" +#include "sql/sql_memory_dump_provider.h" #include "ui/base/clipboard/clipboard.h" #if defined(USE_AURA) || (defined(OS_MACOSX) && !defined(OS_IOS)) @@ -661,6 +662,8 @@ void BrowserMainLoop::PostMainMessageLoopStart() { HostSharedBitmapManager::current()); base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider( skia::SkiaMemoryDumpProvider::GetInstance()); + base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider( + sql::SqlMemoryDumpProvider::GetInstance()); #if defined(TCMALLOC_TRACE_MEMORY_SUPPORTED) trace_memory_controller_.reset(new base::trace_event::TraceMemoryController( diff --git a/sql/BUILD.gn b/sql/BUILD.gn index 57f1b38efd9874..8d071a3e7747fb 100644 --- a/sql/BUILD.gn +++ b/sql/BUILD.gn @@ -15,6 +15,8 @@ component("sql") { "meta_table.h", "recovery.cc", "recovery.h", + "sql_memory_dump_provider.cc", + "sql_memory_dump_provider.h", "statement.cc", "statement.h", "transaction.cc", @@ -77,6 +79,7 @@ test("sql_unittests") { "connection_unittest.cc", "meta_table_unittest.cc", "recovery_unittest.cc", + "sql_memory_dump_provider_unittest.cc", "sqlite_features_unittest.cc", "statement_unittest.cc", "test/paths.cc", diff --git a/sql/connection.cc b/sql/connection.cc index 20f0f075cbafb0..61aebbe0c94f86 100644 --- a/sql/connection.cc +++ b/sql/connection.cc @@ -19,6 +19,8 @@ #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" #include "base/synchronization/lock.h" +#include "base/trace_event/memory_dump_manager.h" +#include "base/trace_event/process_memory_dump.h" #include "sql/statement.h" #include "third_party/sqlite/sqlite3.h" @@ -217,6 +219,44 @@ bool Connection::ShouldIgnoreSqliteError(int error) { return current_ignorer_cb_->Run(error); } +bool Connection::OnMemoryDump(const base::trace_event::MemoryDumpArgs& args, + base::trace_event::ProcessMemoryDump* pmd) { + if (args.level_of_detail == + base::trace_event::MemoryDumpLevelOfDetail::LIGHT || + !db_) { + return true; + } + + // The high water mark is not tracked for the following usages. + int cache_size, dummy_int; + sqlite3_db_status(db_, SQLITE_DBSTATUS_CACHE_USED, &cache_size, &dummy_int, + 0 /* resetFlag */); + int schema_size; + sqlite3_db_status(db_, SQLITE_DBSTATUS_SCHEMA_USED, &schema_size, &dummy_int, + 0 /* resetFlag */); + int statement_size; + sqlite3_db_status(db_, SQLITE_DBSTATUS_STMT_USED, &statement_size, &dummy_int, + 0 /* resetFlag */); + + std::string name = base::StringPrintf( + "sqlite/%s_connection/%p", + histogram_tag_.empty() ? "Unknown" : histogram_tag_.c_str(), this); + base::trace_event::MemoryAllocatorDump* dump = pmd->CreateAllocatorDump(name); + dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize, + base::trace_event::MemoryAllocatorDump::kUnitsBytes, + cache_size + schema_size + statement_size); + dump->AddScalar("cache_size", + base::trace_event::MemoryAllocatorDump::kUnitsBytes, + cache_size); + dump->AddScalar("schema_size", + base::trace_event::MemoryAllocatorDump::kUnitsBytes, + schema_size); + dump->AddScalar("statement_size", + base::trace_event::MemoryAllocatorDump::kUnitsBytes, + statement_size); + return true; +} + // static void Connection::SetErrorIgnorer(Connection::ErrorIgnorerCallback* cb) { CHECK(current_ignorer_cb_ == NULL); @@ -291,9 +331,13 @@ Connection::Connection() update_time_histogram_(NULL), query_time_histogram_(NULL), clock_(new TimeSource()) { + base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider( + this); } Connection::~Connection() { + base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider( + this); Close(); } diff --git a/sql/connection.h b/sql/connection.h index d456b6cd88c962..7d2ab6a355bfc9 100644 --- a/sql/connection.h +++ b/sql/connection.h @@ -18,6 +18,7 @@ #include "base/memory/scoped_ptr.h" #include "base/threading/thread_restrictions.h" #include "base/time/time.h" +#include "base/trace_event/memory_dump_provider.h" #include "sql/sql_export.h" struct sqlite3; @@ -102,7 +103,7 @@ class SQL_EXPORT TimeSource { DISALLOW_COPY_AND_ASSIGN(TimeSource); }; -class SQL_EXPORT Connection { +class SQL_EXPORT Connection : public base::trace_event::MemoryDumpProvider { private: class StatementRef; // Forward declaration, see real one below. @@ -110,7 +111,7 @@ class SQL_EXPORT Connection { // The database is opened by calling Open[InMemory](). Any uncommitted // transactions will be rolled back when this object is deleted. Connection(); - ~Connection(); + ~Connection() override; // Pre-init configuration ---------------------------------------------------- @@ -464,6 +465,11 @@ class SQL_EXPORT Connection { // tests. static bool ShouldIgnoreSqliteError(int error); + // base::trace_event::MemoryDumpProvider implementation. + bool OnMemoryDump( + const base::trace_event::MemoryDumpArgs& args, + base::trace_event::ProcessMemoryDump* process_memory_dump) override; + private: // For recovery module. friend class Recovery; diff --git a/sql/connection_unittest.cc b/sql/connection_unittest.cc index 0038a1d7f57aac..d933a6dab6e6d7 100644 --- a/sql/connection_unittest.cc +++ b/sql/connection_unittest.cc @@ -11,6 +11,7 @@ #include "base/metrics/statistics_recorder.h" #include "base/strings/stringprintf.h" #include "base/test/histogram_tester.h" +#include "base/trace_event/process_memory_dump.h" #include "sql/connection.h" #include "sql/correct_sql_test_base.h" #include "sql/meta_table.h" @@ -1378,4 +1379,12 @@ TEST_F(SQLConnectionTest, MmapTest) { } #endif +TEST_F(SQLConnectionTest, OnMemoryDump) { + base::trace_event::ProcessMemoryDump pmd(nullptr); + base::trace_event::MemoryDumpArgs args = { + base::trace_event::MemoryDumpLevelOfDetail::DETAILED}; + ASSERT_TRUE(db().OnMemoryDump(args, &pmd)); + EXPECT_GE(pmd.allocator_dumps().size(), 1u); +} + } // namespace diff --git a/sql/sql.gyp b/sql/sql.gyp index 115a93bdd5f37d..362597e75f14fa 100644 --- a/sql/sql.gyp +++ b/sql/sql.gyp @@ -29,6 +29,8 @@ 'meta_table.h', 'recovery.cc', 'recovery.h', + 'sql_memory_dump_provider.cc', + 'sql_memory_dump_provider.h', 'statement.cc', 'statement.h', 'transaction.cc', @@ -89,6 +91,7 @@ 'connection_unittest.cc', 'meta_table_unittest.cc', 'recovery_unittest.cc', + 'sql_memory_dump_provider_unittest.cc', 'sqlite_features_unittest.cc', 'statement_unittest.cc', 'test/paths.cc', diff --git a/sql/sql_memory_dump_provider.cc b/sql/sql_memory_dump_provider.cc new file mode 100644 index 00000000000000..bb6d81306c000c --- /dev/null +++ b/sql/sql_memory_dump_provider.cc @@ -0,0 +1,62 @@ +// Copyright 2015 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 "sql/sql_memory_dump_provider.h" + +#include "base/trace_event/memory_dump_manager.h" +#include "base/trace_event/process_memory_dump.h" +#include "third_party/sqlite/sqlite3.h" + +namespace sql { + +// static +SqlMemoryDumpProvider* SqlMemoryDumpProvider::GetInstance() { + return base::Singleton< + SqlMemoryDumpProvider, + base::LeakySingletonTraits>::get(); +} + +SqlMemoryDumpProvider::SqlMemoryDumpProvider() {} + +SqlMemoryDumpProvider::~SqlMemoryDumpProvider() {} + +bool SqlMemoryDumpProvider::OnMemoryDump( + const base::trace_event::MemoryDumpArgs& args, + base::trace_event::ProcessMemoryDump* pmd) { + int memory_used = 0; + int memory_high_water = 0; + int status = sqlite3_status(SQLITE_STATUS_MEMORY_USED, &memory_used, + &memory_high_water, 1 /*resetFlag */); + if (status != SQLITE_OK) + return false; + + base::trace_event::MemoryAllocatorDump* dump = + pmd->CreateAllocatorDump("sqlite"); + dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize, + base::trace_event::MemoryAllocatorDump::kUnitsBytes, + memory_used); + dump->AddScalar("malloc_high_wmark_size", + base::trace_event::MemoryAllocatorDump::kUnitsBytes, + memory_high_water); + + int dummy_high_water = -1; + int malloc_count = -1; + status = sqlite3_status(SQLITE_STATUS_MALLOC_COUNT, &malloc_count, + &dummy_high_water, 0 /* resetFlag */); + if (status == SQLITE_OK) { + dump->AddScalar("malloc_count", + base::trace_event::MemoryAllocatorDump::kUnitsObjects, + malloc_count); + } + + const char* system_allocator_name = + base::trace_event::MemoryDumpManager::GetInstance() + ->system_allocator_pool_name(); + if (system_allocator_name) { + pmd->AddSuballocation(dump->guid(), system_allocator_name); + } + return true; +} + +} // namespace sql diff --git a/sql/sql_memory_dump_provider.h b/sql/sql_memory_dump_provider.h new file mode 100644 index 00000000000000..051755f8859bbc --- /dev/null +++ b/sql/sql_memory_dump_provider.h @@ -0,0 +1,36 @@ +// Copyright 2015 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 SQL_PROCESS_MEMORY_DUMP_PROVIDER_H +#define SQL_PROCESS_MEMORY_DUMP_PROVIDER_H + +#include "base/memory/singleton.h" +#include "base/trace_event/memory_dump_provider.h" +#include "sql/sql_export.h" + +namespace sql { + +// Adds process-wide memory usage statistics about sqlite to chrome://tracing. +// sql::Connection::OnMemoryDump adds per-connection memory statistics. +class SQL_EXPORT SqlMemoryDumpProvider + : public base::trace_event::MemoryDumpProvider { + public: + static SqlMemoryDumpProvider* GetInstance(); + + // MemoryDumpProvider implementation. + bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args, + base::trace_event::ProcessMemoryDump* pmd) override; + + private: + friend struct base::DefaultSingletonTraits; + + SqlMemoryDumpProvider(); + ~SqlMemoryDumpProvider() override; + + DISALLOW_COPY_AND_ASSIGN(SqlMemoryDumpProvider); +}; + +} // namespace sql + +#endif // SQL_PROCESS_MEMORY_DUMP_PROVIDER_H diff --git a/sql/sql_memory_dump_provider_unittest.cc b/sql/sql_memory_dump_provider_unittest.cc new file mode 100644 index 00000000000000..1f1dcf9a689dfb --- /dev/null +++ b/sql/sql_memory_dump_provider_unittest.cc @@ -0,0 +1,22 @@ +// Copyright 2015 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 "sql/sql_memory_dump_provider.h" + +#include "base/trace_event/process_memory_dump.h" +#include "sql/test/sql_test_base.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace { +using SQLMemoryDumpProviderTest = sql::SQLTestBase; +} + +TEST_F(SQLMemoryDumpProviderTest, OnMemoryDump) { + base::trace_event::ProcessMemoryDump pmd(nullptr); + base::trace_event::MemoryDumpArgs args = { + base::trace_event::MemoryDumpLevelOfDetail::DETAILED}; + ASSERT_TRUE( + sql::SqlMemoryDumpProvider::GetInstance()->OnMemoryDump(args, &pmd)); + ASSERT_TRUE(pmd.GetAllocatorDump("sqlite")); +}