Files
ObsidianDragon/src/ui/windows/mining_benchmark.cpp
DanS 9edab31728 Refactor app services and stabilize refresh/UI flows
- Add refresh scheduler and network refresh service boundaries for typed
  refresh results, ordered RPC collectors, applicators, and price parsing.
- Add daemon lifecycle and wallet security workflow helpers while preserving
  App-owned command RPC, decrypt, cancellation, and UI handoff behavior.
- Split balance, console, mining, amount formatting, and async task logic into
  focused modules with expanded Phase 4 test coverage.
- Fix market price loading by triggering price refresh immediately, avoiding
  queue-pressure drops, tracking loading/error state, and adding translations.
- Polish send, explorer, peers, settings, theme/schema, and related tab UI.
- Replace checked-in generated language headers with build-generated resources.
- Document the cleanup audit, UI static-state guidance, and architecture updates.
2026-04-29 12:47:57 -05:00

212 lines
7.2 KiB
C++

#include "mining_benchmark.h"
#include <algorithm>
#include <cmath>
namespace dragonx {
namespace ui {
void ThreadBenchmark::reset()
{
phase = Phase::Idle;
candidates.clear();
current_index = 0;
results.clear();
phase_timer = 0.0f;
prev_window_avg = 0.0;
window_sum = 0.0;
window_samples = 0;
window_timer = 0.0f;
consecutive_stable = 0;
measure_sum = 0.0;
measure_samples = 0;
optimal_threads = 0;
optimal_hashrate = 0.0;
was_pool_running = false;
prev_threads = 0;
total_warmup_secs = 0.0f;
}
void ThreadBenchmark::buildCandidates(int maxThreads)
{
candidates.clear();
int start = std::max(1, maxThreads / 2);
for (int threads = start; threads <= maxThreads; ++threads) {
candidates.push_back(threads);
}
}
float ThreadBenchmark::avgWarmupSecs() const
{
if (current_index > 0) {
return total_warmup_secs / static_cast<float>(current_index);
}
return (MIN_WARMUP_SECS + MAX_WARMUP_SECS) * 0.5f;
}
float ThreadBenchmark::perTestSecs() const
{
return avgWarmupSecs() + MEASURE_SECS;
}
float ThreadBenchmark::totalEstimatedSecs() const
{
int count = static_cast<int>(candidates.size());
if (count <= 0) return 0.0f;
float completedTime = total_warmup_secs
+ static_cast<float>(current_index) * (MEASURE_SECS + COOLDOWN_SECS);
int remaining = count - current_index;
float remainingTime = static_cast<float>(remaining) * (avgWarmupSecs() + MEASURE_SECS)
+ static_cast<float>(std::max(0, remaining - 1)) * COOLDOWN_SECS;
return completedTime + remainingTime;
}
float ThreadBenchmark::elapsedSecs() const
{
float completed = total_warmup_secs
+ static_cast<float>(current_index) * (MEASURE_SECS + COOLDOWN_SECS);
return completed + phase_timer;
}
float ThreadBenchmark::progress() const
{
float total = totalEstimatedSecs();
return (total > 0.0f) ? std::min(1.0f, elapsedSecs() / total) : 0.0f;
}
void ThreadBenchmark::resetStabilityTracking()
{
prev_window_avg = 0.0;
window_sum = 0.0;
window_samples = 0;
window_timer = 0.0f;
consecutive_stable = 0;
}
bool ThreadBenchmark::active() const
{
return phase != Phase::Idle && phase != Phase::Done;
}
ThreadBenchmarkUpdate AdvanceThreadBenchmark(ThreadBenchmark& benchmark,
float deltaSeconds,
double poolHashrate10s)
{
ThreadBenchmarkUpdate update;
if (!benchmark.active()) return update;
benchmark.phase_timer += deltaSeconds;
switch (benchmark.phase) {
case ThreadBenchmark::Phase::Starting:
if (benchmark.current_index < static_cast<int>(benchmark.candidates.size())) {
int threads = benchmark.candidates[benchmark.current_index];
update.stopPoolMining = true;
update.startPoolMining = true;
update.startThreads = threads;
benchmark.phase = ThreadBenchmark::Phase::WarmingUp;
benchmark.phase_timer = 0.0f;
benchmark.resetStabilityTracking();
benchmark.measure_sum = 0.0;
benchmark.measure_samples = 0;
} else {
benchmark.phase = ThreadBenchmark::Phase::Done;
}
break;
case ThreadBenchmark::Phase::WarmingUp: {
bool pastMin = benchmark.phase_timer >= ThreadBenchmark::MIN_WARMUP_SECS;
bool pastMax = benchmark.phase_timer >= ThreadBenchmark::MAX_WARMUP_SECS;
if (poolHashrate10s > 0.0) {
benchmark.window_sum += poolHashrate10s;
benchmark.window_samples++;
}
benchmark.window_timer += deltaSeconds;
bool stable = false;
if (pastMin && benchmark.window_timer >= ThreadBenchmark::STABILITY_WINDOW_SECS &&
benchmark.window_samples > 0) {
double currentAverage = benchmark.window_sum / benchmark.window_samples;
if (benchmark.prev_window_avg > 0.0) {
double change = std::abs(currentAverage - benchmark.prev_window_avg)
/ benchmark.prev_window_avg;
if (change < ThreadBenchmark::STABILITY_THRESHOLD)
benchmark.consecutive_stable++;
else
benchmark.consecutive_stable = 0;
if (benchmark.consecutive_stable >= ThreadBenchmark::STABLE_WINDOWS_NEEDED)
stable = true;
}
benchmark.prev_window_avg = currentAverage;
benchmark.window_sum = 0.0;
benchmark.window_samples = 0;
benchmark.window_timer = 0.0f;
}
if (stable || pastMax) {
benchmark.total_warmup_secs += benchmark.phase_timer;
benchmark.phase = ThreadBenchmark::Phase::Measuring;
benchmark.phase_timer = 0.0f;
benchmark.measure_sum = 0.0;
benchmark.measure_samples = 0;
}
break;
}
case ThreadBenchmark::Phase::Measuring:
if (poolHashrate10s > 0.0) {
benchmark.measure_sum += poolHashrate10s;
benchmark.measure_samples++;
}
if (benchmark.phase_timer >= ThreadBenchmark::MEASURE_SECS) {
int threads = benchmark.candidates[benchmark.current_index];
double average = (benchmark.measure_samples > 0)
? benchmark.measure_sum / benchmark.measure_samples
: 0.0;
benchmark.results.push_back({threads, average});
if (average > benchmark.optimal_hashrate) {
benchmark.optimal_hashrate = average;
benchmark.optimal_threads = threads;
}
benchmark.phase = ThreadBenchmark::Phase::Advancing;
benchmark.phase_timer = 0.0f;
}
break;
case ThreadBenchmark::Phase::Advancing:
update.stopPoolMining = true;
benchmark.current_index++;
if (benchmark.current_index < static_cast<int>(benchmark.candidates.size())) {
benchmark.phase = ThreadBenchmark::Phase::CoolingDown;
benchmark.phase_timer = 0.0f;
} else {
benchmark.phase = ThreadBenchmark::Phase::Done;
if (benchmark.optimal_threads > 0) {
update.saveOptimalThreads = true;
update.optimalThreads = benchmark.optimal_threads;
if (benchmark.was_pool_running) {
update.startPoolMining = true;
update.startThreads = benchmark.optimal_threads;
}
}
}
break;
case ThreadBenchmark::Phase::CoolingDown:
if (benchmark.phase_timer >= ThreadBenchmark::COOLDOWN_SECS) {
benchmark.phase = ThreadBenchmark::Phase::Starting;
benchmark.phase_timer = 0.0f;
}
break;
default:
break;
}
return update;
}
} // namespace ui
} // namespace dragonx