diff options
author | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
---|---|---|
committer | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
commit | ada47b5fe13d89735805b566185f4885f5a3f750 (patch) | |
tree | 644b88f8a71896307d71438e9b3af49126ffb22b /tools/perf/bench | |
parent | 43e98717ad40a4ae64545b5ba047c7b86aa44f4f (diff) | |
parent | 3280f21d43ee541f97f8cda5792150d2dbec20d5 (diff) |
Merge branch 'wip-2.6.34' into old-private-masterarchived-private-master
Diffstat (limited to 'tools/perf/bench')
-rw-r--r-- | tools/perf/bench/bench.h | 17 | ||||
-rw-r--r-- | tools/perf/bench/mem-memcpy.c | 193 | ||||
-rw-r--r-- | tools/perf/bench/sched-messaging.c | 338 | ||||
-rw-r--r-- | tools/perf/bench/sched-pipe.c | 127 |
4 files changed, 675 insertions, 0 deletions
diff --git a/tools/perf/bench/bench.h b/tools/perf/bench/bench.h new file mode 100644 index 000000000000..f7781c6267c0 --- /dev/null +++ b/tools/perf/bench/bench.h | |||
@@ -0,0 +1,17 @@ | |||
1 | #ifndef BENCH_H | ||
2 | #define BENCH_H | ||
3 | |||
4 | extern int bench_sched_messaging(int argc, const char **argv, const char *prefix); | ||
5 | extern int bench_sched_pipe(int argc, const char **argv, const char *prefix); | ||
6 | extern int bench_mem_memcpy(int argc, const char **argv, const char *prefix __used); | ||
7 | |||
8 | #define BENCH_FORMAT_DEFAULT_STR "default" | ||
9 | #define BENCH_FORMAT_DEFAULT 0 | ||
10 | #define BENCH_FORMAT_SIMPLE_STR "simple" | ||
11 | #define BENCH_FORMAT_SIMPLE 1 | ||
12 | |||
13 | #define BENCH_FORMAT_UNKNOWN -1 | ||
14 | |||
15 | extern int bench_format; | ||
16 | |||
17 | #endif | ||
diff --git a/tools/perf/bench/mem-memcpy.c b/tools/perf/bench/mem-memcpy.c new file mode 100644 index 000000000000..89773178e894 --- /dev/null +++ b/tools/perf/bench/mem-memcpy.c | |||
@@ -0,0 +1,193 @@ | |||
1 | /* | ||
2 | * mem-memcpy.c | ||
3 | * | ||
4 | * memcpy: Simple memory copy in various ways | ||
5 | * | ||
6 | * Written by Hitoshi Mitake <mitake@dcl.info.waseda.ac.jp> | ||
7 | */ | ||
8 | #include <ctype.h> | ||
9 | |||
10 | #include "../perf.h" | ||
11 | #include "../util/util.h" | ||
12 | #include "../util/parse-options.h" | ||
13 | #include "../util/string.h" | ||
14 | #include "../util/header.h" | ||
15 | #include "bench.h" | ||
16 | |||
17 | #include <stdio.h> | ||
18 | #include <stdlib.h> | ||
19 | #include <string.h> | ||
20 | #include <sys/time.h> | ||
21 | #include <errno.h> | ||
22 | |||
23 | #define K 1024 | ||
24 | |||
25 | static const char *length_str = "1MB"; | ||
26 | static const char *routine = "default"; | ||
27 | static int use_clock = 0; | ||
28 | static int clock_fd; | ||
29 | |||
30 | static const struct option options[] = { | ||
31 | OPT_STRING('l', "length", &length_str, "1MB", | ||
32 | "Specify length of memory to copy. " | ||
33 | "available unit: B, MB, GB (upper and lower)"), | ||
34 | OPT_STRING('r', "routine", &routine, "default", | ||
35 | "Specify routine to copy"), | ||
36 | OPT_BOOLEAN('c', "clock", &use_clock, | ||
37 | "Use CPU clock for measuring"), | ||
38 | OPT_END() | ||
39 | }; | ||
40 | |||
41 | struct routine { | ||
42 | const char *name; | ||
43 | const char *desc; | ||
44 | void * (*fn)(void *dst, const void *src, size_t len); | ||
45 | }; | ||
46 | |||
47 | struct routine routines[] = { | ||
48 | { "default", | ||
49 | "Default memcpy() provided by glibc", | ||
50 | memcpy }, | ||
51 | { NULL, | ||
52 | NULL, | ||
53 | NULL } | ||
54 | }; | ||
55 | |||
56 | static const char * const bench_mem_memcpy_usage[] = { | ||
57 | "perf bench mem memcpy <options>", | ||
58 | NULL | ||
59 | }; | ||
60 | |||
61 | static struct perf_event_attr clock_attr = { | ||
62 | .type = PERF_TYPE_HARDWARE, | ||
63 | .config = PERF_COUNT_HW_CPU_CYCLES | ||
64 | }; | ||
65 | |||
66 | static void init_clock(void) | ||
67 | { | ||
68 | clock_fd = sys_perf_event_open(&clock_attr, getpid(), -1, -1, 0); | ||
69 | |||
70 | if (clock_fd < 0 && errno == ENOSYS) | ||
71 | die("No CONFIG_PERF_EVENTS=y kernel support configured?\n"); | ||
72 | else | ||
73 | BUG_ON(clock_fd < 0); | ||
74 | } | ||
75 | |||
76 | static u64 get_clock(void) | ||
77 | { | ||
78 | int ret; | ||
79 | u64 clk; | ||
80 | |||
81 | ret = read(clock_fd, &clk, sizeof(u64)); | ||
82 | BUG_ON(ret != sizeof(u64)); | ||
83 | |||
84 | return clk; | ||
85 | } | ||
86 | |||
87 | static double timeval2double(struct timeval *ts) | ||
88 | { | ||
89 | return (double)ts->tv_sec + | ||
90 | (double)ts->tv_usec / (double)1000000; | ||
91 | } | ||
92 | |||
93 | int bench_mem_memcpy(int argc, const char **argv, | ||
94 | const char *prefix __used) | ||
95 | { | ||
96 | int i; | ||
97 | void *dst, *src; | ||
98 | size_t length; | ||
99 | double bps = 0.0; | ||
100 | struct timeval tv_start, tv_end, tv_diff; | ||
101 | u64 clock_start, clock_end, clock_diff; | ||
102 | |||
103 | clock_start = clock_end = clock_diff = 0ULL; | ||
104 | argc = parse_options(argc, argv, options, | ||
105 | bench_mem_memcpy_usage, 0); | ||
106 | |||
107 | tv_diff.tv_sec = 0; | ||
108 | tv_diff.tv_usec = 0; | ||
109 | length = (size_t)perf_atoll((char *)length_str); | ||
110 | |||
111 | if ((s64)length <= 0) { | ||
112 | fprintf(stderr, "Invalid length:%s\n", length_str); | ||
113 | return 1; | ||
114 | } | ||
115 | |||
116 | for (i = 0; routines[i].name; i++) { | ||
117 | if (!strcmp(routines[i].name, routine)) | ||
118 | break; | ||
119 | } | ||
120 | if (!routines[i].name) { | ||
121 | printf("Unknown routine:%s\n", routine); | ||
122 | printf("Available routines...\n"); | ||
123 | for (i = 0; routines[i].name; i++) { | ||
124 | printf("\t%s ... %s\n", | ||
125 | routines[i].name, routines[i].desc); | ||
126 | } | ||
127 | return 1; | ||
128 | } | ||
129 | |||
130 | dst = zalloc(length); | ||
131 | if (!dst) | ||
132 | die("memory allocation failed - maybe length is too large?\n"); | ||
133 | |||
134 | src = zalloc(length); | ||
135 | if (!src) | ||
136 | die("memory allocation failed - maybe length is too large?\n"); | ||
137 | |||
138 | if (bench_format == BENCH_FORMAT_DEFAULT) { | ||
139 | printf("# Copying %s Bytes from %p to %p ...\n\n", | ||
140 | length_str, src, dst); | ||
141 | } | ||
142 | |||
143 | if (use_clock) { | ||
144 | init_clock(); | ||
145 | clock_start = get_clock(); | ||
146 | } else { | ||
147 | BUG_ON(gettimeofday(&tv_start, NULL)); | ||
148 | } | ||
149 | |||
150 | routines[i].fn(dst, src, length); | ||
151 | |||
152 | if (use_clock) { | ||
153 | clock_end = get_clock(); | ||
154 | clock_diff = clock_end - clock_start; | ||
155 | } else { | ||
156 | BUG_ON(gettimeofday(&tv_end, NULL)); | ||
157 | timersub(&tv_end, &tv_start, &tv_diff); | ||
158 | bps = (double)((double)length / timeval2double(&tv_diff)); | ||
159 | } | ||
160 | |||
161 | switch (bench_format) { | ||
162 | case BENCH_FORMAT_DEFAULT: | ||
163 | if (use_clock) { | ||
164 | printf(" %14lf Clock/Byte\n", | ||
165 | (double)clock_diff / (double)length); | ||
166 | } else { | ||
167 | if (bps < K) | ||
168 | printf(" %14lf B/Sec\n", bps); | ||
169 | else if (bps < K * K) | ||
170 | printf(" %14lfd KB/Sec\n", bps / 1024); | ||
171 | else if (bps < K * K * K) | ||
172 | printf(" %14lf MB/Sec\n", bps / 1024 / 1024); | ||
173 | else { | ||
174 | printf(" %14lf GB/Sec\n", | ||
175 | bps / 1024 / 1024 / 1024); | ||
176 | } | ||
177 | } | ||
178 | break; | ||
179 | case BENCH_FORMAT_SIMPLE: | ||
180 | if (use_clock) { | ||
181 | printf("%14lf\n", | ||
182 | (double)clock_diff / (double)length); | ||
183 | } else | ||
184 | printf("%lf\n", bps); | ||
185 | break; | ||
186 | default: | ||
187 | /* reaching this means there's some disaster: */ | ||
188 | die("unknown format: %d\n", bench_format); | ||
189 | break; | ||
190 | } | ||
191 | |||
192 | return 0; | ||
193 | } | ||
diff --git a/tools/perf/bench/sched-messaging.c b/tools/perf/bench/sched-messaging.c new file mode 100644 index 000000000000..81cee78181fa --- /dev/null +++ b/tools/perf/bench/sched-messaging.c | |||
@@ -0,0 +1,338 @@ | |||
1 | /* | ||
2 | * | ||
3 | * sched-messaging.c | ||
4 | * | ||
5 | * messaging: Benchmark for scheduler and IPC mechanisms | ||
6 | * | ||
7 | * Based on hackbench by Rusty Russell <rusty@rustcorp.com.au> | ||
8 | * Ported to perf by Hitoshi Mitake <mitake@dcl.info.waseda.ac.jp> | ||
9 | * | ||
10 | */ | ||
11 | |||
12 | #include "../perf.h" | ||
13 | #include "../util/util.h" | ||
14 | #include "../util/parse-options.h" | ||
15 | #include "../builtin.h" | ||
16 | #include "bench.h" | ||
17 | |||
18 | /* Test groups of 20 processes spraying to 20 receivers */ | ||
19 | #include <pthread.h> | ||
20 | #include <stdio.h> | ||
21 | #include <stdlib.h> | ||
22 | #include <string.h> | ||
23 | #include <errno.h> | ||
24 | #include <unistd.h> | ||
25 | #include <sys/types.h> | ||
26 | #include <sys/socket.h> | ||
27 | #include <sys/wait.h> | ||
28 | #include <sys/time.h> | ||
29 | #include <sys/poll.h> | ||
30 | #include <limits.h> | ||
31 | |||
32 | #define DATASIZE 100 | ||
33 | |||
34 | static int use_pipes = 0; | ||
35 | static unsigned int loops = 100; | ||
36 | static unsigned int thread_mode = 0; | ||
37 | static unsigned int num_groups = 10; | ||
38 | |||
39 | struct sender_context { | ||
40 | unsigned int num_fds; | ||
41 | int ready_out; | ||
42 | int wakefd; | ||
43 | int out_fds[0]; | ||
44 | }; | ||
45 | |||
46 | struct receiver_context { | ||
47 | unsigned int num_packets; | ||
48 | int in_fds[2]; | ||
49 | int ready_out; | ||
50 | int wakefd; | ||
51 | }; | ||
52 | |||
53 | static void barf(const char *msg) | ||
54 | { | ||
55 | fprintf(stderr, "%s (error: %s)\n", msg, strerror(errno)); | ||
56 | exit(1); | ||
57 | } | ||
58 | |||
59 | static void fdpair(int fds[2]) | ||
60 | { | ||
61 | if (use_pipes) { | ||
62 | if (pipe(fds) == 0) | ||
63 | return; | ||
64 | } else { | ||
65 | if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) == 0) | ||
66 | return; | ||
67 | } | ||
68 | |||
69 | barf(use_pipes ? "pipe()" : "socketpair()"); | ||
70 | } | ||
71 | |||
72 | /* Block until we're ready to go */ | ||
73 | static void ready(int ready_out, int wakefd) | ||
74 | { | ||
75 | char dummy; | ||
76 | struct pollfd pollfd = { .fd = wakefd, .events = POLLIN }; | ||
77 | |||
78 | /* Tell them we're ready. */ | ||
79 | if (write(ready_out, &dummy, 1) != 1) | ||
80 | barf("CLIENT: ready write"); | ||
81 | |||
82 | /* Wait for "GO" signal */ | ||
83 | if (poll(&pollfd, 1, -1) != 1) | ||
84 | barf("poll"); | ||
85 | } | ||
86 | |||
87 | /* Sender sprays loops messages down each file descriptor */ | ||
88 | static void *sender(struct sender_context *ctx) | ||
89 | { | ||
90 | char data[DATASIZE]; | ||
91 | unsigned int i, j; | ||
92 | |||
93 | ready(ctx->ready_out, ctx->wakefd); | ||
94 | |||
95 | /* Now pump to every receiver. */ | ||
96 | for (i = 0; i < loops; i++) { | ||
97 | for (j = 0; j < ctx->num_fds; j++) { | ||
98 | int ret, done = 0; | ||
99 | |||
100 | again: | ||
101 | ret = write(ctx->out_fds[j], data + done, | ||
102 | sizeof(data)-done); | ||
103 | if (ret < 0) | ||
104 | barf("SENDER: write"); | ||
105 | done += ret; | ||
106 | if (done < DATASIZE) | ||
107 | goto again; | ||
108 | } | ||
109 | } | ||
110 | |||
111 | return NULL; | ||
112 | } | ||
113 | |||
114 | |||
115 | /* One receiver per fd */ | ||
116 | static void *receiver(struct receiver_context* ctx) | ||
117 | { | ||
118 | unsigned int i; | ||
119 | |||
120 | if (!thread_mode) | ||
121 | close(ctx->in_fds[1]); | ||
122 | |||
123 | /* Wait for start... */ | ||
124 | ready(ctx->ready_out, ctx->wakefd); | ||
125 | |||
126 | /* Receive them all */ | ||
127 | for (i = 0; i < ctx->num_packets; i++) { | ||
128 | char data[DATASIZE]; | ||
129 | int ret, done = 0; | ||
130 | |||
131 | again: | ||
132 | ret = read(ctx->in_fds[0], data + done, DATASIZE - done); | ||
133 | if (ret < 0) | ||
134 | barf("SERVER: read"); | ||
135 | done += ret; | ||
136 | if (done < DATASIZE) | ||
137 | goto again; | ||
138 | } | ||
139 | |||
140 | return NULL; | ||
141 | } | ||
142 | |||
143 | static pthread_t create_worker(void *ctx, void *(*func)(void *)) | ||
144 | { | ||
145 | pthread_attr_t attr; | ||
146 | pthread_t childid; | ||
147 | int err; | ||
148 | |||
149 | if (!thread_mode) { | ||
150 | /* process mode */ | ||
151 | /* Fork the receiver. */ | ||
152 | switch (fork()) { | ||
153 | case -1: | ||
154 | barf("fork()"); | ||
155 | break; | ||
156 | case 0: | ||
157 | (*func) (ctx); | ||
158 | exit(0); | ||
159 | break; | ||
160 | default: | ||
161 | break; | ||
162 | } | ||
163 | |||
164 | return (pthread_t)0; | ||
165 | } | ||
166 | |||
167 | if (pthread_attr_init(&attr) != 0) | ||
168 | barf("pthread_attr_init:"); | ||
169 | |||
170 | #ifndef __ia64__ | ||
171 | if (pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN) != 0) | ||
172 | barf("pthread_attr_setstacksize"); | ||
173 | #endif | ||
174 | |||
175 | err = pthread_create(&childid, &attr, func, ctx); | ||
176 | if (err != 0) { | ||
177 | fprintf(stderr, "pthread_create failed: %s (%d)\n", | ||
178 | strerror(err), err); | ||
179 | exit(-1); | ||
180 | } | ||
181 | return childid; | ||
182 | } | ||
183 | |||
184 | static void reap_worker(pthread_t id) | ||
185 | { | ||
186 | int proc_status; | ||
187 | void *thread_status; | ||
188 | |||
189 | if (!thread_mode) { | ||
190 | /* process mode */ | ||
191 | wait(&proc_status); | ||
192 | if (!WIFEXITED(proc_status)) | ||
193 | exit(1); | ||
194 | } else { | ||
195 | pthread_join(id, &thread_status); | ||
196 | } | ||
197 | } | ||
198 | |||
199 | /* One group of senders and receivers */ | ||
200 | static unsigned int group(pthread_t *pth, | ||
201 | unsigned int num_fds, | ||
202 | int ready_out, | ||
203 | int wakefd) | ||
204 | { | ||
205 | unsigned int i; | ||
206 | struct sender_context *snd_ctx = malloc(sizeof(struct sender_context) | ||
207 | + num_fds * sizeof(int)); | ||
208 | |||
209 | if (!snd_ctx) | ||
210 | barf("malloc()"); | ||
211 | |||
212 | for (i = 0; i < num_fds; i++) { | ||
213 | int fds[2]; | ||
214 | struct receiver_context *ctx = malloc(sizeof(*ctx)); | ||
215 | |||
216 | if (!ctx) | ||
217 | barf("malloc()"); | ||
218 | |||
219 | |||
220 | /* Create the pipe between client and server */ | ||
221 | fdpair(fds); | ||
222 | |||
223 | ctx->num_packets = num_fds * loops; | ||
224 | ctx->in_fds[0] = fds[0]; | ||
225 | ctx->in_fds[1] = fds[1]; | ||
226 | ctx->ready_out = ready_out; | ||
227 | ctx->wakefd = wakefd; | ||
228 | |||
229 | pth[i] = create_worker(ctx, (void *)receiver); | ||
230 | |||
231 | snd_ctx->out_fds[i] = fds[1]; | ||
232 | if (!thread_mode) | ||
233 | close(fds[0]); | ||
234 | } | ||
235 | |||
236 | /* Now we have all the fds, fork the senders */ | ||
237 | for (i = 0; i < num_fds; i++) { | ||
238 | snd_ctx->ready_out = ready_out; | ||
239 | snd_ctx->wakefd = wakefd; | ||
240 | snd_ctx->num_fds = num_fds; | ||
241 | |||
242 | pth[num_fds+i] = create_worker(snd_ctx, (void *)sender); | ||
243 | } | ||
244 | |||
245 | /* Close the fds we have left */ | ||
246 | if (!thread_mode) | ||
247 | for (i = 0; i < num_fds; i++) | ||
248 | close(snd_ctx->out_fds[i]); | ||
249 | |||
250 | /* Return number of children to reap */ | ||
251 | return num_fds * 2; | ||
252 | } | ||
253 | |||
254 | static const struct option options[] = { | ||
255 | OPT_BOOLEAN('p', "pipe", &use_pipes, | ||
256 | "Use pipe() instead of socketpair()"), | ||
257 | OPT_BOOLEAN('t', "thread", &thread_mode, | ||
258 | "Be multi thread instead of multi process"), | ||
259 | OPT_INTEGER('g', "group", &num_groups, | ||
260 | "Specify number of groups"), | ||
261 | OPT_INTEGER('l', "loop", &loops, | ||
262 | "Specify number of loops"), | ||
263 | OPT_END() | ||
264 | }; | ||
265 | |||
266 | static const char * const bench_sched_message_usage[] = { | ||
267 | "perf bench sched messaging <options>", | ||
268 | NULL | ||
269 | }; | ||
270 | |||
271 | int bench_sched_messaging(int argc, const char **argv, | ||
272 | const char *prefix __used) | ||
273 | { | ||
274 | unsigned int i, total_children; | ||
275 | struct timeval start, stop, diff; | ||
276 | unsigned int num_fds = 20; | ||
277 | int readyfds[2], wakefds[2]; | ||
278 | char dummy; | ||
279 | pthread_t *pth_tab; | ||
280 | |||
281 | argc = parse_options(argc, argv, options, | ||
282 | bench_sched_message_usage, 0); | ||
283 | |||
284 | pth_tab = malloc(num_fds * 2 * num_groups * sizeof(pthread_t)); | ||
285 | if (!pth_tab) | ||
286 | barf("main:malloc()"); | ||
287 | |||
288 | fdpair(readyfds); | ||
289 | fdpair(wakefds); | ||
290 | |||
291 | total_children = 0; | ||
292 | for (i = 0; i < num_groups; i++) | ||
293 | total_children += group(pth_tab+total_children, num_fds, | ||
294 | readyfds[1], wakefds[0]); | ||
295 | |||
296 | /* Wait for everyone to be ready */ | ||
297 | for (i = 0; i < total_children; i++) | ||
298 | if (read(readyfds[0], &dummy, 1) != 1) | ||
299 | barf("Reading for readyfds"); | ||
300 | |||
301 | gettimeofday(&start, NULL); | ||
302 | |||
303 | /* Kick them off */ | ||
304 | if (write(wakefds[1], &dummy, 1) != 1) | ||
305 | barf("Writing to start them"); | ||
306 | |||
307 | /* Reap them all */ | ||
308 | for (i = 0; i < total_children; i++) | ||
309 | reap_worker(pth_tab[i]); | ||
310 | |||
311 | gettimeofday(&stop, NULL); | ||
312 | |||
313 | timersub(&stop, &start, &diff); | ||
314 | |||
315 | switch (bench_format) { | ||
316 | case BENCH_FORMAT_DEFAULT: | ||
317 | printf("# %d sender and receiver %s per group\n", | ||
318 | num_fds, thread_mode ? "threads" : "processes"); | ||
319 | printf("# %d groups == %d %s run\n\n", | ||
320 | num_groups, num_groups * 2 * num_fds, | ||
321 | thread_mode ? "threads" : "processes"); | ||
322 | printf(" %14s: %lu.%03lu [sec]\n", "Total time", | ||
323 | diff.tv_sec, | ||
324 | (unsigned long) (diff.tv_usec/1000)); | ||
325 | break; | ||
326 | case BENCH_FORMAT_SIMPLE: | ||
327 | printf("%lu.%03lu\n", diff.tv_sec, | ||
328 | (unsigned long) (diff.tv_usec/1000)); | ||
329 | break; | ||
330 | default: | ||
331 | /* reaching here is something disaster */ | ||
332 | fprintf(stderr, "Unknown format:%d\n", bench_format); | ||
333 | exit(1); | ||
334 | break; | ||
335 | } | ||
336 | |||
337 | return 0; | ||
338 | } | ||
diff --git a/tools/perf/bench/sched-pipe.c b/tools/perf/bench/sched-pipe.c new file mode 100644 index 000000000000..4f77c7c27640 --- /dev/null +++ b/tools/perf/bench/sched-pipe.c | |||
@@ -0,0 +1,127 @@ | |||
1 | /* | ||
2 | * | ||
3 | * sched-pipe.c | ||
4 | * | ||
5 | * pipe: Benchmark for pipe() | ||
6 | * | ||
7 | * Based on pipe-test-1m.c by Ingo Molnar <mingo@redhat.com> | ||
8 | * http://people.redhat.com/mingo/cfs-scheduler/tools/pipe-test-1m.c | ||
9 | * Ported to perf by Hitoshi Mitake <mitake@dcl.info.waseda.ac.jp> | ||
10 | * | ||
11 | */ | ||
12 | |||
13 | #include "../perf.h" | ||
14 | #include "../util/util.h" | ||
15 | #include "../util/parse-options.h" | ||
16 | #include "../builtin.h" | ||
17 | #include "bench.h" | ||
18 | |||
19 | #include <unistd.h> | ||
20 | #include <stdio.h> | ||
21 | #include <stdlib.h> | ||
22 | #include <signal.h> | ||
23 | #include <sys/wait.h> | ||
24 | #include <linux/unistd.h> | ||
25 | #include <string.h> | ||
26 | #include <errno.h> | ||
27 | #include <assert.h> | ||
28 | #include <sys/time.h> | ||
29 | #include <sys/types.h> | ||
30 | |||
31 | #define LOOPS_DEFAULT 1000000 | ||
32 | static int loops = LOOPS_DEFAULT; | ||
33 | |||
34 | static const struct option options[] = { | ||
35 | OPT_INTEGER('l', "loop", &loops, | ||
36 | "Specify number of loops"), | ||
37 | OPT_END() | ||
38 | }; | ||
39 | |||
40 | static const char * const bench_sched_pipe_usage[] = { | ||
41 | "perf bench sched pipe <options>", | ||
42 | NULL | ||
43 | }; | ||
44 | |||
45 | int bench_sched_pipe(int argc, const char **argv, | ||
46 | const char *prefix __used) | ||
47 | { | ||
48 | int pipe_1[2], pipe_2[2]; | ||
49 | int m = 0, i; | ||
50 | struct timeval start, stop, diff; | ||
51 | unsigned long long result_usec = 0; | ||
52 | |||
53 | /* | ||
54 | * why does "ret" exist? | ||
55 | * discarding returned value of read(), write() | ||
56 | * causes error in building environment for perf | ||
57 | */ | ||
58 | int ret, wait_stat; | ||
59 | pid_t pid, retpid; | ||
60 | |||
61 | argc = parse_options(argc, argv, options, | ||
62 | bench_sched_pipe_usage, 0); | ||
63 | |||
64 | assert(!pipe(pipe_1)); | ||
65 | assert(!pipe(pipe_2)); | ||
66 | |||
67 | pid = fork(); | ||
68 | assert(pid >= 0); | ||
69 | |||
70 | gettimeofday(&start, NULL); | ||
71 | |||
72 | if (!pid) { | ||
73 | for (i = 0; i < loops; i++) { | ||
74 | ret = read(pipe_1[0], &m, sizeof(int)); | ||
75 | ret = write(pipe_2[1], &m, sizeof(int)); | ||
76 | } | ||
77 | } else { | ||
78 | for (i = 0; i < loops; i++) { | ||
79 | ret = write(pipe_1[1], &m, sizeof(int)); | ||
80 | ret = read(pipe_2[0], &m, sizeof(int)); | ||
81 | } | ||
82 | } | ||
83 | |||
84 | gettimeofday(&stop, NULL); | ||
85 | timersub(&stop, &start, &diff); | ||
86 | |||
87 | if (pid) { | ||
88 | retpid = waitpid(pid, &wait_stat, 0); | ||
89 | assert((retpid == pid) && WIFEXITED(wait_stat)); | ||
90 | } else { | ||
91 | exit(0); | ||
92 | } | ||
93 | |||
94 | switch (bench_format) { | ||
95 | case BENCH_FORMAT_DEFAULT: | ||
96 | printf("# Extecuted %d pipe operations between two tasks\n\n", | ||
97 | loops); | ||
98 | |||
99 | result_usec = diff.tv_sec * 1000000; | ||
100 | result_usec += diff.tv_usec; | ||
101 | |||
102 | printf(" %14s: %lu.%03lu [sec]\n\n", "Total time", | ||
103 | diff.tv_sec, | ||
104 | (unsigned long) (diff.tv_usec/1000)); | ||
105 | |||
106 | printf(" %14lf usecs/op\n", | ||
107 | (double)result_usec / (double)loops); | ||
108 | printf(" %14d ops/sec\n", | ||
109 | (int)((double)loops / | ||
110 | ((double)result_usec / (double)1000000))); | ||
111 | break; | ||
112 | |||
113 | case BENCH_FORMAT_SIMPLE: | ||
114 | printf("%lu.%03lu\n", | ||
115 | diff.tv_sec, | ||
116 | (unsigned long) (diff.tv_usec / 1000)); | ||
117 | break; | ||
118 | |||
119 | default: | ||
120 | /* reaching here is something disaster */ | ||
121 | fprintf(stderr, "Unknown format:%d\n", bench_format); | ||
122 | exit(1); | ||
123 | break; | ||
124 | } | ||
125 | |||
126 | return 0; | ||
127 | } | ||