xref: /linux/tools/testing/selftests/resctrl/resctrl_val.c (revision a7f2fe32a8066f28c2f5ad90441cc6efc3aa8272)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Memory bandwidth monitoring and allocation library
4  *
5  * Copyright (C) 2018 Intel Corporation
6  *
7  * Authors:
8  *    Sai Praneeth Prakhya <sai.praneeth.prakhya@intel.com>,
9  *    Fenghua Yu <fenghua.yu@intel.com>
10  */
11 #include "resctrl.h"
12 
13 #define UNCORE_IMC		"uncore_imc"
14 #define READ_FILE_NAME		"cas_count_read"
15 #define DYN_PMU_PATH		"/sys/bus/event_source/devices"
16 #define SCALE			0.00006103515625
17 #define MAX_IMCS		40
18 #define MAX_TOKENS		5
19 
20 #define CON_MBM_LOCAL_BYTES_PATH		\
21 	"%s/%s/mon_data/mon_L3_%02d/mbm_local_bytes"
22 
23 struct membw_read_format {
24 	__u64 value;         /* The value of the event */
25 	__u64 time_enabled;  /* if PERF_FORMAT_TOTAL_TIME_ENABLED */
26 	__u64 time_running;  /* if PERF_FORMAT_TOTAL_TIME_RUNNING */
27 	__u64 id;            /* if PERF_FORMAT_ID */
28 };
29 
30 struct imc_counter_config {
31 	struct list_head entry;
32 	__u32 type;
33 	__u64 event;
34 	__u64 umask;
35 	struct perf_event_attr pe;
36 	int fd;
37 };
38 
39 static char mbm_total_path[1024];
40 static int imcs;
41 static struct imc_counter_config imc_counters_config[MAX_IMCS];
42 LIST_HEAD(imc_counters_list);
43 static const struct resctrl_test *current_test;
44 
45 static void read_mem_bw_initialize_perf_event_attr(struct imc_counter_config *imc_counter)
46 {
47 	memset(&imc_counter->pe, 0, sizeof(struct perf_event_attr));
48 	imc_counter->pe.type = imc_counter->type;
49 	imc_counter->pe.size = sizeof(struct perf_event_attr);
50 	imc_counter->pe.disabled = 1;
51 	imc_counter->pe.inherit = 1;
52 	imc_counter->pe.exclude_guest = 0;
53 	imc_counter->pe.config = imc_counter->umask << 8 | imc_counter->event;
54 	imc_counter->pe.sample_type = PERF_SAMPLE_IDENTIFIER;
55 	imc_counter->pe.read_format =
56 		PERF_FORMAT_TOTAL_TIME_ENABLED | PERF_FORMAT_TOTAL_TIME_RUNNING;
57 }
58 
59 static void read_mem_bw_ioctl_perf_event_ioc_reset_enable(struct imc_counter_config *imc_counter)
60 {
61 	ioctl(imc_counter->fd, PERF_EVENT_IOC_RESET, 0);
62 	ioctl(imc_counter->fd, PERF_EVENT_IOC_ENABLE, 0);
63 }
64 
65 static void read_mem_bw_ioctl_perf_event_ioc_disable(struct imc_counter_config *imc_counter)
66 {
67 	ioctl(imc_counter->fd, PERF_EVENT_IOC_DISABLE, 0);
68 }
69 
70 /*
71  * get_read_event_and_umask:	Parse config into event and umask
72  * @cas_count_cfg:	Config
73  * @imc_counter:	iMC counter config
74  */
75 static void get_read_event_and_umask(char *cas_count_cfg, struct imc_counter_config *imc_counter)
76 {
77 	char *token[MAX_TOKENS];
78 	int i = 0;
79 
80 	token[0] = strtok(cas_count_cfg, "=,");
81 
82 	for (i = 1; i < MAX_TOKENS; i++)
83 		token[i] = strtok(NULL, "=,");
84 
85 	for (i = 0; i < MAX_TOKENS - 1; i++) {
86 		if (!token[i])
87 			break;
88 		if (strcmp(token[i], "event") == 0)
89 			imc_counter->event = strtol(token[i + 1], NULL, 16);
90 		if (strcmp(token[i], "umask") == 0)
91 			imc_counter->umask = strtol(token[i + 1], NULL, 16);
92 	}
93 }
94 
95 static int open_perf_read_event(int cpu_no, struct imc_counter_config *imc_counter)
96 {
97 	imc_counter->fd = perf_event_open(&imc_counter->pe, -1, cpu_no, -1,
98 					  PERF_FLAG_FD_CLOEXEC);
99 
100 	if (imc_counter->fd == -1) {
101 		fprintf(stderr, "Error opening leader %llx\n",
102 			imc_counter->pe.config);
103 
104 		return -1;
105 	}
106 
107 	return 0;
108 }
109 
110 static int parse_imc_read_bw_events(char *imc_dir, unsigned int type,
111 				    unsigned int *count)
112 {
113 	char imc_events_dir[PATH_MAX], imc_counter_cfg[PATH_MAX];
114 	struct imc_counter_config *imc_counter;
115 	unsigned int orig_count = *count;
116 	char cas_count_cfg[1024];
117 	struct dirent *ep;
118 	int path_len;
119 	int ret = -1;
120 	int num_cfg;
121 	FILE *fp;
122 	DIR *dp;
123 
124 	path_len = snprintf(imc_events_dir, sizeof(imc_events_dir), "%sevents",
125 			    imc_dir);
126 	if (path_len >= sizeof(imc_events_dir)) {
127 		ksft_print_msg("Unable to create path to %sevents\n", imc_dir);
128 		goto out;
129 	}
130 
131 	dp = opendir(imc_events_dir);
132 	if (!dp) {
133 		ksft_perror("Unable to open PMU events directory");
134 		goto out;
135 	}
136 
137 	while ((ep = readdir(dp))) {
138 		/*
139 		 * Parse all event files with READ_FILE_NAME prefix that
140 		 * contain the event number and umask. Skip files containing
141 		 * "." that contain unused properties of event.
142 		 */
143 		if (!strstr(ep->d_name, READ_FILE_NAME) ||
144 		    strchr(ep->d_name, '.'))
145 			continue;
146 
147 		path_len = snprintf(imc_counter_cfg, sizeof(imc_counter_cfg),
148 				    "%s/%s", imc_events_dir, ep->d_name);
149 		if (path_len >= sizeof(imc_counter_cfg)) {
150 			ksft_print_msg("Unable to create path to %s/%s\n",
151 				       imc_events_dir, ep->d_name);
152 			goto out_close;
153 		}
154 		fp = fopen(imc_counter_cfg, "r");
155 		if (!fp) {
156 			ksft_perror("Failed to open iMC config file");
157 			goto out_close;
158 		}
159 		num_cfg = fscanf(fp, "%1023s", cas_count_cfg);
160 		fclose(fp);
161 		if (num_cfg <= 0) {
162 			ksft_perror("Could not get iMC cas count read");
163 			goto out_close;
164 		}
165 		if (*count >= MAX_IMCS) {
166 			ksft_print_msg("Maximum iMC count exceeded\n");
167 			goto out_close;
168 		}
169 		imc_counter = calloc(1, sizeof(*imc_counter));
170 		if (!imc_counter) {
171 			ksft_perror("Unable to allocate memory for iMC counters");
172 			goto out_close;
173 		}
174 
175 		imc_counters_config[*count].type = type;
176 		get_read_event_and_umask(cas_count_cfg, &imc_counters_config[*count]);
177 		/* Do not fail after incrementing *count. */
178 		*count += 1;
179 		list_add(&imc_counter->entry, &imc_counters_list);
180 	}
181 	if (*count == orig_count) {
182 		ksft_print_msg("Unable to find events in %s\n", imc_events_dir);
183 		goto out_close;
184 	}
185 	ret = 0;
186 out_close:
187 	closedir(dp);
188 out:
189 	if (ret)
190 		cleanup_read_mem_bw_imc();
191 
192 	return ret;
193 }
194 
195 /* Get type and config of an iMC counter's read event. */
196 static int read_from_imc_dir(char *imc_dir, unsigned int *count)
197 {
198 	char imc_counter_type[PATH_MAX];
199 	unsigned int type;
200 	int path_len;
201 	FILE *fp;
202 	int ret;
203 
204 	/* Get type of iMC counter */
205 	path_len = snprintf(imc_counter_type, sizeof(imc_counter_type),
206 			    "%s%s", imc_dir, "type");
207 	if (path_len >= sizeof(imc_counter_type)) {
208 		ksft_print_msg("Unable to create path to %s%s\n",
209 			       imc_dir, "type");
210 		return -1;
211 	}
212 	fp = fopen(imc_counter_type, "r");
213 	if (!fp) {
214 		ksft_perror("Failed to open iMC counter type file");
215 
216 		return -1;
217 	}
218 	ret = fscanf(fp, "%u", &type);
219 	fclose(fp);
220 	if (ret <= 0) {
221 		ksft_perror("Could not get iMC type");
222 		return -1;
223 	}
224 	ret = parse_imc_read_bw_events(imc_dir, type, count);
225 	if (ret) {
226 		ksft_print_msg("Unable to parse bandwidth event and umask\n");
227 		return ret;
228 	}
229 
230 	return 0;
231 }
232 
233 /*
234  * A system can have 'n' number of iMC (Integrated Memory Controller)
235  * counters, get that 'n'. Discover the properties of the available
236  * counters in support of needed performance measurement via perf.
237  * For each iMC counter get it's type and config. Also obtain each
238  * counter's event and umask for the memory read events that will be
239  * measured.
240  *
241  * Enumerate all these details into an array of structures.
242  *
243  * Return: >= 0 on success. < 0 on failure.
244  */
245 static int num_of_imcs(void)
246 {
247 	char imc_dir[512], *temp;
248 	unsigned int count = 0;
249 	struct dirent *ep;
250 	int ret;
251 	DIR *dp;
252 
253 	dp = opendir(DYN_PMU_PATH);
254 	if (dp) {
255 		while ((ep = readdir(dp))) {
256 			temp = strstr(ep->d_name, UNCORE_IMC);
257 			if (!temp)
258 				continue;
259 
260 			/*
261 			 * imc counters are named as "uncore_imc_<n>", hence
262 			 * increment the pointer to point to <n>. Note that
263 			 * sizeof(UNCORE_IMC) would count for null character as
264 			 * well and hence the last underscore character in
265 			 * uncore_imc'_' need not be counted.
266 			 */
267 			temp = temp + sizeof(UNCORE_IMC);
268 
269 			/*
270 			 * Some directories under "DYN_PMU_PATH" could have
271 			 * names like "uncore_imc_free_running", hence, check if
272 			 * first character is a numerical digit or not.
273 			 */
274 			if (temp[0] >= '0' && temp[0] <= '9') {
275 				sprintf(imc_dir, "%s/%s/", DYN_PMU_PATH,
276 					ep->d_name);
277 				ret = read_from_imc_dir(imc_dir, &count);
278 				if (ret) {
279 					closedir(dp);
280 
281 					return ret;
282 				}
283 			}
284 		}
285 		closedir(dp);
286 		if (count == 0) {
287 			ksft_print_msg("Unable to find iMC counters\n");
288 
289 			return -1;
290 		}
291 	} else {
292 		ksft_perror("Unable to open PMU directory");
293 
294 		return -1;
295 	}
296 
297 	return count;
298 }
299 
300 int initialize_read_mem_bw_imc(void)
301 {
302 	int imc;
303 
304 	imcs = num_of_imcs();
305 	if (imcs <= 0)
306 		return imcs;
307 
308 	/* Initialize perf_event_attr structures for all iMC's */
309 	for (imc = 0; imc < imcs; imc++)
310 		read_mem_bw_initialize_perf_event_attr(&imc_counters_config[imc]);
311 
312 	return 0;
313 }
314 
315 void cleanup_read_mem_bw_imc(void)
316 {
317 	struct imc_counter_config *imc_counter, *tmp;
318 
319 	list_for_each_entry_safe(imc_counter, tmp, &imc_counters_list, entry) {
320 		list_del(&imc_counter->entry);
321 		free(imc_counter);
322 	}
323 }
324 
325 static void perf_close_imc_read_mem_bw(void)
326 {
327 	int mc;
328 
329 	for (mc = 0; mc < imcs; mc++) {
330 		if (imc_counters_config[mc].fd != -1)
331 			close(imc_counters_config[mc].fd);
332 	}
333 }
334 
335 /*
336  * perf_open_imc_read_mem_bw - Open perf fds for IMCs
337  * @cpu_no: CPU number that the benchmark PID is bound to
338  *
339  * Return: = 0 on success. < 0 on failure.
340  */
341 static int perf_open_imc_read_mem_bw(int cpu_no)
342 {
343 	int imc, ret;
344 
345 	for (imc = 0; imc < imcs; imc++)
346 		imc_counters_config[imc].fd = -1;
347 
348 	for (imc = 0; imc < imcs; imc++) {
349 		ret = open_perf_read_event(cpu_no, &imc_counters_config[imc]);
350 		if (ret)
351 			goto close_fds;
352 	}
353 
354 	return 0;
355 
356 close_fds:
357 	perf_close_imc_read_mem_bw();
358 	return -1;
359 }
360 
361 /*
362  * do_imc_read_mem_bw_test - Perform memory bandwidth test
363  *
364  * Runs memory bandwidth test over one second period. Also, handles starting
365  * and stopping of the IMC perf counters around the test.
366  */
367 static void do_imc_read_mem_bw_test(void)
368 {
369 	int imc;
370 
371 	for (imc = 0; imc < imcs; imc++)
372 		read_mem_bw_ioctl_perf_event_ioc_reset_enable(&imc_counters_config[imc]);
373 
374 	sleep(1);
375 
376 	/* Stop counters after a second to get results. */
377 	for (imc = 0; imc < imcs; imc++)
378 		read_mem_bw_ioctl_perf_event_ioc_disable(&imc_counters_config[imc]);
379 }
380 
381 /*
382  * get_read_mem_bw_imc - Memory read bandwidth as reported by iMC counters
383  *
384  * Memory read bandwidth utilized by a process on a socket can be calculated
385  * using iMC counters' read events. Perf events are used to read these
386  * counters.
387  *
388  * Return: = 0 on success. < 0 on failure.
389  */
390 static int get_read_mem_bw_imc(float *bw_imc)
391 {
392 	float reads = 0, of_mul_read = 1;
393 	int imc;
394 
395 	/*
396 	 * Log read event values from all iMC counters into
397 	 * struct imc_counter_config.
398 	 * Take overflow into consideration before calculating total bandwidth.
399 	 */
400 	for (imc = 0; imc < imcs; imc++) {
401 		struct membw_read_format measurement;
402 		struct imc_counter_config *r =
403 			&imc_counters_config[imc];
404 
405 		if (read(r->fd, &measurement, sizeof(measurement)) == -1) {
406 			ksft_perror("Couldn't get read bandwidth through iMC");
407 			return -1;
408 		}
409 
410 		__u64 r_time_enabled = measurement.time_enabled;
411 		__u64 r_time_running = measurement.time_running;
412 
413 		if (r_time_enabled != r_time_running)
414 			of_mul_read = (float)r_time_enabled /
415 					(float)r_time_running;
416 
417 		reads += measurement.value * of_mul_read * SCALE;
418 	}
419 
420 	*bw_imc = reads;
421 	return 0;
422 }
423 
424 /*
425  * initialize_mem_bw_resctrl:	Appropriately populate "mbm_total_path"
426  * @param:	Parameters passed to resctrl_val()
427  * @domain_id:	Domain ID (cache ID; for MB, L3 cache ID)
428  */
429 void initialize_mem_bw_resctrl(const struct resctrl_val_param *param,
430 			       int domain_id)
431 {
432 	sprintf(mbm_total_path, CON_MBM_LOCAL_BYTES_PATH, RESCTRL_PATH,
433 		param->ctrlgrp, domain_id);
434 }
435 
436 /*
437  * Open file to read MBM local bytes from resctrl FS
438  */
439 static FILE *open_mem_bw_resctrl(const char *mbm_bw_file)
440 {
441 	FILE *fp;
442 
443 	fp = fopen(mbm_bw_file, "r");
444 	if (!fp)
445 		ksft_perror("Failed to open total memory bandwidth file");
446 
447 	return fp;
448 }
449 
450 /*
451  * Get MBM Local bytes as reported by resctrl FS
452  */
453 static int get_mem_bw_resctrl(FILE *fp, unsigned long *mbm_total)
454 {
455 	if (fscanf(fp, "%lu\n", mbm_total) <= 0) {
456 		ksft_perror("Could not get MBM local bytes");
457 		return -1;
458 	}
459 	return 0;
460 }
461 
462 static pid_t bm_pid;
463 
464 void ctrlc_handler(int signum, siginfo_t *info, void *ptr)
465 {
466 	/* Only kill child after bm_pid is set after fork() */
467 	if (bm_pid)
468 		kill(bm_pid, SIGKILL);
469 	umount_resctrlfs();
470 	if (current_test && current_test->cleanup)
471 		current_test->cleanup();
472 	ksft_print_msg("Ending\n\n");
473 
474 	exit(EXIT_SUCCESS);
475 }
476 
477 /*
478  * Register CTRL-C handler for parent, as it has to kill
479  * child process before exiting.
480  */
481 int signal_handler_register(const struct resctrl_test *test)
482 {
483 	struct sigaction sigact = {};
484 	int ret = 0;
485 
486 	bm_pid = 0;
487 
488 	current_test = test;
489 	sigact.sa_sigaction = ctrlc_handler;
490 	sigemptyset(&sigact.sa_mask);
491 	sigact.sa_flags = SA_SIGINFO;
492 	if (sigaction(SIGINT, &sigact, NULL) ||
493 	    sigaction(SIGTERM, &sigact, NULL) ||
494 	    sigaction(SIGHUP, &sigact, NULL)) {
495 		ksft_perror("sigaction");
496 		ret = -1;
497 	}
498 	return ret;
499 }
500 
501 /*
502  * Reset signal handler to SIG_DFL.
503  * Non-Value return because the caller should keep
504  * the error code of other path even if sigaction fails.
505  */
506 void signal_handler_unregister(void)
507 {
508 	struct sigaction sigact = {};
509 
510 	current_test = NULL;
511 	sigact.sa_handler = SIG_DFL;
512 	sigemptyset(&sigact.sa_mask);
513 	if (sigaction(SIGINT, &sigact, NULL) ||
514 	    sigaction(SIGTERM, &sigact, NULL) ||
515 	    sigaction(SIGHUP, &sigact, NULL)) {
516 		ksft_perror("sigaction");
517 	}
518 }
519 
520 /*
521  * print_results_bw:	the memory bandwidth results are stored in a file
522  * @filename:		file that stores the results
523  * @bm_pid:		child pid that runs benchmark
524  * @bw_imc:		perf imc counter value
525  * @bw_resc:		memory bandwidth value
526  *
527  * Return:		0 on success, < 0 on error.
528  */
529 static int print_results_bw(char *filename, pid_t bm_pid, float bw_imc,
530 			    unsigned long bw_resc)
531 {
532 	unsigned long diff = fabs(bw_imc - bw_resc);
533 	FILE *fp;
534 
535 	if (strcmp(filename, "stdio") == 0 || strcmp(filename, "stderr") == 0) {
536 		printf("Pid: %d \t Mem_BW_iMC: %f \t ", (int)bm_pid, bw_imc);
537 		printf("Mem_BW_resc: %lu \t Difference: %lu\n", bw_resc, diff);
538 	} else {
539 		fp = fopen(filename, "a");
540 		if (!fp) {
541 			ksft_perror("Cannot open results file");
542 
543 			return -1;
544 		}
545 		if (fprintf(fp, "Pid: %d \t Mem_BW_iMC: %f \t Mem_BW_resc: %lu \t Difference: %lu\n",
546 			    (int)bm_pid, bw_imc, bw_resc, diff) <= 0) {
547 			ksft_print_msg("Could not log results\n");
548 			fclose(fp);
549 
550 			return -1;
551 		}
552 		fclose(fp);
553 	}
554 
555 	return 0;
556 }
557 
558 /*
559  * measure_read_mem_bw - Measures read memory bandwidth numbers while benchmark runs
560  * @uparams:		User supplied parameters
561  * @param:		Parameters passed to resctrl_val()
562  * @bm_pid:		PID that runs the benchmark
563  *
564  * Measure memory bandwidth from resctrl and from another source which is
565  * perf imc value or could be something else if perf imc event is not
566  * available. Compare the two values to validate resctrl value. It takes
567  * 1 sec to measure the data.
568  * resctrl does not distinguish between read and write operations so
569  * its data includes all memory operations.
570  */
571 int measure_read_mem_bw(const struct user_params *uparams,
572 			struct resctrl_val_param *param, pid_t bm_pid)
573 {
574 	unsigned long bw_resc, bw_resc_start, bw_resc_end;
575 	FILE *mem_bw_fp;
576 	float bw_imc;
577 	int ret;
578 
579 	mem_bw_fp = open_mem_bw_resctrl(mbm_total_path);
580 	if (!mem_bw_fp)
581 		return -1;
582 
583 	ret = perf_open_imc_read_mem_bw(uparams->cpu);
584 	if (ret < 0)
585 		goto close_fp;
586 
587 	ret = get_mem_bw_resctrl(mem_bw_fp, &bw_resc_start);
588 	if (ret < 0)
589 		goto close_imc;
590 
591 	rewind(mem_bw_fp);
592 
593 	do_imc_read_mem_bw_test();
594 
595 	ret = get_mem_bw_resctrl(mem_bw_fp, &bw_resc_end);
596 	if (ret < 0)
597 		goto close_imc;
598 
599 	ret = get_read_mem_bw_imc(&bw_imc);
600 	if (ret < 0)
601 		goto close_imc;
602 
603 	perf_close_imc_read_mem_bw();
604 	fclose(mem_bw_fp);
605 
606 	bw_resc = (bw_resc_end - bw_resc_start) / MB;
607 
608 	return print_results_bw(param->filename, bm_pid, bw_imc, bw_resc);
609 
610 close_imc:
611 	perf_close_imc_read_mem_bw();
612 close_fp:
613 	fclose(mem_bw_fp);
614 	return ret;
615 }
616 
617 /*
618  * resctrl_val:	execute benchmark and measure memory bandwidth on
619  *			the benchmark
620  * @test:		test information structure
621  * @uparams:		user supplied parameters
622  * @param:		parameters passed to resctrl_val()
623  *
624  * Return:		0 when the test was run, < 0 on error.
625  */
626 int resctrl_val(const struct resctrl_test *test,
627 		const struct user_params *uparams,
628 		struct resctrl_val_param *param)
629 {
630 	unsigned char *buf = NULL;
631 	cpu_set_t old_affinity;
632 	int domain_id;
633 	int ret = 0;
634 	pid_t ppid;
635 
636 	if (strcmp(param->filename, "") == 0)
637 		sprintf(param->filename, "stdio");
638 
639 	ret = get_domain_id(test->resource, uparams->cpu, &domain_id);
640 	if (ret < 0) {
641 		ksft_print_msg("Could not get domain ID\n");
642 		return ret;
643 	}
644 
645 	ppid = getpid();
646 
647 	/* Taskset test to specified CPU. */
648 	ret = taskset_benchmark(ppid, uparams->cpu, &old_affinity);
649 	if (ret)
650 		return ret;
651 
652 	/* Write test to specified control & monitoring group in resctrl FS. */
653 	ret = write_bm_pid_to_resctrl(ppid, param->ctrlgrp, param->mongrp);
654 	if (ret)
655 		goto reset_affinity;
656 
657 	if (param->init) {
658 		ret = param->init(test, uparams, param, domain_id);
659 		if (ret)
660 			goto reset_affinity;
661 	}
662 
663 	/*
664 	 * If not running user provided benchmark, run the default
665 	 * "fill_buf". First phase of "fill_buf" is to prepare the
666 	 * buffer that the benchmark will operate on. No measurements
667 	 * are needed during this phase and prepared memory will be
668 	 * passed to next part of benchmark via copy-on-write thus
669 	 * no impact on the benchmark that relies on reading from
670 	 * memory only.
671 	 */
672 	if (param->fill_buf) {
673 		buf = alloc_buffer(param->fill_buf->buf_size,
674 				   param->fill_buf->memflush);
675 		if (!buf) {
676 			ret = -ENOMEM;
677 			goto reset_affinity;
678 		}
679 	}
680 
681 	fflush(stdout);
682 	bm_pid = fork();
683 	if (bm_pid == -1) {
684 		ret = -errno;
685 		ksft_perror("Unable to fork");
686 		goto free_buf;
687 	}
688 
689 	/*
690 	 * What needs to be measured runs in separate process until
691 	 * terminated.
692 	 */
693 	if (bm_pid == 0) {
694 		if (param->fill_buf)
695 			fill_cache_read(buf, param->fill_buf->buf_size, false);
696 		else if (uparams->benchmark_cmd[0])
697 			execvp(uparams->benchmark_cmd[0], (char **)uparams->benchmark_cmd);
698 		exit(EXIT_SUCCESS);
699 	}
700 
701 	ksft_print_msg("Benchmark PID: %d\n", (int)bm_pid);
702 
703 	/* Give benchmark enough time to fully run. */
704 	sleep(1);
705 
706 	/* Test runs until the callback setup() tells the test to stop. */
707 	while (1) {
708 		ret = param->setup(test, uparams, param);
709 		if (ret == END_OF_TESTS) {
710 			ret = 0;
711 			break;
712 		}
713 		if (ret < 0)
714 			break;
715 
716 		ret = param->measure(uparams, param, bm_pid);
717 		if (ret)
718 			break;
719 	}
720 
721 	kill(bm_pid, SIGKILL);
722 free_buf:
723 	free(buf);
724 reset_affinity:
725 	taskset_restore(ppid, &old_affinity);
726 	return ret;
727 }
728