目录
[TOC]
基类
首先来看 FIFO 基类定义
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 namespace fifo {class AbstractFifo : public cSimpleModule{ protected : cMessage *msgServiced = nullptr ; cMessage *endServiceMsg = nullptr ; cQueue queue; simsignal_t qlenSignal; simsignal_t busySignal; simsignal_t queueingTimeSignal; public : virtual ~AbstractFifo (); protected : virtual void initialize () override ; virtual void handleMessage (cMessage *msg) override ; virtual void arrival (cMessage *msg) {} virtual simtime_t startService (cMessage *msg) = 0 ; virtual void endService (cMessage *msg) = 0 ; }; };
在成员变量中可以看到 cQueue queue;
定义,是整个 FIFO 的核心,围绕着这个数据结构展开 signle-server queues 的框架实现。
基本上所有的处理都在 AbstractFifo 实现了,只有 startService 和 endService 需要在派生类中进行重载。
initialize()
函数
初始化几个统计信号,分别负责 queue 不同状态下的记录统计;初始化 endServiceMsg
消息;发送当前 queue 的长度以及设置 busySignal 。
1 2 3 4 5 6 7 8 9 10 11 void AbstractFifo::initialize () { endServiceMsg = new cMessage ("end-service" ); queue.setName ("queue" ); qlenSignal = registerSignal ("qlen" ); busySignal = registerSignal ("busy" ); queueingTimeSignal = registerSignal ("queueingTime" ); emit (qlenSignal, queue.getLength ()); emit (busySignal, false ); }
handleMessage()
函数
这里只看 AbstractFifo
,其余 module 都很简单不再细看。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 void AbstractFifo::handleMessage (cMessage *msg) { if (msg == endServiceMsg) { EV << "endServiceMsg" << endl; endService (msgServiced); if (queue.isEmpty ()) { msgServiced = nullptr ; emit (busySignal, false ); } else { msgServiced = (cMessage *)queue.pop (); emit (qlenSignal, queue.getLength ()); emit (queueingTimeSignal, simTime () - msgServiced->getTimestamp ()); simtime_t serviceTime = startService (msgServiced); scheduleAt (simTime ()+serviceTime, endServiceMsg); } } else if (!msgServiced) { EV << "!msgServiced" << endl; arrival (msg); msgServiced = msg; emit (queueingTimeSignal, SIMTIME_ZERO); simtime_t serviceTime = startService (msgServiced); scheduleAt (simTime ()+serviceTime, endServiceMsg); emit (busySignal, true ); } else { EV << "arrival" << endl; arrival (msg); queue.insert (msg); msg->setTimestamp (); emit (qlenSignal, queue.getLength ()); } }
这里的三个判断初看不太好理解,额外加了些打印,结合 queue 的操作一起来看。实际的执行顺序如下
当 source 模块在低速发包的时候,可以看到基本不会调用到 queue 的 insert
和 pop
操作,msgServiced
的 reset 值总为 nullptr
,之后执行 2 startService
操作开始加入耗时。如下可以看到系统设置的 source 发包和 fifo 处理的时长,大约每 0.2s 发包一次并且每 0.1s 执行一次 startService,因此可以看到系统运行时基本不会出现入队和出队。
1 2 3 4 5 [Fifo1] description = "low job arrival rate" network = SingleQueue **.source.interarrivalTime = exponential (0.2 s) **.fifo.serviceTime = 0.1 s
但当把 interarrivalTime
调整为 0.1s 后,就可以发现有 fifo 的 service 处理不完的情况。
1 2 3 4 5 [Fifo2] description = "high job arrival rate" network = SingleQueue **.source.interarrivalTime = exponential (0.1 s) **.fifo.serviceTime = 0.1 s
Tandem Queue
Tandem Queue 的组成结构如下
除此之外几乎没有啥明细不同了,fifo 也是依次串联。
1 2 3 4 5 6 7 8 9 10 11 [TandemQueues] network = TandemQueues **.interarrivalTime = exponential (2 s) **.serviceTime = exponential (2 s) [TandemQueueExperiment] # this config is used by test/scave/, do not modify! network = TandemQueues **.interarrivalTime = exponential (2 s) **.serviceTime = truncnormal (${serviceTimeMean=1.5 s, 2.5 s},1 s) repeat = 2 sim-time-limit = 200 s