You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
102 lines
2.5 KiB
102 lines
2.5 KiB
|
|
#include "measure_time.h" |
|
|
|
#include <atomic> |
|
#include <cstdint> |
|
#include <thread> |
|
#include <ext/concurrence.h> |
|
|
|
#define COUNT (1u << 24) |
|
|
|
// use "incl" for 32-bit and "incq" for 64-bit in asm below: |
|
// use 32-bit for now: _Atomic_word should be 32-bit too; |
|
// 64-bit is basically as fast as 32-bit if it fits in your cache |
|
typedef std::uint32_t counting; |
|
|
|
volatile counting __attribute__ ((aligned (64))) volatile_counter; |
|
counting __attribute__ ((aligned (64))) simple_counter; |
|
std::atomic<counting> __attribute__ ((aligned (64))) atomic_counter; |
|
|
|
_Atomic_word __attribute__ ((aligned (64))) gxx_counter; |
|
|
|
void benchmark_volatile() { |
|
// should be the same as asm below |
|
volatile_counter = 0; |
|
for (size_t i = 0; i < COUNT; ++i) { |
|
++volatile_counter; |
|
} |
|
} |
|
|
|
void benchmark_asm() { |
|
simple_counter = 0; |
|
for (size_t i = 0; i < COUNT; ++i) { |
|
asm volatile( |
|
"incl %0;" |
|
: "+m"(simple_counter) |
|
); |
|
} |
|
} |
|
|
|
void benchmark_local_atomic() { |
|
// compiler doesn't realize no one else can read this counter and |
|
// uses real atomic (i.e. "lock") |
|
std::atomic<counting> local_atomic_counter; |
|
local_atomic_counter = 0; |
|
for (size_t i = 0; i < COUNT; ++i) { |
|
++local_atomic_counter; |
|
} |
|
} |
|
|
|
void benchmark_atomic() { |
|
// should be the same as "lock_asm" |
|
atomic_counter = 0; |
|
for (size_t i = 0; i < COUNT; ++i) { |
|
++atomic_counter; |
|
} |
|
} |
|
|
|
void benchmark_lock_asm() { |
|
simple_counter = 0; |
|
for (size_t i = 0; i < COUNT; ++i) { |
|
asm volatile( |
|
"lock incl %0;" |
|
: "+m"(simple_counter) |
|
); |
|
} |
|
} |
|
|
|
void benchmark_gxx_atomic() { |
|
// if linked with pthread this will use "lock" same as atomic, otherwise |
|
// it uses a simple non-volatile non-atomic add instruction |
|
// https://gcc.gnu.org/onlinedocs/libstdc++/manual/ext_concurrency.html |
|
// claims __atomic_add_dispatch uses a volatile counter, but this isn't |
|
// true in gcc 4.9 |
|
gxx_counter = 0; |
|
for (size_t i = 0; i < COUNT; ++i) { |
|
__gnu_cxx::__atomic_add_dispatch(&gxx_counter, 1); |
|
} |
|
} |
|
|
|
|
|
int main() { |
|
// std::thread fake([] { return; }); |
|
// fake.join(); |
|
|
|
std::cout << "volatile counter : "; |
|
measure_time_with_dry_run(benchmark_volatile); |
|
|
|
std::cout << "asm counter : "; |
|
measure_time_with_dry_run(benchmark_asm); |
|
|
|
std::cout << "local atomic counter: "; |
|
measure_time_with_dry_run(benchmark_local_atomic); |
|
|
|
std::cout << "atomic counter : "; |
|
measure_time_with_dry_run(benchmark_atomic); |
|
|
|
std::cout << "lock asm counter : "; |
|
measure_time_with_dry_run(benchmark_lock_asm); |
|
|
|
std::cout << "gxx atomic counter : "; |
|
measure_time_with_dry_run(benchmark_gxx_atomic); |
|
}
|
|
|