pt.minha.calibration.Calibrator.java Source code

Java tutorial

Introduction

Here is the source code for pt.minha.calibration.Calibrator.java

Source

/*
 * Minha.pt: middleware testing platform.
 * Copyright (c) 2011-2014, Universidade do Minho.
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */

package pt.minha.calibration;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.Closeable;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.TimeUnit;

import org.apache.commons.math3.stat.regression.SimpleRegression;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import pt.minha.api.Entry;
import pt.minha.api.sim.Calibration;
import pt.minha.api.sim.Linear;
import pt.minha.api.sim.Simulation;
import pt.minha.calibration.AbstractBenchmark.Result;

/**
 * Calibration tool. This tool runs a micro-benchmark and computes 
 * configuration parameters that calibrate the simulator to mimic
 * the performance of the real hardware. 
 */
public class Calibrator implements Closeable {

    private static Logger logger = LoggerFactory.getLogger("pt.minha.calibration");

    private Socket socket;
    private ObjectOutputStream oos;
    private ObjectInputStream ois;

    public Calibrator(String server) throws UnknownHostException, IOException {
        logger.info("client: connecting to {}", server);

        socket = new Socket(server, 12345);
        oos = new ObjectOutputStream(new BufferedOutputStream(socket.getOutputStream()));
        oos.flush();
        ois = new ObjectInputStream(new BufferedInputStream(socket.getInputStream()));
    }

    private Result runReal(Map<String, Object> p) throws Throwable {
        // Reality

        logger.info("real: sending {}", p);

        oos.writeObject(p);
        oos.flush();
        Thread.sleep(1000);

        logger.info("real: running {}", p);

        Benchmark next = (Benchmark) Class.forName((String) p.get("bench")).newInstance();
        next.setParameters(p);

        Result rcli = (Result) next.client();

        logger.info("real: running {} done", next);

        Object rsrv = ois.readObject();

        logger.info("real server: {}", rsrv);
        logger.info("real client: {}", rcli);

        return rcli;
    }

    private Result runSimulated(Map<String, Object> p, Properties props) throws Throwable {
        Benchmark next = (Benchmark) Class.forName((String) p.get("bench")).newInstance();
        next.setParameters(p);

        Simulation world = new Simulation();
        Calibration c = world.getCalibration();
        c.reset();
        c.load(props);

        Entry<Benchmark>[] e = world.createEntries(2, Benchmark.class, (String) p.get("bench"));

        logger.info("simulation: loading {}", next);

        InetSocketAddress srv = new InetSocketAddress(e[1].getProcess().getHost().getAddress(), 20000);
        p.put("server", srv);
        e[0].call().setParameters(p);
        e[1].call().setParameters(p);

        logger.info("simulation: running {}", next);

        e[1].queue().server();
        e[0].at(1, TimeUnit.SECONDS).queue().client();
        world.runAll(e);

        Object scli = e[0].getResult();
        Object ssrv = e[1].getResult();

        world.close();

        logger.info("simulation server: got {}", ssrv);
        logger.info("simulation client: got {}", scli);

        return (Result) scli;
    }

    public void close() throws IOException {
        socket.close();
    }

    private static void runServer() throws Exception {
        // Reality server
        ServerSocket ss = new ServerSocket(12345);

        logger.info("server: started at {}", ss.getLocalSocketAddress());

        while (true) {
            Socket s = ss.accept();

            logger.info("server: accepted {}", s.getRemoteSocketAddress());

            try {
                ObjectOutputStream oos = new ObjectOutputStream(new BufferedOutputStream(s.getOutputStream()));
                oos.flush();
                ObjectInputStream ois = new ObjectInputStream(new BufferedInputStream(s.getInputStream()));

                while (!s.isClosed()) {
                    Map<String, Object> p = (Map<String, Object>) ois.readObject();
                    Benchmark next = (Benchmark) Class.forName((String) p.get("bench")).newInstance();
                    next.setParameters(p);

                    logger.info("server: running {}", p);

                    Object result = next.server();

                    logger.info("server: running {} done", p);

                    oos.writeObject(result);
                    oos.flush();
                }

                logger.info("server: disconnected {}", s.getRemoteSocketAddress());

            } catch (IOException ioe) {
                logger.info("server: disconnected {} on {}", s.getRemoteSocketAddress(), ioe);
            }
        }
    }

