bare impressions on avx made
This commit is contained in:
@@ -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})
|
||||
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user