eventq.cc revision 9983
12SN/A/* 21762SN/A * Copyright (c) 2000-2005 The Regents of The University of Michigan 35502Snate@binkert.org * Copyright (c) 2008 The Hewlett-Packard Development Company 49983Sstever@gmail.com * Copyright (c) 2013 Advanced Micro Devices, Inc. 52SN/A * All rights reserved. 62SN/A * 72SN/A * Redistribution and use in source and binary forms, with or without 82SN/A * modification, are permitted provided that the following conditions are 92SN/A * met: redistributions of source code must retain the above copyright 102SN/A * notice, this list of conditions and the following disclaimer; 112SN/A * redistributions in binary form must reproduce the above copyright 122SN/A * notice, this list of conditions and the following disclaimer in the 132SN/A * documentation and/or other materials provided with the distribution; 142SN/A * neither the name of the copyright holders nor the names of its 152SN/A * contributors may be used to endorse or promote products derived from 162SN/A * this software without specific prior written permission. 172SN/A * 182SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 192SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 202SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 212SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 222SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 232SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 242SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 252SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 262SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 272SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 282SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 292665Ssaidi@eecs.umich.edu * 302665Ssaidi@eecs.umich.edu * Authors: Steve Reinhardt 312665Ssaidi@eecs.umich.edu * Nathan Binkert 322665Ssaidi@eecs.umich.edu * Steve Raasch 332SN/A */ 342SN/A 355501Snate@binkert.org#include <cassert> 362SN/A#include <iostream> 372SN/A#include <string> 382SN/A#include <vector> 392SN/A 405502Snate@binkert.org#include "base/hashmap.hh" 415501Snate@binkert.org#include "base/misc.hh" 425501Snate@binkert.org#include "base/trace.hh" 431717SN/A#include "cpu/smt.hh" 448232Snate@binkert.org#include "debug/Config.hh" 455501Snate@binkert.org#include "sim/core.hh" 469356Snilay@cs.wisc.edu#include "sim/eventq_impl.hh" 472SN/A 482SN/Ausing namespace std; 492SN/A 509983Sstever@gmail.comTick simQuantum = 0; 519983Sstever@gmail.com 522SN/A// 539983Sstever@gmail.com// Main Event Queues 542SN/A// 559983Sstever@gmail.com// Events on these queues are processed at the *beginning* of each 562SN/A// cycle, before the pipeline simulation is performed. 572SN/A// 589983Sstever@gmail.comuint32_t numMainEventQueues = 0; 599983Sstever@gmail.comvector<EventQueue *> mainEventQueue; 609983Sstever@gmail.com__thread EventQueue *_curEventQueue = NULL; 619983Sstever@gmail.combool inParallelMode = false; 629983Sstever@gmail.com 639983Sstever@gmail.comEventQueue * 649983Sstever@gmail.comgetEventQueue(uint32_t index) 659983Sstever@gmail.com{ 669983Sstever@gmail.com while (numMainEventQueues <= index) { 679983Sstever@gmail.com numMainEventQueues++; 689983Sstever@gmail.com mainEventQueue.push_back( 699983Sstever@gmail.com new EventQueue(csprintf("MainEventQueue-%d", index))); 709983Sstever@gmail.com } 719983Sstever@gmail.com 729983Sstever@gmail.com return mainEventQueue[index]; 739983Sstever@gmail.com} 742SN/A 754017Sstever@eecs.umich.edu#ifndef NDEBUG 764016Sstever@eecs.umich.eduCounter Event::instanceCounter = 0; 774017Sstever@eecs.umich.edu#endif 784016Sstever@eecs.umich.edu 795768Snate@binkert.orgEvent::~Event() 805768Snate@binkert.org{ 815774Snate@binkert.org assert(!scheduled()); 827059Snate@binkert.org flags = 0; 835768Snate@binkert.org} 845768Snate@binkert.org 855768Snate@binkert.orgconst std::string 865768Snate@binkert.orgEvent::name() const 875768Snate@binkert.org{ 885768Snate@binkert.org#ifndef NDEBUG 895768Snate@binkert.org return csprintf("Event_%d", instance); 905768Snate@binkert.org#else 915768Snate@binkert.org return csprintf("Event_%x", (uintptr_t)this); 925768Snate@binkert.org#endif 935768Snate@binkert.org} 945768Snate@binkert.org 955768Snate@binkert.org 965602Snate@binkert.orgEvent * 975602Snate@binkert.orgEvent::insertBefore(Event *event, Event *curr) 985502Snate@binkert.org{ 995503Snate@binkert.org // Either way, event will be the top element in the 'in bin' list 1005502Snate@binkert.org // which is the pointer we need in order to look into the list, so 1015502Snate@binkert.org // we need to insert that into the bin list. 1025502Snate@binkert.org if (!curr || *event < *curr) { 1035502Snate@binkert.org // Insert the event before the current list since it is in the future. 1045502Snate@binkert.org event->nextBin = curr; 1055503Snate@binkert.org event->nextInBin = NULL; 1065502Snate@binkert.org } else { 1075502Snate@binkert.org // Since we're on the correct list, we need to point to the next list 1085502Snate@binkert.org event->nextBin = curr->nextBin; // curr->nextBin can now become stale 1095502Snate@binkert.org 1105503Snate@binkert.org // Insert event at the top of the stack 1115503Snate@binkert.org event->nextInBin = curr; 1125503Snate@binkert.org } 1135502Snate@binkert.org 1145503Snate@binkert.org return event; 1155502Snate@binkert.org} 1165502Snate@binkert.org 1172SN/Avoid 1182SN/AEventQueue::insert(Event *event) 1192SN/A{ 1205502Snate@binkert.org // Deal with the head case 1215502Snate@binkert.org if (!head || *event <= *head) { 1225602Snate@binkert.org head = Event::insertBefore(event, head); 1235502Snate@binkert.org return; 1245502Snate@binkert.org } 1252SN/A 1265502Snate@binkert.org // Figure out either which 'in bin' list we are on, or where a new list 1275502Snate@binkert.org // needs to be inserted 1285503Snate@binkert.org Event *prev = head; 1295503Snate@binkert.org Event *curr = head->nextBin; 1305503Snate@binkert.org while (curr && *curr < *event) { 1315503Snate@binkert.org prev = curr; 1325503Snate@binkert.org curr = curr->nextBin; 1335502Snate@binkert.org } 1342SN/A 1355503Snate@binkert.org // Note: this operation may render all nextBin pointers on the 1365503Snate@binkert.org // prev 'in bin' list stale (except for the top one) 1375602Snate@binkert.org prev->nextBin = Event::insertBefore(event, curr); 1385502Snate@binkert.org} 1392SN/A 1405602Snate@binkert.orgEvent * 1415602Snate@binkert.orgEvent::removeItem(Event *event, Event *top) 1425502Snate@binkert.org{ 1435503Snate@binkert.org Event *curr = top; 1445503Snate@binkert.org Event *next = top->nextInBin; 1455502Snate@binkert.org 1465503Snate@binkert.org // if we removed the top item, we need to handle things specially 1475503Snate@binkert.org // and just remove the top item, fixing up the next bin pointer of 1485503Snate@binkert.org // the new top item 1495503Snate@binkert.org if (event == top) { 1505503Snate@binkert.org if (!next) 1515503Snate@binkert.org return top->nextBin; 1525503Snate@binkert.org next->nextBin = top->nextBin; 1535503Snate@binkert.org return next; 1545503Snate@binkert.org } 1555503Snate@binkert.org 1565503Snate@binkert.org // Since we already checked the current element, we're going to 1575503Snate@binkert.org // keep checking event against the next element. 1585503Snate@binkert.org while (event != next) { 1595503Snate@binkert.org if (!next) 1605502Snate@binkert.org panic("event not found!"); 1615502Snate@binkert.org 1625503Snate@binkert.org curr = next; 1635503Snate@binkert.org next = next->nextInBin; 1642SN/A } 1655502Snate@binkert.org 1665503Snate@binkert.org // remove next from the 'in bin' list since it's what we're looking for 1675503Snate@binkert.org curr->nextInBin = next->nextInBin; 1685503Snate@binkert.org return top; 1692SN/A} 1702SN/A 1712SN/Avoid 1722SN/AEventQueue::remove(Event *event) 1732SN/A{ 1742SN/A if (head == NULL) 1755502Snate@binkert.org panic("event not found!"); 1762SN/A 1779983Sstever@gmail.com assert(event->queue == this); 1789983Sstever@gmail.com 1795502Snate@binkert.org // deal with an event on the head's 'in bin' list (event has the same 1805502Snate@binkert.org // time as the head) 1815502Snate@binkert.org if (*head == *event) { 1825602Snate@binkert.org head = Event::removeItem(event, head); 1832SN/A return; 1842SN/A } 1852SN/A 1865502Snate@binkert.org // Find the 'in bin' list that this event belongs on 1872SN/A Event *prev = head; 1885502Snate@binkert.org Event *curr = head->nextBin; 1895502Snate@binkert.org while (curr && *curr < *event) { 1902SN/A prev = curr; 1915502Snate@binkert.org curr = curr->nextBin; 1922SN/A } 1932SN/A 1945502Snate@binkert.org if (!curr || *curr != *event) 1955502Snate@binkert.org panic("event not found!"); 1965502Snate@binkert.org 1975503Snate@binkert.org // curr points to the top item of the the correct 'in bin' list, when 1985503Snate@binkert.org // we remove an item, it returns the new top item (which may be 1995502Snate@binkert.org // unchanged) 2005602Snate@binkert.org prev->nextBin = Event::removeItem(event, curr); 2012SN/A} 2022SN/A 2032667Sstever@eecs.umich.eduEvent * 2042SN/AEventQueue::serviceOne() 2052SN/A{ 2065503Snate@binkert.org Event *event = head; 2075503Snate@binkert.org Event *next = head->nextInBin; 2085769Snate@binkert.org event->flags.clear(Event::Scheduled); 2095502Snate@binkert.org 2105503Snate@binkert.org if (next) { 2115503Snate@binkert.org // update the next bin pointer since it could be stale 2125503Snate@binkert.org next->nextBin = head->nextBin; 2135503Snate@binkert.org 2145503Snate@binkert.org // pop the stack 2155503Snate@binkert.org head = next; 2165503Snate@binkert.org } else { 2175502Snate@binkert.org // this was the only element on the 'in bin' list, so get rid of 2185502Snate@binkert.org // the 'in bin' list and point to the next bin list 2195503Snate@binkert.org head = head->nextBin; 2205502Snate@binkert.org } 2212SN/A 2222SN/A // handle action 2232667Sstever@eecs.umich.edu if (!event->squashed()) { 2249356Snilay@cs.wisc.edu // forward current cycle to the time when this event occurs. 2259356Snilay@cs.wisc.edu setCurTick(event->when()); 2269356Snilay@cs.wisc.edu 2272SN/A event->process(); 2282667Sstever@eecs.umich.edu if (event->isExitEvent()) { 2299328SAli.Saidi@ARM.com assert(!event->flags.isSet(Event::AutoDelete) || 2309328SAli.Saidi@ARM.com !event->flags.isSet(Event::IsMainQueue)); // would be silly 2312667Sstever@eecs.umich.edu return event; 2322667Sstever@eecs.umich.edu } 2332667Sstever@eecs.umich.edu } else { 2345769Snate@binkert.org event->flags.clear(Event::Squashed); 2352667Sstever@eecs.umich.edu } 2362SN/A 2375769Snate@binkert.org if (event->flags.isSet(Event::AutoDelete) && !event->scheduled()) 2382SN/A delete event; 2392667Sstever@eecs.umich.edu 2402667Sstever@eecs.umich.edu return NULL; 2412SN/A} 2422SN/A 243224SN/Avoid 244224SN/AEvent::serialize(std::ostream &os) 245224SN/A{ 246224SN/A SERIALIZE_SCALAR(_when); 247224SN/A SERIALIZE_SCALAR(_priority); 2485769Snate@binkert.org short _flags = flags; 2495769Snate@binkert.org SERIALIZE_SCALAR(_flags); 250224SN/A} 251224SN/A 252224SN/Avoid 253237SN/AEvent::unserialize(Checkpoint *cp, const string §ion) 254224SN/A{ 2559983Sstever@gmail.com} 2569983Sstever@gmail.com 2579983Sstever@gmail.comvoid 2589983Sstever@gmail.comEvent::unserialize(Checkpoint *cp, const string §ion, EventQueue *eventq) 2599983Sstever@gmail.com{ 2605695Snate@binkert.org if (scheduled()) 2619983Sstever@gmail.com eventq->deschedule(this); 262224SN/A 263224SN/A UNSERIALIZE_SCALAR(_when); 264224SN/A UNSERIALIZE_SCALAR(_priority); 265224SN/A 2665769Snate@binkert.org short _flags; 2675769Snate@binkert.org UNSERIALIZE_SCALAR(_flags); 2687452SLisa.Hsu@amd.com 2697452SLisa.Hsu@amd.com // Old checkpoints had no concept of the Initialized flag 2707452SLisa.Hsu@amd.com // so restoring from old checkpoints always fail. 2717452SLisa.Hsu@amd.com // Events are initialized on construction but original code 2727452SLisa.Hsu@amd.com // "flags = _flags" would just overwrite the initialization. 2737452SLisa.Hsu@amd.com // So, read in the checkpoint flags, but then set the Initialized 2747452SLisa.Hsu@amd.com // flag on top of it in order to avoid failures. 2757451SLisa.Hsu@amd.com assert(initialized()); 2765769Snate@binkert.org flags = _flags; 2777451SLisa.Hsu@amd.com flags.set(Initialized); 2785769Snate@binkert.org 2797452SLisa.Hsu@amd.com // need to see if original event was in a scheduled, unsquashed 2807452SLisa.Hsu@amd.com // state, but don't want to restore those flags in the current 2817452SLisa.Hsu@amd.com // object itself (since they aren't immediately true) 2825769Snate@binkert.org bool wasScheduled = flags.isSet(Scheduled) && !flags.isSet(Squashed); 2835769Snate@binkert.org flags.clear(Squashed | Scheduled); 284224SN/A 285224SN/A if (wasScheduled) { 286224SN/A DPRINTF(Config, "rescheduling at %d\n", _when); 2879983Sstever@gmail.com eventq->schedule(this, _when); 288224SN/A } 289224SN/A} 290224SN/A 2912SN/Avoid 292217SN/AEventQueue::serialize(ostream &os) 2932SN/A{ 294265SN/A std::list<Event *> eventPtrs; 295237SN/A 296237SN/A int numEvents = 0; 2975502Snate@binkert.org Event *nextBin = head; 2985502Snate@binkert.org while (nextBin) { 2995503Snate@binkert.org Event *nextInBin = nextBin; 3005502Snate@binkert.org 3015503Snate@binkert.org while (nextInBin) { 3025769Snate@binkert.org if (nextInBin->flags.isSet(Event::AutoSerialize)) { 3035502Snate@binkert.org eventPtrs.push_back(nextInBin); 3045502Snate@binkert.org paramOut(os, csprintf("event%d", numEvents++), 3055502Snate@binkert.org nextInBin->name()); 3065502Snate@binkert.org } 3075502Snate@binkert.org nextInBin = nextInBin->nextInBin; 3085503Snate@binkert.org } 3095502Snate@binkert.org 3105502Snate@binkert.org nextBin = nextBin->nextBin; 3112SN/A } 312237SN/A 313265SN/A SERIALIZE_SCALAR(numEvents); 314265SN/A 3155502Snate@binkert.org for (std::list<Event *>::iterator it = eventPtrs.begin(); 316265SN/A it != eventPtrs.end(); ++it) { 317265SN/A (*it)->nameOut(os); 318265SN/A (*it)->serialize(os); 319265SN/A } 3202SN/A} 3212SN/A 322237SN/Avoid 323237SN/AEventQueue::unserialize(Checkpoint *cp, const std::string §ion) 324237SN/A{ 325265SN/A int numEvents; 326265SN/A UNSERIALIZE_SCALAR(numEvents); 327265SN/A 328270SN/A std::string eventName; 329265SN/A for (int i = 0; i < numEvents; i++) { 330265SN/A // get the pointer value associated with the event 331270SN/A paramIn(cp, section, csprintf("event%d", i), eventName); 332265SN/A 333265SN/A // create the event based on its pointer value 334395SN/A Serializable::create(cp, eventName); 335237SN/A } 336237SN/A} 337237SN/A 3382SN/Avoid 3395501Snate@binkert.orgEventQueue::dump() const 3402SN/A{ 3412SN/A cprintf("============================================================\n"); 3427823Ssteve.reinhardt@amd.com cprintf("EventQueue Dump (cycle %d)\n", curTick()); 3432SN/A cprintf("------------------------------------------------------------\n"); 3442SN/A 3452SN/A if (empty()) 3462SN/A cprintf("<No Events>\n"); 3472SN/A else { 3485502Snate@binkert.org Event *nextBin = head; 3495502Snate@binkert.org while (nextBin) { 3505502Snate@binkert.org Event *nextInBin = nextBin; 3515503Snate@binkert.org while (nextInBin) { 3525503Snate@binkert.org nextInBin->dump(); 3535502Snate@binkert.org nextInBin = nextInBin->nextInBin; 3545503Snate@binkert.org } 3555502Snate@binkert.org 3565502Snate@binkert.org nextBin = nextBin->nextBin; 3572SN/A } 3582SN/A } 3592SN/A 3602SN/A cprintf("============================================================\n"); 3612SN/A} 3622SN/A 3635502Snate@binkert.orgbool 3645502Snate@binkert.orgEventQueue::debugVerify() const 3655502Snate@binkert.org{ 3665502Snate@binkert.org m5::hash_map<long, bool> map; 3675502Snate@binkert.org 3685502Snate@binkert.org Tick time = 0; 3695502Snate@binkert.org short priority = 0; 3705502Snate@binkert.org 3715502Snate@binkert.org Event *nextBin = head; 3725502Snate@binkert.org while (nextBin) { 3735503Snate@binkert.org Event *nextInBin = nextBin; 3745503Snate@binkert.org while (nextInBin) { 3755502Snate@binkert.org if (nextInBin->when() < time) { 3765502Snate@binkert.org cprintf("time goes backwards!"); 3775502Snate@binkert.org nextInBin->dump(); 3785502Snate@binkert.org return false; 3795502Snate@binkert.org } else if (nextInBin->when() == time && 3805502Snate@binkert.org nextInBin->priority() < priority) { 3815502Snate@binkert.org cprintf("priority inverted!"); 3825502Snate@binkert.org nextInBin->dump(); 3835502Snate@binkert.org return false; 3845502Snate@binkert.org } 3855502Snate@binkert.org 3865502Snate@binkert.org if (map[reinterpret_cast<long>(nextInBin)]) { 3875502Snate@binkert.org cprintf("Node already seen"); 3885502Snate@binkert.org nextInBin->dump(); 3895502Snate@binkert.org return false; 3905502Snate@binkert.org } 3915502Snate@binkert.org map[reinterpret_cast<long>(nextInBin)] = true; 3925502Snate@binkert.org 3935502Snate@binkert.org time = nextInBin->when(); 3945502Snate@binkert.org priority = nextInBin->priority(); 3955502Snate@binkert.org 3965502Snate@binkert.org nextInBin = nextInBin->nextInBin; 3975503Snate@binkert.org } 3985502Snate@binkert.org 3995502Snate@binkert.org nextBin = nextBin->nextBin; 4005502Snate@binkert.org } 4015502Snate@binkert.org 4025502Snate@binkert.org return true; 4035502Snate@binkert.org} 4045502Snate@binkert.org 4058648Snilay@cs.wisc.eduEvent* 4068648Snilay@cs.wisc.eduEventQueue::replaceHead(Event* s) 4078648Snilay@cs.wisc.edu{ 4088648Snilay@cs.wisc.edu Event* t = head; 4098648Snilay@cs.wisc.edu head = s; 4108648Snilay@cs.wisc.edu return t; 4118648Snilay@cs.wisc.edu} 4128648Snilay@cs.wisc.edu 4131019SN/Avoid 4141019SN/AdumpMainQueue() 4151019SN/A{ 4169983Sstever@gmail.com for (uint32_t i = 0; i < numMainEventQueues; ++i) { 4179983Sstever@gmail.com mainEventQueue[i]->dump(); 4189983Sstever@gmail.com } 4191019SN/A} 4201019SN/A 4212SN/A 4222SN/Aconst char * 4235336Shines@cs.fsu.eduEvent::description() const 4242SN/A{ 4252SN/A return "generic"; 4262SN/A} 4272SN/A 4282SN/Avoid 4292SN/AEvent::trace(const char *action) 4302SN/A{ 4312SN/A // This DPRINTF is unconditional because calls to this function 4322SN/A // are protected by an 'if (DTRACE(Event))' in the inlined Event 4332SN/A // methods. 4342SN/A // 4352SN/A // This is just a default implementation for derived classes where 4362SN/A // it's not worth doing anything special. If you want to put a 4372SN/A // more informative message in the trace, override this method on 4382SN/A // the particular subclass where you have the information that 4392SN/A // needs to be printed. 4402SN/A DPRINTFN("%s event %s @ %d\n", description(), action, when()); 4412SN/A} 4422SN/A 4432SN/Avoid 4445501Snate@binkert.orgEvent::dump() const 4452SN/A{ 4465501Snate@binkert.org cprintf("Event %s (%s)\n", name(), description()); 4475769Snate@binkert.org cprintf("Flags: %#x\n", flags); 4485501Snate@binkert.org#ifdef EVENTQ_DEBUG 4495501Snate@binkert.org cprintf("Created: %d\n", whenCreated); 4502SN/A#endif 4512SN/A if (scheduled()) { 4525501Snate@binkert.org#ifdef EVENTQ_DEBUG 4535501Snate@binkert.org cprintf("Scheduled at %d\n", whenScheduled); 4542SN/A#endif 4551019SN/A cprintf("Scheduled for %d, priority %d\n", when(), _priority); 4565501Snate@binkert.org } else { 4571019SN/A cprintf("Not Scheduled\n"); 4582SN/A } 4592SN/A} 4607063Snate@binkert.org 4617063Snate@binkert.orgEventQueue::EventQueue(const string &n) 4629983Sstever@gmail.com : objName(n), head(NULL), _curTick(0), 4639983Sstever@gmail.com async_queue_mutex(new std::mutex()) 4649983Sstever@gmail.com{ 4659983Sstever@gmail.com} 4669983Sstever@gmail.com 4679983Sstever@gmail.comvoid 4689983Sstever@gmail.comEventQueue::asyncInsert(Event *event) 4699983Sstever@gmail.com{ 4709983Sstever@gmail.com async_queue_mutex->lock(); 4719983Sstever@gmail.com async_queue.push_back(event); 4729983Sstever@gmail.com async_queue_mutex->unlock(); 4739983Sstever@gmail.com} 4749983Sstever@gmail.com 4759983Sstever@gmail.comvoid 4769983Sstever@gmail.comEventQueue::handleAsyncInsertions() 4779983Sstever@gmail.com{ 4789983Sstever@gmail.com assert(this == curEventQueue()); 4799983Sstever@gmail.com async_queue_mutex->lock(); 4809983Sstever@gmail.com 4819983Sstever@gmail.com while (!async_queue.empty()) { 4829983Sstever@gmail.com insert(async_queue.front()); 4839983Sstever@gmail.com async_queue.pop_front(); 4849983Sstever@gmail.com } 4859983Sstever@gmail.com 4869983Sstever@gmail.com async_queue_mutex->unlock(); 4879983Sstever@gmail.com} 488