/** start a new, potentially, rate-limited run */ void mkrunner() { runner *run = calloc(1, sizeof(runner)); run->id = runid++; if(run == nil) panic("calloc"); mkhttp(run); if(qps_enabled()) { run->tv.tv_sec = 0; run->tv.tv_usec = 1000000/params.qps + USEC_FUDGE; if(run->tv.tv_usec < 1) run->tv.tv_usec = 1; evtimer_set(&run->ev, runnercb, run); evtimer_add(&run->ev, &run->tv); debug("mkrunner(): evtimer_add(&run->ev, &run->tv);\n"); } else { // skip the timers and just loop as fast as possible runnercb(0, 0, run); } }
void timeoutcb(int fd, short what, void *arg) { struct request *req =(struct request *)arg; /* re-establish the connection */ evhttp_connection_free(req->evcon); req->evcon = mkhttp(); complete(Timeout, req); }
void timeoutcb(int fd, short what, void *arg) { runner *run = (runner *)arg; debug("timeoutcb()\n"); /* re-establish the connection */ evhttp_connection_free(run->evcon); mkhttp(run); complete(Timeout, run); }
void complete(int how, struct request *req) { struct timeval now, diff; int i, total; long milliseconds; evtimer_del(&req->timeoutev); switch(how){ case Success: gettimeofday(&now, nil); timersub(&now, &req->starttv, &diff); milliseconds = diff.tv_sec * 1000 + diff.tv_usec / 1000; for(i=0; params.buckets[i]<milliseconds && params.buckets[i]!=0; i++); counts.counters[i]++; counts.successes++; break; case Error: counts.errors++; break; case Timeout: counts.timeouts++; break; } total = counts.successes + counts.errors + counts.timeouts /*+ counts.closes*/; /* enqueue the next one */ if(params.count<0 || total<params.count){ if(params.rpc<0 || params.rpc>req->evcon_reqno){ dispatch(req->evcon, req->evcon_reqno + 1); }else{ evhttp_connection_free(req->evcon); dispatch(mkhttp(), 1); } }else{ /* We'll count this as a close. I guess that's ok. */ evhttp_connection_free(req->evcon); if(--params.concurrency == 0){ evtimer_del(&reportev); reportcb(0, 0, nil); /* issue a last report */ } } free(req); }
void complete(int how, runner *run) { struct request *req = run->req; save_request(how, run); evtimer_del(&req->timeoutev); debug("complete(): evtimer_del(&req->timeoutev);\n"); /* enqueue the next one */ if(params.count<0 || counts.conns<params.count){ // re-scheduling is handled by the callback if(!qps_enabled()){ if(!rpc_enabled() || req->evcon_reqno<params.rpc){ dispatch(run, req->evcon_reqno + 1); }else{ // re-establish the connection evhttp_connection_free(run->evcon); mkhttp(run); dispatch(run, 1); } } }else{ /* We'll count this as a close. I guess that's ok. */ evhttp_connection_free(req->evcon); if(--params.concurrency == 0){ evtimer_del(&reportev); debug("last call to reportcb\n"); reportcb(0, 0, nil); /* issue a last report */ } } if(!qps_enabled()) // FIXME possible memory leak free(req); }
int main(int argc, char **argv) { int ch, i, nprocs = 1, is_parent = 1, port, *sockets, fds[2]; pid_t pid; char *sp, *ap, *host, *cmd = argv[0]; struct hostent *he; /* Defaults */ params.count = -1; params.rpc = -1; params.concurrency = 1; memset(params.buckets, 0, sizeof(params.buckets)); params.buckets[0] = 1; params.buckets[1] = 10; params.buckets[2] = 100; params.nbuckets = 4; memset(&counts, 0, sizeof(counts)); while((ch = getopt(argc, argv, "c:b:n:p:r:i:hf:")) != -1){ switch(ch){ case 'b': sp = optarg; memset(params.buckets, 0, sizeof(params.buckets)); for(i=0; i<MAX_BUCKETS && (ap=strsep(&sp, ",")) != nil; i++) params.buckets[i] = atoi(ap); params.nbuckets = i; if(params.buckets[0] == 0) panic("first bucket must be >0\n"); for(i=1; params.buckets[i]!=0; i++){ if(params.buckets[i]<params.buckets[i-1]) panic("invalid bucket specification!\n"); } break; case 'c': params.concurrency = atoi(optarg); break; case 'n': params.count = atoi(optarg); break; case 'p': nprocs = atoi(optarg); break; case 'i': reporttv.tv_sec = atoi(optarg); break; case 'r': params.rpc = atoi(optarg); break; case 'h': usage(cmd); break; case 'f': read_config(optarg); break; } } argc -= optind; argv += optind; host = "127.0.0.1"; port = 80; switch(argc){ case 2: port = atoi(argv[1]); case 1: host = argv[0]; case 0: break; default: panic("only 0 or 1(host port) pair are allowed\n"); } http_hostname = host; http_port = port; if(snprintf(http_hosthdr, sizeof(http_hosthdr), "%s:%d", host, port) > sizeof(http_hosthdr)) panic("snprintf"); for(i = 0; params.buckets[i] != 0; i++) request_timeout = params.buckets[i]; if(params.count > 0) params.count /= nprocs; #if 0 event_init(); dispatch(mkhttp(), 1); event_dispatch(); exit(0); #endif fprintf(stderr, "# params: c=%d p=%d n=%d r=%d\n", params.concurrency, nprocs, params.count, params.rpc); fprintf(stderr, "# ts\t\terrors\ttimeout\tcloses\t"); for(i=0; params.buckets[i]!=0; i++) fprintf(stderr, "<%d\t", params.buckets[i]); fprintf(stderr, ">=%d\thz\n", params.buckets[i - 1]); if((sockets = calloc(nprocs + 1, sizeof(int))) == nil) panic("malloc\n"); sockets[nprocs] = -1; for(i=0; i<nprocs; i++){ if(socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0){ perror("socketpair"); exit(1); } sockets[i] = fds[0]; if((pid = fork()) < 0){ kill(0, SIGINT); perror("fork"); exit(1); }else if(pid != 0){ close(fds[1]); continue; } is_parent = 0; evbase = event_init(); /* Set up output. */ if(dup2(fds[1], STDOUT_FILENO) < 0){ perror("dup2"); exit(1); } close(fds[1]); for(i=0; i<params.concurrency; i++) dispatch(mkhttp(), 1); evtimer_set(&reportev, reportcb, nil); evtimer_add(&reportev, &reporttv); event_dispatch(); break; } if(is_parent) parentd(nprocs, sockets); return(0); }
void dispatchcb(int fd, short what, void *arg) { free(arg); dispatch(mkhttp(), 1); }