]> git.saurik.com Git - apple/xnu.git/blame - tools/tests/libMicro/apple/lb_mmtest.c
xnu-3789.1.32.tar.gz
[apple/xnu.git] / tools / tests / libMicro / apple / lb_mmtest.c
CommitLineData
b0d623f7
A
1/*
2 * Copyright (c) 2006 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29
30/*
31 * Order of Execution
32 *
33 * benchmark_init
34 *
35 * benchmark_optswitch
36 *
37 * benchmark_initrun
38 *
39 * benchmark_initworker
40 * benchmark_initbatch
41 * benchmark
42 * benchmark_finibatch
43 * benchmark_initbatch
44 * benchmark
45 * benchmark_finibatch, etc.
46 * benchmark_finiworker
47 *
48 * benchmark_result
49 *
50 * benchmark_finirun
51 *
52 * benchmark_fini
53 */
54
55
56
57#ifdef __sun
58#pragma ident "@(#)lb_mmtest.c 1.0 08/21/06 Apple Inc."
59#endif
60
61
62
63#include <unistd.h>
64#include <stdlib.h>
65#include <stdio.h>
66
67#include <mach/boolean.h>
68#include <mach/mach_error.h>
69#include <mach/mach.h>
70#include <mach/notify.h>
71#include <servers/bootstrap.h>
72#include <signal.h>
73#include <stdio.h>
74#include <stdlib.h>
75#include <string.h>
76#include <sys/signal.h>
77#include <sys/time.h>
78#include <sys/types.h>
79
80#include "../libmicro.h"
81
82/*
83 * Your state variables should live in the tsd_t struct below
84 */
85typedef struct {
86 int server_mode;
87 boolean_t verbose;
88 boolean_t oneway;
89 int overwrite;
90 int msg_type;
91 int num_ints;
92 int num_msgs;
93 const char *server_port_name;
94 mach_port_t server_port;
95 mach_port_t reply_port;
96 int request_msg_size;
97 void *request_msg;
98 int reply_msg_size;
99 void *reply_msg;
100 void *ints;
101 long pid;
102} tsd_t;
103
104static boolean_t opt_verbose;
105static boolean_t opt_oneway;
106static int opt_num_msgs;
107static int opt_msg_type;
108static int opt_num_ints;
109static char * opt_server_port_name;
110
111#pragma mark *** definitions from MMTest.c
112/*
113 * These variables were taken from MMtest.c
114 */
115typedef struct {
116 mach_msg_header_t header;
117 mach_msg_trailer_t trailer; // subtract this when sending
118} ipc_trivial_message;
119
120typedef struct {
121 mach_msg_header_t header;
122 u_int32_t numbers[0];
123 mach_msg_trailer_t trailer; // subtract this when sending
124} ipc_inline_message;
125
126typedef struct {
127 mach_msg_header_t header;
128 mach_msg_body_t body;
129 mach_msg_ool_descriptor_t descriptor;
130 mach_msg_trailer_t trailer; // subtract this when sending
131} ipc_complex_message;
132
133void signal_handler(int sig) {
134}
135
136enum {
137 msg_type_trivial = 0,
138 msg_type_inline = 1,
139 msg_type_complex = 2
140};
141
142void server(void *tsd);
143void client(void *tsd);
144
145#pragma mark *** routines from MMTest.c
146/*
147 * These routines were taken from MMtest.c
148 */
149
150void server(void *tsd) {
151 mach_msg_header_t *request;
152 mach_msg_header_t *reply;
153 mach_msg_option_t option;
154 kern_return_t ret;
155
156 tsd_t *ts = (tsd_t *)tsd;
157
158 request = (mach_msg_header_t *)ts->request_msg;
159
160 reply = (mach_msg_header_t *)ts->reply_msg;
161
162#ifndef OPTIMIZED_SERVER
163 for (;;) {
164#endif /* !OPTIMIZED_SERVER */
165
166 if (ts->verbose) printf("Awaiting message\n");
167 option = MACH_RCV_MSG|MACH_RCV_INTERRUPT|MACH_RCV_LARGE;
168 ret = mach_msg(request,
169 option,
170 0,
171 ts->request_msg_size,
172 ts->server_port,
173 MACH_MSG_TIMEOUT_NONE,
174 MACH_PORT_NULL);
175
176#ifdef OPTIMIZED_SERVER
177 for (;;) {
178 mach_msg_header_t *tmp;
179#endif /* OPTIMIZED_SERVER */
180
181 if (MACH_MSG_SUCCESS != ret)
182 break;
183 if (ts->verbose) printf("Received message\n");
184 if (request->msgh_bits & MACH_MSGH_BITS_COMPLEX) {
185 ipc_complex_message *complex_request;
186
187 complex_request = (ipc_complex_message *)ts->request_msg;
188 ret = vm_deallocate(mach_task_self(),
189 (vm_address_t)complex_request->descriptor.address,
190 complex_request->descriptor.size);
191 }
192 if (1 == request->msgh_id) {
193 if (ts->verbose) printf("Sending reply\n");
194 reply->msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE, 0);
195 reply->msgh_size = ts->reply_msg_size;
196 reply->msgh_remote_port = request->msgh_remote_port;
197 reply->msgh_local_port = MACH_PORT_NULL;
198 reply->msgh_id = 2;
199
200#ifdef OPTIMIZED_SERVER
201 option = MACH_SEND_MSG|MACH_RCV_MSG|MACH_RCV_INTERRUPT|MACH_RCV_LARGE;
202 } else {
203 option = MACH_RCV_MSG|MACH_RCV_INTERRUPT|MACH_RCV_LARGE;
204 }
205
206 ret = mach_msg( reply,
207 option,
208 ts->reply_msg_size,
209 ts->request_msg_size,
210 ts->server_port,
211 MACH_MSG_TIMEOUT_NONE,
212 MACH_PORT_NULL);
213 tmp = reply;
214 reply = request;
215 request = tmp;
216#else /* !OPTIMIZED_SERVER */
217 ret = mach_msg(reply,
218 MACH_SEND_MSG,
219 ts->reply_msg_size,
220 0,
221 MACH_PORT_NULL,
222 MACH_MSG_TIMEOUT_NONE,
223 MACH_PORT_NULL);
224 if (ret != MACH_MSG_SUCCESS)
225 break;
226 }
227#endif /* !OPTIMIZED_SERVER */
228 }
229
230 if (MACH_RCV_INTERRUPTED != ret) {
231 mach_error("mach_msg: ", ret);
232 exit(1);
233 }
234}
235
236void client(void *tsd) {
237 mach_msg_header_t *request;
238 mach_msg_header_t *reply;
239 mach_msg_option_t option;
240 kern_return_t ret;
241 int idx;
242
243 tsd_t *ts = (tsd_t *)tsd;
244
245#ifdef SWAP_BUFFERS
246 mach_msg_header_t *tmp;
247#endif
248
249 request = (mach_msg_header_t *)ts->request_msg;
250 reply = (mach_msg_header_t *)ts->reply_msg;
251
252 for (idx = 0; idx < ts->num_msgs; idx++) {
253 request->msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND,
254 MACH_MSG_TYPE_MAKE_SEND_ONCE);
255 request->msgh_size = ts->request_msg_size;
256 request->msgh_remote_port = ts->server_port;
257 request->msgh_local_port = ts->reply_port;
258
259 if (ts->msg_type == msg_type_complex) {
260 ipc_complex_message *complexmsg = (ipc_complex_message *)request;
261
262 request->msgh_bits |= MACH_MSGH_BITS_COMPLEX;
263 complexmsg->body.msgh_descriptor_count = 1;
264 complexmsg->descriptor.address = ts->ints;
265 complexmsg->descriptor.size = ts->num_ints * sizeof(u_int32_t);
266 complexmsg->descriptor.deallocate = FALSE;
267 complexmsg->descriptor.copy = MACH_MSG_VIRTUAL_COPY;
268 complexmsg->descriptor.type = MACH_MSG_OOL_DESCRIPTOR;
269 }
270
271 if (ts->oneway) {
272 request->msgh_id = 0;
273 option = MACH_SEND_MSG;
274 } else {
275 request->msgh_id = 1;
276 option = MACH_SEND_MSG|MACH_RCV_MSG;
277 }
278
279 if (ts->verbose) printf("Sending request\n");
280#ifdef SWAP_BUFFERS
281 ret = mach_msg( request,
282 option,
283 ts->request_msg_size,
284 ts->reply_msg_size,
285 ts->reply_port,
286 MACH_MSG_TIMEOUT_NONE,
287 MACH_PORT_NULL);
288 if (MACH_MSG_SUCCESS != ret) {
289 mach_error("client: mach_msg: ", ret);
290 fprintf(stderr, "bailing after %u iterations\n", idx);
291 exit(1);
292 }
293 tmp = request;
294 request = reply;
295 reply = tmp;
296#else
297 ret = mach_msg_overwrite(request,
298 option,
299 ts->request_msg_size,
300 ts->reply_msg_size,
301 ts->reply_port,
302 MACH_MSG_TIMEOUT_NONE,
303 MACH_PORT_NULL,
304 reply,
305 0);
306 if (MACH_MSG_SUCCESS != ret) {
307 mach_error("client: mach_msg_overwrite: ", ret);
308 fprintf(stderr, "bailing after %u iterations\n", idx);
309 exit(1);
310 }
311#endif
312 if (ts->verbose && !ts->oneway) printf("Received reply\n");
313 }
314}
315
316
317#pragma mark *** Darbench routines
318
319/*
320 * These routines are required by darbench
321 */
322
323/*ARGSUSED*/
324int
325benchmark_initbatch(void *tsd)
326{
327 /*
328 * initialize your state variables here second
329 */
330 long pid;
331 tsd_t *ts = (tsd_t *)tsd;
332
333 ts->server_mode = -1;
334 ts->verbose = opt_verbose;
335 ts->oneway = opt_oneway;
336 ts->overwrite = 0;
337 ts->msg_type = opt_msg_type;
338 ts->num_ints = opt_num_ints;
339 ts->num_msgs = opt_num_msgs;
340 ts->server_port_name = opt_server_port_name;
341 ts->server_port = MACH_PORT_NULL;
342 ts->reply_port = MACH_PORT_NULL;
343 ts->request_msg = NULL;
344 ts->request_msg_size = 0;
345 ts->reply_msg = NULL;
346 ts->reply_msg_size = 0;
347
348 switch (ts->msg_type) {
349 case msg_type_trivial:
350 ts->request_msg_size = sizeof(ipc_trivial_message);
351 break;
352
353 case msg_type_inline:
354 ts->request_msg_size = sizeof(ipc_inline_message) +
355 sizeof(u_int32_t) * ts->num_ints;
356 break;
357
358 case msg_type_complex:
359 ts->request_msg_size = sizeof(ipc_complex_message);
360 ts->ints = malloc(sizeof(u_int32_t) * ts->num_ints);
361 break;
362 }
363
364 ts->request_msg = malloc(ts->request_msg_size);
365 ts->reply_msg = malloc(ts->reply_msg_size);
366
367 if (ts->server_mode) {
368 kern_return_t ret = 0;
369 mach_port_t bsport;
370
371 ts->reply_msg_size -= sizeof(mach_msg_trailer_t);
372 ret = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE,
373 &(ts->server_port));
374 if (KERN_SUCCESS != ret) {
375 mach_error("mach_port_allocate(): ", ret);
376 exit(1);
377 }
378 ret = mach_port_insert_right(mach_task_self(), ts->server_port,
379 ts->server_port, MACH_MSG_TYPE_MAKE_SEND);
380 if (KERN_SUCCESS != ret) {
381 mach_error("mach_port_insert_right(): ", ret);
382 exit(1);
383 }
384 ret = task_get_bootstrap_port(mach_task_self(), &bsport);
385 if (KERN_SUCCESS != ret) {
386 mach_error("task_get_bootstrap_port(): ", ret);
387 exit(1);
388 }
389 ret = bootstrap_check_in(bsport, (char *)ts->server_port_name,
390 &ts->server_port);
391 if (KERN_SUCCESS != ret) {
392 mach_error("bootstrap_register(): ", ret);
393 exit(1);
394 }
395 } else { /* client mode */
396 kern_return_t ret = 0;
397 mach_port_t bsport;
398
399 ts->request_msg_size -= sizeof(mach_msg_trailer_t);
400
401 ret = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE,
402 &(ts->reply_port));
403 if (KERN_SUCCESS != ret) {
404 mach_error("mach_port_allocate(): ", ret);
405 exit(1);
406 }
407
408 ret = task_get_bootstrap_port(mach_task_self(), &bsport);
409 if (KERN_SUCCESS != ret) {
410 mach_error("task_get_bootstrap_port(): ", ret);
411 exit(1);
412 }
413 ret = bootstrap_look_up(bsport, (char *)ts->server_port_name,
414 &(ts->server_port));
415 if (KERN_SUCCESS != ret) {
416 mach_error("bootstrap_look_up(): ", ret);
417 exit(1);
418 }
419 }
420
421 if (ts->verbose) {
422 if (ts->server_mode) {
423 printf("Server waiting for IPC messages from client on port '%s'.\n",
424 ts->server_port_name);
425 } else {
426 printf("Client sending %d %s IPC messages to port '%s' in %s mode.\n",
427 ts->num_msgs, (ts->msg_type == msg_type_inline) ? "inline" :
428 ((ts->msg_type == msg_type_complex) ? "complex" : "trivial"),
429 ts->server_port_name, (ts->oneway ? "oneway" : "rpc"));
430 }
431 }
432
433 pid = fork();
434 switch (pid) {
435 case 0:
436 server(tsd);
437 exit(0);
438 break;
439 case -1:
440 return (-1);
441 default:
442 ts->pid = pid;
443 break;
444 }
445 return (0);
446}
447
448int
449benchmark_finirun()
450{
451 (void) fprintf(stderr, "benchmark_finirun\n");
452 return (0);
453}
454
455int
456benchmark_init()
457{
458 /*
459 * the lm_optstr must be defined here or no options for you
460 * ...and the framework will throw an error
461 * lm_optstr has two kinds of arguments, boolean (single
462 * lower case character) and with an argument (single lower
463 * case character plus a :, indicating the next option is
464 * the argument)
465 *
466 */
467 (void) sprintf(lm_optstr, "voc:t:n:p:");
468 /*
469 * tsd_t is the struct that we can pass around our
470 * state info in
471 *
472 * lm_tsdsize will allocate the space we need for this
473 * structure throughout the rest of the framework
474 */
475 lm_tsdsize = sizeof (tsd_t);
476
477 (void) sprintf(lm_usage,
478 " -v\t\tbe verbose\n"
479 " -o\t\tdo not request return reply (client)\n"
480 " -c num\t\tnumber of messages to send (client)\n"
481 " -t trivial|inline|complex\ttype of messages to send (client)\n"
482 " -n num\tnumber of 32-bit ints to send in messages\n"
483 "\t\t\t(client's value must be <= the server's)\n"
484 " -p portname\tname of port on which to communicate\n"
485 "\t\t\t(client and server must use the same value)\n");
486
487 opt_verbose = FALSE;
488 opt_oneway = FALSE;
489 opt_num_msgs = 10000;
490 opt_msg_type = msg_type_trivial;
491 opt_num_ints = 64;
492 opt_server_port_name = malloc(32);
493 strcpy(opt_server_port_name, "TEST");
494
495 return (0);
496}
497
498int
499benchmark_fini()
500{
501 free(opt_server_port_name);
502 return (0);
503}
504
505int
506benchmark_finibatch(void *tsd)
507{
508 tsd_t *ts = (tsd_t *)tsd;
509 kill(ts->pid, SIGKILL);
510 return (0);
511}
512
513char *
514benchmark_result()
515{
516 static char result = '\0';
517 (void) fprintf(stderr, "benchmark_result\n");
518 return (&result);
519}
520
521int
522benchmark_finiworker(void *tsd)
523{
524// tsd_t *ts = (tsd_t *)tsd;
525 return (0);
526}
527
528int
529benchmark_optswitch(int opt, char *optarg)
530{
531 (void) fprintf(stderr, "benchmark_optswitch\n");
532
533 switch (opt) {
534 case 'v':
535 opt_verbose = TRUE;
536 break;
537 case 'o':
538 opt_oneway = TRUE;
539 break;
540 case 'c':
541 opt_num_msgs = sizetoint(optarg);
542 break;
543 case 't':
544 if ( 0 == strcmp("trivial", optarg) )
545 opt_msg_type = msg_type_trivial;
546 else if ( 0 == strcmp("inline", optarg) )
547 opt_msg_type = msg_type_inline;
548 else if ( 0 == strcmp("complex", optarg) )
549 opt_msg_type = msg_type_complex;
550 else {
551 (void) fprintf(stderr, "incorrect argument for message type %s\n", optarg);
552 return (-1);
553 }
554 break;
555 case 'n':
556 opt_num_ints = sizetoint(optarg);
557 break;
558 case 'p':
559 strncpy(opt_server_port_name, optarg, 32);
560 break;
561 default:
562 return (-1);
563 }
564 return (0);
565}
566
567int
568benchmark_initworker(void *tsd)
569{
570 /*
571 * initialize your state variables here first
572 */
573// tsd_t *ts = (tsd_t *)tsd;
574 return (0);
575}
576
577int
578benchmark_initrun()
579{
580 (void) fprintf(stderr, "benchmark_initrun\n");
581 return (0);
582}
583
584int
585benchmark(void *tsd, result_t *res)
586{
587 /*
588 * initialize your state variables here last
589 *
590 * and realize that you are paying for your initialization here
591 * and it is really a bad idea
592 */
593// tsd_t *ts = (tsd_t *)tsd;
594 int i;
595
596 for (i = 0; i < lm_optB; i++) {
597 client(tsd);
598 }
599
600 return (0);
601}