From 4153d25f01f9f840df0988340c759b7d29dfa19d Mon Sep 17 00:00:00 2001 From: CoreRasurae <luis.p.mendes@gmail.com> Date: Mon, 23 Apr 2018 23:39:39 +0100 Subject: [PATCH] Update: Enable kernel profiling and execution simultaneously on multiple devices - part2 --- .../internal/kernel/KernelManager.java | 2 +- .../internal/kernel/KernelPreferences.java | 38 +++++++++---------- .../aparapi/internal/kernel/KernelRunner.java | 8 ++-- 3 files changed, 23 insertions(+), 25 deletions(-) diff --git a/src/main/java/com/aparapi/internal/kernel/KernelManager.java b/src/main/java/com/aparapi/internal/kernel/KernelManager.java index 7640a9af..35a20e2c 100644 --- a/src/main/java/com/aparapi/internal/kernel/KernelManager.java +++ b/src/main/java/com/aparapi/internal/kernel/KernelManager.java @@ -48,7 +48,7 @@ public class KernelManager { /** * Default KernelManager initialization.<br/> - * Convenience method for being overriden to an empty implementation, so that derived + * Convenience method for being overridden to an empty implementation, so that derived * KernelManager classes can provide non static parameters to their constructors. */ protected void setup() { diff --git a/src/main/java/com/aparapi/internal/kernel/KernelPreferences.java b/src/main/java/com/aparapi/internal/kernel/KernelPreferences.java index 7c553390..d8cc685d 100644 --- a/src/main/java/com/aparapi/internal/kernel/KernelPreferences.java +++ b/src/main/java/com/aparapi/internal/kernel/KernelPreferences.java @@ -19,11 +19,15 @@ import com.aparapi.*; import com.aparapi.device.*; import java.util.*; +import java.util.concurrent.atomic.AtomicReference; +/** + * Thread safe class holding the kernel preferences for a given kernel class. + */ public class KernelPreferences { private final Class<? extends Kernel> kernelClass; private final KernelManager manager; - private volatile LinkedList<Device> preferredDevices = null; + private final AtomicReference<LinkedList<Device>> preferredDevices = new AtomicReference<>(null); private final LinkedHashSet<Device> failedDevices = new LinkedHashSet<>(); public KernelPreferences(KernelManager manager, Class<? extends Kernel> kernelClass) { @@ -39,14 +43,16 @@ public class KernelPreferences { public List<Device> getPreferredDevices(Kernel kernel) { maybeSetUpDefaultPreferredDevices(); + ArrayList<Device> copy; + synchronized (this) { + copy = new ArrayList<>(preferredDevices.get()); + } + if (kernel == null) { - return Collections.unmodifiableList(preferredDevices); + return Collections.unmodifiableList(copy); } + List<Device> localPreferredDevices = new ArrayList<>(); - ArrayList<Device> copy; - synchronized (preferredDevices) { - copy = new ArrayList(preferredDevices); - } for (Device device : copy) { if (kernel.isAllowDevice(device)) { localPreferredDevices.add(device); @@ -56,12 +62,12 @@ public class KernelPreferences { } synchronized void setPreferredDevices(LinkedHashSet<Device> _preferredDevices) { - if (preferredDevices != null) { - preferredDevices.clear(); - preferredDevices.addAll(_preferredDevices); + if (preferredDevices.get() != null) { + preferredDevices.get().clear(); + preferredDevices.get().addAll(_preferredDevices); } else { - preferredDevices = new LinkedList<>(_preferredDevices); + preferredDevices.set(new LinkedList<>(_preferredDevices)); } failedDevices.clear(); } @@ -72,19 +78,13 @@ public class KernelPreferences { } synchronized void markPreferredDeviceFailed() { - if (preferredDevices.size() > 0) { - failedDevices.add(preferredDevices.remove(0)); + if (preferredDevices.get().size() > 0) { + failedDevices.add(preferredDevices.get().remove(0)); } } private void maybeSetUpDefaultPreferredDevices() { - if (preferredDevices == null) { - synchronized (this) { - if (preferredDevices == null) { - preferredDevices = new LinkedList<>(manager.getDefaultPreferences().getPreferredDevices(null)); - } - } - } + preferredDevices.compareAndSet(null, new LinkedList<>(manager.getDefaultPreferences().getPreferredDevices(null))); } public List<Device> getFailedDevices() { diff --git a/src/main/java/com/aparapi/internal/kernel/KernelRunner.java b/src/main/java/com/aparapi/internal/kernel/KernelRunner.java index fdb45e3e..58960925 100644 --- a/src/main/java/com/aparapi/internal/kernel/KernelRunner.java +++ b/src/main/java/com/aparapi/internal/kernel/KernelRunner.java @@ -1307,6 +1307,8 @@ public class KernelRunner extends KernelRunnerJNI{ logger.warning("Device failed for " + kernel + ": " + _exception.getMessage()); } + //This method is synchronized thus ensuring thread safety on concurrent executions of the same kernel class, + //since preferences is shared between such threads. preferences.markPreferredDeviceFailed(); // Device nextDevice = preferences.getPreferredDevice(kernel); @@ -1337,11 +1339,7 @@ public class KernelRunner extends KernelRunnerJNI{ boolean legacyExecutionMode = kernel.getExecutionMode() != Kernel.EXECUTION_MODE.AUTO; ExecutionSettings settings = new ExecutionSettings(preferences, profile, _entrypoint, _range, _passes, legacyExecutionMode); - // Two Kernels of the same class share the same KernelPreferences object, and since failure (fallback) generally mutates - // the preferences object, we must lock it. Note this prevents two Kernels of the same class executing simultaneously. - synchronized (preferences) { - return executeInternalOuter(settings); - } + return executeInternalOuter(settings); } finally { executing = false; clearCancelMultiPass(); -- GitLab