research: preserve solver experiments and reproducible benchmarks

This commit is contained in:
Yaossg 2026-10-11 12:28:02 +08:00
parent 12e4266950
commit e93bc20b0a
85 changed files with 518443 additions and 0 deletions

View file

@ -0,0 +1,11 @@
# 实验导航
| 目录 | 研究问题 | 结果入口 |
|---|---|---|
| `full_search_feasibility/` | 输出差过滤、区间求交、低位类复用及严格拒绝补扫的成本 | [报告](full_search_feasibility/REPORT.md) |
| `normal_search/` | 普通分支的 16 候选成组筛选 | [报告](normal_search/REPORT.md) |
| `normal_search/` | 把类复用和仅展开有根位置接入批次调度 | [流程报告](normal_search/PIPELINE_REPORT.md) |
这里的 `positions/`、`pipeline_positions/`、`results/`、`pipeline_results/` 是报告和复现脚本使用的数据,作为研究记录保留。日志和空 stderr 文件忽略;二进制一般输出到 `/tmp`。
日常比较本机与服务器的性能请用 [当前 CLI](../../bench/README.md)。实验程序保留用于受控对照,不承担正式 CLI 的职责。普通分支与补扫的覆盖范围不可混用。

View file

@ -0,0 +1,135 @@
# 实验结论:定点求解显著提速,全世界目录仍不适合启动
日期:2026-10-11,Asia/Hong_Kong。硬件:RTX 3060 Laptop、Ryzen 7 5800H,WSL,CUDA 12.0。
## 结论
1. **保留输出差过滤+逐格区间求交。** GPU 搜索 kernel 在三组同任务对照中快 197~292 倍,完整输出一致。
2. **保留低位坐标类复用。** 52,213 个实际位置的完整低位根列表与 32 个代表类一致;它减少根生成,不能消除后续中间位枚举。
3. **否决低位位表查找替换。** 此 GPU 上查表比直接整数计算多耗时约 36%。
4. **保留按首个奇数格逆推拒绝尾部。** 相比逐格枚举全部尾部,128 坐标批次快约 24 倍,并覆盖多次拒绝和多个格子首次拒绝的情况。
5. **当前路线仍不足以生成全世界全部种子的目录。** 随机批次吞吐外推:首次输出分支约 0.9 年;包含拒绝重抽的完整分支约 16 年。这里已乐观地摊薄进程启动、复用低位根生成,不是实际跑完全世界,也不是所有可能算法的下界。
代码是独立实验,没有替换原来的正式入口。
## GPU 求解器对照
全部模式处理相同的 lower35 候选,完整预热后轮换顺序测量五轮,核对排序后的完整 `(world_seed,x,z)` 列表。
| 负载 | lower35 数 | 原排序事件求解器 | 仅区间求交 | 输出差+原求解器 | 输出差+区间求交 | 最佳相对原版 |
| --- | ---: | ---: | ---: | ---: | ---: | ---: |
| 已知位置 `(51069,419124)` | 11,010,048 | 63.750 ms | 0.763 ms | 0.390 ms | **0.324 ms** | **197.0×** |
| 21 个压力/边界坐标 | 62,128,128 | 363.876 ms | 4.674 ms | 1.757 ms | **1.245 ms** | **292.2×** |
| 4096 个均匀随机坐标 | 387,973,120 | 2318.625 ms | 29.380 ms | 12.297 ms | **8.157 ms** | **284.2×** |
| 65536 个均匀随机坐标 | 5,944,901,632 | 未重测 | 407.659 ms | 175.974 ms | **131.670 ms** | — |
以上均为 CUDA event kernel 中位数,不包括低位根生成、CUDA 初始化、分配和传输。21 坐标组包含已知命中附近位置、原点、世界边界和 int32 边界;它不代表随机平均坐标。
已知位置和压力组均得到相同的 24 个种子。两个随机组没有命中。随机无命中不单独构成正确性证据,另有下面的独立校验。
主要收益来自更早排除不可能共同满足模 10 条件的候选:
```
delta_i = (q_i(0) - q_0(0)) mod 2^31
必要条件:delta_i mod 10 属于 {0,8}
```
原因是改变高 13 位,对所有输出施加相同的模 `2^31` 平移;两个最终输出都是 10 的倍数时,差模 `2^31` 只能具有上述余数。多数候选在几个格子后就失败,不再支付 25 格的事件排序成本。差过滤通过后,最多两个“区间+余数”做逐格求交,再完整 Java 验证。
## 根分布与全局工作量
确定性均匀随机抽样 65536 个锚点,两轴范围 `[-1875000,1874999]`:
| 指标 | 结果 |
| --- | ---: |
| 首次输出低位无根比例 | 96.9162% |
| 低 18 位根总数 | 45,356 |
| 每坐标平均根数 | 0.69208 |
| 平均数的正态近似 95% 区间 | 0.61054~0.77361 |
| 最大根数 | 1015 |
分布有较长尾部。置信区间只说明该抽样模型中的根数均值不确定性,不包含 GPU 频率、长期运行、分组调度及模型覆盖的误差。
按样本均值,世界的 `14,062,500,000,000` 个锚点仍约有:
```
14,062,500,000,000 × 0.69207763671875 × 131072
= 1.2756375 × 10^18 个 lower35 候选
```
新 kernel 在 65536 坐标批次中约处理 451.5 亿个 lower35/秒。把实测批次吞吐线性扩展到全部锚点,首次输出分支约 **0.895 年**。这已不适合用早先的“已知命中坐标耗时 × 所有坐标”去估计成几万年,但距离几周完成仍有明显差距。
## 坐标类复用和位表查找
归一化有效种子 `s=world_seed+T(x,z)` 后,图案相对坐标项的低 18 位在 X 上以 `65536`、Z 上以 `131072` 为周期。
选取 32 个有根的类,并展开成世界内全部 52,213 个实际锚点。程序逐一比较每个同类位置的**完整归一化低位根列表**,全部一致。
| 低位筛选负载 | 直接整数计算 | 32 KiB 位表查找 |
| --- | ---: | ---: |
| 65536 随机坐标 | **280.639 ms** | 380.533 ms |
| 32 个类代表 | **0.138 ms** | 0.209 ms |
| 52,213 个实际位置重复计算 | **293.866 ms** | 409.952 ms |
因此查表方案不保留。类复用在算法上成立,表中只比较筛选 kernel,未把归类、展开和传输成本当作零成本的实测完整方案。全世界最多 `2^33` 个类,按大批次根筛选吞吐粗略外推,代表类筛选约 10.2 小时;更高位求解仍须处理具体坐标,不能再乘一个“1637 倍”全流程加速。
首次输出无根并不排除拒绝重抽解,所以不能据此跳过完整语义的异常分支。
## 完整覆盖拒绝重抽
朴素补扫对 25 格分别枚举 `8 × 2^17` 个首次拒绝状态,共 26,214,400 个候选/坐标。
本轮新增的规范化补扫只枚举一次有效种子的低 18 位 `p`:
1. 从 p 算出每格首次输出的奇偶。
2. 若存在奇数格,选第一个。任何真实解必须在这一格首次拒绝,否则不可能返回 0。
3. 该格状态的低 18 位已确定,在拒绝区间中恰好有四个完整推进后状态与它一致;逆推这四个完整种子,执行全部格子的精确 Java 检查。
4. 若全部格子都是偶数,则为每一格补扫四个拒绝状态。
若一个坐标有 R 个全偶低位根,最多生成 `2^20 + 96R` 个补扫候选。无需假设“多个格子同时拒绝不可能”;选择首个奇数格的必要性对这种情况也成立。所有首次输出都被接受的真实解由普通分支覆盖,任何首次拒绝的真实解由补扫覆盖。最终并集去重。
| 对照任务 | 逐格朴素补扫 | 规范化补扫 | 去重命中数 |
| --- | ---: | ---: | ---: |
| 已知坐标的单格约束 | 0.032 ms | 0.026 ms | 104,848 |
| 同坐标前两格约束 | 0.065 ms | 0.053 ms | 20,888 |
| 同坐标前五格约束 | 0.139 ms | 0.084 ms | 109 |
| 128 坐标的完整 5×5 | 93.597 ms | **3.908 ms** | 0 |
两种补扫逐项比较完整去重列表,单格、多格的非空结果也一致。
## 同批完整流程:最终成本判断
在同一个 65536 随机坐标批次中,普通分支和规范化拒绝补扫顺序执行,合并、排序、去重;完整预热后测五轮:
| 区域 | 中位数 |
| --- | ---: |
| 一次低位根准备 kernel | 296.573 ms(单次) |
| 普通搜索 kernel | 129.157 ms |
| 完整拒绝补扫 kernel | 2283.082 ms |
| 两个 kernel 的每轮耗时之和 | **2413.373 ms** |
| 同步、回传、合并在内的 host scan | **2356.676 ms** |
另在 21 坐标压力组完成同样的完整流程,全部 24 个已知结果保留,无额外拒绝解;完整结果已与此前普通分支核对。
本环境观察到 CUDA event 累计时间比 host wall time 高约 2.4%;两种时钟口径分别保留,不用它们混合计算局部加速比。这一差异的原因未单独确定,长期外推只按数量级解释。
按同批完整测量,外推全世界为 **16.0~16.4 年**。这里不重复支付进程启动,低位筛选可按坐标类摊薄;尚未计入全世界调度、建表、长期频率波动和输出持久化等工程成本。不能宣称已实现完整世界扫描。
补扫约占计算时间的 95%。**即使完全删掉这个正确性成本,普通分支仍约需一年。** 因此结论不依赖于罕见分支是否必须支持:这轮优化值得用于定点反查和有限批次,但仍不应启动全世界目录生成。
## 正确性检查与复现
- CPU 独立直接枚举 4096 个高位平面,共 33,554,432 个完整种子,覆盖 1~25 格约束、随机坐标和已知命中平面。原求解器、区间求解器和输出差过滤版本的完整列表一致。
- 用单独的 Java 算术实现核对全部 1,048,576 个单格拒绝状态及逆推;其中存在 52,422 个首次输出为奇数、重抽后成功的例子,防止测试只覆盖空结果。
- CPU 核对 250,000 个格子的坐标周期;GPU 每批抽取最多 64 个坐标完整核对低位根表,并对所有重复坐标类比较完整根列表。
- GPU 四种求解器、两种根筛选、两种拒绝补扫分别完整核对结果,容量溢出会失败。
- GPU 与桌面共享,五轮原始数据、温度、驱动、源码哈希及每项命令保存在结果文件。早期对照和后补完整流程的源码哈希分别记录,计算 kernel 的算法一致。
```
python3 research/experiments/full_search_feasibility/run.py
# GPU 需可访问;无 GPU 时可单独编译运行 cpu_verify.cpp。
python3 research/experiments/full_search_feasibility/run.py --analyse-only
```
核心代码:[interval_solver.hpp](interval_solver.hpp)、[cuda_bench.cu](cuda_bench.cu)。
汇总:[results/summary.json](results/summary.json)。完整实验数据:[results/all.json](results/all.json)。

View file

@ -0,0 +1,73 @@
#include "interval_solver.hpp"
#include <algorithm>
#include <array>
#include <iostream>
#include <random>
#include <stdexcept>
#include <vector>
namespace sr=slime_research;
namespace fs=full_search_experiment;
struct Emit {std::vector<uint64_t>& result;void operator()(uint64_t s){result.push_back(s);}};
void require(bool b,const char*message){if(!b)throw std::runtime_error(message);}
// Separate Java arithmetic oracle. Every conversion is explicit to avoid signed overflow.
uint64_t term(int32_t x,int32_t z){
auto sx=[](uint32_t n){return uint64_t(int64_t(int32_t(n)));};
uint32_t a=uint32_t(x),b=uint32_t(z);
return sx(a*a*4987142U)+sx(a*5947611U)+sx(b*b)*4392871ULL+sx(b*389711U);
}
bool exact(uint64_t seed,uint64_t coordinate){
uint64_t s=((seed+coordinate)^987234911ULL^0x5DEECE66DULL)&((1ULL<<48)-1);
for(;;){s=(s*0x5DEECE66DULL+11)&((1ULL<<48)-1);uint32_t q=s>>17;
if(q<2147483640U)return q%10==0;}
}
int main(){
std::mt19937_64 rng(2026101102);
uint64_t checked=0;
for(int test=0;test<4096;++test){
int32_t x=int32_t(rng()%3750000)-1875000,z=int32_t(rng()%3750000)-1875000;
if(test<24){x=51069;z=419124;}
std::array<sr::CellTerm,25> cells;
for(int j=0;j<5;j++)for(int i=0;i<5;i++)cells[j*5+i]={term(x+i,z+j),sr::kSlime};
int count=test<24?25:1+test%25;
uint64_t low=rng()&((1ULL<<35)-1);
if(test<24)low=(test%2?15959335054446ULL:61692151016558ULL)&((1ULL<<35)-1);
std::vector<uint64_t> direct,old,interval,filtered;Emit a{old},b{interval},c{filtered};
sr::solveUpper13(low,cells.data(),count,a);fs::solveIntervals(low,cells.data(),count,b);
if(fs::differenceFilter(low,cells.data(),count))fs::solveIntervals(low,cells.data(),count,c);
for(uint64_t h=0;h<8192;++h){
uint64_t s=low+(h<<35);bool ok=true;
for(int i=0;i<count;++i){
uint64_t v=(((s+cells[i].term)^0x5E434E432ULL)*0x5DEECE66DULL+11)&((1ULL<<48)-1);
if((v>>17)%10!=0||!exact(s,cells[i].term)){ok=false;break;}
}
if(ok)direct.push_back(s);
}
std::sort(old.begin(),old.end());std::sort(interval.begin(),interval.end());std::sort(filtered.begin(),filtered.end());
require(old==direct&&interval==direct&&filtered==direct,"upper enumeration mismatch");checked+=8192;
}
uint64_t rejectedSlime=0,oddRejectedSlime=0;
for(uint64_t v=uint64_t(2147483640U)<<17;v<(1ULL<<48);++v){
const uint64_t t=term(-1875000,1874999);
const uint64_t u=((v-11)*0xDFE05BCB1365ULL)&((1ULL<<48)-1);
const uint64_t seed=((u^0x5E434E432ULL)-t)&((1ULL<<48)-1);
const uint64_t recovered=(((seed+t)^0x5E434E432ULL)*0x5DEECE66DULL+11)&((1ULL<<48)-1);
require(v==recovered,"tail inversion mismatch");
bool a=exact(seed,t),b=sr::exactIsSlimeFromTerm(seed,t);require(a==b,"Java oracle mismatch");
rejectedSlime+=a;oddRejectedSlime+=a&&((v>>17)&1);
}
require(oddRejectedSlime>0,"missing rejection regression example");
for(int n=0;n<10000;++n){
int32_t x=int32_t(rng()%3750000)-1875000,z=int32_t(rng()%3750000)-1875000;
for(int j=0;j<5;++j)for(int i=0;i<5;++i){
uint64_t d=(term(x+i,z+j)-term(x,z))&((1U<<18)-1);
require(d==((term(x+65536+i,z+j)-term(x+65536,z))&((1U<<18)-1)),"X periodicity mismatch");
require(d==((term(x+i,z+131072+j)-term(x,z+131072))&((1U<<18)-1)),"Z periodicity mismatch");
}
}
std::cout<<"{\"upper_planes\":4096,\"direct_seeds\":"<<checked
<<",\"tail_states\":1048576,\"tail_slime\":"<<rejectedSlime
<<",\"odd_tail_slime\":"<<oddRejectedSlime
<<",\"periodicity_cells\":250000,\"passed\":true}\n";
}

View file

@ -0,0 +1,256 @@
#include "interval_solver.hpp"
#include <cuda_runtime.h>
#include <algorithm>
#include <array>
#include <chrono>
#include <cstdint>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <map>
#include <numeric>
#include <stdexcept>
#include <string>
#include <tuple>
#include <vector>
namespace sr = slime_research;
namespace fs = full_search_experiment;
using Clock = std::chrono::steady_clock;
#define CUDA(call) do { auto e = (call); if (e != cudaSuccess) throw std::runtime_error(std::string(#call)+": "+cudaGetErrorString(e)); } while (0)
struct Position { int32_t x, z; uint64_t anchor; sr::CellTerm cells[25]; };
struct Job { uint32_t position, root; };
struct Match { uint64_t position, seed; bool operator<(const Match& o)const{return std::tie(position,seed)<std::tie(o.position,o.seed);} bool operator==(const Match& o)const{return position==o.position&&seed==o.seed;} };
constexpr uint32_t MATCH_CAPACITY = 1U << 20;
constexpr uint32_t JOB_CAPACITY = 1U << 22;
Position makePosition(int32_t x,int32_t z) {
Position p{}; p.x=x;p.z=z;p.anchor=sr::coordinateTerm(x,z);
for(int j=0;j<5;++j)for(int i=0;i<5;++i)
p.cells[j*5+i]={(sr::coordinateTerm(x+i,z+j)-p.anchor)&sr::kMask48,sr::kSlime};
return p;
}
template<int Mode>
__global__ void rootKernel(const Position* positions,uint32_t count,const uint32_t* good,
uint32_t* counts,Job* jobs,unsigned long long* total,bool collect) {
uint64_t idx=uint64_t(blockIdx.x)*blockDim.x+threadIdx.x;
if(idx >= (uint64_t(count)<<18)) return;
const uint32_t pos=uint32_t(idx>>18), root=uint32_t(idx)&((1U<<18)-1);
const Position& p=positions[pos];
for(int i=0;i<25;++i){
const uint32_t in=root+uint32_t(p.cells[i].term);
if constexpr(Mode==0){
if((((in^uint32_t(sr::kCombinedXor))*uint32_t(sr::kJavaMultiplier)+11U)>>17)&1U)return;
}else{
const uint32_t k=in&((1U<<18)-1);
if(((good[k>>5]>>(k&31))&1U)==0)return;
}
}
atomicAdd(counts+pos,1U);
const auto at=atomicAdd(total,1ULL);
if(collect&&at<JOB_CAPACITY)jobs[at]={pos,root};
}
struct Emitter {
uint32_t position; uint64_t anchor; Match* out; unsigned long long* count;
__device__ void operator()(uint64_t s){
auto at=atomicAdd(count,1ULL);
if(at<MATCH_CAPACITY)out[at]={position,(s-anchor)&sr::kMask48};
}
};
template<int Mode>
__global__ void searchKernel(const Position* positions,const Job* jobs,uint32_t count,
Match* out,unsigned long long* total) {
uint64_t idx=uint64_t(blockIdx.x)*blockDim.x+threadIdx.x;
if(idx >= (uint64_t(count)<<17))return;
const Job job=jobs[idx>>17];
uint64_t low=job.root+((idx&((1U<<17)-1))<<18);
const Position& p=positions[job.position];
Emitter emit{job.position,p.anchor,out,total};
if constexpr(Mode==0)sr::solveUpper13(low,p.cells,25,emit);
else if constexpr(Mode==1)fs::solveIntervals(low,p.cells,25,emit);
else if constexpr(Mode==2){if(fs::differenceFilter(low,p.cells,25))sr::solveUpper13(low,p.cells,25,emit);}
else if constexpr(Mode==3){if(fs::differenceFilter(low,p.cells,25))fs::solveIntervals(low,p.cells,25,emit);}
}
__global__ void tailKernel(const Position* positions,uint32_t count,Match* out,unsigned long long* total,int cellCount){
const uint64_t idx=uint64_t(blockIdx.x)*blockDim.x+threadIdx.x;
if(idx >= uint64_t(count)*cellCount*(1U<<20))return;
const uint64_t cell=idx>>20;
const uint32_t pos=cell/cellCount,i=cell%cellCount;
const uint64_t v=(uint64_t(2147483640U)<<17)+(idx&((1U<<20)-1));
const Position& p=positions[pos];
const uint64_t u=((v-11)*0xDFE05BCB1365ULL)&sr::kMask48;
const uint64_t seed=((u^sr::kCombinedXor)-p.cells[i].term)&sr::kMask48;
if(sr::verifyPattern(seed,p.cells,cellCount)){
Emitter e{pos,p.anchor,out,total};e(seed);
}
}
// If an output is odd, a true solid-pattern seed must reject that output.
// Pick the first odd cell: four tail states correspond to each seed-low18.
// When every output is even, enumerate all cells' four tail states instead.
// This covers multiple-rejection paths too, without assuming they are impossible.
__global__ void canonicalTailKernel(const Position* positions,uint32_t count,Match* out,unsigned long long* total,int cellCount){
const uint64_t idx=uint64_t(blockIdx.x)*blockDim.x+threadIdx.x;
if(idx >= (uint64_t(count)<<18))return;
const uint32_t pos=idx>>18,root=idx&((1U<<18)-1);
const Position& p=positions[pos];
int firstOdd=-1;
for(int i=0;i<cellCount;++i)if((sr::nextStateFromTerm(root,p.cells[i].term)>>17)&1U){firstOdd=i;break;}
const int begin=firstOdd>=0?firstOdd:0,end=firstOdd>=0?firstOdd+1:cellCount;
for(int i=begin;i<end;++i){
const uint32_t vlow=uint32_t(sr::nextStateFromTerm(root,p.cells[i].term))&((1U<<18)-1);
for(uint32_t k=0;k<4;++k){
const uint64_t v=(uint64_t(2147483640U+(vlow>>17)+2*k)<<17)+(vlow&((1U<<17)-1));
const uint64_t u=((v-11)*0xDFE05BCB1365ULL)&sr::kMask48;
const uint64_t seed=((u^sr::kCombinedXor)-p.cells[i].term)&sr::kMask48;
if(sr::verifyPattern(seed,p.cells,cellCount)){Emitter e{pos,p.anchor,out,total};e(seed);}
}
}
}
struct Device {
Position* positions=nullptr; Job* jobs=nullptr; Match* matches=nullptr;
uint32_t* counts=nullptr;uint32_t* good=nullptr;unsigned long long* total=nullptr;
cudaEvent_t start,stop;
Device(const std::vector<Position>& p){
CUDA(cudaMalloc(&positions,p.size()*sizeof(Position)));CUDA(cudaMemcpy(positions,p.data(),p.size()*sizeof(Position),cudaMemcpyHostToDevice));
CUDA(cudaMalloc(&jobs,JOB_CAPACITY*sizeof(Job)));CUDA(cudaMalloc(&matches,MATCH_CAPACITY*sizeof(Match)));
CUDA(cudaMalloc(&counts,p.size()*sizeof(uint32_t)));CUDA(cudaMalloc(&total,sizeof(*total)));
std::array<uint32_t,8192> bits{};
for(uint32_t k=0;k<(1U<<18);++k)if(!((((k^uint32_t(sr::kCombinedXor))*uint32_t(sr::kJavaMultiplier)+11U)>>17)&1U))bits[k>>5]|=1U<<(k&31);
CUDA(cudaMalloc(&good,sizeof(bits)));CUDA(cudaMemcpy(good,bits.data(),sizeof(bits),cudaMemcpyHostToDevice));
CUDA(cudaEventCreate(&start));CUDA(cudaEventCreate(&stop));
}
~Device(){cudaFree(positions);cudaFree(jobs);cudaFree(matches);cudaFree(counts);cudaFree(total);cudaFree(good);cudaEventDestroy(start);cudaEventDestroy(stop);}
float finish(){CUDA(cudaGetLastError());CUDA(cudaEventRecord(stop));CUDA(cudaEventSynchronize(stop));float ms;CUDA(cudaEventElapsedTime(&ms,start,stop));return ms;}
uint64_t totalCount(){unsigned long long n;CUDA(cudaMemcpy(&n,total,sizeof(n),cudaMemcpyDeviceToHost));return n;}
float roots(uint32_t n,int mode,bool collect){
CUDA(cudaMemset(total,0,sizeof(*total)));CUDA(cudaMemset(counts,0,n*sizeof(uint32_t)));CUDA(cudaEventRecord(start));
unsigned blocks=unsigned(((uint64_t(n)<<18)+255)/256);
if(mode==0)rootKernel<0><<<blocks,256>>>(positions,n,good,counts,jobs,total,collect);
else rootKernel<1><<<blocks,256>>>(positions,n,good,counts,jobs,total,collect);
return finish();
}
float search(uint32_t n,int mode){
CUDA(cudaMemset(total,0,sizeof(*total)));CUDA(cudaEventRecord(start));
unsigned blocks=unsigned(((uint64_t(n)<<17)+255)/256);
if(blocks){
if(mode==0)searchKernel<0><<<blocks,256>>>(positions,jobs,n,matches,total);
if(mode==1)searchKernel<1><<<blocks,256>>>(positions,jobs,n,matches,total);
if(mode==2)searchKernel<2><<<blocks,256>>>(positions,jobs,n,matches,total);
if(mode==3)searchKernel<3><<<blocks,256>>>(positions,jobs,n,matches,total);
}
return finish();
}
std::vector<Match> results(){
uint64_t n=totalCount();if(n>MATCH_CAPACITY)throw std::runtime_error("match overflow");
std::vector<Match> r(n);CUDA(cudaMemcpy(r.data(),matches,n*sizeof(Match),cudaMemcpyDeviceToHost));std::sort(r.begin(),r.end());return r;
}
};
int main(int argc,char**argv){
try{
if(argc<3)throw std::runtime_error("usage: cuda_bench positions.txt root|compare|fast|tail|complete [repeats=5] [tail-cells=25]");
std::ifstream in(argv[1]);if(!in)throw std::runtime_error("cannot open positions");
int32_t x,z;std::vector<Position> positions;while(in>>x>>z)positions.push_back(makePosition(x,z));
if(positions.empty()||positions.size()>65536)throw std::runtime_error("position count must be 1..65536");
std::string task=argv[2];int repeats=argc>3?std::stoi(argv[3]):5;
int tailCells=argc>4?std::stoi(argv[4]):25;
if(tailCells<1||tailCells>25)throw std::runtime_error("tail-cells must be 1..25");
auto processStart=Clock::now();Device d(positions);
std::cout<<std::setprecision(10);
cudaDeviceProp prop{};CUDA(cudaGetDeviceProperties(&prop,0));std::cout<<"{\"type\":\"device\",\"name\":\""<<prop.name<<"\",\"positions\":"<<positions.size()<<"}"<<std::endl;
std::vector<uint32_t> referenceCounts;
std::vector<Job> referenceJobs;
auto collectRoots=[&](int mode){
float ms=d.roots(positions.size(),mode,true);uint64_t total=d.totalCount();if(total>JOB_CAPACITY)throw std::runtime_error("job overflow");
std::vector<uint32_t> counts(positions.size());CUDA(cudaMemcpy(counts.data(),d.counts,counts.size()*sizeof(uint32_t),cudaMemcpyDeviceToHost));
std::vector<Job> jobs(total);CUDA(cudaMemcpy(jobs.data(),d.jobs,total*sizeof(Job),cudaMemcpyDeviceToHost));
std::sort(jobs.begin(),jobs.end(),[](Job a,Job b){return std::tie(a.position,a.root)<std::tie(b.position,b.root);});
if(referenceCounts.empty()){referenceCounts=counts;referenceJobs=jobs;}
else {
if(counts!=referenceCounts||jobs.size()!=referenceJobs.size())throw std::runtime_error("root mismatch");
for(size_t i=0;i<jobs.size();++i)if(jobs[i].position!=referenceJobs[i].position||jobs[i].root!=referenceJobs[i].root)throw std::runtime_error("root list mismatch");
}
return ms;
};
if(task=="root"){
collectRoots(0);collectRoots(1);
for(int r=0;r<repeats;++r)for(int k=0;k<2;++k){int mode=(r+k)%2;float ms=collectRoots(mode);std::cout<<"{\"type\":\"root_timing\",\"mode\":"<<mode<<",\"round\":"<<r<<",\"kernel_ms\":"<<ms<<"}"<<std::endl;}
}else if(task=="tail"){
std::vector<Match> expected;
for(int r=-1;r<repeats;++r)for(int k=0;k<2;++k){
const int mode=r<0?k:(r+k)%2;
CUDA(cudaMemset(d.total,0,sizeof(*d.total)));CUDA(cudaEventRecord(d.start));
const uint64_t work=mode==0?uint64_t(positions.size())*tailCells*(1U<<20):(uint64_t(positions.size())<<18);
if((work+255)/256>0x7fffffffULL)throw std::runtime_error("tail grid too large");
unsigned blocks=unsigned((work+255)/256);
if(mode==0)tailKernel<<<blocks,256>>>(d.positions,positions.size(),d.matches,d.total,tailCells);
else canonicalTailKernel<<<blocks,256>>>(d.positions,positions.size(),d.matches,d.total,tailCells);
float ms=d.finish();auto result=d.results();
result.erase(std::unique(result.begin(),result.end()),result.end());
if(r==-1&&mode==0)expected=result;else if(result!=expected)throw std::runtime_error("tail mismatch");
if(r>=0)std::cout<<"{\"type\":\"tail_timing\",\"mode\":"<<mode<<",\"cells\":"<<tailCells<<",\"round\":"<<r<<",\"kernel_ms\":"<<ms<<",\"matches\":"<<result.size()<<"}"<<std::endl;
}
std::cout<<"{\"type\":\"process\",\"ms\":"<<std::chrono::duration<double,std::milli>(Clock::now()-processStart).count()<<"}"<<std::endl;return 0;
}else if(task=="complete"){
const float rootMs=collectRoots(0);
CUDA(cudaMemcpy(d.jobs,referenceJobs.data(),referenceJobs.size()*sizeof(Job),cudaMemcpyHostToDevice));
std::vector<Match> expected;
for(int r=-1;r<repeats;++r){
auto wallStart=Clock::now();
const float firstMs=d.search(referenceJobs.size(),3);
auto result=d.results();
CUDA(cudaMemset(d.total,0,sizeof(*d.total)));CUDA(cudaEventRecord(d.start));
const unsigned blocks=unsigned(((uint64_t(positions.size())<<18)+255)/256);
canonicalTailKernel<<<blocks,256>>>(d.positions,positions.size(),d.matches,d.total,25);
const float tailMs=d.finish();auto tail=d.results();
result.insert(result.end(),tail.begin(),tail.end());std::sort(result.begin(),result.end());
result.erase(std::unique(result.begin(),result.end()),result.end());
if(r==-1)expected=result;else if(result!=expected)throw std::runtime_error("complete pipeline result mismatch");
if(r>=0)std::cout<<"{\"type\":\"complete_timing\",\"round\":"<<r<<",\"first_ms\":"<<firstMs
<<",\"tail_ms\":"<<tailMs<<",\"compute_ms\":"<<(firstMs+tailMs)
<<",\"scan_ms\":"<<std::chrono::duration<double,std::milli>(Clock::now()-wallStart).count()
<<",\"matches\":"<<result.size()<<"}"<<std::endl;
}
std::cout<<"{\"type\":\"complete_info\",\"root_ms\":"<<rootMs<<",\"jobs\":"<<referenceJobs.size()<<",\"matches\":[";
for(size_t i=0;i<expected.size();++i){if(i)std::cout<<",";const auto& p=positions[expected[i].position];std::cout<<"["<<expected[i].seed<<","<<p.x<<","<<p.z<<"]";}std::cout<<"]}"<<std::endl;
}else{
float rootMs=collectRoots(0);
CUDA(cudaMemcpy(d.jobs,referenceJobs.data(),referenceJobs.size()*sizeof(Job),cudaMemcpyHostToDevice));
std::vector<Match> expected;
const std::vector<int> modes=task=="compare"?std::vector<int>{0,1,2,3}:std::vector<int>{1,2,3};
bool first=true;
for(int m:modes){d.search(referenceJobs.size(),m);auto r=d.results();if(first){expected=r;first=false;}else if(r!=expected)throw std::runtime_error("warmup result mismatch");}
for(int r=0;r<repeats;++r)for(size_t k=0;k<modes.size();++k){
int mode=modes[(k+r)%modes.size()];auto wallStart=Clock::now();float ms=d.search(referenceJobs.size(),mode);auto result=d.results();
if(result!=expected)throw std::runtime_error("search result mismatch");
std::cout<<"{\"type\":\"search_timing\",\"mode\":"<<mode<<",\"round\":"<<r<<",\"kernel_ms\":"<<ms<<",\"scan_ms\":"<<std::chrono::duration<double,std::milli>(Clock::now()-wallStart).count()<<",\"matches\":"<<result.size()<<"}"<<std::endl;
}
std::cout<<"{\"type\":\"search_info\",\"root_ms\":"<<rootMs<<",\"jobs\":"<<referenceJobs.size()<<",\"lower35\":"<<(uint64_t(referenceJobs.size())<<17)<<",\"matches\":[";
for(size_t i=0;i<expected.size();++i){if(i)std::cout<<",";const auto& p=positions[expected[i].position];std::cout<<"["<<expected[i].seed<<","<<p.x<<","<<p.z<<"]";}std::cout<<"]}"<<std::endl;
}
// CPU checks of complete low18 root lists, including varied coordinates.
for(size_t n=0;n<std::min<size_t>(64,positions.size());++n){
size_t pos=n*positions.size()/std::min<size_t>(64,positions.size());std::vector<uint32_t> cpu,gpu;
for(uint32_t s=0;s<(1U<<18);++s)if(sr::partialPatternPossible(s,18,positions[pos].cells,25))cpu.push_back(s);
for(auto j:referenceJobs)if(j.position==pos)gpu.push_back(j.root);
if(cpu!=gpu)throw std::runtime_error("CPU/GPU roots mismatch");
}
std::map<uint64_t,std::vector<uint32_t>> classes;
size_t offset=0;
for(size_t pos=0;pos<positions.size();++pos){
uint64_t key=(uint64_t(uint32_t(positions[pos].x)&65535)<<17)|(uint32_t(positions[pos].z)&131071);
std::vector<uint32_t> roots;
while(offset<referenceJobs.size()&&referenceJobs[offset].position==pos)roots.push_back(referenceJobs[offset++].root);
auto it=classes.find(key);
if(it==classes.end())classes.emplace(key,std::move(roots));
else if(it->second!=roots)throw std::runtime_error("periodic class root list mismatch");
}
std::cout<<"{\"type\":\"periodic_validation\",\"classes\":"<<classes.size()<<",\"positions\":"<<positions.size()<<",\"equal\":true}"<<std::endl;
std::cout<<"{\"type\":\"root_counts\",\"counts\":[";for(size_t i=0;i<referenceCounts.size();++i){if(i)std::cout<<",";std::cout<<referenceCounts[i];}std::cout<<"]}"<<std::endl;
std::cout<<"{\"type\":\"process\",\"ms\":"<<std::chrono::duration<double,std::milli>(Clock::now()-processStart).count()<<"}"<<std::endl;
}catch(const std::exception&e){std::cerr<<e.what()<<"\n";return 1;}
}

View file

@ -0,0 +1,3 @@
#pragma once
// Compatibility include for historical experiment entrypoints.
#include "../../../include/slime/upper_interval.hpp"

View file

@ -0,0 +1,32 @@
20508 90242
54865 12632
57808 83448
45571 7025
41354 55843
17402 110862
8259 107266
43482 107388
61898 108538
58072 45380
2384 37823
56566 33756
54050 33180
48027 41698
26400 127463
13969 27082
63274 45862
51826 109902
35332 113389
55589 46936
6571 80653
40963 108250
8207 115527
65432 46739
1632 44691
14689 90828
13769 13900
45145 91692
57059 84915
19692 116595
65533 67472
49762 93725

View file

@ -0,0 +1 @@
51069 419124

View file

@ -0,0 +1 @@
[1596, 1653, 1596, 1653, 1596, 1653, 1653, 1653, 1653, 1596, 1653, 1653, 1653, 1596, 1682, 1653, 1596, 1653, 1682, 1596, 1596, 1653, 1653, 1596, 1596, 1596, 1653, 1653, 1596, 1653, 1596, 1653]

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,21 @@
51069 419124
51069 419125
51070 419124
51068 419124
51069 419123
51071 419124
51069 419126
51071 419126
51067 419122
51068 419125
51070 419123
51072 419124
51069 419127
51072 419127
51066 419124
51069 419121
0 0
-1875000 -1875000
1874995 1874995
2147483643 2147483643
-2147483648 -2147483648

View file

@ -0,0 +1,128 @@
51069 419124
-151639 -947718
1628807 1768848
183149 -1355854
399809 180074
1331359 -949016
-928444 -1623457
-434111 1380151
152758 -903569
1573808 123536
1439373 -1760847
751203 -1435166
610332 1532034
-1825025 -1355719
-115982 205535
1824337 -1691304
653615 -1196891
70982 -1096949
471686 101463
-1283834 -394356
-1077237 -730018
1639252 1254113
798574 629823
27251 -1281168
187989 -364498
-1749840 1146587
800514 -1729353
-1222320 1829300
-21017 1801614
381104 -1778790
-913761 1285921
-1326869 -862681
753606 -1698600
861651 1158886
-853922 -1012344
409724 1445621
820384 -678458
103226 1272878
1600737 263564
-506130 -1245993
-825723 449811
-1683685 -40291
-1566877 1270725
-1224693 -1550920
-643224 416976
1637732 1161249
-540219 629696
385799 1463828
1235472 -549937
1456601 -972438
416534 -1635641
-1301541 -1746936
-1594959 -463516
1204858 -33676
-764975 64792
-123655 -117892
-255226 -926872
838204 1645544
1859060 -694124
-161268 -914208
-1466503 385080
411691 -631360
1613179 175007
-1629505 -215899
-1766803 1662240
-298802 1780132
-966039 -1151326
-1397810 1758470
-1180783 -884455
-1857260 -966834
1432151 1219727
-1042318 166210
1695758 1454030
1282751 1461553
1047318 -175482
-1264922 -901360
1361879 -1342934
-190193 1035186
786218 382124
-441325 310526
274023 1368323
1005396 -1205652
1345022 -242369
1362954 -120311
688497 -1303174
184270 -1475672
1697223 -841268
909342 1403124
-518834 -1841162
-457099 -712327
-1061496 -1132296
-1568524 209693
862602 213688
725831 -374225
-955021 1598463
-1242843 706739
-928275 1211740
-97386 26812
-159596 -898691
559750 -919322
-1261526 -1170283
1217562 -1802980
-273908 -438569
948984 915311
-1190015 -773822
500811 -295186
-489265 1081569
1816094 -1831463
1168538 105449
1031166 1699672
319995 -1076966
-723529 -385152
-1043111 1661566
1503451 -1847764
477739 -899398
-697019 1039008
1089311 1472213
1205717 566995
-1189155 303581
75335 964912
1716857 -1068302
-1646128 1525240
-526278 1172893
-478717 -1696911
-1648970 1053068
-294273 -392369
-341537 1585086
431026 -1312089

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,14 @@
{"type":"device","name":"NVIDIA GeForce RTX 3060 Laptop GPU","positions":32}
{"type":"root_timing","mode":0,"round":0,"kernel_ms":0.1382399946}
{"type":"root_timing","mode":1,"round":0,"kernel_ms":0.2088959962}
{"type":"root_timing","mode":1,"round":1,"kernel_ms":0.2088959962}
{"type":"root_timing","mode":0,"round":1,"kernel_ms":0.1351680011}
{"type":"root_timing","mode":0,"round":2,"kernel_ms":0.1382399946}
{"type":"root_timing","mode":1,"round":2,"kernel_ms":0.2037760019}
{"type":"root_timing","mode":1,"round":3,"kernel_ms":0.2283519953}
{"type":"root_timing","mode":0,"round":3,"kernel_ms":0.1648640037}
{"type":"root_timing","mode":0,"round":4,"kernel_ms":0.1587200016}
{"type":"root_timing","mode":1,"round":4,"kernel_ms":0.2088959962}
{"type":"periodic_validation","classes":32,"positions":32,"equal":true}
{"type":"root_counts","counts":[21,1,4,40,24,1,1,91,3,47,16,15,4,412,1,14,3,5,28,1,2,1,4,7,2,9,34,1,1,3,226,28]}
{"type":"process","ms":249.778637}

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,10 @@
{"type":"device","name":"NVIDIA GeForce RTX 3060 Laptop GPU","positions":21}
{"type":"complete_timing","round":0,"first_ms":1.288192034,"tail_ms":0.7680000067,"compute_ms":2.056191921,"scan_ms":2.294025,"matches":24}
{"type":"complete_timing","round":1,"first_ms":1.290240049,"tail_ms":0.7680000067,"compute_ms":2.058239937,"scan_ms":2.245116,"matches":24}
{"type":"complete_timing","round":2,"first_ms":1.289216042,"tail_ms":0.7680000067,"compute_ms":2.057216167,"scan_ms":2.231547,"matches":24}
{"type":"complete_timing","round":3,"first_ms":1.290240049,"tail_ms":0.7680000067,"compute_ms":2.058239937,"scan_ms":2.249119,"matches":24}
{"type":"complete_timing","round":4,"first_ms":1.289216042,"tail_ms":0.7690240145,"compute_ms":2.058239937,"scan_ms":2.262982,"matches":24}
{"type":"complete_info","root_ms":1.327103972,"jobs":474,"matches":[[10358701894766,51069,419124],[15959335054446,51069,419124],[18914276748398,51069,419124],[24514909908078,51069,419124],[27469851602030,51069,419124],[33070484761710,51069,419124],[36025426455662,51069,419124],[41626059615342,51069,419124],[44581001309294,51069,419124],[50181634468974,51069,419124],[53136576162926,51069,419124],[58737209322606,51069,419124],[61692151016558,51069,419124],[67292784176238,51069,419124],[70247725870190,51069,419124],[75848359029870,51069,419124],[78803300723822,51069,419124],[84403933883502,51069,419124],[87358875577454,51069,419124],[92959508737134,51069,419124],[95914450431086,51069,419124],[101515083590766,51069,419124],[104470025284718,51069,419124],[110070658444398,51069,419124]]}
{"type":"periodic_validation","classes":20,"positions":21,"equal":true}
{"type":"root_counts","counts":[84,152,16,0,2,20,61,22,0,1,35,30,20,29,0,2,0,0,0,0,0]}
{"type":"process","ms":271.397062}

View file

@ -0,0 +1 @@
{"upper_planes":4096,"direct_seeds":33554432,"tail_states":1048576,"tail_slime":104848,"odd_tail_slime":52422,"periodicity_cells":250000,"passed":true}

View file

@ -0,0 +1,4 @@
{
"independent_python_java_verification": true,
"unique_verified_matches": 24
}

View file

