Skip to content
Snippets Groups Projects
Unverified Commit a444615a authored by Ahmat's avatar Ahmat Committed by GitHub
Browse files

Add unit tests for memref (#6)

parent 5e4837f0
No related branches found
No related tags found
No related merge requests found
......@@ -31,6 +31,8 @@ set(BUDDY_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/bin)
set(BUDDY_EXAMPLES_DIR ${BUDDY_SOURCE_DIR}/examples)
set(BUDDY_INCLUDE_DIR ${BUDDY_SOURCE_DIR}/include)
set(BUILD_TESTS OFF CACHE BOOL "Build tests")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${BUDDY_BINARY_DIR})
# Add BUDDY files to the include path
......@@ -76,15 +78,16 @@ target_link_libraries(GoogleBenchmark INTERFACE Threads::Threads)
#-------------------------------------------------------------------------------
# Deploy GoogleTest
#-------------------------------------------------------------------------------
include(FetchContent)
FetchContent_Declare(
googletest
URL https://github.com/google/googletest/archive/609281088cfefc76f9d0ce82e1ff6c30cc3591e5.zip
)
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
FetchContent_MakeAvailable(googletest)
if (BUILD_TESTS)
include(FetchContent)
FetchContent_Declare(
googletest
URL https://github.com/google/googletest/archive/609281088cfefc76f9d0ce82e1ff6c30cc3591e5.zip
)
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
FetchContent_MakeAvailable(googletest)
endif()
#-------------------------------------------------------------------------------
# Find OpenCV
......@@ -106,4 +109,8 @@ include_directories(${PNG_INCLUDE_DIR})
add_subdirectory(lib)
add_subdirectory(benchmarks)
add_subdirectory(tests)
if (BUILD_TESTS)
enable_testing()
add_subdirectory(tests)
endif()
......@@ -71,3 +71,21 @@ Run the DepthwiseConv2DNhwcHwc operation benchmark:
```
$ cd <path to build>/bin && ./depthwise-conv-2d-nhwc-hwc-benchmark
```
## Testing
```
$ cd buddy-benchmark
$ mkdir build && cd build
$ cmake -G Ninja .. \
-DIMAGE_PROCESSING_BENCHMARKS=ON \
-DDEEP_LEARNING_BENCHMARKS=ON \
-DBUILD_TESTS=ON \
-DOpenCV_DIR=/path/to/opencv/build/ \
-DBUDDY_OPT_BUILD_DIR=/path/to/buddy-mlir/build/ \
-DBUDDY_OPT_STRIP_MINING=<strip mining size, default: 256> \
-DBUDDY_OPT_ATTR=<ISA vector extension, default: avx512f>
$ cmake --build . --
$ ninja test
```
......@@ -38,6 +38,7 @@ public:
MemRef(const T *data, intptr_t sizes[N], intptr_t offset = 0);
// Constructor from shape.
MemRef(intptr_t sizes[N], T init = T(0));
MemRef(std::vector<size_t> sizes, T init = T(0));
// Create a memref from an opencv image.
MemRef(cv::Mat image, intptr_t sizes[N]);
// Constructor from a png image.
......@@ -53,10 +54,14 @@ public:
MemRef<T, N> transpose(const std::vector<size_t> &axes = {});
// Get the data pointer.
T *getData() { return aligned; }
// Get the sizes.
// Get the sizes (shape).
const intptr_t *getSizes() { return sizes; }
// Get the strides.
const intptr_t *getStrides() { return strides; }
// Get the rank of the memref.
size_t getRank() const { return N; }
// Get the size (number of elements).
size_t getSize() const { return size; }
// Get the element at index.
const T &operator[](size_t index) const { return aligned[index + offset]; }
T &operator[](size_t index) { return aligned[index + offset]; }
......@@ -77,6 +82,8 @@ private:
intptr_t sizes[N];
// Strides.
intptr_t strides[N];
// Number of elements.
size_t size;
};
#include "Utils/Container.cpp"
......
......@@ -37,7 +37,7 @@ MemRef<T, N>::MemRef(const T *data, intptr_t sizes[N], intptr_t offset) {
this->sizes[i] = sizes[i];
}
setStrides();
size_t size = product(sizes);
size = product(sizes);
T *ptr = new T[size];
for (size_t i = 0; i < size; i++) {
ptr[i] = data[i];
......@@ -54,7 +54,25 @@ MemRef<T, N>::MemRef(intptr_t sizes[N], T init) {
this->sizes[i] = sizes[i];
}
setStrides();
size_t size = product(sizes);
size = product(sizes);
T *data = new T[size];
aligned = data;
allocated = data;
std::fill(data, data + size, init);
}
template <typename T, std::size_t N>
MemRef<T, N>::MemRef(std::vector<size_t> sizes, T init) {
if (sizes.size() != N) {
throw std::runtime_error("Invalid number of dimensions.");
}
static_assert(N >= 1 && N <= 4, "MemRef size not supported.");
for (size_t i = 0; i < N; i++) {
this->sizes[i] = sizes[i];
}
setStrides();
size = product(this->sizes);
T *data = new T[size];
aligned = data;
allocated = data;
......@@ -67,6 +85,7 @@ MemRef<T, N>::MemRef(cv::Mat image, intptr_t sizes[N]) {
for (size_t i = 0; i < N; i++)
this->sizes[i] = sizes[i];
size = product(this->sizes);
if (N == 2) {
// Copy image pixels for image processing memref.
auto ptr = new T[image.rows * image.cols];
......@@ -114,7 +133,7 @@ MemRef<T, N>::MemRef(const PNGImage &img, intptr_t sizes[N]) {
size_t channels = img.channels;
size_t height = img.height;
size_t width = img.width;
size_t size = channels * height * width;
size = channels * height * width;
T *data = new T[size];
for (size_t h = 0; h < height; h++) {
for (size_t w = 0; w < width; w++) {
......@@ -150,7 +169,7 @@ MemRef<T, N>::MemRef(const std::vector<PNGImage> &imgs, intptr_t sizes[N]) {
size_t channels = imgs[0].channels;
size_t height = imgs[0].height;
size_t width = imgs[0].width;
size_t size = batch * channels * height * width;
size = batch * channels * height * width;
T *data = new T[size];
for (size_t b = 0; b < batch; b++) {
for (size_t h = 0; h < height; h++) {
......
enable_testing()
add_executable(
fake_test
container.cpp
)
target_link_libraries(
fake_test
gtest_main
)
include(GoogleTest)
gtest_discover_tests(fake_test)
add_subdirectory(UnitTests)
add_executable(
test-container
TestContainer.cpp
)
target_link_libraries(
test-container
gtest_main
)
include(GoogleTest)
gtest_discover_tests(test-container)
//===- Test.h -------------------------------------------------------------===//
//
// 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.
//
//===----------------------------------------------------------------------===//
//
// This file implements helper functions for the tests.
//
//===----------------------------------------------------------------------===//
#include <gtest/gtest.h>
// Test if:
// - two arrays of integral type (intptr_t, int, size_t, ..) are equal
// - two arrays of float or double are approximatively eqaul, to within 4 ulps
// (unit in the last space) from each other.
template <typename T>
void ASSERT_ARRAY_EQ(const T *x, const T *y, const size_t n) {
if (std::is_integral<T>::value) {
for (size_t i = 0; i < n; i++) {
ASSERT_EQ(x[i], y[i]);
}
} else if (std::is_same<T, float>::value) {
for (size_t i = 0; i < n; i++) {
ASSERT_FLOAT_EQ(x[i], y[i]);
}
} else if (std::is_same<T, double>::value) {
for (size_t i = 0; i < n; i++) {
ASSERT_DOUBLE_EQ(x[i], y[i]);
}
}
}
//===- TestContainer.cpp --------------------------------------------------===//
//
// 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.
//
//===----------------------------------------------------------------------===//
//
// This file implements the tests for the MemRef class.
//
//===----------------------------------------------------------------------===//
#include "Test.h"
#include "Utils/Container.h"
// Fixture for testing the MemRef class.
class MemRefTest : public ::testing::Test {
protected:
MemRefTest()
: m1(MemRef<float, 1>({2})), m2(MemRef<float, 2>({2, 3})),
m3(MemRef<float, 3>({2, 3, 4})), m4(MemRef<float, 4>({2, 3, 4, 5})) {}
void SetUp() override {
std::iota(m3.getData(), m3.getData() + 2, 0.);
std::iota(m2.getData(), m2.getData() + 6, 0.);
std::iota(m3.getData(), m3.getData() + 24, 0.);
std::iota(m4.getData(), m4.getData() + 120, 0.);
}
MemRef<float, 1> m1;
MemRef<float, 2> m2;
MemRef<float, 3> m3;
MemRef<float, 4> m4;
};
// 1 dimensional memref.
TEST_F(MemRefTest, 1DMemref) {
intptr_t true_strides[] = {1};
size_t n_sizes = sizeof(true_strides) / sizeof(intptr_t);
ASSERT_EQ(m1.getRank(), n_sizes);
ASSERT_ARRAY_EQ(m1.getStrides(), true_strides, n_sizes);
}
// 2 dimensional memref.
TEST_F(MemRefTest, 2DMemref) {
intptr_t true_strides[] = {3, 1};
size_t n_strides = sizeof(true_strides) / sizeof(intptr_t);
ASSERT_EQ(m2.getRank(), n_strides);
ASSERT_ARRAY_EQ(m2.getStrides(), true_strides, n_strides);
}
// Transpose a 2d memref.
TEST_F(MemRefTest, Transpose2DMemref) {
MemRef<float, 2> transposed = m2.transpose();
// Sizes.
intptr_t true_sizes[] = {3, 2};
size_t n_sizes = sizeof(true_sizes) / sizeof(intptr_t);
ASSERT_EQ(transposed.getRank(), n_sizes);
ASSERT_ARRAY_EQ(transposed.getSizes(), true_sizes, n_sizes);
// Strides.
intptr_t true_strides[] = {2, 1};
size_t n_strides = sizeof(true_strides) / sizeof(intptr_t);
ASSERT_EQ(transposed.getRank(), n_strides);
ASSERT_ARRAY_EQ(transposed.getStrides(), true_strides, n_strides);
// Data.
float true_data[] = {0., 3., 1., 4., 2., 5.};
size_t n_data = sizeof(true_data) / sizeof(float);
ASSERT_EQ(transposed.getSize(), n_data);
ASSERT_ARRAY_EQ(transposed.getData(), true_data, n_data);
}
// 3 dimensional memref.
TEST_F(MemRefTest, 3DMemref) {
intptr_t true_strides[] = {12, 4, 1};
size_t n_strides = sizeof(true_strides) / sizeof(intptr_t);
ASSERT_EQ(m3.getRank(), n_strides);
ASSERT_ARRAY_EQ(m3.getStrides(), true_strides, n_strides);
}
// Transpose a 3d memref.
TEST_F(MemRefTest, Transpose3DMemRef) {
MemRef<float, 3> transposed = m3.transpose();
// Sizes.
intptr_t true_sizes[] = {4, 3, 2};
size_t n_sizes = sizeof(true_sizes) / sizeof(intptr_t);
ASSERT_EQ(transposed.getRank(), n_sizes);
ASSERT_ARRAY_EQ(transposed.getSizes(), true_sizes, n_sizes);
// Strides.
intptr_t true_strides[] = {6, 2, 1};
size_t n_strides = sizeof(true_strides) / sizeof(intptr_t);
ASSERT_EQ(transposed.getRank(), n_strides);
ASSERT_ARRAY_EQ(transposed.getStrides(), true_strides, n_strides);
// Data.
float true_data[] = {0., 12., 4., 16., 8., 20., 1., 13., 5., 17., 9., 21.,
2., 14., 6., 18., 10., 22., 3., 15., 7., 19., 11., 23.};
size_t n_data = sizeof(true_data) / sizeof(float);
ASSERT_EQ(transposed.getSize(), n_data);
ASSERT_ARRAY_EQ(transposed.getData(), true_data, n_data);
}
// Convert a 3d memref from CHW to HWC.
TEST_F(MemRefTest, TransposeCHWToHWC) {
MemRef<float, 3> transposed = m3.transpose({1, 2, 0});
// Sizes.
intptr_t true_sizes[] = {3, 4, 2};
size_t n_sizes = sizeof(true_sizes) / sizeof(intptr_t);
ASSERT_EQ(transposed.getRank(), n_sizes);
ASSERT_ARRAY_EQ(transposed.getSizes(), true_sizes, n_sizes);
// Strides.
intptr_t true_strides[] = {8, 2, 1};
size_t n_strides = sizeof(true_strides) / sizeof(intptr_t);
ASSERT_EQ(transposed.getRank(), n_strides);
ASSERT_ARRAY_EQ(transposed.getStrides(), true_strides, n_strides);
// Data.
float true_data[] = {0., 12., 1., 13., 2., 14., 3., 15., 4., 16., 5., 17.,
6., 18., 7., 19., 8., 20., 9., 21., 10., 22., 11., 23.};
size_t n_data = sizeof(true_data) / sizeof(float);
ASSERT_EQ(transposed.getSize(), n_data);
ASSERT_ARRAY_EQ(transposed.getData(), true_data, n_data);
}
// 4 dimensional memref.
TEST_F(MemRefTest, 4DMemref) {
intptr_t true_strides[] = {60, 20, 5, 1};
size_t n_strides = sizeof(true_strides) / sizeof(intptr_t);
ASSERT_EQ(m4.getRank(), n_strides);
ASSERT_ARRAY_EQ(m4.getStrides(), true_strides, n_strides);
}
// Transpose a 4d memref.
TEST_F(MemRefTest, Transpose4DMemRef) {
MemRef<float, 4> transposed = m4.transpose();
// Sizes.
intptr_t true_sizes[] = {5, 4, 3, 2};
size_t n_sizes = sizeof(true_sizes) / sizeof(intptr_t);
ASSERT_EQ(transposed.getRank(), n_sizes);
ASSERT_ARRAY_EQ(transposed.getSizes(), true_sizes, n_sizes);
// Strides.
intptr_t true_strides[] = {24, 6, 2, 1};
size_t n_strides = sizeof(true_strides) / sizeof(intptr_t);
ASSERT_EQ(transposed.getRank(), n_strides);
ASSERT_ARRAY_EQ(transposed.getStrides(), true_strides, n_strides);
// Data.
float true_data[] = {
0., 60., 20., 80., 40., 100., 5., 65., 25., 85., 45., 105.,
10., 70., 30., 90., 50., 110., 15., 75., 35., 95., 55., 115.,
1., 61., 21., 81., 41., 101., 6., 66., 26., 86., 46., 106.,
11., 71., 31., 91., 51., 111., 16., 76., 36., 96., 56., 116.,
2., 62., 22., 82., 42., 102., 7., 67., 27., 87., 47., 107.,
12., 72., 32., 92., 52., 112., 17., 77., 37., 97., 57., 117.,
3., 63., 23., 83., 43., 103., 8., 68., 28., 88., 48., 108.,
13., 73., 33., 93., 53., 113., 18., 78., 38., 98., 58., 118.,
4., 64., 24., 84., 44., 104., 9., 69., 29., 89., 49., 109.,
14., 74., 34., 94., 54., 114., 19., 79., 39., 99., 59., 119.};
size_t n_data = sizeof(true_data) / sizeof(float);
ASSERT_EQ(transposed.getSize(), n_data);
ASSERT_ARRAY_EQ(transposed.getData(), true_data, n_data);
}
// Convert a 4d memref from NCHW to NHWC.
TEST_F(MemRefTest, TransposeNCHWToNHWC) {
MemRef<float, 4> transposed = m4.transpose({0, 2, 3, 1});
// Sizes.
intptr_t true_sizes[] = {2, 4, 5, 3};
size_t n_sizes = sizeof(true_sizes) / sizeof(intptr_t);
ASSERT_EQ(transposed.getRank(), n_sizes);
ASSERT_ARRAY_EQ(transposed.getSizes(), true_sizes, n_sizes);
// Strides.
intptr_t true_strides[] = {60, 15, 3, 1};
size_t n_strides = sizeof(true_strides) / sizeof(intptr_t);
ASSERT_EQ(transposed.getRank(), n_strides);
ASSERT_ARRAY_EQ(transposed.getStrides(), true_strides, n_strides);
// Data.
float true_data[] = {
0., 20., 40., 1., 21., 41., 2., 22., 42., 3., 23., 43.,
4., 24., 44., 5., 25., 45., 6., 26., 46., 7., 27., 47.,
8., 28., 48., 9., 29., 49., 10., 30., 50., 11., 31., 51.,
12., 32., 52., 13., 33., 53., 14., 34., 54., 15., 35., 55.,
16., 36., 56., 17., 37., 57., 18., 38., 58., 19., 39., 59.,
60., 80., 100., 61., 81., 101., 62., 82., 102., 63., 83., 103.,
64., 84., 104., 65., 85., 105., 66., 86., 106., 67., 87., 107.,
68., 88., 108., 69., 89., 109., 70., 90., 110., 71., 91., 111.,
72., 92., 112., 73., 93., 113., 74., 94., 114., 75., 95., 115.,
76., 96., 116., 77., 97., 117., 78., 98., 118., 79., 99., 119.};
size_t n_data = sizeof(true_data) / sizeof(float);
ASSERT_EQ(transposed.getSize(), n_data);
ASSERT_ARRAY_EQ(transposed.getData(), true_data, n_data);
}
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
#include "Utils/Container.h"
#include <gtest/gtest.h>
// Use fake test for the initial version.
TEST(FakeTest, BasicAssertions) {
EXPECT_STRNE("after landing the improvements of memref descriptor",
"please remove this!");
}
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment