Bug 1078979 - Add more testing of dmd.py. r=erahm.
authorNicholas Nethercote <nnethercote@mozilla.com>
Thu, 09 Oct 2014 16:50:12 -0700
changeset 233064 1c7a61385d1718fd13f1d1a59a41254923b554ae
parent 233063 367b155c5b5e07683a4a4fd3208ab91401d162bb
child 233065 fb7198e662d9e9d5a0585961623af0664db66798
push id4187
push userbhearsum@mozilla.com
push dateFri, 28 Nov 2014 15:29:12 +0000
treeherdermozilla-beta@f23cc6a30c11 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerserahm
bugs1078979
milestone35.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1078979 - Add more testing of dmd.py. r=erahm.
memory/replace/dmd/DMD.cpp
memory/replace/dmd/dmd.py
memory/replace/dmd/test/full-heap-empty-expected.txt
memory/replace/dmd/test/full-heap-expected1.txt
memory/replace/dmd/test/full-heap-expected2.txt
memory/replace/dmd/test/full-heap-expected3.txt
memory/replace/dmd/test/full-heap-expected4.txt
memory/replace/dmd/test/full-heap-sampled-expected.txt
memory/replace/dmd/test/full-heap-unsampled1-expected.txt
memory/replace/dmd/test/full-heap-unsampled2-expected.txt
memory/replace/dmd/test/full-reports-empty-expected.txt
memory/replace/dmd/test/full-reports-expected1.txt
memory/replace/dmd/test/full-reports-expected2.txt
memory/replace/dmd/test/full-reports-expected3.txt
memory/replace/dmd/test/full-reports-expected4.txt
memory/replace/dmd/test/full-reports-sampled-expected.txt
memory/replace/dmd/test/full-reports-unsampled1-expected.txt
memory/replace/dmd/test/full-reports-unsampled2-expected.txt
memory/replace/dmd/test/script-ignore-alloc-fns-expected.txt
memory/replace/dmd/test/script-ignore-alloc-fns.json
memory/replace/dmd/test/script-max-frames-1-expected.txt
memory/replace/dmd/test/script-max-frames-3-expected.txt
memory/replace/dmd/test/script-max-frames-8-expected.txt
memory/replace/dmd/test/script-max-frames.json
memory/replace/dmd/test/script-show-all-block-sizes-expected.txt
memory/replace/dmd/test/script-show-all-block-sizes.json
memory/replace/dmd/test/script-sort-by-req-expected.txt
memory/replace/dmd/test/script-sort-by-slop-expected.txt
memory/replace/dmd/test/script-sort-by-usable-expected.txt
memory/replace/dmd/test/script-sort-by.json
memory/replace/dmd/test/test_dmd.js
memory/replace/dmd/test/xpcshell.ini
--- a/memory/replace/dmd/DMD.cpp
+++ b/memory/replace/dmd/DMD.cpp
@@ -1442,20 +1442,20 @@ Init(const malloc_table_t* aMallocTable)
   if (gOptions->IsTestMode()) {
     // Do all necessary allocations before setting gIsDMDRunning so those
     // allocations don't show up in our results.  Once gIsDMDRunning is set we
     // are intercepting malloc et al. in earnest.
     //
     // These files are written to $CWD. It would probably be better to write
     // them to "TmpD" using the directory service, but that would require
     // linking DMD with XPCOM.
-    auto f1 = MakeUnique<FpWriteFunc>(OpenOutputFile("full1.json"));
-    auto f2 = MakeUnique<FpWriteFunc>(OpenOutputFile("full2.json"));
-    auto f3 = MakeUnique<FpWriteFunc>(OpenOutputFile("full3.json"));
-    auto f4 = MakeUnique<FpWriteFunc>(OpenOutputFile("full4.json"));
+    auto f1 = MakeUnique<FpWriteFunc>(OpenOutputFile("full-empty.json"));
+    auto f2 = MakeUnique<FpWriteFunc>(OpenOutputFile("full-unsampled1.json"));
+    auto f3 = MakeUnique<FpWriteFunc>(OpenOutputFile("full-unsampled2.json"));
+    auto f4 = MakeUnique<FpWriteFunc>(OpenOutputFile("full-sampled.json"));
     gIsDMDRunning = true;
 
     StatusMsg("running test mode...\n");
     RunTestMode(Move(f1), Move(f2), Move(f3), Move(f4));
     StatusMsg("finished test mode; DMD is now disabled again\n");
 
     // Continue running so that the xpcshell test can complete, but DMD no
     // longer needs to be running.
--- a/memory/replace/dmd/dmd.py
+++ b/memory/replace/dmd/dmd.py
@@ -17,17 +17,19 @@ import re
 import shutil
 import sys
 import tempfile
 
 # The DMD output version this script handles.
 outputVersion = 1
 
 # If --ignore-alloc-fns is specified, stack frames containing functions that
-# match these strings will be removed.
+# match these strings will be removed from the *start* of stack traces. (Once
+# we hit a non-matching frame, any subsequent frames won't be removed even if
+# they do match.)
 allocatorFns = [
     'replace_malloc',
     'replace_calloc',
     'replace_realloc',
     'replace_memalign',
     'replace_posix_memalign',
     'moz_xmalloc',
     'moz_xcalloc',
@@ -43,16 +45,20 @@ allocatorFns = [
     'vpx_realloc',
     'vpx_memalign',
     'js_malloc',
     'js_calloc',
     'js_realloc',
     'pod_malloc',
     'pod_calloc',
     'pod_realloc',
+    # This one necessary to fully filter some sequences of allocation functions
+    # that happen in practice. Note that ??? entries that follow non-allocation
+    # functions won't be stripped, as explained above.
+    '???',
 ]
 
 class Record(object):
     def __init__(self):
         self.numBlocks = 0
         self.reqSize = 0
         self.slopSize = 0
         self.usableSize = 0
rename from memory/replace/dmd/test/full-heap-expected1.txt
rename to memory/replace/dmd/test/full-heap-empty-expected.txt
rename from memory/replace/dmd/test/full-heap-expected4.txt
rename to memory/replace/dmd/test/full-heap-sampled-expected.txt
rename from memory/replace/dmd/test/full-heap-expected2.txt
rename to memory/replace/dmd/test/full-heap-unsampled1-expected.txt
rename from memory/replace/dmd/test/full-heap-expected3.txt
rename to memory/replace/dmd/test/full-heap-unsampled2-expected.txt
rename from memory/replace/dmd/test/full-reports-expected1.txt
rename to memory/replace/dmd/test/full-reports-empty-expected.txt
rename from memory/replace/dmd/test/full-reports-expected4.txt
rename to memory/replace/dmd/test/full-reports-sampled-expected.txt
rename from memory/replace/dmd/test/full-reports-expected2.txt
rename to memory/replace/dmd/test/full-reports-unsampled1-expected.txt
rename from memory/replace/dmd/test/full-reports-expected3.txt
rename to memory/replace/dmd/test/full-reports-unsampled2-expected.txt
new file mode 100644
--- /dev/null
+++ b/memory/replace/dmd/test/script-ignore-alloc-fns-expected.txt
@@ -0,0 +1,56 @@
+#-----------------------------------------------------------------
+
+Invocation {
+  $DMD = '1'
+  Sample-below size = 2500
+}
+
+#-----------------------------------------------------------------
+
+Live {
+  1 block in heap block record 1 of 4
+  1,048,576 bytes (1,048,576 requested / 0 slop)
+  93.22% of the heap (93.22% cumulative)
+  Allocated at {
+    #01: A (A.cpp:99)
+  }
+}
+
+Live {
+  1 block in heap block record 2 of 4
+  65,536 bytes (65,536 requested / 0 slop)
+  5.83% of the heap (99.05% cumulative)
+  Allocated at {
+    #01: js::jit::JitRuntime::initialize(JSContext*) (Ion.cpp:301)
+  }
+}
+
+Live {
+  1 block in heap block record 3 of 4
+  8,192 bytes (8,000 requested / 192 slop)
+  0.73% of the heap (99.78% cumulative)
+  Allocated at {
+    #01: mozilla::Vector::growStorageBy(unsigned long) (Vector.h:802)
+    #02: D (D.cpp:99)
+  }
+}
+
+Live {
+  ~1 block in heap block record 4 of 4
+  ~2,500 bytes (~2,500 requested / ~0 slop)
+  0.22% of the heap (100.00% cumulative)
+  Allocated at {
+    #01: g_type_create_instance (/usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0)
+    #02: not_an_alloc_function_so_alloc_functions_below_here_will_not_be_stripped (blah)
+    #03: replace_posix_memalign (replace_malloc.h:120)
+    #04: ??? (/lib/x86_64-linux-gnu/libglib-2.0.so.0)
+    #05: another_non_alloc_function (blah)
+  }
+}
+
+#-----------------------------------------------------------------
+
+Summary {
+  Total: ~1,124,804 bytes in ~4 blocks
+}
+
new file mode 100644
--- /dev/null
+++ b/memory/replace/dmd/test/script-ignore-alloc-fns.json
@@ -0,0 +1,46 @@
+{
+ "version": 1,
+ "invocation": {
+  "dmdEnvVar": "1",
+  "sampleBelowSize": 2500
+ },
+ "blockList": [
+  {"req": 1048576,           "alloc": "A"},
+  {"req": 65536,             "alloc": "B"},
+  {"req": 8000, "slop": 192, "alloc": "C"},
+  {                          "alloc": "D"}
+ ],
+ "traceTable": {
+  "A": ["AA", "AB", "AC", "AD"],
+  "B": ["BA", "BB", "BC"],
+  "C": ["CA", "CB", "CC", "CD"],
+  "D": ["DA", "DB", "DD", "DD", "DE", "DF", "DG", "DH", "DI", "DJ"]
+ },
+ "frameTable": {
+  "AA": "#00: replace_malloc (DMD.cpp:1106)",
+  "AB": "#00: moz_xmalloc (mozalloc.cpp:68)",
+  "AC": "#00: operator new(unsigned long) (mozalloc.h:208)",
+  "AD": "#00: A (A.cpp:99)",
+
+  "BA": "#00: replace_calloc (DMD.cpp:1125)",
+  "BB": "#00: js_calloc(unsigned long) (Utility.h:107)",
+  "BC": "#06: js::jit::JitRuntime::initialize(JSContext*) (Ion.cpp:301)",
+
+  "CA": "#00: replace_realloc (DMD.cpp:1153)",
+  "CB": "#00: bool* mozilla::MallocAllocPolicy::pod_realloc<bool>(bool*, unsigned long, unsigned long) (AllocPolicy.h:74)",
+  "CC": "#00: mozilla::Vector::growStorageBy(unsigned long) (Vector.h:802)",
+  "CD": "#00: D (D.cpp:99)",
+
+  "DA": "#00: replace_memalign (DMD.cpp:1181)",
+  "DB": "#00: replace_posix_memalign (replace_malloc.h:120)",
+  "DC": "#00: ??? (/lib/x86_64-linux-gnu/libglib-2.0.so.0)",
+  "DD": "#00: g_slice_alloc (/lib/x86_64-linux-gnu/libglib-2.0.so.0)",
+  "DE": "#00: g_slice_alloc0 (/lib/x86_64-linux-gnu/libglib-2.0.so.0)",
+  "DF": "#00: g_type_create_instance (/usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0)",
+  "DG": "#00: not_an_alloc_function_so_alloc_functions_below_here_will_not_be_stripped (blah)",
+  "DH": "#00: replace_posix_memalign (replace_malloc.h:120)",
+  "DI": "#00: ??? (/lib/x86_64-linux-gnu/libglib-2.0.so.0)",
+  "DJ": "#00: another_non_alloc_function (blah)"
+ }
+}
+
new file mode 100644
--- /dev/null
+++ b/memory/replace/dmd/test/script-max-frames-1-expected.txt
@@ -0,0 +1,24 @@
+#-----------------------------------------------------------------
+
+Invocation {
+  $DMD = '1'
+  Sample-below size = 1
+}
+
+#-----------------------------------------------------------------
+
+Live {
+  4 blocks in heap block record 1 of 1
+  4,416 bytes (4,404 requested / 12 slop)
+  100.00% of the heap (100.00% cumulative)
+  Allocated at {
+    #01: E (E.cpp:99)
+  }
+}
+
+#-----------------------------------------------------------------
+
+Summary {
+  Total: 4,416 bytes in 4 blocks
+}
+
new file mode 100644
--- /dev/null
+++ b/memory/replace/dmd/test/script-max-frames-3-expected.txt
@@ -0,0 +1,46 @@
+#-----------------------------------------------------------------
+
+Invocation {
+  $DMD = '1'
+  Sample-below size = 1
+}
+
+#-----------------------------------------------------------------
+
+Live {
+  2 blocks in heap block record 1 of 3
+  4,224 bytes (4,224 requested / 0 slop)
+  95.65% of the heap (95.65% cumulative)
+  Allocated at {
+    #01: E (E.cpp:99)
+    #02: F (F.cpp:99)
+    #03: G (G.cpp:99)
+  }
+}
+
+Live {
+  1 block in heap block record 2 of 3
+  112 bytes (100 requested / 12 slop)
+  2.54% of the heap (98.19% cumulative)
+  Allocated at {
+    #01: E (E.cpp:99)
+    #02: X (X.cpp:99)
+    #03: Y (Y.cpp:99)
+  }
+}
+
+Live {
+  1 block in heap block record 3 of 3
+  80 bytes (80 requested / 0 slop)
+  1.81% of the heap (100.00% cumulative)
+  Allocated at {
+    #01: E (E.cpp:99)
+  }
+}
+
+#-----------------------------------------------------------------
+
+Summary {
+  Total: 4,416 bytes in 4 blocks
+}
+
new file mode 100644
--- /dev/null
+++ b/memory/replace/dmd/test/script-max-frames-8-expected.txt
@@ -0,0 +1,68 @@
+#-----------------------------------------------------------------
+
+Invocation {
+  $DMD = '1'
+  Sample-below size = 1
+}
+
+#-----------------------------------------------------------------
+
+Live {
+  1 block in heap block record 1 of 4
+  4,096 bytes (4,096 requested / 0 slop)
+  92.75% of the heap (92.75% cumulative)
+  Allocated at {
+    #01: E (E.cpp:99)
+    #02: F (F.cpp:99)
+    #03: G (G.cpp:99)
+    #04: H (H.cpp:99)
+    #05: I (I.cpp:99)
+    #06: J (J.cpp:99)
+    #07: K (K.cpp:99)
+    #08: L (L.cpp:99)
+  }
+}
+
+Live {
+  1 block in heap block record 2 of 4
+  128 bytes (128 requested / 0 slop)
+  2.90% of the heap (95.65% cumulative)
+  Allocated at {
+    #01: E (E.cpp:99)
+    #02: F (F.cpp:99)
+    #03: G (G.cpp:99)
+    #04: R (R.cpp:99)
+    #05: S (S.cpp:99)
+    #06: T (T.cpp:99)
+    #07: U (U.cpp:99)
+    #08: V (V.cpp:99)
+  }
+}
+
+Live {
+  1 block in heap block record 3 of 4
+  112 bytes (100 requested / 12 slop)
+  2.54% of the heap (98.19% cumulative)
+  Allocated at {
+    #01: E (E.cpp:99)
+    #02: X (X.cpp:99)
+    #03: Y (Y.cpp:99)
+    #04: Z (Z.cpp:99)
+  }
+}
+
+Live {
+  1 block in heap block record 4 of 4
+  80 bytes (80 requested / 0 slop)
+  1.81% of the heap (100.00% cumulative)
+  Allocated at {
+    #01: E (E.cpp:99)
+  }
+}
+
+#-----------------------------------------------------------------
+
+Summary {
+  Total: 4,416 bytes in 4 blocks
+}
+
new file mode 100644
--- /dev/null
+++ b/memory/replace/dmd/test/script-max-frames.json
@@ -0,0 +1,43 @@
+{
+ "version": 1,
+ "invocation": {
+  "dmdEnvVar": "1",
+  "sampleBelowSize": 1
+ },
+ "blockList": [
+  {"req": 4096, "alloc": "A"},
+  {"req": 128, "alloc": "B"},
+  {"req": 100, "slop":12, "alloc": "C"},
+  {"req": 80, "alloc": "D"}
+ ],
+ "traceTable": {
+  "A": ["E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P"],
+  "B": ["E", "F", "G", "R", "S", "T", "U", "V"],
+  "C": ["E", "X", "Y", "Z"],
+  "D": ["E"]
+ },
+ "frameTable": {
+  "E": "#00: E (E.cpp:99)",
+  "F": "#00: F (F.cpp:99)",
+  "G": "#00: G (G.cpp:99)",
+  "H": "#00: H (H.cpp:99)",
+  "I": "#00: I (I.cpp:99)",
+  "J": "#00: J (J.cpp:99)",
+  "K": "#00: K (K.cpp:99)",
+  "L": "#00: L (L.cpp:99)",
+  "M": "#00: M (M.cpp:99)",
+  "N": "#00: N (N.cpp:99)",
+  "O": "#00: O (O.cpp:99)",
+  "P": "#00: P (P.cpp:99)",
+  "Q": "#00: Q (Q.cpp:99)",
+  "R": "#00: R (R.cpp:99)",
+  "S": "#00: S (S.cpp:99)",
+  "T": "#00: T (T.cpp:99)",
+  "U": "#00: U (U.cpp:99)",
+  "V": "#00: V (V.cpp:99)",
+  "W": "#00: W (W.cpp:99)",
+  "X": "#00: X (X.cpp:99)",
+  "Y": "#00: Y (Y.cpp:99)",
+  "Z": "#00: Z (Z.cpp:99)"
+ }
+}
new file mode 100644
--- /dev/null
+++ b/memory/replace/dmd/test/script-show-all-block-sizes-expected.txt
@@ -0,0 +1,25 @@
+#-----------------------------------------------------------------
+
+Invocation {
+  $DMD = '1'
+  Sample-below size = 4093
+}
+
+#-----------------------------------------------------------------
+
+Live {
+  ~15 blocks in heap block record 1 of 1
+  ~1,343,470 bytes (~1,342,313 requested / ~1,157 slop)
+  100.00% of the heap (100.00% cumulative)
+  Individual block sizes: 1,048,576; 65,536 x 3; 40,960; 8,192 x 4; ~4,093 x 6
+  Allocated at {
+    #01: A (A.cpp:99)
+  }
+}
+
+#-----------------------------------------------------------------
+
+Summary {
+  Total: ~1,343,470 bytes in ~15 blocks
+}
+
new file mode 100644
--- /dev/null
+++ b/memory/replace/dmd/test/script-show-all-block-sizes.json
@@ -0,0 +1,35 @@
+{
+ "version": 1,
+ "invocation": {
+  "dmdEnvVar": "1",
+  "sampleBelowSize": 4093
+ },
+ "blockList": [
+  {"req": 1048576, "alloc": "A"},
+
+  {"req": 65536,            "alloc": "A"},
+  {"req": 65535, "slop": 1, "alloc": "A"},
+  {"req": 65534, "slop": 2, "alloc": "A"},
+
+  {"req": 40000, "slop": 960, "alloc": "A"},
+
+  {"req": 8192,              "alloc": "A"},
+  {"req": 8192,              "alloc": "A"},
+  {"req": 8190, "slop":   2, "alloc": "A"},
+  {"req": 8000, "slop": 192, "alloc": "A"},
+
+  {"alloc": "A"},
+  {"alloc": "A"},
+  {"alloc": "A"},
+  {"alloc": "A"},
+  {"alloc": "A"},
+  {"alloc": "A"}
+ ],
+ "traceTable": {
+  "A": ["AA"]
+ },
+ "frameTable": {
+  "AA": "#00: A (A.cpp:99)"
+ }
+}
+
new file mode 100644
--- /dev/null
+++ b/memory/replace/dmd/test/script-sort-by-req-expected.txt
@@ -0,0 +1,42 @@
+#-----------------------------------------------------------------
+
+Invocation {
+  $DMD = '1'
+  Sample-below size = 1
+}
+
+#-----------------------------------------------------------------
+
+Live {
+  5 blocks in heap block record 1 of 3
+  16,392 bytes (16,392 requested / 0 slop)
+  33.33% of the heap (33.33% cumulative)
+  Allocated at {
+    #01: A (A.cpp:99)
+  }
+}
+
+Live {
+  5 blocks in heap block record 2 of 3
+  16,400 bytes (12,016 requested / 4,384 slop)
+  33.35% of the heap (66.68% cumulative)
+  Allocated at {
+    #01: B (B.cpp:99)
+  }
+}
+
+Live {
+  4 blocks in heap block record 3 of 3
+  16,384 bytes (8,196 requested / 8,188 slop)
+  33.32% of the heap (100.00% cumulative)
+  Allocated at {
+    #01: C (C.cpp:99)
+  }
+}
+
+#-----------------------------------------------------------------
+
+Summary {
+  Total: 49,176 bytes in 14 blocks
+}
+
new file mode 100644
--- /dev/null
+++ b/memory/replace/dmd/test/script-sort-by-slop-expected.txt
@@ -0,0 +1,42 @@
+#-----------------------------------------------------------------
+
+Invocation {
+  $DMD = '1'
+  Sample-below size = 1
+}
+
+#-----------------------------------------------------------------
+
+Live {
+  4 blocks in heap block record 1 of 3
+  16,384 bytes (8,196 requested / 8,188 slop)
+  33.32% of the heap (33.32% cumulative)
+  Allocated at {
+    #01: C (C.cpp:99)
+  }
+}
+
+Live {
+  5 blocks in heap block record 2 of 3
+  16,400 bytes (12,016 requested / 4,384 slop)
+  33.35% of the heap (66.67% cumulative)
+  Allocated at {
+    #01: B (B.cpp:99)
+  }
+}
+
+Live {
+  5 blocks in heap block record 3 of 3
+  16,392 bytes (16,392 requested / 0 slop)
+  33.33% of the heap (100.00% cumulative)
+  Allocated at {
+    #01: A (A.cpp:99)
+  }
+}
+
+#-----------------------------------------------------------------
+
+Summary {
+  Total: 49,176 bytes in 14 blocks
+}
+
new file mode 100644
--- /dev/null
+++ b/memory/replace/dmd/test/script-sort-by-usable-expected.txt
@@ -0,0 +1,42 @@
+#-----------------------------------------------------------------
+
+Invocation {
+  $DMD = '1'
+  Sample-below size = 1
+}
+
+#-----------------------------------------------------------------
+
+Live {
+  5 blocks in heap block record 1 of 3
+  16,400 bytes (12,016 requested / 4,384 slop)
+  33.35% of the heap (33.35% cumulative)
+  Allocated at {
+    #01: B (B.cpp:99)
+  }
+}
+
+Live {
+  5 blocks in heap block record 2 of 3
+  16,392 bytes (16,392 requested / 0 slop)
+  33.33% of the heap (66.68% cumulative)
+  Allocated at {
+    #01: A (A.cpp:99)
+  }
+}
+
+Live {
+  4 blocks in heap block record 3 of 3
+  16,384 bytes (8,196 requested / 8,188 slop)
+  33.32% of the heap (100.00% cumulative)
+  Allocated at {
+    #01: C (C.cpp:99)
+  }
+}
+
+#-----------------------------------------------------------------
+
+Summary {
+  Total: 49,176 bytes in 14 blocks
+}
+
new file mode 100644
--- /dev/null
+++ b/memory/replace/dmd/test/script-sort-by.json
@@ -0,0 +1,35 @@
+{
+ "version": 1,
+ "invocation": {
+  "dmdEnvVar": "1",
+  "sampleBelowSize": 1
+ },
+ "blockList": [
+  {"req": 4096, "alloc": "A"},
+  {"req": 4096, "alloc": "A"},
+  {"req": 4096, "alloc": "A"},
+  {"req": 4096, "alloc": "A"},
+  {"req": 8,    "alloc": "A"},
+
+  {"req": 3000, "slop": 1096, "alloc": "B"},
+  {"req": 3000, "slop": 1096, "alloc": "B"},
+  {"req": 3000, "slop": 1096, "alloc": "B"},
+  {"req": 3000, "slop": 1096, "alloc": "B"},
+  {"req": 16,                 "alloc": "B"},
+
+  {"req": 2049, "slop": 2047, "alloc": "C"},
+  {"req": 2049, "slop": 2047, "alloc": "C"},
+  {"req": 2049, "slop": 2047, "alloc": "C"},
+  {"req": 2049, "slop": 2047, "alloc": "C"}
+ ],
+ "traceTable": {
+  "A": ["AA"],
+  "B": ["BB"],
+  "C": ["CC"]
+ },
+ "frameTable": {
+  "AA": "#00: A (A.cpp:99)",
+  "BB": "#00: B (B.cpp:99)",
+  "CC": "#00: C (C.cpp:99)"
+ }
+}
--- a/memory/replace/dmd/test/test_dmd.js
+++ b/memory/replace/dmd/test/test_dmd.js
@@ -1,14 +1,16 @@
 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*-*/
 /* vim: set ts=8 sts=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/. */
 
+"use strict";
+
 const {classes: Cc, interfaces: Ci, utils: Cu} = Components
 
 Cu.import("resource://gre/modules/FileUtils.jsm");
 
 // The xpcshell test harness sets PYTHON so we can read it here.
 let gEnv = Cc["@mozilla.org/process/environment;1"]
              .getService(Ci.nsIEnvironment);
 let gPythonName = gEnv.get("PYTHON");
@@ -20,25 +22,21 @@ if (!gDmdScriptFile.exists()) {
   gDmdScriptFile = FileUtils.getFile("CurWorkD", []);
   while (gDmdScriptFile.path.contains("xpcshell")) {
     gDmdScriptFile = gDmdScriptFile.parent;
   }
   gDmdScriptFile.append("bin");
   gDmdScriptFile.append("dmd.py");
 }
 
-function test(aJsonFile, aKind, aOptions, aN) {
+function test(aJsonFile, aPrefix, aOptions) {
   // DMD writes the JSON files to CurWorkD, so we do likewise here with
   // |actualFile| for consistency. It is removed once we've finished.
-  let expectedFile =
-    FileUtils.getFile("CurWorkD",
-                      ["full-" + aKind + "-expected" + aN + ".txt"]);
-  let actualFile =
-    FileUtils.getFile("CurWorkD",
-                      ["full-" + aKind + "-actual"   + aN + ".txt"]);
+  let expectedFile = FileUtils.getFile("CurWorkD", [aPrefix + "-expected.txt"]);
+  let actualFile   = FileUtils.getFile("CurWorkD", [aPrefix + "-actual.txt"]);
 
   // Run dmd.py on the JSON file, producing |actualFile|.
 
   let pythonFile = new FileUtils.File(gPythonName);
   let pythonProcess = Cc["@mozilla.org/process/util;1"]
                         .createInstance(Components.interfaces.nsIProcess);
   pythonProcess.init(pythonFile);
 
@@ -59,29 +57,65 @@ function test(aJsonFile, aKind, aOptions
   let diffProcess = Cc["@mozilla.org/process/util;1"]
                       .createInstance(Components.interfaces.nsIProcess);
   // XXX: this doesn't work on Windows (bug 1076446).
   diffProcess.init(diffFile);
 
   args = ["-u", expectedFile.path, actualFile.path];
   diffProcess.run(/* blocking = */true, args, args.length);
   let success = diffProcess.exitValue == 0;
-  ok(success, aKind + " " + aN);
+  ok(success, aPrefix);
 
   actualFile.remove(true);
 }
 
 function run_test() {
+  let jsonFile;
+
   // These tests do full end-to-end testing of DMD, i.e. both the C++ code that
   // generates the JSON output, and the script that post-processes that output.
   // The test relies on DMD's test mode executing beforehand, in order to
   // produce the relevant JSON files.
   //
   // Run these synchronously, because test() updates the full*.json files
   // in-place (to fix stacks) when it runs dmd.py, and that's not safe to do
   // asynchronously.
-  for (let i = 1; i <= 4; i++) {
-      let jsonFile = FileUtils.getFile("CurWorkD", ["full" + i + ".json"]);
-      test(jsonFile, "heap", ["--ignore-reports"], i);
-      test(jsonFile, "reports", [], i);
+  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(jsonFile, "full-heap-" + name, ["--ignore-reports"])
+      test(jsonFile, "full-reports-" + name, [])
       jsonFile.remove(true);
   }
+
+  // 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
+  // explanations here.
+
+  // This just tests that stack traces of various lengths are truncated
+  // appropriately. The number of records in the output is different for each
+  // of the tested values.
+  jsonFile = FileUtils.getFile("CurWorkD", ["script-max-frames.json"]);
+  test(jsonFile, "script-max-frames-8", ["-r", "--max-frames=8"]);
+  test(jsonFile, "script-max-frames-3", ["-r", "--max-frames=3",
+                                         "--no-fix-stacks"]);
+  test(jsonFile, "script-max-frames-1", ["-r", "--max-frames=1"]);
+
+  // This test has three records that are shown in a different order for each
+  // of the different sort values.
+  jsonFile = FileUtils.getFile("CurWorkD", ["script-sort-by.json"]);
+  test(jsonFile, "script-sort-by-usable", ["-r", "--sort-by=usable"]);
+  test(jsonFile, "script-sort-by-req",    ["-r", "--sort-by=req",
+                                           "--no-fix-stacks"]);
+  test(jsonFile, "script-sort-by-slop",   ["-r", "--sort-by=slop"]);
+
+  // This test 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(jsonFile, "script-ignore-alloc-fns", ["-r", "--ignore-alloc-fns"]);
+
+  // This test has numerous allocations of different sizes, some repeated, some
+  // sampled, that all end up in the same record.
+  jsonFile = FileUtils.getFile("CurWorkD", ["script-show-all-block-sizes.json"]);
+  test(jsonFile, "script-show-all-block-sizes", ["-r", "--show-all-block-sizes"]);
 }
--- a/memory/replace/dmd/test/xpcshell.ini
+++ b/memory/replace/dmd/test/xpcshell.ini
@@ -1,16 +1,28 @@
 [DEFAULT]
 support-files =
-  full-heap-expected1.txt
-  full-heap-expected2.txt
-  full-heap-expected3.txt
-  full-heap-expected4.txt
-  full-reports-expected1.txt
-  full-reports-expected2.txt
-  full-reports-expected3.txt
-  full-reports-expected4.txt
+  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
+  script-max-frames.json
+  script-max-frames-8-expected.txt
+  script-max-frames-3-expected.txt
+  script-max-frames-1-expected.txt
+  script-sort-by.json
+  script-sort-by-usable-expected.txt
+  script-sort-by-req-expected.txt
+  script-sort-by-slop-expected.txt
+  script-ignore-alloc-fns.json
+  script-ignore-alloc-fns-expected.txt
+  script-show-all-block-sizes.json
+  script-show-all-block-sizes-expected.txt
 
 # Bug 1077230 explains why this test is disabled on Mac 10.6.
 # Bug 1076446 is open for getting this test working on on Windows.
 [test_dmd.js]
 dmd = true
 run-if = os == 'linux' || os == 'mac' && os_version != '10.6'