15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2011 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/metrics/stats_table.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h" 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/scoped_ptr.h" 97dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "base/memory/shared_memory.h" 1058e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch#include "base/process/process_handle.h" 11c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/strings/string_piece.h" 12868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h" 13868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/threading/platform_thread.h" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/threading/thread_local_storage.h" 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_POSIX) 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "errno.h" 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace base { 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The StatsTable uses a shared memory segment that is laid out as follows 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// +-------------------------------------------+ 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// | Version | Size | MaxCounters | MaxThreads | 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// +-------------------------------------------+ 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// | Thread names table | 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// +-------------------------------------------+ 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// | Thread TID table | 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// +-------------------------------------------+ 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// | Thread PID table | 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// +-------------------------------------------+ 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// | Counter names table | 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// +-------------------------------------------+ 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// | Data | 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// +-------------------------------------------+ 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The data layout is a grid, where the columns are the thread_ids and the 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// rows are the counter_ids. 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// If the first character of the thread_name is '\0', then that column is 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// empty. 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// If the first character of the counter_name is '\0', then that row is 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// empty. 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// About Locking: 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This class is designed to be both multi-thread and multi-process safe. 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Aside from initialization, this is done by partitioning the data which 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// each thread uses so that no locking is required. However, to allocate 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the rows and columns of the table to particular threads, locking is 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// required. 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// At the shared-memory level, we have a lock. This lock protects the 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// shared-memory table only, and is used when we create new counters (e.g. 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// use rows) or when we register new threads (e.g. use columns). Reading 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// data from the table does not require any locking at the shared memory 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// level. 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Each process which accesses the table will create a StatsTable object. 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The StatsTable maintains a hash table of the existing counters in the 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// table for faster lookup. Since the hash table is process specific, 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// each process maintains its own cache. We avoid complexity here by never 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// de-allocating from the hash table. (Counters are dynamically added, 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// but not dynamically removed). 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// In order for external viewers to be able to read our shared memory, 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// we all need to use the same size ints. 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)COMPILE_ASSERT(sizeof(int)==4, expect_4_byte_ints); 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// An internal version in case we ever change the format of this 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// file, and so that we can identify our table. 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kTableVersion = 0x13131313; 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The name for un-named counters and threads in the table. 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kUnknownName[] = "<unknown>"; 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Calculates delta to align an offset to the size of an int 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)inline int AlignOffset(int offset) { 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return (sizeof(int) - (offset % sizeof(int))) % sizeof(int); 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)inline int AlignedSize(int size) { 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return size + AlignOffset(size); 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The StatsTable::Private maintains convenience pointers into the 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// shared memory segment. Use this class to keep the data structure 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// clean and accessible. 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class StatsTable::Private { 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Various header information contained in the memory mapped segment. 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct TableHeader { 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int version; 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int size; 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int max_counters; 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int max_threads; 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Construct a new Private based on expected size parameters, or 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // return NULL on failure. 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static Private* New(const std::string& name, int size, 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int max_threads, int max_counters); 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SharedMemory* shared_memory() { return &shared_memory_; } 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Accessors for our header pointers 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TableHeader* table_header() const { return table_header_; } 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int version() const { return table_header_->version; } 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int size() const { return table_header_->size; } 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int max_counters() const { return table_header_->max_counters; } 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int max_threads() const { return table_header_->max_threads; } 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Accessors for our tables 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char* thread_name(int slot_id) const { 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return &thread_names_table_[ 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (slot_id-1) * (StatsTable::kMaxThreadNameLength)]; 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PlatformThreadId* thread_tid(int slot_id) const { 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return &(thread_tid_table_[slot_id-1]); 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int* thread_pid(int slot_id) const { 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return &(thread_pid_table_[slot_id-1]); 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char* counter_name(int counter_id) const { 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return &counter_names_table_[ 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (counter_id-1) * (StatsTable::kMaxCounterNameLength)]; 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int* row(int counter_id) const { 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return &data_table_[(counter_id-1) * max_threads()]; 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Constructor is private because you should use New() instead. 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Private() 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : table_header_(NULL), 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) thread_names_table_(NULL), 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) thread_tid_table_(NULL), 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) thread_pid_table_(NULL), 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) counter_names_table_(NULL), 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) data_table_(NULL) { 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Initializes the table on first access. Sets header values 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // appropriately and zeroes all counters. 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void InitializeTable(void* memory, int size, int max_counters, 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int max_threads); 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Initializes our in-memory pointers into a pre-created StatsTable. 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void ComputeMappedPointers(void* memory); 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SharedMemory shared_memory_; 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TableHeader* table_header_; 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char* thread_names_table_; 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PlatformThreadId* thread_tid_table_; 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int* thread_pid_table_; 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char* counter_names_table_; 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int* data_table_; 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)StatsTable::Private* StatsTable::Private::New(const std::string& name, 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int size, 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int max_threads, 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int max_counters) { 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<Private> priv(new Private()); 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!priv->shared_memory_.CreateNamed(name, true, size)) 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!priv->shared_memory_.Map(size)) 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void* memory = priv->shared_memory_.memory(); 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TableHeader* header = static_cast<TableHeader*>(memory); 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If the version does not match, then assume the table needs 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // to be initialized. 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (header->version != kTableVersion) 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) priv->InitializeTable(memory, size, max_counters, max_threads); 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We have a valid table, so compute our pointers. 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) priv->ComputeMappedPointers(memory); 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return priv.release(); 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void StatsTable::Private::InitializeTable(void* memory, int size, 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int max_counters, 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int max_threads) { 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Zero everything. 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memset(memory, 0, size); 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Initialize the header. 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TableHeader* header = static_cast<TableHeader*>(memory); 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) header->version = kTableVersion; 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) header->size = size; 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) header->max_counters = max_counters; 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) header->max_threads = max_threads; 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void StatsTable::Private::ComputeMappedPointers(void* memory) { 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char* data = static_cast<char*>(memory); 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int offset = 0; 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) table_header_ = reinterpret_cast<TableHeader*>(data); 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) offset += sizeof(*table_header_); 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) offset += AlignOffset(offset); 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Verify we're looking at a valid StatsTable. 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_EQ(table_header_->version, kTableVersion); 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) thread_names_table_ = reinterpret_cast<char*>(data + offset); 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) offset += sizeof(char) * 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) max_threads() * StatsTable::kMaxThreadNameLength; 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) offset += AlignOffset(offset); 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) thread_tid_table_ = reinterpret_cast<PlatformThreadId*>(data + offset); 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) offset += sizeof(int) * max_threads(); 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) offset += AlignOffset(offset); 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) thread_pid_table_ = reinterpret_cast<int*>(data + offset); 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) offset += sizeof(int) * max_threads(); 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) offset += AlignOffset(offset); 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) counter_names_table_ = reinterpret_cast<char*>(data + offset); 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) offset += sizeof(char) * 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) max_counters() * StatsTable::kMaxCounterNameLength; 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) offset += AlignOffset(offset); 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) data_table_ = reinterpret_cast<int*>(data + offset); 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) offset += sizeof(int) * max_threads() * max_counters(); 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_EQ(offset, size()); 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TLSData carries the data stored in the TLS slots for the 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// StatsTable. This is used so that we can properly cleanup when the 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// thread exits and return the table slot. 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Each thread that calls RegisterThread in the StatsTable will have 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// a TLSData stored in its TLS. 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct StatsTable::TLSData { 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StatsTable* table; 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int slot; 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// We keep a singleton table which can be easily accessed. 25190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)StatsTable* global_table = NULL; 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)StatsTable::StatsTable(const std::string& name, int max_threads, 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int max_counters) 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : impl_(NULL), 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tls_index_(SlotReturnFunction) { 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int table_size = 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AlignedSize(sizeof(Private::TableHeader)) + 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AlignedSize((max_counters * sizeof(char) * kMaxCounterNameLength)) + 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AlignedSize((max_threads * sizeof(char) * kMaxThreadNameLength)) + 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AlignedSize(max_threads * sizeof(int)) + 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AlignedSize(max_threads * sizeof(int)) + 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AlignedSize((sizeof(int) * (max_counters * max_threads))); 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) impl_ = Private::New(name, table_size, max_threads, max_counters); 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!impl_) 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DPLOG(ERROR) << "StatsTable did not initialize"; 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)StatsTable::~StatsTable() { 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Before we tear down our copy of the table, be sure to 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // unregister our thread. 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UnregisterThread(); 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Return ThreadLocalStorage. At this point, if any registered threads 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // still exist, they cannot Unregister. 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tls_index_.Free(); 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Cleanup our shared memory. 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) delete impl_; 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If we are the global table, unregister ourselves. 28490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (global_table == this) 28590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) global_table = NULL; 28690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} 28790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 28890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)StatsTable* StatsTable::current() { 28990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return global_table; 29090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} 29190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 29290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void StatsTable::set_current(StatsTable* value) { 29390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) global_table = value; 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int StatsTable::GetSlot() const { 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TLSData* data = GetTLSData(); 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!data) 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return data->slot; 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int StatsTable::RegisterThread(const std::string& name) { 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int slot = 0; 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!impl_) 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Registering a thread requires that we lock the shared memory 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // so that two threads don't grab the same slot. Fortunately, 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // thread creation shouldn't happen in inner loops. 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SharedMemoryAutoLock lock(impl_->shared_memory()); 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) slot = FindEmptyThread(); 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!slot) { 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We have space, so consume a column in the table. 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string thread_name = name; 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (name.empty()) 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) thread_name = kUnknownName; 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) strlcpy(impl_->thread_name(slot), thread_name.c_str(), 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kMaxThreadNameLength); 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *(impl_->thread_tid(slot)) = PlatformThread::CurrentId(); 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *(impl_->thread_pid(slot)) = GetCurrentProcId(); 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Set our thread local storage. 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TLSData* data = new TLSData; 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) data->table = this; 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) data->slot = slot; 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tls_index_.Set(data); 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return slot; 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int StatsTable::CountThreadsRegistered() const { 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!impl_) 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Loop through the shared memory and count the threads that are active. 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We intentionally do not lock the table during the operation. 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int count = 0; 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int index = 1; index <= impl_->max_threads(); index++) { 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char* name = impl_->thread_name(index); 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (*name != '\0') 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) count++; 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return count; 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int StatsTable::FindCounter(const std::string& name) { 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Note: the API returns counters numbered from 1..N, although 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // internally, the array is 0..N-1. This is so that we can return 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // zero as "not found". 3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!impl_) 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Create a scope for our auto-lock. 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { 3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AutoLock scoped_lock(counters_lock_); 3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Attempt to find the counter. 3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CountersMap::const_iterator iter; 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) iter = counters_.find(name); 3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (iter != counters_.end()) 3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return iter->second; 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Counter does not exist, so add it. 3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return AddCounter(name); 3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int* StatsTable::GetLocation(int counter_id, int slot_id) const { 3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!impl_) 3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (slot_id > impl_->max_threads()) 3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int* row = impl_->row(counter_id); 3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return &(row[slot_id-1]); 3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char* StatsTable::GetRowName(int index) const { 3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!impl_) 3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return impl_->counter_name(index); 3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int StatsTable::GetRowValue(int index) const { 3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return GetRowValue(index, 0); 3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int StatsTable::GetRowValue(int index, int pid) const { 3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!impl_) 3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int rv = 0; 3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int* row = impl_->row(index); 4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int slot_id = 0; slot_id < impl_->max_threads(); slot_id++) { 4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (pid == 0 || *impl_->thread_pid(slot_id) == pid) 4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rv += row[slot_id]; 4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return rv; 4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int StatsTable::GetCounterValue(const std::string& name) { 4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return GetCounterValue(name, 0); 4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int StatsTable::GetCounterValue(const std::string& name, int pid) { 4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!impl_) 4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int row = FindCounter(name); 4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!row) 4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return GetRowValue(row, pid); 4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int StatsTable::GetMaxCounters() const { 4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!impl_) 4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return impl_->max_counters(); 4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int StatsTable::GetMaxThreads() const { 4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!impl_) 4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return impl_->max_threads(); 4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int* StatsTable::FindLocation(const char* name) { 4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Get the static StatsTable 4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StatsTable *table = StatsTable::current(); 4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!table) 4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Get the slot for this thread. Try to register 4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // it if none exists. 4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int slot = table->GetSlot(); 442c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (!slot && !(slot = table->RegisterThread(std::string()))) 443c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return NULL; 4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Find the counter id for the counter. 4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string str_name(name); 4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int counter = table->FindCounter(str_name); 4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Now we can find the location in the table. 4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return table->GetLocation(counter, slot); 4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void StatsTable::UnregisterThread() { 4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UnregisterThread(GetTLSData()); 4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void StatsTable::UnregisterThread(TLSData* data) { 4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!data) 4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(impl_); 4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Mark the slot free by zeroing out the thread name. 4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char* name = impl_->thread_name(data->slot); 4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *name = '\0'; 4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Remove the calling thread's TLS so that it cannot use the slot. 4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tls_index_.Set(NULL); 4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) delete data; 4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void StatsTable::SlotReturnFunction(void* data) { 4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This is called by the TLS destructor, which on some platforms has 4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // already cleared the TLS info, so use the tls_data argument 4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // rather than trying to fetch it ourselves. 4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TLSData* tls_data = static_cast<TLSData*>(data); 4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (tls_data) { 4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(tls_data->table); 4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tls_data->table->UnregisterThread(tls_data); 4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int StatsTable::FindEmptyThread() const { 4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Note: the API returns slots numbered from 1..N, although 4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // internally, the array is 0..N-1. This is so that we can return 4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // zero as "not found". 4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The reason for doing this is because the thread 'slot' is stored 4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // in TLS, which is always initialized to zero, not -1. If 0 were 4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // returned as a valid slot number, it would be confused with the 4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // uninitialized state. 4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!impl_) 4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int index = 1; 4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (; index <= impl_->max_threads(); index++) { 4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char* name = impl_->thread_name(index); 4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!*name) 4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (index > impl_->max_threads()) 5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; // The table is full. 5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return index; 5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int StatsTable::FindCounterOrEmptyRow(const std::string& name) const { 5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Note: the API returns slots numbered from 1..N, although 5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // internally, the array is 0..N-1. This is so that we can return 5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // zero as "not found". 5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // There isn't much reason for this other than to be consistent 5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // with the way we track columns for thread slots. (See comments 5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // in FindEmptyThread for why it is done this way). 5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!impl_) 5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int free_slot = 0; 5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int index = 1; index <= impl_->max_counters(); index++) { 5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char* row_name = impl_->counter_name(index); 5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!*row_name && !free_slot) 5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) free_slot = index; // save that we found a free slot 5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else if (!strncmp(row_name, name.c_str(), kMaxCounterNameLength)) 5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return index; 5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return free_slot; 5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int StatsTable::AddCounter(const std::string& name) { 5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!impl_) 5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int counter_id = 0; 5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { 5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // To add a counter to the shared memory, we need the 5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // shared memory lock. 5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SharedMemoryAutoLock lock(impl_->shared_memory()); 5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We have space, so create a new counter. 5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) counter_id = FindCounterOrEmptyRow(name); 5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!counter_id) 5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string counter_name = name; 5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (name.empty()) 5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) counter_name = kUnknownName; 5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) strlcpy(impl_->counter_name(counter_id), counter_name.c_str(), 5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kMaxCounterNameLength); 5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // now add to our in-memory cache 5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { 5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AutoLock lock(counters_lock_); 5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) counters_[name] = counter_id; 5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return counter_id; 5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)StatsTable::TLSData* StatsTable::GetTLSData() const { 5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TLSData* data = 5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static_cast<TLSData*>(tls_index_.Get()); 5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!data) 5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(data->slot); 5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_EQ(data->table, this); 5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return data; 5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace base 569