Orrery
A GPU-accelerated N-body gravitational simulator
Loading...
Searching...
No Matches
worker_statistics.hpp File Reference

What each worker thread did, and how long it spent doing nothing. More...

#include <chrono>
#include <cstdint>
#include <vector>
#include "orrery/core/aligned_allocator.hpp"

Go to the source code of this file.

Classes

struct  orrery::backend::WorkerStatistics
 One worker's record, accumulated over every region since the last reset. More...
struct  orrery::backend::PaddedWorkerStatistics
 One worker's record, on a cache line of its own. More...
struct  orrery::backend::ExecutorStatistics
 The whole pool's record. More...

Typedefs

using orrery::backend::Clock = std::chrono::steady_clock
 The clock every duration here is measured on.
using orrery::backend::Duration = std::chrono::nanoseconds
 Durations are stored in nanoseconds so that they add without conversion and mean the same thing on every platform, whatever the clock's native period is.

Detailed Description

What each worker thread did, and how long it spent doing nothing.

Phase 6 exists to answer a question that a speedup figure cannot: when eight threads run on four performance cores and four efficiency cores, how much of the wall time do the fast cores spend waiting for the slow ones. A scheduler that hides that behind a single number is a scheduler nobody can improve, so the instrumentation is part of the design rather than something bolted on for one benchmark.

The accounting is deliberately simple and closed. Within one parallel region every worker is either running a chunk of the caller's work or it is not, and the region lasts from the moment the submitting thread hands the work over to the moment the last worker finishes. So for each worker

busy + idle = the duration of the region

and summing over W workers gives W times the region duration. Idle time measured this way includes everything that is not the caller's arithmetic: the wake-up latency of a sleeping thread, the wait for a chunk to become available, and the wait at the end for slower workers to finish. That is deliberate. Those costs are real, they are what a threading scheme is judged on, and a definition that excluded them would flatter the scheduler by measuring only the part of it that was already working.

The cost of the measurement is two clock readings per chunk. Chunks are sized so that each is tens of microseconds of work at the sizes this project runs at, against roughly a hundred nanoseconds for the pair of readings, so the instrumentation is under a part in a hundred and is left permanently on. That is worth more than the last fraction of a percent: a scheduler whose behaviour can only be seen in a special build is a scheduler whose behaviour is not seen.

Typedef Documentation

◆ Clock

using orrery::backend::Clock = std::chrono::steady_clock

The clock every duration here is measured on.

steady_clock rather than high_resolution_clock, which on some standard libraries is an alias for the system clock and therefore moves when the wall clock is adjusted. An interval that can go backwards is not a measurement.