|
18 | 18 |
|
19 | 19 | #include <benchmark/benchmark.h> |
20 | 20 |
|
| 21 | +#include <utils/memalign.h> |
| 22 | + |
| 23 | +#include <cstddef> |
| 24 | +#include <cstdint> |
| 25 | +#include <cstdlib> |
| 26 | +#include <cstring> |
| 27 | +#include <vector> |
| 28 | + |
| 29 | +// ------------------------------------------------------------------------------------------------ |
| 30 | + |
| 31 | +#ifdef __linux__ |
| 32 | +#include <sched.h> |
| 33 | +#include <unistd.h> |
| 34 | +#include <sys/syscall.h> |
| 35 | +#endif |
| 36 | + |
| 37 | +// Returns true if successful, false if failed |
| 38 | +static bool pinThreadToCore(int core_id) { |
| 39 | +#ifdef __linux__ |
| 40 | + cpu_set_t cpuset; |
| 41 | + CPU_ZERO(&cpuset); |
| 42 | + CPU_SET(core_id, &cpuset); |
| 43 | + |
| 44 | + // 0 = current thread |
| 45 | + int const result = sched_setaffinity(0, sizeof(cpu_set_t), &cpuset); |
| 46 | + return (result == 0); |
| 47 | +#else |
| 48 | + (void)core_id; |
| 49 | + return false; |
| 50 | +#endif |
| 51 | +} |
| 52 | + |
| 53 | +// ------------------------------------------------------------------------------------------------ |
| 54 | + |
| 55 | +static constexpr size_t ALIGNMENT = 16 << 10; |
| 56 | + |
| 57 | +template<class T, size_t Align> |
| 58 | +struct AlignedAllocator { |
| 59 | + using value_type = T; |
| 60 | + |
| 61 | + template<class U> |
| 62 | + struct rebind { |
| 63 | + using other = AlignedAllocator<U, Align>; |
| 64 | + }; |
| 65 | + |
| 66 | + AlignedAllocator() noexcept = default; |
| 67 | + |
| 68 | + template<class U> |
| 69 | + explicit AlignedAllocator(const AlignedAllocator<U, Align>&) noexcept {} |
| 70 | + |
| 71 | + T* allocate(size_t const n) { |
| 72 | + size_t const bytes = n * sizeof(T); |
| 73 | + // std::aligned_alloc requires size to be a multiple of alignment. |
| 74 | + size_t const aligned_bytes = ((bytes + Align - 1) / Align) * Align; |
| 75 | + void* ptr = utils::aligned_alloc(aligned_bytes, Align); |
| 76 | + return static_cast<T*>(ptr); |
| 77 | + } |
| 78 | + |
| 79 | + void deallocate(T* p, size_t) noexcept { |
| 80 | + utils::aligned_free(p); |
| 81 | + } |
| 82 | +}; |
| 83 | + |
| 84 | +template<typename T> |
| 85 | +using PageAlignedVector = std::vector<T, AlignedAllocator<T, ALIGNMENT>>; |
| 86 | + |
| 87 | +// ------------------------------------------------------------------------------------------------ |
21 | 88 |
|
22 | 89 | static void BM_memcpy(benchmark::State& state) { |
23 | | - char* src = new char[state.range(0)]; |
24 | | - char* dst = new char[state.range(0)]; |
25 | | - memset(src, 'x', (size_t)state.range(0)); |
| 90 | + // pinThreadToCore(7); |
| 91 | + int64_t const size = state.range(0); |
| 92 | + PageAlignedVector<char> src(size); |
| 93 | + PageAlignedVector<char> dst(size); |
| 94 | + |
| 95 | + // make all these pages resident |
| 96 | + memset(src.data(), 0, size); |
| 97 | + memset(dst.data(), 0, size); |
| 98 | + benchmark::ClobberMemory(); |
26 | 99 |
|
27 | 100 | { |
28 | | - PerformanceCounters pc(state); |
29 | | - for (auto _ : state) { |
30 | | - memcpy(dst, src, (size_t)state.range(0)); |
| 101 | + // PerformanceCounters const pc(state); |
| 102 | + for (auto _: state) { |
| 103 | + memcpy(dst.data(), src.data(), size); |
31 | 104 | benchmark::DoNotOptimize(dst); |
32 | 105 | benchmark::DoNotOptimize(src); |
33 | | - benchmark::ClobberMemory(); |
34 | 106 | } |
35 | 107 | } |
36 | | - state.SetBytesProcessed(int64_t(state.iterations()) * int64_t(state.range(0))); |
| 108 | + state.SetBytesProcessed(int64_t(state.iterations()) * int64_t(size)); |
| 109 | +} |
| 110 | + |
| 111 | +static void BM_memset(benchmark::State& state) { |
| 112 | + //pinThreadToCore(7); |
| 113 | + int64_t const size = state.range(0); |
| 114 | + PageAlignedVector<char> src(size); |
37 | 115 |
|
38 | | - delete[] src; |
39 | | - delete[] dst; |
| 116 | + // make all these pages resident |
| 117 | + memset(src.data(), 0, size); |
| 118 | + benchmark::ClobberMemory(); |
| 119 | + |
| 120 | + { |
| 121 | + // PerformanceCounters const pc(state); |
| 122 | + for (auto _: state) { |
| 123 | + memset(src.data(), 0, size); |
| 124 | + benchmark::DoNotOptimize(src); |
| 125 | + } |
| 126 | + } |
| 127 | + state.SetBytesProcessed(int64_t(state.iterations()) * int64_t(size)); |
40 | 128 | } |
41 | 129 |
|
42 | | -BENCHMARK(BM_memcpy)->Range(8, 8192<<10)->Threads(1)->Threads(8); |
| 130 | +BENCHMARK(BM_memcpy) |
| 131 | + ->DenseRange( 4<<10, 128<<10, 8<<10) |
| 132 | + ->DenseRange(128<<10, 4<<20, 128<<10) |
| 133 | + ->DenseRange( 4<<20, 16<<20, 1<<20) |
| 134 | + ->DenseRange( 16<<20, 32<<20, 2<<20) |
| 135 | + ; |
| 136 | + |
| 137 | +BENCHMARK(BM_memset) |
| 138 | + ->DenseRange( 4<<10, 128<<10, 8<<10) |
| 139 | + ->DenseRange(128<<10, 4<<20, 128<<10) |
| 140 | + ->DenseRange( 4<<20, 16<<20, 1<<20) |
| 141 | + ->DenseRange( 16<<20, 32<<20, 2<<20) |
| 142 | + ; |
0 commit comments