xref: /xnu-11215.81.4/tests/counter/benchmark.c (revision d4514f0bc1d3f944c22d92e68b646ac3fb40d452)
1*d4514f0bSApple OSS Distributions /* Per-cpu counter microbenchmarks. */
2*d4514f0bSApple OSS Distributions 
3*d4514f0bSApple OSS Distributions #include <assert.h>
4*d4514f0bSApple OSS Distributions #include <inttypes.h>
5*d4514f0bSApple OSS Distributions #include <pthread.h>
6*d4514f0bSApple OSS Distributions #include <stdatomic.h>
7*d4514f0bSApple OSS Distributions #include <stdbool.h>
8*d4514f0bSApple OSS Distributions #include <stdio.h>
9*d4514f0bSApple OSS Distributions #include <stdlib.h>
10*d4514f0bSApple OSS Distributions #include <string.h>
11*d4514f0bSApple OSS Distributions 
12*d4514f0bSApple OSS Distributions #include <sys/types.h>
13*d4514f0bSApple OSS Distributions #include <sys/sysctl.h>
14*d4514f0bSApple OSS Distributions 
15*d4514f0bSApple OSS Distributions #include "benchmark/helpers.h"
16*d4514f0bSApple OSS Distributions #include "counter/common.h"
17*d4514f0bSApple OSS Distributions 
18*d4514f0bSApple OSS Distributions typedef enum test_variant {
19*d4514f0bSApple OSS Distributions 	VARIANT_SCALABLE_COUNTER,
20*d4514f0bSApple OSS Distributions 	VARIANT_ATOMIC,
21*d4514f0bSApple OSS Distributions 	VARIANT_RACY
22*d4514f0bSApple OSS Distributions } test_variant_t;
23*d4514f0bSApple OSS Distributions 
24*d4514f0bSApple OSS Distributions static const char* kScalableCounterArgument = "scalable";
25*d4514f0bSApple OSS Distributions static const char* kAtomicCounterArgument = "atomic";
26*d4514f0bSApple OSS Distributions static const char* kRacyCounterArgument = "racy";
27*d4514f0bSApple OSS Distributions 
28*d4514f0bSApple OSS Distributions static const int64_t kChunkSize = 100000000;
29*d4514f0bSApple OSS Distributions 
30*d4514f0bSApple OSS Distributions /* Arguments parsed from the command line */
31*d4514f0bSApple OSS Distributions typedef struct test_args {
32*d4514f0bSApple OSS Distributions 	size_t n_threads;
33*d4514f0bSApple OSS Distributions 	unsigned long long num_writes;
34*d4514f0bSApple OSS Distributions 	test_variant_t variant;
35*d4514f0bSApple OSS Distributions 	bool verbose;
36*d4514f0bSApple OSS Distributions } test_args_t;
37*d4514f0bSApple OSS Distributions 
38*d4514f0bSApple OSS Distributions typedef struct {
39*d4514f0bSApple OSS Distributions 	char _padding1[128];
40*d4514f0bSApple OSS Distributions 	atomic_bool tg_test_start;
41*d4514f0bSApple OSS Distributions 	atomic_ullong tg_num_writes_remaining;
42*d4514f0bSApple OSS Distributions 	atomic_ullong tg_threads_ready;
43*d4514f0bSApple OSS Distributions 	test_args_t tg_args;
44*d4514f0bSApple OSS Distributions 	uint64_t tg_start_time;
45*d4514f0bSApple OSS Distributions 	uint64_t tg_end_time;
46*d4514f0bSApple OSS Distributions 	uint64_t tg_start_value;
47*d4514f0bSApple OSS Distributions 	uint64_t tg_end_value;
48*d4514f0bSApple OSS Distributions 	char _padding2[128];
49*d4514f0bSApple OSS Distributions } test_globals_t;
50*d4514f0bSApple OSS Distributions 
51*d4514f0bSApple OSS Distributions static void parse_arguments(int argc, char** argv, test_args_t *args);
52*d4514f0bSApple OSS Distributions static const char *get_sysctl_name_for_test_variant(test_variant_t variant);
53*d4514f0bSApple OSS Distributions static void *writer(void *);
54*d4514f0bSApple OSS Distributions static uint64_t counter_read(test_variant_t);
55*d4514f0bSApple OSS Distributions 
56*d4514f0bSApple OSS Distributions int
main(int argc,char ** argv)57*d4514f0bSApple OSS Distributions main(int argc, char** argv)
58*d4514f0bSApple OSS Distributions {
59*d4514f0bSApple OSS Distributions 	test_globals_t globals = {0};
60*d4514f0bSApple OSS Distributions 	pthread_t* threads = NULL;
61*d4514f0bSApple OSS Distributions 	int ret;
62*d4514f0bSApple OSS Distributions 	int is_development_kernel;
63*d4514f0bSApple OSS Distributions 	size_t is_development_kernel_size = sizeof(is_development_kernel);
64*d4514f0bSApple OSS Distributions 	pthread_attr_t pthread_attrs;
65*d4514f0bSApple OSS Distributions 	uint64_t duration, writes_stored;
66*d4514f0bSApple OSS Distributions 	double writes_per_second;
67*d4514f0bSApple OSS Distributions 	double loss;
68*d4514f0bSApple OSS Distributions 
69*d4514f0bSApple OSS Distributions 	if (sysctlbyname("kern.development", &is_development_kernel,
70*d4514f0bSApple OSS Distributions 	    &is_development_kernel_size, NULL, 0) != 0 || !is_development_kernel) {
71*d4514f0bSApple OSS Distributions 		fprintf(stderr, "%s requires the development kernel\n", argv[0]);
72*d4514f0bSApple OSS Distributions 		exit(1);
73*d4514f0bSApple OSS Distributions 	}
74*d4514f0bSApple OSS Distributions 
75*d4514f0bSApple OSS Distributions 	parse_arguments(argc, argv, &(globals.tg_args));
76*d4514f0bSApple OSS Distributions 	atomic_store(&(globals.tg_num_writes_remaining), globals.tg_args.num_writes);
77*d4514f0bSApple OSS Distributions 
78*d4514f0bSApple OSS Distributions 	threads = malloc(sizeof(pthread_t) * globals.tg_args.n_threads);
79*d4514f0bSApple OSS Distributions 	assert(threads);
80*d4514f0bSApple OSS Distributions 	ret = pthread_attr_init(&pthread_attrs);
81*d4514f0bSApple OSS Distributions 	assert(ret == 0);
82*d4514f0bSApple OSS Distributions 	ret = init_scalable_counter_test();
83*d4514f0bSApple OSS Distributions 	assert(ret == 0);
84*d4514f0bSApple OSS Distributions 	globals.tg_start_value = counter_read(globals.tg_args.variant);
85*d4514f0bSApple OSS Distributions 	for (size_t i = 0; i < globals.tg_args.n_threads; i++) {
86*d4514f0bSApple OSS Distributions 		ret = pthread_create(threads + i, &pthread_attrs, writer, &globals);
87*d4514f0bSApple OSS Distributions 		assert(ret == 0);
88*d4514f0bSApple OSS Distributions 	}
89*d4514f0bSApple OSS Distributions 	for (size_t i = 0; i < globals.tg_args.n_threads; i++) {
90*d4514f0bSApple OSS Distributions 		ret = pthread_join(threads[i], NULL);
91*d4514f0bSApple OSS Distributions 		assert(ret == 0);
92*d4514f0bSApple OSS Distributions 	}
93*d4514f0bSApple OSS Distributions 	ret = fini_scalable_counter_test();
94*d4514f0bSApple OSS Distributions 	assert(ret == 0);
95*d4514f0bSApple OSS Distributions 	globals.tg_end_value = counter_read(globals.tg_args.variant);
96*d4514f0bSApple OSS Distributions 
97*d4514f0bSApple OSS Distributions 	duration = globals.tg_end_time - globals.tg_start_time;
98*d4514f0bSApple OSS Distributions 	printf("-----Results-----\n");
99*d4514f0bSApple OSS Distributions 	printf("rate,loss\n");
100*d4514f0bSApple OSS Distributions 	writes_per_second = globals.tg_args.num_writes / ((double) duration / kNumNanosecondsInSecond);
101*d4514f0bSApple OSS Distributions 	writes_stored = globals.tg_end_value - globals.tg_start_value;
102*d4514f0bSApple OSS Distributions 	loss = (1.0 - ((double) writes_stored / globals.tg_args.num_writes)) * 100;
103*d4514f0bSApple OSS Distributions 	printf("%.4f,%.4f\n", writes_per_second, loss);
104*d4514f0bSApple OSS Distributions 	return 0;
105*d4514f0bSApple OSS Distributions }
106*d4514f0bSApple OSS Distributions 
107*d4514f0bSApple OSS Distributions static void *
writer(void * arg)108*d4514f0bSApple OSS Distributions writer(void *arg)
109*d4514f0bSApple OSS Distributions {
110*d4514f0bSApple OSS Distributions 	int ret;
111*d4514f0bSApple OSS Distributions 	const char* sysctl_name;
112*d4514f0bSApple OSS Distributions 	test_globals_t *globals = arg;
113*d4514f0bSApple OSS Distributions 	int64_t value = kChunkSize;
114*d4514f0bSApple OSS Distributions 	//size_t size = sizeof(value);
115*d4514f0bSApple OSS Distributions 
116*d4514f0bSApple OSS Distributions 	sysctl_name = get_sysctl_name_for_test_variant(globals->tg_args.variant);
117*d4514f0bSApple OSS Distributions 	assert(sysctl_name != NULL);
118*d4514f0bSApple OSS Distributions 
119*d4514f0bSApple OSS Distributions 	if (atomic_fetch_add(&(globals->tg_threads_ready), 1) == globals->tg_args.n_threads - 1) {
120*d4514f0bSApple OSS Distributions 		globals->tg_start_time = current_timestamp_ns();
121*d4514f0bSApple OSS Distributions 		atomic_store(&globals->tg_test_start, true);
122*d4514f0bSApple OSS Distributions 	}
123*d4514f0bSApple OSS Distributions 	while (!atomic_load(&(globals->tg_test_start))) {
124*d4514f0bSApple OSS Distributions 		;
125*d4514f0bSApple OSS Distributions 	}
126*d4514f0bSApple OSS Distributions 
127*d4514f0bSApple OSS Distributions 	while (true) {
128*d4514f0bSApple OSS Distributions 		unsigned long long remaining = atomic_fetch_sub(&(globals->tg_num_writes_remaining), value);
129*d4514f0bSApple OSS Distributions 		if (remaining < kChunkSize || remaining > globals->tg_args.num_writes) {
130*d4514f0bSApple OSS Distributions 			break;
131*d4514f0bSApple OSS Distributions 		}
132*d4514f0bSApple OSS Distributions 
133*d4514f0bSApple OSS Distributions 		ret = sysctlbyname(sysctl_name, NULL, NULL, &value, sizeof(value));
134*d4514f0bSApple OSS Distributions 		assert(ret == 0);
135*d4514f0bSApple OSS Distributions 		if (remaining == kChunkSize || remaining - kChunkSize > remaining) {
136*d4514f0bSApple OSS Distributions 			break;
137*d4514f0bSApple OSS Distributions 		}
138*d4514f0bSApple OSS Distributions 	}
139*d4514f0bSApple OSS Distributions 
140*d4514f0bSApple OSS Distributions 	if (atomic_fetch_sub(&(globals->tg_threads_ready), 1) == 1) {
141*d4514f0bSApple OSS Distributions 		globals->tg_end_time = current_timestamp_ns();
142*d4514f0bSApple OSS Distributions 	}
143*d4514f0bSApple OSS Distributions 
144*d4514f0bSApple OSS Distributions 	return NULL;
145*d4514f0bSApple OSS Distributions }
146*d4514f0bSApple OSS Distributions 
147*d4514f0bSApple OSS Distributions static const char*
get_sysctl_name_for_test_variant(test_variant_t variant)148*d4514f0bSApple OSS Distributions get_sysctl_name_for_test_variant(test_variant_t variant)
149*d4514f0bSApple OSS Distributions {
150*d4514f0bSApple OSS Distributions 	switch (variant) {
151*d4514f0bSApple OSS Distributions 	case VARIANT_SCALABLE_COUNTER:
152*d4514f0bSApple OSS Distributions 		return "kern.scalable_counter_write_benchmark";
153*d4514f0bSApple OSS Distributions 	case VARIANT_ATOMIC:
154*d4514f0bSApple OSS Distributions 		return "kern.scalable_counter_atomic_counter_write_benchmark";
155*d4514f0bSApple OSS Distributions 	case VARIANT_RACY:
156*d4514f0bSApple OSS Distributions 		return "kern.scalable_counter_racy_counter_benchmark";
157*d4514f0bSApple OSS Distributions 	default:
158*d4514f0bSApple OSS Distributions 		return NULL;
159*d4514f0bSApple OSS Distributions 	}
160*d4514f0bSApple OSS Distributions }
161*d4514f0bSApple OSS Distributions 
162*d4514f0bSApple OSS Distributions static const char*
get_sysctl_load_name_for_test_variant(test_variant_t variant)163*d4514f0bSApple OSS Distributions get_sysctl_load_name_for_test_variant(test_variant_t variant)
164*d4514f0bSApple OSS Distributions {
165*d4514f0bSApple OSS Distributions 	switch (variant) {
166*d4514f0bSApple OSS Distributions 	case VARIANT_SCALABLE_COUNTER:
167*d4514f0bSApple OSS Distributions 		return "kern.scalable_counter_test_load";
168*d4514f0bSApple OSS Distributions 	case VARIANT_ATOMIC:
169*d4514f0bSApple OSS Distributions 		return "kern.scalable_counter_atomic_counter_load";
170*d4514f0bSApple OSS Distributions 	case VARIANT_RACY:
171*d4514f0bSApple OSS Distributions 		return "kern.scalable_counter_racy_counter_load";
172*d4514f0bSApple OSS Distributions 	default:
173*d4514f0bSApple OSS Distributions 		return NULL;
174*d4514f0bSApple OSS Distributions 	}
175*d4514f0bSApple OSS Distributions }
176*d4514f0bSApple OSS Distributions 
177*d4514f0bSApple OSS Distributions static uint64_t
counter_read(test_variant_t variant)178*d4514f0bSApple OSS Distributions counter_read(test_variant_t variant)
179*d4514f0bSApple OSS Distributions {
180*d4514f0bSApple OSS Distributions 	const char *sysctl_name = get_sysctl_load_name_for_test_variant(variant);
181*d4514f0bSApple OSS Distributions 	int result;
182*d4514f0bSApple OSS Distributions 	uint64_t value;
183*d4514f0bSApple OSS Distributions 	size_t size = sizeof(value);
184*d4514f0bSApple OSS Distributions 	result = sysctlbyname(sysctl_name, &value, &size, NULL, 0);
185*d4514f0bSApple OSS Distributions 	assert(result == 0);
186*d4514f0bSApple OSS Distributions 	return value;
187*d4514f0bSApple OSS Distributions }
188*d4514f0bSApple OSS Distributions 
189*d4514f0bSApple OSS Distributions static void
print_help(char ** argv)190*d4514f0bSApple OSS Distributions print_help(char** argv)
191*d4514f0bSApple OSS Distributions {
192*d4514f0bSApple OSS Distributions 	fprintf(stderr, "%s: <test-variant> [-v] num_writes num_threads\n", argv[0]);
193*d4514f0bSApple OSS Distributions 	fprintf(stderr, "\ntest variants:\n");
194*d4514f0bSApple OSS Distributions 	fprintf(stderr, "	%s	Benchmark scalable counters.\n", kScalableCounterArgument);
195*d4514f0bSApple OSS Distributions 	fprintf(stderr, "	%s	Benchmark single atomic counter.\n", kAtomicCounterArgument);
196*d4514f0bSApple OSS Distributions 	fprintf(stderr, "	%s	Benchmark racy counter.\n", kRacyCounterArgument);
197*d4514f0bSApple OSS Distributions }
198*d4514f0bSApple OSS Distributions 
199*d4514f0bSApple OSS Distributions static void
parse_arguments(int argc,char ** argv,test_args_t * args)200*d4514f0bSApple OSS Distributions parse_arguments(int argc, char** argv, test_args_t *args)
201*d4514f0bSApple OSS Distributions {
202*d4514f0bSApple OSS Distributions 	int current_argument = 1;
203*d4514f0bSApple OSS Distributions 	memset(args, 0, sizeof(test_args_t));
204*d4514f0bSApple OSS Distributions 	if (argc < 4 || argc > 6) {
205*d4514f0bSApple OSS Distributions 		print_help(argv);
206*d4514f0bSApple OSS Distributions 		exit(1);
207*d4514f0bSApple OSS Distributions 	}
208*d4514f0bSApple OSS Distributions 	if (argv[current_argument][0] == '-') {
209*d4514f0bSApple OSS Distributions 		if (strcmp(argv[current_argument], "-v") == 0) {
210*d4514f0bSApple OSS Distributions 			args->verbose = true;
211*d4514f0bSApple OSS Distributions 		} else {
212*d4514f0bSApple OSS Distributions 			fprintf(stderr, "Unknown argument %s\n", argv[current_argument]);
213*d4514f0bSApple OSS Distributions 			print_help(argv);
214*d4514f0bSApple OSS Distributions 			exit(1);
215*d4514f0bSApple OSS Distributions 		}
216*d4514f0bSApple OSS Distributions 		current_argument++;
217*d4514f0bSApple OSS Distributions 	}
218*d4514f0bSApple OSS Distributions 	if (strncasecmp(argv[current_argument], kScalableCounterArgument, strlen(kScalableCounterArgument)) == 0) {
219*d4514f0bSApple OSS Distributions 		args->variant = VARIANT_SCALABLE_COUNTER;
220*d4514f0bSApple OSS Distributions 	} else if (strncasecmp(argv[current_argument], kAtomicCounterArgument, strlen(kAtomicCounterArgument)) == 0) {
221*d4514f0bSApple OSS Distributions 		args->variant = VARIANT_ATOMIC;
222*d4514f0bSApple OSS Distributions 	} else if (strncasecmp(argv[current_argument], kRacyCounterArgument, strlen(kRacyCounterArgument)) == 0) {
223*d4514f0bSApple OSS Distributions 		args->variant = VARIANT_RACY;
224*d4514f0bSApple OSS Distributions 	} else {
225*d4514f0bSApple OSS Distributions 		print_help(argv);
226*d4514f0bSApple OSS Distributions 		exit(1);
227*d4514f0bSApple OSS Distributions 	}
228*d4514f0bSApple OSS Distributions 	current_argument++;
229*d4514f0bSApple OSS Distributions 
230*d4514f0bSApple OSS Distributions 	long num_writes = strtol(argv[current_argument++], NULL, 10);
231*d4514f0bSApple OSS Distributions 	if (num_writes == 0) {
232*d4514f0bSApple OSS Distributions 		print_help(argv);
233*d4514f0bSApple OSS Distributions 		exit(1);
234*d4514f0bSApple OSS Distributions 	}
235*d4514f0bSApple OSS Distributions 	long num_cores = strtol(argv[current_argument++], NULL, 10);
236*d4514f0bSApple OSS Distributions 	if (num_cores == 0) {
237*d4514f0bSApple OSS Distributions 		print_help(argv);
238*d4514f0bSApple OSS Distributions 		exit(1);
239*d4514f0bSApple OSS Distributions 	}
240*d4514f0bSApple OSS Distributions 	assert(num_cores > 0 && num_cores <= get_ncpu());
241*d4514f0bSApple OSS Distributions 	args->n_threads = (unsigned int) num_cores;
242*d4514f0bSApple OSS Distributions 	args->num_writes = (unsigned long long) num_writes;
243*d4514f0bSApple OSS Distributions }
244