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)namespace base { 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The StatsTable uses a shared memory segment that is laid out as follows 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// +-------------------------------------------+ 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// | Version | Size | MaxCounters | MaxThreads | 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// +-------------------------------------------+ 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// | Thread names table | 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// +-------------------------------------------+ 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// | Thread TID table | 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// +-------------------------------------------+ 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// | Thread PID table | 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// +-------------------------------------------+ 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// | Counter names table | 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// +-------------------------------------------+ 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// | Data | 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// +-------------------------------------------+ 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The data layout is a grid, where the columns are the thread_ids and the 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// rows are the counter_ids. 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// If the first character of the thread_name is '\0', then that column is 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// empty. 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// If the first character of the counter_name is '\0', then that row is 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// empty. 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// About Locking: 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This class is designed to be both multi-thread and multi-process safe. 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Aside from initialization, this is done by partitioning the data which 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// each thread uses so that no locking is required. However, to allocate 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the rows and columns of the table to particular threads, locking is 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// required. 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// At the shared-memory level, we have a lock. This lock protects the 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// shared-memory table only, and is used when we create new counters (e.g. 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// use rows) or when we register new threads (e.g. use columns). Reading 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// data from the table does not require any locking at the shared memory 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// level. 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Each process which accesses the table will create a StatsTable object. 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The StatsTable maintains a hash table of the existing counters in the 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// table for faster lookup. Since the hash table is process specific, 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// each process maintains its own cache. We avoid complexity here by never 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// de-allocating from the hash table. (Counters are dynamically added, 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// but not dynamically removed). 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// In order for external viewers to be able to read our shared memory, 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// we all need to use the same size ints. 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)COMPILE_ASSERT(sizeof(int)==4, expect_4_byte_ints); 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// An internal version in case we ever change the format of this 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// file, and so that we can identify our table. 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kTableVersion = 0x13131313; 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The name for un-named counters and threads in the table. 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kUnknownName[] = "<unknown>"; 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Calculates delta to align an offset to the size of an int 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)inline int AlignOffset(int offset) { 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return (sizeof(int) - (offset % sizeof(int))) % sizeof(int); 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)inline int AlignedSize(int size) { 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return size + AlignOffset(size); 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 874e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// The StatsTable::Internal maintains convenience pointers into the 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// shared memory segment. Use this class to keep the data structure 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// clean and accessible. 904e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)class StatsTable::Internal { 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Various header information contained in the memory mapped segment. 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct TableHeader { 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int version; 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int size; 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int max_counters; 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int max_threads; 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1004e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // Construct a new Internal based on expected size parameters, or 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // return NULL on failure. 102c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch static Internal* New(const StatsTable::TableIdentifier& table, 1034e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) int size, 1044e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) int max_threads, 1054e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) int max_counters); 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1074e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) SharedMemory* shared_memory() { return shared_memory_.get(); } 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Accessors for our header pointers 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TableHeader* table_header() const { return table_header_; } 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int version() const { return table_header_->version; } 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int size() const { return table_header_->size; } 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int max_counters() const { return table_header_->max_counters; } 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int max_threads() const { return table_header_->max_threads; } 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Accessors for our tables 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char* thread_name(int slot_id) const { 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return &thread_names_table_[ 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (slot_id-1) * (StatsTable::kMaxThreadNameLength)]; 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PlatformThreadId* thread_tid(int slot_id) const { 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return &(thread_tid_table_[slot_id-1]); 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int* thread_pid(int slot_id) const { 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return &(thread_pid_table_[slot_id-1]); 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char* counter_name(int counter_id) const { 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return &counter_names_table_[ 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (counter_id-1) * (StatsTable::kMaxCounterNameLength)]; 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int* row(int counter_id) const { 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return &data_table_[(counter_id-1) * max_threads()]; 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Constructor is private because you should use New() instead. 1374e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) explicit Internal(SharedMemory* shared_memory) 1384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) : shared_memory_(shared_memory), 1394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) table_header_(NULL), 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) thread_names_table_(NULL), 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) thread_tid_table_(NULL), 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) thread_pid_table_(NULL), 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) counter_names_table_(NULL), 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) data_table_(NULL) { 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // Create or open the SharedMemory used by the stats table. 148c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch static SharedMemory* CreateSharedMemory( 149c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch const StatsTable::TableIdentifier& table, 150c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch int size); 1514e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Initializes the table on first access. Sets header values 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // appropriately and zeroes all counters. 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void InitializeTable(void* memory, int size, int max_counters, 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int max_threads); 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Initializes our in-memory pointers into a pre-created StatsTable. 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void ComputeMappedPointers(void* memory); 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) scoped_ptr<SharedMemory> shared_memory_; 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TableHeader* table_header_; 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char* thread_names_table_; 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PlatformThreadId* thread_tid_table_; 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int* thread_pid_table_; 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char* counter_names_table_; 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int* data_table_; 1674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 1684e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(Internal); 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 172c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen MurdochStatsTable::Internal* StatsTable::Internal::New( 173c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch const StatsTable::TableIdentifier& table, 174c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch int size, 175c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch int max_threads, 176c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch int max_counters) { 177c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch scoped_ptr<SharedMemory> shared_memory(CreateSharedMemory(table, size)); 1784e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (!shared_memory.get()) 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 1804e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (!shared_memory->Map(size)) 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 1824e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) void* memory = shared_memory->memory(); 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1844e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) scoped_ptr<Internal> internal(new Internal(shared_memory.release())); 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TableHeader* header = static_cast<TableHeader*>(memory); 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If the version does not match, then assume the table needs 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // to be initialized. 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (header->version != kTableVersion) 1904e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) internal->InitializeTable(memory, size, max_counters, max_threads); 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We have a valid table, so compute our pointers. 1934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) internal->ComputeMappedPointers(memory); 1944e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 1954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return internal.release(); 1964e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1984e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// static 199c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen MurdochSharedMemory* StatsTable::Internal::CreateSharedMemory( 200c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch const StatsTable::TableIdentifier& table, 201c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch int size) { 2024e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#if defined(OS_POSIX) 203c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch // Check for existing table. 204c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch if (table.fd != -1) 205c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch return new SharedMemory(table, false); 206c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 2074e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // Otherwise we need to create it. 2084e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) scoped_ptr<SharedMemory> shared_memory(new SharedMemory()); 2094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (!shared_memory->CreateAnonymous(size)) 2104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return NULL; 2114e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return shared_memory.release(); 2124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#elif defined(OS_WIN) 2134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) scoped_ptr<SharedMemory> shared_memory(new SharedMemory()); 214c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch if (table.empty()) { 215c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch // Create an anonymous table. 216c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch if (!shared_memory->CreateAnonymous(size)) 217c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch return NULL; 218c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch } else { 219c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch // Create a named table for sharing between processes. 220c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch if (!shared_memory->CreateNamedDeprecated(table, true, size)) 221c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch return NULL; 222c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch } 2234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return shared_memory.release(); 2244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#endif 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void StatsTable::Internal::InitializeTable(void* memory, int size, 228c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch int max_counters, 229c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch int max_threads) { 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Zero everything. 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memset(memory, 0, size); 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Initialize the header. 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TableHeader* header = static_cast<TableHeader*>(memory); 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) header->version = kTableVersion; 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) header->size = size; 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) header->max_counters = max_counters; 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) header->max_threads = max_threads; 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void StatsTable::Internal::ComputeMappedPointers(void* memory) { 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char* data = static_cast<char*>(memory); 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int offset = 0; 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) table_header_ = reinterpret_cast<TableHeader*>(data); 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) offset += sizeof(*table_header_); 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) offset += AlignOffset(offset); 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Verify we're looking at a valid StatsTable. 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_EQ(table_header_->version, kTableVersion); 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) thread_names_table_ = reinterpret_cast<char*>(data + offset); 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) offset += sizeof(char) * 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) max_threads() * StatsTable::kMaxThreadNameLength; 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) offset += AlignOffset(offset); 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) thread_tid_table_ = reinterpret_cast<PlatformThreadId*>(data + offset); 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) offset += sizeof(int) * max_threads(); 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) offset += AlignOffset(offset); 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) thread_pid_table_ = reinterpret_cast<int*>(data + offset); 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) offset += sizeof(int) * max_threads(); 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) offset += AlignOffset(offset); 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) counter_names_table_ = reinterpret_cast<char*>(data + offset); 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) offset += sizeof(char) * 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) max_counters() * StatsTable::kMaxCounterNameLength; 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) offset += AlignOffset(offset); 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) data_table_ = reinterpret_cast<int*>(data + offset); 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) offset += sizeof(int) * max_threads() * max_counters(); 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_EQ(offset, size()); 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TLSData carries the data stored in the TLS slots for the 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// StatsTable. This is used so that we can properly cleanup when the 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// thread exits and return the table slot. 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Each thread that calls RegisterThread in the StatsTable will have 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// a TLSData stored in its TLS. 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct StatsTable::TLSData { 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StatsTable* table; 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int slot; 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// We keep a singleton table which can be easily accessed. 28890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)StatsTable* global_table = NULL; 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 290c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen MurdochStatsTable::StatsTable(const TableIdentifier& table, 291c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch int max_threads, 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int max_counters) 2934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) : internal_(NULL), 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tls_index_(SlotReturnFunction) { 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int table_size = 2964e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) AlignedSize(sizeof(Internal::TableHeader)) + 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AlignedSize((max_counters * sizeof(char) * kMaxCounterNameLength)) + 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AlignedSize((max_threads * sizeof(char) * kMaxThreadNameLength)) + 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AlignedSize(max_threads * sizeof(int)) + 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AlignedSize(max_threads * sizeof(int)) + 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AlignedSize((sizeof(int) * (max_counters * max_threads))); 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 303c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch internal_ = Internal::New(table, table_size, max_threads, max_counters); 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3054e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (!internal_) 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DPLOG(ERROR) << "StatsTable did not initialize"; 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)StatsTable::~StatsTable() { 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Before we tear down our copy of the table, be sure to 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // unregister our thread. 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UnregisterThread(); 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Return ThreadLocalStorage. At this point, if any registered threads 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // still exist, they cannot Unregister. 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tls_index_.Free(); 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Cleanup our shared memory. 3194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) delete internal_; 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If we are the global table, unregister ourselves. 32290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (global_table == this) 32390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) global_table = NULL; 32490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} 32590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 32690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)StatsTable* StatsTable::current() { 32790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return global_table; 32890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} 32990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 33090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void StatsTable::set_current(StatsTable* value) { 33190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) global_table = value; 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int StatsTable::GetSlot() const { 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TLSData* data = GetTLSData(); 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!data) 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return data->slot; 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int StatsTable::RegisterThread(const std::string& name) { 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int slot = 0; 3434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (!internal_) 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Registering a thread requires that we lock the shared memory 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // so that two threads don't grab the same slot. Fortunately, 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // thread creation shouldn't happen in inner loops. 349a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // TODO(viettrungluu): crbug.com/345734: Use a different locking mechanism. 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { 351a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) SharedMemoryAutoLockDeprecated lock(internal_->shared_memory()); 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) slot = FindEmptyThread(); 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!slot) { 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We have space, so consume a column in the table. 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string thread_name = name; 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (name.empty()) 3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) thread_name = kUnknownName; 3614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) strlcpy(internal_->thread_name(slot), thread_name.c_str(), 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kMaxThreadNameLength); 3634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) *(internal_->thread_tid(slot)) = PlatformThread::CurrentId(); 3644e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) *(internal_->thread_pid(slot)) = GetCurrentProcId(); 3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Set our thread local storage. 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TLSData* data = new TLSData; 3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) data->table = this; 3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) data->slot = slot; 3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tls_index_.Set(data); 3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return slot; 3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int StatsTable::CountThreadsRegistered() const { 3764e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (!internal_) 3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Loop through the shared memory and count the threads that are active. 3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We intentionally do not lock the table during the operation. 3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int count = 0; 3824e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) for (int index = 1; index <= internal_->max_threads(); index++) { 3834e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) char* name = internal_->thread_name(index); 3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (*name != '\0') 3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) count++; 3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return count; 3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int StatsTable::FindCounter(const std::string& name) { 3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Note: the API returns counters numbered from 1..N, although 3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // internally, the array is 0..N-1. This is so that we can return 3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // zero as "not found". 3944e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (!internal_) 3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Create a scope for our auto-lock. 3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { 3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AutoLock scoped_lock(counters_lock_); 4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Attempt to find the counter. 4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CountersMap::const_iterator iter; 4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) iter = counters_.find(name); 4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (iter != counters_.end()) 4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return iter->second; 4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Counter does not exist, so add it. 4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return AddCounter(name); 4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int* StatsTable::GetLocation(int counter_id, int slot_id) const { 4134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (!internal_) 4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 4154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (slot_id > internal_->max_threads()) 4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) int* row = internal_->row(counter_id); 4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return &(row[slot_id-1]); 4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char* StatsTable::GetRowName(int index) const { 4234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (!internal_) 4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return internal_->counter_name(index); 4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int StatsTable::GetRowValue(int index) const { 4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return GetRowValue(index, 0); 4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int StatsTable::GetRowValue(int index, int pid) const { 4344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (!internal_) 4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int rv = 0; 4384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) int* row = internal_->row(index); 4394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) for (int slot_id = 1; slot_id <= internal_->max_threads(); slot_id++) { 4404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (pid == 0 || *internal_->thread_pid(slot_id) == pid) 441424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) rv += row[slot_id-1]; 4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return rv; 4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int StatsTable::GetCounterValue(const std::string& name) { 4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return GetCounterValue(name, 0); 4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int StatsTable::GetCounterValue(const std::string& name, int pid) { 4514e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (!internal_) 4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int row = FindCounter(name); 4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!row) 4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return GetRowValue(row, pid); 4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int StatsTable::GetMaxCounters() const { 4614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (!internal_) 4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 4634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return internal_->max_counters(); 4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int StatsTable::GetMaxThreads() const { 4674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (!internal_) 4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 4694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return internal_->max_threads(); 4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int* StatsTable::FindLocation(const char* name) { 4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Get the static StatsTable 4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StatsTable *table = StatsTable::current(); 4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!table) 4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Get the slot for this thread. Try to register 4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // it if none exists. 4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int slot = table->GetSlot(); 481116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (!slot) 482116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch slot = table->RegisterThread(std::string()); 483116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (!slot) 484c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return NULL; 4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Find the counter id for the counter. 4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string str_name(name); 4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int counter = table->FindCounter(str_name); 4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Now we can find the location in the table. 4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return table->GetLocation(counter, slot); 4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void StatsTable::UnregisterThread() { 4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UnregisterThread(GetTLSData()); 4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void StatsTable::UnregisterThread(TLSData* data) { 4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!data) 5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 5014e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) DCHECK(internal_); 5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Mark the slot free by zeroing out the thread name. 5044e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) char* name = internal_->thread_name(data->slot); 5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *name = '\0'; 5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Remove the calling thread's TLS so that it cannot use the slot. 5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tls_index_.Set(NULL); 5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) delete data; 5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void StatsTable::SlotReturnFunction(void* data) { 5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This is called by the TLS destructor, which on some platforms has 5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // already cleared the TLS info, so use the tls_data argument 5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // rather than trying to fetch it ourselves. 5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TLSData* tls_data = static_cast<TLSData*>(data); 5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (tls_data) { 5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(tls_data->table); 5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tls_data->table->UnregisterThread(tls_data); 5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int StatsTable::FindEmptyThread() const { 5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Note: the API returns slots numbered from 1..N, although 5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // internally, the array is 0..N-1. This is so that we can return 5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // zero as "not found". 5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The reason for doing this is because the thread 'slot' is stored 5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // in TLS, which is always initialized to zero, not -1. If 0 were 5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // returned as a valid slot number, it would be confused with the 5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // uninitialized state. 5324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (!internal_) 5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int index = 1; 5364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) for (; index <= internal_->max_threads(); index++) { 5374e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) char* name = internal_->thread_name(index); 5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!*name) 5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (index > internal_->max_threads()) 5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; // The table is full. 5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return index; 5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int StatsTable::FindCounterOrEmptyRow(const std::string& name) const { 5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Note: the API returns slots numbered from 1..N, although 5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // internally, the array is 0..N-1. This is so that we can return 5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // zero as "not found". 5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // There isn't much reason for this other than to be consistent 5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // with the way we track columns for thread slots. (See comments 5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // in FindEmptyThread for why it is done this way). 5544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (!internal_) 5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int free_slot = 0; 5584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) for (int index = 1; index <= internal_->max_counters(); index++) { 5594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) char* row_name = internal_->counter_name(index); 5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!*row_name && !free_slot) 5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) free_slot = index; // save that we found a free slot 5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else if (!strncmp(row_name, name.c_str(), kMaxCounterNameLength)) 5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return index; 5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return free_slot; 5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int StatsTable::AddCounter(const std::string& name) { 5694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (!internal_) 5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int counter_id = 0; 5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { 5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // To add a counter to the shared memory, we need the 5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // shared memory lock. 576a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) SharedMemoryAutoLockDeprecated lock(internal_->shared_memory()); 5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We have space, so create a new counter. 5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) counter_id = FindCounterOrEmptyRow(name); 5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!counter_id) 5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string counter_name = name; 5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (name.empty()) 5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) counter_name = kUnknownName; 5864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) strlcpy(internal_->counter_name(counter_id), counter_name.c_str(), 5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kMaxCounterNameLength); 5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // now add to our in-memory cache 5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { 5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AutoLock lock(counters_lock_); 5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) counters_[name] = counter_id; 5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return counter_id; 5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)StatsTable::TLSData* StatsTable::GetTLSData() const { 5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TLSData* data = 6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static_cast<TLSData*>(tls_index_.Get()); 6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!data) 6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(data->slot); 6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_EQ(data->table, this); 6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return data; 6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#if defined(OS_POSIX) 6104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)SharedMemoryHandle StatsTable::GetSharedMemoryHandle() const { 6114e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (!internal_) 6124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return SharedMemory::NULLHandle(); 6134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return internal_->shared_memory()->handle(); 6144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 6154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#endif 6164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace base 618