Commit 31312610 authored by Andrey Filippov's avatar Andrey Filippov

CLAUDE: step-3 carve_combo case - pose DP + render chain in disjoint green-ctx carves, one thread

MAP v1 (B) at real-kernel level: pose scene_dp (K=2) in its carve while
render_dp flies in a disjoint carve. Gates: pose packed result + vector
bit-identical solo-vs-combo EVERY scene (cross-ctx numerical isolation),
render output tol-0 vs solo. Measured (pinned): pose 5.1->8.3 ms p50 with
render in ANY disjoint carve (+3.1 = DRAM/L2 contention, SM-invariant);
uncarved-pose fallback (A) worst at +4.3 (primary spreads into render SMs).
Render residual wait ~0 in all arrangements.
Co-Authored-By: 's avatarClaude Fable 5 <noreply@anthropic.com>
parent baa6c592
...@@ -73,6 +73,7 @@ case scene_dp_split test_pose_scene_dp_split_jna ${MODEL}/testdata/pose_corr ...@@ -73,6 +73,7 @@ case scene_dp_split test_pose_scene_dp_split_jna ${MODEL}/testdata/pose_corr
case u16_cond test_u16_cond_jna ${REPO} --tol 0 # T2 16-bit feeder: u16 staging + swap/RowCol/two-map kernel bit-exact vs host ref AND vs the float/preload path (synthetic) # By Claude on 07/18/2026 case u16_cond test_u16_cond_jna ${REPO} --tol 0 # T2 16-bit feeder: u16 staging + swap/RowCol/two-map kernel bit-exact vs host ref AND vs the float/preload path (synthetic) # By Claude on 07/18/2026
#case render_full test_render_full_jna ${MODEL}/testdata/pose_corr --tol 0 # R0 bench (ROADMAP item 4): full-frame combined-render chain ms/scene (timing, PASS=sanity only; run by name, pin clocks: perfctl hold measure -- ./run_cases.sh render_full) # By Claude on 07/19/2026 #case render_full test_render_full_jna ${MODEL}/testdata/pose_corr --tol 0 # R0 bench (ROADMAP item 4): full-frame combined-render chain ms/scene (timing, PASS=sanity only; run by name, pin clocks: perfctl hold measure -- ./run_cases.sh render_full) # By Claude on 07/19/2026
case render_pipe test_render_pipe_jna ${MODEL}/testdata/pose_corr --tol 0 # item-4 R1a: async full-frame render chain bit-exact vs blocking path + concurrency stress (add --bench 50 for ms/scene) # By Claude on 07/19/2026 case render_pipe test_render_pipe_jna ${MODEL}/testdata/pose_corr --tol 0 # item-4 R1a: async full-frame render chain bit-exact vs blocking path + concurrency stress (add --bench 50 for ms/scene) # By Claude on 07/19/2026
#case carve_combo test_carve_combo_jna ${MODEL}/testdata/pose_corr --tol 0 # item-4 step-3: pose DP in its green-ctx carve + render chain in a disjoint carve, one thread; bit-identity + latency percentiles (--pose-green/--render-green/--scenes) # By Claude on 07/19/2026
#case convert_direct test_convert_direct ${REPO}/testdata/convert_direct_legacy # local blessed goldens (~200MB, make_convert_direct_case.py) #case convert_direct test_convert_direct ${REPO}/testdata/convert_direct_legacy # local blessed goldens (~200MB, make_convert_direct_case.py)
# gen <name(s)> <generator command, run from ${REPO}> # gen <name(s)> <generator command, run from ${REPO}>
......
// test_carve_combo_jna.cu - imagej ROADMAP item 4, step-3 sizing: the MAP v1
// (B) validation case at REAL-KERNEL level. ONE process, ONE host thread (the
// ruled submission shape): the full per-scene pose DP parent (scene_dp, K=2
// cycles) runs in ITS green-ctx SM carve while the full-frame combined-render
// chain (render_dp) flies in a DISJOINT carve - the production concurrency,
// native. A third module with an UNCARVED (plain) context replays the probe2k
// k8/k9 negative control with the real render: a carve does not fence PRIMARY-
// style work out of the pose partition, so pose latency should degrade there.
//
// Gates:
// - pose solo repeat: two solo scene_dp calls bit-identical (self-check);
// - combo: EVERY scene_dp call under concurrent render returns the packed
// result + solve vector bit-identical to solo (cross-ctx numerical
// isolation - the fresh-run byte-identity prediction for step 4);
// - render output after the combo loop equals the solo render, tol 0.
// - timing: pose call wall p50/p95/max per arrangement; render residual
// wait after pose completes (expect ~0: 4.3 ms render < pose K=2 wall).
//
// Modules: three NVRTC compiles of the same source (pose carve / render carve
// / plain negative control); TP_GREEN_SM is read per tp_create_module call,
// set via setenv() between creates - partitions are disjoint by the
// skip+count spec ("8" pose, "8+16" render).
//
// Build (after jna/build_lib.sh):
// cd tile_processor_gpu && /usr/local/cuda-12.8/bin/nvcc -std=c++17 -O2 \
// -I src -I $HOME/git/cuda-samples/Common \
// jna/test_carve_combo_jna.cu src/tests/tp_test_data.cu \
// -o tests_bin/test_carve_combo_jna -L jna -ltileproc \
// -Xlinker -rpath -Xlinker $PWD/jna
// Run: tests_bin/test_carve_combo_jna --data <model>/testdata/pose_corr
// [--pose-green 8] [--render-green 8+16] [--scenes 300] [--skip-neg]
//
// Created on: Jul 19, 2026
// Author: Claude (Anthropic), for Elphel
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <chrono>
#include <string>
#include <vector>
#include <cuda_runtime.h>
#include "tests/tp_test_data.h"
#include "geometry_correction.h" // TP_TASK_*_OFFSET
extern "C" {
void* tp_create_module(const char*, const char*);
const char* tp_last_error();
void* tp_proc_create(void*);
int tp_proc_setup(void*, int,int,int,int,int,int);
int tp_proc_set_geometry(void*, const float*, int);
int tp_proc_set_correction_vector(void*, const float*, int);
int tp_proc_set_kernels(void*, int, const float*, int);
int tp_proc_set_kernel_offsets(void*, int, const float*, int);
int tp_proc_set_image(void*, int, const float*);
int tp_proc_set_tasks_slot(void*, const float*, int, int, int);
int tp_proc_set_const(void*, const char*, const float*, int);
int tp_proc_set_clt(void*, int, const float*, int);
int tp_proc_setup_rbg_corr(void*, int, int,int,int,int, float,float,float, int);
int tp_proc_set_peak_debias(void*, const float*, int);
int tp_proc_set_pose_cycle(void*, int,int, float, float,float,float,float,
int,int, float,float,float,float, float,float,
float,float, int, float,float,float, double,int,
int, float,float,float,float, int, float,float,float, int);
int tp_proc_exec_pose_scene_dp(void*,
const float*,const float*,const float*,int,const float*,int,
const float*,const float*,const float*,int,const float*,int,
const float*,const int*,const float*,
int,float,float,float,int,int,int,int,int,float,float,float,int,int,
const float*,const float*,const float*,const float*,
float*,int*,float*,float*,float*,int*);
// item-4 R1a render chain
int tp_proc_render_setup(void*, float, float, float, float, float, float, float);
int tp_proc_render_set_tasks(void*, int, const float*, int, int);
int tp_proc_render_scene(void*, const float*, int, float,float,float,float, float,float, int,int, int, int);
int tp_proc_render_status(void*, int, int*);
int tp_proc_render_get(void*, float*);
void tp_proc_destroy(void*);
void tp_destroy_module(void*);
}
enum { RESULT=25, MSTATS=5, NUM_PARAMS=3, NUM_COMPONENTS=2, PREP_FLOATS=8 };
enum { CORR_SLOT=0xff, NTILE_SHIFT=8, USE_EIGEN=1, SAME_WEIGHTS=0 };
static const float EIG_MIN_SQRT=0.4f, EIG_MAX_SQRT=4.0f, MIN_CONFIDENCE=0.0f;
static const float RMS_DIFF=0.001f;
static const int K_CYCLES=2; static const float LAMBDA=0.0005f;
static void pct(std::vector<double>& v, double* p50, double* p95, double* mx){
std::sort(v.begin(), v.end());
*p50 = v[v.size()/2]; *p95 = v[(size_t)(v.size()*0.95)]; *mx = v.back();
}
// bit-exact (NaN==NaN) image compare
static long imgCompare(const float* a, const float* b, size_t n, double* maxd){
long bad = 0; *maxd = 0;
for (size_t i = 0; i < n; i++){
const bool an = std::isnan(a[i]), bn = std::isnan(b[i]);
if (an && bn) continue;
if (an != bn){ bad++; continue; }
const double d = std::fabs((double)a[i]-(double)b[i]);
if (d > 0){ bad++; if (d > *maxd) *maxd = d; }
}
return bad;
}
static void* makeModule(const char* spec, const char* srcdir, const char* devrt){
if (spec && *spec) setenv("TP_GREEN_SM", spec, 1); else unsetenv("TP_GREEN_SM");
void* m = tp_create_module(srcdir, devrt);
if (!m) printf("FAIL module (TP_GREEN_SM=%s): %s\n", spec?spec:"", tp_last_error());
unsetenv("TP_GREEN_SM");
return m;
}
int main(int argc, char** argv){
std::string data_dir = "testdata/pose_corr";
std::string srcdir = "src";
std::string devrt = "/usr/local/cuda-12.8/lib64/libcudadevrt.a";
std::string pose_green = "8", render_green = "8+16";
int scenes = 300, skip_neg = 0;
for (int i = 1; i < argc; i++){
if (!strcmp(argv[i],"--data") && (i+1<argc)) data_dir = argv[++i];
else if (!strcmp(argv[i],"--src") && (i+1<argc)) srcdir = argv[++i];
else if (!strcmp(argv[i],"--devrt") && (i+1<argc)) devrt = argv[++i];
else if (!strcmp(argv[i],"--pose-green") && (i+1<argc)) pose_green = argv[++i];
else if (!strcmp(argv[i],"--render-green") && (i+1<argc)) render_green = argv[++i];
else if (!strcmp(argv[i],"--scenes") && (i+1<argc)) scenes = atoi(argv[++i]);
else if (!strcmp(argv[i],"--skip-neg")) skip_neg = 1;
else if (!strcmp(argv[i],"--tol") && (i+1<argc)) i++; // manifest form; gate is bit-exact
else { fprintf(stderr,"Usage: %s --data <pose_corr case> [--pose-green 8] [--render-green 8+16] [--scenes N] [--skip-neg]\n", argv[0]); return EXIT_FAILURE; }
}
printf("%s: data=%s pose carve '%s', render carve '%s', %d scenes/arrangement\n",
argv[0], data_dir.c_str(), pose_green.c_str(), render_green.c_str(), scenes);
TpTestData data(data_dir);
const int num_cams = data.paramInt("num_sensors", 16);
const int num_colors = data.paramInt("colors", 1);
const int img_width = data.paramInt("img_width", 640);
const int img_height = data.paramInt("img_height", 512);
const int kernels_hor = data.paramInt("kernels_hor", 82);
const int kernels_vert = data.paramInt("kernels_vert", 66);
const int task_size = data.paramInt("task_size", 6 + 6*num_cams);
const int sel_sensors = data.paramInt("sel_sensors", 1);
const float soft_margin = (float)data.param("soft_margin", 12.0);
const float hard_margin = (float)data.param("hard_margin", 8.0);
const float s0 = (float)data.param("scale0",1.0), s1 = (float)data.param("scale1",0.0), s2 = (float)data.param("scale2",0.0);
const double fz_inter = data.param("fz_inter", 10000.0);
const int corr_rad = 7;
const float p_abs_min = (float)data.param("eig_min_abs", 0.0);
const float p_rel_min = (float)data.param("eig_min_rel", 0.0);
const float p_min_peak = (float)data.param("min_str_sum", 0.0);
const float p_sub_frac = (float)data.param("eig_sub_frac", 0.0);
const int p_recenter = data.paramInt("pose_recenter", 0);
const float p_sub_frac1 = (float)data.param("eig_sub_frac1", 0.0);
const float p_scale_ax = (float)data.param("eig_scale_axes",1.2);
const float p_inc_ax = (float)data.param("eig_inc_axes", 1.0);
const int kern_tiles = kernels_hor*kernels_vert*num_colors;
const int tilesx = img_width/8, tilesy = img_height/8;
const int numTiles = tilesx*tilesy;
// ---- pose-side task template from the captured production stream (D2 rule) ----
const float* ft0 = data.hostFloat("ftasks0_it0");
const float* ft1 = data.hostFloat("ftasks1_it0");
const int num_tasks = (int)(data.elements("ftasks0_it0")/task_size);
if (num_tasks <= 0 || (int)(data.elements("ftasks1_it0")/task_size) != num_tasks){
printf("FAIL: captured task streams missing/mismatched\n"); return EXIT_FAILURE; }
std::vector<int> task_map(num_tasks);
std::vector<float> task_centers(3*num_tasks);
int task_code_main = 0, task_code_sub = 0;
std::memcpy(&task_code_main, ft0 + TP_TASK_TASK_OFFSET, sizeof(int));
std::memcpy(&task_code_sub, ft1 + TP_TASK_TASK_OFFSET, sizeof(int));
std::vector<float> lma_centers(3*(size_t)numTiles, 0.0f);
for (int i = 0; i < num_tasks; i++){
std::memcpy(&task_map[i], ft0 + (size_t)i*task_size + TP_TASK_TXY_OFFSET, sizeof(int));
task_centers[3*i+0] = ft0[(size_t)i*task_size + TP_TASK_CENTERXY_OFFSET];
task_centers[3*i+1] = ft0[(size_t)i*task_size + TP_TASK_CENTERXY_OFFSET+1];
task_centers[3*i+2] = 0.0f;
const int tx = task_map[i] & 0xffff, ty = (task_map[i] >> 16) & 0xffff;
const int tile = ty*tilesx + tx;
if (tile < 0 || tile >= numTiles){ printf("FAIL: task %d txy out of grid\n", i); return EXIT_FAILURE; }
lma_centers[3*(size_t)tile+0] = task_centers[3*i+0];
lma_centers[3*(size_t)tile+1] = task_centers[3*i+1];
}
// synthetic-but-real-dims camera pair (D2 precedent)
const int rbr_len=5001, ers_len=img_height*14;
const float meta[8]={(float)img_width,(float)img_height,4.0f,5.0f,2.85f,1.0f,0.0f,0.0004f};
const float radial[7]={0,0,0,0,0,0,0};
std::vector<float> rbr(rbr_len,1.0f), ers((size_t)ers_len,0.0f);
for(int line=0;line<img_height;line++) ers[(size_t)line*14+6]=1.0f;
const float dx_main=0.35f, dy_main=-0.25f, dx_sub=-0.35f, dy_sub=0.25f;
const float scale_main=1.0f, scale_sub=-1.0f;
const float min_px=8.0f, max_px=(float)(img_width-8), min_py=8.0f, max_py=(float)(img_height-8);
const float v0[NUM_PARAMS]={0.0020f,-0.0010f,0.0005f};
const float pull[NUM_PARAMS]={v0[0]+0.0004f,v0[1]-0.0002f,v0[2]+0.0001f};
const float regw[NUM_PARAMS]={0.08f,0.08f,0.08f};
// ---- render-side full-frame tasks, EXPLICIT centers (render_pipe stage-1 form) ----
const float mb_dx = 0.3125f, mb_dy = -0.171875f;
const int ntiles = tilesx*tilesy;
std::vector<float> rtasks[2];
for (int nset = 0; nset < 2; nset++){
const float* tmpl = (nset==0)? ft0 : ft1;
rtasks[nset].assign((size_t)ntiles*task_size, 0.f);
for (int ty = 0; ty < tilesy; ty++)
for (int tx = 0; tx < tilesx; tx++){
float* t = rtasks[nset].data() + (size_t)(ty*tilesx+tx)*task_size;
memcpy(t, tmpl, 6*sizeof(float));
const int txy = (ty << 16) | tx;
memcpy(t+1, &txy, sizeof(int));
t[3] = tx*8 + 4 + ((nset==1)? mb_dx : 0.f);
t[4] = ty*8 + 4 + ((nset==1)? mb_dy : 0.f);
}
}
const int rbg_w = img_width + 8, rbg_h = num_colors*(img_height + 8);
const size_t rbg_n = (size_t)rbg_w*rbg_h;
const float* h_kern = data.hostFloat("kernels");
const float* h_offs = data.hostFloat("kernel_offsets");
const float* h_imgs = data.hostFloat("images");
const int kern_elems = (int)(data.elements("kernels")/num_cams);
const int offs_elems = (int)(data.elements("kernel_offsets")/num_cams);
const int num_pairs = num_cams*(num_cams-1)/2;
// common per-proc upload (both sides need geometry/kernels/images/LPF)
auto setupProc = [&](void* m, int for_pose)->void*{
void* p = tp_proc_create(m);
if(!p || tp_proc_setup(p, num_cams, num_colors, img_width, img_height, kernels_hor, kern_tiles)){
printf("FAIL setup: %s\n", tp_last_error()); return nullptr; }
tp_proc_set_geometry(p, data.hostFloat("geometry_correction"), (int)data.elements("geometry_correction"));
tp_proc_set_correction_vector(p, data.hostFloat("correction_vector"), (int)data.elements("correction_vector"));
for (int c = 0; c < num_cams; c++){
tp_proc_set_kernels (p, c, h_kern + (size_t)c*kern_elems, kern_elems);
tp_proc_set_kernel_offsets(p, c, h_offs + (size_t)c*offs_elems, offs_elems);
tp_proc_set_image (p, c, h_imgs + (size_t)c*img_width*img_height);
}
tp_proc_set_const(p, "lpf_data", data.hostFloat("lpf_data"), 4*64);
tp_proc_set_const(p, "lpf_corr", data.hostFloat("lpf_corr"), 64);
tp_proc_set_const(p, "lpf_rb_corr", data.hostFloat("lpf_rb_corr"), 64);
tp_proc_set_const(p, "LoG_corr", data.hostFloat("log_corr"), 64);
if (for_pose){
tp_proc_set_clt(p, 0, data.hostFloat("clt_ref_cam0"), 1); // resident center TD
tp_proc_setup_rbg_corr(p, num_pairs, 0,0,0,0, 1.f,1.f,1.f, corr_rad);
if (data.has("debias")) tp_proc_set_peak_debias(p, data.hostFloat("debias"), (int)data.elements("debias"));
if(tp_proc_set_tasks_slot(p, ft0, num_tasks, num_tasks*task_size, 0) ||
tp_proc_set_tasks_slot(p, ft1, num_tasks, num_tasks*task_size, 1)){
printf("FAIL set_tasks_slot: %s\n", tp_last_error()); return nullptr; }
if(tp_proc_set_pose_cycle(p, num_tasks, task_size, 0.0f,
min_px, max_px, min_py, max_py, task_code_main, task_code_sub,
dx_main, dy_main, dx_sub, dy_sub, scale_main, scale_sub,
soft_margin, hard_margin, sel_sensors, s0, s1, s2,
fz_inter, corr_rad, 0xff,
p_abs_min, p_rel_min, p_min_peak, p_sub_frac,
p_recenter, p_sub_frac1, p_scale_ax, p_inc_ax, 1)){
printf("FAIL set_pose_cycle: %s\n", tp_last_error()); return nullptr; }
} else {
tp_proc_setup_rbg_corr(p, 1, 0,0,0,0, 1.f,1.f,1.f, 7);
if(tp_proc_render_setup(p, 0.f, 0.f,0.f,0.f,0.f, soft_margin, hard_margin)){
printf("FAIL render_setup: %s\n", tp_last_error()); return nullptr; }
for (int nset = 0; nset < 2; nset++)
if(tp_proc_render_set_tasks(p, nset, rtasks[nset].data(), ntiles, ntiles*task_size)){
printf("FAIL render_set_tasks: %s\n", tp_last_error()); return nullptr; }
}
return p;
};
// one pose scene = one D3 DP entry, IDENTICAL args every call (fixed anchor)
float packed_ref[RESULT], vector_ref[NUM_PARAMS];
auto poseScene = [&](void* p, int first, float* packed_out, float* vector_out)->int{
const float poseK[12]={0,0,0, 0,0,0, 0,0,0, v0[0],v0[1],v0[2]};
float anchor[NUM_PARAMS]={v0[0],v0[1],v0[2]};
std::vector<float> trace((size_t)K_CYCLES*RESULT,0.0f);
std::vector<int> mstats((size_t)K_CYCLES*MSTATS,-1);
float prep[PREP_FLOATS]={0}; int stats[3]={-1,-1,-1};
return tp_proc_exec_pose_scene_dp(p,
first?meta:nullptr, first?radial:nullptr, first?rbr.data():nullptr, first?rbr_len:0,
first?ers.data():nullptr, first?ers_len:0,
first?meta:nullptr, first?radial:nullptr, first?rbr.data():nullptr, first?rbr_len:0,
first?ers.data():nullptr, first?ers_len:0,
poseK, first?task_map.data():nullptr, first?task_centers.data():nullptr,
K_CYCLES, LAMBDA, 0.0f, RMS_DIFF,
numTiles, CORR_SLOT, NTILE_SHIFT, NUM_COMPONENTS, USE_EIGEN,
EIG_MIN_SQRT, EIG_MAX_SQRT, MIN_CONFIDENCE, SAME_WEIGHTS,
0, first?lma_centers.data():nullptr,
pull, regw, anchor,
trace.data(), mstats.data(), packed_out, vector_out, prep, stats);
};
int fail = 0;
// ---- modules: pose carve, render carve, (optional) plain negative control ----
void* mP = makeModule(pose_green.c_str(), srcdir.c_str(), devrt.c_str());
if(!mP) return EXIT_FAILURE;
void* pP = setupProc(mP, 1); if(!pP) return EXIT_FAILURE;
void* mR = makeModule(render_green.c_str(), srcdir.c_str(), devrt.c_str());
if(!mR) return EXIT_FAILURE;
void* pR = setupProc(mR, 0); if(!pR) return EXIT_FAILURE;
void* mN = nullptr; void* pN = nullptr;
if (!skip_neg){
mN = makeModule("", srcdir.c_str(), devrt.c_str());
if(!mN) return EXIT_FAILURE;
pN = setupProc(mN, 0); if(!pN) return EXIT_FAILURE;
}
// ---- pose solo: first call (uploads) + reference capture + repeat self-check ----
float packed2[RESULT], vector2[NUM_PARAMS];
if (poseScene(pP, 1, packed_ref, vector_ref) <= 0){
printf("FAIL pose first call: %s\n", tp_last_error()); return EXIT_FAILURE; }
if (poseScene(pP, 0, packed_ref, vector_ref) <= 0){
printf("FAIL pose ref call: %s\n", tp_last_error()); return EXIT_FAILURE; }
if (poseScene(pP, 0, packed2, vector2) <= 0){
printf("FAIL pose repeat call: %s\n", tp_last_error()); return EXIT_FAILURE; }
{ const int d = std::memcmp(packed_ref,packed2,sizeof(packed_ref)) ||
std::memcmp(vector_ref,vector2,sizeof(vector_ref));
printf("pose solo repeat self-check: %s\n", d?"DIFF -> FAIL":"bit-identical");
if (d) fail = 1; }
// ---- render solo reference output ----
std::vector<float> render_ref(rbg_n);
if(tp_proc_render_scene(pR, nullptr, 0, 0,0,0,0, 0,0, 0,0, -1, 0) ||
tp_proc_render_status(pR, 1, nullptr) != 1){
printf("FAIL render solo: %s\n", tp_last_error()); return EXIT_FAILURE; }
if(tp_proc_render_get(pR, render_ref.data()) != 1){
printf("FAIL render_get: %s\n", tp_last_error()); return EXIT_FAILURE; }
// ---- arrangement runner: scenes x [enqueue render? -> pose -> wait render] ----
auto arrangement = [&](const char* name, void* renderProc)->void{
std::vector<double> tp(scenes), tr(scenes);
long mm = 0;
for (int s = 0; s < scenes; s++){
if (renderProc){
if(tp_proc_render_scene(renderProc, nullptr, 0, 0,0,0,0, 0,0, 0,0, -1, 0)){
printf("FAIL %s render enqueue: %s\n", name, tp_last_error()); fail=1; return; }
}
const auto t0 = std::chrono::steady_clock::now();
if (poseScene(pP, 0, packed2, vector2) <= 0){
printf("FAIL %s pose scene %d: %s\n", name, s, tp_last_error()); fail=1; return; }
const auto t1 = std::chrono::steady_clock::now();
if (std::memcmp(packed_ref,packed2,sizeof(packed_ref)) ||
std::memcmp(vector_ref,vector2,sizeof(vector_ref))) mm++;
if (renderProc){
if(tp_proc_render_status(renderProc, 1, nullptr) != 1){
printf("FAIL %s render wait: %s\n", name, tp_last_error()); fail=1; return; }
}
const auto t2 = std::chrono::steady_clock::now();
tp[s] = std::chrono::duration<double,std::milli>(t1-t0).count();
tr[s] = std::chrono::duration<double,std::milli>(t2-t1).count();
}
double p50,p95,mx, r50,r95,rmx;
pct(tp,&p50,&p95,&mx); pct(tr,&r50,&r95,&rmx);
printf("%s: pose %6.3f p50 %6.3f p95 %7.3f max ms", name, p50, p95, mx);
if (renderProc) printf(" | render residual wait %5.3f p50 %5.3f p95 %6.3f max", r50, r95, rmx);
printf(" | pose result mismatches=%ld -> %s\n", mm, mm?"FAIL":"bit-identical");
if (mm) fail = 1;
};
arrangement("a0 pose(carve) solo ", nullptr);
arrangement("a1 pose(carve)+render(carve) ", pR);
{ // combo render output must equal the solo reference
std::vector<float> got(rbg_n);
if(tp_proc_render_get(pR, got.data()) != 1){ printf("FAIL combo render_get\n"); fail=1; }
else { double maxd=0; const long bad = imgCompare(got.data(), render_ref.data(), rbg_n, &maxd);
printf("a1 render output vs solo: mismatches=%ld max|diff|=%g -> %s\n", bad, maxd, bad?"FAIL":"PASS");
if (bad) fail=1; } }
if (pN) arrangement("a2 pose(carve)+render(UNCARVED) ", pN);
arrangement("a3 pose(carve) solo re-check ", nullptr);
printf("%s: %s\n", argv[0], fail ? "FAIL" : "PASS");
tp_proc_destroy(pP); if(pR) tp_proc_destroy(pR); if(pN) tp_proc_destroy(pN);
tp_destroy_module(mP); tp_destroy_module(mR); if(mN) tp_destroy_module(mN);
return fail ? EXIT_FAILURE : EXIT_SUCCESS;
}
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