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} 602