static int elapsed(const struct timeval *start) { struct timeval end; xgettimeofday(&end); return timeval_to_msec(&end) - timeval_to_msec(start); }
static void benchmark(struct classifier *cls) { struct timespec before, after; struct rusage rbefore, rafter; struct flow_wildcards wc; struct match match_wc_str; struct flow flow; size_t i; memset(&flow, 0, sizeof flow); flow.in_port.ofp_port = OFPP_LOCAL; flow.dl_type = htons(ETH_TYPE_IP); flow.nw_proto = IPPROTO_TCP; fat_rwlock_rdlock(&cls->rwlock); clock_gettime(CLOCK_MONOTONIC_RAW, &before); getrusage(RUSAGE_SELF, &rbefore); for (i = 0; i < 10000000; i++) { eth_addr_random(flow.dl_src); eth_addr_random(flow.dl_dst); flow.nw_src = htonl(random_uint32()); flow.nw_dst = htonl(random_uint32()); flow.tp_src = htons(random_uint16()); flow.tp_dst = htons(random_uint16()); flow.tp_dst = htons(i); flow_wildcards_init_catchall(&wc); //VLOG_DBG("Finding relevant wc's for flow: tp_dst=%d (0x%04x)", // ntohs(flow.tp_dst), ntohs(flow.tp_dst)); classifier_lookup(cls, &flow, &wc); match_init(&match_wc_str, &flow, &wc); //VLOG_DBG("Relevant fields: %s", match_to_string(&match_wc_str, 0)); } getrusage(RUSAGE_SELF, &rafter); clock_gettime(CLOCK_MONOTONIC_RAW, &after); fat_rwlock_unlock(&cls->rwlock); printf("real %lldms\n" "user %lldms\n" "sys %lldms\n" "soft faults %ld\n" "hard faults %ld\n", timespec_to_msec(&after) - timespec_to_msec(&before), timeval_to_msec(&rafter.ru_utime) - timeval_to_msec(&rbefore.ru_utime), timeval_to_msec(&rafter.ru_stime) - timeval_to_msec(&rbefore.ru_stime), rafter.ru_minflt - rbefore.ru_minflt, rafter.ru_majflt - rbefore.ru_majflt); }
hurl_hook_error_t stat_pre_connect(HURLPath *path, HURLConnection *connection) { (void)connection; ElementStat *stat = (ElementStat *)path->tag; /* TODO: Check if first element has been downloaded? If not then wait for it. */ /* Initialize HTTP statistics */ if (!stat->http) { stat->http = calloc(1, sizeof(HTTPStat)); } gettimeofday(&stat->http->begin_connect, NULL); log_debug(__func__, "Began connecting @ %f %s%s", timeval_to_msec(&stat->http->begin_connect), path->server->domain->domain, path->path); /* Always allow connect */ return HURL_HOOK_OK; }
void stat_response_latency(HURLPath *path, HURLConnection *conn, char *data, size_t data_len) { (void)conn; char *eof_header; int first_recv = 0; #ifndef NDEBUG struct timeval diff, now; #endif ElementStat *stat = (ElementStat *)path->tag; /* Initialize HTTP statistics */ if (!stat->http) { stat->http = calloc(1, sizeof(HTTPStat)); } if (stat->http->bgof_header > 0 && stat->http->bgof_body > 0) { /* The statistics of interest have already been recorded. */ return; } /* Find end of header */ if (stat->http->header_len == 0) { eof_header = strstr(data, "\r\n\r\n"); /* TODO Use header offset instead? */ stat->http->header_len = (size_t)(eof_header - data + 4); first_recv = 1; } if (stat->http->bgof_header == 0) { /* First header byte received */ gettimeofday(&now, NULL); timersub(&now, &stat->http->request_sent, &diff); stat->http->bgof_header = timeval_to_msec(&diff); log_debug(__func__, "First header bytes received after %f ms.", stat->http->bgof_header); } if (stat->http->bgof_body == 0 && stat->http->header_len > 0) { if (stat->http->header_len < data_len) { /* First content byte received. */ if (!first_recv) { /* The first header and body bytes were NOT received at the same time. */ gettimeofday(&now, NULL); } timersub(&now, &stat->http->request_sent, &diff); stat->http->bgof_body = timeval_to_msec(&diff); log_debug(__func__, "First body bytes received after %f ms.", stat->http->bgof_body); } } }
void stat_transfer_complete(HURLPath *path, HURLConnection *connection, HURLTransferResult result, size_t content_length, size_t overhead) { (void)connection; struct timeval diff; #ifdef __linux__ unsigned int tcp_stats_len = sizeof(struct tcp_info); #endif ElementStat *stat = (ElementStat *)path->tag; assert(stat->no_hostname || result == HURL_XFER_DNS || (!stat->dns_trigger && stat->dns) || (stat->dns_trigger && !stat->dns)); if (stat->dns_trigger) { log_debug(__func__, "%s has a DNS trigger: %s", stat->url_hash, stat->dns_trigger); } /* Initialize HTTP statistics */ if (!stat->http) { stat->http = calloc(1, sizeof(HTTPStat)); } /* Save time of completion */ gettimeofday(&stat->end_transfer, NULL); /* Calculate transfer time */ timersub(&stat->end_transfer, &stat->begin_transfer, &diff); stat->http->download_time = timeval_to_msec(&diff); /* Calculate ready time */ timersub(&stat->end_transfer, &test->manager->bgof_exec, &diff); stat->http->ready_time = timeval_to_msec(&diff); /* Save overhead size - HTTP header + chunking */ stat->http->overhead = overhead; /* Save transfer result code */ stat->http->result = result; #ifdef __linux__ if (test->stats.http.tcp_stats) { if ((stat->http->tcp_stats = calloc(1, sizeof(struct tcp_info))) != NULL) { if (getsockopt(connection->sock, SOL_TCP, TCP_INFO, (void *) stat->http->tcp_stats, &tcp_stats_len) != 0) { log_debug(__func__, "Failed to get TCP stats."); } } } #endif /* Fix time to first body byte. */ if (content_length == 0) { stat->http->bgof_body = stat->http->bgof_header; } }
void dns_resolve_wrapper(HURLDomain *domain, HURLPath *path) { int retval, i; char *final_qname = NULL; DNSRecord *record; DNSMessage *response = NULL; DNSResolverState state; struct timeval begin_resolve, end_resolve, exec_time; ElementStat *stat = (ElementStat *)path->tag; int nrof_addresses = 0; log_debug(__func__, "Resolving %s", domain->domain); log_debug(__func__, "Resolution triggered by %s%s", domain->domain, path->path); /* Check if domain string is actually and IP address */ domain->addresses = calloc(1, sizeof(struct sockaddr *)); domain->addresses[0] = calloc(1, sizeof(struct sockaddr)); if (inet_pton(AF_INET, domain->domain, &((struct sockaddr_in *)domain->addresses[0])->sin_addr) == 1) { /* The string was actually an IPv4 address */ nrof_addresses++; ((struct sockaddr_in *)domain->addresses[0])->sin_family = AF_INET; } else if (inet_pton(AF_INET6, domain->domain, &((struct sockaddr_in6 *)domain->addresses[0])->sin6_addr) == 1) { /* The string was actually an IPv6 address */ nrof_addresses++; ((struct sockaddr_in6 *)domain->addresses[0])->sin6_family = AF_INET6; } else { /* The string was not an IPv4 or IPv6 address -- continue with DNS lookup */ free(domain->addresses); } if (nrof_addresses > 0) { log_debug(__func__, "URL contained IP address. Skipping DNS lookup..."); stat->no_hostname = 1; domain->nrof_addresses = nrof_addresses; domain->dns_state = DNS_STATE_RESOLVED; return; } /* Copy resolver state template. */ memcpy(&state, test->dns_state_template, sizeof(DNSResolverState)); gettimeofday(&begin_resolve, NULL); retval = dns_resolve(test->cache, &state, domain->domain, test->dns_query_type, &final_qname); gettimeofday(&end_resolve, NULL); log_debug(__func__, "DNS resolv retval: %d", retval); if (retval == DNS_OK) { domain->dns_state = DNS_STATE_RESOLVED; response = state.responses[state.nrof_responses - 1]; domain->nrof_addresses = dns_count_rr(test->dns_query_type, ANSWERS, response); /* Allocate memory for address structures */ if ((domain->addresses = calloc((size_t)domain->nrof_addresses, sizeof(struct sockaddr *))) == NULL) { domain->dns_state = DNS_STATE_ERROR; return; } for (i = 0; i < response->nrof_answers; i++) { record = response->answers[i]; record_debug(__func__, record); if (record->type == A) { domain->addresses[nrof_addresses] = calloc(1, sizeof(struct sockaddr)); domain->addresses[nrof_addresses++]->sa_family = AF_INET; memcpy(&((struct sockaddr_in * ) domain->addresses[i])->sin_addr.s_addr, record->data, record->data_len); } else if (record->type == AAAA) { domain->addresses[nrof_addresses] = calloc(1, sizeof(struct sockaddr)); domain->addresses[nrof_addresses++]->sa_family = AF_INET6; memcpy(&((struct sockaddr_in6 * ) domain->addresses[i])->sin6_addr, record->data, record->data_len); } } /* Detect CDN provider */ cdn_detect(stat, &state); } else { domain->dns_state = DNS_STATE_ERROR; gettimeofday(&stat->end_transfer, NULL); } if ((stat->dns = calloc(1, sizeof(DNSStat))) == NULL) { /* Out of memory */ /* Free DNS resolver queries and responses. */ dns_state_reset(&state); return; } /* Save return value */ stat->dns->return_code = retval; /* Calculate DNS execution time. */ timersub(&end_resolve, &begin_resolve, &exec_time); stat->dns->exec_time = timeval_to_msec(&exec_time); memcpy(&stat->dns->begin_resolve, &begin_resolve, sizeof(struct timeval)); /* Get DNS network time. */ stat->dns->network_time = state.stats.network_time; /* Save message and data counters. */ stat->dns->msg_tx = state.stats.packet_tx; stat->dns->msg_rx = state.stats.packet_rx; stat->dns->data_tx = state.stats.data_tx; stat->dns->data_rx = state.stats.data_rx; /* Get query name and final query name */ stat->dns->qname = strdup(domain->domain); stat->dns->qname_final = final_qname; /* Reusing pointer, so dont free() it! */ /* Get number of domain names resolved in order to resolve the target domain name. */ stat->dns->queries = state.nrof_queries; if (retval == 0) { /* Get number of A and AAAA records. */ stat->dns->nrof_answers_a = dns_count_rr(A, ANSWERS, response); stat->dns->nrof_answers_aaaa = dns_count_rr(AAAA, ANSWERS, response); /* Get first A record and its TTL */ if ((record = dns_message_find_rr(response, ANSWERS, final_qname, A)) != NULL) { stat->dns->answer_a = dns_record_rdata_str(record); stat->dns->answer_a_ttl = (int)record->ttl; } else { stat->dns->answer_a = calloc(1, sizeof(char)); stat->dns->answer_a_ttl = -1; } /* Get first AAAA record and its TTL */ if ((record = dns_message_find_rr(response, ANSWERS, final_qname, AAAA)) != NULL) { stat->dns->answer_aaaa = dns_record_rdata_str(record); stat->dns->answer_aaaa_ttl = (int)record->ttl; } else { stat->dns->answer_aaaa = calloc(1, sizeof(char)); stat->dns->answer_aaaa_ttl = -1; } } else { stat->dns->answer_a = calloc(1, sizeof(char)); stat->dns->answer_a_ttl = -1; stat->dns->answer_aaaa = calloc(1, sizeof(char)); stat->dns->answer_aaaa_ttl = -1; } /* Dump DNS trace */ if (test->stats.dns.trace) { stat->dns->trace = dns_trace_json(&state); } /* Free DNS resolver queries and responses. */ dns_state_reset(&state); }
int current_msec() { struct timeval t; gettimeofday(&t,0); return timeval_to_msec(&t); }
void wait_for_ack(int sock) { // repeatedly send it until we get an ack while(1) { fd_set readset; FD_ZERO(&readset); FD_SET(sock,&readset); struct timeval t; if(window[0].sent_at + timeout > current_msec()) { unsigned msec_until_expiry = window[0].sent_at + timeout - current_msec(); msec_to_timeval(msec_until_expiry,&t); } else { msec_to_timeval(10,&t); } /* // always allow a 1 msec wait if(msec_until_expiry<0) { t.tv_sec = 0; t.tv_usec = 100; // memset(&t,0,sizeof(t)); }*/ int rdy = select(FD_SETSIZE,&readset,0,0,&t); char incoming[1400]; struct hw6_hdr *hdr = (struct hw6_hdr*)incoming; if(rdy>0) { struct sockaddr_in from_addr; unsigned int addrsize = sizeof(from_addr); int recv_count=recvfrom(sock,incoming,1400,0,(struct sockaddr*)&from_addr,&addrsize); if(recv_count<0) { perror("When receiving packet."); return; } } // if we timed out, or got a double acknowledgment, double the timeout value and send again if(rdy==0 || // double acknowledgment only triggers retransmission once per round-trip time (ntohl(hdr->ack_number)==ntohl(window[0].data->sequence_number)-1 && ((current_msec() - window[0].sent_at) > rtt))) { //last_ack_number) { if(rdy==0) fprintf(stderr,"\nTimed out on packet %d, msec %u\n",ntohl(window[0].data->sequence_number),timeval_to_msec(&t));//,msec_until_expiry); else fprintf(stderr,"\nDouble ack indicating loss of packet %d, msec %u\n",ntohl(window[0].data->sequence_number),timeval_to_msec(&t));//,msec_until_expiry); fprintf(stderr,"Window packets: "); for(int p=0;p<packets_outstanding;p++) { fprintf(stderr,"%d, ",ntohl(window[p].data->sequence_number)); } fprintf(stderr,"\n"); timeout *= 2; if(timeout > MAX_TIMEOUT) timeout = MAX_TIMEOUT; window_size /=2; if(window_size < 1) window_size=1; ssthresh = window_size; congestion_avoidance = 1; ca_last_increase = current_msec(); for(int i=0;i<packets_outstanding && i<window_size;i++) { fprintf(stderr,"Resending Packet %d with rtt %f dev %f timeout %d ms window %d to %s \n",ntohl(window[i].data->sequence_number),rtt, deviation,timeout,window_size,inet_ntoa(peeraddr.sin_addr)); if(sendto(sock, window[i].data, window[i].len, 0,(struct sockaddr*)&peeraddr,sizeof(peeraddr)) <=0) perror("Couldn't send!"); window[i].retx = 1; window[i].sent_at = current_msec(); // update the timestamp } fprintf(stderr,"Done resending, for now\n"); } else if(rdy==-1) { perror("select error"); } else { /* blow away all the packets acked here */ // fprintf(stderr,"Got ack for %d, time left %d, rtt %d, retx %d\n",ntohl(hdr->ack_number), timeval_to_msec(&t), current_msec() - window[0].sent_at, window[0].retx); int got_ack=0; last_ack_number = ntohl(hdr->ack_number); while(packets_outstanding > 0 && ntohl(hdr->ack_number) >= ntohl(window[0].data->sequence_number)) { if(!window[0].retx) update_rtt(current_msec() - window[0].sent_at); pop_packet(sock); got_ack=1; } if(got_ack) break; if(! (hdr->flags & ACK)) { // ack whatever we have so far struct hw6_hdr ack; ack.flags = ACK; if(ntohl(hdr->sequence_number) == expected_sequence_number) { expected_sequence_number++; } else { fprintf(stderr,"Unexpected non-ACK in rel_send(). Acking what we have so far. \n"); } ack.ack_number = htonl(expected_sequence_number-1); sendto(sock, &ack, sizeof(ack), 0,(struct sockaddr*)&peeraddr,sizeof(peeraddr)); } } } }
static long long int timeval_diff_msec(const struct timeval *a, const struct timeval *b) { return timeval_to_msec(a) - timeval_to_msec(b); }
void send_all_unacked_packets_again(int sock){ int n; n = getCurrentQSize(); for(int i = 0; i < n ; i++){ struct senderQelements *s; s = getNthElement(i); if(!s->ack_rxed){ //todo:resend fprintf(stderr,"\r<SHUBHAM>Retransmitted Packet - %d with rtt %d dev %d timeout - %d ms \n",i+start_seq_no,rtt, deviation,timeval_to_msec(&timeout)); s->retx = 1; //s->sent_time = current_msec(); //doesnt matter...will not be used if it is a retx sendto(sock, s->packet, s->packet_len, 0,(struct sockaddr*)&peeraddr,sizeof(peeraddr)); } } }
void rel_send(int sock, void *buf, int len) { if(user == UNKNOWN){ user = SENDER; } int flag_ack_checked; int flag_packet_dropped; // make the packet = header + buf char packet[1400]; struct hw7_hdr *hdr = (struct hw7_hdr*)packet; flag_ack_checked = 0; flag_packet_dropped = 0; memset(hdr,0,sizeof(struct hw7_hdr)); hdr->sequence_number = htonl(sequence_number); memcpy(hdr+1,buf,len); fprintf(stderr,"\r<SHUBHAM>Sent Packet - %d with rtt %d dev %d timeout - %d ms \n",sequence_number,rtt, deviation,timeval_to_msec(&timeout)); sendto(sock, packet, sizeof(struct hw7_hdr)+len, 0,(struct sockaddr*)&peeraddr,sizeof(peeraddr)); // put packet in queue, flag = ack not rxed, seq_no struct senderQelements *s; s = calloc(sizeof(struct senderQelements),1); s->magic = 'S'; s->ack_rxed = 0; s->retx = 0; s->packet_len = sizeof(struct hw7_hdr) + len; s->sent_time = current_msec(); memcpy(s->packet, packet, s->packet_len); doQInsert((char *)s); // 1. If queue has no. of elements == window size or if this is the close packet if(getCurrentQSize() == window_size || len == 0){ int ack_count; ack_count = 0; // wait for acks from all while(ack_count < window_size) { if(getCurrentQSize() == 0){ //double check...otherwise we might go in infinite loop //remove break; } fd_set readset; FD_ZERO(&readset); FD_SET(sock,&readset); struct timeval t = timeout; // select changes the timeout parameter on some platforms, so make a copy int rdy = select(FD_SETSIZE,&readset,0,0,&t); if(rdy==0) { //send all unacked packets again send_all_unacked_packets_again(sock); flag_packet_dropped = 1; // if we timed out, send again double the timeout value msec_to_timeval(min(1000,2*timeval_to_msec(&timeout)), &timeout); /* fprintf(stderr,"\rSent Packet %d with rtt %d dev %d timeout %d ms ",sequence_number,rtt, deviation,timeval_to_msec(&timeout)); sendto(sock, packet, sizeof(struct hw7_hdr)+len, 0,(struct sockaddr*)&peeraddr,sizeof(peeraddr)); //s->retx=1; fprintf(stderr,"\r<SHUBHAM>Retransmitting - Packet %d with rtt %d dev %d timeout %d ms \n",sequence_number,rtt, deviation,timeval_to_msec(&timeout)); */ } else if(rdy==-1) { perror("select error"); } else { char incoming[1400]; struct sockaddr_in from_addr; unsigned int addrsize = sizeof(from_addr); int recv_count=recvfrom(sock,incoming,1400,0,(struct sockaddr*)&from_addr,&addrsize); if(recv_count<0) { perror("When receiving packet."); return; } struct hw7_hdr *hdr = (struct hw7_hdr*)incoming; if(ntohl(hdr->ack_number) >= start_seq_no && ntohl(hdr->ack_number) <= (start_seq_no + window_size - 1)) { fprintf(stderr,"\r<SHUBHAM>Got ack for %d \n",ntohl(hdr->ack_number)); fprintf(stderr,"<SHUBHAM> Ack rxed - %d , start_seq_no , redundant log\n", (ntohl(hdr->ack_number)) - start_seq_no, start_seq_no); struct senderQelements *s; s = getNthElement((ntohl(hdr->ack_number)) - start_seq_no); fprintf(stderr,"<SHUBHAM> nth element in Q packet->seq_no = %d\n", ntohl(((struct hw7_hdr *)s->packet)->sequence_number)); if(s->ack_rxed){ fprintf(stderr,"<SHUBHAM> RE-Ack rxed - %d , doing nothing\n", (ntohl(hdr->ack_number)) - start_seq_no); } else{ ack_count++; if(!s->retx){ // if this is an ack for our present packet, update the rtt and exit update_rtt(current_msec() - s->sent_time); } } s->ack_rxed = 1; //break; } // if it's not an ack, it's the end of the stream. ACK it. // Scenario: 1. Sender sends close, 2. rxer sends ack(it is lost), 3. rxer sends close, 4. sender recives close in rel_send() /*SHUBHAM: todo?? Handle the close part here?? */ if(! (hdr->flags & ACK)) { // ack whatever we have so far struct hw7_hdr ack; ack.flags = ACK; if(ntohl(hdr->sequence_number) == expected_sequence_number) { expected_sequence_number++; } else { fprintf(stderr,"Unexpected non-ACK in rel_send(), size %d. Acking what we have so far. \n",recv_count); } ack.ack_number = htonl(expected_sequence_number-1); fprintf(stderr,"\r<SHUBHAM>Exception: Sending ACK - %d for a non-ack packet receivd \n",ntohl(ack.ack_number)); sendto(sock, &ack, sizeof(ack), 0,(struct sockaddr*)&peeraddr,sizeof(peeraddr)); } } flag_ack_checked = 1; } } /* else{ // return, so that user can send next packet. return; } */ if(len == 0 && !flag_ack_checked){ perror("Some problem"); exit(2); } if(flag_ack_checked){ while(getCurrentQSize() > 0){ //make_raghvan_change struct senderQelements *s; s = doQDelete(); free(s); } start_seq_no = start_seq_no + window_size; //make_raghvan_change if(start_seq_no != sequence_number+1){ exit(20); //assert_remove } if(flag_packet_dropped == 1){ decrease_window_size(); } else{ increase_window_size(); } } sequence_number++; }