xref: /openbmc/linux/tools/testing/selftests/powerpc/pmu/lib.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
1f50a7f3dSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
23752e453SMichael Ellerman /*
33752e453SMichael Ellerman  * Copyright 2014, Michael Ellerman, IBM Corp.
43752e453SMichael Ellerman  */
53752e453SMichael Ellerman 
63752e453SMichael Ellerman #define _GNU_SOURCE	/* For CPU_ZERO etc. */
73752e453SMichael Ellerman 
83752e453SMichael Ellerman #include <errno.h>
93752e453SMichael Ellerman #include <sched.h>
103752e453SMichael Ellerman #include <setjmp.h>
113752e453SMichael Ellerman #include <stdlib.h>
123752e453SMichael Ellerman #include <sys/wait.h>
133752e453SMichael Ellerman 
143752e453SMichael Ellerman #include "utils.h"
153752e453SMichael Ellerman #include "lib.h"
163752e453SMichael Ellerman 
173752e453SMichael Ellerman #define PARENT_TOKEN	0xAA
183752e453SMichael Ellerman #define CHILD_TOKEN	0x55
193752e453SMichael Ellerman 
sync_with_child(union pipe read_pipe,union pipe write_pipe)203752e453SMichael Ellerman int sync_with_child(union pipe read_pipe, union pipe write_pipe)
213752e453SMichael Ellerman {
223752e453SMichael Ellerman 	char c = PARENT_TOKEN;
233752e453SMichael Ellerman 
243752e453SMichael Ellerman 	FAIL_IF(write(write_pipe.write_fd, &c, 1) != 1);
253752e453SMichael Ellerman 	FAIL_IF(read(read_pipe.read_fd, &c, 1) != 1);
263752e453SMichael Ellerman 	if (c != CHILD_TOKEN) /* sometimes expected */
273752e453SMichael Ellerman 		return 1;
283752e453SMichael Ellerman 
293752e453SMichael Ellerman 	return 0;
303752e453SMichael Ellerman }
313752e453SMichael Ellerman 
wait_for_parent(union pipe read_pipe)323752e453SMichael Ellerman int wait_for_parent(union pipe read_pipe)
333752e453SMichael Ellerman {
343752e453SMichael Ellerman 	char c;
353752e453SMichael Ellerman 
363752e453SMichael Ellerman 	FAIL_IF(read(read_pipe.read_fd, &c, 1) != 1);
373752e453SMichael Ellerman 	FAIL_IF(c != PARENT_TOKEN);
383752e453SMichael Ellerman 
393752e453SMichael Ellerman 	return 0;
403752e453SMichael Ellerman }
413752e453SMichael Ellerman 
notify_parent(union pipe write_pipe)423752e453SMichael Ellerman int notify_parent(union pipe write_pipe)
433752e453SMichael Ellerman {
443752e453SMichael Ellerman 	char c = CHILD_TOKEN;
453752e453SMichael Ellerman 
463752e453SMichael Ellerman 	FAIL_IF(write(write_pipe.write_fd, &c, 1) != 1);
473752e453SMichael Ellerman 
483752e453SMichael Ellerman 	return 0;
493752e453SMichael Ellerman }
503752e453SMichael Ellerman 
notify_parent_of_error(union pipe write_pipe)513752e453SMichael Ellerman int notify_parent_of_error(union pipe write_pipe)
523752e453SMichael Ellerman {
533752e453SMichael Ellerman 	char c = ~CHILD_TOKEN;
543752e453SMichael Ellerman 
553752e453SMichael Ellerman 	FAIL_IF(write(write_pipe.write_fd, &c, 1) != 1);
563752e453SMichael Ellerman 
573752e453SMichael Ellerman 	return 0;
583752e453SMichael Ellerman }
593752e453SMichael Ellerman 
wait_for_child(pid_t child_pid)603752e453SMichael Ellerman int wait_for_child(pid_t child_pid)
613752e453SMichael Ellerman {
623752e453SMichael Ellerman 	int rc;
633752e453SMichael Ellerman 
643752e453SMichael Ellerman 	if (waitpid(child_pid, &rc, 0) == -1) {
653752e453SMichael Ellerman 		perror("waitpid");
663752e453SMichael Ellerman 		return 1;
673752e453SMichael Ellerman 	}
683752e453SMichael Ellerman 
693752e453SMichael Ellerman 	if (WIFEXITED(rc))
703752e453SMichael Ellerman 		rc = WEXITSTATUS(rc);
713752e453SMichael Ellerman 	else
723752e453SMichael Ellerman 		rc = 1; /* Signal or other */
733752e453SMichael Ellerman 
743752e453SMichael Ellerman 	return rc;
753752e453SMichael Ellerman }
763752e453SMichael Ellerman 
kill_child_and_wait(pid_t child_pid)773752e453SMichael Ellerman int kill_child_and_wait(pid_t child_pid)
783752e453SMichael Ellerman {
793752e453SMichael Ellerman 	kill(child_pid, SIGTERM);
803752e453SMichael Ellerman 
813752e453SMichael Ellerman 	return wait_for_child(child_pid);
823752e453SMichael Ellerman }
833752e453SMichael Ellerman 
eat_cpu_child(union pipe read_pipe,union pipe write_pipe)843752e453SMichael Ellerman static int eat_cpu_child(union pipe read_pipe, union pipe write_pipe)
853752e453SMichael Ellerman {
863752e453SMichael Ellerman 	volatile int i = 0;
873752e453SMichael Ellerman 
883752e453SMichael Ellerman 	/*
893752e453SMichael Ellerman 	 * We are just here to eat cpu and die. So make sure we can be killed,
903752e453SMichael Ellerman 	 * and also don't do any custom SIGTERM handling.
913752e453SMichael Ellerman 	 */
923752e453SMichael Ellerman 	signal(SIGTERM, SIG_DFL);
933752e453SMichael Ellerman 
943752e453SMichael Ellerman 	notify_parent(write_pipe);
953752e453SMichael Ellerman 	wait_for_parent(read_pipe);
963752e453SMichael Ellerman 
973752e453SMichael Ellerman 	/* Soak up cpu forever */
983752e453SMichael Ellerman 	while (1) i++;
993752e453SMichael Ellerman 
1003752e453SMichael Ellerman 	return 0;
1013752e453SMichael Ellerman }
1023752e453SMichael Ellerman 
eat_cpu(int (test_function)(void))1033752e453SMichael Ellerman pid_t eat_cpu(int (test_function)(void))
1043752e453SMichael Ellerman {
1053752e453SMichael Ellerman 	union pipe read_pipe, write_pipe;
106*6ff4dc25SBenjamin Gray 	int rc;
1073752e453SMichael Ellerman 	pid_t pid;
1083752e453SMichael Ellerman 
109*6ff4dc25SBenjamin Gray 	FAIL_IF(bind_to_cpu(BIND_CPU_ANY) < 0);
1103752e453SMichael Ellerman 
1113752e453SMichael Ellerman 	if (pipe(read_pipe.fds) == -1)
1123752e453SMichael Ellerman 		return -1;
1133752e453SMichael Ellerman 
1143752e453SMichael Ellerman 	if (pipe(write_pipe.fds) == -1)
1153752e453SMichael Ellerman 		return -1;
1163752e453SMichael Ellerman 
1173752e453SMichael Ellerman 	pid = fork();
1183752e453SMichael Ellerman 	if (pid == 0)
1193752e453SMichael Ellerman 		exit(eat_cpu_child(write_pipe, read_pipe));
1203752e453SMichael Ellerman 
1213752e453SMichael Ellerman 	if (sync_with_child(read_pipe, write_pipe)) {
1223752e453SMichael Ellerman 		rc = -1;
1233752e453SMichael Ellerman 		goto out;
1243752e453SMichael Ellerman 	}
1253752e453SMichael Ellerman 
1263752e453SMichael Ellerman 	printf("main test running as pid %d\n", getpid());
1273752e453SMichael Ellerman 
1283752e453SMichael Ellerman 	rc = test_function();
1293752e453SMichael Ellerman out:
1303752e453SMichael Ellerman 	kill(pid, SIGKILL);
1313752e453SMichael Ellerman 
1323752e453SMichael Ellerman 	return rc;
1333752e453SMichael Ellerman }
1343752e453SMichael Ellerman 
1353752e453SMichael Ellerman struct addr_range libc, vdso;
1363752e453SMichael Ellerman 
parse_proc_maps(void)1373752e453SMichael Ellerman int parse_proc_maps(void)
1383752e453SMichael Ellerman {
1396861b44aSMichael Ellerman 	unsigned long start, end;
1403752e453SMichael Ellerman 	char execute, name[128];
1413752e453SMichael Ellerman 	FILE *f;
1423752e453SMichael Ellerman 	int rc;
1433752e453SMichael Ellerman 
1443752e453SMichael Ellerman 	f = fopen("/proc/self/maps", "r");
1453752e453SMichael Ellerman 	if (!f) {
1463752e453SMichael Ellerman 		perror("fopen");
1473752e453SMichael Ellerman 		return -1;
1483752e453SMichael Ellerman 	}
1493752e453SMichael Ellerman 
1503752e453SMichael Ellerman 	do {
1513752e453SMichael Ellerman 		/* This skips line with no executable which is what we want */
1523752e453SMichael Ellerman 		rc = fscanf(f, "%lx-%lx %*c%*c%c%*c %*x %*d:%*d %*d %127s\n",
1533752e453SMichael Ellerman 			    &start, &end, &execute, name);
1543752e453SMichael Ellerman 		if (rc <= 0)
1553752e453SMichael Ellerman 			break;
1563752e453SMichael Ellerman 
1573752e453SMichael Ellerman 		if (execute != 'x')
1583752e453SMichael Ellerman 			continue;
1593752e453SMichael Ellerman 
1603752e453SMichael Ellerman 		if (strstr(name, "libc")) {
1613752e453SMichael Ellerman 			libc.first = start;
1623752e453SMichael Ellerman 			libc.last = end - 1;
1633752e453SMichael Ellerman 		} else if (strstr(name, "[vdso]")) {
1643752e453SMichael Ellerman 			vdso.first = start;
1653752e453SMichael Ellerman 			vdso.last = end - 1;
1663752e453SMichael Ellerman 		}
1673752e453SMichael Ellerman 	} while(1);
1683752e453SMichael Ellerman 
1693752e453SMichael Ellerman 	fclose(f);
1703752e453SMichael Ellerman 
1713752e453SMichael Ellerman 	return 0;
1723752e453SMichael Ellerman }
1733752e453SMichael Ellerman 
1743752e453SMichael Ellerman #define PARANOID_PATH	"/proc/sys/kernel/perf_event_paranoid"
1753752e453SMichael Ellerman 
require_paranoia_below(int level)1763752e453SMichael Ellerman bool require_paranoia_below(int level)
1773752e453SMichael Ellerman {
178a974f0c1SBenjamin Gray 	int err;
179d4ecdff2SCyril Bur 	long current;
1803752e453SMichael Ellerman 
1815c20de57SBenjamin Gray 	err = read_long(PARANOID_PATH, &current, 10);
182d1bc05b7SBenjamin Gray 	if (err) {
1833752e453SMichael Ellerman 		printf("Couldn't parse " PARANOID_PATH "?\n");
184a974f0c1SBenjamin Gray 		return false;
1853752e453SMichael Ellerman 	}
1863752e453SMichael Ellerman 
187a974f0c1SBenjamin Gray 	return current < level;
1883752e453SMichael Ellerman }
189