init
This commit is contained in:
commit
89c98adf3c
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
build
|
||||||
|
CMakeUserPresets.json
|
||||||
|
compile_commands.json
|
||||||
|
.cache/
|
||||||
10
CMakeLists.txt
Normal file
10
CMakeLists.txt
Normal 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
5
conanfile.txt
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
[requires]
|
||||||
|
benchmark/1.9.4
|
||||||
|
[generators]
|
||||||
|
CMakeDeps
|
||||||
|
CMakeToolchain
|
||||||
148
src/bench.cc
Normal file
148
src/bench.cc
Normal 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
38
src/main.cc
Normal 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;
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user