Path: blob/master/tools/perf/bench/sched-messaging.c
10821 views
/*1*2* sched-messaging.c3*4* messaging: Benchmark for scheduler and IPC mechanisms5*6* Based on hackbench by Rusty Russell <[email protected]>7* Ported to perf by Hitoshi Mitake <[email protected]>8*9*/1011#include "../perf.h"12#include "../util/util.h"13#include "../util/parse-options.h"14#include "../builtin.h"15#include "bench.h"1617/* Test groups of 20 processes spraying to 20 receivers */18#include <pthread.h>19#include <stdio.h>20#include <stdlib.h>21#include <string.h>22#include <errno.h>23#include <unistd.h>24#include <sys/types.h>25#include <sys/socket.h>26#include <sys/wait.h>27#include <sys/time.h>28#include <sys/poll.h>29#include <limits.h>3031#define DATASIZE 1003233static bool use_pipes = false;34static unsigned int loops = 100;35static bool thread_mode = false;36static unsigned int num_groups = 10;3738struct sender_context {39unsigned int num_fds;40int ready_out;41int wakefd;42int out_fds[0];43};4445struct receiver_context {46unsigned int num_packets;47int in_fds[2];48int ready_out;49int wakefd;50};5152static void barf(const char *msg)53{54fprintf(stderr, "%s (error: %s)\n", msg, strerror(errno));55exit(1);56}5758static void fdpair(int fds[2])59{60if (use_pipes) {61if (pipe(fds) == 0)62return;63} else {64if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) == 0)65return;66}6768barf(use_pipes ? "pipe()" : "socketpair()");69}7071/* Block until we're ready to go */72static void ready(int ready_out, int wakefd)73{74char dummy;75struct pollfd pollfd = { .fd = wakefd, .events = POLLIN };7677/* Tell them we're ready. */78if (write(ready_out, &dummy, 1) != 1)79barf("CLIENT: ready write");8081/* Wait for "GO" signal */82if (poll(&pollfd, 1, -1) != 1)83barf("poll");84}8586/* Sender sprays loops messages down each file descriptor */87static void *sender(struct sender_context *ctx)88{89char data[DATASIZE];90unsigned int i, j;9192ready(ctx->ready_out, ctx->wakefd);9394/* Now pump to every receiver. */95for (i = 0; i < loops; i++) {96for (j = 0; j < ctx->num_fds; j++) {97int ret, done = 0;9899again:100ret = write(ctx->out_fds[j], data + done,101sizeof(data)-done);102if (ret < 0)103barf("SENDER: write");104done += ret;105if (done < DATASIZE)106goto again;107}108}109110return NULL;111}112113114/* One receiver per fd */115static void *receiver(struct receiver_context* ctx)116{117unsigned int i;118119if (!thread_mode)120close(ctx->in_fds[1]);121122/* Wait for start... */123ready(ctx->ready_out, ctx->wakefd);124125/* Receive them all */126for (i = 0; i < ctx->num_packets; i++) {127char data[DATASIZE];128int ret, done = 0;129130again:131ret = read(ctx->in_fds[0], data + done, DATASIZE - done);132if (ret < 0)133barf("SERVER: read");134done += ret;135if (done < DATASIZE)136goto again;137}138139return NULL;140}141142static pthread_t create_worker(void *ctx, void *(*func)(void *))143{144pthread_attr_t attr;145pthread_t childid;146int err;147148if (!thread_mode) {149/* process mode */150/* Fork the receiver. */151switch (fork()) {152case -1:153barf("fork()");154break;155case 0:156(*func) (ctx);157exit(0);158break;159default:160break;161}162163return (pthread_t)0;164}165166if (pthread_attr_init(&attr) != 0)167barf("pthread_attr_init:");168169#ifndef __ia64__170if (pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN) != 0)171barf("pthread_attr_setstacksize");172#endif173174err = pthread_create(&childid, &attr, func, ctx);175if (err != 0) {176fprintf(stderr, "pthread_create failed: %s (%d)\n",177strerror(err), err);178exit(-1);179}180return childid;181}182183static void reap_worker(pthread_t id)184{185int proc_status;186void *thread_status;187188if (!thread_mode) {189/* process mode */190wait(&proc_status);191if (!WIFEXITED(proc_status))192exit(1);193} else {194pthread_join(id, &thread_status);195}196}197198/* One group of senders and receivers */199static unsigned int group(pthread_t *pth,200unsigned int num_fds,201int ready_out,202int wakefd)203{204unsigned int i;205struct sender_context *snd_ctx = malloc(sizeof(struct sender_context)206+ num_fds * sizeof(int));207208if (!snd_ctx)209barf("malloc()");210211for (i = 0; i < num_fds; i++) {212int fds[2];213struct receiver_context *ctx = malloc(sizeof(*ctx));214215if (!ctx)216barf("malloc()");217218219/* Create the pipe between client and server */220fdpair(fds);221222ctx->num_packets = num_fds * loops;223ctx->in_fds[0] = fds[0];224ctx->in_fds[1] = fds[1];225ctx->ready_out = ready_out;226ctx->wakefd = wakefd;227228pth[i] = create_worker(ctx, (void *)receiver);229230snd_ctx->out_fds[i] = fds[1];231if (!thread_mode)232close(fds[0]);233}234235/* Now we have all the fds, fork the senders */236for (i = 0; i < num_fds; i++) {237snd_ctx->ready_out = ready_out;238snd_ctx->wakefd = wakefd;239snd_ctx->num_fds = num_fds;240241pth[num_fds+i] = create_worker(snd_ctx, (void *)sender);242}243244/* Close the fds we have left */245if (!thread_mode)246for (i = 0; i < num_fds; i++)247close(snd_ctx->out_fds[i]);248249/* Return number of children to reap */250return num_fds * 2;251}252253static const struct option options[] = {254OPT_BOOLEAN('p', "pipe", &use_pipes,255"Use pipe() instead of socketpair()"),256OPT_BOOLEAN('t', "thread", &thread_mode,257"Be multi thread instead of multi process"),258OPT_UINTEGER('g', "group", &num_groups, "Specify number of groups"),259OPT_UINTEGER('l', "loop", &loops, "Specify number of loops"),260OPT_END()261};262263static const char * const bench_sched_message_usage[] = {264"perf bench sched messaging <options>",265NULL266};267268int bench_sched_messaging(int argc, const char **argv,269const char *prefix __used)270{271unsigned int i, total_children;272struct timeval start, stop, diff;273unsigned int num_fds = 20;274int readyfds[2], wakefds[2];275char dummy;276pthread_t *pth_tab;277278argc = parse_options(argc, argv, options,279bench_sched_message_usage, 0);280281pth_tab = malloc(num_fds * 2 * num_groups * sizeof(pthread_t));282if (!pth_tab)283barf("main:malloc()");284285fdpair(readyfds);286fdpair(wakefds);287288total_children = 0;289for (i = 0; i < num_groups; i++)290total_children += group(pth_tab+total_children, num_fds,291readyfds[1], wakefds[0]);292293/* Wait for everyone to be ready */294for (i = 0; i < total_children; i++)295if (read(readyfds[0], &dummy, 1) != 1)296barf("Reading for readyfds");297298gettimeofday(&start, NULL);299300/* Kick them off */301if (write(wakefds[1], &dummy, 1) != 1)302barf("Writing to start them");303304/* Reap them all */305for (i = 0; i < total_children; i++)306reap_worker(pth_tab[i]);307308gettimeofday(&stop, NULL);309310timersub(&stop, &start, &diff);311312switch (bench_format) {313case BENCH_FORMAT_DEFAULT:314printf("# %d sender and receiver %s per group\n",315num_fds, thread_mode ? "threads" : "processes");316printf("# %d groups == %d %s run\n\n",317num_groups, num_groups * 2 * num_fds,318thread_mode ? "threads" : "processes");319printf(" %14s: %lu.%03lu [sec]\n", "Total time",320diff.tv_sec,321(unsigned long) (diff.tv_usec/1000));322break;323case BENCH_FORMAT_SIMPLE:324printf("%lu.%03lu\n", diff.tv_sec,325(unsigned long) (diff.tv_usec/1000));326break;327default:328/* reaching here is something disaster */329fprintf(stderr, "Unknown format:%d\n", bench_format);330exit(1);331break;332}333334return 0;335}336337338