aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthew Bentham <matthew.bentham@arm.com>2020-03-09 10:55:40 +0000
committerMichele Di Giorgio <michele.digiorgio@arm.com>2020-03-12 13:52:15 +0000
commit470bc1eea65560d13001e60a7f7b22b12ec89bbc (patch)
treea0bfae560f2871c7b4e1518b4c8d185f4e07442c
parenta14817a7eee8b8cb7e5ccb6186ca01c23eec2629 (diff)
downloadComputeLibrary-470bc1eea65560d13001e60a7f7b22b12ec89bbc.tar.gz
COMPMID-3069: Improve compilation time by removing regex from test framework headers
Regex is used as an implementation detail by TestFilter and libnpy, is an expensive header to parse, and also instantiates static objects. Move TestFilter out of Framework.h by using a partial definition and a unique_ptr instead of storing the TestFilter by value. Move npy.h out of AssetsLibrary.h by moving part of a template definition into AssetsLibrary.cpp Knocks about 15% off compilation time of small test cases (for me, knocked .7s off 5s compilation of HogDetector.cpp) Signed-off-by: Matthew Bentham <matthew.bentham@arm.com> Change-Id: I1dce18855d0752ec25b2165fddbc6861a4c55a76 Reviewed-on: https://eu-gerrit-1.euhpc.arm.com/c/VisualCompute/ComputeLibrary/+/229181 Reviewed-by: Georgios Pinitas <georgios.pinitas@arm.com> Tested-by: bsgcomp <bsgcomp@arm.com> Reviewed-on: https://review.mlplatform.org/c/ml/ComputeLibrary/+/2856 Tested-by: Arm Jenkins <bsgcomp@arm.com> Comments-Addressed: Arm Jenkins <bsgcomp@arm.com> Reviewed-by: Michele Di Giorgio <michele.digiorgio@arm.com>
-rw-r--r--tests/AssetsLibrary.cpp44
-rw-r--r--tests/AssetsLibrary.h43
-rw-r--r--tests/framework/Framework.cpp8
-rw-r--r--tests/framework/Framework.h7
4 files changed, 62 insertions, 40 deletions
diff --git a/tests/AssetsLibrary.cpp b/tests/AssetsLibrary.cpp
index c6d86d1c1a..eafa6314b1 100644
--- a/tests/AssetsLibrary.cpp
+++ b/tests/AssetsLibrary.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2018 ARM Limited.
+ * Copyright (c) 2017-2020 ARM Limited.
*
* SPDX-License-Identifier: MIT
*
@@ -28,6 +28,11 @@
#include "arm_compute/core/ITensor.h"
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#include "libnpy/npy.hpp"
+#pragma GCC diagnostic pop
+
#include <cctype>
#include <fstream>
#include <limits>
@@ -511,5 +516,42 @@ RawTensor AssetsLibrary::get(const std::string &name, Format format, Channel cha
{
return RawTensor(find_or_create_raw_tensor(name, format, channel));
}
+
+namespace detail
+{
+inline void validate_npy_header(std::ifstream &stream, const std::string &expect_typestr, const TensorShape &expect_shape)
+{
+ ARM_COMPUTE_UNUSED(expect_typestr);
+ ARM_COMPUTE_UNUSED(expect_shape);
+
+ std::string header = npy::read_header(stream);
+
+ // Parse header
+ std::vector<unsigned long> shape;
+ bool fortran_order = false;
+ std::string typestr;
+ npy::parse_header(header, typestr, fortran_order, shape);
+
+ // Check if the typestring matches the given one
+ ARM_COMPUTE_ERROR_ON_MSG(typestr != expect_typestr, "Typestrings mismatch");
+
+ // Validate tensor shape
+ ARM_COMPUTE_ERROR_ON_MSG(shape.size() != expect_shape.num_dimensions(), "Tensor ranks mismatch");
+ if(fortran_order)
+ {
+ for(size_t i = 0; i < shape.size(); ++i)
+ {
+ ARM_COMPUTE_ERROR_ON_MSG(expect_shape[i] != shape[i], "Tensor dimensions mismatch");
+ }
+ }
+ else
+ {
+ for(size_t i = 0; i < shape.size(); ++i)
+ {
+ ARM_COMPUTE_ERROR_ON_MSG(expect_shape[i] != shape[shape.size() - i - 1], "Tensor dimensions mismatch");
+ }
+ }
+}
+} // namespace detail
} // namespace test
} // namespace arm_compute
diff --git a/tests/AssetsLibrary.h b/tests/AssetsLibrary.h
index e625c37505..84653ed089 100644
--- a/tests/AssetsLibrary.h
+++ b/tests/AssetsLibrary.h
@@ -32,10 +32,6 @@
#include "arm_compute/core/Types.h"
#include "arm_compute/core/Window.h"
#include "arm_compute/core/utils/misc/Random.h"
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wunused-parameter"
-#include "libnpy/npy.hpp"
-#pragma GCC diagnostic pop
#include "tests/RawTensor.h"
#include "tests/TensorCache.h"
#include "tests/Utils.h"
@@ -469,6 +465,16 @@ inline std::vector<std::pair<T, T>> convert_range_pair(const std::vector<AssetsL
});
return converted;
}
+
+/* Read npy header and check the payload is suitable for the specified type and shape
+ *
+ * @param[in] stream ifstream of the npy file
+ * @param[in] expect_typestr Expected typestr
+ * @param[in] expect_shape Shape of tensor expected to receive the data
+ *
+ * @note Advances stream to the beginning of the data payload
+ */
+void validate_npy_header(std::ifstream &stream, const std::string &expect_typestr, const TensorShape &expect_shape);
} // namespace detail
template <typename T, typename D>
@@ -959,41 +965,14 @@ void AssetsLibrary::fill_layer_data(T &&tensor, std::string name) const
#endif /* _WIN32 */
const std::string path = _library_path + path_separator + name;
- std::vector<unsigned long> shape;
-
// Open file
std::ifstream stream(path, std::ios::in | std::ios::binary);
if(!stream.good())
{
throw framework::FileNotFound("Could not load npy file: " + path);
}
- std::string header = npy::read_header(stream);
-
- // Parse header
- bool fortran_order = false;
- std::string typestr;
- npy::parse_header(header, typestr, fortran_order, shape);
- // Check if the typestring matches the given one
- std::string expect_typestr = get_typestring(tensor.data_type());
- ARM_COMPUTE_ERROR_ON_MSG(typestr != expect_typestr, "Typestrings mismatch");
-
- // Validate tensor shape
- ARM_COMPUTE_ERROR_ON_MSG(shape.size() != tensor.shape().num_dimensions(), "Tensor ranks mismatch");
- if(fortran_order)
- {
- for(size_t i = 0; i < shape.size(); ++i)
- {
- ARM_COMPUTE_ERROR_ON_MSG(tensor.shape()[i] != shape[i], "Tensor dimensions mismatch");
- }
- }
- else
- {
- for(size_t i = 0; i < shape.size(); ++i)
- {
- ARM_COMPUTE_ERROR_ON_MSG(tensor.shape()[i] != shape[shape.size() - i - 1], "Tensor dimensions mismatch");
- }
- }
+ validate_npy_header(stream, tensor.data_type(), tensor.shape());
// Read data
if(tensor.padding().empty())
diff --git a/tests/framework/Framework.cpp b/tests/framework/Framework.cpp
index c6aaad0586..dff280dc8c 100644
--- a/tests/framework/Framework.cpp
+++ b/tests/framework/Framework.cpp
@@ -26,6 +26,7 @@
#include "arm_compute/runtime/Scheduler.h"
#include "support/MemorySupport.h"
#include "tests/framework/ParametersLibrary.h"
+#include "tests/framework/TestFilter.h"
#ifdef ARM_COMPUTE_CL
#include "arm_compute/runtime/CL/CLRuntimeContext.h"
@@ -49,6 +50,7 @@ namespace framework
std::unique_ptr<InstrumentsInfo> instruments_info;
Framework::Framework()
+ : _test_filter(nullptr)
{
_available_instruments.emplace(std::pair<InstrumentType, ScaleFactor>(InstrumentType::WALL_CLOCK_TIMESTAMPS, ScaleFactor::NONE), Instrument::make_instrument<WallClockTimestamps, ScaleFactor::NONE>);
_available_instruments.emplace(std::pair<InstrumentType, ScaleFactor>(InstrumentType::WALL_CLOCK_TIMESTAMPS, ScaleFactor::TIME_MS),
@@ -127,7 +129,7 @@ Framework &Framework::get()
void Framework::init(const FrameworkConfig &config)
{
- _test_filter = TestFilter(config.mode, config.name_filter, config.id_filter);
+ _test_filter.reset(new TestFilter(config.mode, config.name_filter, config.id_filter));
_num_iterations = config.num_iterations;
_log_level = config.log_level;
_cooldown_sec = config.cooldown_sec;
@@ -558,7 +560,7 @@ bool Framework::run()
const std::string test_case_name = test_factory->name();
const TestInfo test_info{ id, test_case_name, test_factory->mode(), test_factory->status() };
- if(_test_filter.is_selected(test_info))
+ if(_test_filter->is_selected(test_info))
{
#ifdef ARM_COMPUTE_CL
// Every 100 tests, reset the OpenCL context to release the allocated memory
@@ -678,7 +680,7 @@ std::vector<TestInfo> Framework::test_infos() const
{
TestInfo test_info{ id, factory->name(), factory->mode(), factory->status() };
- if(_test_filter.is_selected(test_info))
+ if(_test_filter->is_selected(test_info))
{
ids.emplace_back(std::move(test_info));
}
diff --git a/tests/framework/Framework.h b/tests/framework/Framework.h
index fb52fd8ffe..11dedfe89f 100644
--- a/tests/framework/Framework.h
+++ b/tests/framework/Framework.h
@@ -29,7 +29,6 @@
#include "Profiler.h"
#include "TestCase.h"
#include "TestCaseFactory.h"
-#include "TestFilter.h"
#include "TestResult.h"
#include "Utils.h"
#include "instruments/Instruments.h"
@@ -41,11 +40,9 @@
#include <memory>
#include <numeric>
#include <ostream>
-#include <regex>
#include <set>
#include <sstream>
#include <string>
-#include <tuple>
#include <vector>
namespace arm_compute
@@ -54,6 +51,8 @@ namespace test
{
namespace framework
{
+class TestFilter;
+
/** Framework configuration structure */
struct FrameworkConfig
{
@@ -346,7 +345,7 @@ private:
std::map<InstrumentsDescription, create_function *> _available_instruments{};
std::set<framework::InstrumentsDescription> _instruments{ std::pair<InstrumentType, ScaleFactor>(InstrumentType::NONE, ScaleFactor::NONE) };
- TestFilter _test_filter{};
+ std::unique_ptr<TestFilter> _test_filter;
LogLevel _log_level{ LogLevel::ALL };
const TestInfo *_current_test_info{ nullptr };
TestResult *_current_test_result{ nullptr };