DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Implementation

Mercurial (d38398e5144e)

VCS Links

AllocEntry

AllocEvent

AutoMPLock

MemoryProfiler

ProfilerForJSContext

ProfilerImpl

Macros

Line Code
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