void ptimer_consume_time(ptimer_table_t *table, u32 time) { ptimer_t *timer; u32 i; if(table == NULL) return; for(i=0; i<time; i++) { while(!DLLIST_EMPTY(&table->table[table->curslot])) { timer = (ptimer_t *)DLLIST_HEAD(&table->table[table->curslot]); assert(ptimer_is_running(timer)); /* remove all timers in current slot */ dllist_remove(NULL, (dllist_node_t *)timer); /* handle remainder */ if(timer->remainder) { ptimer_start_remainder(table, timer, timer->remainder); continue; } /* mark timer as not running */ timer->flags &= ~PTIMER_FLAG_RUNNING; /* call onexpired_func */ // ZLOG_DEBUG("timer expired: 0x%p at slot %u\n", timer, table->curslot); if(timer->onexpired_func) { timer->onexpired_func(timer, timer->param[0], timer->param[1]); } /* if periodic timer */ if((timer->flags & PTIMER_FLAG_PERIODIC) && !(timer->flags & PTIMER_FLAG_RUNNING)) ptimer_start(table, timer, timer->duration); } table->curslot = (table->curslot + 1) & (table->allslots - 1); } }
void output_rx_throughput(packet_t *pktt) { static dllist_node_t rx_tpt_list = { .prev = &rx_tpt_list, .next = &rx_tpt_list }; if (pktt && pktt->ptt != RX_OK) return; if (pktt == NULL) { /* output the result */ while (!DLLIST_EMPTY(&rx_tpt_list)) { rx_throughput_t *ttt = (rx_throughput_t*) DLLIST_HEAD(&rx_tpt_list); ZLOG_INFO("rx tpt: at [%d, %d)s, throughput %d bps\n", ttt->time, ttt->time + 1, ttt->throughput /* bps */); dllist_remove(&rx_tpt_list, &(ttt->node)); free(ttt); } return; } /* pktt != NULL, calcuate the rx *delivery* throughput */ u32 remainder = pktt->rx_deliver_timestamp % (u32) MS2US(S2MS(1)); u32 integer = (pktt->rx_deliver_timestamp - remainder) / MS2US(S2MS(1)); rx_throughput_t * ttt = (rx_throughput_t*) DLLIST_TAIL(&rx_tpt_list); if (DLLIST_IS_HEAD(&rx_tpt_list, ttt) || ttt->time != integer) { /* new one */ rx_throughput_t *new_ttt = (rx_throughput_t*) malloc(sizeof(rx_throughput_t)); assert(new_ttt); new_ttt->time = integer; new_ttt->throughput = pktt->packet_size; dllist_append(&rx_tpt_list, &(new_ttt->node)); } else { /* already existed, update it */ ttt->throughput += (pktt->packet_size * OCTET); } }
int main (int argc, char *argv[]) { /* 1. acquire all simulation parameters or use the default values 2. generate the simulation begin event @time = 0 3. add this event to the timer queue 4. while (simulatio not finished) { advance the simu time by 1 time unit (ms) } */ /* 1. */ simu_paras_t spt; spt.t.packet_size = PKT_SIZE; /* bytes */ spt.rl.link_distance = 0; spt.rl.prop_delay = MS2US(270); /* 270 ms */ spt.rl.link_bandwidth = BANDWIDTH; /* bps */ spt.rl.per = PER; /* x/10000 */ /* this should be set when the mac pdu is build (at the tx_begin_event) */ /* spt.tx_delay = ( (1e3 * OCTET * (spt.t.packet_size + MAC_HEADER_SIZE + PHY_HEADER_SIZE)) / spt.rl.link_bandwidth ); */ /* rlc params */ spt.rlc_paras.ump.t_Reordering = MS2US(T_REORDERING); /* ms */ spt.rlc_paras.ump.UM_Window_Size = UWSize; /* window size */ spt.rlc_paras.ump.sn_FieldLength = SN_LEN; /* sn length */ #define PTIMER_MEM_MAX 4096*16 spt.g_mem_ptimer_t = fastalloc_create(sizeof(ptimer_t), PTIMER_MEM_MAX, 0, 100); assert(spt.g_mem_ptimer_t); /* #define PACKET_MEM_MAX (4096*16*16*8) */ /* spt.g_mem_packet_t = fastalloc_create(sizeof(packet_t), PACKET_MEM_MAX, 0, 100); */ /* assert(spt.g_mem_packet_t); */ /* @transmitter */ /* @receiver */ /* leave these to be done at the simulatioin begin event */ /* init log */ zlog_default = openzlog(ZLOG_STDOUT); zlog_set_pri(zlog_default, LOG_INFO); zlog_reset_flag(zlog_default, ZLOG_LOGTIME); /* no time display */ ZLOG_DEBUG("pkt size = %d, prop delay = %d, link bandwidth = %d\n", spt.t.packet_size, spt.rl.prop_delay, spt.rl.link_bandwidth); /* 2. */ /* FIXME: simu time unit: 1us! */ ptimer_t simu_begin_timer = { .duration = 0, .onexpired_func = simu_begin_event, .param[0] = (void*) &spt, .param[1] = (void*) SIMU_BEGIN, }; time_t t; srand((unsigned) time(&t)); /* 3. */ rlc_init(); rlc_timer_start(&simu_begin_timer); /* 4. */ int step_in_us = 1; while (g_is_finished == NOT_FINISHED && g_time_elasped_in_us <= MS2US(S2MS(SIMU_TIME)) ) { rlc_timer_push(step_in_us); /* us */ g_time_elasped_in_us += step_in_us; if ( g_time_elasped_in_us % (int)MS2US(S2MS(1)) == 0 ) { ZLOG_INFO("simu time = %f\n", g_time_elasped_in_us/MS2US(S2MS(1))); } } /* output the simu result */ ZLOG_DEBUG("time_elasped_in_us = %d\n", g_time_elasped_in_us); int cnt = 0; int output_e2e_delay = 1; int n_rxok = 0, n_rxerr = 0; while (!DLLIST_EMPTY(&g_sink_packet_list)) { packet_t *pktt = (packet_t*) DLLIST_HEAD(&g_sink_packet_list); /* 1. tx throughput */ // output_tx_throughput(pktt); // output_rx_throughput(pktt); /* 2. e2e delay */ switch (pktt->ptt) { case RX_OK: n_rxok++; break; case RX_ERR: n_rxerr++; break; default: assert(0); break; } if( output_e2e_delay ) { if (pktt->ptt == RX_OK ) ZLOG_INFO("SN, buffering: %u, %u\n", pktt->sequence_no, pktt->rx_deliver_timestamp - pktt->rx_end_timestamp); } dllist_remove(&g_sink_packet_list, &(pktt->node)); cnt++; // FASTFREE(spt.g_mem_packet_t, pktt); free(pktt); pktt = NULL; } output_tx_throughput(NULL); output_rx_throughput(NULL); ZLOG_INFO("n_txed = %d, n_rxok = %d, n_rxerr = %d\n", cnt, n_rxok, n_rxerr); return 0; }
void output_tx_throughput(packet_t *pktt) { /* unit: second, based on the pktt->tx_begin_timestamp, the pktt->tx_end_timestamp */ static dllist_node_t tx_tpt_list = { .prev = &tx_tpt_list, .next = &tx_tpt_list }; if (pktt == NULL) { /* output the result */ while (!DLLIST_EMPTY(&tx_tpt_list)) { tx_throughput_t *ttt = (tx_throughput_t*) DLLIST_HEAD(&tx_tpt_list); ZLOG_INFO("tx tpt: at [%d, %d)s, throughput %d bps\n", ttt->time, ttt->time + 1, ttt->throughput /* bps */); dllist_remove(&tx_tpt_list, &(ttt->node)); free(ttt); } return; } /* pktt != NULL, calcuate the tx throughput */ u32 remainder_begin = pktt->tx_begin_timestamp % (u32) MS2US(S2MS(1)); u32 remainder_end = pktt->tx_end_timestamp % (u32) (MS2US(S2MS(1))); u32 integer_begin = (pktt->tx_begin_timestamp - remainder_begin) / MS2US(S2MS(1)); u32 integer_end = (pktt->tx_end_timestamp - remainder_end) / MS2US(S2MS(1)); tx_throughput_t * ttt = (tx_throughput_t*) DLLIST_TAIL(&tx_tpt_list); if ( integer_begin == integer_end ) { /* in the same time range */ /* if have, get it */ if (DLLIST_IS_HEAD(&tx_tpt_list, ttt) || ttt->time != integer_begin) { /* new one */ tx_throughput_t *new_ttt = (tx_throughput_t*) malloc(sizeof(tx_throughput_t)); assert(new_ttt); new_ttt->time = integer_begin; new_ttt->throughput = pktt->mac_pdu_size * OCTET; dllist_append(&tx_tpt_list, &(new_ttt->node)); } else { /* already existed, update it */ ttt->throughput += (pktt->mac_pdu_size * OCTET); } } else { /* not in the same time range, split it based on the pktt->mac_pdu_size */ assert(integer_end - integer_begin == 1); u32 total = pktt->tx_end_timestamp - pktt->tx_begin_timestamp; if (DLLIST_IS_HEAD(&tx_tpt_list, ttt)) { ttt = (tx_throughput_t*) malloc(sizeof(tx_throughput_t)); dllist_append(&tx_tpt_list, &(ttt->node)); } u32 part = (pktt->mac_pdu_size * OCTET) * remainder_end / total; tx_throughput_t *new_ttt = (tx_throughput_t*) malloc(sizeof(tx_throughput_t)); assert(new_ttt); new_ttt->time = integer_end; new_ttt->throughput = (pktt->mac_pdu_size * OCTET) * remainder_end / total; dllist_append(&tx_tpt_list, &(new_ttt->node)); ttt->time = integer_begin; ttt->throughput += (pktt->mac_pdu_size * OCTET) * (1 - remainder_end / total); ZLOG_DEBUG("begin %d, remainder %d, tpt: %d, end %d, remainder %d, tpt: %d\n", integer_begin, remainder_begin, pktt->mac_pdu_size * OCTET - part, integer_end, remainder_end, part); } }