diff -r 51af672c9841 -r 6f9b44011132 src/dev/Ethernet.py --- a/src/dev/Ethernet.py Tue Jun 23 16:58:14 2015 -0500 +++ b/src/dev/Ethernet.py Tue Jun 23 17:11:53 2015 -0500 @@ -45,6 +45,9 @@ delay_var = Param.Latency('0ns', "packet transmit delay variability") speed = Param.NetworkBandwidth('1Gbps', "link speed") dump = Param.EtherDump(NULL, "dump object") + mode = Param.Int(0,"etherlink mode for operating in pd-gem5") + nic_speed = Param.NetworkBandwidth('1Gbps', "link speed") + nic_delay = Param.Latency('0us', "packet transmit delay") class EtherBus(EtherObject): type = 'EtherBus' diff -r 51af672c9841 -r 6f9b44011132 src/dev/etherlink.hh --- a/src/dev/etherlink.hh Tue Jun 23 16:58:14 2015 -0500 +++ b/src/dev/etherlink.hh Tue Jun 23 17:11:53 2015 -0500 @@ -74,6 +74,13 @@ Tick linkDelay; Tick delayVar; EtherDump *dump; + /* + pd-gem5 extention + */ + int mode; + Tick releaseTick; + double nicTicksPerByte; + Tick nicDelay; protected: /* @@ -90,7 +97,8 @@ public: Link(const std::string &name, EtherObject *p, int num, - double rate, Tick delay, Tick delay_var, EtherDump *dump); + double rate, Tick delay, Tick delay_var, EtherDump *dump, + int mode = 0, double nic_rate = 0, Tick nic_delay = 0); ~Link() {} const std::string name() const { return objName; } @@ -104,6 +112,11 @@ void serialize(const std::string &base, std::ostream &os); void unserialize(const std::string &base, Checkpoint *cp, const std::string §ion); + /* + pd-gem5 extention + */ + uint64_t getTimeStamp(); + void setTimeStamp(uint64_t time_stamp); }; protected: diff -r 51af672c9841 -r 6f9b44011132 src/dev/etherlink.cc --- a/src/dev/etherlink.cc Tue Jun 23 16:58:14 2015 -0500 +++ b/src/dev/etherlink.cc Tue Jun 23 17:11:53 2015 -0500 @@ -57,9 +57,11 @@ : EtherObject(p) { link[0] = new Link(name() + ".link0", this, 0, p->speed, - p->delay, p->delay_var, p->dump); + p->delay, p->delay_var, p->dump, + p->mode, p->nic_speed, p->nic_delay); link[1] = new Link(name() + ".link1", this, 1, p->speed, - p->delay, p->delay_var, p->dump); + p->delay, p->delay_var, p->dump, + p->mode, p->nic_speed, p->nic_delay); interface[0] = new Interface(name() + ".int0", link[0], link[1]); interface[1] = new Interface(name() + ".int1", link[1], link[0]); @@ -99,10 +101,12 @@ } EtherLink::Link::Link(const string &name, EtherObject *p, int num, - double rate, Tick delay, Tick delay_var, EtherDump *d) + double rate, Tick delay, Tick delay_var, EtherDump *d, + int mode_, double nic_rate, Tick nic_delay) : objName(name), parent(p), number(num), txint(NULL), rxint(NULL), ticksPerByte(rate), linkDelay(delay), delayVar(delay_var), dump(d), - doneEvent(this) + mode(mode_), releaseTick(0), nicTicksPerByte(nic_rate), + nicDelay(nic_delay), doneEvent(this) { } void @@ -153,7 +157,179 @@ { if (dump) dump->dump(packet); + DPRINTF(Ethernet, "receive packet in txDone: mode=%d\n",mode); + //mode = 1 is 'no delay' mode + if (mode == 1) { + txComplete(packet); + packet = 0; + assert(!busy()); + txint->sendDone(); + return; + } + //mode = 2 is 'nic connector' mode + if (mode == 2) { + /* + We assume that int0 is connected to NIC + We should timestamp packets that we recieve form int0 (NIC) before + sending them to peer (EtherTap) + */ + if (name().find("link0") != std::string::npos) { + DPRINTF(Ethernet, "receive packet from interface0, " + "start to add time stamp, len=%d, releaseTick=%lu\n", + packet->length, releaseTick); + uint64_t time_stamp_int; + char time_stamp_cstr[13]; + int data_len = packet->length; + char buff[10000]; + /* + NIC Timing params + + We have already applied nic transmission delay at transmit + function, add nic propagation delay here + */ + time_stamp_int = curTick() + nicDelay; + /* + Link Timing params + + Add link transmission and propagation delay to time_stamp + To make sure that we don't reorder packets after adding transmission + latency (size/bw), we utilize "releaseTick" variable to serialize + outgoing packets. + We assume that link bw is not network bottleneck + */ + Tick link_trans_delay = (Tick)ceil(((double)packet->length + * ticksPerByte) + 1.0); + if (releaseTick > time_stamp_int){ + time_stamp_int = releaseTick + link_trans_delay + linkDelay; + releaseTick += link_trans_delay; + } + else { + releaseTick = time_stamp_int + link_trans_delay; + time_stamp_int += link_trans_delay + linkDelay; + } + DPRINTF(Ethernet, "time_stamp=%lu, link_trans_delay=%lu\n", + time_stamp_int, link_trans_delay); + + /* + number of time stamp digits is set to 12, which means each + timestamp can capture 1 second of simulation time + + */ + //Get the 12 least significant digits of the time stamp + time_stamp_int = time_stamp_int % 1000000000000; + //convert int to c-string + sprintf(time_stamp_cstr,"%lu",time_stamp_int); + //copy packet->data into buff + for (int i = 0; i < data_len; i++) + buff[i] = packet->data[i]; + //if time stamp digits is smaller than 12, then skip the difference + for (int i = 12 - strlen(time_stamp_cstr); i < 12; i++) { + buff[i + data_len] = + time_stamp_cstr[i - (12 - strlen(time_stamp_cstr))]; + } + //zero pad and close end of the buff + for(int i = 0; i < 12 - strlen(time_stamp_cstr); i++) + buff[i + data_len] = '0'; + buff[data_len + 12]='\0'; + //generate a new time-stamped packet + packet = make_shared(data_len + 12); + packet->length = data_len + 12; + memcpy(packet->data, buff, data_len + 12); + DPRINTF(Ethernet, "added %lu as time stamp, len=%d\n", + time_stamp_int, packet->length); + //send packet immediately to peer (EtherTap) + txComplete(packet); + packet = 0; + assert(!busy()); + + txint->sendDone(); + return; + } + /* + Otherwise, we should extract time stamp form the incoming packet and + send it to peer (NIC) at "time_stamp + link latency" + */ + else { + DPRINTF(Ethernet, "receive packet from interface1," + " startng to remove time stamp, len=%d\n", packet->length); + int data_len = packet->length; + uint64_t time_stamp, delivery_tick; + char buff[10000]; + + Tick trans_delay = (Tick)ceil(((double)packet->length + * ticksPerByte) + 1.0); + time_stamp = getTimeStamp(); + //get a backup from packet data + memcpy(buff, packet->data, data_len); + //generate a new packet without timestamp + packet = make_shared(data_len - 12); + packet->length = data_len - 12; + memcpy(packet->data, buff, data_len - 12); + DPRINTF(Ethernet, "remove time stamp %lu, len=%d\n", + time_stamp, packet->length); + /* + Link Timing params + + To make sure that we don't reorder packets after adding link + transmission latency (size/bw), we utilize "releaseTick" variable + to serialize outgoing packets. + We assume that link bw is not network bottleneck + */ + if (releaseTick > time_stamp){ + delivery_tick = releaseTick + trans_delay + linkDelay; + releaseTick += trans_delay; + } + else { + delivery_tick = time_stamp + trans_delay + linkDelay; + releaseTick = time_stamp + trans_delay; + } + + if (delivery_tick < curTick()){ + ccprintf(cerr, "VIOLATION, packet arrived late %lu\n", + curTick() - delivery_tick); + delivery_tick = curTick(); + } + //deliver packet at delivery_tick to peer (NIC) + Event *event = new LinkDelayEvent(this, packet); + parent->schedule(event, delivery_tick); + packet = 0; + assert(!busy()); + + txint->sendDone(); + return; + } + } + //mode = 3 is 'switch connector' mode + if (mode == 3) { + /* + we should add link_latency (transmission + propagation) to time_stamp + and deliver packets to peer (Switch) instantly + + To make sure that we don't reorder packets after adding switch + transmission latency (size/bw), we utilize "releaseTick" variable + to serialize outgoing packets. + We assume that link bw is not network bottleneck + */ + uint64_t time_stamp; + Tick trans_delay = (Tick)ceil(((double)packet->length * ticksPerByte) + 1.0); + time_stamp = getTimeStamp(); + if (releaseTick > time_stamp){ + setTimeStamp(releaseTick + trans_delay + linkDelay); + releaseTick += trans_delay; + } + else { + setTimeStamp(time_stamp + trans_delay + linkDelay); + releaseTick = time_stamp + trans_delay; + } + txComplete(packet); + packet = 0; + assert(!busy()); + + txint->sendDone(); + return; + } + //etherlink defualt functionality if (linkDelay > 0) { DPRINTF(Ethernet, "packet delayed: delay=%d\n", linkDelay); Event *event = new LinkDelayEvent(this, packet); @@ -176,10 +352,49 @@ return false; } - DPRINTF(Ethernet, "packet sent: len=%d\n", pkt->length); + DPRINTF(Ethernet, "packet sent: len=%d, mode=%d\n", pkt->length, mode); DDUMP(EthernetData, pkt->data, pkt->length); packet = pkt; + //mode = 1 is 'no delay' mode + if (mode == 1) { + DPRINTF(Ethernet,"No Delay enabled!\n"); + txDone(); + return true; + } + //mode = 2 is 'nic connector' mode + if (mode == 2) { + /* + We assume that int0 is connected to NIC and int1 to EtherTap + + If we recieve packets form int1 (EtherTap), then we should call txDone + instantly + */ + if (name().find("link1") != std::string::npos) { + txDone(); + return true; + } + /* + If we recieve packets form NIC, we should apply NIC transmission delay, + and keep link busy during that period to make sure NIC sending rate + would not exceed the nic_speed parameter + */ + Tick trans_delay = (Tick)ceil(((double)pkt->length * nicTicksPerByte) + + 1.0); + if (delayVar != 0) + trans_delay += random_mt.random(0, delayVar); + DPRINTF(Ethernet, "scheduling packet: nic_delay=%d, (nic_rate=%f)\n", + trans_delay, nicTicksPerByte); + parent->schedule(doneEvent, curTick() + trans_delay); + return true; + } + //mode = 3 is 'switch connector' + if (mode == 3) { + //call txDone instantly + txDone(); + return true; + } + //etherlink defualt functionality Tick delay = (Tick)ceil(((double)pkt->length * ticksPerByte) + 1.0); if (delayVar != 0) delay += random_mt.random(0, delayVar); @@ -228,6 +443,54 @@ } } +//this function return the time stamp of the packet in the link +uint64_t +EtherLink::Link::getTimeStamp() +{ + DPRINTF(Ethernet, "get packet time stamp\n"); + + char time_stamp_cstr[13]; + uint64_t time_stamp_int; + int i = 0; + memmove(time_stamp_cstr, packet->data + packet->length - 12, 12); + //find the first non-zero digit, i = position of the first non zero digit + for (i = 0; i < 12; i++) + if(time_stamp_cstr[i] != '0') + break; + memmove(time_stamp_cstr, time_stamp_cstr + i, 12 - i); + time_stamp_cstr[12 - i] = '\0'; + time_stamp_int = atol(time_stamp_cstr) + curTick() - + curTick() % 1000000000000; + /* + Sanity check + If we had a transition to next second of simulation while packet was in + flight. We assume that the flight time is not more than 0.5 second in + simulted time + */ + if (time_stamp_int > curTick() + 500000000000) + time_stamp_int = time_stamp_int - 1000000000000; + if (time_stamp_int < curTick() - 500000000000) + time_stamp_int = time_stamp_int + 1000000000000; + return time_stamp_int; +} + +void +EtherLink::Link::setTimeStamp(uint64_t time_stamp) +{ + DPRINTF(Ethernet, "set packet time stamp to %lu\n", time_stamp); + + char time_stamp_cstr[13]; + char zero_pad[13] = "000000000000"; + //convert tick to c_string + sprintf(time_stamp_cstr, "%lu", time_stamp % 1000000000000); + //put new tick into the zero-padded string + memmove(zero_pad + strlen(zero_pad) - strlen(time_stamp_cstr), + time_stamp_cstr, strlen(time_stamp_cstr)); + //replace zero padded string with the current time stamp + memmove(packet->data + packet->length - 12, zero_pad, 12); +} + + LinkDelayEvent::LinkDelayEvent() : Event(Default_Pri, AutoSerialize | AutoDelete), link(NULL) { diff -r 51af672c9841 -r 6f9b44011132 src/sim/simulate.cc --- a/src/sim/simulate.cc Tue Jun 23 16:58:14 2015 -0500 +++ b/src/sim/simulate.cc Tue Jun 23 17:11:53 2015 -0500 @@ -103,7 +103,8 @@ "simulate() limit reached", 0); } - inform("Entering event queue @ %d. Starting simulation...\n", curTick()); + // it will print every time we start a new quantum simulation + //inform("Entering event queue @ %d. Starting simulation...\n", curTick()); if (num_cycles < MaxTick - curTick()) num_cycles = curTick() + num_cycles;