FileIO for Execution Time (#5226)
authorАндрей Шедько/AI Tools Lab /SRR/Engineer/삼성전자 <a.shedko@samsung.com>
Tue, 21 May 2019 00:37:26 +0000 (03:37 +0300)
committer오형석/On-Device Lab(SR)/Staff Engineer/삼성전자 <hseok82.oh@samsung.com>
Tue, 21 May 2019 00:37:26 +0000 (09:37 +0900)
This class handles saving and parsing ExecTime data.

Signed-off-by: Andrei Shedko <a.shedko@samsung.com>
runtimes/neurun/core/include/backend/JSONExecTime.h [new file with mode: 0644]
runtimes/neurun/core/src/backend/JSONExecTime.cc [new file with mode: 0644]

diff --git a/runtimes/neurun/core/include/backend/JSONExecTime.h b/runtimes/neurun/core/include/backend/JSONExecTime.h
new file mode 100644 (file)
index 0000000..e42a8a9
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __NEURUN_BACKEND_JSON_EXEC_TIME_H__
+#define __NEURUN_BACKEND_JSON_EXEC_TIME_H__
+
+#include <fstream>
+#include <unordered_map>
+#include <map>
+#include <vector>
+#include "backend/Backend.h"
+#include "backend/IConfig.h"
+
+namespace neurun
+{
+namespace backend
+{
+
+/**
+ * @brief table, that contains execution time of an operation on some backend for different input
+ * sizes and transfer time from one backend to another for various input sizes (permutation time)
+ *
+ *               backend ->  op ->  quant->  size   --> time
+ * _measurements[Backend*]["string"][bool][uint32_t] = int64_t
+ */
+using MeasurementData = std::unordered_map<
+    const Backend *,
+    std::unordered_map<std::string, std::unordered_map<bool, std::map<uint32_t, int64_t>>>>;
+
+class JSON
+{
+public:
+  explicit JSON(const std::vector<Backend *> &backends, MeasurementData &measurements)
+      : _measurement_file("exec_time.json"), _backends(), _measurements(measurements)
+  {
+    for (const auto b : backends)
+    {
+      _backends.emplace(b->config()->id(), b);
+    }
+    loadOperationsExecTime();
+  };
+  ~JSON() { uploadOperationsExecTime(); };
+
+private:
+  ///@brief file containing measurements
+  std::string _measurement_file;
+  std::unordered_map<std::string, const Backend *> _backends;
+  std::unordered_map<
+      const Backend *,
+      std::unordered_map<std::string, std::unordered_map<bool, std::map<uint32_t, int64_t>>>>
+      &_measurements;
+  /**
+   * @brief Helper function for inserting data to OperationExecTimes
+   *
+   * @param backend String name of backend
+   * @param operation String name of operation
+   * @param quant if input type quantized
+   * @param stream File stream
+   */
+  void readOperation(const std::string &backend, const std::string &operation, bool quant,
+                     std::ifstream &stream);
+
+  /**
+   * @brief Helper function for writing OperationExecTimes to stream
+   *
+   * @param operation_info Map of operations execution information
+   * @param stream File stream
+   */
+  void printOperation(const std::map<uint32_t, int64_t> &operation_info,
+                      std::ofstream &stream) const;
+  /**
+   * @brief Parse and load operations_exec_time from _operations_exec_time_file.
+   */
+  void loadOperationsExecTime();
+  /**
+   * @brief Update _operations_exec_time_file with new data.
+   */
+  void uploadOperationsExecTime() const;
+};
+
+} // namespace backend
+} // namespace neurun
+
+#endif // __NEURUN_BACKEND_JSON_EXEC_TIME_H__
diff --git a/runtimes/neurun/core/src/backend/JSONExecTime.cc b/runtimes/neurun/core/src/backend/JSONExecTime.cc
new file mode 100644 (file)
index 0000000..59c8a33
--- /dev/null
@@ -0,0 +1,233 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "backend/JSONExecTime.h"
+#include "backend/IConfig.h"
+#include <fstream>
+
+namespace neurun
+{
+namespace backend
+{
+/**
+ * @brief Helper function for reading string from stream
+ *
+ * @param str Output string
+ * @param stream File stream
+ */
+void readString(std::string &str, std::ifstream &stream)
+{
+  str.clear();
+  char buf;
+  while (stream.good())
+  {
+    stream.get(buf);
+    if (buf == '"')
+      break;
+    str.push_back(buf);
+  }
+}
+
+/**
+ * @brief Helper function for reading bool from stream
+ *
+ * @param quant Output bool
+ * @param stream File stream
+ */
+void readBool(bool &quant, std::ifstream &stream)
+{
+  char buf;
+  stream.get(buf);
+  quant = (buf == '1');
+  stream.get(buf);
+}
+
+void printString(const std::string &str, std::ofstream &stream) { stream << "\"" << str << "\""; }
+
+void printBool(bool quant, std::ofstream &stream) { stream << "\"" << quant << "\""; }
+
+void JSON::readOperation(const std::string &backend, const std::string &operation, bool quant,
+                         std::ifstream &stream)
+{
+  uint32_t size = 0;
+  int64_t time = 0;
+
+  std::string int_buf;
+  char buf;
+  int number_of_closed_braces = 0;
+  int number_of_commas = 0;
+
+  while (stream.good())
+  {
+    stream.get(buf);
+
+    switch (buf)
+    {
+      case ']':
+      {
+        number_of_closed_braces++;
+        break;
+      }
+      case '[':
+      {
+        number_of_closed_braces--;
+        break;
+      }
+      default:
+      {
+        if (std::isdigit(buf))
+        {
+          int_buf.push_back(buf);
+        }
+        break;
+      }
+    }
+
+    if (number_of_closed_braces == 1)
+      break;
+
+    if ((buf == ']' && number_of_closed_braces == 0) ||
+        (buf == ',' && number_of_closed_braces == -1))
+    {
+      switch (number_of_commas % 2)
+      {
+        case 0:
+        {
+          size = static_cast<uint32_t>(std::atoi(int_buf.c_str()));
+          break;
+        }
+        case 1:
+        {
+          time = static_cast<int64_t>(std::atol(int_buf.c_str()));
+          auto bf = _backends.find(backend);
+          if (bf != _backends.end())
+          {
+            _measurements[bf->second][operation][quant][size] = time;
+          } // we ignore the records for unsupported backends
+          break;
+        }
+        default:
+          break;
+      }
+      number_of_commas++;
+      int_buf.clear();
+    }
+  }
+}
+void JSON::printOperation(const std::map<uint32_t, int64_t> &operation_info,
+                          std::ofstream &stream) const
+{
+  for (const auto &items : operation_info)
+  {
+    stream << "[" << items.first << ", " << items.second << "], ";
+  }
+  stream.seekp(-2, std::ofstream::end);
+}
+
+void JSON::uploadOperationsExecTime() const
+{
+  std::ofstream stream(_measurement_file);
+  if (!stream.is_open())
+  {
+    throw std::runtime_error("Failed to save backend config file");
+  }
+  else
+  {
+    stream << "{";
+    for (const auto &backend : _measurements)
+    {
+      printString(backend.first->config()->id(), stream);
+      stream << ": {";
+      for (const auto &operation : backend.second)
+      {
+        printString(operation.first, stream);
+        stream << ": {";
+        for (const auto &type : operation.second)
+        {
+          printBool(type.first, stream);
+          stream << ": [";
+          printOperation(type.second, stream);
+          stream << "], ";
+        }
+        stream.seekp(-2, std::ofstream::end);
+        stream << "}, ";
+      }
+      stream.seekp(-2, std::ofstream::end);
+      stream << "}, ";
+    }
+    stream.seekp(-2, std::ofstream::end);
+    stream << "}";
+    stream.close();
+  }
+}
+
+void JSON::loadOperationsExecTime()
+{
+  std::ifstream stream(_measurement_file);
+  if (stream.is_open())
+  {
+    std::string backend;
+    std::string operation;
+    bool quant;
+    char buf;
+    int number_of_open_braces = 0;
+
+    while (stream.good())
+    {
+      stream.get(buf);
+      switch (buf)
+      {
+        case '{':
+          number_of_open_braces++;
+          break;
+        case '}':
+          number_of_open_braces--;
+          break;
+        case '"':
+        {
+          if (number_of_open_braces == 1)
+          {
+            // read backend string
+            readString(backend, stream);
+          }
+          if (number_of_open_braces == 2)
+          {
+            // read operation string
+            readString(operation, stream);
+          }
+          if (number_of_open_braces == 3)
+          {
+            // read operation string
+            readBool(quant, stream);
+          }
+          break;
+        }
+        case '[':
+        {
+          // reading and creating all info for operation
+          readOperation(backend, operation, quant, stream);
+          break;
+        }
+        default:
+          break;
+      }
+    }
+    stream.close();
+  }
+}
+
+} // namespace backend
+} // namespace neurun