@sparkleideas/cuda-wasm 1.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +53 -0
- package/LICENSE +21 -0
- package/README.md +1444 -0
- package/bindings/node/binding.gyp +112 -0
- package/bindings/node/src/cuda_rust_wasm.cc +157 -0
- package/cli/index.js +240 -0
- package/dist/index.js +144 -0
- package/package.json +185 -0
- package/scripts/postinstall.js +95 -0
- package/scripts/test-integration.js +393 -0
package/package.json
ADDED
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@sparkleideas/cuda-wasm",
|
|
3
|
+
"version": "1.1.2",
|
|
4
|
+
"description": "High-performance CUDA to WebAssembly/WebGPU transpiler with Rust safety - Run GPU kernels in browsers and Node.js",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"module": "dist/index.esm.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"browser": "dist/index.browser.js",
|
|
9
|
+
"bin": {
|
|
10
|
+
"@sparkleideas/cuda-wasm": "./cli/index.js"
|
|
11
|
+
},
|
|
12
|
+
"exports": {
|
|
13
|
+
".": {
|
|
14
|
+
"import": "./dist/index.esm.js",
|
|
15
|
+
"require": "./dist/index.js",
|
|
16
|
+
"browser": "./dist/index.browser.js",
|
|
17
|
+
"types": "./dist/index.d.ts"
|
|
18
|
+
},
|
|
19
|
+
"./wasm": {
|
|
20
|
+
"import": "./dist/cuda_rust_wasm_bg.wasm",
|
|
21
|
+
"require": "./dist/cuda_rust_wasm_bg.wasm"
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"scripts": {
|
|
25
|
+
"build": "npm run clean && npm run build:rust && npm run build:wasm && npm run build:node && npm run build:types",
|
|
26
|
+
"build:all": "npm run build",
|
|
27
|
+
"build:rust": "cargo build --release --features optimized-build",
|
|
28
|
+
"build:rust:native": "cargo build --release --features native-gpu,optimized-build,parallel-compilation",
|
|
29
|
+
"build:rust:wasm": "cargo build --profile wasm --target wasm32-unknown-unknown --features wasm-simd",
|
|
30
|
+
"build:wasm": "./scripts/build-wasm.sh",
|
|
31
|
+
"build:wasm:dev": "BUILD_MODE=dev ./scripts/build-wasm.sh",
|
|
32
|
+
"build:wasm:size": "OPTIMIZE_SIZE=true BUILD_MODE=release ./scripts/build-wasm.sh",
|
|
33
|
+
"build:wasm:speed": "OPTIMIZE_SIZE=false BUILD_MODE=release ./scripts/build-wasm.sh",
|
|
34
|
+
"build:wasm:simd": "ENABLE_SIMD=true ./scripts/build-wasm.sh",
|
|
35
|
+
"build:node": "node-gyp rebuild",
|
|
36
|
+
"build:types": "tsc --declaration --emitDeclarationOnly --outDir dist",
|
|
37
|
+
"clean": "rm -rf dist build pkg target/wasm32-unknown-unknown .cargo-cache",
|
|
38
|
+
"clean:full": "cargo clean && npm run clean",
|
|
39
|
+
"clean:cache": "ENABLE_CACHE=false ./scripts/build-wasm.sh clean",
|
|
40
|
+
"test": "npm run test:rust && npm run test:node && npm run test:integration",
|
|
41
|
+
"test:rust": "cargo test --features native-gpu,optimized-build",
|
|
42
|
+
"test:wasm": "cargo test --target wasm32-unknown-unknown --features wasm-simd",
|
|
43
|
+
"test:node": "jest --passWithNoTests",
|
|
44
|
+
"test:integration": "node scripts/test-integration.js",
|
|
45
|
+
"test:package": "npm pack && npm install -g ./cuda-wasm-core-*.tgz && npm run test:smoke",
|
|
46
|
+
"test:smoke": "cuda-wasm --help && node -e 'require(\"cuda-rust-wasm\")'",
|
|
47
|
+
"test:bench": "cargo bench --features native-gpu",
|
|
48
|
+
"test:coverage": "cargo tarpaulin --out html --output-dir coverage --features native-gpu",
|
|
49
|
+
"test:memory": "valgrind --tool=memcheck cargo test --features native-gpu",
|
|
50
|
+
"lint": "cargo clippy --features native-gpu -- -W clippy::all && eslint cli/ --ext .js --fix",
|
|
51
|
+
"lint:rust": "cargo clippy --features native-gpu -- -D warnings",
|
|
52
|
+
"lint:js": "eslint cli/ --ext .js --fix",
|
|
53
|
+
"format": "cargo fmt && prettier --write 'cli/**/*.js' 'scripts/**/*.js'",
|
|
54
|
+
"format:check": "cargo fmt -- --check && prettier --check 'cli/**/*.js' 'scripts/**/*.js'",
|
|
55
|
+
"audit": "cargo audit && npm audit",
|
|
56
|
+
"prebuild": "echo 'Skipping build checks'",
|
|
57
|
+
"prepublishOnly": "echo 'Publishing dist files'",
|
|
58
|
+
"postinstall": "node scripts/postinstall.js",
|
|
59
|
+
"demo": "cd demo && npm start",
|
|
60
|
+
"docs": "cargo doc --open --features native-gpu,optimized-build",
|
|
61
|
+
"docs:build": "cargo doc --no-deps --features native-gpu,optimized-build",
|
|
62
|
+
"size-analysis": "npm run build:wasm && twiggy top dist/cuda_rust_wasm_bg.wasm -n 20",
|
|
63
|
+
"benchmark": "cargo bench --features native-gpu && node cli/benchmark.js",
|
|
64
|
+
"benchmark:wasm": "npm run build:wasm && node scripts/benchmark-wasm.js",
|
|
65
|
+
"profile": "cargo build --profile bench --features native-gpu && perf record target/release/cuda2rust",
|
|
66
|
+
"dev": "npm run build:wasm:dev && npm run test:node",
|
|
67
|
+
"dev:watch": "cargo watch -x 'build --profile wasm-dev --target wasm32-unknown-unknown'",
|
|
68
|
+
"ci": "npm run format:check && npm run lint && npm run test && npm run build && npm run audit",
|
|
69
|
+
"ci:quick": "npm run lint:rust && cargo test --features native-gpu",
|
|
70
|
+
"version": "npm run build && git add dist/",
|
|
71
|
+
"postversion": "git push && git push --tags",
|
|
72
|
+
"release": "npm run ci && npm version patch && npm publish",
|
|
73
|
+
"release:minor": "npm run ci && npm version minor && npm publish",
|
|
74
|
+
"release:major": "npm run ci && npm version major && npm publish"
|
|
75
|
+
},
|
|
76
|
+
"repository": {
|
|
77
|
+
"type": "git",
|
|
78
|
+
"url": "git+https://github.com/ruvnet/ruv-FANN.git",
|
|
79
|
+
"directory": "cuda-wasm"
|
|
80
|
+
},
|
|
81
|
+
"keywords": [
|
|
82
|
+
"cuda",
|
|
83
|
+
"webassembly",
|
|
84
|
+
"wasm",
|
|
85
|
+
"webgpu",
|
|
86
|
+
"gpu",
|
|
87
|
+
"parallel-computing",
|
|
88
|
+
"transpiler",
|
|
89
|
+
"rust",
|
|
90
|
+
"scientific-computing",
|
|
91
|
+
"machine-learning",
|
|
92
|
+
"high-performance-computing",
|
|
93
|
+
"browser-gpu",
|
|
94
|
+
"compute-shaders",
|
|
95
|
+
"nvidia",
|
|
96
|
+
"opencl",
|
|
97
|
+
"vulkan",
|
|
98
|
+
"performance",
|
|
99
|
+
"compiler",
|
|
100
|
+
"kernel",
|
|
101
|
+
"simd"
|
|
102
|
+
],
|
|
103
|
+
"author": {
|
|
104
|
+
"name": "CUDA-WASM Team",
|
|
105
|
+
"url": "https://github.com/ruvnet/ruv-FANN"
|
|
106
|
+
},
|
|
107
|
+
"contributors": [
|
|
108
|
+
{
|
|
109
|
+
"name": "VibeCast Team",
|
|
110
|
+
"url": "https://github.com/vibecast"
|
|
111
|
+
}
|
|
112
|
+
],
|
|
113
|
+
"license": "MIT",
|
|
114
|
+
"bugs": {
|
|
115
|
+
"url": "https://github.com/ruvnet/ruv-FANN/issues"
|
|
116
|
+
},
|
|
117
|
+
"homepage": "https://github.com/ruvnet/ruv-FANN/tree/main/cuda-wasm#readme",
|
|
118
|
+
"funding": {
|
|
119
|
+
"type": "github",
|
|
120
|
+
"url": "https://github.com/sponsors/ruvnet"
|
|
121
|
+
},
|
|
122
|
+
"dependencies": {
|
|
123
|
+
"commander": "^11.1.0",
|
|
124
|
+
"chalk": "^4.1.2",
|
|
125
|
+
"semver": "^7.5.4"
|
|
126
|
+
},
|
|
127
|
+
"devDependencies": {
|
|
128
|
+
"@types/node": "^20.10.0",
|
|
129
|
+
"@types/jest": "^29.5.8",
|
|
130
|
+
"jest": "^29.7.0",
|
|
131
|
+
"node-gyp": "^10.0.1",
|
|
132
|
+
"typescript": "^5.3.2",
|
|
133
|
+
"eslint": "^8.55.0",
|
|
134
|
+
"prettier": "^3.1.0",
|
|
135
|
+
"@typescript-eslint/eslint-plugin": "^6.13.0",
|
|
136
|
+
"@typescript-eslint/parser": "^6.13.0"
|
|
137
|
+
},
|
|
138
|
+
"engines": {
|
|
139
|
+
"node": ">=16.0.0",
|
|
140
|
+
"npm": ">=8.0.0"
|
|
141
|
+
},
|
|
142
|
+
"os": [
|
|
143
|
+
"linux",
|
|
144
|
+
"darwin",
|
|
145
|
+
"win32"
|
|
146
|
+
],
|
|
147
|
+
"cpu": [
|
|
148
|
+
"x64",
|
|
149
|
+
"arm64"
|
|
150
|
+
],
|
|
151
|
+
"files": [
|
|
152
|
+
"dist/",
|
|
153
|
+
"cli/",
|
|
154
|
+
"bindings/",
|
|
155
|
+
"scripts/postinstall.js",
|
|
156
|
+
"scripts/test-integration.js",
|
|
157
|
+
"README.md",
|
|
158
|
+
"LICENSE",
|
|
159
|
+
"CHANGELOG.md",
|
|
160
|
+
"pkg/cuda_rust_wasm_bg.wasm"
|
|
161
|
+
],
|
|
162
|
+
"publishConfig": {
|
|
163
|
+
"registry": "https://registry.npmjs.org/",
|
|
164
|
+
"access": "public",
|
|
165
|
+
"tag": "latest"
|
|
166
|
+
},
|
|
167
|
+
"browserslist": [
|
|
168
|
+
"> 1%",
|
|
169
|
+
"last 2 versions",
|
|
170
|
+
"not dead",
|
|
171
|
+
"Chrome >= 80",
|
|
172
|
+
"Firefox >= 78",
|
|
173
|
+
"Safari >= 14",
|
|
174
|
+
"Edge >= 80"
|
|
175
|
+
],
|
|
176
|
+
"ava": {
|
|
177
|
+
"extensions": [
|
|
178
|
+
"js",
|
|
179
|
+
"ts"
|
|
180
|
+
],
|
|
181
|
+
"require": [
|
|
182
|
+
"ts-node/register"
|
|
183
|
+
]
|
|
184
|
+
}
|
|
185
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const { execSync } = require('child_process');
|
|
6
|
+
|
|
7
|
+
console.log('🚀 CUDA-Rust-WASM Post-install Setup');
|
|
8
|
+
|
|
9
|
+
// Check if we're in development (npm link) or production
|
|
10
|
+
const isDev = process.env.npm_lifecycle_event === 'install' &&
|
|
11
|
+
process.cwd().includes('cuda-rust-wasm');
|
|
12
|
+
|
|
13
|
+
if (isDev) {
|
|
14
|
+
console.log('📋 Development mode detected, skipping post-install');
|
|
15
|
+
process.exit(0);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// Check for WebAssembly support
|
|
19
|
+
try {
|
|
20
|
+
new WebAssembly.Module(new Uint8Array([0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00]));
|
|
21
|
+
console.log('✅ WebAssembly support detected');
|
|
22
|
+
} catch (e) {
|
|
23
|
+
console.warn('⚠️ WebAssembly not supported in this environment');
|
|
24
|
+
console.warn(' Some features may not be available');
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Check for native dependencies
|
|
28
|
+
const optionalDeps = [
|
|
29
|
+
{ name: 'node-gyp', install: 'npm install -g node-gyp' },
|
|
30
|
+
{ name: 'wasm-pack', install: 'cargo install wasm-pack' },
|
|
31
|
+
{ name: 'wasm-opt', install: 'npm install -g wasm-opt' }
|
|
32
|
+
];
|
|
33
|
+
|
|
34
|
+
console.log('📋 Checking optional dependencies...');
|
|
35
|
+
optionalDeps.forEach(dep => {
|
|
36
|
+
try {
|
|
37
|
+
execSync(`which ${dep.name}`, { stdio: 'ignore' });
|
|
38
|
+
console.log(` ✅ ${dep.name} found`);
|
|
39
|
+
} catch (e) {
|
|
40
|
+
console.log(` ⚠️ ${dep.name} not found`);
|
|
41
|
+
console.log(` Install with: ${dep.install}`);
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
// Create example directory if it doesn't exist
|
|
46
|
+
const exampleDir = path.join(process.cwd(), 'cuda-examples');
|
|
47
|
+
if (!fs.existsSync(exampleDir)) {
|
|
48
|
+
console.log('📁 Creating example directory...');
|
|
49
|
+
fs.mkdirSync(exampleDir, { recursive: true });
|
|
50
|
+
|
|
51
|
+
// Create a simple example
|
|
52
|
+
const exampleContent = `// Example: Vector Addition
|
|
53
|
+
const { transpileCuda } = require('cuda-rust-wasm');
|
|
54
|
+
|
|
55
|
+
const cudaCode = \`
|
|
56
|
+
__global__ void vectorAdd(float* a, float* b, float* c, int n) {
|
|
57
|
+
int tid = blockIdx.x * blockDim.x + threadIdx.x;
|
|
58
|
+
if (tid < n) {
|
|
59
|
+
c[tid] = a[tid] + b[tid];
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
\`;
|
|
63
|
+
|
|
64
|
+
async function main() {
|
|
65
|
+
try {
|
|
66
|
+
const result = await transpileCuda(cudaCode, {
|
|
67
|
+
target: 'wasm',
|
|
68
|
+
optimize: true
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
console.log('✅ Transpilation successful!');
|
|
72
|
+
console.log('Generated code length:', result.code.length);
|
|
73
|
+
|
|
74
|
+
if (result.wasmBinary) {
|
|
75
|
+
console.log('WASM binary size:', result.wasmBinary.length, 'bytes');
|
|
76
|
+
}
|
|
77
|
+
} catch (error) {
|
|
78
|
+
console.error('❌ Transpilation failed:', error.message);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
main();
|
|
83
|
+
`;
|
|
84
|
+
|
|
85
|
+
fs.writeFileSync(
|
|
86
|
+
path.join(exampleDir, 'vector_add.js'),
|
|
87
|
+
exampleContent
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
console.log('✅ Example created at cuda-examples/vector_add.js');
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
console.log('\n🎉 CUDA-Rust-WASM setup complete!');
|
|
94
|
+
console.log('📚 Documentation: https://github.com/vibecast/cuda-rust-wasm');
|
|
95
|
+
console.log('🚀 Get started with: npx cuda-rust-wasm --help\n');
|
|
@@ -0,0 +1,393 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Integration test suite for @cuda-wasm/core
|
|
5
|
+
* Tests the complete pipeline from CUDA code to execution
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const fs = require('fs');
|
|
9
|
+
const path = require('path');
|
|
10
|
+
const { spawn } = require('child_process');
|
|
11
|
+
|
|
12
|
+
// Test colors
|
|
13
|
+
const colors = {
|
|
14
|
+
reset: '\x1b[0m',
|
|
15
|
+
green: '\x1b[32m',
|
|
16
|
+
red: '\x1b[31m',
|
|
17
|
+
yellow: '\x1b[33m',
|
|
18
|
+
blue: '\x1b[34m',
|
|
19
|
+
cyan: '\x1b[36m'
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
function log(message, color = 'reset') {
|
|
23
|
+
console.log(colors[color] + message + colors.reset);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
class IntegrationTester {
|
|
27
|
+
constructor() {
|
|
28
|
+
this.tests = [];
|
|
29
|
+
this.passed = 0;
|
|
30
|
+
this.failed = 0;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
addTest(name, testFn) {
|
|
34
|
+
this.tests.push({ name, testFn });
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
async runTests() {
|
|
38
|
+
log('\n🧪 Running CUDA-WASM Integration Tests\n', 'cyan');
|
|
39
|
+
|
|
40
|
+
for (const test of this.tests) {
|
|
41
|
+
try {
|
|
42
|
+
log(`Running: ${test.name}`, 'blue');
|
|
43
|
+
await test.testFn();
|
|
44
|
+
log(`✅ PASSED: ${test.name}`, 'green');
|
|
45
|
+
this.passed++;
|
|
46
|
+
} catch (error) {
|
|
47
|
+
log(`❌ FAILED: ${test.name}`, 'red');
|
|
48
|
+
log(` Error: ${error.message}`, 'red');
|
|
49
|
+
this.failed++;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
log(`\n📊 Test Results:`, 'cyan');
|
|
54
|
+
log(` ✅ Passed: ${this.passed}`, 'green');
|
|
55
|
+
log(` ❌ Failed: ${this.failed}`, this.failed > 0 ? 'red' : 'green');
|
|
56
|
+
log(` 📈 Success Rate: ${((this.passed / this.tests.length) * 100).toFixed(1)}%`,
|
|
57
|
+
this.failed === 0 ? 'green' : 'yellow');
|
|
58
|
+
|
|
59
|
+
return this.failed === 0;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
async runCommand(command, args = []) {
|
|
63
|
+
return new Promise((resolve, reject) => {
|
|
64
|
+
const proc = spawn(command, args, {
|
|
65
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
66
|
+
shell: process.platform === 'win32'
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
let stdout = '';
|
|
70
|
+
let stderr = '';
|
|
71
|
+
|
|
72
|
+
proc.stdout.on('data', (data) => {
|
|
73
|
+
stdout += data.toString();
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
proc.stderr.on('data', (data) => {
|
|
77
|
+
stderr += data.toString();
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
proc.on('close', (code) => {
|
|
81
|
+
if (code === 0) {
|
|
82
|
+
resolve({ stdout, stderr });
|
|
83
|
+
} else {
|
|
84
|
+
reject(new Error(`Command failed with code ${code}: ${stderr}`));
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Sample CUDA kernels for testing
|
|
92
|
+
const testKernels = {
|
|
93
|
+
vectorAdd: `
|
|
94
|
+
__global__ void vectorAdd(float* a, float* b, float* c, int n) {
|
|
95
|
+
int tid = blockIdx.x * blockDim.x + threadIdx.x;
|
|
96
|
+
if (tid < n) {
|
|
97
|
+
c[tid] = a[tid] + b[tid];
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
`,
|
|
101
|
+
|
|
102
|
+
matrixMultiply: `
|
|
103
|
+
__global__ void matrixMul(float* A, float* B, float* C, int N) {
|
|
104
|
+
int row = blockIdx.y * blockDim.y + threadIdx.y;
|
|
105
|
+
int col = blockIdx.x * blockDim.x + threadIdx.x;
|
|
106
|
+
|
|
107
|
+
if (row < N && col < N) {
|
|
108
|
+
float sum = 0.0f;
|
|
109
|
+
for (int k = 0; k < N; k++) {
|
|
110
|
+
sum += A[row * N + k] * B[k * N + col];
|
|
111
|
+
}
|
|
112
|
+
C[row * N + col] = sum;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
`,
|
|
116
|
+
|
|
117
|
+
reduction: `
|
|
118
|
+
__global__ void reduce(float* input, float* output, int n) {
|
|
119
|
+
__shared__ float sdata[256];
|
|
120
|
+
|
|
121
|
+
int tid = threadIdx.x;
|
|
122
|
+
int i = blockIdx.x * blockDim.x + threadIdx.x;
|
|
123
|
+
|
|
124
|
+
sdata[tid] = (i < n) ? input[i] : 0;
|
|
125
|
+
__syncthreads();
|
|
126
|
+
|
|
127
|
+
for (int s = blockDim.x / 2; s > 0; s >>= 1) {
|
|
128
|
+
if (tid < s) {
|
|
129
|
+
sdata[tid] += sdata[tid + s];
|
|
130
|
+
}
|
|
131
|
+
__syncthreads();
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (tid == 0) output[blockIdx.x] = sdata[0];
|
|
135
|
+
}
|
|
136
|
+
`
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
async function main() {
|
|
140
|
+
const tester = new IntegrationTester();
|
|
141
|
+
|
|
142
|
+
// Test 1: Package installation
|
|
143
|
+
tester.addTest('Package can be imported', async () => {
|
|
144
|
+
try {
|
|
145
|
+
const cudaWasm = require('../dist/index.js');
|
|
146
|
+
if (!cudaWasm.transpileCuda) {
|
|
147
|
+
throw new Error('Main function not exported');
|
|
148
|
+
}
|
|
149
|
+
if (!cudaWasm.getVersion) {
|
|
150
|
+
throw new Error('Version function not exported');
|
|
151
|
+
}
|
|
152
|
+
} catch (error) {
|
|
153
|
+
throw new Error(`Failed to import package: ${error.message}`);
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
// Test 2: CLI availability
|
|
158
|
+
tester.addTest('CLI tool is accessible', async () => {
|
|
159
|
+
try {
|
|
160
|
+
const result = await tester.runCommand('node', ['cli/index.js', '--help']);
|
|
161
|
+
if (!result.stdout.includes('cuda-wasm')) {
|
|
162
|
+
throw new Error('CLI help does not contain expected content');
|
|
163
|
+
}
|
|
164
|
+
} catch (error) {
|
|
165
|
+
throw new Error(`CLI not accessible: ${error.message}`);
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
// Test 3: Version command
|
|
170
|
+
tester.addTest('Version command works', async () => {
|
|
171
|
+
try {
|
|
172
|
+
const cudaWasm = require('../dist/index.js');
|
|
173
|
+
const version = cudaWasm.getVersion();
|
|
174
|
+
|
|
175
|
+
if (!version.version || !version.features) {
|
|
176
|
+
throw new Error('Version info incomplete');
|
|
177
|
+
}
|
|
178
|
+
} catch (error) {
|
|
179
|
+
throw new Error(`Version command failed: ${error.message}`);
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
// Test 4: Basic transpilation
|
|
184
|
+
tester.addTest('Basic CUDA transpilation', async () => {
|
|
185
|
+
try {
|
|
186
|
+
const cudaWasm = require('../dist/index.js');
|
|
187
|
+
const result = await cudaWasm.transpileCuda(testKernels.vectorAdd, {
|
|
188
|
+
target: 'wasm',
|
|
189
|
+
optimize: false
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
if (!result.code || result.code.length === 0) {
|
|
193
|
+
throw new Error('No transpiled code generated');
|
|
194
|
+
}
|
|
195
|
+
} catch (error) {
|
|
196
|
+
throw new Error(`Transpilation failed: ${error.message}`);
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
// Test 5: Kernel analysis
|
|
201
|
+
tester.addTest('Kernel analysis functionality', async () => {
|
|
202
|
+
try {
|
|
203
|
+
const cudaWasm = require('../dist/index.js');
|
|
204
|
+
const analysis = await cudaWasm.analyzeKernel(testKernels.vectorAdd);
|
|
205
|
+
|
|
206
|
+
if (typeof analysis.threadUtilization !== 'number') {
|
|
207
|
+
throw new Error('Analysis missing thread utilization');
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
if (!Array.isArray(analysis.suggestions)) {
|
|
211
|
+
throw new Error('Analysis missing suggestions array');
|
|
212
|
+
}
|
|
213
|
+
} catch (error) {
|
|
214
|
+
throw new Error(`Kernel analysis failed: ${error.message}`);
|
|
215
|
+
}
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
// Test 6: Code validation
|
|
219
|
+
tester.addTest('CUDA code validation', async () => {
|
|
220
|
+
try {
|
|
221
|
+
const cudaWasm = require('../dist/index.js');
|
|
222
|
+
|
|
223
|
+
const validResult = cudaWasm.validateCudaCode(testKernels.vectorAdd);
|
|
224
|
+
if (!validResult.isValid && validResult.errors.length > 0) {
|
|
225
|
+
throw new Error('Valid CUDA code marked as invalid');
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
const invalidResult = cudaWasm.validateCudaCode('invalid code');
|
|
229
|
+
if (invalidResult.warnings.length === 0) {
|
|
230
|
+
throw new Error('Invalid code should generate warnings');
|
|
231
|
+
}
|
|
232
|
+
} catch (error) {
|
|
233
|
+
throw new Error(`Code validation failed: ${error.message}`);
|
|
234
|
+
}
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
// Test 7: Kernel parsing
|
|
238
|
+
tester.addTest('CUDA kernel parsing', async () => {
|
|
239
|
+
try {
|
|
240
|
+
const cudaWasm = require('../dist/index.js');
|
|
241
|
+
const kernels = cudaWasm.parseCudaKernels(testKernels.vectorAdd);
|
|
242
|
+
|
|
243
|
+
if (!Array.isArray(kernels) || kernels.length === 0) {
|
|
244
|
+
throw new Error('No kernels parsed from valid CUDA code');
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
if (kernels[0].name !== 'vectorAdd') {
|
|
248
|
+
throw new Error('Incorrect kernel name parsed');
|
|
249
|
+
}
|
|
250
|
+
} catch (error) {
|
|
251
|
+
throw new Error(`Kernel parsing failed: ${error.message}`);
|
|
252
|
+
}
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
// Test 8: Benchmark functionality
|
|
256
|
+
tester.addTest('Benchmark functionality', async () => {
|
|
257
|
+
try {
|
|
258
|
+
const cudaWasm = require('../dist/index.js');
|
|
259
|
+
const benchmark = await cudaWasm.benchmark(testKernels.vectorAdd, {
|
|
260
|
+
iterations: 5,
|
|
261
|
+
warmupIterations: 2
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
if (typeof benchmark.avgTime !== 'number' || benchmark.avgTime <= 0) {
|
|
265
|
+
throw new Error('Invalid benchmark timing');
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
if (typeof benchmark.throughput !== 'number') {
|
|
269
|
+
throw new Error('Missing throughput measurement');
|
|
270
|
+
}
|
|
271
|
+
} catch (error) {
|
|
272
|
+
throw new Error(`Benchmark failed: ${error.message}`);
|
|
273
|
+
}
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
// Test 9: WebGPU availability check
|
|
277
|
+
tester.addTest('WebGPU availability check', async () => {
|
|
278
|
+
try {
|
|
279
|
+
const cudaWasm = require('../dist/index.js');
|
|
280
|
+
const available = cudaWasm.isWebGPUAvailable();
|
|
281
|
+
|
|
282
|
+
// In Node.js environment, this should return false
|
|
283
|
+
if (available !== false) {
|
|
284
|
+
log(' Note: WebGPU availability check behavior may vary by environment', 'yellow');
|
|
285
|
+
}
|
|
286
|
+
} catch (error) {
|
|
287
|
+
throw new Error(`WebGPU availability check failed: ${error.message}`);
|
|
288
|
+
}
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
// Test 10: Complex kernel transpilation
|
|
292
|
+
tester.addTest('Complex kernel transpilation', async () => {
|
|
293
|
+
try {
|
|
294
|
+
const cudaWasm = require('../dist/index.js');
|
|
295
|
+
const result = await cudaWasm.transpileCuda(testKernels.reduction, {
|
|
296
|
+
target: 'wasm',
|
|
297
|
+
optimize: true,
|
|
298
|
+
profile: true
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
if (!result.code) {
|
|
302
|
+
throw new Error('No code generated for complex kernel');
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
if (!result.profile) {
|
|
306
|
+
throw new Error('Profiling data not generated');
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
if (typeof result.profile.totalTime !== 'number') {
|
|
310
|
+
throw new Error('Invalid profiling data');
|
|
311
|
+
}
|
|
312
|
+
} catch (error) {
|
|
313
|
+
throw new Error(`Complex kernel transpilation failed: ${error.message}`);
|
|
314
|
+
}
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
// Test 11: File operations test
|
|
318
|
+
tester.addTest('CLI file operations', async () => {
|
|
319
|
+
try {
|
|
320
|
+
// Create a temporary CUDA file
|
|
321
|
+
const tempFile = path.join(__dirname, 'temp_kernel.cu');
|
|
322
|
+
fs.writeFileSync(tempFile, testKernels.vectorAdd);
|
|
323
|
+
|
|
324
|
+
try {
|
|
325
|
+
// Test CLI transpilation with file input
|
|
326
|
+
const result = await tester.runCommand('node', [
|
|
327
|
+
'cli/index.js',
|
|
328
|
+
'transpile',
|
|
329
|
+
tempFile,
|
|
330
|
+
'--output',
|
|
331
|
+
'temp_output.wasm'
|
|
332
|
+
]);
|
|
333
|
+
|
|
334
|
+
if (!result.stdout.includes('Transpilation complete') &&
|
|
335
|
+
!result.stdout.includes('Success')) {
|
|
336
|
+
throw new Error('CLI transpilation did not complete successfully');
|
|
337
|
+
}
|
|
338
|
+
} finally {
|
|
339
|
+
// Cleanup
|
|
340
|
+
if (fs.existsSync(tempFile)) {
|
|
341
|
+
fs.unlinkSync(tempFile);
|
|
342
|
+
}
|
|
343
|
+
const outputFile = path.join(__dirname, 'temp_output.wasm');
|
|
344
|
+
if (fs.existsSync(outputFile)) {
|
|
345
|
+
fs.unlinkSync(outputFile);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
} catch (error) {
|
|
349
|
+
throw new Error(`CLI file operations failed: ${error.message}`);
|
|
350
|
+
}
|
|
351
|
+
});
|
|
352
|
+
|
|
353
|
+
// Test 12: TypeScript definitions
|
|
354
|
+
tester.addTest('TypeScript definitions available', async () => {
|
|
355
|
+
try {
|
|
356
|
+
const typesFile = path.join(__dirname, '../dist/index.d.ts');
|
|
357
|
+
|
|
358
|
+
if (!fs.existsSync(typesFile)) {
|
|
359
|
+
throw new Error('TypeScript definitions file not found');
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
const typesContent = fs.readFileSync(typesFile, 'utf8');
|
|
363
|
+
|
|
364
|
+
if (!typesContent.includes('TranspileOptions') ||
|
|
365
|
+
!typesContent.includes('transpileCuda')) {
|
|
366
|
+
throw new Error('TypeScript definitions incomplete');
|
|
367
|
+
}
|
|
368
|
+
} catch (error) {
|
|
369
|
+
throw new Error(`TypeScript definitions test failed: ${error.message}`);
|
|
370
|
+
}
|
|
371
|
+
});
|
|
372
|
+
|
|
373
|
+
// Run all tests
|
|
374
|
+
const success = await tester.runTests();
|
|
375
|
+
|
|
376
|
+
if (success) {
|
|
377
|
+
log('\n🎉 All integration tests passed!', 'green');
|
|
378
|
+
process.exit(0);
|
|
379
|
+
} else {
|
|
380
|
+
log('\n💥 Some integration tests failed!', 'red');
|
|
381
|
+
process.exit(1);
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
// Run tests if this file is executed directly
|
|
386
|
+
if (require.main === module) {
|
|
387
|
+
main().catch((error) => {
|
|
388
|
+
log(`\n💥 Integration test runner failed: ${error.message}`, 'red');
|
|
389
|
+
process.exit(1);
|
|
390
|
+
});
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
module.exports = { IntegrationTester, testKernels };
|