This commit is contained in:
Artur Mukhamadiev 2025-10-07 22:40:20 +03:00
commit 89c98adf3c
5 changed files with 205 additions and 0 deletions

4
.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
build
CMakeUserPresets.json
compile_commands.json
.cache/

10
CMakeLists.txt Normal file
View File

@ -0,0 +1,10 @@
cmake_minimum_required(VERSION 3.5)
project(vector-extension)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
add_executable(${PROJECT_NAME} src/bench.cc)
find_package(benchmark REQUIRED)
target_link_libraries(${PROJECT_NAME} PRIVATE benchmark::benchmark_main)
target_compile_options(${PROJECT_NAME} PRIVATE -save-temps)
target_compile_options(${PROJECT_NAME} PUBLIC -mavx -mavx2 -march=native -O2)

5
conanfile.txt Normal file
View File

@ -0,0 +1,5 @@
[requires]
benchmark/1.9.4
[generators]
CMakeDeps
CMakeToolchain

148
src/bench.cc Normal file
View File

@ -0,0 +1,148 @@
// 1.2.1: Example of SSE2 intrinsics
// for int32_t
#include <benchmark/benchmark.h>
#include <stdint.h>
// for SSE2 intrinsics
#include <emmintrin.h>
// for AVX2 intrinsics
#include <immintrin.h>
void vector(void)
{
int32_t array_a[4] = { 0, 2, 1, 2 }; // 128 bit
int32_t array_b[4] = { 8, 5, 0, 6 };
int32_t array_c[4];
__m128i a, b, c;
a = _mm_loadu_si128((__m128i*)array_a); // loading array_a into register a
b = _mm_loadu_si128((__m128i*)array_b);
c = _mm_add_epi32(a, b); // must be { 8,7,1,8 }
_mm_storeu_si128((__m128i*)array_c, c);
}
static void BM_calculateVector(benchmark::State& state)
{
for (auto _ : state)
vector();
}
BENCHMARK(BM_calculateVector);
void scalar()
{
int32_t array_a[4] = { 0, 2, 1, 2 }; // 128 bit
int32_t array_b[4] = { 8, 5, 0, 6 };
int32_t array_c[4];
for (int i = 0; i < 4; i++)
array_c[i] = array_a[i] + array_b[i];
}
static void BM_calculateScalar(benchmark::State& state)
{
for (auto _ : state)
scalar();
}
BENCHMARK(BM_calculateScalar);
template <typename T = int, size_t size = 1024>
std::array<T, size> generateLongArray()
{
std::array<T, size> arr;
for (auto& a : arr) {
a = rand() % 100;
}
return arr;
}
template <typename T = int, size_t size = 1024>
std::array<T, size> with_vector(std::array<T, size>& arr, std::array<T, size>& arr2)
{
std::array<T, size> result;
auto resPos = result.begin();
for (auto it = arr.begin(), it2 = arr2.begin();
it < arr.end() && it2 < arr.end();
it2 += 4, it += 4) {
__m128i a, b, c;
a = _mm_loadu_si128((__m128i*)&(*it)); // loading array_a into register a
b = _mm_loadu_si128((__m128i*)&(*it2));
c = _mm_add_epi32(a, b);
_mm_storeu_si128((__m128i*)&(*resPos), c);
resPos += 4;
}
return result;
}
static void BM_arrayVector(benchmark::State& state)
{
auto arr1 = generateLongArray<int, 1 << 16>();
auto arr2 = generateLongArray<int, 1 << 16>();
for (auto _ : state)
auto arr3 = with_vector(arr1, arr2);
}
BENCHMARK(BM_arrayVector);
template <typename T = int, size_t size = 1024>
std::array<T, size> with_scalar(std::array<T, size>& arr, std::array<T, size>& arr2)
{
std::array<T, size> result;
auto resPos = result.begin();
for (auto it = arr.begin(), it2 = arr2.begin();
it < arr.end() && it2 < arr.end();
++it2, ++it) {
*resPos = *it + *it2;
}
return result;
}
static void BM_arrayScalar(benchmark::State& state)
{
auto arr1 = generateLongArray<int, 1 << 16>();
auto arr2 = generateLongArray<int, 1 << 16>();
for (auto _ : state)
auto arr3 = with_scalar(arr1, arr2);
}
BENCHMARK(BM_arrayScalar);
template <typename T = int, size_t size = 1024>
std::array<T, size> with_vectorAVX2(std::array<T, size>& arr, std::array<T, size>& arr2)
{
std::array<T, size> result;
auto resPos = result.begin();
__m256i a, b, c;
for (auto it = arr.begin(), it2 = arr2.begin();
it < arr.end() && it2 < arr.end();
it2 += 4, it += 4) {
a = _mm256_stream_load_si256((__m256i*)&(*it));
b = _mm256_stream_load_si256((__m256i*)&(*it2));
c = _mm256_add_epi64(a, b);
_mm256_store_si256((__m256i*)&(*resPos), c);
resPos += 4;
}
return result;
}
static void BM_arrayAVX2Vector(benchmark::State& state)
{
auto arr1 = generateLongArray<int64_t, 1 << 16>();
auto arr2 = generateLongArray<int64_t, 1 << 16>();
for (auto _ : state)
auto arr3 = with_vectorAVX2(arr1, arr2);
}
static void BM_arrayScalar64(benchmark::State& state)
{
auto arr1 = generateLongArray<int64_t, 1 << 16>();
auto arr2 = generateLongArray<int64_t, 1 << 16>();
for (auto _ : state)
auto arr3 = with_scalar(arr1, arr2);
}
BENCHMARK(BM_arrayAVX2Vector);
BENCHMARK(BM_arrayScalar64);
BENCHMARK_MAIN();

38
src/main.cc Normal file
View File

@ -0,0 +1,38 @@
#include <array>
#include <emmintrin.h>
template <typename T = int, size_t size = 1024>
void generateLongArray(std::array<T, size>& arr)
{
for (int& a : arr) {
a = rand() % 100;
}
}
template <typename T = int, size_t size = 1024>
std::array<T, size> with_vector(std::array<T, size>& arr, std::array<T, size>& arr2)
{
std::array<T, size> result;
auto resPos = result.begin();
for (auto it = arr.begin(), it2 = arr2.begin();
it < arr.end(), it2 < arr.end();
++it2, ++it) {
int32_t array_a[4] = { *it++, *it++, *it++, *it }; // 128 bit
int32_t array_b[4] = { *it2++, *it2++, *it2++, *it2 };
__m128i a, b, c;
a = _mm_loadu_si128((__m128i*)array_a); // loading array_a into register a
b = _mm_loadu_si128((__m128i*)array_b);
c = _mm_add_epi32(a, b);
_mm_storeu_si128((__m128i*)&(*resPos), c);
resPos += 4;
}
return result;
}
int main()
{
std::array<int, 1024> a;
generateLongArray(a);
return 0;
}