Repository: LLNL/Caliper (language: python)

Issue:
Bug in loop-report when using blank space
There seems to be a bug in loop-report if there is a blank space in the name of the loop. In that case, the `Loop summary` works fine but the `Iteration summary` does not print anything. The `cxx-example` uses `mainloop` and everything works fine:
```
./cxx-example -P loop-report 5000

Loop summary:
------------

Loop     Iterations Time (s) Iter/s (min) Iter/s (max) Iter/s (avg)
mainloop       5000 7.020397   371.149326  2408.294927   690.052330

Iteration summary (mainloop):
-----------------

Block Iterations Time (s) Iter/s
    0       1205 0.500354 2408.294927
 1205        555 0.500450 1109.001898
 1760        436 0.500720  870.746126
 2196        367 0.500213  733.687449
 2563        327 0.500546  653.286611
 2890        296 0.501063  590.744078
 3186        273 0.500636  545.306370
 3459        255 0.501695  508.276941
 3714        239 0.501501  476.569339
 3953        233 0.500510  465.525164
 4186        218 0.501248  434.914454
 4404        206 0.502460  409.982884
 4610        197 0.500139  393.890498
 4807        190 0.500779  379.408881
 4997          3 0.008083  371.149326 
```
If I just change `mainloop` to `main loop` and here is what I get:
```
./cxx-example -P loop-report 5000

Loop summary:
------------

Loop      Iterations Time (s) Iter/s (min) Iter/s (max) Iter/s (avg)
main loop       5000 7.041216   373.641304  2430.606873   689.089144

Iteration summary (main loop):
-----------------

Block Iterations Time (s) Iter/s
```


Discussion / hints:

Fix patch:
diff --git a/src/mpi/controllers/LoopReportController.cpp b/src/mpi/controllers/LoopReportController.cpp
index f38150b3f..da9957a96 100644
--- a/src/mpi/controllers/LoopReportController.cpp
+++ b/src/mpi/controllers/LoopReportController.cpp
@@ -173,7 +173,7 @@ class LoopReportController : public cali::ChannelController
                 { "let",      block   },
                 { "select",   select  },
                 { "group by", "Block" },
-                { "where",    std::string("loop=")+loopname }
+                { "where",    std::string("loop=\"")+loopname+"\"" }
             }, false);
 
         return local_aggregate(c, db, CalQLParser(query.c_str()).spec());
diff --git a/src/mpi/controllers/SpotController.cpp b/src/mpi/controllers/SpotController.cpp
index 67f3ffa2f..ea7fd7f50 100644
--- a/src/mpi/controllers/SpotController.cpp
+++ b/src/mpi/controllers/SpotController.cpp
@@ -186,7 +186,7 @@ class SpotTimeseriesController : public cali::ChannelController
                 { "let",      block },
                 { "select",   select },
                 { "group by", "cali.channel,loop,block" },
-                { "where",    std::string("loop.start_iteration,loop=") + loopname }
+                { "where",    std::string("loop.start_iteration,loop=\"") + loopname + "\"" }
             }, false /* no aliases */);
 
         local_aggregate(query.c_str(), c, channel(), db, output_agg);


Test patch:
diff --git a/test/ci_app_tests/ci_test_macros.cpp b/test/ci_app_tests/ci_test_macros.cpp
index 85c5e7d36..4542eea08 100644
--- a/test/ci_app_tests/ci_test_macros.cpp
+++ b/test/ci_app_tests/ci_test_macros.cpp
@@ -61,7 +61,7 @@ int main(int argc, char* argv[])
             count = std::max(1, std::stoi(argv[3]));
     }
 
-    CALI_CXX_MARK_LOOP_BEGIN(mainloop, "mainloop");
+    CALI_CXX_MARK_LOOP_BEGIN(mainloop, "main loop");
 
     for (int i = 0; i < count; ++i) {
         CALI_CXX_MARK_LOOP_ITERATION(mainloop, i);
diff --git a/test/ci_app_tests/test_basictrace.py b/test/ci_app_tests/test_basictrace.py
index 575741836..df0bbe12a 100644
--- a/test/ci_app_tests/test_basictrace.py
+++ b/test/ci_app_tests/test_basictrace.py
@@ -230,8 +230,8 @@ def test_macros(self):
         self.assertTrue(cat.has_snapshot_with_attributes(
             snapshots, {
                 'function'   : 'main',
-                'loop'       : 'mainloop',
-                'iteration#mainloop' : '3' }))
+                'loop'       : 'main loop',
+                'iteration#main loop' : '3' }))
         self.assertTrue(cat.has_snapshot_with_attributes(
             snapshots, {
                 'function'   : 'main/foo',
@@ -244,7 +244,7 @@ def test_macros(self):
         self.assertTrue(cat.has_snapshot_with_attributes(
             snapshots, {
                 'function'   : 'main/foo',
-                'loop'       : 'mainloop/fooloop',
+                'loop'       : 'main loop/fooloop',
                 'iteration#fooloop' : '3' }))
 
     def test_property_override(self):
diff --git a/test/ci_app_tests/test_json.py b/test/ci_app_tests/test_json.py
index e2df18538..72f0ca89c 100644
--- a/test/ci_app_tests/test_json.py
+++ b/test/ci_app_tests/test_json.py
@@ -63,7 +63,7 @@ def test_jsontree(self):
 
         target_cmd = [ './ci_test_macros' ]
         query_cmd  = [ '../../src/tools/cali-query/cali-query',
-                       '-q', 'SELECT count(),sum(time.inclusive.duration),loop,iteration#mainloop group by loop,iteration#mainloop format json-split' ]
+                       '-q', 'SELECT count(),sum(time.inclusive.duration),loop,iteration#main\ loop group by loop,iteration#main\ loop format json-split' ]
 
         caliper_config = {
             'CALI_CONFIG_PROFILE'    : 'serial-trace',
@@ -77,7 +77,7 @@ def test_jsontree(self):
 
         columns = obj['columns']
 
-        self.assertEqual( { 'path', 'iteration#mainloop', 'count', 'sum#time.inclusive.duration' }, set(columns) )
+        self.assertEqual( { 'path', 'iteration#main loop', 'count', 'sum#time.inclusive.duration' }, set(columns) )
 
         data = obj['data']
 
@@ -92,13 +92,13 @@ def test_jsontree(self):
 
         nodes = obj['nodes']
 
-        self.assertEqual(nodes[0]['label' ], 'mainloop')
+        self.assertEqual(nodes[0]['label' ], 'main loop')
         self.assertEqual(nodes[0]['column'], 'path')
         self.assertEqual(nodes[1]['label' ], 'fooloop')
         self.assertEqual(nodes[1]['column'], 'path')
         self.assertEqual(nodes[1]['parent'], 0)
 
-        iterindex = columns.index('iteration#mainloop')
+        iterindex = columns.index('iteration#main loop')
 
         # Note: this is a pretty fragile test
         self.assertEqual(data[9][iterindex], 3)
diff --git a/test/ci_app_tests/test_loopreport.py b/test/ci_app_tests/test_loopreport.py
index 18071e8a9..b25f73cea 100644
--- a/test/ci_app_tests/test_loopreport.py
+++ b/test/ci_app_tests/test_loopreport.py
@@ -17,8 +17,8 @@ def test_loopreport_summary(self):
 
         log_targets = [
             'Loop summary:',
-            'Loop     Iterations Time (s)',
-            'mainloop         20'
+            'Loop      Iterations Time (s)',
+            'main loop         20'
         ]
 
         report_out,_ = cat.run_test(target_cmd, caliper_config)
@@ -40,7 +40,7 @@ def test_loopreport_timeseries(self):
         }
 
         log_targets = [
-            'Iteration summary (mainloop):',
+            'Iteration summary (main loop):',
             'Block Iterations Time (s)',
             '    0         15',
             '   30         15',
@@ -95,7 +95,7 @@ def test_loopreport_target_loop_selection(self):
 
         log_targets = [
             'Iteration summary (fooloop):',
-            'mainloop/fooloop        400',
+            'main loop/fooloop        400',
             'Block Iterations Time (s)',
             '    0        100',
             '    5        100',
diff --git a/test/ci_app_tests/test_monitor.py b/test/ci_app_tests/test_monitor.py
index e6e903cf3..12ce93ca5 100644
--- a/test/ci_app_tests/test_monitor.py
+++ b/test/ci_app_tests/test_monitor.py
@@ -14,7 +14,7 @@ def test_loopmonitor_iter_interval(self):
         caliper_config = {
             'CALI_SERVICES_ENABLE'   : 'loop_monitor,trace,report',
             'CALI_LOOP_MONITOR_ITERATION_INTERVAL' : '5',
-            'CALI_REPORT_CONFIG'     : 'select * where iteration#mainloop format expand',
+            'CALI_REPORT_CONFIG'     : 'select * where iteration#main\ loop format expand',
             'CALI_REPORT_FILENAME'   : 'stdout',
             'CALI_LOG_VERBOSITY'     : '0'
         }
@@ -24,8 +24,8 @@ def test_loopmonitor_iter_interval(self):
 
         self.assertTrue(len(snapshots) == 2)
         self.assertTrue(cat.has_snapshot_with_attributes(
-            snapshots, { 'iteration#mainloop' : '4',
-                         'loop.iterations'    : '5'
+            snapshots, { 'iteration#main loop' : '4',
+                         'loop.iterations'     : '5'
             }))
 
     def test_loopmonitor_time_interval(self):
@@ -67,16 +67,16 @@ def test_loopmonitor_target_loop(self):
 
         self.assertEqual(len(snapshots), 20)
         self.assertTrue(cat.has_snapshot_with_attributes(
-            snapshots, { 'iteration#mainloop' : '3',
-                         'iteration#fooloop'  : '4',
-                         'loop.iterations'    : '5',
-                         'loop'               : 'mainloop/fooloop'
+            snapshots, { 'iteration#main loop' : '3',
+                         'iteration#fooloop'   : '4',
+                         'loop.iterations'     : '5',
+                         'loop'                : 'main loop/fooloop'
             }))
         self.assertTrue(cat.has_snapshot_with_attributes(
-            snapshots, { 'iteration#mainloop' : '7',
-                         'iteration#fooloop'  : '9',
-                         'loop.iterations'    : '5',
-                         'loop'               : 'mainloop/fooloop'
+            snapshots, { 'iteration#main loop' : '7',
+                         'iteration#fooloop'   : '9',
+                         'loop.iterations'     : '5',
+                         'loop'                : 'main loop/fooloop'
             }))
 
     def test_regionmonitor_time_interval(self):
@@ -95,7 +95,7 @@ def test_regionmonitor_time_interval(self):
 
         self.assertTrue(len(snapshots) == 4)
         self.assertTrue(cat.has_snapshot_with_attributes(
-            snapshots, { 'loop'     : 'mainloop/fooloop',
+            snapshots, { 'loop'     : 'main loop/fooloop',
                          'function' : 'main/foo'
             }))
         self.assertFalse(cat.has_snapshot_with_attributes(
diff --git a/test/ci_app_tests/test_report.py b/test/ci_app_tests/test_report.py
index 3ecd0ccb3..d932e2b37 100644
--- a/test/ci_app_tests/test_report.py
+++ b/test/ci_app_tests/test_report.py
@@ -52,7 +52,7 @@ def test_report_nested_key(self):
 
         caliper_config = {
             'CALI_SERVICES_ENABLE'   : 'event,trace,report',
-            'CALI_REPORT_CONFIG'     : 'select *,count() group by prop:nested,iteration#mainloop format expand',
+            'CALI_REPORT_CONFIG'     : 'select *,count() group by prop:nested,iteration#main\ loop format expand',
             'CALI_LOG_VERBOSITY'     : '0'
         }
 
@@ -61,16 +61,16 @@ def test_report_nested_key(self):
 
         self.assertTrue(cat.has_snapshot_with_attributes(
             snapshots, { 'function'   : 'main/foo',
-                         'loop'       : 'mainloop',
+                         'loop'       : 'main loop',
                          'annotation' : 'pre-loop',
                          'statement'  : 'foo.init',
-                         'iteration#mainloop' : '2',
+                         'iteration#main loop' : '2',
                          'count'      : '1'
             }))
         self.assertTrue(cat.has_snapshot_with_attributes(
             snapshots, { 'function'   : 'main/foo',
-                         'loop'       : 'mainloop/fooloop',
-                         'iteration#mainloop' : '3',
+                         'loop'       : 'main loop/fooloop',
+                         'iteration#main loop' : '3',
                          'count'      : '9'
             }))
 
@@ -88,8 +88,8 @@ def test_report_class_iteration(self):
 
         self.assertTrue(cat.has_snapshot_with_attributes(
             snapshots, { 'function'   : 'main/foo',
-                         'loop'       : 'mainloop/fooloop',
-                         'iteration#mainloop' : '3',
+                         'loop'       : 'main loop/fooloop',
+                         'iteration#main loop' : '3',
                          'iteration#fooloop'  : '1',
                          'count'      : '1'
             }))
@@ -99,7 +99,7 @@ def test_report_aggregation_aliases(self):
 
         caliper_config = {
             'CALI_SERVICES_ENABLE'   : 'event,trace,report',
-            'CALI_REPORT_CONFIG'     : 'select *,count() as my\\ count\\ alias group by prop:nested,iteration#mainloop format expand',
+            'CALI_REPORT_CONFIG'     : 'select *,count() as my\\ count\\ alias group by prop:nested,iteration#main\ loop format expand',
             'CALI_LOG_VERBOSITY'     : '0'
         }
 
@@ -108,17 +108,17 @@ def test_report_aggregation_aliases(self):
 
         self.assertTrue(cat.has_snapshot_with_attributes(
             snapshots, { 'function'   : 'main/foo',
-                         'loop'       : 'mainloop',
+                         'loop'       : 'main loop',
                          'annotation' : 'pre-loop',
                          'statement'  : 'foo.init',
-                         'iteration#mainloop' : '2',
-                         'my count alias'     : '1'
+                         'iteration#main loop' : '2',
+                         'my count alias'      : '1'
             }))
         self.assertTrue(cat.has_snapshot_with_attributes(
             snapshots, { 'function'   : 'main/foo',
-                         'loop'       : 'mainloop/fooloop',
-                         'iteration#mainloop' : '3',
-                         'my count alias'     : '9'
+                         'loop'       : 'main loop/fooloop',
+                         'iteration#main loop' : '3',
+                         'my count alias'      : '9'
             }))
 
     def test_report_tree_formatter(self):
@@ -133,7 +133,7 @@ def test_report_tree_formatter(self):
         report_targets = [
             'Path             Count',
             'main                 1',
-            '  mainloop           5',
+            '  main loop          5',
             '    foo              4',
             '      fooloop       20',
             '      pre-loop       4',
@@ -161,9 +161,9 @@ def test_report_table_formatter(self):
         }
 
         report_targets = [
-            'loop             count',
-            'mainloop/fooloop     4',
-            'mainloop             1'
+            'loop              count',
+            'main loop/fooloop     4',
+            'main loop             1'
         ]
 
         report_output,_ = cat.run_test(target_cmd, caliper_config)
diff --git a/test/ci_app_tests/test_runtimereport.py b/test/ci_app_tests/test_runtimereport.py
index 4041a2e82..6b35fdb0c 100644
--- a/test/ci_app_tests/test_runtimereport.py
+++ b/test/ci_app_tests/test_runtimereport.py
@@ -18,7 +18,7 @@ def test_runtime_report_default(self):
         log_targets = [
             'Path',
             'main',
-            '  mainloop',
+            '  main loop',
             '    foo',
             '      fooloop'
         ]
@@ -43,7 +43,7 @@ def test_runtime_report_nompi(self):
         log_targets = [
             'Time (E) Time (I) Time % (E) Time % (I)',
             'main',
-            '  mainloop',
+            '  main loop',
             '    foo',
             '      fooloop'
         ]
diff --git a/test/ci_app_tests/test_textlog.py b/test/ci_app_tests/test_textlog.py
index f65d593f0..ae9c91fe7 100644
--- a/test/ci_app_tests/test_textlog.py
+++ b/test/ci_app_tests/test_textlog.py
@@ -12,8 +12,8 @@ def test_textlog(self):
 
         caliper_config = {
             'CALI_SERVICES_ENABLE'      : 'event,textlog',
-            'CALI_TEXTLOG_TRIGGER'      : 'iteration#mainloop',
-            'CALI_TEXTLOG_FORMATSTRING' : '%function% iteration: %[2]iteration#mainloop',
+            'CALI_TEXTLOG_TRIGGER'      : 'iteration#main\ loop',
+            'CALI_TEXTLOG_FORMATSTRING' : '%function% iteration: %[2]iteration#main loop%',
             'CALI_LOG_VERBOSITY'        : '0',
         }
 
@@ -44,7 +44,7 @@ def test_textlog_autostring(self):
         }
 
         log_targets = [
-            'loop=mainloop/fooloop'
+            'loop=main loop/fooloop'
         ]
 
         report_out,_ = cat.run_test(target_cmd, caliper_config)