package com.amd.aparapi; import java.util.LinkedHashSet; import java.util.logging.Logger; import com.amd.aparapi.internal.opencl.OpenCLLoader; /** * The <i>execution mode</i> ENUM enumerates the possible modes of executing a kernel. * One can request a mode of execution using the values below, and query a kernel after it first executes to * determine how it executed. * * <p> * Aparapi supports 4 execution modes. * <ul> * <table> * <tr><th align="left">Enum value</th><th align="left">Execution</th></tr> * <tr><td><code><b>GPU</b></code></td><td>Execute using OpenCL on first available GPU device</td></tr> * <tr><td><code><b>CPU</b></code></td><td>Execute using OpenCL on first available CPU device</td></tr> * <tr><td><code><b>JTP</b></code></td><td>Execute using a Java Thread Pool (one thread spawned per available core)</td></tr> * <tr><td><code><b>SEQ</b></code></td><td>Execute using a single loop. This is useful for debugging but will be less * performant than the other modes</td></tr> * </table> * </ul> * <p> * To request that a kernel is executed in a specific mode, call <code>Kernel.setExecutionMode(EXECUTION_MODE)</code> before the * kernel first executes. * <p> * <blockquote><pre> * int[] values = new int[1024]; * // fill values array * SquareKernel kernel = new SquareKernel(values); * kernel.setExecutionMode(Kernel.EXECUTION_MODE.JTP); * kernel.execute(values.length); * </pre></blockquote> * <p> * Alternatively, the property <code>com.amd.aparapi.executionMode</code> can be set to one of <code>JTP,GPU,CPU,SEQ</code> * when an application is launched. * <p><blockquote><pre> * java -classpath ....;aparapi.jar -Dcom.amd.aparapi.executionMode=GPU MyApplication * </pre></blockquote><p> * Generally setting the execution mode is not recommended (it is best to let Aparapi decide automatically) but the option * provides a way to compare a kernel's performance under multiple execution modes. * * @author gfrost AMD Javalabs * @version Alpha, 21/09/2010 */ public enum EXECUTION_MODE { /** * A dummy value to indicate an unknown state. */ NONE, /** * The value representing execution on a GPU device via OpenCL. */ GPU, /** * The value representing execution on a CPU device via OpenCL. * <p> * <b>Note</b> not all OpenCL implementations support OpenCL compute on the CPU. */ CPU, /** * The value representing execution on a Java Thread Pool. * <p> * By default one Java thread is started for each available core and each core will execute <code>globalSize/cores</code> work items. * This creates a total of <code>globalSize%cores</code> threads to complete the work. * Choose suitable values for <code>globalSize</code> to minimize the number of threads that are spawned. */ JTP, /** * The value representing execution sequentially in a single loop. * <p> * This is meant to be used for debugging a kernel. */ SEQ; private static Logger logger = Logger.getLogger(Config.getLoggerName()); public static EXECUTION_MODE getDefaultExecutionMode() { EXECUTION_MODE defaultExecutionMode = OpenCLLoader.isOpenCLAvailable() ? GPU : JTP; final String executionMode = Config.executionMode; if (executionMode != null) { try { EXECUTION_MODE requestedExecutionMode; requestedExecutionMode = getExecutionModeFromString(executionMode).iterator().next(); logger.fine("requested execution mode ="); if ((OpenCLLoader.isOpenCLAvailable() && requestedExecutionMode.isOpenCL()) || !requestedExecutionMode.isOpenCL()) { defaultExecutionMode = requestedExecutionMode; } } catch (final Throwable t) { // we will take the default } } logger.fine("default execution modes = " + defaultExecutionMode); return (defaultExecutionMode); } public static LinkedHashSet<EXECUTION_MODE> getDefaultExecutionModes() { LinkedHashSet<EXECUTION_MODE> defaultExecutionModes = new LinkedHashSet<EXECUTION_MODE>(); if (OpenCLLoader.isOpenCLAvailable()) { defaultExecutionModes.add(GPU); defaultExecutionModes.add(JTP); } else { defaultExecutionModes.add(JTP); } final String executionMode = Config.executionMode; if (executionMode != null) { try { LinkedHashSet<EXECUTION_MODE> requestedExecutionModes; requestedExecutionModes = EXECUTION_MODE.getExecutionModeFromString(executionMode); logger.fine("requested execution mode ="); for (final EXECUTION_MODE mode : requestedExecutionModes) { logger.fine(" " + mode); } if ((OpenCLLoader.isOpenCLAvailable() && EXECUTION_MODE.anyOpenCL(requestedExecutionModes)) || !EXECUTION_MODE.anyOpenCL(requestedExecutionModes)) { defaultExecutionModes = requestedExecutionModes; } } catch (final Throwable t) { // we will take the default } } logger.info("default execution modes = " + defaultExecutionModes); for (final EXECUTION_MODE e : defaultExecutionModes) { logger.info("SETTING DEFAULT MODE: " + e.toString()); } return (defaultExecutionModes); } static LinkedHashSet<EXECUTION_MODE> getExecutionModeFromString(String executionMode) { final LinkedHashSet<EXECUTION_MODE> executionModes = new LinkedHashSet<EXECUTION_MODE>(); for (final String mode : executionMode.split(",")) { executionModes.add(valueOf(mode.toUpperCase())); } return executionModes; } public static EXECUTION_MODE getFallbackExecutionMode() { final EXECUTION_MODE defaultFallbackExecutionMode = JTP; logger.info("fallback execution mode = " + defaultFallbackExecutionMode); return (defaultFallbackExecutionMode); } static boolean anyOpenCL(LinkedHashSet<EXECUTION_MODE> _executionModes) { for (final EXECUTION_MODE mode : _executionModes) { if ((mode == GPU) || (mode == CPU)) { return true; } } return false; } public boolean isOpenCL() { return (this == GPU) || (this == CPU); } }