summaryrefslogtreecommitdiff
path: root/runtimes/contrib/mlapse
diff options
context:
space:
mode:
Diffstat (limited to 'runtimes/contrib/mlapse')
-rw-r--r--runtimes/contrib/mlapse/CMakeLists.txt8
-rw-r--r--runtimes/contrib/mlapse/README.md3
-rw-r--r--runtimes/contrib/mlapse/tfl/CMakeLists.txt12
-rw-r--r--runtimes/contrib/mlapse/tfl/driver.cc280
-rw-r--r--runtimes/contrib/mlapse/tfl/mlapse/CSV_report_generator.cc67
-rw-r--r--runtimes/contrib/mlapse/tfl/mlapse/CSV_report_generator.h50
-rw-r--r--runtimes/contrib/mlapse/tfl/mlapse/benchmark_observer.cc24
-rw-r--r--runtimes/contrib/mlapse/tfl/mlapse/benchmark_observer.h77
-rw-r--r--runtimes/contrib/mlapse/tfl/mlapse/benchmark_runner.cc124
-rw-r--r--runtimes/contrib/mlapse/tfl/mlapse/benchmark_runner.h63
-rw-r--r--runtimes/contrib/mlapse/tfl/mlapse/multicast_observer.cc17
-rw-r--r--runtimes/contrib/mlapse/tfl/mlapse/multicast_observer.h75
-rw-r--r--runtimes/contrib/mlapse/tfl/mlapse/tfl/load.cc55
-rw-r--r--runtimes/contrib/mlapse/tfl/mlapse/tfl/load.h40
14 files changed, 895 insertions, 0 deletions
diff --git a/runtimes/contrib/mlapse/CMakeLists.txt b/runtimes/contrib/mlapse/CMakeLists.txt
new file mode 100644
index 000000000..bba79971a
--- /dev/null
+++ b/runtimes/contrib/mlapse/CMakeLists.txt
@@ -0,0 +1,8 @@
+if(NOT BUILD_MLAPSE)
+ return()
+endif(NOT BUILD_MLAPSE)
+
+message(STATUS "Build mlapse: TRUE")
+
+# TODO Add "core"
+add_subdirectory(tfl)
diff --git a/runtimes/contrib/mlapse/README.md b/runtimes/contrib/mlapse/README.md
new file mode 100644
index 000000000..36f14ac39
--- /dev/null
+++ b/runtimes/contrib/mlapse/README.md
@@ -0,0 +1,3 @@
+# mlapse
+
+_mlapse_ is a toolkit for model inference latency benchmark.
diff --git a/runtimes/contrib/mlapse/tfl/CMakeLists.txt b/runtimes/contrib/mlapse/tfl/CMakeLists.txt
new file mode 100644
index 000000000..36f32d7ef
--- /dev/null
+++ b/runtimes/contrib/mlapse/tfl/CMakeLists.txt
@@ -0,0 +1,12 @@
+message(STATUS "Build mlapse-tfl: TRUE")
+
+file(GLOB_RECURSE SOURCES "*.cc")
+
+add_executable(mlapse-tfl ${SOURCES})
+target_include_directories(mlapse-tfl PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
+target_link_libraries(mlapse-tfl nnfw_lib_tflite)
+target_link_libraries(mlapse-tfl nnfw_lib_misc)
+target_link_libraries(mlapse-tfl nnfw_lib_cpp14)
+target_link_libraries(mlapse-tfl tensorflow-lite)
+
+install(TARGETS mlapse-tfl DESTINATION bin)
diff --git a/runtimes/contrib/mlapse/tfl/driver.cc b/runtimes/contrib/mlapse/tfl/driver.cc
new file mode 100644
index 000000000..867a6051a
--- /dev/null
+++ b/runtimes/contrib/mlapse/tfl/driver.cc
@@ -0,0 +1,280 @@
+/*
+ * 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 "mlapse/benchmark_runner.h"
+#include "mlapse/multicast_observer.h"
+#include "mlapse/CSV_report_generator.h"
+
+#include "mlapse/tfl/load.h"
+
+// From 'nnfw_lib_tflite'
+#include <tflite/InterpreterSession.h>
+#include <tflite/NNAPISession.h>
+
+// From 'nnfw_lib_cpp14'
+#include <cpp14/memory.h>
+
+// From C++ Standard Library
+#include <cassert>
+#include <fstream>
+#include <iostream>
+#include <vector>
+
+namespace
+{
+
+using namespace mlapse;
+
+class ConsoleReporter final : public mlapse::BenchmarkObserver
+{
+public:
+ ConsoleReporter() = default;
+
+public:
+ void notify(const NotificationArg<PhaseBegin> &arg) final
+ {
+ _phase = arg.phase;
+ _count = arg.count;
+
+ std::cout << tag() << " BEGIN" << std::endl;
+ }
+
+ void notify(const NotificationArg<PhaseEnd> &arg) final
+ {
+ std::cout << tag() << " END" << std::endl;
+
+ _phase = mlapse::uninitialized_phase();
+ _count = 0;
+ }
+
+ void notify(const NotificationArg<IterationBegin> &arg) final { _index = arg.index; }
+
+ void notify(const NotificationArg<IterationEnd> &arg) final
+ {
+ std::cout << tag() << " " << progress() << " - " << arg.latency.count() << "ms" << std::endl;
+ }
+
+private:
+ std::string progress(void) const
+ {
+ return "[" + std::to_string(_index + 1) + "/" + std::to_string(_count) + "]";
+ }
+
+ std::string tag(void) const
+ {
+ switch (_phase)
+ {
+ case Phase::Warmup:
+ return "WARMUP";
+ case Phase::Record:
+ return "RECORD";
+ default:
+ break;
+ }
+
+ return "unknown";
+ }
+
+ Phase _phase = mlapse::uninitialized_phase();
+ uint32_t _count = 0;
+ uint32_t _index = 0;
+};
+
+} // namespace
+
+// Q. Is is worth to make a library for these routines?
+namespace
+{
+
+enum class SessionType
+{
+ Interp,
+ NNAPI,
+};
+
+class SessionBuilder
+{
+public:
+ SessionBuilder(const SessionType &type) : _type{type}
+ {
+ // DO NOTHING
+ }
+
+public:
+ std::unique_ptr<nnfw::tflite::Session> with(tflite::Interpreter *interp) const
+ {
+ switch (_type)
+ {
+ case SessionType::Interp:
+ return nnfw::cpp14::make_unique<nnfw::tflite::InterpreterSession>(interp);
+ case SessionType::NNAPI:
+ return nnfw::cpp14::make_unique<nnfw::tflite::NNAPISession>(interp);
+ default:
+ break;
+ }
+
+ return nullptr;
+ }
+
+ std::unique_ptr<nnfw::tflite::Session>
+ with(const std::unique_ptr<tflite::Interpreter> &interp) const
+ {
+ return with(interp.get());
+ }
+
+private:
+ SessionType _type;
+};
+
+SessionBuilder make_session(const SessionType &type) { return SessionBuilder{type}; }
+
+} // namespace
+
+namespace
+{
+
+// mlapse-tfl
+// [REQUIRED] --model <path/to/tflite>
+// [OPTIONAL] --warmup-count N (default = 3)
+// [OPTIONAL] --record-count N (default = 10)
+// [OPTIONAL] --thread N or auto (default = auto)
+// [OPTIOANL] --nnapi (default = off)
+// [OPTIONAL] --pause N (default = 0)
+// [OPTIONAL] --csv-report <path/to/csv>
+int entry(const int argc, char **argv)
+{
+ // Create an observer
+ mlapse::MulticastObserver observer;
+
+ observer.append(nnfw::cpp14::make_unique<ConsoleReporter>());
+
+ // Set default parameters
+ std::string model_path;
+ bool model_path_initialized = false;
+
+ SessionType session_type = SessionType::Interp;
+ uint32_t warmup_count = 3;
+ uint32_t record_count = 10;
+ int num_thread = -1; // -1 means "auto"
+
+ // Read command-line arguments
+ std::map<std::string, std::function<uint32_t(const char *const *)>> opts;
+
+ opts["--model"] = [&model_path, &model_path_initialized](const char *const *tok) {
+ model_path = std::string{tok[0]};
+ model_path_initialized = true;
+ return 1; // # of arguments
+ };
+
+ opts["--record-count"] = [&record_count](const char *const *tok) {
+ record_count = std::stoi(tok[0]);
+ return 1; // # of arguments
+ };
+
+ opts["--thread"] = [](const char *const *tok) {
+ assert(std::string{tok[0]} == "auto");
+ return 1;
+ };
+
+ opts["--nnapi"] = [&session_type](const char *const *) {
+ session_type = SessionType::NNAPI;
+ return 0;
+ };
+
+ opts["--csv-report"] = [&observer](const char *const *tok) {
+ observer.append(nnfw::cpp14::make_unique<mlapse::CSVReportGenerator>(tok[0]));
+ return 1;
+ };
+
+ {
+ uint32_t offset = 1;
+
+ while (offset < argc)
+ {
+ auto opt = argv[offset];
+
+ auto it = opts.find(opt);
+
+ if (it == opts.end())
+ {
+ std::cout << "INVALID OPTION: " << opt << std::endl;
+ return 255;
+ }
+
+ auto func = it->second;
+
+ auto num_skip = func(argv + offset + 1);
+
+ offset += 1;
+ offset += num_skip;
+ }
+ }
+
+ // Check arguments
+ if (!model_path_initialized)
+ {
+ std::cerr << "ERROR: --model is missing" << std::endl;
+ return 255;
+ }
+
+ // Load T/F Lite model
+ auto model = mlapse::tfl::load_model(model_path);
+
+ if (model == nullptr)
+ {
+ std::cerr << "ERROR: Failed to load '" << model_path << "'" << std::endl;
+ return 255;
+ }
+
+ auto interp = mlapse::tfl::make_interpreter(model.get());
+
+ if (interp == nullptr)
+ {
+ std::cerr << "ERROR: Failed to create a T/F Lite interpreter" << std::endl;
+ return 255;
+ }
+
+ auto sess = make_session(session_type).with(interp);
+
+ if (sess == nullptr)
+ {
+ std::cerr << "ERROR: Failed to create a session" << std::endl;
+ }
+
+ // Run benchmark
+ mlapse::BenchmarkRunner benchmark_runner{warmup_count, record_count};
+
+ benchmark_runner.attach(&observer);
+ benchmark_runner.run(sess);
+
+ return 0;
+}
+
+} // namespace
+
+int main(int argc, char **argv)
+{
+ try
+ {
+ return entry(argc, argv);
+ }
+ catch (const std::exception &e)
+ {
+ std::cerr << e.what() << std::endl;
+ }
+
+ return 255;
+}
diff --git a/runtimes/contrib/mlapse/tfl/mlapse/CSV_report_generator.cc b/runtimes/contrib/mlapse/tfl/mlapse/CSV_report_generator.cc
new file mode 100644
index 000000000..c6237a04f
--- /dev/null
+++ b/runtimes/contrib/mlapse/tfl/mlapse/CSV_report_generator.cc
@@ -0,0 +1,67 @@
+/*
+ * 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 "mlapse/CSV_report_generator.h"
+
+#include <cassert>
+#include <stdexcept>
+
+namespace
+{
+
+std::string tag(const mlapse::Phase &phase)
+{
+ switch (phase)
+ {
+ case mlapse::Phase::Warmup:
+ return "WARMUP";
+ case mlapse::Phase::Record:
+ return "STEADY";
+ default:
+ break;
+ }
+
+ throw std::invalid_argument{"phase"};
+}
+
+} // namespace
+
+namespace mlapse
+{
+
+void CSVReportGenerator::notify(const NotificationArg<PhaseBegin> &arg)
+{
+ assert(_phase == uninitialized_phase());
+ _phase = arg.phase;
+}
+
+void CSVReportGenerator::notify(const NotificationArg<PhaseEnd> &arg)
+{
+ assert(_phase != uninitialized_phase());
+ _phase = uninitialized_phase();
+}
+
+void CSVReportGenerator::notify(const NotificationArg<IterationBegin> &arg)
+{
+ // DO NOTHING
+}
+
+void CSVReportGenerator::notify(const NotificationArg<IterationEnd> &arg)
+{
+ _ofs << tag(_phase) << "," << arg.latency.count() << std::endl;
+}
+
+} // namespace mlapse
diff --git a/runtimes/contrib/mlapse/tfl/mlapse/CSV_report_generator.h b/runtimes/contrib/mlapse/tfl/mlapse/CSV_report_generator.h
new file mode 100644
index 000000000..8842baf8e
--- /dev/null
+++ b/runtimes/contrib/mlapse/tfl/mlapse/CSV_report_generator.h
@@ -0,0 +1,50 @@
+/*
+ * 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 __MLAPSE_CSV_REPORT_GENERATOR_H__
+#define __MLAPSE_CSV_REPORT_GENERATOR_H__
+
+#include "mlapse/benchmark_observer.h"
+
+#include <fstream>
+#include <string>
+
+namespace mlapse
+{
+
+class CSVReportGenerator final : public BenchmarkObserver
+{
+public:
+ CSVReportGenerator(const std::string &path) : _ofs{path, std::ofstream::out}
+ {
+ // DO NOTHING
+ }
+
+public:
+ void notify(const NotificationArg<PhaseBegin> &arg) final;
+ void notify(const NotificationArg<PhaseEnd> &arg) final;
+ void notify(const NotificationArg<IterationBegin> &arg) final;
+ void notify(const NotificationArg<IterationEnd> &arg);
+
+private:
+ std::ofstream _ofs;
+
+ Phase _phase = uninitialized_phase();
+};
+
+} // namespace mlapse
+
+#endif // __MLAPSE_MULTICAST_OBSERER_H__
diff --git a/runtimes/contrib/mlapse/tfl/mlapse/benchmark_observer.cc b/runtimes/contrib/mlapse/tfl/mlapse/benchmark_observer.cc
new file mode 100644
index 000000000..f6d596a7b
--- /dev/null
+++ b/runtimes/contrib/mlapse/tfl/mlapse/benchmark_observer.cc
@@ -0,0 +1,24 @@
+/*
+ * 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 "mlapse/benchmark_observer.h"
+
+namespace mlapse
+{
+
+Phase uninitialized_phase(void) { return static_cast<Phase>(0); }
+
+} // namespace mlapse
diff --git a/runtimes/contrib/mlapse/tfl/mlapse/benchmark_observer.h b/runtimes/contrib/mlapse/tfl/mlapse/benchmark_observer.h
new file mode 100644
index 000000000..8fc570d24
--- /dev/null
+++ b/runtimes/contrib/mlapse/tfl/mlapse/benchmark_observer.h
@@ -0,0 +1,77 @@
+/*
+ * 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 __MLAPSE_BENCHMARK_OBSERVER_H__
+#define __MLAPSE_BENCHMARK_OBSERVER_H__
+
+#include <cstdint>
+#include <chrono>
+
+namespace mlapse
+{
+
+enum Phase : int32_t
+{
+ // 0 denotes "uninitialized value"
+ Warmup = 1,
+ Record = 2,
+};
+
+Phase uninitialized_phase(void);
+
+enum Notification
+{
+ PhaseBegin,
+ PhaseEnd,
+ IterationBegin,
+ IterationEnd,
+};
+
+template <Notification N> struct NotificationArg;
+
+template <> struct NotificationArg<PhaseBegin>
+{
+ Phase phase;
+ uint32_t count;
+};
+
+template <> struct NotificationArg<PhaseEnd>
+{
+};
+
+template <> struct NotificationArg<IterationBegin>
+{
+ uint32_t index;
+};
+
+template <> struct NotificationArg<IterationEnd>
+{
+ std::chrono::milliseconds latency;
+};
+
+struct BenchmarkObserver
+{
+ virtual ~BenchmarkObserver() = default;
+
+ virtual void notify(const NotificationArg<PhaseBegin> &arg) = 0;
+ virtual void notify(const NotificationArg<PhaseEnd> &arg) = 0;
+ virtual void notify(const NotificationArg<IterationBegin> &arg) = 0;
+ virtual void notify(const NotificationArg<IterationEnd> &arg) = 0;
+};
+
+} // namespace mlpase
+
+#endif // __MLAPSE_BENCHMARK_OBSERVER_H__
diff --git a/runtimes/contrib/mlapse/tfl/mlapse/benchmark_runner.cc b/runtimes/contrib/mlapse/tfl/mlapse/benchmark_runner.cc
new file mode 100644
index 000000000..f5fc7302d
--- /dev/null
+++ b/runtimes/contrib/mlapse/tfl/mlapse/benchmark_runner.cc
@@ -0,0 +1,124 @@
+/*
+ * 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 "mlapse/benchmark_runner.h"
+
+// From 'nnfw_lib_misc'
+#include <misc/benchmark.h>
+
+// From C++ Standard Library
+#include <cassert>
+
+namespace mlapse
+{
+void BenchmarkRunner::attach(BenchmarkObserver *observer)
+{
+ assert(_observer == nullptr);
+ _observer = observer;
+}
+
+void BenchmarkRunner::run(nnfw::tflite::Session *sess) const
+{
+ for (auto phase : {Warmup, Record})
+ {
+ uint32_t const count = _count.at(phase);
+
+ // Notify when each phase begins
+ {
+ NotificationArg<PhaseBegin> arg;
+
+ arg.phase = phase;
+ arg.count = count;
+
+ notify(arg);
+ }
+
+ for (uint32_t n = 0; n < count; ++n)
+ {
+ std::chrono::milliseconds elapsed(0);
+
+ sess->prepare();
+
+ // Notify when each iteration begins
+ {
+ NotificationArg<IterationBegin> arg;
+
+ arg.index = n;
+
+ notify(arg);
+ };
+
+ nnfw::misc::benchmark::measure(elapsed) << [&](void) {
+ if (!sess->run())
+ {
+ throw std::runtime_error{"run failed"};
+ }
+ };
+
+ // Notify when each iteration ends
+ {
+ NotificationArg<IterationEnd> arg;
+
+ arg.latency = elapsed;
+
+ notify(arg);
+ };
+
+ sess->teardown();
+ }
+
+ // Notify when each phase ends
+ {
+ NotificationArg<PhaseEnd> arg;
+
+ notify(arg);
+ }
+ }
+}
+
+void BenchmarkRunner::notify(const NotificationArg<PhaseBegin> &arg) const
+{
+ if (_observer)
+ {
+ _observer->notify(arg);
+ }
+}
+
+void BenchmarkRunner::notify(const NotificationArg<PhaseEnd> &arg) const
+{
+ if (_observer)
+ {
+ _observer->notify(arg);
+ }
+}
+
+void BenchmarkRunner::notify(const NotificationArg<IterationBegin> &arg) const
+{
+ if (_observer)
+ {
+ _observer->notify(arg);
+ }
+}
+
+void BenchmarkRunner::notify(const NotificationArg<IterationEnd> &arg) const
+{
+ if (_observer)
+ {
+ _observer->notify(arg);
+ }
+}
+
+} // namespace mlapse
diff --git a/runtimes/contrib/mlapse/tfl/mlapse/benchmark_runner.h b/runtimes/contrib/mlapse/tfl/mlapse/benchmark_runner.h
new file mode 100644
index 000000000..fcbb41d1b
--- /dev/null
+++ b/runtimes/contrib/mlapse/tfl/mlapse/benchmark_runner.h
@@ -0,0 +1,63 @@
+/*
+ * 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 __MLAPSE_BENCHMARK_RUNNER_H__
+#define __MLAPSE_BENCHMARK_RUNNER_H__
+
+#include "mlapse/benchmark_observer.h"
+
+#include <tflite/Session.h>
+
+#include <chrono>
+#include <map>
+
+namespace mlapse
+{
+
+class BenchmarkRunner final
+{
+public:
+ BenchmarkRunner(uint32_t warmup_count, uint32_t record_count)
+ {
+ _count[Warmup] = warmup_count;
+ _count[Record] = record_count;
+ }
+
+public:
+ void attach(BenchmarkObserver *observer);
+
+public:
+ void run(nnfw::tflite::Session *sess) const;
+
+public:
+ void run(const std::unique_ptr<nnfw::tflite::Session> &sess) const { run(sess.get()); }
+
+private:
+ void notify(const NotificationArg<PhaseBegin> &arg) const;
+ void notify(const NotificationArg<PhaseEnd> &arg) const;
+ void notify(const NotificationArg<IterationBegin> &arg) const;
+ void notify(const NotificationArg<IterationEnd> &arg) const;
+
+private:
+ std::map<Phase, uint32_t> _count;
+
+private:
+ BenchmarkObserver *_observer = nullptr;
+};
+
+} // namespace mlpase
+
+#endif // __MLAPSE_BENCHMARK_RUNNER_H__
diff --git a/runtimes/contrib/mlapse/tfl/mlapse/multicast_observer.cc b/runtimes/contrib/mlapse/tfl/mlapse/multicast_observer.cc
new file mode 100644
index 000000000..639acfe45
--- /dev/null
+++ b/runtimes/contrib/mlapse/tfl/mlapse/multicast_observer.cc
@@ -0,0 +1,17 @@
+/*
+ * 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 "mlapse/multicast_observer.h"
diff --git a/runtimes/contrib/mlapse/tfl/mlapse/multicast_observer.h b/runtimes/contrib/mlapse/tfl/mlapse/multicast_observer.h
new file mode 100644
index 000000000..e4aac50a9
--- /dev/null
+++ b/runtimes/contrib/mlapse/tfl/mlapse/multicast_observer.h
@@ -0,0 +1,75 @@
+/*
+ * 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 __MLAPSE_MULTICAST_OBSERER_H__
+#define __MLAPSE_MULTICAST_OBSERER_H__
+
+#include "mlapse/benchmark_observer.h"
+
+#include <memory>
+#include <vector>
+
+namespace mlapse
+{
+
+class MulticastObserver final : public BenchmarkObserver
+{
+public:
+ MulticastObserver() = default;
+
+public:
+ void append(std::unique_ptr<BenchmarkObserver> &&o) { _observers.emplace_back(std::move(o)); }
+
+public:
+ void notify(const NotificationArg<PhaseBegin> &arg) final
+ {
+ for (const auto &o : _observers)
+ {
+ o->notify(arg);
+ }
+ }
+
+ void notify(const NotificationArg<PhaseEnd> &arg) final
+ {
+ for (const auto &o : _observers)
+ {
+ o->notify(arg);
+ }
+ }
+
+ void notify(const NotificationArg<IterationBegin> &arg) final
+ {
+ for (const auto &o : _observers)
+ {
+ o->notify(arg);
+ }
+ }
+
+ void notify(const NotificationArg<IterationEnd> &arg) final
+ {
+ for (const auto &o : _observers)
+ {
+ o->notify(arg);
+ }
+ }
+
+private:
+ std::vector<std::unique_ptr<BenchmarkObserver>> _observers;
+};
+
+} // namespace mlapse
+
+#endif // __MLAPSE_MULTICAST_OBSERER_H__
diff --git a/runtimes/contrib/mlapse/tfl/mlapse/tfl/load.cc b/runtimes/contrib/mlapse/tfl/mlapse/tfl/load.cc
new file mode 100644
index 000000000..9e770aecf
--- /dev/null
+++ b/runtimes/contrib/mlapse/tfl/mlapse/tfl/load.cc
@@ -0,0 +1,55 @@
+/*
+ * 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 "mlapse/tfl/load.h"
+
+#include <tflite/ext/kernels/register.h>
+
+namespace
+{
+
+tflite::StderrReporter error_reporter;
+
+} // namespace
+
+namespace mlapse
+{
+namespace tfl
+{
+
+std::unique_ptr<tflite::FlatBufferModel> load_model(const std::string &path)
+{
+ return tflite::FlatBufferModel::BuildFromFile(path.c_str(), &error_reporter);
+}
+
+std::unique_ptr<tflite::Interpreter> make_interpreter(const tflite::FlatBufferModel *model)
+{
+ // Let's use extended resolver!
+ nnfw::tflite::BuiltinOpResolver resolver;
+ tflite::InterpreterBuilder builder(*model, resolver);
+
+ std::unique_ptr<tflite::Interpreter> interpreter;
+
+ if (builder(&interpreter) != kTfLiteOk)
+ {
+ return nullptr;
+ }
+
+ return std::move(interpreter);
+}
+
+} // namespace tfl
+} // namespace mlapse
diff --git a/runtimes/contrib/mlapse/tfl/mlapse/tfl/load.h b/runtimes/contrib/mlapse/tfl/mlapse/tfl/load.h
new file mode 100644
index 000000000..6f5a8f1ea
--- /dev/null
+++ b/runtimes/contrib/mlapse/tfl/mlapse/tfl/load.h
@@ -0,0 +1,40 @@
+/*
+ * 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 __MLAPSE_TFL_LOAD_H__
+#define __MLAPSE_TFL_LOAD_H__
+
+#include <tensorflow/lite/interpreter.h>
+#include <tensorflow/lite/model.h>
+
+#include <memory>
+
+namespace mlapse
+{
+namespace tfl
+{
+
+std::unique_ptr<tflite::FlatBufferModel> load_model(const std::string &path);
+
+// WARNING
+//
+// model SHOULD outlive Interpreter
+std::unique_ptr<tflite::Interpreter> make_interpreter(const tflite::FlatBufferModel *model);
+
+} // namespace tfl
+} // namespace mlapse
+
+#endif // __MLAPSE_TFL_LOAD_H__