15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2007, Google Inc.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// All rights reserved.
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Redistribution and use in source and binary forms, with or without
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// modification, are permitted provided that the following conditions are
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// met:
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//     * Redistributions of source code must retain the above copyright
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// notice, this list of conditions and the following disclaimer.
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//     * Redistributions in binary form must reproduce the above
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// copyright notice, this list of conditions and the following disclaimer
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// in the documentation and/or other materials provided with the
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// distribution.
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//     * Neither the name of Google Inc. nor the names of its
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// contributors may be used to endorse or promote products derived from
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// this software without specific prior written permission.
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ---
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Author: Sanjay Ghemawat
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//         Chris Demetriou (refactoring)
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Collect profiling data.
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The profile data file format is documented in
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// doc/cpuprofile-fileformat.html
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef BASE_PROFILEDATA_H_
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define BASE_PROFILEDATA_H_
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <config.h>
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <time.h>   // for time_t
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdint.h>
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/basictypes.h"
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// A class that accumulates profile samples and writes them to a file.
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Each sample contains a stack trace and a count.  Memory usage is
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// reduced by combining profile samples that have the same stack trace
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// by adding up the associated counts.
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Profile data is accumulated in a bounded amount of memory, and will
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// flushed to a file as necessary to stay within the memory limit.
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this class assumes external synchronization.  The exact
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// requirements of that synchronization are that:
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//  - 'Add' may be called from asynchronous signals, but is not
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//    re-entrant.
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//  - None of 'Start', 'Stop', 'Reset', 'Flush', and 'Add' may be
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//    called at the same time.
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//  - 'Start', 'Stop', or 'Reset' should not be called while 'Enabled'
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//     or 'GetCurrent' are running, and vice versa.
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// A profiler which uses asyncronous signals to add samples will
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// typically use two locks to protect this data structure:
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//  - A SpinLock which is held over all calls except for the 'Add'
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//    call made from the signal handler.
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//  - A SpinLock which is held over calls to 'Start', 'Stop', 'Reset',
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//    'Flush', and 'Add'.  (This SpinLock should be acquired after
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//    the first SpinLock in all cases where both are needed.)
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class ProfileData {
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct State {
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool     enabled;             // Is profiling currently enabled?
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    time_t   start_time;          // If enabled, when was profiling started?
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    char     profile_name[1024];  // Name of file being written, or '\0'
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int      samples_gathered;    // Number of samples gathered to far (or 0)
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  class Options {
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   public:
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Options();
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Get and set the sample frequency.
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int frequency() const {
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return frequency_;
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    void set_frequency(int frequency) {
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      frequency_ = frequency;
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   private:
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int      frequency_;                  // Sample frequency.
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static const int kMaxStackDepth = 64;  // Max stack depth stored in profile
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ProfileData();
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ~ProfileData();
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If data collection is not already enabled start to collect data
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // into fname.  Parameters related to this profiling run are specified
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // by 'options'.
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Returns true if data collection could be started, otherwise (if an
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // error occurred or if data collection was already enabled) returns
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // false.
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool Start(const char *fname, const Options& options);
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If data collection is enabled, stop data collection and write the
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // data to disk.
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void Stop();
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Stop data collection without writing anything else to disk, and
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // discard any collected data.
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void Reset();
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If data collection is enabled, record a sample with 'depth'
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // entries from 'stack'.  (depth must be > 0.)  At most
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // kMaxStackDepth stack entries will be recorded, starting with
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // stack[0].
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This function is safe to call from asynchronous signals (but is
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // not re-entrant).
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void Add(int depth, const void* const* stack);
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If data collection is enabled, write the data to disk (and leave
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the collector enabled).
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void FlushTable();
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Is data collection currently enabled?
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool enabled() const { return out_ >= 0; }
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get the current state of the data collector.
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void GetCurrentState(State* state) const;
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static const int kAssociativity = 4;          // For hashtable
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static const int kBuckets = 1 << 10;          // For hashtable
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static const int kBufferLength = 1 << 18;     // For eviction buffer
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Type of slots: each slot can be either a count, or a PC value
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  typedef uintptr_t Slot;
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Hash-table/eviction-buffer entry (a.k.a. a sample)
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct Entry {
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Slot count;                  // Number of hits
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Slot depth;                  // Stack depth
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Slot stack[kMaxStackDepth];  // Stack contents
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Hash table bucket
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct Bucket {
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Entry entry[kAssociativity];
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Bucket*       hash_;          // hash table
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Slot*         evict_;         // evicted entries
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int           num_evicted_;   // how many evicted entries?
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int           out_;           // fd for output file.
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int           count_;         // How many samples recorded
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int           evictions_;     // How many evictions
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t        total_bytes_;   // How much output
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char*         fname_;         // Profile file name
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  time_t        start_time_;    // Start time, or 0
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Move 'entry' to the eviction buffer.
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void Evict(const Entry& entry);
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Write contents of eviction buffer to disk.
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void FlushEvicted();
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(ProfileData);
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif  // BASE_PROFILEDATA_H_
184