package io.hummer.prefetch.sim; import io.hummer.prefetch.PrefetchStrategy; import io.hummer.prefetch.PrefetchingService.PrefetchRequest; import io.hummer.prefetch.PrefetchingService.ServiceInvocation; import io.hummer.prefetch.client.PrefetchingCapableClient; import io.hummer.prefetch.context.Context; import io.hummer.prefetch.context.Path.PathPoint; import io.hummer.prefetch.context.Time; import io.hummer.prefetch.context.TimeClock; import io.hummer.prefetch.impl.UsagePattern; import io.hummer.prefetch.impl.UsagePattern.UsagePatternPredictionBased; import io.hummer.prefetch.sim.SimulationTestData.ServiceUsage; import io.hummer.prefetch.sim.VehicleSimulation.MovingEntities; import io.hummer.prefetch.sim.VehicleSimulation.MovingEntity; import io.hummer.prefetch.sim.util.AuditEvent; import io.hummer.prefetch.strategy.PrefetchStrategyContextBased; import io.hummer.prefetch.strategy.PrefetchStrategyPeriodic; import io.hummer.util.coll.Pair; import io.hummer.util.log.LogUtil; import io.hummer.util.test.GenericTestResult; import io.hummer.util.test.GenericTestResult.IterationResult; import io.hummer.util.test.GenericTestResult.ResultType; import io.hummer.util.test.result.IterationBasedAggregatedDescriptiveStatistics.IterationBasedAggregatedDescriptiveStatisticsDefault; import java.io.File; import java.util.Arrays; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicLong; import org.apache.log4j.Logger; import com.google.common.util.concurrent.AtomicDouble; public class SimulationMain { static final Logger LOG = LogUtil.getLogger(); static GenericTestResult result = new GenericTestResult(); static IterationResult test = result.newIteration(); static final IterationBasedAggregatedDescriptiveStatisticsDefault successInvocations = new IterationBasedAggregatedDescriptiveStatisticsDefault(); static final IterationBasedAggregatedDescriptiveStatisticsDefault failedInvocations = new IterationBasedAggregatedDescriptiveStatisticsDefault(); static final IterationBasedAggregatedDescriptiveStatisticsDefault prefetchHits = new IterationBasedAggregatedDescriptiveStatisticsDefault(); static final IterationBasedAggregatedDescriptiveStatisticsDefault prefetchMisses = new IterationBasedAggregatedDescriptiveStatisticsDefault(); static final IterationBasedAggregatedDescriptiveStatisticsDefault resultsUnused = new IterationBasedAggregatedDescriptiveStatisticsDefault(); static final IterationBasedAggregatedDescriptiveStatisticsDefault resultAges = new IterationBasedAggregatedDescriptiveStatisticsDefault(); //static final AtomicInteger prefetchMisses = new AtomicInteger(); static final AtomicLong dataPoints = new AtomicLong(); static final AtomicLong dataPointsGross = new AtomicLong(); static final AtomicDouble maxTimePoint = new AtomicDouble(); static final AtomicBoolean firstStrategyIteration = new AtomicBoolean(true); static final List<? extends PrefetchStrategy> strategies = Arrays.asList( new PrefetchStrategyPeriodic(2, "P1"), new PrefetchStrategyPeriodic(10, "P2"), new PrefetchStrategyContextBased(null, 0, 0, "C") // , new PrefetchStrategyNone() ); static final double startTime = System.currentTimeMillis(); static final List<Integer> numsSecsLookIntoContextFuture = Arrays.asList(30, 180, 900); static final List<Integer> snapshotTimeSteps = Arrays.asList(500, 1000); static final String resultFile = SimulationMain.class.getResource("/").getPath() + "/../../etc/sim_result.xml"; public static void runWithConfig(MovingEntities ents, PrefetchStrategy strat, int secsLookIntoContextFuture) throws Exception { int startSecs = 15000; double stopSecs = 31000; //maxTimePoint.get(); // int stepSecs = 10; TimeClock.setTime(0); String stratID = strat.id; /* get service usages */ List<ServiceUsage> usages = new LinkedList<ServiceUsage>(); usages.add(SimulationTestData.getServiceUsage1()); usages.add(SimulationTestData.getServiceUsage2()); usages.add(SimulationTestData.getServiceUsage3()); usages.add(SimulationTestData.getServiceUsage4()); usages.add(SimulationTestData.getServiceUsage5()); usages.add(SimulationTestData.getServiceUsage6()); UsagePattern usageCombined = ServiceUsage.combine( usages.toArray(new ServiceUsage[0])); /* initialize clients */ Map<MovingEntity,PrefetchingCapableClient> clients = new HashMap<>(); for(MovingEntity ent : ents.entities) { Context<Object> ctx = new Context<>(); PrefetchingCapableClient client = new PrefetchingCapableClient(ctx); if(strat instanceof PrefetchStrategyContextBased) { ctx.addChangeListener(client); } clients.put(ent, client); /* add subscriptions for service prefetchings */ for(ServiceUsage usage : usages) { /* set context TODO hacky*/ if(((UsagePatternPredictionBased)usage.pattern).context == null) { ((UsagePatternPredictionBased)usage.pattern).context = ctx; } /* prepare prefetch request*/ PrefetchRequest r = new PrefetchRequest(); r.invocationPredictor = usage.invocationPredictor; r.strategy = strat; r.lookIntoFutureSecs = secsLookIntoContextFuture; int stepsLookFutureToTriggerStrategy = 2; // int stepsLookFutureToTriggerStrategy = (int)(secsLookIntoContextFuture / stepSecs); if(strat instanceof PrefetchStrategyContextBased) { r.strategy = new PrefetchStrategyContextBased( usage.pattern, stepsLookFutureToTriggerStrategy, stepSecs); } else if(strat instanceof PrefetchStrategyPeriodic) { r.strategy = new PrefetchStrategyPeriodic( Math.max(20, secsLookIntoContextFuture/ ((PrefetchStrategyPeriodic)strat).timeoutSecs)); } client.setPrefetchingStrategy(r); } } /* start main loop */ for(int t = startSecs; t < stopSecs; t += stepSecs) { //System.out.println(t); int secs = t - startSecs; System.out.println("Time: " + t); TimeClock.setTime(t); for(int j : snapshotTimeSteps) { if(secs % j == 0) { String prefix = "s" + stratID + "m" + j + "f" + secsLookIntoContextFuture + "t" + secs /* + "i" + (secs / j) +*/; test.addEntry(prefix + "hit", prefetchHits.getLastStatistics(j, t).getSecond().getSum()); test.addEntry(prefix + "miss", prefetchMisses.getLastStatistics(j, t).getSecond().getSum()); test.addEntry(prefix + "unused", resultsUnused.getLastStatistics(j, t).getSecond().getSum()); test.addEntry(prefix + "resultAge", resultAges.getLastStatistics(j, t).getSecond().getMean()); test.addEntry(prefix + "resultAgeMin", resultAges.getLastStatistics(j, t).getSecond().getMin()); test.addEntry(prefix + "resultAgeMax", resultAges.getLastStatistics(j, t).getSecond().getMax()); test.addEntry(prefix + "resultAgeQ1", resultAges.getLastStatistics(j, t).getSecond().getPercentile(25)); test.addEntry(prefix + "resultAgeMed", resultAges.getLastStatistics(j, t).getSecond().getPercentile(50)); test.addEntry(prefix + "resultAgeQ3", resultAges.getLastStatistics(j, t).getSecond().getPercentile(75)); test.addEntry(prefix + "hitTotal", prefetchHits.getStatistics().getSum()); test.addEntry(prefix + "missTotal", prefetchMisses.getStatistics().getSum()); test.addEntry(prefix + "unusedTotal", resultsUnused.getStatistics().getSum()); test.addEntry(prefix + "resultAgeTotal", resultAges.getStatistics().getSum()); // test.addEntry(prefix + "resultAge", // new MathUtil().average(TimeClock. // filterTimestampedValues(resultAges, t-j, t))); if(firstStrategyIteration.get()) { test.addEntry(prefix + "failed", failedInvocations.getStatistics().getSum()); test.addEntry(prefix + "success", successInvocations.getStatistics().getSum()); } } } double maxTimeToMeasureLinkUsage = 3000; if(firstStrategyIteration.get()) { if(secs < maxTimeToMeasureLinkUsage) { double usage = usageCombined.predictUsage(t); if(usage > 0.0) { test.addEntryAndRemoveOldIfSame( "t[0-9]+usage", "t" + secs + "usage", usage, result); } } } /* move forward */ for(MovingEntity ent : ents.entities) { PathPoint loc = ent.getLocationAtTime(t); if(loc != null) { dataPointsGross.addAndGet(1); PrefetchingCapableClient client = clients.get(ent); Context<Object> ctx = client.getContext(); Map<String,Object> ctxUpdates = Context.generateUpdates(t, ent.path, loc); if(firstStrategyIteration.get()) { if(secs < maxTimeToMeasureLinkUsage) { test.addEntryAndRemoveOldIfSame( "e" + ent.id + "t[0-9]+linkSpeed", "e" + ent.id + "t" + secs + "linkSpeed", loc.cellNetworkCoverage.getMaxSpeed().getCapacityKbitPerSec(), result); } } /* do the context update */ ctx.setContextAttributes(ctxUpdates); LOG.info("Car " + ent.id + ": coverage at " + t + "(" + loc.time + "): " + loc.cellNetworkCoverage.hasSufficientCoverage()); /* make invocations */ for(ServiceUsage u : usages) { // if(u.pattern.predictUsage(t) > 0) { try { List<Pair<Context<Object>,ServiceInvocation>> invs = u.invocationPredictor.predictInvocations( ctx, new Time(t), new Time(t + stepSecs)); //System.out.println("client inv: " + Util.toString(inv)); for(Pair<Context<Object>,ServiceInvocation> inv : invs) { client.invoke(inv.getSecond()); // for now, only run one invocation per time interval, hence break here break; } } catch (IllegalStateException e) { /* swallow invocation errors (due to lack of * network connectivity, which we simulate) */ } // } } } } } } static void createGraphs() throws Exception { GenericTestResult r1 = GenericTestResult.load(resultFile); List<String> stratIDs = new LinkedList<>(); int stratNum = 0; for(PrefetchStrategy strat : strategies) { stratNum ++; String stratID = strat.id; stratIDs.add(stratID); for(int j : snapshotTimeSteps) { for(int f : numsSecsLookIntoContextFuture) { String prefix = "s" + stratID + "m" + j + "f" + f; r1.createGnuplot(r1.getAllLevelIDsByPattern(prefix + "t([0-9]+)hit", 1), new String[]{prefix + "t<level>hit", prefix + "t<level>miss"}, new String[]{"Prefetch Hits", "Prefetch Misses"}, ResultType.MEAN, "Simulation Time (sec)", "Value", "etc/result_" + prefix + "_hitmiss.pdf"); r1.createGnuplot(r1.getAllLevelIDsByPattern(prefix + "t([0-9]+)resultAge", 1), new String[]{prefix + "t<level>resultAgeQ1:" + prefix + "t<level>resultAgeMin:" + prefix + "t<level>resultAgeMax:" + prefix + "t<level>resultAgeQ3:" + prefix + "t<level>resultAge"//, prefix + "t<level>resultAge" }, new String[]{"Prefetched Result Age"}, ResultType.MEAN, "Simulation Time (sec)", "Result Age (sec)", "etc/result_" + prefix + "_age.pdf", GenericTestResult.CMD_DRAW_LINE_THROUGH_CANDLESTICKS, "set boxwidth 200"); r1.createGnuplot(r1.getAllLevelIDsByPattern(prefix + "t([0-9]+)resultAgeTotal", 1), new String[]{prefix + "t<level>resultAgeTotal"}, new String[]{"Prefetched Result Age"}, ResultType.MEAN, "Simulation Time (sec)", "Result Age (sec)", "etc/result_" + prefix + "_ageTotal.pdf"); r1.createGnuplot(r1.getAllLevelIDsByPattern(prefix + "t([0-9]+)unused", 1), new String[]{prefix + "t<level>unused"}, new String[]{"Unused Invocations"}, ResultType.MEAN, "Time", "Value", "etc/result_" + prefix + "_unused.pdf"); } } String prefix = "s" + stratID + "m" + snapshotTimeSteps.get(0); int futSecs1 = numsSecsLookIntoContextFuture.get(0); int futSecs2 = numsSecsLookIntoContextFuture.get(1); int futSecs3 = numsSecsLookIntoContextFuture.get(2); r1.createGnuplot(r1.getAllLevelIDsByPattern(prefix + "f" + numsSecsLookIntoContextFuture.get(0) + "t([0-9]+)miss", 1), new String[]{ prefix + "f" + futSecs1 + "t<level>miss", prefix + "f" + futSecs2 + "t<level>miss", prefix + "f" + futSecs3 + "t<level>miss" }, new String[]{"t_p = " + futSecs1 + "sec","t_p = " + futSecs2 + "sec","t_p = " + futSecs3 + "sec"}, ResultType.MEAN, "Simulation Time (sec)", "Prefetch Misses", "etc/result_" + prefix + "_misses.pdf"); if(stratNum <= 1) { r1.createGnuplot(r1.getAllLevelIDsByPattern(prefix + "f" + futSecs1 + "t([0-9]+)failed", 1), new String[]{prefix + "f" + futSecs1 + "t<level>success", prefix + "f" + futSecs1 + "t<level>failed"}, new String[]{"Request Possible (q_a >= q_r)", "Prefetching Required (q_a < q_r)"}, ResultType.MEAN, "Simulation Time (sec)", "Number of Occurrences", "etc/result_success.pdf", "set yrange [0:45000]"); } } String suffix = "m" + snapshotTimeSteps.get(0) + "f" + numsSecsLookIntoContextFuture.get(numsSecsLookIntoContextFuture.size() - 1); String pref1 = "s" + stratIDs.get(0) + suffix; String pref2 = "s" + stratIDs.get(1) + suffix; String pref3 = "s" + stratIDs.get(2) + suffix; System.out.println(pref1 + "t([0-9]+)resultAgeTotal"); System.out.println(r1.getAllLevelIDsByPattern(pref1 + "t([0-9]+)resultAgeTotal", 1)); r1.createGnuplot(r1.getAllLevelIDsByPattern(pref1 + "t([0-9]+)resultAgeTotal", 1), new String[]{pref1 + "t<level>resultAgeTotal", pref2 + "t<level>resultAgeTotal", pref3 + "t<level>resultAgeTotal"}, new String[]{"Periodic Prefetching (t_p = 900, t_i = 450)", "Periodic Prefetching (t_p = 900, t_i = 90)", "Context-Based Prefetching (t_p = 900)"}, ResultType.MEAN, "Simulation Time (sec)", "Accumulated Result Age (sec)", "etc/result_ageTotal.pdf", "set yrange [0:250000]", "set key at -3500,240000" ); System.out.println(pref1 + "t([0-9]+)unusedTotal"); System.out.println(r1.getAllLevelIDsByPattern(pref1 + "t([0-9]+)unusedTotal", 1)); r1.createGnuplot(r1.getAllLevelIDsByPattern(pref1 + "t([0-9]+)unusedTotal", 1), new String[]{pref2 + "t<level>unusedTotal", pref1 + "t<level>unusedTotal"}, new String[]{"Periodic Prefetching (t_p = 900, t_i = 90)", "Periodic Prefetching (t_p = 900, t_i = 450)"}, ResultType.MEAN, "Simulation Time (sec)", "Unused Prefetched Results", "etc/result_unusedTotal.pdf" , "set yrange [0:4000]", "set key at -3500,3800" ); System.out.println(pref1 + "t([0-9]+)unused"); System.out.println(r1.getAllLevelIDsByPattern(pref1 + "t([0-9]+)unused", 1)); r1.createGnuplot(r1.getAllLevelIDsByPattern(pref1 + "t([0-9]+)unused", 1), new String[]{pref2 + "t<level>unused", pref1 + "t<level>unused"}, new String[]{"Periodic Prefetching (t_p = 900, t_i = 90)", "Periodic Prefetching (t_p = 900, t_i = 450)"}, ResultType.MEAN, "Simulation Time (sec)", "Unused Prefetched Results", "etc/result_unused.pdf" , "set yrange [0:600]", "set key at -3500,580" ); String prefix = ""; r1.createGnuplot(r1.getAllLevelIDsByPattern(prefix + "t([0-9]+)usage", 1), new String[]{prefix + "t<level>usage"}, new String[]{"Service Data Usage"}, ResultType.MEAN, "Time", "Data Rate (kbps)", "etc/result_usage.pdf"); String clientID = "1"; String prefix1 = "e" + clientID; String pattern = "(" + prefix1 + ")?t([0-9]+)((linkSpeed)|(usage))"; r1.createGnuplot(r1.getAllLevelIDsByPattern(pattern, 2), new String[]{prefix + "t<level>usage", prefix1 + "t<level>linkSpeed"}, new String[]{"Projected Required Network Quality (q_r)", "Estimated Available Network Quality (q_a)"}, ResultType.MEAN, "Simulation Time (sec)", "Data Rate (kbps)", "etc/result_client1_linkSpeed.pdf", "set logscale y", "set yrange [1:1000000]", //"set xrange [2970:*]", "set xtics format '%s%c'" "set xtics rotate by 90 offset 0,-2", "set format x '%.1tK'", "set format y '10^{%T}'" ); } public static void startSimulation(String serviceURL) throws Exception { SimulationTestData.setServiceURL(serviceURL); int numCars = 50; MovingEntities entities = SimulationTestData.getData(1, numCars); // MovingEntities entities = SimulationTestData.getData(29, 29); for(MovingEntity ent : entities.entities) { dataPoints.addAndGet(ent.path.size()); double maxTime = ent.path.points.get(ent.path.points.size() - 1).time.time; if(maxTime > maxTimePoint.get()) { maxTimePoint.set(maxTime); } } test.addEntry("dataPoints", dataPoints.get()); System.out.println("Starting simulation..."); System.out.println(maxTimePoint.get()); Runtime.getRuntime().addShutdownHook(new Thread() { public void run() { test.addEntry("dataPointsGross", dataPointsGross.get()); double totalTime = System.currentTimeMillis() - startTime; LOG.info("Total execution time: " + totalTime); test.addEntry("totalRunTime", totalTime); result.save(resultFile); } }); AuditEvent.addListener(".*", new AuditEvent.EventListener() { public void notify(AuditEvent e) { if(e.type.equals(AuditEvent.E_INV_FAILED)) { failedInvocations.addValue(TimeClock.now(), 1); } else if(e.type.equals(AuditEvent.E_INV_SUCCESS)) { //System.out.println(e); // TODO successInvocations.addValue(TimeClock.now(), 1); } else if(e.type.equals(AuditEvent.E_PREFETCH_HIT)) { System.out.println(e); // TODO prefetchHits.addValue(TimeClock.now(), 1); @SuppressWarnings("unchecked") double resultTime = (double)((Map<String,Object>)e.data).get(Context.ATTR_TIME); //System.out.println("age: " + (TimeClock.now() - resultTime)); resultAges.addValue(TimeClock.now(), TimeClock.now() - resultTime); } else if(e.type.equals(AuditEvent.E_PREFETCH_MISS)) { System.out.println(e); // TODO prefetchMisses.addValue(TimeClock.now(), 1); //throw new RuntimeException(); } else if(e.type.equals(AuditEvent.E_UNUSED_RESULT)) { resultsUnused.addValue(TimeClock.now(), 1); } } }); for(PrefetchStrategy s : strategies) { for(int futSecs : numsSecsLookIntoContextFuture) { failedInvocations.clear(); successInvocations.clear(); prefetchHits.clear(); prefetchMisses.clear(); resultsUnused.clear(); resultAges.clear(); runWithConfig(entities, s, futSecs); firstStrategyIteration.set(false); System.gc(); } } } public static void main(String[] args) throws Exception { boolean startServices = true; boolean startClients = true; String serviceHost = "localhost"; if(args.length > 0 && args[0].equals("services")) { startClients = false; } else if(args.length > 0 && args[0].equals("clients")) { startServices = false; serviceHost = args[1]; } // draw graphs boolean createGraphs = false; if(createGraphs && new File(resultFile).exists()) { createGraphs(); System.exit(0); } String serviceURL = "http://" + serviceHost + ":8283/traffic"; if(startServices) { /* deploy services */ SimulationTestData.deployTestServices(serviceURL); } if(startClients) { startSimulation(serviceURL); System.exit(0); } } }