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