Merge remote-tracking branch 'origin/rotate-cpx-vector-benchmark' into integration_2024_w35
This commit is contained in:
@@ -2367,6 +2367,19 @@ if(ENABLE_TESTS)
|
|||||||
add_library(GTest::gtest ALIAS gtest)
|
add_library(GTest::gtest ALIAS gtest)
|
||||||
add_library(GTest::gtest_main ALIAS gtest_main)
|
add_library(GTest::gtest_main ALIAS gtest_main)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
find_package(benchmark)
|
||||||
|
if (NOT benchmark_FOUND)
|
||||||
|
message(STATUS "benchmark package not found, will download benchmark automatically. To prevent that install google benchmark on your system (libbenchmark-dev)")
|
||||||
|
include(FetchContent)
|
||||||
|
set(BENCHMARK_ENABLE_TESTING OFF)
|
||||||
|
FetchContent_Declare(
|
||||||
|
benchmark
|
||||||
|
GIT_REPOSITORY https://github.com/google/benchmark.git
|
||||||
|
GIT_TAG v1.9.0
|
||||||
|
)
|
||||||
|
FetchContent_MakeAvailable(benchmark)
|
||||||
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_subdirectory(common)
|
add_subdirectory(common)
|
||||||
|
|||||||
@@ -107,3 +107,65 @@ that directory directly, which you might also use to compare to the
|
|||||||
slight complication is due to using shell scripts. An easier way is to
|
slight complication is due to using shell scripts. An easier way is to
|
||||||
directly declare the executable in `add_test()`, and `ctest` will locate and
|
directly declare the executable in `add_test()`, and `ctest` will locate and
|
||||||
run the executable properly.
|
run the executable properly.
|
||||||
|
|
||||||
|
# Benchmarking
|
||||||
|
|
||||||
|
Google benchmark can be used to profile and benchmark small pieces of code. See
|
||||||
|
`benchmark_rotate_vector` for reference implementation. To start benchmarking code,
|
||||||
|
write a benchmark first and compare your implementation against baseline result.
|
||||||
|
To ensure your results are reproducible see this [guide](https://github.com/google/benchmark/blob/main/docs/reducing_variance.md)
|
||||||
|
|
||||||
|
Example output follows:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
2024-08-26T11:55:49+02:00
|
||||||
|
Running ./openair1/PHY/TOOLS/tests/benchmark_rotate_vector
|
||||||
|
Run on (8 X 4700 MHz CPU s)
|
||||||
|
CPU Caches:
|
||||||
|
L1 Data 48 KiB (x4)
|
||||||
|
L1 Instruction 32 KiB (x4)
|
||||||
|
L2 Unified 1280 KiB (x4)
|
||||||
|
L3 Unified 12288 KiB (x1)
|
||||||
|
Load Average: 0.51, 0.31, 0.29
|
||||||
|
***WARNING*** CPU scaling is enabled, the benchmark real time measurements may be noisy and will incur extra overhead.
|
||||||
|
---------------------------------------------------------------------
|
||||||
|
Benchmark Time CPU Iterations
|
||||||
|
---------------------------------------------------------------------
|
||||||
|
BM_rotate_cpx_vector/100 43.1 ns 43.1 ns 16683136
|
||||||
|
BM_rotate_cpx_vector/256 70.1 ns 70.0 ns 9647446
|
||||||
|
BM_rotate_cpx_vector/1024 277 ns 277 ns 2378273
|
||||||
|
BM_rotate_cpx_vector/4096 1070 ns 1070 ns 654792
|
||||||
|
BM_rotate_cpx_vector/16384 4220 ns 4220 ns 169070
|
||||||
|
BM_rotate_cpx_vector/20000 5288 ns 5289 ns 136190
|
||||||
|
```
|
||||||
|
|
||||||
|
## Comparing results
|
||||||
|
|
||||||
|
Benchmark results can be output to json by using command line arguments, example below
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./benchmark_rotate_vector --benchmark_out=file.json --benchmark_repetitions=10
|
||||||
|
```
|
||||||
|
|
||||||
|
These results can be compared by a tool provided with google benchmark
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./compare.py benchmarks ../../file.json ../../file1.json
|
||||||
|
```
|
||||||
|
|
||||||
|
Example output:
|
||||||
|
```
|
||||||
|
Comparing ../../file.json to ../../file1.json
|
||||||
|
Benchmark Time CPU Time Old Time New CPU Old CPU New
|
||||||
|
--------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
BM_rotate_cpx_vector/100 +0.3383 +0.3384 43 58 43 58
|
||||||
|
BM_rotate_cpx_vector/100 +0.2334 +0.2335 42 52 42 52
|
||||||
|
BM_rotate_cpx_vector/100 +0.1685 +0.1683 42 49 42 49
|
||||||
|
BM_rotate_cpx_vector/100 +0.1890 +0.1889 42 50 42 50
|
||||||
|
BM_rotate_cpx_vector/100 +0.0456 +0.0457 42 44 42 44
|
||||||
|
BM_rotate_cpx_vector/100 +0.0163 +0.0162 42 42 42 42
|
||||||
|
BM_rotate_cpx_vector/100 +0.0005 +0.0004 43 43 43 43
|
||||||
|
BM_rotate_cpx_vector/100 +0.0134 +0.0129 43 43 43 43
|
||||||
|
BM_rotate_cpx_vector/100 +0.0162 +0.0162 42 42 42 42
|
||||||
|
BM_rotate_cpx_vector/100 +0.0003 +0.0003 42 42 42 42
|
||||||
|
```
|
||||||
|
|||||||
@@ -56,18 +56,9 @@ void exit_function(const char *file, const char *function, const int line, const
|
|||||||
#include "common/utils/LOG/log.h"
|
#include "common/utils/LOG/log.h"
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include "openair1/PHY/TOOLS/phy_test_tools.hpp"
|
||||||
#include <random>
|
#include <random>
|
||||||
|
|
||||||
constexpr bool is_power_of_two(uint64_t n)
|
|
||||||
{
|
|
||||||
return n > 0 && (n & (n - 1)) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t align_up(size_t a, size_t b)
|
|
||||||
{
|
|
||||||
return (a + b - 1) / b * b;
|
|
||||||
}
|
|
||||||
|
|
||||||
int16_t saturating_sub(int16_t a, int16_t b)
|
int16_t saturating_sub(int16_t a, int16_t b)
|
||||||
{
|
{
|
||||||
int32_t result = (int32_t)a - (int32_t)b;
|
int32_t result = (int32_t)a - (int32_t)b;
|
||||||
@@ -81,44 +72,6 @@ int16_t saturating_sub(int16_t a, int16_t b)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Template adaptations for std::vector. This is needed because the avx functions expect 256 bit alignment.
|
|
||||||
template <typename T, size_t alignment>
|
|
||||||
class AlignedAllocator {
|
|
||||||
public:
|
|
||||||
static_assert(is_power_of_two(alignment), "Alignment should be power of 2");
|
|
||||||
static_assert(alignment >= 8, "Alignment must be at least 8 bits");
|
|
||||||
using value_type = T;
|
|
||||||
|
|
||||||
AlignedAllocator() = default;
|
|
||||||
|
|
||||||
AlignedAllocator(const AlignedAllocator &) = default;
|
|
||||||
|
|
||||||
AlignedAllocator &operator=(const AlignedAllocator &) = default;
|
|
||||||
|
|
||||||
template <typename U>
|
|
||||||
struct rebind {
|
|
||||||
using other = AlignedAllocator<U, alignment>;
|
|
||||||
};
|
|
||||||
|
|
||||||
T *allocate(size_t n)
|
|
||||||
{
|
|
||||||
size_t alignment_bytes = alignment / 8;
|
|
||||||
void *ptr = ::aligned_alloc(alignment_bytes, align_up(n * sizeof(T), alignment_bytes));
|
|
||||||
return static_cast<T *>(ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void deallocate(T *p, size_t n)
|
|
||||||
{
|
|
||||||
::free(p);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Using 512-aligned vector in case some functions use avx-512
|
|
||||||
template <typename T>
|
|
||||||
using AlignedAllocator512 = AlignedAllocator<T, 512>;
|
|
||||||
template <typename T>
|
|
||||||
using AlignedVector512 = std::vector<T, AlignedAllocator512<T>>;
|
|
||||||
|
|
||||||
void nr_ulsch_16qam_llr_ref(c16_t *rxdataF_comp, int32_t *ul_ch_mag, int16_t *ulsch_llr, uint32_t nb_re, uint8_t symbol)
|
void nr_ulsch_16qam_llr_ref(c16_t *rxdataF_comp, int32_t *ul_ch_mag, int16_t *ulsch_llr, uint32_t nb_re, uint8_t symbol)
|
||||||
{
|
{
|
||||||
int16_t *ul_ch_mag_i16 = (int16_t *)ul_ch_mag;
|
int16_t *ul_ch_mag_i16 = (int16_t *)ul_ch_mag;
|
||||||
@@ -190,27 +143,6 @@ void nr_ulsch_256qam_llr_ref(c16_t *rxdataF_comp,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AlignedVector512<c16_t> generate_random_c16(size_t num)
|
|
||||||
{
|
|
||||||
std::random_device rd;
|
|
||||||
std::mt19937 rng(rd());
|
|
||||||
std::uniform_int_distribution<int16_t> dist(INT16_MIN, INT16_MAX);
|
|
||||||
AlignedVector512<c16_t> vec;
|
|
||||||
vec.resize(num);
|
|
||||||
auto gen = [&]() { return (c16_t){dist(rng), dist(rng)}; };
|
|
||||||
std::generate(vec.begin(), vec.end(), gen);
|
|
||||||
return vec;
|
|
||||||
}
|
|
||||||
|
|
||||||
AlignedVector512<uint16_t> generate_random_uint16(size_t num)
|
|
||||||
{
|
|
||||||
AlignedVector512<uint16_t> vec;
|
|
||||||
vec.resize(num);
|
|
||||||
auto gen = [&]() { return static_cast<uint16_t>(std::rand()); };
|
|
||||||
std::generate(vec.begin(), vec.end(), gen);
|
|
||||||
return vec;
|
|
||||||
}
|
|
||||||
|
|
||||||
void test_function_16_qam(AlignedVector512<uint32_t> nb_res)
|
void test_function_16_qam(AlignedVector512<uint32_t> nb_res)
|
||||||
{
|
{
|
||||||
for (auto i = 0U; i < nb_res.size(); i++) {
|
for (auto i = 0U; i < nb_res.size(); i++) {
|
||||||
|
|||||||
@@ -0,0 +1,101 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||||
|
* the OAI Public License, Version 1.1 (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.openairinterface.org/?page_id=698
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*-------------------------------------------------------------------------------
|
||||||
|
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||||
|
* contact@openairinterface.org
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __PHY_TEST_TOOLS_HPP__
|
||||||
|
#define __PHY_TEST_TOOLS_HPP__
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <random>
|
||||||
|
#include <algorithm>
|
||||||
|
extern "C" {
|
||||||
|
#include "openair1/PHY/TOOLS/tools_defs.h"
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool is_power_of_two(uint64_t n)
|
||||||
|
{
|
||||||
|
return n != 0 && (n & (n - 1)) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t align_up(size_t a, size_t b)
|
||||||
|
{
|
||||||
|
return (a + b - 1) / b * b;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Template adaptations for std::vector. This is needed because the avx functions expect 256 bit alignment.
|
||||||
|
template <typename T, size_t alignment>
|
||||||
|
class AlignedAllocator {
|
||||||
|
public:
|
||||||
|
static_assert(is_power_of_two(alignment), "Alignment should be power of 2");
|
||||||
|
static_assert(alignment >= 8, "Alignment must be at least 8 bits");
|
||||||
|
using value_type = T;
|
||||||
|
|
||||||
|
AlignedAllocator() = default;
|
||||||
|
|
||||||
|
AlignedAllocator(const AlignedAllocator &) = default;
|
||||||
|
|
||||||
|
AlignedAllocator &operator=(const AlignedAllocator &) = default;
|
||||||
|
|
||||||
|
template <typename U>
|
||||||
|
struct rebind {
|
||||||
|
using other = AlignedAllocator<U, alignment>;
|
||||||
|
};
|
||||||
|
|
||||||
|
T *allocate(size_t n)
|
||||||
|
{
|
||||||
|
size_t alignment_bytes = alignment / 8;
|
||||||
|
void *ptr = ::aligned_alloc(alignment_bytes, align_up(n * sizeof(T), alignment_bytes));
|
||||||
|
return static_cast<T *>(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void deallocate(T *p, size_t n)
|
||||||
|
{
|
||||||
|
::free(p);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Using 512-aligned vector in case some functions use avx-512
|
||||||
|
template <typename T>
|
||||||
|
using AlignedAllocator512 = AlignedAllocator<T, 512>;
|
||||||
|
template <typename T>
|
||||||
|
using AlignedVector512 = std::vector<T, AlignedAllocator512<T>>;
|
||||||
|
|
||||||
|
AlignedVector512<c16_t> generate_random_c16(size_t num)
|
||||||
|
{
|
||||||
|
std::random_device rd;
|
||||||
|
std::mt19937 rng(rd());
|
||||||
|
std::uniform_int_distribution<int16_t> dist(INT16_MIN, INT16_MAX);
|
||||||
|
AlignedVector512<c16_t> vec;
|
||||||
|
vec.resize(num);
|
||||||
|
auto gen = [&]() { return (c16_t){dist(rng), dist(rng)}; };
|
||||||
|
std::generate(vec.begin(), vec.end(), gen);
|
||||||
|
return vec;
|
||||||
|
}
|
||||||
|
|
||||||
|
AlignedVector512<uint16_t> generate_random_uint16(size_t num)
|
||||||
|
{
|
||||||
|
AlignedVector512<uint16_t> vec;
|
||||||
|
vec.resize(num);
|
||||||
|
auto gen = [&]() { return static_cast<uint16_t>(std::rand()); };
|
||||||
|
std::generate(vec.begin(), vec.end(), gen);
|
||||||
|
return vec;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -3,3 +3,9 @@ target_link_libraries(test_signal_energy PRIVATE GTest::gtest UTIL)
|
|||||||
add_dependencies(tests test_signal_energy)
|
add_dependencies(tests test_signal_energy)
|
||||||
add_test(NAME test_signal_energy
|
add_test(NAME test_signal_energy
|
||||||
COMMAND ./test_signal_energy)
|
COMMAND ./test_signal_energy)
|
||||||
|
|
||||||
|
add_executable(benchmark_rotate_vector benchmark_rotate_vector.cpp)
|
||||||
|
target_link_libraries(benchmark_rotate_vector PRIVATE benchmark::benchmark UTIL PHY_NR)
|
||||||
|
add_dependencies(tests benchmark_rotate_vector)
|
||||||
|
add_test(NAME benchmark_rotate_vector
|
||||||
|
COMMAND ./benchmark_rotate_vector)
|
||||||
|
|||||||
@@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||||
|
* the OAI Public License, Version 1.1 (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.openairinterface.org/?page_id=698
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*-------------------------------------------------------------------------------
|
||||||
|
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||||
|
* contact@openairinterface.org
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <vector>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <numeric>
|
||||||
|
extern "C" {
|
||||||
|
#include "openair1/PHY/TOOLS/tools_defs.h"
|
||||||
|
struct configmodule_interface_s;
|
||||||
|
struct configmodule_interface_s *uniqCfg = NULL;
|
||||||
|
void exit_function(const char *file, const char *function, const int line, const char *s, const int assert)
|
||||||
|
{
|
||||||
|
if (assert) {
|
||||||
|
abort();
|
||||||
|
} else {
|
||||||
|
exit(EXIT_SUCCESS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#include <cstdio>
|
||||||
|
#include "common/utils/LOG/log.h"
|
||||||
|
#include "benchmark/benchmark.h"
|
||||||
|
#include "openair1/PHY/TOOLS/phy_test_tools.hpp"
|
||||||
|
|
||||||
|
static void BM_rotate_cpx_vector(benchmark::State &state)
|
||||||
|
{
|
||||||
|
int vector_size = state.range(0);
|
||||||
|
auto input_complex_16 = generate_random_c16(vector_size);
|
||||||
|
auto input_alpha = generate_random_c16(vector_size);
|
||||||
|
AlignedVector512<c16_t> output;
|
||||||
|
output.resize(vector_size);
|
||||||
|
int shift = 2;
|
||||||
|
for (auto _ : state) {
|
||||||
|
rotate_cpx_vector(input_complex_16.data(), input_alpha.data(), output.data(), vector_size, shift);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BENCHMARK(BM_rotate_cpx_vector)->RangeMultiplier(4)->Range(100, 20000);
|
||||||
|
|
||||||
|
BENCHMARK_MAIN();
|
||||||
Reference in New Issue
Block a user