dist, dev: Fixed the packet ordering in etherswitch
Review Request #3465 - Created May 6, 2016 and submitted
| Information | |
|---|---|
| Mohammad Alian | |
| gem5 | |
| default | |
| Reviewers | |
| Default | |
Changeset 11472:d97d6bf2206b --------------------------- dist, dev: Fixed the packet ordering in etherswitch This patch fixes the order that packets gets pushed into the output fifo of etherswitch. If two packets arrive at the same tick to the etherswitch, we sort and push them based on their source port id. In dist-gem5 simulations, if there is no ordering inforced while two packets arrive at the same tick, it can lead to non-deterministic simulations
Hi Mohammad, nice catch, thanks for fixing this!
-
src/dev/net/etherswitch.hh (Diff revision 1) -
nullptr ?
-
src/dev/net/etherswitch.hh (Diff revision 1) -
I would suggest to use a std::set instead of std::list for the fifo. You can define a compare object that uses the recvTick and the sourceId as the primary and secondary key, respectively. The fifo.push() method could then be much simpler. (See my futher commnents there.)
-
src/dev/net/etherswitch.hh (Diff revision 1) -
'const' modifier?
-
src/dev/net/etherswitch.hh (Diff revision 1) -
The preferred way for serializing child objects is using 'serializeSection' from the parent. PortFifo should derive from 'Serializable' and then you can drop the extra 'base' argument here and for 'unserialize()', too.
-
src/dev/net/etherswitch.cc (Diff revision 1) -
If the fifo were a std::set with a custom comparator (using recvTick as primary and sourceId as secondary key) then you could simply call 'fifo.insert(entry)'. All entries would be kept in the correct order by the container. If the size of fifo is too big after the insert then you could simply erase the last element (i.e. at fifo.rbegin()) to drop a single packet (instead of dropping potentially many packets with the current code). Does that make sense?
-
src/dev/net/etherswitch.cc (Diff revision 1) -
You can use the fifo.front() accessor instead of creating a temporary copy of the entry.
-
src/dev/net/etherswitch.cc (Diff revision 1) -
This could be simplified as 'for (auto i : fifo)'
Description: |
|
|||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Diff: |
Revision 2 (+197 -34) |
-
src/dev/net/etherswitch.cc (Diff revision 2) -
You can avoid the extra copy by using fifo.emplace(...) instead of fifo.insert(). Even better would be to use fifo.emplace_hint(fifo.rbegin(), ...) which can make the common case insertion path faster. (I guess the common case is when the packet gets inserted at the end of the fifo.)
-
src/dev/net/etherswitch.cc (Diff revision 2) -
You can replace std::prev(fifo.end()) by fifo.rbegin() (in the next line, too).
-
src/dev/net/etherswitch.cc (Diff revision 2) -
Return
-
src/dev/net/etherswitch.cc (Diff revision 2) -
return
-
src/dev/net/etherswitch.cc (Diff revision 2) -
The check could be simpler by comparing only the (shared) packet pointer (EthPacketPtr).
However, can there be a problem here in the pathological case when the fifo is empty originally but the size of the current packet is larger then max_size ? Then, at this point the fifo would be empty.
-
src/dev/net/etherswitch.cc (Diff revision 2) -
_maxsize is also serialized but it is not unserialized here
Description: |
|
|||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Diff: |
Revision 3 (+196 -34) |
Diff: |
Revision 4 (+196 -34) |
|---|
Description: |
|
|||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Diff: |
Revision 5 (+196 -34) |
-
src/dev/net/etherswitch.hh (Diff revision 5) -
This is not needed here I think.
-
src/dev/net/etherswitch.hh (Diff revision 5) -
Should this be <set> instead?
-
src/dev/net/etherswitch.hh (Diff revision 5) -
Delete empty line.
-
src/dev/net/etherswitch.cc (Diff revision 5) -
This include should be after etherswitch.hh and before the m5 includes according to coding styles.
-
src/dev/net/etherswitch.cc (Diff revision 5) -
I think this will still create a temporary PortFifoEntry object in this form. To avoid the extra object and copy, change this to:
fifo.emplace_hint(fifo.end, ptr, curTick(), senderId); -
src/dev/net/etherswitch.cc (Diff revision 5) -
Could you add an extra DPRINTF message here in case when the fifo is empty? That may be a big help to find the issue if somebody hits this by accident.
Description: |
|
|||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Diff: |
Revision 6 (+202 -35) |
-
src/dev/net/etherswitch.cc (Diff revision 6) -
This DPRINTF is useful but I am still concerned a bit about hitting the pathological case when the packet is too long to go through even if the fifo is empty (regardless how may times the user application tries to re-send it). Could you please add another DPRINTF after this loop to catch that, i.e. something like:
if (empty()) {
DPRINTF(Ethernet, "Packet length (%d) exceeds the maximum storage capacity of port fifo (%d)", ptr->length, _maxsize);
}
Description: |
|
|||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Diff: |
Revision 7 (+207 -36) |
It looks good to me! Thanks again for fixing this!
-
src/dev/net/etherswitch.hh (Diff revision 7) -
all these members could be const?
-
src/dev/net/etherswitch.hh (Diff revision 7) -
unsigned? if not it really needs a comment
-
src/dev/net/etherswitch.hh (Diff revision 7) -
==
it is unsigned
-
src/dev/net/etherswitch.cc (Diff revision 7) -
should this perhaps even be a warn (or do we ever expect this to happen in a correct setup?
-
src/dev/net/etherswitch.cc (Diff revision 7) -
could you add an assert here that size >= packet->length?
-
src/dev/net/etherswitch.cc (Diff revision 7) -
all reschedule instead?
-
src/dev/net/etherswitch.cc (Diff revision 7) -
Does this break checkpoint compatibility?
If so that needs to be addressed.
Description: |
|
|||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Diff: |
Revision 8 (+207 -37) |
-
src/dev/net/etherswitch.cc (Diff revision 7) -
I would say we either need to allow for these to be optional (there is a macro for that if I remember correctly), or alternatively the cpt_upgrader.py in util needs to be updated and add the field.
Description: |
|
|||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Diff: |
Revision 9 (+228 -37) |
Description: |
|
|||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Diff: |
Revision 10 (+228 -37) |
Ship It!
