1 // Copyright (c) 2007, Google Inc. 2 // All rights reserved. 3 // 4 // Redistribution and use in source and binary forms, with or without 5 // modification, are permitted provided that the following conditions are 6 // met: 7 // 8 // * Redistributions of source code must retain the above copyright 9 // notice, this list of conditions and the following disclaimer. 10 // * Redistributions in binary form must reproduce the above 11 // copyright notice, this list of conditions and the following disclaimer 12 // in the documentation and/or other materials provided with the 13 // distribution. 14 // * Neither the name of Google Inc. nor the names of its 15 // contributors may be used to endorse or promote products derived from 16 // this software without specific prior written permission. 17 // 18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 // 30 // --- 31 // Author: Sanjay Ghemawat 32 // Chris Demetriou (refactoring) 33 // 34 // Collect profiling data. 35 // 36 // The profile data file format is documented in 37 // doc/cpuprofile-fileformat.html 38 39 40 #ifndef BASE_PROFILEDATA_H_ 41 #define BASE_PROFILEDATA_H_ 42 43 #include <config.h> 44 #include <time.h> // for time_t 45 #include <stdint.h> 46 #include "base/basictypes.h" 47 48 // A class that accumulates profile samples and writes them to a file. 49 // 50 // Each sample contains a stack trace and a count. Memory usage is 51 // reduced by combining profile samples that have the same stack trace 52 // by adding up the associated counts. 53 // 54 // Profile data is accumulated in a bounded amount of memory, and will 55 // flushed to a file as necessary to stay within the memory limit. 56 // 57 // Use of this class assumes external synchronization. The exact 58 // requirements of that synchronization are that: 59 // 60 // - 'Add' may be called from asynchronous signals, but is not 61 // re-entrant. 62 // 63 // - None of 'Start', 'Stop', 'Reset', 'Flush', and 'Add' may be 64 // called at the same time. 65 // 66 // - 'Start', 'Stop', or 'Reset' should not be called while 'Enabled' 67 // or 'GetCurrent' are running, and vice versa. 68 // 69 // A profiler which uses asyncronous signals to add samples will 70 // typically use two locks to protect this data structure: 71 // 72 // - A SpinLock which is held over all calls except for the 'Add' 73 // call made from the signal handler. 74 // 75 // - A SpinLock which is held over calls to 'Start', 'Stop', 'Reset', 76 // 'Flush', and 'Add'. (This SpinLock should be acquired after 77 // the first SpinLock in all cases where both are needed.) 78 class ProfileData { 79 public: 80 struct State { 81 bool enabled; // Is profiling currently enabled? 82 time_t start_time; // If enabled, when was profiling started? 83 char profile_name[1024]; // Name of file being written, or '\0' 84 int samples_gathered; // Number of samples gathered to far (or 0) 85 }; 86 87 class Options { 88 public: 89 Options(); 90 91 // Get and set the sample frequency. frequency()92 int frequency() const { 93 return frequency_; 94 } set_frequency(int frequency)95 void set_frequency(int frequency) { 96 frequency_ = frequency; 97 } 98 99 private: 100 int frequency_; // Sample frequency. 101 }; 102 103 static const int kMaxStackDepth = 64; // Max stack depth stored in profile 104 105 ProfileData(); 106 ~ProfileData(); 107 108 // If data collection is not already enabled start to collect data 109 // into fname. Parameters related to this profiling run are specified 110 // by 'options'. 111 // 112 // Returns true if data collection could be started, otherwise (if an 113 // error occurred or if data collection was already enabled) returns 114 // false. 115 bool Start(const char *fname, const Options& options); 116 117 // If data collection is enabled, stop data collection and write the 118 // data to disk. 119 void Stop(); 120 121 // Stop data collection without writing anything else to disk, and 122 // discard any collected data. 123 void Reset(); 124 125 // If data collection is enabled, record a sample with 'depth' 126 // entries from 'stack'. (depth must be > 0.) At most 127 // kMaxStackDepth stack entries will be recorded, starting with 128 // stack[0]. 129 // 130 // This function is safe to call from asynchronous signals (but is 131 // not re-entrant). 132 void Add(int depth, const void* const* stack); 133 134 // If data collection is enabled, write the data to disk (and leave 135 // the collector enabled). 136 void FlushTable(); 137 138 // Is data collection currently enabled? enabled()139 bool enabled() const { return out_ >= 0; } 140 141 // Get the current state of the data collector. 142 void GetCurrentState(State* state) const; 143 144 private: 145 static const int kAssociativity = 4; // For hashtable 146 static const int kBuckets = 1 << 10; // For hashtable 147 static const int kBufferLength = 1 << 18; // For eviction buffer 148 149 // Type of slots: each slot can be either a count, or a PC value 150 typedef uintptr_t Slot; 151 152 // Hash-table/eviction-buffer entry (a.k.a. a sample) 153 struct Entry { 154 Slot count; // Number of hits 155 Slot depth; // Stack depth 156 Slot stack[kMaxStackDepth]; // Stack contents 157 }; 158 159 // Hash table bucket 160 struct Bucket { 161 Entry entry[kAssociativity]; 162 }; 163 164 Bucket* hash_; // hash table 165 Slot* evict_; // evicted entries 166 int num_evicted_; // how many evicted entries? 167 int out_; // fd for output file. 168 int count_; // How many samples recorded 169 int evictions_; // How many evictions 170 size_t total_bytes_; // How much output 171 char* fname_; // Profile file name 172 time_t start_time_; // Start time, or 0 173 174 // Move 'entry' to the eviction buffer. 175 void Evict(const Entry& entry); 176 177 // Write contents of eviction buffer to disk. 178 void FlushEvicted(); 179 180 DISALLOW_COPY_AND_ASSIGN(ProfileData); 181 }; 182 183 #endif // BASE_PROFILEDATA_H_ 184