Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set ts=2 et sw=2 tw=80: */
3 : /* This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this file,
5 : * You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : #ifndef tools_profiler_MemoryProfiler_h
8 : #define tools_profiler_MemoryProfiler_h
9 :
10 : #include "nsIMemoryProfiler.h"
11 :
12 : #include "mozilla/StaticPtr.h"
13 : #include "mozilla/TimeStamp.h"
14 :
15 : #include "CompactTraceTable.h"
16 : #include "nsTArray.h"
17 : #include "prlock.h"
18 :
19 : #define MEMORY_PROFILER_CID \
20 : { 0xf976eaa2, 0xcc1f, 0x47ee, \
21 : { 0x81, 0x29, 0xb8, 0x26, 0x2a, 0x3d, 0xb6, 0xb2 } }
22 :
23 : #define MEMORY_PROFILER_CONTRACT_ID "@mozilla.org/tools/memory-profiler;1"
24 :
25 : struct PRLock;
26 :
27 : namespace mozilla {
28 :
29 : class NativeProfilerImpl;
30 : class GCHeapProfilerImpl;
31 :
32 : struct ProfilerForJSContext
33 : {
34 0 : ProfilerForJSContext()
35 0 : : mProfiler(nullptr)
36 0 : , mEnabled(false)
37 0 : {}
38 : GCHeapProfilerImpl* mProfiler;
39 : bool mEnabled;
40 : };
41 : using JSContextProfilerMap =
42 : nsDataHashtable<nsClearingPtrHashKey<JSContext>, ProfilerForJSContext>;
43 :
44 0 : class MemoryProfiler final : public nsIMemoryProfiler
45 : {
46 : public:
47 : NS_DECL_ISUPPORTS
48 : NS_DECL_NSIMEMORYPROFILER
49 :
50 : private:
51 : static void InitOnce();
52 0 : ~MemoryProfiler() {}
53 :
54 : // The accesses to other static member are guarded by sLock and
55 : // sProfileContextCount.
56 : static PRLock* sLock;
57 : static uint32_t sProfileContextCount;
58 :
59 : static StaticAutoPtr<NativeProfilerImpl> sNativeProfiler;
60 : static StaticAutoPtr<JSContextProfilerMap> sJSContextProfilerMap;
61 : static TimeStamp sStartTime;
62 : };
63 :
64 : // Allocation events to be reported.
65 : struct AllocEvent {
66 : TimeStamp mTimestamp;
67 : // index to a stacktrace singleton.
68 : uint32_t mTraceIdx;
69 : // Allocation size
70 : int32_t mSize;
71 :
72 0 : AllocEvent(uint32_t aTraceIdx, int32_t aSize, TimeStamp aTimestamp)
73 0 : : mTimestamp(aTimestamp)
74 : , mTraceIdx(aTraceIdx)
75 0 : , mSize(aSize)
76 0 : {}
77 : };
78 :
79 : // Index to allocation events but also a mark bit to be GC-able.
80 : struct AllocEntry {
81 : uint32_t mEventIdx : 31;
82 : bool mMarked : 1;
83 :
84 : // Default constructor for uninitialized stack value required by
85 : // getter methods.
86 0 : AllocEntry()
87 0 : : mEventIdx(0)
88 0 : , mMarked(false)
89 0 : {}
90 0 : explicit AllocEntry(int aEventIdx)
91 0 : : mEventIdx(aEventIdx)
92 0 : , mMarked(false)
93 0 : {}
94 : };
95 :
96 : using AllocMap = nsDataHashtable<nsClearingVoidPtrHashKey, AllocEntry>;
97 :
98 : class ProfilerImpl
99 : {
100 : public:
101 : static nsTArray<nsCString> GetStacktrace();
102 : static double DRandom();
103 :
104 : ProfilerImpl();
105 : virtual nsTArray<nsCString> GetNames() const = 0;
106 : virtual nsTArray<TrieNode> GetTraces() const = 0;
107 : virtual const nsTArray<AllocEvent>& GetEvents() const = 0;
108 :
109 : protected:
110 : /**
111 : * The sampler generates a random variable which conforms to a geometric
112 : * distribution of probability p = 1 / mSampleSize to calculate the
113 : * next-to-be-sampled byte directly; It avoids rolling a dice on each byte.
114 : *
115 : * Let Bn denote a Bernoulli process with first success on n-th trial, the
116 : * cumulative distribution function of Bn is Cn = 1 - (1 - p) ^ n.
117 : * Let U denote a uniformly distributed random variable in [0, 1).
118 : * A geometric random variable can be generated by Cn's reverse function:
119 : * G = floor(log(1 - U) / log(1 - p)).
120 : *
121 : * @param aSize the number of bytes seen
122 : * @return the number of events sampled
123 : */
124 : size_t AddBytesSampled(uint32_t aBytes);
125 :
126 : uint32_t mSampleSize;
127 :
128 : private:
129 : uint32_t mRemainingBytes;
130 : double mLog1minusP;
131 : };
132 :
133 : /*
134 : * This class is used to make sure the profile data is only accessed
135 : * on one thread at a time. Don't use mozilla::Mutex because we don't
136 : * want to allocate memory.
137 : */
138 : class AutoMPLock
139 : {
140 : public:
141 0 : explicit AutoMPLock(PRLock* aLock)
142 0 : {
143 0 : MOZ_ASSERT(aLock);
144 0 : mLock = aLock;
145 0 : PR_Lock(mLock);
146 0 : }
147 :
148 0 : ~AutoMPLock()
149 0 : {
150 0 : PR_Unlock(mLock);
151 0 : }
152 :
153 : private:
154 : PRLock* mLock;
155 : };
156 :
157 : } // namespace mozilla
158 :
159 : #endif
|