SystemManager.java 18.7 KB
Newer Older
1 2
package mvd.jester.model;

3
import java.math.RoundingMode;
4
import java.util.HashSet;
5
import java.util.LinkedHashSet;
6 7
import java.util.Map;
import java.util.Optional;
8 9
import java.util.Set;
import java.util.concurrent.ThreadLocalRandom;
10 11
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
12 13
import com.google.common.math.LongMath;
import org.apache.commons.math3.distribution.GammaDistribution;
14 15
import org.jgrapht.experimental.dag.DirectedAcyclicGraph;
import org.jgrapht.graph.DefaultEdge;
16
import mvd.jester.utils.DagUtils;
17
import mvd.jester.model.SystemManager.Builder;
18 19 20 21

/**
 * TaskSet
 */
22
public class SystemManager<T extends Builder> implements SystemManagerInterface {
23

24 25 26 27 28 29 30 31
    private final T builder;

    public SystemManager(Class<T> builder) {
        try {
            this.builder = builder.getDeclaredConstructor().newInstance();
        } catch (Exception e) {
            throw new RuntimeException("Builder could not be instantiated!");
        }
32 33 34 35 36 37
    }

    /**
     * @return the numberOfProcessors
     */
    public long getNumberOfProcessors() {
38
        return builder.getNumberOfProcessors();
39 40
    }

Michael Schmid committed
41 42 43 44
    /**
     * @param numberOfProcessors the numberOfProcessors to set
     */
    public void setNumberOfProcessors(long numberOfProcessors) {
45 46 47 48 49 50 51 52 53 54 55 56 57
        builder.setNumberOfProcessors(numberOfProcessors);
    }

    public T getBuilder() {
        return builder;
    }

    public static interface Builder {

        public long getNumberOfProcessors();

        public Builder setNumberOfProcessors(long numberOfProcessors);

58 59
    }

60
    public static class SynchronousTaskBuilder implements Builder {
61 62
        private long numberOfProcessors = 4;
        private long minPeriod = 100;
Michael Schmid committed
63 64
        private long maxSequentialPeriod = 1000;
        private long maxParallelPeriod = 10000;
65 66 67 68
        private long minNumberOfSegments = 3;
        private long maxNumberOfSegments = 7;
        private long minNumberOfJobs = 2;
        private long maxNumberOfJobs = 3 * numberOfProcessors / 2;
69
        private final long minWcet = 1;
70
        private long ratio = randomTaskRatio(this.parallelTaskRatio);
71
        private final long parallelTaskRatio = 0;
72

73
        public SynchronousTaskBuilder() {
74 75
        }

Michael Schmid committed
76 77 78 79 80 81
        private long randomSequentialTaskPeriod() {
            return ThreadLocalRandom.current().nextLong(minPeriod, maxSequentialPeriod);
        }

        private long randomParallelTaskPeriod() {
            return ThreadLocalRandom.current().nextLong(minPeriod, maxParallelPeriod);
82 83
        }

84
        private long randomTaskRatio(final long min) {
85
            return ThreadLocalRandom.current().nextLong(min, 100);
86 87 88 89 90 91 92
        }

        private long randomNumberOfSegments() {
            return ThreadLocalRandom.current().nextLong(minNumberOfSegments, maxNumberOfSegments);
        }

        private long randomNumberOfJobs() {
93
            this.maxNumberOfJobs = 3 * this.numberOfProcessors / 2;
94 95 96
            return ThreadLocalRandom.current().nextLong(minNumberOfJobs, maxNumberOfJobs);
        }

97 98
        private long randomWcet(final long period, final long numberOfSegments) {
            final long maxWcet = period / numberOfSegments;
99 100 101 102

            return ThreadLocalRandom.current().nextLong(minWcet, maxWcet);
        }

103 104 105 106 107 108
        private SynchronousTask generateTask() {
            final boolean serial = randomTaskRatio(0) > this.ratio;
            final long period = serial ? randomSequentialTaskPeriod() : randomParallelTaskPeriod();
            final long numberOfSegments = serial ? 1 : randomNumberOfSegments();
            final long parallelNumberOfJobs = serial ? 1 : randomNumberOfJobs();
            final Set<Segment> segments = new LinkedHashSet<Segment>();
109

110
            for (int i = 0; i < numberOfSegments; ++i) {
111 112
                final long numberOfJobs = i % 2 == 1 ? parallelNumberOfJobs : 1;
                final long wcet = randomWcet(period, numberOfSegments);
113 114
                segments.add(new Segment(wcet, numberOfJobs));
            }
115
            return new SynchronousTask(segments, period, numberOfProcessors);
116 117
        }

118 119 120
        public Set<SynchronousTask> generateTaskSet() {
            this.ratio = randomTaskRatio(this.parallelTaskRatio);
            final Set<SynchronousTask> taskSet = new HashSet<>();
121

122
            for (int i = 0; i < numberOfProcessors; ++i) {
123
                final SynchronousTask task = generateTask();
124 125 126 127 128 129
                taskSet.add(task);
            }

            return taskSet;
        }

130 131
        public boolean addTask(final Set<SynchronousTask> taskSet) {
            return taskSet.add(generateTask());
132 133
        }

134
        @Override
135
        public SynchronousTaskBuilder setNumberOfProcessors(final long numberOfProcessors) {
136 137 138 139
            this.numberOfProcessors = numberOfProcessors;

            return this;
        }
140

141 142
        public SynchronousTaskBuilder setNumberOfSegments(final long minNumberOfSegments,
                final long maxNumberOfSegments) {
143 144 145 146 147 148
            this.minNumberOfSegments = minNumberOfSegments;
            this.maxNumberOfSegments = maxNumberOfSegments;

            return this;
        }

149 150
        public SynchronousTaskBuilder setPeriods(final long minPeriod,
                final long maxSequentialPeriod, final long maxParallelPeriod) {
151
            this.minPeriod = minPeriod;
Michael Schmid committed
152 153
            this.maxSequentialPeriod = maxSequentialPeriod;
            this.maxParallelPeriod = maxParallelPeriod;
154 155 156 157 158 159 160

            return this;
        }

        /**
         * @param maxNumberOfJobs the maxNumberOfJobs to set
         */
161 162
        public SynchronousTaskBuilder setNumberOfJobs(final long minNumberOfJobs,
                final long maxNumberOfJobs) {
163 164 165 166
            this.minNumberOfJobs = minNumberOfJobs;
            this.maxNumberOfJobs = maxNumberOfJobs;
            return this;
        }
167 168 169 170 171

        @Override
        public long getNumberOfProcessors() {
            return numberOfProcessors;
        }
172 173
    }

174
    public static class DagTaskBuilder implements Builder {
Michael Schmid committed
175
        private long numberOfProcessors = 8;
176 177
        private long minimumWcet = 1;
        private long maximumWcet = 100;
Michael Schmid committed
178
        private long maxNumberOfBranches = 5;
179
        private long maxNumberOfThreads = numberOfProcessors;
Michael Schmid committed
180
        private long depth = 2;
181
        private long p_par = 80;
182
        private long p_add = 20; // TODO: Change back to 0.2
183

Michael Schmid committed
184
        public DagTaskBuilder() {
185
        }
186

187
        public double getBeta() {
188 189 190 191
            return 0.035 * numberOfProcessors;
        }

