@datagrok-libraries/math
Advanced tools
Comparing version 1.1.2 to 1.1.3
# math changelog | ||
## 1.1.3 (2024-04-23) | ||
Introduce rules for GPU usage | ||
## 1.1.2 (2024-04-15) | ||
@@ -4,0 +8,0 @@ |
@@ -11,3 +11,3 @@ { | ||
"friendlyName": "Datagrok math library", | ||
"version": "1.1.2", | ||
"version": "1.1.3", | ||
"description": "Library for high performance computations", | ||
@@ -20,2 +20,3 @@ "dependencies": { | ||
"file-loader": "latest", | ||
"ml-levenberg-marquardt": "^4.1.3", | ||
"rxjs": "^6.5.5", | ||
@@ -25,3 +26,3 @@ "source-map-loader": "^4.0.1", | ||
"wu": "latest", | ||
"ml-levenberg-marquardt": "^4.1.3" | ||
"eslint-plugin-gpu-rules": "./eslint-plugin-gpu-rules" | ||
}, | ||
@@ -34,3 +35,4 @@ "devDependencies": { | ||
"eslint": "latest", | ||
"eslint-config-google": "latest", | ||
"eslint-config-eslint": "^9.0.0", | ||
"eslint-config-google": "^0.14.0", | ||
"style-loader": "^3.3.2", | ||
@@ -37,0 +39,0 @@ "ts-loader": "^9.2.6", |
/// <reference types="dist" /> | ||
export declare function getGPUDevice(): Promise<GPUDevice | null>; | ||
export declare function getGPUAdapterDescription(): Promise<string | null>; | ||
//# sourceMappingURL=getGPUDevice.d.ts.map |
@@ -10,25 +10,54 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
}; | ||
let gpuAdapter = null; | ||
let gpuDevice = null; | ||
export function getGPUDevice() { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const adapter = yield navigator.gpu.requestAdapter({ powerPreference: 'high-performance' }); | ||
if (adapter == null) | ||
return null; | ||
const requiredBufferSize = 1000000000; // ~1000MB | ||
const adapterLimits = adapter.limits; | ||
const buffferSizeLimit = adapterLimits.maxBufferSize; | ||
const storageBufferSizeLimit = adapterLimits.maxStorageBufferBindingSize; | ||
try { | ||
const device = yield adapter.requestDevice({ requiredLimits: { | ||
maxBufferSize: Math.min(buffferSizeLimit, requiredBufferSize), | ||
maxStorageBufferBindingSize: Math.min(storageBufferSizeLimit, requiredBufferSize) | ||
} }); | ||
return device; | ||
if (!gpuAdapter) { | ||
//reason: only here we get the gpuAdapter | ||
// eslint-disable-next-line no-restricted-syntax | ||
gpuAdapter = yield navigator.gpu.requestAdapter({ powerPreference: 'high-performance' }); | ||
if (gpuAdapter == null) | ||
return null; | ||
} | ||
catch (e) { | ||
console.error('Failed to create device with required limits', e); | ||
const device = yield adapter.requestDevice(); | ||
return device; | ||
let isLost = false; | ||
if (gpuDevice) { | ||
gpuDevice.lost.then(() => { | ||
isLost = true; | ||
}); | ||
yield new Promise((r) => setTimeout(r, 10)); // wait to see if the device is lost | ||
} | ||
if (!gpuDevice || isLost) { | ||
const requiredBufferSize = 1000000000; // ~1000MB | ||
const adapterLimits = gpuAdapter.limits; | ||
const buffferSizeLimit = adapterLimits.maxBufferSize; | ||
const storageBufferSizeLimit = adapterLimits.maxStorageBufferBindingSize; | ||
try { | ||
gpuDevice = yield gpuAdapter.requestDevice({ requiredLimits: { | ||
maxBufferSize: Math.min(buffferSizeLimit, requiredBufferSize), | ||
maxStorageBufferBindingSize: Math.min(storageBufferSizeLimit, requiredBufferSize) | ||
} }); | ||
return gpuDevice; | ||
} | ||
catch (e) { | ||
console.error('Failed to create device with required limits', e); | ||
gpuDevice = yield gpuAdapter.requestDevice(); | ||
return gpuDevice; | ||
} | ||
} | ||
return gpuDevice; | ||
}); | ||
} | ||
export function getGPUAdapterDescription() { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
if (!gpuAdapter) { | ||
// reason: only here we get the gpuAdapter | ||
// eslint-disable-next-line no-restricted-syntax | ||
gpuAdapter = yield navigator.gpu.requestAdapter(); | ||
if (gpuAdapter == null) | ||
return null; | ||
} | ||
const info = yield gpuAdapter.requestAdapterInfo(); | ||
return info.description; | ||
}); | ||
} | ||
//# sourceMappingURL=getGPUDevice.js.map |
@@ -56,2 +56,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
return null; | ||
// device may be lost | ||
let deviceLost = false; | ||
device.lost.then(() => { | ||
deviceLost = true; | ||
}); | ||
const listSize = entryList[0].length; // size of each list (or column) | ||
@@ -132,4 +137,3 @@ const processInfo = entryList.map((entry, i) => { | ||
@compute @workgroup_size(${workGroupDivision}, ${workGroupDivision}) fn calcKNN( | ||
@builtin(global_invocation_id) id: vec3<u32>, | ||
@builtin(local_invocation_id) localId: vec3<u32> | ||
@builtin(global_invocation_id) id: vec3<u32> | ||
) { | ||
@@ -300,2 +304,13 @@ ${needsDummy ? `let otherDummy = suppInfo.dummy * 2;` : ''} // just to make sure that the suppInfo is not optimized out | ||
}); | ||
//create a buffer on the GPU to get a copy of the results | ||
const resultBufferDistances = device.createBuffer({ | ||
label: 'result buffer distances', | ||
size: bufferDistances.size, | ||
usage: GPUBufferUsage.MAP_READ | GPUBufferUsage.COPY_DST, | ||
}); | ||
const resultBufferIndexes = device.createBuffer({ | ||
label: 'result buffer indexes', | ||
size: bufferIndexes.size, | ||
usage: GPUBufferUsage.MAP_READ | GPUBufferUsage.COPY_DST, | ||
}); | ||
for (let iter = 0; iter < Math.ceil(listSize / computationsPerPass); iter++) { | ||
@@ -330,15 +345,4 @@ startAt = iter * computationsPerPass; | ||
if (pairIter === pairComparisonPasses - 1) { | ||
//create a buffer on the GPU to get a copy of the results | ||
const resultBufferDistances = device.createBuffer({ | ||
label: 'result buffer distances', | ||
size: bufferDistances.size, | ||
usage: GPUBufferUsage.MAP_READ | GPUBufferUsage.COPY_DST, | ||
}); | ||
// Encode a command to copy the results to a mappable buffer. | ||
encoder.copyBufferToBuffer(bufferDistances, 0, resultBufferDistances, 0, resultBufferDistances.size); | ||
const resultBufferIndexes = device.createBuffer({ | ||
label: 'result buffer indexes', | ||
size: bufferIndexes.size, | ||
usage: GPUBufferUsage.MAP_READ | GPUBufferUsage.COPY_DST, | ||
}); | ||
encoder.copyBufferToBuffer(bufferIndexes, 0, resultBufferIndexes, 0, resultBufferIndexes.size); | ||
@@ -378,6 +382,15 @@ // Finish encoding and submit the commands | ||
} | ||
// console.timeEnd("decode"); | ||
// device may get lost during opperation, so in this case, we need to return null | ||
if (deviceLost) | ||
return null; | ||
} | ||
} | ||
device.destroy(); | ||
bufferDistances.destroy(); | ||
bufferIndexes.destroy(); | ||
computeInfoBuffer.destroy(); | ||
suppInfoBuffer.destroy(); | ||
resultBufferDistances.destroy(); | ||
resultBufferIndexes.destroy(); | ||
if (deviceLost) | ||
return null; | ||
return { knnIndexes: resultIndexes, knnDistances: resultDistances }; | ||
@@ -384,0 +397,0 @@ }); |
@@ -386,14 +386,2 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
const totalResults = resultsFound.reduce((a, b) => a + b, 0); | ||
//combinedFound += totalResults; | ||
//console.log(resultsFound); | ||
// const doneCopy = new Uint32Array(numOfThreads); | ||
// doneCopy.set(resultsDone); | ||
// const resultsFoundCopy = new Uint32Array(numOfThreads); | ||
// resultsFoundCopy.set(resultsFound); | ||
// const iCopy = new Uint32Array(resultsI.length); | ||
// iCopy.set(resultsI); | ||
// const jCopy = new Uint32Array(resultsJ.length); | ||
// jCopy.set(resultsJ); | ||
// console.log(jCopy.filter((d) => d !== 0)); | ||
// console.log(iCopy.filter((d) => d !== 0)); | ||
const combinedI = new Uint32Array(totalResults); | ||
@@ -428,6 +416,7 @@ const combinedJ = new Uint32Array(totalResults); | ||
} | ||
// console.log(finalI); | ||
// console.log(finalJ); | ||
// console.log(finalDistances); | ||
device.destroy(); | ||
// as rule mandates, destroy all buffers. | ||
computeInfoBuffer.destroy(); | ||
suppInfoBuffer.destroy(); | ||
resultsBuffer.destroy(); | ||
resultsOutBuffer.destroy(); | ||
return { i: finalI, j: finalJ, distance: finalDistances }; | ||
@@ -434,0 +423,0 @@ }); |
@@ -122,3 +122,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
const unionMatrixSize = resultUnionSizesArray.reduce((old, val) => old + val, 0); | ||
device.destroy(); | ||
resultUnionSizesBuffer.destroy(); | ||
resultTransposeSizesBuffer.destroy(); | ||
sizesBuffer.destroy(); | ||
indexBuffer.destroy(); | ||
unionSizesBuffer.destroy(); | ||
// sizes of each transposed knn row, sizes of each union of knn and its transpose row, total size of union matrix | ||
@@ -125,0 +129,0 @@ return { resultTransposeSizesArray, resultUnionSizesArray, unionMatrixSize }; |
@@ -109,3 +109,5 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
resultBufferDistances.unmap(); | ||
device.destroy(); | ||
resultBufferDistances.destroy(); | ||
knnDistancesBuffer.destroy(); | ||
membershipStrengthsInfoBuffer.destroy(); | ||
return resKnnDistances; | ||
@@ -112,0 +114,0 @@ }); |
@@ -170,3 +170,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
} | ||
device.destroy(); | ||
matrixStorageBuffer.destroy(); | ||
epochStorageBuffer.destroy(); | ||
embeddingStorageBuffer.destroy(); | ||
computeInfoBuffer.destroy(); | ||
outEmbedViewBuffer.destroy(); | ||
return result; | ||
@@ -173,0 +177,0 @@ }); |
@@ -238,3 +238,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
resultBuffer.unmap(); | ||
device.destroy(); | ||
resultBuffer.destroy(); | ||
source1Buffer.destroy(); | ||
source2Buffer.destroy(); | ||
resBuffer.destroy(); | ||
unionMatrixOffsetsBuffer.destroy(); | ||
return { resultKnnIndexes, resultKnnDistances }; | ||
@@ -241,0 +245,0 @@ }); |
@@ -106,3 +106,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
resultBufferSigmas.unmap(); | ||
device.destroy(); | ||
distancesBuffer.destroy(); | ||
bufferSigmas.destroy(); | ||
bufferRhos.destroy(); | ||
resultBufferRhos.destroy(); | ||
resultBufferSigmas.destroy(); | ||
return { resultRhos, resultSigmas }; | ||
@@ -109,0 +113,0 @@ }); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
GitHub dependency
Supply chain riskContains a dependency which resolves to a GitHub URL. Dependencies fetched from GitHub specifiers are not immutable can be used to inject untrusted code or reduce the likelihood of a reproducible install.
Found 1 instance in 1 package
484605
170
5403
11
10
1