int mg_distribute_send_single( struct mg_distribute_config *cfg, struct rte_mbuf *pkt, void **entry ){ //printf(">>dis s\n"); uint8_t output = ((uint8_t*)(*entry))[cfg->entry_offset]; //printf("dis o\n"); //printf(" send out to %d\n", output); // send pkt to the corresponding output... int8_t status = mg_distribute_enqueue(cfg->outputs[output].queue, pkt); //printf("dis st\n"); if( unlikely( status == 2 ) ){ //printf(" ful\n"); // packet was enqueued, but queue is full // flush queue mg_distribute_output_flush(cfg, output); //printf(" fd\n"); } if( unlikely( status == 1 ) ){ //printf(" empty\n"); // packet was enqueued, queue was empty // record the time, for possible future timeout cfg->outputs[output].time_first_added = rte_rdtsc(); //printf(" stored_time\n"); } if(unlikely(cfg->always_flush)){ int i; //FIXME check if output valid for (i = 0; i < cfg->nr_outputs; i++){ if(likely(cfg->outputs[i].valid)){ mg_distribute_output_flush(cfg, i); } } } //printf("dis d\n"); return 0; }
// Call frequency of this function defines the resolution of timeouts for // queue flushes. void mg_distribute_handle_timeouts( struct mg_distribute_config *cfg ){ int i; uint64_t time = rte_rdtsc(); struct mg_distribute_output *output = cfg->outputs; for (i = 0; i < cfg->nr_outputs; i++){ if(likely(output->valid)){ if(output->time_first_added + output->timeout < time){ //printf("added = %lu, timeout = %lu, current time = %lu\n", output->time_first_added, output->timeout, time); // timeout hit -> flush queue //printf("timeout of output %d was hit\n", i); mg_distribute_output_flush(cfg, i); // prevent timeout from occuring again // (will work for a runtime <199 years on 3GHz CPUs) output->time_first_added = 0xffffffffffffffff - output->timeout; } } output++; } }
int mg_distribute_send( struct mg_distribute_config *cfg, struct rte_mbuf **pkts, struct mg_bitmask* pkts_mask, void **entries ){ // XXX: IDEA: only store time for buffer, when this function ends. // as a timeout during runtime of this function will never occur anyways. // this would make the loop and enqueue much faster //printf("ENTRIES = %p\n", entries); //printf(" d iface = %d\n", ((uint8_t*)(entries[0]))[4]); //printf(" d iface = %d\n", ((uint8_t*)(*entries))[4]); //printf("offset = %d\n", cfg->entry_offset); //printf("i am in send\n"); // TODO: performance considerations: // - loop unrolling (is compiler doing that?) // - we always iterate multiple of 64... // -> maybe save cycles, when burst is not multiple of 64? int i; //uint16_t count = 0; for(i = 0; i < pkts_mask->n_blocks; i++){ //printf(" block %d\n", i); uint64_t mask = 1ULL; while(mask){ //printf("while LOOP\n"); if(mask & pkts_mask->mask[i]){ //count++; //printf(" pkt mask true\n"); // determine output, to send the packet to // printf(" entry = %p\n", *entries); // printf(" d iface = %d\n", ((uint8_t*)(entries[0]))[4]); // printf(" d iface = %d\n", ((uint8_t*)(*entries))[4]); uint8_t output = ((uint8_t*)(*entries))[cfg->entry_offset]; //printf(" send out to %d\n", output); // send pkt to the corresponding output... int8_t status = mg_distribute_enqueue(cfg->outputs[output].queue, *pkts); // TODO: switch would be better here or if/else if if( unlikely( status == 2 ) ){ //printf(" full\n"); // packet was enqueued, but queue is full // flush queue mg_distribute_output_flush(cfg, output); } if( unlikely( status == 1 ) ){ //printf(" empty\n"); // packet was enqueued, queue was empty // record the time, for possible future timeout cfg->outputs[output].time_first_added = rte_rdtsc(); //printf(" stored_time\n"); } } pkts++; entries++; mask = mask<<1; } } //printf("enqueued %u packets\n", count); if(unlikely(cfg->always_flush)){ int i; //FIXME check if output valid for (i = 0; i < cfg->nr_outputs; i++){ if(likely(cfg->outputs[i].valid)){ mg_distribute_output_flush(cfg, i); } } } return 0; }