SystemManager.java 18.5 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;
Michael Schmid committed
182
        private long p_add = 20; 
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
        public Set<DagTask> generateRenyiTaskSet(final double totalUtilization) {
            final LinkedHashSet<DagTask> taskSet = new LinkedHashSet<>();
            double currentUtilization = 0;
198

199 200 201 202 203 204 205 206 207 208 209
            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()) {
210 211
                        final DagTask modifiedTask = new DagTask(dagTask.getJobDag(), period,
                                dagTask.getNumberOfThreads());
212 213 214 215 216 217 218 219 220
                        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
            final long numberOfThreads = randomNumberOfThreads(numberOfProcessors / 2);
284

285
            return new DagTask(jobDag, period, numberOfThreads);
286 287 288 289
        }

        private long randomRenyiPeriod(final long workload, final long criticalPath,
                final double totalUtilization) {
290
            final double firstPart = (criticalPath + (double) (workload) / (0.4 * totalUtilization));
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
            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
321 322 323 324 325 326 327 328 329 330
        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);

331
            final long period = (long) Math.ceil(workload / utilization);
Michael Schmid committed
332 333 334

            return new DagTask(jobDag, period, numberOfProcessors);
        }
335 336 337 338 339 340 341

        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);
342
            randomEdges(jobDag);
343 344 345 346 347 348

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

            final long period = randomTaskPeriod(criticalPath, workload);

349 350 351 352
            final long minNumberOfThreads = LongMath.divide(workload, period, RoundingMode.CEILING);
            final long numberOfThreads = randomNumberOfThreads(minNumberOfThreads);

            return new DagTask(jobDag, period, numberOfThreads);
353 354 355 356 357 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
        }

        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!");
                }
            }
384
            if (depth >= 0 && randomProbability() < p_par) {
385 386 387 388 389 390 391 392 393 394 395 396 397
                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) {
398
                    if (randomProbability() < p_add) {
399 400 401 402 403 404 405 406 407
                        edgePairs.put(j1, j2);
                    }
                }
            }

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

413 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
        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);
        }

439
        private long randomTaskPeriod(final long criticalPathLength, final long workload) {
Michael Schmid committed
440 441
            return ThreadLocalRandom.current().nextLong(criticalPathLength,
                    (long) (workload / getBeta()));
442 443 444
        }

        private long randomNumberOfBranches() {
Michael Schmid committed
445
            return ThreadLocalRandom.current().nextLong(2, maxNumberOfBranches);
446 447
        }

448 449 450 451
        private long randomNumberInRange(final long min, final long max) {
            return ThreadLocalRandom.current().nextLong(min, max);
        }

452
        private long randomWcet() {
Michael Schmid committed
453
            return ThreadLocalRandom.current().nextLong(minimumWcet, maximumWcet);
454 455 456 457 458
        }

        /**
         * @param numberOfProcessors the numberOfProcessors to set
         */
459
        @Override
460 461 462 463 464
        public DagTaskBuilder setNumberOfProcessors(final long numberOfProcessors) {
            this.numberOfProcessors = numberOfProcessors;
            return this;
        }

Michael Schmid committed
465 466 467
        /**
         * @return the numberOfProcessors
         */
468
        @Override
Michael Schmid committed
469 470 471 472
        public long getNumberOfProcessors() {
            return numberOfProcessors;
        }

473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491
        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;
        }
492

493 494 495 496 497 498
        public DagTaskBuilder setNumberOfThreads(final long maxNumberOfThreads) {
            this.maxNumberOfThreads = maxNumberOfThreads;

            return this;
        }

499 500 501 502 503 504 505
        /**
         * @param depth the depth to set
         */
        public DagTaskBuilder setDepth(final long depth) {
            this.depth = depth;
            return this;
        }
506 507
    }
}