-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbranch.cpp
96 lines (86 loc) · 3.65 KB
/
branch.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
#include <algorithm>
#include <cstdint>
#include <fstream>
#include <iostream>
#include <random>
#ifdef _MSC_VER
#include <intrin.h>
#else
#include <x86intrin.h>
#endif
// optional wrapper if you don't want to just use __rdtsc() everywhere
inline __attribute__((always_inline)) unsigned long long readTSC() {
_mm_lfence(); // optionally wait for earlier insns to retire before reading
// the clock
auto result = __rdtsc();
_mm_lfence(); // optionally block later instructions until rdtsc retires
return result;
}
std::mt19937_64 m_generator{std::random_device()()};
std::uniform_int_distribution<> distrib{0, 100};
// User-defined literals
auto constexpr operator"" _B(unsigned long long int n) { return n; }
auto constexpr operator"" _KB(unsigned long long int n) { return n * 1024; }
auto constexpr operator"" _M(unsigned long long int n) {
return n * 1000 * 1000;
}
// This function check is the csv file exists
// if it does not exist it creates it and writes the header
// the header contains the name branching probability and the number of
// instructions per cycle if the file exists it appends the branching
// probability and the number of instructions per cycle
static void write_csv(const unsigned branch_prob,
const double instructions_per_cycle,
const bool branchless = false
) {
std::ofstream file;
file.open("branch.csv", std::ios_base::app);
if (file.tellp() == 0) { file << "probability,cycles,branchless" << std::endl; }
file << branch_prob << ", " << instructions_per_cycle <<"," << branchless << std::endl;
file.close();
}
// This function is used to benchmark the branching
// it takes a branch_prob parameter which is the probability of the branch being
// taken it measures the number of instructions per cycle
static void branching_benchmark(const unsigned branch_prob) {
const auto num_ops = 100_M;
std::vector<unsigned long> list(num_ops);
// initialise the array with the distribution
for (auto i = 0; i < num_ops; ++i) { list[i] = distrib(m_generator); }
volatile int sum = 0;
const auto start = readTSC();
// sum the array into sum
for (auto i = 0; i < num_ops; ++i) {
if (list[i] < branch_prob) { sum += list[i]; }
}
const auto stop = readTSC();
std::cout << "branching_benchmark(" << branch_prob << ") took "
<< double(stop - start) / num_ops << " cycles per iteration"
<< std::endl;
write_csv(branch_prob, double(stop - start) / num_ops);
}
// This function is used to benchmark the branchless version
// it takes a branch_prob parameter which is the probability of the branch being
// taken it measures the number of instructions per cycle
static void branchless_benchmark(const unsigned branch_prob) {
const auto num_ops = 100_M;
std::vector<unsigned long> list(num_ops);
// initialise the array with the distribution
for (auto i = 0; i < num_ops; ++i) { list[i] = distrib(m_generator); }
volatile int sum = 0;
const auto start = readTSC();
// sum the array into sum
for (auto i = 0; i < num_ops; ++i) {
sum += list[i] * (list[i] < branch_prob);
}
const auto stop = readTSC();
std::cout << "branchless_benchmark(" << branch_prob << ") took "
<< double(stop - start) / num_ops << " cycles per iteration"
<< std::endl;
write_csv(branch_prob, double(stop - start) / num_ops, true);
}
int main() {
for (size_t i = 0; i < 101; i++) { branching_benchmark(i); }
for (size_t i = 0; i < 101; i++) { branchless_benchmark(i); }
return 0;
}