Repository: elastic/rally

Issue:
Add total merges and refreshes in summary output
Currently our summary output includes sections like:

```
|   All |                   Total refresh time |                            |   131.531 |    min |
|   All |           Min refresh time per shard |                            |   43.0791 |    min |
|   All |        Median refresh time per shard |                            |   44.0437 |    min |
|   All |           Max refresh time per shard |                            |   44.4079 |    min |
```

i.e. only times not count.

Given #608 we can't rely too much on node-stats atm, so makes sense to also present the `Total refreshes` / `Total merges` (maybe an avg rate too based on total time?)


Discussion:
dliappis: @danielmitterdorfer in 3d12203 I switched to the new "cumulative" terminology from "totals" and made the clarifications for "across primary shards" for min/median/max metrics; would be appreciated if you could take a quick look before merge. 

Patch:
diff --git a/docs/metrics.rst b/docs/metrics.rst
index a7dd0ca6..bdc45bd9 100644
--- a/docs/metrics.rst
+++ b/docs/metrics.rst
@@ -143,13 +143,16 @@ Rally stores the following metrics:
 * ``segments_terms_memory_in_bytes``: Number of bytes used for terms as reported by the indices stats API.
 * ``segments_norms_memory_in_bytes``: Number of bytes used for norms as reported by the indices stats API.
 * ``segments_points_memory_in_bytes``: Number of bytes used for points as reported by the indices stats API.
-* ``merges_total_time``: Total runtime of merges as reported by the indices stats API. Note that this is not Wall clock time (i.e. if M merge threads ran for N minutes, we will report M * N minutes, not N minutes). These metrics records also have a ``per-shard`` property that contains the times per primary shard in an array.
-* ``merges_total_throttled_time``: Total time within merges have been throttled as reported by the indices stats API. Note that this is not Wall clock time.  These metrics records also have a ``per-shard`` property that contains the times per primary shard in an array.
-* ``indexing_total_time``: Total time used for indexing as reported by the indices stats API. Note that this is not Wall clock time.  These metrics records also have a ``per-shard`` property that contains the times per primary shard in an array.
-* ``indexing_throttle_time``: Total time that indexing has been throttled as reported by the indices stats API. Note that this is not Wall clock time.  These metrics records also have a ``per-shard`` property that contains the times per primary shard in an array.
-* ``refresh_total_time``: Total time used for index refresh as reported by the indices stats API. Note that this is not Wall clock time.  These metrics records also have a ``per-shard`` property that contains the times per primary shard in an array.
-* ``flush_total_time``: Total time used for index flush as reported by the indices stats API. Note that this is not Wall clock time.  These metrics records also have a ``per-shard`` property that contains the times per primary shard in an array.
+* ``merges_total_time``: Cumulative runtime of merges of primary shards, as reported by the indices stats API. Note that this is not Wall clock time (i.e. if M merge threads ran for N minutes, we will report M * N minutes, not N minutes). These metrics records also have a ``per-shard`` property that contains the times across primary shards in an array.
+* ``merges_total_count``: Cumulative number of merges of primary shards, as reported by indices stats API under ``_all/primaries``.
+* ``merges_total_throttled_time``: Cumulative time within merges have been throttled as reported by the indices stats API. Note that this is not Wall clock time.  These metrics records also have a ``per-shard`` property that contains the times across primary shards in an array.
+* ``indexing_total_time``: Cumulative time used for indexing of primary shards, as reported by the indices stats API. Note that this is not Wall clock time.  These metrics records also have a ``per-shard`` property that contains the times across primary shards in an array.
+* ``indexing_throttle_time``: Cumulative time that indexing has been throttled, as reported by the indices stats API. Note that this is not Wall clock time.  These metrics records also have a ``per-shard`` property that contains the times across primary shards in an array.
+* ``refresh_total_time``: Cumulative time used for index refresh of primary shards, as reported by the indices stats API. Note that this is not Wall clock time.  These metrics records also have a ``per-shard`` property that contains the times across primary shards in an array.
+* ``refresh_total_count``: Cumulative number of refreshes of primary shards, as reported by indices stats API under ``_all/primaries``.
+* ``flush_total_time``: Cumulative time used for index flush of primary shards, as reported by the indices stats API. Note that this is not Wall clock time.  These metrics records also have a ``per-shard`` property that contains the times across primary shards in an array.
+* ``flush_total_count``: Cumulative number of flushes of primary shards, as reported by indices stats API under ``_all/primaries``.
 * ``final_index_size_bytes``: Final resulting index size on the file system after all nodes have been shutdown at the end of the benchmark. It includes all files in the nodes' data directories (actual index files and translog).
-* ``store_size_in_bytes``: The size in bytes of the index (excluding the translog) as reported by the indices stats API.
-* ``translog_size_in_bytes``: The size in bytes of the translog as reported by the indices stats API.
+* ``store_size_in_bytes``: The size in bytes of the index (excluding the translog), as reported by the indices stats API.
+* ``translog_size_in_bytes``: The size in bytes of the translog, as reported by the indices stats API.
 * ``ml_processing_time``: A structure containing the minimum, mean, median and maximum bucket processing time in milliseconds per machine learning job. These metrics are only available if a machine learning job has been created in the respective benchmark.
diff --git a/docs/quickstart.rst b/docs/quickstart.rst
index cb833425..39314738 100644
--- a/docs/quickstart.rst
+++ b/docs/quickstart.rst
@@ -25,9 +25,10 @@ Run your first race
 
 Now we're ready to run our first :doc:`race </glossary>`::
 
-    esrally --distribution-version=6.0.0
+    esrally --distribution-version=6.5.3
+
+This will download Elasticsearch 6.5.3 and run Rally's default :doc:`track </glossary>` - the `geonames track <https://github.com/elastic/rally-tracks/tree/master/geonames>`_ - against it. After the race, a :doc:`summary report </summary_report>` is written to the command line:::
 
-This will download Elasticsearch 6.0.0 and run Rally's default :doc:`track </glossary>` - the `geonames track <https://github.com/elastic/rally-tracks/tree/master/geonames>`_ - against it. After the race, a :doc:`summary report </summary_report>` is written to the command line:::
 
     ------------------------------------------------------
         _______             __   _____
@@ -37,54 +38,81 @@ This will download Elasticsearch 6.0.0 and run Rally's default :doc:`track </glo
     /_/   /_/_/ /_/\__,_/_/   /____/\___/\____/_/   \___/
     ------------------------------------------------------
 
-    |                         Metric |                 Task |     Value |   Unit |
-    |-------------------------------:|---------------------:|----------:|-------:|
-    |            Total indexing time |                      |   28.0997 |    min |
-    |               Total merge time |                      |   6.84378 |    min |
-    |             Total refresh time |                      |   3.06045 |    min |
-    |               Total flush time |                      |  0.106517 |    min |
-    |      Total merge throttle time |                      |   1.28193 |    min |
-    |               Median CPU usage |                      |     471.6 |      % |
-    |             Total Young Gen GC |                      |    16.237 |      s |
-    |               Total Old Gen GC |                      |     1.796 |      s |
-    |                     Index size |                      |   2.60124 |     GB |
-    |                Totally written |                      |   11.8144 |     GB |
-    |         Heap used for segments |                      |   14.7326 |     MB |
-    |       Heap used for doc values |                      |  0.115917 |     MB |
-    |            Heap used for terms |                      |   13.3203 |     MB |
-    |            Heap used for norms |                      | 0.0734253 |     MB |
-    |           Heap used for points |                      |    0.5793 |     MB |
-    |    Heap used for stored fields |                      |  0.643608 |     MB |
-    |                  Segment count |                      |        97 |        |
-    |                 Min Throughput |         index-append |   31925.2 | docs/s |
-    |              Median Throughput |         index-append |   39137.5 | docs/s |
-    |                 Max Throughput |         index-append |   39633.6 | docs/s |
-    |      50.0th percentile latency |         index-append |   872.513 |     ms |
-    |      90.0th percentile latency |         index-append |   1457.13 |     ms |
-    |      99.0th percentile latency |         index-append |   1874.89 |     ms |
-    |       100th percentile latency |         index-append |   2711.71 |     ms |
-    | 50.0th percentile service time |         index-append |   872.513 |     ms |
-    | 90.0th percentile service time |         index-append |   1457.13 |     ms |
-    | 99.0th percentile service time |         index-append |   1874.89 |     ms |
-    |  100th percentile service time |         index-append |   2711.71 |     ms |
-    |                           ...  |                  ... |       ... |    ... |
-    |                           ...  |                  ... |       ... |    ... |
-    |                 Min Throughput |     painless_dynamic |   2.53292 |  ops/s |
-    |              Median Throughput |     painless_dynamic |   2.53813 |  ops/s |
-    |                 Max Throughput |     painless_dynamic |   2.54401 |  ops/s |
-    |      50.0th percentile latency |     painless_dynamic |    172208 |     ms |
-    |      90.0th percentile latency |     painless_dynamic |    310401 |     ms |
-    |      99.0th percentile latency |     painless_dynamic |    341341 |     ms |
-    |      99.9th percentile latency |     painless_dynamic |    344404 |     ms |
-    |       100th percentile latency |     painless_dynamic |    344754 |     ms |
-    | 50.0th percentile service time |     painless_dynamic |    393.02 |     ms |
-    | 90.0th percentile service time |     painless_dynamic |   407.579 |     ms |
-    | 99.0th percentile service time |     painless_dynamic |   430.806 |     ms |
-    | 99.9th percentile service time |     painless_dynamic |   457.352 |     ms |
-    |  100th percentile service time |     painless_dynamic |   459.474 |     ms |
+    |   Lap |                                                          Metric |                   Task |     Value |    Unit |
+    |------:|----------------------------------------------------------------:|-----------------------:|----------:|--------:|
+    |   All |                      Cumulative indexing time of primary shards |                        |   54.5878 |     min |
+    |   All |              Min cumulative indexing time across primary shards |                        |   10.7519 |     min |
+    |   All |           Median cumulative indexing time across primary shards |                        |   10.9219 |     min |
+    |   All |              Max cumulative indexing time across primary shards |                        |   11.1754 |     min |
+    |   All |             Cumulative indexing throttle time of primary shards |                        |         0 |     min |
+    |   All |     Min cumulative indexing throttle time across primary shards |                        |         0 |     min |
+    |   All |  Median cumulative indexing throttle time across primary shards |                        |         0 |     min |
+    |   All |     Max cumulative indexing throttle time across primary shards |                        |         0 |     min |
+    |   All |                         Cumulative merge time of primary shards |                        |   20.4128 |     min |
+    |   All |                        Cumulative merge count of primary shards |                        |       136 |         |
+    |   All |                 Min cumulative merge time across primary shards |                        |   3.82548 |     min |
+    |   All |              Median cumulative merge time across primary shards |                        |    4.1088 |     min |
+    |   All |                 Max cumulative merge time across primary shards |                        |   4.38148 |     min |
+    |   All |                Cumulative merge throttle time of primary shards |                        |   1.17975 |     min |
+    |   All |        Min cumulative merge throttle time across primary shards |                        |    0.1169 |     min |
+    |   All |     Median cumulative merge throttle time across primary shards |                        |   0.26585 |     min |
+    |   All |        Max cumulative merge throttle time across primary shards |                        |  0.291033 |     min |
+    |   All |                       Cumulative refresh time of primary shards |                        |    7.0317 |     min |
+    |   All |                      Cumulative refresh count of primary shards |                        |       420 |         |
+    |   All |               Min cumulative refresh time across primary shards |                        |   1.37088 |     min |
+    |   All |            Median cumulative refresh time across primary shards |                        |    1.4076 |     min |
+    |   All |               Max cumulative refresh time across primary shards |                        |   1.43343 |     min |
+    |   All |                         Cumulative flush time of primary shards |                        |  0.599417 |     min |
+    |   All |                        Cumulative flush count of primary shards |                        |        10 |         |
+    |   All |                 Min cumulative flush time across primary shards |                        | 0.0946333 |     min |
+    |   All |              Median cumulative flush time across primary shards |                        |  0.118767 |     min |
+    |   All |                 Max cumulative flush time across primary shards |                        |   0.14145 |     min |
+    |   All |                                                Median CPU usage |                        |     284.4 |       % |
+    |   All |                                              Total Young Gen GC |                        |    12.868 |       s |
+    |   All |                                                Total Old Gen GC |                        |     3.803 |       s |
+    |   All |                                                      Store size |                        |   3.17241 |      GB |
+    |   All |                                                   Translog size |                        |   2.62736 |      GB |
+    |   All |                                                      Index size |                        |   5.79977 |      GB |
+    |   All |                                                 Totally written |                        |   22.8536 |      GB |
+    |   All |                                          Heap used for segments |                        |   18.8885 |      MB |
+    |   All |                                        Heap used for doc values |                        | 0.0322647 |      MB |
+    |   All |                                             Heap used for terms |                        |   17.7184 |      MB |
+    |   All |                                             Heap used for norms |                        | 0.0723877 |      MB |
+    |   All |                                            Heap used for points |                        |  0.277171 |      MB |
+    |   All |                                     Heap used for stored fields |                        |  0.788307 |      MB |
+    |   All |                                                   Segment count |                        |        94 |         |
+    |   All |                                                  Min Throughput |           index-append |   38089.5 |  docs/s |
+    |   All |                                               Median Throughput |           index-append |   38613.9 |  docs/s |
+    |   All |                                                  Max Throughput |           index-append |   40693.3 |  docs/s |
+    |   All |                                         50th percentile latency |           index-append |   803.417 |      ms |
+    |   All |                                         90th percentile latency |           index-append |    1913.7 |      ms |
+    |   All |                                         99th percentile latency |           index-append |   3591.23 |      ms |
+    |   All |                                       99.9th percentile latency |           index-append |   6176.23 |      ms |
+    |   All |                                        100th percentile latency |           index-append |   6642.97 |      ms |
+    |   All |                                    50th percentile service time |           index-append |   803.417 |      ms |
+    |   All |                                    90th percentile service time |           index-append |    1913.7 |      ms |
+    |   All |                                    99th percentile service time |           index-append |   3591.23 |      ms |
+    |   All |                                  99.9th percentile service time |           index-append |   6176.23 |      ms |
+    |   All |                                   100th percentile service time |           index-append |   6642.97 |      ms |
+    |   All |                                                      error rate |           index-append |         0 |       % |
+    |   All |                                                            ...  |                    ... |       ... |     ... |
+    |   All |                                                            ...  |                    ... |       ... |     ... |
+    |   All |                                                  Min Throughput | large_prohibited_terms |         2 |   ops/s |
+    |   All |                                               Median Throughput | large_prohibited_terms |         2 |   ops/s |
+    |   All |                                                  Max Throughput | large_prohibited_terms |         2 |   ops/s |
+    |   All |                                         50th percentile latency | large_prohibited_terms |   344.429 |      ms |
+    |   All |                                         90th percentile latency | large_prohibited_terms |   353.187 |      ms |
+    |   All |                                         99th percentile latency | large_prohibited_terms |    377.22 |      ms |
+    |   All |                                        100th percentile latency | large_prohibited_terms |   392.918 |      ms |
+    |   All |                                    50th percentile service time | large_prohibited_terms |   341.177 |      ms |
+    |   All |                                    90th percentile service time | large_prohibited_terms |   349.979 |      ms |
+    |   All |                                    99th percentile service time | large_prohibited_terms |   374.958 |      ms |
+    |   All |                                   100th percentile service time | large_prohibited_terms |    388.62 |      ms |
+    |   All |                                                      error rate | large_prohibited_terms |         0 |       % |
+
 
     ----------------------------------
-    [INFO] SUCCESS (took 2634 seconds)
+    [INFO] SUCCESS (took 1862 seconds)
     ----------------------------------
 
 
@@ -94,4 +122,3 @@ Next steps
 Now you can check :doc:`how to run benchmarks </race>`, get a better understanding how to interpret the numbers in the :doc:`summary report </summary_report>` or start to :doc:`create your own tracks </adding_tracks>`. Be sure to check also some :doc:`tips and tricks </recipes>` to help you understand how to solve specific problems in Rally.
 
 Also run ``esrally --help`` to see what options are available and keep the :doc:`command line reference </command_line_reference>` handy for more detailed explanations of each option.
-
diff --git a/docs/summary_report.rst b/docs/summary_report.rst
index 010948dc..970cadb0 100644
--- a/docs/summary_report.rst
+++ b/docs/summary_report.rst
@@ -3,76 +3,94 @@ Summary Report
 
 At the end of each :doc:`race </race>`, Rally shows a summary report. Below we'll explain the meaning of each line including a reference to its corresponding :doc:`metrics key </metrics>` which can be helpful if you want to build your own reports in Kibana. Note that not every summary report will show all lines.
 
-Total indexing time
--------------------
+Cumulative indexing time of primary shards
+------------------------------------------
 
-* **Definition**: Total time used for indexing as reported by the indices stats API. Note that this is not Wall clock time (i.e. if M indexing threads ran for N minutes, we will report M * N minutes, not N minutes).
+* **Definition**: Cumulative time used for indexing as reported by the indices stats API. Note that this is not Wall clock time (i.e. if M indexing threads ran for N minutes, we will report M * N minutes, not N minutes).
 * **Corresponding metrics key**: ``indexing_total_time``
 
-Indexing time per shard
------------------------
+Cumulative indexing time across primary shards
+----------------------------------------------
 
-* **Definition**: Minimum, median and maximum time used for indexing per primary shard as reported by the indices stats API.
+* **Definition**: Minimum, median and maximum cumulative time used for indexing across primary shards as reported by the indices stats API.
 * **Corresponding metrics key**: ``indexing_total_time`` (property: ``per-shard``)
 
-Total indexing throttle time
-----------------------------
+Cumulative indexing throttle time of primary shards
+---------------------------------------------------
 
-* **Definition**: Total time that indexing has been throttled as reported by the indices stats API. Note that this is not Wall clock time (i.e. if M indexing threads ran for N minutes, we will report M * N minutes, not N minutes).
+* **Definition**: Cumulative time that indexing has been throttled as reported by the indices stats API. Note that this is not Wall clock time (i.e. if M indexing threads ran for N minutes, we will report M * N minutes, not N minutes).
 * **Corresponding metrics key**: ``indexing_throttle_time``
 
-Indexing throttle time per shard
---------------------------------
+Cumulative indexing throttle time across primary shards
+-------------------------------------------------------
 
-* **Definition**: Minimum, median and maximum time used that indexing has been throttled per primary shard as reported by the indices stats API.
+* **Definition**: Minimum, median and maximum cumulative time used that indexing has been throttled across primary shards as reported by the indices stats API.
 * **Corresponding metrics key**: ``indexing_throttle_time`` (property: ``per-shard``)
 
-Total merge time
-----------------
+Cumulative merge time of primary shards
+---------------------------------------
 
-* **Definition**: Total runtime of merges as reported by the indices stats API. Note that this is not Wall clock time.
+* **Definition**: Cumulative runtime of merges of primary shards, as reported by the indices stats API. Note that this is not Wall clock time.
 * **Corresponding metrics key**: ``merges_total_time``
 
-Merge time per shard
---------------------
+Cumulative merge count of primary shards
+----------------------------------------
+
+* **Definition**: Cumulative number of merges of primary shards, as reported by indices stats API under ``_all/primaries``.
+* **Corresponding metrics key**: ``merges_total_count``
 
-* **Definition**: Minimum, median and maximum time of merges per primary shard as reported by the indices stats API.
+Cumulative merge time across primary shards
+-------------------------------------------
+
+* **Definition**: Minimum, median and maximum cumulative time of merges across primary shards, as reported by the indices stats API.
 * **Corresponding metrics key**: ``merges_total_time`` (property: ``per-shard``)
 
-Total refresh time
-------------------
+Cumulative refresh time of primary shards
+-----------------------------------------
 
-* **Definition**: Total time used for index refresh as reported by the indices stats API. Note that this is not Wall clock time.
+* **Definition**: Cumulative time used for index refresh of primary shards, as reported by the indices stats API. Note that this is not Wall clock time.
 * **Corresponding metrics key**: ``refresh_total_time``
 
-Refresh time per shard
-----------------------
+Cumulative refresh count of primary shards
+------------------------------------------
 
-* **Definition**: Minimum, median and maximum time for index refresh per primary shard as reported by the indices stats API.
+* **Definition**: Cumulative number of refreshes of primary shards, as reported by indices stats API under ``_all/primaries``.
+* **Corresponding metrics key**: ``refresh_total_count``
+
+Cumulative refresh time across primary shards
+---------------------------------------------
+
+* **Definition**: Minimum, median and maximum cumulative time for index refresh across primary shards, as reported by the indices stats API.
 * **Corresponding metrics key**: ``refresh_total_time`` (property: ``per-shard``)
 
-Total flush time
-----------------
+Cumulative flush time of primary shards
+---------------------------------------
 
-* **Definition**: Total time used for index flush as reported by the indices stats API. Note that this is not Wall clock time.
+* **Definition**: Cumulative time used for index flush of primary shards, as reported by the indices stats API. Note that this is not Wall clock time.
 * **Corresponding metrics key**: ``flush_total_time``
 
-Flush time per shard
---------------------
+Cumulative flush count of primary shards
+----------------------------------------
+
+* **Definition**: Cumulative number of flushes of primary shards, as reported by indices stats API under ``_all/primaries``.
+* **Corresponding metrics key**: ``flush_total_count``
+
+Cumulative flush time across primary shards
+-------------------------------------------
 
-* **Definition**: Minimum, median and maximum time for index flush per primary shard as reported by the indices stats API.
+* **Definition**: Minimum, median and maximum time for index flush across primary shards as reported by the indices stats API.
 * **Corresponding metrics key**: ``flush_total_time`` (property: ``per-shard``)
 
-Total merge throttle time
--------------------------
+Cumulative merge throttle time of primary shards
+------------------------------------------------
 
-* **Definition**: Total time within merges have been throttled as reported by the indices stats API. Note that this is not Wall clock time.
+* **Definition**: Cumulative time within merges that have been throttled, as reported by the indices stats API. Note that this is not Wall clock time.
 * **Corresponding metrics key**: ``merges_total_throttled_time``
 
-Merge throttle time per shard
------------------------------
+Cumulative merge throttle time across primary shards
+----------------------------------------------------
 
-* **Definition**: Minimum, median and maximum time that merges have been throttled per primary shard as reported by the indices stats API.
+* **Definition**: Minimum, median and maximum cumulative time that merges have been throttled across primary shards as reported by the indices stats API.
 * **Corresponding metrics key**: ``merges_total_throttled_time`` (property: ``per-shard``)
 
 Merge time (``X``)
diff --git a/esrally/mechanic/telemetry.py b/esrally/mechanic/telemetry.py
index 95a9c901..2ae21036 100644
--- a/esrally/mechanic/telemetry.py
+++ b/esrally/mechanic/telemetry.py
@@ -1061,6 +1061,9 @@ class IndexStats(InternalTelemetryDevice):
         for t in self.index_times(index_stats):
             self.metrics_store.put_doc(doc=t, level=metrics.MetaInfoScope.cluster)
 
+        for ct in self.index_counts(index_stats):
+            self.metrics_store.put_doc(doc=ct, level=metrics.MetaInfoScope.cluster)
+
         self.add_metrics(self.extract_value(p, ["segments", "doc_values_memory_in_bytes"]), "segments_doc_values_memory_in_bytes", "byte")
         self.add_metrics(self.extract_value(p, ["segments", "stored_fields_memory_in_bytes"]), "segments_stored_fields_memory_in_bytes", "byte")
         self.add_metrics(self.extract_value(p, ["segments", "terms_memory_in_bytes"]), "segments_terms_memory_in_bytes", "byte")
@@ -1090,7 +1093,7 @@ class IndexStats(InternalTelemetryDevice):
     def index_time(self, values, stats, name, path, per_shard_stats):
         primary_total_stats = self.extract_value(stats, ["_all", "primaries"], default_value={})
         value = self.extract_value(primary_total_stats, path)
-        if value:
+        if value is not None:
             doc = {
                 "name": name,
                 "value": value,
@@ -1100,6 +1103,23 @@ class IndexStats(InternalTelemetryDevice):
                 doc["per-shard"] = self.primary_shard_stats(stats, path)
             values.append(doc)
 
+    def index_counts(self, stats):
+        counts = []
+        self.index_count(counts, stats, "merges_total_count", ["merges", "total"])
+        self.index_count(counts, stats, "refresh_total_count", ["refresh", "total"])
+        self.index_count(counts, stats, "flush_total_count", ["flush", "total"])
+        return counts
+
+    def index_count(self, values, stats, name, path):
+        primary_total_stats = self.extract_value(stats, ["_all", "primaries"], default_value={})
+        value = self.extract_value(primary_total_stats, path)
+        if value is not None:
+            doc = {
+                "name": name,
+                "value": value
+            }
+            values.append(doc)
+
     def primary_shard_stats(self, stats, path):
         shard_stats = []
         try:
diff --git a/esrally/reporter.py b/esrally/reporter.py
index 1e2413f8..9dbe6285 100644
--- a/esrally/reporter.py
+++ b/esrally/reporter.py
@@ -160,10 +160,13 @@ class StatsCalculator:
         result.indexing_throttle_time_per_shard = self.shard_stats("indexing_throttle_time")
         result.merge_time = self.sum("merges_total_time")
         result.merge_time_per_shard = self.shard_stats("merges_total_time")
+        result.merge_count = self.sum("merges_total_count")
         result.refresh_time = self.sum("refresh_total_time")
         result.refresh_time_per_shard = self.shard_stats("refresh_total_time")
+        result.refresh_count = self.sum("refresh_total_count")
         result.flush_time = self.sum("flush_total_time")
         result.flush_time_per_shard = self.shard_stats("flush_total_time")
+        result.flush_count = self.sum("flush_total_count")
         result.merge_throttle_time = self.sum("merges_total_throttled_time")
         result.merge_throttle_time_per_shard = self.shard_stats("merges_total_throttled_time")
 
@@ -300,10 +303,13 @@ class Stats:
         self.indexing_throttle_time_per_shard = self.v(d, "indexing_throttle_time_per_shard", default={})
         self.merge_time = self.v(d, "merge_time")
         self.merge_time_per_shard = self.v(d, "merge_time_per_shard", default={})
+        self.merge_count = self.v(d, "merge_count")
         self.refresh_time = self.v(d, "refresh_time")
         self.refresh_time_per_shard = self.v(d, "refresh_time_per_shard", default={})
+        self.refresh_count = self.v(d, "refresh_count")
         self.flush_time = self.v(d, "flush_time")
         self.flush_time_per_shard = self.v(d, "flush_time_per_shard", default={})
+        self.flush_count = self.v(d, "flush_count")
         self.merge_throttle_time = self.v(d, "merge_throttle_time")
         self.merge_throttle_time_per_shard = self.v(d, "merge_throttle_time_per_shard", default={})
         self.ml_processing_time = self.v(d, "ml_processing_time", default=[])
@@ -450,7 +456,7 @@ class SummaryReporter:
 
         warnings = []
         metrics_table = []
-        metrics_table.extend(self.report_total_times(stats))
+        metrics_table.extend(self.report_totals(stats))
         metrics_table.extend(self.report_merge_part_times(stats))
         metrics_table.extend(self.report_ml_processing_times(stats))
 
@@ -520,23 +526,42 @@ class SummaryReporter:
             self.line("error rate", task, values["error_rate"], "%", lambda v: "%.2f" % (v * 100.0))
         )
 
-    def report_total_times(self, stats):
+    def report_totals(self, stats):
         lines = []
-        lines.extend(self.report_total_time("indexing time", stats.total_time, stats.total_time_per_shard))
-        lines.extend(self.report_total_time("indexing throttle time", stats.indexing_throttle_time, stats.indexing_throttle_time_per_shard))
-        lines.extend(self.report_total_time("merge time", stats.merge_time, stats.merge_time_per_shard))
-        lines.extend(self.report_total_time("merge throttle time", stats.merge_throttle_time, stats.merge_throttle_time_per_shard))
-        lines.extend(self.report_total_time("refresh time", stats.refresh_time, stats.refresh_time_per_shard))
-        lines.extend(self.report_total_time("flush time", stats.flush_time, stats.flush_time_per_shard))
+        lines.extend(self.report_total_time("indexing time", stats.total_time))
+        lines.extend(self.report_total_time_per_shard("indexing time", stats.total_time_per_shard))
+        lines.extend(self.report_total_time("indexing throttle time", stats.indexing_throttle_time))
+        lines.extend(self.report_total_time_per_shard("indexing throttle time", stats.indexing_throttle_time_per_shard))
+        lines.extend(self.report_total_time("merge time", stats.merge_time))
+        lines.extend(self.report_total_count("merge count", stats.merge_count))
+        lines.extend(self.report_total_time_per_shard("merge time", stats.merge_time_per_shard))
+        lines.extend(self.report_total_time("merge throttle time", stats.merge_throttle_time))
+        lines.extend(self.report_total_time_per_shard("merge throttle time", stats.merge_throttle_time_per_shard))
+        lines.extend(self.report_total_time("refresh time", stats.refresh_time))
+        lines.extend(self.report_total_count("refresh count", stats.refresh_count))
+        lines.extend(self.report_total_time_per_shard("refresh time", stats.refresh_time_per_shard))
+        lines.extend(self.report_total_time("flush time", stats.flush_time))
+        lines.extend(self.report_total_count("flush count", stats.flush_count))
+        lines.extend(self.report_total_time_per_shard("flush time", stats.flush_time_per_shard))
         return lines
 
-    def report_total_time(self, name, total_time, total_time_per_shard):
+    def report_total_time(self, name, total_time):
         unit = "min"
         return self.join(
-            self.line("Total {}".format(name), "", total_time, unit, convert.ms_to_minutes),
-            self.line("Min {} per shard".format(name), "", total_time_per_shard.get("min"), unit, convert.ms_to_minutes),
-            self.line("Median {} per shard".format(name), "", total_time_per_shard.get("median"), unit, convert.ms_to_minutes),
-            self.line("Max {} per shard".format(name), "", total_time_per_shard.get("max"), unit, convert.ms_to_minutes),
+            self.line("Cumulative {} of primary shards".format(name), "", total_time, unit, convert.ms_to_minutes),
+        )
+
+    def report_total_time_per_shard(self, name, total_time_per_shard):
+        unit = "min"
+        return self.join(
+            self.line("Min cumulative {} across primary shards".format(name), "", total_time_per_shard.get("min"), unit, convert.ms_to_minutes),
+            self.line("Median cumulative {} across primary shards".format(name), "", total_time_per_shard.get("median"), unit, convert.ms_to_minutes),
+            self.line("Max cumulative {} across primary shards".format(name), "", total_time_per_shard.get("max"), unit, convert.ms_to_minutes),
+        )
+
+    def report_total_count(self, name, total_count):
+        return self.join(
+            self.line("Cumulative {} of primary shards".format(name), "", total_count, ""),
         )
 
     def report_merge_part_times(self, stats):
@@ -753,39 +778,97 @@ class ComparisonReporter:
 
     def report_total_times(self, baseline_stats, contender_stats):
         lines = []
-        lines.extend(self.report_total_time("indexing time",
-                                            baseline_stats.total_time, baseline_stats.total_time_per_shard,
-                                            contender_stats.total_time, contender_stats.total_time_per_shard))
-        lines.extend(self.report_total_time("indexing throttle time",
-                                            baseline_stats.indexing_throttle_time, baseline_stats.indexing_throttle_time_per_shard,
-                                            contender_stats.indexing_throttle_time, contender_stats.indexing_throttle_time_per_shard))
-        lines.extend(self.report_total_time("merge time",
-                                            baseline_stats.merge_time, baseline_stats.merge_time_per_shard,
-                                            contender_stats.merge_time, contender_stats.merge_time_per_shard))
-        lines.extend(self.report_total_time("merge throttle time",
-                                            baseline_stats.merge_throttle_time, baseline_stats.merge_throttle_time_per_shard,
-                                            contender_stats.merge_throttle_time, contender_stats.merge_throttle_time_per_shard))
-        lines.extend(self.report_total_time("refresh time",
-                                            baseline_stats.refresh_time, baseline_stats.refresh_time_per_shard,
-                                            contender_stats.refresh_time, contender_stats.refresh_time_per_shard))
-        lines.extend(self.report_total_time("flush time",
-                                            baseline_stats.flush_time, baseline_stats.flush_time_per_shard,
-                                            contender_stats.flush_time, contender_stats.flush_time_per_shard))
+        lines.extend(self.report_total_time(
+            "indexing time",
+            baseline_stats.total_time, contender_stats.total_time
+        ))
+        lines.extend(self.report_total_time_per_shard(
+            "indexing time",
+            baseline_stats.total_time_per_shard, contender_stats.total_time_per_shard
+        ))
+        lines.extend(self.report_total_time(
+            "indexing throttle time",
+            baseline_stats.indexing_throttle_time, contender_stats.indexing_throttle_time
+        ))
+        lines.extend(self.report_total_time_per_shard(
+            "indexing throttle time",
+            baseline_stats.indexing_throttle_time_per_shard,
+            contender_stats.indexing_throttle_time_per_shard
+        ))
+        lines.extend(self.report_total_time(
+            "merge time",
+            baseline_stats.merge_time, contender_stats.merge_time,
+        ))
+        lines.extend(self.report_total_count(
+            "merge count",
+            baseline_stats.merge_count, contender_stats.merge_count
+        ))
+        lines.extend(self.report_total_time_per_shard(
+            "merge time",
+            baseline_stats.merge_time_per_shard,
+            contender_stats.merge_time_per_shard
+        ))
+        lines.extend(self.report_total_time(
+            "merge throttle time",
+            baseline_stats.merge_throttle_time,
+            contender_stats.merge_throttle_time
+        ))
+        lines.extend(self.report_total_time_per_shard(
+            "merge throttle time",
+            baseline_stats.merge_throttle_time_per_shard,
+            contender_stats.merge_throttle_time_per_shard
+        ))
+        lines.extend(self.report_total_time(
+            "refresh time",
+            baseline_stats.refresh_time, contender_stats.refresh_time
+        ))
+        lines.extend(self.report_total_count(
+            "refresh count",
+            baseline_stats.refresh_count, contender_stats.refresh_count
+        ))
+        lines.extend(self.report_total_time_per_shard(
+            "refresh time",
+            baseline_stats.refresh_time_per_shard,
+            contender_stats.refresh_time_per_shard
+        ))
+        lines.extend(self.report_total_time(
+            "flush time",
+            baseline_stats.flush_time, contender_stats.flush_time
+        ))
+        lines.extend(self.report_total_count(
+            "flush count",
+            baseline_stats.flush_count, contender_stats.flush_count
+        ))
+        lines.extend(self.report_total_time_per_shard(
+            "flush time",
+            baseline_stats.flush_time_per_shard, contender_stats.flush_time_per_shard
+        ))
         return lines
 
-    def report_total_time(self, name, baseline_total, baseline_per_shard, contender_total, contender_per_shard):
+    def report_total_time(self, name, baseline_total, contender_total):
         unit = "min"
         return self.join(
-            self.line("Total {}".format(name), baseline_total, contender_total, "", unit,
+            self.line("Cumulative {} of primary shards".format(name), baseline_total, contender_total, "", unit,
                       treat_increase_as_improvement=False, formatter=convert.ms_to_minutes),
-            self.line("Min {} per shard".format(name), baseline_per_shard.get("min"), contender_per_shard.get("min"), "", unit,
+        )
+
+    def report_total_time_per_shard(self, name, baseline_per_shard, contender_per_shard):
+        unit = "min"
+        return self.join(
+            self.line("Min cumulative {} across primary shard".format(name), baseline_per_shard.get("min"), contender_per_shard.get("min"), "", unit,
                       treat_increase_as_improvement=False, formatter=convert.ms_to_minutes),
-            self.line("Median {} per shard".format(name), baseline_per_shard.get("median"), contender_per_shard.get("median"), "", unit,
+            self.line("Median cumulative {} across primary shard".format(name), baseline_per_shard.get("median"), contender_per_shard.get("median"), "", unit,
                       treat_increase_as_improvement=False, formatter=convert.ms_to_minutes),
-            self.line("Max {} per shard".format(name), baseline_per_shard.get("max"), contender_per_shard.get("max"), "", unit,
+            self.line("Max cumulative {} across primary shard".format(name), baseline_per_shard.get("max"), contender_per_shard.get("max"), "", unit,
                       treat_increase_as_improvement=False, formatter=convert.ms_to_minutes),
         )
 
+    def report_total_count(self, name, baseline_total, contender_total):
+        return self.join(
+            self.line("Cumulative {} of primary shards".format(name), baseline_total, contender_total, "", "",
+                      treat_increase_as_improvement=False)
+        )
+
     def report_gc_times(self, baseline_stats, contender_stats):
         return self.join(
             self.line("Total Young Gen GC", baseline_stats.young_gc_time, contender_stats.young_gc_time, "", "s",


Test patch:
diff --git a/tests/mechanic/telemetry_test.py b/tests/mechanic/telemetry_test.py
index 5c94d0f1..027dc77a 100644
--- a/tests/mechanic/telemetry_test.py
+++ b/tests/mechanic/telemetry_test.py
@@ -1917,16 +1917,19 @@ class IndexStatsTests(TestCase):
                     },
                     "merges": {
                         "total_time_in_millis": 0,
-                        "total_throttled_time_in_millis": 0
+                        "total_throttled_time_in_millis": 0,
+                        "total": 0
                     },
                     "indexing": {
                         "index_time_in_millis": 0
                     },
                     "refresh": {
-                        "total_time_in_millis": 0
+                        "total_time_in_millis": 0,
+                        "total": 0
                     },
                     "flush": {
-                        "total_time_in_millis": 0
+                        "total_time_in_millis": 0,
+                        "total": 0
                     }
                 }
             }
@@ -1951,16 +1954,19 @@ class IndexStatsTests(TestCase):
                     },
                     "merges": {
                         "total_time_in_millis": 509341,
-                        "total_throttled_time_in_millis": 98925
+                        "total_throttled_time_in_millis": 98925,
+                        "total": 3
                     },
                     "indexing": {
                         "index_time_in_millis": 1065688
                     },
                     "refresh": {
-                        "total_time_in_millis": 158465
+                        "total_time_in_millis": 158465,
+                        "total": 10
                     },
                     "flush": {
-                        "total_time_in_millis": 19082
+                        "total_time_in_millis": 0,
+                        "total": 0
                     }
                 },
                 "total": {
@@ -1998,7 +2004,7 @@ class IndexStatsTests(TestCase):
                                     "total_time_in_millis": 81004
                                 },
                                 "flush": {
-                                    "total_time_in_millis": 9879
+                                    "total_time_in_millis": 0
                                 }
                             }
                         ],
