summaryrefslogtreecommitdiffstats
path: root/tools/memory-profiler/MemoryProfiler.h
blob: 85a378fb238acb02bbf5937f6c40f87c0e3dd347 (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
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef tools_profiler_MemoryProfiler_h
#define tools_profiler_MemoryProfiler_h

#include "nsIMemoryProfiler.h"

#include "mozilla/StaticPtr.h"
#include "mozilla/TimeStamp.h"

#include "CompactTraceTable.h"
#include "nsTArray.h"
#include "prlock.h"

#define MEMORY_PROFILER_CID                                     \
  { 0xf976eaa2, 0xcc1f, 0x47ee,                                 \
    { 0x81, 0x29, 0xb8, 0x26, 0x2a, 0x3d, 0xb6, 0xb2 } }

#define MEMORY_PROFILER_CONTRACT_ID "@mozilla.org/tools/memory-profiler;1"

struct PRLock;

namespace mozilla {

class NativeProfilerImpl;
class GCHeapProfilerImpl;

struct ProfilerForJSContext
{
  ProfilerForJSContext()
    : mProfiler(nullptr)
    , mEnabled(false)
  {}
  GCHeapProfilerImpl* mProfiler;
  bool mEnabled;
};
using JSContextProfilerMap =
  nsDataHashtable<nsClearingPtrHashKey<JSContext>, ProfilerForJSContext>;

class MemoryProfiler final : public nsIMemoryProfiler
{
public:
  NS_DECL_ISUPPORTS
  NS_DECL_NSIMEMORYPROFILER

private:
  static void InitOnce();
  ~MemoryProfiler() {}

  // The accesses to other static member are guarded by sLock and
  // sProfileContextCount.
  static PRLock* sLock;
  static uint32_t sProfileContextCount;

  static StaticAutoPtr<NativeProfilerImpl> sNativeProfiler;
  static StaticAutoPtr<JSContextProfilerMap> sJSContextProfilerMap;
  static TimeStamp sStartTime;
};

// Allocation events to be reported.
struct AllocEvent {
  TimeStamp mTimestamp;
  // index to a stacktrace singleton.
  uint32_t mTraceIdx;
  // Allocation size
  int32_t mSize;

  AllocEvent(uint32_t aTraceIdx, int32_t aSize, TimeStamp aTimestamp)
    : mTimestamp(aTimestamp)
    , mTraceIdx(aTraceIdx)
    , mSize(aSize)
  {}
};

// Index to allocation events but also a mark bit to be GC-able.
struct AllocEntry {
  uint32_t mEventIdx : 31;
  bool mMarked : 1;

  // Default constructor for uninitialized stack value required by
  // getter methods.
  AllocEntry()
    : mEventIdx(0)
    , mMarked(false)
  {}
  explicit AllocEntry(int aEventIdx)
    : mEventIdx(aEventIdx)
    , mMarked(false)
  {}
};

using AllocMap = nsDataHashtable<nsClearingVoidPtrHashKey, AllocEntry>;

class ProfilerImpl
{
public:
  static nsTArray<nsCString> GetStacktrace();
  static double DRandom();

  ProfilerImpl();
  virtual nsTArray<nsCString> GetNames() const = 0;
  virtual nsTArray<TrieNode> GetTraces() const = 0;
  virtual const nsTArray<AllocEvent>& GetEvents() const = 0;

protected:
  /**
   * The sampler generates a random variable which conforms to a geometric
   * distribution of probability p = 1 / mSampleSize to calculate the
   * next-to-be-sampled byte directly; It avoids rolling a dice on each byte.
   *
   * Let Bn denote a Bernoulli process with first success on n-th trial, the
   * cumulative distribution function of Bn is Cn = 1 - (1 - p) ^ n.
   * Let U denote a uniformly distributed random variable in [0, 1).
   * A geometric random variable can be generated by Cn's reverse function:
   * G = floor(log(1 - U) / log(1 - p)).
   *
   * @param aSize the number of bytes seen
   * @return the number of events sampled
   */
  size_t AddBytesSampled(uint32_t aBytes);

  uint32_t mSampleSize;

private:
  uint32_t mRemainingBytes;
  double mLog1minusP;
};

/*
 * This class is used to make sure the profile data is only accessed
 * on one thread at a time. Don't use mozilla::Mutex because we don't
 * want to allocate memory.
 */
class AutoMPLock
{
public:
  explicit AutoMPLock(PRLock* aLock)
  {
    MOZ_ASSERT(aLock);
    mLock = aLock;
    PR_Lock(mLock);
  }

  ~AutoMPLock()
  {
    PR_Unlock(mLock);
  }

private:
  PRLock* mLock;
};

} // namespace mozilla

#endif