Clang -ffp-contract=on/fast and GCC's default (fast) all change the density hash on the L1 view; contraction off reproduces L1 (= Windows S13) at W1/W12. Seed sweep: 48 FloatingIslands seeds and 14 effective SurfaceWorld seeds (34 of 48 fell on a seed-independent cube) match across Clang/GCC and W1/W12. Standalone gains --seed/--recipe/--render-distance-chunks (viewer + headless) and a Windows replay script. Linux standalone workers get 32 MiB pthread stacks (TLS is 17.3 MiB/thread), so no external stack limit is needed. No Core or world-output change; MSVC compile unverified. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
54 lines
2.1 KiB
C++
54 lines
2.1 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:
|
|
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>(8,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;
|
|
}
|
|
};
|