Package co.paralleluniverse.spaceships

Source Code of co.paralleluniverse.spaceships.Spaceships

/*
* Copyright (C) 2013 Parallel Universe Software Co.
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package co.paralleluniverse.spaceships;

import co.paralleluniverse.actors.Actor;
import co.paralleluniverse.actors.ActorSpec;
import co.paralleluniverse.actors.behaviors.Supervisor;
import co.paralleluniverse.actors.behaviors.SupervisorActor;
import co.paralleluniverse.common.monitoring.Counter;
import co.paralleluniverse.common.monitoring.CpuUsageGaugeSet;
import co.paralleluniverse.common.monitoring.Metrics;
import co.paralleluniverse.common.monitoring.MonitorType;
import co.paralleluniverse.data.record.Record;
import co.paralleluniverse.db.store.galaxy.GalaxyStore;
import co.paralleluniverse.db.store.galaxy.MigrationListener;
import co.paralleluniverse.fibers.*;
import co.paralleluniverse.galaxy.Grid;
import co.paralleluniverse.spacebase.AABB;
import co.paralleluniverse.spacebase.quasar.SpaceBase;
import co.paralleluniverse.spacebase.quasar.SpaceBaseBuilder;
import static co.paralleluniverse.spaceships.SpaceshipState.$spaceship;
import co.paralleluniverse.spaceships.render.GLPort;
import co.paralleluniverse.strands.concurrent.Phaser;
import com.codahale.metrics.jvm.MemoryUsageGaugeSet;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.util.Properties;
import java.util.concurrent.TimeUnit;

public class Spaceships {
    public static Spaceships spaceships;
    public static final int POSTPONE_GLPORT_UNTIL_SB_CYCLE_UNDER_X_MILLIS = 250;

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) throws Exception {
        System.out.println("COMPILER: " + System.getProperty("java.vm.name"));
        System.out.println("VERSION: " + System.getProperty("java.version"));
        System.out.println("OS: " + System.getProperty("os.name"));
        System.out.println("PROCESSORS: " + Runtime.getRuntime().availableProcessors());
        System.out.println();

        Properties props = new Properties();
        props.load(new InputStreamReader(ClassLoader.getSystemResourceAsStream("spaceships.properties")));

//        Metrics.register("cpu", new CpuUsageGaugeSet());
//        Metrics.register("memory", new MemoryUsageGaugeSet());
        int glxNode = args.length > 0 ? Integer.parseInt(args[0]) : -1;
        if (glxNode < 0)
            glxNode = Integer.parseInt(props.getProperty("galaxy.nodeId", "-1"));

        if (glxNode >= 0) {
            if (glxNode == 0)
                throw new IllegalArgumentException("Node cannot be 0. Reserved for Galaxy server.");
            System.out.println("Connecting to Galaxy cluster...");

            System.setProperty("co.paralleluniverse.flightRecorderDumpFile", "spaceships-" + glxNode + ".log");

            System.setProperty("galaxy.nodeId", Integer.toString(glxNode));
            System.setProperty("galaxy.port", props.getProperty("galaxy.port", Integer.toString(7050 + glxNode)));
            System.setProperty("galaxy.slave_port", props.getProperty("galaxy.port", Integer.toString(8050 + glxNode)));
            Grid.getInstance();
        }

        System.out.println("Initializing...");
        spaceships = new Spaceships(glxNode, props);

        System.out.println("Running...");
        spaceships.run();

        Thread.sleep(100000);
    }
    //
    private final int glxNode;
    private final GLPort.Toolkit toolkit;
    public final SpaceBase<Record<SpaceshipState>> sb;
    private GLPort port = null;
    public final RandSpatial random;
    //
    private final int N;
    public final AABB bounds;
    public final boolean extrapolate;
    public final double speedVariance;
    public final double range;
    private final Phaser phaser;
    private File metricsDir;
    private PrintStream configStream;
    private PrintStream timeStream;
    final Counter spaceshipsCycles = new Counter();
    //
    private long cycleStart;

    public Spaceships(int node, Properties props) throws Exception {
        if (props.getProperty("parallelism") != null)
            System.setProperty("co.paralleluniverse.fibers.DefaultFiberPool.parallelism", props.getProperty("parallelism"));
        final int parallelism = ((FiberForkJoinScheduler) DefaultFiberScheduler.getInstance()).getForkJoinPool().getParallelism();// Integer.parseInt(props.getProperty("parallelism", "2"));

        this.glxNode = node;

        final double b = Double.parseDouble(props.getProperty("world-length", "20000"));
        if (node < 0) {
            this.bounds = AABB.create(-b / 2, b / 2, -b / 2 * 0.7, b / 2 * 0.7);
        } else {
            final double northSign;
            final double eastSign;
            switch (node) {
                case 1:
                    northSign = 1.0;
                    eastSign = 1.0;
                    break;
                case 2:
                    northSign = 1.0;
                    eastSign = -1.0;
                    break;
                case 3:
                    northSign = -1.0;
                    eastSign = 1.0;
                    break;
                case 4:
                    northSign = -1.0;
                    eastSign = -1.0;
                    break;
                default:
                    throw new IllegalArgumentException("Node must be between 1 and 4 (inclusive)"); // arbitrary; so only becuase we divide the world into 4 quadrants
            }
            this.bounds = AABB.create(Math.min(0, eastSign * b), Math.max(0, eastSign * b), Math.min(0, northSign * b), Math.max(0, northSign * b));
        }

        this.N = Integer.parseInt(props.getProperty("N", "10000"));
        this.speedVariance = Double.parseDouble(props.getProperty("speed-variance", "1"));
        this.range = Double.parseDouble(props.getProperty("radar-range", "10"));
        this.extrapolate = Boolean.parseBoolean(props.getProperty("extrapolate", "true"));

        this.phaser = Boolean.parseBoolean(props.getProperty("phaser", "false")) ? new Phaser() : null;

        if (props.getProperty("dir") != null) // collect performance metrics in csv files
            createMetricsFiles(props);

        println("Galaxy node: " + (glxNode > 0 ? glxNode : " NOT DISTRIBUTED"));
        println("World bounds: " + bounds);
        println("N: " + N);
        println("Parallelism: " + parallelism);
        println("Phaser: " + (phaser != null));
        println("Extrapolate: " + extrapolate);
        println();

        this.random = new RandSpatial();

        this.sb = initSpaceBase(props);
        // sb.setDefaultTimeoutMillis(1000);

        this.toolkit = GLPort.Toolkit.valueOf(props.getProperty("ui-component", "NEWT").toUpperCase());

        println("UI Component: " + toolkit);
    }

    private void createMetricsFiles(Properties props) throws FileNotFoundException {
        this.metricsDir = new File(System.getProperty("user.home") + "/" + props.getProperty("dir"));

        if (metricsDir.isDirectory()) {
            for (File file : metricsDir.listFiles())
                file.delete();
        }
        metricsDir.mkdir();

        final File configFile = new File(metricsDir, "config.txt");
        this.configStream = new PrintStream(new FileOutputStream(configFile), true);

        final File timeFile = new File(metricsDir, "times.csv");
        this.timeStream = new PrintStream(new FileOutputStream(timeFile), true);
    }

    public co.paralleluniverse.spacebase.SpaceBase<Record<SpaceshipState>> getPlainSpaceBase() {
        return co.paralleluniverse.spacebase.SpaceBaseBuilder.from(sb);
    }

    /**
     * reads properties file and creates a SpaceBase instance with the requested properties.
     */
    private SpaceBase<Record<SpaceshipState>> initSpaceBase(Properties props) {
        final boolean optimistic = Boolean.parseBoolean(props.getProperty("optimistic", "true"));
        final int optimisticHeight = Integer.parseInt(props.getProperty("optimistic-height", "1"));
        final int optimisticRetryLimit = Integer.parseInt(props.getProperty("optimistic-retry-limit", "3"));
        final boolean compressed = Boolean.parseBoolean(props.getProperty("compressed", "false"));
        final boolean singlePrecision = Boolean.parseBoolean(props.getProperty("single-precision", "false"));
        final int nodeWidth = Integer.parseInt(props.getProperty("node-width", "10"));

        println("SpaceBase properties");
        println("Optimistic: " + optimistic);
        println("Optimistic height: " + optimisticHeight);
        println("Optimistic retry limit: " + optimisticRetryLimit);
        println("Node width: " + nodeWidth);
        println("Compressed: " + compressed);
        println("Single precision: " + singlePrecision);
        println();

        SpaceBaseBuilder builder = new SpaceBaseBuilder();

        if (glxNode > 0)
            builder.setStore(GalaxyStore.class);

        builder.setQueueBackpressure(1000);

        if (optimistic)
            builder.setOptimisticLocking(optimisticHeight, optimisticRetryLimit);
        else
            builder.setPessimisticLocking();

        builder.setDimensions(2);

        builder.setSinglePrecision(singlePrecision).setCompressed(compressed);
        builder.setNodeWidth(nodeWidth);

        builder.setMonitoringType(MonitorType.JMX);
        if (metricsDir != null) {
            com.codahale.metrics.CsvReporter.forRegistry(Metrics.registry())
                    .convertRatesTo(TimeUnit.SECONDS)
                    .convertDurationsTo(TimeUnit.MILLISECONDS)
                    .build(metricsDir)
                    .start(1, TimeUnit.SECONDS);
        }

        final SpaceBase<Record<SpaceshipState>> space = builder.build("base1");

        if (glxNode > 0) {
            GalaxyStore store = (GalaxyStore) space.getStore();
//            store.addMigrationListener(new MigrationListener<Record<SpaceshipState>>() {
//
//                @Override
//                public void immigrating(Record<SpaceshipState> record) {
//                    try {
//                        Actor.hire(record.get($spaceship));
//                    } catch (SuspendExecution e) {
//                        throw new AssertionError(e);
//                    }
//                }
//
//                @Override
//                public void emigrating(Record<SpaceshipState> record) {
//                    try {
//                        Actor.xxx(record.get($spaceship));
//                    } catch (SuspendExecution e) {
//                        throw new AssertionError(e);
//                    }
//                }
//            });
        }

        return space;
    }

    /**
     * Main loop: loops over all spaceships and initiates each spaceship's actions. Simulates an IO thread receiving commands over the net.
     */
    private void run() throws Exception {
        final Supervisor sup = new SupervisorActor(SupervisorActor.RestartStrategy.ONE_FOR_ONE) {
            @Override
            protected void init() throws InterruptedException, SuspendExecution {
                for (int i = 0; i < N; i++)
                    addChild(new Supervisor.ChildSpec("ship-" + i, Supervisor.ChildMode.PERMANENT, 5, 1, TimeUnit.SECONDS, 3, ActorSpec.of(Spaceship.class, Spaceships.this, i, phaser)));
            }
        }.spawn();

        Thread.sleep(5000); // wait for things to optimize a bit.
        port = new GLPort(toolkit, N + 20, Spaceships.this, bounds, glxNode);

        if (timeStream != null)
            timeStream.println("# time, millis, millis1, millis0");

        if (true || phaser == null) {
            long prevTime = System.nanoTime();
            for (int k = 0;; k++) {
                Thread.sleep(1000);
                long cycles = spaceshipsCycles.getAndReset();
                long now = System.nanoTime();

                double seconds = (double) (now - prevTime) * 1e-9;
                double frames = (double) cycles / (double) N;

                double fps = frames / seconds;
                System.out.println(k + "\tRATE: " + fps + " fps");

                prevTime = now;
            }
        } else {
            for (int k = 0;; k++) {
                cycleStart = System.nanoTime();

                phaser.awaitAdvance(k);
                //phaser.arriveAndAwaitAdvance();

                float millis = millis(cycleStart);
                if (timeStream != null)
                    timeStream.println(k + "," + millis);

                if (millis(cycleStart) < 10) // don't work too hard: if the cycle has taken less than 10 millis, wait a little.
                    Thread.sleep(10 - (int) millis(cycleStart));

                millis = millis(cycleStart);

                System.out.println("CYCLE: " + millis + " millis ");
            }
        }
    }

    public long now() {
        return System.currentTimeMillis();
    }

    private float millis(long nanoStart) {
        return (float) (System.nanoTime() - nanoStart) / 1000000;
    }

    private void println() {
        println("");
    }

    private void println(String str) {
        if (configStream != null)
            configStream.println(str);
        System.out.println(str);
    }
}
TOP

Related Classes of co.paralleluniverse.spaceships.Spaceships

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.