001/*
002 * JavaCL - Java API and utilities for OpenCL
003 * http://javacl.googlecode.com/
004 *
005 * Copyright (c) 2009-2013, Olivier Chafik (http://ochafik.com/)
006 * All rights reserved.
007 *
008 * Redistribution and use in source and binary forms, with or without
009 * modification, are permitted provided that the following conditions are met:
010 * 
011 *     * Redistributions of source code must retain the above copyright
012 *       notice, this list of conditions and the following disclaimer.
013 *     * Redistributions in binary form must reproduce the above copyright
014 *       notice, this list of conditions and the following disclaimer in the
015 *       documentation and/or other materials provided with the distribution.
016 *     * Neither the name of Olivier Chafik nor the
017 *       names of its contributors may be used to endorse or promote products
018 *       derived from this software without specific prior written permission.
019 * 
020 * THIS SOFTWARE IS PROVIDED BY OLIVIER CHAFIK AND CONTRIBUTORS ``AS IS'' AND ANY
021 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
022 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
023 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
024 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
025 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
026 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
027 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
028 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
029 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
030 */
031        
032
033
034
035
036        
037
038        
039        
040
041
042
043        
044
045        
046        
047        
048
049        
050package com.nativelibs4java.opencl;
051import static com.nativelibs4java.opencl.library.OpenCLLibrary.*;
052import static com.nativelibs4java.opencl.library.IOpenCLLibrary.*;
053import com.nativelibs4java.opencl.library.OpenCLLibrary;
054import com.ochafik.util.string.StringUtils;
055import java.lang.annotation.Retention;
056import java.lang.annotation.RetentionPolicy;
057import java.util.*;
058import java.lang.reflect.*;
059import static com.nativelibs4java.opencl.JavaCL.log;
060import java.util.logging.Level;
061import java.util.logging.Logger;
062
063/**
064 * OpenCL error
065 * @author ochafik
066 */
067@SuppressWarnings("serial")
068public class CLException extends RuntimeException {
069    protected int code;
070    CLException(String message, int code) {
071        super(message);
072        this.code = code;
073    }
074    public int getCode() {
075        return code;
076    }
077
078        @Retention(RetentionPolicy.RUNTIME)
079        public @interface ErrorCode {
080                int value();
081        }
082
083        public static class CLVersionException extends CLException {
084                public CLVersionException(String message) {
085                        super(message, 0);
086                }
087        }
088
089        public static class CLTypedException extends CLException {
090                protected String message;
091                public CLTypedException() {
092                        super("", 0);
093                        ErrorCode code = getClass().getAnnotation(ErrorCode.class);
094                        this.code = code.value();
095                        this.message = getClass().getSimpleName();
096                }
097
098                @Override
099                public String getMessage() {
100                        return message + logSuffix;
101                }
102                
103                void setKernelArg(CLKernel kernel, int argIndex) {
104                        message += " (kernel name = " + kernel.getFunctionName() + ", num args = " + kernel.getNumArgs() + ", arg index = " + argIndex;
105                        CLProgram program = kernel.getProgram();
106                        if (program != null)
107                                message += ", source = <<<\n\t" + program.getSource().replaceAll("\n", "\n\t");
108                        
109                        message += "\n>>> )";
110                }
111        
112        }
113
114        @ErrorCode(CL_DEVICE_PARTITION_FAILED)
115        public static class DevicePartitionFailed extends CLTypedException {}
116        @ErrorCode(CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST)
117        public static class ExecStatusErrorForEventsInWaitList extends CLTypedException {}
118        @ErrorCode(CL_MISALIGNED_SUB_BUFFER_OFFSET)
119        public static class MisalignedSubBufferOffset extends CLTypedException {}
120        @ErrorCode(CL_COMPILE_PROGRAM_FAILURE)
121        public static class CompileProgramFailure extends CLTypedException {}
122        @ErrorCode(CL_LINKER_NOT_AVAILABLE)
123        public static class LinkerNotAvailable extends CLTypedException {}
124        @ErrorCode(CL_LINK_PROGRAM_FAILURE)
125        public static class LinkProgramFailure extends CLTypedException {}
126        @ErrorCode(CL_KERNEL_ARG_INFO_NOT_AVAILABLE)
127        public static class KernelArgInfoNotAvailable extends CLTypedException {}
128        @ErrorCode(CL_IMAGE_FORMAT_MISMATCH)
129        public static class ImageFormatMismatch extends CLTypedException {}
130        @ErrorCode(CL_PROFILING_INFO_NOT_AVAILABLE)
131        public static class ProfilingInfoNotAvailable extends CLTypedException {}
132        @ErrorCode(CL_DEVICE_NOT_AVAILABLE)
133        public static class DeviceNotAvailable extends CLTypedException {}
134        @ErrorCode(CL_OUT_OF_RESOURCES)
135        public static class OutOfResources extends CLTypedException {}
136    @ErrorCode(CL_COMPILER_NOT_AVAILABLE)
137        public static class CompilerNotAvailable extends CLTypedException {}
138        @ErrorCode(CL_INVALID_GLOBAL_WORK_SIZE)
139    public static class InvalidGlobalWorkSize extends CLTypedException {}
140        @ErrorCode(CL_MAP_FAILURE)
141        public static class MapFailure extends CLTypedException {}
142        @ErrorCode(CL_MEM_OBJECT_ALLOCATION_FAILURE)
143        public static class MemObjectAllocationFailure extends CLTypedException {}
144    @ErrorCode(CL_INVALID_EVENT_WAIT_LIST)
145        public static class InvalidEventWaitList extends CLTypedException {}
146        @ErrorCode(CL_INVALID_ARG_INDEX)
147        public static class InvalidArgIndex extends CLTypedException {}
148        @ErrorCode(CL_INVALID_ARG_SIZE)
149        public static class InvalidArgSize extends CLTypedException {}
150        @ErrorCode(CL_INVALID_ARG_VALUE)
151        public static class InvalidArgValue extends CLTypedException {}
152        @ErrorCode(CL_INVALID_BINARY)
153        public static class InvalidBinary extends CLTypedException {}
154        @ErrorCode(CL_INVALID_EVENT)
155        public static class InvalidEvent extends CLTypedException {}
156        @ErrorCode(CL_INVALID_IMAGE_FORMAT_DESCRIPTOR)
157        public static class InvalidImageFormatDescriptor extends CLTypedException {}
158        @ErrorCode(CL_INVALID_IMAGE_SIZE)
159        public static class InvalidImageSize extends CLTypedException {}
160        @ErrorCode(CL_INVALID_WORK_DIMENSION)
161        public static class InvalidWorkDimension extends CLTypedException {}
162        @ErrorCode(CL_INVALID_WORK_GROUP_SIZE)
163        public static class InvalidWorkGroupSize extends CLTypedException {}
164        @ErrorCode(CL_INVALID_WORK_ITEM_SIZE)
165        public static class InvalidWorkItemSize extends CLTypedException {}
166        @ErrorCode(CL_INVALID_OPERATION)
167        public static class InvalidOperation extends CLTypedException {}
168        @ErrorCode(CL_INVALID_BUFFER_SIZE)
169        public static class InvalidBufferSize extends CLTypedException {}
170        @ErrorCode(CL_INVALID_GLOBAL_OFFSET)
171        public static class InvalidGlobalOffset extends CLTypedException {}
172        @ErrorCode(CL_OUT_OF_HOST_MEMORY)
173        public static class OutOfHostMemory extends CLTypedException {}
174        @ErrorCode(CL_INVALID_COMPILER_OPTIONS)
175        public static class InvalidCompilerOptions extends CLTypedException {}
176        @ErrorCode(CL_INVALID_DEVICE)
177        public static class InvalidDevice extends CLTypedException {}
178        @ErrorCode(CL_INVALID_DEVICE_PARTITION_COUNT)
179        public static class InvalidDevicePartitionCount extends CLTypedException {}
180        @ErrorCode(CL_INVALID_HOST_PTR)
181        public static class InvalidHostPtr extends CLTypedException {}
182        @ErrorCode(CL_INVALID_IMAGE_DESCRIPTOR)
183        public static class InvalidImageDescriptor extends CLTypedException {}
184        @ErrorCode(CL_INVALID_LINKER_OPTIONS)
185        public static class InvalidLinkerOptions extends CLTypedException {}
186        @ErrorCode(CL_INVALID_PLATFORM)
187        public static class InvalidPlatform extends CLTypedException {}
188        @ErrorCode(CL_INVALID_PROPERTY)
189        public static class InvalidProperty extends CLTypedException {}
190        @ErrorCode(CL_INVALID_COMMAND_QUEUE)
191        public static class InvalidCommandQueue extends CLTypedException {}
192    @ErrorCode(CL_MEM_COPY_OVERLAP)
193        public static class MemCopyOverlap extends CLTypedException {}
194        @ErrorCode(CL_INVALID_CONTEXT)
195        public static class InvalidContext extends CLTypedException {}
196        @ErrorCode(CL_INVALID_KERNEL)
197        public static class InvalidKernel extends CLTypedException {}
198        @ErrorCode(CL_INVALID_GL_CONTEXT_APPLE)
199        public static class InvalidGLContextApple extends CLTypedException {}
200    @ErrorCode(CL_INVALID_GL_SHAREGROUP_REFERENCE_KHR)
201        public static class InvalidGLShareGroupReference extends CLTypedException {}
202        @ErrorCode(CL_INVALID_GL_OBJECT)
203        public static class InvalidGLObject extends CLTypedException {}
204        @ErrorCode(CL_INVALID_KERNEL_ARGS)
205        public static class InvalidKernelArgs extends CLTypedException {}
206        @ErrorCode(CL_INVALID_KERNEL_DEFINITION)
207        public static class InvalidKernelDefinition extends CLTypedException {}
208        @ErrorCode(CL_INVALID_KERNEL_NAME)
209        public static class InvalidKernelName extends CLTypedException {}
210        @ErrorCode(CL_INVALID_MEM_OBJECT)
211        public static class InvalidMemObject extends CLTypedException {}
212        @ErrorCode(CL_INVALID_MIP_LEVEL)
213        public static class InvalidMipLevel extends CLTypedException {}
214        @ErrorCode(CL_INVALID_PROGRAM)
215        public static class InvalidProgram extends CLTypedException {}
216        @ErrorCode(CL_INVALID_PROGRAM_EXECUTABLE)
217        public static class InvalidProgramExecutable extends CLTypedException {}
218        @ErrorCode(CL_INVALID_QUEUE_PROPERTIES)
219        public static class InvalidQueueProperties extends CLTypedException {}
220        @ErrorCode(CL_INVALID_VALUE)
221        public static class InvalidValue extends CLTypedException {}
222        @ErrorCode(CL_INVALID_SAMPLER)
223        public static class InvalidSampler extends CLTypedException {}
224        @ErrorCode(CL_INVALID_DEVICE_TYPE)
225        public static class InvalidDeviceType extends CLTypedException {}
226        @ErrorCode(CL_INVALID_BUILD_OPTIONS)
227        public static class InvalidBuildOptions extends CLTypedException {}
228        @ErrorCode(CL_BUILD_PROGRAM_FAILURE)
229        public static class BuildProgramFailure extends CLTypedException {}
230
231    public static String errorString(int err) {
232        if (err == CL_SUCCESS)
233            return null;
234
235        List<String> candidates = new ArrayList<String>();
236        for (Field f : OpenCLLibrary.class.getDeclaredFields()) {
237            if (!Modifier.isStatic(f.getModifiers())) {
238                continue;
239            }
240            if (f.getType().equals(Integer.TYPE)) {
241                try {
242                    int i = (Integer) f.get(null);
243                    if (i == err) {
244                        String name = f.getName(), lname = name.toLowerCase();
245                        if (lname.contains("invalid") || lname.contains("bad") || lname.contains("illegal") || lname.contains("wrong")) {
246                            candidates.clear();
247                            candidates.add(name);
248                            break;
249                        } else
250                            candidates.add(name);
251                    }
252                } catch (Exception e) {
253                    e.printStackTrace();
254                }
255            }
256        }
257        return StringUtils.implode(candidates, " or ");
258    }
259
260    static boolean failedForLackOfMemory(int err, int previousAttempts) {
261        switch (err) {
262        case CL_SUCCESS:
263                return false;
264        case CL_OUT_OF_HOST_MEMORY:
265        case CL_OUT_OF_RESOURCES:
266        case CL_MEM_OBJECT_ALLOCATION_FAILURE:
267                if (previousAttempts <= 1) {
268                        System.gc();
269                        if (previousAttempts == 1) {
270                                try {
271                                        Thread.sleep(100);
272                                } catch (InterruptedException ex) {}
273                        }
274                        return true;
275                }
276                default:
277                        error(err);
278                        assert false; // won't reach
279                        return false;
280        }
281    }
282    static final String logSuffix = System.getenv("CL_LOG_ERRORS") == null ? " (make sure to log all errors with environment variable CL_LOG_ERRORS=stdout)" : "";
283        
284        static Map<Integer, Class<? extends CLTypedException>> typedErrorClassesByCode;
285    @SuppressWarnings("unchecked")
286        public static void error(int err) {
287        if (err == CL_SUCCESS)
288            return;
289
290        if (typedErrorClassesByCode == null) {
291                typedErrorClassesByCode = new HashMap<Integer, Class<? extends CLTypedException>>();
292                for (Class<?> c : CLException.class.getDeclaredClasses()) {
293                        if (c == CLTypedException.class || !CLTypedException.class.isAssignableFrom(c))
294                                continue;
295                        typedErrorClassesByCode.put(c.getAnnotation(ErrorCode.class).value(), (Class<? extends CLTypedException>)c);
296                }
297        }
298        CLException toThrow = null;
299        Class<? extends CLTypedException> c = typedErrorClassesByCode.get(err);
300        if (c != null) {
301                        try {
302                                toThrow = c.newInstance();
303                        } catch (InstantiationException ex) {
304                                assert log(Level.SEVERE, null, ex);
305                        } catch (IllegalAccessException ex) {
306                                assert log(Level.SEVERE, null, ex);
307                        }
308        }
309        if (toThrow == null)
310                        toThrow = new CLException("OpenCL Error : " + errorString(err) + logSuffix, err);
311                
312        throw toThrow;
313    }
314}