        private long randomProbability() {
Michael Schmid committed
192
            return ThreadLocalRandom.current().nextLong(0, 100);
193 194
        }

195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220
        public Set<DagTask> generateRenyiTaskSet(final double totalUtilization) {
            final LinkedHashSet<DagTask> taskSet = new LinkedHashSet<>();

            double currentUtilization = 0;
            while (currentUtilization <= totalUtilization) {
                final DagTask dagTask = generateRenyiTask(totalUtilization);

                if (currentUtilization + dagTask.getUtilization() < totalUtilization) {
                    currentUtilization += dagTask.getUtilization();
                    taskSet.add(dagTask);
                } else {
                    final double remainingUtilization = totalUtilization - currentUtilization;
                    final long period =
                            (long) Math.ceil(dagTask.getWorkload() / remainingUtilization);
                    if (period >= dagTask.getCriticalPath()) {
                        final DagTask modifiedTask =
                                new DagTask(dagTask.getJobDag(), period, numberOfProcessors);
                        taskSet.add(modifiedTask);
                        break;
                    }
                }
            }

            return taskSet;
        }

Michael Schmid committed
221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240
        public Set<DagTask> generateUUnifastTaskSet(final long numberOfTasks,
                final double totalUtilization) {
            final LinkedHashSet<DagTask> taskSet = new LinkedHashSet<>();

            if (numberOfTasks > 0) {
                double sumU = totalUtilization;
                for (int i = 1; i <= numberOfTasks - 1; i++) {
                    Double nextSumU = sumU * Math.pow(ThreadLocalRandom.current().nextDouble(),
                            (1.0 / (double) (numberOfTasks - i)));
                    DagTask task = generateTask(sumU - nextSumU);
                    taskSet.add(task);
                    sumU = nextSumU;
                }
                DagTask task = generateTask(sumU);
                taskSet.add(task);
            }

            return taskSet;
        }

241
        public Set<DagTask> generateTaskSet(final double totalUtilization) {
242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265
            final LinkedHashSet<DagTask> taskSet = new LinkedHashSet<>();
            double currentUtilization = 0;
            while (currentUtilization <= totalUtilization) {
                final DagTask dagTask = generateTask();

                if (currentUtilization + dagTask.getUtilization() < totalUtilization) {
                    currentUtilization += dagTask.getUtilization();
                    taskSet.add(dagTask);
                } else {
                    final double remainingUtilization = totalUtilization - currentUtilization;
                    final long period =
                            (long) Math.ceil(dagTask.getWorkload() / remainingUtilization);
                    if (period >= dagTask.getCriticalPath()) {
                        final DagTask modifiedTask =
                                new DagTask(dagTask.getJobDag(), period, numberOfProcessors);
                        taskSet.add(modifiedTask);
                        break;
                    }
                }
            }

            return taskSet;
        }

266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282
        public DagTask generateRenyiTask(final double totalUtilization) {
            final DirectedAcyclicGraph<Job, DefaultEdge> jobDag =
                    new DirectedAcyclicGraph<>(DefaultEdge.class);
            final long numberOfVertices = randomNumberInRange(50, 250);
            for (int i = 0; i < numberOfVertices - 2; ++i) {
                final long wcet = randomNumberInRange(50, 100);
                Job j = new Job(wcet);
                jobDag.addVertex(j);
            }

            randomEdgesRenyi(jobDag);
            addSourceAndSink(jobDag);

            final long workload = DagUtils.calculateWorkload(jobDag);
            final long criticalPath = DagUtils.calculateCriticalPath(jobDag);
            final long period = randomRenyiPeriod(workload, criticalPath, totalUtilization);

283 284
            final long minNumberOfThreads = LongMath.divide(workload - criticalPath,
                    period - criticalPath, RoundingMode.FLOOR);
285

286 287
            // TODO: change back to following:
            // final long numberOfThreads = randomNumberOfThreads(minNumberOfThreads);
288

289
            return new DagTask(jobDag, period, minNumberOfThreads);
290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325
        }

        private long randomRenyiPeriod(final long workload, final long criticalPath,
                final double totalUtilization) {
            final double firstPart =
                    (criticalPath + (double) (workload) / (0.4 * totalUtilization));
            final double gamma = new GammaDistribution(2, 1).sample();
            final double secondPart = 1 + 0.25 * gamma;

            return (long) Math.ceil(firstPart * secondPart);
        }

