mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1094552 (part 5) - DMD: choose the profiling mode at start-up. r=mccr8.
This patch moves profiling mode selection from post-processing (in dmd.py) to DMD start-up. This will make it easier to add new kinds of profiling, such as cumulative heap profiling. Specifically: - There's a new --mode option. |LiveWithReports| is the default, as it is currently. - dmd.py's --ignore-reports option is gone. - There's a new |mode| field in the JSON output. - Reports-related operations are now no-ops if DMD isn't in LiveWithReports mode. - Diffs are only allowed for output files that have the same mode. - A new function ResetEverything() replaces the SetSampleBelowSize() and ClearBlocks(), which were used by the test to change DMD options. - The tests in SmokeDMD.cpp are split up so they can be run multiple times, in different modes. The exact combinations of tests and modes has been changed a bit. --HG-- rename : memory/replace/dmd/test/full-reports-empty-expected.txt => memory/replace/dmd/test/full-empty-dark-matter-expected.txt rename : memory/replace/dmd/test/full-heap-empty-expected.txt => memory/replace/dmd/test/full-empty-live-expected.txt rename : memory/replace/dmd/test/full-heap-sampled-expected.txt => memory/replace/dmd/test/full-sampled-live-expected.txt rename : memory/replace/dmd/test/full-reports-unsampled1-expected.txt => memory/replace/dmd/test/full-unsampled1-dark-matter-expected.txt rename : memory/replace/dmd/test/full-heap-unsampled1-expected.txt => memory/replace/dmd/test/full-unsampled1-live-expected.txt rename : memory/replace/dmd/test/full-reports-unsampled2-expected.txt => memory/replace/dmd/test/full-unsampled2-dark-matter-expected.txt rename : memory/replace/dmd/test/script-diff-basic-expected.txt => memory/replace/dmd/test/script-diff-live-expected.txt rename : memory/replace/dmd/test/script-diff1.json => memory/replace/dmd/test/script-diff-live1.json rename : memory/replace/dmd/test/script-diff2.json => memory/replace/dmd/test/script-diff-live2.json extra : rebase_source : bf32cc4e0d82aa1a20ceb55e8ea259850b49cc06
This commit is contained in:
parent
d1bf866e67
commit
5b5d3c27bb
@ -305,9 +305,44 @@ class Options
|
||||
{}
|
||||
};
|
||||
|
||||
// DMD has several modes. These modes affect what data is recorded and
|
||||
// written to the output file, and the written data affects the
|
||||
// post-processing that dmd.py can do.
|
||||
//
|
||||
// Users specify the mode as soon as DMD starts. This leads to minimal memory
|
||||
// usage and log file size. It has the disadvantage that is inflexible -- if
|
||||
// you want to change modes you have to re-run DMD. But in practice changing
|
||||
// modes seems to be rare, so it's not much of a problem.
|
||||
//
|
||||
// An alternative possibility would be to always record and output *all* the
|
||||
// information needed for all modes. This would let you choose the mode when
|
||||
// running dmd.py, and so you could do multiple kinds of profiling on a
|
||||
// single DMD run. But if you are only interested in one of the simpler
|
||||
// modes, you'd pay the price of (a) increased memory usage and (b) *very*
|
||||
// large log files.
|
||||
//
|
||||
// Finally, another alternative possibility would be to do mode selection
|
||||
// partly at DMD startup or recording, and then partly in dmd.py. This would
|
||||
// give some extra flexibility at moderate memory and file size cost. But
|
||||
// certain mode pairs wouldn't work, which would be confusing.
|
||||
//
|
||||
enum Mode
|
||||
{
|
||||
// For each live block, this mode outputs: size (usable and slop),
|
||||
// allocation stack, and whether it's sampled. This mode is good for live
|
||||
// heap profiling.
|
||||
Live,
|
||||
|
||||
// Like "Live", but for each live block it also outputs: zero or more
|
||||
// report stacks. This mode is good for identifying where memory reporters
|
||||
// should be added. This is the default mode.
|
||||
DarkMatter
|
||||
};
|
||||
|
||||
char* mDMDEnvVar; // a saved copy, for later printing
|
||||
|
||||
NumOption<size_t> mSampleBelowSize;
|
||||
Mode mMode;
|
||||
NumOption<size_t> mSampleBelowSize;
|
||||
NumOption<uint32_t> mMaxFrames;
|
||||
bool mShowDumpStats;
|
||||
|
||||
@ -320,13 +355,14 @@ class Options
|
||||
public:
|
||||
explicit Options(const char* aDMDEnvVar);
|
||||
|
||||
bool IsLiveMode() const { return mMode == Live; }
|
||||
bool IsDarkMatterMode() const { return mMode == DarkMatter; }
|
||||
|
||||
const char* DMDEnvVar() const { return mDMDEnvVar; }
|
||||
|
||||
size_t SampleBelowSize() const { return mSampleBelowSize.mActual; }
|
||||
size_t MaxFrames() const { return mMaxFrames.mActual; }
|
||||
size_t ShowDumpStats() const { return mShowDumpStats; }
|
||||
|
||||
void SetSampleBelowSize(size_t aSize) { mSampleBelowSize.mActual = aSize; }
|
||||
};
|
||||
|
||||
static Options *gOptions;
|
||||
@ -401,8 +437,11 @@ public:
|
||||
bool IsLocked() { return mIsLocked; }
|
||||
};
|
||||
|
||||
// This lock must be held while manipulating global state, such as
|
||||
// gStackTraceTable, gLiveBlockTable, etc.
|
||||
// This lock must be held while manipulating global state such as
|
||||
// gStackTraceTable, gLiveBlockTable, etc. Note that gOptions is *not*
|
||||
// protected by this lock because it is only written to by Options(), which is
|
||||
// only invoked at start-up and in ResetEverything(), which is only used by
|
||||
// SmokeDMD.cpp.
|
||||
static Mutex* gStateLock = nullptr;
|
||||
|
||||
class AutoLockState
|
||||
@ -780,7 +819,8 @@ public:
|
||||
bool Tag() const { return bool(mUint & kTagMask); }
|
||||
};
|
||||
|
||||
// A live heap block.
|
||||
// A live heap block. Stores both basic data and data about reports, if we're
|
||||
// in DarkMatter mode.
|
||||
class LiveBlock
|
||||
{
|
||||
const void* mPtr;
|
||||
@ -788,6 +828,8 @@ class LiveBlock
|
||||
|
||||
// Ptr: |mAllocStackTrace| - stack trace where this block was allocated.
|
||||
// Tag bit 0: |mIsSampled| - was this block sampled? (if so, slop == 0).
|
||||
//
|
||||
// Only used in DarkMatter mode.
|
||||
TaggedPtr<const StackTrace* const>
|
||||
mAllocStackTrace_mIsSampled;
|
||||
|
||||
@ -801,6 +843,8 @@ class LiveBlock
|
||||
//
|
||||
// |mPtr| is used as the key in LiveBlockTable, so it's ok for this member
|
||||
// to be |mutable|.
|
||||
//
|
||||
// Only used in DarkMatter mode.
|
||||
mutable TaggedPtr<const StackTrace*> mReportStackTrace_mReportedOnAlloc[2];
|
||||
|
||||
public:
|
||||
@ -841,38 +885,45 @@ public:
|
||||
|
||||
const StackTrace* ReportStackTrace1() const
|
||||
{
|
||||
MOZ_ASSERT(gOptions->IsDarkMatterMode());
|
||||
return mReportStackTrace_mReportedOnAlloc[0].Ptr();
|
||||
}
|
||||
|
||||
const StackTrace* ReportStackTrace2() const
|
||||
{
|
||||
MOZ_ASSERT(gOptions->IsDarkMatterMode());
|
||||
return mReportStackTrace_mReportedOnAlloc[1].Ptr();
|
||||
}
|
||||
|
||||
bool ReportedOnAlloc1() const
|
||||
{
|
||||
MOZ_ASSERT(gOptions->IsDarkMatterMode());
|
||||
return mReportStackTrace_mReportedOnAlloc[0].Tag();
|
||||
}
|
||||
|
||||
bool ReportedOnAlloc2() const
|
||||
{
|
||||
MOZ_ASSERT(gOptions->IsDarkMatterMode());
|
||||
return mReportStackTrace_mReportedOnAlloc[1].Tag();
|
||||
}
|
||||
|
||||
void AddStackTracesToTable(StackTraceSet& aStackTraces) const
|
||||
{
|
||||
aStackTraces.put(AllocStackTrace()); // never null
|
||||
const StackTrace* st;
|
||||
if ((st = ReportStackTrace1())) { // may be null
|
||||
aStackTraces.put(st);
|
||||
}
|
||||
if ((st = ReportStackTrace2())) { // may be null
|
||||
aStackTraces.put(st);
|
||||
if (gOptions->IsDarkMatterMode()) {
|
||||
const StackTrace* st;
|
||||
if ((st = ReportStackTrace1())) { // may be null
|
||||
aStackTraces.put(st);
|
||||
}
|
||||
if ((st = ReportStackTrace2())) { // may be null
|
||||
aStackTraces.put(st);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t NumReports() const
|
||||
{
|
||||
MOZ_ASSERT(gOptions->IsDarkMatterMode());
|
||||
if (ReportStackTrace2()) {
|
||||
MOZ_ASSERT(ReportStackTrace1());
|
||||
return 2;
|
||||
@ -886,6 +937,7 @@ public:
|
||||
// This is |const| thanks to the |mutable| fields above.
|
||||
void Report(Thread* aT, bool aReportedOnAlloc) const
|
||||
{
|
||||
MOZ_ASSERT(gOptions->IsDarkMatterMode());
|
||||
// We don't bother recording reports after the 2nd one.
|
||||
uint32_t numReports = NumReports();
|
||||
if (numReports < 2) {
|
||||
@ -896,6 +948,7 @@ public:
|
||||
|
||||
void UnreportIfNotReportedOnAlloc() const
|
||||
{
|
||||
MOZ_ASSERT(gOptions->IsDarkMatterMode());
|
||||
if (!ReportedOnAlloc1() && !ReportedOnAlloc2()) {
|
||||
mReportStackTrace_mReportedOnAlloc[0].Set(nullptr, 0);
|
||||
mReportStackTrace_mReportedOnAlloc[1].Set(nullptr, 0);
|
||||
@ -1236,10 +1289,11 @@ Options::GetBool(const char* aArg, const char* aOptionName, bool* aValue)
|
||||
// prime size will explore all possible values of the alloc counter.
|
||||
//
|
||||
Options::Options(const char* aDMDEnvVar)
|
||||
: mDMDEnvVar(InfallibleAllocPolicy::strdup_(aDMDEnvVar)),
|
||||
mSampleBelowSize(4093, 100 * 100 * 1000),
|
||||
mMaxFrames(StackTrace::MaxFrames, StackTrace::MaxFrames),
|
||||
mShowDumpStats(false)
|
||||
: mDMDEnvVar(InfallibleAllocPolicy::strdup_(aDMDEnvVar))
|
||||
, mMode(DarkMatter)
|
||||
, mSampleBelowSize(4093, 100 * 100 * 1000)
|
||||
, mMaxFrames(StackTrace::MaxFrames, StackTrace::MaxFrames)
|
||||
, mShowDumpStats(false)
|
||||
{
|
||||
char* e = mDMDEnvVar;
|
||||
if (strcmp(e, "1") != 0) {
|
||||
@ -1265,7 +1319,13 @@ Options::Options(const char* aDMDEnvVar)
|
||||
// Handle arg
|
||||
long myLong;
|
||||
bool myBool;
|
||||
if (GetLong(arg, "--sample-below", 1, mSampleBelowSize.mMax, &myLong)) {
|
||||
if (strcmp(arg, "--mode=live") == 0) {
|
||||
mMode = Options::Live;
|
||||
} else if (strcmp(arg, "--mode=dark-matter") == 0) {
|
||||
mMode = Options::DarkMatter;
|
||||
|
||||
} else if (GetLong(arg, "--sample-below", 1, mSampleBelowSize.mMax,
|
||||
&myLong)) {
|
||||
mSampleBelowSize.mActual = myLong;
|
||||
|
||||
} else if (GetLong(arg, "--max-frames", 1, mMaxFrames.mMax, &myLong)) {
|
||||
@ -1298,6 +1358,8 @@ Options::BadArg(const char* aArg)
|
||||
StatusMsg("entries.\n");
|
||||
StatusMsg("\n");
|
||||
StatusMsg("The following options are allowed; defaults are shown in [].\n");
|
||||
StatusMsg(" --mode=<mode> Profiling mode [dark-matter]\n");
|
||||
StatusMsg(" where <mode> is one of: live, dark-matter\n");
|
||||
StatusMsg(" --sample-below=<1..%d> Sample blocks smaller than this [%d]\n",
|
||||
int(mSampleBelowSize.mMax),
|
||||
int(mSampleBelowSize.mDefault));
|
||||
@ -1374,13 +1436,13 @@ Init(const malloc_table_t* aMallocTable)
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// DMD reporting and unreporting
|
||||
// Block reporting and unreporting
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
static void
|
||||
ReportHelper(const void* aPtr, bool aReportedOnAlloc)
|
||||
{
|
||||
if (!aPtr) {
|
||||
if (!gOptions->IsDarkMatterMode() || !aPtr) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1416,12 +1478,9 @@ DMDFuncs::ReportOnAlloc(const void* aPtr)
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
// The version number of the output format. Increment this if you make
|
||||
// backwards-incompatible changes to the format.
|
||||
//
|
||||
// Version history:
|
||||
// - 1: The original format (bug 1044709).
|
||||
//
|
||||
static const int kOutputVersionNumber = 1;
|
||||
// backwards-incompatible changes to the format. See DMD.h for the version
|
||||
// history.
|
||||
static const int kOutputVersionNumber = 2;
|
||||
|
||||
// Note that, unlike most SizeOf* functions, this function does not take a
|
||||
// |mozilla::MallocSizeOf| argument. That's because those arguments are
|
||||
@ -1472,6 +1531,10 @@ DMDFuncs::SizeOf(Sizes* aSizes)
|
||||
void
|
||||
DMDFuncs::ClearReports()
|
||||
{
|
||||
if (!gOptions->IsDarkMatterMode()) {
|
||||
return;
|
||||
}
|
||||
|
||||
AutoLockState lock;
|
||||
|
||||
// Unreport all blocks that were marked reported by a memory reporter. This
|
||||
@ -1487,8 +1550,8 @@ class ToIdStringConverter MOZ_FINAL
|
||||
public:
|
||||
ToIdStringConverter() : mNextId(0) { mIdMap.init(512); }
|
||||
|
||||
// Converts a pointer to a unique ID. Reuses the existing ID for the pointer if
|
||||
// it's been seen before.
|
||||
// Converts a pointer to a unique ID. Reuses the existing ID for the pointer
|
||||
// if it's been seen before.
|
||||
const char* ToIdString(const void* aPtr)
|
||||
{
|
||||
uint32_t id;
|
||||
@ -1576,6 +1639,16 @@ AnalyzeImpl(UniquePtr<JSONWriteFunc> aWriter)
|
||||
writer.StartObjectProperty("invocation");
|
||||
{
|
||||
writer.StringProperty("dmdEnvVar", gOptions->DMDEnvVar());
|
||||
const char* mode;
|
||||
if (gOptions->IsLiveMode()) {
|
||||
mode = "live";
|
||||
} else if (gOptions->IsDarkMatterMode()) {
|
||||
mode = "dark-matter";
|
||||
} else {
|
||||
MOZ_ASSERT(false);
|
||||
mode = "(unknown DMD mode)";
|
||||
}
|
||||
writer.StringProperty("mode", mode);
|
||||
writer.IntProperty("sampleBelowSize", gOptions->SampleBelowSize());
|
||||
}
|
||||
writer.EndObject();
|
||||
@ -1599,7 +1672,8 @@ AnalyzeImpl(UniquePtr<JSONWriteFunc> aWriter)
|
||||
}
|
||||
}
|
||||
writer.StringProperty("alloc", isc.ToIdString(b.AllocStackTrace()));
|
||||
if (b.NumReports() > 0) {
|
||||
if (gOptions->IsDarkMatterMode() && b.NumReports() > 0) {
|
||||
MOZ_ASSERT(gOptions->IsDarkMatterMode());
|
||||
writer.StartArrayProperty("reps");
|
||||
{
|
||||
if (b.ReportStackTrace1()) {
|
||||
@ -1735,14 +1809,15 @@ DMDFuncs::Analyze(UniquePtr<JSONWriteFunc> aWriter)
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
void
|
||||
DMDFuncs::SetSampleBelowSize(size_t aSize)
|
||||
DMDFuncs::ResetEverything(const char* aOptions)
|
||||
{
|
||||
gOptions->SetSampleBelowSize(aSize);
|
||||
}
|
||||
AutoLockState lock;
|
||||
|
||||
void
|
||||
DMDFuncs::ClearBlocks()
|
||||
{
|
||||
// Reset options.
|
||||
InfallibleAllocPolicy::delete_(gOptions);
|
||||
gOptions = InfallibleAllocPolicy::new_<Options>(aOptions);
|
||||
|
||||
// Clear all existing blocks.
|
||||
gLiveBlockTable->clear();
|
||||
gSmallBlockActualSizeCounter = 0;
|
||||
}
|
||||
|
@ -51,9 +51,7 @@ struct DMDFuncs
|
||||
|
||||
virtual void StatusMsg(const char*, va_list);
|
||||
|
||||
virtual void SetSampleBelowSize(size_t);
|
||||
|
||||
virtual void ClearBlocks();
|
||||
virtual void ResetEverything(const char*);
|
||||
|
||||
#ifndef REPLACE_MALLOC_IMPL
|
||||
// We deliberately don't use ReplaceMalloc::GetDMDFuncs here, because if we
|
||||
@ -146,13 +144,21 @@ ClearReports()
|
||||
// {
|
||||
// // The version number of the format, which will be incremented each time
|
||||
// // backwards-incompatible changes are made. A mandatory integer.
|
||||
// "version": 1,
|
||||
// //
|
||||
// // Version history:
|
||||
// // - 1: The original format. Implemented in bug 1044709.
|
||||
// // - 2: Added the "mode" field under "invocation". Added in bug 1094552.
|
||||
// "version": 2,
|
||||
//
|
||||
// // Information about how DMD was invoked. A mandatory object.
|
||||
// "invocation": {
|
||||
// // The contents of the $DMD environment variable. A mandatory string.
|
||||
// "dmdEnvVar": "1",
|
||||
//
|
||||
// // The profiling mode. A mandatory string taking one of the following
|
||||
// // values: "live", "dark-matter".
|
||||
// "mode": "dark-matter",
|
||||
//
|
||||
// // The value of the --sample-below-size option. A mandatory integer.
|
||||
// "sampleBelowSize": 4093
|
||||
// },
|
||||
@ -182,8 +188,9 @@ ClearReports()
|
||||
// "alloc": "B",
|
||||
//
|
||||
// // One or more stack traces at which this heap block was reported by a
|
||||
// // memory reporter. An optional array. The elements are strings that
|
||||
// // index into the "traceTable" object.
|
||||
// // memory reporter. An optional array that will only be present in
|
||||
// // "dark-matter" mode. The elements are strings that index into
|
||||
// // the "traceTable" object.
|
||||
// "reps": ["C"]
|
||||
// }
|
||||
// ],
|
||||
@ -221,11 +228,13 @@ ClearReports()
|
||||
// "H": "#00: quuux (Quux.cpp:567)"
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// Implementation note: normally, this wouldn't be templated, but in that case,
|
||||
// the function is compiled, which makes the destructor for the UniquePtr fire
|
||||
// up, and that needs JSONWriteFunc to be fully defined. That, in turn,
|
||||
// requires to include JSONWriter.h, which includes double-conversion.h, which
|
||||
// ends up breaking various things built with -Werror for various reasons.
|
||||
//
|
||||
template <typename JSONWriteFunc>
|
||||
inline void
|
||||
Analyze(UniquePtr<JSONWriteFunc> aWriteFunc)
|
||||
@ -267,23 +276,15 @@ IsRunning()
|
||||
return !!DMDFuncs::Get();
|
||||
}
|
||||
|
||||
// Sets the sample-below size. Only used for testing purposes.
|
||||
// Resets all DMD options and then sets new ones according to those specified
|
||||
// in |aOptions|. Also clears all recorded data about allocations. Only used
|
||||
// for testing purposes.
|
||||
inline void
|
||||
SetSampleBelowSize(size_t aSize)
|
||||
ResetEverything(const char* aOptions)
|
||||
{
|
||||
DMDFuncs* funcs = DMDFuncs::Get();
|
||||
if (funcs) {
|
||||
funcs->SetSampleBelowSize(aSize);
|
||||
}
|
||||
}
|
||||
|
||||
// Clears all records of live allocations. Only used for testing purposes.
|
||||
inline void
|
||||
ClearBlocks()
|
||||
{
|
||||
DMDFuncs* funcs = DMDFuncs::Get();
|
||||
if (funcs) {
|
||||
funcs->ClearBlocks();
|
||||
funcs->ResetEverything(aOptions);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -20,7 +20,7 @@ import sys
|
||||
import tempfile
|
||||
|
||||
# The DMD output version this script handles.
|
||||
outputVersion = 1
|
||||
outputVersion = 2
|
||||
|
||||
# If --ignore-alloc-fns is specified, stack frames containing functions that
|
||||
# match these strings will be removed from the *start* of stack traces. (Once
|
||||
@ -184,10 +184,6 @@ variable is used to find breakpad symbols for stack fixing.
|
||||
p.add_argument('-f', '--max-frames', type=range_1_24,
|
||||
help='maximum number of frames to consider in each trace')
|
||||
|
||||
p.add_argument('-r', '--ignore-reports', action='store_true',
|
||||
help='ignore memory reports data; useful if you just ' +
|
||||
'want basic heap profiling')
|
||||
|
||||
p.add_argument('-s', '--sort-by', choices=sortByChoices.keys(),
|
||||
default=sortByChoices.keys()[0],
|
||||
help='sort the records by a particular metric')
|
||||
@ -278,11 +274,15 @@ def getDigestFromFile(args, inputFile):
|
||||
# Extract the main parts of the JSON object.
|
||||
invocation = j['invocation']
|
||||
dmdEnvVar = invocation['dmdEnvVar']
|
||||
mode = invocation['mode']
|
||||
sampleBelowSize = invocation['sampleBelowSize']
|
||||
blockList = j['blockList']
|
||||
traceTable = j['traceTable']
|
||||
frameTable = j['frameTable']
|
||||
|
||||
if not mode in ['live', 'dark-matter']:
|
||||
raise Exception("bad 'mode' property: '{:s}'".format(mode))
|
||||
|
||||
heapIsSampled = sampleBelowSize > 1 # is sampling present?
|
||||
|
||||
# Remove allocation functions at the start of traces.
|
||||
@ -336,9 +336,9 @@ def getDigestFromFile(args, inputFile):
|
||||
# Aggregate blocks into records. All sufficiently similar blocks go into a
|
||||
# single record.
|
||||
|
||||
if args.ignore_reports:
|
||||
if mode == 'live':
|
||||
liveRecords = collections.defaultdict(Record)
|
||||
else:
|
||||
elif mode == 'dark-matter':
|
||||
unreportedRecords = collections.defaultdict(Record)
|
||||
onceReportedRecords = collections.defaultdict(Record)
|
||||
twiceReportedRecords = collections.defaultdict(Record)
|
||||
@ -369,10 +369,10 @@ def getDigestFromFile(args, inputFile):
|
||||
traceTable[traceKey]))
|
||||
|
||||
allocatedAtTraceKey = block['alloc']
|
||||
if args.ignore_reports:
|
||||
if mode == 'live':
|
||||
recordKey = makeRecordKeyPart(allocatedAtTraceKey)
|
||||
records = liveRecords
|
||||
else:
|
||||
elif mode == 'dark-matter':
|
||||
recordKey = makeRecordKeyPart(allocatedAtTraceKey)
|
||||
if 'reps' in block:
|
||||
reportedAtTraceKeys = block['reps']
|
||||
@ -414,9 +414,9 @@ def getDigestFromFile(args, inputFile):
|
||||
buildTraceDescription(traceTable, frameTable,
|
||||
allocatedAtTraceKey)
|
||||
|
||||
if args.ignore_reports:
|
||||
if mode == 'live':
|
||||
pass
|
||||
else:
|
||||
elif mode == 'dark-matter':
|
||||
if 'reps' in block and record.reportedAtDescs == []:
|
||||
f = lambda k: buildTraceDescription(traceTable, frameTable, k)
|
||||
record.reportedAtDescs = map(f, reportedAtTraceKeys)
|
||||
@ -425,13 +425,14 @@ def getDigestFromFile(args, inputFile):
|
||||
# All the processed data for a single DMD file is called a "digest".
|
||||
digest = {}
|
||||
digest['dmdEnvVar'] = dmdEnvVar
|
||||
digest['mode'] = mode
|
||||
digest['sampleBelowSize'] = sampleBelowSize
|
||||
digest['heapUsableSize'] = heapUsableSize
|
||||
digest['heapBlocks'] = heapBlocks
|
||||
digest['heapIsSampled'] = heapIsSampled
|
||||
if args.ignore_reports:
|
||||
if mode == 'live':
|
||||
digest['liveRecords'] = liveRecords
|
||||
else:
|
||||
elif mode == 'dark-matter':
|
||||
digest['unreportedRecords'] = unreportedRecords
|
||||
digest['onceReportedRecords'] = onceReportedRecords
|
||||
digest['twiceReportedRecords'] = twiceReportedRecords
|
||||
@ -464,16 +465,20 @@ def diffRecords(args, records1, records2):
|
||||
|
||||
|
||||
def diffDigests(args, d1, d2):
|
||||
if (d1['mode'] != d2['mode']):
|
||||
raise Exception("the input files have different 'mode' properties")
|
||||
|
||||
d3 = {}
|
||||
d3['dmdEnvVar'] = (d1['dmdEnvVar'], d2['dmdEnvVar'])
|
||||
d3['mode'] = d1['mode']
|
||||
d3['sampleBelowSize'] = (d1['sampleBelowSize'], d2['sampleBelowSize'])
|
||||
d3['heapUsableSize'] = d2['heapUsableSize'] - d1['heapUsableSize']
|
||||
d3['heapBlocks'] = d2['heapBlocks'] - d1['heapBlocks']
|
||||
d3['heapIsSampled'] = d2['heapIsSampled'] or d1['heapIsSampled']
|
||||
if args.ignore_reports:
|
||||
if d1['mode'] == 'live':
|
||||
d3['liveRecords'] = diffRecords(args, d1['liveRecords'],
|
||||
d2['liveRecords'])
|
||||
else:
|
||||
elif d1['mode'] == 'dark-matter':
|
||||
d3['unreportedRecords'] = diffRecords(args, d1['unreportedRecords'],
|
||||
d2['unreportedRecords'])
|
||||
d3['onceReportedRecords'] = diffRecords(args, d1['onceReportedRecords'],
|
||||
@ -485,13 +490,14 @@ def diffDigests(args, d1, d2):
|
||||
|
||||
def printDigest(args, digest):
|
||||
dmdEnvVar = digest['dmdEnvVar']
|
||||
mode = digest['mode']
|
||||
sampleBelowSize = digest['sampleBelowSize']
|
||||
heapUsableSize = digest['heapUsableSize']
|
||||
heapIsSampled = digest['heapIsSampled']
|
||||
heapBlocks = digest['heapBlocks']
|
||||
if args.ignore_reports:
|
||||
if mode == 'live':
|
||||
liveRecords = digest['liveRecords']
|
||||
else:
|
||||
elif mode == 'dark-matter':
|
||||
unreportedRecords = digest['unreportedRecords']
|
||||
onceReportedRecords = digest['onceReportedRecords']
|
||||
twiceReportedRecords = digest['twiceReportedRecords']
|
||||
@ -583,9 +589,9 @@ def printDigest(args, digest):
|
||||
out(' {:4.2f}% of the heap ({:4.2f}% cumulative)'.
|
||||
format(perc(record.usableSize, heapUsableSize),
|
||||
perc(kindCumulativeUsableSize, heapUsableSize)))
|
||||
if args.ignore_reports:
|
||||
if mode == 'live':
|
||||
pass
|
||||
else:
|
||||
elif mode == 'dark-matter':
|
||||
out(' {:4.2f}% of {:} ({:4.2f}% cumulative)'.
|
||||
format(perc(record.usableSize, kindUsableSize),
|
||||
recordKind,
|
||||
@ -593,9 +599,9 @@ def printDigest(args, digest):
|
||||
out(' Allocated at {')
|
||||
printStack(record.allocatedAtDesc)
|
||||
out(' }')
|
||||
if args.ignore_reports:
|
||||
if mode == 'live':
|
||||
pass
|
||||
else:
|
||||
elif mode == 'dark-matter':
|
||||
for n, reportedAtDesc in enumerate(record.reportedAtDescs):
|
||||
again = 'again ' if n > 0 else ''
|
||||
out(' Reported {:}at {{'.format(again))
|
||||
@ -625,10 +631,10 @@ def printDigest(args, digest):
|
||||
printInvocation(' 2', dmdEnvVar[1], sampleBelowSize[1])
|
||||
|
||||
# Print records.
|
||||
if args.ignore_reports:
|
||||
if mode == 'live':
|
||||
liveUsableSize, liveBlocks = \
|
||||
printRecords('live', liveRecords, heapUsableSize)
|
||||
else:
|
||||
elif mode == 'dark-matter':
|
||||
twiceReportedUsableSize, twiceReportedBlocks = \
|
||||
printRecords('twice-reported', twiceReportedRecords, heapUsableSize)
|
||||
|
||||
@ -641,11 +647,11 @@ def printDigest(args, digest):
|
||||
# Print summary.
|
||||
out(separator)
|
||||
out('Summary {')
|
||||
if args.ignore_reports:
|
||||
if mode == 'live':
|
||||
out(' Total: {:} bytes in {:} blocks'.
|
||||
format(number(liveUsableSize, heapIsSampled),
|
||||
number(liveBlocks, heapIsSampled)))
|
||||
else:
|
||||
elif mode == 'dark-matter':
|
||||
fmt = ' {:15} {:>12} bytes ({:6.2f}%) in {:>7} blocks ({:6.2f}%)'
|
||||
out(fmt.
|
||||
format('Total:',
|
||||
|
@ -89,165 +89,160 @@ void Foo(int aSeven)
|
||||
}
|
||||
|
||||
void
|
||||
RunTests()
|
||||
TestEmpty(const char* aTestName, const char* aMode)
|
||||
{
|
||||
// These files are written to $CWD.
|
||||
auto f1 = MakeUnique<FpWriteFunc>("full-empty.json");
|
||||
auto f2 = MakeUnique<FpWriteFunc>("full-unsampled1.json");
|
||||
auto f3 = MakeUnique<FpWriteFunc>("full-unsampled2.json");
|
||||
auto f4 = MakeUnique<FpWriteFunc>("full-sampled.json");
|
||||
char filename[128];
|
||||
sprintf(filename, "full-%s-%s.json", aTestName, aMode);
|
||||
auto f = MakeUnique<FpWriteFunc>(filename);
|
||||
|
||||
// This test relies on the compiler not doing various optimizations, such as
|
||||
// eliding unused malloc() calls or unrolling loops with fixed iteration
|
||||
// counts. So we compile it with -O0 (or equivalent), which probably prevents
|
||||
// that. We also use the following variable for various loop iteration
|
||||
// counts, just in case compilers might unroll very small loops even with
|
||||
// -O0.
|
||||
int seven = 7;
|
||||
char options[128];
|
||||
sprintf(options, "--mode=%s --sample-below=1", aMode);
|
||||
ResetEverything(options);
|
||||
|
||||
// Make sure that DMD is actually running; it is initialized on the first
|
||||
// allocation.
|
||||
int *x = (int*)malloc(100);
|
||||
UseItOrLoseIt(x, seven);
|
||||
MOZ_RELEASE_ASSERT(IsRunning());
|
||||
// Zero for everything.
|
||||
Analyze(Move(f));
|
||||
}
|
||||
|
||||
// The first part of this test requires sampling to be disabled.
|
||||
SetSampleBelowSize(1);
|
||||
void
|
||||
TestUnsampled(const char* aTestName, int aNum, const char* aMode, int aSeven)
|
||||
{
|
||||
char filename[128];
|
||||
sprintf(filename, "full-%s%d-%s.json", aTestName, aNum, aMode);
|
||||
auto f = MakeUnique<FpWriteFunc>(filename);
|
||||
|
||||
// The file manipulations above may have done some heap allocations.
|
||||
// Clear all knowledge of existing blocks to give us a clean slate.
|
||||
ClearBlocks();
|
||||
// The --show-dump-stats=yes is there just to give that option some basic
|
||||
// testing, e.g. ensure it doesn't crash. It's hard to test much beyond that.
|
||||
char options[128];
|
||||
sprintf(options, "--mode=%s --sample-below=1 --show-dump-stats=yes", aMode);
|
||||
ResetEverything(options);
|
||||
|
||||
//---------
|
||||
|
||||
// Analyze 1. Zero for everything.
|
||||
Analyze(Move(f1));
|
||||
|
||||
//---------
|
||||
|
||||
// Analyze 2: 1 freed, 9 out of 10 unreported.
|
||||
// Analyze 3: still present and unreported.
|
||||
// Analyze 1: 1 freed, 9 out of 10 unreported.
|
||||
// Analyze 2: still present and unreported.
|
||||
int i;
|
||||
char* a = nullptr;
|
||||
for (i = 0; i < seven + 3; i++) {
|
||||
for (i = 0; i < aSeven + 3; i++) {
|
||||
a = (char*) malloc(100);
|
||||
UseItOrLoseIt(a, seven);
|
||||
UseItOrLoseIt(a, aSeven);
|
||||
}
|
||||
free(a);
|
||||
|
||||
// Note: 8 bytes is the smallest requested size that gives consistent
|
||||
// behaviour across all platforms with jemalloc.
|
||||
// Analyze 2: reported.
|
||||
// Analyze 3: thrice-reported.
|
||||
// Analyze 1: reported.
|
||||
// Analyze 2: thrice-reported.
|
||||
char* a2 = (char*) malloc(8);
|
||||
Report(a2);
|
||||
|
||||
// Analyze 2: reported.
|
||||
// Analyze 3: reportedness carries over, due to ReportOnAlloc.
|
||||
// Analyze 1: reported.
|
||||
// Analyze 2: reportedness carries over, due to ReportOnAlloc.
|
||||
char* b = (char*) malloc(10);
|
||||
ReportOnAlloc(b);
|
||||
|
||||
// ReportOnAlloc, then freed.
|
||||
// Analyze 1: freed, irrelevant.
|
||||
// Analyze 2: freed, irrelevant.
|
||||
// Analyze 3: freed, irrelevant.
|
||||
char* b2 = (char*) malloc(1);
|
||||
ReportOnAlloc(b2);
|
||||
free(b2);
|
||||
|
||||
// Analyze 2: reported 4 times.
|
||||
// Analyze 3: freed, irrelevant.
|
||||
// Analyze 1: reported 4 times.
|
||||
// Analyze 2: freed, irrelevant.
|
||||
char* c = (char*) calloc(10, 3);
|
||||
Report(c);
|
||||
for (int i = 0; i < seven - 4; i++) {
|
||||
for (int i = 0; i < aSeven - 4; i++) {
|
||||
Report(c);
|
||||
}
|
||||
|
||||
// Analyze 2: ignored.
|
||||
// Analyze 3: irrelevant.
|
||||
// Analyze 1: ignored.
|
||||
// Analyze 2: irrelevant.
|
||||
Report((void*)(intptr_t)i);
|
||||
|
||||
// jemalloc rounds this up to 8192.
|
||||
// Analyze 2: reported.
|
||||
// Analyze 3: freed.
|
||||
// Analyze 1: reported.
|
||||
// Analyze 2: freed.
|
||||
char* e = (char*) malloc(4096);
|
||||
e = (char*) realloc(e, 4097);
|
||||
Report(e);
|
||||
|
||||
// First realloc is like malloc; second realloc is shrinking.
|
||||
// Analyze 2: reported.
|
||||
// Analyze 3: re-reported.
|
||||
// Analyze 1: reported.
|
||||
// Analyze 2: re-reported.
|
||||
char* e2 = (char*) realloc(nullptr, 1024);
|
||||
e2 = (char*) realloc(e2, 512);
|
||||
Report(e2);
|
||||
|
||||
// First realloc is like malloc; second realloc creates a min-sized block.
|
||||
// XXX: on Windows, second realloc frees the block.
|
||||
// Analyze 2: reported.
|
||||
// Analyze 3: freed, irrelevant.
|
||||
// Analyze 1: reported.
|
||||
// Analyze 2: freed, irrelevant.
|
||||
char* e3 = (char*) realloc(nullptr, 1023);
|
||||
//e3 = (char*) realloc(e3, 0);
|
||||
MOZ_ASSERT(e3);
|
||||
Report(e3);
|
||||
|
||||
// Analyze 1: freed, irrelevant.
|
||||
// Analyze 2: freed, irrelevant.
|
||||
// Analyze 3: freed, irrelevant.
|
||||
char* f = (char*) malloc(64);
|
||||
free(f);
|
||||
char* f1 = (char*) malloc(64);
|
||||
free(f1);
|
||||
|
||||
// Analyze 2: ignored.
|
||||
// Analyze 3: irrelevant.
|
||||
// Analyze 1: ignored.
|
||||
// Analyze 2: irrelevant.
|
||||
Report((void*)(intptr_t)0x0);
|
||||
|
||||
// Analyze 2: mixture of reported and unreported.
|
||||
// Analyze 3: all unreported.
|
||||
Foo(seven);
|
||||
// Analyze 1: mixture of reported and unreported.
|
||||
// Analyze 2: all unreported.
|
||||
Foo(aSeven);
|
||||
|
||||
// Analyze 1: twice-reported.
|
||||
// Analyze 2: twice-reported.
|
||||
// Analyze 3: twice-reported.
|
||||
char* g1 = (char*) malloc(77);
|
||||
ReportOnAlloc(g1);
|
||||
ReportOnAlloc(g1);
|
||||
|
||||
// Analyze 2: mixture of reported and unreported.
|
||||
// Analyze 3: all unreported.
|
||||
// Analyze 1: mixture of reported and unreported.
|
||||
// Analyze 2: all unreported.
|
||||
// Nb: this Foo() call is deliberately not adjacent to the previous one. See
|
||||
// the comment about adjacent calls in Foo() for more details.
|
||||
Foo(seven);
|
||||
Foo(aSeven);
|
||||
|
||||
// Analyze 2: twice-reported.
|
||||
// Analyze 3: once-reported.
|
||||
// Analyze 1: twice-reported.
|
||||
// Analyze 2: once-reported.
|
||||
char* g2 = (char*) malloc(78);
|
||||
Report(g2);
|
||||
ReportOnAlloc(g2);
|
||||
|
||||
// Analyze 2: twice-reported.
|
||||
// Analyze 3: once-reported.
|
||||
// Analyze 1: twice-reported.
|
||||
// Analyze 2: once-reported.
|
||||
char* g3 = (char*) malloc(79);
|
||||
ReportOnAlloc(g3);
|
||||
Report(g3);
|
||||
|
||||
// All the odd-ball ones.
|
||||
// Analyze 2: all unreported.
|
||||
// Analyze 3: all freed, irrelevant.
|
||||
// Analyze 1: all unreported.
|
||||
// Analyze 2: all freed, irrelevant.
|
||||
// XXX: no memalign on Mac
|
||||
//void* w = memalign(64, 65); // rounds up to 128
|
||||
//UseItOrLoseIt(w, seven);
|
||||
//UseItOrLoseIt(w, aSeven);
|
||||
|
||||
// XXX: posix_memalign doesn't work on B2G
|
||||
//void* x;
|
||||
//posix_memalign(&y, 128, 129); // rounds up to 256
|
||||
//UseItOrLoseIt(x, seven);
|
||||
//UseItOrLoseIt(x, aSeven);
|
||||
|
||||
// XXX: valloc doesn't work on Windows.
|
||||
//void* y = valloc(1); // rounds up to 4096
|
||||
//UseItOrLoseIt(y, seven);
|
||||
//UseItOrLoseIt(y, aSeven);
|
||||
|
||||
// XXX: C11 only
|
||||
//void* z = aligned_alloc(64, 256);
|
||||
//UseItOrLoseIt(z, seven);
|
||||
//UseItOrLoseIt(z, aSeven);
|
||||
|
||||
// Analyze 2.
|
||||
Analyze(Move(f2));
|
||||
if (aNum == 1) {
|
||||
// Analyze 1.
|
||||
Analyze(Move(f));
|
||||
}
|
||||
|
||||
ClearReports();
|
||||
|
||||
//---------
|
||||
|
||||
@ -262,67 +257,102 @@ RunTests()
|
||||
//free(y);
|
||||
//free(z);
|
||||
|
||||
// Analyze 3.
|
||||
Analyze(Move(f3));
|
||||
if (aNum == 2) {
|
||||
// Analyze 2.
|
||||
Analyze(Move(f));
|
||||
}
|
||||
}
|
||||
|
||||
//---------
|
||||
void
|
||||
TestSampled(const char* aTestName, const char* aMode, int aSeven)
|
||||
{
|
||||
char filename[128];
|
||||
sprintf(filename, "full-%s-%s.json", aTestName, aMode);
|
||||
auto f = MakeUnique<FpWriteFunc>(filename);
|
||||
|
||||
// The first part of this test requires sampling to be disabled.
|
||||
SetSampleBelowSize(128);
|
||||
|
||||
// Clear all knowledge of existing blocks to give us a clean slate.
|
||||
ClearBlocks();
|
||||
char options[128];
|
||||
sprintf(options, "--mode=%s --sample-below=128", aMode);
|
||||
ResetEverything(options);
|
||||
|
||||
char* s;
|
||||
|
||||
// This equals the sample size, and so is reported exactly. It should be
|
||||
// listed before records of the same size that are sampled.
|
||||
s = (char*) malloc(128);
|
||||
UseItOrLoseIt(s, seven);
|
||||
UseItOrLoseIt(s, aSeven);
|
||||
|
||||
// This exceeds the sample size, and so is reported exactly.
|
||||
s = (char*) malloc(160);
|
||||
UseItOrLoseIt(s, seven);
|
||||
UseItOrLoseIt(s, aSeven);
|
||||
|
||||
// These together constitute exactly one sample.
|
||||
for (int i = 0; i < seven + 9; i++) {
|
||||
for (int i = 0; i < aSeven + 9; i++) {
|
||||
s = (char*) malloc(8);
|
||||
UseItOrLoseIt(s, seven);
|
||||
UseItOrLoseIt(s, aSeven);
|
||||
}
|
||||
|
||||
// These fall 8 bytes short of a full sample.
|
||||
for (int i = 0; i < seven + 8; i++) {
|
||||
for (int i = 0; i < aSeven + 8; i++) {
|
||||
s = (char*) malloc(8);
|
||||
UseItOrLoseIt(s, seven);
|
||||
UseItOrLoseIt(s, aSeven);
|
||||
}
|
||||
|
||||
// This exceeds the sample size, and so is recorded exactly.
|
||||
s = (char*) malloc(256);
|
||||
UseItOrLoseIt(s, seven);
|
||||
UseItOrLoseIt(s, aSeven);
|
||||
|
||||
// This gets more than to a full sample from the |i < seven + 8| loop above.
|
||||
// This gets more than to a full sample from the |i < aSeven + 8| loop above.
|
||||
s = (char*) malloc(96);
|
||||
UseItOrLoseIt(s, seven);
|
||||
UseItOrLoseIt(s, aSeven);
|
||||
|
||||
// This gets to another full sample.
|
||||
for (int i = 0; i < seven - 2; i++) {
|
||||
for (int i = 0; i < aSeven - 2; i++) {
|
||||
s = (char*) malloc(8);
|
||||
UseItOrLoseIt(s, seven);
|
||||
UseItOrLoseIt(s, aSeven);
|
||||
}
|
||||
|
||||
// This allocates 16, 32, ..., 128 bytes, which results in a heap block
|
||||
// record that contains a mix of sample and non-sampled blocks, and so should
|
||||
// be printed with '~' signs.
|
||||
for (int i = 1; i <= seven + 1; i++) {
|
||||
for (int i = 1; i <= aSeven + 1; i++) {
|
||||
s = (char*) malloc(i * 16);
|
||||
UseItOrLoseIt(s, seven);
|
||||
UseItOrLoseIt(s, aSeven);
|
||||
}
|
||||
|
||||
// At the end we're 64 bytes into the current sample so we report ~1,424
|
||||
// bytes of allocation overall, which is 64 less than the real value 1,488.
|
||||
|
||||
// Analyze 4.
|
||||
Analyze(Move(f4));
|
||||
Analyze(Move(f));
|
||||
}
|
||||
|
||||
void
|
||||
RunTests()
|
||||
{
|
||||
// This test relies on the compiler not doing various optimizations, such as
|
||||
// eliding unused malloc() calls or unrolling loops with fixed iteration
|
||||
// counts. So we compile it with -O0 (or equivalent), which probably prevents
|
||||
// that. We also use the following variable for various loop iteration
|
||||
// counts, just in case compilers might unroll very small loops even with
|
||||
// -O0.
|
||||
int seven = 7;
|
||||
|
||||
// Make sure that DMD is actually running; it is initialized on the first
|
||||
// allocation.
|
||||
int *x = (int*)malloc(100);
|
||||
UseItOrLoseIt(x, seven);
|
||||
MOZ_RELEASE_ASSERT(IsRunning());
|
||||
|
||||
// Please keep this in sync with run_test in test_dmd.js.
|
||||
|
||||
TestEmpty("empty", "live");
|
||||
TestEmpty("empty", "dark-matter");
|
||||
|
||||
TestUnsampled("unsampled", 1, "live", seven);
|
||||
TestUnsampled("unsampled", 1, "dark-matter", seven);
|
||||
|
||||
TestUnsampled("unsampled", 2, "dark-matter", seven);
|
||||
|
||||
TestSampled("sampled", "live", seven);
|
||||
}
|
||||
|
||||
int main()
|
||||
|
@ -1,8 +1,8 @@
|
||||
#-----------------------------------------------------------------
|
||||
# dmd.py --filter-stacks-for-testing -o full-reports-empty-actual.txt full-empty.json
|
||||
# dmd.py --filter-stacks-for-testing -o full-empty-dark-matter-actual.txt full-empty-dark-matter.json
|
||||
|
||||
Invocation {
|
||||
$DMD = '1'
|
||||
$DMD = '--mode=dark-matter --sample-below=1'
|
||||
Sample-below size = 1
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
#-----------------------------------------------------------------
|
||||
# dmd.py --filter-stacks-for-testing -o full-heap-empty-actual.txt --ignore-reports full-empty.json
|
||||
# dmd.py --filter-stacks-for-testing -o full-empty-live-actual.txt full-empty-live.json
|
||||
|
||||
Invocation {
|
||||
$DMD = '1'
|
||||
$DMD = '--mode=live --sample-below=1'
|
||||
Sample-below size = 1
|
||||
}
|
||||
|
@ -1,100 +0,0 @@
|
||||
#-----------------------------------------------------------------
|
||||
# dmd.py --filter-stacks-for-testing -o full-heap-unsampled2-actual.txt --ignore-reports full-unsampled2.json
|
||||
|
||||
Invocation {
|
||||
$DMD = '1'
|
||||
Sample-below size = 1
|
||||
}
|
||||
|
||||
#-----------------------------------------------------------------
|
||||
|
||||
Live {
|
||||
9 blocks in heap block record 1 of 9
|
||||
1,008 bytes (900 requested / 108 slop)
|
||||
Individual block sizes: 112 x 9
|
||||
35.49% of the heap (35.49% cumulative)
|
||||
Allocated at {
|
||||
#01: ... DMD.cpp ...
|
||||
}
|
||||
}
|
||||
|
||||
Live {
|
||||
6 blocks in heap block record 2 of 9
|
||||
528 bytes (528 requested / 0 slop)
|
||||
Individual block sizes: 128; 112; 96; 80; 64; 48
|
||||
18.59% of the heap (54.08% cumulative)
|
||||
Allocated at {
|
||||
#01: ... DMD.cpp ...
|
||||
}
|
||||
}
|
||||
|
||||
Live {
|
||||
6 blocks in heap block record 3 of 9
|
||||
528 bytes (528 requested / 0 slop)
|
||||
Individual block sizes: 128; 112; 96; 80; 64; 48
|
||||
18.59% of the heap (72.68% cumulative)
|
||||
Allocated at {
|
||||
#01: ... DMD.cpp ...
|
||||
}
|
||||
}
|
||||
|
||||
Live {
|
||||
1 block in heap block record 4 of 9
|
||||
512 bytes (512 requested / 0 slop)
|
||||
18.03% of the heap (90.70% cumulative)
|
||||
Allocated at {
|
||||
#01: ... DMD.cpp ...
|
||||
}
|
||||
}
|
||||
|
||||
Live {
|
||||
1 block in heap block record 5 of 9
|
||||
80 bytes (79 requested / 1 slop)
|
||||
2.82% of the heap (93.52% cumulative)
|
||||
Allocated at {
|
||||
#01: ... DMD.cpp ...
|
||||
}
|
||||
}
|
||||
|
||||
Live {
|
||||
1 block in heap block record 6 of 9
|
||||
80 bytes (78 requested / 2 slop)
|
||||
2.82% of the heap (96.34% cumulative)
|
||||
Allocated at {
|
||||
#01: ... DMD.cpp ...
|
||||
}
|
||||
}
|
||||
|
||||
Live {
|
||||
1 block in heap block record 7 of 9
|
||||
80 bytes (77 requested / 3 slop)
|
||||
2.82% of the heap (99.15% cumulative)
|
||||
Allocated at {
|
||||
#01: ... DMD.cpp ...
|
||||
}
|
||||
}
|
||||
|
||||
Live {
|
||||
1 block in heap block record 8 of 9
|
||||
16 bytes (10 requested / 6 slop)
|
||||
0.56% of the heap (99.72% cumulative)
|
||||
Allocated at {
|
||||
#01: ... DMD.cpp ...
|
||||
}
|
||||
}
|
||||
|
||||
Live {
|
||||
1 block in heap block record 9 of 9
|
||||
8 bytes (8 requested / 0 slop)
|
||||
0.28% of the heap (100.00% cumulative)
|
||||
Allocated at {
|
||||
#01: ... DMD.cpp ...
|
||||
}
|
||||
}
|
||||
|
||||
#-----------------------------------------------------------------
|
||||
|
||||
Summary {
|
||||
Total: 2,840 bytes in 27 blocks
|
||||
}
|
||||
|
@ -1,98 +0,0 @@
|
||||
#-----------------------------------------------------------------
|
||||
# dmd.py --filter-stacks-for-testing -o full-reports-sampled-actual.txt full-sampled.json
|
||||
|
||||
Invocation {
|
||||
$DMD = '1'
|
||||
Sample-below size = 128
|
||||
}
|
||||
|
||||
#-----------------------------------------------------------------
|
||||
|
||||
# no twice-reported heap blocks
|
||||
|
||||
#-----------------------------------------------------------------
|
||||
|
||||
Unreported {
|
||||
~4 blocks in heap block record 1 of 7
|
||||
~512 bytes (~512 requested / ~0 slop)
|
||||
Individual block sizes: ~128 x 3; 128
|
||||
35.56% of the heap (35.56% cumulative)
|
||||
35.56% of unreported (35.56% cumulative)
|
||||
Allocated at {
|
||||
#01: ... DMD.cpp ...
|
||||
}
|
||||
}
|
||||
|
||||
Unreported {
|
||||
1 block in heap block record 2 of 7
|
||||
256 bytes (256 requested / 0 slop)
|
||||
17.78% of the heap (53.33% cumulative)
|
||||
17.78% of unreported (53.33% cumulative)
|
||||
Allocated at {
|
||||
#01: ... DMD.cpp ...
|
||||
}
|
||||
}
|
||||
|
||||
Unreported {
|
||||
1 block in heap block record 3 of 7
|
||||
160 bytes (160 requested / 0 slop)
|
||||
11.11% of the heap (64.44% cumulative)
|
||||
11.11% of unreported (64.44% cumulative)
|
||||
Allocated at {
|
||||
#01: ... DMD.cpp ...
|
||||
}
|
||||
}
|
||||
|
||||
Unreported {
|
||||
1 block in heap block record 4 of 7
|
||||
128 bytes (128 requested / 0 slop)
|
||||
8.89% of the heap (73.33% cumulative)
|
||||
8.89% of unreported (73.33% cumulative)
|
||||
Allocated at {
|
||||
#01: ... DMD.cpp ...
|
||||
}
|
||||
}
|
||||
|
||||
Unreported {
|
||||
~1 block in heap block record 5 of 7
|
||||
~128 bytes (~128 requested / ~0 slop)
|
||||
8.89% of the heap (82.22% cumulative)
|
||||
8.89% of unreported (82.22% cumulative)
|
||||
Allocated at {
|
||||
#01: ... DMD.cpp ...
|
||||
}
|
||||
}
|
||||
|
||||
Unreported {
|
||||
~1 block in heap block record 6 of 7
|
||||
~128 bytes (~128 requested / ~0 slop)
|
||||
8.89% of the heap (91.11% cumulative)
|
||||
8.89% of unreported (91.11% cumulative)
|
||||
Allocated at {
|
||||
#01: ... DMD.cpp ...
|
||||
}
|
||||
}
|
||||
|
||||
Unreported {
|
||||
~1 block in heap block record 7 of 7
|
||||
~128 bytes (~128 requested / ~0 slop)
|
||||
8.89% of the heap (100.00% cumulative)
|
||||
8.89% of unreported (100.00% cumulative)
|
||||
Allocated at {
|
||||
#01: ... DMD.cpp ...
|
||||
}
|
||||
}
|
||||
|
||||
#-----------------------------------------------------------------
|
||||
|
||||
# no once-reported heap blocks
|
||||
|
||||
#-----------------------------------------------------------------
|
||||
|
||||
Summary {
|
||||
Total: ~1,440 bytes (100.00%) in ~10 blocks (100.00%)
|
||||
Unreported: ~1,440 bytes (100.00%) in ~10 blocks (100.00%)
|
||||
Once-reported: ~0 bytes ( 0.00%) in ~0 blocks ( 0.00%)
|
||||
Twice-reported: ~0 bytes ( 0.00%) in ~0 blocks ( 0.00%)
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
#-----------------------------------------------------------------
|
||||
# dmd.py --filter-stacks-for-testing -o full-heap-sampled-actual.txt --ignore-reports full-sampled.json
|
||||
# dmd.py --filter-stacks-for-testing -o full-sampled-live-actual.txt full-sampled-live.json
|
||||
|
||||
Invocation {
|
||||
$DMD = '1'
|
||||
$DMD = '--mode=live --sample-below=128'
|
||||
Sample-below size = 128
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
#-----------------------------------------------------------------
|
||||
# dmd.py --filter-stacks-for-testing -o full-reports-unsampled1-actual.txt full-unsampled1.json
|
||||
# dmd.py --filter-stacks-for-testing -o full-unsampled1-dark-matter-actual.txt full-unsampled1-dark-matter.json
|
||||
|
||||
Invocation {
|
||||
$DMD = '1'
|
||||
$DMD = '--mode=dark-matter --sample-below=1 --show-dump-stats=yes'
|
||||
Sample-below size = 1
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
#-----------------------------------------------------------------
|
||||
# dmd.py --filter-stacks-for-testing -o full-heap-unsampled1-actual.txt --ignore-reports full-unsampled1.json
|
||||
# dmd.py --filter-stacks-for-testing -o full-unsampled1-live-actual.txt full-unsampled1-live.json
|
||||
|
||||
Invocation {
|
||||
$DMD = '1'
|
||||
$DMD = '--mode=live --sample-below=1 --show-dump-stats=yes'
|
||||
Sample-below size = 1
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
#-----------------------------------------------------------------
|
||||
# dmd.py --filter-stacks-for-testing -o full-reports-unsampled2-actual.txt full-unsampled2.json
|
||||
# dmd.py --filter-stacks-for-testing -o full-unsampled2-dark-matter-actual.txt full-unsampled2-dark-matter.json
|
||||
|
||||
Invocation {
|
||||
$DMD = '1'
|
||||
$DMD = '--mode=dark-matter --sample-below=1 --show-dump-stats=yes'
|
||||
Sample-below size = 1
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
#-----------------------------------------------------------------
|
||||
# dmd.py --filter-stacks-for-testing -o script-diff-basic-actual.txt script-diff1.json script-diff2.json
|
||||
# dmd.py --filter-stacks-for-testing -o script-diff-dark-matter-actual.txt script-diff-dark-matter1.json script-diff-dark-matter2.json
|
||||
|
||||
Invocation 1 {
|
||||
$DMD = '--sample-below=127'
|
@ -1,7 +1,8 @@
|
||||
{
|
||||
"version": 1,
|
||||
"version": 2,
|
||||
"invocation": {
|
||||
"dmdEnvVar": "--sample-below=127",
|
||||
"mode": "dark-matter",
|
||||
"sampleBelowSize": 127
|
||||
},
|
||||
"blockList": [
|
@ -1,7 +1,8 @@
|
||||
{
|
||||
"version": 1,
|
||||
"version": 2,
|
||||
"invocation": {
|
||||
"dmdEnvVar": "--sample-below=63",
|
||||
"mode": "dark-matter",
|
||||
"sampleBelowSize": 63
|
||||
},
|
||||
"blockList": [
|
@ -1,5 +1,5 @@
|
||||
#-----------------------------------------------------------------
|
||||
# dmd.py --filter-stacks-for-testing -o script-diff-options-actual.txt --ignore-reports script-diff1.json script-diff2.json
|
||||
# dmd.py --filter-stacks-for-testing -o script-diff-live-actual.txt script-diff-live1.json script-diff-live2.json
|
||||
|
||||
Invocation 1 {
|
||||
$DMD = '--sample-below=127'
|
63
memory/replace/dmd/test/script-diff-live1.json
Normal file
63
memory/replace/dmd/test/script-diff-live1.json
Normal file
@ -0,0 +1,63 @@
|
||||
{
|
||||
"version": 2,
|
||||
"invocation": {
|
||||
"dmdEnvVar": "--sample-below=127",
|
||||
"mode": "live",
|
||||
"sampleBelowSize": 127
|
||||
},
|
||||
"blockList": [
|
||||
{"req": 4096, "alloc": "A"},
|
||||
{"req": 4096, "alloc": "A"},
|
||||
{"req": 4096, "alloc": "A"},
|
||||
{"req": 4096, "alloc": "A"},
|
||||
|
||||
{"req": 4096, "alloc": "B"},
|
||||
{"req": 4096, "alloc": "B"},
|
||||
{"req": 4096, "alloc": "B"},
|
||||
{"req": 4096, "alloc": "B"},
|
||||
|
||||
{"req": 4096, "alloc": "C"},
|
||||
{"req": 4096, "alloc": "C"},
|
||||
{"req": 4096, "alloc": "C"},
|
||||
{"req": 4096, "alloc": "C"},
|
||||
|
||||
{"req": 4096, "alloc": "D"},
|
||||
{"req": 4096, "alloc": "D"},
|
||||
{"req": 2000, "slop": 48, "alloc": "D"},
|
||||
|
||||
{"req": 15360, "alloc": "F"},
|
||||
{"req": 512, "alloc": "F"},
|
||||
{"req": 512, "alloc": "F"},
|
||||
{ "alloc": "F"},
|
||||
{"req": 1024, "alloc": "F"},
|
||||
{ "alloc": "F"},
|
||||
{"req": 1000, "slop": 24, "alloc": "F"},
|
||||
{ "alloc": "F"},
|
||||
|
||||
{"req": 4096, "alloc": "G"},
|
||||
{"req": 8192, "alloc": "G"},
|
||||
{"req": 16384, "alloc": "G"}
|
||||
],
|
||||
"traceTable": {
|
||||
"A": ["AA"],
|
||||
"B": ["BB"],
|
||||
"C": ["CC"],
|
||||
"D": ["DD"],
|
||||
"E": ["EE"],
|
||||
"F": ["FF"],
|
||||
"G": ["GG"],
|
||||
"R1": ["RR1"],
|
||||
"R2": ["RR2"]
|
||||
},
|
||||
"frameTable": {
|
||||
"AA": "#00: A (A.cpp:99)",
|
||||
"BB": "#00: B (B.cpp:99)",
|
||||
"CC": "#00: C (C.cpp:99)",
|
||||
"DD": "#00: D (D.cpp:99)",
|
||||
"EE": "#00: E (E.cpp:99)",
|
||||
"FF": "#00: F (F.cpp:99)",
|
||||
"GG": "#00: G (G.cpp:99)",
|
||||
"RR1": "#00: R1 (R1.cpp:99)",
|
||||
"RR2": "#00: R2 (R2.cpp:99)"
|
||||
}
|
||||
}
|
67
memory/replace/dmd/test/script-diff-live2.json
Normal file
67
memory/replace/dmd/test/script-diff-live2.json
Normal file
@ -0,0 +1,67 @@
|
||||
{
|
||||
"version": 2,
|
||||
"invocation": {
|
||||
"dmdEnvVar": "--sample-below=63",
|
||||
"mode": "live",
|
||||
"sampleBelowSize": 63
|
||||
},
|
||||
"blockList": [
|
||||
{"req": 4096, "alloc": "A"},
|
||||
{"req": 4096, "alloc": "A"},
|
||||
{"req": 4096, "alloc": "A"},
|
||||
{"req": 4096, "alloc": "A"},
|
||||
|
||||
{"req": 8192, "alloc": "B"},
|
||||
{"req": 8192, "alloc": "B"},
|
||||
|
||||
{"req": 4000, "slop": 96, "alloc": "C"},
|
||||
{"req": 4000, "slop": 96, "alloc": "C"},
|
||||
{"req": 4000, "slop": 96, "alloc": "C"},
|
||||
{"req": 4000, "slop": 96, "alloc": "C"},
|
||||
|
||||
{"req": 4096, "alloc": "E"},
|
||||
{"req": 4096, "alloc": "E"},
|
||||
{"req": 4096, "alloc": "E"},
|
||||
{"req": 4096, "alloc": "E"},
|
||||
|
||||
{"req": 2000, "slop": 48, "alloc": "F"},
|
||||
{"req": 1000, "slop": 24, "alloc": "F"},
|
||||
{"req": 512, "alloc": "F"},
|
||||
{"req": 512, "alloc": "F"},
|
||||
{"req": 512, "alloc": "F"},
|
||||
{"req": 512, "alloc": "F"},
|
||||
{"req": 128, "alloc": "F"},
|
||||
{ "alloc": "F"},
|
||||
{"req": 64, "alloc": "F"},
|
||||
{"req": 64, "alloc": "F"},
|
||||
{"req": 64, "alloc": "F"},
|
||||
{"req": 64, "alloc": "F"},
|
||||
{ "alloc": "F"},
|
||||
|
||||
{"req": 4096, "alloc": "G"},
|
||||
{"req": 4096, "alloc": "G"},
|
||||
{"req": 20480, "alloc": "G"}
|
||||
],
|
||||
"traceTable": {
|
||||
"A": ["AA"],
|
||||
"B": ["BB"],
|
||||
"C": ["CC"],
|
||||
"D": ["DD"],
|
||||
"E": ["EE"],
|
||||
"F": ["FF"],
|
||||
"G": ["GG"],
|
||||
"R1": ["RR1"],
|
||||
"R2": ["RR2"]
|
||||
},
|
||||
"frameTable": {
|
||||
"AA": "#00: A (A.cpp:99)",
|
||||
"BB": "#00: B (B.cpp:99)",
|
||||
"CC": "#00: C (C.cpp:99)",
|
||||
"DD": "#00: D (D.cpp:99)",
|
||||
"EE": "#00: E (E.cpp:99)",
|
||||
"FF": "#00: F (F.cpp:99)",
|
||||
"GG": "#00: G (G.cpp:99)",
|
||||
"RR1": "#00: R1 (R1.cpp:99)",
|
||||
"RR2": "#00: R2 (R2.cpp:99)"
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
#-----------------------------------------------------------------
|
||||
# dmd.py --filter-stacks-for-testing -o script-ignore-alloc-fns-actual.txt --ignore-reports --ignore-alloc-fns script-ignore-alloc-fns.json
|
||||
# dmd.py --filter-stacks-for-testing -o script-ignore-alloc-fns-actual.txt --ignore-alloc-fns script-ignore-alloc-fns.json
|
||||
|
||||
Invocation {
|
||||
$DMD = '1'
|
||||
|
@ -1,7 +1,8 @@
|
||||
{
|
||||
"version": 1,
|
||||
"version": 2,
|
||||
"invocation": {
|
||||
"dmdEnvVar": "1",
|
||||
"mode": "live",
|
||||
"sampleBelowSize": 2500
|
||||
},
|
||||
"blockList": [
|
||||
|
@ -1,5 +1,5 @@
|
||||
#-----------------------------------------------------------------
|
||||
# dmd.py --filter-stacks-for-testing -o script-max-frames-1-actual.txt --ignore-reports --max-frames=1 script-max-frames.json
|
||||
# dmd.py --filter-stacks-for-testing -o script-max-frames-1-actual.txt --max-frames=1 script-max-frames.json
|
||||
|
||||
Invocation {
|
||||
$DMD = '1'
|
||||
|
@ -1,5 +1,5 @@
|
||||
#-----------------------------------------------------------------
|
||||
# dmd.py --filter-stacks-for-testing -o script-max-frames-3-actual.txt --ignore-reports --max-frames=3 --no-fix-stacks script-max-frames.json
|
||||
# dmd.py --filter-stacks-for-testing -o script-max-frames-3-actual.txt --max-frames=3 --no-fix-stacks script-max-frames.json
|
||||
|
||||
Invocation {
|
||||
$DMD = '1'
|
||||
|
@ -1,5 +1,5 @@
|
||||
#-----------------------------------------------------------------
|
||||
# dmd.py --filter-stacks-for-testing -o script-max-frames-8-actual.txt --ignore-reports --max-frames=8 script-max-frames.json
|
||||
# dmd.py --filter-stacks-for-testing -o script-max-frames-8-actual.txt --max-frames=8 script-max-frames.json
|
||||
|
||||
Invocation {
|
||||
$DMD = '1'
|
||||
|
@ -1,7 +1,8 @@
|
||||
{
|
||||
"version": 1,
|
||||
"version": 2,
|
||||
"invocation": {
|
||||
"dmdEnvVar": "1",
|
||||
"mode": "live",
|
||||
"sampleBelowSize": 1
|
||||
},
|
||||
"blockList": [
|
||||
|
@ -1,5 +1,5 @@
|
||||
#-----------------------------------------------------------------
|
||||
# dmd.py --filter-stacks-for-testing -o script-sort-by-req-actual.txt --ignore-reports --sort-by=req --no-fix-stacks script-sort-by.json.gz
|
||||
# dmd.py --filter-stacks-for-testing -o script-sort-by-req-actual.txt --sort-by=req --no-fix-stacks script-sort-by.json.gz
|
||||
|
||||
Invocation {
|
||||
$DMD = '1'
|
||||
|
@ -1,5 +1,5 @@
|
||||
#-----------------------------------------------------------------
|
||||
# dmd.py --filter-stacks-for-testing -o script-sort-by-slop-actual.txt --ignore-reports --sort-by=slop script-sort-by.json.gz
|
||||
# dmd.py --filter-stacks-for-testing -o script-sort-by-slop-actual.txt --sort-by=slop script-sort-by.json.gz
|
||||
|
||||
Invocation {
|
||||
$DMD = '1'
|
||||
|
@ -1,5 +1,5 @@
|
||||
#-----------------------------------------------------------------
|
||||
# dmd.py --filter-stacks-for-testing -o script-sort-by-usable-actual.txt --ignore-reports --sort-by=usable script-sort-by.json.gz
|
||||
# dmd.py --filter-stacks-for-testing -o script-sort-by-usable-actual.txt --sort-by=usable script-sort-by.json.gz
|
||||
|
||||
Invocation {
|
||||
$DMD = '1'
|
||||
|
Binary file not shown.
@ -128,15 +128,25 @@ function run_test() {
|
||||
|
||||
runProcess(gDmdTestFile, []);
|
||||
|
||||
let fullTestNames = ["empty", "unsampled1", "unsampled2", "sampled"];
|
||||
for (let i = 0; i < fullTestNames.length; i++) {
|
||||
let name = fullTestNames[i];
|
||||
jsonFile = FileUtils.getFile("CurWorkD", ["full-" + name + ".json"]);
|
||||
test("full-heap-" + name, ["--ignore-reports", jsonFile.path])
|
||||
test("full-reports-" + name, [jsonFile.path])
|
||||
jsonFile.remove(true);
|
||||
function test2(aTestName, aMode) {
|
||||
let name = "full-" + aTestName + "-" + aMode;
|
||||
jsonFile = FileUtils.getFile("CurWorkD", [name + ".json"]);
|
||||
test(name, [jsonFile.path]);
|
||||
jsonFile.remove(true);
|
||||
}
|
||||
|
||||
// Please keep this in sync with RunTests() in SmokeDMD.cpp.
|
||||
|
||||
test2("empty", "live");
|
||||
test2("empty", "dark-matter");
|
||||
|
||||
test2("unsampled1", "live");
|
||||
test2("unsampled1", "dark-matter");
|
||||
|
||||
test2("unsampled2", "dark-matter");
|
||||
|
||||
test2("sampled", "live");
|
||||
|
||||
// These tests only test the post-processing script. They use hand-written
|
||||
// JSON files as input. Ideally the JSON files would contain comments
|
||||
// explaining how they work, but JSON doesn't allow comments, so I've put
|
||||
@ -147,37 +157,39 @@ function run_test() {
|
||||
// of the tested values.
|
||||
jsonFile = FileUtils.getFile("CurWorkD", ["script-max-frames.json"]);
|
||||
test("script-max-frames-8",
|
||||
["--ignore-reports", "--max-frames=8", jsonFile.path]);
|
||||
["--max-frames=8", jsonFile.path]);
|
||||
test("script-max-frames-3",
|
||||
["--ignore-reports", "--max-frames=3", "--no-fix-stacks",
|
||||
jsonFile.path]);
|
||||
["--max-frames=3", "--no-fix-stacks", jsonFile.path]);
|
||||
test("script-max-frames-1",
|
||||
["--ignore-reports", "--max-frames=1", jsonFile.path]);
|
||||
["--max-frames=1", jsonFile.path]);
|
||||
|
||||
// This file has three records that are shown in a different order for each
|
||||
// of the different sort values. It also tests the handling of gzipped JSON
|
||||
// files.
|
||||
jsonFile = FileUtils.getFile("CurWorkD", ["script-sort-by.json.gz"]);
|
||||
test("script-sort-by-usable",
|
||||
["--ignore-reports", "--sort-by=usable", jsonFile.path]);
|
||||
["--sort-by=usable", jsonFile.path]);
|
||||
test("script-sort-by-req",
|
||||
["--ignore-reports", "--sort-by=req", "--no-fix-stacks", jsonFile.path]);
|
||||
["--sort-by=req", "--no-fix-stacks", jsonFile.path]);
|
||||
test("script-sort-by-slop",
|
||||
["--ignore-reports", "--sort-by=slop", jsonFile.path]);
|
||||
["--sort-by=slop", jsonFile.path]);
|
||||
|
||||
// This file has several real stack traces taken from Firefox execution, each
|
||||
// of which tests a different allocator function (or functions).
|
||||
jsonFile = FileUtils.getFile("CurWorkD", ["script-ignore-alloc-fns.json"]);
|
||||
test("script-ignore-alloc-fns",
|
||||
["--ignore-reports", "--ignore-alloc-fns", jsonFile.path]);
|
||||
["--ignore-alloc-fns", jsonFile.path]);
|
||||
|
||||
// This tests diffs. The first invocation has no options, the second has
|
||||
// several.
|
||||
jsonFile = FileUtils.getFile("CurWorkD", ["script-diff1.json"]);
|
||||
jsonFile2 = FileUtils.getFile("CurWorkD", ["script-diff2.json"]);
|
||||
test("script-diff-basic",
|
||||
// This tests "live"-mode diffs.
|
||||
jsonFile = FileUtils.getFile("CurWorkD", ["script-diff-live1.json"]);
|
||||
jsonFile2 = FileUtils.getFile("CurWorkD", ["script-diff-live2.json"]);
|
||||
test("script-diff-live",
|
||||
[jsonFile.path, jsonFile2.path]);
|
||||
|
||||
// This tests "dark-matter"-mode diffs.
|
||||
jsonFile = FileUtils.getFile("CurWorkD", ["script-diff-dark-matter1.json"]);
|
||||
jsonFile2 = FileUtils.getFile("CurWorkD", ["script-diff-dark-matter2.json"]);
|
||||
test("script-diff-dark-matter",
|
||||
[jsonFile.path, jsonFile2.path]);
|
||||
test("script-diff-options",
|
||||
["--ignore-reports", jsonFile.path, jsonFile2.path]);
|
||||
}
|
||||
|
||||
|
@ -1,13 +1,11 @@
|
||||
[DEFAULT]
|
||||
support-files =
|
||||
full-heap-empty-expected.txt
|
||||
full-heap-unsampled1-expected.txt
|
||||
full-heap-unsampled2-expected.txt
|
||||
full-heap-sampled-expected.txt
|
||||
full-reports-empty-expected.txt
|
||||
full-reports-unsampled1-expected.txt
|
||||
full-reports-unsampled2-expected.txt
|
||||
full-reports-sampled-expected.txt
|
||||
full-empty-live-expected.txt
|
||||
full-empty-dark-matter-expected.txt
|
||||
full-unsampled1-live-expected.txt
|
||||
full-unsampled1-dark-matter-expected.txt
|
||||
full-unsampled2-dark-matter-expected.txt
|
||||
full-sampled-live-expected.txt
|
||||
script-max-frames.json
|
||||
script-max-frames-8-expected.txt
|
||||
script-max-frames-3-expected.txt
|
||||
@ -18,10 +16,12 @@ support-files =
|
||||
script-sort-by-slop-expected.txt
|
||||
script-ignore-alloc-fns.json
|
||||
script-ignore-alloc-fns-expected.txt
|
||||
script-diff1.json
|
||||
script-diff2.json
|
||||
script-diff-basic-expected.txt
|
||||
script-diff-options-expected.txt
|
||||
script-diff-live1.json
|
||||
script-diff-live2.json
|
||||
script-diff-live-expected.txt
|
||||
script-diff-dark-matter1.json
|
||||
script-diff-dark-matter2.json
|
||||
script-diff-dark-matter-expected.txt
|
||||
|
||||
# Bug 1077230 explains why this test is disabled on Mac 10.6.
|
||||
# Bug 1076446 comment 20 explains why this test is only enabled on Windows 5.1
|
||||
|
@ -893,6 +893,8 @@ class RunProgram(MachCommandBase):
|
||||
@CommandArgumentGroup('DMD')
|
||||
@CommandArgument('--dmd', action='store_true', group='DMD',
|
||||
help='Enable DMD. The following arguments have no effect without this.')
|
||||
@CommandArgument('--mode', choices=['live', 'dark-matter'], group='DMD',
|
||||
help='Profiling mode. The default is \'dark-matter\'.')
|
||||
@CommandArgument('--sample-below', default=None, type=str, group='DMD',
|
||||
help='Sample blocks smaller than this. Use 1 for no sampling. The default is 4093.')
|
||||
@CommandArgument('--max-frames', default=None, type=str, group='DMD',
|
||||
@ -900,7 +902,7 @@ class RunProgram(MachCommandBase):
|
||||
@CommandArgument('--show-dump-stats', action='store_true', group='DMD',
|
||||
help='Show stats when doing dumps.')
|
||||
def run(self, params, remote, background, noprofile, debug, debugger,
|
||||
debugparams, slowscript, dmd, sample_below, max_frames,
|
||||
debugparams, slowscript, dmd, mode, sample_below, max_frames,
|
||||
show_dump_stats):
|
||||
|
||||
try:
|
||||
@ -967,6 +969,8 @@ class RunProgram(MachCommandBase):
|
||||
if dmd:
|
||||
dmd_params = []
|
||||
|
||||
if mode:
|
||||
dmd_params.append('--mode=' + mode)
|
||||
if sample_below:
|
||||
dmd_params.append('--sample-below=' + sample_below)
|
||||
if max_frames:
|
||||
|
Loading…
Reference in New Issue
Block a user