Skip to content
Snippets Groups Projects
Commit 6f66f7e5 authored by Mattia Mancini's avatar Mattia Mancini
Browse files

Update code with unittests

parent 35f69616
No related branches found
No related tags found
1 merge request!3Add test for matrix
Pipeline #81436 failed
......@@ -2,6 +2,7 @@ stages: # List of stages for jobs, and their order of execution
- prepare
- build
- test
- benchmark
docker-base:
stage: prepare
......@@ -34,10 +35,22 @@ build-job: # This job runs in the build stage, which runs first.
- cmake -B build .
- make -C build
unittests:
stage: test
before_script:
- module load spack
- module load cmake
- module load boost
- module load casacore
script:
- cmake -B build .
- make -C build
- build/unittests
collect-performance: # This job runs in the test stage.
tags:
- das6-gpu
stage: test # It only starts when the job in the build stage completes successfully.
stage: benchmark # It only starts when the job in the build stage completes successfully.
dependencies:
- build-job
before_script:
......@@ -58,7 +71,7 @@ collect-performance: # This job runs in the test stage.
expire_in: 1 days
collect-performance-generic:
stage: test
stage: benchmark
image: "$CI_REGISTRY_IMAGE:latest"
script:
- cmake -B build . -DCMAKE_BUILD_TYPE=Release
......
......@@ -8,7 +8,12 @@ set(CMAKE_CXX_STANDARD_REQUIRED True)
set(BENCHMARK_ENABLE_GTEST_TESTS
OFF
CACHE INTERNAL "Download GTest sources")
set(BENCHMARK_ENABLE_LIBPFM ON CACHE INTERNAL "Enable perf")
include(FetchContent)
include(CTest)
FetchContent_Declare(
googlebenchmark
GIT_REPOSITORY https://github.com/google/benchmark.git
......@@ -18,6 +23,16 @@ FetchContent_Declare(
# Make the fetched content available.
FetchContent_MakeAvailable(googlebenchmark)
Include(FetchContent)
FetchContent_Declare(
Catch2
GIT_REPOSITORY https://github.com/catchorg/Catch2.git
GIT_TAG v3.4.0 # or a later release
)
FetchContent_MakeAvailable(Catch2)
include(Catch)
set(BENCHMARK_ENABLE_GTEST_TESTS
OFF
......@@ -32,10 +47,26 @@ FetchContent_Declare(
FetchContent_MakeAvailable(aocommon)
# Add the benchmark executable
add_executable(microbenchmarks benchmarks/matrix_multiplication.cpp)
file(GLOB BENCHMARK_SOURCES "benchmarks/*.cpp")
add_executable(microbenchmarks ${BENCHMARK_SOURCES})
file(GLOB TEST_SOURCES "test/*.cpp")
add_executable(unittests ${TEST_SOURCES})
# Link against Google Benchmark
target_link_libraries(microbenchmarks benchmark::benchmark)
target_include_directories(microbenchmarks PRIVATE ${aocommon_SOURCE_DIR}/include)
target_include_directories(microbenchmarks PRIVATE code)
target_compile_options(microbenchmarks PUBLIC "-O3;-march=native;-ggdb;")
list(APPEND CMAKE_MODULE_PATH ${catch2_SOURCE_DIR}/extras)
catch_discover_tests(unittests WORKING_DIRECTORY)
target_link_libraries(unittests PRIVATE Catch2::Catch2WithMain)
target_include_directories(unittests PRIVATE code)
target_include_directories(unittests PRIVATE ${aocommon_SOURCE_DIR}/include)
target_compile_options(unittests PUBLIC "-O3;-march=native;-ggdb;")
#include <aocommon/avx/MatrixComplexFloat2x2.h>
#include <benchmark/benchmark.h>
#include <complex>
#include <new> // For std::align_val_t
#include <random>
// Function to perform matrix multiplication for 2x2 complex matrices
void matrixMultiply(const std::complex<float>* A, const std::complex<float>* B,
std::complex<float>* C) {
for (int i = 0; i < 2; ++i) {
for (int j = 0; j < 2; ++j) {
std::complex<float> sum = 0.0f;
for (int k = 0; k < 2; ++k) {
sum += A[i * 2 + k] * B[k * 2 + j];
}
C[i * 2 + j] = sum;
}
}
}
inline void multiply_mat(const float* a, const float* b, float* c, float sign) {
c[0] += sign * (a[0] * b[0] + a[1] * b[2]);
c[1] += sign * (a[0] * b[1] + a[1] * b[3]);
c[2] += sign * (a[2] * b[0] + a[3] * b[2]);
c[3] += sign * (a[2] * b[1] + a[3] * b[3]);
}
void matrixMultiplyNaive(const std::complex<float>* a,
const std::complex<float>* b, std::complex<float>* c) {
const float a_real[] = {a[0].real(), a[1].real(), a[2].real(), a[3].real()};
const float b_real[] = {b[0].real(), b[1].real(), b[2].real(), b[3].real()};
const float a_imag[] = {a[0].imag(), a[1].imag(), a[2].imag(), a[3].imag()};
const float b_imag[] = {b[0].imag(), b[1].imag(), b[2].imag(), b[3].imag()};
float c_real[4] = {0, 0, 0, 0};
float c_imag[4] = {0, 0, 0, 0};
multiply_mat(a_real, b_real, c_real, 1.0f);
multiply_mat(a_imag, b_imag, c_real, -1.0f);
multiply_mat(a_real, b_imag, c_imag, 1.0f);
multiply_mat(a_imag, b_real, c_imag, 1.0f);
c[0] = {c_real[0], c_imag[0]};
c[1] = {c_real[1], c_imag[1]};
c[2] = {c_real[2], c_imag[2]};
c[3] = {c_real[3], c_imag[3]};
}
void matrixMultiplyAoCommon(const std::complex<float>* a,
const std::complex<float>* b,
std::complex<float>* c) {
const aocommon::avx::MatrixComplexFloat2x2 A(a[0], a[1], a[2], a[3]);
const aocommon::avx::MatrixComplexFloat2x2 B(a[0], a[1], a[2], a[3]);
const aocommon::avx::MatrixComplexFloat2x2 C = A * B;
c[0] = C[0];
c[1] = C[1];
c[2] = C[2];
}
// Initialize matrices with random complex values
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_real_distribution<float> dis(-1.0, 1.0);
inline void Initialize(std::complex<float>* a) {
for (int i = 0; i < 4; ++i) {
a[i] = std::complex<float>(dis(gen), dis(gen));
}
}
#include <matrix_multiplication.h>
class InitializeInput : public benchmark::Fixture {
public:
......
#include <aocommon/avx/MatrixComplexFloat2x2.h>
#include <complex>
#include <new> // For std::align_val_t
#include <random>
// Initialize matrices with random complex values
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_real_distribution<float> dis(-1.0, 1.0);
inline void Initialize(std::complex<float>* a) {
for (int i = 0; i < 4; ++i) {
a[i] = std::complex<float>(dis(gen), dis(gen));
}
}
// Function to perform matrix multiplication for 2x2 complex matrices
void matrixMultiply(const std::complex<float>* A, const std::complex<float>* B,
std::complex<float>* C) {
for (int i = 0; i < 2; ++i) {
for (int j = 0; j < 2; ++j) {
std::complex<float> sum = 0.0f;
for (int k = 0; k < 2; ++k) {
sum += A[i * 2 + k] * B[k * 2 + j];
}
C[i * 2 + j] = sum;
}
}
}
inline void multiply_mat(const float* a, const float* b, float* c, float sign) {
c[0] += sign * (a[0] * b[0] + a[1] * b[2]);
c[1] += sign * (a[0] * b[1] + a[1] * b[3]);
c[2] += sign * (a[2] * b[0] + a[3] * b[2]);
c[3] += sign * (a[2] * b[1] + a[3] * b[3]);
}
void matrixMultiplyNaive(const std::complex<float>* a,
const std::complex<float>* b, std::complex<float>* c) {
const float a_real[] = {a[0].real(), a[1].real(), a[2].real(), a[3].real()};
const float b_real[] = {b[0].real(), b[1].real(), b[2].real(), b[3].real()};
const float a_imag[] = {a[0].imag(), a[1].imag(), a[2].imag(), a[3].imag()};
const float b_imag[] = {b[0].imag(), b[1].imag(), b[2].imag(), b[3].imag()};
float c_real[4] = {0, 0, 0, 0};
float c_imag[4] = {0, 0, 0, 0};
multiply_mat(a_real, b_real, c_real, 1.0f);
multiply_mat(a_imag, b_imag, c_real, -1.0f);
multiply_mat(a_real, b_imag, c_imag, 1.0f);
multiply_mat(a_imag, b_real, c_imag, 1.0f);
c[0] = {c_real[0], c_imag[0]};
c[1] = {c_real[1], c_imag[1]};
c[2] = {c_real[2], c_imag[2]};
c[3] = {c_real[3], c_imag[3]};
}
void matrixMultiplyAoCommon(const std::complex<float>* a,
const std::complex<float>* b,
std::complex<float>* c) {
const aocommon::avx::MatrixComplexFloat2x2 A(a[0], a[1], a[2], a[3]);
const aocommon::avx::MatrixComplexFloat2x2 B(b[0], b[1], b[2], b[3]);
const aocommon::avx::MatrixComplexFloat2x2 C = A * B;
c[0] = C[0];
c[1] = C[1];
c[2] = C[2];
c[3] = C[3];
}
#include <array>
#include <catch2/matchers/catch_matchers_floating_point.hpp>
#include <string>
#include <vector>
#define COMPARE_ARRAYS(lhs, rhs, precision) \
compareArrays(Catch::getResultCapture().getCurrentTestName(), __LINE__, lhs, \
rhs, precision)
template <typename T>
void compareSingle(const std::vector<T>& lv, const std::vector<T>& rv,
float precision) {
REQUIRE_THAT(lv, Catch::Matchers::WithinAbs(rv, precision));
}
template <>
void compareSingle(const std::vector<std::complex<float>>& lv,
const std::vector<std::complex<float>>& rv,
float precision) {
for (size_t idx = 0; idx < lv.size(); idx++) {
const auto le = lv[idx];
const auto re = rv[idx];
REQUIRE_THAT(le.real(), Catch::Matchers::WithinAbs(re.real(), precision));
REQUIRE_THAT(le.imag(), Catch::Matchers::WithinAbs(re.imag(), precision));
}
}
template <typename T, size_t N>
void compareArrays(const std::string& test, unsigned line, std::array<T, N> lhs,
std::array<T, N> rhs, float precision) {
std::vector<T> lv(lhs.begin(), lhs.end());
std::vector<T> rv(rhs.begin(), rhs.end());
INFO("Test case [" << test << "] failed at line "
<< line); // Reported only if REQUIRE fails
compareSingle(lv, rv, precision);
}
#include <matrix_multiplication.h>
#include <catch2/catch_test_macros.hpp>
#include "helpers.h"
TEST_CASE("test complex matrix multiplication", "[float]") {
// This setup will be done 4 times in total, once for each section
std::array<std::complex<float>, 4> A;
std::array<std::complex<float>, 4> B;
std::array<std::complex<float>, 4> C;
std::array<std::complex<float>, 4> C_expected;
Initialize(A.data());
Initialize(B.data());
matrixMultiply(A.data(), B.data(), C_expected.data());
SECTION("test correctness of naive implementation") {
matrixMultiplyNaive(A.data(), B.data(), C.data());
COMPARE_ARRAYS(C_expected, C, 1.e-6);
}
SECTION("test correctness of aocommon implementation") {
matrixMultiplyAoCommon(A.data(), B.data(), C.data());
COMPARE_ARRAYS(C_expected, C, 1.e-6);
}
}
\ No newline at end of file
#define CATCH_CONFIG_MAIN // This tells Catch to provide a main() - only do
// this in one cpp file
#include <catch2/catch_all.hpp>
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment