bare impressions on avx made

This commit is contained in:
Ano-sys
2026-09-01 22:52:15 +02:00
commit cfadc8f0d6
3 changed files with 147 additions and 0 deletions
+8
View File
@@ -0,0 +1,8 @@
cmake_minimum_required(VERSION 4.4.3)
project(simd_avx_example)
add_compile_options(-Wall -Werror -std=c++23 -march=native -O3)
FILE(GLOB sourcefiles src/*.c*)
add_executable(simd_avx_example ${sourcefiles})
+14
View File
@@ -0,0 +1,14 @@
# Performance Test
Example Project to test the performance increase of avx multiplication in contrast to standard multiplication by multiplying 16 32bit integer a fixed number of times.
## Programstructure
The program creates two arrays with each containing 16 integers which are dispatched to a thread in a timer environment to track the execution time. The results are then printed to stdout.
## Benchmark by 2147483647 iterations
| | ./program | nice -20 program | chrt -f 99 program |
| :---: | :---: | :---: | :---: |
| AVX | 9.46229s | 6.651s | 11.7455s |
| Std | 16.7001s | 13.6682s | 16.828s |
+125
View File
@@ -0,0 +1,125 @@
#include <cstdlib>
#include <iostream>
#include <immintrin.h>
#include <mutex>
#include <cstdint>
#include <chrono>
#include <thread>
#include <mutex>
#define _ITERATIONS std::numeric_limits<int>::max()
typedef __m512i vec16a32;
std::mutex cout_mutex;
void avx_mult32(uint32_t* a1, uint32_t* a2, __m512i* out){
vec16a32 v1 = _mm512_loadu_si512(a1);
vec16a32 v2 = _mm512_loadu_si512(a2);
*out = _mm512_mullo_epi32(v1, v2);
}
void avx_mult_example(uint32_t* values1, uint32_t* values2, vec16a32* out){
asm volatile(
""
:
: "m"(values1), "m"(values2)
: "memory"
);
avx_mult32(values1, values2, out);
asm volatile(
""
:
: "v"(out)
: "memory"
);
}
void standard_mult_example(uint32_t* values1, uint32_t* values2, uint32_t* out){
asm volatile(
""
:
: "m"(values1), "m"(values2)
: "memory"
);
for(int i = 0; i < 16; i++) out[i] = values1[i] * values2[i];
asm volatile(
""
:
: "m"(out)
: "memory"
);
}
class Timer{
private:
std::chrono::time_point<std::chrono::high_resolution_clock> start;
std::chrono::time_point<std::chrono::high_resolution_clock> end;
std::string name;
public:
Timer(std::string name, auto&& func) : name(name){
start = std::chrono::high_resolution_clock::now();
func();
end = std::chrono::high_resolution_clock::now();
}
Timer(std::string name, auto&& func, int iterations) : name(name){
start = std::chrono::high_resolution_clock::now();
for(int i = 0; i < iterations; i++) func();
end = std::chrono::high_resolution_clock::now();
}
long long get_duration() const {
return std::chrono::duration_cast<std::chrono::microseconds>(end - start).count();
}
void print_duration() const {
std::scoped_lock lock(cout_mutex);
auto duration = get_duration();
std::cout << name << " took " << duration << "μs, ";
std::cout << duration / 1000.0 << "ms, ";
std::cout << duration / 1000000.0 << "s." << std::endl;
}
};
std::thread dispatch_timer(std::string name, auto&& func, int iterations){
return std::thread(
[name = std::move(name), func = std::forward<decltype(func)>(func), iterations]() mutable {
Timer timer(name, func, iterations);
timer.print_duration();
});
}
void fill_pseudorandom(uint32_t* arr, size_t size){
for(size_t i = 0; i < size; i++) arr[i] = std::rand() % 100;
}
int main(){
std::srand(42);
auto array_size = 16;
uint32_t values1[array_size];
uint32_t values2[array_size];
fill_pseudorandom(values1, array_size);
fill_pseudorandom(values2, array_size);
std::cout << "For " << _ITERATIONS << " iterations:" << std::endl;
vec16a32 avx_result;
uint32_t standard_result[16];
std::thread standard_thread = dispatch_timer("Standard multiplication", [&](){ standard_mult_example(values1, values2, standard_result); }, _ITERATIONS);
std::thread avx_thread = dispatch_timer("AVX multiplication", [&](){ avx_mult_example(values1, values2, &avx_result); }, _ITERATIONS);
avx_thread.join();
standard_thread.join();
(void)avx_result;
(void)standard_result;
}