Home | History | Annotate | Download | only in base
      1 // Copyright (c) 2006-2008 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_STATS_TABLE_H__
     21 #define BASE_STATS_TABLE_H__
     22 
     23 #include <string>
     24 #include "base/basictypes.h"
     25 #include "base/hash_tables.h"
     26 #include "base/lock.h"
     27 #include "base/thread_local_storage.h"
     28 
     29 class StatsTablePrivate;
     30 
     31 namespace {
     32 struct StatsTableTLSData;
     33 }
     34 
     35 class StatsTable {
     36  public:
     37   // Create a new StatsTable.
     38   // If a StatsTable already exists with the specified name, this StatsTable
     39   // will use the same shared memory segment as the original.  Otherwise,
     40   // a new StatsTable is created and all counters are zeroed.
     41   //
     42   // name is the name of the StatsTable to use.
     43   //
     44   // max_threads is the maximum number of threads the table will support.
     45   // If the StatsTable already exists, this number is ignored.
     46   //
     47   // max_counters is the maximum number of counters the table will support.
     48   // If the StatsTable already exists, this number is ignored.
     49   StatsTable(const std::string& name, int max_threads, int max_counters);
     50 
     51   // Destroys the StatsTable.  When the last StatsTable is destroyed
     52   // (across all processes), the StatsTable is removed from disk.
     53   ~StatsTable();
     54 
     55   // For convenience, we create a static table.  This is generally
     56   // used automatically by the counters.
     57   static StatsTable* current() { return global_table_; }
     58 
     59   // Set the global table for use in this process.
     60   static void set_current(StatsTable* value) { global_table_ = value; }
     61 
     62   // Get the slot id for the calling thread. Returns 0 if no
     63   // slot is assigned.
     64   int GetSlot() const;
     65 
     66   // All threads that contribute data to the table must register with the
     67   // table first.  This function will set thread local storage for the
     68   // thread containing the location in the table where this thread will
     69   // write its counter data.
     70   //
     71   // name is just a debugging tag to label the thread, and it does not
     72   // need to be unique.  It will be truncated to kMaxThreadNameLength-1
     73   // characters.
     74   //
     75   // On success, returns the slot id for this thread.  On failure,
     76   // returns 0.
     77   int RegisterThread(const std::string& name);
     78 
     79   // Returns the number of threads currently registered.  This is really not
     80   // useful except for diagnostics and debugging.
     81   int CountThreadsRegistered() const;
     82 
     83   // Find a counter in the StatsTable.
     84   //
     85   // Returns an id for the counter which can be used to call GetLocation().
     86   // If the counter does not exist, attempts to create a row for the new
     87   // counter.  If there is no space in the table for the new counter,
     88   // returns 0.
     89   int FindCounter(const std::string& name);
     90 
     91   // TODO(mbelshe): implement RemoveCounter.
     92 
     93   // Gets the location of a particular value in the table based on
     94   // the counter id and slot id.
     95   int* GetLocation(int counter_id, int slot_id) const;
     96 
     97   // Gets the counter name at a particular row.  If the row is empty,
     98   // returns NULL.
     99   const char* GetRowName(int index) const;
    100 
    101   // Gets the sum of the values for a particular row.
    102   int GetRowValue(int index) const;
    103 
    104   // Gets the sum of the values for a particular row for a given pid.
    105   int GetRowValue(int index, int pid) const;
    106 
    107   // Gets the sum of the values for a particular counter.  If the counter
    108   // does not exist, creates the counter.
    109   int GetCounterValue(const std::string& name);
    110 
    111   // Gets the sum of the values for a particular counter for a given pid.
    112   // If the counter does not exist, creates the counter.
    113   int GetCounterValue(const std::string& name, int pid);
    114 
    115   // The maxinum number of counters/rows in the table.
    116   int GetMaxCounters() const;
    117 
    118   // The maxinum number of threads/columns in the table.
    119   int GetMaxThreads() const;
    120 
    121   // The maximum length (in characters) of a Thread's name including
    122   // null terminator, as stored in the shared memory.
    123   static const int kMaxThreadNameLength = 32;
    124 
    125   // The maximum length (in characters) of a Counter's name including
    126   // null terminator, as stored in the shared memory.
    127   static const int kMaxCounterNameLength = 32;
    128 
    129   // Convenience function to lookup a counter location for a
    130   // counter by name for the calling thread.  Will register
    131   // the thread if it is not already registered.
    132   static int* FindLocation(const char *name);
    133 
    134  private:
    135   // Returns the space occupied by a thread in the table.  Generally used
    136   // if a thread terminates but the process continues.  This function
    137   // does not zero out the thread's counters.
    138   // Cannot be used inside a posix tls destructor.
    139   void UnregisterThread();
    140 
    141   // This variant expects the tls data to be passed in, so it is safe to
    142   // call from inside a posix tls destructor (see doc for pthread_key_create).
    143   void UnregisterThread(StatsTableTLSData* tls_data);
    144 
    145   // The SlotReturnFunction is called at thread exit for each thread
    146   // which used the StatsTable.
    147   static void SlotReturnFunction(void* data);
    148 
    149   // Locates a free slot in the table.  Returns a number > 0 on success,
    150   // or 0 on failure.  The caller must hold the shared_memory lock when
    151   // calling this function.
    152   int FindEmptyThread() const;
    153 
    154   // Locates a counter in the table or finds an empty row.  Returns a
    155   // number > 0 on success, or 0 on failure.  The caller must hold the
    156   // shared_memory_lock when calling this function.
    157   int FindCounterOrEmptyRow(const std::string& name) const;
    158 
    159   // Internal function to add a counter to the StatsTable.  Assumes that
    160   // the counter does not already exist in the table.
    161   //
    162   // name is a unique identifier for this counter, and will be truncated
    163   // to kMaxCounterNameLength-1 characters.
    164   //
    165   // On success, returns the counter_id for the newly added counter.
    166   // On failure, returns 0.
    167   int AddCounter(const std::string& name);
    168 
    169   // Get the TLS data for the calling thread.  Returns NULL if none is
    170   // initialized.
    171   StatsTableTLSData* GetTLSData() const;
    172 
    173   typedef base::hash_map<std::string, int> CountersMap;
    174 
    175   StatsTablePrivate* impl_;
    176   // The counters_lock_ protects the counters_ hash table.
    177   Lock counters_lock_;
    178   // The counters_ hash map is an in-memory hash of the counters.
    179   // It is used for quick lookup of counters, but is cannot be used
    180   // as a substitute for what is in the shared memory.  Even though
    181   // we don't have a counter in our hash table, another process may
    182   // have created it.
    183   CountersMap counters_;
    184   TLSSlot tls_index_;
    185 
    186   static StatsTable* global_table_;
    187 
    188   DISALLOW_EVIL_CONSTRUCTORS(StatsTable);
    189 };
    190 
    191 #endif  // BASE_STATS_TABLE_H__
    192