Add APIs for PMU configuration in library

Change-Id: I7694ab9dd5ff20c29feb0506bcf36a1cf4983243
diff --git a/driver_library/include/ethosu.hpp b/driver_library/include/ethosu.hpp
index 12192bf..70d0701 100644
--- a/driver_library/include/ethosu.hpp
+++ b/driver_library/include/ethosu.hpp
@@ -96,19 +96,46 @@
         network(network) {
         std::copy(ifmBegin, ifmEnd, std::back_inserter(ifmBuffers));
         std::copy(ofmBegin, ofmEnd, std::back_inserter(ofmBuffers));
-        create();
+        std::vector<uint32_t> counterConfigs = initializeCounterConfig();
+
+        create(counterConfigs, false);
     }
+    template <typename T, typename U>
+    Inference(std::shared_ptr<Network> &network,
+              const T &ifmBegin,
+              const T &ifmEnd,
+              const T &ofmBegin,
+              const T &ofmEnd,
+              const U &counters,
+              bool enableCycleCounter) :
+        network(network) {
+        std::copy(ifmBegin, ifmEnd, std::back_inserter(ifmBuffers));
+        std::copy(ofmBegin, ofmEnd, std::back_inserter(ofmBuffers));
+        std::vector<uint32_t> counterConfigs = initializeCounterConfig();
+
+        if (counters.size() > counterConfigs.size())
+            throw EthosU::Exception("PMU Counters argument to large.");
+
+        std::copy(counters.begin(), counters.end(), counterConfigs.begin());
+        create(counterConfigs, enableCycleCounter);
+    }
+
     virtual ~Inference();
 
-    void wait(int timeoutSec = -1);
+    int wait(int timeoutSec = -1);
+    const std::vector<uint32_t> getPmuCounters();
+    uint64_t getCycleCounter();
     bool failed();
     int getFd();
     std::shared_ptr<Network> getNetwork();
     std::vector<std::shared_ptr<Buffer>> &getIfmBuffers();
     std::vector<std::shared_ptr<Buffer>> &getOfmBuffers();
 
+    static uint32_t getMaxPmuEventCounters();
+
 private:
-    void create();
+    void create(std::vector<uint32_t> &counterConfigs, bool enableCycleCounter);
+    std::vector<uint32_t> initializeCounterConfig();
 
     int fd;
     std::shared_ptr<Network> network;
diff --git a/driver_library/src/ethosu.cpp b/driver_library/src/ethosu.cpp
index 9de26af..6b30827 100644
--- a/driver_library/src/ethosu.cpp
+++ b/driver_library/src/ethosu.cpp
@@ -232,7 +232,7 @@
     close(fd);
 }
 
-void Inference::create() {
+void Inference::create(std::vector<uint32_t> &counterConfigs, bool cycleCounterEnable = false) {
     ethosu_uapi_inference_create uapi;
 
     if (ifmBuffers.size() > ETHOSU_FD_MAX) {
@@ -243,6 +243,10 @@
         throw Exception("OFM buffer overflow");
     }
 
+    if (counterConfigs.size() != ETHOSU_PMU_EVENT_MAX) {
+        throw Exception("Wrong size of counter configurations");
+    }
+
     uapi.ifm_count = 0;
     for (auto it : ifmBuffers) {
         uapi.ifm_fd[uapi.ifm_count++] = it->getFd();
@@ -253,10 +257,24 @@
         uapi.ofm_fd[uapi.ofm_count++] = it->getFd();
     }
 
+    for (int i = 0; i < ETHOSU_PMU_EVENT_MAX; i++) {
+        uapi.pmu_config.events[i] = counterConfigs[i];
+    }
+
+    uapi.pmu_config.cycle_count = cycleCounterEnable;
+
     fd = network->ioctl(ETHOSU_IOCTL_INFERENCE_CREATE, static_cast<void *>(&uapi));
 }
 
-void Inference::wait(int timeoutSec) {
+std::vector<uint32_t> Inference::initializeCounterConfig() {
+    return std::vector<uint32_t>(ETHOSU_PMU_EVENT_MAX, 0);
+}
+
+uint32_t Inference::getMaxPmuEventCounters() {
+    return ETHOSU_PMU_EVENT_MAX;
+}
+
+int Inference::wait(int timeoutSec) {
     pollfd pfd;
 
     pfd.fd      = fd;
@@ -266,12 +284,39 @@
     int ret = ::poll(&pfd, 1, timeoutSec * 1000);
 
     cout << "Poll. ret=" << ret << ", revents=" << pfd.revents << endl;
+
+    return ret;
 }
 
 bool Inference::failed() {
-    ethosu_uapi_status status = static_cast<ethosu_uapi_status>(eioctl(fd, ETHOSU_IOCTL_INFERENCE_STATUS));
+    ethosu_uapi_result_status uapi;
 
-    return status != ETHOSU_UAPI_STATUS_OK;
+    eioctl(fd, ETHOSU_IOCTL_INFERENCE_STATUS, static_cast<void *>(&uapi));
+
+    return uapi.status != ETHOSU_UAPI_STATUS_OK;
+}
+
+const std::vector<uint32_t> Inference::getPmuCounters() {
+    ethosu_uapi_result_status uapi;
+    std::vector<uint32_t> counterValues = std::vector<uint32_t>(ETHOSU_PMU_EVENT_MAX, 0);
+
+    eioctl(fd, ETHOSU_IOCTL_INFERENCE_STATUS, static_cast<void *>(&uapi));
+
+    for (int i = 0; i < ETHOSU_PMU_EVENT_MAX; i++) {
+        if (uapi.pmu_config.events[i]) {
+            counterValues.at(i) = uapi.pmu_count.events[i];
+        }
+    }
+
+    return counterValues;
+}
+
+uint64_t Inference::getCycleCounter() {
+    ethosu_uapi_result_status uapi;
+
+    eioctl(fd, ETHOSU_IOCTL_INFERENCE_STATUS, static_cast<void *>(&uapi));
+
+    return uapi.pmu_count.cycle_count;
 }
 
 int Inference::getFd() {