        private void addSourceAndSink(final DirectedAcyclicGraph<Job, DefaultEdge> jobDag) {
            final Multimap<Job, Job> edgePairs = ArrayListMultimap.create();
            Job source = new Job(randomNumberInRange(50, 100));
            Job sink = new Job(randomNumberInRange(50, 100));
            jobDag.addVertex(source);
            jobDag.addVertex(sink);
            for (Job j : jobDag) {
                if (jobDag.inDegreeOf(j) == 0) {
                    edgePairs.put(source, j);
                }
                if (jobDag.outDegreeOf(j) == 0) {
                    edgePairs.put(j, sink);
                }
            }

            for (final Map.Entry<Job, Job> pairs : edgePairs.entries()) {
                try {
                    jobDag.addDagEdge(pairs.getKey(), pairs.getValue());
                } catch (final Exception e) {
                    // nothing to do here
                }
            }
        }

Michael Schmid committed
326 327 328 329 330 331 332 333 334 335
        public DagTask generateTask(double utilization) {
            final DirectedAcyclicGraph<Job, DefaultEdge> jobDag =
                    new DirectedAcyclicGraph<>(DefaultEdge.class);

            final Job j = fork(jobDag, Optional.empty(), this.depth);
            fork(jobDag, Optional.of(j), this.depth);
            randomEdges(jobDag);

            final long workload = DagUtils.calculateWorkload(jobDag);

336
            final long period = (long) Math.ceil(workload / utilization);
Michael Schmid committed
337 338 339

            return new DagTask(jobDag, period, numberOfProcessors);
        }
340 341 342 343 344 345 346

        public DagTask generateTask() {
            final DirectedAcyclicGraph<Job, DefaultEdge> jobDag =
                    new DirectedAcyclicGraph<>(DefaultEdge.class);

            final Job j = fork(jobDag, Optional.empty(), this.depth);
            fork(jobDag, Optional.of(j), this.depth);
347
            randomEdges(jobDag);
348 349 350 351 352 353

            final long workload = DagUtils.calculateWorkload(jobDag);
            final long criticalPath = DagUtils.calculateCriticalPath(jobDag);

            final long period = randomTaskPeriod(criticalPath, workload);

354 355 356 357
            final long minNumberOfThreads = LongMath.divide(workload, period, RoundingMode.CEILING);
            final long numberOfThreads = randomNumberOfThreads(minNumberOfThreads);

            return new DagTask(jobDag, period, numberOfThreads);
358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388
        }

        private Job join(final DirectedAcyclicGraph<Job, DefaultEdge> jobDag, final Job current,
                final Set<Job> childs) {
            if (childs.size() > 0) {
                final Job job = new Job(randomWcet());
                jobDag.addVertex(job);
                for (final Job c : childs) {
                    try {
                        jobDag.addDagEdge(c, job);
                    } catch (final Exception e) {
                        System.out.println("Failed to join nodes!");
                    }
                }
                return job;
            }
            return current;
        }

        private Job fork(final DirectedAcyclicGraph<Job, DefaultEdge> jobDag,
                final Optional<Job> predecessor, final long depth) {
            final Job job = new Job(randomWcet());
            jobDag.addVertex(job);
            final Set<Job> childs = new HashSet<>();
            if (predecessor.isPresent()) {
                try {
                    jobDag.addDagEdge(predecessor.get(), job);
                } catch (final Exception e) {
                    System.out.println("Adding fork edge failed!");
                }
            }
389
            if (depth >= 0 && randomProbability() < p_par) {
390 391 392 393 394 395 396 397 398 399 400 401 402
                final long numberOfJobs = randomNumberOfBranches();
                for (int i = 0; i < numberOfJobs; ++i) {
                    childs.add(fork(jobDag, Optional.of(job), depth - 1));
                }
            }

            return join(jobDag, job, childs);
        }

        private void randomEdges(final DirectedAcyclicGraph<Job, DefaultEdge> jobDag) {
            final Multimap<Job, Job> edgePairs = ArrayListMultimap.create();
            for (final Job j1 : jobDag) {
                for (final Job j2 : jobDag) {
403
                    if (randomProbability() < p_add) {
404 405 406 407 408 409 410 411 412
                        edgePairs.put(j1, j2);
                    }
                }
            }

            for (final Map.Entry<Job, Job> pairs : edgePairs.entries()) {
                try {
                    jobDag.addDagEdge(pairs.getKey(), pairs.getValue());
                } catch (final Exception e) {
413
                    // nothing to do here
414 415 416 417
                }
            }
        }

418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443
        private void randomEdgesRenyi(final DirectedAcyclicGraph<Job, DefaultEdge> jobDag) {
            final Multimap<Job, Job> edgePairs = ArrayListMultimap.create();
            for (final Job j1 : jobDag) {
                for (final Job j2 : jobDag) {
                    if (j2 == j1) {
                        break;
                    }
                    if (randomProbability() < p_add) {
                        edgePairs.put(j1, j2);
                    }
                }
            }

            for (final Map.Entry<Job, Job> pairs : edgePairs.entries()) {
                try {
                    jobDag.addDagEdge(pairs.getKey(), pairs.getValue());
                } catch (final Exception e) {
                    // nothing to do here
                }
            }
        }

        private long randomNumberOfThreads(final long minNumberOfThreads) {
            return ThreadLocalRandom.current().nextLong(minNumberOfThreads, maxNumberOfThreads);
        }

444
        private long randomTaskPeriod(final long criticalPathLength, final long workload) {
Michael Schmid committed
445 446
            return ThreadLocalRandom.current().nextLong(criticalPathLength,
                    (long) (workload / getBeta()));
447 448 449
        }

        private long randomNumberOfBranches() {
Michael Schmid committed
450
            return ThreadLocalRandom.current().nextLong(2, maxNumberOfBranches);
451 452
        }

453 454 455 456
        private long randomNumberInRange(final long min, final long max) {
            return ThreadLocalRandom.current().nextLong(min, max);
        }

457
        private long randomWcet() {
Michael Schmid committed
458
            return ThreadLocalRandom.current().nextLong(minimumWcet, maximumWcet);
459 460 461 462 463
        }

        /**
         * @param numberOfProcessors the numberOfProcessors to set
         */
464
        @Override
465 466 467 468 469
        public DagTaskBuilder setNumberOfProcessors(final long numberOfProcessors) {
            this.numberOfProcessors = numberOfProcessors;
            return this;
        }

Michael Schmid committed
470 471 472
        /**
         * @return the numberOfProcessors
         */
473
        @Override
Michael Schmid committed
474 475 476 477
        public long getNumberOfProcessors() {
            return numberOfProcessors;
        }

478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496
        public DagTaskBuilder setWcets(final long minimumWcet, final long maximumWcet) {
            this.minimumWcet = minimumWcet;
            this.maximumWcet = maximumWcet;
            return this;
        }

        /**
         * @param maxNumberOfBranches the maxNumberOfBranches to set
         */
        public DagTaskBuilder setMaxNumberOfBranches(final long maxNumberOfBranches) {
            this.maxNumberOfBranches = maxNumberOfBranches;
            return this;
        }

        public DagTaskBuilder setPropabilities(final long p_par, final long p_add) {
            this.p_par = p_par;
            this.p_add = p_add;
            return this;
        }
497

498 499 500 501 502 503
        public DagTaskBuilder setNumberOfThreads(final long maxNumberOfThreads) {
            this.maxNumberOfThreads = maxNumberOfThreads;

            return this;
        }

504 505 506 507 508 509 510
        /**
         * @param depth the depth to set
         */
        public DagTaskBuilder setDepth(final long depth) {
            this.depth = depth;
            return this;
        }
511 512
    }
}