gem5 Simulator System. http://gem5.org gem5 is copyrighted software; use the --copyright option for details.
gem5 compiled Jan 4201711:01:46 gem5 started Jan 4201713:41:38 gem5 executing on chinook, pid 1834 command line: build/X86/gem5.opt --debug-flags=Hello configs/learning_gem5/part2/run_hello.py
Global frequency set at 1000000000000 ticks per second 0: hello: Created the hello object Beginning simulation! info: Entering event queue @ 0. Starting simulation... 100: hello: Hello world! Processing the event! Exiting @ tick 18446744073709551615 because simulate() limit reached
classEvent : public EventBase, public Serializable { Event *nextBin; // Bin defined as when+priority Event *nextInBin; Tick _when; // timestamp when event should be processed Priority _priority; //!< event priority Flags flags; Counter instance; // event unique ID EventQueue *queue;
classEventQueue { Event *head; Tick _curTick; //! Mutex to protect async queue. UncontendedMutex async_queue_mutex; //! List of events added by other threads to this event queue. std::list<Event*> async_queue; // taken when servicing events UncontendedMutex service_mutex; }
//! 当前的执行模式: parallel / serial externbool inParallelMode;
voidschedule(Event *event, Tick when, bool global=false){ event->setWhen(when, this); // 两种模式: // a. 异步插入:硬件线程将局部事件调度到一个不属于自己的其他队列 需要 `asyncq`. // b. 全局调度:硬件线程将全局事件调度到 `asyncq` 需要维护全局事件的整体顺序 // See global_event.{cc,hh} for more explanation. if (inParallelMode && (this != curEventQueue() || global)) { // 异步插入 asyncInsert(event); } else { // 同步插入 insert(event); } event->flags.set(Event::Scheduled); event->acquire();
if (debug::Event) event->trace("scheduled"); }
同步插入
同步事件的调度需要调用 insert() 函数,且此时 global 参数为 false。这是很简单的链表插入动作,插入在插入点之前,符合编程惯例。之前提到,EventQueue 队列是一个二级链表,是由一串串单链表的头节点组成的链表。从以下代码可知,在 in Bin 链表中,使用头插法插入了新节点,因此二级链表是 LIFO 的。
/* Releasing the current queue, locking the new queue * and updating curEventQueue(). This can, for example * be useful when performing IO across thread event * queues when timing is not crucial (e.g., during fast * forwarding). */ ScopedMigration(EventQueue *_new_eq, bool _doMigrate = true) :new_eq(*_new_eq), old_eq(*curEventQueue()), doMigrate((&new_eq != &old_eq)&&_doMigrate) { if (doMigrate) { old_eq.unlock(); new_eq.lock(); curEventQueue(&new_eq); } } // Temporarily migrate execution to a different event queue. classEventQueue::ScopedMigration { private: EventQueue &new_eq; EventQueue &old_eq; bool doMigrate; }
voidEventQueue::remove(Event *event){ if (head == NULL) panic("event not found!"); // deal with an event on the head's 'in bin' list (event has the same // time as the head) if (*head == *event) { head = Event::removeItem(event, head); return; } // Find the 'in bin' list that this event belongs on Event *prev = head; Event *curr = head->nextBin; while (curr && *curr < *event) { prev = curr; curr = curr->nextBin; } if (!curr || *curr != *event) panic("event not found!"); prev->nextBin = Event::removeItem(event, curr); }
Event *Event::removeItem(Event *event, Event *top){ Event *curr = top; Event *next = top->nextInBin; // if we removed the top item, we need to handle things specially // and just remove the top item, fixing up the next bin pointer of // the new top item if (event == top) { if (!next) return top->nextBin; next->nextBin = top->nextBin; return next; } // Since we already checked the current element, we're going to // keep checking event against the next element. while (event != next) { if (!next) panic("event not found!");
curr = next; next = next->nextInBin; } // remove next from the 'in bin' list since it's what we're looking for curr->nextInBin = next->nextInBin; return top; }
if (next) { next->nextBin = head->nextBin; head = next; } else head = head->nextBin; if (!event->squashed()) { // forward current cycle to the time when this event occurs. setCurTick(event->when()); if (debug::Event) event->trace("executed"); event->process(); if (event->isExitEvent()) { assert(!event->flags.isSet(Event::Managed) || !event->flags.isSet(Event::IsMainQueue)); // would be silly return event; } } else event->flags.clear(Event::Squashed); event->release(); returnNULL; }