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