import java.util.*; import java.util.concurrent.*; import java.lang.*; /** * Runs MyScheduler.java to test running time. Usage: $ java * * @author Kyle Burke <kburke@flsouthern.edu> */ public class SchedulerTester { //properties to measure private static final String[] GOALS = {"max wait", "avg wait", /* "efficiency",*/ "combined", "deadlines"}; //default number of jobs private static final int DEFAULT_NUM_JOBS = 1000; //default min job length private static final int DEFAULT_MIN_LENGTH = 1; //default max job length private static final int DEFAULT_MAX_LENGTH = 100; //default fake speedup TODO: In future years, use this! private static final int DEFAULT_SPEEDUP = 1; public static void main(String[] args) { boolean verbose = false; for (int i = 0; i < args.length; i++) { if (args[i].equalsIgnoreCase("verbose")) { //found verbose! verbose = true; //reset args by removing 'verbose' String[] newArgs = new String[args.length-1]; for (int j = 0; j < i; j++) { newArgs[j] = args[j]; } for (int j = i; j < newArgs.length; j++) { newArgs[j] = args[j+1]; } args = newArgs; break; } } // You may rename this method to better suit the purpose of your test case // Your test case logic here int numJobsInput; try { numJobsInput = Integer.parseInt(args[0]); } catch (Exception e) { numJobsInput = DEFAULT_NUM_JOBS; } final int numJobs = numJobsInput; int minJobInput; try { minJobInput = Integer.parseInt(args[1]); } catch (Exception e) { minJobInput = DEFAULT_MIN_LENGTH; } final int minJobLength = minJobInput; int maxJobInput; try { maxJobInput = Integer.parseInt(args[2]); } catch (Exception e) { maxJobInput = DEFAULT_MAX_LENGTH; } final int maxJobLength = maxJobInput; int averageLength = (minJobLength + maxJobLength) / 2; int defaultAvgLength = (DEFAULT_MIN_LENGTH + DEFAULT_MAX_LENGTH) / 2; //run the tests and get the results long[] testResults = new long[GOALS.length]; System.out.println("\n*********************************************************************"); System.out.println("About to run the simulations with:\n * Num. Jobs: " + numJobs + "\n * Min job length: " + minJobLength + "\n * Max job length: " + maxJobLength); for (int i = 0; i < GOALS.length; i++) { testResults[i] = runTest(GOALS[i], numJobs, minJobLength, maxJobLength, verbose); } //set up the goals of the tests Map<String, List<Integer>> goals = new TreeMap<>(); List<Integer> maxWaitTimeGoals = new ArrayList<>(); List<Integer> avgWaitTimeGoals = new ArrayList<>(); //List<Integer> efficiencyGoals = new ArrayList<>(); List<Integer> combinedGoals = new ArrayList<>(); for (int i = 0; i < 7; i++) { int maxWaitGoal = (11000 + 1000 * i) * (averageLength / defaultAvgLength); maxWaitTimeGoals.add(maxWaitGoal); int avgWaitGoal = (50 + 100 * i) * (averageLength / defaultAvgLength); avgWaitTimeGoals.add(avgWaitGoal); //efficiencyGoals.add(34 - (2 * i)); int combinedGoal = (37000 + 1000 * i) * (averageLength / defaultAvgLength); combinedGoals.add(combinedGoal); } maxWaitTimeGoals = Arrays.asList(new Integer[] {1600, 2000, 2500, 3500, 5500});//, 10000, 20000}); avgWaitTimeGoals = Arrays.asList(new Integer[] {240, 300, 420, 600, 900});//, 1500, 2500}); combinedGoals = Arrays.asList(new Integer[] {2275, 2350, 2500, 2700, 2900});//, 3000, 3400}); int percentageToNumJobs = (int) Math.ceil(numJobs/100); List<Integer> deadlineGoals = Arrays.asList(new Integer[] { 85 * percentageToNumJobs, 80 * percentageToNumJobs, 75 * percentageToNumJobs, 70 * percentageToNumJobs, 65 * percentageToNumJobs //,50 * percentageToNumJobs //,40 * percentageToNumJobs }); //old versions /* maxWaitTimeGoals = Arrays.asList(new Integer[] {4000, 6000, 9000, 14000, 21000, 32000, 48000}); avgWaitTimeGoals = Arrays.asList(new Integer[] {1500, 1600, 1700, 1800, 1900, 2100, 2500}); combinedGoals = Arrays.asList(new Integer[] {6700, 7000, 7500, 8100, 8800, 9500, 10500}); */ goals.put(GOALS[0], maxWaitTimeGoals); goals.put(GOALS[1], avgWaitTimeGoals); //goals.put("efficiency", efficiencyGoals); goals.put(GOALS[2], combinedGoals); goals.put(GOALS[3], deadlineGoals); //calculate the points based on the goals int totalScore = 0; int totalMax = 0; for (String goal : goals.keySet()) { List<Integer> statGoals = goals.get(goal); boolean reversed = false; if (statGoals.get(0) > statGoals.get(1)) { reversed = true; } int goalIndex = goalToIndex(goal); int time = (int) testResults[goalIndex]; System.out.println("Your code had a " + goal + " of: " + time); System.out.println("Brackets: " + statGoals); Integer[] array = statGoals.toArray(new Integer[0]); if (reversed) { Arrays.sort(array); } int index = Arrays.binarySearch(array, time); if (index < 0 ) { index = -1 * (index + 1); } int rank = statGoals.size() - index; if (reversed) { rank = index; } System.out.println("Rank: " + rank); int score = 10 * rank; int maxScore = 10 * statGoals.size(); System.out.println("That earns: " + score + "/" + maxScore + " points!\n"); totalScore += score; totalMax += maxScore; } //25 points for completing the tests int pointsForFinishing = 25; totalMax += pointsForFinishing; totalScore += pointsForFinishing; System.out.println("All tests completed: " + pointsForFinishing + " points"); System.out.println("Total score: " + totalScore + "/" + totalMax); } // Runs a test looking to optimize a specified property, returning the stats from the run. Stats are returned as: // [maxWaitingTime, totalWaitingTime] private static long runTest(String property, int numJobs, int minJobLength, int maxJobLength, boolean verbose) { int propertyIndex = goalToIndex(property); List<String> ids = new ArrayList<>(); Random rng = new Random(System.currentTimeMillis()); for (int i = 0; i < numJobs; i++) { ids.add("" + rng.nextInt(10000)); } System.out.println("\n*********************************************************************"); System.out.println("Testing for: " + property + " **************************************"); MyScheduler scheduler = new MyScheduler(numJobs, property); LinkedBlockingQueue<Job> schedulerToCpu = scheduler.getOutgoingQueue(); LinkedBlockingQueue<Job> generatorToScheduler = scheduler.getIncomingQueue(); CPU cpu = new CPU("1", schedulerToCpu, verbose); cpu.setNumJobs(numJobs); //scheduler.setCPU(cpu); List<Integer> lengths = new ArrayList<>(); //adds a linear distribution of jobs int jobsThisPart = numJobs/2; for (int i = 0; i < numJobs/2; i++) { int jobLength = (int) i * (maxJobLength/2 - minJobLength) / jobsThisPart + minJobLength; lengths.add(jobLength); //jobs.add(new Job(jobLength, ids.get(i))); //System.out.print(jobLength + ", "); } //adds a bunch more smaller jobs int jobsRemaining = numJobs - (numJobs/2); int jobsLastPart = 10; jobsThisPart = jobsRemaining - jobsLastPart; for (int i = 0; i < jobsThisPart; i++) { int jobLength = (int) i * (maxJobLength/20 - minJobLength) / jobsThisPart + minJobLength; lengths.add(jobLength); } //now add a few long jobs jobsThisPart = jobsLastPart; for (int i = 0; i < jobsThisPart; i++) { int jobLength = maxJobLength; lengths.add(jobLength); } Collections.shuffle(lengths, rng); //for (Job job : jobs) { //System.out.print(job.getLength() + ", "); //} Thread jobGenerator = new Thread(() -> { int i = 0; int numToPrime = Math.min(50, numJobs / 2); int maxDeadlineDiff = 150; int minDeadlineDiff = 50; //prime it with some jobs without waiting between creation for (; i < numToPrime; ) { /* int jobLength = ThreadLocalRandom.current().nextInt(minJobLength, maxJobLength + 1); Job job = new Job(jobLength, ids.get(i)); */ int minDeadline = lengths.get(i) + minDeadlineDiff; int maxDeadline = Math.max(minDeadline + 5, maxDeadlineDiff); long deadline = ThreadLocalRandom.current().nextInt(minDeadline, maxDeadline) + System.currentTimeMillis(); //System.out.println("Created a job with " + (deadline - System.currentTimeMillis()) + " milliseconds allowed to run."); Job job = new Job(lengths.get(i), ids.get(i), deadline); try { generatorToScheduler.put(job); if (verbose) { System.out.println("Job #" + i + " created!"); } i++; } catch (InterruptedException e) { System.err.println("Putting a job in the queue to reach the scheduler (while priming) got interrupted!"); } } System.out.println("!!!!!!! Done priming the simulation!!!!!!!!"); //now generate jobs for the scheduler, waiting between each one you create. for (; i < numJobs; ) { /* int jobLength = ThreadLocalRandom.current().nextInt(minJobLength, maxJobLength + 1); Job job = new Job(jobLength, ids.get(i)); */ int minDeadline = lengths.get(i) + minDeadlineDiff; int maxDeadline = Math.max(minDeadline + 5, maxDeadlineDiff); long deadline = ThreadLocalRandom.current().nextInt(minDeadline, maxDeadline) + System.currentTimeMillis(); //System.out.println("Created a job with " + (deadline - System.currentTimeMillis()) + " milliseconds allowed to run."); Job job = new Job(lengths.get(i), ids.get(i), deadline); //Job job = new Job(lengths.get(i), ids.get(i)); int j = i; //add the job to the scheduler in a separate thread so that our processing can't be blocked by an unnaturally small BlockingQueue headed into the scheduler. Thread giveToScheduler = new Thread(() -> { try { generatorToScheduler.put(job); if (verbose) { System.out.println("Job #" + j + " created!"); } } catch (InterruptedException e) { System.err.println("Adding a job in the queue to reach the scheduler got interrupted!"); } }); giveToScheduler.start(); /* int minWait = (int) Math.floor(.5 * jobLength); int maxWait = (int) Math.ceil(1.5 * jobLength); int waitTime = ThreadLocalRandom.current().nextInt(minWait, maxWait); /* */ int waitTime = lengths.get((i + numJobs/2) % numJobs); try { Thread.sleep(waitTime); } catch (Exception e) { //do nothing } i++; } //now tell the cpu it's done by sending it a Kill job }); cpu.start(); Thread schedulerThread = new Thread(() -> { scheduler.run(); }); schedulerThread.start(); System.out.println("Launched MyScheduler!"); //scheduler.start(); jobGenerator.start(); //System.out.println("Total Wait Time: " + cpu.getTotalWaitTime()); //scheduler.stop(); cpu.blockUntilDone(); List<Job> completed = cpu.getCompleted(); assert completed.size() == numJobs : "The number of completed jobs doesn't match the number created!"; for (Job job : completed) { ids.remove(job.getId()); } assert ids.size() == 0 : "Not all job ids were completed!"; return (new long[] {cpu.getMaxWaitTime(), cpu.getAverageWaitTime(), /*cpu.getEfficiency(), */ cpu.getMaxWaitTime() + 2* cpu.getAverageWaitTime(), cpu.getTotalDeadlinesMade()})[propertyIndex]; } //gets the index of a goal private static int goalToIndex(String goal) { for (int i = 0; i < GOALS.length; i++) { String goalX = GOALS[i]; if (goal.equals(goalX)) { return i; } } throw new IllegalArgumentException("\"" + goal + "\" is not an appopriate goal!"); } }