/* $Id: playtrace.C,v 1.7 2000/08/29 06:43:58 fubob Exp $ */ /* * * Copyright (C) 2000 David Mazieres (dm@uun.org) * Copyright (C) 2000 Kevin Fu (fubob@mit.edu) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2, or (at * your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA * */ #include "arpc.h" #include "sfsmisc.h" #include "sfsro_prot.h" #include "parseopt.h" char trace_apache_maxro[][20] = { #include "trace_apache_maxro.h" }; size_t trace_size_apache_maxro = sizeof (trace_apache_maxro) / sizeof (trace_apache_maxro[0]); char trace_emacs_maxro[][20] = { #include "trace_emacs_maxro2.h" }; size_t trace_size_emacs_maxro = sizeof (trace_emacs_maxro) / sizeof (trace_emacs_maxro[0]); char trace_readlink_maxro[][20] = { #include "trace_readlink_single.h" }; size_t trace_size_readlink_maxro = sizeof (trace_readlink_maxro) / sizeof (trace_readlink_maxro[0]); char trace_readlinkm_maxro[][20] = { #include "trace_readlink_multi.h" }; size_t trace_size_readlinkm_maxro = sizeof (trace_readlinkm_maxro) / sizeof (trace_readlinkm_maxro[0]); struct tracevec { const char *name; char (*trace)[20]; size_t trace_size; }; const tracevec traces[] = { { "Apache-RO", trace_apache_maxro, trace_size_apache_maxro }, { "Emacs-RO", trace_emacs_maxro, trace_size_emacs_maxro }, { "Readlink-Single", trace_readlink_maxro, trace_size_readlink_maxro }, { "Readlink-Multi", trace_readlinkm_maxro, trace_size_readlinkm_maxro } }; size_t tracevec_size = 4; struct player { static u_int64_t bytecount; static unsigned long playcount; static unsigned long playcount_attempted; const in_addr srvaddr; const aclnt_cb mycb; unsigned reqno; ptr cs; ptr cr; sfs_connectres cres; sfs_fsinfo fsires; sfsro_datares res; player (in_addr a) : srvaddr (a), mycb (wrap (this, &player::nextreq)), reqno (0) { start (); } void start (); void getfd (int fd); void conres (clnt_stat stat); void fsinfores (clnt_stat stat); void nextreq (clnt_stat stat); }; u_int64_t player::bytecount; unsigned long player::playcount; unsigned long player::playcount_attempted; bool opt_verbose = false; int opt_trace = -1; char *opt_name = NULL; void player::start () { cr = cs = NULL; reqno = 0; playcount_attempted++; res.set_status (SFSRO_OK); res.resok->data.setsize (0); tcpconnect (srvaddr, sfs_port, wrap (this, &player::getfd)); } void player::getfd (int fd) { if (fd < 0) { warn ("tcpconnect: %m\n"); // XXX timecb (timenow + 1, wrap (this, &player::start)); return; } ref x (axprt_stream::alloc (fd)); cs = aclnt::alloc (x, sfs_program_1); cr = aclnt::alloc (x, sfsro_program_1); sfs_connectarg carg; carg.release = sfs_release; carg.service = SFS_SFS; carg.name = ""; cs->call (SFSPROC_CONNECT, &carg, &cres, wrap (this, &player::conres)); } void player::conres (clnt_stat stat) { if (stat) { warn << stat; start (); return; } bytecount += 76 + (cres.reply->servinfo.host.hostname.len () + 3 & ~3) + (mpz_rawsize (&cres.reply->servinfo.host.pubkey) + 3 & ~3); /* Account for overhead */ cs->call (SFSPROC_GETFSINFO, NULL, &fsires, wrap (this, &player::fsinfores)); } void player::fsinfores (clnt_stat stat) { if (stat) { warn << stat; start (); return; } bytecount += 108 + (mpz_rawsize (&fsires.sfsro->v1->sig) + 3 & ~3); /* Account for overhead */ cr->call (SFSROPROC_GETDATA, traces[opt_trace].trace[reqno++], &res, mycb); } void player::nextreq (clnt_stat stat) { if (stat) { warn << stat << "\n"; start (); return; } if (!res.status) bytecount += res.resok->data.size () + 32; /* Account for overhead */ else warn ("ENOENT\n"); if (reqno >= traces[opt_trace].trace_size) { playcount++; start (); } else cr->call (SFSROPROC_GETDATA, traces[opt_trace].trace[reqno++], &res, mycb); } inline u_int64_t gettime () { timeval tv; gettimeofday (&tv, NULL); return tv.tv_sec * INT64(1000000) + tv.tv_usec; } u_int64_t starttime; void finish () { u_int64_t elapsed_usec = gettime () - starttime; if (opt_verbose) { printf ("Bytes: %qd\n", player::bytecount); printf (" usec: %qd\n", elapsed_usec); printf (" MB/s: %f\n", 0.953674316406 * player::bytecount / elapsed_usec); printf ("Successful plays: %lu\n", player::playcount); printf ("Attempted plays: %lu\n", player::playcount_attempted); printf ("Successful plays/s: %f\n", player::playcount / (elapsed_usec / 1e6F)); printf ("Attempted plays/s: %f\n\n", player::playcount_attempted / (elapsed_usec/ 1e6F)); printf ("Test: %s\n", traces[opt_trace].name); printf ("RPCs per play: %d\n", traces[opt_trace].trace_size); } else { printf ("%5s %10qd %10qd %10f %6lu %6lu %8.2f %8.2f\n", opt_name?opt_name:"Local", player::bytecount, elapsed_usec, 0.953674316406 * player::bytecount / elapsed_usec, player::playcount, player::playcount_attempted, player::playcount / (elapsed_usec / 1e6F), player::playcount_attempted / (elapsed_usec/ 1e6F)); } exit (0); } void usage () { warnx << "Trace numbers are:\n\n"; for (unsigned int i = 0; i < tracevec_size; i++) warnx << i << ": " << traces[i].name << "\n"; fatal << "\nusage: " << progname << " [-p trigger-port] [-n num-clients]\n" << " [-t seconds] [-l label] [-v] -r trace-num server\n\n" << "Remember to set SFS_PORT\n"; } int main (int argc, char **argv) { setprogname (argv[0]); sfsconst_init (); int opt_triggerport = 0; int opt_nclients = 20; double opt_nseconds = 5.0; int ch; while ((ch = getopt (argc, argv, "p:n:t:r:l:v")) != -1) switch (ch) { case 'p': if (!convertint (optarg, &opt_triggerport)) usage (); break; case 'n': if (!convertint (optarg, &opt_nclients)) usage (); break; case 't': opt_nseconds = atof (optarg); if (opt_nseconds <= 0) usage (); break; case 'r': if (!convertint (optarg, &opt_trace)) usage (); break; case 'v': opt_verbose = true; break; case 'l': opt_name = optarg; break; default: usage (); break; } if ((optind + 1 != argc) || (opt_trace < 0) || (opt_trace >= (int)tracevec_size)) usage (); hostent *hp = gethostbyname (argv[optind]); if (!hp) fatal << argv[1] << ": no such host\n"; in_addr addr = *(in_addr *) hp->h_addr; itimerval itv; bzero (&itv, sizeof (itv)); itv.it_value.tv_sec = long (opt_nseconds); itv.it_value.tv_usec = long (1000000 * (opt_nseconds - itv.it_value.tv_sec)); sigcb (SIGALRM, wrap (finish)); if (opt_verbose) { printf ("Clients Est. Duration (usec) Bytes Act. Duration (usec) MB/s Succ. Plays Attem. Plays Succ. Plays/s Attem. Plays/s\n"); printf ("[ %d clients / %f seconds ]\n", opt_nclients, opt_nseconds); } if (opt_triggerport) { int fd = inetsocket (SOCK_DGRAM, opt_triggerport); if (fd < 0) fatal ("socket: %m\n"); char c; socklen_t l = 0; recvfrom (fd, &c, 1, 0, NULL, &l); } if (setitimer (ITIMER_REAL, &itv, NULL) < 0) fatal ("setitimer: %m\n"); starttime = gettime (); for (int i = 0; i < opt_nclients; i++) vNew player (addr); amain (); }