Index: doc/theses/mike_brooks_MMath/benchmarks/string/Makefile
===================================================================
--- doc/theses/mike_brooks_MMath/benchmarks/string/Makefile	(revision f85de474d7bae82407a8ea5f1551da282d77d9bd)
+++ doc/theses/mike_brooks_MMath/benchmarks/string/Makefile	(revision 7d02d35a7f30abbea5194b398c84870163fbe5dd)
@@ -1,2 +1,12 @@
+# Usage
+# $cfabuild/driver/cfa -nodebug -quiet -c -x c /dev/null && rm null.o || echo Need to fix \$cfabuild
+# make CFABUILD=$cfabuild -j8															     											# compile
+# make measurement  CFA_APILEVELS=ll OPERATIONS='pta peq pbv'                             CORPORI='corpus-100-*-1.txt corpus-1-*-1.txt'	# append-pbv
+# make measurement2 CFA_APILEVELS=ll OPERATIONS='pall' PLATFORMS=cfa CFA_SHARINGS=share   CORPORI='corpus-1-*-1.txt'						# allocate-speed-cfa
+# make measurement2 CFA_APILEVELS=ll OPERATIONS='pall' PLATFORMS=stl CFA_EXPANSIONS=-1.0  CORPORI='corpus-1-*-1.txt'						# allocate-speed-stl
+# make measurement3 CFA_APILEVELS=ll OPERATIONS='pall' PLATFORMS=cfa CFA_SHARINGS=share   CORPORI='corpus-1-*-1.txt'						# allocate-space-cfa
+# make measurement3 CFA_APILEVELS=ll OPERATIONS='pall' PLATFORMS=stl CFA_EXPANSIONS=-1.0  CORPORI='corpus-1-*-1.txt'						# allocate-space-stl
+# make measurement4 CFA_APILEVELS=ll OPERATIONS='pall' PLATFORMS=cfa CFA_EXPANSIONS=0.2   CFA_SHARINGS=share   CORPORI='corpus-1-*-1.txt'	# allocate-attrib-cfa
+# make measurement4 CFA_APILEVELS=ll OPERATIONS='pall' PLATFORMS=stl CFA_EXPANSIONS=-1.0                       CORPORI='corpus-1-*-1.txt'	# allocate-attrib-stl
 
 CFABUILD = ~/cfa2/build-perf
@@ -37,9 +47,9 @@
 endef
 
-OPERATIONS=pta peq pbv pall pno
+OPERATIONS=pta peq pbv pall #pno
 ALLOCS=reuse fresh
 CFA_APILEVELS=hl ll
 CFA_SHARINGS=share noshare
-PLATFORMS=cfa stl buhr94
+PLATFORMS=cfa stl #buhr94
 
 ifneq ($(filter cfa,$(PLATFORMS)),)
@@ -142,4 +152,8 @@
 CORPORI = corpus-100-*-1.txt
 
+RUN_TASKSET_CPULIST=6
+
+# General timing
+# Output file gets concatenation of program outputs
 measurement: $(MEASURE)
 	tofile=measurement-`date '+%F--%H-%M-%S'`.csv ; \
@@ -148,13 +162,14 @@
 	    for corpus in $(CORPORI) ; do \
 			corpusbody=`cat $$corpus` ; \
-			printed=`./$$prog 100 10 $$corpusbody` ; \
-			echo $$prog,$$corpus,$$printed  >>  $$tofile ; \
-			echo $$prog,$$corpus,$$printed  ; \
-		done ; \
-	done
-#			printed=`./$$prog 10000 - 10 $$corpusbody` ; \
-
-CFA_EXPANSIONS=0.02 0.05 0.1 0.2 0.5 0.9
-
+			resulttext=`taskset --cpu-list $(RUN_TASKSET_CPULIST) ./$$prog 100 10 $$corpusbody` ; \
+			echo $$prog,$$corpus,$$resulttext  >>  $$tofile ; \
+			echo $$prog,$$corpus,$$resulttext  ; \
+		done ; \
+	done
+
+CFA_EXPANSIONS=0.02 0.05 0.1 0.2 0.4 0.5 0.9 0.98
+
+# Special-case timing with extra IV for CFA_EXPANSIONS
+# Output file gets concatenation of program outputs (one line per run)
 measurement2: $(MEASURE)
 	tofile=measurement-`date '+%F--%H-%M-%S'`.csv ; \
@@ -179,12 +194,43 @@
 	done
 
+# Space, with the IV for CFA_EXPANSIONS
+# Runs Mubeen's malloc interceptor to get malloc-request state
+# Output file gets concatenation of the interceptor's output (one line per run); program's output ignorred
+# Expect and ignore crashes; they're during shutdown, after everything we care about is over
 measurement3: $(MEASURE)
+	tofile=measurement-`date '+%F--%H-%M-%S'`.ssv ; \
 	for prog in $(MEASURE) ; do \
 	    for corpus in $(CORPORI) ; do \
 			for expansion in $(CFA_EXPANSIONS) ; do \
 				corpusbody=`cat $$corpus` ; \
-				LD_PRELOAD=~/plg2/mubeen-stat-shim/malloc/mallocWrappers.so ./$$prog 1000 1.006 $$expansion 1 $$corpusbody ; \
-				mv preload_dump.txt preload_dump--qrun1--$$corpus--expansion-$$expansion.txt ; \
-			done ; \
-		done ; \
-	done
+				LD_PRELOAD=~/plg2/mubeen-stat-shim/malloc/mallocWrappers.so ./$$prog 1000 1.006 $$expansion 10 $$corpusbody ; \
+				printed=`tail -n 1 preload_dump.txt` ; \
+				echo $$prog $$corpus $$expansion $$printed  >>  $$tofile ; \
+				echo $$prog $$corpus $$expansion $$printed  ; \
+				rm preload_dump.txt ; \
+			done ; \
+		done ; \
+	done
+
+# Time attribution, with the IV for CFA_EXPANSIONS
+# Runs the SUT under perf, then crunches the perf result
+# Output file gets concatenation of perf summaries (several lines per run); program's output ignorred
+# Expect and ignore output "addr2line: DWARF error: section .debug_info is larger than its filesize!"
+measurement4: $(MEASURE)
+	RUNID=`date '+%F--%H-%M-%S'` ; \
+	tofile=measurement-$$RUNID.ssv ; \
+	echo $$tofile ; \
+	for prog in $(MEASURE) ; do \
+	    for corpus in $(CORPORI) ; do \
+			for expansion in $(CFA_EXPANSIONS) ; do \
+				SLUG=measurement--$$prog--$$corpus--$$expansion--$$RUNID ; \
+				corpusbody=`cat $$corpus` ; \
+				perf record --call-graph dwarf -m16M ./$$prog 1000 1.006 $$expansion 10 $$corpusbody ; \
+				mv perf.data $$SLUG.data ; \
+				perf script -i $$SLUG.data > $$SLUG.perf ; \
+				~/flamegraph/FlameGraph/stackcollapse-perf.pl $$SLUG.perf > $$SLUG.folded ; \
+				~/flamegraph/FlameGraph/flamegraph.pl $$SLUG.folded > $$SLUG.svg ; \
+				python3 process-allocn-attrib.py $$SLUG.folded | xargs -L1 echo $$prog $$corpus $$expansion >> $$tofile ; \
+			done ; \
+		done ; \
+	done
Index: doc/theses/mike_brooks_MMath/benchmarks/string/make-flamegraph.sh
===================================================================
--- doc/theses/mike_brooks_MMath/benchmarks/string/make-flamegraph.sh	(revision f85de474d7bae82407a8ea5f1551da282d77d9bd)
+++ doc/theses/mike_brooks_MMath/benchmarks/string/make-flamegraph.sh	(revision 7d02d35a7f30abbea5194b398c84870163fbe5dd)
@@ -10,7 +10,9 @@
 # $3 is coprus id  : x-100-20-1  (goes with corpusx-100-20-1.txt)
 
-SLUG=perf--$1--${2//[ .]/-}--$3
+SLUG=perf--$1--${2//[ .]/-}--$3--`date '+%F--%H-%M-%S'`
+benchdir=$(dirname "$0")
+echo benchdir = $benchdir
 
-perf record --call-graph dwarf -m16M ~/plg2/cfa2/cfa-cc/tests/zombies/string-perf/perfexp-$1 $2 `cat ~/plg2/cfa2/cfa-cc/tests/zombies/string-perf/corpus$3.txt`
+perf record --call-graph dwarf -m16M $benchdir/perfexp-$1 $2 `cat $benchdir/corpus$3.txt`
 
 mv perf.data $SLUG.data
@@ -18,3 +20,3 @@
 ../flamegraph/FlameGraph/stackcollapse-perf.pl $SLUG.perf > $SLUG.folded
 ../flamegraph/FlameGraph/flamegraph.pl $SLUG.folded > $SLUG.svg
-cp $SLUG.svg ~/plg2/flames
+#cp $SLUG.svg ~/plg2/flames
Index: doc/theses/mike_brooks_MMath/benchmarks/string/process-allocn-attrib.py
===================================================================
--- doc/theses/mike_brooks_MMath/benchmarks/string/process-allocn-attrib.py	(revision 7d02d35a7f30abbea5194b398c84870163fbe5dd)
+++ doc/theses/mike_brooks_MMath/benchmarks/string/process-allocn-attrib.py	(revision 7d02d35a7f30abbea5194b398c84870163fbe5dd)
@@ -0,0 +1,107 @@
+import sys
+import re
+import pandas as pd
+from collections import defaultdict
+
+# Matched top to bottom, bailing on first match
+# More general rules are not double-counted if they occur later
+# Such cases are commented "overlap"; don't move those too far up
+CATEGORY_RULES = {
+    "text-import": [
+        "_X19eagerCopyCtorHelperFv_S10string_resPKcm__1;_X12_constructorFv_S10string_resPKcm__1;__memmove_ssse3",
+        "_X19eagerCopyCtorHelperFv_S10string_resPKcm__1;_X12_constructorFv_S10string_resPKcm__1;__memcpy_ssse3",
+        "helper;__memcpy_ssse3",
+#        "strlen"
+    ],
+    "gc": [
+        "_X19eagerCopyCtorHelperFv_S10string_resPKcm__1;_X12_constructorFv_S10string_resPKcm__1;_X7garbageFv_S9VbyteHeapi__1"
+    ],
+    "malloc-free": [
+        "operator new;_X8doMallocFPv_mj__1",
+        "operator new;malloc",
+        "_X6doFreeFv_Pv__1",
+        "free"
+    ],
+    "ctor-dtor": [
+        "std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_create",
+        "operator new", # overlap stl malloc-free
+        "operator delete",
+        "_X12_constructorFv_S10string_resPKcm__1" # overlap cfa text import
+    ]
+}
+
+DEFAULT_CATEGORY = "other"
+
+def classify_stack(stack):
+    for category, patterns in CATEGORY_RULES.items():
+        for pattern in patterns:
+            if pattern in stack:
+                return category
+    if re.search(r"_X6helperFv_i__1$", stack):
+        return "harness-leaf"
+    if re.search(r"helper$", stack):
+        return "harness-leaf"
+    return DEFAULT_CATEGORY
+
+# def parse_sut_and_size(filename):
+#     # Extract SUT after "perfexp-" and before the next hyphen
+#     sut_match = re.search(r"perfexp-([a-zA-Z0-9]+)", filename)
+#     # Extract SIZE from "corpus-A-B-C.txt", capturing B
+#     size_match = re.search(r"corpus-\d+-(\d+)-\d+\.txt", filename)
+    
+#     if not sut_match or not size_match:
+#         print("Error: Could not parse sut or size from filename.")
+#         sys.exit(1)
+    
+#     return sut_match.group(1), size_match.group(1)
+
+def read_and_aggregate(input_file):
+    category_map = defaultdict(lambda: defaultdict(int))  # category -> lineno -> sample_count
+    total_samples = 0
+
+    with open(input_file) as f:
+        for lineno, line in enumerate(f, 1):
+            line = line.strip()
+            if not line:
+                continue
+            *stack_parts, count_str = line.split()
+            count = int(count_str)
+            stack = ' '.join(stack_parts)
+            category = classify_stack(stack)
+            category_map[category][lineno] += count
+            total_samples += count
+
+    return category_map, total_samples
+
+def flatten(category_map, total_samples): #, sut, size):
+    rows = []
+    for category, source_map in category_map.items():
+        samples_in_category = sum(source_map.values())
+        sources = "|".join(f"{lineno}:{count}" for lineno, count in source_map.items())
+        fraction = samples_in_category / total_samples if total_samples else 0.0
+        rows.append({
+#            "sut": sut,
+#            "size": size,
+            "category": category,
+            "samples_in_category": samples_in_category,
+            "total_samples": total_samples,
+            "fraction": fraction,
+            "sources": sources
+        })
+    return pd.DataFrame(rows)
+
+def main():
+    if len(sys.argv) != 2:
+        print("Usage: python3 process-allocn-attrib.py <input_file>")
+        sys.exit(1)
+
+    input_file = sys.argv[1]
+    # sut, size = parse_sut_and_size(input_file)
+    category_map, total_samples = read_and_aggregate(input_file)
+    df = flatten(category_map, total_samples) #, sut, size)
+
+    # Print the result to stdout in tab-separated format
+    df.to_csv(sys.stdout, sep="\t", index=False, header=False)
+
+if __name__ == "__main__":
+    main()
Index: doc/theses/mike_brooks_MMath/benchmarks/string/prog-allocn.cfa
===================================================================
--- doc/theses/mike_brooks_MMath/benchmarks/string/prog-allocn.cfa	(revision f85de474d7bae82407a8ea5f1551da282d77d9bd)
+++ doc/theses/mike_brooks_MMath/benchmarks/string/prog-allocn.cfa	(revision 7d02d35a7f30abbea5194b398c84870163fbe5dd)
@@ -42,10 +42,11 @@
 #endif
 
-
 #if defined IMPL_CFA_HL
   #include <string.hfa>
+  #include <fstream.hfa>
   extern void TUNING_set_string_heap_liveness_threshold(double);  // in string_res.hfa
 #elif defined IMPL_CFA_LL
   #include <string_res.hfa>
+  #include <fstream.hfa>
 #endif
 
Index: doc/theses/mike_brooks_MMath/benchmarks/string/prog-passbyval.cfa
===================================================================
--- doc/theses/mike_brooks_MMath/benchmarks/string/prog-passbyval.cfa	(revision f85de474d7bae82407a8ea5f1551da282d77d9bd)
+++ doc/theses/mike_brooks_MMath/benchmarks/string/prog-passbyval.cfa	(revision 7d02d35a7f30abbea5194b398c84870163fbe5dd)
@@ -45,6 +45,8 @@
 #if defined IMPL_CFA_HL
   #include <string.hfa>
+  #include <fstream.hfa>
 #elif defined IMPL_CFA_LL
   #include <string_res.hfa>
+  #include <fstream.hfa>
 #endif
 
Index: doc/theses/mike_brooks_MMath/benchmarks/string/prog.cfa
===================================================================
--- doc/theses/mike_brooks_MMath/benchmarks/string/prog.cfa	(revision f85de474d7bae82407a8ea5f1551da282d77d9bd)
+++ doc/theses/mike_brooks_MMath/benchmarks/string/prog.cfa	(revision 7d02d35a7f30abbea5194b398c84870163fbe5dd)
@@ -45,6 +45,8 @@
 #if defined IMPL_CFA_HL
   #include <string.hfa>
+  #include <fstream.hfa>
 #elif defined IMPL_CFA_LL
   #include <string_res.hfa>
+  #include <fstream.hfa>
 #endif
 
