ワンクリックで
fix-cuda-concat-perf
Replace element-by-element cudaMemcpy loop with cudaMemcpy2D for batched strided copy (2390x speedup on typical sizes)
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
メニュー
Replace element-by-element cudaMemcpy loop with cudaMemcpy2D for batched strided copy (2390x speedup on typical sizes)
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
SOC 職業分類に基づく
Add device information query functions through HAL → ins:: API → language bindings
Add --device all/--timer/--info CLI flags to demos across all languages for competition scoring
Add composite signal operators using existing primitives (no dedicated backend kernels needed)
How to port a cusignal Python/CUDA module to ins::signal C++ using Insight7 primitives and HAL
Profile and optimize binding language (Lua/Julia/Python) demo performance to match or exceed C++ baseline
busted loads _insight.so from ~/.luarocks/lib first, not build/ — must copy .so after rebuild
| name | fix-cuda-concat-perf |
| description | Replace element-by-element cudaMemcpy loop with cudaMemcpy2D for batched strided copy (2390x speedup on typical sizes) |
| source | auto-skill |
| extracted_at | 2026-06-06T21:25:49.785Z |
当发现某个 CUDA 操作异常慢(比合理预期慢 1000x+),用 逐段计时 定位瓶颈:
t0 = time.time()
result = some_operation(a, b)
print(f"op: {(time.time() - t0)*1000:.2f} ms")
然后在微基准测试中隔离各个子操作:
# 测试 concat 本身
t0 = time.time()
for _ in range(20):
c = ins.concat([a, b], -1)
print(f"concat: {(time.time()-t0)/20*1000:.3f} ms per call")
cudaMemcpy 有 ~5μs 的驱动级开销。 如果在 for 循环中逐元素调用:
for (int64_t linear = 0; linear < src_size; ++linear) {
cudaMemcpy(dst + offset, src + offset, element_size, cudaMemcpyDeviceToDevice);
}
对 32000 个元素,32000 × 5μs ≈ 160ms。这个时间与数据量无关,纯粹是调用次数开销。
cudaMemcpy2D用 cudaMemcpy2D 做批量 strided copy,将 O(N) 次 cudaMemcpy 降为 O(num_inputs) 次:
// For each input in concat:
// inner = product of dims after concat axis
// outer = product of dims before concat axis
size_t width = src_axis_dim * inner * elem_size; // bytes per "row"
size_t height = outer; // number of rows
size_t src_pitch = width; // contiguous source
size_t dst_pitch = out_axis_dim * inner * elem_size; // strided output
size_t dst_off = axis_offset * inner * elem_size; // offset in bytes
cudaMemcpy2D(
(char*)out->data + dst_off, dst_pitch,
(const char*)src->data + src_off, src_pitch,
width, height, cudaMemcpyDeviceToDevice);
对 concat 沿 axis A 操作的数组 [d0, d1, ..., dA, ..., d_{n-1}]:
inner = d_{A+1} × ... × d_{n-1}(axis 后面的维度乘积)outer = d_0 × ... × d_{A-1}(axis 前面的维度乘积)width = src->dims[A] × inner × elem_size(每个 "chunk" 的字节数)height = outer(chunk 的数量)src_pitch = width(源数据连续)dst_pitch = out->dims[A] × inner × elem_size(输出中的 stride)dst_off = axis_offset × inner × elem_size(该输入在输出中的偏移)该参数化对所有 axis 都成立。
| 方式 | 调用次数 | 耗时 ([32,1000,1]×2 f64) | 加速比 |
|---|---|---|---|
| 逐元素 cudaMemcpy | 32000 | ~196ms | 1x |
| cudaMemcpy2D | 2 | ~0.082ms | 2390x |
在 CUDA kernel 代码中搜索以下反模式:
for (int64_t linear = 0; linear < src_size; ++linear) {
// ... compute indices ...
cudaMemcpy(...); // ← 逐元素 cudaMemcpy 在循环中!
}
应当用批量的 cudaMemcpy / cudaMemcpy2D / cudaMemcpy3D 替代。
concat / stack 等需要批量内存拷贝的 kernelcudaMemcpy 的代码cudaMemcpy2D 的 pitch 参数支持任意 stride,适用于所有 axis 的 concat