1 /*
2 * CEventQueue.cc
3 *
4 * Copyright 2014-2018 D. Mitch Bailey cvc at shuharisystem dot com
5 *
6 * This file is part of cvc.
7 *
8 * cvc is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * cvc is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with cvc. If not, see <http://www.gnu.org/licenses/>.
20 *
21 * You can download cvc from https://github.com/d-m-bailey/cvc.git
22 */
23
24 #include "CEventQueue.hh"
25
ResetQueue(deviceId_t theDeviceCount)26 void CEventQueue::ResetQueue(deviceId_t theDeviceCount) {
27 queueArray.clear();
28 queueArray.resize(theDeviceCount, UNKNOWN_DEVICE);
29 enqueueCount = dequeueCount = requeueCount = 0;
30 queueStart = false;
31 virtualNet_v.lastUpdate = 0;
32 }
33
IsNextMainQueue()34 bool CEventQueue::IsNextMainQueue() {
35 if ( mainQueue.empty() ) return false;
36 if ( delayQueue.empty() ) return true;
37 // for SIM_QUEUE, mainQueue has priority always. for MIN/MAX_QUEUE, mainQueue has priority if not later key
38 return ( queueType == SIM_QUEUE || ( mainQueue.begin()->first <= delayQueue.begin()->first ) );
39 }
40
AddEvent(eventKey_t theEventKey,deviceId_t theDeviceIndex,queuePosition_t theQueuePosition)41 void CEventQueue::AddEvent(eventKey_t theEventKey, deviceId_t theDeviceIndex, queuePosition_t theQueuePosition) {
42 // theDelay = 1 : front of delay queue
43 // theDelay = 2 : back of delay queue
44 // theDelay = 0 : back of main queue
45 // theDelay = -1 : front of main queue (mos diode)
46 // theDelay = -2 : skip (shouldn't be here)
47 // theDelay = -3 : front of main queue (HiZ)
48 if ( queueType == MAX_QUEUE ) theEventKey = - theEventKey;
49 switch (theQueuePosition) {
50 case QUEUE_HIZ:
51 case MOS_DIODE: { mainQueue[theEventKey].push_front(theDeviceIndex); break; }
52 case MAIN_BACK: { mainQueue[theEventKey].push_back(theDeviceIndex); break; }
53 case DELAY_FRONT: { delayQueue[theEventKey].push_front(theDeviceIndex); break; }
54 case DELAY_BACK: { delayQueue[theEventKey].push_back(theDeviceIndex); break; }
55 default: { throw EFatalError("invalid queue delay " + to_string<int>((int) theQueuePosition)); }
56 }
57 enqueueCount++;
58 if ( --printCounter <= 0 ) PrintStatus();
59 if (gDebug_cvc) cout << "Adding to queue(" << gEventQueueTypeMap[queueType] << ") device: " << theDeviceIndex << "@" << theEventKey << "+" << theQueuePosition << endl;
60 }
61
GetMainEvent()62 deviceId_t CEventQueue::GetMainEvent() {
63 deviceId_t myDeviceIndex = mainQueue.begin()->second.pop_front(); //mainQueue.begin()->second.front();
64 if ( mainQueue.begin()->second.empty() ) {
65 mainQueue.erase(mainQueue.begin());
66 }
67 dequeueCount++;
68 if ( --printCounter <= 0 ) PrintStatus();
69 return myDeviceIndex;
70 }
71
GetDelayEvent()72 deviceId_t CEventQueue::GetDelayEvent() {
73 deviceId_t myDeviceIndex = delayQueue.begin()->second.pop_front(); //delayQueue.begin()->second.front();
74 if ( delayQueue.begin()->second.empty() ) {
75 delayQueue.erase(delayQueue.begin());
76 }
77 dequeueCount++;
78 if ( --printCounter <= 0 ) PrintStatus();
79 return myDeviceIndex;
80 }
81
GetEvent()82 deviceId_t CEventQueue::GetEvent() {
83 if ( IsNextMainQueue() ) {
84 return GetMainEvent();
85 } else {
86 return GetDelayEvent();
87 }
88 }
89
AddLeak(deviceId_t theDevice,CConnection & theConnections)90 void CEventQueue::AddLeak(deviceId_t theDevice, CConnection& theConnections) {
91 string myKey;
92 if ( theConnections.sourcePower_p->powerId < theConnections.drainPower_p->powerId ) {
93 myKey = to_string<int>(theConnections.sourcePower_p->powerId) + " " + to_string<int>(theConnections.drainPower_p->powerId);
94 } else {
95 myKey = to_string<int>(theConnections.drainPower_p->powerId) + " " + to_string<int>(theConnections.sourcePower_p->powerId);
96 }
97 leakMap[myKey].push_front(theDevice);
98 if (gDebug_cvc) cout << "leak key " << myKey << " map size " << leakMap.size() << " list size " << leakMap[myKey].listSize << endl;
99 }
100
Print(string theIndentation)101 void CEventQueue::Print(string theIndentation) {
102 string myIndentation = theIndentation + " ";
103 cout << theIndentation << "EventQueue(" << gEventQueueTypeMap[queueType] << ")> start" << endl;
104 cout << myIndentation << "Counts (enqueue/dequeue/requeue) " << enqueueCount << "/" << dequeueCount << "/" << requeueCount << endl;
105 cout << myIndentation << "Main Queue>" << endl;
106 for (CEventSubQueue::iterator eventPair_pit = mainQueue.begin(); eventPair_pit != mainQueue.end(); eventPair_pit++) {
107 cout << myIndentation << "Time: " << eventPair_pit->first << " (" << eventPair_pit->second.size() << "):";
108 for (deviceId_t device_it = eventPair_pit->second.first, myLastDevice = UNKNOWN_DEVICE;
109 device_it != UNKNOWN_DEVICE && device_it != myLastDevice;
110 myLastDevice = device_it, device_it = queueArray[device_it]) {
111 cout << " " << device_it;
112 }
113 cout << endl;
114 }
115 cout << myIndentation << "Delay Queue>" << endl;
116 for (CEventSubQueue::iterator eventPair_pit = delayQueue.begin(); eventPair_pit != delayQueue.end(); eventPair_pit++) {
117 cout << myIndentation << "Time: " << eventPair_pit->first << " (" << eventPair_pit->second.size() << "):";
118 for (deviceId_t device_it = eventPair_pit->second.first, myLastDevice = UNKNOWN_DEVICE;
119 device_it != UNKNOWN_DEVICE && device_it != myLastDevice;
120 myLastDevice = device_it, device_it = queueArray[device_it]) {
121 cout << " " << device_it;
122 }
123 cout << endl;
124 }
125 leakMap.Print(myIndentation);
126 cout << theIndentation << "EventQueue> end" << endl;
127 }
128
operator [](eventKey_t theEventKey)129 CEventList& CEventSubQueue::operator[] (eventKey_t theEventKey) {
130 CEventSubQueue::iterator myItem_it = find(theEventKey);
131 if ( myItem_it == end() ) {
132 pair<CEventSubQueue::iterator, bool> myResult;
133 myResult = insert(make_pair(theEventKey, CEventList(queueArray)));
134 return (myResult.first->second);
135 } else {
136 return (myItem_it->second);
137 }
138 }
139
QueueTime(eventQueue_t theQueueType)140 eventKey_t CEventSubQueue::QueueTime(eventQueue_t theQueueType) {
141 if ( size() == 0 ) return MAX_EVENT_TIME;
142 return ( begin()->first );
143 }
144
QueueTime()145 eventKey_t CEventQueue::QueueTime() {
146 if ( (! queueStart) || (delayQueue.empty() && mainQueue.empty()) ) return 0;
147 if ( queueType == MAX_QUEUE ) {
148 return (- min(mainQueue.QueueTime(queueType), delayQueue.QueueTime(queueType)));
149 } else {
150 return (min(mainQueue.QueueTime(queueType), delayQueue.QueueTime(queueType)));
151 }
152 }
153
Later(eventKey_t theEventKey)154 bool CEventQueue::Later(eventKey_t theEventKey) {
155 if ( queueType == MAX_QUEUE ) {
156 return ( theEventKey < QueueTime() );
157 } else {
158 return ( theEventKey > QueueTime() );
159 }
160 }
161
Later(eventKey_t theFirstKey,eventKey_t theSecondKey)162 bool CEventQueue::Later(eventKey_t theFirstKey, eventKey_t theSecondKey) {
163 if ( queueType == MAX_QUEUE ) {
164 return ( theFirstKey < theSecondKey );
165 } else {
166 return ( theFirstKey > theSecondKey );
167 }
168 }
169
Print(string theIndentation)170 void CLeakList::Print(string theIndentation) {
171 cout << theIndentation << "LeakList>";
172 for (CLeakList::iterator device_pit = begin(); device_pit != end(); device_pit++) {
173 cout << " " << *device_pit;
174 }
175 cout << endl;
176 }
177
PrintLeakKey(string theKey)178 string CLeakMap::PrintLeakKey(string theKey) {
179 unsigned int myFirstKey = from_string<unsigned int>(theKey.substr(0, theKey.find(" ")));
180 unsigned int mySecondKey = from_string<unsigned int>(theKey.substr(theKey.find(" ")));
181 string myFirstPowerName = "", mySecondPowerName = "";
182 for (CPowerPtrList::iterator power_ppit = powerPtrList_p->begin(); power_ppit != powerPtrList_p->end(); power_ppit++) {
183 if ( (*power_ppit)->powerId == myFirstKey ) myFirstPowerName = string((*power_ppit)->powerSignal());
184 if ( (*power_ppit)->powerId == mySecondKey ) mySecondPowerName = string((*power_ppit)->powerSignal());
185 }
186 return (myFirstPowerName + ":" + mySecondPowerName);
187 }
188
Print(string theIndentation)189 void CLeakMap::Print(string theIndentation) {
190 string myIndentation = theIndentation + " ";
191 cout << theIndentation << "LeakMap(" << size() << ")> start" << endl;
192 for (CLeakMap::iterator leakPair_pit = begin(); leakPair_pit != end(); leakPair_pit++) {
193 cout << myIndentation << "Key: " << PrintLeakKey(leakPair_pit->first) << " :(" << leakPair_pit->second.listSize << ") ";
194 leakPair_pit->second.Print("");
195 }
196 cout << theIndentation << "LeakMap> end" << endl;
197 }
198
PrintStatus(int theNextPrintCount)199 void CEventQueue::PrintStatus(int theNextPrintCount) {
200 cout << gEventQueueTypeMap[queueType] << " Counts (size/enqueue/requeue) " << enqueueCount - dequeueCount<< "/" << enqueueCount << "/" << requeueCount << "\r" << std::flush;
201 printCounter = theNextPrintCount;
202 }
203
push_back(deviceId_t theDevice)204 void CEventList::push_back(deviceId_t theDevice) {
205 if (queueArray[theDevice] != UNKNOWN_DEVICE) throw EQueueError(to_string<deviceId_t> (theDevice));
206 queueArray[theDevice] = theDevice;
207 if ( first == UNKNOWN_DEVICE ) {
208 assert(second == UNKNOWN_DEVICE);
209 first = theDevice;
210 } else {
211 assert(second != UNKNOWN_DEVICE);
212 queueArray[second] = theDevice;
213 }
214 eventListSize++;
215 second = theDevice;
216 }
217
push_front(deviceId_t theDevice)218 void CEventList::push_front(deviceId_t theDevice) {
219 if (queueArray[theDevice] != UNKNOWN_DEVICE) throw EQueueError(to_string<deviceId_t> (theDevice));
220 if ( first == UNKNOWN_DEVICE ) {
221 assert(second == UNKNOWN_DEVICE);
222 second = theDevice;
223 queueArray[theDevice] = theDevice;
224 } else {
225 assert(second != UNKNOWN_DEVICE);
226 queueArray[theDevice] = first;
227 }
228 eventListSize++;
229 first = theDevice;
230 }
231
pop_front()232 deviceId_t CEventList::pop_front() {
233 if (first == UNKNOWN_DEVICE) throw EQueueError("empty queue");
234 deviceId_t myDevice;
235 myDevice = first;
236 if ( first == queueArray[first] ) { // last element in queue
237 first = second = UNKNOWN_DEVICE;
238 } else {
239 first = queueArray[first];
240 }
241 queueArray[myDevice] = UNKNOWN_DEVICE;
242 eventListSize--;
243 return(myDevice);
244 }
245
front()246 inline deviceId_t CEventList::front() {
247 return(first);
248 }
249
empty()250 bool CEventList::empty() {
251 return(first == UNKNOWN_DEVICE);
252 }
253
254