org.carrot2.workbench.core.ui.BenchmarkJob.java Source code

Java tutorial

Introduction

Here is the source code for org.carrot2.workbench.core.ui.BenchmarkJob.java

Source

/*
 * Carrot2 project.
 *
 * Copyright (C) 2002-2015, Dawid Weiss, Stanisaw Osiski.
 * All rights reserved.
 *
 * Refer to the full license file "carrot2.LICENSE"
 * in the root folder of the repository checkout or at:
 * http://www.carrot2.org/carrot2.LICENSE
 */

package org.carrot2.workbench.core.ui;

import static org.apache.commons.lang.SystemUtils.*;

import java.io.*;
import java.util.*;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;

import org.apache.commons.lang.mutable.MutableInt;
import org.carrot2.core.*;
import org.carrot2.core.attribute.AttributeNames;
import org.carrot2.util.CloseableUtils;
import org.carrot2.workbench.core.WorkbenchCorePlugin;
import org.carrot2.workbench.core.helpers.Utils;
import org.eclipse.core.runtime.*;
import org.eclipse.core.runtime.jobs.Job;

import com.google.common.collect.Maps;

/**
 * Actual background benchmarking job.
 */
final class BenchmarkJob extends Job {
    /**
     * Search input for this job.
     */
    private final SearchInput input;

    /**
     * A clone of benchmark settings for this job.
     */
    final BenchmarkSettings settings;

    /**
     * Public volatile statistics when the job is in progress.
     */
    public volatile BenchmarkStatistics statistics;

    /**
     * Shared log writer. You must synchronize on this object to write.
     */
    public PrintWriter logWriter;

    /**
     * Log file (if {@link #logWriter} is writing to a file).
     */
    public File logFile;

    public BenchmarkJob(SearchInput input, BenchmarkSettings settings) {
        super("Benchmarking...");

        this.settings = settings;
        this.input = input;
        this.statistics = new BenchmarkStatistics(settings.warmupRounds, settings.benchmarksRounds);
    }

    /* */
    @Override
    protected IStatus run(IProgressMonitor monitor) {
        prepareLogs();
        pushLogHeaders();

        // Create a pool of executing threads.
        final int totalRounds = settings.getTotalRounds();
        final CountDownLatch latch = new CountDownLatch(1);
        final MutableInt rounds = new MutableInt(totalRounds);
        final Callable<Long> benchmarkRunner = createBenchmarkRunner();
        final Thread[] pool = createBenchmarkThreads(latch, rounds, monitor, benchmarkRunner);

        // Start all benchmark threads at once and wait for all of them to finish.
        monitor.beginTask("Running...", totalRounds);
        latch.countDown();
        for (Thread t : pool) {
            try {
                t.join();
            } catch (InterruptedException e) {
                // If interrupted, fall through, but terminate all threads whenever possible.
                monitor.setCanceled(true);
            }
        }

        synchronized (logWriter) {
            if (monitor.isCanceled()) {
                logWriter.println("# (cancelled)");
            } else {
                logWriter.println("# Statistics:");
                logWriter.println("# " + statistics.toString());
            }
        }

        monitor.done();
        CloseableUtils.close(logWriter);

        return Status.OK_STATUS;
    }

    /**
     * Return the benchmark runner.
     */
    private Callable<Long> createBenchmarkRunner() {
        final WorkbenchCorePlugin core = WorkbenchCorePlugin.getDefault();
        final Controller controller = core.getController();

        final ProcessingComponentDescriptor source = core.getComponent(input.getSourceId());
        final ProcessingComponentDescriptor algorithm = core.getComponent(input.getAlgorithmId());

        final Map<String, Object> attributes = Maps.newHashMap(input.getAttributeValueSet().getAttributeValues());

        return new Callable<Long>() {
            public Long call() throws Exception {
                final long start = System.currentTimeMillis();
                controller.process(attributes, source.getId(), algorithm.getId());
                return System.currentTimeMillis() - start;
            }
        };
    }

    /**
     * Create a set of benchmark threads.
     */
    private Thread[] createBenchmarkThreads(final CountDownLatch latch, final MutableInt rounds,
            final IProgressMonitor monitor, final Callable<Long> benchmarkRunner) {
        final Thread[] pool = new Thread[settings.threads];
        for (int i = 0; i < settings.threads; i++) {
            final int threadID = i + 1;
            pool[i] = new Thread() {
                public void run() {
                    while (!Thread.currentThread().isInterrupted()) {
                        final int totalRounds = settings.warmupRounds + settings.benchmarksRounds;
                        final int round;
                        synchronized (logWriter) {
                            round = rounds.intValue();
                            if (round == 0 || monitor.isCanceled()) {
                                // Exit if tests finished.
                                return;
                            }
                            rounds.decrement();
                        }

                        long time;
                        try {
                            time = benchmarkRunner.call();
                        } catch (Exception e) {
                            Utils.logError(e, false);
                            time = 0;
                        }

                        synchronized (logWriter) {
                            logWriter.format(Locale.ENGLISH, "%2d  %4d  %8.03f\n", threadID, totalRounds - round,
                                    time / 1000d);

                            statistics = statistics.update((int) time);
                            monitor.worked(1);
                        }
                    }
                }
            };
            pool[i].setName("benchmark-" + i);
            pool[i].setPriority(settings.priority.threadPriority);
            pool[i].start();
        }

        return pool;
    }

    /**
     * Push log headers.
     */
    private void pushLogHeaders() {
        if (logWriter == null)
            return;

        logWriter.println("# Benchmarking log.");
        logWriter.println("# ");
        logWriter.println("# Source: " + input.getSourceId());
        logWriter.println("# Algorithm: " + input.getAlgorithmId());
        logWriter.println("# Query: " + input.getAttribute(AttributeNames.QUERY));
        logWriter.println("# Results: " + input.getAttribute(AttributeNames.RESULTS));
        logWriter.println("# ");
        logWriter.println(
                "# JVM: " + JAVA_VM_NAME + ", " + JAVA_VM_VERSION + ", " + JAVA_VM_INFO + ", " + JAVA_VM_VENDOR);
        logWriter.println("# OS arch: " + OS_ARCH + ", name: " + OS_NAME + ", version: " + OS_VERSION);
        logWriter.println("# ");
        logWriter.println("# Benchmark rounds: " + settings.benchmarksRounds);
        logWriter.println("# Warmup rounds: " + settings.warmupRounds);
        logWriter.println("# Threads: " + settings.threads + " (available CPUs or cores: "
                + Runtime.getRuntime().availableProcessors() + "), " + "running at " + settings.priority
                + " priority.");
        logWriter.println("# ");
        logWriter.println("# thread_id  round_number  time[s]");
    }

    /**
     * Prepare log output.
     */
    private void prepareLogs() {
        final String logName = String.format(Locale.ENGLISH, "benchmark_%1$tF_%1$tH-%1$tM-%1$tS.txt", new Date());

        try {
            if (this.settings.logDirectory != null) {
                this.logFile = new File(settings.logDirectory, logName);
            } else {
                this.logFile = new File(System.getProperty("java.io.tmpdir", "."), logName);
            }
            this.logWriter = new PrintWriter(logFile, "UTF-8");
        } catch (IOException e) {
            Utils.logError(e, false);

            this.logFile = null;
            this.logWriter = null;
        }
    }
}