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 { ProfilerForJSContextProfilerForJSContext34 ProfilerForJSContext() 35 : mProfiler(nullptr) 36 , mEnabled(false) 37 {} 38 GCHeapProfilerImpl* mProfiler; 39 bool mEnabled; 40 }; 41 using JSContextProfilerMap = 42 nsDataHashtable<nsClearingPtrHashKey<JSContext>, ProfilerForJSContext>; 43 44 class MemoryProfiler final : public nsIMemoryProfiler 45 { 46 public: 47 NS_DECL_ISUPPORTS 48 NS_DECL_NSIMEMORYPROFILER 49 50 private: 51 static void InitOnce(); ~MemoryProfiler()52 ~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 AllocEventAllocEvent72 AllocEvent(uint32_t aTraceIdx, int32_t aSize, TimeStamp aTimestamp) 73 : mTimestamp(aTimestamp) 74 , mTraceIdx(aTraceIdx) 75 , mSize(aSize) 76 {} 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. AllocEntryAllocEntry86 AllocEntry() 87 : mEventIdx(0) 88 , mMarked(false) 89 {} AllocEntryAllocEntry90 explicit AllocEntry(int aEventIdx) 91 : mEventIdx(aEventIdx) 92 , mMarked(false) 93 {} 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: AutoMPLock(PRLock * aLock)141 explicit AutoMPLock(PRLock* aLock) 142 { 143 MOZ_ASSERT(aLock); 144 mLock = aLock; 145 PR_Lock(mLock); 146 } 147 ~AutoMPLock()148 ~AutoMPLock() 149 { 150 PR_Unlock(mLock); 151 } 152 153 private: 154 PRLock* mLock; 155 }; 156 157 } // namespace mozilla 158 159 #endif 160