EMMA Coverage Report (generated Sun Feb 05 10:43:15 CET 2012)
[all classes][de.uka.ipd.sdq.measurement.strategies.activeresource]

COVERAGE SUMMARY FOR SOURCE FILE [AbstractDemandStrategy.java]

nameclass, %method, %block, %line, %
AbstractDemandStrategy.java0%   (0/1)0%   (0/26)0%   (0/1149)0%   (0/178)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class AbstractDemandStrategy0%   (0/1)0%   (0/26)0%   (0/1149)0%   (0/178)
$SWITCH_TABLE$de$uka$ipd$sdq$measurement$strategies$activeresource$DegreeOfAc... 0%   (0/1)0%   (0/34)0%   (0/1)
<static initializer> 0%   (0/1)0%   (0/66)0%   (0/5)
AbstractDemandStrategy (int, int, int, int, int): void 0%   (0/1)0%   (0/22)0%   (0/8)
calcRunTimeFunction (long, Amount): Amount 0%   (0/1)0%   (0/7)0%   (0/1)
calibrate (): void 0%   (0/1)0%   (0/67)0%   (0/13)
consume (double): void 0%   (0/1)0%   (0/74)0%   (0/14)
fillTimeFrame (Amount): long [] 0%   (0/1)0%   (0/74)0%   (0/11)
formatDuration (Amount): String 0%   (0/1)0%   (0/75)0%   (0/8)
getAccuracyValue (): int 0%   (0/1)0%   (0/33)0%   (0/10)
getCalibrationCycles (int, Amount): int 0%   (0/1)0%   (0/17)0%   (0/2)
getCalibrationFileName (): String 0%   (0/1)0%   (0/23)0%   (0/2)
getCalibrationPath (): String 0%   (0/1)0%   (0/27)0%   (0/6)
getEpsilon (Amount): Amount 0%   (0/1)0%   (0/15)0%   (0/4)
getRoot (Amount): long 0%   (0/1)0%   (0/5)0%   (0/1)
getRoot (Amount, int): long 0%   (0/1)0%   (0/20)0%   (0/4)
getRootOnce (Amount): long 0%   (0/1)0%   (0/177)0%   (0/23)
getRunTime (long, Amount): Amount 0%   (0/1)0%   (0/65)0%   (0/11)
hasRoot (Amount, Amount): boolean 0%   (0/1)0%   (0/11)0%   (0/1)
hasSameSign (double, double): boolean 0%   (0/1)0%   (0/10)0%   (0/1)
initialiseInterval (Amount, long [], Amount []): void 0%   (0/1)0%   (0/100)0%   (0/14)
initializeStrategy (DegreeOfAccuracyEnum, double): void 0%   (0/1)0%   (0/66)0%   (0/10)
initializeStrategy (DegreeOfAccuracyEnum, double, String): void 0%   (0/1)0%   (0/17)0%   (0/5)
mean (long []): long 0%   (0/1)0%   (0/41)0%   (0/6)
recalibrate (long, int): Amount 0%   (0/1)0%   (0/13)0%   (0/2)
setProperties (Properties): void 0%   (0/1)0%   (0/4)0%   (0/2)
watchConsume (double): void 0%   (0/1)0%   (0/86)0%   (0/14)

