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

com.aparapi.examples.afmandelbrot.AfAparapiUtils Maven / Gradle / Ivy

The newest version!
/**
 * Copyright (c) 2016 - 2018 Syncleus, Inc.
 *
 * 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 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
 * @version $Id: $Id
 * @since 2.0.1
 */
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 devicesMap = new TreeMap<>();

	/** keep a kernel instance ready for each device */
	private TreeMap 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 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 a {@link java.lang.String} object.
	 * @param W a int.
	 * @param H a int.
	 */
	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 deviceKey a {@link java.lang.String} object.
	 * @param W a int.
	 * @param H a int.
	 * @param localSize0 a int.
	 * @param localSize1 a int.
	 */
	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
	 * @param cx1 a double.
	 * @param cy1 a double.
	 * @param cx2 a double.
	 * @param cy2 a double.
	 * @param w a int.
	 * @param h a int.
	 * @param maxIterations a int.
	 */
	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 */
	/**
	 * 

Getter for the field deviceKeys.

* * @return an array of {@link java.lang.String} objects. */ public String[] getDeviceKeys() { return deviceKeys; } /** @return the name of the last device used */ /** *

Getter for the field deviceName.

* * @return a {@link java.lang.String} object. */ public String getDeviceName() { return deviceName; } /** @return the dimension XxY of the local widths of the range */ /** *

getLocalSizes.

* * @return a {@link java.lang.String} object. */ public String getLocalSizes() { String localSizes = range.getLocalSize_0() + " x " + range.getLocalSize_1(); return localSizes; } /** *

Getter for the field bestDeviceKey.

* * @return the key of the best device by KernelManager */ public String getBestDeviceKey() { return bestDeviceKey; } /** *

Getter for the field device.

* * @return last device selected */ public Device getDevice() { return device; } /** *

Getter for the field kernel.

* * @return the kernel of the selected device */ public AfKernel getKernel() { return kernel; } /** *

Getter for the field range.

* * @return the range */ public Range getRange() { return range; } /** *

getResult.

* * @return an array of {@link int} objects. */ public int[][] getResult() { return kernel.getResult(); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy