Merge performance samples

Update the Ethos-U Monitor to merge performance samples where the
qread or status register have not changed.

Change-Id: I8b4ea728e004bd2ff05ad1c90326a864dc592f4d
diff --git a/lib/ethosu_monitor/include/ethosu_monitor.hpp b/lib/ethosu_monitor/include/ethosu_monitor.hpp
index c76ee8b..2bdeb4a 100644
--- a/lib/ethosu_monitor/include/ethosu_monitor.hpp
+++ b/lib/ethosu_monitor/include/ethosu_monitor.hpp
@@ -32,10 +32,19 @@
 public:
     enum Backend { PRINTF, EVENT_RECORDER };
 
-    EthosUMonitor(Backend backend = PRINTF);
+    /**
+     * @param backend   Select which backend to output performance data to.
+     * @param merge     Merge performance samples if QREAD or STATUS has not changed
+     */
+    EthosUMonitor(Backend backend = PRINTF, bool merge = true);
 
     template <typename T>
     void configure(ethosu_driver *drv, const T &eventIds) {
+        // Reset previous record
+        prevRecord.qread  = -1;
+        prevRecord.status = -1;
+        mergeCount        = 0;
+
         // Set event ids
         numEvents = std::min(static_cast<size_t>(ETHOSU_PMU_NCOUNTERS), eventIds.size());
         for (size_t i = 0; i < numEvents; i++) {
@@ -60,6 +69,8 @@
 
     void monitorSample(ethosu_driver *drv);
 
+    size_t getMergeCount() const;
+
 private:
     struct EthosuEventRecord {
         uint64_t cycleCount;
@@ -75,7 +86,10 @@
 
     ethosu_pmu_event_type ethosuEventIds[ETHOSU_PMU_NCOUNTERS];
     size_t numEvents;
-    Backend backend;
+    const Backend backend;
+    const bool merge;
+    size_t mergeCount;
+    EthosuEventRecord prevRecord;
 };
 
 #endif
diff --git a/lib/ethosu_monitor/src/ethosu_monitor.cpp b/lib/ethosu_monitor/src/ethosu_monitor.cpp
index d13e6c2..e4e100c 100644
--- a/lib/ethosu_monitor/src/ethosu_monitor.cpp
+++ b/lib/ethosu_monitor/src/ethosu_monitor.cpp
@@ -21,18 +21,27 @@
 #include <inttypes.h>
 #include <stdio.h>
 
-EthosUMonitor::EthosUMonitor(Backend __backend) : backend(__backend) {}
+EthosUMonitor::EthosUMonitor(Backend __backend, bool _merge) : backend(__backend), merge(_merge) {}
 
 void EthosUMonitor::monitorSample(ethosu_driver *drv) {
     switch (backend) {
     case EVENT_RECORDER: {
-        EthosuEventRecord record = {ETHOSU_PMU_Get_CCNTR(drv),
-                                    ETHOSU_PMU_Get_QREAD(drv),
-                                    ETHOSU_PMU_Get_STATUS(drv),
-                                    {{ethosuEventIds[0], ETHOSU_PMU_Get_EVCNTR(drv, 0)},
-                                     {ethosuEventIds[1], ETHOSU_PMU_Get_EVCNTR(drv, 1)},
-                                     {ethosuEventIds[2], ETHOSU_PMU_Get_EVCNTR(drv, 2)},
-                                     {ethosuEventIds[3], ETHOSU_PMU_Get_EVCNTR(drv, 3)}}};
+        const EthosuEventRecord record = {ETHOSU_PMU_Get_CCNTR(drv),
+                                          ETHOSU_PMU_Get_QREAD(drv),
+                                          ETHOSU_PMU_Get_STATUS(drv),
+                                          {{ethosuEventIds[0], ETHOSU_PMU_Get_EVCNTR(drv, 0)},
+                                           {ethosuEventIds[1], ETHOSU_PMU_Get_EVCNTR(drv, 1)},
+                                           {ethosuEventIds[2], ETHOSU_PMU_Get_EVCNTR(drv, 2)},
+                                           {ethosuEventIds[3], ETHOSU_PMU_Get_EVCNTR(drv, 3)}}};
+
+        // Merge records if qread or status has not changed
+        if (merge && prevRecord.qread == record.qread && prevRecord.status == record.status) {
+            mergeCount++;
+            break;
+        }
+
+        prevRecord.qread  = record.qread;
+        prevRecord.status = record.status;
 
         EventRecordData(EventID(EventLevelDetail, EthosuEventComponentNo, 0), &record, sizeof(record));
         break;
@@ -48,3 +57,7 @@
 void EthosUMonitor::release(ethosu_driver *drv) {
     ETHOSU_PMU_Disable(drv);
 }
+
+size_t EthosUMonitor::getMergeCount() const {
+    return mergeCount;
+}