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.
This commit is contained in:
211
src/ui/windows/mining_benchmark.cpp
Normal file
211
src/ui/windows/mining_benchmark.cpp
Normal file
@@ -0,0 +1,211 @@
|
||||
#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
|
||||
Reference in New Issue
Block a user