status: implement Benchmarks submenu

This commit is contained in:
hinto.janai 2023-03-17 16:12:06 -04:00
parent 4058aa0f8f
commit 7e29462f79
No known key found for this signature in database
GPG key ID: D47CE05FA175A499
12 changed files with 228 additions and 96 deletions

View file

@ -604,7 +604,7 @@ You need [`cargo`](https://www.rust-lang.org/learn/get-started), Rust's build to
The `--release` profile in Gupax is set to prefer code performance & small binary sizes over compilation speed (see [`Cargo.toml`](https://github.com/hinto-janaiyo/gupax/blob/main/Cargo.toml)). Gupax itself (with all dependencies already built) takes around 1m30s to build (vs 10s on a normal `--release`) with a Ryzen 5950x.
There are `38` unit tests throughout the codebase files, you should probably run:
There are `40` unit tests throughout the codebase files, you should probably run:
```
cargo test
```

View file

@ -18,7 +18,7 @@
## Structure
| File/Folder | Purpose |
|--------------|---------|
| benchmark.rs | Code for handling [XMRig's benchmark data](https://xmrig.com/docs/api/1/benchmark)
| cpu.json | [XMRig benchmark data in JSON](https://github.com/hinto-janaiyo/xmrig-benchmarks)
| constants.rs | General constants used in Gupax
| disk.rs | Code for writing to disk: `state.toml/node.toml/pool.toml`; This holds the structs for the [State] struct
| ferris.rs | Cute crab bytes

View file

@ -1,87 +0,0 @@
// Gupax - GUI Uniting P2Pool And XMRig
//
// Copyright (c) 2022-2023 hinto-janai
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
// This file contains backend code for handling XMRig's benchmark data:
// - HTTP(s) fetchs to [https://xmrig.com]
// - (De)serialization of JSON data
// - (De)serialization of CPU topology XML (./xmrig --export topology)
use serde::{Serialize, Deserialize};
use std::fmt::Write;
// Input: Full [&str] of XMRig's [topology.xml] file
// Output: The CPU name formatted so it's usable as the endpoint, e.g: [AMD+Ryzen+9+5950X+16-Core+Processor]
fn cpu_name_from_xml(xml: &str) -> Option<String> {
// A minimal matching struct for the [CPUModel] <info> field in the XML file
#[derive(Debug, Serialize, Deserialize, PartialEq)]
struct Info { // <info [...] />
name: String, // name="CPUModel"
value: String, // value="Ryzen ..."
}
// Regex to find matching field
let regex = regex::Regex::new("\"CPUModel\"").unwrap();
for line in xml.lines() {
if !regex.is_match(&line) { continue }
// If found, attempt to serialize XML proper
if let Ok(info) = serde_xml_rs::from_str::<Info>(&line) {
// Return early if empty
if info.value.is_empty() {
return None
}
// If serialized, turn whitespaces into '+'
let words: Vec<&str> = info.value.split_whitespace().collect();
let last_word = words.len();
let mut result = String::new();
let mut n = 1;
for word in words.iter() {
match n == last_word {
false => write!(result, "{}+", word),
true => write!(result, "{}", word),
};
n += 1;
}
return Some(result)
}
}
// If loop didn't return early, return none
None
}
//---------------------------------------------------------------------------------------------------- TESTS
#[cfg(test)]
mod test {
#[test]
fn get_cpu_from_xml() {
let string =
r#"<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE topology SYSTEM "hwloc2.dtd">
<topology version="2.0">
<object type="Machine" os_index="0" cpuset="0xffffffff" complete_cpuset="0xffffffff" allowed_cpuset="0xffffffff" nodeset="0x00000001" complete_nodeset="0x00000001" allowed_nodeset="0x00000001" gp_index="1">
<info name="DMIBIOSVendor" value="American Megatrends International, LLC."/>
<info name="Backend" value="Linux"/>
<info name="LinuxCgroup" value="/"/>
<info name="OSName" value="Linux"/>
<info name="CPUModel" value="AMD Ryzen 9 5950X 16-Core Processor "/>
<info name="CPUStepping" value="0"/>
"#;
assert_eq!(crate::benchmark::cpu_name_from_xml(&string).unwrap(), "AMD+Ryzen+9+5950X+16-Core+Processor");
}
}

View file

@ -174,6 +174,7 @@ pub const STATUS_XMRIG_THREADS: &str = "The amount of threads XMRig is curre
// Status Submenus
pub const STATUS_SUBMENU_PROCESSES: &str = "View the status of process related data for [Gupax|P2Pool|XMRig]";
pub const STATUS_SUBMENU_P2POOL: &str = "View P2Pool specific data";
pub const STATUS_SUBMENU_HASHRATE: &str = "Compare your CPU hashrate with others";
//-- P2Pool
pub const STATUS_SUBMENU_PAYOUT: &str = "The total amount of payouts received via P2Pool across all time. This includes all payouts you have ever received using Gupax and P2Pool.";
pub const STATUS_SUBMENU_XMR: &str = "The total of XMR mined via P2Pool across all time. This includes all the XMR you have ever mined using Gupax and P2Pool.";
@ -200,6 +201,21 @@ pub const STATUS_SUBMENU_P2POOL_DOMINANCE: &str = "The percent of hashrate
pub const STATUS_SUBMENU_YOUR_P2POOL_DOMINANCE: &str = "The percent of hashrate you account for in P2Pool";
pub const STATUS_SUBMENU_YOUR_MONERO_DOMINANCE: &str = "The percent of hashrate you account for in the entire Monero network";
pub const STATUS_SUBMENU_PROGRESS_BAR: &str = "The next time Gupax will update P2Pool stats. Each [*] is 900ms (updates roughly every 54 seconds)";
//-- Benchmarks
pub const STATUS_SUBMENU_YOUR_CPU: &str = "The CPU detected by Gupax";
pub const STATUS_SUBMENU_YOUR_BENCHMARKS: &str = "How many benchmarks your CPU has had uploaded to [https://xmrig.com/benchmark] ";
pub const STATUS_SUBMENU_YOUR_RANK: &str = "Your CPU's rank out of all CPUs listed on [https://xmrig.com/benchmark] (higher is better)";
pub const STATUS_SUBMENU_YOUR_HIGH: &str = "The highest hashrate recorded for your CPU on [https://xmrig.com/benchmark]";
pub const STATUS_SUBMENU_YOUR_AVERAGE: &str = "The average hashrate of your CPU based off the data at [https://xmrig.com/benchmark]";
pub const STATUS_SUBMENU_YOUR_LOW: &str = "The lowest hashrate recorded for your CPU on [https://xmrig.com/benchmark]";
pub const STATUS_SUBMENU_OTHER_CPUS: &str = "A list of ALL the recorded CPU benchmarks. The CPUs most similar to yours are listed first. All this data is taken from [https://github.com/hinto-janai/xmrig-benchmarks] which itself takes from [https://xmrig.com/benchmark].";
pub const STATUS_SUBMENU_OTHER_CPU: &str = "The CPU name";
pub const STATUS_SUBMENU_OTHER_RELATIVE: &str = "The relative hashrate power compared to the fastest recorded CPU, which is current: [AMD EPYC 7T83 64-Core Processor]";
pub const STATUS_SUBMENU_OTHER_HIGH: &str = "Highest hashrate record";
pub const STATUS_SUBMENU_OTHER_AVERAGE: &str = "Average hashrate";
pub const STATUS_SUBMENU_OTHER_LOW: &str = "Lowest hashrate record";
pub const STATUS_SUBMENU_OTHER_RANK: &str = "The rank of this CPU out of [1567] (lower is better)";
pub const STATUS_SUBMENU_OTHER_BENCHMARKS: &str = "How many benchmarks this CPU has had posted to [https://xmrig.com/benchmark]";
// Gupax
pub const GUPAX_UPDATE: &str = "Check for updates on Gupax, P2Pool, and XMRig via GitHub's API and upgrade automatically";

View file

@ -825,6 +825,7 @@ pub enum File {
pub enum Submenu {
Processes,
P2pool,
Benchmarks,
}
impl Default for Submenu {

View file

@ -82,6 +82,7 @@ pub enum Ratio {
//---------------------------------------------------------------------------------------------------- Gupax
impl crate::disk::Gupax {
#[inline(always)]
pub fn show(&mut self, og: &Arc<Mutex<State>>, state_path: &Path, update: &Arc<Mutex<Update>>, file_window: &Arc<Mutex<FileWindow>>, error_state: &mut ErrorState, restart: &Arc<Mutex<Restart>>, width: f32, height: f32, frame: &mut eframe::Frame, _ctx: &egui::Context, ui: &mut egui::Ui) {
// Update button + Progress bar
debug!("Gupax Tab | Rendering [Update] button + progress bar");

View file

@ -1731,6 +1731,8 @@ pub struct PubXmrigApi {
pub diff: HumanNumber,
pub accepted: HumanNumber,
pub rejected: HumanNumber,
pub hashrate_raw: f32,
}
impl Default for PubXmrigApi {
@ -1750,6 +1752,7 @@ impl PubXmrigApi {
diff: HumanNumber::unknown(),
accepted: HumanNumber::unknown(),
rejected: HumanNumber::unknown(),
hashrate_raw: 0.0,
}
}
@ -1780,6 +1783,11 @@ impl PubXmrigApi {
// Formats raw private data into ready-to-print human readable version.
fn update_from_priv(public: &Arc<Mutex<Self>>, private: PrivXmrigApi) {
let mut public = lock!(public);
let hashrate_raw = match private.hashrate.total.get(0) {
Some(Some(h)) => *h,
_ => 0.0,
};
*public = Self {
worker_id: private.worker_id,
resources: HumanNumber::from_load(private.resources.load_average),
@ -1787,6 +1795,7 @@ impl PubXmrigApi {
diff: HumanNumber::from_u128(private.connection.diff),
accepted: HumanNumber::from_u128(private.connection.accepted),
rejected: HumanNumber::from_u128(private.connection.rejected),
hashrate_raw,
..std::mem::take(&mut *public)
}
}

View file

@ -116,6 +116,9 @@ impl HumanNumber {
pub fn from_str(s: &str) -> Self {
Self(s.to_string())
}
pub fn to_hashrate(f: f32) -> Self {
Self(format!("{} H/s", Self::from_f32(f)))
}
pub fn to_percent(f: f32) -> Self {
if f < 0.01 {
Self("0%".to_string())

View file

@ -51,6 +51,7 @@ use std::{
};
// Sysinfo
use sysinfo::SystemExt;
use sysinfo::CpuExt;
// Modules
//mod benchmark;
mod ferris;
@ -140,6 +141,7 @@ pub struct App {
// actual stats, and all the functions needed to mutate them.
gupax_p2pool_api: Arc<Mutex<GupaxP2poolApi>>,
// Static stuff
benchmarks: Vec<Benchmark>, // XMRig CPU benchmarks
pid: sysinfo::Pid, // Gupax's PID
max_threads: usize, // Max amount of detected system threads
now: Instant, // Internal timer
@ -199,6 +201,18 @@ impl App {
};
let pub_sys = arc_mut!(Sys::new());
// CPU Benchmark data initialization.
info!("App Init | Initializing CPU benchmarks...");
let benchmarks: Vec<Benchmark> = {
let cpu = sysinfo.cpus()[0].brand();
let mut json: Vec<Benchmark> = serde_json::from_slice(include_bytes!("cpu.json")).unwrap();
json.sort_by(|a, b| {
cmp_f64(strsim::jaro(&b.cpu, &cpu), strsim::jaro(&a.cpu, &cpu))
});
json
};
info!("App Init | Assuming user's CPU is: {}", benchmarks[0].cpu);
info!("App Init | The rest of the [App]...");
let mut app = Self {
tab: Tab::default(),
@ -232,6 +246,7 @@ impl App {
no_startup: false,
gupax_p2pool_api: arc_mut!(GupaxP2poolApi::new()),
pub_sys,
benchmarks,
pid,
max_threads: num_cpus::get(),
now,
@ -507,6 +522,18 @@ impl Default for Tab {
}
}
//---------------------------------------------------------------------------------------------------- CPU Benchmarks.
#[derive(Debug,Serialize,Deserialize)]
pub struct Benchmark {
pub cpu: String,
pub rank: u16,
pub percent: f32,
pub benchmarks: u16,
pub average: f32,
pub high: f32,
pub low: f32,
}
//---------------------------------------------------------------------------------------------------- [Restart] Enum
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Restart {
@ -688,6 +715,7 @@ impl KeyPressed {
}
//---------------------------------------------------------------------------------------------------- Init functions
#[inline(always)]
fn init_text_styles(ctx: &egui::Context, width: f32) {
let scale = width / 30.0;
let mut style = (*ctx.style()).clone();
@ -711,6 +739,7 @@ fn init_text_styles(ctx: &egui::Context, width: f32) {
ctx.request_repaint();
}
#[inline(always)]
fn init_logger(now: Instant) {
use env_logger::fmt::Color;
let filter_env = std::env::var("RUST_LOG").unwrap_or_else(|_| "INFO".to_string());
@ -746,6 +775,7 @@ fn init_logger(now: Instant) {
info!("Log level ... {}", filter);
}
#[inline(always)]
fn init_options(initial_window_size: Option<Vec2>) -> NativeOptions {
let mut options = eframe::NativeOptions::default();
options.min_window_size = Some(Vec2::new(APP_MIN_WIDTH, APP_MIN_HEIGHT));
@ -764,6 +794,7 @@ fn init_options(initial_window_size: Option<Vec2>) -> NativeOptions {
options
}
#[inline(always)]
fn init_auto(app: &mut App) {
// Return early if [--no-startup] was not passed
if app.no_startup {
@ -831,6 +862,7 @@ fn reset_state(path: &PathBuf) -> Result<(), TomlError> {
}
}
#[inline(always)]
fn reset_nodes(path: &PathBuf) -> Result<(), TomlError> {
match Node::create_new(path) {
Ok(_) => { info!("Resetting [node.toml] ... OK"); Ok(()) },
@ -838,6 +870,7 @@ fn reset_nodes(path: &PathBuf) -> Result<(), TomlError> {
}
}
#[inline(always)]
fn reset_pools(path: &PathBuf) -> Result<(), TomlError> {
match Pool::create_new(path) {
Ok(_) => { info!("Resetting [pool.toml] ... OK"); Ok(()) },
@ -845,6 +878,7 @@ fn reset_pools(path: &PathBuf) -> Result<(), TomlError> {
}
}
#[inline(always)]
fn reset_gupax_p2pool_api(path: &PathBuf) -> Result<(), TomlError> {
match GupaxP2poolApi::create_new(path) {
Ok(_) => { info!("Resetting GupaxP2poolApi ... OK"); Ok(()) },
@ -852,6 +886,7 @@ fn reset_gupax_p2pool_api(path: &PathBuf) -> Result<(), TomlError> {
}
}
#[inline(always)]
fn reset(path: &PathBuf, state: &PathBuf, node: &PathBuf, pool: &PathBuf, gupax_p2pool_api: &PathBuf) {
let mut code = 0;
// Attempt to remove directory first
@ -888,6 +923,7 @@ fn reset(path: &PathBuf, state: &PathBuf, node: &PathBuf, pool: &PathBuf, gupax_
}
//---------------------------------------------------------------------------------------------------- Misc functions
#[inline(always)]
fn parse_args<S: Into<String>>(mut app: App, panic: S) -> App {
info!("Parsing CLI arguments...");
let mut args: Vec<String> = env::args().collect();
@ -930,6 +966,7 @@ fn parse_args<S: Into<String>>(mut app: App, panic: S) -> App {
}
// Get absolute [Gupax] binary path
#[inline(always)]
pub fn get_exe() -> Result<String, std::io::Error> {
match std::env::current_exe() {
Ok(path) => { Ok(path.display().to_string()) },
@ -938,6 +975,7 @@ pub fn get_exe() -> Result<String, std::io::Error> {
}
// Get absolute [Gupax] directory path
#[inline(always)]
pub fn get_exe_dir() -> Result<String, std::io::Error> {
match std::env::current_exe() {
Ok(mut path) => { path.pop(); Ok(path.display().to_string()) },
@ -947,6 +985,7 @@ pub fn get_exe_dir() -> Result<String, std::io::Error> {
// Clean any [gupax_update_.*] directories
// The trailing random bits must be exactly 10 alphanumeric characters
#[inline(always)]
pub fn clean_dir() -> Result<(), anyhow::Error> {
let regex = Regex::new("^gupax_update_[A-Za-z0-9]{10}$").unwrap();
for entry in std::fs::read_dir(get_exe_dir()?)? {
@ -964,6 +1003,7 @@ pub fn clean_dir() -> Result<(), anyhow::Error> {
}
// Print disk files to console
#[inline(always)]
fn print_disk_file(path: &PathBuf) {
match std::fs::read_to_string(path) {
Ok(string) => { print!("{}", string); exit(0); },
@ -972,6 +1012,7 @@ fn print_disk_file(path: &PathBuf) {
}
// Prints the GupaxP2PoolApi files.
#[inline(always)]
fn print_gupax_p2pool_api(gupax_p2pool_api: &Arc<Mutex<GupaxP2poolApi>>) {
let api = lock!(gupax_p2pool_api);
let log = match std::fs::read_to_string(&api.path_log) {
@ -994,6 +1035,16 @@ fn print_gupax_p2pool_api(gupax_p2pool_api: &Arc<Mutex<GupaxP2poolApi>>) {
exit(0);
}
#[inline(always)]
fn cmp_f64(a: f64, b: f64) -> std::cmp::Ordering {
match (a <= b, a >= b) {
(false, true) => std::cmp::Ordering::Greater,
(true, false) => std::cmp::Ordering::Less,
(true, true) => std::cmp::Ordering::Equal,
_ => std::cmp::Ordering::Less,
}
}
//---------------------------------------------------------------------------------------------------- Main [App] frame
fn main() {
let now = Instant::now();
@ -1018,6 +1069,7 @@ fn main() {
}
impl eframe::App for App {
#[inline(always)]
fn on_close_event(&mut self) -> bool {
if self.state.gupax.ask_before_quit {
// If we're already on the [ask_before_quit] screen and
@ -1037,6 +1089,7 @@ impl eframe::App for App {
}
}
#[inline(always)]
fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) {
// *-------*
// | DEBUG |
@ -1104,8 +1157,9 @@ impl eframe::App for App {
match self.tab {
Tab::Status => {
match self.state.status.submenu {
Submenu::Processes => self.state.status.submenu = Submenu::P2pool,
Submenu::Processes => self.state.status.submenu = Submenu::Benchmarks,
Submenu::P2pool => self.state.status.submenu = Submenu::Processes,
Submenu::Benchmarks => self.state.status.submenu = Submenu::P2pool,
}
},
Tab::Gupax => flip!(self.state.gupax.simple),
@ -1119,7 +1173,8 @@ impl eframe::App for App {
Tab::Status => {
match self.state.status.submenu {
Submenu::Processes => self.state.status.submenu = Submenu::P2pool,
Submenu::P2pool => self.state.status.submenu = Submenu::Processes,
Submenu::P2pool => self.state.status.submenu = Submenu::Benchmarks,
Submenu::Benchmarks => self.state.status.submenu = Submenu::Processes,
}
},
Tab::Gupax => flip!(self.state.gupax.simple),
@ -1517,7 +1572,11 @@ impl eframe::App for App {
match self.tab {
Tab::Status => {
ui.group(|ui| {
let width = (ui.available_width() / 2.0)-10.5;
let width = (ui.available_width() / 3.0)-14.0;
if ui.add_sized([width, height], SelectableLabel::new(self.state.status.submenu == Submenu::Benchmarks, "Benchmarks")).on_hover_text(STATUS_SUBMENU_HASHRATE).clicked() {
self.state.status.submenu = Submenu::Benchmarks;
}
ui.separator();
if ui.add_sized([width, height], SelectableLabel::new(self.state.status.submenu == Submenu::P2pool, "P2Pool")).on_hover_text(STATUS_SUBMENU_P2POOL).clicked() {
self.state.status.submenu = Submenu::P2pool;
}
@ -1800,7 +1859,7 @@ path_xmr: {:#?}\n
}
Tab::Status => {
debug!("App | Entering [Status] Tab");
crate::disk::Status::show(&mut self.state.status, &self.pub_sys, &self.p2pool_api, &self.xmrig_api, &self.p2pool_img, &self.xmrig_img, p2pool_is_alive, xmrig_is_alive, self.max_threads, &self.gupax_p2pool_api, self.width, self.height, ctx, ui);
crate::disk::Status::show(&mut self.state.status, &self.pub_sys, &self.p2pool_api, &self.xmrig_api, &self.p2pool_img, &self.xmrig_img, p2pool_is_alive, xmrig_is_alive, self.max_threads, &self.gupax_p2pool_api, &self.benchmarks, self.width, self.height, ctx, ui);
}
Tab::Gupax => {
debug!("App | Entering [Gupax] Tab");
@ -1840,4 +1899,21 @@ mod test {
assert!(!Regex::is_match(&r.port, "0"));
assert!(!Regex::is_match(&r.port, "65536"));
}
#[test]
fn detect_benchmark_cpu() {
use super::{Benchmark,cmp_f64};
let cpu = "AMD Ryzen 9 5950X 16-Core Processor";
let benchmarks: Vec<Benchmark> = {
let mut json: Vec<Benchmark> = serde_json::from_slice(include_bytes!("cpu.json")).unwrap();
json.sort_by(|a, b| {
cmp_f64(strsim::jaro(&b.cpu, &cpu), strsim::jaro(&a.cpu, &cpu))
});
json
};
assert!(benchmarks[0].cpu == "AMD Ryzen 9 5950X 16-Core Processor");
}
}

View file

@ -33,6 +33,7 @@ use regex::Regex;
use log::*;
impl crate::disk::P2pool {
#[inline(always)]
pub fn show(&mut self, node_vec: &mut Vec<(String, Node)>, _og: &Arc<Mutex<State>>, ping: &Arc<Mutex<Ping>>, regex: &Regexes, process: &Arc<Mutex<Process>>, api: &Arc<Mutex<PubP2poolApi>>, buffer: &mut String, width: f32, height: f32, _ctx: &egui::Context, ui: &mut egui::Ui) {
let text_edit = height / 25.0;
//---------------------------------------------------------------------------------------------------- [Simple] Console

View file

@ -28,6 +28,7 @@ use crate::{
GupaxP2poolApi,
PayoutView,
human::HumanNumber,
Benchmark,
};
use std::sync::{Arc,Mutex};
use log::*;
@ -36,12 +37,13 @@ use egui::{
TextStyle::Monospace,
TextStyle::Name,
TextEdit,
SelectableLabel,
Slider,
SelectableLabel,Hyperlink,
Slider,ProgressBar,Spinner,
};
impl crate::disk::Status {
pub fn show(&mut self, sys: &Arc<Mutex<Sys>>, p2pool_api: &Arc<Mutex<PubP2poolApi>>, xmrig_api: &Arc<Mutex<PubXmrigApi>>, p2pool_img: &Arc<Mutex<ImgP2pool>>, xmrig_img: &Arc<Mutex<ImgXmrig>>, p2pool_alive: bool, xmrig_alive: bool, max_threads: usize, gupax_p2pool_api: &Arc<Mutex<GupaxP2poolApi>>, width: f32, height: f32, _ctx: &egui::Context, ui: &mut egui::Ui) {
#[inline(always)]
pub fn show(&mut self, sys: &Arc<Mutex<Sys>>, p2pool_api: &Arc<Mutex<PubP2poolApi>>, xmrig_api: &Arc<Mutex<PubXmrigApi>>, p2pool_img: &Arc<Mutex<ImgP2pool>>, xmrig_img: &Arc<Mutex<ImgXmrig>>, p2pool_alive: bool, xmrig_alive: bool, max_threads: usize, gupax_p2pool_api: &Arc<Mutex<GupaxP2poolApi>>, benchmarks: &[Benchmark], width: f32, height: f32, _ctx: &egui::Context, ui: &mut egui::Ui) {
//---------------------------------------------------------------------------------------------------- [Processes]
if self.submenu == Submenu::Processes {
let width = (width/3.0)-(SPACE*1.666);
@ -268,6 +270,115 @@ pub fn show(&mut self, sys: &Arc<Mutex<Sys>>, p2pool_api: &Arc<Mutex<PubP2poolAp
// Tick bar
ui.add_sized([ui.available_width(), text], Label::new(api.calculate_tick_bar())).on_hover_text(STATUS_SUBMENU_PROGRESS_BAR);
drop(api);
//---------------------------------------------------------------------------------------------------- [Benchmarks]
} else if self.submenu == Submenu::Benchmarks {
debug!("Status Tab | Rendering [Benchmarks]");
let text = height / 20.0;
let double = text * 2.0;
let log = height / 3.0;
ui.style_mut().override_text_style = Some(Monospace);
// [0], The user's CPU (most likely).
let cpu = &benchmarks[0];
ui.horizontal(|ui| {
let width = (width/2.0)-(SPACE*1.666);
let min_height = log;
ui.group(|ui| { ui.vertical(|ui| {
ui.set_min_height(min_height);
ui.add_sized([width, text], Label::new(RichText::new("Your CPU").underline().color(BONE))).on_hover_text(STATUS_SUBMENU_YOUR_CPU);
ui.add_sized([width, text], Label::new(cpu.cpu.as_str()));
ui.add_sized([width, text], Label::new(RichText::new("Total Benchmarks").underline().color(BONE))).on_hover_text(STATUS_SUBMENU_YOUR_BENCHMARKS);
ui.add_sized([width, text], Label::new(format!("{}", cpu.benchmarks)));
ui.add_sized([width, text], Label::new(RichText::new("Rank").underline().color(BONE))).on_hover_text(STATUS_SUBMENU_YOUR_RANK);
ui.add_sized([width, text], Label::new(format!("{}/{}", cpu.rank, &benchmarks.len())));
})});
ui.group(|ui| { ui.vertical(|ui| {
ui.set_min_height(min_height);
ui.add_sized([width, text], Label::new(RichText::new("High Hashrate").underline().color(BONE))).on_hover_text(STATUS_SUBMENU_YOUR_HIGH);
ui.add_sized([width, text], Label::new(format!("{} H/s", HumanNumber::from_f32(cpu.high))));
ui.add_sized([width, text], Label::new(RichText::new("Average Hashrate").underline().color(BONE))).on_hover_text(STATUS_SUBMENU_YOUR_AVERAGE);
ui.add_sized([width, text], Label::new(format!("{} H/s", HumanNumber::from_f32(cpu.average))));
ui.add_sized([width, text], Label::new(RichText::new("Low Hashrate").underline().color(BONE))).on_hover_text(STATUS_SUBMENU_YOUR_LOW);
ui.add_sized([width, text], Label::new(format!("{} H/s", HumanNumber::from_f32(cpu.low))));
})})
});
// User's CPU hashrate comparison (if XMRig is alive).
ui.scope(|ui| {
if xmrig_alive {
let api = lock!(xmrig_api);
let percent = (api.hashrate_raw / cpu.high) * 100.0;
let human = HumanNumber::to_percent(percent);
if percent > 100.0 {
ui.add_sized([width, double], Label::new(format!("Your CPU's is faster than the highest benchmark! It is [{}] faster @ {}!", human, api.hashrate)));
ui.add_sized([width, text], ProgressBar::new(1.0));
} else if api.hashrate_raw == 0.0 {
ui.add_sized([width, text], Label::new("Measuring hashrate..."));
ui.add_sized([width, text], Spinner::new().size(text));
ui.add_sized([width, text], ProgressBar::new(0.0));
} else {
ui.add_sized([width, double], Label::new(format!("Your CPU's hashrate is [{}] of the highest benchmark @ {}", human, api.hashrate)));
ui.add_sized([width, text], ProgressBar::new(percent / 100.0));
}
} else {
ui.set_enabled(xmrig_alive);
ui.add_sized([width, double], Label::new("XMRig is offline. Hashrate cannot be determined."));
ui.add_sized([width, text], ProgressBar::new(0.0));
}
});
// Comparison
ui.group(|ui| {
ui.add_sized([width, text], Hyperlink::from_label_and_url("Other CPUs", "https://github.com/hinto-janai/xmrig-benchmarks")).on_hover_text(STATUS_SUBMENU_OTHER_CPUS);
});
egui::ScrollArea::both().max_width(f32::INFINITY).max_height(height).auto_shrink([false; 2]).show_viewport(ui, |ui, _| {
let width = width / 20.0;
let (cpu, bar, high, average, low, rank, bench) = (
width*10.0,
width*3.0,
width*2.0,
width*2.0,
width*2.0,
width,
width*2.0,
);
ui.group(|ui| {
ui.horizontal(|ui| {
ui.add_sized([cpu, double], Label::new("CPU")).on_hover_text(STATUS_SUBMENU_OTHER_CPU);
ui.separator();
ui.add_sized([bar, double], Label::new("Relative")).on_hover_text(STATUS_SUBMENU_OTHER_RELATIVE);
ui.separator();
ui.add_sized([high, double], Label::new("High")).on_hover_text(STATUS_SUBMENU_OTHER_HIGH);
ui.separator();
ui.add_sized([average, double], Label::new("Average")).on_hover_text(STATUS_SUBMENU_OTHER_AVERAGE);
ui.separator();
ui.add_sized([low, double], Label::new("Low")).on_hover_text(STATUS_SUBMENU_OTHER_LOW);
ui.separator();
ui.add_sized([rank, double], Label::new("Rank")).on_hover_text(STATUS_SUBMENU_OTHER_RANK);
ui.separator();
ui.add_sized([bench, double], Label::new("Benchmarks")).on_hover_text(STATUS_SUBMENU_OTHER_BENCHMARKS);
});
});
for benchmark in benchmarks[1..].iter() {
ui.group(|ui| { ui.horizontal(|ui| {
ui.add_sized([cpu, text], Label::new(benchmark.cpu.as_str()));
ui.separator();
ui.add_sized([bar, text], ProgressBar::new(benchmark.percent / 100.0));
ui.separator();
ui.add_sized([high, text], Label::new(HumanNumber::to_hashrate(benchmark.high).as_str()));
ui.separator();
ui.add_sized([average, text], Label::new(HumanNumber::to_hashrate(benchmark.average).as_str()));
ui.separator();
ui.add_sized([low, text], Label::new(HumanNumber::to_hashrate(benchmark.low).as_str()));
ui.separator();
ui.add_sized([rank, text], Label::new(HumanNumber::from_u16(benchmark.rank).as_str()));
ui.separator();
ui.add_sized([bench, text], Label::new(HumanNumber::from_u16(benchmark.benchmarks).as_str()));
})});
}
});
}
}
}

View file

@ -34,6 +34,7 @@ use regex::Regex;
use log::*;
impl crate::disk::Xmrig {
#[inline(always)]
pub fn show(&mut self, pool_vec: &mut Vec<(String, Pool)>, regex: &Regexes, process: &Arc<Mutex<Process>>, api: &Arc<Mutex<PubXmrigApi>>, buffer: &mut String, width: f32, height: f32, _ctx: &egui::Context, ui: &mut egui::Ui) {
let text_edit = height / 25.0;
//---------------------------------------------------------------------------------------------------- [Simple] Console