summaryrefslogtreecommitdiff
path: root/src/profiledata.h
blob: 3521bac35b60c01cc9b8ef049cd1e0c93389968b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
// Copyright (c) 2007, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// ---
// Author: Sanjay Ghemawat
//         Chris Demetriou (refactoring)
//
// Collect profiling data.
//
// The profile data file format is documented in
// doc/cpuprofile-fileformat.html


#ifndef BASE_PROFILEDATA_H_
#define BASE_PROFILEDATA_H_

#include <config.h>
#include <time.h>   // for time_t
#include <stdint.h>
#include "base/basictypes.h"

// A class that accumulates profile samples and writes them to a file.
//
// Each sample contains a stack trace and a count.  Memory usage is
// reduced by combining profile samples that have the same stack trace
// by adding up the associated counts.
//
// Profile data is accumulated in a bounded amount of memory, and will
// flushed to a file as necessary to stay within the memory limit.
//
// Use of this class assumes external synchronization.  The exact
// requirements of that synchronization are that:
//
//  - 'Add' may be called from asynchronous signals, but is not
//    re-entrant.
//
//  - None of 'Start', 'Stop', 'Reset', 'Flush', and 'Add' may be
//    called at the same time.
//
//  - 'Start', 'Stop', or 'Reset' should not be called while 'Enabled'
//     or 'GetCurrent' are running, and vice versa.
//
// A profiler which uses asyncronous signals to add samples will
// typically use two locks to protect this data structure:
//
//  - A SpinLock which is held over all calls except for the 'Add'
//    call made from the signal handler.
//
//  - A SpinLock which is held over calls to 'Start', 'Stop', 'Reset',
//    'Flush', and 'Add'.  (This SpinLock should be acquired after
//    the first SpinLock in all cases where both are needed.)
class ProfileData {
 public:
  struct State {
    bool     enabled;             // Is profiling currently enabled?
    time_t   start_time;          // If enabled, when was profiling started?
    char     profile_name[1024];  // Name of file being written, or '\0'
    int      samples_gathered;    // Number of samples gathered to far (or 0)
  };

  class Options {
   public:
    Options();

    // Get and set the sample frequency.
    int frequency() const {
      return frequency_;
    }
    void set_frequency(int frequency) {
      frequency_ = frequency;
    }

   private:
    int      frequency_;                  // Sample frequency.
  };

  static const int kMaxStackDepth = 64;  // Max stack depth stored in profile

  ProfileData();
  ~ProfileData();

  // If data collection is not already enabled start to collect data
  // into fname.  Parameters related to this profiling run are specified
  // by 'options'.
  //
  // Returns true if data collection could be started, otherwise (if an
  // error occurred or if data collection was already enabled) returns
  // false.
  bool Start(const char *fname, const Options& options);

  // If data collection is enabled, stop data collection and write the
  // data to disk.
  void Stop();

  // Stop data collection without writing anything else to disk, and
  // discard any collected data.
  void Reset();

  // If data collection is enabled, record a sample with 'depth'
  // entries from 'stack'.  (depth must be > 0.)  At most
  // kMaxStackDepth stack entries will be recorded, starting with
  // stack[0].
  //
  // This function is safe to call from asynchronous signals (but is
  // not re-entrant).
  void Add(int depth, const void* const* stack);

  // If data collection is enabled, write the data to disk (and leave
  // the collector enabled).
  void FlushTable();

  // Is data collection currently enabled?
  bool enabled() const { return out_ >= 0; }

  // Get the current state of the data collector.
  void GetCurrentState(State* state) const;

 private:
  static const int kAssociativity = 4;          // For hashtable
  static const int kBuckets = 1 << 10;          // For hashtable
  static const int kBufferLength = 1 << 18;     // For eviction buffer

  // Type of slots: each slot can be either a count, or a PC value
  typedef uintptr_t Slot;

  // Hash-table/eviction-buffer entry (a.k.a. a sample)
  struct Entry {
    Slot count;                  // Number of hits
    Slot depth;                  // Stack depth
    Slot stack[kMaxStackDepth];  // Stack contents
  };

  // Hash table bucket
  struct Bucket {
    Entry entry[kAssociativity];
  };

  Bucket*       hash_;          // hash table
  Slot*         evict_;         // evicted entries
  int           num_evicted_;   // how many evicted entries?
  int           out_;           // fd for output file.
  int           count_;         // How many samples recorded
  int           evictions_;     // How many evictions
  size_t        total_bytes_;   // How much output
  char*         fname_;         // Profile file name
  time_t        start_time_;    // Start time, or 0

  // Move 'entry' to the eviction buffer.
  void Evict(const Entry& entry);

  // Write contents of eviction buffer to disk.
  void FlushEvicted();

  DISALLOW_COPY_AND_ASSIGN(ProfileData);
};

#endif  // BASE_PROFILEDATA_H_