blob: 8a36ee6340e56f42af3efa0c7b44289fc999c5b1 [file] [log] [blame]
/*
* Copyright (c) 2008 The Native Client Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
/** @file
*
* Measure the performace of the Nrd Xfer protocol implementation.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <time.h>
#include <fcntl.h>
#include <pthread.h>
#include <errno.h>
/* NOTE(robertm): no errno magic here, why? */
#include "native_client/src/public/imc_syscalls.h"
#include "native_client/src/public/imc_types.h"
int debug = 0;
void report(struct timeval *time_start,
struct timeval *time_end,
int num_rep,
int transfer_count) {
struct timeval time_elapsed;
double time_per_call;
time_elapsed.tv_sec = time_end->tv_sec - time_start->tv_sec;
time_elapsed.tv_usec = time_end->tv_usec - time_start->tv_usec;
if (time_elapsed.tv_usec < 0) {
--time_elapsed.tv_sec;
time_elapsed.tv_usec += 1000000;
}
printf("Number of nrd xfers: %d\n", num_rep);
printf("Number of descs per xfer: %d\n", transfer_count);
printf("Elapsed time: %d.%06dS\n",
(int) time_elapsed.tv_sec,
(int) time_elapsed.tv_usec);
time_per_call = ((time_elapsed.tv_sec + time_elapsed.tv_usec / 1.0e6)
/ num_rep);
printf("Time per call: %gS or %fnS\n",
time_per_call,
1.0e9 * time_per_call);
printf("Calls per sec: %d\n", (int) (1.0 / time_per_call));
}
void server_side(int channel,
int num_rep) {
int rep;
int rv;
int i;
int nrds_per_call = -1;
struct timeval time_start;
struct timeval time_end;
struct NaClAbiNaClImcMsgHdr msg_hdr;
struct NaClAbiNaClImcMsgIoVec iov[1];
char data_buffer[4096];
int desc_buffer[NACL_ABI_IMC_USER_DESC_MAX];
gettimeofday(&time_start, (void *) NULL);
for (rep = 0; rep < num_rep; ++rep) {
iov[0].base = data_buffer;
iov[0].length = sizeof data_buffer;
msg_hdr.iov = iov;
msg_hdr.iov_length = 1;
msg_hdr.descv = desc_buffer;
msg_hdr.desc_length = sizeof desc_buffer / sizeof desc_buffer[0];
rv = imc_recvmsg(channel, &msg_hdr, 0);
if (debug) {
printf("Received %d data bytes\n", rv);
}
if (rv >= 0) {
if (debug) {
printf("Received %d descriptors\n", msg_hdr.desc_length);
}
if (nrds_per_call == -1) {
nrds_per_call = msg_hdr.desc_length;
} else {
if (nrds_per_call != msg_hdr.desc_length) {
fprintf(stderr, "inconsistent number of nrds per call\n");
fprintf(stderr, "earlier was %d, now %d\n",
nrds_per_call,
msg_hdr.desc_length);
exit(105);
}
}
for (i = 0; i < msg_hdr.desc_length; ++i) {
int rcvd_desc;
rcvd_desc = msg_hdr.descv[i];
if (-1 == close(rcvd_desc)) {
fprintf(stderr, "close of transferred descriptor %d failed\n",
rcvd_desc);
}
}
}
}
gettimeofday(&time_end, (void *) NULL);
report(&time_start, &time_end, num_rep, nrds_per_call);
}
void client_side(int channel,
int num_rep,
int transfer_count,
int xfer_fd) {
int i;
int rv;
struct timeval time_start;
struct timeval time_end;
struct NaClAbiNaClImcMsgHdr msg_hdr;
struct NaClAbiNaClImcMsgIoVec iov[1];
char data_buffer[4096];
int desc_buffer[NACL_ABI_IMC_USER_DESC_MAX];
iov[0].base = data_buffer;
iov[0].length = 0;
msg_hdr.iov = iov;
msg_hdr.iov_length = 0;
msg_hdr.descv = desc_buffer;
for (i = 0; i < transfer_count; ++i) {
desc_buffer[i] = xfer_fd;
}
msg_hdr.desc_length = transfer_count;
gettimeofday(&time_start, (void *) NULL);
for (i = 0; i < num_rep; ++i) {
rv = imc_sendmsg(channel, &msg_hdr, 0);
if (-1 == rv) {
fprintf(stderr,
"imc_sendmsg returned %d, errno %d\n",
rv, errno);
exit(105);
}
}
gettimeofday(&time_end, (void *) NULL);
report(&time_start, &time_end, num_rep, transfer_count);
}
int main(int ac,
char **av) {
int opt;
int server = 0;
int client_desc = -1;
int channel;
size_t i;
char *transfer_file = "/dev/null";
unsigned long num_rep = 1;
/* default transfer_file inappropriate for windows! */
while (EOF != (opt = getopt(ac, av, "c:dn:st:T:"))) {
switch (opt) {
case 'c':
client_desc = strtol(optarg, (char **) 0, 0);
/* descriptor holds a connection capability for the server */
break;
case 'd':
++debug;
break;
case 'n':
num_rep = strtoul(optarg, (char **) 0, 0);
break;
case 's':
server = 1;
break;
case 't':
transfer_file = optarg;
break;
default:
fprintf(stderr,
"Usage: sel_ldr [sel_ldr_args] -- " /* no newline */
"nrd_xfer_test.nexe [-c server-addr-desc] [-s]\n"
" [-n num_rep]\n"
" [-t file-to-open-and-transfer]\n"
"\n"
"Typically, server is run using a command such as\n"
"\n"
" sel_ldr -X -1 -D 1 -- nrd_xfer_perf.nexe -s\n"
"\n"
"so the socket address is printed to standard output,\n"
"and then the client is run with a command such as\n"
"\n"
" sel_ldr -d -X -1 -a 6:<addr-from-server> " /* no \n */
"-- nrd_xfer_perf.nexe -c 6\n"
"\n"
"to have descriptor 6 be used to represent the socket\n"
"address for connecting to the server\n"
"\n"
"For the client side, -t specifies the file to open\n"
"to pass to the server --\n"
"remember that the -d (debug) flag is needed for\n"
"sel_ldr to enable file opens.\n");
return 1;
}
}
printf("\nStarting in %s mode\n", server ? "server" : "client");
printf("Debug is %d\n", debug);
if (server) {
channel = imc_accept(3);
for (i = 0; i < NACL_ABI_IMC_USER_DESC_MAX; ++i) {
server_side(channel, num_rep);
}
if (-1 == close(channel)) {
fprintf(stderr, "close of channel %d failed\n", channel);
}
} else {
int xfer_fd = -1;
if (-1 == client_desc) {
fprintf(stderr,
"Client needs server socket address to which to connect\n");
return 100;
}
channel = imc_connect(client_desc);
if (-1 == channel) {
fprintf(stderr, "Client could not connect\n");
return 102;
}
xfer_fd = open(transfer_file, O_CREAT | O_RDONLY, 0777);
if (-1 == xfer_fd) {
fprintf(stderr,
"Could not open file \"%s\" to transfer descriptor.\n",
transfer_file);
return 104;
}
for (i = 1; i <= NACL_ABI_IMC_USER_DESC_MAX; ++i) {
client_side(channel, num_rep, i, xfer_fd);
}
}
return 0;
}