/******************************************************************************* * File: ops.c * Description: OPS simulations with FCFS buffers and wavelength-converters * Author: Vijay Sivaraman * History: Mar 2007: v1.0 released ******************************************************************************/ #include #include #include #include #include #include "skiplist/skiplist.h" /* some standard defines */ #ifndef int8_t #define int8_t char #endif #ifndef uint8_t #define uint8_t unsigned char #endif #ifndef int16_t #define int16_t short #endif #ifndef uint16_t #define uint16_t unsigned short #endif #ifndef int32_t #define int32_t long #endif #ifndef uint32_t #define uint32_t unsigned long #endif #define MIN(a,b) ((b)<(a)? (b):(a)) #define MAX(a,b) ((b)>(a)? (b):(a)) /* simulation parameters */ #define EPSILON 1.0e-6 #define LIGHT_SPEED 0.2 /* km/usec */ #define LINK_RATE 10000.0 /* bits-per-usec over all wavelengths */ #define NWAVELENGTH_LIMIT 300 /* limit on number of wavelengths per link */ #define RATE_INFINITY 0.0 #define COS_CLASS_RT 0 /* real-time traffic class */ #define COS_CLASS_BE 1 /* best-effort traffic class */ /* topology and traffic related */ #ifdef TOPOLOGY_SINGLE8x1 /* single core node topology */ #define NUM_EDGE_NODES 9 /* number of E nodes */ #define NUM_CORE_NODES 1 /* number of O nodes */ #define MAX_LINKS 9 /* maximum links per node */ #define NUM_FLOWS 8 /* number of traffic flows */ #define CONF_FILE "conf.single8x1" #elif defined TOPOLOGY_CeNTIE /* CeNTIE topology */ #define NUM_CORE_NODES 4 /* number of O nodes */ #define NUM_EDGE_NODES 10 /* number of E nodes */ #define MAX_LINKS 5 /* maximum links per node */ #define NUM_FLOWS 8 /* number of traffic flows */ #define CONF_FILE "conf.centie" #elif defined TOPOLOGY_NSFNET /* NSFNet topology */ #define NUM_CORE_NODES 24 /* number of O nodes */ #define NUM_EDGE_NODES 96 /* number of E nodes */ #define MAX_LINKS 9 /* maximum links per node */ #define NUM_FLOWS 96 /* number of traffic flows */ #define CONF_FILE "conf.nsfnet" #else undefined_topology; #endif /* node-id is 16-bits, top 8-bits denote core/edge, lower 8-bits denote index */ #define NODE_IS_CORE(id) (((id)&0xFF00)? 1:0) #define NODE_IS_EDGE(id) (!NODE_IS_CORE(id)) #define NODE_ID_TO_INDEX(id) ((id) & 0xFF) #define NODE_INDEX_TO_ID_CORE(i) ((i) | 0x0100) #define NODE_INDEX_TO_ID_EDGE(i) ((i) | 0x0000) /* events - Do NOT change the order below (event type is the sorting key) */ #define EVENT_NONE 0 /* blank event */ #define EVENT_HULL 1 /* hull bend or pkt release */ #define EVENT_PKTARR 2 /* pkt arrival */ #define EVENT_PKTTXSTART 3 /* start transmit pkt */ #define EVENT_PKTTXEND 4 /* end transmit pkt */ #define EVENT_PKTRX 5 /* receive pkt */ typedef struct Event_s { uint16_t type; /* type of event */ uint16_t nodeId; /* node-id where event occurs */ double time; /* time at which event happens */ void *info; /* event specific info */ } Event_t; /* data packet */ typedef struct Packet_s { uint16_t fid; /* flow-id of pkt */ uint16_t size; /* packet size in bytes */ uint32_t pid; /* pkt id for stats purposes */ uint32_t elig; /* pkt eligible (from hull) or not */ double arrTime; /* time of arrival of last bit to system */ double deadline; /* packet deadline at edge node */ double exitTime; /* time of exit of last bit from system */ struct Packet_s *next; /* next pkt in dst list */ } Packet_t; /* traffic flows */ typedef struct Flow_s { uint16_t src; /* nodeid of flow source */ uint16_t dst; /* nodeid of flow dest */ uint16_t fid; /* flow id */ uint16_t qos; /* flow qos level */ double load; /* flow load */ Event_t arrEvent; /* arrival event */ FILE *inFp; /* input file pointer */ double sampleT; /* sample size in milliseconds */ double S; /* scaling */ double C; /* mean bits per sampleT */ double lastArrTime; /* time of last pkt arrival */ double resTime; /* residual time in current sample */ double resBits; /* residual bits in current sample */ uint32_t lTrunc; /* number of lower truncations */ uint32_t pktTx; /* packets transmitted */ uint32_t pktRx; /* packets rcvd */ uint32_t pktLost; /* packets dropped */ double totDelay; /* total delay for average computation */ } Flow_t; /* packet queue on E switches */ typedef struct Queue_s { uint32_t size; /* queue length in bytes */ Packet_t *head; /* head of packets in queue */ Packet_t *tail; /* tail of packets in queue */ } Queue_t; typedef struct HullPt_s { double endTime; /* end time of current segment */ double svcRate; /* svc rate */ struct HullPt_s *prev; /* previous hull point */ struct HullPt_s *next; /* next hull point */ } HullPt_t; #define ROUTE_SELF 0xFFFF /* denotes self as route destination */ /* common switch structures */ typedef struct Switch_s { char name[32]; /* node name */ uint16_t nodeId; /* id of node */ uint16_t nLinks; /* # of outgoing fibres (numbered 0 to nLinks-1) */ double linkDelay[MAX_LINKS]; /* length/delay on each fiber (usec)*/ double linkLoad[MAX_LINKS]; /* load on this link */ uint16_t linkMap[MAX_LINKS]; /* nodeid of other end of link */ uint16_t routeMap[NUM_EDGE_NODES]; /* eswitch-idx to egress fiber# map */ Queue_t queue[MAX_LINKS]; /* pkt queue per link */ double pktTxEndTime[MAX_LINKS][NWAVELENGTH_LIMIT]; /* tx end-time of last pkt */ Event_t pktTxEndEvent[MAX_LINKS][NWAVELENGTH_LIMIT]; /* tx end-event */ } Switch_t; /* edge switch */ typedef struct ESwitch_s { Switch_t s; /* common switch structures */ uint32_t propDelay[NUM_EDGE_NODES]; /* end-to-end propagation delay */ HullPt_t *hullHead[MAX_LINKS], *hullTail[MAX_LINKS]; /* hull */ double hullCredit[MAX_LINKS]; /* credit in bytes */ double hullLastUpdate[MAX_LINKS]; /* last time hull was updated */ Event_t hullEvent[MAX_LINKS]; /* hull event for this node-link */ } ESwitch_t; /* core switch */ typedef struct OSwitch_s { Switch_t s; /* common switch structures */ } OSwitch_t; typedef struct SimClass_s { int (*arrNext)(uint16_t fid); /* arrival function */ int (*arrCleanup)(); /* arrival process cleanup function */ char inFilePrefix[128]; /* input file prefix */ char outFilePrefix[128]; /* output file prefix */ uint32_t pktsToSimulate; /* max number of pkts to simulate */ double beDbound; /* delay bound for best-effort pkts */ uint32_t maxBufSize; /* fifo buffer size (bytes) per output link of core node */ uint32_t nWavelengths; /* number of operational wavelengths */ SkipList_t *eventList; /* list of events */ double curTime; /* current simulation time in usec */ uint32_t txPkts; /* #pkts transmitted, also id of next pkt */ uint32_t rxPkts; /* #pkts received */ uint32_t lostPkts; /* number of pkts lost */ ESwitch_t eSwitch[NUM_EDGE_NODES]; /* per-Eswitch info */ OSwitch_t oSwitch[NUM_CORE_NODES]; /* per-Oswitch info */ Flow_t flow[NUM_FLOWS]; /* flow information */ } SimClass_t; /* debugging */ #define DEBUG_ARR 0x01 /* debug pkt arrivals */ #define DEBUG_HULL 0x02 /* debug hull */ #define DEBUG_TX 0x04 /* debug tx of pkts */ #define DEBUG_RX 0x08 /* debug rx of pkts */ double pktSizeDist[1501]; SimClass_t simClass, *sim; /* globals for simulation */ /* mask for debugging */ int simDebug = 0/*DEBUG_ARR | DEBUG_HULL | DEBUG_TX | DEBUG_RX*/; /******************************************************************************* * Event library ******************************************************************************/ /*------------------------------------------------------------------------------ * eventSkipListCmp(): compare function for sorting events */ int eventSkipListCmp(void *k1, void *k2) { Event_t *e1 = (Event_t *)k1; Event_t *e2 = (Event_t *)k2; if (e1->time < e2->time) return -1; else if (e1->time > e2->time) return 1; else if (e1->type < e2->type) return -1; else if (e1->type > e2->type) return 1; else if (e1->nodeId!=e2->nodeId) return (e1->nodeId - e2->nodeId); else return (int)(e1->info - e2->info); } void eventSkipListFree(void *e) { return; } /******************************************************************************* * General utilities ******************************************************************************/ /*------------------------------------------------------------------------------ * recordPkt(): record pkt stats */ void recordPktStats(Packet_t *pkt) { ++sim->flow[pkt->fid].pktRx; sim->flow[pkt->fid].totDelay += /* end-to-end delay in us excluding prop */ (pkt->exitTime - pkt->arrTime) - sim->eSwitch[NODE_ID_TO_INDEX(sim->flow[pkt->fid].dst)] .propDelay[NODE_ID_TO_INDEX(sim->flow[pkt->fid].src)]; return; } /******************************************************************************* * Arrival Process ******************************************************************************/ /*------------------------------------------------------------------------------ * pktSizeDistInit(): initialize distribution of pkt size */ int pktSizeDistInit() { FILE *fp; int nread, pktSize, lastPktSize, i; double pcntVal, lastPcntVal, inc; fp = fopen("../../utils/pkthist.dat", "r"); assert(fp); memset(pktSizeDist, 0x0, sizeof(pktSizeDist)); for (lastPktSize=0, lastPcntVal=0.0; ;) { nread = fscanf(fp, "%d %lf", &pktSize, &pcntVal); if (nread < 2) break; assert((pktSize>lastPktSize)&&(pktSize<=1500)); assert((pcntVal>=lastPcntVal)&&(pcntVal<=100.0)); /* linear interpolate between last and current values */ inc = (pcntVal-lastPcntVal)/(100.0*(double)(pktSize-lastPktSize)); for (i=lastPktSize+1; i1; mid=(lo+hi)/2) { if (r < pktSizeDist[mid]) { hi = mid; } else { lo = mid; } } return hi; } /*------------------------------------------------------------------------------ * rvExp(): generate an exponentially distributed random variable */ double rvExp(double rate) { double r, interArr; r = drand48(); interArr = -log(1.0-r)/rate; return interArr; } /*------------------------------------------------------------------------------ * arrPoisson(): poisson arrival function */ int arrPoisson(uint16_t fid) { int pktSize; double pktRate; Packet_t *pkt; #define MEAN_PKT_SIZE 420 /* bytes */ if (sim->flow[fid].lastArrTime==0.0) { /* set event fields */ memset(&sim->flow[fid].arrEvent, 0x0, sizeof(Event_t)); sim->flow[fid].arrEvent.type = EVENT_PKTARR; sim->flow[fid].arrEvent.nodeId = sim->flow[fid].src; } /* create packet */ pktRate = (LINK_RATE*sim->flow[fid].load) / (double)(MEAN_PKT_SIZE<<3); /* pkts/usec */ pktSize = rvPktSize(); pkt = (Packet_t *)malloc(sizeof(Packet_t)); assert(pkt); memset(pkt, 0x0, sizeof(Packet_t)); pkt->fid = fid; pkt->size = pktSize; /* schedule event */ sim->flow[fid].arrEvent.time = sim->curTime + rvExp(pktRate); sim->flow[fid].arrEvent.info = pkt; SkipListInsert(sim->eventList, &sim->flow[fid].arrEvent, &sim->flow[fid].arrEvent, 0); return 0; } /*------------------------------------------------------------------------------ * arrFile(): read arrivals from file */ int arrFile(uint16_t fid) { char fileName[256]; Packet_t *pkt; int pktSize; int nread; double arrBits, interArrTime, val; if (sim->flow[fid].lastArrTime==0.0) { /* open input file */ sprintf(fileName, "%s%02d.txt", sim->inFilePrefix, fid); sim->flow[fid].inFp = fopen(fileName, "r"); assert(sim->flow[fid].inFp); /* set event fields */ memset(&sim->flow[fid].arrEvent, 0x0, sizeof(Event_t)); sim->flow[fid].arrEvent.type = EVENT_PKTARR; sim->flow[fid].arrEvent.nodeId = sim->flow[fid].src; /* clear some fields */ sim->flow[fid].resTime = sim->flow[fid].resBits = 0.0; } pktSize = rvPktSize(); if (sim->flow[fid].resBits >= (double)(pktSize<<3)) { /* already have enough bits for next pkt */ interArrTime = (double)(pktSize<<3) * sim->flow[fid].resTime / sim->flow[fid].resBits; sim->flow[fid].resTime -= interArrTime; sim->flow[fid].resBits -= (double)(pktSize<<3); sim->flow[fid].lastArrTime += interArrTime; } else { /* read fBm samples from file till next pkt is ready */ sim->flow[fid].resTime = 0.0; sim->flow[fid].lastArrTime = sim->flow[fid].sampleT * ceil(sim->flow[fid].lastArrTime/sim->flow[fid].sampleT); for (;;) { nread = fscanf(sim->flow[fid].inFp, "%le", &val); if (nread <= 0) return -1; arrBits = sim->flow[fid].C + sim->flow[fid].S * val; if (arrBits < 0.0) { /* lower truncate */ arrBits = 0.0; ++sim->flow[fid].lTrunc; } if ((sim->flow[fid].resBits + arrBits) >= (double)(pktSize<<3)) break; else { sim->flow[fid].resBits += arrBits; sim->flow[fid].lastArrTime += sim->flow[fid].sampleT; } } /* end of loop finding slot in which pkt will arrive */ assert(sim->flow[fid].resBits < (double)(pktSize<<3) && (sim->flow[fid].resBits+arrBits) >= (double)(pktSize<<3)); interArrTime = sim->flow[fid].sampleT * ((double)(pktSize<<3) - sim->flow[fid].resBits) / arrBits; sim->flow[fid].lastArrTime = sim->flow[fid].lastArrTime + interArrTime; sim->flow[fid].resTime = sim->flow[fid].sampleT * ceil(sim->flow[fid].lastArrTime/sim->flow[fid].sampleT) - sim->flow[fid].lastArrTime; sim->flow[fid].resBits += (arrBits - (double)(pktSize<<3)); } /* create packet */ pkt = (Packet_t *)malloc(sizeof(Packet_t)); assert(pkt); memset(pkt, 0x0, sizeof(Packet_t)); pkt->fid = fid; pkt->size = pktSize; /* schedule arrival event */ sim->flow[fid].arrEvent.time = sim->flow[fid].lastArrTime; sim->flow[fid].arrEvent.info = pkt; SkipListInsert(sim->eventList, &sim->flow[fid].arrEvent, &sim->flow[fid].arrEvent, 0); return 0; } /*------------------------------------------------------------------------------ * arrFileCleanup: cleanup arrivals from file */ int arrFileCleanup() { int i; for (i=0; i< NUM_FLOWS; ++i) { assert(sim->flow[i].inFp); fclose(sim->flow[i].inFp); sim->flow[i].inFp = NULL; } return 0; } /******************************************************************************* * Processing of events ******************************************************************************/ /*------------------------------------------------------------------------------ * eventArr(): pkt arrival event */ int eventArr(Event_t *event) { Packet_t *pkt; int sidx, didx, outLink; HullPt_t *hullPt, *hullPtPrev; double lastPtTime; ESwitch_t *node; assert(event); pkt = (Packet_t *)event->info; assert(pkt); /* extract edge node index */ assert(NODE_IS_EDGE(event->nodeId)); assert(event->nodeId==sim->flow[pkt->fid].src); sidx = NODE_ID_TO_INDEX(sim->flow[pkt->fid].src); /* pkt src */ didx = NODE_ID_TO_INDEX(sim->flow[pkt->fid].dst); /* pkt dst */ node = &sim->eSwitch[sidx]; assert(node); /* fill in packet fields and queue the arrival */ pkt->pid = sim->txPkts++; pkt->arrTime = sim->curTime; outLink = node->s.routeMap[didx]; assert(outLink!=ROUTE_SELF); pkt->deadline = pkt->arrTime + ((sim->flow[pkt->fid].qos==COS_CLASS_BE)? sim->beDbound : 0.0); if (node->s.queue[outLink].head==NULL) node->s.queue[outLink].head = pkt; if (node->s.queue[outLink].tail) node->s.queue[outLink].tail->next = pkt; node->s.queue[outLink].tail = pkt; node->s.queue[outLink].size += pkt->size; /* update arrival stats */ ++sim->flow[pkt->fid].pktTx; /* debug logging */ if (simDebug & DEBUG_ARR) { printf("pkt=%lu fid=%d(%s/%d) len=%d q=%ld\n", pkt->pid, pkt->fid, sim->eSwitch[NODE_ID_TO_INDEX(sim->flow[pkt->fid].dst)].s.name, sim->flow[pkt->fid].qos, pkt->size, node->s.queue[outLink].size); } if (pkt->pid%1000000==0) { printf("%lum...", pkt->pid/1000000); fflush(stdout); } /* schedule next arrival */ if (sim->txPkts < sim->pktsToSimulate) sim->arrNext(pkt->fid); /* schedule next arrival */ else { /* clear the arrival event structure */ sim->flow[pkt->fid].arrEvent.time = 0.0; sim->flow[pkt->fid].arrEvent.info = NULL; } /* create new hull point and update credits */ hullPt = (HullPt_t *)malloc(sizeof(HullPt_t)); assert(hullPt); memset(hullPt, 0x0, sizeof(HullPt_t)); hullPt->endTime = pkt->deadline; if (node->hullTail[outLink]) { assert(node->hullTail[outLink]->endTime >= sim->curTime); hullPt->svcRate = (double)pkt->size / (double)(pkt->deadline - node->hullTail[outLink]->endTime); } else if (pkt->deadline==sim->curTime) { hullPt->svcRate = RATE_INFINITY; } else { hullPt->svcRate = (double)pkt->size / (double)(pkt->deadline - sim->curTime); } if (node->hullTail[outLink]) node->hullTail[outLink]->next = hullPt; hullPt->prev = node->hullTail[outLink]; node->hullTail[outLink] = hullPt; if (node->hullHead[outLink]==NULL) { /* no other hull piece */ node->hullHead[outLink] = hullPt; node->hullCredit[outLink] = 0.0; node->hullLastUpdate[outLink] = sim->curTime; /* schedule hull event */ node->hullEvent[outLink].time = pkt->deadline; SkipListInsert(sim->eventList, &node->hullEvent[outLink], &node->hullEvent[outLink], 0); } else { /* hull piece already exists */ /* find first ineligible pkt in queue */ Packet_t *hullQHead; for (hullQHead=node->s.queue[outLink].head; (hullQHead!=NULL) && (hullQHead->elig); hullQHead = hullQHead->next); assert(hullQHead!=NULL); /* then update hull credits */ assert(node->hullHead[outLink]->endTime > sim->curTime); node->hullCredit[outLink] += (sim->curTime - node->hullLastUpdate[outLink]) * node->hullHead[outLink]->svcRate; assert(node->hullCredit[outLink] < hullQHead->size); node->hullLastUpdate[outLink] = sim->curTime; /* now scan backwards to make the hull convex */ for (hullPt=node->hullTail[outLink]; ((hullPtPrev=hullPt->prev)!=NULL) && (hullPt->svcRate >= hullPtPrev->svcRate); ) { /* rate has to be monotonically decreasing; subsume hullPt->prev */ if (hullPtPrev->prev) { lastPtTime = hullPtPrev->prev->endTime; assert(lastPtTime >= sim->curTime); } else { lastPtTime = sim->curTime; } hullPt->svcRate = (hullPt->svcRate * (hullPt->endTime - hullPtPrev->endTime) + hullPtPrev->svcRate * (hullPtPrev->endTime - lastPtTime)) / (hullPt->endTime - lastPtTime); hullPt->prev = hullPtPrev->prev; if (hullPtPrev->prev) hullPtPrev->prev->next = hullPt; else { double pktRelTime; node->hullHead[outLink] = hullPt; /* hull head has changed - reschedule hull event */ SkipListDelete(sim->eventList, &node->hullEvent[outLink]); pktRelTime = sim->curTime + (((double)hullQHead->size - node->hullCredit[outLink]) / node->hullHead[outLink]->svcRate); node->hullEvent[outLink].time = MIN(pktRelTime,node->hullHead[outLink]->endTime); SkipListInsert(sim->eventList, &node->hullEvent[outLink], &node->hullEvent[outLink], 0); } free(hullPtPrev); } /* done making hull convex */ } /* done updating existing hull */ if (simDebug & DEBUG_HULL) { printf("hull: "); for (hullPt=node->hullHead[outLink]; hullPt; hullPt=hullPt->next) { printf("[%.4lf,%.4lf] ", hullPt->endTime, hullPt->svcRate); } printf("Credits=%lf\n", node->hullCredit[outLink]); } return 0; } /*------------------------------------------------------------------------------ * eventHull(): hull segment is ending or pkt is to be released */ int eventHull(Event_t *event) { ESwitch_t *node; int outLink, w; HullPt_t *hullPt; double pktRelTime; Packet_t *hullQHead; assert(event); assert(NODE_IS_EDGE(event->nodeId)); node = &sim->eSwitch[NODE_ID_TO_INDEX(event->nodeId)]; assert(node); outLink = (int)event->info; assert(event==&node->hullEvent[outLink]); /* determine first ineligible pkt */ for (hullQHead=node->s.queue[outLink].head; (hullQHead!=NULL) && (hullQHead->elig); hullQHead = hullQHead->next); assert(hullQHead!=NULL); /* update credits */ assert(sim->curTime<=node->hullHead[outLink]->endTime); if (node->hullHead[outLink]->svcRate==RATE_INFINITY) { node->hullCredit[outLink] += hullQHead->size; } else { node->hullCredit[outLink] += (sim->curTime - node->hullLastUpdate[outLink]) * node->hullHead[outLink]->svcRate; } node->hullLastUpdate[outLink] = sim->curTime; /* delete used hull piece if done */ if (fabs(sim->curTime - node->hullHead[outLink]->endTime) < EPSILON) { hullPt = node->hullHead[outLink]; if (hullPt->next) { hullPt->next->prev = NULL; node->hullHead[outLink] = hullPt->next; } else node->hullHead[outLink] = node->hullTail[outLink] = NULL; free(hullPt); if (simDebug & DEBUG_HULL) printf("piece removed "); } /* check if pkt can be released */ if (fabs(node->hullCredit[outLink] - hullQHead->size) < EPSILON) { hullQHead->elig = 1; /* mark pkt eligible */ if (simDebug & DEBUG_HULL) printf("pkt=%ld released ", hullQHead->pid); node->hullCredit[outLink] = 0.0; /* debit the credits */ /* check if channel is idle */ for (w=0; w < sim->nWavelengths; ++w) { if (node->s.pktTxEndTime[outLink][w] <= sim->curTime) { /* idle channel exists - schedule pkt tx start event */ Event_t *txEvent = (Event_t *)malloc(sizeof(Event_t)); assert(txEvent); memset(txEvent, 0x0, sizeof(Event_t)); assert(hullQHead==node->s.queue[outLink].head); txEvent->type = EVENT_PKTTXSTART; txEvent->nodeId = node->s.nodeId; txEvent->time = sim->curTime; txEvent->info = (void *)((outLink<<16) | w); SkipListInsert(sim->eventList, txEvent, txEvent, 0); break; } /* end of if idle channel found */ } /* done scanning for available channel */ } /* done with checking pkt release */ /* redetermine first ineligible pkt in queue */ for (hullQHead=node->s.queue[outLink].head; (hullQHead!=NULL) && (hullQHead->elig); hullQHead = hullQHead->next); if (node->hullHead[outLink]) { /* more segments */ assert(hullQHead); pktRelTime = sim->curTime + (((double)hullQHead->size - node->hullCredit[outLink]) / node->hullHead[outLink]->svcRate); node->hullEvent[outLink].time = MIN(pktRelTime,node->hullHead[outLink]->endTime); SkipListInsert(sim->eventList, &node->hullEvent[outLink], &node->hullEvent[outLink], 0); } else { assert(hullQHead==NULL); } if (simDebug & DEBUG_HULL) printf("\n"); return 0; } /*------------------------------------------------------------------------------ * eventTxStart(): start pkt transmission */ int eventTxStart(Event_t *event) { Switch_t *sw; int outLink, outWavelength; Packet_t *pkt; assert(event); /* extract outlink, switch, and pkt */ outLink = ((int)event->info >> 16); outWavelength = ((int)event->info & 0xFFFF); sw = NODE_IS_EDGE(event->nodeId)? &sim->eSwitch[NODE_ID_TO_INDEX(event->nodeId)].s: &sim->oSwitch[NODE_ID_TO_INDEX(event->nodeId)].s; pkt = sw->queue[outLink].head; /* verify channel is available */ assert(sw->pktTxEndTime[outLink][outWavelength] <= sim->curTime); /* dequeue the pkt */ sw->queue[outLink].head = pkt->next; if (sw->queue[outLink].tail==pkt) sw->queue[outLink].tail = NULL; sw->queue[outLink].size -= pkt->size; pkt->next = NULL; /* schedule pkt rx event on next node */ event->type = EVENT_PKTRX; event->nodeId = sw->linkMap[outLink]; event->time = sim->curTime + sw->linkDelay[outLink]; event->info = pkt; SkipListInsert(sim->eventList, event, event, 0); /* update tx finish time */ sw->pktTxEndTime[outLink][outWavelength] = sim->curTime + ((double)pkt->size*8.0)/(LINK_RATE/(double)sim->nWavelengths) - EPSILON; /* schedule tx end event */ sw->pktTxEndEvent[outLink][outWavelength].type = EVENT_PKTTXEND; sw->pktTxEndEvent[outLink][outWavelength].nodeId = sw->nodeId; sw->pktTxEndEvent[outLink][outWavelength].time = sw->pktTxEndTime[outLink][outWavelength]; sw->pktTxEndEvent[outLink][outWavelength].info = (void *)((outLink<<16) | outWavelength); SkipListInsert(sim->eventList, &sw->pktTxEndEvent[outLink][outWavelength], &sw->pktTxEndEvent[outLink][outWavelength], 0); /* print debug msg */ if (simDebug & DEBUG_TX) { printf("pkt=%lu fid=%d outlink=%d wavelength=%d ends=%.4lf q=%ld\n", pkt->pid, pkt->fid, outLink, outWavelength, sw->pktTxEndTime[outLink][outWavelength], sw->queue[outLink].size); } return 0; } /*------------------------------------------------------------------------------ * eventTxEnd(): end of pkt transmission */ int eventTxEnd(Event_t *event) { int outLink, outWavelength; Switch_t *sw; Event_t *txEvent; /* extract outlink, switch, and pkt */ outLink = ((int)event->info >> 16); outWavelength = ((int)event->info & 0xFFFF); sw = NODE_IS_EDGE(event->nodeId)? &sim->eSwitch[NODE_ID_TO_INDEX(event->nodeId)].s: &sim->oSwitch[NODE_ID_TO_INDEX(event->nodeId)].s; /* check if more eligible pkts to transmit */ if (sw->queue[outLink].head && sw->queue[outLink].head->elig) { txEvent = (Event_t *)malloc(sizeof(Event_t)); assert(txEvent); memset(txEvent, 0x0, sizeof(Event_t)); txEvent->type = EVENT_PKTTXSTART; txEvent->nodeId = sw->nodeId; txEvent->time = sim->curTime; txEvent->info = (void *)((outLink << 16) | outWavelength); SkipListInsert(sim->eventList, txEvent, txEvent, 0); } if (simDebug & DEBUG_TX) { printf("outlink=%d wavelength=%d q=%ld\n", outLink, outWavelength, sw->queue[outLink].size); } return 0; } /*------------------------------------------------------------------------------ * eventRx(): process pkt receipt */ int eventRx(Event_t *event) { Packet_t *pkt; assert(event); pkt = (Packet_t *)(event->info); assert(pkt); if (NODE_IS_EDGE(event->nodeId)) { /* pkt rx at edge node */ ESwitch_t *node; node = &sim->eSwitch[NODE_ID_TO_INDEX(event->nodeId)]; assert(node); pkt->exitTime = sim->curTime; recordPktStats(pkt); /* record stats of pkt */ ++sim->rxPkts; if (simDebug & DEBUG_RX) { printf("pkt=%lu, fid=%d, end-to-end delay = %lfus\n", pkt->pid, pkt->fid, (pkt->exitTime - pkt->arrTime) - sim->eSwitch[NODE_ID_TO_INDEX(sim->flow[pkt->fid].dst)] .propDelay[NODE_ID_TO_INDEX(sim->flow[pkt->fid].src)]); } free(pkt); free(event); } /* end of if edge node */ else { /* node is core */ OSwitch_t *node; int outLink, idleChannel, w, outWavelength; node = &sim->oSwitch[NODE_ID_TO_INDEX(event->nodeId)]; assert(node); /* determine destination fibre */ outLink = node->s.routeMap[NODE_ID_TO_INDEX(sim->flow[pkt->fid].dst)]; assert(outLink!=ROUTE_SELF); /* check if output channel is available */ idleChannel = 0; if (node->s.queue[outLink].head==NULL) for (w=0; (wnWavelengths) && (idleChannel==0); ++w) if (sim->curTime >= node->s.pktTxEndTime[outLink][w]) idleChannel = 1; if (idleChannel) { outWavelength = w-1; /* transmit pkt cut-through; schedule rx event */ event->nodeId = node->s.linkMap[outLink]; event->time = sim->curTime + node->s.linkDelay[outLink]; SkipListInsert(sim->eventList, event, event, 0); /* update tx finish time */ node->s.pktTxEndTime[outLink][outWavelength] = sim->curTime + ((double)pkt->size*8.0)/(LINK_RATE/(double)sim->nWavelengths) - EPSILON; /* schedule tx-end event */ node->s.pktTxEndEvent[outLink][outWavelength].type = EVENT_PKTTXEND; node->s.pktTxEndEvent[outLink][outWavelength].nodeId = node->s.nodeId; node->s.pktTxEndEvent[outLink][outWavelength].time = node->s.pktTxEndTime[outLink][outWavelength]; node->s.pktTxEndEvent[outLink][outWavelength].info = (void *)((outLink<<16) | outWavelength); SkipListInsert(sim->eventList, &node->s.pktTxEndEvent[outLink][outWavelength], &node->s.pktTxEndEvent[outLink][outWavelength], 0); /* print debugging msgs */ if (simDebug & DEBUG_RX) { printf("pkt=%lu fid=%d TX immed (ends %.4lf) outlink:(%d,%d)\n", pkt->pid, pkt->fid, node->s.pktTxEndTime[outLink][outWavelength], outLink, outWavelength); } } /* end of if idle channel found */ else if (node->s.queue[outLink].size + pkt->size <= sim->maxBufSize) { /* buffer this pkt */ if (node->s.queue[outLink].head==NULL) node->s.queue[outLink].head = pkt; if (node->s.queue[outLink].tail) node->s.queue[outLink].tail->next = pkt; node->s.queue[outLink].tail = pkt; node->s.queue[outLink].size += pkt->size; if (simDebug & DEBUG_RX) { printf("pkt=%lu fid=%d, outlink:%d queued q=%ld\n", pkt->pid, pkt->fid, outLink, node->s.queue[outLink].size); } free(event); } /* end of if space in buffer for pkt */ else { /* no space in optical buffer - drop this pkt */ if (simDebug & DEBUG_RX) { printf("pkt=%lu fid=%ld, outlink:%d q=%ld DROPPED\n", pkt->pid, pkt->fid, outLink, node->s.queue[outLink].size); } ++sim->lostPkts; ++sim->flow[pkt->fid].pktLost; free(pkt); free(event); } /* end of if no space in buffer for pkt */ } /* end of if core node */ return 0; } /******************************************************************************* * runSim: runs the simulation for given parameters ******************************************************************************/ int runSim(SimClass_t *sim) { int i; Event_t *e; /* start the arrival process */ for (i=0; i < NUM_FLOWS; ++i) { sim->arrNext(i); } /* process events */ while ((e = (Event_t *)SKIPLIST_NODE_VALUE(SkipListGetFirst(sim->eventList)))!=NULL) { /* delete element from skiplist */ SkipListDelete(sim->eventList, e); sim->curTime = e->time; switch (e->type) { case EVENT_HULL: assert(NODE_IS_EDGE(e->nodeId)); if (simDebug & DEBUG_HULL) printf("%.4lf [%s]: HULL ", sim->curTime, sim->eSwitch[NODE_ID_TO_INDEX(e->nodeId)].s.name); eventHull(e); break; case EVENT_PKTARR: assert(NODE_IS_EDGE(e->nodeId)); if (simDebug & DEBUG_ARR) printf("%.4lf [%s]: ARRIVAL ", sim->curTime, sim->eSwitch[NODE_ID_TO_INDEX(e->nodeId)].s.name); eventArr(e); break; case EVENT_PKTRX: if (simDebug & DEBUG_RX) { printf("%.4lf [%s]: RX ", sim->curTime, (NODE_IS_EDGE(e->nodeId)? sim->eSwitch[NODE_ID_TO_INDEX(e->nodeId)].s.name: sim->oSwitch[NODE_ID_TO_INDEX(e->nodeId)].s.name)); } eventRx(e); break; case EVENT_PKTTXSTART: if (simDebug & DEBUG_TX) { printf("%.4lf [%s]: TX-START ", sim->curTime, (NODE_IS_EDGE(e->nodeId)? sim->eSwitch[NODE_ID_TO_INDEX(e->nodeId)].s.name: sim->oSwitch[NODE_ID_TO_INDEX(e->nodeId)].s.name)); } eventTxStart(e); break; case EVENT_PKTTXEND: if (simDebug & DEBUG_TX) { printf("%.4lf [%s]: TX-END ", sim->curTime, (NODE_IS_EDGE(e->nodeId)? sim->eSwitch[NODE_ID_TO_INDEX(e->nodeId)].s.name: sim->oSwitch[NODE_ID_TO_INDEX(e->nodeId)].s.name)); } eventTxEnd(e); break; default: printf("%.4lf: Unknown event type %d\n", sim->curTime, e->type); assert(0); } /* end of switch */ } /* end of while loop */ if (sim->arrCleanup) sim->arrCleanup(); return 0; } /******************************************************************************* * utils for reading config file */ char *getNextLine(char line[], int size, FILE *fp) { char *p; for (p = fgets(line, size, fp); p; p = fgets(line, size, fp)) { if ((line[0]!='\0') && (line[0]!='#') && !isspace(line[0])) return p; } return NULL; } /*----------------------------------------------------------------------------*/ char *getNextWord(char *word, char *ptr) { int i; assert(word && ptr); for (; isspace(*ptr); ++ptr); /* skip leading spaces */ if (*ptr=='\0') return NULL; for (i=0; (!isspace(*ptr)&&(*ptr!='\0')); ++ptr, ++i) word[i] = *ptr; word[i] = '\0'; return ptr; } /*----------------------------------------------------------------------------*/ uint16_t getNodeId(char *name) { int i; for (i=0; ioSwitch[i].s.name)==0) return sim->oSwitch[i].s.nodeId; for (i=0; ieSwitch[i].s.name)==0) return sim->eSwitch[i].s.nodeId; return 0xFFFF; } /******************************************************************************* * main: run simulation repeatedly for varying parameters ******************************************************************************/ int main(int argc, char *argv[]) { int i, j, w, wconv, darg, nruns, maxruns; char fileName[128]; char line[512], word[32], *p; FILE *confFp, *resFp = NULL; double pktLoss, pktDelay, maxLoad; #define NUM_B_VALS 18 /* number of buffer size values */ double b_vals[NUM_B_VALS] = {0, 420, 840, 1260, 1680, 2520, 3360, 4200, 5040, 5880, 6720, 7560, 8400, 10500, 12600, 14700, 16800, 21000}; #define NUM_W_VALS 12 /* number of wavelength values */ double w_vals[NUM_W_VALS] = {1, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 120}; /* initialize random seed */ unsigned short s[3]; unsigned long t; t = time(NULL); s[0] = 0; s[1] = (t >> 16); s[2] = t & 0xFFFF; seed48(s); if (argc < 5) { printf("Usage: %s [B|W] poisson| [ ...]\n", argv[0]); printf("\tUse [B] for buffered system and [W] for wavelength converter system\n"); printf("\t denotes smoothing delay in slot units (usec)\n"); exit(0); } /* initialize globals and extract command line args */ sim = &simClass; memset(sim, 0x0, sizeof(SimClass_t)); sim->eventList = SkipListAlloc(eventSkipListCmp, eventSkipListFree); assert(sim->eventList); if (strcmp(argv[1], "W")==0) { wconv = 1; maxruns = NUM_W_VALS; } else { wconv = 0; maxruns = NUM_B_VALS; } sim->pktsToSimulate = atoi(argv[2]); pktSizeDistInit(); /* initialise pkt size distribution */ if (strcmp(argv[3], "poisson")==0) { /* poisson traffic */ strcpy(sim->inFilePrefix, ""); sim->arrNext = arrPoisson; sim->arrCleanup = NULL; } else { strcpy(sim->inFilePrefix, argv[3]); sim->arrNext = arrFile; sim->arrCleanup = arrFileCleanup; } strcpy(sim->outFilePrefix, argv[4]); /* initialize topology and routing */ confFp = fopen(CONF_FILE, "r"); assert(confFp); /* get the list of core nodes */ p = getNextLine(line, 511, confFp); assert(p); p = getNextWord(word, p = &line[0]); assert(p); assert(strcmp(word, "core:")==0); for (i=0; ioSwitch[i].s.name, p); assert(p); sim->oSwitch[i].s.nodeId = NODE_INDEX_TO_ID_CORE(i); } /* get the list of edge nodes */ p = getNextLine(line, 511, confFp); assert(p); p = getNextWord(word, p = &line[0]); assert(p); assert(strcmp(word, "edge:")==0); for (i=0; ieSwitch[i].s.name, p); assert(p); sim->eSwitch[i].s.nodeId = NODE_INDEX_TO_ID_EDGE(i); } printf("\nCore-nodes = %d, Edge-nodes = %d", NUM_CORE_NODES, NUM_EDGE_NODES); /* read in details of core nodes */ for (i=0; ioSwitch[nodeIdx].s.linkMap[n] = getNodeId(&word[c1+1]); assert(sim->oSwitch[nodeIdx].s.linkMap[n]!=0xFFFF); sscanf(&word[c2+1], "%lf", &sim->oSwitch[nodeIdx].s.linkDelay[n]); sim->oSwitch[nodeIdx].s.linkDelay[n] /= LIGHT_SPEED; } sim->oSwitch[nodeIdx].s.nLinks = n; /* get routes for this node */ p = getNextLine(line, 511, confFp); assert(p); p = getNextWord(word, p = &line[0]); assert(p); assert(strcmp(word, "routes:")==0); for (n=0; n < NUM_EDGE_NODES; ++n) { /* route to each edge node */ p = getNextWord(word, p); assert(p); sim->oSwitch[nodeIdx].s.routeMap[n] = atoi(word); } } /* done reading core nodes */ /* print core node info */ for (i = 0; i < NUM_CORE_NODES; ++i) { int j; printf("\n%s(0x%x): has %d links\n", sim->oSwitch[i].s.name, sim->oSwitch[i].s.nodeId, sim->oSwitch[i].s.nLinks); for (j=0; j < sim->oSwitch[i].s.nLinks; ++j) { printf("\t0x%x: %s, d=%0.2lf slots\n", sim->oSwitch[i].s.linkMap[j], (NODE_IS_CORE(sim->oSwitch[i].s.linkMap[j])? sim->oSwitch[NODE_ID_TO_INDEX( sim->oSwitch[i].s.linkMap[j])].s.name: sim->eSwitch[NODE_ID_TO_INDEX( sim->oSwitch[i].s.linkMap[j])].s.name), sim->oSwitch[i].s.linkDelay[j]); } printf("\tRoutes:"); for (j=0; j < NUM_EDGE_NODES; ++j) { printf(" <%s:%s>", sim->eSwitch[j].s.name, (NODE_IS_CORE(sim->oSwitch[i].s.linkMap[ sim->oSwitch[i].s.routeMap[j]]))? sim->oSwitch[NODE_ID_TO_INDEX( sim->oSwitch[i].s.linkMap[sim->oSwitch[i].s.routeMap[j]])].s.name : sim->eSwitch[NODE_ID_TO_INDEX( sim->oSwitch[i].s.linkMap[sim->oSwitch[i].s.routeMap[j]])].s.name); } printf("\n"); } /* read in details of edge nodes */ for (i=0; ieSwitch[nodeIdx].s.linkMap[n] = getNodeId(&word[c1+1]); assert(sim->eSwitch[nodeIdx].s.linkMap[n]!=0xFFFF); sscanf(&word[c2+1], "%lf", &sim->eSwitch[nodeIdx].s.linkDelay[n]); sim->eSwitch[nodeIdx].s.linkDelay[n] /= LIGHT_SPEED; } sim->eSwitch[nodeIdx].s.nLinks = n; /* get routes for this node */ p = getNextLine(line, 511, confFp); assert(p); p = getNextWord(word, p = &line[0]); assert(p); assert(strcmp(word, "routes:")==0); for (n=0; n < NUM_EDGE_NODES; ++n) { /* route to each edge node */ p = getNextWord(word, p); assert(p); sim->eSwitch[nodeIdx].s.routeMap[n] = atoi(word); } /* compute the end-to-end propagation delay */ for (n=0; neSwitch[nodeIdx].propDelay[n] = 0.0; continue; } sim->eSwitch[nodeIdx].propDelay[n] = sim->eSwitch[nodeIdx].s.linkDelay[ sim->eSwitch[nodeIdx].s.routeMap[n]]; hopId = sim->eSwitch[nodeIdx].s.linkMap[ sim->eSwitch[nodeIdx].s.routeMap[n]]; for (; hopId != NODE_INDEX_TO_ID_EDGE(n); hopId = sim->oSwitch[NODE_ID_TO_INDEX(hopId)].s.linkMap[ sim->oSwitch[NODE_ID_TO_INDEX(hopId)].s.routeMap[n]]) { sim->eSwitch[nodeIdx].propDelay[n] += sim->oSwitch[NODE_ID_TO_INDEX(hopId)].s.linkDelay[ sim->oSwitch[NODE_ID_TO_INDEX(hopId)].s.routeMap[n]]; } } } /* done reading edge nodes */ /* print edge node info */ printf("\n%d edge nodes:", NUM_EDGE_NODES); for (i = 0; i < NUM_EDGE_NODES; ++i) { printf("\n%s(0x%x): has %d links\n", sim->eSwitch[i].s.name, sim->eSwitch[i].s.nodeId, sim->eSwitch[i].s.nLinks); for (j=0; j < sim->eSwitch[i].s.nLinks; ++j) { printf("\t0x%x: %s, d=%0.2lf slots\n", sim->eSwitch[i].s.linkMap[j], (NODE_IS_CORE(sim->eSwitch[i].s.linkMap[j])? sim->oSwitch[NODE_ID_TO_INDEX( sim->eSwitch[i].s.linkMap[j])].s.name: sim->eSwitch[NODE_ID_TO_INDEX( sim->eSwitch[i].s.linkMap[j])].s.name), sim->eSwitch[i].s.linkDelay[j]); } printf("\tRoutes:"); for (j=0; j < NUM_EDGE_NODES; ++j) { if (sim->eSwitch[i].s.routeMap[j]!=ROUTE_SELF) assert(NODE_IS_CORE(sim->eSwitch[i].s.linkMap[ sim->eSwitch[i].s.routeMap[j]])); printf(" <%s:%s/%lu>", sim->eSwitch[j].s.name, (sim->eSwitch[i].s.routeMap[j]==ROUTE_SELF)? "-" : sim->oSwitch[NODE_ID_TO_INDEX( sim->eSwitch[i].s.linkMap[sim->eSwitch[i].s.routeMap[j]])].s.name, sim->eSwitch[i].propDelay[j]); } printf("\n"); } /* read in flow details */ printf("\nFlows = %d:\n", NUM_FLOWS); for (i=0; iflow[i].src = getNodeId(word); assert(sim->flow[i].src!=0xFFFF); p = getNextWord(word, p); assert(p); /* dst */ sim->flow[i].dst = getNodeId(word); assert(sim->flow[i].dst!=0xFFFF); sim->flow[i].fid = i; p = getNextWord(word, p); assert(p); /* qos */ sim->flow[i].qos = atoi(word); p = getNextWord(word, p); assert(p); /* load */ sscanf(word, "%lf", &sim->flow[i].load); printf("\tflow-%d: %s -> %s, qos=%d, load=%lf\n", i, sim->eSwitch[NODE_ID_TO_INDEX(sim->flow[i].src)].s.name, sim->eSwitch[NODE_ID_TO_INDEX(sim->flow[i].dst)].s.name, sim->flow[i].qos, sim->flow[i].load); /* update the load on each core link */ hopId = sim->eSwitch[NODE_ID_TO_INDEX(sim->flow[i].src)].s .linkMap[sim->eSwitch[NODE_ID_TO_INDEX(sim->flow[i].src)].s .routeMap[NODE_ID_TO_INDEX(sim->flow[i].dst)]]; for (; hopId != sim->flow[i].dst; hopId = sim->oSwitch[NODE_ID_TO_INDEX(hopId)].s .linkMap[sim->oSwitch[NODE_ID_TO_INDEX(hopId)].s .routeMap[NODE_ID_TO_INDEX(sim->flow[i].dst)]]) { sim->oSwitch[NODE_ID_TO_INDEX(hopId)].s .linkLoad[sim->oSwitch[NODE_ID_TO_INDEX(hopId)].s .routeMap[NODE_ID_TO_INDEX(sim->flow[i].dst)]] += sim->flow[i].load; } } /* done reading flows */ /* print link loads */ printf("Link loads:\n"); for (i = 0, maxLoad=0.0; i < NUM_CORE_NODES; ++i) { int j; printf("%s:", sim->oSwitch[i].s.name); for (j=0; j < sim->oSwitch[i].s.nLinks; ++j) { maxLoad = MAX(maxLoad, sim->oSwitch[i].s.linkLoad[j]); if (NODE_IS_CORE(sim->oSwitch[i].s.linkMap[j])) { printf(" [%s:%lf]",sim->oSwitch[NODE_ID_TO_INDEX( sim->oSwitch[i].s.linkMap[j])].s.name, sim->oSwitch[i].s.linkLoad[j]); } } printf("\n"); } printf("maxLoad = %lf\n", maxLoad); fclose(confFp); confFp = NULL; /* close the input conf file */ /* start the runs */ for (darg = 5; darg < argc; ++darg) { sim->beDbound = (double)atoi(argv[darg]); /* spreading delay value */ /* open results file */ sprintf(fileName, "%s_s%03d", sim->outFilePrefix, atoi(argv[darg])); resFp = fopen(fileName, "w"); assert(resFp); /* run for each buffer size or number of wavelength */ for (nruns=0; nruns < maxruns; ++nruns) { if (wconv) { sim->maxBufSize = 0; sim->nWavelengths = w_vals[nruns]; } else { sim->nWavelengths = 0; sim->maxBufSize = b_vals[nruns]; } /* clear simClass fields */ assert(SkipListGetCount(sim->eventList)==0); sim->curTime = 0.0; sim->txPkts = sim->rxPkts = sim->lostPkts = 0; /* clear core node data structure fields */ for (i = 0; i < NUM_CORE_NODES; ++i) { for (j = 0; j < MAX_LINKS; ++j) { assert(sim->oSwitch[i].s.queue[j].size==0); assert(sim->oSwitch[i].s.queue[j].head==NULL); assert(sim->oSwitch[i].s.queue[j].tail==NULL); for (w=0; woSwitch[i].s.pktTxEndTime[j][w] = 0.0; } } /* clear edge node data structures */ for (i = 0; i < NUM_EDGE_NODES; ++i) { for (j = 0; j < MAX_LINKS; ++j) { assert(sim->eSwitch[i].s.queue[j].size==0); assert(sim->eSwitch[i].s.queue[j].head==NULL); assert(sim->eSwitch[i].s.queue[j].tail==NULL); assert(sim->eSwitch[i].hullHead[j]==NULL); assert(sim->eSwitch[i].hullTail[j]==NULL); sim->eSwitch[i].hullCredit[j] = sim->eSwitch[i].hullLastUpdate[j] = 0.0; sim->eSwitch[i].hullEvent[j].type = EVENT_HULL; sim->eSwitch[i].hullEvent[j].nodeId = NODE_INDEX_TO_ID_EDGE(i); sim->eSwitch[i].hullEvent[j].time = 0.0; assert(sim->eSwitch[i].hullEvent[j].info==NULL); for (w=0; weSwitch[i].s.pktTxEndTime[j][w] = 0.0; } } /* clear flow data structures */ for (i = 0; i < NUM_FLOWS; ++i) { assert(sim->flow[i].inFp==NULL); sim->flow[i].sampleT = 1.0; /* usec */ #define CBYS_1_S 1384.6382 /* mean rate per-flow = 1.5Gbps */ #define CBYS_1_C 1384.6382 sim->flow[i].S = CBYS_1_S; sim->flow[i].C = CBYS_1_C; sim->flow[i].lastArrTime = 0.0; sim->flow[i].resTime = sim->flow[i].resBits = 0.0; sim->flow[i].lTrunc = 0; sim->flow[i].pktTx = sim->flow[i].pktRx = sim->flow[i].pktLost = 0; sim->flow[i].totDelay = 0.0; } /* print simulation params */ printf("\n******************** RUN# %d *************************\n", nruns); printf("Wavelengths=%d, Buffer=%d, beDbound=%.2lf\n", sim->nWavelengths, sim->maxBufSize, sim->beDbound); runSim(sim); /* runs the simulation */ printf("\nDone with simulation! Here's the tally:\n"); /* global stats */ pktLoss = (double)sim->lostPkts/(double)sim->txPkts; printf("Total pkt loss = %lu/%lu = %e\n", sim->lostPkts, sim->txPkts, pktLoss); if (wconv) { fprintf(resFp, "%d %.2lf %e\n", sim->nWavelengths, sim->beDbound, pktLoss); fflush(resFp); } else { fprintf(resFp, "%d %.2lf %e\n", sim->maxBufSize, sim->beDbound, pktLoss); fflush(resFp); } for (i=0; i < NUM_FLOWS; ++i) { /* per-flow stats */ pktLoss = (double)sim->flow[i].pktLost / (double)sim->flow[i].pktTx; pktDelay = sim->flow[i].totDelay/(double)sim->flow[i].pktRx; printf("Flow-%d: tx=%lu, rx=%lu, drop=%lu, loss=%e, d_av=%lf\n", i+1, sim->flow[i].pktTx, sim->flow[i].pktRx, sim->flow[i].pktLost, pktLoss, pktDelay); assert(sim->flow[i].pktTx == (sim->flow[i].pktRx + sim->flow[i].pktLost)); } printf("\n"); } /* end of for loop varying spreading */ fclose(resFp); } /* end of for loop varying delay */ return 0; }