Skip to content

Commit ee64322

Browse files
authored
improve the memcpy benchmark (#9490)
- remove the multi-threaded tests, they added too much noise - added a memset test - make sure we allocate the buffer aligned to 16KB
1 parent 79d65a7 commit ee64322

1 file changed

Lines changed: 111 additions & 11 deletions

File tree

libs/utils/benchmark/benchmark_memcpy.cpp

Lines changed: 111 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,25 +18,125 @@
1818

1919
#include <benchmark/benchmark.h>
2020

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+
// ------------------------------------------------------------------------------------------------
2188

2289
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();
2699

27100
{
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);
31104
benchmark::DoNotOptimize(dst);
32105
benchmark::DoNotOptimize(src);
33-
benchmark::ClobberMemory();
34106
}
35107
}
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);
37115

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));
40128
}
41129

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

Comments
 (0)