@@ -2018,7 +2024,7 @@ class IndexStatsTests(TestCase):
                                     "total_time_in_millis": 77461,
                                 },
                                 "flush": {
-                                    "total_time_in_millis": 9203
+                                    "total_time_in_millis": 0
                                 }
                             }
                         ]
@@ -2042,7 +2048,7 @@ class IndexStatsTests(TestCase):
                                     "total_time_in_millis": 81004,
                                 },
                                 "flush": {
-                                    "total_time_in_millis": 9879
+                                    "total_time_in_millis": 0
                                 }
                             }
                         ],
@@ -2063,7 +2069,7 @@ class IndexStatsTests(TestCase):
                                     "total_time_in_millis": 77461,
                                 },
                                 "flush": {
-                                    "total_time_in_millis": 9203
+                                    "total_time_in_millis": 0
                                 }
                             }
                         ]
@@ -2115,11 +2121,23 @@ class IndexStatsTests(TestCase):
             }, level=metrics.MetaInfoScope.cluster),
             mock.call(doc={
                 "name": "flush_total_time",
-                "value": 19082,
+                "value": 0,
                 "unit": "ms",
-                # [9203, 9879]
+                # [0, 0]
                 "per-shard": [s["flush"]["total_time_in_millis"] for s in primary_shards]
             }, level=metrics.MetaInfoScope.cluster),
+            mock.call(doc={
+                "name": "merges_total_count",
+                "value": 3
+            }, level=metrics.MetaInfoScope.cluster),
+            mock.call(doc={
+                "name": "refresh_total_count",
+                "value": 10
+            }, level=metrics.MetaInfoScope.cluster),
+            mock.call(doc={
+                "name": "flush_total_count",
+                "value": 0
+            }, level=metrics.MetaInfoScope.cluster),
         ])
 
         metrics_store_cluster_count.assert_has_calls([
diff --git a/tests/reporter_test.py b/tests/reporter_test.py
index 4739949e..9022951c 100644
--- a/tests/reporter_test.py
+++ b/tests/reporter_test.py
@@ -136,6 +136,14 @@ class StatsTests(TestCase):
             ],
             "young_gc_time": 68,
             "old_gc_time": 0,
+            "merge_time": 3702,
+            "merge_time_per_shard": {
+                "min": 40,
+                "median": 3702,
+                "max": 3900,
+                "unit": "ms"
+            },
+            "merge_count": 2,
             "refresh_time": 596,
             "refresh_time_per_shard": {
                 "min": 48,
@@ -143,8 +151,10 @@ class StatsTests(TestCase):
                 "max": 204,
                 "unit": "ms"
             },
+            "refresh_count": 10,
             "flush_time": None,
-            "flush_time_per_shard": {}
+            "flush_time_per_shard": {},
+            "flush_count": 0
         }
 
         s = reporter.Stats(d)
@@ -242,6 +252,30 @@ class StatsTests(TestCase):
             }
         }, select(metric_list, "old_gc_time"))
 
+        self.assertEqual({
+            "name": "merge_time",
+            "value": {
+                "single": 3702
+            }
+        }, select(metric_list, "merge_time"))
+
+        self.assertEqual({
+            "name": "merge_time_per_shard",
+            "value": {
+                "min": 40,
+                "median": 3702,
+                "max": 3900,
+                "unit": "ms"
+            }
+        }, select(metric_list, "merge_time_per_shard"))
+
+        self.assertEqual({
+            "name": "merge_count",
+            "value": {
+                "single": 2
+            }
+        }, select(metric_list, "merge_count"))
+
         self.assertEqual({
             "name": "refresh_time",
             "value": {
@@ -259,8 +293,21 @@ class StatsTests(TestCase):
             }
         }, select(metric_list, "refresh_time_per_shard"))
 
+        self.assertEqual({
+            "name": "refresh_count",
+            "value": {
+                "single": 10
+            }
+        }, select(metric_list, "refresh_count"))
+
         self.assertIsNone(select(metric_list, "flush_time"))
         self.assertIsNone(select(metric_list, "flush_time_per_shard"))
+        self.assertEqual({
+            "name": "flush_count",
+            "value": {
+                "single": 0
+            }
+        }, select(metric_list, "flush_count"))
 
 
 class FormatterTests(TestCase):