Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

selftests/powerpc: Add process creation benchmark

Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
[mpe: Add SPDX, and fixup formatting]
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>

authored by

Nicholas Piggin and committed by
Michael Ellerman
dd40c5b4 a0828cf5

+346 -1
+2
tools/testing/selftests/powerpc/benchmarks/.gitignore
··· 1 1 gettimeofday 2 2 context_switch 3 + fork 4 + exec_target 3 5 mmap_bench 4 6 futex_bench 5 7 null_syscall
+6 -1
tools/testing/selftests/powerpc/benchmarks/Makefile
··· 1 1 # SPDX-License-Identifier: GPL-2.0 2 - TEST_GEN_PROGS := gettimeofday context_switch mmap_bench futex_bench null_syscall 2 + TEST_GEN_PROGS := gettimeofday context_switch fork mmap_bench futex_bench null_syscall 3 + TEST_GEN_FILES := exec_target 3 4 4 5 CFLAGS += -O2 5 6 ··· 11 10 $(OUTPUT)/context_switch: ../utils.c 12 11 $(OUTPUT)/context_switch: CFLAGS += -maltivec -mvsx -mabi=altivec 13 12 $(OUTPUT)/context_switch: LDLIBS += -lpthread 13 + 14 + $(OUTPUT)/fork: LDLIBS += -lpthread 15 + 16 + $(OUTPUT)/exec_target: CFLAGS += -static -nostartfiles
+13
tools/testing/selftests/powerpc/benchmarks/exec_target.c
··· 1 + // SPDX-License-Identifier: GPL-2.0+ 2 + 3 + /* 4 + * Part of fork context switch microbenchmark. 5 + * 6 + * Copyright 2018, Anton Blanchard, IBM Corp. 7 + */ 8 + 9 + void _exit(int); 10 + void _start(void) 11 + { 12 + _exit(0); 13 + }
+325
tools/testing/selftests/powerpc/benchmarks/fork.c
··· 1 + // SPDX-License-Identifier: GPL-2.0+ 2 + 3 + /* 4 + * Context switch microbenchmark. 5 + * 6 + * Copyright 2018, Anton Blanchard, IBM Corp. 7 + */ 8 + 9 + #define _GNU_SOURCE 10 + #include <assert.h> 11 + #include <errno.h> 12 + #include <getopt.h> 13 + #include <limits.h> 14 + #include <linux/futex.h> 15 + #include <pthread.h> 16 + #include <sched.h> 17 + #include <signal.h> 18 + #include <stdio.h> 19 + #include <stdlib.h> 20 + #include <string.h> 21 + #include <sys/shm.h> 22 + #include <sys/syscall.h> 23 + #include <sys/time.h> 24 + #include <sys/types.h> 25 + #include <sys/wait.h> 26 + #include <unistd.h> 27 + 28 + static unsigned int timeout = 30; 29 + 30 + static void set_cpu(int cpu) 31 + { 32 + cpu_set_t cpuset; 33 + 34 + if (cpu == -1) 35 + return; 36 + 37 + CPU_ZERO(&cpuset); 38 + CPU_SET(cpu, &cpuset); 39 + 40 + if (sched_setaffinity(0, sizeof(cpuset), &cpuset)) { 41 + perror("sched_setaffinity"); 42 + exit(1); 43 + } 44 + } 45 + 46 + static void start_process_on(void *(*fn)(void *), void *arg, int cpu) 47 + { 48 + int pid; 49 + 50 + pid = fork(); 51 + if (pid == -1) { 52 + perror("fork"); 53 + exit(1); 54 + } 55 + 56 + if (pid) 57 + return; 58 + 59 + set_cpu(cpu); 60 + 61 + fn(arg); 62 + 63 + exit(0); 64 + } 65 + 66 + static int cpu; 67 + static int do_fork = 0; 68 + static int do_vfork = 0; 69 + static int do_exec = 0; 70 + static char *exec_file; 71 + static int exec_target = 0; 72 + static unsigned long iterations; 73 + static unsigned long iterations_prev; 74 + 75 + static void run_exec(void) 76 + { 77 + char *const argv[] = { "./exec_target", NULL }; 78 + 79 + if (execve("./exec_target", argv, NULL) == -1) { 80 + perror("execve"); 81 + exit(1); 82 + } 83 + } 84 + 85 + static void bench_fork(void) 86 + { 87 + while (1) { 88 + pid_t pid = fork(); 89 + if (pid == -1) { 90 + perror("fork"); 91 + exit(1); 92 + } 93 + if (pid == 0) { 94 + if (do_exec) 95 + run_exec(); 96 + _exit(0); 97 + } 98 + pid = waitpid(pid, NULL, 0); 99 + if (pid == -1) { 100 + perror("waitpid"); 101 + exit(1); 102 + } 103 + iterations++; 104 + } 105 + } 106 + 107 + static void bench_vfork(void) 108 + { 109 + while (1) { 110 + pid_t pid = vfork(); 111 + if (pid == -1) { 112 + perror("fork"); 113 + exit(1); 114 + } 115 + if (pid == 0) { 116 + if (do_exec) 117 + run_exec(); 118 + _exit(0); 119 + } 120 + pid = waitpid(pid, NULL, 0); 121 + if (pid == -1) { 122 + perror("waitpid"); 123 + exit(1); 124 + } 125 + iterations++; 126 + } 127 + } 128 + 129 + static void *null_fn(void *arg) 130 + { 131 + pthread_exit(NULL); 132 + } 133 + 134 + static void bench_thread(void) 135 + { 136 + pthread_t tid; 137 + cpu_set_t cpuset; 138 + pthread_attr_t attr; 139 + int rc; 140 + 141 + rc = pthread_attr_init(&attr); 142 + if (rc) { 143 + errno = rc; 144 + perror("pthread_attr_init"); 145 + exit(1); 146 + } 147 + 148 + if (cpu != -1) { 149 + CPU_ZERO(&cpuset); 150 + CPU_SET(cpu, &cpuset); 151 + 152 + rc = pthread_attr_setaffinity_np(&attr, sizeof(cpu_set_t), &cpuset); 153 + if (rc) { 154 + errno = rc; 155 + perror("pthread_attr_setaffinity_np"); 156 + exit(1); 157 + } 158 + } 159 + 160 + while (1) { 161 + rc = pthread_create(&tid, &attr, null_fn, NULL); 162 + if (rc) { 163 + errno = rc; 164 + perror("pthread_create"); 165 + exit(1); 166 + } 167 + rc = pthread_join(tid, NULL); 168 + if (rc) { 169 + errno = rc; 170 + perror("pthread_join"); 171 + exit(1); 172 + } 173 + iterations++; 174 + } 175 + } 176 + 177 + static void sigalrm_handler(int junk) 178 + { 179 + unsigned long i = iterations; 180 + 181 + printf("%ld\n", i - iterations_prev); 182 + iterations_prev = i; 183 + 184 + if (--timeout == 0) 185 + kill(0, SIGUSR1); 186 + 187 + alarm(1); 188 + } 189 + 190 + static void sigusr1_handler(int junk) 191 + { 192 + exit(0); 193 + } 194 + 195 + static void *bench_proc(void *arg) 196 + { 197 + signal(SIGALRM, sigalrm_handler); 198 + alarm(1); 199 + 200 + if (do_fork) 201 + bench_fork(); 202 + else if (do_vfork) 203 + bench_vfork(); 204 + else 205 + bench_thread(); 206 + 207 + return NULL; 208 + } 209 + 210 + static struct option options[] = { 211 + { "fork", no_argument, &do_fork, 1 }, 212 + { "vfork", no_argument, &do_vfork, 1 }, 213 + { "exec", no_argument, &do_exec, 1 }, 214 + { "timeout", required_argument, 0, 's' }, 215 + { "exec-target", no_argument, &exec_target, 1 }, 216 + { NULL }, 217 + }; 218 + 219 + static void usage(void) 220 + { 221 + fprintf(stderr, "Usage: fork <options> CPU\n\n"); 222 + fprintf(stderr, "\t\t--fork\tUse fork() (default threads)\n"); 223 + fprintf(stderr, "\t\t--vfork\tUse vfork() (default threads)\n"); 224 + fprintf(stderr, "\t\t--exec\tAlso exec() (default no exec)\n"); 225 + fprintf(stderr, "\t\t--timeout=X\tDuration in seconds to run (default 30)\n"); 226 + fprintf(stderr, "\t\t--exec-target\tInternal option for exec workload\n"); 227 + } 228 + 229 + int main(int argc, char *argv[]) 230 + { 231 + signed char c; 232 + 233 + while (1) { 234 + int option_index = 0; 235 + 236 + c = getopt_long(argc, argv, "", options, &option_index); 237 + 238 + if (c == -1) 239 + break; 240 + 241 + switch (c) { 242 + case 0: 243 + if (options[option_index].flag != 0) 244 + break; 245 + 246 + usage(); 247 + exit(1); 248 + break; 249 + 250 + case 's': 251 + timeout = atoi(optarg); 252 + break; 253 + 254 + default: 255 + usage(); 256 + exit(1); 257 + } 258 + } 259 + 260 + if (do_fork && do_vfork) { 261 + usage(); 262 + exit(1); 263 + } 264 + if (do_exec && !do_fork && !do_vfork) { 265 + usage(); 266 + exit(1); 267 + } 268 + 269 + if (do_exec) { 270 + char *dirname = strdup(argv[0]); 271 + int i; 272 + i = strlen(dirname) - 1; 273 + while (i) { 274 + if (dirname[i] == '/') { 275 + dirname[i] = '\0'; 276 + if (chdir(dirname) == -1) { 277 + perror("chdir"); 278 + exit(1); 279 + } 280 + break; 281 + } 282 + i--; 283 + } 284 + } 285 + 286 + if (exec_target) { 287 + exit(0); 288 + } 289 + 290 + if (((argc - optind) != 1)) { 291 + cpu = -1; 292 + } else { 293 + cpu = atoi(argv[optind++]); 294 + } 295 + 296 + if (do_exec) 297 + exec_file = argv[0]; 298 + 299 + set_cpu(cpu); 300 + 301 + printf("Using "); 302 + if (do_fork) 303 + printf("fork"); 304 + else if (do_vfork) 305 + printf("vfork"); 306 + else 307 + printf("clone"); 308 + 309 + if (do_exec) 310 + printf(" + exec"); 311 + 312 + printf(" on cpu %d\n", cpu); 313 + 314 + /* Create a new process group so we can signal everyone for exit */ 315 + setpgid(getpid(), getpid()); 316 + 317 + signal(SIGUSR1, sigusr1_handler); 318 + 319 + start_process_on(bench_proc, NULL, cpu); 320 + 321 + while (1) 322 + sleep(3600); 323 + 324 + return 0; 325 + }