    public static void main(String[] args) throws Throwable {
        if (args.length != 1) {
            logger.error("missing command line argument (--server | <servername>)");
        } else if (args[0].equals("--server")) {
            runServer();
        } else {
            Calibrator calib = new Calibrator(args[0]);

            Properties props = new Properties();

            SimpleRegression cpuoh = new SimpleRegression(true);
            for (int i : new int[] { 100, 1000, 10000, 20000 }) {
                Map<String, Object> p = new HashMap<String, Object>();
                p.put("bench", CPUBenchmark.class.getName());
                p.put("samples", 50000);
                p.put("payload", i);
                Result r = calib.runReal(p);
                Result s = calib.runSimulated(p, props);
                cpuoh.addData(s.meanCPU, r.meanCPU);
            }

            props.setProperty("cpuScaling", new Linear(cpuoh.getIntercept(), cpuoh.getSlope()).toString());

            // Run

            double max = Double.MIN_VALUE;
            SimpleRegression netCPU = new SimpleRegression(true);
            SimpleRegression netCPU_s = new SimpleRegression(true);
            for (int i : new int[] { 1, 100, 1000, 4000, 8000, 16000 }) {
                Map<String, Object> p = new HashMap<String, Object>();
                p.put("bench", TCPOverheadBenchmark.class.getName());
                p.put("server", new InetSocketAddress(args[0], 20000));
                p.put("samples", 5000);
                p.put("payload", i);
                Result r = calib.runReal(p);
                netCPU.addData(i, r.meanCPU);
                Result s = calib.runSimulated(p, props);
                netCPU_s.addData(i, s.meanCPU);

                double bw = 8 * i * 1e9d / r.meanLatency;
                if (bw > max)
                    max = bw;
            }

            props.setProperty("networkBandwidth", Long.toString((long) max));
            props.setProperty("tcpOverhead", new Linear((netCPU.getIntercept() - netCPU_s.getIntercept()) / 2,
                    (netCPU.getSlope() - netCPU_s.getSlope()) / 2).toString());

            SimpleRegression udpCPU = new SimpleRegression(true);
            SimpleRegression udpCPU_s = new SimpleRegression(true);
            for (int i : new int[] { 1, 100, 1000, 4000, 8000, 16000 }) {
                Map<String, Object> p = new HashMap<String, Object>();
                p.put("bench", UDPOverheadBenchmark.class.getName());
                p.put("server", new InetSocketAddress(args[0], 20000));
                p.put("samples", 5000);
                p.put("payload", i);
                Result r = calib.runReal(p);
                udpCPU.addData(i, r.meanCPU);
                Result s = calib.runSimulated(p, props);
                udpCPU_s.addData(i, s.meanCPU);
            }

            props.setProperty("udpOverhead", new Linear((udpCPU.getIntercept() - udpCPU_s.getIntercept()) / 2,
                    (udpCPU.getSlope() - udpCPU_s.getSlope()) / 2).toString());

            SimpleRegression rtt = new SimpleRegression(true);
            SimpleRegression rtt_s = new SimpleRegression(true);
            for (int i : new int[] { 1, 100, 1000, 4000, 8000, 16000 }) {
                Map<String, Object> p = new HashMap<String, Object>();
                p.put("bench", TCPLatencyBenchmark.class.getName());
                p.put("server", new InetSocketAddress(args[0], 20000));
                p.put("samples", 5000);
                p.put("payload", i);
                Result r = calib.runReal(p);
                rtt.addData(i, r.meanLatency);
                Result s = calib.runSimulated(p, props);
                rtt_s.addData(i, s.meanLatency);
            }

            props.setProperty("networkLatency", new Linear((rtt.getIntercept() - rtt_s.getIntercept()) / 2,
                    (rtt.getSlope() - rtt_s.getSlope()) / 2).toString());

            calib.close();

            for (String key : props.stringPropertyNames())
                logger.info("result: {}={}", key, props.getProperty(key));

            // Write results

            FileOutputStream file = new FileOutputStream("calibration.properties");
            props.store(file, "Generated calibration properties");
            file.close();
        }
    }
}