• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /******************************************************************************/
2 /* Copyright Rusty Russell,                                                   */
3 /* Copyright Pierre Peiffer                                                   */
4 /* Copyright Zhang, Yanmin,                                                   */
5 /* Copyright Ingo Molnar,                                                     */
6 /* Copyright Arjan van de Ven,                                                */
7 /* Copyright (c) International Business Machines  Corp., 2008                 */
8 /*                                                                            */
9 /* This program is free software;  you can redistribute it and/or modify      */
10 /* it under the terms of the GNU General Public License as published by       */
11 /* the Free Software Foundation; either version 2 of the License, or          */
12 /* (at your option) any later version.                                        */
13 /*                                                                            */
14 /* This program is distributed in the hope that it will be useful,            */
15 /* but WITHOUT ANY WARRANTY;  without even the implied warranty of            */
16 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See                  */
17 /* the GNU General Public License for more details.                           */
18 /*                                                                            */
19 /* You should have received a copy of the GNU General Public License          */
20 /* along with this program;  if not, write to the Free Software               */
21 /* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA    */
22 /*                                                                            */
23 /******************************************************************************/
24 
25 /******************************************************************************/
26 /*                                                                            */
27 /* File:        hackbench.c                                                   */
28 /*                                                                            */
29 /* Description: hackbench tests the Linux scheduler. Test groups of 20        */
30 /*              processes spraying to 20 receivers                            */
31 /*                                                                            */
32 /* Total Tests: 1                                                             */
33 /*                                                                            */
34 /* Test Name:   hackbench01 and hackbench02                                   */
35 /*                                                                            */
36 /* Test Assertion:                                                            */
37 /*                                                                            */
38 /* Author(s):   Rusty Russell <rusty@rustcorp.com.au>,                        */
39 /*              Pierre Peiffer <pierre.peiffer@bull.net>,                     */
40 /*              Ingo Molnar <mingo@elte.hu>,                                  */
41 /*              Arjan van de Ven <arjan@infradead.org>,                       */
42 /*              "Zhang, Yanmin" <yanmin_zhang@linux.intel.com>,               */
43 /*              Nathan Lynch <ntl@pobox.com>                                  */
44 /*                                                                            */
45 /* History:     Included into LTP                                             */
46 /*                  - June 26 2008 - Subrata Modak<subrata@linux.vnet.ibm.com>*/
47 /*                                                                            */
48 /******************************************************************************/
49 #include <pthread.h>
50 #include <stdio.h>
51 #include <stdlib.h>
52 #include <string.h>
53 #include <errno.h>
54 #include <unistd.h>
55 #include <sys/types.h>
56 #include <sys/socket.h>
57 #include <sys/wait.h>
58 #include <sys/time.h>
59 #include <sys/poll.h>
60 #include <limits.h>
61 
62 #define SAFE_FREE(p) { if (p) { free(p); (p)=NULL; } }
63 #define DATASIZE 100
64 static struct sender_context **snd_ctx_tab;	/*Table for sender context pointers. */
65 static struct receiver_context **rev_ctx_tab;	/*Table for receiver context pointers. */
66 static int gr_num = 0;		/*For group calculation */
67 static unsigned int loops = 100;
68 /*
69  * 0 means thread mode and others mean process (default)
70  */
71 static unsigned int process_mode = 1;
72 
73 static int use_pipes = 0;
74 
75 struct sender_context {
76 	unsigned int num_fds;
77 	int ready_out;
78 	int wakefd;
79 	int out_fds[0];
80 };
81 
82 struct receiver_context {
83 	unsigned int num_packets;
84 	int in_fds[2];
85 	int ready_out;
86 	int wakefd;
87 };
88 
barf(const char * msg)89 static void barf(const char *msg)
90 {
91 	fprintf(stderr, "%s (error: %s)\n", msg, strerror(errno));
92 	exit(1);
93 }
94 
print_usage_exit(void)95 static void print_usage_exit(void)
96 {
97 	printf
98 	    ("Usage: hackbench [-pipe] <num groups> [process|thread] [loops]\n");
99 	exit(1);
100 }
101 
fdpair(int fds[2])102 static void fdpair(int fds[2])
103 {
104 	if (use_pipes) {
105 		if (pipe(fds) == 0)
106 			return;
107 	} else {
108 		if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) == 0)
109 			return;
110 	}
111 	barf("Creating fdpair");
112 }
113 
114 /* Block until we're ready to go */
ready(int ready_out,int wakefd)115 static void ready(int ready_out, int wakefd)
116 {
117 	char dummy;
118 	struct pollfd pollfd = {.fd = wakefd,.events = POLLIN };
119 
120 	/* Tell them we're ready. */
121 	if (write(ready_out, &dummy, 1) != 1)
122 		barf("CLIENT: ready write");
123 
124 	/* Wait for "GO" signal */
125 	if (poll(&pollfd, 1, -1) != 1)
126 		barf("poll");
127 }
128 
129 /* Sender sprays loops messages down each file descriptor */
sender(struct sender_context * ctx)130 static void *sender(struct sender_context *ctx)
131 {
132 	char data[DATASIZE];
133 	unsigned int i, j;
134 
135 	ready(ctx->ready_out, ctx->wakefd);
136 
137 	/* Now pump to every receiver. */
138 	for (i = 0; i < loops; i++) {
139 		for (j = 0; j < ctx->num_fds; j++) {
140 			int ret, done = 0;
141 
142 again:
143 			ret =
144 			    write(ctx->out_fds[j], data + done,
145 				  sizeof(data) - done);
146 			if (ret < 0)
147 				barf("SENDER: write");
148 			done += ret;
149 			if (done < sizeof(data))
150 				goto again;
151 		}
152 	}
153 
154 	return NULL;
155 }
156 
157 /* One receiver per fd */
receiver(struct receiver_context * ctx)158 static void *receiver(struct receiver_context *ctx)
159 {
160 	unsigned int i;
161 
162 	if (process_mode)
163 		close(ctx->in_fds[1]);
164 
165 	/* Wait for start... */
166 	ready(ctx->ready_out, ctx->wakefd);
167 
168 	/* Receive them all */
169 	for (i = 0; i < ctx->num_packets; i++) {
170 		char data[DATASIZE];
171 		int ret, done = 0;
172 
173 again:
174 		ret = read(ctx->in_fds[0], data + done, DATASIZE - done);
175 		if (ret < 0)
176 			barf("SERVER: read");
177 		done += ret;
178 		if (done < DATASIZE)
179 			goto again;
180 	}
181 
182 	return NULL;
183 }
184 
create_worker(void * ctx,void * (* func)(void *))185 pthread_t create_worker(void *ctx, void *(*func) (void *))
186 {
187 	pthread_attr_t attr;
188 	pthread_t childid;
189 	int err;
190 
191 	if (process_mode) {
192 		/* process mode */
193 		/* Fork the receiver. */
194 		switch (fork()) {
195 		case -1:
196 			barf("fork()");
197 		case 0:
198 			(*func) (ctx);
199 			exit(0);
200 		}
201 
202 		return (pthread_t) 0;
203 	}
204 
205 	if (pthread_attr_init(&attr) != 0)
206 		barf("pthread_attr_init:");
207 
208 #ifndef __ia64__
209 	if (pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN) != 0)
210 		barf("pthread_attr_setstacksize");
211 #endif
212 
213 	if ((err = pthread_create(&childid, &attr, func, ctx)) != 0) {
214 		fprintf(stderr, "pthread_create failed: %s (%d)\n",
215 			strerror(err), err);
216 		exit(-1);
217 	}
218 	return (childid);
219 }
220 
reap_worker(pthread_t id)221 void reap_worker(pthread_t id)
222 {
223 	int status;
224 
225 	if (process_mode) {
226 		/* process mode */
227 		wait(&status);
228 		if (!WIFEXITED(status))
229 			exit(1);
230 	} else {
231 		void *status;
232 
233 		pthread_join(id, &status);
234 	}
235 }
236 
237 /* One group of senders and receivers */
group(pthread_t * pth,unsigned int num_fds,int ready_out,int wakefd)238 static unsigned int group(pthread_t * pth,
239 			  unsigned int num_fds, int ready_out, int wakefd)
240 {
241 	unsigned int i;
242 	struct sender_context *snd_ctx = malloc(sizeof(struct sender_context) + num_fds * sizeof(int));
243 	if (!snd_ctx)
244 		barf("malloc()");
245 	else
246 		snd_ctx_tab[gr_num] = snd_ctx;
247 
248 	for (i = 0; i < num_fds; i++) {
249 		int fds[2];
250 		struct receiver_context *ctx = malloc(sizeof(*ctx));
251 
252 		if (!ctx)
253 			barf("malloc()");
254 		else
255 			rev_ctx_tab[gr_num * num_fds + i] = ctx;
256 
257 		/* Create the pipe between client and server */
258 		fdpair(fds);
259 
260 		ctx->num_packets = num_fds * loops;
261 		ctx->in_fds[0] = fds[0];
262 		ctx->in_fds[1] = fds[1];
263 		ctx->ready_out = ready_out;
264 		ctx->wakefd = wakefd;
265 
266 		pth[i] = create_worker(ctx, (void *)(void *)receiver);
267 
268 		snd_ctx->out_fds[i] = fds[1];
269 		if (process_mode)
270 			close(fds[0]);
271 	}
272 
273 	/* Now we have all the fds, fork the senders */
274 	for (i = 0; i < num_fds; i++) {
275 		snd_ctx->ready_out = ready_out;
276 		snd_ctx->wakefd = wakefd;
277 		snd_ctx->num_fds = num_fds;
278 
279 		pth[num_fds + i] =
280 		    create_worker(snd_ctx, (void *)(void *)sender);
281 	}
282 
283 	/* Close the fds we have left */
284 	if (process_mode)
285 		for (i = 0; i < num_fds; i++)
286 			close(snd_ctx->out_fds[i]);
287 
288 	gr_num++;
289 	/* Return number of children to reap */
290 	return num_fds * 2;
291 }
292 
main(int argc,char * argv[])293 int main(int argc, char *argv[])
294 {
295 	unsigned int i, j, num_groups = 10, total_children;
296 	struct timeval start, stop, diff;
297 	unsigned int num_fds = 20;
298 	int readyfds[2], wakefds[2];
299 	char dummy;
300 	pthread_t *pth_tab;
301 
302 	if (argv[1] && strcmp(argv[1], "-pipe") == 0) {
303 		use_pipes = 1;
304 		argc--;
305 		argv++;
306 	}
307 
308 	if (argc >= 2 && (num_groups = atoi(argv[1])) == 0)
309 		print_usage_exit();
310 
311 	printf("Running with %d*40 (== %d) tasks.\n",
312 	       num_groups, num_groups * 40);
313 
314 	fflush(NULL);
315 
316 	if (argc > 2) {
317 		if (!strcmp(argv[2], "process"))
318 			process_mode = 1;
319 		else if (!strcmp(argv[2], "thread"))
320 			process_mode = 0;
321 		else
322 			print_usage_exit();
323 	}
324 
325 	if (argc > 3)
326 		loops = atoi(argv[3]);
327 
328 	pth_tab = malloc(num_fds * 2 * num_groups * sizeof(pthread_t));
329 	snd_ctx_tab = malloc(num_groups * sizeof(void *));
330 	rev_ctx_tab = malloc(num_groups * num_fds * sizeof(void *));
331 	if (!pth_tab || !snd_ctx_tab || !rev_ctx_tab)
332 		barf("main:malloc()");
333 
334 	fdpair(readyfds);
335 	fdpair(wakefds);
336 
337 	total_children = 0;
338 	for (i = 0; i < num_groups; i++)
339 		total_children +=
340 		    group(pth_tab + total_children, num_fds, readyfds[1],
341 			  wakefds[0]);
342 
343 	/* Wait for everyone to be ready */
344 	for (i = 0; i < total_children; i++)
345 		if (read(readyfds[0], &dummy, 1) != 1)
346 			barf("Reading for readyfds");
347 
348 	gettimeofday(&start, NULL);
349 
350 	/* Kick them off */
351 	if (write(wakefds[1], &dummy, 1) != 1)
352 		barf("Writing to start them");
353 
354 	/* Reap them all */
355 	for (i = 0; i < total_children; i++)
356 		reap_worker(pth_tab[i]);
357 
358 	gettimeofday(&stop, NULL);
359 
360 	/* Print time... */
361 	timersub(&stop, &start, &diff);
362 	printf("Time: %lu.%03lu\n", diff.tv_sec, diff.tv_usec / 1000);
363 
364 	/* free the memory */
365 	for (i = 0; i < num_groups; i++) {
366 		for (j = 0; j < num_fds; j++) {
367 			SAFE_FREE(rev_ctx_tab[i * num_fds + j])
368 		}
369 		SAFE_FREE(snd_ctx_tab[i]);
370 	}
371 	SAFE_FREE(pth_tab);
372 	SAFE_FREE(snd_ctx_tab);
373 	SAFE_FREE(rev_ctx_tab);
374 	exit(0);
375 }
376