The ONE仿真器读取外部事件(StandardEventsReader
的readEvents
)存在BUG(感谢@馒头分享),本文描述并修复该BUG。
1. BUG描述
The ONE读取外部事件是由StandardEventsReader
的readEvents
完成。默认情况下,每次读取500个,可以在设置文件修改默认值,如下:
public static final int DEFAULT_NROF_PRELOAD = 500 //ExternalEventsQueue.java //设置文件 Events1.class = ExternalEventsQueue Events1.nrofPreload = …
readEvents
每次读取501个事件,500个放入events,另一个没有做任何处理,所以每500个事件会有1个漏掉,以下是我某次仿真的结果,可见实际创建的消息数目少于消息创建事件的数目。
#消息事件数目 #实际创建的消息数目 20000 199601 24000 239521 26000 259482 30000 299402 36000 359282
2. BUG分析及修复
(1)BUG分析
产生该的BUG原因是readEvents
先读取事件再判断循环条件,相关源代码如下:
// StandardEventsReader.java public List<ExternalEvent> readEvents(int nrof) { ... while (eventsRead < nrof && line != null) { ... line = this.reader.readLine(); //问题在这里! eventsRead++; ... } return events; }
问题就出在第6行,先读取下一行,再判断eventsRead
是否小于nrof
,若不小于,则结束事件读取,这样就漏掉了一个事件。
(2)修复BUG
修改该BUG也简单,先对eventsRead
做判断再决定是否读取下一个事件,如下:
line = this.reader.readLine(); eventsRead++; // 改成: eventsRead++; if (eventsRead < nrof) { line = this.reader.readLine(); }
事实上,读取事件readEvents
完全可以用do-while
来做,代码会更加整洁,如下(注:以下代码没有测试):
// StandardEventsReader.java, fix the bug, events reader public List<ExternalEvent> readEvents(int nrof) { ArrayList<ExternalEvent> events = new ArrayList<ExternalEvent>(nrof); int eventsRead = 0; // skip empty and comment lines Pattern skipPattern = Pattern.compile("(#.*)|(^\\s*$)"); String line; do { /*** Step 1: read a line ***/ try { line = this.reader.readLine(); } catch (IOException e1) { throw new SimError("Reading from external event file failed."); } Scanner lineScan = new Scanner(line); if (skipPattern.matcher(line).matches()) { // skip empty and comment lines continue; } /*** Step 2: process the line ***/ double time; String action; String msgId; int hostAddr; int host2Addr; try { time = lineScan.nextDouble(); action = lineScan.next(); /*** drop message event ***/ if (action.equals(DROP)) { // public static final String DROP = "DR"; msgId = lineScan.next(); hostAddr = getHostAddress(lineScan.next()); events.add(new MessageDeleteEvent(hostAddr, msgId, time, true)); } /*** remove message event ***/ else if (action.equals(REMOVE)) { // public static final String REMOVE = "R"; msgId = lineScan.next(); hostAddr = getHostAddress(lineScan.next()); events.add(new MessageDeleteEvent(hostAddr, msgId, time, false)); } /*** connection event ***/ else if (action.equals(CONNECTION)) { // public static final String CONNECTION = "CONN"; String connEventType; boolean isUp; hostAddr = getHostAddress(lineScan.next()); host2Addr = getHostAddress(lineScan.next()); connEventType = lineScan.next(); String interfaceId = null; if (lineScan.hasNext()) { interfaceId = lineScan.next(); } if (connEventType.equalsIgnoreCase(CONNECTION_UP)) { isUp = true; } else if (connEventType.equalsIgnoreCase(CONNECTION_DOWN)) { isUp = false; } else { throw new SimError("Unknown up/down value '" + connEventType + "'"); } ConnectionEvent ce = new ConnectionEvent(hostAddr, host2Addr, interfaceId, isUp, time); events.add(ce); } else { msgId = lineScan.next(); hostAddr = getHostAddress(lineScan.next()); host2Addr = getHostAddress(lineScan.next()); /*** create message event ***/ if (action.equals(CREATE)){ // public static final String CREATE = "C"; int size = lineScan.nextInt(); int respSize = 0; if (lineScan.hasNextInt()) { respSize = lineScan.nextInt(); } events.add(new MessageCreateEvent(hostAddr, host2Addr, msgId, size, respSize, time)); } else { int stage = -1; /*** send message event ***/ if (action.equals(SEND)) { // public static final String SEND = "S"; stage = MessageRelayEvent.SENDING; } /*** delivered message event ***/ else if (action.equals(DELIVERED)) { // public static final String DELIVERED = "DE"; stage = MessageRelayEvent.TRANSFERRED; } /*** abort message event ***/ else if (action.equals(ABORT)) { // public static final String ABORT = "A"; stage = MessageRelayEvent.ABORTED; } else { throw new SimError("Unknown action '" + action + "' in external events"); } events.add(new MessageRelayEvent(hostAddr, host2Addr, msgId, time, stage)); } } // discard the newline in the end if (lineScan.hasNextLine()) { lineScan.nextLine(); // TODO: test } }catch (Exception e) { throw new SimError("Can't parse external event " + (eventsRead+1) + " from '" + line + "'", e); } eventsRead++; } while (eventsRead < nrof && line != null); return events; }赞赏
微信赞赏
支付宝赞赏
打扰博主一下,自己设置的网络拓扑读取外部事件,信息事件产生器是MessageBurstGenerator,运行结束后MessageStatsReport中created是0,这是会是因为哪个参数设置错误导致的?
调试吧。
#消息事件数目 #实际创建的消息数目20000 199601请问这里为什么是2000010-(2000010/500)+1=199601?消息事件数目为什么要乘以10?
看不懂你的问题。
Pingback: The ONE使用笔记:目录 | | Spark & Shine