summaryrefslogtreecommitdiff
path: root/runtime/neurun/core/src/util
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/neurun/core/src/util')
-rw-r--r--runtime/neurun/core/src/util/ConfigSource.cc116
-rw-r--r--runtime/neurun/core/src/util/EnvConfigSource.cc40
-rw-r--r--runtime/neurun/core/src/util/EventCollectorGlobal.cc86
-rw-r--r--runtime/neurun/core/src/util/GeneralConfigSource.cc45
-rw-r--r--runtime/neurun/core/src/util/Padding.cc119
-rw-r--r--runtime/neurun/core/src/util/ShapeInference.cc200
-rw-r--r--runtime/neurun/core/src/util/Utils.cc68
-rw-r--r--runtime/neurun/core/src/util/logging.cc7
8 files changed, 681 insertions, 0 deletions
diff --git a/runtime/neurun/core/src/util/ConfigSource.cc b/runtime/neurun/core/src/util/ConfigSource.cc
new file mode 100644
index 000000000..7d57ec178
--- /dev/null
+++ b/runtime/neurun/core/src/util/ConfigSource.cc
@@ -0,0 +1,116 @@
+/*
+ * 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 "util/ConfigSource.h"
+#include "util/GeneralConfigSource.h"
+#include "util/EnvConfigSource.h"
+
+#include <array>
+#include <algorithm>
+#include <cassert>
+
+#include "cpp14/memory.h"
+
+namespace neurun
+{
+namespace util
+{
+
+static std::unique_ptr<IConfigSource> _source;
+
+void config_source(std::unique_ptr<IConfigSource> &&source) { _source = std::move(source); }
+
+static IConfigSource *config_source()
+{
+ if (!_source)
+ {
+#ifdef ENVVAR_FOR_DEFAULT_CONFIG
+ // Default ConfigSource is EnvConfigSource
+ _source = nnfw::cpp14::make_unique<EnvConfigSource>();
+#else
+ _source = nnfw::cpp14::make_unique<GeneralConfigSource>();
+#endif // ENVVAR_FOR_DEFAULT_CONFIG
+ }
+ return _source.get();
+}
+
+static std::string getConfigOrDefault(const std::string &key)
+{
+ static std::unordered_map<std::string, std::string> defaults;
+ if (defaults.empty())
+ {
+#define CONFIG(Name, Type, Default) \
+ { \
+ auto name = std::string{#Name}; \
+ defaults.emplace(name, std::string{Default}); \
+ }
+
+#include "util/Config.lst"
+
+#undef CONFIG
+ }
+
+ // Treat empty string and absence of the value to be the same
+ auto ret = config_source()->get(key);
+ if (ret.empty())
+ {
+ auto itr = defaults.find(key);
+ if (itr != defaults.end())
+ {
+ // Return the default value if exists
+ ret = itr->second;
+ }
+ }
+
+ return ret;
+}
+
+bool getConfigBool(const std::string &key)
+{
+ auto raw = getConfigOrDefault(key);
+ static const std::array<std::string, 5> false_list{"0", "OFF", "FALSE", "N", "NO"};
+ auto false_found = std::find(false_list.begin(), false_list.end(), raw);
+
+ return (false_found == false_list.end());
+}
+
+int getConfigInt(const std::string &key)
+{
+ auto raw = getConfigOrDefault(key);
+ return std::stoi(raw);
+}
+
+std::string getConfigString(const std::string &key) { return getConfigOrDefault(key); }
+
+} // namespace util
+} // namespace neurun
+
+namespace neurun
+{
+namespace util
+{
+namespace config
+{
+
+#define CONFIG(Name, Type, Default) const char *Name = #Name;
+
+#include "util/Config.lst"
+
+#undef CONFIG
+
+} // namespace config
+} // namespace util
+} // namespace neurun
diff --git a/runtime/neurun/core/src/util/EnvConfigSource.cc b/runtime/neurun/core/src/util/EnvConfigSource.cc
new file mode 100644
index 000000000..52a6bf2a4
--- /dev/null
+++ b/runtime/neurun/core/src/util/EnvConfigSource.cc
@@ -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.
+ */
+
+#include "util/EnvConfigSource.h"
+
+#include <cstdlib>
+
+namespace neurun
+{
+namespace util
+{
+
+std::string EnvConfigSource::get(const std::string &key) const
+{
+ const char *value = std::getenv(key.c_str());
+ if (value != nullptr)
+ {
+ return value;
+ }
+ else
+ {
+ return GeneralConfigSource::get(key);
+ }
+}
+
+} // namespace util
+} // namespace neurun
diff --git a/runtime/neurun/core/src/util/EventCollectorGlobal.cc b/runtime/neurun/core/src/util/EventCollectorGlobal.cc
new file mode 100644
index 000000000..6c3594f5f
--- /dev/null
+++ b/runtime/neurun/core/src/util/EventCollectorGlobal.cc
@@ -0,0 +1,86 @@
+/*
+ * 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 "util/EventCollectorGlobal.h"
+
+#include <cassert>
+#include <fstream>
+
+#include "util/ConfigSource.h"
+
+namespace neurun
+{
+namespace util
+{
+
+EventCollectorGlobal::EventCollectorGlobal() : _recorder{}, _collector{&_recorder}
+{
+ // DO NOTHING
+}
+
+EventCollectorGlobal::~EventCollectorGlobal()
+{
+ auto path = util::getConfigString(util::config::TRACE_FILEPATH);
+ if (!path.empty())
+ {
+ // TODO Need better way for saved file path than just appending ".global" to the trace file path
+ std::ofstream ofs{path + ".global"};
+ _recorder.writeToFile(ofs);
+ }
+}
+
+EventCollectorGlobal &EventCollectorGlobal::get()
+{
+ static EventCollectorGlobal instance;
+ return instance;
+}
+
+EventDurationBlock::EventDurationBlock(const std::string &tag) : _tag{tag}
+{
+ auto &glob = EventCollectorGlobal::get();
+ glob.collector().onEvent(EventCollector::Event{EventCollector::Edge::BEGIN, "0", _tag});
+}
+EventDurationBlock::~EventDurationBlock()
+{
+ auto &glob = EventCollectorGlobal::get();
+ glob.collector().onEvent(EventCollector::Event{EventCollector::Edge::END, "0", _tag});
+}
+
+EventDurationManual::EventDurationManual(const std::string &tag) : _tag{tag}, _pair{true} {}
+
+EventDurationManual::~EventDurationManual()
+{
+ // Check if it has called begin-end pair
+ assert(_pair);
+}
+
+void EventDurationManual::begin()
+{
+ _pair = false;
+ auto &glob = EventCollectorGlobal::get();
+ glob.collector().onEvent(EventCollector::Event{EventCollector::Edge::BEGIN, "0", _tag});
+}
+
+void EventDurationManual::end()
+{
+ assert(!_pair);
+ _pair = true;
+ auto &glob = EventCollectorGlobal::get();
+ glob.collector().onEvent(EventCollector::Event{EventCollector::Edge::END, "0", _tag});
+}
+
+} // namespace util
+} // namespace neurun
diff --git a/runtime/neurun/core/src/util/GeneralConfigSource.cc b/runtime/neurun/core/src/util/GeneralConfigSource.cc
new file mode 100644
index 000000000..084e4c109
--- /dev/null
+++ b/runtime/neurun/core/src/util/GeneralConfigSource.cc
@@ -0,0 +1,45 @@
+/*
+ * 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 "util/GeneralConfigSource.h"
+#include "util/logging.h"
+
+namespace neurun
+{
+namespace util
+{
+
+std::string GeneralConfigSource::get(const std::string &key) const
+{
+ auto itr = _map.find(key);
+ if (itr == _map.end())
+ {
+ return "";
+ }
+ else
+ {
+ return itr->second;
+ }
+}
+
+void GeneralConfigSource::set(const std::string &key, const std::string &val)
+{
+ VERBOSE(GeneralConfigSource) << key << " : " << val << std::endl;
+ _map[key] = val;
+}
+
+} // namespace util
+} // namespace neurun
diff --git a/runtime/neurun/core/src/util/Padding.cc b/runtime/neurun/core/src/util/Padding.cc
new file mode 100644
index 000000000..2e2202b58
--- /dev/null
+++ b/runtime/neurun/core/src/util/Padding.cc
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2018 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 "util/Padding.h"
+#include "util/Utils.h"
+
+#include <algorithm>
+#include <stdexcept>
+
+namespace neurun
+{
+namespace util
+{
+
+ir::ExplicitPadding validPadding(void)
+{
+ //
+ // ANEURALNETWORKS_PADDING_VALID
+ //
+ // VALID padding. No padding.
+ //
+ // When the input size is not evenly divisible by the filter size,
+ // the input at the end that could not fill the whole filter tile
+ // will simply be ignored.
+ //
+ ir::ExplicitPadding padding;
+
+ padding.top = 0;
+ padding.bottom = 0;
+ padding.left = 0;
+ padding.right = 0;
+
+ return padding;
+}
+
+ir::ExplicitPadding samePaddingUsingIFM(const ir::FeatureShape &ifm_shape, const ir::Stride &stride,
+ uint32_t kw, uint32_t kh)
+{
+ ir::ExplicitPadding padding;
+
+ // ANEURALNETWORKS_PADDING_SAME (from NNAPI spec)
+ //
+ // SAME padding. Padding on both ends are the "same":
+ //
+ // padding_to_beginning = total_padding / 2
+ // padding_to_end = (total_padding + 1)/2.
+ //
+ const int32_t vertical_expected_output = (ifm_shape.H + stride.vertical - 1) / stride.vertical;
+ const int32_t horizontal_expected_output =
+ (ifm_shape.W + stride.horizontal - 1) / stride.horizontal;
+
+ const int32_t vertical_needed_input = (vertical_expected_output - 1) * stride.vertical + kh;
+ const int32_t vertical_total_padding = std::max(0, vertical_needed_input - ifm_shape.H);
+
+ const int32_t horizontal_needed_input = (horizontal_expected_output - 1) * stride.horizontal + kw;
+ const int32_t horizontal_total_padding = std::max(0, horizontal_needed_input - ifm_shape.W);
+
+ padding.top = vertical_total_padding / 2;
+ padding.bottom = (vertical_total_padding + 1) / 2;
+ padding.left = horizontal_total_padding / 2;
+ padding.right = (horizontal_total_padding + 1) / 2;
+
+ return padding;
+}
+
+ir::ExplicitPadding samePadding(const ir::FeatureShape &ifm_shape,
+ const ir::FeatureShape &ofm_shape, const ir::Stride &stride,
+ uint32_t kw, uint32_t kh)
+{
+ const int32_t vertical_expected_output = (ifm_shape.H + stride.vertical - 1) / stride.vertical;
+ const int32_t horizontal_expected_output =
+ (ifm_shape.W + stride.horizontal - 1) / stride.horizontal;
+ assert(vertical_expected_output == ofm_shape.H);
+ assert(horizontal_expected_output == ofm_shape.W);
+
+ UNUSED_RELEASE(ofm_shape);
+ UNUSED_RELEASE(vertical_expected_output);
+ UNUSED_RELEASE(horizontal_expected_output);
+
+ return samePaddingUsingIFM(ifm_shape, stride, kw, kh);
+}
+
+ir::ExplicitPadding calculatePadding(const ir::Padding &padding, const ir::FeatureShape &ifm_shape,
+ const ir::FeatureShape &ofm_shape, const ir::Stride &stride,
+ uint32_t kw, uint32_t kh)
+{
+ if (padding.type == ir::PaddingType::EXPLICIT)
+ {
+ return padding.param;
+ }
+ else if (padding.type == ir::PaddingType::SAME)
+ {
+ return samePadding(ifm_shape, ofm_shape, stride, kw, kh);
+ }
+ else if (padding.type == ir::PaddingType::VALID)
+ {
+ return validPadding();
+ }
+ else
+ {
+ throw std::runtime_error{"Cannot handle padding type"};
+ }
+}
+
+} // namespace util
+} // namespace neurun
diff --git a/runtime/neurun/core/src/util/ShapeInference.cc b/runtime/neurun/core/src/util/ShapeInference.cc
new file mode 100644
index 000000000..6fa29e7d8
--- /dev/null
+++ b/runtime/neurun/core/src/util/ShapeInference.cc
@@ -0,0 +1,200 @@
+/*
+ * 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 "util/Utils.h"
+#include "ir/InternalType.h"
+#include "ir/Shape.h"
+#include "ir/operation/AvgPool2D.h"
+#include "ir/operation/MaxPool2D.h"
+#include "util/ShapeInference.h"
+
+namespace neurun
+{
+namespace shape_inference
+{
+
+//
+// Helper functions
+//
+
+namespace
+{
+
+template <typename T, typename U>
+typename std::enable_if<std::is_integral<T>::value && std::is_integral<U>::value,
+ typename std::common_type<T, U>::type>::type
+ceil_div(T dividend, U divisor)
+{
+ assert(dividend > 0 && divisor > 0 && "this implementations is for positive numbers only");
+ return (dividend + divisor - 1) / divisor;
+}
+
+// Calculate the result of broadcast of two shapes
+ir::Shape broadcastShapes(const ir::Shape &lhs_shape, const ir::Shape &rhs_shape)
+{
+ ir::Shape out_shape;
+ auto max_rank = std::max(lhs_shape.rank(), rhs_shape.rank());
+
+ for (int idx = 0; idx < max_rank; ++idx)
+ {
+ // Go over operands dimensions from right to left
+ int lhs_idx = lhs_shape.rank() - idx - 1;
+ int rhs_idx = rhs_shape.rank() - idx - 1;
+
+ int32_t lhs_dim = lhs_idx >= 0 ? lhs_shape.dim(lhs_idx) : 1;
+ int32_t rhs_dim = rhs_idx >= 0 ? rhs_shape.dim(rhs_idx) : 1;
+
+ if (lhs_dim != 1 && rhs_dim != 1 && lhs_dim != rhs_dim)
+ throw std::runtime_error("Incompatible shapes for broadcast");
+
+ out_shape.prepend(std::max(lhs_dim, rhs_dim));
+ }
+
+ return out_shape;
+}
+
+// Calculate output height and width of convolution-like operation
+std::pair<int, int> calcConvLikeHeightAndWidth(const int in_h, const int in_w, const int ker_h,
+ const int ker_w, const ir::Padding pad,
+ const ir::Stride stride)
+{
+ int32_t out_h = 0, out_w = 0;
+
+ switch (pad.type)
+ {
+ case ir::PaddingType::SAME:
+ out_h = ceil_div(in_h, stride.vertical);
+ out_w = ceil_div(in_w, stride.horizontal);
+ break;
+ case ir::PaddingType::VALID:
+ out_h = ceil_div(in_h - ker_h + 1, stride.vertical);
+ out_w = ceil_div(in_w - ker_w + 1, stride.horizontal);
+ break;
+ case ir::PaddingType::EXPLICIT:
+ out_h = (in_h + pad.param.top + pad.param.bottom - ker_h) / stride.vertical + 1;
+ out_w = (in_w + pad.param.left + pad.param.right - ker_w) / stride.horizontal + 1;
+ break;
+ default:
+ assert(false);
+ }
+
+ return {out_h, out_w};
+}
+
+} // namespace
+
+//
+// Shape inference
+//
+
+Shapes inferEltwiseShape(const ir::Shape &lhs_shape, const ir::Shape &rhs_shape)
+{
+ return {broadcastShapes(lhs_shape, rhs_shape)};
+}
+
+Shapes inferAvgPoolShape(const ir::Shape &in_shape, const ir::operation::AvgPool2D::Param &param,
+ const ir::Layout layout)
+{
+ assert(layout == ir::Layout::NHWC);
+ auto ifm_shape = in_shape.asFeature(layout);
+ const auto out_h_w = calcConvLikeHeightAndWidth(ifm_shape.H, ifm_shape.W, param.kh, param.kw,
+ param.padding, param.stride);
+ // Pooling don't change number of channels and batch size
+ return {ir::Shape{ifm_shape.N, out_h_w.first, out_h_w.second, ifm_shape.C}};
+}
+
+Shapes inferConcatShape(const Shapes &in_shapes, const ir::operation::Concat::Param &param)
+{
+ const int32_t concat_axis = param.axis;
+ const auto &first_in_shape = in_shapes[0];
+
+ // Check that all shapes are equal except for concat axis dimension
+ for (const auto &in_shape : in_shapes)
+ {
+ assert(in_shape.rank() == first_in_shape.rank());
+ for (int64_t dim_idx = 0; dim_idx < in_shape.rank(); ++dim_idx)
+ assert(dim_idx == concat_axis || in_shape.dim(dim_idx) == first_in_shape.dim(dim_idx));
+ }
+
+ // Calculate output shape
+ ir::Shape out_shape(first_in_shape);
+ out_shape.dim(concat_axis) = 0;
+ for (const auto &in_shape : in_shapes)
+ out_shape.dim(concat_axis) += in_shape.dim(concat_axis);
+ return {out_shape};
+}
+
+Shapes inferMaxPoolShape(const ir::Shape &in_shape, const ir::operation::MaxPool2D::Param &param,
+ const ir::Layout layout)
+{
+ assert(layout == ir::Layout::NHWC);
+ auto ifm_shape = in_shape.asFeature(layout);
+ const auto out_h_w = calcConvLikeHeightAndWidth(ifm_shape.H, ifm_shape.W, param.kh, param.kw,
+ param.padding, param.stride);
+ // Pooling don't change number of channels and batch size
+ return {ir::Shape{ifm_shape.N, out_h_w.first, out_h_w.second, ifm_shape.C}};
+}
+
+Shapes inferConv2DShape(const ir::Shape &in_shape, const ir::Shape &ker_shape,
+ const ir::operation::Conv2D::Param &param, ir::Layout layout)
+{
+ assert(layout == ir::Layout::NHWC);
+ auto ifm_shape = in_shape.asFeature(layout);
+
+ // Kernel format is [depth_out, kernel_height, kernel_width, depth_in]
+ auto kf_shape = ker_shape.asFeature(layout);
+ assert(ifm_shape.C == kf_shape.C);
+
+ const auto out_h_w = calcConvLikeHeightAndWidth(ifm_shape.H, ifm_shape.W, kf_shape.H, kf_shape.W,
+ param.padding, param.stride);
+
+ return {ir::Shape{ifm_shape.N, out_h_w.first, out_h_w.second, kf_shape.N}};
+}
+
+Shapes inferDepthwiseConv2DShape(const ir::Shape &in_shape, const ir::Shape &ker_shape,
+ const ir::operation::DepthwiseConv2D::Param &param,
+ ir::Layout layout)
+{
+ assert(layout == ir::Layout::NHWC);
+ auto ifm_shape = in_shape.asFeature(layout);
+
+ // Kernel format is [1, kernel_height, kernel_width, depth_out]
+ auto kf_shape = ker_shape.asFeature(layout);
+ assert(kf_shape.C == static_cast<int32_t>(ifm_shape.C * param.multiplier));
+ assert(kf_shape.N == 1);
+
+ const auto out_h_w = calcConvLikeHeightAndWidth(ifm_shape.H, ifm_shape.W, kf_shape.H, kf_shape.W,
+ param.padding, param.stride);
+
+ return {ir::Shape{ifm_shape.N, out_h_w.first, out_h_w.second, kf_shape.C}};
+}
+
+Shapes inferFullyConnectedShape(const ir::Shape &in_shape, const ir::Shape &ker_shape)
+{
+ assert(in_shape.rank() >= 2);
+ assert(ker_shape.rank() == 2);
+
+ const auto input_size_with_batch = in_shape.num_elements();
+ const auto num_units = ker_shape.dim(0);
+ const auto input_size = ker_shape.dim(1);
+ const auto batch_size = input_size_with_batch / input_size;
+ assert(input_size_with_batch % input_size == 0);
+
+ return {{ir::Shape({static_cast<int32_t>(batch_size), num_units})}};
+}
+
+} // namespace shape_inference
+} // namespace neurun
diff --git a/runtime/neurun/core/src/util/Utils.cc b/runtime/neurun/core/src/util/Utils.cc
new file mode 100644
index 000000000..1e24e28d4
--- /dev/null
+++ b/runtime/neurun/core/src/util/Utils.cc
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2018 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 "util/Utils.h"
+
+#include <cassert>
+
+namespace neurun
+{
+namespace util
+{
+
+const char *to_string(const ir::PaddingType type)
+{
+ assert((type == ir::PaddingType::EXPLICIT) || (type == ir::PaddingType::SAME) ||
+ (type == ir::PaddingType::VALID));
+
+ switch (type)
+ {
+ case ir::PaddingType::EXPLICIT:
+ return "Padding::EXPLICIT";
+ case ir::PaddingType::SAME:
+ return "Padding::SAME";
+ case ir::PaddingType::VALID:
+ return "Padding::VALID";
+ }
+
+ return nullptr;
+}
+
+Coordinates convertCoordinates(const Coordinates &from_coordinates, ir::Layout from_layout,
+ ir::Layout to_layout)
+{
+ assert(from_coordinates.size() == 4);
+ Coordinates to{from_coordinates};
+ if (from_layout == ir::Layout::NHWC && to_layout == ir::Layout::NCHW)
+ {
+ to.set(0, from_coordinates[0]);
+ to.set(1, from_coordinates[3]);
+ to.set(2, from_coordinates[1]);
+ to.set(3, from_coordinates[2]);
+ }
+ else if (from_layout == ir::Layout::NCHW && to_layout == ir::Layout::NHWC)
+ {
+ to.set(0, from_coordinates[0]);
+ to.set(1, from_coordinates[2]);
+ to.set(2, from_coordinates[3]);
+ to.set(3, from_coordinates[1]);
+ }
+
+ return to;
+}
+
+} // namespace util
+} // namespace neurun
diff --git a/runtime/neurun/core/src/util/logging.cc b/runtime/neurun/core/src/util/logging.cc
new file mode 100644
index 000000000..c23e2b53c
--- /dev/null
+++ b/runtime/neurun/core/src/util/logging.cc
@@ -0,0 +1,7 @@
+#include "util/logging.h"
+
+neurun::util::logging::Context &neurun::util::logging::Context::get() noexcept
+{
+ static Context ctx;
+ return ctx;
+}