Skip to content

Commit 122cce8

Browse files
authored
Add C++ examples, C++ CI (#10)
* Add C++ examples, C++ CI * Remove extraneous entry from CMake * Use g++-14 for C++ CI * Minor fix * Verbose build for debugging * Use gcc 13 * GCC 12
1 parent 705f775 commit 122cce8

16 files changed

+1009
-3
lines changed

Diff for: .github/workflows/ci.yml

+3-3
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,9 @@ jobs:
3333
- name: CMake
3434
run: |
3535
sudo apt-get update
36-
sudo apt-get install libhdf5-dev
37-
cmake -B build
36+
sudo apt-get install libhdf5-dev g++-12
37+
CXX=g++-12 cmake -B build
3838
- name: Build
39-
run: make -C build -j `nproc`
39+
run: VERBOSE=true make -C build -j `nproc`
4040
- name: Test
4141
run: ctest --test-dir ./build/test/bash

Diff for: CMakeLists.txt

+2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ cmake_policy(SET CMP0079 NEW)
55

66
set(CMAKE_C_STANDARD 11)
77

8+
set(CMAKE_CXX_STANDARD 20)
9+
810
set(CMAKE_C_FLAGS "-O3 -march=native")
911

1012
add_subdirectory(include)

Diff for: examples/CMakeLists.txt

+2
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,5 @@ add_example(bsp-ls)
1414
add_example(benchmark_read)
1515
add_example(benchmark_read_parallel)
1616
add_example(benchmark_write)
17+
18+
add_subdirectory(cpp)

Diff for: examples/cpp/CMakeLists.txt

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
function(add_example example_name)
2+
add_executable(${example_name}-cpp ${example_name}.cpp)
3+
target_link_libraries(${example_name}-cpp binsparse-rc)
4+
endfunction()
5+
6+
add_example(simple_matrix_write)
7+
add_example(simple_matrix_read)
8+
add_example(simple_read)
9+
add_example(simple_write)
10+
add_example(mtx2bsp)
11+
add_example(bsp2mtx)
12+
add_example(check_equivalence)
13+
add_example(bsp-ls)
14+
add_example(benchmark_read)
15+
add_example(benchmark_write)

Diff for: examples/cpp/benchmark_read.cpp

+123
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
#include <binsparse/binsparse.h>
2+
#include <stdlib.h>
3+
#include <time.h>
4+
5+
double gettime() {
6+
struct timespec time;
7+
clock_gettime(CLOCK_MONOTONIC, &time);
8+
return ((double) time.tv_sec) + ((double) 1e-9) * time.tv_nsec;
9+
}
10+
11+
int compar(const void* a, const void* b) {
12+
double x = *((const double*) a);
13+
double y = *((const double*) b);
14+
15+
double diff = x - y;
16+
17+
if (diff > 0) {
18+
return 1;
19+
} else if (diff < 0) {
20+
return -1;
21+
} else {
22+
return 0;
23+
}
24+
}
25+
26+
double compute_variance(double* x, size_t n) {
27+
double sum = 0;
28+
29+
for (size_t i = 0; i < n; i++) {
30+
sum += x[i];
31+
}
32+
33+
double mean = sum / n;
34+
35+
double sum_of_squares = 0;
36+
for (size_t i = 0; i < n; i++) {
37+
sum_of_squares += (x[i] - mean) * (x[i] - mean);
38+
}
39+
40+
return sum_of_squares / (n - 1);
41+
}
42+
43+
void flush_cache() {
44+
#ifdef __APPLE__
45+
system("bash -c \"sync && sudo purge\"");
46+
#elif __linux__
47+
system("bash -c \"sync\" && sudo echo 3 > /proc/sys/vm/drop_caches");
48+
#else
49+
static_assert(false);
50+
#endif
51+
}
52+
53+
int main(int argc, char** argv) {
54+
if (argc < 2) {
55+
fprintf(stderr, "usage: ./benchmark_read [file_name.h5]\n");
56+
return 1;
57+
}
58+
59+
char* file_name = argv[1];
60+
61+
printf("Opening %s\n", file_name);
62+
63+
const int num_trials = 1;
64+
65+
double durations[num_trials];
66+
67+
size_t nbytes = 0;
68+
69+
// To flush the filesystem cache before each trial, change to `true`.
70+
bool cold_cache = false;
71+
72+
for (size_t i = 0; i < num_trials; i++) {
73+
if (cold_cache) {
74+
flush_cache();
75+
}
76+
double begin = gettime();
77+
bsp_matrix_t mat = bsp_read_matrix(file_name, NULL);
78+
double end = gettime();
79+
durations[i] = end - begin;
80+
nbytes = bsp_matrix_nbytes(mat);
81+
bsp_destroy_matrix_t(mat);
82+
}
83+
84+
printf("[");
85+
for (size_t i = 0; i < num_trials; i++) {
86+
printf("%lf", durations[i]);
87+
if (i + 1 < num_trials) {
88+
printf(", ");
89+
}
90+
}
91+
printf("]\n");
92+
93+
qsort(durations, num_trials, sizeof(double), compar);
94+
95+
double variance = compute_variance(durations, num_trials);
96+
97+
double median_time = durations[num_trials / 2];
98+
99+
printf("Read file in %lf seconds\n", median_time);
100+
101+
if (num_trials > 1) {
102+
printf("Variance is %lf seconds, standard devication is %lf seconds\n",
103+
variance, sqrt(variance));
104+
}
105+
106+
double gbytes = ((double) nbytes) / 1024 / 1024 / 1024;
107+
double gbytes_s = gbytes / median_time;
108+
109+
printf("Achieved %lf GiB/s\n", gbytes_s);
110+
111+
printf("[");
112+
for (size_t i = 0; i < num_trials; i++) {
113+
printf("%lf", durations[i]);
114+
if (i + 1 < num_trials) {
115+
printf(", ");
116+
}
117+
}
118+
printf("]\n");
119+
120+
printf("FORPARSER: %s,%lf,%lf\n", file_name, median_time, gbytes_s);
121+
122+
return 0;
123+
}

Diff for: examples/cpp/benchmark_write.cpp

+170
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
#include <binsparse/binsparse.h>
2+
#include <stdlib.h>
3+
#include <time.h>
4+
5+
double gettime() {
6+
struct timespec time;
7+
clock_gettime(CLOCK_MONOTONIC, &time);
8+
return ((double) time.tv_sec) + ((double) 1e-9) * time.tv_nsec;
9+
}
10+
11+
int compar(const void* a, const void* b) {
12+
double x = *((const double*) a);
13+
double y = *((const double*) b);
14+
15+
double diff = x - y;
16+
17+
if (diff > 0) {
18+
return 1;
19+
} else if (diff < 0) {
20+
return -1;
21+
} else {
22+
return 0;
23+
}
24+
}
25+
26+
double compute_variance(double* x, size_t n) {
27+
double sum = 0;
28+
29+
for (size_t i = 0; i < n; i++) {
30+
sum += x[i];
31+
}
32+
33+
double mean = sum / n;
34+
35+
double sum_of_squares = 0;
36+
for (size_t i = 0; i < n; i++) {
37+
sum_of_squares += (x[i] - mean) * (x[i] - mean);
38+
}
39+
40+
return sum_of_squares / (n - 1);
41+
}
42+
43+
void flush_cache() {
44+
#ifdef __APPLE__
45+
system("bash -c \"sync && sudo purge\"");
46+
#elif __linux__
47+
system("bash -c \"sync\" && sudo echo 3 > /proc/sys/vm/drop_caches");
48+
#else
49+
static_assert(false);
50+
#endif
51+
}
52+
53+
void flush_writes() {
54+
#ifdef __APPLE__
55+
system("bash -c \"sync\"");
56+
#elif __linux__
57+
system("bash -c \"sync\"");
58+
#else
59+
static_assert(false);
60+
#endif
61+
}
62+
63+
void delete_file(const char* file_name) {
64+
char command[2048];
65+
snprintf(command, 2047, "rm %s", file_name);
66+
system(command);
67+
}
68+
69+
int main(int argc, char** argv) {
70+
if (argc < 2) {
71+
fprintf(stderr,
72+
"usage: ./benchmark_read [file_name.h5] [scratch_space] [optional: "
73+
"compression_level]\n");
74+
return 1;
75+
}
76+
77+
char* file_name = argv[1];
78+
char* scratch_space = argv[2];
79+
80+
int compression_level = 0;
81+
82+
if (argc >= 4) {
83+
compression_level = atoi(argv[3]);
84+
}
85+
86+
printf("Opening %s\n", file_name);
87+
88+
const int num_trials = 1;
89+
90+
double durations[num_trials];
91+
92+
bsp_matrix_t mat = bsp_read_matrix(file_name, NULL);
93+
size_t nbytes = bsp_matrix_nbytes(mat);
94+
95+
char output_filename[2048];
96+
strncpy(output_filename, scratch_space, 2047);
97+
strncpy(output_filename + strlen(scratch_space), "/benchmark_write_file_n.h5",
98+
2047 - strlen(scratch_space));
99+
100+
// Current output name logic does not do much.
101+
assert(num_trials <= 10);
102+
103+
// To flush the filesystem cache before each trial, change to `true`.
104+
bool cold_cache = false;
105+
106+
// To flush each write to the filesystem and include this in the timing,
107+
// change to `true`.
108+
bool flush_each_write = true;
109+
110+
for (size_t i = 0; i < num_trials; i++) {
111+
if (cold_cache) {
112+
flush_cache();
113+
}
114+
115+
output_filename[strlen(scratch_space) + 21] = '0' + i;
116+
printf("Writing to file %s\n", output_filename);
117+
118+
double begin = gettime();
119+
bsp_write_matrix(output_filename, mat, NULL, NULL, compression_level);
120+
121+
if (flush_each_write) {
122+
flush_writes();
123+
}
124+
125+
double end = gettime();
126+
durations[i] = end - begin;
127+
128+
delete_file(output_filename);
129+
}
130+
131+
printf("[");
132+
for (size_t i = 0; i < num_trials; i++) {
133+
printf("%lf", durations[i]);
134+
if (i + 1 < num_trials) {
135+
printf(", ");
136+
}
137+
}
138+
printf("]\n");
139+
140+
qsort(durations, num_trials, sizeof(double), compar);
141+
142+
double variance = compute_variance(durations, num_trials);
143+
144+
double median_time = durations[num_trials / 2];
145+
146+
printf("Wrote file in %lf seconds\n", median_time);
147+
148+
if (num_trials > 1) {
149+
printf("Variance is %lf seconds, standard devication is %lf seconds\n",
150+
variance, sqrt(variance));
151+
}
152+
153+
double gbytes = ((double) nbytes) / 1024 / 1024 / 1024;
154+
double gbytes_s = gbytes / median_time;
155+
156+
printf("Achieved %lf GiB/s\n", gbytes_s);
157+
158+
printf("[");
159+
for (size_t i = 0; i < num_trials; i++) {
160+
printf("%lf", durations[i]);
161+
if (i + 1 < num_trials) {
162+
printf(", ");
163+
}
164+
}
165+
printf("]\n");
166+
167+
printf("FORPARSER: %s,%lf,%lf\n", file_name, median_time, gbytes_s);
168+
169+
return 0;
170+
}

0 commit comments

Comments
 (0)