-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcommon.h
166 lines (148 loc) · 4.76 KB
/
common.h
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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
#ifndef __BENCH_COMMON_H__
#define __BENCH_COMMON_H__
#define HAVE_ARCH_STRUCT_FLOCK
#ifdef __linux__
#define _GNU_SOURCE
#include <linux/fcntl.h>
#else
#include <fcntl.h>
#endif
#ifdef __MACH__
#include <libproc.h>
#endif
#include <assert.h>
#include <inttypes.h>
#include <limits.h>
#include <pthread.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <sys/resource.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <unistd.h>
#define PAGE_SIZE (1 << 12)
#define MICROSECONDS_IN_ONE_SECOND 1000000
#define NANOSECONDS_IN_ONE_SECOND (MICROSECONDS_IN_ONE_SECOND * 1000)
#define MAX_NUM_THREADS 64
#define OPEN_DIRECT (1 << 0)
#define OPEN_SYNC (1 << 1)
#define CLOSE_FSYNC (1 << 2)
#define CLOSE_MSYNC (1 << 3)
#define WRITE_VFS (1 << 4)
#define WRITE_MMAP (1 << 5)
#define USE_URING (1 << 6)
#define VERBOSE (1 << 7)
typedef struct bench_args {
int num_threads, num_files, flags;
size_t file_size;
} bench_args_t;
extern bench_args_t bench_args;
extern pthread_t threads[MAX_NUM_THREADS];
extern struct timespec start, stop;
extern _Atomic ssize_t iteration_write;
extern _Atomic ssize_t iteration_close;
extern _Atomic bool is_started;
extern _Atomic uint64_t total_cpu_usr;
extern _Atomic uint64_t total_cpu_sys;
extern uint8_t *buf;
static inline uint64_t getthid() {
#ifdef __linux__
const pid_t tid = syscall(SYS_gettid);
#elif defined(__MACH__)
uint64_t tid;
pthread_threadid_np(NULL, &tid);
#endif
return tid;
}
typedef struct cpu_usage {
uint64_t usr_usec, sys_usec;
} cpu_usage_t;
#if defined(__linux__) && 0
static inline int read_cpu(const uint64_t tid, cpu_usage_t *const cpu_usage) {
char proc_file_path_buf[256];
snprintf(proc_file_path_buf, sizeof(proc_file_path_buf),
"/proc/self/task/%d/stat", (int)tid);
const int proc_fd = open(proc_file_path_buf, O_RDONLY);
if (proc_fd < 0)
goto err_open;
{
char proc_stat_buf[512];
if (read(proc_fd, proc_stat_buf, sizeof(proc_stat_buf)) < 0)
goto err_read;
proc_stat_buf[511] = 0;
uint64_t utime, stime;
if (sscanf(proc_stat_buf,
"%*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %lu %lu",
&utime, &stime) == 2) {
const uint64_t clk_ticks_per_s = sysconf(_SC_CLK_TCK);
cpu_usage->usr_usec =
utime / (clk_ticks_per_s / MICROSECONDS_IN_ONE_SECOND);
cpu_usage->sys_usec =
stime / (clk_ticks_per_s / MICROSECONDS_IN_ONE_SECOND);
close(proc_fd);
return 0;
}
}
err_read:
close(proc_fd);
err_open:
return -1;
}
#endif
#ifdef __linux__
static inline int read_cpu(const uint64_t _tid, cpu_usage_t *const cpu_usage) {
struct rusage usage;
if (getrusage(RUSAGE_THREAD, &usage) < 0)
return -1;
const struct timeval utime = usage.ru_utime, stime = usage.ru_stime;
assert((ULONG_MAX / MICROSECONDS_IN_ONE_SECOND) > (uint64_t)utime.tv_sec);
assert((ULONG_MAX / MICROSECONDS_IN_ONE_SECOND) > (uint64_t)stime.tv_sec);
cpu_usage->usr_usec =
(uint64_t)utime.tv_sec * MICROSECONDS_IN_ONE_SECOND + utime.tv_usec;
cpu_usage->sys_usec =
(uint64_t)stime.tv_sec * MICROSECONDS_IN_ONE_SECOND + stime.tv_usec;
return 0;
}
#endif
#ifdef __MACH__
static inline int read_cpu(const uint64_t tid, cpu_usage_t *const cpu_usage) {
struct proc_threadinfo pth;
if (PROC_PIDTHREADINFO_SIZE == proc_pidinfo(getpid(), PROC_PIDTHREADID64INFO,
tid, &pth,
PROC_PIDTHREADINFO_SIZE)) {
cpu_usage->usr_usec = pth.pth_user_time / 1000;
cpu_usage->sys_usec = pth.pth_system_time / 1000;
return 0;
}
return -1;
}
#endif
static inline struct timespec delta(struct timespec start,
struct timespec end) {
struct timespec temp;
if ((end.tv_nsec - start.tv_nsec) < 0) {
temp.tv_sec = end.tv_sec - start.tv_sec - 1;
temp.tv_nsec = NANOSECONDS_IN_ONE_SECOND + end.tv_nsec - start.tv_nsec;
} else {
temp.tv_sec = end.tv_sec - start.tv_sec;
temp.tv_nsec = end.tv_nsec - start.tv_nsec;
}
return temp;
}
static inline long timespec_to_total_nanoseconds(struct timespec timespec) {
assert((LONG_MAX / NANOSECONDS_IN_ONE_SECOND) > timespec.tv_sec);
return timespec.tv_sec * NANOSECONDS_IN_ONE_SECOND + timespec.tv_nsec;
}
static inline void print_throughput(const bench_args_t *const bench_args,
struct timespec start,
struct timespec end) {
const double delta_in_ns =
(double)timespec_to_total_nanoseconds(delta(start, end));
const double duration = delta_in_ns / 10e6;
const double throughput =
((double)(bench_args->file_size * bench_args->num_files)) / delta_in_ns;
printf("duration: %.3f ms\n", duration);
printf("throughput: %.3f GB/s\n", throughput);
}
#endif