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