Package se.llbit.chunky.renderer

Source Code of se.llbit.chunky.renderer.BenchmarkManager

/* Copyright (c) 2012-2013 Jesper Öqvist <jesper@llbit.se>
*
* This file is part of Chunky.
*
* Chunky 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 3 of the License, or
* (at your option) any later version.
*
* Chunky 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 Chunky.  If not, see <http://www.gnu.org/licenses/>.
*/
package se.llbit.chunky.renderer;

import java.io.IOException;
import java.util.concurrent.atomic.AtomicInteger;

import org.apache.log4j.Logger;

import se.llbit.chunky.renderer.scene.Scene;
import se.llbit.chunky.renderer.scene.SceneLoadingError;

/**
* Benchmarks the renderer.
* @author Jesper Öqvist <jesper@llbit.se>
*/
public class BenchmarkManager extends AbstractRenderManager {
  /**
   * Default number of worker threads.
   * Is set to the number of available CPU cores.
   */
  public static final int NUM_RENDER_THREADS_DEFAULT =
      Runtime.getRuntime().availableProcessors();

  private static final Logger logger =
      Logger.getLogger(BenchmarkManager.class);

  private final Thread[] workers;

  private final int numJobs;

  /**
    * The benchmark scene.
    */
  private final Scene scene;

  /**
   * Next job on the job queue.
   */
  private final AtomicInteger nextJob;

  /**
   * Number of completed jobs.
   */
  private final AtomicInteger finishedJobs;

  private final RenderStatusListener renderListener;

  private final static String BENCHMARK_NAME = "benchmark-1";

  private int score;

  /**
   * Constructor
   * @param context
   * @param renderStatusListener
   */
  public BenchmarkManager(RenderContext context,
      RenderStatusListener renderStatusListener) {

    super(context);

    context = new EmbeddedResourceContext(context);

    renderListener = renderStatusListener;

    scene = new Scene();
    try {
      scene.loadScene(context,
          renderStatusListener, BENCHMARK_NAME);
    } catch (IOException e) {
      logger.warn("Failed to load benchmark scene!", e);
    } catch (SceneLoadingError e) {
      logger.warn("Failed to load benchmark scene!", e);
    } catch (InterruptedException e) {
      logger.warn("Interrupted while loading benchmark scene");
    }

    scene.setBufferFinalization(false);

    int canvasWidth = scene.canvasWidth();
    int canvasHeight = scene.canvasHeight();
    numJobs = ((canvasWidth+(tileWidth-1)) / tileWidth) *
        ((canvasHeight+(tileWidth-1)) / tileWidth);
    nextJob = new AtomicInteger(0);
    finishedJobs = new AtomicInteger(0);

    // start worker threads
    long seed = System.currentTimeMillis();
    workers = new Thread[numThreads];
    for (int i = 0; i < numThreads; ++i) {
      workers[i] = new RenderWorker(this, i, seed + i);
      workers[i].start();
    }
  }

  @Override
  public void run() {
    try {

      long millis;

      String task = "Benchmarking";
      renderListener.setProgress(task, 0, 0, 120);

      // warm up ten iterations with JIT enabled
      java.lang.Compiler.enable();
      scene.refresh();
      for (int i = 0; i < 10; ++i) {
        renderListener.setProgress(task, i, 0, 120);
        giveTickets();
        waitOnWorkers();
      }

      // warm up ten iterations with JIT disabled
      java.lang.Compiler.disable();
      scene.refresh();
      for (int i = 0; i < 10; ++i) {
        renderListener.setProgress(task, i+10, 0, 120);
        giveTickets();
        waitOnWorkers();
      }

      // time 100 iterations with JIT disabled
      millis = System.currentTimeMillis();
      scene.refresh();
      for (int i = 0; i < 100; ++i) {
        renderListener.setProgress(task, i+20, 0, 120);
        giveTickets();
        waitOnWorkers();
      }
      millis = System.currentTimeMillis() - millis;

      int canvasWidth = scene.canvasWidth();
      int canvasHeight = scene.canvasHeight();
      long pixelsPerFrame = canvasWidth * canvasHeight;
      score = (int) ((100 * pixelsPerFrame) / (millis / 1000.0));

      renderListener.setProgress(task, 120, 0, 120);

    } catch (InterruptedException e) {
      // 3D view was closed
    } catch (Throwable e) {
      logger.error("Uncaught exception in render manager", e);
    }

    // Halt all worker threads
    for (int i = 0; i < numThreads; ++i) {
      workers[i].interrupt();
    }
  }

  private synchronized void waitOnWorkers() throws InterruptedException {
    while (finishedJobs.get() < numJobs)
      wait();
  }

  private synchronized void giveTickets() {
    nextJob.set(0);
    finishedJobs.set(0);
    notifyAll();
  }

  @Override
  public int getNextJob() throws InterruptedException {
    int jobId = nextJob.getAndIncrement();
    if (jobId >= numJobs) {
      synchronized (this) {
        do {
          wait();
          jobId = nextJob.getAndIncrement();
        } while (jobId >= numJobs);
      }
    }
    return jobId;
  }

  @Override
  public void jobDone() {
    int finished = finishedJobs.incrementAndGet();
    if (finished >= numJobs) {
      synchronized (this) {
        notifyAll();
      }
    }
  }

  @Override
  public Scene bufferedScene() {
    return scene;
  }

  /**
   * @return The benchmark score
   */
  public int getScore() {
    return score;
  }

  /**
   * @return The name of the benchmark scene
   */
  public String getSceneName() {
    return BENCHMARK_NAME;
  }
}
TOP

Related Classes of se.llbit.chunky.renderer.BenchmarkManager

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.