001/* A extension of the SDFScheduler that caches the schedules. 002 003 Copyright (c) 2006-2014 The Regents of the University of California. 004 All rights reserved. 005 Permission is hereby granted, without written agreement and without 006 license or royalty fees, to use, copy, modify, and distribute this 007 software and its documentation for any purpose, provided that the above 008 copyright notice and the following two paragraphs appear in all copies 009 of this software. 010 011 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY 012 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 013 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF 014 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF 015 SUCH DAMAGE. 016 017 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, 018 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 019 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE 020 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF 021 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, 022 ENHANCEMENTS, OR MODIFICATIONS. 023 PT_COPYRIGHT_VERSION_2 024 COPYRIGHTENDKEY 025 026 */ 027package ptolemy.domains.sdf.kernel; 028 029import java.util.ArrayList; 030import java.util.HashMap; 031import java.util.Iterator; 032import java.util.LinkedList; 033import java.util.List; 034import java.util.Map; 035import java.util.TreeMap; 036 037import ptolemy.actor.Actor; 038import ptolemy.actor.CompositeActor; 039import ptolemy.actor.Director; 040import ptolemy.actor.IOPort; 041import ptolemy.actor.sched.NotSchedulableException; 042import ptolemy.actor.sched.Schedule; 043import ptolemy.actor.util.DFUtilities; 044import ptolemy.kernel.util.IllegalActionException; 045import ptolemy.kernel.util.NameDuplicationException; 046import ptolemy.kernel.util.Workspace; 047 048/////////////////////////////////////////////////////////////////// 049//// CachedSDFScheduler 050 051/** 052 The CachedSDFScheduler extends the SDFScheduler by caching schedules. 053 The cached schedules are labeled by their corresponding rate signatures, 054 with the most recently used at the beginning of the cache queue. If the 055 rate signatures are contained in the cache keys, then the corresponding 056 schedule in the cache is used. Therefore, we do not need to recompute the 057 schedule again. 058 <p> 059 The size of the cache in the CachedSDFScheduler is usually set by its 060 containing director when constructing this scheduler. If the cache is 061 full, the least recently used schedule (at the end of the cache) is 062 discarded. 063 064 @see SDFScheduler 065 066 @author Ye Zhou. Contributor: Brian K. Vogel 067 @version $Id$ 068 @since Ptolemy II 5.2 069 @Pt.ProposedRating Red (zhouye) 070 @Pt.AcceptedRating Red (cxh) 071 */ 072public class CachedSDFScheduler extends SDFScheduler { 073 /** Construct a scheduler with no container(director) 074 * in the default workspace, the name of the scheduler is 075 * "Scheduler". The cache size is the default value of 0. 076 */ 077 public CachedSDFScheduler() { 078 super(); 079 constructCaches(0); 080 } 081 082 /** Construct a scheduler in the given workspace with the name 083 * "Scheduler". The cache size is the default value of 0. 084 * If the workspace argument is null, use the default workspace. 085 * The scheduler is added to the list of objects in the workspace. 086 * Increment the version number of the workspace. 087 * 088 * @param workspace Object for synchronization and version tracking. 089 */ 090 public CachedSDFScheduler(Workspace workspace) { 091 super(workspace); 092 constructCaches(0); 093 } 094 095 /** Construct a scheduler in the given container with the given name 096 * and given cache size. The container argument must not be null, or a 097 * NullPointerException will be thrown. This attribute will use the 098 * workspace of the container for synchronization and version counts. 099 * If the name argument is null, then the name is set to the empty string. 100 * Increment the version of the workspace. 101 * @param container The container. 102 * @param name The name of this attribute. 103 * @param cacheSize The cache size of this scheduler. 104 * @exception IllegalActionException If the super class throws it. 105 * @exception NameDuplicationException If the super class throws it. 106 */ 107 public CachedSDFScheduler(Director container, String name, int cacheSize) 108 throws IllegalActionException, NameDuplicationException { 109 super(container, name); 110 constructCaches(cacheSize); 111 } 112 113 /////////////////////////////////////////////////////////////////// 114 //// public methods //// 115 116 /** Clear the schedule cache, cache keys and cache for external rates 117 * of this scheduler. 118 */ 119 public void clearCaches() { 120 if (_cacheSize > 0) { 121 _scheduleKeyList.clear(); 122 } 123 124 _scheduleCache.clear(); 125 _externalRatesCache.clear(); 126 _mostRecentRates = ""; 127 } 128 129 /** Construct the caches of this scheduler with the given cache size. 130 * @param cacheSize The given cache sie. 131 */ 132 public void constructCaches(int cacheSize) { 133 _scheduleCache = new HashMap(); 134 135 if (cacheSize > 0) { 136 _scheduleKeyList = new ArrayList(cacheSize); 137 } 138 139 _externalRatesCache = new TreeMap(); 140 _cacheSize = cacheSize; 141 } 142 143 /////////////////////////////////////////////////////////////////// 144 //// protected methods //// 145 146 /** Return the scheduling sequence. If the schedule exist in the 147 * cache (schedules are identified by the rate signatures of ports), 148 * then return the corresponding schedule in the cache. Otherwise, 149 * compute the schedule and return it. 150 * @return A schedule of the deeply contained opaque entities 151 * in the firing order. 152 * @exception NotSchedulableException If the super class throws it. 153 * @exception IllegalActionException If the super class throws it. 154 */ 155 @Override 156 protected Schedule _getSchedule() 157 throws NotSchedulableException, IllegalActionException { 158 Schedule schedule; 159 160 if (_inputPortList == null 161 || _workspaceVersion != workspace().getVersion()) { 162 _inputPortList = _getInputPortList(); 163 } 164 165 if (_outputPortList == null 166 || _workspaceVersion != workspace().getVersion()) { 167 _outputPortList = _getOutputPortList(); 168 } 169 170 _workspaceVersion = workspace().getVersion(); 171 172 StringBuffer rates = new StringBuffer(); 173 174 Iterator inputPorts = _inputPortList.iterator(); 175 176 while (inputPorts.hasNext()) { 177 IOPort inputPort = (IOPort) inputPorts.next(); 178 int rate = DFUtilities.getTokenConsumptionRate(inputPort); 179 rates.append(rate); 180 181 int initRate = DFUtilities.getTokenInitConsumption(inputPort); 182 rates.append("_"); 183 rates.append(initRate); 184 } 185 186 Iterator outputPorts = _outputPortList.iterator(); 187 188 while (outputPorts.hasNext()) { 189 IOPort outputPort = (IOPort) outputPorts.next(); 190 int rate = DFUtilities.getTokenProductionRate(outputPort); 191 rates.append(rate); 192 193 int initRate = DFUtilities.getTokenInitProduction(outputPort); 194 rates.append("_"); 195 rates.append(initRate); 196 } 197 198 String rateKey = rates.toString(); 199 200 if (_scheduleCache.containsKey(rateKey)) { 201 // cache hit. 202 schedule = (Schedule) _scheduleCache.get(rateKey); 203 204 if (!rateKey.equals(_mostRecentRates)) { 205 _mostRecentRates = rateKey; 206 207 if (_cacheSize > 0) { 208 // Remove the key from its old position in 209 // the list and add it to the head of the list. 210 _scheduleKeyList.remove(rateKey); 211 _scheduleKeyList.add(0, rateKey); 212 } 213 214 Map externalRates = (Map) _externalRatesCache.get(rateKey); 215 _saveContainerRates(externalRates); 216 } 217 } else { 218 // cache miss. 219 _mostRecentRates = rateKey; 220 221 if (_cacheSize > 0) { 222 while (_scheduleKeyList.size() >= _cacheSize) { 223 // Cache is full. Remove the end of the caches. 224 Object key = _scheduleKeyList.get(_cacheSize - 1); 225 _scheduleKeyList.remove(_cacheSize - 1); 226 _scheduleCache.remove(key); 227 _externalRatesCache.remove(key); 228 } 229 230 // Add key to head of list. 231 _scheduleKeyList.add(0, rateKey); 232 } 233 234 // Compute the SDF schedule. 235 schedule = super._getSchedule(); 236 237 // Add key/schedule to the schedule map. 238 _scheduleCache.put(rateKey, schedule); 239 240 // Add external rates map to the external rates cache. 241 Map externalRates = getExternalRates(); 242 _externalRatesCache.put(rateKey, externalRates); 243 244 // Note: we do not need to set the external rates of 245 // the container here. When the SDFSchedule is recomputed, 246 // it will set the external rates. 247 } 248 249 setValid(true); 250 return schedule; 251 } 252 253 /////////////////////////////////////////////////////////////////// 254 //// private methods //// 255 256 /** Return a list of all the input ports contained by the 257 * deeply contained entities of the container of this director. 258 * @return The list of input ports. 259 */ 260 private List _getInputPortList() { 261 CompositeActor container = (CompositeActor) getContainer() 262 .getContainer(); 263 List actors = container.deepEntityList(); 264 Iterator actorIterator = actors.iterator(); 265 List inputPortList = new LinkedList(); 266 267 while (actorIterator.hasNext()) { 268 Actor containedActor = (Actor) actorIterator.next(); 269 List temporaryInputPortList = containedActor.inputPortList(); 270 Iterator inputPortIterator = temporaryInputPortList.iterator(); 271 272 while (inputPortIterator.hasNext()) { 273 IOPort inputPort = (IOPort) inputPortIterator.next(); 274 inputPortList.add(inputPort); 275 } 276 } 277 278 return inputPortList; 279 } 280 281 /** Return a list of all the output ports contained by the 282 * deeply contained entities of the container of this director. 283 * @return The list of output ports. 284 */ 285 private List _getOutputPortList() { 286 CompositeActor container = (CompositeActor) getContainer() 287 .getContainer(); 288 List actors = container.deepEntityList(); 289 Iterator actorIterator2 = actors.iterator(); 290 List outputPortList = new LinkedList(); 291 292 while (actorIterator2.hasNext()) { 293 Actor containedActor = (Actor) actorIterator2.next(); 294 List temporaryOutputPortList = containedActor.outputPortList(); 295 Iterator outputPortIterator = temporaryOutputPortList.iterator(); 296 297 while (outputPortIterator.hasNext()) { 298 IOPort outputPort = (IOPort) outputPortIterator.next(); 299 outputPortList.add(outputPort); 300 } 301 } 302 303 return outputPortList; 304 } 305 306 /////////////////////////////////////////////////////////////////// 307 //// private variables //// 308 // The size of the cache. 309 private int _cacheSize; 310 311 // Map for the schedule cache. 312 private Map _scheduleCache; 313 314 // List of the schedule keys, which are strings that represent 315 // the rate signature. 316 private List _scheduleKeyList; 317 318 // Map for the cache of the external rates. 319 private Map _externalRatesCache; 320 321 // A string that represents the most recent port rates. 322 private String _mostRecentRates; 323 324 // A list of the input ports. 325 private List _inputPortList; 326 327 // A list of the output ports. 328 private List _outputPortList; 329 330 // Local workspace version 331 private long _workspaceVersion = 0; 332}