diff --git a/compiler/record-minmax/CMakeLists.txt b/compiler/record-minmax/CMakeLists.txt index 3feca330ad0..6755de36eda 100644 --- a/compiler/record-minmax/CMakeLists.txt +++ b/compiler/record-minmax/CMakeLists.txt @@ -57,6 +57,7 @@ endif("${CMAKE_SIZEOF_VOID_P}" STREQUAL "8" AND FALSE) # record-minmax is executable, so we do not link it to the test. # Instead, we use TEST_SOURCES to specify sources uesd for tests. set(TEST_SOURCES + "src/Utils.cpp" "src/RecordFunction.cpp" "src/MinMaxComputer.cpp") diff --git a/compiler/record-minmax/include/RandomIterator.h b/compiler/record-minmax/include/RandomIterator.h new file mode 100644 index 00000000000..2a58f588fb7 --- /dev/null +++ b/compiler/record-minmax/include/RandomIterator.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2024 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 __RECORD_MINMAX_RANDOM_ITERATOR_H__ +#define __RECORD_MINMAX_RANDOM_ITERATOR_H__ + +#include "DataBuffer.h" +#include "DataSetIterator.h" + +#include +#include + +#include +#include + +namespace record_minmax +{ + +class RandomIterator final : public DataSetIterator +{ +public: + RandomIterator(luci::Module *module); + + bool hasNext() const override; + + std::vector next() override; + + bool check_type_shape() const override; + +private: + std::mt19937 _gen; + std::vector _input_nodes; + uint32_t _curr_idx = 0; + uint32_t _num_data = 0; +}; + +} // namespace record_minmax + +#endif // __RECORD_MINMAX_RANDOM_ITERATOR_H__ diff --git a/compiler/record-minmax/include/Utils.h b/compiler/record-minmax/include/Utils.h new file mode 100644 index 00000000000..7c74fe25e1e --- /dev/null +++ b/compiler/record-minmax/include/Utils.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2024 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 __RECORD_MINMAX_UTILS_H__ +#define __RECORD_MINMAX_UTILS_H__ + +#include + +#include +#include + +namespace record_minmax +{ + +// Return total number of elements of the node's output tensor +uint32_t numElements(const luci::CircleNode *node); + +// Return the node's output tensor size in bytes +size_t getTensorSize(const luci::CircleNode *node); + +} // namespace record_minmax + +#endif // __RECORD_MINMAX_UTILS_H__ diff --git a/compiler/record-minmax/src/RandomIterator.cpp b/compiler/record-minmax/src/RandomIterator.cpp new file mode 100644 index 00000000000..fbe9fa0886e --- /dev/null +++ b/compiler/record-minmax/src/RandomIterator.cpp @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2024 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 "RandomIterator.h" +#include "DataBuffer.h" +#include "Utils.h" + +#include +#include + +#include +#include + +namespace +{ + +std::vector genRandomData(std::mt19937 &gen, uint32_t num_elements, float min, float max) +{ + std::uniform_real_distribution dist(min, max); + std::vector input_data(num_elements); + + // Write random data + { + auto const generator = [&gen, &dist]() { return static_cast(dist(gen)); }; + std::generate(begin(input_data), end(input_data), generator); + } + + return input_data; +} + +template +std::vector genRandomIntData(std::mt19937 &gen, uint32_t num_elements, T min, T max) +{ + std::uniform_int_distribution dist(min, max); + std::vector input_data(num_elements); + + // Write random data + { + auto const generator = [&gen, &dist]() { return dist(gen); }; + std::generate(begin(input_data), end(input_data), generator); + } + + return input_data; +} + +} // namespace + +namespace record_minmax +{ + +RandomIterator::RandomIterator(luci::Module *module) +{ + assert(module); // FIX_CALLER_UNLESS + + std::random_device rd; + std::mt19937 _gen(rd()); + + auto input_nodes = loco::input_nodes(module->graph()); + for (auto input_node : input_nodes) + { + const auto cnode = loco::must_cast(input_node); + _input_nodes.emplace_back(cnode); + } + + // Hardcoded + _num_data = 3; +} + +bool RandomIterator::hasNext() const { return _curr_idx < _num_data; } + +std::vector RandomIterator::next() +{ + std::vector res; + + for (auto input_node : _input_nodes) + { + DataBuffer buf; + + const auto dtype = input_node->dtype(); + const auto num_elements = numElements(input_node); + + buf.data.resize(getTensorSize(input_node)); + + switch (dtype) + { + case loco::DataType::FLOAT32: + { + const auto input_data = genRandomData(_gen, num_elements, -5, 5); + const auto data_size = input_data.size() * sizeof(float); + assert(buf.data.size() == data_size); + memcpy(buf.data.data(), input_data.data(), data_size); + break; + } + case loco::DataType::S32: + { + const auto input_data = genRandomIntData(_gen, num_elements, 0, 100); + const auto data_size = input_data.size() * sizeof(int32_t); + assert(buf.data.size() == data_size); + memcpy(buf.data.data(), input_data.data(), data_size); + break; + } + case loco::DataType::S64: + { + const auto input_data = genRandomIntData(_gen, num_elements, 0, 100); + const auto data_size = input_data.size() * sizeof(int64_t); + assert(buf.data.size() == data_size); + memcpy(buf.data.data(), input_data.data(), data_size); + break; + } + case loco::DataType::BOOL: + { + const auto input_data = genRandomIntData(_gen, num_elements, 0, 1); + const auto data_size = input_data.size() * sizeof(uint8_t); + assert(buf.data.size() == data_size); + memcpy(buf.data.data(), input_data.data(), data_size); + break; + } + default: + throw std::runtime_error("Unsupported datatype"); + } + + res.emplace_back(buf); + } + + _curr_idx++; // move to the next index + + return res; +} + +bool RandomIterator::check_type_shape() const { return false; } + +} // namespace record_minmax diff --git a/compiler/record-minmax/src/Utils.cpp b/compiler/record-minmax/src/Utils.cpp new file mode 100644 index 00000000000..dd8fa7a05fe --- /dev/null +++ b/compiler/record-minmax/src/Utils.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2024 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 "Utils.h" + +#include +#include + +namespace record_minmax +{ + +uint32_t numElements(const luci::CircleNode *node) +{ + assert(node); // FIX_CALLER_UNLESS + + uint32_t num_elements = 1; + for (uint32_t i = 0; i < node->rank(); i++) + { + if (not node->dim(i).known()) + throw std::runtime_error("Unknown dimension found in " + node->name()); + + num_elements *= node->dim(i).value(); + } + + return num_elements; +} + +size_t getTensorSize(const luci::CircleNode *node) +{ + assert(node); // FIX_CALLER_UNLESS + + uint32_t elem_size = luci::size(node->dtype()); + return numElements(node) * elem_size; +} + +} // namespace record_minmax diff --git a/compiler/record-minmax/tests/Utils.test.cpp b/compiler/record-minmax/tests/Utils.test.cpp new file mode 100644 index 00000000000..6bac8fc6cb8 --- /dev/null +++ b/compiler/record-minmax/tests/Utils.test.cpp @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2024 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 "Utils.h" + +#include + +#include + +using namespace record_minmax; + +TEST(UtilsTest, num_elements) +{ + luci::CircleAdd node; + node.rank(3); + node.dim(0).set(1); + node.dim(1).set(2); + node.dim(2).set(3); + node.dtype(loco::DataType::FLOAT32); + + EXPECT_EQ(6, numElements(&node)); +} + +TEST(UtilsTest, num_elements_NEG) +{ + luci::CircleAdd node; + node.rank(3); + node.dim(0).set(1); + node.dim(1).set(2); + node.dim(2).set(3); + node.dtype(loco::DataType::FLOAT32); + + node.dim(0).unset(); + + EXPECT_ANY_THROW(numElements(&node)); +} + +TEST(UtilsTest, get_tensor_size) +{ + luci::CircleAdd node; + node.rank(3); + node.dim(0).set(1); + node.dim(1).set(2); + node.dim(2).set(3); + node.dtype(loco::DataType::FLOAT32); + + EXPECT_EQ(24, getTensorSize(&node)); +} + +TEST(UtilsTest, get_tensor_size_NEG) +{ + luci::CircleAdd node; + node.rank(3); + node.dim(0).set(1); + node.dim(1).set(2); + node.dim(2).set(3); + node.dtype(loco::DataType::FLOAT32); + + node.dim(0).unset(); + + EXPECT_ANY_THROW(getTensorSize(&node)); +}