#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 matches;std::vector rootList;}; Run run(const std::vector>& coords,Device& d,Extra& extra,int mode){ const auto start=Clock::now(); auto ms=[](auto t){return std::chrono::duration(Clock::now()-t).count();}; std::vector positions;positions.reserve(coords.size()); if(mode!=3)for(auto [x,z]:coords)positions.push_back(makePosition(x,z)); std::vector reps;std::vector pc; if(mode>=2){ std::map 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><<>>(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 originalIndices; if(mode>=2){ std::vector cj(n);if(n)CUDA(cudaMemcpy(cj.data(),d.jobs,n*sizeof(Job),cudaMemcpyDeviceToHost)); std::vector> lists(reps.size()); for(auto j:cj)lists[j.position].push_back(j.root); if(mode==3){ std::vector compactClasses; for(uint32_t i=0;i 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<<>>(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)> 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(coords.size()));Extra e(coords.size()); std::cout<(Clock::now()-process).count()<<"}"<=0)std::cout<<"{\"type\":\"pipeline\",\"mode\":"<