Index: tests/zombies/string-perf/prog.cfa
===================================================================
--- tests/zombies/string-perf/prog.cfa	(revision 01db3013a1860498b8e5281ebd2e0dab01171bf5)
+++ tests/zombies/string-perf/prog.cfa	(revision 4d0eb1cc12137b66f31427f1f5dad58df3bae128)
@@ -5,18 +5,23 @@
   #include <cstdio>
   using namespace std;
+  #define IMPL_CXX
 
 #elif defined IMPL_CFA_HL_SHARE
   #define IMPL_CFA_HL
+  #define IMPL_CFA
 
 #elif defined IMPL_CFA_LL_SHARE
   #define IMPL_CFA_LL
+  #define IMPL_CFA
 
 #elif defined IMPL_CFA_HL_NOSHARE
   #define IMPL_CFA_HL
   #define CFA_NOSHARE
+  #define IMPL_CFA
 
 #elif defined IMPL_CFA_LL_NOSHARE
   #define IMPL_CFA_LL
   #define CFA_NOSHARE
+  #define IMPL_CFA
 
 #elif defined IMPL_BUHR94
@@ -24,4 +29,5 @@
   #include <cstdio>
   #include "/u0/mlbrooks/usys1/sm/string/StringSharing/src/string.h"
+  #define IMPL_CXX
 
 #else
@@ -44,7 +50,14 @@
 #endif
 
+#if defined IMPL_CFA
+  #include <math.hfa>
+#elif defined IMPL_CXX
+  #include <algorithm>
+  using std::min;
+#endif
 
 #include <time.h>
-
+#include <stdlib.h> // atoi
+#include <string.h> // strlen, only during setup
 
 #if defined IMPL_STL || defined IMPL_BUHR94
@@ -56,4 +69,12 @@
 #endif
 
+double meanLen(int N, char ** strings) {
+    int totalLen = 0;
+    for (int i = 0 ; i < N; i ++) {
+        totalLen += strlen(strings[i]);
+    }
+    return (double)totalLen / (double)N;
+}
+
 volatile int checkthis = 0;
 #define MAYBE( op ) if (checkthis) { op; }
@@ -61,19 +82,39 @@
 int main( int argc, char ** argv ) {
 
-        STRING_SHARING_CONTROL
+    STRING_SHARING_CONTROL
 
-        enum { NumConcats = 100, Times = 5000000 };
-        clock_t start, end;
 
-    int corpuslen = argc - 1;
-    char ** corpus = argv + 1;
+    const char * usage_args = "ConcatsPerReset ExecTimeSecs Corpus...";
+    const int static_arg_posns = 3;
+
+    int concatsPerReset = -1, execTimeSecs = -1;
+
+    switch (min(argc, static_arg_posns)) {
+      case 3: execTimeSecs = atoi(argv[2]);
+      case 2: concatsPerReset = atoi(argv[1]);
+    }
+
+    int corpuslen = argc - static_arg_posns;
+    char ** corpus = argv + static_arg_posns;
+
+    if (execTimeSecs < 1 || concatsPerReset < 1 || corpuslen < 1) {
+      printf("usage: %s %s\n", argv[0], usage_args);
+      printf("output:\nconcatsPerReset,corpusItemCount,corpusMeanLenChars,concatDoneActualCount,execTimeActualSec\n");
+      exit(1);
+    }
+
+    double meanCorpusLen = meanLen(corpuslen, corpus);
+
+    clock_t start, end_target, end_actual;
 
     #if defined IMPL_CFA_LL
-        string_res x = "foo2";
+        string_res x = "starter";
         string_res y;
+      #if defined OP_PLUS_THEN_ASSIGN
         string_res z;
+      #endif
         #define RESET y = x;
     #else
-        string x = "foo2";
+        string x = "starter";
         string y;
         #define RESET y = x;
@@ -81,9 +122,11 @@
 
     start = clock();
-    for ( volatile unsigned int t = 0; t < Times; t += 1 ) {
+    end_target = start + CLOCKS_PER_SEC * execTimeSecs;
+    volatile unsigned int t = 0;
+    for ( ; t % 100 != 0 || clock() < end_target ; t += 1 ) {
             RESET
-            for ( volatile unsigned int i = 0; i < NumConcats; i += 1 ) {
+            for ( volatile unsigned int i = 0; i < concatsPerReset; i += 1 ) {
               MAYBE( PRINT(y) )
-              char *toAppend = corpus[i%corpuslen];
+              char *toAppend = corpus[i % corpuslen]; // ? corpus[rand() % corpuslen]
               #if defined OP_PLUS_THEN_ASSIGN && defined IMPL_CFA_LL
                  z = y;
@@ -97,7 +140,8 @@
             }
     }
-    end = clock();
-    double elapsed = ((double) (end - start)) / CLOCKS_PER_SEC;
-    printf("%f sec\n", elapsed);
+    end_actual = clock();
+    unsigned int concatsDone = t * concatsPerReset;
+    double elapsed = ((double) (end_actual - start)) / CLOCKS_PER_SEC;
+    printf("%d,%d,%f,%d,%f\n", concatsPerReset, corpuslen, meanCorpusLen, concatsDone, elapsed);
 
     return 0;
