• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 //
5 // A StatsTable is a table of statistics.  It can be used across multiple
6 // processes and threads, maintaining cheap statistics counters without
7 // locking.
8 //
9 // The goal is to make it very cheap and easy for developers to add
10 // counters to code, without having to build one-off utilities or mechanisms
11 // to track the counters, and also to allow a single "view" to display
12 // the contents of all counters.
13 //
14 // To achieve this, StatsTable creates a shared memory segment to store
15 // the data for the counters.  Upon creation, it has a specific size
16 // which governs the maximum number of counters and concurrent
17 // threads/processes which can use it.
18 //
19 
20 #ifndef BASE_METRICS_STATS_TABLE_H_
21 #define BASE_METRICS_STATS_TABLE_H_
22 
23 #include <string>
24 
25 #include "base/base_export.h"
26 #include "base/basictypes.h"
27 #include "base/containers/hash_tables.h"
28 #include "base/memory/shared_memory.h"
29 #include "base/synchronization/lock.h"
30 #include "base/threading/thread_local_storage.h"
31 #include "build/build_config.h"
32 
33 #if defined(OS_POSIX)
34 #include "base/file_descriptor_posix.h"
35 #endif
36 
37 namespace base {
38 
39 class BASE_EXPORT StatsTable {
40  public:
41   // Identifies a StatsTable. We often want to share these between processes.
42   //
43   // On Windows, we use a named shared memory segment so the table identifier
44   // should be a relatively unique string identifying the table to use. An
45   // empty string can be used to use an anonymous shared memory segment for
46   // cases where the table does not need to be shared between processes.
47   //
48   // Posix does not support named memory so we explicitly share file
49   // descriptors. On Posix, pass a default-constructed file descriptor if a
50   // handle doesn't already exist, and a new one will be created.
51   //
52   // If a table doesn't already exist with the given identifier, a new one will
53   // be created with zeroed counters.
54 #if defined(OS_POSIX)
55   typedef FileDescriptor TableIdentifier;
56 #elif defined(OS_WIN)
57   typedef std::string TableIdentifier;
58 #endif
59 
60   // Create a new StatsTable.
61   //
62   // max_threads is the maximum number of threads the table will support.
63   // If the StatsTable already exists, this number is ignored.
64   //
65   // max_counters is the maximum number of counters the table will support.
66   // If the StatsTable already exists, this number is ignored.
67   StatsTable(const TableIdentifier& table,
68              int max_threads,
69              int max_counters);
70 
71   // Destroys the StatsTable.  When the last StatsTable is destroyed
72   // (across all processes), the StatsTable is removed from disk.
73   ~StatsTable();
74 
75   // For convenience, we create a static table.  This is generally
76   // used automatically by the counters.
77   static StatsTable* current();
78 
79   // Set the global table for use in this process.
80   static void set_current(StatsTable* value);
81 
82   // Get the slot id for the calling thread. Returns 0 if no
83   // slot is assigned.
84   int GetSlot() const;
85 
86   // All threads that contribute data to the table must register with the
87   // table first.  This function will set thread local storage for the
88   // thread containing the location in the table where this thread will
89   // write its counter data.
90   //
91   // name is just a debugging tag to label the thread, and it does not
92   // need to be unique.  It will be truncated to kMaxThreadNameLength-1
93   // characters.
94   //
95   // On success, returns the slot id for this thread.  On failure,
96   // returns 0.
97   int RegisterThread(const std::string& name);
98 
99   // Returns the number of threads currently registered.  This is really not
100   // useful except for diagnostics and debugging.
101   int CountThreadsRegistered() const;
102 
103   // Find a counter in the StatsTable.
104   //
105   // Returns an id for the counter which can be used to call GetLocation().
106   // If the counter does not exist, attempts to create a row for the new
107   // counter.  If there is no space in the table for the new counter,
108   // returns 0.
109   int FindCounter(const std::string& name);
110 
111   // TODO(mbelshe): implement RemoveCounter.
112 
113   // Gets the location of a particular value in the table based on
114   // the counter id and slot id.
115   int* GetLocation(int counter_id, int slot_id) const;
116 
117   // Gets the counter name at a particular row.  If the row is empty,
118   // returns NULL.
119   const char* GetRowName(int index) const;
120 
121   // Gets the sum of the values for a particular row.
122   int GetRowValue(int index) const;
123 
124   // Gets the sum of the values for a particular row for a given pid.
125   int GetRowValue(int index, int pid) const;
126 
127   // Gets the sum of the values for a particular counter.  If the counter
128   // does not exist, creates the counter.
129   int GetCounterValue(const std::string& name);
130 
131   // Gets the sum of the values for a particular counter for a given pid.
132   // If the counter does not exist, creates the counter.
133   int GetCounterValue(const std::string& name, int pid);
134 
135   // The maxinum number of counters/rows in the table.
136   int GetMaxCounters() const;
137 
138   // The maxinum number of threads/columns in the table.
139   int GetMaxThreads() const;
140 
141 #if defined(OS_POSIX)
142   // Get the underlying shared memory handle for the table.
143   base::SharedMemoryHandle GetSharedMemoryHandle() const;
144 #endif
145 
146   // The maximum length (in characters) of a Thread's name including
147   // null terminator, as stored in the shared memory.
148   static const int kMaxThreadNameLength = 32;
149 
150   // The maximum length (in characters) of a Counter's name including
151   // null terminator, as stored in the shared memory.
152   static const int kMaxCounterNameLength = 64;
153 
154   // Convenience function to lookup a counter location for a
155   // counter by name for the calling thread.  Will register
156   // the thread if it is not already registered.
157   static int* FindLocation(const char *name);
158 
159  private:
160   class Internal;
161   struct TLSData;
162   typedef hash_map<std::string, int> CountersMap;
163 
164   // Returns the space occupied by a thread in the table.  Generally used
165   // if a thread terminates but the process continues.  This function
166   // does not zero out the thread's counters.
167   // Cannot be used inside a posix tls destructor.
168   void UnregisterThread();
169 
170   // This variant expects the tls data to be passed in, so it is safe to
171   // call from inside a posix tls destructor (see doc for pthread_key_create).
172   void UnregisterThread(TLSData* tls_data);
173 
174   // The SlotReturnFunction is called at thread exit for each thread
175   // which used the StatsTable.
176   static void SlotReturnFunction(void* data);
177 
178   // Locates a free slot in the table.  Returns a number > 0 on success,
179   // or 0 on failure.  The caller must hold the shared_memory lock when
180   // calling this function.
181   int FindEmptyThread() const;
182 
183   // Locates a counter in the table or finds an empty row.  Returns a
184   // number > 0 on success, or 0 on failure.  The caller must hold the
185   // shared_memory_lock when calling this function.
186   int FindCounterOrEmptyRow(const std::string& name) const;
187 
188   // Internal function to add a counter to the StatsTable.  Assumes that
189   // the counter does not already exist in the table.
190   //
191   // name is a unique identifier for this counter, and will be truncated
192   // to kMaxCounterNameLength-1 characters.
193   //
194   // On success, returns the counter_id for the newly added counter.
195   // On failure, returns 0.
196   int AddCounter(const std::string& name);
197 
198   // Get the TLS data for the calling thread.  Returns NULL if none is
199   // initialized.
200   TLSData* GetTLSData() const;
201 
202   Internal* internal_;
203 
204   // The counters_lock_ protects the counters_ hash table.
205   base::Lock counters_lock_;
206 
207   // The counters_ hash map is an in-memory hash of the counters.
208   // It is used for quick lookup of counters, but is cannot be used
209   // as a substitute for what is in the shared memory.  Even though
210   // we don't have a counter in our hash table, another process may
211   // have created it.
212   CountersMap counters_;
213   ThreadLocalStorage::Slot tls_index_;
214 
215   DISALLOW_COPY_AND_ASSIGN(StatsTable);
216 };
217 
218 }  // namespace base
219 
220 #endif  // BASE_METRICS_STATS_TABLE_H_
221