/* * Copyright (C) 2007, Ingo Molnar * * ring-test.c: run a ring of tasks which run in a turn, synchronized * via an array of pipes, and each task executes a workload function * when it has its turn. This simulates a fundamentally single-threaded * workload spread out across lots of tasks. * * Compile with: gcc -O2 -g -Wall -o ring-test ring-test.c -lrt */ #include #include #include #include #define MAX_NR_TASKS 1000 static unsigned int nr_tasks; static int pipes[MAX_NR_TASKS][2]; static void create_pipes(void) { char first_message = '+'; int i, err; for (i = 0; i < nr_tasks; i++) { err = pipe(pipes[i]); if (err < 0) { fprintf(stderr, "could not create the pipe-ring\n"); exit(-1); } } err = write(pipes[1][1], &first_message, 1); if (err != 1) { fprintf(stderr, "pipe first-write error\n"); exit(-1); } } unsigned long long rdclock(void) { struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts); return ts.tv_sec * 1000000000ULL + ts.tv_nsec; } /* * CPU-bound workload: runs 100 msecs then sleeps 1 msec: */ static void workload(void) { unsigned long long t0 = rdclock(), t1; struct timespec delay = { 0 , 1 * 1000000 }; for (;;) { t1 = rdclock(); if (t1 - t0 >= 100*1000000) break; } nanosleep(&delay , NULL); } static void worker(int task) { char message = '0'; int err, next_task; next_task = task + 1; if (next_task == nr_tasks) next_task = 0; err = read(pipes[task][0], &message, 1); if (err != 1) { fprintf(stderr, "pipe read error\n"); exit(-1); } if (message != '+') { fprintf(stderr, "pipe message error\n"); exit(-1); } workload(); message = '+'; err = write(pipes[next_task][1], &message, 1); if (err != 1) { fprintf(stderr, "next task pipe write error\n"); exit(-1); } } int main(int argc, char **argv) { int i, parent, me; if (argc > 2) { usage: fprintf(stderr, "usage: ring-test \n"); exit(-1); } if (argc == 2) { nr_tasks = atol(argv[1]); if (!nr_tasks) goto usage; } else nr_tasks = 100; if (nr_tasks > MAX_NR_TASKS) nr_tasks = MAX_NR_TASKS; printf("running %d ring-tasks.\n", nr_tasks); parent = getpid(); create_pipes(); for (i = 1; i < nr_tasks; i++) if (!fork()) break; me = getpid(); if (me == parent) i = 0; while (1) { worker(i); } return 0; }