Compare commits
7 Commits
b0b31419b0
...
0abf6a1ecf
Author | SHA1 | Date | |
---|---|---|---|
0abf6a1ecf | |||
867136ff1b | |||
4b8f7320d3 | |||
6628092384 | |||
a0a4f1afea | |||
ca479c03ce | |||
0a2e133ab9 |
@@ -7,7 +7,6 @@
|
|||||||
void showMemory(const ConflictSet &cs);
|
void showMemory(const ConflictSet &cs);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define ANKERL_NANOBENCH_IMPLEMENT
|
|
||||||
#include "third_party/nanobench.h"
|
#include "third_party/nanobench.h"
|
||||||
|
|
||||||
constexpr int kNumKeys = 1000000;
|
constexpr int kNumKeys = 1000000;
|
||||||
|
@@ -138,6 +138,8 @@ include(CTest)
|
|||||||
# disable tests if this is being used through e.g. FetchContent
|
# disable tests if this is being used through e.g. FetchContent
|
||||||
if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR AND BUILD_TESTING)
|
if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR AND BUILD_TESTING)
|
||||||
|
|
||||||
|
add_library(nanobench ${CMAKE_CURRENT_SOURCE_DIR}/nanobench.cpp)
|
||||||
|
|
||||||
set(TEST_FLAGS -Wall -Wextra -Wunreachable-code -Wpedantic -UNDEBUG)
|
set(TEST_FLAGS -Wall -Wextra -Wunreachable-code -Wpedantic -UNDEBUG)
|
||||||
|
|
||||||
# corpus tests, which are tests curated by libfuzzer. The goal is to get broad
|
# corpus tests, which are tests curated by libfuzzer. The goal is to get broad
|
||||||
@@ -185,6 +187,7 @@ if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR AND BUILD_TESTING)
|
|||||||
target_include_directories(conflict_set_main
|
target_include_directories(conflict_set_main
|
||||||
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include)
|
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||||
target_compile_definitions(conflict_set_main PRIVATE ENABLE_MAIN)
|
target_compile_definitions(conflict_set_main PRIVATE ENABLE_MAIN)
|
||||||
|
target_link_libraries(conflict_set_main PRIVATE nanobench)
|
||||||
|
|
||||||
if(NOT APPLE)
|
if(NOT APPLE)
|
||||||
# libfuzzer target, to generate/manage corpus
|
# libfuzzer target, to generate/manage corpus
|
||||||
@@ -330,7 +333,7 @@ if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR AND BUILD_TESTING)
|
|||||||
|
|
||||||
# bench
|
# bench
|
||||||
add_executable(conflict_set_bench Bench.cpp)
|
add_executable(conflict_set_bench Bench.cpp)
|
||||||
target_link_libraries(conflict_set_bench PRIVATE ${PROJECT_NAME})
|
target_link_libraries(conflict_set_bench PRIVATE ${PROJECT_NAME} nanobench)
|
||||||
set_target_properties(conflict_set_bench PROPERTIES SKIP_BUILD_RPATH ON)
|
set_target_properties(conflict_set_bench PROPERTIES SKIP_BUILD_RPATH ON)
|
||||||
add_executable(real_data_bench RealDataBench.cpp)
|
add_executable(real_data_bench RealDataBench.cpp)
|
||||||
target_link_libraries(real_data_bench PRIVATE ${PROJECT_NAME})
|
target_link_libraries(real_data_bench PRIVATE ${PROJECT_NAME})
|
||||||
@@ -345,6 +348,9 @@ if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR AND BUILD_TESTING)
|
|||||||
add_executable(server_bench ServerBench.cpp)
|
add_executable(server_bench ServerBench.cpp)
|
||||||
target_link_libraries(server_bench PRIVATE ${PROJECT_NAME})
|
target_link_libraries(server_bench PRIVATE ${PROJECT_NAME})
|
||||||
set_target_properties(server_bench PROPERTIES SKIP_BUILD_RPATH ON)
|
set_target_properties(server_bench PROPERTIES SKIP_BUILD_RPATH ON)
|
||||||
|
|
||||||
|
add_executable(interleaving_test InterleavingTest.cpp)
|
||||||
|
target_link_libraries(interleaving_test PRIVATE nanobench)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# packaging
|
# packaging
|
||||||
|
@@ -766,6 +766,8 @@ private:
|
|||||||
|
|
||||||
int getNodeIndex(Node3 *self, uint8_t index) {
|
int getNodeIndex(Node3 *self, uint8_t index) {
|
||||||
Node3 *n = (Node3 *)self;
|
Node3 *n = (Node3 *)self;
|
||||||
|
assume(n->numChildren >= 1);
|
||||||
|
assume(n->numChildren <= 3);
|
||||||
for (int i = 0; i < n->numChildren; ++i) {
|
for (int i = 0; i < n->numChildren; ++i) {
|
||||||
if (n->index[i] == index) {
|
if (n->index[i] == index) {
|
||||||
return i;
|
return i;
|
||||||
@@ -1070,6 +1072,8 @@ ChildAndMaxVersion getChildAndMaxVersion(Node *self, uint8_t index) {
|
|||||||
Node *getChildGeq(Node0 *, int) { return nullptr; }
|
Node *getChildGeq(Node0 *, int) { return nullptr; }
|
||||||
|
|
||||||
Node *getChildGeq(Node3 *n, int child) {
|
Node *getChildGeq(Node3 *n, int child) {
|
||||||
|
assume(n->numChildren >= 1);
|
||||||
|
assume(n->numChildren <= 3);
|
||||||
for (int i = 0; i < n->numChildren; ++i) {
|
for (int i = 0; i < n->numChildren; ++i) {
|
||||||
if (n->index[i] >= child) {
|
if (n->index[i] >= child) {
|
||||||
return n->children[i];
|
return n->children[i];
|
||||||
@@ -3923,7 +3927,6 @@ struct __attribute__((visibility("default"))) PeakPrinter {
|
|||||||
|
|
||||||
#ifdef ENABLE_MAIN
|
#ifdef ENABLE_MAIN
|
||||||
|
|
||||||
#define ANKERL_NANOBENCH_IMPLEMENT
|
|
||||||
#include "third_party/nanobench.h"
|
#include "third_party/nanobench.h"
|
||||||
|
|
||||||
template <int kN> void benchRezero() {
|
template <int kN> void benchRezero() {
|
||||||
|
178
InterleavingTest.cpp
Normal file
178
InterleavingTest.cpp
Normal file
@@ -0,0 +1,178 @@
|
|||||||
|
#include <alloca.h>
|
||||||
|
#include <cassert>
|
||||||
|
#ifdef __x86_64__
|
||||||
|
#include <immintrin.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "third_party/nanobench.h"
|
||||||
|
|
||||||
|
struct Job {
|
||||||
|
int *input;
|
||||||
|
// Returned void* is a function pointer to the next continuation. We have to
|
||||||
|
// use void* because otherwise the type would be recursive.
|
||||||
|
typedef void *(*continuation)(Job *);
|
||||||
|
continuation next;
|
||||||
|
};
|
||||||
|
|
||||||
|
void *stepJob(Job *j) {
|
||||||
|
auto done = --(*j->input) == 0;
|
||||||
|
#ifdef __x86_64__
|
||||||
|
_mm_clflush(j->input);
|
||||||
|
#endif
|
||||||
|
return done ? nullptr : (void *)stepJob;
|
||||||
|
}
|
||||||
|
|
||||||
|
// So we can look at the disassembly more easily
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
void sequential(Job **jobs, int count) {
|
||||||
|
for (int i = 0; i < count; ++i) {
|
||||||
|
do {
|
||||||
|
jobs[i]->next = (Job::continuation)jobs[i]->next(jobs[i]);
|
||||||
|
} while (jobs[i]->next);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void sequentialNoFuncPtr(Job **jobs, int count) {
|
||||||
|
for (int i = 0; i < count; ++i) {
|
||||||
|
while (stepJob(jobs[i]))
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void interleaveSwapping(Job **jobs, int remaining) {
|
||||||
|
int current = 0;
|
||||||
|
while (remaining > 0) {
|
||||||
|
auto next = (Job::continuation)jobs[current]->next(jobs[current]);
|
||||||
|
jobs[current]->next = next;
|
||||||
|
if (next == nullptr) {
|
||||||
|
jobs[current] = jobs[remaining - 1];
|
||||||
|
--remaining;
|
||||||
|
} else {
|
||||||
|
++current;
|
||||||
|
}
|
||||||
|
if (current == remaining) {
|
||||||
|
current = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void interleaveBoundedCyclicList(Job **jobs, int count) {
|
||||||
|
if (count == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr int kConcurrent = 32;
|
||||||
|
Job *inProgress[kConcurrent];
|
||||||
|
int nextJob[kConcurrent];
|
||||||
|
|
||||||
|
int started = std::min(kConcurrent, count);
|
||||||
|
for (int i = 0; i < started; i++) {
|
||||||
|
inProgress[i] = jobs[i];
|
||||||
|
nextJob[i] = i + 1;
|
||||||
|
}
|
||||||
|
nextJob[started - 1] = 0;
|
||||||
|
|
||||||
|
int prevJob = started - 1;
|
||||||
|
int job = 0;
|
||||||
|
for (;;) {
|
||||||
|
auto next = (Job::continuation)inProgress[job]->next(inProgress[job]);
|
||||||
|
inProgress[job]->next = next;
|
||||||
|
if (next == nullptr) {
|
||||||
|
if (started == count) {
|
||||||
|
if (prevJob == job)
|
||||||
|
break;
|
||||||
|
nextJob[prevJob] = nextJob[job];
|
||||||
|
job = prevJob;
|
||||||
|
} else {
|
||||||
|
int temp = started++;
|
||||||
|
inProgress[job] = jobs[temp];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
prevJob = job;
|
||||||
|
job = nextJob[job];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void interleaveCyclicList(Job **jobs, int count) {
|
||||||
|
auto *nextJob = (int *)alloca(sizeof(int) * count);
|
||||||
|
|
||||||
|
for (int i = 0; i < count - 1; ++i) {
|
||||||
|
nextJob[i] = i + 1;
|
||||||
|
}
|
||||||
|
nextJob[count - 1] = 0;
|
||||||
|
|
||||||
|
int prevJob = count - 1;
|
||||||
|
int job = 0;
|
||||||
|
for (;;) {
|
||||||
|
auto next = (Job::continuation)jobs[job]->next(jobs[job]);
|
||||||
|
jobs[job]->next = next;
|
||||||
|
if (next == nullptr) {
|
||||||
|
if (prevJob == job)
|
||||||
|
break;
|
||||||
|
nextJob[prevJob] = nextJob[job];
|
||||||
|
job = prevJob;
|
||||||
|
}
|
||||||
|
prevJob = job;
|
||||||
|
job = nextJob[job];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
ankerl::nanobench::Bench bench;
|
||||||
|
|
||||||
|
constexpr int kNumJobs = 100;
|
||||||
|
bench.relative(true);
|
||||||
|
|
||||||
|
Job jobs[kNumJobs];
|
||||||
|
Job jobsCopy[kNumJobs];
|
||||||
|
int iters = 0;
|
||||||
|
int originalInput[kNumJobs];
|
||||||
|
for (int i = 0; i < kNumJobs; ++i) {
|
||||||
|
originalInput[i] = rand() % 5 + 3;
|
||||||
|
jobs[i].input = new int{originalInput[i]};
|
||||||
|
jobs[i].next = stepJob;
|
||||||
|
iters += *jobs[i].input;
|
||||||
|
}
|
||||||
|
bench.batch(iters);
|
||||||
|
|
||||||
|
for (auto [scheduler, name] :
|
||||||
|
{std::make_pair(sequentialNoFuncPtr, "sequentialNoFuncPtr"),
|
||||||
|
std::make_pair(sequential, "sequential"),
|
||||||
|
std::make_pair(interleaveSwapping, "interleavingSwapping"),
|
||||||
|
std::make_pair(interleaveBoundedCyclicList,
|
||||||
|
"interleaveBoundedCyclicList"),
|
||||||
|
std::make_pair(interleaveCyclicList, "interleaveCyclicList")}) {
|
||||||
|
for (int i = 0; i < kNumJobs; ++i) {
|
||||||
|
*jobs[i].input = originalInput[i];
|
||||||
|
}
|
||||||
|
memcpy(jobsCopy, jobs, sizeof(jobs));
|
||||||
|
Job *ps[kNumJobs];
|
||||||
|
for (int i = 0; i < kNumJobs; ++i) {
|
||||||
|
ps[i] = jobsCopy + i;
|
||||||
|
}
|
||||||
|
scheduler(ps, kNumJobs);
|
||||||
|
for (int i = 0; i < kNumJobs; ++i) {
|
||||||
|
if (*jobsCopy[i].input != 0) {
|
||||||
|
fprintf(stderr, "%s failed\n", name);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bench.run(name, [&]() {
|
||||||
|
for (int i = 0; i < kNumJobs; ++i) {
|
||||||
|
*jobs[i].input = originalInput[i];
|
||||||
|
}
|
||||||
|
memcpy(jobsCopy, jobs, sizeof(jobs));
|
||||||
|
Job *ps[kNumJobs];
|
||||||
|
for (int i = 0; i < kNumJobs; ++i) {
|
||||||
|
ps[i] = jobsCopy + i;
|
||||||
|
}
|
||||||
|
scheduler(ps, kNumJobs);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
for (int i = 0; i < kNumJobs; ++i) {
|
||||||
|
delete jobs[i].input;
|
||||||
|
}
|
||||||
|
}
|
2
nanobench.cpp
Normal file
2
nanobench.cpp
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
#define ANKERL_NANOBENCH_IMPLEMENT
|
||||||
|
#include "third_party/nanobench.h"
|
Reference in New Issue
Block a user