All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.diirt.graphene.profile.MultiLevelProfiler Maven / Gradle / Ivy

There is a newer version: 3.1.7
Show newest version
/**
 * Copyright (C) 2010-14 diirt developers. See COPYRIGHT.TXT
 * All rights reserved. Use is subject to license terms. See LICENSE.TXT
 */
package org.diirt.graphene.profile;

import java.awt.image.BufferedImage;
import java.io.File;
import org.diirt.graphene.profile.settings.SaveSettings;
import org.diirt.graphene.profile.utils.Statistics;
import org.diirt.graphene.profile.utils.Resolution;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.diirt.graphene.Point2DDataset;
import org.diirt.graphene.Point2DDatasets;
import org.diirt.graphene.profile.image.ShowResizableGraph;
import org.diirt.graphene.profile.io.CSVWriter;
import org.diirt.graphene.profile.io.DateUtils;
import org.diirt.graphene.profile.io.ImageWriter;
import org.diirt.graphene.profile.utils.DatasetFactory;

/**
 * Handles the profiling for testing rendering (specifically the draw) of a
 * Graph2DRenderer through sets of testing settings.
 * Has a ProfileGraph2D with the type of the
 * Graph2DRenderer being profiled.
 * 

* Enables the profile object to be profile at various image resolutions * and dataset sizes. These statistics may then be graphed or saved. * * @author asbarber */ public class MultiLevelProfiler{ private ProfileGraph2D profiler; private List resolutions; private List datasetSizes; private Map> results; private Map> images; /** * Creates a object to profile a Graph2DRenderer * using a ProfileGraph2D and analyzing performance * through various sets of renderings at specified intervals * of data sizes and image resolution sizes. * * @param profiler graph renderer with given profile settings to * do extensive testing on */ public MultiLevelProfiler(ProfileGraph2D profiler){ this.profiler = profiler; this.results = new HashMap<>(); this.images = new HashMap<>(); } //Profile Running /** * Runs through the list of dataset sizes paired with every element * from the list of image resolutions to profile a * ProfileGraph2D to analyze the performance of the graph * renderer and how the performance is effected by data size and * image size. *
* Precondition: the set of dataset sizes and the set of resolutions to * test are both not null and not empty. *
* A mapping of results is created to link dataset size, resolution, * and statistics. * This is done by creating a map, map_A, for a link between * the statistics and the dataset size, and mapping map_A * to a second map for every resolution. * * @see #getResults() */ public void profile(){ if (datasetSizes == null || datasetSizes.isEmpty()){ throw new NullPointerException("Use the setter to list dataset sizes."); } if (resolutions == null || resolutions.isEmpty()){ throw new NullPointerException("Use the setter to list resolutions."); } //Can give warning about how long this method will profile this.processTimeWarning(datasetSizes.size() * resolutions.size() * profiler.getProfileSettings().getTestTime()); //Loop through combinations of settings for (int r = 0; r < resolutions.size() && !Thread.currentThread().isInterrupted(); r++){ HashMap map = new HashMap<>(); HashMap imageMap = new HashMap<>(); for (int s = 0; s < datasetSizes.size() && !Thread.currentThread().isInterrupted(); s++){ //Use this to process before the result, such as to print to console this.processPreResult(resolutions.get(r), datasetSizes.get(s)); //Apply settings profiler.setNumDataPoints(datasetSizes.get(s)); profiler.getResolution().setWidth(resolutions.get(r).getWidth()); profiler.getResolution().setHeight(resolutions.get(r).getHeight()); //Profiler profiler.profile(); //Track results (dataset size and statistics) map.put(datasetSizes.get(s), profiler.getStatistics()); imageMap.put(datasetSizes.get(s), profiler.getSaveSettings().getSaveImage()); //Use to process the result, such as print to console this.processResult(resolutions.get(r), datasetSizes.get(s), profiler.getStatistics()); } //Put dataSize & statistics map into resolution set results.put(resolutions.get(r), map); images.put(resolutions.get(r), imageMap); } } //Post-Run Options /** * A mapping that gets the results of profiler that * maps a statistics result to every dataset size that is * mapped to every resolution. *

* The keys to the outer map are the set of resolutions. * The keys to the inner map are the set of dataset sizes. * The value of the outer map is the inner map. * The value of the inner map is the statistics of the profiling. * * Precondition: #profile() has been called. * * @return a mapping that gets the results of running the profiler * associated resolution sizes to dataset sizes to statistical timing * results */ public Map> getResults(){ if (results == null){ throw new NullPointerException("Profiling has not been run."); } return results; } /** * Forms a set of point 2D data for each resolution profiled * where the point is composed of the number of data points profiled * and the average profile time. * * Each point has the form (size, time). * * @return lines for each resolution composed of average profile time and * dataset size points, with the point have the form (size, time) */ public List getStatisticLineData(){ List allLines = new ArrayList<>(); //Resolution[] keys for resolutions Object[] resolutionKeys = results.keySet().toArray(); //Resolution Map for (int i = 0; i < results.size(); i++){ Resolution resolution = (Resolution) resolutionKeys[i]; Map map = results.get(resolution); //Integer[] keys for dataset sizes Object[] sizeKeys = map.keySet().toArray(); double[] sizes = new double[map.size()]; double[] times = new double[map.size()]; //Dataset Size Map for (int j = 0; j < map.size(); j++){ Integer size = (Integer) sizeKeys[j]; Statistics stats = map.get(size); sizes[j] = size; times[j] = stats.getAverageTime(); } Point2DDataset data = Point2DDatasets.lineData(sizes, times); allLines.add(data); } return allLines; } /** * Displays a separate frame for every profile operation * performed. * * Plots the sizes on the x-axis and the times on the y-axis. * * Precondition: #profile() has been called. */ public void graphStatistics(){ if (results == null){ throw new NullPointerException("Profiling has not been run."); } List lines = getStatisticLineData(); for (Point2DDataset data: lines){ ShowResizableGraph.showLineGraph(data); } } /** * Creates a table (.CSV format) to display the results, * with the dataset sizes as the row heading and the * resolution as the column heading. *

* Saves the CSV file to the same directory as general profile results, * with the specific profile graph type as well as the date. * * Precondition: results is non-null and not empty, meaning profiling * has been completed. */ public void saveStatistics(){ if (Thread.currentThread().isInterrupted()){ return; } if (results == null){ throw new NullPointerException("Profiling has not been run."); } //Should not occur since resolutions must be non-empty if (results.isEmpty()){ return; } //Assumption: the set of keys for dataset sizes are the same //for each line (the Map keys are equivalent for //each resolutioin) Resolution[] resKeys = results.keySet().toArray(new Resolution[0]); Integer[] sizeKeys = results.get(resKeys[0]).keySet().toArray(new Integer[0]); List data = new ArrayList(); //Sorts keys so table has sorted columns/rows Arrays.sort(resKeys); Arrays.sort(sizeKeys); //For all dataset sizes for (int i = 0; i < sizeKeys.length; i++){ ArrayList row = new ArrayList(); //Dataset column row.add(sizeKeys[i]); //Finds the timings for the dataset size for all resolutions for (int j = 0; j < resKeys.length; j++){ row.add( String.format("%.3f", results.get(resKeys[j]).get(sizeKeys[i]).getAverageTime() )); } data.add(row); } String filename = ProfileGraph2D.LOG_FILEPATH + DateUtils.getDate(DateUtils.DateFormat.NONDELIMITED) + "-" + profiler.getGraphTitle() + "-" + "Table2D"; File output = CSVWriter.createFile(filename); CSVWriter.writeRow(output, CSVWriter.arrayCombine("", resKeys)); CSVWriter.writeData(output, data); saveAdditionalInfo(filename); } /** * Creates a table (.out.CSV format) to display the save settings, * such as author, dataset message, save message, * as well as information about the physical computer profiling. *

* Saves the CSV file to the same directory as general profile results, * with the specific profile graph type as well as the date. */ private void saveAdditionalInfo(String filename){ File output = CSVWriter.createFile(filename + ".out"); CSVWriter.writeRow(output, CSVWriter.arrayCombine( "Graph Type", "Date", profiler.getProfileSettings().getTitle(), profiler.getRenderSettings().getTitle(), profiler.getSaveSettings().getTitle() )); CSVWriter.writeRow(output, CSVWriter.arrayCombine( profiler.getGraphTitle(), DateUtils.getDate(DateUtils.DateFormat.DELIMITED), profiler.getProfileSettings().getOutput(), profiler.getRenderSettings().getOutput(), profiler.getSaveSettings().getOutput() )); } /** * Saves the images generated by the profiling. * Saves the image files to a directory with the specific profile graph * type as well as the date. * * * Precondition: images is non-null and not empty, meaning profiling * has been completed. */ public void saveImages(){ if (Thread.currentThread().isInterrupted()){ return; } if (images == null){ throw new NullPointerException("Profiling has not been run."); } //Should not occur since resolutions must be non-empty if (images.isEmpty()){ return; } //Makes directory //-------------------------------------------------------------- String path = ProfileGraph2D.LOG_FILEPATH + DateUtils.getDate(DateUtils.DateFormat.NONDELIMITED) + "-" + profiler.getGraphTitle() + "-" + "Table2D"; boolean success = (new File(path)).mkdir(); //Failed to make directory if (!success){ return; } //-------------------------------------------------------------- //Assumption: the set of keys for dataset sizes are the same //for each line (the Map keys are equivalent for //each resolutioin) Resolution[] resKeys = images.keySet().toArray(new Resolution[0]); Integer[] sizeKeys = images.get(resKeys[0]).keySet().toArray(new Integer[0]); //Sorts keys so table has sorted columns/rows Arrays.sort(resKeys); Arrays.sort(sizeKeys); //For all dataset sizes for (int i = 0; i < sizeKeys.length; i++){ //For all resolutions for (int j = 0; j < resKeys.length; j++){ BufferedImage img = images.get(resKeys[j]).get(sizeKeys[i]); String name = resKeys[j].toString() + "." + sizeKeys[i].toString(); ImageWriter.saveImage(path + "/", name, img); } } } //During Profile /** * Performed after the call to profile but prior to actual * image rendering. *

* Default behavior will display the estimated time based on the * number of resolutions, number of dataset sizes, and the test time. * * @param estimatedTime estimated time to profile * * @see #profile() */ public void processTimeWarning(int estimatedTime){ System.out.println("The estimated run time is " + estimatedTime + " seconds."); } /** * Performed every iteration of profiling and is the action undertaken * before knowing the statistics about the profile. *

* Default behavior is to print the resolution and dataset * size to the console. *

* Override this to provide custom behaviors. * * @param resolution resolution about to be profiled (image width, height) * @param datasetSize size of data about to be profiled */ public void processPreResult(Resolution resolution, int datasetSize){ System.out.print(resolution + ": " + datasetSize + ": " ); } /** * Performed every iteration of profiling and is the action undertaken * after knowing the statistics about the profile. *

* Default behavior is to print the average time to the console. *

* Override this to provide custom behaviors. * * @param resolution resolution just profiled (image width, height) * @param datasetSize size of data just profiled * @param stats results of the profiling */ public void processResult(Resolution resolution, int datasetSize, Statistics stats){ System.out.println(stats.getAverageTime() + "ms"); } //Test Parameter Setters /** * Sets the resolution sizes to be profiled. * Precondition: resolution set is not null and not empty * @param resolutions set of resolutions to profile */ public void setImageSizes(List resolutions){ if (resolutions == null){ throw new IllegalArgumentException("The list of image resolutions must be non-null."); } if (resolutions.isEmpty()){ throw new IllegalArgumentException("The list of image resolutions must be non-empty."); } this.resolutions = resolutions; } /** * Sets the dataset sizes to be profiled. * The ProfileGraph2D field of this object will profile * repeatedly updating the number of data points in rendering. * @param nPoints */ public void setDatasetSizes(List nPoints){ if (nPoints == null){ throw new IllegalArgumentException("The list of dataset sizes must be non-null."); } if (nPoints.isEmpty()){ throw new IllegalArgumentException("The list of dataset sizes must be non-empty."); } this.datasetSizes = nPoints; } //Save Parameters /** * Gets the settings to be saved to the output file * for a profile. * Some settings include: *

    *
  • Author
  • *
  • Dataset message
  • *
  • Save message
  • *
* @return the messages about settings information to * be saved to an output file */ public SaveSettings getSaveSettings(){ return this.profiler.getSaveSettings(); } //Defaults /** * Sample multi-level profiling for a given renderer. * Uses the default resolutions and default datasets as data. *

* Graphs and saves the data. * * @param profiler renderer to profile at multiple levels */ public static void defaultProfile(ProfileGraph2D profiler){ MultiLevelProfiler layer = new MultiLevelProfiler(profiler); layer.setImageSizes(Resolution.defaultResolutions()); layer.setDatasetSizes(DatasetFactory.defaultDatasetSizes()); layer.profile(); layer.graphStatistics(); layer.saveStatistics(); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy