The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/tools/tests/MMTest/MMtest.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 #include <pthread.h>
    2 #include <stdio.h>
    3 #include <stdlib.h>
    4 #include <string.h>
    5 
    6 #include <mach/mach.h>
    7 #include <mach/mach_error.h>
    8 #include <mach/notify.h>
    9 #include <servers/bootstrap.h>
   10 #include <sys/types.h>
   11 #include <sys/time.h>
   12 #include <sys/signal.h>
   13 
   14 #define MAX(A, B) ((A) < (B) ? (B) : (A))
   15 
   16 static __inline__ unsigned long long ReadTSR() {
   17         union {
   18                 unsigned long long time64;
   19                 unsigned long word[2];
   20         } now;
   21 #if defined(__i386__)
   22         /* Read from Pentium and Pentium Pro 64-bit timestamp counter.
   23          * The counter is set to 0 at processor reset and increments on
   24          * every clock cycle. */
   25         __asm__ volatile("rdtsc" : : : "eax", "edx");
   26         __asm__ volatile("movl %%eax,%0" : "=m" (now.word[0]) : : "eax");
   27         __asm__ volatile("movl %%edx,%0" : "=m" (now.word[1]) : : "edx");
   28 #elif defined(__ppc__)
   29         /* Read from PowerPC 64-bit time base register. The increment
   30          * rate of the time base is implementation-dependent, but is
   31          * 1/4th the bus clock cycle on 603/604 processors. */
   32         unsigned long t3;
   33         do {
   34                 __asm__ volatile("mftbu %0" : "=r" (now.word[0]));
   35                 __asm__ volatile("mftb %0" : "=r" (now.word[1]));
   36                 __asm__ volatile("mftbu %0" : "=r" (t3));
   37         } while (now.word[0] != t3);
   38 #else
   39 #warning Do not know how to read a time stamp register on this architecture
   40         now.time64 = 0ULL;
   41 #endif
   42         return now.time64;
   43 }
   44 
   45 typedef struct  {
   46         unsigned int        msgt_name : 8,
   47                             msgt_size : 8,
   48                             msgt_number : 12,
   49                             msgt_inline : 1,
   50                             msgt_longform : 1,
   51                             msgt_deallocate : 1,
   52                             msgt_unused : 1;
   53 } mach_msg_type_t;
   54 
   55 typedef struct  {
   56         mach_msg_type_t     msgtl_header;
   57         unsigned short      msgtl_name;
   58         unsigned short      msgtl_size;
   59         natural_t           msgtl_number;
   60 } mach_msg_type_long_t;
   61 #define MACH_MSG_TYPE_INTEGER_32 0
   62 
   63 
   64 typedef struct {
   65         mach_msg_header_t       header;
   66         mach_msg_trailer_t      trailer;                // subtract this when sending
   67 } ipc_trivial_message;
   68 
   69 typedef struct {
   70         mach_msg_header_t       header;
   71         mach_msg_type_t         type;
   72         u_int32_t               numbers[0];
   73         mach_msg_trailer_t      trailer;                // subtract this when sending
   74 } ipc_inline_message;
   75 
   76 typedef struct {
   77         mach_msg_header_t               header;
   78         mach_msg_body_t                 body;
   79         mach_msg_ool_descriptor_t       descriptor;
   80         mach_msg_trailer_t              trailer;        // subtract this when sending
   81 } ipc_complex_message;
   82 
   83 enum {
   84         msg_type_trivial = 0,
   85         msg_type_inline = 1,
   86         msg_type_complex = 2
   87 };
   88 
   89 struct port_args {
   90         int req_size;
   91         mach_msg_header_t *req_msg;
   92         int reply_size;
   93         mach_msg_header_t *reply_msg;
   94         mach_port_t port;
   95 };
   96 
   97 /* Global options */
   98 static int verbose;
   99 int oneway;
  100 int msg_type;
  101 int num_ints;
  102 int num_msgs;
  103 int num_clients;
  104 int client_delay;
  105 char *server_port_name;
  106 
  107 void signal_handler(int sig) {
  108 }
  109 
  110 void usage(const char *progname) {
  111         fprintf(stderr, "usage: %s [options]\n", progname);
  112         fprintf(stderr, "where options are:\n");
  113         fprintf(stderr, "    -verbose\t\tbe verbose\n");
  114         fprintf(stderr, "    -oneway\t\tdo not request return reply\n");
  115         fprintf(stderr, "    -count num\t\tnumber of messages to send\n");
  116         fprintf(stderr, "    -type trivial|inline|complex\ttype of messages to send\n");
  117         fprintf(stderr, "    -numints num\tnumber of 32-bit ints to send in messages\n");
  118         fprintf(stderr, "    -clients num\tnumber of client threads to run\n");
  119         fprintf(stderr, "    -delay num\t\tmicroseconds to sleep clients between messages\n");
  120         fprintf(stderr, "    -name portname\tname of port on which to communicate\n");
  121         fprintf(stderr, "default values are:\n");
  122         fprintf(stderr, "    . not verbose\n");
  123         fprintf(stderr, "    . not oneway\n");
  124         fprintf(stderr, "    . client sends 10000 messages\n");
  125         fprintf(stderr, "    . inline message type\n");
  126         fprintf(stderr, "    . 64 32-bit integers in inline/complex messages\n");
  127         fprintf(stderr, "    . avail_cpus - 1 clients\n");
  128         fprintf(stderr, "    . no delay\n");
  129         fprintf(stderr, "    . port name 'TEST'\n");
  130         exit(1);
  131 }
  132 
  133 void parse_args(int argc, char *argv[]) {
  134         host_basic_info_data_t          info;
  135         mach_msg_type_number_t          count;
  136         kern_return_t                   result;
  137 
  138         /* Initialize defaults */
  139         verbose = 0;
  140         oneway = 0;
  141         msg_type = msg_type_trivial;
  142         num_ints = 64;
  143         num_msgs = 10000;
  144         client_delay = 0;
  145         server_port_name = "TEST";
  146 
  147         count = HOST_BASIC_INFO_COUNT;
  148         result = host_info(mach_host_self(), HOST_BASIC_INFO, 
  149                         (host_info_t)&info, &count);
  150         if (result == KERN_SUCCESS)
  151                 num_clients = MAX(1, info.avail_cpus - 1);
  152         else
  153                 num_clients = 1;
  154 
  155         const char *progname = argv[0];
  156         argc--; argv++;
  157         while (0 < argc) {
  158                 if (0 == strcmp("-verbose", argv[0])) {
  159                         verbose = 1;
  160                         argc--; argv++;
  161                 } else if (0 == strcmp("-oneway", argv[0])) {
  162                         oneway = 1;
  163                         argc--; argv++;
  164                 } else if (0 == strcmp("-type", argv[0])) {
  165                         if (argc < 2) 
  166                                 usage(progname);
  167                         if (0 == strcmp("trivial", argv[1])) {
  168                                 msg_type = msg_type_trivial;
  169                         } else if (0 == strcmp("inline", argv[1])) {
  170                                 msg_type = msg_type_inline;
  171                         } else if (0 == strcmp("complex", argv[1])) {
  172                                 msg_type = msg_type_complex;
  173                         } else 
  174                                 usage(progname);
  175                         argc -= 2; argv += 2;
  176                 } else if (0 == strcmp("-name", argv[0])) {
  177                         if (argc < 2) 
  178                                 usage(progname);
  179                         server_port_name = argv[1];
  180                         argc -= 2; argv += 2;
  181                 } else if (0 == strcmp("-numints", argv[0])) {
  182                         if (argc < 2) 
  183                                 usage(progname);
  184                         num_ints = strtoul(argv[1], NULL, 0);
  185                         argc -= 2; argv += 2;
  186                 } else if (0 == strcmp("-count", argv[0])) {
  187                         if (argc < 2) 
  188                                 usage(progname);
  189                         num_msgs = strtoul(argv[1], NULL, 0);
  190                         argc -= 2; argv += 2;
  191                 }  else if (0 == strcmp("-clients", argv[0])) {
  192                         if (argc < 2) 
  193                                 usage(progname);
  194                         num_clients = strtoul(argv[1], NULL, 0);
  195                         argc -= 2; argv += 2;
  196                 } else if (0 == strcmp("-delay", argv[0])) {
  197                         if (argc < 2) 
  198                                 usage(progname);
  199                         client_delay = strtoul(argv[1], NULL, 0);
  200                         argc -= 2; argv += 2;
  201                 } else 
  202                         usage(progname);
  203         }
  204 }
  205 
  206 void setup_server_ports(struct port_args *ports)
  207 {
  208         kern_return_t ret = 0;
  209         mach_port_t bsport;
  210 
  211         ports->req_size = MAX(sizeof(ipc_inline_message) +  
  212                         sizeof(u_int32_t) * num_ints, 
  213                         sizeof(ipc_complex_message));
  214         ports->reply_size = sizeof(ipc_trivial_message) - 
  215                 sizeof(mach_msg_trailer_t);
  216         ports->req_msg = malloc(ports->req_size);
  217         ports->reply_msg = malloc(ports->reply_size);
  218 
  219         ret = mach_port_allocate(mach_task_self(), 
  220                         MACH_PORT_RIGHT_RECEIVE,  
  221                         &(ports->port));
  222         if (KERN_SUCCESS != ret) {
  223                 mach_error("mach_port_allocate(): ", ret);
  224                 exit(1);
  225         }
  226 
  227         ret = mach_port_insert_right(mach_task_self(), 
  228                         ports->port, 
  229                         ports->port, 
  230                         MACH_MSG_TYPE_MAKE_SEND);
  231         if (KERN_SUCCESS != ret) {
  232                 mach_error("mach_port_insert_right(): ", ret);
  233                 exit(1);
  234         }
  235 
  236         ret = task_get_bootstrap_port(mach_task_self(), &bsport);
  237         if (KERN_SUCCESS != ret) {
  238                 mach_error("task_get_bootstrap_port(): ", ret);
  239                 exit(1);
  240         }
  241 
  242         ret = bootstrap_register(bsport, server_port_name, ports->port);
  243         if (KERN_SUCCESS != ret) {
  244                 mach_error("bootstrap_register(): ", ret);
  245                 exit(1);
  246         }
  247         if (verbose) {
  248                 printf("server waiting for IPC messages from client on port '%s'.\n",
  249                                 server_port_name);
  250         }
  251 }
  252 
  253 void setup_client_ports(struct port_args *ports)
  254 {
  255         kern_return_t ret = 0;
  256         switch(msg_type) {
  257                 case msg_type_trivial:
  258                         ports->req_size = sizeof(ipc_trivial_message);
  259                         break;
  260                 case msg_type_inline:
  261                         ports->req_size = sizeof(ipc_inline_message) +  
  262                                 sizeof(u_int32_t) * num_ints;
  263                         break;
  264                 case msg_type_complex:
  265                         ports->req_size = sizeof(ipc_complex_message);
  266                         break;
  267         }
  268         ports->req_size -= sizeof(mach_msg_trailer_t);
  269         ports->reply_size = sizeof(ipc_trivial_message);
  270         ports->req_msg = malloc(ports->req_size);
  271         ports->reply_msg = malloc(ports->reply_size);
  272 
  273         ret = mach_port_allocate(mach_task_self(), 
  274                         MACH_PORT_RIGHT_RECEIVE,  
  275                         &(ports->port));
  276         if (KERN_SUCCESS != ret) {
  277                 mach_error("mach_port_allocate(): ", ret);
  278                 exit(1);
  279         }
  280         if (verbose) {
  281                 printf("Client sending %d %s IPC messages to port '%s' in %s mode.\n",
  282                                 num_msgs, (msg_type == msg_type_inline) ? 
  283                                 "inline" :  ((msg_type == msg_type_complex) ? 
  284                                         "complex" : "trivial"),  
  285                                 server_port_name, (oneway ? "oneway" : "rpc"));
  286         }
  287 
  288 }
  289 
  290 void server(struct port_args *args) 
  291 {
  292         int idx;
  293         kern_return_t ret;
  294         int totalmsg = num_msgs * num_clients;
  295 
  296         unsigned long long starttsc, endtsc, deltatsc;
  297         struct timeval starttv, endtv, deltatv;
  298 
  299         /* Call gettimeofday() once and throw away result; some implementations
  300          * (like Mach's) cache some time zone info on first call.  Then, call
  301          * ReadTSR in case that helps warm things up, again discarding the 
  302          * results.
  303          */
  304         gettimeofday(&starttv, NULL);
  305         ReadTSR();
  306 
  307         gettimeofday(&starttv, NULL);
  308         starttsc = ReadTSR();
  309 
  310         for (idx = 0; idx < totalmsg; idx++) {
  311                 if (verbose) 
  312                         printf("server awaiting message %d\n", idx);
  313                 args->req_msg->msgh_bits = 0;
  314                 args->req_msg->msgh_size = args->req_size;
  315                 args->req_msg->msgh_local_port = args->port;
  316                 ret = mach_msg(args->req_msg,  
  317                                 MACH_RCV_MSG|MACH_RCV_INTERRUPT|MACH_RCV_LARGE, 
  318                                 0, 
  319                                 args->req_size,  
  320                                 args->port, 
  321                                 MACH_MSG_TIMEOUT_NONE, 
  322                                 MACH_PORT_NULL);
  323                 if (MACH_MSG_SUCCESS != ret) {
  324                         mach_error("mach_msg (receive): ", ret);
  325                         exit(1);
  326                 }
  327                 if (verbose)
  328                         printf("server received message %d\n", idx);
  329                 if (args->req_msg->msgh_bits & MACH_MSGH_BITS_COMPLEX) {
  330                         ret = vm_deallocate(mach_task_self(),  
  331                                         (vm_address_t)((ipc_complex_message *)args->req_msg)->descriptor.address,  
  332                                         ((ipc_complex_message *)args->req_msg)->descriptor.size);
  333                 }
  334 
  335                 if (1 == args->req_msg->msgh_id) {
  336                         if (verbose) 
  337                                 printf("server sending reply %d\n", idx);
  338                         args->reply_msg->msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND,  
  339                                         MACH_MSG_TYPE_MAKE_SEND);
  340                         args->reply_msg->msgh_size = args->reply_size;
  341                         args->reply_msg->msgh_remote_port = args->req_msg->msgh_remote_port;
  342                         args->reply_msg->msgh_local_port = args->req_msg->msgh_local_port;
  343                         args->reply_msg->msgh_id = 2;
  344                         ret = mach_msg(args->reply_msg, 
  345                                         MACH_SEND_MSG, 
  346                                         args->reply_size, 
  347                                         0, 
  348                                         MACH_PORT_NULL, 
  349                                         MACH_MSG_TIMEOUT_NONE,  
  350                                         MACH_PORT_NULL);
  351                         if (MACH_MSG_SUCCESS != ret) {
  352                                 mach_error("mach_msg (send): ", ret);
  353                                 exit(1);
  354                         }
  355                 }
  356         }
  357 
  358         endtsc = ReadTSR();
  359         gettimeofday(&endtv, NULL);
  360 
  361         /* report results */
  362         deltatsc = endtsc - starttsc;
  363         deltatv.tv_sec = endtv.tv_sec - starttv.tv_sec;
  364         deltatv.tv_usec = endtv.tv_usec - starttv.tv_usec;
  365         if (endtv.tv_usec < starttv.tv_usec) {
  366                 deltatv.tv_sec--;
  367                 deltatv.tv_usec += 1000000;
  368         }
  369 
  370         double dsecs = (double) deltatv.tv_sec + 
  371                 1.0E-6 * (double) deltatv.tv_usec;
  372 
  373         printf("\n%u messages during %qd time stamp ticks\n", 
  374                         totalmsg, deltatsc);
  375         printf("%g time stamp ticks per message\n", 
  376                         (double) deltatsc / (double) totalmsg);
  377         printf("\n%u messages during %u.%06u seconds\n",  
  378                         totalmsg, deltatv.tv_sec, deltatv.tv_usec);
  379         printf("%g messages per second\n", (double)totalmsg /  dsecs);
  380         printf("%g microseconds per message\n\n", 
  381                         dsecs * 1.0E6 / (double) totalmsg); 
  382 }
  383 
  384 void *client(void *threadarg) 
  385 {
  386         struct port_args args;
  387         int idx;
  388         mach_msg_header_t *req, *reply; 
  389         mach_port_t bsport, servport;
  390         kern_return_t ret;
  391         void *ints = malloc(sizeof(u_int32_t) * num_ints);
  392 
  393         /* find server port */
  394         ret = task_get_bootstrap_port(mach_task_self(), &bsport);
  395         if (KERN_SUCCESS != ret) {
  396                 mach_error("task_get_bootstrap_port(): ", ret);
  397                 exit(1);
  398         }
  399         ret = bootstrap_look_up(bsport, server_port_name, &servport); 
  400         if (KERN_SUCCESS != ret) {
  401                 mach_error("bootstrap_look_up(): ", ret);
  402                 exit(1);
  403         }
  404 
  405         setup_client_ports(&args);
  406         
  407         /* start message loop */
  408         for (idx = 0; idx < num_msgs; idx++) {
  409                 req = args.req_msg;
  410                 reply = args.reply_msg;
  411 
  412                 req->msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 
  413                                 MACH_MSG_TYPE_MAKE_SEND);
  414                 req->msgh_size = args.req_size;
  415                 req->msgh_remote_port = servport;
  416                 req->msgh_local_port = args.port;
  417                 req->msgh_id = oneway ? 0 : 1;
  418                 switch (msg_type) {
  419                         case msg_type_trivial:
  420                                 break;
  421                         case msg_type_inline:
  422                                 ((ipc_inline_message *)req)->type.msgt_name = MACH_MSG_TYPE_INTEGER_32;
  423                                 ((ipc_inline_message *)req)->type.msgt_size = 32;
  424                                 ((ipc_inline_message *)req)->type.msgt_number = num_ints;
  425                                 ((ipc_inline_message *)req)->type.msgt_inline = TRUE;
  426                                 ((ipc_inline_message *)req)->type.msgt_longform = FALSE;
  427                                 ((ipc_inline_message *)req)->type.msgt_deallocate = FALSE;
  428                                 ((ipc_inline_message *)req)->type.msgt_unused = 0;
  429                                 break;
  430                         case msg_type_complex:
  431                                 (req)->msgh_bits |=  MACH_MSGH_BITS_COMPLEX;
  432                                 ((ipc_complex_message *)req)->body.msgh_descriptor_count = 1;
  433                                 ((ipc_complex_message *)req)->descriptor.address = ints;
  434                                 ((ipc_complex_message *)req)->descriptor.size = 
  435                                         num_ints * sizeof(u_int32_t);
  436                                 ((ipc_complex_message *)req)->descriptor.deallocate = FALSE;
  437                                 ((ipc_complex_message *)req)->descriptor.copy = MACH_MSG_VIRTUAL_COPY;
  438                                 ((ipc_complex_message *)req)->descriptor.type = MACH_MSG_OOL_DESCRIPTOR;
  439                                 break;
  440                 }
  441                 if (verbose) 
  442                         printf("client sending message %d\n", idx);
  443                 ret = mach_msg(req,  
  444                                 MACH_SEND_MSG, 
  445                                 args.req_size, 
  446                                 0, 
  447                                 MACH_PORT_NULL,  
  448                                 MACH_MSG_TIMEOUT_NONE, 
  449                                 MACH_PORT_NULL);
  450                 if (MACH_MSG_SUCCESS != ret) {
  451                         mach_error("mach_msg (send): ", ret);
  452                         fprintf(stderr, "bailing after %u iterations\n", idx);
  453                         exit(1);
  454                         break;
  455                 }
  456                 if (!oneway) {
  457                         if (verbose) 
  458                                 printf("client awaiting reply %d\n", idx);
  459                         reply->msgh_bits = 0;
  460                         reply->msgh_size = args.reply_size;
  461                         reply->msgh_local_port = args.port;
  462                         ret = mach_msg(args.reply_msg,  
  463                                         MACH_RCV_MSG|MACH_RCV_INTERRUPT, 
  464                                         0, 
  465                                         args.reply_size, 
  466                                         args.port,  
  467                                         MACH_MSG_TIMEOUT_NONE, 
  468                                         MACH_PORT_NULL);
  469                         if (MACH_MSG_SUCCESS != ret) {
  470                                 mach_error("mach_msg (receive): ", ret);
  471                                 fprintf(stderr, "bailing after %u iterations\n",
  472                                                 idx);
  473                                 exit(1);
  474                         }
  475                         if (verbose) 
  476                                 printf("client received reply %d\n", idx);
  477                 }
  478 
  479                 if (client_delay) {
  480                         usleep(client_delay);
  481                 }
  482         }
  483 
  484         free(ints);
  485         return;
  486 }
  487 
  488 
  489 int main(int argc, char *argv[]) 
  490 {
  491         struct port_args portargs;
  492         int i;
  493 
  494         signal(SIGINT, signal_handler);
  495         parse_args(argc, argv);
  496 
  497         setup_server_ports(&portargs);
  498 
  499         if (fork() != 0) {
  500                 server(&portargs);
  501                 exit(0);
  502         }
  503 
  504         if (num_clients > 1) {
  505                 for (i = 1; i < num_clients; i++) {
  506                         if (fork() == 0) {
  507                                 client(NULL);
  508                                 exit(0);
  509                         }
  510                 }
  511         }
  512 
  513         client(NULL);
  514 
  515         return (0);
  516 }

Cache object: 45229fd1877e418dabacf91e10c9083f


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.