Skip to content
Snippets Groups Projects
Commit 3ba4c152 authored by Marco Stefanetti's avatar Marco Stefanetti Committed by Marco Stefanetti
Browse files

AparapiFractals - Mandelbrot explorer and benchmarks

parent af4f8972
No related branches found
No related tags found
1 merge request!8AparapiFractals - Mandelbrot explorer and benchmarks
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
* Paul Miner * Paul Miner
* Lorenzo Gallucci * Lorenzo Gallucci
* Subhomoy Haldar (HungryBlueDev) * Subhomoy Haldar (HungryBlueDev)
* Marco Stefanetti
# Details # Details
......
...@@ -83,6 +83,9 @@ public class All { ...@@ -83,6 +83,9 @@ public class All {
System.out.println(" 34) OOPN Body"); System.out.println(" 34) OOPN Body");
System.out.println(" 35) Map-reduce"); System.out.println(" 35) Map-reduce");
System.out.println(" 36) Correlation Matrix"); System.out.println(" 36) Correlation Matrix");
System.out.println(" 37) AparapiFractals - Mandelbrot explorer ");
System.out.println(" 38) AparapiFractals - soft benchmark ");
System.out.println(" 39) AparapiFractals - hard benchmark ");
System.out.println(); System.out.println();
Scanner in = new Scanner(System.in); Scanner in = new Scanner(System.in);
...@@ -221,6 +224,15 @@ public class All { ...@@ -221,6 +224,15 @@ public class All {
case "36": case "36":
com.aparapi.examples.matrix.Main.main(args); com.aparapi.examples.matrix.Main.main(args);
break; break;
case "37":
com.aparapi.examples.afmandelbrot.AfMain.main(args);
break;
case "38":
com.aparapi.examples.afmandelbrot.AfBenchmark.main(new String[]{"SOFT"});
break;
case "39":
com.aparapi.examples.afmandelbrot.AfBenchmark.main(new String[]{"HARD"});
break;
default: default:
System.out.println("Invalid selection."); System.out.println("Invalid selection.");
} }
......
package com.aparapi.examples.afmandelbrot;
import java.util.List;
import java.util.TreeMap;
import org.apache.log4j.Logger;
import com.aparapi.Kernel;
import com.aparapi.Range;
import com.aparapi.device.Device;
import com.aparapi.device.OpenCLDevice;
import com.aparapi.internal.kernel.KernelManager;
/**
* Aparapi Fractals
*
* Aparapi code is here and in the kernel.
*
* The constructor prepares a map of Aparapi Devices using a String as a key.
* The strings used as keys are created combining device shortDescription and
* deviceId. That's for convenience, to show the keys on the gui combo box and
* use them to retrieve the selected device and kernel from the maps.
*
* @author marco.stefanetti at gmail.com
*
*/
public class AfAparapiUtils {
/** logger */
private static final Logger LOG = Logger.getLogger(AfAparapiUtils.class);
/** the list of device keys in an array, used to populate the Swing JComboBox */
private String[] deviceKeys;
/** a map between device keys and available devices */
private TreeMap<String, Device> devicesMap = new TreeMap<>();
/** keep a kernel instance ready for each device */
private TreeMap<String, AfKernel> kernelsMap = new TreeMap<>();
/** best device key, based on KernelManager.instance().bestDevice() */
private String bestDeviceKey;
/** selected device */
private Device device;
/** the range to be used by the kernel */
private Range range;
/** the kernel for the selected device */
private AfKernel kernel;
/** the name of the last device used */
private String deviceName;
/**
* The constructor prepares the keys, the map containing the devices and a map
* with a kernel instance for each device.
*/
@SuppressWarnings("deprecation")
public AfAparapiUtils() {
List<Device> devices = KernelManager.instance().getDefaultPreferences().getPreferredDevices(null);
deviceKeys = new String[devices.size()];
int p = 0;
for (Device device : devices) {
/** prepare a talking key, description and id **/
String talkingKey = device.getType().toString() + " " + device.getShortDescription() + " ("
+ device.getDeviceId() + ")";
if (device == KernelManager.instance().bestDevice()) {
talkingKey += " *";
bestDeviceKey = talkingKey;
}
/** add the device to the devices map */
devicesMap.put(talkingKey, device);
/**
* must instantiate a dedicated new kernel for each device, otherwise It's
* always using the first GPU device
*/
AfKernel deviceKernel = new AfKernel();
/** add a kernel dedicated to this device in the map of kernels */
kernelsMap.put(talkingKey, deviceKernel);
/**
* I set the execution mode to GPU or CPU to have legacyExecutionMode in
* Kernel.execute(String _entrypoint, Range _range, int _passes)
**/
if (device.getType().equals(Device.TYPE.GPU)) {
deviceKernel.setExecutionModeWithoutFallback(Kernel.EXECUTION_MODE.GPU);
} else if (device.getType().equals(Device.TYPE.CPU)) {
deviceKernel.setExecutionModeWithoutFallback(Kernel.EXECUTION_MODE.CPU);
} else {
deviceKernel.setFallbackExecutionMode();
}
/** fake execution on the device before adding to the array for the GUI */
boolean success = fakeExecution(talkingKey);
if (!success) {
LOG.warn("AfAparapiUtils device test FAILED : " + talkingKey);
} else {
/**
* I save the keys both in an array and in a map for convenience. The array
* contains devices that succeeded the fake execution.
**/
deviceKeys[p++] = talkingKey;
LOG.info("AfAparapiUtils device test OK : " + talkingKey);
}
}
}
/**
* fake execution to see kernel working on a device and to see kernel
* compilation at startup
*
* @return fake execution success
*/
private boolean fakeExecution(String key) {
try {
/** prepares the kernel as for an image 1x1 pixels */
init(key, 1, 1);
kernel.init(-2, -2, 2, 2, 1, 1, 1);
kernel.execute(range);
} catch (Throwable exc) {
LOG.error("!!! " + exc.getMessage());
LOG.error("fake execution FAILED");
return false;
}
return true;
}
/**
* calls the init with a default localSize.
*
* @param deviceKey
* @param W
* @param H
*/
public void init(String deviceKey, int W, int H) {
/**
* TODO 8x8 is empirically the best
*/
init(deviceKey, W, H, 8, 8);
}
/**
* Prepares the range and reads device description, based on the device and
* image size the range can be reused many times, so we need to instantiate the
* range only when device changes or image size changes
* @param localSize2
*/
public void init(String deviceKey, int W, int H, int localSize0, int localSize1) {
device = devicesMap.get(deviceKey);
kernel = kernelsMap.get(deviceKey);
int localWidth = localSize0;
int localHeight = localSize1;
/** global sizes must be a multiple of local sizes */
int globalWidth = (1 + W / localWidth) * localWidth;
int globalHeight = (1 + H / localHeight) * localHeight;
range = device.createRange2D(globalWidth, globalHeight, localWidth, localHeight);
deviceName = device.getShortDescription();
if (device instanceof OpenCLDevice) {
OpenCLDevice ocld = (OpenCLDevice) device;
deviceName = ocld.getName();
}
}
/**
* call the kernel execution and track elapsed time
*
* @return elapsed milliseconds
*/
public long execute(double cx1, double cy1, double cx2, double cy2, int w, int h, int maxIterations) {
if (kernel == null) {
LOG.error("null Kernel");
return 0;
}
while (kernel.isExecuting()) {
LOG.warn("Already running, waiting ... " + device.getShortDescription());
try {
Thread.sleep(10l);
} catch (InterruptedException e) {
}
}
long startTime = System.currentTimeMillis();
kernel.init(cx1, cy1, cx2, cy2, w, h, maxIterations);
kernel.execute(range);
long endTime = System.currentTimeMillis();
long elapsed = (endTime - startTime);
if ((kernel != null) && (kernel.getProfileInfo() != null)) {
kernel.cleanUpArrays();
}
return elapsed;
}
/** @return the list of keys of the devices */
public String[] getDeviceKeys() {
return deviceKeys;
}
/** @return the name of the last device used */
public String getDeviceName() {
return deviceName;
}
/** @return the dimension XxY of the local widths of the range */
public String getLocalSizes() {
String localSizes = range.getLocalSize_0() + " x " + range.getLocalSize_1();
return localSizes;
}
/**
* @return the key of the best device by KernelManager
*/
public String getBestDeviceKey() {
return bestDeviceKey;
}
/**
* @return last device selected
*/
public Device getDevice() {
return device;
}
/**
* @return the kernel of the selected device
*/
public AfKernel getKernel() {
return kernel;
}
/**
* @return the range
*/
public Range getRange() {
return range;
}
public int[][] getResult() {
return kernel.getResult();
}
}
package com.aparapi.examples.afmandelbrot;
import java.lang.management.ManagementFactory;
import java.lang.management.OperatingSystemMXBean;
import org.apache.log4j.Logger;
import com.aparapi.device.Device;
/**
* Aparapi Fractals
*
* only benchmark, results on the console, no graphics
*
* @author marco.stefanetti at gmail.com
*
*/
public class AfBenchmark {
/** logger */
private static final Logger LOG = Logger.getLogger(AfBenchmark.class);
/** flag to stop benchmarks */
private static boolean running = false;
/** no localSize specified */
private static int[][] defaultLocalSizes = { { 0, 0 } };
/** set of different range2D, localSize x localSize */
private static int[][] multipleLocalSizes = { {2,2}, {4,4}, {4,8}, {8,4}, {8,8}, {10,10}, {4,16}, {16,8}, {16,16} };
/** used by the GUI to ask to stop benchmark */
public static void requestStop() {
running = false;
}
/**
* executes a soft benchmark
*
* @param afAparapiUtils
*/
public static void benchmarkSoft(AfAparapiUtils afAparapiUtils) {
LOG.debug("Starting benchmark Soft");
AfBenchmark.benchmark(afAparapiUtils, false, "Soft", -2, -2, 2, 2, 500, 500, 100000, "ALL", 1000);
}
/**
* executes a hard benchmark
*
* @param afAparapiUtils
*/
public static void benchmarkHard(AfAparapiUtils afAparapiUtils) {
LOG.debug("Starting benchmark Hard");
AfBenchmark.benchmark(afAparapiUtils, false, "Hard", -2, -2, 2, 2, 500, 500, 1000000, "ALL", 1000);
}
/**
* executes with different localSizes
*
* @param afAparapiUtils
*/
public static void benchmarkLocalSizes(AfAparapiUtils afAparapiUtils) {
LOG.debug("Starting benchmark localSizes");
AfBenchmark.benchmark(afAparapiUtils, true, "localSizes", -2, -2, 2, 2, 900, 900, 10000, "GPU", 10);
}
/**
* executes a repeated loop over all devices
*
* @param afAparapiUtils
*/
public static void benchmarkStress(AfAparapiUtils afAparapiUtils) {
LOG.debug("Starting benchmark Stress");
for (int n = 0; n < 100; n++) {
AfBenchmark.benchmark(afAparapiUtils, false, "Stress" + n, -2, -2, 2, 2, 500, 500, 10000, "ALL", 0);
}
}
public static void benchmark(AfAparapiUtils afAparapiUtils, String mode) {
if ("SOFT".equals(mode)) {
benchmarkSoft(afAparapiUtils);
} else if ("HARD".equals(mode)) {
benchmarkHard(afAparapiUtils);
} else if ("STRESS".equals(mode)) {
benchmarkStress(afAparapiUtils);
} else if ("LSIZE".equals(mode)) {
benchmarkLocalSizes(afAparapiUtils);
} else {
LOG.warn("Unknown mode : "+mode);
}
}
/**
* execute the kernel on different devices and tracks timings. The iterations
* are discarded, used only here, no image refresh.
*/
@SuppressWarnings("deprecation")
public static void benchmark(AfAparapiUtils afAparapiUtils, boolean loopLocalSizes, String title, double cx1,
double cy1, double cx2, double cy2, int W, int H, int max_iterations, String deviceTypeFilter, long sleep) {
running = true;
OperatingSystemMXBean osBean = ManagementFactory.getOperatingSystemMXBean();
int cpus = osBean.getAvailableProcessors();
String osArc = osBean.getArch();
String osName = osBean.getName();
System.out.println();
System.out.println("Starting benchmark...");
System.out.println("Example : 'GeForce GTX 1650 SUPER' soft 348ms, hard 3058ms ");
System.out.println("Example : 'Java Alternative Algorithm', AMD 3700X, soft 390ms, hard 3993ms ");
System.out.println();
System.out.println("OperatingSystem: " + osName + " CPU:" + cpus + " " + osArc);
System.out.println(
"=======================================================================================================================================");
System.out.printf("AparapiFractals - Mandelbrot Benchmark - %s \n", title);
System.out.printf(" image size : %d x %d \n", W, H);
System.out.printf(" maxIterations : %,d \n", max_iterations);
System.out.printf(" complex region : %2.16fd,%2.16fd %2.16fd,%2.16fd \n", cx1, cy1, cx2, cy2);
System.out.println();
System.out.println(
"+-----+--------------------------------+----------------+--------------------------------------------+----------+--------+------------+");
System.out.println(
"|Type | shortDescription | deviceId | Name | LSizes | ExMode | Elapsed(ms)|");
System.out.println(
"+-----+--------------------------------+----------------+--------------------------------------------+----------+--------+------------+");
int[][] localSizes;
if (loopLocalSizes) {
localSizes = multipleLocalSizes;
} else {
localSizes = defaultLocalSizes;
}
for (String key : afAparapiUtils.getDeviceKeys()) {
for (int[] localSize : localSizes) {
if (!running) {
System.out.println("benchmark interrupted");
return;
}
if(localSize[0]==0) {
afAparapiUtils.init(key, W, H);
} else {
afAparapiUtils.init(key, W, H, localSize[0], localSize[1]);
}
Device device = afAparapiUtils.getDevice();
if (("ALL".equals(deviceTypeFilter)) || (device.getType().toString().equals(deviceTypeFilter))) {
String description = device.getShortDescription();
String execMode;
long elapsed = 0;
elapsed = afAparapiUtils.execute(cx1, cy1, cx2, cy2, W, H, max_iterations);
execMode = afAparapiUtils.getKernel().getExecutionMode().toString();
/*
* int[][] iterations = afAparapiUtils.getResult();
* long totalIterations = 0;
* for (int i = 0; i < W; i++) { for (int j = 0; j < H; j++) { totalIterations
* += iterations[i][j]; } }
*
* if (totalIterations < 1000) { LOG.warn("FAILED totalIterations:" +
* totalIterations); }
*/
System.out.printf("| %3s | %-30s | %-14d | %-42s | %-8s | %6s | %10d |\n",
device.getType().toString(), description, device.getDeviceId(),
afAparapiUtils.getDeviceName(), afAparapiUtils.getLocalSizes(), execMode, elapsed);
}
if (!running) {
System.out.println("benchmark interrupted");
return;
}
try {
Thread.sleep(sleep);
} catch (InterruptedException e) {
}
}
}
System.out.println(
"+-----+--------------------------------+----------------+--------------------------------------------+----------+--------+------------+");
System.out.println();
System.out.println(
"=======================================================================================================================================");
running = false;
LOG.debug("Benchmark over");
}
public static void main(String[] args) {
System.setProperty("com.aparapi.enableShowGeneratedOpenCL", "true");
System.setProperty("com.aparapi.dumpProfilesOnExit", "true");
String mode = "SOFT";
if (args.length > 0) {
mode = args[0];
}
AfAparapiUtils afAparapiUtils = new AfAparapiUtils();
benchmark(afAparapiUtils, mode);
}
}
This diff is collapsed.
package com.aparapi.examples.afmandelbrot;
import com.aparapi.Kernel;
/**
* Aparapi Fractals
*
* the kernel executes the math with complex numbers. Coordinates refer to
* complex plane. result is a vector of number of iterations, It is transformed
* in a color in the GUI, not here
*
* @author marco.stefanetti at gmail.com
*
*/
public class AfKernel extends Kernel {
/** the result of all calculations, the iterations for each pixel */
private int[][] result;
/** max iterations for pixel */
private int max_iterations;
/** starting point, x lower-left */
private double cx1;
/** starting point, y lower-left */
private double cy1;
/** max width */
private int wmax;
/** max height */
private int hmax;
/** one pixel width */
private double wx;
/** one pixel height */
private double hy;
/** no values on the constructor, we will reuse the kernel after init */
public AfKernel() {
super();
}
/**
* sets the parameters, send only few double to the device and a pointer to an
* array to retrieve iterations
*/
public void init(double _cx1, double _cy1, double _cx2, double _cy2, int _W, int _H, int _max_iterations) {
wmax = _W;
hmax = _H;
result = new int[_W][_H];
max_iterations = _max_iterations;
cx1 = _cx1;
cy1 = _cy1;
wx = (_cx2 - cx1) / (double) wmax;
hy = (_cy2 - cy1) / (double) hmax;
}
/**
* just executes the "simple" math on a pixel
*/
@Override
public void run() {
final int w = getGlobalId(0);
final int h = getGlobalId(1);
if ((w < wmax) && (h < hmax)) {
/** from pixel to complex coordinates */
final double cx = cx1 + w * wx;
final double cy = cy1 + h * hy;
double xn = cx;
double yn = cy;
double y2 = cy * cy;
/** I don't save x2, x squared, It's slower **/
int t = 0;
/**
* the original code gave a "goto" error in some platform while(
* (++t<max_iterations) && (xn*xn+y2<4) )
*/
for (t = 0; (t < max_iterations) && (xn * xn + y2 < 4); t++) {
yn = 2d * xn * yn + cy;
xn = xn * xn - y2 + cx;
y2 = yn * yn;
}
result[w][h] = t;
}
}
public int[][] getResult() {
return result;
}
}
package com.aparapi.examples.afmandelbrot;
import org.apache.log4j.Logger;
/**
* Aparapi Fractals
*
* The main class coordinates the GUI and Aparapi's executions. Complex plane
* coordinates and iterations are saved here. If you are interested in Aparapi
* code, just check AfAparapiUtils and AfKernel.
*
* @author marco.stefanetti at gmail.com
*
*/
public class AfMain {
/** logger */
private static final Logger LOG = Logger.getLogger(AfMain.class);
/** the GUI contains only swing controls and events handling */
private AfGUI gui;
/** devices list and kernel execution */
private AfAparapiUtils afAparapiUtils;
/** the key of the current selected device */
protected String selectedDeviceKey = null;
/** image width */
protected int W = 500;
/** image height */
protected int H = 500;
/** minimal iterations */
final protected int __MIN_ITERATIONS = 512;
/** max iterations per image pixel, It will vary while zooming */
private int maxIterations = 512;
/** the result of the iterations, It is transformed in colors in the GUI */
protected int[][] iterations;
/** lower-left in the complex plane */
protected double cx1 = -2;
protected double cy1 = -2;
/** top-right in the complex plane */
protected double cx2 = +2;
protected double cy2 = +2;
/** width and height in the complex plane */
protected double dx = +4;
protected double dy = +4;
/** minimum width in the complex plane using double */
protected double minXWidth = 0.000000000001d;
/** just to show total iterations for each image */
protected long totalIterations;
/** elapsed time for last image calculation */
protected long elapsed;
/** the thread is used to separate the GUI and the kernel */
protected GoThread goThread = null;
/** profile startup of main and GUI */
private long profilerLastTimeMillis = System.currentTimeMillis();
/** flag for benchmark running */
boolean benchmarkRunning = false;
/** separate thread for benchmarks */
private Thread benchmarkThread;
/**
* the thread is used to separate calculations and keep the gui responsive to
* other events
*/
class GoThread extends Thread {
private volatile boolean running = true;
/** destination coordinates */
private double tx1 = -2;
private double ty1 = -2;
private double tx2 = +2;
private double ty2 = +2;
/** steps to go from current coordinates to destination */
private double steps = 0;
public GoThread(double _tx1, double _ty1, double _tx2, double _ty2, double _steps) {
tx1 = _tx1;
ty1 = _ty1;
tx2 = _tx2;
ty2 = _ty2;
steps = _steps;
}
public void interrupt() {
running = false;
}
public boolean isRunning() {
return running;
}
public void run() {
if (steps == 0) {
go(tx1, ty1, tx2, ty2);
running = false;
return;
}
// start center
double sox = (cx2 + cx1) / 2d;
double soy = (cy2 + cy1) / 2d;
// initial with and height
double dsx = (cx2 - cx1);
double dsy = (cy2 - cy1);
// target center
double tox = (tx2 + tx1) / 2d;
double toy = (ty2 + ty1) / 2d;
// target with and height
double dtx = (tx2 - tx1);
double dty = (ty2 - ty1);
/**
* d(0)=dsx ... d(n+1)=d(n)*f=d(0)*f^n ... d(N)=dtx=d(0)*f^N=dsx*f^N
*
* f^N=dtx/dsx f=(dtx/dsx)^(1/n)
*/
double fx = Math.pow(dtx / dsx, 1 / (steps - 1));
double fy = Math.pow(dty / dsy, 1 / (steps - 1));
/** f^n */
double fxn = 1;
double fyn = 1;
/** new coordinates */
double nx1;
double ny1;
double nx2;
double ny2;
double ndx;
double ndy;
double mx;
double my;
double nox;
double noy;
/** sleep if the refresh is less than these ms */
long min_sleep = 30;
for (double s = 0; s < steps; s++) {
// used externally to stop the thread
if (!running) {
return;
}
/** activation function, to move fast but smootly on new center **/
mx = 2d * (1d / (1 + Math.exp(-(35d * s) / steps)) - 0.5d);
my = mx;
nox = sox + (tox - sox) * mx;
noy = soy + (toy - soy) * my;
ndx = dsx * fxn;
ndy = dsy * fyn;
nx1 = nox - ndx / 2d;
ny1 = noy - ndy / 2d;
nx2 = nox + ndx / 2d;
ny2 = noy + ndy / 2d;
long t = go(nx1, ny1, nx2, ny2);
fxn *= fx;
fyn *= fy;
/** sleep if the refresh was too fast **/
if (t < min_sleep)
try {
LOG.warn(String.format("sleeping %d ms ... ", min_sleep - t));
Thread.sleep(min_sleep - t);
} catch (InterruptedException e) {
}
}
if (!running) {
return;
}
go(tx1, ty1, tx2, ty2);
running = false;
}
}
/** constructor */
public AfMain() {
profiler("MAIN start");
afAparapiUtils = new AfAparapiUtils();
selectedDeviceKey = afAparapiUtils.getBestDeviceKey();
profiler("MAIN aparapi init");
}
/** initialize based on saved values */
private void init() {
init(selectedDeviceKey, W, H);
}
/**
* initialize local iterations array and aparapiUtils
*
* @param selectedDeviceKey new device key
* @param _W new image width
* @param _H new image height
*/
public synchronized void init(String _selectedDeviceKey, int _W, int _H) {
selectedDeviceKey = _selectedDeviceKey;
W = _W;
H = _H;
afAparapiUtils.init(selectedDeviceKey, W, H);
LOG.debug(String.format("canvas : %dx%d - max_iterations : %,d - LocalSizes %s ", W, H, maxIterations,
afAparapiUtils.getLocalSizes()));
LOG.debug(String.format("DeviceKey : %s - Device : %s ", selectedDeviceKey, afAparapiUtils.getDeviceName()));
}
/**
* go to new coordinates using x,y pixel as new center and a zoom factor.
*
* @param x new central pixel x
* @param y new central pixel y
* @param zoomFactor zoomFactor is relative to dimensions in complex plane
*/
public void move(int x, int y, double zoomFactor) {
double nx1 = cx1 + x * (cx2 - cx1) / W;
double ny1 = cy1 + y * (cy2 - cy1) / H;
double cw = zoomFactor * (cx2 - cx1);
double ch = zoomFactor * (cy2 - cy1);
/** stop when too small and zooming in **/
if ((cw < minXWidth) && (zoomFactor < 1d)) {
LOG.warn(String.format("!!! Zoom limit !!! x range : %2.20f", cw));
gui.mouseWheelZooming = false;
return;
}
/** too big or too far, the set is between -2 and 2 **/
if (((cw > 10) && (zoomFactor > 1d)) || (nx1 > 5) || (nx1 < -5) || (ny1 > 5) || (ny1 < -5)) {
LOG.warn(String.format("too big or too far, " + zoomFactor));
gui.mouseWheelZooming = false;
return;
}
threadGo(nx1 - 0.5f * cw, ny1 - 0.5f * ch, nx1 + 0.5f * cw, ny1 + 0.5f * ch, 0);
}
/**
* go to new complex coordinates
*
* @param tx1 target lower-left x
* @param ty1 target lower-left y
* @param tx2 target up-right x
* @param ty2 target up-right y
* @return elapsed refresh time
*/
private long go(double tx1, double ty1, double tx2, double ty2) {
dx = tx2 - tx1;
/**
* we do not use ty2-ty1 as dy, to keep always proportional we use a calculated
* dy based on dx,H,W
**/
dy = dx * H / W;
cx1 = tx1;
cy1 = (ty2 + ty1) / 2d - 0.5d * dy;
cx2 = tx2;
cy2 = (ty2 + ty1) / 2d + 0.5d * dy;
dy = cy2 - cy1;
/** while zooming increase iterations, empirical formula **/
maxIterations = (int) (__MIN_ITERATIONS * (1d + 0.5d * Math.log(1 / (cx2 - cx1))));
if (maxIterations < __MIN_ITERATIONS) {
maxIterations = __MIN_ITERATIONS;
}
return refresh();
}
/**
* call the aparapi execution and then refresh the gui
*
* @return calculations elapsed time, not considering gui refreshing time
*/
private synchronized long refresh() {
if (benchmarkRunning) {
LOG.warn("Benchmark in progress...");
return 0;
}
gui.deviceLedOn();
gui.lastMaxIterations = maxIterations;
elapsed = afAparapiUtils.execute(cx1, cy1, cx2, cy2, W + 1, H + 1, maxIterations);
iterations = afAparapiUtils.getResult();
/*
* long totalIterations=0; for(int i=0;i<W;i++) { for(int j=0;j<H;j++) {
* totalIterations+=iterations[i][j]; } }
*
* if(totalIterations<1000) { LOG.fatal("totalIterations:"+totalIterations+
* " very small aborting"); System.exit(1); }
*/
LOG.debug(String.format("%2.16fd,%2.16fd %2.16fd,%2.16fd MaxIterations : %10d - Elapsed : %d ms", cx1, cy1, cx2,
cy2, maxIterations, elapsed));
gui.deviceLedOff();
gui.refresh();
return elapsed;
}
public void threadGoHome(int steps) {
threadGo(-2d, -2d, 2d, 2d, steps);
}
public void goHome() {
stopThread();
go(-2d, -2d, 2d, 2d);
}
public void stopThread() {
if (goThread == null) {
return;
}
goThread.interrupt();
try {
goThread.join();
} catch (InterruptedException e) {
LOG.error("error joining threadGO");
}
}
public void threadGo() {
threadGo(cx1, cy1, cx2, cy2, 0);
}
public void threadGo(double tx1, double ty1, double tx2, double ty2, double steps) {
stopThread();
goThread = new GoThread(tx1, ty1, tx2, ty2, steps);
goThread.start();
}
/** starts a benchmark in a separate thread */
public void benchmark(final String benchmarkMode) {
if (benchmarkRunning) {
LOG.warn("Benchmark akready running");
return;
}
benchmarkThread = new Thread() {
public void run() {
benchmarkRunning = true;
gui.benchmarkLedOn();
if ("CURRENT".equals(benchmarkMode)) {
/** executes the benchmark using current coordinates and max iterations */
AfBenchmark.benchmark(afAparapiUtils, false, "CurrentRegion", cx1, cy1, cx2, cy2, W, H, maxIterations,
"ALL", 100);
} else {
AfBenchmark.benchmark(afAparapiUtils,benchmarkMode);
}
init();
gui.benchmarkLedOff();
benchmarkRunning = false;
}
};
benchmarkThread.start();
}
/** stops the benchmark thread */
public void stopBenchmark() {
if (!benchmarkRunning) {
return;
}
AfBenchmark.requestStop();
try {
benchmarkThread.join();
} catch (InterruptedException e) {
}
}
/**
* used by the GUI, the GUI has no direct access to the aparapi stuffs
*
* @return the list of devices from aparapiUtils
*/
public String[] getDeviceKeys() {
return afAparapiUtils.getDeviceKeys();
}
/**
* used by the GUI to show the name of the device. It's different from the
* combobox (selectedDeviceKey), here you get the real name of the device, e.g.
* "NVidia 1650 SUPER""
*
* @return the name of the current device
*/
public String getDeviceName() {
return afAparapiUtils.getDeviceName();
}
/** used to profile main and gui startup */
protected void profiler(String message) {
long ms = System.currentTimeMillis() - profilerLastTimeMillis;
LOG.debug(String.format("profiler - %-20s : %-10d ms", message, ms));
profilerLastTimeMillis = System.currentTimeMillis();
}
/** gui creation executed in the swing thread */
protected void createAndShowGUI() {
// swing load
java.awt.Window window = new java.awt.Window(null);
window.dispose();
profiler("GUI swing load");
// create the GUI
gui = new AfGUI(this);
profiler("GUI costructor");
}
public static void main(String[] args) {
System.setProperty("com.aparapi.enableShowGeneratedOpenCL", "true");
System.setProperty("com.aparapi.dumpProfilesOnExit", "true");
LOG.info("AparapiFractals");
LOG.info("double-click : recenter");
LOG.info("click : stop zoom");
LOG.info("mouse wheel : zoom");
LOG.info("mouse drag : move");
final AfMain main = new AfMain();
// creating and showing this application's GUI
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
main.createAndShowGUI();
}
});
// waits the GUI
while ((main.gui == null) || (main.gui.frame == null) || (!main.gui.frame.isValid())) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
}
}
main.profiler("GUI valid");
// gui validation
main.gui.frame.validate();
main.profiler("GUI validate");
// image refresh
main.gui.resizeImage();
main.profiler("GUI refresh");
// hope to ignore and flush starting events
try {
Thread.sleep(50);
} catch (InterruptedException e) {
}
// enables real handling of gui events
main.gui.guiEvents = true;
main.profiler("GUI events");
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment