ワンクリックで
optimize-cross-language-perf
Profile and optimize binding language (Lua/Julia/Python) demo performance to match or exceed C++ baseline
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
メニュー
Profile and optimize binding language (Lua/Julia/Python) demo performance to match or exceed C++ baseline
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
busted loads _insight.so from ~/.luarocks/lib first, not build/ — must copy .so after rebuild
Julia C API bindings must check for nullptr return — silent failure otherwise
| name | optimize-cross-language-perf |
| description | Profile and optimize binding language (Lua/Julia/Python) demo performance to match or exceed C++ baseline |
| source | auto-skill |
| extracted_at | 2026-06-07T00:30:00.000Z |
Binding languages (Lua/LuaJIT, Julia, Python) are slower than C++ due to:
Add timing around each pipeline section in ALL languages (C++/Python/Lua/Julia):
echo_ms — simulate_echoes
pc_ms — pulse_compression
doppler_ms — doppler processing (mean + window + FFT + fftshift)
cfar_ms — CA-CFAR
ext_ms — target extraction (nonzero + transfer + clustering)
Compare breakdowns across languages to find the slowest section in each language.
Pre-compute anything that doesn't change between frames:
_TEMPLATE — pulse compression template slice_HAMMING — window array reshaped to [N_PULSES, 1]_SLOW_TIMES — arange(N_PULSES) * T_PRFMust apply to ALL languages for algorithm alignment.
Instead of scanning all 32000 elements:
-- ❌ Slow: 32000 sol2 get() calls
for idx = 0, det.numel - 1 do
if det:get(idx) ~= 0 then ... end
end
-- ✅ Fast: nonzero on GPU + bulk table()
local idx = ins.nonzero(det)
local doppler_list = idx[1]:table() -- ~90 elements
local range_list = idx[2]:table()
local energy_cpu = energy:to(cpu)
for k = 1, #doppler_list do
local v = energy_cpu:get(doppler_list[k] * N + range_list[k])
end
-- ❌ Slow: string concatenation + parsing per call
local src = _S_TX["1:" .. tostring(N - ds + 1)]
-- ✅ Fast: integer params, no parsing
local src = ins.slice(_S_TX, 1, 1, N - ds + 1)
Requires adding m["slice"] to Lua binding:
m["slice"] = [](const Array &a, int dim, int64_t start, int64_t stop) {
return a.slice(dim - 1, start - 1, stop - 1); // 1-based → 0-based
};
Functions with C++ default parameters lose defaults when bound as bare pointers:
// ❌ Loses defaults — sol2 requires all args
sig["pulse_doppler"] = &signal::pulse_doppler;
// ✅ Lambda preserves defaults
sig["pulse_doppler"] = [](const Array &x, sol::optional<std::string> window,
sol::optional<int64_t> nfft) {
return signal::pulse_doppler(x, window.value_or(""), nfft.value_or(0));
};
GC.enable(false)
for frame in 0:n_frames-1
# ... run_frame ...
end
GC.enable(true)
GC.gc()
This prevents finalizer overhead during the loop. Memory accumulates but is freed after.
If fftshift/ifftshift add contiguous() copies that the optimized concat kernel doesn't need:
// ❌ Unnecessary — our concat handles non-contiguous views
Array last_contig = contiguous(last);
Array first_contig = contiguous(first);
Array result = concat({last_contig, first_contig}, ax);
// ✅ Direct — concat handles views via cudaMemcpy2D
Array result = concat({last, first}, ax);
After merging external PRs, check for:
array_type["table"] removed from Lua bindingarray_type["slice"] removed from Lua bindingcontiguous() calls added to core ops.shape() → .shape API changes in Python demosbuild.luarocks/ accidentally committed (add to .gitignore)y[1] returns a 0-d Array (not a number). Tests must use :item():
-- ❌ Wrong: compares Array vs number
assert.are.equal(5.0, y[1])
-- ✅ Correct: extract scalar first
assert.are.equal(5.0, y[1]:item())
sol::optional<Array> default parameters cause segfault when bound as bare function pointers:
// ❌ CRASH: sol2 passes empty Array() which segfaults inside ambgfun
sig["ambgfun"] = &signal::ambgfun;
// ✅ Safe: explicit sol::optional with default
sig["ambgfun"] = [](const Array &x, double fs, double prf,
sol::optional<Array> y) {
return signal::ambgfun(x, fs, prf, y.value_or(Array()));
};
| Language | 50-frame avg | Frame 9 steady | Key bottleneck |
|---|---|---|---|
| C++ | 4.45ms | 4.16ms | — |
| Python | 5.15ms | 4.51ms | pybind11 overhead |
| Lua/LuaJIT | 5.69ms | 4.59ms | sol2 overhead + extract |
| Julia | 8.45ms | 5.22ms | ccall finalizer GC |
For GPU-heavy workloads where computation happens in C++/CUDA kernels:
new Array()Pure compute benchmark (fib(35), 1e8 sum, sin+cos 1e7): LuaJIT 10-60x faster than Python. GPU framework benchmark (Insight7 radar): Python ≈ LuaJIT — binding layer is negligible.
Conclusion: For Insight7-style frameworks, optimize C++/CUDA kernels first. Language choice is an ecosystem decision, not a performance decision.
When implementing CWT (Continuous Wavelet Transform) with multiple scales:
Problem: Per-scale FFT creates N_scales FFT plans, each with overhead.
Solution: Batch all scales into a single 2D array and do batched FFT:
// 1. Pre-compute all wavelets, zero-pad to n
// 2. Stack into [n_scales, n]
Array w_stack = stack(w_rows, 0);
// 3. Batched FFT along axis 1
Array w_fft = fft::fft(w_stack, n, 1);
// 4. Broadcast multiply with data_fft
Array conv_fft = mul(w_fft, data_fft_2d);
// 5. Batched inverse FFT
Array conv_result = fft::ifft(conv_fft, n, 1);
Speedup: C++ CPU 10s → 3.2s on GPU (3x), because FFT plan creation is amortized.
Binding C++ functions that take std::function callbacks requires wrapping sol::function:
sig["cwt"] = [](const Array &data, sol::function wavelet,
std::vector<double> widths) {
auto wavelet_fn = [&wavelet](int64_t points, double a) -> Array {
sol::function_result r = wavelet(points, a);
return r.get<Array>();
};
return signal::cwt(data, wavelet_fn, widths);
};
Key: Use sol::function_result to get the return value, not sol::object.