drain.hh (10912:b99a6662d7c2) | drain.hh (10913:38dbdeea7f1f) |
---|---|
1/* 2 * Copyright (c) 2012, 2015 ARM Limited 3 * All rights reserved 4 * 5 * The license below extends only to copyright in the software and shall 6 * not be construed as granting a license to any other intellectual 7 * property including but not limited to intellectual property relating 8 * to a hardware implementation of the functionality of the software --- 178 unchanged lines hidden (view full) --- 187 * An object's internal state needs to be drained when creating a 188 * checkpoint, switching between CPU models, or switching between 189 * timing models. Once the internal state has been drained from 190 * <i>all</i> objects in the simulator, the objects are serialized to 191 * disc or the configuration change takes place. The process works as 192 * follows (see simulate.py for details): 193 * 194 * <ol> | 1/* 2 * Copyright (c) 2012, 2015 ARM Limited 3 * All rights reserved 4 * 5 * The license below extends only to copyright in the software and shall 6 * not be construed as granting a license to any other intellectual 7 * property including but not limited to intellectual property relating 8 * to a hardware implementation of the functionality of the software --- 178 unchanged lines hidden (view full) --- 187 * An object's internal state needs to be drained when creating a 188 * checkpoint, switching between CPU models, or switching between 189 * timing models. Once the internal state has been drained from 190 * <i>all</i> objects in the simulator, the objects are serialized to 191 * disc or the configuration change takes place. The process works as 192 * follows (see simulate.py for details): 193 * 194 * <ol> |
195 * <li>Call Drainable::drain() for every object in the 196 * system. Draining has completed if all of them return 197 * zero. Otherwise, the sum of the return values is loaded into 198 * the counter of the DrainManager. A pointer to the drain 199 * manager is passed as an argument to the drain() method. | 195 * <li>DrainManager::tryDrain() calls Drainable::drain() for every 196 * object in the system. Draining has completed if all of them 197 * return true. Otherwise, the drain manager keeps track of the 198 * objects that requested draining and waits for them to signal 199 * that they are done draining using the signalDrainDone() method. |
200 * 201 * <li>Continue simulation. When an object has finished draining its 202 * internal state, it calls DrainManager::signalDrainDone() on the | 200 * 201 * <li>Continue simulation. When an object has finished draining its 202 * internal state, it calls DrainManager::signalDrainDone() on the |
203 * manager. When the counter in the manager reaches zero, the 204 * simulation stops. | 203 * manager. The drain manager keeps track of the objects that 204 * haven't drained yet, simulation stops when the set of 205 * non-drained objects becomes empty. |
205 * | 206 * |
206 * <li>Check if any object still needs draining, if so repeat the 207 * process above. | 207 * 208 * (DrainManager::tryDrain()), if so repeat the process above. |
208 * 209 * <li>Serialize objects, switch CPU model, or change timing model. 210 * | 209 * 210 * <li>Serialize objects, switch CPU model, or change timing model. 211 * |
211 * <li>Call Drainable::drainResume() and continue the simulation. | 212 * <li>Call DrainManager::resume(), which intern calls 213 * Drainable::drainResume() for all objects, and continue the 214 * simulation. |
212 * </ol> 213 * 214 */ 215class Drainable 216{ 217 friend class DrainManager; 218 | 215 * </ol> 216 * 217 */ 218class Drainable 219{ 220 friend class DrainManager; 221 |
219 public: | 222 protected: |
220 Drainable(); 221 virtual ~Drainable(); 222 223 /** 224 * Determine if an object needs draining and register a 225 * DrainManager. 226 * | 223 Drainable(); 224 virtual ~Drainable(); 225 226 /** 227 * Determine if an object needs draining and register a 228 * DrainManager. 229 * |
227 * When draining the state of an object, the simulator calls drain 228 * with a pointer to a drain manager. If the object does not need 229 * further simulation to drain internal buffers, it switched to 230 * the Drained state and returns 0, otherwise it switches to the 231 * Draining state and returns the number of times that it will 232 * call Event::process() on the drain event. Most objects are 233 * expected to return either 0 or 1. | 230 * If the object does not need further simulation to drain 231 * internal buffers, it returns true and automatically switches to 232 * the Drained state, otherwise it switches to the Draining state. |
234 * 235 * @note An object that has entered the Drained state can be 236 * disturbed by other objects in the system and consequently be | 233 * 234 * @note An object that has entered the Drained state can be 235 * disturbed by other objects in the system and consequently be |
237 * forced to enter the Draining state again. The simulator 238 * therefore repeats the draining process until all objects return 239 * 0 on the first call to drain(). | 236 * being drained. These perturbations are not visible in the 237 * drain state. The simulator therefore repeats the draining 238 * process until all objects return DrainState::Drained on the 239 * first call to drain(). |
240 * | 240 * |
241 * @param drainManager DrainManager to use to inform the simulator 242 * when draining has completed. 243 * 244 * @return 0 if the object is ready for serialization now, >0 if 245 * it needs further simulation. | 241 * @return DrainState::Drained if the object is ready for 242 * serialization now, DrainState::Draining if it needs further 243 * simulation. |
246 */ | 244 */ |
247 virtual unsigned int drain(DrainManager *drainManager) = 0; | 245 virtual DrainState drain() = 0; |
248 249 /** 250 * Resume execution after a successful drain. | 246 247 /** 248 * Resume execution after a successful drain. |
249 */ 250 virtual void drainResume() {}; 251 252 /** 253 * Signal that an object is drained |
|
251 * | 254 * |
252 * @note This method is normally only called from the simulation 253 * scripts. | 255 * This method is designed to be called whenever an object enters 256 * into a state where it is ready to be drained. The method is 257 * safe to call multiple times and there is no need to check that 258 * draining has been requested before calling this method. |
254 */ | 259 */ |
255 virtual void drainResume(); | 260 void signalDrainDone() const { 261 switch (_drainState) { 262 case DrainState::Running: 263 case DrainState::Drained: 264 return; 265 case DrainState::Draining: 266 _drainState = DrainState::Drained; 267 _drainManager.signalDrainDone(); 268 return; 269 } 270 } |
256 | 271 |
257 DrainState getDrainState() const { return _drainState; } | 272 public: 273 /** Return the current drain state of an object. */ 274 DrainState drainState() const { return _drainState; } |
258 | 275 |
259 protected: 260 void setDrainState(DrainState new_state) { _drainState = new_state; } 261 | |
262 private: | 276 private: |
277 /** DrainManager interface to request a drain operation */ 278 DrainState dmDrain(); 279 /** DrainManager interface to request a resume operation */ 280 void dmDrainResume(); 281 282 /** Convenience reference to the drain manager */ |
|
263 DrainManager &_drainManager; | 283 DrainManager &_drainManager; |
264 DrainState _drainState; | 284 285 /** 286 * Current drain state of the object. Needs to be mutable since 287 * objects need to be able to signal that they have transitioned 288 * into a Drained state even if the calling method is const. 289 */ 290 mutable DrainState _drainState; |
265}; 266 267#endif | 291}; 292 293#endif |