1package de.uka.ipd.sdq.measurement.strategies.activeresource;
2 
3import java.io.File;
4import java.util.Arrays;
5import java.util.Properties;
6 
7import javax.measure.quantity.Dimensionless;
8import javax.measure.quantity.Duration;
9import javax.measure.quantity.Quantity;
10import javax.measure.unit.BaseUnit;
11import javax.measure.unit.NonSI;
12import javax.measure.unit.ProductUnit;
13import javax.measure.unit.SI;
14import javax.measure.unit.Unit;
15 
16import org.apache.log4j.Logger;
17import org.jscience.physics.amount.Amount;
18 
19/**
20 * Abstract superclass of all active demand strategies.
21 * 
22 * c.f.: Steffen Becker, Tobias Dencker, and Jens Happe. 
23 *       Model-Driven Generation of Performance Prototypes. 
24 *       In Performance Evaluation: Metrics, Models and Benchmarks (SIPEW 2008), volume 5119 of Lecture Notes in Computer Science, pages 79-98. 
25 *       Springer-Verlag Berlin Heidelberg, 2008.
26 * 
27 * @author Tobias Denker, Anne Koziolek, Steffen Becker, Thomas Zolynski
28 */
29public abstract class AbstractDemandStrategy implements IDemandStrategy {
30        
31        private static final int RIGHT_ENDPOINT = 1;
32 
33        private static final int LEFT_ENDPOINT = 0;
34 
35        public static final Unit<Work> WORKUNITS = new BaseUnit<Work>("WU");
36        public interface Work extends Quantity {
37                public static final Unit<Work> UNIT = WORKUNITS;
38        }
39        
40        public interface ProcessingRate extends Quantity {
41                public static final Unit<ProcessingRate> UNIT = new ProductUnit<ProcessingRate>(Work.UNIT.divide(SI.SECOND));
42        }
43        
44        public static final String CALIBRATION_PATH_CONFIG_KEY = "CalibrationPath";
45 
46        private static final int MIN_CALIBRATION_CYCLES = 5;
47 
48        private CalibrationTable calibrationTable; 
49        
50        private static final Amount<Duration> ONE_MILLISECOND = Amount.valueOf(1,SI.MILLI(SI.SECOND));
51 
52        private static final int DEFAULT_ACCURACY = 8;
53 
54        private final int warmUpCycles;
55        
56        /** Modifier for low, medium and high calibration.  */
57        private final int low, medium, high;
58 
59        /** Iteration count for calibration */
60        protected long defaultIterationCount;
61        
62        private Properties properties;
63 
64        private Amount<ProcessingRate> processingRate;
65 
66        private File configFile = null;
67 
68        protected DegreeOfAccuracyEnum degreeOfAccuracy;
69        private static Logger logger = Logger.getLogger(AbstractDemandStrategy.class.getName());
70 
71        private static final String CONFIG_PATH = "./conf/";
72 
73        // define constants
74        private static final int[] CALIBRATION_CYCLES = { 1024, 512, 256, 128, 64, 50, 40, 30, 25, 20, 15, 10 };
75 
76        /** Amount of outlier when calculating the mean. elements/OUTLIER_RATE of lowest and highest values are discarded */
77        private static final int OUTLIER_RATE = 5;
78        
79        /**
80         * Constructor. Configures a demand strategy with low, medium and high modifier, as well 
81         * as number of standard and warm-up cycles
82         *  
83         * @param low                accuracy modifier for low precision calibration
84         * @param medium        accuracy modifier for medium precision calibration
85         * @param high                accuracy modifier for high precision calibration
86         * @param iterationCount
87         * @param warmups
88         */
89        public AbstractDemandStrategy(int low, int medium, int high, int iterationCount, int warmups) {
90                super();
91                
92                /**
93                 * Initialise the calibration algorithm's parameter set
94                 */
95                this.low = low; 
96                this.medium = medium;
97                this.high = high;
98                this.defaultIterationCount = iterationCount; 
99                this.warmUpCycles = warmups;
100        }
101        
102        /**
103         * @see IDemandStrategy#initializeStrategy(DegreeOfAccuracyEnum, double)
104         */
105        @Override
106        public void initializeStrategy(DegreeOfAccuracyEnum degree, double initProcessingRate) {
107                logger.info("Initialising " + getName() + " " + getStrategysResource().name() + "  strategy with accuracy "+degree.name());
108                
109                this.degreeOfAccuracy = degree;
110                this.processingRate = Amount.valueOf(initProcessingRate,ProcessingRate.UNIT);
111                this.configFile = new File(getCalibrationFileName());
112 
113                CalibrationTable loadedCalibration = CalibrationTable.load(configFile);
114 
115                if (loadedCalibration != null) {
116                        calibrationTable = loadedCalibration;
117 
118                } else {
119                        calibrate();
120                }
121                logger.debug(getName() + " " + getStrategysResource().name() + " strategy initialised");
122        }
123 
124        /**
125         * @see IDemandStrategy#initializeStrategy(DegreeOfAccuracyEnum, double, String)
126         */
127        @Override
128        public void initializeStrategy(DegreeOfAccuracyEnum degreeOfAccuracy, double processingRate, String calibrationPath) {
129                Properties props = new Properties();
130                props.setProperty(CALIBRATION_PATH_CONFIG_KEY, calibrationPath);
131                setProperties(props);
132                
133                initializeStrategy(degreeOfAccuracy, processingRate);
134        }
135 
136        /**
137         * @see IDemandStrategy#setProperties(Properties)
138         */
139        @Override
140        public void setProperties(Properties properties) {
141                this.properties = properties;
142        }
143 
144        /**
145         * @see IDemandStrategy#consume(double)
146         */
147        @Override
148        public void consume(double demand) {
149                if (calibrationTable == null) {
150                        logger.fatal("No calibration found - STRATEGY HAS TO BE INITIALIZED FIRST!");
151                        throw new RuntimeException("No calibration found - STRATEGY HAS TO BE INITIALIZED FIRST!");
152                }
153        
154                Amount<Work> demandedWork = Amount.valueOf(demand,Work.UNIT);
155                Amount<Duration> millisec = demandedWork.divide(processingRate).to(SI.SECOND);
156                if (logger.isDebugEnabled()) {
157                        logger.debug("Consume called, demand is : " + demandedWork + ", " + millisec);
158                }
159                
160                long[] factors = fillTimeFrame(millisec);
161        
162                for (int i = 0; i < factors.length; i++) {
163                        long loopCount = factors[i];
164                        for (int j = 0; j < loopCount; j++) {
165                                run(calibrationTable.getEntry(i).getParameter());
166                        }
167                }
168                logger.debug("Demand consumed");
169        }
170 
171        /**
172         * Template method to return the real hardware resource type simulated by this strategy
173         * @see de.uka.ipd.sdq.measurement.strategies.activeresource.IDemandStrategy#getStrategysResource()
174         */
175        public abstract ResourceTypeEnum getStrategysResource();
176 
177        /**
178         * Template method to return the name of this strategy
179         * @see de.uka.ipd.sdq.measurement.strategies.activeresource.IDemandStrategy#getName()
180         */
181        public abstract String getName();
182 
183        /** Returns the name of the file used to store the calibration table
184         * Filename depends on paramters of this class
185         * @return The calibration table file name
186         */
187        protected String getCalibrationFileName() {
188                return getCalibrationPath() + getName() + "_"
189                                + CalibrationTable.DEFAULT_CALIBRATION_TABLE_SIZE + "_" + this.degreeOfAccuracy.name() + ".ser";
190        }
191 
192        /**
193         * Query the calibration path from the properties of this object
194         * @return The file system path used to load and store the calibration data, or the current working directory if it is not set
195         */
196        protected String getCalibrationPath() {
197                String result = null;
198                
199                // Test whether properties have been set externally
200                if (properties != null) {
201                        result = properties.getProperty(CALIBRATION_PATH_CONFIG_KEY);
202                        if ((result != null) && (!result.equals(""))) {
203                                return result + "/";
204                        }
205                }
206                
207                return CONFIG_PATH;
208        }
209 
210        /**
211         * Template method. This starts running the strategy with the parameter load
212         * @param load Complexity parameter. Algorithm should take longer if parameter is larger,
213         * i.e., ideally run(a) < run(b) <==> a < b
214         */
215        protected abstract void run(long load);
216 
217        /**
218         * Create a new calibration table for this host by measuring the execution times of
219         * our algorithm and creating an according calibration table
220         */
221        private void calibrate() {
222                this.calibrationTable = new CalibrationTable();
223                
224                for (int i = 0; i < warmUpCycles; i++) {
225                        run(defaultIterationCount);
226                }
227 
228                logger.info("The timetable with the corresponding parameters:");
229                for (int i = 0; i < calibrationTable.size(); i++) {
230                        Amount<Duration> targetTime = Amount.valueOf(1 << i,SI.MILLI(SI.SECOND));
231                        long parameter = getRoot(targetTime);
232                        
233                        if (i > 2) { //TODO: Why 2?
234                                //TODO: This is smart, but absolutely not maintainable...
235                                targetTime = recalibrate(parameter, i);
236                        }
237                        
238                        calibrationTable.addEntry(i, targetTime, parameter);
239                        logger.info(calibrationTable.getEntry(i));
240                }
241                calibrationTable.save(configFile);
242        }
243 
244        /**
245         * Iteratively approximates the best input value to reach a specified execution time.
246         * Let the result of this method be parameter. Then this method determines a parameter, 
247         * s.t. exec_alg(parameter) = targetTime 
248         * 
249         * The accepted tolerance is one millisecond.
250         * 
251         * @param targetTime        target time in milliseconds
252         * @return exec_alg^(-1)(targetTime)
253         */
254        private long getRoot(Amount<Duration> targetTime) {
255                final int numberOfRepetitions = 2; // TODO: Why 2? Configurable?
256                return getRoot(targetTime, numberOfRepetitions);
257        }
258        
259        /**
260         * Iteratively approximates the best input value to reach a specified execution time.
261         * Let the result of this method be parameter. Then this method determines a parameter, 
262         * s.t. exec_alg(parameter) = targetTime 
263         * 
264         * The accepted tolerance is one millisecond.
265         * 
266         * @param targetTime        target time in milliseconds
267         * @param numberOfRepetitions number of times the algorithm determines the root. This is needed 
268         *                                                 as the function is only approximated by running measurements
269         * @return exec_alg^(-1)(targetTime)
270         */
271        private long getRoot(Amount<Duration> targetTime, int numberOfRepetitions) {
272                // approximated parameters
273                long[] targetParameter = new long[numberOfRepetitions];
274 
275                // run a couple of times and calculate mean
276                for (int i = 0; i < numberOfRepetitions; i++) {
277                        targetParameter[i] = getRootOnce(targetTime);
278                }
279                return mean(targetParameter);
280        }
281 
282        /**
283         * Mathematical root finding algorithm. Calculation based on bisection method.
284         * 
285         * @param targetTime
286         * @return root
287         */
288        private long getRootOnce(Amount<Duration> targetTime) {
289                long[] intervalEndpoints = new long[2];
290                Amount<Duration>[] intervalFunctionValues = new Amount[2];
291            initialiseInterval(targetTime,intervalEndpoints,intervalFunctionValues);
292                if (!hasRoot(intervalFunctionValues[LEFT_ENDPOINT], intervalFunctionValues[RIGHT_ENDPOINT]) || intervalFunctionValues[LEFT_ENDPOINT].isGreaterThan(intervalFunctionValues[RIGHT_ENDPOINT])) { 
293                        logger.error("PROBLEM: No root found. Special algorithm"
294                                                        + " without monotonically increasing load !?!");
295                        logger.error("f_n_left = "+intervalFunctionValues[LEFT_ENDPOINT]);
296                        logger.error("f_n_right = " +intervalFunctionValues[RIGHT_ENDPOINT]);
297                        throw new RuntimeException("PROBLEM: No root found. Special algorithm"
298                                        + " without monotonically increasing load !?!");
299                } 
300                
301                logger.debug("--- Running bisection method ----");
302                Amount<Duration> epsilon = getEpsilon(targetTime);
303                while (Math.abs(intervalEndpoints[LEFT_ENDPOINT]-intervalEndpoints[RIGHT_ENDPOINT]) > 2 && 
304                                intervalFunctionValues[RIGHT_ENDPOINT].minus(intervalFunctionValues[LEFT_ENDPOINT]).abs().isLargerThan(epsilon)) {
305                        if (logger.isDebugEnabled()) {
306                                logger.debug("["+intervalEndpoints[LEFT_ENDPOINT]+", "+intervalEndpoints[RIGHT_ENDPOINT]+"] --> "+
307                                                "["+formatDuration(intervalFunctionValues[LEFT_ENDPOINT])+", "+formatDuration(intervalFunctionValues[RIGHT_ENDPOINT])+"]");
308                        }
309                        long intervalMedian = (intervalEndpoints[LEFT_ENDPOINT] + intervalEndpoints[RIGHT_ENDPOINT]) / 2;
310                        Amount<Duration> f_n_median = calcRunTimeFunction(intervalMedian, targetTime);
311                        if (hasSameSign(intervalFunctionValues[LEFT_ENDPOINT].getEstimatedValue(), f_n_median.getEstimatedValue())) {
312                                intervalEndpoints[LEFT_ENDPOINT] = intervalMedian;
313                                intervalFunctionValues[LEFT_ENDPOINT] = f_n_median;
314                        } else {
315                                intervalEndpoints[RIGHT_ENDPOINT] = intervalMedian;
316                                intervalFunctionValues[RIGHT_ENDPOINT] = f_n_median;
317                        }
318                }
319                return (intervalEndpoints[LEFT_ENDPOINT] + intervalEndpoints[RIGHT_ENDPOINT]) / 2;
320        
321        }
322 
323        private Amount<Duration> getEpsilon(Amount<Duration> targetTime) {
324                Amount<Duration> result = targetTime.times(0.01d);
325                if (result.to(SI.MILLI(SI.SECOND)).isGreaterThan(ONE_MILLISECOND))
326                        return ONE_MILLISECOND;
327                return result;
328        }
329 
330        /**
331         * @param a
332         * @param b
333         * @return true if a and b have the same sign
334         */
335        private boolean hasSameSign(double a, double b) {
336                return a * b > 0;
337        }
338 
339        
340        private Amount<Duration> recalibrate(long parameter, int index) {
341                int cycles = CALIBRATION_CYCLES[index];
342                return getRunTime(parameter, Amount.valueOf(cycles,SI.MILLI(SI.SECOND)));
343        }
344        
345        /**
346         * The initial value of f(n_right) has to be greater than 0.
347         * 
348         * @param targetTime
349         * @return n_right with f(n_right) > 0
350         */
351        private void initialiseInterval(Amount<Duration> targetTime, long[] intervalEndpoints, Amount<Duration>[] intervalFunctionValues) {
352                if (logger.isDebugEnabled()){
353                        logger.debug("Find inital interval for target time "+formatDuration(targetTime));
354                }
355                long z = 0;
356                do {
357                        intervalEndpoints[LEFT_ENDPOINT] = intervalEndpoints[RIGHT_ENDPOINT];
358                        intervalFunctionValues[LEFT_ENDPOINT] = intervalFunctionValues[RIGHT_ENDPOINT];
359                        intervalEndpoints[RIGHT_ENDPOINT] = z * defaultIterationCount; 
360                        intervalFunctionValues[RIGHT_ENDPOINT] = calcRunTimeFunction(intervalEndpoints[RIGHT_ENDPOINT], targetTime);
361                        z = z == 0 ? 1 : z << 1;
362                        if (logger.isDebugEnabled()) {
363                                logger.debug("["+intervalEndpoints[LEFT_ENDPOINT]+", "+intervalEndpoints[RIGHT_ENDPOINT]+"] --> "+
364                                                "["+formatDuration(intervalFunctionValues[LEFT_ENDPOINT])+", "+formatDuration(intervalFunctionValues[RIGHT_ENDPOINT])+"]");
365                        }
366                } while (intervalFunctionValues[RIGHT_ENDPOINT].isLessThan(Amount.valueOf(0L, SI.SECOND)));
367        }
368 
369        /**
370         * Checks whether there is a root (Nullstelle) between the two function values
371         * @param f_n_left Left interval end point function value
372         * @param f_n_right Right interval end point function value
373         * @return true if there is a root between the two function values
374         */
375        private boolean hasRoot(Amount<Duration> f_n_left, Amount<Duration> f_n_right) {
376                return (!hasSameSign(f_n_left.getEstimatedValue(), f_n_right.getEstimatedValue()));
377        }
378 
379 
380        /**
381         * Derives a function f(n) = exec_alg(n) - targetTime, whose root is at 
382         * targetTime, i.e, f(targetTime) = 0
383         *  
384         * @param parameter
385         * @param targetTime
386         * @return
387         */
388        private Amount<Duration> calcRunTimeFunction(long parameter, Amount<Duration> targetTime) {
389                return getRunTime(parameter, targetTime).minus(targetTime);
390        }
391 
392        /**
393         * Returns mean algorithm run time depending on the parameter. The approximation 
394         * accuracy of the algorithm run time depends on the targetTime. For small 
395         * targetTime several approximation cycles are executed and their mean is returned. 
396         * For larger targetTime just a single cycle is executed.
397         * 
398         * @param parameter                characterising parameter of the load generating algorithm
399         * @param targetTime        target time (used to determine approximation accuracy, s.a.)
400         * @return approximated run time in nanoseconds, i.e., exec_alg(parameter)
401         */
402        private Amount<Duration> getRunTime(long parameter, Amount<Duration> targetTime) {
403                int cycles = getCalibrationCycles(getAccuracyValue(), targetTime);
404 
405                long[] approximation = new long[cycles];
406                
407                for (int i = 0; i < cycles; i++) {
408                        if (logger.isTraceEnabled()) {
409                                logger.trace("Measuring calibration run " + i + " of " + cycles);
410                        }
411                        long start = System.nanoTime();
412                        run(parameter);
413                        approximation[i] = (System.nanoTime() - start);
414                }
415                
416                long mean = mean(approximation);
417                logger.debug("Mean time for parameter " + parameter + " is " + mean);
418                return Amount.valueOf(mean,SI.NANO(SI.SECOND));
419        }
420 
421        /**
422         * Calculates mean value of array p. If p has more than five elements, the lowest 
423         * and highest 'length / OUTLIER_RATE' are removed.
424         * 
425         * @param p                array of numbers
426         * @return                mean value
427         */
428        private long mean(long[] p) {
429                long sum = 0; 
430                Arrays.sort(p);
431                int start = p.length > OUTLIER_RATE ? p.length / OUTLIER_RATE : 0;
432                for (int i = start; i < p.length - start; i++) {
433                        sum += p[i];
434                }
435 
436                return sum / (p.length - start * 2);
437        }
438 
439        /**
440         * Returns number of iterations to calculate the mean from. It is aimed
441         * at being reverse proportional to the targetTime.
442         * 
443         * For long target times only one cycle will be executed.
444         * Example: MEDIUM accuracy: Exponent = DEFAULT_ACCURACY (8) + 0 = 8
445         *                           TargetTime >= 2^8 => len = 1
446         *                                      <  2^8 => len = 2^8/TargetTime
447     *
448         * @param exponent
449         * @param targetTime
450         * @return
451         */
452        private int getCalibrationCycles(int exponent, Amount<Duration> targetTime) {
453                Amount<Duration> threshold = Amount.valueOf(1 << exponent,SI.MILLI(SI.SECOND));
454        
455                return Math.max((int)Math.floor(threshold.divide(targetTime).getEstimatedValue()), MIN_CALIBRATION_CYCLES);
456        }
457 
458        /**
459         * Maps an accuracy (LOW, MEDIUM, HIGH) to the values specified during the 
460         * configuration (in the constructor).
461         * 
462         * @return                        accuracy modifier
463         */
464        private int getAccuracyValue() {
465                int result = DEFAULT_ACCURACY;
466                
467                switch(this.degreeOfAccuracy) {
468                case HIGH:
469                        result += high;
470                        break;
471                case MEDIUM:
472                        result += medium;
473                        break;
474                case LOW:
475                        result += low;
476                        break;
477                default:
478                        throw new IllegalArgumentException("Unsupported degree of accuracy");
479                }
480                return result;
481        }
482        
483        /**
484         * Computes a vector of (scaling) factors for each entry in the 
485         * calibration table. These factors give the number of repetitions 
486         * of each of the calibration entries to reach a given target time.  
487         * Use greedy strategy to fill time frame with smaller run times
488         * 
489         * @param millisec The target time to factorise
490         * @return An array of scaling factors for the calibration table entries
491         */
492        private long[] fillTimeFrame(Amount<Duration> millisec) {
493                long[] result = new long[CalibrationTable.DEFAULT_CALIBRATION_TABLE_SIZE];
494                Amount<Duration> sum = millisec;
495 
496                for (int i = CalibrationTable.DEFAULT_CALIBRATION_TABLE_SIZE - 1; i >= 0; i--) {
497                        CalibrationEntry calibrationEntry = calibrationTable.getEntry(i);
498                        
499                        result[i] = (long) Math.floor(((Amount<Dimensionless>) (sum.divide(calibrationEntry.getTargetTime())).to(Unit.ONE)).getEstimatedValue());
500                        if (result[i] >= 1) {
501                                sum = sum.minus(calibrationEntry.getTargetTime().times(result[i]));
502                        }
503                        if (logger.isTraceEnabled()) {
504                                logger.trace(formatDuration(calibrationEntry.getTargetTime()) + " | "
505                                                    + calibrationEntry.getParameter() + " | " + result[i] + "|" + formatDuration(sum));
506                        }
507                }
508                return result;
509        }
510 
511        /**
512         * Consumes demands (only used for testing purpose!)
513         * @param demand
514         */
515        @Deprecated
516        public void watchConsume(double demand) {
517                final int repetitionCount = 10;
518                if (calibrationTable == null) {
519                        logger.fatal("No calibration found - STRATEGY HAS TO BE INITIALIZED FIRST!");
520                        throw new RuntimeException("No calibration found - STRATEGY HAS TO BE INITIALIZED FIRST!");
521                }
522 
523                Amount<Work> demandedWork = Amount.valueOf(demand,Work.UNIT);
524                Amount<Duration> expectedTime = demandedWork.divide(processingRate).to(SI.SECOND);
525                logger.info("Request issued to consume " + demandedWork);
526                logger.info("Expected duration is " + formatDuration(expectedTime));
527                long theTime = System.nanoTime();
528        
529                for (int h = 0; h < repetitionCount; h++) {
530                        consume(demand);
531                }
532                Amount<Duration> measuredTime = Amount.valueOf((System.nanoTime() - theTime) / repetitionCount,SI.NANO(SI.SECOND));
533                logger.info("Demand of "+formatDuration(expectedTime)+" consumed at an average value of " + formatDuration(measuredTime)
534                                + ". Abs. difference is "+formatDuration(measuredTime.minus(expectedTime).abs()));
535        }
536        
537        @SuppressWarnings("unchecked")
538        public static String formatDuration(Amount<Duration> t) {
539                if (t == null)
540                        return "null";
541                
542                Unit<Duration>[] units = new Unit[] {SI.NANO(SI.SECOND), SI.MICRO(SI.SECOND), SI.MILLI(SI.SECOND), SI.SECOND, NonSI.MINUTE, NonSI.HOUR};
543                for (Unit<Duration> u : units) {
544                        double value = t.to(u).getEstimatedValue();
545                        if (Math.abs(value) < 1000) {
546                                return value + " " + u;
547                        }
548                }
549                return t.toText().toString();
550        }
551}

[all classes][de.uka.ipd.sdq.measurement.strategies.activeresource]
EMMA 2.0.9414 (unsupported private build) (C) Vladimir Roubtsov