notaql.performance.PerformanceTest.java Source code

Java tutorial

Introduction

Here is the source code for notaql.performance.PerformanceTest.java

Source

/*
 * Copyright 2015 by Thomas Lottermann
 *
 * 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 notaql.performance;

import notaql.NotaQL;
import org.apache.commons.cli.*;
import org.json.JSONArray;
import org.json.JSONObject;

import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.file.*;
import java.time.Duration;
import java.time.Instant;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;

/**
 * TODO: The mongodb collections must be compacted before running performance tests!
 */
public class PerformanceTest {
    private static final String BASE_PATH = "/performanceTest/tests";
    private static final int RUNS = 5;

    private static String inEngine = null;
    private static String outEngine = null;
    private static String testCase = null;

    public static void main(String... args) throws IOException, URISyntaxException, ParseException {
        final Options options = new Options();
        options.addOption("c", "config", true, "The notaql config file.");
        options.addOption("i", "inengine", true, "Execute for certain input engines");
        options.addOption("o", "outengine", true, "Execute for certain output engines");
        options.addOption("t", "test", true, "Execute certain test case only");

        final CommandLineParser parser = new PosixParser();
        final CommandLine cmd = parser.parse(options, args);

        if (cmd.hasOption("config")) {

            final String path = cmd.getOptionValue("config");

            NotaQL.loadConfig(path);
        }

        inEngine = cmd.getOptionValue("inengine");
        outEngine = cmd.getOptionValue("outengine");
        testCase = cmd.getOptionValue("test");

        runTests();
    }

    public static void runTests() throws URISyntaxException, IOException {
        URI basePath = NotaQL.class.getResource(BASE_PATH).toURI();

        Map<String, String> env = new HashMap<>();
        env.put("create", "true");
        FileSystem zipfs = FileSystems.newFileSystem(basePath, env);

        final List<Path> tests = Files.list(Paths.get(basePath)).filter(p -> p.toString().endsWith(".json"))
                .sorted((a, b) -> a.toString().compareTo(b.toString())).collect(Collectors.toList());

        List<String> csv = new LinkedList<>();

        for (Path test : tests) {
            if (testCase != null && !test.getFileName().toString().equals(testCase))
                continue;

            final List<JSONObject> transformations = readArray(test);

            csv.add(test.getFileName().toString());

            int i = 1;

            for (JSONObject transformation : transformations) {
                final String name = transformation.getString("name");
                final String notaqlTransformation = composeTransformation(transformation);

                if (!(inEngine == null && outEngine == null
                        || inEngine != null
                                && transformation.getJSONObject("IN-ENGINE").getString("engine").equals(inEngine)
                        || outEngine != null && transformation.getJSONObject("OUT-ENGINE").getString("engine")
                                .equals(outEngine)))
                    continue;

                System.out.println("Evaluation test (" + i++ + "/" + transformations.size() + "): "
                        + test.getFileName() + ": " + name);

                List<Duration> durations = new LinkedList<>();

                for (int j = 0; j < RUNS; j++) {
                    clean(transformation);

                    final Instant startTime = Instant.now();

                    NotaQL.evaluate(notaqlTransformation);

                    final Instant endTime = Instant.now();

                    final Duration duration = Duration.between(startTime, endTime);

                    durations.add(duration);

                    System.out.println("Testrun(" + j + ") " + name + " took: " + duration);
                }

                System.out.println("!!=================================================================!!");

                System.out.println("Test " + name + " took: "
                        + durations.stream().map(Duration::toString).collect(Collectors.joining(", ")));

                System.out.println("Test " + name + " took millis: " + durations.stream()
                        .map(d -> Long.toString(d.toMillis())).collect(Collectors.joining(", ")));

                System.out.println("Test " + name + " took on average (millis): "
                        + durations.stream().mapToLong(Duration::toMillis).average());

                System.out.println("Test " + name + " took on average (ignoring first - millis): "
                        + durations.stream().skip(1).mapToLong(Duration::toMillis).average());

                System.out.println("!!=================================================================!!");

                csv.add(name);
                csv.add(durations.stream().map(d -> Long.toString(d.toMillis())).collect(Collectors.joining(",")));
            }

        }

        System.out.println(csv.stream().collect(Collectors.joining("\n")));
    }

    private static void clean(JSONObject transformation) throws IOException {
        final JSONObject outEngine = transformation.getJSONObject("OUT-ENGINE");

        final String engineName = outEngine.getString("engine");
        if (engineName.equals("csv")) {
            deleteRecursive(Paths.get(outEngine.getString("csv_path")));
        }
        if (engineName.equals("json")) {
            deleteRecursive(Paths.get(outEngine.getString("path")));
        }
    }

    private static void deleteRecursive(Path path) throws IOException {
        if (!Files.exists(path))
            return;

        Files.walk(path).sorted((a, b) -> b.compareTo(a)). // reverse; files before dirs
                forEach(p -> {
                    try {
                        Files.delete(p);
                    } catch (IOException e) {
                        /* ... */ }
                });
    }

    private static String composeTransformation(JSONObject transformation) {
        final JSONObject inEngine = transformation.getJSONObject("IN-ENGINE");
        final JSONObject outEngine = transformation.getJSONObject("OUT-ENGINE");
        final String mapping = transformation.getString("transformation");

        return "IN-ENGINE: " + composeEngine(inEngine) + ",\n" + "OUT-ENGINE: " + composeEngine(outEngine) + ",\n"
                + mapping;
    }

    private static String composeEngine(JSONObject engine) {
        final StringBuilder builder = new StringBuilder();
        builder.append(engine.get("engine"));
        builder.append("(");

        final String params = StreamSupport
                .stream(Spliterators.spliteratorUnknownSize(engine.keys(), Spliterator.ORDERED), false)
                .filter(k -> !k.equals("engine")).map(k -> k + " <- " + toArg(k, engine))
                .collect(Collectors.joining(", "));

        builder.append(params);
        builder.append(")");

        return builder.toString();
    }

    private static String toArg(String key, JSONObject engine) {
        final Object val = engine.get(key);
        if (val instanceof Boolean || val instanceof Number)
            return val.toString();

        return "'" + val.toString() + "'";
    }

    private static List<JSONObject> readArray(Path path) throws IOException {
        final String input = Files.lines(path).collect(Collectors.joining());
        final JSONArray jsonArray = new JSONArray(input);

        final List<JSONObject> elements = new LinkedList<>();
        for (int i = 0; i < jsonArray.length(); i++) {
            final Object element = jsonArray.get(i);
            if (!(element instanceof JSONObject))
                throw new IOException("Expecting an array of objects as input.");
            elements.add((JSONObject) element);
        }

        return elements;
    }
}