Commit 6c10fe38 authored by Andrey Filippov's avatar Andrey Filippov

CLAUDE: 3-B rung B0 - one-shot attribution micro-measurements (grid transform,...

CLAUDE: 3-B rung B0 - one-shot attribution micro-measurements (grid transform, task build, MB setup, conditioning split)

Design: attic/imagej-elphel-internal/handoffs/2026-07-16_3b_measure_chain_residency_design.md
(all 4 rulings approved 07/16). B0 = attribute before B1 deletes the stages:

- grid transform (pose_lma_debug>=1, once/program): warm re-runs of
  transformToScenePxPyD full-grid vs selection-only x multi vs single
  thread - splits thread-array churn / full-grid-for-150-tiles waste /
  irreducible per-tile ERS work.
- task build: warm multi vs single-thread setInterTasksMotionBlur rebuild.
- MB setup: warm repeat of uniformMotionBlur (sizes the B2 descriptor win).
- conditioning (once/program, both direct and preloaded paths): prepare /
  cpu-condition / setBayerImages H2D / gpu-condition split - sizes B4's
  pinned+async overlap honestly (only the H2D share can hide).

One-shot: extra runs land in 'leanMeasure other' for a single call, steady
state unchanged. No behavior change; mvn -DskipTests package PASS.
Co-Authored-By: 's avatarClaude Fable 5 <noreply@anthropic.com>
parent 07606a27
......@@ -437,10 +437,15 @@ public class CuasConditioning {
final Config cfg,
final int threadsMax,
final int debugLevel) {
// B0 conditioning attribution (one-shot, 3-B design 2026-07-16): direct-path
// twin of the preloaded split below. By Claude on 07/16/2026.
final boolean b0_report = !b0_condition_reported;
final long b0_t0 = b0_report ? System.nanoTime() : 0L;
final double [][][] data = CuasMotion.readRawImageData(scene, threadsMax, debugLevel);
if (data == null) {
return false;
}
final long b0_t1 = b0_report ? System.nanoTime() : 0L;
final int width = scene.getGeometryCorrection().getSensorWH()[0];
final Config use_cfg = (cfg != null) ? cfg : new Config();
final GpuQuad gpuQuad = scene.getGPUQuad();
......@@ -460,7 +465,16 @@ public class CuasConditioning {
}
scene.saveQuadClt(); // bind this scene (conditional; resets bayer guard on switch)
scene.setHasNewImageData(false); // the guard's other re-pull trigger - must be clear
final long b0_t2 = b0_report ? System.nanoTime() : 0L;
gpuQuad.setBayerImages(data, true); // CPU path: conditioned; GPU path: raw (linear-only Config)
if (b0_report) {
b0_condition_reported = true;
System.out.println(String.format(
"CuasConditioning B0 direct split (one-shot): read+decode=%.3f ms,"+
" prepare+cpu-condition=%.3f ms (gpu_condition=%b), setBayerImages H2D=%.3f ms",
(b0_t1-b0_t0)*1e-6, (b0_t2-b0_t1)*1e-6, gpu_condition,
(System.nanoTime()-b0_t2)*1e-6));
}
if (gpu_condition && !gpuQuad.execConditioning()) {
// Fail safe: rebuild the known CPU result and replace the raw device image.
condition(data, width, scene.getLwirScales(), scene.getLwirOffsets(),
......@@ -519,10 +533,17 @@ public class CuasConditioning {
if ((raw[s] == null) || (raw[s].length != num_pixels)) return false;
}
final GpuQuad gpuQuad = scene.getGPUQuad();
// B0 conditioning attribution (one-shot, 3-B design 2026-07-16): split the
// per-scene "conditioning+H2D" stage into prepare / CPU-condition / H2D /
// GPU-condition - sizes the B4 stream-overlap rung (H2D share = what
// pinned+async can hide). By Claude on 07/16/2026.
final boolean b0_report = !b0_condition_reported;
final long b0_t0 = b0_report ? System.nanoTime() : 0L;
boolean gpu_condition = prepareGpuConditioning(
gpuQuad, num_sens, num_pixels,
scene.getLwirScales(), scene.getLwirOffsets(),
scene.getLwirScales2(), scene.getFPN(), use_cfg);
final long b0_t1 = b0_report ? System.nanoTime() : 0L;
final float [][] upload;
if (gpu_condition) {
upload = raw;
......@@ -533,16 +554,30 @@ public class CuasConditioning {
}
scene.saveQuadClt();
scene.setHasNewImageData(false);
final long b0_t2 = b0_report ? System.nanoTime() : 0L;
gpuQuad.setBayerImages(upload, true);
final long b0_t3 = b0_report ? System.nanoTime() : 0L;
if (gpu_condition && !gpuQuad.execConditioning()) {
conditionLinearToFloat(raw, cpu_scratch, scene.getLwirScales(), scene.getLwirOffsets(),
scene.getLwirScales2(), scene.getFPN(), use_cfg);
gpuQuad.setBayerImages(cpu_scratch, true);
gpu_condition = false;
}
if (b0_report) {
b0_condition_reported = true;
System.out.println(String.format(
"CuasConditioning B0 preloaded split (one-shot): prepare=%.3f ms,"+
" cpu-condition=%.3f ms (gpu_condition=%b), setBayerImages H2D=%.3f ms,"+
" gpu-condition+guards=%.3f ms (%d sensors x %d px)",
(b0_t1-b0_t0)*1e-6, (b0_t2-b0_t1)*1e-6, gpu_condition,
(b0_t3-b0_t2)*1e-6, (System.nanoTime()-b0_t3)*1e-6, num_sens, num_pixels));
}
return true;
}
// 3-B rung B0: one-shot conditioning-stage split (see above). By Claude on 07/16/2026.
private static boolean b0_condition_reported = false;
/** CPU float-output oracle for the immutable preloaded input. */
private static void conditionLinearToFloat(
final float [][] raw,
......
......@@ -599,6 +599,33 @@ public class CuasPoseRT {
final double [][] scene_pXpYD = OpticalFlow.transformToScenePxPyD(
null, center_disparity, scene_xyz, scene_atr, scene, center_CLT);
if (rtProfile != null) measureAccounted += rtProfile.addElapsed(RtPoseProfile.GRID_TRANSFORM, profileStart);
// B0 grid-transform attribution (one-shot): full-grid vs selection-only,
// multi-thread vs single-thread. churn ~= multi - single/threads;
// full-grid waste ~= full - selected-only. By Claude on 07/16/2026.
if ((clt_parameters.curt.pose_lma_debug >= 1) && !b0_grid_reported) {
b0_grid_reported = true;
int n_def = 0;
for (double [] p : scene_pXpYD) if (p != null) n_def++;
int n_sel = 0;
for (boolean s : selection) if (s) n_sel++;
final double [] sel_disparity = center_disparity.clone();
for (int i = 0; i < sel_disparity.length; i++) if (!selection[i]) sel_disparity[i] = Double.NaN;
final long b0_t0 = System.nanoTime();
OpticalFlow.transformToScenePxPyD(null, center_disparity, scene_xyz, scene_atr, scene, center_CLT); // warm full multi
final long b0_t1 = System.nanoTime();
OpticalFlow.transformToScenePxPyD(null, center_disparity, scene_xyz, scene_atr, scene, center_CLT, 1); // full single
final long b0_t2 = System.nanoTime();
OpticalFlow.transformToScenePxPyD(null, sel_disparity, scene_xyz, scene_atr, scene, center_CLT); // selected multi
final long b0_t3 = System.nanoTime();
OpticalFlow.transformToScenePxPyD(null, sel_disparity, scene_xyz, scene_atr, scene, center_CLT, 1); // selected single
final long b0_t4 = System.nanoTime();
System.out.println(String.format(
"CuasPoseRT B0 grid-transform (one-shot, warm): full grid defined=%d selected=%d;"+
" full multi=%.3f ms, full single=%.3f ms; selected-only multi=%.3f ms, selected-only single=%.3f ms"+
" (threads=%d; churn ~= multi - single/threads; full-grid waste ~= full - selected)",
n_def, n_sel, (b0_t1-b0_t0)*1e-6, (b0_t2-b0_t1)*1e-6,
(b0_t3-b0_t2)*1e-6, (b0_t4-b0_t3)*1e-6, ImageDtt.THREADS_MAX));
}
final double disparity_corr = clt_parameters.imp.disparity_corr + center_CLT.getDispInfinityRef();
final TpTask [][] cons_tasks; // the convert task sets, hoisted for the consolidation OOB filter // By Claude on 07/12/2026
final boolean resident_tasks; // post-offset slots stay native on the JNA MB path // By Codex on 07/15/2026
......@@ -634,6 +661,29 @@ public class CuasPoseRT {
// No-op unless the curt.kernel_test=pose_corr run armed it. By Claude on 07/13/2026.
PoseCorrExport.iterTasksPre(clt_parameters, image_dtt, gpuQuad, scene, cons_tasks);
if (rtProfile != null) measureAccounted += rtProfile.addElapsed(RtPoseProfile.TASK_BUILD_SORT, profileStart);
// B0 task-build attribution (one-shot): warm multi-thread vs single-thread
// rebuild (pure CPU, no GPU state). By Claude on 07/16/2026.
if ((clt_parameters.curt.pose_lma_debug >= 1) && !b0_task_reported) {
b0_task_reported = true;
int n_task = 0;
for (TpTask t : tp_tasks2[0]) if (t != null) n_task++;
final long b0_t0 = System.nanoTime();
GpuQuad.setInterTasksMotionBlur(
scene.getNumSensors(), scene.getGeometryCorrection().getSensorWH()[0],
false, scene_pXpYD, selection, mb_tau, mb_max_gain, mb_vectors,
scene.getGeometryCorrection(), disparity_corr, margin, null,
ImageDtt.THREADS_MAX);
final long b0_t1 = System.nanoTime();
GpuQuad.setInterTasksMotionBlur(
scene.getNumSensors(), scene.getGeometryCorrection().getSensorWH()[0],
false, scene_pXpYD, selection, mb_tau, mb_max_gain, mb_vectors,
scene.getGeometryCorrection(), disparity_corr, margin, null, 1);
final long b0_t2 = System.nanoTime();
System.out.println(String.format(
"CuasPoseRT B0 task-build (one-shot, warm): tasks=%d (x2 MB sets);"+
" multi=%.3f ms, single=%.3f ms (threads=%d; sort excluded - timed stage includes it)",
n_task, (b0_t1-b0_t0)*1e-6, (b0_t2-b0_t1)*1e-6, ImageDtt.THREADS_MAX));
}
profileStart = (rtProfile != null) ? rtProfile.start() : 0L;
image_dtt.interCorrTDMotionBlur(
clt_parameters.img_dtt,
......@@ -873,6 +923,15 @@ public class CuasPoseRT {
private static boolean pose_prepare_path_reported = false; // rung C1 // By Claude on 07/17/2026
// one raw-pixel/J comparison of the float oracle against the current double geometry
private static boolean float_jacobian_oracle_reported = false;
// 3-B rung B0 (design 2026-07-16): one-shot attribution micro-measurements at
// pose_lma_debug>=1 - re-run the CPU front-end stages under controlled variants
// (single-thread, selection-only grid) to split thread-array churn / full-grid
// waste / irreducible work BEFORE B1 deletes the stages. The extra runs happen
// ONCE per program on the first measured cycle and land in "leanMeasure other"
// for that one call only. By Claude on 07/16/2026.
private static boolean b0_grid_reported = false;
private static boolean b0_task_reported = false;
private static boolean b0_mb_reported = false;
private static int GPUTileProcessorDttSize() {
return com.elphel.imagej.gpu.GPUTileProcessor.DTT_SIZE;
......@@ -1826,6 +1885,23 @@ public class CuasPoseRT {
"CuasPoseRT: scene %s uniform MB vector = (%.4f, %.4f) px/s",
ts_name, mb_vectors_scene[0][0], mb_vectors_scene[1][0]));
}
// B0 MB-setup attribution (one-shot): warm repeat of the whole
// uniformMotionBlur (representative scan + one-point getMotionBlur +
// 2 full-grid fills) - a large warm time means ERS/thread overhead
// inside getMotionBlur, not the fills. By Claude on 07/16/2026.
if ((clt_parameters.curt.pose_lma_debug >= 1) && !b0_mb_reported &&
(mb_vectors_scene != null)) {
b0_mb_reported = true;
final long b0_t0 = System.nanoTime();
uniformMotionBlur(center_CLT, quadCLTs[nscene], pXpYD_center,
predicted[0], predicted[1], dxyzatr_dt[0], dxyzatr_dt[1],
debugLevel - 2);
final long b0_t1 = System.nanoTime();
System.out.println(String.format(
"CuasPoseRT B0 MB-setup (one-shot, warm repeat): %.3f ms"+
" (grid fill alone is ~%d doubles - trivial)",
(b0_t1-b0_t0)*1e-6, 2*pXpYD_center.length));
}
}
if (mb_vectors_scene == null) { // legacy per-tile path (pose_mb_uniform OFF or degenerate fallback) // By Claude on 07/12/2026
mb_vectors_scene = OpticalFlow.getMotionBlur(
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment