mirror of
https://github.com/Cyrix126/gupaxx.git
synced 2024-12-22 22:59:27 +00:00
status: implement Benchmarks
submenu
This commit is contained in:
parent
4058aa0f8f
commit
7e29462f79
12 changed files with 228 additions and 96 deletions
|
@ -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
|
||||
```
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
}
|
|
@ -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";
|
||||
|
|
|
@ -825,6 +825,7 @@ pub enum File {
|
|||
pub enum Submenu {
|
||||
Processes,
|
||||
P2pool,
|
||||
Benchmarks,
|
||||
}
|
||||
|
||||
impl Default for Submenu {
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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())
|
||||
|
|
84
src/main.rs
84
src/main.rs
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
117
src/status.rs
117
src/status.rs
|
@ -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()));
|
||||
})});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue