UNPKG

nodecl

Version:

An implementation of the JavaScript bindings for OpenCL

275 lines (238 loc) 13.9 kB
/* * nodecl - An implementation of the JavaScript bindings for OpenCL. * https://github.com/jiahansu/nodecl * * Copyright (c) 2013-2013, Jia-Han Su (https://github.com/jiahansu) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of Jia-Han Su nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY JIA-HAN SU AND CONTRIBUTORS ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ var my = require("myclass"), bridjs = require("bridjs"), log4js = require("log4js"), log = log4js.getLogger("NodeCL"), Type = require("./cl_type"), NodeCLException = require("./nodecl_exception"), Signature = bridjs.Signature, cl10 = require("./cl_1_0"), cl11 = require("./cl_1_1"), cl12 = require("./cl_1_2"); var libraries = [cl10, cl11, cl12]; /* for(i=0;i<libraries.length;++i){ bridjs.register(libraries[i],"OpenCL"); }*/ module.exports = my.Class({ STATIC: { Type: Type, NativeValue: bridjs.NativeValue, Signature: bridjs.Signature, getDeviceInfoString: function(cl, deviceId, info) { var error, pSize2 = new bridjs.NativeValue.size(), buffer, str; error = cl.getDeviceInfo(deviceId, info, 0, null, bridjs.byPointer(pSize2)); module.exports.checkError(error); buffer = new Buffer(pSize2.get()); error = cl.getDeviceInfo(deviceId, info, buffer.length, buffer, null); module.exports.checkError(error); str = bridjs.toString(buffer); return str; }, getDeviceInfoInt: function(cl,deviceId, info) { var error, pInt = new bridjs.NativeValue.int(); error = cl.getDeviceInfo(deviceId, info, bridjs.sizeof(pInt), bridjs.byPointer(pInt), null); module.exports.checkError(error); return pInt.get(); }, findMaxFlopsDeviceFromContext: function(cl, pFlops, context, supportImage, extensions) { var maxFlops = -1, pSize = new bridjs.NativeValue.size(), error, devices, deviceId, i, pDeviceType = new bridjs.newNativeValue(Type.deviceType), /*pInt = new bridjs.NativeValue.int(),*/ j, deviceName, computeUnits, frequency, temp, maxDeviceId = null, pBool = new bridjs.NativeValue.bool(), deviceExtionStr, deviceType, processingElementsPerComputeUnit; error = cl.getContextInfo(context, cl.CONTEXT_DEVICES, 0, null, bridjs.byPointer(pSize)); module.exports.checkError(error); devices = bridjs.newArray(Type.deviceId, pSize.get()); bridjs.fill(devices, 0); error = cl.getContextInfo(context, cl.CONTEXT_DEVICES, devices.length, bridjs.byPointer(devices), bridjs.byPointer(pSize)); module.exports.checkError(error); for (i = 0; i < pSize.get(); ++i) { deviceId = devices.get(i); if (deviceId !== null) { //log.info(i); /* error = this.getDeviceInfo(deviceId, this.DEVICE_NAME, 0, null, bridjs.byPointer(pSize2)); this.checkError(error); deviceNameBuffer = new Buffer(pSize2.get()); error = this.getDeviceInfo(deviceId, this.DEVICE_NAME, deviceNameBuffer.length, deviceNameBuffer, null); this.checkError(error);*/ deviceName = module.exports.getDeviceInfoString(cl, deviceId, cl.DEVICE_NAME);//bridjs.toString(deviceNameBuffer); /* error = this.getDeviceInfo(deviceId, this.DEVICE_EXTENSIONS, 0, null, bridjs.byPointer(pSize2)); this.checkError(error); deviceExtensions = new Buffer(pSize2.get()); error = this.getDeviceInfo(deviceId, this.DEVICE_EXTENSIONS, deviceExtensions.length, deviceExtensions, bridjs.byPointer(pSize2)); this.checkError(error);*/ deviceExtionStr = module.exports.getDeviceInfoString(cl, deviceId, cl.DEVICE_EXTENSIONS);//bridjs.toString(deviceExtensions); //error = this.getDeviceInfo(deviceId, this.DEVICE_MAX_COMPUTE_UNITS, bridjs.sizeof(Signature.int), bridjs.byPointer(pInt), null); //this.checkError(error); computeUnits = this.getDeviceInfoInt(cl, deviceId, cl.DEVICE_MAX_COMPUTE_UNITS);// pInt.get(); // error = this.getDeviceInfo(deviceId, this.DEVICE_MAX_CLOCK_FREQUENCY, bridjs.sizeof(Signature.int), bridjs.byPointer(pInt), null); // this.checkError(error); frequency = module.exports.getDeviceInfoInt(cl, deviceId, cl.DEVICE_MAX_CLOCK_FREQUENCY);// pInt.get(); error = cl.getDeviceInfo( deviceId, cl.DEVICE_TYPE, bridjs.sizeof(pDeviceType), bridjs.byPointer(pDeviceType), null); module.exports.checkError(error); deviceType = pDeviceType.get(); processingElementsPerComputeUnit = 8; if (deviceType !== cl.DEVICE_TYPE_GPU) { processingElementsPerComputeUnit = 1; } else if (deviceExtionStr.indexOf("cl_nv_device_attribute_query") >= 0) { var majorNv = module.exports.getDeviceInfoInt(cl, deviceId, cl.DEVICE_COMPUTE_CAPABILITY_MAJOR_NV);//this.getDeviceInfo(deviceId, this.DEVICE_COMPUTE_CAPABILITY_MAJOR_NV, //bridjs.sizeof(Signature.int), bridjs.byPointer(pInt), null); module.exports.checkError(error); processingElementsPerComputeUnit = (majorNv < 2 ? 8 : 32); } else if (deviceExtionStr.indexOf("cl_amd_device_attribute_query") >= 0) { // This attribute does not ensure that all queries are supported by the runtime (it may be an older runtime, // or the CPU device) so still have to check for errors. try { processingElementsPerComputeUnit = // AMD GPUs either have a single VLIW SIMD or multiple scalar SIMDs. // The SIMD width is the number of threads the SIMD executes per cycle. // This will be less than the wavefront width since it takes several // cycles to execute the full wavefront. // The SIMD instruction width is the VLIW instruction width (or 1 for scalar), // this is the number of ALUs that can be executing per instruction per thread. module.exports.getDeviceInfoInt(cl, deviceId, cl.DEVICE_SIMD_PER_COMPUTE_UNIT_AMD) * module.exports, getDeviceInfoInt(cl, deviceId, cl.DEVICE_SIMD_WIDTH_AMD) * module.exports.getDeviceInfoInt(cl, deviceId, cl.DEVICE_SIMD_INSTRUCTION_WIDTH_AMD); // Just in case any of the queries return 0. if (processingElementsPerComputeUnit <= 0) { processingElementsPerComputeUnit = 1; } } catch (e) { // Runtime does not support the queries so use default. } } temp = computeUnits * frequency * processingElementsPerComputeUnit; log.debug("Find device: " + deviceName + " with flops = " + temp); error = cl.getDeviceInfo(deviceId, cl.DEVICE_IMAGE_SUPPORT, bridjs.sizeof(Signature.bool), bridjs.byPointer(pBool), null); module.exports.checkError(error); if (supportImage && !pBool.get()) { continue; } else { if (extensions) { //var str = bridjs.toString(deviceExtensions); //log.info(deviceExtionStr); for (j = 0; j < extensions.length; ++j) { if (deviceExtionStr.indexOf(extensions[j]) < 0) { log.debug("Unqualified device: " + deviceName + " for " + extensions[j]); temp = -1; break; } } } if (temp > maxFlops) { maxFlops = temp; maxDeviceId = deviceId; } } ///log.info(pInt.get()); } } pFlops.set(maxFlops); return maxDeviceId; }, findMaxFlopsDevice: function(cl, deviceType, supportImage, extensions) { var plaformIds, numPlatforms = new bridjs.NativeValue.uint(), error, i, platformId, pFlops = new bridjs.NativeValue.double(), contextProperties = bridjs.newArray(Type.platformId, 3), context, pError = new bridjs.NativeValue.int(), maxFlopsDeviceId = null, maxFlops = -1, deviceId, maxPlatformId = null; error = cl.getPlatformIDs(0, null, bridjs.byPointer(numPlatforms)); module.exports.checkError(error); plaformIds = bridjs.newArray(Type.platformId, numPlatforms.get()); error = cl.getPlatformIDs(plaformIds.length, bridjs.byPointer(plaformIds), bridjs.byPointer(numPlatforms)); contextProperties.set(0, cl.CONTEXT_PLATFORM); contextProperties.set(2, 0); for (i = 0; i < numPlatforms.get(); ++i) { platformId = plaformIds.get(i); contextProperties.set(1, platformId); context = cl.createContextFromType(bridjs.byPointer(contextProperties), deviceType, null, null, bridjs.byPointer(pError)); //log.info(context); if (pError.get() !== cl.DEVICE_NOT_FOUND) { module.exports.checkError(pError); deviceId = module.exports.findMaxFlopsDeviceFromContext(cl, pFlops, context, supportImage, extensions); if (pFlops.get() > maxFlops) { maxFlops = pFlops.get(); maxFlopsDeviceId = deviceId; maxPlatformId = platformId; } cl.releaseContext(context); context = null; } } return {platformId: maxPlatformId, deviceId: maxFlopsDeviceId}; //log.info(maxFlopsDeviceId); }, checkError: function(errorCode) { var value; if (typeof (errorCode) === "number") { value = errorCode; } else { value = errorCode.get(); } if (value !== 0) { throw new NodeCLException("OpenCL error :" + value); } }, newArray: function(type, length, ptr) { return bridjs.newArray(type, length, ptr); }, byPointer: function(obj) { return bridjs.byPointer(obj); }, sizeof: function(obj) { return bridjs.sizeof(obj); }, load: function(version) { var i, selectIndex = libraries.length - 1, lib; if (version === null || version === undefined) { version = libraries[libraries.length - 1].getVersion(); } else if (typeof (version) === "string") { version = parseFloat(version); } for (i = 0; i < libraries.length; ++i) { //log.info(i); if (version <= libraries[i].getVersion()) { selectIndex = i; break; } } lib = libraries[selectIndex]; bridjs.register(lib, /^win/.test(process.platform) ? "OpenCL" : "libOpenCL.so"); log.info("Load OpenCL library: " + lib.getVersion()); return new lib(); }, toString:function(str){ return bridjs.toString(str); } } });