econtroller.modeler.Modeler.java Source code

Java tutorial

Introduction

Here is the source code for econtroller.modeler.Modeler.java

Source

/**
 * Copyright 2011 Amir Moulavi (amir.moulavi@gmail.com)
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package econtroller.modeler;

import cloud.common.RequestTrainingData;
import cloud.common.SLAViolation;
import cloud.common.StateVariables;
import cloud.common.TrainingData;
import cloud.elb.SenseData;
import econtroller.controller.NewNodeRequest;
import econtroller.controller.RemoveNode;
import econtroller.gui.ControllerGUI;
import logger.Logger;
import logger.LoggerFactory;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.data.xy.XYDataset;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
import se.sics.kompics.ComponentDefinition;
import se.sics.kompics.Handler;
import se.sics.kompics.Negative;
import se.sics.kompics.Positive;
import se.sics.kompics.address.Address;
import se.sics.kompics.network.Network;
import se.sics.kompics.timer.CancelTimeout;
import se.sics.kompics.timer.ScheduleTimeout;
import se.sics.kompics.timer.Timer;

import java.util.UUID;

/**
 *
 * @author Amir Moulavi
 * @date 2011-05-08
 *
 */

public class Modeler extends ComponentDefinition {

    private Logger logger = LoggerFactory.getLogger(Modeler.class, ControllerGUI.getInstance());

    // Ports
    Negative<ModelPort> modeler = provides(ModelPort.class);
    Positive<Network> network = requires(Network.class);
    Positive<Timer> timer = requires(Timer.class);

    // Variables
    private long SAMPLING_INTERVAL = 10000;
    private long ORDER_INTERVAL = 90000;
    private Address cloudProvider;
    private Address self;
    private ControllerGUI gui;
    private int maxNrInstances = 8;
    private int minNrInstances = 2;
    private int currentlyOrdered = 0;
    private boolean add = true;
    private Long start = null;
    private UUID samplingTimeoutId;
    private UUID actuationTimeoutId;
    private int snapshotId = 0;
    private boolean orderingEnabled = true;
    private boolean snapshotTaken = false;
    private double takeSnapshotTime = 2050;

    private DataFilesGenerator2 generator = new DataFilesGenerator2();
    private XYSeries nrInstancesSeries = new XYSeries("# of Instances");
    private XYSeries rtSeries = new XYSeries("Average ResponseTime");
    private XYSeries tpSeries = new XYSeries("Average Throughput");
    private XYSeries cpuLoadSeries = new XYSeries("Average CPU Load");
    private XYSeries costSeries = new XYSeries("Total Cost");
    private XYSeries bandwidthSeries = new XYSeries("Average Bandwidth");

    public Modeler() {
        gui = ControllerGUI.getInstance();
        gui.setModeler(this);

        subscribe(initHandler, control);

        subscribe(startModelerHandler, modeler);
        subscribe(senseDataHandler, modeler);

        subscribe(sampleTrainingDataHandler, timer);
        subscribe(instanceCreationHandler, timer);

        subscribe(trainingDataHandler, network);
    }

    Handler<ModelerInit> initHandler = new Handler<ModelerInit>() {
        @Override
        public void handle(ModelerInit event) {
            self = event.getSelf();
            logger.info("Modeler started...");
            gui.updateBandwidthChart(getBandwidthChart());
            gui.updateCpuLoadChart(getCPUChart());
            gui.updateResponseTimeChart(getResponseTimeChart());
            gui.updateTotalCostChart(getTotalCostChart());
            gui.updateNrOfInstancesChart(getNrInstancesChart());
            gui.updateThroughputChart(getAverageThroughputChart());
        }
    };

    /**
     * This handler is triggered when the Controller issues a START signal to Modeler
     */
    Handler<StartModeler> startModelerHandler = new Handler<StartModeler>() {
        @Override
        public void handle(StartModeler event) {
            logger.info("Modeler received START signal from controller");
            cloudProvider = event.getCloudProviderAddress();
        }
    };

    /**
     * This handler is responsible for requesting training data from cloudProvider
     */
    Handler<SampleTrainingData> sampleTrainingDataHandler = new Handler<SampleTrainingData>() {
        @Override
        public void handle(SampleTrainingData event) {
            trigger(new RequestTrainingData(self, cloudProvider), network);
            scheduleSampling();
        }
    };

    /**
     * This handler is responsible for adding and removing instances so the modeler can have a range for the system inputs
     */
    Handler<InstanceCreation> instanceCreationHandler = new Handler<InstanceCreation>() {
        @Override
        public void handle(InstanceCreation event) {
            if (orderingEnabled) {
                if (add) {
                    if (currentlyOrdered < maxNrInstances) {
                        requestNewNode();
                    } else {
                        add = false;
                        removeNode();
                    }
                } else {
                    if (currentlyOrdered > minNrInstances) {
                        removeNode();
                    } else {
                        generator.dump();
                        takeSnapshot();
                        add = true;
                        requestNewNode();
                    }
                }
            }
            scheduleActuation();
        }
    };

    /**
     * This handler is responsible for sorting out the response (raw data tuples) it receives from cloudProvider
     */
    Handler<TrainingData> trainingDataHandler = new Handler<TrainingData>() {
        @Override
        public void handle(TrainingData event) {
            logger.info("Training data: \n" + event.toString());
            generator.add(event);
            saveAndPlotData(event.getCpuLoadMean(), event.getCpuLoadSTD(), event.getBandwidthMean(),
                    event.responseTimeMean(), event.periodicTotalCost(), event.getThroughputMean(),
                    event.getNrNodes());
            printViolations(event);
            printTotalCost(event);
            dumpAndSnapshot();
        }
    };

    /**
     * This handler is triggered only when the controller runs and it enables monitoring
     */
    Handler<SenseData> senseDataHandler = new Handler<SenseData>() {
        @Override
        public void handle(SenseData event) {
            if (start == null)
                start = System.currentTimeMillis();
            generator.add(event);
            saveAndPlotData(event.getCpuLoadMean(), event.getCpuLoadSTD(), event.getBandwidthMean(),
                    event.getResponseTimeMean(), event.getPeriodicTotalCost(), event.getThroughputMean(),
                    event.getNrNodes());
            printViolations(event);
            printTotalCost(event);
            dumpAndSnapshot();
        }
    };

    private void dumpAndSnapshot() {
        if (!snapshotTaken) {
            if (logger.getTime() >= takeSnapshotTime) {
                snapshotTaken = true;
                generator.dump();
                takeSnapshot();
            }
        }
    }

    private void printTotalCost(StateVariables event) {
        logger.warn("Total Cost: $ " + event.getTotalCost());
    }

    private void printViolations(SLAViolation event) {
        logger.warn("Violations: {CPULoad: %" + event.getCpuLoadViolation() + ", ResponseTime: %"
                + event.getResponseTimeViolation() + ", Bandwidth: %" + event.getBandwidthViolation() + "}");
    }

    private void saveAndPlotData(double cpuLoad, double cpuSTD, double bandwidth, double responseTime,
            double totalCost, double throughPut, int numberOfNodes) {
        bandwidthSeries.add(System.currentTimeMillis() - start, bandwidth);
        gui.updateBandwidthChart(getBandwidthChart());
        cpuLoadSeries.add(System.currentTimeMillis() - start, cpuLoad);
        gui.updateCpuLoadChart(getCPUChart());
        rtSeries.add(System.currentTimeMillis() - start, responseTime);
        gui.updateResponseTimeChart(getResponseTimeChart());
        costSeries.add(System.currentTimeMillis() - start, totalCost);
        gui.updateTotalCostChart(getTotalCostChart());
        tpSeries.add(System.currentTimeMillis() - start, throughPut);
        gui.updateThroughputChart(getAverageThroughputChart());
        nrInstancesSeries.add(System.currentTimeMillis() - start, numberOfNodes);
        gui.updateNrOfInstancesChart(getNrInstancesChart());
    }

    protected void scheduleSampling() {
        ScheduleTimeout st = new ScheduleTimeout(SAMPLING_INTERVAL);
        st.setTimeoutEvent(new SampleTrainingData(st));
        samplingTimeoutId = st.getTimeoutEvent().getTimeoutId();
        trigger(st, timer);
    }

    public String estimateParameters() {
        generator.dump();
        return "Done";
    }

    protected void removeNode() {
        currentlyOrdered--;
        trigger(new RemoveNode(self, cloudProvider, 1), network);
    }

    protected void requestNewNode() {
        currentlyOrdered++;
        trigger(new NewNodeRequest(self, cloudProvider, 1), network);
    }

    public void startModeler(boolean orderingEnabled, int maximumNrInstances, int minimumNrInstances,
            int sampleInterval, int orderInterval) {
        this.orderingEnabled = orderingEnabled;
        start = System.currentTimeMillis();
        trigger(new RequestTrainingData(self, cloudProvider), network);
        maxNrInstances = maximumNrInstances;
        minNrInstances = minimumNrInstances;
        currentlyOrdered = minimumNrInstances;
        SAMPLING_INTERVAL = sampleInterval * 1000;
        ORDER_INTERVAL = orderInterval * 1000;
        scheduleSampling();
        scheduleActuation();
    }

    public void stopModeler() {
        trigger(new CancelTimeout(actuationTimeoutId), timer);
        trigger(new CancelTimeout(samplingTimeoutId), timer);
    }

    private void scheduleActuation() {
        ScheduleTimeout st = new ScheduleTimeout(ORDER_INTERVAL);
        st.setTimeoutEvent(new InstanceCreation(st));
        actuationTimeoutId = st.getTimeoutEvent().getTimeoutId();
        trigger(st, timer);
    }

    private JFreeChart getCPUChart() {
        JFreeChart chart = ChartFactory.createXYLineChart("Average CPU Load", "Time (ms)", "Average CPU Load",
                getDataset(cpuLoadSeries), PlotOrientation.VERTICAL, true, true, false);
        return chart;
    }

    private JFreeChart getResponseTimeChart() {
        JFreeChart chart = ChartFactory.createXYLineChart("Average Response Time", "Time (ms)",
                "Average Response Time (ms)", getDataset(rtSeries), PlotOrientation.VERTICAL, true, true, false);
        return chart;
    }

    private JFreeChart getBandwidthChart() {
        JFreeChart chart = ChartFactory.createXYLineChart("Average Bandwidth per Download", "Time (ms)",
                "Bandwidth (B/s)", getDataset(bandwidthSeries), PlotOrientation.VERTICAL, true, true, false);
        return chart;
    }

    private JFreeChart getNrInstancesChart() {
        JFreeChart chart = ChartFactory.createXYLineChart("Number of Instances", "Time (ms)", "# of Instances",
                getDataset(nrInstancesSeries), PlotOrientation.VERTICAL, true, true, false);
        return chart;
    }

    private JFreeChart getTotalCostChart() {
        JFreeChart chart = ChartFactory.createXYLineChart("Total Cost", "Time (ms)", "Total Cost ($)",
                getDataset(costSeries), PlotOrientation.VERTICAL, true, true, false);
        return chart;
    }

    private JFreeChart getAverageThroughputChart() {
        JFreeChart chart = ChartFactory.createXYLineChart("Average Throughput", "Time (ms)",
                "Average Throughput (every seconds)", getDataset(tpSeries), PlotOrientation.VERTICAL, true, true,
                false);
        return chart;
    }

    private XYDataset getDataset(XYSeries series) {
        XYSeriesCollection dataSet = new XYSeriesCollection();
        dataSet.addSeries(series);
        return dataSet;
    }

    public void takeSnapshot() {
        snapshotId++;
        ModelerSnapshot snapshot = new ModelerSnapshot(snapshotId);
        snapshot.setCpuChart(getCPUChart());
        snapshot.setResponseTimeChart(getResponseTimeChart());
        snapshot.setAverageBandwidth(getBandwidthChart());
        snapshot.setNrInstanceChart(getNrInstancesChart());
        snapshot.setTotalCostChart(getTotalCostChart());
        snapshot.setAverageThroughputChart(getAverageThroughputChart());
        gui.addSnapshot(snapshot);
    }

    public void reset() {
        cpuLoadSeries.clear();
        rtSeries.clear();
        bandwidthSeries.clear();
        nrInstancesSeries.clear();
        costSeries.clear();
        tpSeries.clear();

        generator.clear();
    }

}