0001
0002
0003
0004
0005
0006
0007
0008
0009 #define _GNU_SOURCE
0010 #include <assert.h>
0011 #include <errno.h>
0012 #include <getopt.h>
0013 #include <limits.h>
0014 #include <linux/futex.h>
0015 #include <pthread.h>
0016 #include <sched.h>
0017 #include <signal.h>
0018 #include <stdio.h>
0019 #include <stdlib.h>
0020 #include <string.h>
0021 #include <sys/shm.h>
0022 #include <sys/syscall.h>
0023 #include <sys/time.h>
0024 #include <sys/types.h>
0025 #include <sys/wait.h>
0026 #include <unistd.h>
0027
0028 static unsigned int timeout = 30;
0029
0030 static void set_cpu(int cpu)
0031 {
0032 cpu_set_t cpuset;
0033
0034 if (cpu == -1)
0035 return;
0036
0037 CPU_ZERO(&cpuset);
0038 CPU_SET(cpu, &cpuset);
0039
0040 if (sched_setaffinity(0, sizeof(cpuset), &cpuset)) {
0041 perror("sched_setaffinity");
0042 exit(1);
0043 }
0044 }
0045
0046 static void start_process_on(void *(*fn)(void *), void *arg, int cpu)
0047 {
0048 int pid;
0049
0050 pid = fork();
0051 if (pid == -1) {
0052 perror("fork");
0053 exit(1);
0054 }
0055
0056 if (pid)
0057 return;
0058
0059 set_cpu(cpu);
0060
0061 fn(arg);
0062
0063 exit(0);
0064 }
0065
0066 static int cpu;
0067 static int do_fork = 0;
0068 static int do_vfork = 0;
0069 static int do_exec = 0;
0070 static char *exec_file;
0071 static int exec_target = 0;
0072 static unsigned long iterations;
0073 static unsigned long iterations_prev;
0074
0075 static void run_exec(void)
0076 {
0077 char *const argv[] = { "./exec_target", NULL };
0078
0079 if (execve("./exec_target", argv, NULL) == -1) {
0080 perror("execve");
0081 exit(1);
0082 }
0083 }
0084
0085 static void bench_fork(void)
0086 {
0087 while (1) {
0088 pid_t pid = fork();
0089 if (pid == -1) {
0090 perror("fork");
0091 exit(1);
0092 }
0093 if (pid == 0) {
0094 if (do_exec)
0095 run_exec();
0096 _exit(0);
0097 }
0098 pid = waitpid(pid, NULL, 0);
0099 if (pid == -1) {
0100 perror("waitpid");
0101 exit(1);
0102 }
0103 iterations++;
0104 }
0105 }
0106
0107 static void bench_vfork(void)
0108 {
0109 while (1) {
0110 pid_t pid = vfork();
0111 if (pid == -1) {
0112 perror("fork");
0113 exit(1);
0114 }
0115 if (pid == 0) {
0116 if (do_exec)
0117 run_exec();
0118 _exit(0);
0119 }
0120 pid = waitpid(pid, NULL, 0);
0121 if (pid == -1) {
0122 perror("waitpid");
0123 exit(1);
0124 }
0125 iterations++;
0126 }
0127 }
0128
0129 static void *null_fn(void *arg)
0130 {
0131 pthread_exit(NULL);
0132 }
0133
0134 static void bench_thread(void)
0135 {
0136 pthread_t tid;
0137 cpu_set_t cpuset;
0138 pthread_attr_t attr;
0139 int rc;
0140
0141 rc = pthread_attr_init(&attr);
0142 if (rc) {
0143 errno = rc;
0144 perror("pthread_attr_init");
0145 exit(1);
0146 }
0147
0148 if (cpu != -1) {
0149 CPU_ZERO(&cpuset);
0150 CPU_SET(cpu, &cpuset);
0151
0152 rc = pthread_attr_setaffinity_np(&attr, sizeof(cpu_set_t), &cpuset);
0153 if (rc) {
0154 errno = rc;
0155 perror("pthread_attr_setaffinity_np");
0156 exit(1);
0157 }
0158 }
0159
0160 while (1) {
0161 rc = pthread_create(&tid, &attr, null_fn, NULL);
0162 if (rc) {
0163 errno = rc;
0164 perror("pthread_create");
0165 exit(1);
0166 }
0167 rc = pthread_join(tid, NULL);
0168 if (rc) {
0169 errno = rc;
0170 perror("pthread_join");
0171 exit(1);
0172 }
0173 iterations++;
0174 }
0175 }
0176
0177 static void sigalrm_handler(int junk)
0178 {
0179 unsigned long i = iterations;
0180
0181 printf("%ld\n", i - iterations_prev);
0182 iterations_prev = i;
0183
0184 if (--timeout == 0)
0185 kill(0, SIGUSR1);
0186
0187 alarm(1);
0188 }
0189
0190 static void sigusr1_handler(int junk)
0191 {
0192 exit(0);
0193 }
0194
0195 static void *bench_proc(void *arg)
0196 {
0197 signal(SIGALRM, sigalrm_handler);
0198 alarm(1);
0199
0200 if (do_fork)
0201 bench_fork();
0202 else if (do_vfork)
0203 bench_vfork();
0204 else
0205 bench_thread();
0206
0207 return NULL;
0208 }
0209
0210 static struct option options[] = {
0211 { "fork", no_argument, &do_fork, 1 },
0212 { "vfork", no_argument, &do_vfork, 1 },
0213 { "exec", no_argument, &do_exec, 1 },
0214 { "timeout", required_argument, 0, 's' },
0215 { "exec-target", no_argument, &exec_target, 1 },
0216 { NULL },
0217 };
0218
0219 static void usage(void)
0220 {
0221 fprintf(stderr, "Usage: fork <options> CPU\n\n");
0222 fprintf(stderr, "\t\t--fork\tUse fork() (default threads)\n");
0223 fprintf(stderr, "\t\t--vfork\tUse vfork() (default threads)\n");
0224 fprintf(stderr, "\t\t--exec\tAlso exec() (default no exec)\n");
0225 fprintf(stderr, "\t\t--timeout=X\tDuration in seconds to run (default 30)\n");
0226 fprintf(stderr, "\t\t--exec-target\tInternal option for exec workload\n");
0227 }
0228
0229 int main(int argc, char *argv[])
0230 {
0231 signed char c;
0232
0233 while (1) {
0234 int option_index = 0;
0235
0236 c = getopt_long(argc, argv, "", options, &option_index);
0237
0238 if (c == -1)
0239 break;
0240
0241 switch (c) {
0242 case 0:
0243 if (options[option_index].flag != 0)
0244 break;
0245
0246 usage();
0247 exit(1);
0248 break;
0249
0250 case 's':
0251 timeout = atoi(optarg);
0252 break;
0253
0254 default:
0255 usage();
0256 exit(1);
0257 }
0258 }
0259
0260 if (do_fork && do_vfork) {
0261 usage();
0262 exit(1);
0263 }
0264 if (do_exec && !do_fork && !do_vfork) {
0265 usage();
0266 exit(1);
0267 }
0268
0269 if (do_exec) {
0270 char *dirname = strdup(argv[0]);
0271 int i;
0272 i = strlen(dirname) - 1;
0273 while (i) {
0274 if (dirname[i] == '/') {
0275 dirname[i] = '\0';
0276 if (chdir(dirname) == -1) {
0277 perror("chdir");
0278 exit(1);
0279 }
0280 break;
0281 }
0282 i--;
0283 }
0284 }
0285
0286 if (exec_target) {
0287 exit(0);
0288 }
0289
0290 if (((argc - optind) != 1)) {
0291 cpu = -1;
0292 } else {
0293 cpu = atoi(argv[optind++]);
0294 }
0295
0296 if (do_exec)
0297 exec_file = argv[0];
0298
0299 set_cpu(cpu);
0300
0301 printf("Using ");
0302 if (do_fork)
0303 printf("fork");
0304 else if (do_vfork)
0305 printf("vfork");
0306 else
0307 printf("clone");
0308
0309 if (do_exec)
0310 printf(" + exec");
0311
0312 printf(" on cpu %d\n", cpu);
0313
0314
0315 setpgid(getpid(), getpid());
0316
0317 signal(SIGUSR1, sigusr1_handler);
0318
0319 start_process_on(bench_proc, NULL, cpu);
0320
0321 while (1)
0322 sleep(3600);
0323
0324 return 0;
0325 }