172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved. 2c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Use of this source code is governed by a BSD-style license that can be 3c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// found in the LICENSE file. 4c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 5731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "base/metrics/stats_table.h" 6c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 7c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/logging.h" 8ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/memory/scoped_ptr.h" 9c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/process_util.h" 10c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/shared_memory.h" 11c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/string_piece.h" 12c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/string_util.h" 133f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "base/threading/platform_thread.h" 143f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "base/threading/thread_local_storage.h" 15c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/utf_string_conversions.h" 16c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 17c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#if defined(OS_POSIX) 18c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "errno.h" 19c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#endif 20c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 21731df977c0511bca2206b5f333555b1205ff1f43Iain Merricknamespace base { 22731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 23c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// The StatsTable uses a shared memory segment that is laid out as follows 24c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// 25c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// +-------------------------------------------+ 26c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// | Version | Size | MaxCounters | MaxThreads | 27c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// +-------------------------------------------+ 28c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// | Thread names table | 29c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// +-------------------------------------------+ 30c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// | Thread TID table | 31c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// +-------------------------------------------+ 32c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// | Thread PID table | 33c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// +-------------------------------------------+ 34c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// | Counter names table | 35c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// +-------------------------------------------+ 36c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// | Data | 37c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// +-------------------------------------------+ 38c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// 39c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// The data layout is a grid, where the columns are the thread_ids and the 40c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// rows are the counter_ids. 41c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// 42c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// If the first character of the thread_name is '\0', then that column is 43c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// empty. 44c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// If the first character of the counter_name is '\0', then that row is 45c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// empty. 46c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// 47c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// About Locking: 48c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// This class is designed to be both multi-thread and multi-process safe. 49c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Aside from initialization, this is done by partitioning the data which 50c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// each thread uses so that no locking is required. However, to allocate 51c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// the rows and columns of the table to particular threads, locking is 52c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// required. 53c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// 54c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// At the shared-memory level, we have a lock. This lock protects the 55c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// shared-memory table only, and is used when we create new counters (e.g. 56c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// use rows) or when we register new threads (e.g. use columns). Reading 57c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// data from the table does not require any locking at the shared memory 58c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// level. 59c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// 60c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Each process which accesses the table will create a StatsTable object. 61c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// The StatsTable maintains a hash table of the existing counters in the 62c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// table for faster lookup. Since the hash table is process specific, 63c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// each process maintains its own cache. We avoid complexity here by never 64c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// de-allocating from the hash table. (Counters are dynamically added, 65c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// but not dynamically removed). 66c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 67c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// In order for external viewers to be able to read our shared memory, 68c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// we all need to use the same size ints. 69c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottCOMPILE_ASSERT(sizeof(int)==4, expect_4_byte_ints); 70c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 71c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottnamespace { 72c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 73c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// An internal version in case we ever change the format of this 74c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// file, and so that we can identify our table. 75c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottconst int kTableVersion = 0x13131313; 76c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 77c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// The name for un-named counters and threads in the table. 78c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottconst char kUnknownName[] = "<unknown>"; 79c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 80c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Calculates delta to align an offset to the size of an int 81c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottinline int AlignOffset(int offset) { 82c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return (sizeof(int) - (offset % sizeof(int))) % sizeof(int); 83c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 84c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 85c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottinline int AlignedSize(int size) { 86c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return size + AlignOffset(size); 87c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 88c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 89c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} // namespace 90c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 91731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// The StatsTable::Private maintains convenience pointers into the 92c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// shared memory segment. Use this class to keep the data structure 93c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// clean and accessible. 94731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickclass StatsTable::Private { 95c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott public: 96c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Various header information contained in the memory mapped segment. 97c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott struct TableHeader { 98c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott int version; 99c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott int size; 100c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott int max_counters; 101c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott int max_threads; 102c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott }; 103c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 104731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // Construct a new Private based on expected size parameters, or 105c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // return NULL on failure. 106731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick static Private* New(const std::string& name, int size, 107c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott int max_threads, int max_counters); 108c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 109731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick SharedMemory* shared_memory() { return &shared_memory_; } 110c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 111c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Accessors for our header pointers 112c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott TableHeader* table_header() const { return table_header_; } 113c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott int version() const { return table_header_->version; } 114c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott int size() const { return table_header_->size; } 115c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott int max_counters() const { return table_header_->max_counters; } 116c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott int max_threads() const { return table_header_->max_threads; } 117c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 118c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Accessors for our tables 119c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott char* thread_name(int slot_id) const { 120c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return &thread_names_table_[ 121c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott (slot_id-1) * (StatsTable::kMaxThreadNameLength)]; 122c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 123c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott PlatformThreadId* thread_tid(int slot_id) const { 124c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return &(thread_tid_table_[slot_id-1]); 125c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 126c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott int* thread_pid(int slot_id) const { 127c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return &(thread_pid_table_[slot_id-1]); 128c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 129c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott char* counter_name(int counter_id) const { 130c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return &counter_names_table_[ 131c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott (counter_id-1) * (StatsTable::kMaxCounterNameLength)]; 132c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 133c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott int* row(int counter_id) const { 134c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return &data_table_[(counter_id-1) * max_threads()]; 135c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 136c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 137c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott private: 138c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Constructor is private because you should use New() instead. 13972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen Private() 14072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen : table_header_(NULL), 14172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen thread_names_table_(NULL), 14272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen thread_tid_table_(NULL), 14372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen thread_pid_table_(NULL), 14472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen counter_names_table_(NULL), 14572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen data_table_(NULL) { 14672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 147c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 148c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Initializes the table on first access. Sets header values 149c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // appropriately and zeroes all counters. 150c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott void InitializeTable(void* memory, int size, int max_counters, 151c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott int max_threads); 152c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 153c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Initializes our in-memory pointers into a pre-created StatsTable. 154c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott void ComputeMappedPointers(void* memory); 155c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 156731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick SharedMemory shared_memory_; 157c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott TableHeader* table_header_; 158c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott char* thread_names_table_; 159c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott PlatformThreadId* thread_tid_table_; 160c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott int* thread_pid_table_; 161c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott char* counter_names_table_; 162c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott int* data_table_; 163c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}; 164c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 165c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// static 166731df977c0511bca2206b5f333555b1205ff1f43Iain MerrickStatsTable::Private* StatsTable::Private::New(const std::string& name, 167731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick int size, 168731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick int max_threads, 169731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick int max_counters) { 1702255f234e3edbf06b52de2ab4329d1564ef8efb0Iain Merrick#ifdef ANDROID 1712255f234e3edbf06b52de2ab4329d1564ef8efb0Iain Merrick return NULL; 1722255f234e3edbf06b52de2ab4329d1564ef8efb0Iain Merrick#else 173731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick scoped_ptr<Private> priv(new Private()); 174513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch if (!priv->shared_memory_.CreateNamed(name, true, size)) 175c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return NULL; 176c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (!priv->shared_memory_.Map(size)) 177c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return NULL; 178c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott void* memory = priv->shared_memory_.memory(); 179c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 180c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott TableHeader* header = static_cast<TableHeader*>(memory); 181c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 182c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // If the version does not match, then assume the table needs 183c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // to be initialized. 184c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (header->version != kTableVersion) 185c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott priv->InitializeTable(memory, size, max_counters, max_threads); 186c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 187c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // We have a valid table, so compute our pointers. 188c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott priv->ComputeMappedPointers(memory); 189c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 190c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return priv.release(); 19100d26a728db2814620f390b418a7d6325ce5aca6Ben Murdoch#endif 192c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 193c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 194731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickvoid StatsTable::Private::InitializeTable(void* memory, int size, 195731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick int max_counters, 196731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick int max_threads) { 197c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Zero everything. 198c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott memset(memory, 0, size); 199c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 200c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Initialize the header. 201c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott TableHeader* header = static_cast<TableHeader*>(memory); 202c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott header->version = kTableVersion; 203c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott header->size = size; 204c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott header->max_counters = max_counters; 205c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott header->max_threads = max_threads; 206c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 207c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 208731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickvoid StatsTable::Private::ComputeMappedPointers(void* memory) { 209c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott char* data = static_cast<char*>(memory); 210c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott int offset = 0; 211c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 212c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott table_header_ = reinterpret_cast<TableHeader*>(data); 213c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott offset += sizeof(*table_header_); 214c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott offset += AlignOffset(offset); 215c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 216c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Verify we're looking at a valid StatsTable. 217c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DCHECK_EQ(table_header_->version, kTableVersion); 218c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 219c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott thread_names_table_ = reinterpret_cast<char*>(data + offset); 220c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott offset += sizeof(char) * 221c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott max_threads() * StatsTable::kMaxThreadNameLength; 222c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott offset += AlignOffset(offset); 223c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 224c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott thread_tid_table_ = reinterpret_cast<PlatformThreadId*>(data + offset); 225c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott offset += sizeof(int) * max_threads(); 226c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott offset += AlignOffset(offset); 227c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 228c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott thread_pid_table_ = reinterpret_cast<int*>(data + offset); 229c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott offset += sizeof(int) * max_threads(); 230c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott offset += AlignOffset(offset); 231c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 232c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott counter_names_table_ = reinterpret_cast<char*>(data + offset); 233c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott offset += sizeof(char) * 234c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott max_counters() * StatsTable::kMaxCounterNameLength; 235c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott offset += AlignOffset(offset); 236c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 237c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott data_table_ = reinterpret_cast<int*>(data + offset); 238c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott offset += sizeof(int) * max_threads() * max_counters(); 239c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 240c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DCHECK_EQ(offset, size()); 241c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 242c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 243731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// TLSData carries the data stored in the TLS slots for the 244731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// StatsTable. This is used so that we can properly cleanup when the 245731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// thread exits and return the table slot. 246731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// 247731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// Each thread that calls RegisterThread in the StatsTable will have 248731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// a TLSData stored in its TLS. 249731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickstruct StatsTable::TLSData { 250731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick StatsTable* table; 251731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick int slot; 252731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}; 253c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 254c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// We keep a singleton table which can be easily accessed. 255c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottStatsTable* StatsTable::global_table_ = NULL; 256c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 257c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottStatsTable::StatsTable(const std::string& name, int max_threads, 258c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott int max_counters) 259c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott : impl_(NULL), 260c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott tls_index_(SlotReturnFunction) { 261c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott int table_size = 262731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick AlignedSize(sizeof(Private::TableHeader)) + 263c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott AlignedSize((max_counters * sizeof(char) * kMaxCounterNameLength)) + 264c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott AlignedSize((max_threads * sizeof(char) * kMaxThreadNameLength)) + 265c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott AlignedSize(max_threads * sizeof(int)) + 266c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott AlignedSize(max_threads * sizeof(int)) + 267c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott AlignedSize((sizeof(int) * (max_counters * max_threads))); 268c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 269731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick impl_ = Private::New(name, table_size, max_threads, max_counters); 270c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 271c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (!impl_) 272c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott PLOG(ERROR) << "StatsTable did not initialize"; 273c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 274c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 275c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottStatsTable::~StatsTable() { 276c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Before we tear down our copy of the table, be sure to 277c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // unregister our thread. 278c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott UnregisterThread(); 279c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 280c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Return ThreadLocalStorage. At this point, if any registered threads 281c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // still exist, they cannot Unregister. 282c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott tls_index_.Free(); 283c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 284c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Cleanup our shared memory. 285c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott delete impl_; 286c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 287c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // If we are the global table, unregister ourselves. 288c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (global_table_ == this) 289c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott global_table_ = NULL; 290c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 291c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 29272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenint StatsTable::GetSlot() const { 29372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen TLSData* data = GetTLSData(); 29472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (!data) 29572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return 0; 29672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return data->slot; 29772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen} 29872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 299c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottint StatsTable::RegisterThread(const std::string& name) { 30000d26a728db2814620f390b418a7d6325ce5aca6Ben Murdoch#ifdef ANDROID 30100d26a728db2814620f390b418a7d6325ce5aca6Ben Murdoch return 0; 30200d26a728db2814620f390b418a7d6325ce5aca6Ben Murdoch#else 303c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott int slot = 0; 304c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (!impl_) 305c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return 0; 306c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 307c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Registering a thread requires that we lock the shared memory 308c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // so that two threads don't grab the same slot. Fortunately, 309c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // thread creation shouldn't happen in inner loops. 310c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott { 311731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick SharedMemoryAutoLock lock(impl_->shared_memory()); 312c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott slot = FindEmptyThread(); 313c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (!slot) { 314c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return 0; 315c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 316c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 317c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // We have space, so consume a column in the table. 318c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott std::string thread_name = name; 319c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (name.empty()) 320c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott thread_name = kUnknownName; 321731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick strlcpy(impl_->thread_name(slot), thread_name.c_str(), 322731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick kMaxThreadNameLength); 323c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott *(impl_->thread_tid(slot)) = PlatformThread::CurrentId(); 324731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick *(impl_->thread_pid(slot)) = GetCurrentProcId(); 325c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 326c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 327c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Set our thread local storage. 328731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick TLSData* data = new TLSData; 329c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott data->table = this; 330c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott data->slot = slot; 331c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott tls_index_.Set(data); 332c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return slot; 33300d26a728db2814620f390b418a7d6325ce5aca6Ben Murdoch#endif 334c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 335c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 33672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenint StatsTable::CountThreadsRegistered() const { 33772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (!impl_) 33872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return 0; 33972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 34072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // Loop through the shared memory and count the threads that are active. 34172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // We intentionally do not lock the table during the operation. 34272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen int count = 0; 34372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen for (int index = 1; index <= impl_->max_threads(); index++) { 34472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen char* name = impl_->thread_name(index); 34572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (*name != '\0') 34672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen count++; 34772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 34872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return count; 34972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen} 35072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 35172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenint StatsTable::FindCounter(const std::string& name) { 35272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // Note: the API returns counters numbered from 1..N, although 35372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // internally, the array is 0..N-1. This is so that we can return 35472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // zero as "not found". 35572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (!impl_) 35672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return 0; 35772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 35872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // Create a scope for our auto-lock. 35972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen { 36072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen AutoLock scoped_lock(counters_lock_); 36172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 36272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // Attempt to find the counter. 36372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen CountersMap::const_iterator iter; 36472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen iter = counters_.find(name); 36572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (iter != counters_.end()) 36672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return iter->second; 36772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 36872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 36972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // Counter does not exist, so add it. 37072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return AddCounter(name); 37172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen} 37272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 37372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenint* StatsTable::GetLocation(int counter_id, int slot_id) const { 37472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (!impl_) 37572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return NULL; 37672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (slot_id > impl_->max_threads()) 377c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return NULL; 378c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 37972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen int* row = impl_->row(counter_id); 38072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return &(row[slot_id-1]); 38172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen} 38272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 38372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenconst char* StatsTable::GetRowName(int index) const { 38472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (!impl_) 38572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return NULL; 38672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 38772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return impl_->counter_name(index); 38872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen} 38972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 39072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenint StatsTable::GetRowValue(int index) const { 39172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return GetRowValue(index, 0); 39272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen} 39372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 39472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenint StatsTable::GetRowValue(int index, int pid) const { 39572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (!impl_) 39672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return 0; 39772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 39872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen int rv = 0; 39972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen int* row = impl_->row(index); 40072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen for (int slot_id = 0; slot_id < impl_->max_threads(); slot_id++) { 40172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (pid == 0 || *impl_->thread_pid(slot_id) == pid) 40272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen rv += row[slot_id]; 40372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 40472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return rv; 40572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen} 40672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 40772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenint StatsTable::GetCounterValue(const std::string& name) { 40872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return GetCounterValue(name, 0); 40972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen} 41072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 41172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenint StatsTable::GetCounterValue(const std::string& name, int pid) { 41272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (!impl_) 41372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return 0; 41472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 41572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen int row = FindCounter(name); 41672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (!row) 41772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return 0; 41872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return GetRowValue(row, pid); 41972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen} 42072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 42172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenint StatsTable::GetMaxCounters() const { 42272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (!impl_) 42372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return 0; 42472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return impl_->max_counters(); 42572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen} 42672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 42772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenint StatsTable::GetMaxThreads() const { 42872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (!impl_) 42972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return 0; 43072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return impl_->max_threads(); 43172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen} 43272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 43372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenint* StatsTable::FindLocation(const char* name) { 43472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // Get the static StatsTable 43572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen StatsTable *table = StatsTable::current(); 43672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (!table) 43772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return NULL; 43872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 43972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // Get the slot for this thread. Try to register 44072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // it if none exists. 44172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen int slot = table->GetSlot(); 44272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (!slot && !(slot = table->RegisterThread(""))) 44372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return NULL; 44472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 44572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // Find the counter id for the counter. 44672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen std::string str_name(name); 44772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen int counter = table->FindCounter(str_name); 44872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 44972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // Now we can find the location in the table. 45072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return table->GetLocation(counter, slot); 451c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 452c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 453c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid StatsTable::UnregisterThread() { 454c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott UnregisterThread(GetTLSData()); 455c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 456c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 457731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickvoid StatsTable::UnregisterThread(TLSData* data) { 458c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (!data) 459c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return; 460c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DCHECK(impl_); 461c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 462c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Mark the slot free by zeroing out the thread name. 463c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott char* name = impl_->thread_name(data->slot); 464c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott *name = '\0'; 465c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 466c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Remove the calling thread's TLS so that it cannot use the slot. 467c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott tls_index_.Set(NULL); 468c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott delete data; 469c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 470c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 471c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid StatsTable::SlotReturnFunction(void* data) { 472c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // This is called by the TLS destructor, which on some platforms has 473c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // already cleared the TLS info, so use the tls_data argument 474c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // rather than trying to fetch it ourselves. 475731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick TLSData* tls_data = static_cast<TLSData*>(data); 476c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (tls_data) { 477c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DCHECK(tls_data->table); 478c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott tls_data->table->UnregisterThread(tls_data); 479c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 480c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 481c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 482c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottint StatsTable::FindEmptyThread() const { 483c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Note: the API returns slots numbered from 1..N, although 484c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // internally, the array is 0..N-1. This is so that we can return 485c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // zero as "not found". 486c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // 487c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // The reason for doing this is because the thread 'slot' is stored 488c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // in TLS, which is always initialized to zero, not -1. If 0 were 489c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // returned as a valid slot number, it would be confused with the 490c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // uninitialized state. 491c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (!impl_) 492c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return 0; 493c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 494c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott int index = 1; 495c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott for (; index <= impl_->max_threads(); index++) { 496c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott char* name = impl_->thread_name(index); 497c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (!*name) 498c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott break; 499c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 500c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (index > impl_->max_threads()) 501c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return 0; // The table is full. 502c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return index; 503c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 504c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 505c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottint StatsTable::FindCounterOrEmptyRow(const std::string& name) const { 506c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Note: the API returns slots numbered from 1..N, although 507c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // internally, the array is 0..N-1. This is so that we can return 508c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // zero as "not found". 509c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // 510c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // There isn't much reason for this other than to be consistent 511c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // with the way we track columns for thread slots. (See comments 512c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // in FindEmptyThread for why it is done this way). 513c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (!impl_) 514c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return 0; 515c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 516c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott int free_slot = 0; 517c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott for (int index = 1; index <= impl_->max_counters(); index++) { 518c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott char* row_name = impl_->counter_name(index); 519c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (!*row_name && !free_slot) 520c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott free_slot = index; // save that we found a free slot 521c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott else if (!strncmp(row_name, name.c_str(), kMaxCounterNameLength)) 522c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return index; 523c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 524c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return free_slot; 525c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 526c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 527c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottint StatsTable::AddCounter(const std::string& name) { 52800d26a728db2814620f390b418a7d6325ce5aca6Ben Murdoch#ifdef ANDROID 52900d26a728db2814620f390b418a7d6325ce5aca6Ben Murdoch return 0; 53000d26a728db2814620f390b418a7d6325ce5aca6Ben Murdoch#else 53100d26a728db2814620f390b418a7d6325ce5aca6Ben Murdoch 532c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (!impl_) 533c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return 0; 534c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 535c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott int counter_id = 0; 536c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott { 537c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // To add a counter to the shared memory, we need the 538c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // shared memory lock. 539731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick SharedMemoryAutoLock lock(impl_->shared_memory()); 540c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 541c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // We have space, so create a new counter. 542c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott counter_id = FindCounterOrEmptyRow(name); 543c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (!counter_id) 544c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return 0; 545c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 546c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott std::string counter_name = name; 547c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (name.empty()) 548c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott counter_name = kUnknownName; 549731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick strlcpy(impl_->counter_name(counter_id), counter_name.c_str(), 550731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick kMaxCounterNameLength); 551c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 552c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 553c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // now add to our in-memory cache 554c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott { 555c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott AutoLock lock(counters_lock_); 556c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott counters_[name] = counter_id; 557c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 558c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return counter_id; 55900d26a728db2814620f390b418a7d6325ce5aca6Ben Murdoch#endif 560c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 561c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 56272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian MonsenStatsTable::TLSData* StatsTable::GetTLSData() const { 56372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen TLSData* data = 56472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen static_cast<TLSData*>(tls_index_.Get()); 56572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (!data) 566c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return NULL; 567c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 56872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen DCHECK(data->slot); 56972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen DCHECK_EQ(data->table, this); 57072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return data; 571c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 572731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 573731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick} // namespace base 574