@ -0,0 +1,25 @@
{"type":"device","name":"NVIDIA GeForce RTX 3060 Laptop GPU","positions":1}
{"type":"search_timing","mode":0,"round":0,"kernel_ms":65.88722992,"scan_ms":64.322731,"matches":24}
{"type":"search_timing","mode":1,"round":0,"kernel_ms":0.7966719866,"scan_ms":0.989482,"matches":24}
{"type":"search_timing","mode":2,"round":0,"kernel_ms":0.3901439905,"scan_ms":0.568541,"matches":24}
{"type":"search_timing","mode":3,"round":0,"kernel_ms":0.3235839903,"scan_ms":0.475938,"matches":24}
{"type":"search_timing","mode":1,"round":1,"kernel_ms":0.7956479788,"scan_ms":0.931277,"matches":24}
{"type":"search_timing","mode":2,"round":1,"kernel_ms":0.3921920061,"scan_ms":0.537933,"matches":24}
{"type":"search_timing","mode":3,"round":1,"kernel_ms":0.318464011,"scan_ms":0.484489,"matches":24}
{"type":"search_timing","mode":0,"round":1,"kernel_ms":67.21331024,"scan_ms":65.89873,"matches":24}
{"type":"search_timing","mode":2,"round":2,"kernel_ms":0.3983359933,"scan_ms":0.656092,"matches":24}
{"type":"search_timing","mode":3,"round":2,"kernel_ms":0.3235839903,"scan_ms":0.448731,"matches":24}
{"type":"search_timing","mode":0,"round":2,"kernel_ms":63.08863831,"scan_ms":61.613729,"matches":24}
{"type":"search_timing","mode":1,"round":2,"kernel_ms":0.7587839961,"scan_ms":0.978891,"matches":24}
{"type":"search_timing","mode":3,"round":3,"kernel_ms":0.5212159753,"scan_ms":1.030974,"matches":24}
{"type":"search_timing","mode":0,"round":3,"kernel_ms":62.64831924,"scan_ms":61.355937,"matches":24}
{"type":"search_timing","mode":1,"round":3,"kernel_ms":0.7587839961,"scan_ms":0.913884,"matches":24}
{"type":"search_timing","mode":2,"round":3,"kernel_ms":0.3696640134,"scan_ms":0.516653,"matches":24}
{"type":"search_timing","mode":0,"round":4,"kernel_ms":63.75014496,"scan_ms":62.243002,"matches":24}
{"type":"search_timing","mode":1,"round":4,"kernel_ms":0.7628800273,"scan_ms":0.910191,"matches":24}
{"type":"search_timing","mode":2,"round":4,"kernel_ms":0.3768320084,"scan_ms":0.498385,"matches":24}
{"type":"search_timing","mode":3,"round":4,"kernel_ms":0.3102720082,"scan_ms":0.436487,"matches":24}
{"type":"search_info","root_ms":0.8509439826,"jobs":84,"lower35":11010048,"matches":[[10358701894766,51069,419124],[15959335054446,51069,419124],[18914276748398,51069,419124],[24514909908078,51069,419124],[27469851602030,51069,419124],[33070484761710,51069,419124],[36025426455662,51069,419124],[41626059615342,51069,419124],[44581001309294,51069,419124],[50181634468974,51069,419124],[53136576162926,51069,419124],[58737209322606,51069,419124],[61692151016558,51069,419124],[67292784176238,51069,419124],[70247725870190,51069,419124],[75848359029870,51069,419124],[78803300723822,51069,419124],[84403933883502,51069,419124],[87358875577454,51069,419124],[92959508737134,51069,419124],[95914450431086,51069,419124],[101515083590766,51069,419124],[104470025284718,51069,419124],[110070658444398,51069,419124]]}
{"type":"periodic_validation","classes":1,"positions":1,"equal":true}
{"type":"root_counts","counts":[84]}
{"type":"process","ms":618.005189}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,25 @@
{"type":"device","name":"NVIDIA GeForce RTX 3060 Laptop GPU","positions":21}
{"type":"search_timing","mode":0,"round":0,"kernel_ms":379.4073486,"scan_ms":368.969147,"matches":24}
{"type":"search_timing","mode":1,"round":0,"kernel_ms":3.854336023,"scan_ms":3.911966,"matches":24}
{"type":"search_timing","mode":2,"round":0,"kernel_ms":1.691648006,"scan_ms":1.808333,"matches":24}
{"type":"search_timing","mode":3,"round":0,"kernel_ms":1.225728035,"scan_ms":1.328216,"matches":24}
{"type":"search_timing","mode":1,"round":1,"kernel_ms":4.673535824,"scan_ms":4.759871,"matches":24}
{"type":"search_timing","mode":2,"round":1,"kernel_ms":2.663424015,"scan_ms":2.865543,"matches":24}
{"type":"search_timing","mode":3,"round":1,"kernel_ms":1.217535973,"scan_ms":1.325398,"matches":24}
{"type":"search_timing","mode":0,"round":1,"kernel_ms":371.9034729,"scan_ms":362.378901,"matches":24}
{"type":"search_timing","mode":2,"round":2,"kernel_ms":1.757184029,"scan_ms":1.912097,"matches":24}
{"type":"search_timing","mode":3,"round":2,"kernel_ms":1.245183945,"scan_ms":1.355726,"matches":24}
{"type":"search_timing","mode":0,"round":2,"kernel_ms":363.8763428,"scan_ms":356.104291,"matches":24}
{"type":"search_timing","mode":1,"round":2,"kernel_ms":3.95571208,"scan_ms":4.099446,"matches":24}
{"type":"search_timing","mode":3,"round":3,"kernel_ms":2.305023909,"scan_ms":2.485873,"matches":24}
{"type":"search_timing","mode":0,"round":3,"kernel_ms":361.4719849,"scan_ms":353.99145,"matches":24}
{"type":"search_timing","mode":1,"round":3,"kernel_ms":5.737472057,"scan_ms":5.931658,"matches":24}
{"type":"search_timing","mode":2,"round":3,"kernel_ms":1.793023944,"scan_ms":2.044199,"matches":24}
{"type":"search_timing","mode":0,"round":4,"kernel_ms":361.7187805,"scan_ms":354.316081,"matches":24}
{"type":"search_timing","mode":1,"round":4,"kernel_ms":5.419007778,"scan_ms":5.597639,"matches":24}
{"type":"search_timing","mode":2,"round":4,"kernel_ms":1.728512049,"scan_ms":1.845705,"matches":24}
{"type":"search_timing","mode":3,"round":4,"kernel_ms":1.251327991,"scan_ms":1.363353,"matches":24}
{"type":"search_info","root_ms":0.79974401,"jobs":474,"lower35":62128128,"matches":[[10358701894766,51069,419124],[15959335054446,51069,419124],[18914276748398,51069,419124],[24514909908078,51069,419124],[27469851602030,51069,419124],[33070484761710,51069,419124],[36025426455662,51069,419124],[41626059615342,51069,419124],[44581001309294,51069,419124],[50181634468974,51069,419124],[53136576162926,51069,419124],[58737209322606,51069,419124],[61692151016558,51069,419124],[67292784176238,51069,419124],[70247725870190,51069,419124],[75848359029870,51069,419124],[78803300723822,51069,419124],[84403933883502,51069,419124],[87358875577454,51069,419124],[92959508737134,51069,419124],[95914450431086,51069,419124],[101515083590766,51069,419124],[104470025284718,51069,419124],[110070658444398,51069,419124]]}
{"type":"periodic_validation","classes":20,"positions":21,"equal":true}
{"type":"root_counts","counts":[84,152,16,0,2,20,61,22,0,1,35,30,20,29,0,2,0,0,0,0,0]}
{"type":"process","ms":2434.177987}

View file

@ -0,0 +1,499 @@
{
"known": {
"kernel_median_ms": {
"0": 63.75014496,
"1": 0.7628800273,
"2": 0.3901439905,
"3": 0.3235839903
},
"type": "search_info",
"root_ms": 0.8509439826,
"jobs": 84,
"lower35": 11010048,
"matches": [
[
10358701894766,
51069,
419124
],
[
15959335054446,
51069,
419124
],
[
18914276748398,
51069,
419124
],
[
24514909908078,
51069,
419124
],
[
27469851602030,
51069,
419124
],
[
33070484761710,
51069,
419124
],
[
36025426455662,
51069,
419124
],
[
41626059615342,
51069,
419124
],
[
44581001309294,
51069,
419124
],
[
50181634468974,
51069,
419124
],
[
53136576162926,
51069,
419124
],
[
58737209322606,
51069,
419124
],
[
61692151016558,
51069,
419124
],
[
67292784176238,
51069,
419124
],
[
70247725870190,
51069,
419124
],
[
75848359029870,
51069,
419124
],
[
78803300723822,
51069,
419124
],
[
84403933883502,
51069,
419124
],
[
87358875577454,
51069,
419124
],
[
92959508737134,
51069,
419124
],
[
95914450431086,
51069,
419124
],
[
101515083590766,
51069,
419124
],
[
104470025284718,
51069,
419124
],
[
110070658444398,
51069,
419124
]
]
},
"stress": {
"kernel_median_ms": {
"0": 363.8763428,
"1": 4.673535824,
"2": 1.757184029,
"3": 1.245183945
},
"type": "search_info",
"root_ms": 0.79974401,
"jobs": 474,
"lower35": 62128128,
"matches": [
[
10358701894766,
51069,
419124
],
[
15959335054446,
51069,
419124
],
[
18914276748398,
51069,
419124
],
[
24514909908078,
51069,
419124
],
[
27469851602030,
51069,
419124
],
[
33070484761710,
51069,
419124
],
[
36025426455662,
51069,
419124
],
[
41626059615342,
51069,
419124
],
[
44581001309294,
51069,
419124
],
[
50181634468974,
51069,
419124
],
[
53136576162926,
51069,
419124
],
[
58737209322606,
51069,
419124
],
[
61692151016558,
51069,
419124
],
[
67292784176238,
51069,
419124
],
[
70247725870190,
51069,
419124
],
[
75848359029870,
51069,
419124
],
[
78803300723822,
51069,
419124
],
[
84403933883502,
51069,
419124
],
[
87358875577454,
51069,
419124
],
[
92959508737134,
51069,
419124
],
[
95914450431086,
51069,
419124
],
[
101515083590766,
51069,
419124
],
[
104470025284718,
51069,
419124
],
[
110070658444398,
51069,
419124
]
]
},
"random4096": {
"kernel_median_ms": {
"0": 2318.624756,
"1": 29.37958336,
"2": 12.29721642,
"3": 8.157183647
},
"type": "search_info",
"root_ms": 16.9953289,
"jobs": 2960,
"lower35": 387973120,
"matches": []
},
"random65536": {
"kernel_median_ms": {
"1": 407.6585083,
"2": 175.9743958,
"3": 131.6700134
},
"type": "search_info",
"root_ms": 268.6993713,
"jobs": 45356,
"lower35": 5944901632,
"matches": []
},
"distribution": {
"positions": 65536,
"roots": 45356,
"mean": 0.69207763671875,
"mean_normal95": [
0.6105416864300699,
0.7736135870074301
],
"zero_fraction": 0.9691619873046875,
"max": 1015
},
"roots65536": {
"0": 280.6394958,
"1": 380.5327454
},
"classes32": {
"0": 0.1382399946,
"1": 0.2088959962
},
"lifts": {
"0": 293.8664856,
"1": 409.9522705
},
"tail_one_cell": {
"kernel_median_ms": {
"0": 0.03174399957,
"1": 0.02559999935
},
"matches": 104848
},
"tail_two_cells": {
"kernel_median_ms": {
"0": 0.06451199949,
"1": 0.0532479994
},
"matches": 20888
},
"tail_five_cells": {
"kernel_median_ms": {
"0": 0.1392640024,
"1": 0.08396799862
},
"matches": 109
},
"tail128": {
"kernel_median_ms": {
"0": 93.59667206,
"1": 3.907583952
},
"matches": 0
},
"projections": {
"world_anchors": 14062500000000,
"lower35_visits": 1.2756375e+18,
"first_draw_kernel_years": 0.8952936774216201,
"root_no_reuse_years": 1.908215543817446,
"root_class_reuse_hours": 10.217772220416,
"canonical_tail_kernel_years": 13.603695931457478,
"complete_compute_years": 14.498989608879096,
"complete_same_batch_kernel_years": 16.409789423895784,
"complete_same_batch_scan_years": 16.024280153342424
},
"complete_stress": {
"first_ms": 1.289216042,
"tail_ms": 0.7680000067,
"compute_ms": 2.058239937,
"scan_ms": 2.249119,
"type": "complete_info",
"root_ms": 1.327103972,
"jobs": 474,
"matches": [
[
10358701894766,
51069,
419124
],
[
15959335054446,
51069,
419124
],
[
18914276748398,
51069,
419124
],
[
24514909908078,
51069,
419124
],
[
27469851602030,
51069,
419124
],
[
33070484761710,
51069,
419124
],
[
36025426455662,
51069,
419124
],
[
41626059615342,
51069,
419124
],
[
44581001309294,
51069,
419124
],
[
50181634468974,
51069,
419124
],
[
53136576162926,
51069,
419124
],
[
58737209322606,
51069,
419124
],
[
61692151016558,
51069,
419124
],
[
67292784176238,
51069,
419124
],
[
70247725870190,
51069,
419124
],
[
75848359029870,
51069,
419124
],
[
78803300723822,
51069,
419124
],
[
84403933883502,
51069,
419124
],
[
87358875577454,
51069,
419124
],
[
92959508737134,
51069,
419124
],
[
95914450431086,
51069,
419124
],
[
101515083590766,
51069,
419124
],
[
104470025284718,
51069,
419124
],
[
110070658444398,
51069,
419124
]
]
},
"complete65536": {
"first_ms": 129.1571198,
"tail_ms": 2283.081787,
"compute_ms": 2413.372559,
"scan_ms": 2356.676067,
"type": "complete_info",
"root_ms": 296.572937,
"jobs": 45356,
"matches": []
},
"cache_counts_equal": true
}

View file

@ -0,0 +1,12 @@
{"type":"device","name":"NVIDIA GeForce RTX 3060 Laptop GPU","positions":128}
{"type":"tail_timing","mode":0,"cells":25,"round":0,"kernel_ms":93.59667206,"matches":0}
{"type":"tail_timing","mode":1,"cells":25,"round":0,"kernel_ms":3.907583952,"matches":0}
{"type":"tail_timing","mode":1,"cells":25,"round":1,"kernel_ms":3.909631968,"matches":0}
{"type":"tail_timing","mode":0,"cells":25,"round":1,"kernel_ms":93.7738266,"matches":0}
{"type":"tail_timing","mode":0,"cells":25,"round":2,"kernel_ms":92.06886292,"matches":0}
{"type":"tail_timing","mode":1,"cells":25,"round":2,"kernel_ms":5.363711834,"matches":0}
{"type":"tail_timing","mode":1,"cells":25,"round":3,"kernel_ms":3.903487921,"matches":0}
{"type":"tail_timing","mode":0,"cells":25,"round":3,"kernel_ms":91.83436584,"matches":0}
{"type":"tail_timing","mode":0,"cells":25,"round":4,"kernel_ms":93.8915863,"matches":0}
{"type":"tail_timing","mode":1,"cells":25,"round":4,"kernel_ms":3.904511929,"matches":0}
{"type":"process","ms":778.407359}

View file

@ -0,0 +1,12 @@
{"type":"device","name":"NVIDIA GeForce RTX 3060 Laptop GPU","positions":1}
{"type":"tail_timing","mode":0,"cells":5,"round":0,"kernel_ms":0.1402879953,"matches":109}
{"type":"tail_timing","mode":1,"cells":5,"round":0,"kernel_ms":0.08499199897,"matches":109}
{"type":"tail_timing","mode":1,"cells":5,"round":1,"kernel_ms":0.08396799862,"matches":109}
{"type":"tail_timing","mode":0,"cells":5,"round":1,"kernel_ms":0.1392640024,"matches":109}
{"type":"tail_timing","mode":0,"cells":5,"round":2,"kernel_ms":0.1392640024,"matches":109}
{"type":"tail_timing","mode":1,"cells":5,"round":2,"kernel_ms":0.08499199897,"matches":109}
{"type":"tail_timing","mode":1,"cells":5,"round":3,"kernel_ms":0.08396799862,"matches":109}
{"type":"tail_timing","mode":0,"cells":5,"round":3,"kernel_ms":0.1351680011,"matches":109}
{"type":"tail_timing","mode":0,"cells":5,"round":4,"kernel_ms":0.1392640024,"matches":109}
{"type":"tail_timing","mode":1,"cells":5,"round":4,"kernel_ms":0.08396799862,"matches":109}
{"type":"process","ms":199.03863}

View file

@ -0,0 +1,12 @@
{"type":"device","name":"NVIDIA GeForce RTX 3060 Laptop GPU","positions":1}
{"type":"tail_timing","mode":0,"cells":1,"round":0,"kernel_ms":0.03174399957,"matches":104848}
{"type":"tail_timing","mode":1,"cells":1,"round":0,"kernel_ms":0.02559999935,"matches":104848}
{"type":"tail_timing","mode":1,"cells":1,"round":1,"kernel_ms":0.02559999935,"matches":104848}
{"type":"tail_timing","mode":0,"cells":1,"round":1,"kernel_ms":0.03174399957,"matches":104848}
{"type":"tail_timing","mode":0,"cells":1,"round":2,"kernel_ms":0.0308480002,"matches":104848}
{"type":"tail_timing","mode":1,"cells":1,"round":2,"kernel_ms":0.0266239997,"matches":104848}
{"type":"tail_timing","mode":1,"cells":1,"round":3,"kernel_ms":0.02559999935,"matches":104848}
{"type":"tail_timing","mode":0,"cells":1,"round":3,"kernel_ms":0.03190400079,"matches":104848}
{"type":"tail_timing","mode":0,"cells":1,"round":4,"kernel_ms":0.03174399957,"matches":104848}
{"type":"tail_timing","mode":1,"cells":1,"round":4,"kernel_ms":0.02559999935,"matches":104848}
{"type":"process","ms":294.256955}

View file

@ -0,0 +1,12 @@
{"type":"device","name":"NVIDIA GeForce RTX 3060 Laptop GPU","positions":1}
{"type":"tail_timing","mode":0,"cells":2,"round":0,"kernel_ms":0.06451199949,"matches":20888}
{"type":"tail_timing","mode":1,"cells":2,"round":0,"kernel_ms":0.05017599836,"matches":20888}
{"type":"tail_timing","mode":1,"cells":2,"round":1,"kernel_ms":0.0532479994,"matches":20888}
{"type":"tail_timing","mode":0,"cells":2,"round":1,"kernel_ms":0.06451199949,"matches":20888}
{"type":"tail_timing","mode":0,"cells":2,"round":2,"kernel_ms":0.06553599983,"matches":20888}
{"type":"tail_timing","mode":1,"cells":2,"round":2,"kernel_ms":0.05734400079,"matches":20888}
{"type":"tail_timing","mode":1,"cells":2,"round":3,"kernel_ms":0.0532479994,"matches":20888}
{"type":"tail_timing","mode":0,"cells":2,"round":3,"kernel_ms":0.06041600183,"matches":20888}
{"type":"tail_timing","mode":0,"cells":2,"round":4,"kernel_ms":0.06656000018,"matches":20888}
{"type":"tail_timing","mode":1,"cells":2,"round":4,"kernel_ms":0.04915200174,"matches":20888}
{"type":"process","ms":224.394511}

View file

@ -0,0 +1,195 @@
#!/usr/bin/env python3
"""Reproducible CPU validation and sequential CUDA experiments (no network)."""
from __future__ import annotations
import argparse
import hashlib
import json
import platform
import random
import statistics
import subprocess
import time
from datetime import datetime
from pathlib import Path
from zoneinfo import ZoneInfo
HERE = Path(__file__).resolve().parent
POS = HERE / "positions"
OUT = HERE / "results"
BIN = "/tmp/slime_feasibility_cuda"
def save_positions(name, points):
(POS / f"{name}.txt").write_text("".join(f"{x} {z}\n" for x, z in points))
def prepare():
POS.mkdir(exist_ok=True)
OUT.mkdir(exist_ok=True)
save_positions("known", [(51069, 419124)])
offsets = [(0, 0), (0, 1), (1, 0), (-1, 0), (0, -1), (2, 0), (0, 2),
(2, 2), (-2, -2), (-1, 1), (1, -1), (3, 0), (0, 3), (3, 3),
(-3, 0), (0, -3)]
save_positions("stress", [(51069 + x, 419124 + z) for x, z in offsets] +
[(0, 0), (-1875000, -1875000), (1874995, 1874995),
(2147483643, 2147483643), (-2147483648, -2147483648)])
rng = random.Random(2026101101)
coords = [(rng.randrange(-1875000, 1875000), rng.randrange(-1875000, 1875000))
for _ in range(65536)]
save_positions("random4096", coords[:4096])
save_positions("random65536", coords)
save_positions("tail128", [(51069, 419124)] + coords[:127])
return coords
def run_case(name, positions, task, repeats=5, cells=None):
cmd = [BIN, str(POS / f"{positions}.txt"), task, str(repeats)]
if cells is not None:
cmd.append(str(cells))
start = time.perf_counter()
result = subprocess.run(cmd, capture_output=True, text=True, timeout=300)
(OUT / f"{name}.jsonl").write_text(result.stdout)
(OUT / f"{name}.stderr").write_text(result.stderr)
if result.returncode:
raise RuntimeError(f"{name} failed: {result.stderr}")
rows = [json.loads(line) for line in result.stdout.splitlines()]
record = {"command": cmd, "wall_ms": (time.perf_counter() - start) * 1000,
"rows": rows}
print(json.dumps({"finished": name, "wall_ms": record["wall_ms"]}), flush=True)
return record
def median(rows, kind, mode):
return statistics.median(r["kernel_ms"] for r in rows
if r["type"] == kind and r["mode"] == mode)
def main():
ap = argparse.ArgumentParser()
ap.add_argument("--analyse-only", action="store_true")
ap.add_argument("--complete-only", action="store_true")
args = ap.parse_args()
if args.analyse_only or args.complete_only:
records = json.loads((OUT / "all.json").read_text())
else:
coords = prepare()
subprocess.run(["nvcc", "-O3", "-std=c++17", "-arch=sm_86",
str(HERE / "cuda_bench.cu"), "-o", BIN], check=True)
subprocess.run(["g++", "-O3", "-std=c++17", "-march=native", "-Wall", "-Wextra",
str(HERE / "cpu_verify.cpp"), "-o", "/tmp/slime_feasibility_verify"], check=True)
cpu = subprocess.check_output(["/tmp/slime_feasibility_verify"], text=True)
(OUT / "cpu_verify.json").write_text(cpu)
gpu_query = ["nvidia-smi", "--query-gpu=name,driver_version,temperature.gpu,utilization.gpu", "--format=csv"]
records = {"metadata": {
"date": datetime.now(ZoneInfo("Asia/Hong_Kong")).isoformat(),
"platform": platform.platform(), "cpu_validation": json.loads(cpu),
"gpu_before": subprocess.check_output(gpu_query, text=True),
"source_sha256": {p.name: hashlib.sha256(p.read_bytes()).hexdigest()
for p in [HERE / "cuda_bench.cu", HERE / "interval_solver.hpp",
HERE / "cpu_verify.cpp", HERE / "run.py",
HERE.parent.parent / "slime_solver_core.hpp",
HERE.parents[2] / "include/slime/solver_core.hpp",
HERE.parents[2] / "include/slime/upper_interval.hpp"]}}}
def record(name, positions, task, repeats=5, cells=None):
records[name] = run_case(name, positions, task, repeats, cells)
(OUT / "all.json").write_text(json.dumps(records, indent=2))
record("known", "known", "compare")
record("stress", "stress", "compare")
record("random4096", "random4096", "compare")
record("random65536", "random65536", "fast")
record("roots65536", "random65536", "root")
counts = next(r["counts"] for r in records["random4096"]["rows"] if r["type"] == "root_counts")
classes = [(x % 65536, z % 131072) for (x, z), n in zip(coords, counts) if n][:32]
save_positions("classes32", classes)
lifts, groups = [], []
for x, z in classes:
current = [(xx, zz)
for xx in range(-1875000 + (x + 1875000) % 65536, 1875000, 65536)
for zz in range(-1875000 + (z + 1875000) % 131072, 1875000, 131072)]
groups.append(len(current))
lifts.extend(current)
save_positions("lifts", lifts)
(POS / "lift_groups.json").write_text(json.dumps(groups))
record("classes32", "classes32", "root")
record("lifts", "lifts", "root")
record("tail_one_cell", "known", "tail", cells=1)
record("tail_two_cells", "known", "tail", cells=2)
record("tail_five_cells", "known", "tail", cells=5)
record("tail128", "tail128", "tail")
records["metadata"]["gpu_after"] = subprocess.check_output(gpu_query, text=True)
(OUT / "all.json").write_text(json.dumps(records, indent=2))
if not args.analyse_only:
if args.complete_only:
subprocess.run(["nvcc", "-O3", "-std=c++17", "-arch=sm_86",
str(HERE / "cuda_bench.cu"), "-o", BIN], check=True)
records["complete_stress"] = run_case("complete_stress", "stress", "complete")
records["complete65536"] = run_case("complete65536", "random65536", "complete")
records["metadata"]["complete_source_sha256"] = {
p.name: hashlib.sha256(p.read_bytes()).hexdigest()
for p in [HERE / "cuda_bench.cu", HERE / "interval_solver.hpp", HERE / "run.py",
HERE.parents[2] / "include/slime/solver_core.hpp",
HERE.parents[2] / "include/slime/upper_interval.hpp"]}
(OUT / "all.json").write_text(json.dumps(records, indent=2))
summary = {}
for name in ["known", "stress", "random4096", "random65536"]:
rows = records[name]["rows"]
modes = sorted({r["mode"] for r in rows if r["type"] == "search_timing"})
summary[name] = {"kernel_median_ms": {str(m): median(rows, "search_timing", m) for m in modes}}
summary[name].update(next(r for r in rows if r["type"] == "search_info"))
counts = next(r["counts"] for r in records["random65536"]["rows"] if r["type"] == "root_counts")
n = len(counts)
mean = statistics.mean(counts)
sem = statistics.stdev(counts) / n**0.5
summary["distribution"] = {"positions": n, "roots": sum(counts), "mean": mean,
"mean_normal95": [mean - 1.96 * sem, mean + 1.96 * sem],
"zero_fraction": counts.count(0) / n, "max": max(counts)}
for name in ["roots65536", "classes32", "lifts"]:
summary[name] = {str(m): median(records[name]["rows"], "root_timing", m) for m in [0, 1]}
for name in ["tail_one_cell", "tail_two_cells", "tail_five_cells", "tail128"]:
rows = records[name]["rows"]
summary[name] = {"kernel_median_ms": {str(m): median(rows, "tail_timing", m) for m in [0, 1]},
"matches": next(r["matches"] for r in rows if r["type"] == "tail_timing")}
# All projections are throughput extrapolations, not measured full-world scans.
world = 3750000**2
year = 365.25 * 86400
fast_ms = summary["random65536"]["kernel_median_ms"]["3"]
tail_ms = summary["tail128"]["kernel_median_ms"]["1"]
root_ms = min(summary["roots65536"].values())
summary["projections"] = {
"world_anchors": world,
"lower35_visits": world * mean * 131072,
"first_draw_kernel_years": fast_ms / 1000 / n * world / year,
"root_no_reuse_years": root_ms / 1000 / n * world / year,
"root_class_reuse_hours": root_ms / 1000 / n * (2**33) / 3600,
"canonical_tail_kernel_years": tail_ms / 1000 / 128 * world / year,
"complete_compute_years": (fast_ms / 1000 / n + tail_ms / 1000 / 128) * world / year,
}
for name in ["complete_stress", "complete65536"]:
if name in records:
rows = records[name]["rows"]
summary[name] = {key: statistics.median(r[key] for r in rows if r["type"] == "complete_timing")
for key in ["first_ms", "tail_ms", "compute_ms", "scan_ms"]}
summary[name].update(next(r for r in rows if r["type"] == "complete_info"))
if "complete65536" in summary:
summary["projections"]["complete_same_batch_kernel_years"] = summary["complete65536"]["compute_ms"] / 1000 / n * world / year
summary["projections"]["complete_same_batch_scan_years"] = summary["complete65536"]["scan_ms"] / 1000 / n * world / year
assert summary["complete_stress"]["matches"] == summary["stress"]["matches"]
# Count equality is checked here; the CUDA program additionally compares complete
# normalized root lists for every repeated coordinate class in its input.
base_counts = next(r["counts"] for r in records["classes32"]["rows"] if r["type"] == "root_counts")
lifted_counts = next(r["counts"] for r in records["lifts"]["rows"] if r["type"] == "root_counts")
groups = json.loads((POS / "lift_groups.json").read_text())
assert lifted_counts == [c for c, number in zip(base_counts, groups) for _ in range(number)]
summary["cache_counts_equal"] = True
(OUT / "summary.json").write_text(json.dumps(summary, indent=2))
print(json.dumps(summary, indent=2))
if __name__ == "__main__":
main()

View file

@ -0,0 +1,76 @@
# 普通搜索:坐标类复用及只展开有根类
2026-10-11(Asia/Hong_Kong);RTX 3060 Laptop GPU。接续 [16 候选成组筛选实验](REPORT.md)。补扫未修改、未运行。
结论:复用已接入可执行实验流程,计入分组、根生成、候选展开、必要传输、搜索和结果回传后仍有效。收益取决于同批坐标类重复率及有根类比例,不是统一倍数。对几乎无重复类的散点,直接成组筛选更快。
## 四条路径
- 模式 0:每个位置生成根,旧差过滤+区间求交。
- 模式 1:每个位置生成根,上一轮 16 候选成组筛选。
- 模式 2:坐标按 `(x mod 65536,z mod 131072)` 分类,每类生成一次根,再在 GPU 上展开任务,成组筛选。
- 模式 3:先分类、只构造代表位置;筛出类根后,仅构造和上传有根类的具体位置,再展开任务,成组筛选。
四条路径都重算本轮的类根,没有拿前一轮缓存假装免费。模式 2/3 使用各类排序后的完整根列表和位置偏移,在 GPU 上生成 `(具体位置,root)` 任务。模式 3 压缩位置后,将结果还原到原始输入索引。
程序检查根缓冲区和命中缓冲区容量,超限明确失败,不截断。单批支持最多 65,536 个位置、4,194,304 个展开后的根任务;较大任务仍需外层分批。当前是批次级调度实验,不是已经具备全世界断点续跑能力的正式扫描器。
## 实测批次耗时
预热一次、三轮轮换模式顺序。下表为 CPU 单调时钟测量的批次耗时中位数,单位 ms。
| 输入 | 位置数 / 类数 | 模式 0 | 模式 1 | 模式 2 | 模式 3 |
|---|---:|---:|---:|---:|---:|
| 已知位置所属类的全部世界内位置 | 1653 / 1 | 364.023 | 62.016 | 55.373 | 56.867 |
| 32 个有根类的全部世界内位置 | 52213 / 32 | 4691.311 | 915.446 | 656.710 | 676.742 |
| 512 个随机类,每类抽 64 个世界内位置 | 32768 / 512 | 172.222 | 141.138 | 14.235 | 9.586 |
| 4096 个均匀随机散点 | 4096 / 4096 | 24.022 | 17.902 | 19.239 | 19.502 |
**计入**:本批次位置项构造、分类、代表类筛根、类根回传/整理、偏移构造、必要 H2D 传输、GPU 根任务展开、每根公共项预计算、搜索、命中回传及排序、模式 3 结果索引还原。
**不计入**:输入文件读取、一次性 CUDA 初始化/工作区申请、专用于对照验证的完整任务回传和排序、日志打印。一次性准备另记为 `setup_ms`,这四批约 217~242 ms。预热复用了显存;新增预计算仍每轮执行。这里是长期运行时可摊薄初始化后的批次耗时,不是启动一次命令的进程总耗时。
本轮直接使用 host 时间,不与前一轮的 CUDA event 时间混算。
## 收益在哪里
以随机 512 类批次为例:
- 原先要为 32,768 个位置重复筛根;现在仅筛 512 个代表。
- 其中 19 个类有根,只有 1,216 个具体位置需要构造坐标项并传入后续搜索。
- 展开后的完整任务仍是相同的 15,424 个 `(位置,root)`,没有省略任何普通分支候选。
- 模式 3 的阶段中位数:初始分类/代表构造约 0.416 ms,类根生成约 2.049 ms,整理/展开约 0.690 ms,搜索及回传约 6.775 ms。各阶段中位数不必精确相加等于总耗时中位数。
- 相比上一轮成组筛选流程,本批再加速 14.72×;相对模式 0 为 17.97×。
32 个有根类的压力批次有 1,693,228 个根任务,全部类都必须展开,计算主要花在后续搜索。模式 3 相对模式 1 仅加速 1.35×;模式 2 略优,因为无需压缩位置和还原索引。
随机散点没有类复用收益,分类、回传和整理增加开销;模式 3 比模式 1 多耗时约 8.9%。因此应按类组织大范围遍历;不能对任意散点输入无条件启用该流程。
## 正确性和边界检查
每一轮、每一种模式均将**全部展开根任务列表**排序后与模式 0 逐项比较,并比较完整命中列表,不只是比较数量。
- 四批完整根列表和命中列表全部一致。
- 已知类批次保留原有 24 个命中,其他三批无命中。
- 全无根类的全部世界内位置:四条路径都生成 0 个任务、0 个命中;模式 3 正确处理没有具体位置可展开的情况。
- 原 21 个压力/边界位置:覆盖原点、世界边界和 int32 边界,四条路径相同的 24 个命中。
- 随机打乱 32,768 个混合位置的输入顺序:完整根和结果列表依然一致,位置压缩/还原不依赖同类位置连续排列。
原始记录在 `pipeline_results/*.jsonl`,汇总、源码哈希在 `pipeline_results/summary.json`;补充检查在 `pipeline_results/edge_validation.json`。
## 对全世界估算的影响
本轮证明此前“复用低位根”的前提可以落地,且筛类后只展开有根位置能控制部分开销。但不能把本轮 14.72× 再乘到此前约 50 天的估算上:此前约 50 天已经假定根充分复用,主要计算的是后续搜索。
本轮仅抽取 512 个随机类,根分布样本不足以重新估计全世界平均耗时;32 个有根类更是有意选择的压力集。维持此前约 50 天作为普通搜索阶段的乐观吞吐量级,不将其升级为完整全世界工期承诺。
下一步若继续研究算法,应优先减少剩余中间位组的筛选工作,或研究不同实际位置之间能否共享更高位的必要条件。当前低位根复用只消除了根生成重复,不能推导出高位结果也相同。
## 复现
```
python3 research/experiments/normal_search/run_pipeline.py
python3 research/experiments/normal_search/verify_pipeline_edges.py
```
两个脚本都会编译 GPU 基准程序。需要 NVIDIA GPU、nvcc 和 g++ 环境。实现入口为 `pipeline_bench.cu`,复用上一轮 `cuda_bench.cu` 中的内核。原正式入口未替换。

View file

@ -0,0 +1,87 @@
# 普通搜索:16 个中间位候选成组筛选
2026-10-11;RTX 3060 Laptop GPU;CUDA sm_86。仅研究普通首次输出分支,未修改或测试补扫。
结论:保留公共项预计算和 16 候选成组筛选。相对上一轮最优的“输出差过滤+区间求交”,两个独立的 65,536 随机坐标批次,搜索阶段分别加速 6.51×、6.56×。本轮代码在独立实验入口,未替换正式程序。
## 同任务实测
预热后轮换模式顺序,七轮中位数。模式 4~7 每轮重新执行 GPU 预计算,耗时已包括预计算 kernel。所有模式使用相同完整低位根列表,完整输出列表逐项比较。
| 输入 | 旧最优(模式 3) | 32 位预计算(4) | 成组筛选(7) | 3/7 |
|---|---:|---:|---:|---:|
| 已知命中位置 | 0.323584 ms | 0.268288 ms | 0.156672 ms | 2.07× |
| 21 压力/边界位置 | 1.288192 ms | 0.926720 ms | 0.223232 ms | 5.77× |
| 4096 随机位置 | 8.857600 ms | 5.859328 ms | 1.141760 ms | 7.76× |
| 65536 随机位置,原批次 | 130.136063 ms | 98.654205 ms | 19.982336 ms | 6.51× |
| 65536 随机位置,独立新批次 | 134.184967 ms | 102.582275 ms | 20.440063 ms | 6.56× |
另外测试了半差模 5(模式 5),以及半差模 5 配合角落优先检查(模式 6)。均未优于模式 7,不作为最终方案。原批次模式 5/6 分别为 114.548737/108.295166 ms。
这是搜索阶段的 CUDA event 时间,**不包括低位根生成、初始化、显存分配、排序及传输**。同次运行原批次根生成 kernel 为 267.922424 ms;若每个坐标仍单独生成根,则根生成加搜索的 kernel 时间之和从 398.058487 ms 降到 287.904760 ms,仅 1.38×。这个和是阶段计时相加,不是完整应用耗时。
此前已经验证坐标类之间可以复用低位根,但本实验没有实现全世界分组调度;不可把 6.5× 写成现有完整程序的加速倍数。
## 公共项预计算
使用归一化种子,令首格坐标项为 0。固定低 18 位 `root`,中间 17 位记为 `m`:
```
a_i = root + term_i
h_i = a_i >> 18
l_i = (a_i XOR C) & (2^18 - 1)
b_i = (A*l_i + 11) >> 17
c = C >> 18 = 0x1790d
q_i(m) = [b_i + 2*A*((m+h_i) XOR c)] mod 2^31
```
`A=0x5DEECE66D`,`C=0x5E434E432`。`h_i,b_i` 对同一个根的全部 131,072 个 m 共用,每根准备一次。最后公式按 uint32 运算取模即可,无需每个候选重复 64 位乘法。
## 为什么可以 16 个一起筛
`c=0x1790d` 的第 4~7 位为 0(最低位编号为 0)。将全部 m 唯一划分为:
```
base = (g >> 4)*256 + (g & 15), g=0..8191
m = base + 16*j, j=0..15
```
每组仅变化 m 的第 4~7 位:
- 首格 term 为 0,因此 `(m XOR c)` 随 j 线性增加,不会跨 256 边界。
- 对任意其他格,`m+h_i` 在这段长度 240 的范围内最多跨一次 256 边界。
- 同一段内,两格的输出都有相同线性增量。因此 `(q_i-q_0) mod 2^31` 是常数;整组最多两段。
- 只需计算首尾两处差值,并由进位位置求分界,即可准确判断 16 个候选哪些满足 `delta % 10 ∈ {0,8}`。
用 16 位 mask 表示一组的候选,逐格与允许 mask 求交,变成 0 就整组退出。最终剩余的具体 m 才进入原有高位区间求交及精确 Java 验证。
每根筛选线程从 131,072 个减少到 8,192 个。仍覆盖所有 m,每个线程所做的工作有所增加,因此实际收益不是理论 16×。这也没有消除中间位维度,只是利用局部等价批量处理。
## 正确性验证
- 5,000,000 次随机完整输出对照:预计算公式和原 48 位状态公式一致。
- 200,000 个随机组,约束数量循环覆盖 1~25:成组 mask 和逐个检查 16 个候选的差过滤完全一致。包括 159,120 个通过的候选,避免只对照空集。
- 已知位置全部 84 个低位根 × 8192 组,与原逐候选差过滤完全一致,共覆盖 11,010,048 个中间位候选,保留 36 个差过滤候选。
- 以上共验证 888,128 个完整组 mask。
- 五组 GPU 基准,全部模式预热与七轮测量均逐项比较完整结果列表;已知位置与压力批次保留原有 24 个命中;随机批次均无命中。
- 每批最多 64 个坐标的完整低位根列表与 CPU 对照;压力集包括世界边界、int32 边界及原点。
普通分支原有的拒绝重抽覆盖范围未改变。本实验不声称单独覆盖所有 Java 重试解。
## 全世界量级与下一步
若沿用之前的乐观假设:低位根充分复用、初始化充分摊薄,只用本次搜索阶段吞吐外推 `3,750,000²` 个锚点,则两批分别约 **49.6 天、50.8 天**,相比之前约 0.9 年有明显改善。这不是完整全世界运行时间,不含全世界分组、根缓存展开及传输,也不含补扫;不能据此承诺两个月完成。
接下来普通流程优先项:实际接上低位坐标类复用调度,计入分组、候选展开、传输的总成本。随后再研究是否能合并更多中间位组,而不是继续仅压缩高位求解的少量幸存者。
## 复现
```
python3 research/experiments/normal_search/run.py
```
需要可访问 NVIDIA GPU、nvcc、g++。脚本编译程序、运行 CPU 验证、生成独立随机坐标、顺序运行五组 GPU 基准,并写入 `results/`。不会调用补扫 kernel。
实现:`grouped.hpp`(预计算和组 mask)、`cuda_bench.cu`(基准与分组 kernel)、`cpu_verify.cpp`(独立对照)。原始七轮数据在 `results/*.jsonl`,汇总与源码哈希在 `results/summary.json`。
后续已完成计入分组、展开及传输的坐标类复用实验,见 [完整批次流程报告](PIPELINE_REPORT.md)。

View file

@ -0,0 +1,51 @@
#include "grouped.hpp"
#include <random>
#include <iostream>
#include <stdexcept>
namespace sr=slime_research;
namespace ns=normal_search;
int main(){
std::mt19937_64 rng(2026101103);
uint64_t qchecks=0,groups=0,partialSurvivors=0;
for(int test=0;test<200000;++test){
sr::CellTerm cells[25];
int32_t x=int32_t(rng()%3750000)-1875000,z=int32_t(rng()%3750000)-1875000;
const uint64_t anchor=sr::coordinateTerm(x,z);
for(int i=0;i<25;++i)cells[i]={(sr::coordinateTerm(x+i%5,z+i/5)-anchor)&sr::kMask48,sr::kSlime};
uint32_t root=rng()&((1U<<18)-1);
// Full-width random middle values also test carry and modulo behavior.
uint32_t m=rng()&((1U<<17)-1);
ns::Prepared p;ns::prepare(root,cells,p);
for(int i=0;i<25;++i){
uint32_t expected=sr::nextStateFromTerm(root+(uint64_t(m)<<18),cells[i].term)>>17;
if(ns::preparedQ(p,i,m)!=expected)throw std::runtime_error("q mismatch");
++qchecks;
}
// groupMask matches the difference filter even on odd roots; final
// solver parity checks remain responsible for discarding those roots.
int count=1+test%25;
uint32_t base=m&~240U,expected=0;
for(uint32_t j=0;j<16;++j)
if(full_search_experiment::differenceFilter(root+(uint64_t(base+16*j)<<18),cells,count))expected|=1U<<j;
partialSurvivors+=__builtin_popcount(expected);
if(ns::groupMask(p,base,count)!=expected)throw std::runtime_error("group mask mismatch");
++groups;
}
// Positive low18 roots and all middle values: check complete filter masks.
sr::CellTerm cells[25];const uint64_t anchor=sr::coordinateTerm(51069,419124);
for(int i=0;i<25;++i)cells[i]={(sr::coordinateTerm(51069+i%5,419124+i/5)-anchor)&sr::kMask48,sr::kSlime};
uint64_t accepted=0;
for(uint32_t root=0;root<(1U<<18);++root){
if(!sr::partialPatternPossible(root,18,cells,25))continue;
ns::Prepared p;ns::prepare(root,cells,p);
for(uint32_t g=0;g<8192;++g){
uint32_t base=((g>>4)<<8)+(g&15),expected=0;
for(uint32_t j=0;j<16;++j)if(full_search_experiment::differenceFilter(root+(uint64_t(base+16*j)<<18),cells,25))expected|=1U<<j;
const uint32_t actual=ns::groupMask(p,base);
if(actual!=expected)throw std::runtime_error("positive group mask mismatch");
accepted+=__builtin_popcount(actual);++groups;
}
}
if(!accepted)throw std::runtime_error("no positive candidates tested");
std::cout<<"{\"q_checks\":"<<qchecks<<",\"group_masks\":"<<groups<<",\"partial_filter_survivors\":"<<partialSurvivors<<",\"known_filter_survivors\":"<<accepted<<",\"passed\":true}\n";
}

View file

@ -0,0 +1,215 @@
#include "grouped.hpp"
#include <cuda_runtime.h>
#include <algorithm>
#include <array>
#include <chrono>
#include <cstdint>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <map>
#include <numeric>
#include <stdexcept>
#include <string>
#include <tuple>
#include <vector>
namespace sr = slime_research;
namespace fs = full_search_experiment;
using Clock = std::chrono::steady_clock;
#define CUDA(call) do { auto e = (call); if (e != cudaSuccess) throw std::runtime_error(std::string(#call)+": "+cudaGetErrorString(e)); } while (0)
struct Position { int32_t x, z; uint64_t anchor; sr::CellTerm cells[25]; };
struct Job { uint32_t position, root; };
struct Match { uint64_t position, seed; bool operator<(const Match& o)const{return std::tie(position,seed)<std::tie(o.position,o.seed);} bool operator==(const Match& o)const{return position==o.position&&seed==o.seed;} };
constexpr uint32_t MATCH_CAPACITY = 1U << 20;
constexpr uint32_t JOB_CAPACITY = 1U << 22;
Position makePosition(int32_t x,int32_t z) {
Position p{}; p.x=x;p.z=z;p.anchor=sr::coordinateTerm(x,z);
for(int j=0;j<5;++j)for(int i=0;i<5;++i)
p.cells[j*5+i]={(sr::coordinateTerm(x+i,z+j)-p.anchor)&sr::kMask48,sr::kSlime};
return p;
}
template<int Mode>
__global__ void rootKernel(const Position* positions,uint32_t count,const uint32_t* good,
uint32_t* counts,Job* jobs,unsigned long long* total,bool collect) {
uint64_t idx=uint64_t(blockIdx.x)*blockDim.x+threadIdx.x;
if(idx >= (uint64_t(count)<<18)) return;
const uint32_t pos=uint32_t(idx>>18), root=uint32_t(idx)&((1U<<18)-1);
const Position& p=positions[pos];
for(int i=0;i<25;++i){
const uint32_t in=root+uint32_t(p.cells[i].term);
if constexpr(Mode==0){
if((((in^uint32_t(sr::kCombinedXor))*uint32_t(sr::kJavaMultiplier)+11U)>>17)&1U)return;
}else{
const uint32_t k=in&((1U<<18)-1);
if(((good[k>>5]>>(k&31))&1U)==0)return;
}
}
atomicAdd(counts+pos,1U);
const auto at=atomicAdd(total,1ULL);
if(collect&&at<JOB_CAPACITY)jobs[at]={pos,root};
}
struct Emitter {
uint32_t position; uint64_t anchor; Match* out; unsigned long long* count;
__device__ void operator()(uint64_t s){
auto at=atomicAdd(count,1ULL);
if(at<MATCH_CAPACITY)out[at]={position,(s-anchor)&sr::kMask48};
}
};
using normal_search::Prepared;
using normal_search::preparedQ;
__global__ void prepareKernel(const Position* positions,const Job* jobs,uint32_t count,Prepared* out){
const uint32_t j=blockIdx.x*blockDim.x+threadIdx.x;
if(j<count)normal_search::prepare(jobs[j].root,positions[jobs[j].position].cells,out[j]);
}
template<int Mode>
__global__ void searchKernel(const Position* positions,const Job* jobs,uint32_t count,
Match* out,unsigned long long* total,const Prepared* prepared) {
uint64_t idx=uint64_t(blockIdx.x)*blockDim.x+threadIdx.x;
constexpr int bits=Mode==7?13:17;
if(idx >= (uint64_t(count)<<bits))return;
const Job job=jobs[idx>>bits];
const uint32_t m=idx&((1U<<bits)-1);
uint64_t low=job.root+(uint64_t(m)<<18);
const Position& p=positions[job.position];
Emitter emit{job.position,p.anchor,out,total};
if constexpr(Mode==7){
const uint32_t base=((m>>4)<<8)+(m&15);
uint32_t mask=normal_search::groupMask(prepared[idx>>13],base);
while(mask){
const uint32_t j=__ffs(mask)-1;mask &= mask-1;
const uint64_t candidate=job.root+(uint64_t(base+16*j)<<18);
fs::solveIntervals(candidate,p.cells,25,emit);
}
}
else if constexpr(Mode==3){if(fs::differenceFilter(low,p.cells,25))fs::solveIntervals(low,p.cells,25,emit);}
else {
const Prepared& t=prepared[idx>>17];
const uint32_t q0=preparedQ(t,0,m);
const uint32_t u0=(m+t.h[0])^uint32_t(sr::kCombinedXor>>18);
const int order[24]={24,4,20,12,2,10,14,22,6,8,16,18,1,3,5,9,15,19,21,23,7,11,13,17};
for(int k=1;k<25;++k){
const int i=Mode==6?order[k-1]:k;
if constexpr(Mode==4){
const uint32_t r=((preparedQ(t,i,m)-q0)&0x7fffffffU)%10;
if(r!=0&&r!=8)return;
}else{
const uint32_t ui=(m+t.h[i])^uint32_t(sr::kCombinedXor>>18);
const uint32_t d=((t.b[i]>>1)-(t.b[0]>>1)+uint32_t(sr::kJavaMultiplier)*(ui-u0))&((1U<<30)-1);
const uint32_t r=d%5;
if(r!=0&&r!=4)return;
}
}
fs::solveIntervals(low,p.cells,25,emit);
}
}
struct Device {
Prepared* prepared=nullptr; Position* positions=nullptr; Job* jobs=nullptr; Match* matches=nullptr;
uint32_t* counts=nullptr;uint32_t* good=nullptr;unsigned long long* total=nullptr;
cudaEvent_t start,stop;
Device(const std::vector<Position>& p){
CUDA(cudaMalloc(&positions,p.size()*sizeof(Position)));CUDA(cudaMemcpy(positions,p.data(),p.size()*sizeof(Position),cudaMemcpyHostToDevice));
CUDA(cudaMalloc(&jobs,JOB_CAPACITY*sizeof(Job)));CUDA(cudaMalloc(&matches,MATCH_CAPACITY*sizeof(Match)));
CUDA(cudaMalloc(&counts,p.size()*sizeof(uint32_t)));CUDA(cudaMalloc(&total,sizeof(*total)));
std::array<uint32_t,8192> bits{};
for(uint32_t k=0;k<(1U<<18);++k)if(!((((k^uint32_t(sr::kCombinedXor))*uint32_t(sr::kJavaMultiplier)+11U)>>17)&1U))bits[k>>5]|=1U<<(k&31);
CUDA(cudaMalloc(&good,sizeof(bits)));CUDA(cudaMemcpy(good,bits.data(),sizeof(bits),cudaMemcpyHostToDevice));
CUDA(cudaEventCreate(&start));CUDA(cudaEventCreate(&stop));
}
~Device(){cudaFree(prepared);cudaFree(positions);cudaFree(jobs);cudaFree(matches);cudaFree(counts);cudaFree(total);cudaFree(good);cudaEventDestroy(start);cudaEventDestroy(stop);}
float finish(){CUDA(cudaGetLastError());CUDA(cudaEventRecord(stop));CUDA(cudaEventSynchronize(stop));float ms;CUDA(cudaEventElapsedTime(&ms,start,stop));return ms;}
uint64_t totalCount(){unsigned long long n;CUDA(cudaMemcpy(&n,total,sizeof(n),cudaMemcpyDeviceToHost));return n;}
float roots(uint32_t n,int mode,bool collect){
CUDA(cudaMemset(total,0,sizeof(*total)));CUDA(cudaMemset(counts,0,n*sizeof(uint32_t)));CUDA(cudaEventRecord(start));
unsigned blocks=unsigned(((uint64_t(n)<<18)+255)/256);
if(mode==0)rootKernel<0><<<blocks,256>>>(positions,n,good,counts,jobs,total,collect);
else rootKernel<1><<<blocks,256>>>(positions,n,good,counts,jobs,total,collect);
return finish();
}
float search(uint32_t n,int mode){
if(!prepared&&n)CUDA(cudaMalloc(&prepared,n*sizeof(Prepared)));
CUDA(cudaMemset(total,0,sizeof(*total)));CUDA(cudaEventRecord(start));
unsigned blocks=unsigned(((uint64_t(n)<<17)+255)/256);
if(blocks){
if(mode>=4)prepareKernel<<<(n+127)/128,128>>>(positions,jobs,n,prepared);
if(mode==3)searchKernel<3><<<blocks,256>>>(positions,jobs,n,matches,total,prepared);
if(mode==4)searchKernel<4><<<blocks,256>>>(positions,jobs,n,matches,total,prepared);
if(mode==5)searchKernel<5><<<blocks,256>>>(positions,jobs,n,matches,total,prepared);
if(mode==6)searchKernel<6><<<blocks,256>>>(positions,jobs,n,matches,total,prepared);
if(mode==7)searchKernel<7><<<unsigned(((uint64_t(n)<<13)+255)/256),256>>>(positions,jobs,n,matches,total,prepared);
}
return finish();
}
std::vector<Match> results(){
uint64_t n=totalCount();if(n>MATCH_CAPACITY)throw std::runtime_error("match overflow");
std::vector<Match> r(n);CUDA(cudaMemcpy(r.data(),matches,n*sizeof(Match),cudaMemcpyDeviceToHost));std::sort(r.begin(),r.end());return r;
}
};
int main(int argc,char**argv){
try{
if(argc<3)throw std::runtime_error("usage: cuda_bench positions.txt normal [repeats=7]");
std::ifstream in(argv[1]);if(!in)throw std::runtime_error("cannot open positions");
int32_t x,z;std::vector<Position> positions;while(in>>x>>z)positions.push_back(makePosition(x,z));
if(positions.empty()||positions.size()>65536)throw std::runtime_error("position count must be 1..65536");
std::string task=argv[2];int repeats=argc>3?std::stoi(argv[3]):5;
if(task!="normal"||repeats<1)throw std::runtime_error("expected normal and positive repeat count");
auto processStart=Clock::now();Device d(positions);
std::cout<<std::setprecision(10);
cudaDeviceProp prop{};CUDA(cudaGetDeviceProperties(&prop,0));std::cout<<"{\"type\":\"device\",\"name\":\""<<prop.name<<"\",\"positions\":"<<positions.size()<<"}"<<std::endl;
std::vector<uint32_t> referenceCounts;
std::vector<Job> referenceJobs;
auto collectRoots=[&](int mode){
float ms=d.roots(positions.size(),mode,true);uint64_t total=d.totalCount();if(total>JOB_CAPACITY)throw std::runtime_error("job overflow");
std::vector<uint32_t> counts(positions.size());CUDA(cudaMemcpy(counts.data(),d.counts,counts.size()*sizeof(uint32_t),cudaMemcpyDeviceToHost));
std::vector<Job> jobs(total);CUDA(cudaMemcpy(jobs.data(),d.jobs,total*sizeof(Job),cudaMemcpyDeviceToHost));
std::sort(jobs.begin(),jobs.end(),[](Job a,Job b){return std::tie(a.position,a.root)<std::tie(b.position,b.root);});
if(referenceCounts.empty()){referenceCounts=counts;referenceJobs=jobs;}
else {
if(counts!=referenceCounts||jobs.size()!=referenceJobs.size())throw std::runtime_error("root mismatch");
for(size_t i=0;i<jobs.size();++i)if(jobs[i].position!=referenceJobs[i].position||jobs[i].root!=referenceJobs[i].root)throw std::runtime_error("root list mismatch");
}
return ms;
};
{
float rootMs=collectRoots(0);
CUDA(cudaMemcpy(d.jobs,referenceJobs.data(),referenceJobs.size()*sizeof(Job),cudaMemcpyHostToDevice));
std::vector<Match> expected;
const std::vector<int> modes=std::vector<int>{3,4,5,6,7};
bool first=true;
for(int m:modes){d.search(referenceJobs.size(),m);auto r=d.results();if(first){expected=r;first=false;}else if(r!=expected)throw std::runtime_error("warmup result mismatch");}
for(int r=0;r<repeats;++r)for(size_t k=0;k<modes.size();++k){
int mode=modes[(k+r)%modes.size()];auto wallStart=Clock::now();float ms=d.search(referenceJobs.size(),mode);auto result=d.results();
if(result!=expected)throw std::runtime_error("search result mismatch");
std::cout<<"{\"type\":\"search_timing\",\"mode\":"<<mode<<",\"round\":"<<r<<",\"kernel_ms\":"<<ms<<",\"scan_ms\":"<<std::chrono::duration<double,std::milli>(Clock::now()-wallStart).count()<<",\"matches\":"<<result.size()<<"}"<<std::endl;
}
std::cout<<"{\"type\":\"search_info\",\"root_ms\":"<<rootMs<<",\"jobs\":"<<referenceJobs.size()<<",\"lower35\":"<<(uint64_t(referenceJobs.size())<<17)<<",\"matches\":[";
for(size_t i=0;i<expected.size();++i){if(i)std::cout<<",";const auto& p=positions[expected[i].position];std::cout<<"["<<expected[i].seed<<","<<p.x<<","<<p.z<<"]";}std::cout<<"]}"<<std::endl;
}
// CPU checks of complete low18 root lists, including varied coordinates.
for(size_t n=0;n<std::min<size_t>(64,positions.size());++n){
size_t pos=n*positions.size()/std::min<size_t>(64,positions.size());std::vector<uint32_t> cpu,gpu;
for(uint32_t s=0;s<(1U<<18);++s)if(sr::partialPatternPossible(s,18,positions[pos].cells,25))cpu.push_back(s);
for(auto j:referenceJobs)if(j.position==pos)gpu.push_back(j.root);
if(cpu!=gpu)throw std::runtime_error("CPU/GPU roots mismatch");
}
std::map<uint64_t,std::vector<uint32_t>> classes;
size_t offset=0;
for(size_t pos=0;pos<positions.size();++pos){
uint64_t key=(uint64_t(uint32_t(positions[pos].x)&65535)<<17)|(uint32_t(positions[pos].z)&131071);
std::vector<uint32_t> roots;
while(offset<referenceJobs.size()&&referenceJobs[offset].position==pos)roots.push_back(referenceJobs[offset++].root);
auto it=classes.find(key);
if(it==classes.end())classes.emplace(key,std::move(roots));
else if(it->second!=roots)throw std::runtime_error("periodic class root list mismatch");
}
std::cout<<"{\"type\":\"periodic_validation\",\"classes\":"<<classes.size()<<",\"positions\":"<<positions.size()<<",\"equal\":true}"<<std::endl;
std::cout<<"{\"type\":\"root_counts\",\"counts\":[";for(size_t i=0;i<referenceCounts.size();++i){if(i)std::cout<<",";std::cout<<referenceCounts[i];}std::cout<<"]}"<<std::endl;
std::cout<<"{\"type\":\"process\",\"ms\":"<<std::chrono::duration<double,std::milli>(Clock::now()-processStart).count()<<"}"<<std::endl;
return 0;
}catch(const std::exception&e){std::cerr<<e.what()<<"\n";return 1;}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,42 @@
#pragma once
#include "../full_search_feasibility/interval_solver.hpp"
#if defined(__CUDACC__)
#define NS_HD __host__ __device__ __forceinline__
#else
#define NS_HD inline
#endif
namespace normal_search {
namespace sr=slime_research;
struct Prepared { uint32_t h[25], b[25]; };
NS_HD void prepare(uint32_t root,const sr::CellTerm* cells,Prepared& out){
for(int i=0;i<25;++i){
const uint64_t a=root+cells[i].term;
out.h[i]=uint32_t(a>>18);
const uint64_t lo=(a^sr::kCombinedXor)&((1U<<18)-1);
out.b[i]=uint32_t((lo*sr::kJavaMultiplier+11)>>17);
}
}
NS_HD uint32_t preparedQ(const Prepared& p,int i,uint32_t m){
const uint32_t u=(m+p.h[i])^uint32_t(sr::kCombinedXor>>18);
return (p.b[i]+2U*uint32_t(sr::kJavaMultiplier)*u)&0x7fffffffU;
}
// Bits 4..7 of kCombinedXor >> 18 are zero. For m=base+16*j,
// j in [0,16), m XOR C is affine. Each shifted input crosses at
// most one 256 boundary, so each output difference has at most two values.
// base bits 4..7 must be zero; cells[0].term must be zero (normalized anchor).
NS_HD uint32_t groupMask(const Prepared& p,uint32_t base,int count=25){
uint32_t mask=65535;
const uint32_t q0=preparedQ(p,0,base),qend=preparedQ(p,0,base+240);
for(int i=1;i<count&&mask;++i){
const uint32_t n=(256-((base+p.h[i])&255)+15)>>4;
const uint32_t before=(1U<<n)-1;
const uint32_t r0=((preparedQ(p,i,base)-q0)&0x7fffffffU)%10;
const uint32_t r1=((preparedQ(p,i,base+240)-qend)&0x7fffffffU)%10;
const uint32_t allowed=((r0==0||r0==8)?before:0U)|((r1==0||r1==8)?(65535U^before):0U);
mask &= allowed;
}
return mask;
}
}
#undef NS_HD

View file

@ -0,0 +1,114 @@
#define main component_benchmark_main
#include "cuda_bench.cu"
#undef main
__global__ void expandJobs(const uint32_t* positionClass,const uint32_t* offsets,
const uint32_t* classOffsets,const uint32_t* roots,
uint32_t n,Job* jobs){
uint32_t p=blockIdx.x*blockDim.x+threadIdx.x;
if(p>=n)return;
const uint32_t c=positionClass[p];
for(uint32_t i=classOffsets[c];i<classOffsets[c+1];++i)
jobs[offsets[p]+i-classOffsets[c]]={p,roots[i]};
}
struct Extra {
Position* reps;uint32_t *positionClass,*offsets,*classOffsets,*roots;
Extra(size_t n){
CUDA(cudaMalloc(&reps,n*sizeof(Position)));
CUDA(cudaMalloc(&positionClass,n*sizeof(uint32_t)));
CUDA(cudaMalloc(&offsets,(n+1)*sizeof(uint32_t)));
CUDA(cudaMalloc(&classOffsets,(n+1)*sizeof(uint32_t)));
CUDA(cudaMalloc(&roots,JOB_CAPACITY*sizeof(uint32_t)));
}
~Extra(){cudaFree(reps);cudaFree(positionClass);cudaFree(offsets);cudaFree(classOffsets);cudaFree(roots);}
};
struct Run {double hostMs,buildMs,rootMs,expandMs,searchMs;uint32_t classes,jobs,activePositions;std::vector<Match> matches;std::vector<Job> rootList;};
Run run(const std::vector<std::pair<int32_t,int32_t>>& coords,Device& d,Extra& extra,int mode){
const auto start=Clock::now();
auto ms=[](auto t){return std::chrono::duration<double,std::milli>(Clock::now()-t).count();};
std::vector<Position> positions;positions.reserve(coords.size());
if(mode!=3)for(auto [x,z]:coords)positions.push_back(makePosition(x,z));
std::vector<Position> reps;std::vector<uint32_t> pc;
if(mode>=2){
std::map<uint64_t,uint32_t> map;
for(auto [x,z]:coords){
uint64_t key=(uint64_t(uint32_t(x)&65535)<<17)|(uint32_t(z)&131071);
auto [it,inserted]=map.emplace(key,uint32_t(reps.size()));
if(inserted)reps.push_back(makePosition(x,z));
pc.push_back(it->second);
}
}
if(!positions.empty())CUDA(cudaMemcpy(d.positions,positions.data(),positions.size()*sizeof(Position),cudaMemcpyHostToDevice));
Run r{};r.classes=mode>=2?reps.size():positions.size();r.buildMs=ms(start);
const auto rootStart=Clock::now();
if(mode>=2){
CUDA(cudaMemcpy(extra.reps,reps.data(),reps.size()*sizeof(Position),cudaMemcpyHostToDevice));
CUDA(cudaMemset(d.total,0,sizeof(*d.total)));CUDA(cudaMemset(d.counts,0,reps.size()*sizeof(uint32_t)));
rootKernel<0><<<unsigned(((uint64_t(reps.size())<<18)+255)/256),256>>>(extra.reps,reps.size(),nullptr,d.counts,d.jobs,d.total,true);
}else d.roots(positions.size(),0,true);
uint64_t n=d.totalCount();if(n>JOB_CAPACITY)throw std::runtime_error("root capacity exceeded");
r.rootMs=ms(rootStart);
const auto expandStart=Clock::now();
std::vector<uint32_t> originalIndices;
if(mode>=2){
std::vector<Job> cj(n);if(n)CUDA(cudaMemcpy(cj.data(),d.jobs,n*sizeof(Job),cudaMemcpyDeviceToHost));
std::vector<std::vector<uint32_t>> lists(reps.size());
for(auto j:cj)lists[j.position].push_back(j.root);
if(mode==3){
std::vector<uint32_t> compactClasses;
for(uint32_t i=0;i<coords.size();++i)if(!lists[pc[i]].empty()){
auto [x,z]=coords[i];positions.push_back(makePosition(x,z));
compactClasses.push_back(pc[i]);originalIndices.push_back(i);
}
pc=std::move(compactClasses);
if(!positions.empty())CUDA(cudaMemcpy(d.positions,positions.data(),positions.size()*sizeof(Position),cudaMemcpyHostToDevice));
}
std::vector<uint32_t> roots,co{0},offsets{0};
for(auto& list:lists){std::sort(list.begin(),list.end());roots.insert(roots.end(),list.begin(),list.end());co.push_back(roots.size());}
uint64_t expanded=0;
for(auto c:pc){expanded+=lists[c].size();if(expanded>JOB_CAPACITY)throw std::runtime_error("expanded capacity exceeded; use smaller batch");offsets.push_back(expanded);}
n=expanded;
CUDA(cudaMemcpy(extra.positionClass,pc.data(),pc.size()*sizeof(uint32_t),cudaMemcpyHostToDevice));
CUDA(cudaMemcpy(extra.offsets,offsets.data(),offsets.size()*sizeof(uint32_t),cudaMemcpyHostToDevice));
CUDA(cudaMemcpy(extra.classOffsets,co.data(),co.size()*sizeof(uint32_t),cudaMemcpyHostToDevice));
if(!roots.empty())CUDA(cudaMemcpy(extra.roots,roots.data(),roots.size()*sizeof(uint32_t),cudaMemcpyHostToDevice));
if(!positions.empty())expandJobs<<<unsigned((positions.size()+255)/256),256>>>(extra.positionClass,extra.offsets,extra.classOffsets,extra.roots,positions.size(),d.jobs);
CUDA(cudaGetLastError());CUDA(cudaDeviceSynchronize());
}
r.expandMs=ms(expandStart);r.jobs=n;r.activePositions=positions.size();
const auto searchStart=Clock::now();
d.search(n,mode==0?3:7);r.matches=d.results();
if(mode==3)for(auto& match:r.matches)match.position=originalIndices[match.position];
r.searchMs=ms(searchStart);r.hostMs=ms(start);
// Validation-only transfers/sorting are outside reported pipeline time.
r.rootList.resize(n);if(n)CUDA(cudaMemcpy(r.rootList.data(),d.jobs,n*sizeof(Job),cudaMemcpyDeviceToHost));
if(mode==3)for(auto& job:r.rootList)job.position=originalIndices[job.position];
std::sort(r.rootList.begin(),r.rootList.end(),[](Job a,Job b){return std::tie(a.position,a.root)<std::tie(b.position,b.root);});
return r;
}
int main(int argc,char**argv){try{
if(argc<2)throw std::runtime_error("usage: pipeline_bench positions.txt [repeats=5]");
const auto process=Clock::now();
std::ifstream in(argv[1]);if(!in)throw std::runtime_error("cannot open input");
std::vector<std::pair<int32_t,int32_t>> coords;int32_t x,z;while(in>>x>>z)coords.emplace_back(x,z);
if(coords.empty()||coords.size()>65536)throw std::runtime_error("expected 1..65536 coordinates");
int repeats=argc>2?std::stoi(argv[2]):5;if(repeats<1)throw std::runtime_error("invalid repeats");
Device d(std::vector<Position>(coords.size()));Extra e(coords.size());
std::cout<<std::setprecision(10);
std::cout<<"{\"type\":\"setup\",\"host_ms\":"<<std::chrono::duration<double,std::milli>(Clock::now()-process).count()<<"}"<<std::endl;
Run ref;
for(int round=-1;round<repeats;++round)for(int k=0;k<4;++k){
int mode=round<0?k:(round+k)%4;
Run r=run(coords,d,e,mode);
if(round==-1&&mode==0)ref=r;
else {
if(r.matches!=ref.matches||r.rootList.size()!=ref.rootList.size())throw std::runtime_error("pipeline mismatch");
for(size_t i=0;i<r.rootList.size();++i)if(r.rootList[i].position!=ref.rootList[i].position||r.rootList[i].root!=ref.rootList[i].root)throw std::runtime_error("complete root list mismatch");
}
if(round>=0)std::cout<<"{\"type\":\"pipeline\",\"mode\":"<<mode<<",\"round\":"<<round<<",\"positions\":"<<coords.size()<<",\"classes\":"<<r.classes<<",\"active_positions\":"<<r.activePositions<<",\"jobs\":"<<r.jobs<<",\"matches\":"<<r.matches.size()<<",\"host_ms\":"<<r.hostMs<<",\"build_ms\":"<<r.buildMs<<",\"root_ms\":"<<r.rootMs<<",\"expand_ms\":"<<r.expandMs<<",\"search_ms\":"<<r.searchMs<<"}"<<std::endl;
}
std::cout<<"{\"type\":\"validation\",\"complete_roots_equal\":true,\"complete_matches_equal\":true,\"matches\":[";
for(size_t i=0;i<ref.matches.size();++i){if(i)std::cout<<",";auto m=ref.matches[i];std::cout<<"["<<m.seed<<","<<coords[m.position].first<<","<<coords[m.position].second<<"]";}
std::cout<<"]}"<<std::endl;
return 0;
}catch(const std::exception& e){std::cerr<<e.what()<<"\n";return 1;}}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,339 @@
{
"zero_lifts": {
"validation": {
"type": "validation",
"complete_roots_equal": true,
"complete_matches_equal": true,
"matches": []
},
"modes": [
{
"type": "pipeline",
"mode": 0,
"round": 0,
"positions": 1653,
"classes": 1653,
"active_positions": 1653,
"jobs": 0,
"matches": 0,
"host_ms": 5.571692,
"build_ms": 0.090188,
"root_ms": 5.379603,
"expand_ms": 0,
"search_ms": 0.101716
},
{
"type": "pipeline",
"mode": 1,
"round": 0,
"positions": 1653,
"classes": 1653,
"active_positions": 1653,
"jobs": 0,
"matches": 0,
"host_ms": 5.729661,
"build_ms": 0.1019,
"root_ms": 5.497826,
"expand_ms": 0,
"search_ms": 0.12975
},
{
"type": "pipeline",
"mode": 2,
"round": 0,
"positions": 1653,
"classes": 1,
"active_positions": 1653,
"jobs": 0,
"matches": 0,
"host_ms": 0.56059,
"build_ms": 0.10771,
"root_ms": 0.251016,
"expand_ms": 0.131594,
"search_ms": 0.070177
},
{
"type": "pipeline",
"mode": 3,
"round": 0,
"positions": 1653,
"classes": 1,
"active_positions": 0,
"jobs": 0,
"matches": 0,
"host_ms": 0.230821,
"build_ms": 0.006363,
"root_ms": 0.083272,
"expand_ms": 0.071838,
"search_ms": 0.069348
}
]
},
"stress": {
"validation": {
"type": "validation",
"complete_roots_equal": true,
"complete_matches_equal": true,
"matches": [
[
10358701894766,
51069,
419124
],
[
15959335054446,
51069,
419124
],
[
18914276748398,
51069,
419124
],
[
24514909908078,
51069,
419124
],
[
27469851602030,
51069,
419124
],
[
33070484761710,
51069,
419124
],
[
36025426455662,
51069,
419124
],
[
41626059615342,
51069,
419124
],
[
44581001309294,
51069,
419124
],
[
50181634468974,
51069,
419124
],
[
53136576162926,
51069,
419124
],
[
58737209322606,
51069,
419124
],
[
61692151016558,
51069,
419124
],
[
67292784176238,
51069,
419124
],
[
70247725870190,
51069,
419124
],
[
75848359029870,
51069,
419124
],
[
78803300723822,
51069,
419124
],
[
84403933883502,
51069,
419124
],
[
87358875577454,
51069,
419124
],
[
92959508737134,
51069,
419124
],
[
95914450431086,
51069,
419124
],
[
101515083590766,
51069,
419124
],
[
104470025284718,
51069,
419124
],
[
110070658444398,
51069,
419124
]
]
},
"modes": [
{
"type": "pipeline",
"mode": 0,
"round": 0,
"positions": 21,
"classes": 21,
"active_positions": 21,
"jobs": 474,
"matches": 24,
"host_ms": 1.476311,
"build_ms": 0.003135,
"root_ms": 0.17549,
"expand_ms": 0,
"search_ms": 1.297501
},
{
"type": "pipeline",
"mode": 1,
"round": 0,
"positions": 21,
"classes": 21,
"active_positions": 21,
"jobs": 474,
"matches": 24,
"host_ms": 0.505168,
"build_ms": 0.004611,
"root_ms": 0.175213,
"expand_ms": 9.3e-05,
"search_ms": 0.325159
},
{
"type": "pipeline",
"mode": 2,
"round": 0,
"positions": 21,
"classes": 20,
"active_positions": 21,
"jobs": 474,
"matches": 24,
"host_ms": 0.834753,
"build_ms": 0.011158,
"root_ms": 0.242071,
"expand_ms": 0.210348,
"search_ms": 0.370991
},
{
"type": "pipeline",
"mode": 3,
"round": 0,
"positions": 21,
"classes": 20,
"active_positions": 13,
"jobs": 474,
"matches": 24,
"host_ms": 0.782097,
"build_ms": 0.004335,
"root_ms": 0.1967,
"expand_ms": 0.261529,
"search_ms": 0.319533
}
]
},
"shuffled_mixed": {
"validation": {
"type": "validation",
"complete_roots_equal": true,
"complete_matches_equal": true,
"matches": []
},
"modes": [
{
"type": "pipeline",
"mode": 0,
"round": 0,
"positions": 32768,
"classes": 32768,
"active_positions": 32768,
"jobs": 15424,
"matches": 0,
"host_ms": 152.132767,
"build_ms": 4.096027,
"root_ms": 113.387564,
"expand_ms": 0.000184,
"search_ms": 34.648623
},
{
"type": "pipeline",
"mode": 1,
"round": 0,
"positions": 32768,
"classes": 32768,
"active_positions": 32768,
"jobs": 15424,
"matches": 0,
"host_ms": 124.087013,
"build_ms": 4.152926,
"root_ms": 113.998689,
"expand_ms": 0.000184,
"search_ms": 5.934844
},
{
"type": "pipeline",
"mode": 2,
"round": 0,
"positions": 32768,
"classes": 512,
"active_positions": 32768,
"jobs": 15424,
"matches": 0,
"host_ms": 13.605316,
"build_ms": 5.613835,
"root_ms": 1.992268,
"expand_ms": 0.604117,
"search_ms": 5.394911
},
{
"type": "pipeline",
"mode": 3,
"round": 0,
"positions": 32768,
"classes": 512,
"active_positions": 1216,
"jobs": 15424,
"matches": 0,
"host_ms": 9.609161,
"build_ms": 1.342779,
"root_ms": 2.238581,
"expand_ms": 0.603472,
"search_ms": 5.424052
}
]
},
"source_sha256": {
"pipeline_bench.cu": "31da815aa0ee8904c702e55d2d685282fc64bfada24dd208e151faac5c55c37c",
"cuda_bench.cu": "3e1fd6fe3bdb87ac68fe853dc4e6d2275d6aa00a692c7d630391fd12c0105c20",
"grouped.hpp": "5d48c4a45e7f7b07a362c69b5163f48d44bd45d18e7f0f02b00bda0edaadeb23",
"verify_pipeline_edges.py": "97a2b4642e871149519a79c73b7b617dd7a0cc47cd0f0dfe59cc7c8afdf0507c"
}
}

View file

@ -0,0 +1,301 @@
{
"metadata": {
"date": "2026-10-11T10:49:17.203764+08:00",
"gpu": "name, driver_version\nNVIDIA GeForce RTX 3060 Laptop GPU, 596.49\n"
},
"known_lifts": {
"0": {
"host_ms": 359.494613,
"build_ms": 0.100726,
"root_ms": 8.470989,
"expand_ms": 9.6e-05,
"search_ms": 350.821402,
"jobs": 138852,
"classes": 1653,
"positions": 1653,
"matches": 24
},
"1": {
"host_ms": 61.726379,
"build_ms": 0.127304,
"root_ms": 8.947655,
"expand_ms": 0,
"search_ms": 52.659413,
"jobs": 138852,
"classes": 1653,
"positions": 1653,
"matches": 24
},
"2": {
"host_ms": 53.625264,
"build_ms": 0.166015,
"root_ms": 0.356104,
"expand_ms": 0.319126,
"search_ms": 52.783635,
"jobs": 138852,
"classes": 1,
"positions": 1653,
"matches": 24
},
"validation": {
"type": "validation",
"complete_roots_equal": true,
"complete_matches_equal": true,
"matches": [
[
10358701894766,
51069,
419124
],
[
15959335054446,
51069,
419124
],
[
18914276748398,
51069,
419124
],
[
24514909908078,
51069,
419124
],
[
27469851602030,
51069,
419124
],
[
33070484761710,
51069,
419124
],
[
36025426455662,
51069,
419124
],
[
41626059615342,
51069,
419124
],
[
44581001309294,
51069,
419124
],
[
50181634468974,
51069,
419124
],
[
53136576162926,
51069,
419124
],
[
58737209322606,
51069,
419124
],
[
61692151016558,
51069,
419124
],
[
67292784176238,
51069,
419124
],
[
70247725870190,
51069,
419124
],
[
75848359029870,
51069,
419124
],
[
78803300723822,
51069,
419124
],
[
84403933883502,
51069,
419124
],
[
87358875577454,
51069,
419124
],
[
92959508737134,
51069,
419124
],
[
95914450431086,
51069,
419124
],
[
101515083590766,
51069,
419124
],
[
104470025284718,
51069,
419124
],
[
110070658444398,
51069,
419124
]
]
},
"setup_ms": 269.594069
},
"nonempty32": {
"0": {
"host_ms": 4621.165908,
"build_ms": 7.240293,
"root_ms": 257.582953,
"expand_ms": 0,
"search_ms": 4356.341998,
"jobs": 1693228,
"classes": 52213,
"positions": 52213,
"matches": 0
},
"1": {
"host_ms": 926.774796,
"build_ms": 7.307786,
"root_ms": 251.583683,
"expand_ms": 0,
"search_ms": 668.081633,
"jobs": 1693228,
"classes": 52213,
"positions": 52213,
"matches": 0
},
"2": {
"host_ms": 664.598058,
"build_ms": 8.052305,
"root_ms": 0.602059,
"expand_ms": 1.15488,
"search_ms": 654.776953,
"jobs": 1693228,
"classes": 32,
"positions": 52213,
"matches": 0
},
"validation": {
"type": "validation",
"complete_roots_equal": true,
"complete_matches_equal": true,
"matches": []
},
"setup_ms": 281.326323
},
"mixed512": {
"0": {
"host_ms": 170.81455,
"build_ms": 4.3475,
"root_ms": 125.510086,
"expand_ms": 0,
"search_ms": 41.628402,
"jobs": 15424,
"classes": 32768,
"positions": 32768,
"matches": 0
},
"1": {
"host_ms": 138.433459,
"build_ms": 4.575848,
"root_ms": 128.008956,
"expand_ms": 0,
"search_ms": 5.843008,
"jobs": 15424,
"classes": 32768,
"positions": 32768,
"matches": 0
},
"2": {
"host_ms": 14.418511,
"build_ms": 5.463323,
"root_ms": 2.456199,
"expand_ms": 0.614328,
"search_ms": 5.820053,
"jobs": 15424,
"classes": 512,
"positions": 32768,
"matches": 0
},
"validation": {
"type": "validation",
"complete_roots_equal": true,
"complete_matches_equal": true,
"matches": []
},
"setup_ms": 259.425362
},
"random4096": {
"0": {
"host_ms": 22.41199,
"build_ms": 0.318132,
"root_ms": 15.081804,
"expand_ms": 0,
"search_ms": 6.895335,
"jobs": 2960,
"classes": 4096,
"positions": 4096,
"matches": 0
},
"1": {
"host_ms": 16.864992,
"build_ms": 0.311931,
"root_ms": 15.251468,
"expand_ms": 0,
"search_ms": 1.256979,
"jobs": 2960,
"classes": 4096,
"positions": 4096,
"matches": 0
},
"2": {
"host_ms": 19.192994,
"build_ms": 1.265494,
"root_ms": 15.992881,
"expand_ms": 0.767331,
"search_ms": 1.202645,
"jobs": 2960,
"classes": 4096,
"positions": 4096,
"matches": 0
},
"validation": {
"type": "validation",
"complete_roots_equal": true,
"complete_matches_equal": true,
"matches": []
},
"setup_ms": 248.445216
},
"source_sha256": {
"pipeline_bench.cu": "249b6119832788d37643591407bc7eeebc086af452fe22cf0c756004a28596b0",
"cuda_bench.cu": "f762ea050d7c93c00903928f972e41106e917d37a4caceb79630bacd0f9316e1",
"grouped.hpp": "5d48c4a45e7f7b07a362c69b5163f48d44bd45d18e7f0f02b00bda0edaadeb23",
"run_pipeline.py": "a1aaea904d5a3a0d341ed1956e15f20af93c42c76205a2b8df108878f445ac59"
}
}

View file

@ -0,0 +1,14 @@
{"type":"setup","host_ms":220.229718}
{"type":"pipeline","mode":0,"round":0,"positions":1653,"classes":1653,"active_positions":1653,"jobs":138852,"matches":24,"host_ms":351.890247,"build_ms":0.123965,"root_ms":8.648427,"expand_ms":0.000189,"search_ms":343.117004}
{"type":"pipeline","mode":1,"round":0,"positions":1653,"classes":1653,"active_positions":1653,"jobs":138852,"matches":24,"host_ms":60.282088,"build_ms":0.106201,"root_ms":8.500842,"expand_ms":0.000189,"search_ms":51.674478}
{"type":"pipeline","mode":2,"round":0,"positions":1653,"classes":1,"active_positions":1653,"jobs":138852,"matches":24,"host_ms":54.114753,"build_ms":0.118106,"root_ms":0.32588,"expand_ms":0.297156,"search_ms":53.373222}
{"type":"pipeline","mode":3,"round":0,"positions":1653,"classes":1,"active_positions":1653,"jobs":138852,"matches":24,"host_ms":56.8665,"build_ms":0.0101,"root_ms":0.2025,"expand_ms":0.6349,"search_ms":56.0187}
{"type":"pipeline","mode":1,"round":1,"positions":1653,"classes":1653,"active_positions":1653,"jobs":138852,"matches":24,"host_ms":63.2884,"build_ms":0.113,"root_ms":9.1249,"expand_ms":0.0003,"search_ms":54.0495}
{"type":"pipeline","mode":2,"round":1,"positions":1653,"classes":1,"active_positions":1653,"jobs":138852,"matches":24,"host_ms":55.3725,"build_ms":0.1507,"root_ms":0.4095,"expand_ms":0.2649,"search_ms":54.5471}
{"type":"pipeline","mode":3,"round":1,"positions":1653,"classes":1,"active_positions":1653,"jobs":138852,"matches":24,"host_ms":55.7387,"build_ms":0.0109,"root_ms":0.2574,"expand_ms":0.7803,"search_ms":54.6898}
{"type":"pipeline","mode":0,"round":1,"positions":1653,"classes":1653,"active_positions":1653,"jobs":138852,"matches":24,"host_ms":374.3942,"build_ms":0.114,"root_ms":8.904,"expand_ms":0.0001,"search_ms":365.3759}
{"type":"pipeline","mode":2,"round":2,"positions":1653,"classes":1,"active_positions":1653,"jobs":138852,"matches":24,"host_ms":56.1846,"build_ms":0.133,"root_ms":0.3246,"expand_ms":0.2974,"search_ms":55.4289}
{"type":"pipeline","mode":3,"round":2,"positions":1653,"classes":1,"active_positions":1653,"jobs":138852,"matches":24,"host_ms":57.1526,"build_ms":0.0088,"root_ms":0.1615,"expand_ms":0.6781,"search_ms":56.3039}
{"type":"pipeline","mode":0,"round":2,"positions":1653,"classes":1653,"active_positions":1653,"jobs":138852,"matches":24,"host_ms":364.022951,"build_ms":0.1147,"root_ms":8.7547,"expand_ms":0.0001,"search_ms":355.153251}
{"type":"pipeline","mode":1,"round":2,"positions":1653,"classes":1653,"active_positions":1653,"jobs":138852,"matches":24,"host_ms":62.015757,"build_ms":0.113887,"root_ms":8.742087,"expand_ms":0.000191,"search_ms":53.159211}
{"type":"validation","complete_roots_equal":true,"complete_matches_equal":true,"matches":[[10358701894766,51069,419124],[15959335054446,51069,419124],[18914276748398,51069,419124],[24514909908078,51069,419124],[27469851602030,51069,419124],[33070484761710,51069,419124],[36025426455662,51069,419124],[41626059615342,51069,419124],[44581001309294,51069,419124],[50181634468974,51069,419124],[53136576162926,51069,419124],[58737209322606,51069,419124],[61692151016558,51069,419124],[67292784176238,51069,419124],[70247725870190,51069,419124],[75848359029870,51069,419124],[78803300723822,51069,419124],[84403933883502,51069,419124],[87358875577454,51069,419124],[92959508737134,51069,419124],[95914450431086,51069,419124],[101515083590766,51069,419124],[104470025284718,51069,419124],[110070658444398,51069,419124]]}

View file

@ -0,0 +1,14 @@
{"type":"setup","host_ms":242.015308}
{"type":"pipeline","mode":0,"round":0,"positions":32768,"classes":32768,"active_positions":32768,"jobs":15424,"matches":0,"host_ms":172.222139,"build_ms":5.020376,"root_ms":125.961985,"expand_ms":0.000192,"search_ms":41.239203}
{"type":"pipeline","mode":1,"round":0,"positions":32768,"classes":32768,"active_positions":32768,"jobs":15424,"matches":0,"host_ms":141.138417,"build_ms":4.616912,"root_ms":130.393185,"expand_ms":0.000287,"search_ms":6.127841}
{"type":"pipeline","mode":2,"round":0,"positions":32768,"classes":512,"active_positions":32768,"jobs":15424,"matches":0,"host_ms":14.093525,"build_ms":5.009729,"root_ms":2.227974,"expand_ms":0.638962,"search_ms":6.216476}
{"type":"pipeline","mode":3,"round":0,"positions":32768,"classes":512,"active_positions":1216,"jobs":15424,"matches":0,"host_ms":9.527453,"build_ms":0.399052,"root_ms":2.04888,"expand_ms":0.821317,"search_ms":6.257916}
{"type":"pipeline","mode":1,"round":1,"positions":32768,"classes":32768,"active_positions":32768,"jobs":15424,"matches":0,"host_ms":137.613046,"build_ms":4.711591,"root_ms":126.754716,"expand_ms":9.6e-05,"search_ms":6.145971}
{"type":"pipeline","mode":2,"round":1,"positions":32768,"classes":512,"active_positions":32768,"jobs":15424,"matches":0,"host_ms":14.235207,"build_ms":5.358898,"root_ms":2.203034,"expand_ms":0.604141,"search_ms":6.068846}
{"type":"pipeline","mode":3,"round":1,"positions":32768,"classes":512,"active_positions":1216,"jobs":15424,"matches":0,"host_ms":9.585776,"build_ms":0.416318,"root_ms":1.860291,"expand_ms":0.534307,"search_ms":6.774668}
{"type":"pipeline","mode":0,"round":1,"positions":32768,"classes":32768,"active_positions":32768,"jobs":15424,"matches":0,"host_ms":171.867118,"build_ms":4.452687,"root_ms":126.737258,"expand_ms":0.000288,"search_ms":40.676693}
{"type":"pipeline","mode":2,"round":2,"positions":32768,"classes":512,"active_positions":32768,"jobs":15424,"matches":0,"host_ms":15.318882,"build_ms":5.280144,"root_ms":2.701464,"expand_ms":0.670138,"search_ms":6.666944}
{"type":"pipeline","mode":3,"round":2,"positions":32768,"classes":512,"active_positions":1216,"jobs":15424,"matches":0,"host_ms":10.647196,"build_ms":0.441931,"root_ms":2.114877,"expand_ms":0.690187,"search_ms":7.400009}
{"type":"pipeline","mode":0,"round":2,"positions":32768,"classes":32768,"active_positions":32768,"jobs":15424,"matches":0,"host_ms":174.051349,"build_ms":4.55245,"root_ms":127.973647,"expand_ms":0.000192,"search_ms":41.524773}
{"type":"pipeline","mode":1,"round":2,"positions":32768,"classes":32768,"active_positions":32768,"jobs":15424,"matches":0,"host_ms":144.526135,"build_ms":4.499307,"root_ms":133.867236,"expand_ms":0.000192,"search_ms":6.159304}
{"type":"validation","complete_roots_equal":true,"complete_matches_equal":true,"matches":[]}

View file

@ -0,0 +1,14 @@
{"type":"setup","host_ms":219.927973}
{"type":"pipeline","mode":0,"round":0,"positions":52213,"classes":52213,"active_positions":52213,"jobs":1693228,"matches":0,"host_ms":4362.48845,"build_ms":7.490479,"root_ms":252.85323,"expand_ms":0.000286,"search_ms":4102.144074}
{"type":"pipeline","mode":1,"round":0,"positions":52213,"classes":52213,"active_positions":52213,"jobs":1693228,"matches":0,"host_ms":909.690741,"build_ms":7.012591,"root_ms":242.747725,"expand_ms":0.000183,"search_ms":659.929967}
{"type":"pipeline","mode":2,"round":0,"positions":52213,"classes":32,"active_positions":52213,"jobs":1693228,"matches":0,"host_ms":636.817316,"build_ms":7.196841,"root_ms":0.554217,"expand_ms":1.022633,"search_ms":628.04335}
{"type":"pipeline","mode":3,"round":0,"positions":52213,"classes":32,"active_positions":52213,"jobs":1693228,"matches":0,"host_ms":633.461125,"build_ms":0.338158,"root_ms":0.504258,"expand_ms":8.844275,"search_ms":623.77425}
{"type":"pipeline","mode":1,"round":1,"positions":52213,"classes":52213,"active_positions":52213,"jobs":1693228,"matches":0,"host_ms":915.445942,"build_ms":7.53445,"root_ms":245.545208,"expand_ms":9.2e-05,"search_ms":662.365642}
{"type":"pipeline","mode":2,"round":1,"positions":52213,"classes":32,"active_positions":52213,"jobs":1693228,"matches":0,"host_ms":656.710025,"build_ms":9.4644,"root_ms":0.576767,"expand_ms":1.500033,"search_ms":645.168458}
{"type":"pipeline","mode":3,"round":1,"positions":52213,"classes":32,"active_positions":52213,"jobs":1693228,"matches":0,"host_ms":676.742292,"build_ms":0.3428,"root_ms":0.671,"expand_ms":9.1207,"search_ms":666.607392}
{"type":"pipeline","mode":0,"round":1,"positions":52213,"classes":52213,"active_positions":52213,"jobs":1693228,"matches":0,"host_ms":4691.310731,"build_ms":7.216464,"root_ms":255.097691,"expand_ms":0.000286,"search_ms":4428.995719}
{"type":"pipeline","mode":2,"round":2,"positions":52213,"classes":32,"active_positions":52213,"jobs":1693228,"matches":0,"host_ms":685.115982,"build_ms":7.652735,"root_ms":0.58709,"expand_ms":1.326998,"search_ms":675.548969}
{"type":"pipeline","mode":3,"round":2,"positions":52213,"classes":32,"active_positions":52213,"jobs":1693228,"matches":0,"host_ms":681.412155,"build_ms":0.344485,"root_ms":0.473976,"expand_ms":8.571836,"search_ms":672.021573}
{"type":"pipeline","mode":0,"round":2,"positions":52213,"classes":52213,"active_positions":52213,"jobs":1693228,"matches":0,"host_ms":4816.532778,"build_ms":9.669654,"root_ms":263.964214,"expand_ms":0.000191,"search_ms":4542.898147}
{"type":"pipeline","mode":1,"round":2,"positions":52213,"classes":52213,"active_positions":52213,"jobs":1693228,"matches":0,"host_ms":980.983116,"build_ms":7.505432,"root_ms":259.835073,"expand_ms":0.000191,"search_ms":713.641749}
{"type":"validation","complete_roots_equal":true,"complete_matches_equal":true,"matches":[]}

View file

@ -0,0 +1,14 @@
{"type":"setup","host_ms":216.555239}
{"type":"pipeline","mode":0,"round":0,"positions":4096,"classes":4096,"active_positions":4096,"jobs":2960,"matches":0,"host_ms":22.564546,"build_ms":0.29315,"root_ms":15.171827,"expand_ms":0.000192,"search_ms":7.099377}
{"type":"pipeline","mode":1,"round":0,"positions":4096,"classes":4096,"active_positions":4096,"jobs":2960,"matches":0,"host_ms":17.388386,"build_ms":0.316459,"root_ms":15.843212,"expand_ms":0.000192,"search_ms":1.228427}
{"type":"pipeline","mode":2,"round":0,"positions":4096,"classes":4096,"active_positions":4096,"jobs":2960,"matches":0,"host_ms":19.225847,"build_ms":1.497691,"root_ms":15.909497,"expand_ms":0.624573,"search_ms":1.193798}
{"type":"pipeline","mode":3,"round":0,"positions":4096,"classes":4096,"active_positions":118,"jobs":2960,"matches":0,"host_ms":17.880678,"build_ms":1.123676,"root_ms":14.852298,"expand_ms":0.623134,"search_ms":1.281474}
{"type":"pipeline","mode":1,"round":1,"positions":4096,"classes":4096,"active_positions":4096,"jobs":2960,"matches":0,"host_ms":17.902261,"build_ms":0.291998,"root_ms":16.411382,"expand_ms":0.000287,"search_ms":1.19821}
{"type":"pipeline","mode":2,"round":1,"positions":4096,"classes":4096,"active_positions":4096,"jobs":2960,"matches":0,"host_ms":19.238988,"build_ms":1.595823,"root_ms":15.836689,"expand_ms":0.631288,"search_ms":1.174708}
{"type":"pipeline","mode":3,"round":1,"positions":4096,"classes":4096,"active_positions":118,"jobs":2960,"matches":0,"host_ms":21.575071,"build_ms":1.05058,"root_ms":17.458508,"expand_ms":0.716758,"search_ms":2.349129}
{"type":"pipeline","mode":0,"round":1,"positions":4096,"classes":4096,"active_positions":4096,"jobs":2960,"matches":0,"host_ms":33.127423,"build_ms":0.307347,"root_ms":24.924514,"expand_ms":0.000192,"search_ms":7.895082}
{"type":"pipeline","mode":2,"round":2,"positions":4096,"classes":4096,"active_positions":4096,"jobs":2960,"matches":0,"host_ms":20.589721,"build_ms":1.355912,"root_ms":17.315675,"expand_ms":0.630137,"search_ms":1.287517}
{"type":"pipeline","mode":3,"round":2,"positions":4096,"classes":4096,"active_positions":118,"jobs":2960,"matches":0,"host_ms":19.501921,"build_ms":1.103531,"root_ms":16.471047,"expand_ms":0.668987,"search_ms":1.257972}
{"type":"pipeline","mode":0,"round":2,"positions":4096,"classes":4096,"active_positions":4096,"jobs":2960,"matches":0,"host_ms":24.022332,"build_ms":0.288545,"root_ms":16.179721,"expand_ms":0.000191,"search_ms":7.553683}
{"type":"pipeline","mode":1,"round":2,"positions":4096,"classes":4096,"active_positions":4096,"jobs":2960,"matches":0,"host_ms":18.798496,"build_ms":0.350033,"root_ms":16.509706,"expand_ms":0.000191,"search_ms":1.938279}
{"type":"validation","complete_roots_equal":true,"complete_matches_equal":true,"matches":[]}

View file

@ -0,0 +1,6 @@
{"type":"setup","host_ms":200.876289}
{"type":"pipeline","mode":0,"round":0,"positions":32768,"classes":32768,"active_positions":32768,"jobs":15424,"matches":0,"host_ms":152.132767,"build_ms":4.096027,"root_ms":113.387564,"expand_ms":0.000184,"search_ms":34.648623}
{"type":"pipeline","mode":1,"round":0,"positions":32768,"classes":32768,"active_positions":32768,"jobs":15424,"matches":0,"host_ms":124.087013,"build_ms":4.152926,"root_ms":113.998689,"expand_ms":0.000184,"search_ms":5.934844}
{"type":"pipeline","mode":2,"round":0,"positions":32768,"classes":512,"active_positions":32768,"jobs":15424,"matches":0,"host_ms":13.605316,"build_ms":5.613835,"root_ms":1.992268,"expand_ms":0.604117,"search_ms":5.394911}
{"type":"pipeline","mode":3,"round":0,"positions":32768,"classes":512,"active_positions":1216,"jobs":15424,"matches":0,"host_ms":9.609161,"build_ms":1.342779,"root_ms":2.238581,"expand_ms":0.603472,"search_ms":5.424052}
{"type":"validation","complete_roots_equal":true,"complete_matches_equal":true,"matches":[]}

View file

@ -0,0 +1,6 @@
{"type":"setup","host_ms":175.300766}
{"type":"pipeline","mode":0,"round":0,"positions":21,"classes":21,"active_positions":21,"jobs":474,"matches":24,"host_ms":1.476311,"build_ms":0.003135,"root_ms":0.17549,"expand_ms":0,"search_ms":1.297501}
{"type":"pipeline","mode":1,"round":0,"positions":21,"classes":21,"active_positions":21,"jobs":474,"matches":24,"host_ms":0.505168,"build_ms":0.004611,"root_ms":0.175213,"expand_ms":9.3e-05,"search_ms":0.325159}
{"type":"pipeline","mode":2,"round":0,"positions":21,"classes":20,"active_positions":21,"jobs":474,"matches":24,"host_ms":0.834753,"build_ms":0.011158,"root_ms":0.242071,"expand_ms":0.210348,"search_ms":0.370991}
{"type":"pipeline","mode":3,"round":0,"positions":21,"classes":20,"active_positions":13,"jobs":474,"matches":24,"host_ms":0.782097,"build_ms":0.004335,"root_ms":0.1967,"expand_ms":0.261529,"search_ms":0.319533}
{"type":"validation","complete_roots_equal":true,"complete_matches_equal":true,"matches":[[10358701894766,51069,419124],[15959335054446,51069,419124],[18914276748398,51069,419124],[24514909908078,51069,419124],[27469851602030,51069,419124],[33070484761710,51069,419124],[36025426455662,51069,419124],[41626059615342,51069,419124],[44581001309294,51069,419124],[50181634468974,51069,419124],[53136576162926,51069,419124],[58737209322606,51069,419124],[61692151016558,51069,419124],[67292784176238,51069,419124],[70247725870190,51069,419124],[75848359029870,51069,419124],[78803300723822,51069,419124],[84403933883502,51069,419124],[87358875577454,51069,419124],[92959508737134,51069,419124],[95914450431086,51069,419124],[101515083590766,51069,419124],[104470025284718,51069,419124],[110070658444398,51069,419124]]}

View file

@ -0,0 +1,361 @@
{
"metadata": {
"date": "2026-10-11T10:51:13.411084+08:00",
"gpu": "name, driver_version\nNVIDIA GeForce RTX 3060 Laptop GPU, 596.49\n"
},
"known_lifts": {
"0": {
"host_ms": 364.022951,
"build_ms": 0.1147,
"root_ms": 8.7547,
"expand_ms": 0.0001,
"search_ms": 355.153251,
"jobs": 138852,
"classes": 1653,
"positions": 1653,
"active_positions": 1653,
"matches": 24
},
"1": {
"host_ms": 62.015757,
"build_ms": 0.113,
"root_ms": 8.742087,
"expand_ms": 0.000191,
"search_ms": 53.159211,
"jobs": 138852,
"classes": 1653,
"positions": 1653,
"active_positions": 1653,
"matches": 24
},
"2": {
"host_ms": 55.3725,
"build_ms": 0.133,
"root_ms": 0.32588,
"expand_ms": 0.297156,
"search_ms": 54.5471,
"jobs": 138852,
"classes": 1,
"positions": 1653,
"active_positions": 1653,
"matches": 24
},
"3": {
"host_ms": 56.8665,
"build_ms": 0.0101,
"root_ms": 0.2025,
"expand_ms": 0.6781,
"search_ms": 56.0187,
"jobs": 138852,
"classes": 1,
"positions": 1653,
"active_positions": 1653,
"matches": 24
},
"validation": {
"type": "validation",
"complete_roots_equal": true,
"complete_matches_equal": true,
"matches": [
[
10358701894766,
51069,
419124
],
[
15959335054446,
51069,
419124
],
[
18914276748398,
51069,
419124
],
[
24514909908078,
51069,
419124
],
[
27469851602030,
51069,
419124
],
[
33070484761710,
51069,
419124
],
[
36025426455662,
51069,
419124
],
[
41626059615342,
51069,
419124
],
[
44581001309294,
51069,
419124
],
[
50181634468974,
51069,
419124
],
[
53136576162926,
51069,
419124
],
[
58737209322606,
51069,
419124
],
[
61692151016558,
51069,
419124
],
[
67292784176238,
51069,
419124
],
[
70247725870190,
51069,
419124
],
[
75848359029870,
51069,
419124
],
[
78803300723822,
51069,
419124
],
[
84403933883502,
51069,
419124
],
[
87358875577454,
51069,
419124
],
[
92959508737134,
51069,
419124
],
[
95914450431086,
51069,
419124
],
[
101515083590766,
51069,
419124
],
[
104470025284718,
51069,
419124
],
[
110070658444398,
51069,
419124
]
]
},
"setup_ms": 220.229718
},
"nonempty32": {
"0": {
"host_ms": 4691.310731,
"build_ms": 7.490479,
"root_ms": 255.097691,
"expand_ms": 0.000286,
"search_ms": 4428.995719,
"jobs": 1693228,
"classes": 52213,
"positions": 52213,
"active_positions": 52213,
"matches": 0
},
"1": {
"host_ms": 915.445942,
"build_ms": 7.505432,
"root_ms": 245.545208,
"expand_ms": 0.000183,
"search_ms": 662.365642,
"jobs": 1693228,
"classes": 52213,
"positions": 52213,
"active_positions": 52213,
"matches": 0
},
"2": {
"host_ms": 656.710025,
"build_ms": 7.652735,
"root_ms": 0.576767,
"expand_ms": 1.326998,
"search_ms": 645.168458,
"jobs": 1693228,
"classes": 32,
"positions": 52213,
"active_positions": 52213,
"matches": 0
},
"3": {
"host_ms": 676.742292,
"build_ms": 0.3428,
"root_ms": 0.504258,
"expand_ms": 8.844275,
"search_ms": 666.607392,
"jobs": 1693228,
"classes": 32,
"positions": 52213,
"active_positions": 52213,
"matches": 0
},
"validation": {
"type": "validation",
"complete_roots_equal": true,
"complete_matches_equal": true,
"matches": []
},
"setup_ms": 219.927973
},
"mixed512": {
"0": {
"host_ms": 172.222139,
"build_ms": 4.55245,
"root_ms": 126.737258,
"expand_ms": 0.000192,
"search_ms": 41.239203,
"jobs": 15424,
"classes": 32768,
"positions": 32768,
"active_positions": 32768,
"matches": 0
},
"1": {
"host_ms": 141.138417,
"build_ms": 4.616912,
"root_ms": 130.393185,
"expand_ms": 0.000192,
"search_ms": 6.145971,
"jobs": 15424,
"classes": 32768,
"positions": 32768,
"active_positions": 32768,
"matches": 0
},
"2": {
"host_ms": 14.235207,
"build_ms": 5.280144,
"root_ms": 2.227974,
"expand_ms": 0.638962,
"search_ms": 6.216476,
"jobs": 15424,
"classes": 512,
"positions": 32768,
"active_positions": 32768,
"matches": 0
},
"3": {
"host_ms": 9.585776,
"build_ms": 0.416318,
"root_ms": 2.04888,
"expand_ms": 0.690187,
"search_ms": 6.774668,
"jobs": 15424,
"classes": 512,
"positions": 32768,
"active_positions": 1216,
"matches": 0
},
"validation": {
"type": "validation",
"complete_roots_equal": true,
"complete_matches_equal": true,
"matches": []
},
"setup_ms": 242.015308
},
"random4096": {
"0": {
"host_ms": 24.022332,
"build_ms": 0.29315,
"root_ms": 16.179721,
"expand_ms": 0.000192,
"search_ms": 7.553683,
"jobs": 2960,
"classes": 4096,
"positions": 4096,
"active_positions": 4096,
"matches": 0
},
"1": {
"host_ms": 17.902261,
"build_ms": 0.316459,
"root_ms": 16.411382,
"expand_ms": 0.000192,
"search_ms": 1.228427,
"jobs": 2960,
"classes": 4096,
"positions": 4096,
"active_positions": 4096,
"matches": 0
},
"2": {
"host_ms": 19.238988,
"build_ms": 1.497691,
"root_ms": 15.909497,
"expand_ms": 0.630137,
"search_ms": 1.193798,
"jobs": 2960,
"classes": 4096,
"positions": 4096,
"active_positions": 4096,
"matches": 0
},
"3": {
"host_ms": 19.501921,
"build_ms": 1.103531,
"root_ms": 16.471047,
"expand_ms": 0.668987,
"search_ms": 1.281474,
"jobs": 2960,
"classes": 4096,
"positions": 4096,
"active_positions": 118,
"matches": 0
},
"validation": {
"type": "validation",
"complete_roots_equal": true,
"complete_matches_equal": true,
"matches": []
},
"setup_ms": 216.555239
},
"source_sha256": {
"pipeline_bench.cu": "31da815aa0ee8904c702e55d2d685282fc64bfada24dd208e151faac5c55c37c",
"cuda_bench.cu": "3e1fd6fe3bdb87ac68fe853dc4e6d2275d6aa00a692c7d630391fd12c0105c20",
"grouped.hpp": "5d48c4a45e7f7b07a362c69b5163f48d44bd45d18e7f0f02b00bda0edaadeb23",
"run_pipeline.py": "ce3f9e01fad8978541c581233bfeaa4023acade24bbc736f479be6ac14e88591"
}
}

View file

@ -0,0 +1,6 @@
{"type":"setup","host_ms":197.591869}
{"type":"pipeline","mode":0,"round":0,"positions":1653,"classes":1653,"active_positions":1653,"jobs":0,"matches":0,"host_ms":5.571692,"build_ms":0.090188,"root_ms":5.379603,"expand_ms":0,"search_ms":0.101716}
{"type":"pipeline","mode":1,"round":0,"positions":1653,"classes":1653,"active_positions":1653,"jobs":0,"matches":0,"host_ms":5.729661,"build_ms":0.1019,"root_ms":5.497826,"expand_ms":0,"search_ms":0.12975}
{"type":"pipeline","mode":2,"round":0,"positions":1653,"classes":1,"active_positions":1653,"jobs":0,"matches":0,"host_ms":0.56059,"build_ms":0.10771,"root_ms":0.251016,"expand_ms":0.131594,"search_ms":0.070177}
{"type":"pipeline","mode":3,"round":0,"positions":1653,"classes":1,"active_positions":0,"jobs":0,"matches":0,"host_ms":0.230821,"build_ms":0.006363,"root_ms":0.083272,"expand_ms":0.071838,"search_ms":0.069348}
{"type":"validation","complete_roots_equal":true,"complete_matches_equal":true,"matches":[]}

View file

@ -0,0 +1 @@
{"q_checks":5000000,"group_masks":888128,"partial_filter_survivors":159120,"known_filter_survivors":36,"passed":true}

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,40 @@
{"type":"device","name":"NVIDIA GeForce RTX 3060 Laptop GPU","positions":1}
{"type":"search_timing","mode":3,"round":0,"kernel_ms":0.3235839903,"scan_ms":0.46062,"matches":24}
{"type":"search_timing","mode":4,"round":0,"kernel_ms":0.2693119943,"scan_ms":0.393283,"matches":24}
{"type":"search_timing","mode":5,"round":0,"kernel_ms":0.2897920012,"scan_ms":0.44485,"matches":24}
{"type":"search_timing","mode":6,"round":0,"kernel_ms":0.2846719921,"scan_ms":0.431015,"matches":24}
{"type":"search_timing","mode":7,"round":0,"kernel_ms":0.1566720009,"scan_ms":0.292181,"matches":24}
{"type":"search_timing","mode":4,"round":1,"kernel_ms":0.2682879865,"scan_ms":0.380609,"matches":24}
{"type":"search_timing","mode":5,"round":1,"kernel_ms":0.2959359884,"scan_ms":0.421824,"matches":24}
{"type":"search_timing","mode":6,"round":1,"kernel_ms":0.2887679935,"scan_ms":0.400152,"matches":24}
{"type":"search_timing","mode":7,"round":1,"kernel_ms":0.1556479931,"scan_ms":0.275249,"matches":24}
{"type":"search_timing","mode":3,"round":1,"kernel_ms":0.3235839903,"scan_ms":0.449784,"matches":24}
{"type":"search_timing","mode":5,"round":2,"kernel_ms":0.2938880026,"scan_ms":0.40615,"matches":24}
{"type":"search_timing","mode":6,"round":2,"kernel_ms":0.2897920012,"scan_ms":0.40199,"matches":24}
{"type":"search_timing","mode":7,"round":2,"kernel_ms":0.1566720009,"scan_ms":0.269735,"matches":24}
{"type":"search_timing","mode":3,"round":2,"kernel_ms":0.3225600123,"scan_ms":0.437013,"matches":24}
{"type":"search_timing","mode":4,"round":2,"kernel_ms":0.2693119943,"scan_ms":0.3779,"matches":24}
{"type":"search_timing","mode":6,"round":3,"kernel_ms":0.2897920012,"scan_ms":0.411375,"matches":24}
{"type":"search_timing","mode":7,"round":3,"kernel_ms":0.1556479931,"scan_ms":0.269929,"matches":24}
{"type":"search_timing","mode":3,"round":3,"kernel_ms":0.3194879889,"scan_ms":0.427629,"matches":24}
{"type":"search_timing","mode":4,"round":3,"kernel_ms":0.2682879865,"scan_ms":0.375288,"matches":24}
{"type":"search_timing","mode":5,"round":3,"kernel_ms":0.2969599962,"scan_ms":0.414665,"matches":24}
{"type":"search_timing","mode":7,"round":4,"kernel_ms":0.1566720009,"scan_ms":0.268187,"matches":24}
{"type":"search_timing","mode":3,"round":4,"kernel_ms":0.3235839903,"scan_ms":0.426952,"matches":24}
{"type":"search_timing","mode":4,"round":4,"kernel_ms":0.2682879865,"scan_ms":0.425307,"matches":24}
{"type":"search_timing","mode":5,"round":4,"kernel_ms":0.2949120104,"scan_ms":0.415051,"matches":24}
{"type":"search_timing","mode":6,"round":4,"kernel_ms":0.2897920012,"scan_ms":0.407022,"matches":24}
{"type":"search_timing","mode":3,"round":5,"kernel_ms":0.3235839903,"scan_ms":0.427339,"matches":24}
{"type":"search_timing","mode":4,"round":5,"kernel_ms":0.2631680071,"scan_ms":0.37432,"matches":24}
{"type":"search_timing","mode":5,"round":5,"kernel_ms":0.2949120104,"scan_ms":0.403248,"matches":24}
{"type":"search_timing","mode":6,"round":5,"kernel_ms":0.2846719921,"scan_ms":0.436142,"matches":24}
{"type":"search_timing","mode":7,"round":5,"kernel_ms":0.1505279988,"scan_ms":0.388832,"matches":24}
{"type":"search_timing","mode":4,"round":6,"kernel_ms":0.4679679871,"scan_ms":0.896375,"matches":24}
{"type":"search_timing","mode":5,"round":6,"kernel_ms":0.5027840137,"scan_ms":0.714295,"matches":24}
{"type":"search_timing","mode":6,"round":6,"kernel_ms":0.4864000082,"scan_ms":0.691172,"matches":24}
{"type":"search_timing","mode":7,"round":6,"kernel_ms":0.1587200016,"scan_ms":0.454428,"matches":24}
{"type":"search_timing","mode":3,"round":6,"kernel_ms":0.3205119967,"scan_ms":0.426854,"matches":24}
{"type":"search_info","root_ms":1.090559959,"jobs":84,"lower35":11010048,"matches":[[10358701894766,51069,419124],[15959335054446,51069,419124],[18914276748398,51069,419124],[24514909908078,51069,419124],[27469851602030,51069,419124],[33070484761710,51069,419124],[36025426455662,51069,419124],[41626059615342,51069,419124],[44581001309294,51069,419124],[50181634468974,51069,419124],[53136576162926,51069,419124],[58737209322606,51069,419124],[61692151016558,51069,419124],[67292784176238,51069,419124],[70247725870190,51069,419124],[75848359029870,51069,419124],[78803300723822,51069,419124],[84403933883502,51069,419124],[87358875577454,51069,419124],[92959508737134,51069,419124],[95914450431086,51069,419124],[101515083590766,51069,419124],[104470025284718,51069,419124],[110070658444398,51069,419124]]}
{"type":"periodic_validation","classes":1,"positions":1,"equal":true}
{"type":"root_counts","counts":[84]}
{"type":"process","ms":234.661262}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,40 @@
{"type":"device","name":"NVIDIA GeForce RTX 3060 Laptop GPU","positions":21}
{"type":"search_timing","mode":3,"round":0,"kernel_ms":1.288192034,"scan_ms":1.497474,"matches":24}
{"type":"search_timing","mode":4,"round":0,"kernel_ms":0.9256960154,"scan_ms":1.163402,"matches":24}
{"type":"search_timing","mode":5,"round":0,"kernel_ms":1.083392024,"scan_ms":1.280467,"matches":24}
{"type":"search_timing","mode":6,"round":0,"kernel_ms":1.010687947,"scan_ms":1.163015,"matches":24}
{"type":"search_timing","mode":7,"round":0,"kernel_ms":0.224255994,"scan_ms":0.397249,"matches":24}
{"type":"search_timing","mode":4,"round":1,"kernel_ms":0.922623992,"scan_ms":1.157113,"matches":24}
{"type":"search_timing","mode":5,"round":1,"kernel_ms":2.477056026,"scan_ms":2.639978,"matches":24}
{"type":"search_timing","mode":6,"round":1,"kernel_ms":1.007616043,"scan_ms":1.288401,"matches":24}
{"type":"search_timing","mode":7,"round":1,"kernel_ms":0.2191359997,"scan_ms":0.471262,"matches":24}
{"type":"search_timing","mode":3,"round":1,"kernel_ms":1.288192034,"scan_ms":1.444263,"matches":24}
{"type":"search_timing","mode":5,"round":2,"kernel_ms":1.078271985,"scan_ms":1.256764,"matches":24}
{"type":"search_timing","mode":6,"round":2,"kernel_ms":1.006592035,"scan_ms":1.21168,"matches":24}
{"type":"search_timing","mode":7,"round":2,"kernel_ms":0.2232320011,"scan_ms":0.403248,"matches":24}
{"type":"search_timing","mode":3,"round":2,"kernel_ms":1.288192034,"scan_ms":1.439328,"matches":24}
{"type":"search_timing","mode":4,"round":2,"kernel_ms":0.9277439713,"scan_ms":1.074297,"matches":24}
{"type":"search_timing","mode":6,"round":3,"kernel_ms":1.010687947,"scan_ms":1.17298,"matches":24}
{"type":"search_timing","mode":7,"round":3,"kernel_ms":0.2191359997,"scan_ms":0.391735,"matches":24}
{"type":"search_timing","mode":3,"round":3,"kernel_ms":1.28512001,"scan_ms":1.408369,"matches":24}
{"type":"search_timing","mode":4,"round":3,"kernel_ms":0.922623992,"scan_ms":1.240607,"matches":24}
{"type":"search_timing","mode":5,"round":3,"kernel_ms":1.338368058,"scan_ms":1.72406,"matches":24}
{"type":"search_timing","mode":7,"round":4,"kernel_ms":0.2273280025,"scan_ms":0.686431,"matches":24}
{"type":"search_timing","mode":3,"round":4,"kernel_ms":1.284096003,"scan_ms":1.587644,"matches":24}
{"type":"search_timing","mode":4,"round":4,"kernel_ms":0.9267200232,"scan_ms":1.158467,"matches":24}
{"type":"search_timing","mode":5,"round":4,"kernel_ms":1.08544004,"scan_ms":1.29943,"matches":24}
{"type":"search_timing","mode":6,"round":4,"kernel_ms":1.010687947,"scan_ms":1.240704,"matches":24}
{"type":"search_timing","mode":3,"round":5,"kernel_ms":1.289216042,"scan_ms":1.494572,"matches":24}
{"type":"search_timing","mode":4,"round":5,"kernel_ms":0.9267200232,"scan_ms":1.150921,"matches":24}
{"type":"search_timing","mode":5,"round":5,"kernel_ms":1.084416032,"scan_ms":1.289078,"matches":24}
{"type":"search_timing","mode":6,"round":5,"kernel_ms":1.010687947,"scan_ms":1.221837,"matches":24}
{"type":"search_timing","mode":7,"round":5,"kernel_ms":0.2201599926,"scan_ms":0.470488,"matches":24}
{"type":"search_timing","mode":4,"round":6,"kernel_ms":0.9277439713,"scan_ms":1.136892,"matches":24}
{"type":"search_timing","mode":5,"round":6,"kernel_ms":1.083392024,"scan_ms":1.321102,"matches":24}
{"type":"search_timing","mode":6,"round":6,"kernel_ms":1.781759977,"scan_ms":1.983442,"matches":24}
{"type":"search_timing","mode":7,"round":6,"kernel_ms":0.2252800018,"scan_ms":0.355744,"matches":24}
{"type":"search_timing","mode":3,"round":6,"kernel_ms":1.93740797,"scan_ms":2.027463,"matches":24}
{"type":"search_info","root_ms":1.161216021,"jobs":474,"lower35":62128128,"matches":[[10358701894766,51069,419124],[15959335054446,51069,419124],[18914276748398,51069,419124],[24514909908078,51069,419124],[27469851602030,51069,419124],[33070484761710,51069,419124],[36025426455662,51069,419124],[41626059615342,51069,419124],[44581001309294,51069,419124],[50181634468974,51069,419124],[53136576162926,51069,419124],[58737209322606,51069,419124],[61692151016558,51069,419124],[67292784176238,51069,419124],[70247725870190,51069,419124],[75848359029870,51069,419124],[78803300723822,51069,419124],[84403933883502,51069,419124],[87358875577454,51069,419124],[92959508737134,51069,419124],[95914450431086,51069,419124],[101515083590766,51069,419124],[104470025284718,51069,419124],[110070658444398,51069,419124]]}
{"type":"periodic_validation","classes":20,"positions":21,"equal":true}
{"type":"root_counts","counts":[84,152,16,0,2,20,61,22,0,1,35,30,20,29,0,2,0,0,0,0,0]}
{"type":"process","ms":276.458389}

View file

@ -0,0 +1,331 @@
{
"metadata": {
"date": "2026-10-11T09:46:12.120634+08:00",
"cpu_validation": {
"q_checks": 5000000,
"group_masks": 888128,
"partial_filter_survivors": 159120,
"known_filter_survivors": 36,
"passed": true
},
"gpu": "name, driver_version\nNVIDIA GeForce RTX 3060 Laptop GPU, 596.49\n"
},
"known": {
"3": 0.3235839903,
"4": 0.2682879865,
"5": 0.2949120104,
"6": 0.2897920012,
"7": 0.1566720009,
"info": {
"type": "search_info",
"root_ms": 1.090559959,
"jobs": 84,
"lower35": 11010048,
"matches": [
[
10358701894766,
51069,
419124
],
[
15959335054446,
51069,
419124
],
[
18914276748398,
51069,
419124
],
[
24514909908078,
51069,
419124
],
[
27469851602030,
51069,
419124
],
[
33070484761710,
51069,
419124
],
[
36025426455662,
51069,
419124
],
[
41626059615342,
51069,
419124
],
[
44581001309294,
51069,
419124
],
[
50181634468974,
51069,
419124
],
[
53136576162926,
51069,
419124
],
[
58737209322606,
51069,
419124
],
[
61692151016558,
51069,
419124
],
[
67292784176238,
51069,
419124
],
[
70247725870190,
51069,
419124
],
[
75848359029870,
51069,
419124
],
[
78803300723822,
51069,
419124
],
[
84403933883502,
51069,
419124
],
[
87358875577454,
51069,
419124
],
[
92959508737134,
51069,
419124
],
[
95914450431086,
51069,
419124
],
[
101515083590766,
51069,
419124
],
[
104470025284718,
51069,
419124
],
[
110070658444398,
51069,
419124
]
]
}
},
"stress": {
"3": 1.288192034,
"4": 0.9267200232,
"5": 1.084416032,
"6": 1.010687947,
"7": 0.2232320011,
"info": {
"type": "search_info",
"root_ms": 1.161216021,
"jobs": 474,
"lower35": 62128128,
"matches": [
[
10358701894766,
51069,
419124
],
[
15959335054446,
51069,
419124
],
[
18914276748398,
51069,
419124
],
[
24514909908078,
51069,
419124
],
[
27469851602030,
51069,
419124
],
[
33070484761710,
51069,
419124
],
[
36025426455662,
51069,
419124
],
[
41626059615342,
51069,
419124
],
[
44581001309294,
51069,
419124
],
[
50181634468974,
51069,
419124
],
[
53136576162926,
51069,
419124
],
[
58737209322606,
51069,
419124
],
[
61692151016558,
51069,
419124
],
[
67292784176238,
51069,
419124
],
[
70247725870190,
51069,
419124
],
[
75848359029870,
51069,
419124
],
[
78803300723822,
51069,
419124
],
[
84403933883502,
51069,
419124
],
[
87358875577454,
51069,
419124
],
[
92959508737134,
51069,
419124
],
[
95914450431086,
51069,
419124
],
[
101515083590766,
51069,
419124
],
[
104470025284718,
51069,
419124
],
[
110070658444398,
51069,
419124
]
]
}
},
"random4096": {
"3": 8.857600212,
"4": 5.859327793,
"5": 6.7450881,
"6": 5.53574419,
"7": 1.141759992,
"info": {
"type": "search_info",
"root_ms": 19.01977539,
"jobs": 2960,
"lower35": 387973120,
"matches": []
}
},
"random65536": {
"3": 130.1360626,
"4": 98.65420532,
"5": 114.5487366,
"6": 108.295166,
"7": 19.98233604,
"info": {
"type": "search_info",
"root_ms": 267.9224243,
"jobs": 45356,
"lower35": 5944901632,
"matches": []
}
},
"fresh65536": {
"3": 134.184967,
"4": 102.5822754,
"5": 118.9703674,
"6": 112.1454086,
"7": 20.44006348,
"info": {
"type": "search_info",
"root_ms": 277.3555298,
"jobs": 46148,
"lower35": 6048710656,
"matches": []
}
},
"source_sha256": {
"cuda_bench.cu": "f762ea050d7c93c00903928f972e41106e917d37a4caceb79630bacd0f9316e1",
"grouped.hpp": "5d48c4a45e7f7b07a362c69b5163f48d44bd45d18e7f0f02b00bda0edaadeb23",
"cpu_verify.cpp": "2e2b6799bd624b3e0a3022c2144c4a6f665c08de530d8f2846e6bc748ba6412f",
"run.py": "daca9d7de3463fd501a99b10d921974b73c206acc6e1438a246ae5729043c15e"
}
}

View file

@ -0,0 +1,28 @@
#!/usr/bin/env python3
import subprocess,json,statistics,hashlib,random,datetime
from pathlib import Path
HERE=Path(__file__).resolve().parent
POS=HERE.parent/'full_search_feasibility'/'positions'
OUT=HERE/'results'
OUT.mkdir(exist_ok=True)
subprocess.run(['nvcc','-O3','-std=c++17','-arch=sm_86',str(HERE/'cuda_bench.cu'),'-o','/tmp/slime_normal_cuda'],check=True)
subprocess.run(['g++','-O3','-std=c++17','-Wall','-Wextra',str(HERE/'cpu_verify.cpp'),'-o','/tmp/slime_normal_verify'],check=True)
validation=subprocess.check_output(['/tmp/slime_normal_verify'],text=True)
(OUT/'cpu_verify.json').write_text(validation)
rng=random.Random(2026101104)
fresh=HERE/'fresh65536.txt'
fresh.write_text(''.join(f'{rng.randrange(-1875000,1875000)} {rng.randrange(-1875000,1875000)}\n' for _ in range(65536)))
summary={'metadata':{'date':datetime.datetime.now().astimezone().isoformat(),'cpu_validation':json.loads(validation),'gpu':subprocess.check_output(['nvidia-smi','--query-gpu=name,driver_version','--format=csv'],text=True)}}
for name in ['known','stress','random4096','random65536','fresh65536']:
cmd=['/tmp/slime_normal_cuda',str(fresh if name=='fresh65536' else POS/(name+'.txt')),'normal','7']
r=subprocess.run(cmd,capture_output=True,text=True,timeout=300)
(OUT/(name+'.jsonl')).write_text(r.stdout)
(OUT/(name+'.stderr')).write_text(r.stderr)
if r.returncode: raise RuntimeError(r.stderr)
rows=[json.loads(s) for s in r.stdout.splitlines()]
summary[name]={str(m):statistics.median(v['kernel_ms'] for v in rows if v['type']=='search_timing' and v['mode']==m) for m in [3,4,5,6,7]}
summary[name]['info']=next(v for v in rows if v['type']=='search_info')
print(name,json.dumps(summary[name]),flush=True)
summary['source_sha256']={name:hashlib.sha256((HERE/name).read_bytes()).hexdigest() for name in ['cuda_bench.cu','grouped.hpp','cpu_verify.cpp','run.py']}
summary['shared_headers_sha256']={name:hashlib.sha256((HERE.parents[2]/'include'/'slime'/name).read_bytes()).hexdigest() for name in ['solver_core.hpp','upper_interval.hpp']}
(OUT/'summary.json').write_text(json.dumps(summary,indent=2))

View file

@ -0,0 +1,44 @@
#!/usr/bin/env python3
import subprocess,json,random,statistics,hashlib,datetime
from pathlib import Path
HERE=Path(__file__).resolve().parent
OLD=HERE.parent/'full_search_feasibility'
OUT=HERE/'pipeline_results'
POS=HERE/'pipeline_positions'
OUT.mkdir(exist_ok=True);POS.mkdir(exist_ok=True)
def lifts(x,z):
return [(xx,zz) for xx in range(-1875000+(x+1875000)%65536,1875000,65536)
for zz in range(-1875000+(z+1875000)%131072,1875000,131072)]
def save(name,coords):
p=POS/(name+'.txt');p.write_text(''.join(f'{x} {z}\n' for x,z in coords));return p
known=save('known_lifts',lifts(51069,419124))
rng=random.Random(2026101105)
coords=[]
classes=set()
while len(classes)<512:
c=(rng.randrange(65536),rng.randrange(131072))
if c in classes:continue
classes.add(c)
coords.extend(rng.sample(lifts(*c),64))
mixed=save('mixed512',coords)
cases={'known_lifts':known,'nonempty32':OLD/'positions/lifts.txt','mixed512':mixed,'random4096':OLD/'positions/random4096.txt'}
subprocess.run(['nvcc','-O3','-std=c++17','-arch=sm_86',str(HERE/'pipeline_bench.cu'),'-o','/tmp/slime_pipeline_cuda'],check=True)
summary={'metadata':{'date':datetime.datetime.now().astimezone().isoformat(),'gpu':subprocess.check_output(['nvidia-smi','--query-gpu=name,driver_version','--format=csv'],text=True)}}
for name,path in cases.items():
cmd=['/tmp/slime_pipeline_cuda',str(path),'3']
p=subprocess.run(cmd,capture_output=True,text=True,timeout=300)
(OUT/(name+'.jsonl')).write_text(p.stdout);(OUT/(name+'.stderr')).write_text(p.stderr)
if p.returncode:raise RuntimeError(p.stderr)
rows=[json.loads(l) for l in p.stdout.splitlines()]
d={}
for m in range(4):
a=[r for r in rows if r['type']=='pipeline' and r['mode']==m]
d[str(m)]={k:statistics.median(r[k] for r in a) for k in ['host_ms','build_ms','root_ms','expand_ms','search_ms','jobs','classes','positions','active_positions','matches']}
d['validation']=next(r for r in rows if r['type']=='validation')
d['setup_ms']=next(r['host_ms'] for r in rows if r['type']=='setup')
summary[name]=d
(OUT/'summary.json').write_text(json.dumps(summary,indent=2))
print(name,json.dumps({k:v for k,v in d.items() if k!='validation'}),flush=True)
summary['source_sha256']={n:hashlib.sha256((HERE/n).read_bytes()).hexdigest() for n in ['pipeline_bench.cu','cuda_bench.cu','grouped.hpp','run_pipeline.py']}
summary['shared_headers_sha256']={name:hashlib.sha256((HERE.parents[2]/'include'/'slime'/name).read_bytes()).hexdigest() for name in ['solver_core.hpp','upper_interval.hpp']}
(OUT/'summary.json').write_text(json.dumps(summary,indent=2))

View file

@ -0,0 +1,28 @@
#!/usr/bin/env python3
import json,subprocess,random,hashlib
from pathlib import Path
H=Path(__file__).resolve().parent
OLD=H.parent/'full_search_feasibility'
POS=H/'pipeline_positions';OUT=H/'pipeline_results'
rows=[json.loads(l) for l in (OLD/'results/random4096.jsonl').read_text().splitlines()]
counts=next(r['counts'] for r in rows if r['type']=='root_counts')
points=[tuple(map(int,l.split())) for l in (OLD/'positions/random4096.txt').read_text().splitlines()]
x,z=points[counts.index(0)]
zero=[(xx,zz) for xx in range(-1875000+(x+1875000)%65536,1875000,65536) for zz in range(-1875000+(z+1875000)%131072,1875000,131072)]
p=POS/'zero_lifts.txt';p.write_text(''.join(f'{x} {z}\n' for x,z in zero))
shuffled=(POS/'mixed512.txt').read_text().splitlines();random.Random(2026101106).shuffle(shuffled)
q=POS/'shuffled_mixed.txt';q.write_text('\n'.join(shuffled)+'\n')
subprocess.run(['nvcc','-O3','-std=c++17','-arch=sm_86',str(H/'pipeline_bench.cu'),'-o','/tmp/slime_pipeline_cuda'],check=True)
checks={}
for name,path in [('zero_lifts',p),('stress',OLD/'positions/stress.txt'),('shuffled_mixed',q)]:
r=subprocess.run(['/tmp/slime_pipeline_cuda',str(path),'1'],capture_output=True,text=True,timeout=120)
(OUT/(name+'.jsonl')).write_text(r.stdout);(OUT/(name+'.stderr')).write_text(r.stderr)
if r.returncode:raise RuntimeError(r.stderr)
rows=[json.loads(l) for l in r.stdout.splitlines()]
checks[name]={'validation':next(r for r in rows if r['type']=='validation'),'modes':[r for r in rows if r['type']=='pipeline']}
if name=='zero_lifts':assert all(r['jobs']==0 and r['matches']==0 for r in checks[name]['modes'])
if name=='stress':assert len(checks[name]['validation']['matches'])==24
print(name,'passed',flush=True)
checks['source_sha256']={n:hashlib.sha256((H/n).read_bytes()).hexdigest() for n in ['pipeline_bench.cu','cuda_bench.cu','grouped.hpp','verify_pipeline_edges.py']}
checks['shared_headers_sha256']={name:hashlib.sha256((H.parents[2]/'include'/'slime'/name).read_bytes()).hexdigest() for name in ['solver_core.hpp','upper_interval.hpp']}
(OUT/'edge_validation.json').write_text(json.dumps(checks,indent=2))