Files
VoxelForge/Standalone/Source/StandaloneCoreScheduler.h
T
Fr0zkaandClaude Opus 5.5 aee1487410 perf(core): tile-drain instrumentation; parallel FI sign-edge repair, FI first tile 1.28 -> 0.85 s (L55); R24
Opt-in --instrument-tile-drain records per-tile queue/dispatch/finish timelines, stage spans and counters
(proof skips, X8 lanes, GradAt/midpoint memo, skirts, FI cache stats); <2% when off. Measured: SW 13.3 and
FI 50.2 worker-s across LOD0-8, tails are work-saturated. FI sign-edge repair now computes in parallel and
publishes in sorted serial order (exact output): sign-edge 535 -> 47 ms, FI first tile 1.28 -> 0.85 s, near
ring 1.46 -> 1.04 s, whole view 6.09 -> 5.65 s. Proof block size, lane batching, SW midpoint memo and helper
cap 12 measured and left off. fast/medium/full PASS, Clang and GCC. Research R24: slab + motif generator.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016dhxM43dnWvUu2B5Ph1iG1
2026-10-25 06:16:07 +01:00

60 lines
2.3 KiB
C++

#pragma once
#include "VoxelForgeCore/VoxelForgeCore.h"
#include "StandaloneWorkerThread.h"
#include <algorithm>
#include <atomic>
#include <chrono>
#include <thread>
#include <vector>
// This executor belongs to the standalone host. VoxelForgeCore submits indexed work but never
// creates or owns worker threads.
class FStandaloneCoreScheduler final : public VoxelForgeCore::JobScheduler
{
public:
explicit FStandaloneCoreScheduler(std::size_t helperLimit=12)
:HelperLimit(std::clamp<std::size_t>(helperLimit,1,12)){}
double parallel_for(std::size_t count,std::size_t batchSize,std::size_t workerLimit,
void* context,Task task,double* workerActiveSeconds,
std::size_t workerActiveCapacity) const override
{
if(count==0)return 0.0;
const std::size_t workers=std::clamp<std::size_t>(workerLimit,1,
std::min<std::size_t>(HelperLimit,std::max<std::size_t>(1,count)));
const std::size_t grain=std::max<std::size_t>(1,batchSize);
std::atomic<std::size_t> next{0};
std::vector<double> active(workers,0.0);
std::vector<FStandaloneWorkerThread> threads;
threads.reserve(workers);
for(std::size_t worker=0;worker<workers;++worker)
threads.emplace_back([&,worker]
{
const auto started=std::chrono::steady_clock::now();
for(;;)
{
const std::size_t first=next.fetch_add(grain,std::memory_order_relaxed);
if(first>=count)break;
const std::size_t end=first+std::min(grain,count-first);
for(std::size_t index=first;index<end;++index)task(context,index,worker);
}
active[worker]=std::chrono::duration<double>(
std::chrono::steady_clock::now()-started).count();
});
for(FStandaloneWorkerThread& thread:threads)thread.join();
double total=0.0;
for(std::size_t worker=0;worker<workers;++worker)
{
total+=active[worker];
if(workerActiveSeconds&&worker<workerActiveCapacity)
workerActiveSeconds[worker]=active[worker];
}
return total;
}
private:
std::size_t HelperLimit=8;
};