#include #include #include #include #include #include #include #include #include extern "C" { #include #include #include "bench.h" #include "cpu_stress.h" #include "gpu_bw.h" #include "gpu_stress.h" #include "hoc_clk.h" #include "mt_cpu.h" #include "mt_gpu.h" #include "run_furmark.h" } static std::string fstr(const char *f, double v) { char b[64]; std::snprintf(b, sizeof(b), f, v); return b; } static std::string fstru(const char *f, unsigned long long v) { char b[64]; std::snprintf(b, sizeof(b), f, v); return b; } static brls::Label *makeRow(brls::Box *parent, const std::string &name) { auto *row = new brls::Box(brls::Axis::ROW); row->setMarginBottom(8.0f); auto *n = new brls::Label(); n->setText(name); n->setGrow(1.0f); auto *v = new brls::Label(); v->setText("-"); row->addView(n); row->addView(v); parent->addView(row); return v; } struct StatCells { brls::Label *load = nullptr, *clock = nullptr, *volt = nullptr, *vddq = nullptr, *temp = nullptr; }; static brls::Label *statCell(brls::Box *row, float fs) { auto *l = new brls::Label(); if (fs > 0.0f) l->setFontSize(fs); row->addView(l); return l; } static void statSep(brls::Box *row, float fs) { auto *s = new brls::Label(); s->setText("|"); if (fs > 0.0f) s->setFontSize(fs); s->setTextColor(nvgRGB(120, 120, 120)); s->setMarginLeft(7.0f); s->setMarginRight(7.0f); row->addView(s); } static void fmtLoad(brls::Label *l, unsigned val, bool isRam) { char b[32]; if (isRam) std::snprintf(b, sizeof b, "%u.%u GB/s", val / 1000u, (val % 1000u) / 100u); else std::snprintf(b, sizeof b, "%u%%", val); l->setText(b); } static void fmtClock1(brls::Label *l, uint32_t hz) { char b[32]; std::snprintf(b, sizeof b, "%u.%u MHz", hz / 1000000u, (hz / 100000u) % 10u); l->setText(b); } static void fmtVolt(brls::Label *l, uint32_t uv) { char b[32]; std::snprintf(b, sizeof b, "%u mV", uv / 1000u); l->setText(b); } static void fmtTemp(brls::Label *l, int32_t mc) { char b[32]; std::snprintf(b, sizeof b, "%d°C", mc / 1000); l->setText(b); } class SysInfoTab : public brls::Box { public: SysInfoTab() { this->setAxis(brls::Axis::COLUMN); this->setGrow(1.0f); this->setPadding(40.0f, 60.0f, 40.0f, 60.0f); auto *clk = new brls::Header(); clk->setTitle("Clocks"); this->addView(clk); cpuR = makeCompRow(this, "CPU"); gpuR = makeCompRow(this, "GPU"); ramR = makeRamRow(this); auto *sys = new brls::Header(); sys->setTitle("System"); this->addView(sys); mode = makeRow(this, "Mode"); threads = makeRow(this, "Threads"); hocclk_init(); refresh(); } void frame(brls::FrameContext *ctx) override { if (++tick >= 15) { tick = 0; refresh(); } brls::Box::frame(ctx); } private: static StatCells makeCompRow(brls::Box *parent, const char *name) { auto *row = new brls::Box(brls::Axis::ROW); row->setMarginBottom(10.0f); auto *n = new brls::Label(); n->setText(name); n->setGrow(1.0f); row->addView(n); StatCells c; c.load = statCell(row, 0); statSep(row, 0); c.clock = statCell(row, 0); statSep(row, 0); c.volt = statCell(row, 0); statSep(row, 0); c.temp = statCell(row, 0); parent->addView(row); return c; } static StatCells makeRamRow(brls::Box *parent) { auto *row = new brls::Box(brls::Axis::ROW); row->setMarginBottom(10.0f); auto *n = new brls::Label(); n->setText("RAM"); n->setGrow(1.0f); row->addView(n); StatCells c; c.load = statCell(row, 0); statSep(row, 0); c.clock = statCell(row, 0); statSep(row, 0); c.volt = statCell(row, 0); statSep(row, 0); c.vddq = statCell(row, 0); statSep(row, 0); c.temp = statCell(row, 0); parent->addView(row); return c; } void setRow(StatCells &r, unsigned loadOrBw, bool isRam, uint32_t hz, uint32_t uv, int32_t mc) { fmtLoad(r.load, loadOrBw, isRam); fmtClock1(r.clock, hz); fmtVolt(r.volt, uv); fmtTemp(r.temp, mc); } void naRow(StatCells &r) { r.load->setText("N/A"); r.clock->setText("-"); r.volt->setText("-"); r.temp->setText("-"); } void refresh() { sysinfo_t s; bench_get_sysinfo(&s); mode->setText(s.is_4gb ? "Application" : "Applet"); threads->setText(fstru("%llu", (unsigned long long)s.threads)); HocClkContext c; if (hocclk_get(&c)) { setRow(cpuR, c.stable.partLoad[3] / 10, false, c.stable.freqs[0], c.stable.voltages[2], c.stable.temps[5]); setRow(gpuR, c.stable.partLoad[2] / 10, false, c.stable.freqs[1], c.stable.voltages[3], c.stable.temps[6]); setRow(ramR, c.stable.partLoad[6], true, c.stable.freqs[2], c.stable.voltages[1], c.stable.temps[7]); fmtVolt(ramR.vddq, c.stable.voltages[4]); } else { naRow(cpuR); naRow(gpuR); naRow(ramR); ramR.vddq->setText("-"); } } StatCells cpuR, gpuR, ramR; brls::Label *mode, *threads; int tick = 0; }; class BenchTab : public brls::Box { public: BenchTab() { this->setAxis(brls::Axis::COLUMN); this->setGrow(1.0f); this->setPadding(40.0f, 60.0f, 40.0f, 60.0f); runBtn = new brls::Button(); runBtn->setText("Run"); runBtn->registerClickAction([this](brls::View *) { start(); return true; }); this->addView(runBtn); status = new brls::Label(); status->setText("Idle"); status->setMarginTop(8.0f); status->setMarginBottom(6.0f); this->addView(status); bar = new brls::Box(brls::Axis::ROW); bar->setHeight(18.0f); bar->setWidthPercentage(100.0f); bar->setMarginBottom(14.0f); barFill = new brls::Rectangle(); barFill->setColor(nvgRGB(0, 193, 210)); barFill->setWidthPercentage(0.0f); barTrack = new brls::Rectangle(); barTrack->setColor(nvgRGB(48, 48, 54)); barTrack->setGrow(1.0f); bar->addView(barFill); bar->addView(barTrack); this->addView(bar); auto *h1 = new brls::Header(); h1->setTitle("GPU bandwidth"); this->addView(h1); gpuCopy = makeRow(this, "GPU Copy"); gpuRead = makeRow(this, "GPU Read"); gpuWrite = makeRow(this, "GPU Write"); auto *h2 = new brls::Header(); h2->setTitle("CPU bandwidth"); this->addView(h2); cpuCopy = makeRow(this, "CPU Copy"); cpuRead = makeRow(this, "CPU Read"); cpuWrite = makeRow(this, "CPU Write"); auto *h3 = new brls::Header(); h3->setTitle("RAM latency"); this->addView(h3); l2 = makeRow(this, "L2"); ram = makeRow(this, "Full RAM"); } ~BenchTab() override { if (ctx) bench_end(ctx); } void frame(brls::FrameContext *fc) override { if (running) { if (primed) { primed = false; } else { const char *label = ""; float frac = 0.0f; bool more = bench_step(ctx, &res, &label, &frac); setProgress(frac); if (more) { status->setText(fstr("%.0f%%", frac * 100.0f) + " " + label); primed = true; } else { showResults(); bench_end(ctx); ctx = nullptr; running = false; status->setText("Done"); appletSetAutoSleepDisabled(false); } } } brls::Box::frame(fc); } private: void setProgress(float f) { barFill->setWidthPercentage(f * 100.0f); } void showResults() { gpuCopy->setText(fstr("%.1f MB/s", res.gpu_copy)); gpuRead->setText(fstr("%.1f MB/s", res.gpu_read)); gpuWrite->setText(fstr("%.1f MB/s", res.gpu_write)); cpuCopy->setText(fstr("%.1f MB/s", res.cpu_copy)); cpuRead->setText(fstr("%.1f MB/s", res.cpu_read)); cpuWrite->setText(fstr("%.1f MB/s", res.cpu_write)); l2->setText(fstr("%.1f ns", res.l2_ns)); ram->setText(fstr("%.1f ns", res.ram_ns)); } void start() { if (running) return; memset(&res, 0, sizeof(res)); ctx = bench_begin(); if (!ctx) { status->setText("Out of memory"); return; } running = true; primed = true; setProgress(0.0f); status->setText("Running benchmark..."); appletSetAutoSleepDisabled(true); } bench_ctx *ctx = nullptr; bool running = false; bool primed = false; bench_results_t res{}; brls::Button *runBtn; brls::Label *status; brls::Box *bar; brls::Rectangle *barFill, *barTrack; brls::Label *gpuCopy, *gpuRead, *gpuWrite, *cpuCopy, *cpuRead, *cpuWrite, *l2, *ram; }; struct StressShared { std::atomic running{ false }, stop{ false }; std::atomic gflops{ 0.0 }; std::atomic dispatches{ 0 }, mismatches{ 0 }; std::thread worker; }; class StressTab : public brls::Box { public: StressTab() { this->setAxis(brls::Axis::COLUMN); this->setGrow(1.0f); this->setPadding(40.0f, 60.0f, 40.0f, 60.0f); toggle = new brls::Button(); toggle->setText("Start GPU stress"); toggle->registerClickAction([this](brls::View *) { onToggle(); return true; }); this->addView(toggle); statusL = new brls::Label(); statusL->setText("Stopped"); statusL->setMarginTop(8.0f); statusL->setMarginBottom(8.0f); this->addView(statusL); auto *h = new brls::Header(); h->setTitle("Info"); this->addView(h); gflops = makeRow(this, "GFLOPS"); dispatches = makeRow(this, "Dispatches"); mismatches = makeRow(this, "Mismatches"); auto *info = new brls::Label(); info->setText("GPU stress test, Mismatches > 0 indicate instability."); info->setMarginTop(16.0f); this->addView(info); } ~StressTab() override { stopWorker(); } void willDisappear(bool resetState = false) override { stopWorker(); brls::Box::willDisappear(resetState); } void frame(brls::FrameContext *ctx) override { if (sh.running.load()) { gflops->setText(fstr("%.1f", sh.gflops.load())); dispatches->setText(fstru("%llu", (unsigned long long)sh.dispatches.load())); mismatches->setText(fstru("%llu", (unsigned long long)sh.mismatches.load())); } brls::Box::frame(ctx); } private: void onToggle() { if (sh.running.load()) stopWorker(); else startWorker(); } void startWorker() { if (sh.worker.joinable()) sh.worker.join(); sh.stop.store(false); sh.running.store(true); toggle->setText("Stop GPU stress"); statusL->setText("Running..."); sh.worker = std::thread([this] { appletSetAutoSleepDisabled(true); uint64_t totD = 0, totM = 0; while (!sh.stop.load()) { double g = 0; uint64_t d = 0, m = 0; if (!gpu_stress_run(&g, &d, &m)) break; totD += d; totM += m; sh.gflops.store(g); sh.dispatches.store(totD); sh.mismatches.store(totM); } appletSetAutoSleepDisabled(false); sh.running.store(false); }); } void stopWorker() { sh.stop.store(true); if (sh.worker.joinable()) sh.worker.join(); gpu_stress_shutdown(); sh.running.store(false); if (toggle) toggle->setText("Start GPU stress"); if (statusL) statusL->setText("Stopped"); } StressShared sh; brls::Button *toggle; brls::Label *statusL, *gflops, *dispatches, *mismatches; }; class FurmarkTab : public brls::Box { public: FurmarkTab(int which, const char *desc) : which(which) { this->setAxis(brls::Axis::COLUMN); this->setGrow(1.0f); this->setPadding(40.0f, 60.0f, 40.0f, 60.0f); toggle = new brls::Button(); toggle->setText("Start"); toggle->registerClickAction([this](brls::View *) { onToggle(); return true; }); this->addView(toggle); statusL = new brls::Label(); statusL->setText("Stopped"); statusL->setMarginTop(8.0f); statusL->setMarginBottom(12.0f); this->addView(statusL); auto *info = new brls::Label(); info->setText(desc); info->setMarginBottom(8.0f); this->addView(info); auto *h = new brls::Header(); h->setTitle("Info"); this->addView(h); if (which == 3) { gpuFpsL = makeRow(this, "GPU FPS"); cpuFpsL = makeRow(this, "CPU FPS"); } else { gpuFpsL = makeRow(this, "FPS"); } } ~FurmarkTab() override { if (run_furmark_running()) run_furmark_stop(); } void willDisappear(bool resetState = false) override { if (run_furmark_running()) run_furmark_stop(); brls::Box::willDisappear(resetState); } void frame(brls::FrameContext *fc) override { bool r = run_furmark_running() != 0; if (r != shown) { shown = r; toggle->setText(r ? "Stop" : "Start"); statusL->setText(r ? "Running..." : "Stopped"); if (!r) { gpuFpsL->setText("-"); if (cpuFpsL) cpuFpsL->setText("-"); } } if (r) { gpuFpsL->setText(fstr("%.1f", run_furmark_fps())); if (cpuFpsL) cpuFpsL->setText(fstr("%.1f", run_furmark_cpu_fps())); } brls::Box::frame(fc); } private: void onToggle() { if (run_furmark_running()) run_furmark_stop(); else run_furmark_start(which); } int which; bool shown = false; brls::Button *toggle; brls::Label *statusL; brls::Label *gpuFpsL = nullptr; brls::Label *cpuFpsL = nullptr; }; class MemtesterTab : public brls::Box { public: MemtesterTab() { this->setAxis(brls::Axis::COLUMN); this->setGrow(1.0f); this->setPadding(40.0f, 60.0f, 40.0f, 60.0f); auto *modeRow = new brls::Box(brls::Axis::ROW); modeRow->setMarginBottom(10.0f); auto *ml = new brls::Label(); ml->setText("Mode"); ml->setGrow(1.0f); modeRow->addView(ml); modeVal = new brls::Label(); modeVal->setText(modeName(mode)); modeRow->addView(modeVal); this->addView(modeRow); auto *hint = new brls::Label(); hint->setText("Use L / R to select the memtester mode. Press A to run."); hint->setFontSize(15.0f); hint->setTextColor(nvgRGB(150, 150, 150)); hint->setMarginBottom(14.0f); this->addView(hint); toggle = new brls::Button(); toggle->setText("Start"); toggle->registerClickAction([this](brls::View *) { onToggle(); return true; }); this->addView(toggle); this->registerAction("Prev mode", brls::ControllerButton::BUTTON_LB, [this](brls::View *) { cycle(-1); return true; }); this->registerAction("Next mode", brls::ControllerButton::BUTTON_RB, [this](brls::View *) { cycle(1); return true; }); statusL = new brls::Label(); statusL->setText("Stopped"); statusL->setMarginTop(10.0f); statusL->setMarginBottom(8.0f); this->addView(statusL); bar = new brls::Box(brls::Axis::ROW); bar->setHeight(18.0f); bar->setWidthPercentage(100.0f); bar->setMarginBottom(14.0f); barFill = new brls::Rectangle(); barFill->setColor(nvgRGB(0, 193, 210)); barFill->setWidthPercentage(0.0f); barTrack = new brls::Rectangle(); barTrack->setColor(nvgRGB(48, 48, 54)); barTrack->setGrow(1.0f); bar->addView(barFill); bar->addView(barTrack); this->addView(bar); auto *h = new brls::Header(); h->setTitle("Info"); this->addView(h); rowA = makeRow(this, "Loops"); rowB = makeRow(this, "Mismatches"); rowC = makeRow(this, "Detail"); updateBar(); } void setProgress(float f) { barFill->setWidthPercentage(f * 100.0f); } void updateBar() { bar->setVisibility(isGpu() ? brls::Visibility::GONE : brls::Visibility::VISIBLE); } ~MemtesterTab() override { stopAny(); } void willDisappear(bool resetState = false) override { stopAny(); brls::Box::willDisappear(resetState); } void frame(brls::FrameContext *ctx) override { if (isGpu()) { mt_gpu_status_t s; mt_gpu_get(&s); if (s.running || lastRunning) { rowA->setText(fstru("%llu", (unsigned long long)s.loop)); rowB->setText(fstru("%llu", (unsigned long long)s.mismatches)); rowC->setText(fstru("%llu MB tested", (unsigned long long)s.size_mb)); statusL->setText(s.error ? std::string("Error: ") + s.status : std::string(s.status)); } syncToggle(s.running != 0); } else { mt_cpu_status_t s; mt_cpu_get(&s); if (mt_cpu_running() || lastRunning) { rowA->setText(fstru("%llu", (unsigned long long)s.loop)); rowB->setText(fstru("%llu", (unsigned long long)s.mismatches)); char d[96]; if (mode == 1) std::snprintf(d, sizeof d, "%llu MB, burn-in x%llu", (unsigned long long)s.total_mb, (unsigned long long)s.burnin_iters); else std::snprintf(d, sizeof d, "%llu MB, %d threads", (unsigned long long)s.total_mb, s.threads); rowC->setText(d); setProgress(mt_cpu_running() ? s.progress : 0.0f); if (mt_cpu_running()) statusL->setText(std::string(s.mismatches ? "Errors found! Running - " : "Running - ") + (s.test ? s.test : "")); } syncToggle(mt_cpu_running() != 0); } brls::Box::frame(ctx); } private: static const char *modeName(int m) { switch (m) { case 0: return "CPU - Memtester"; case 1: return "CPU - Memtester + BW Burn-in"; case 2: return "GPU - Memtester (Fast)"; case 3: return "GPU - Memtester (Full)"; } return ""; } bool isGpu() const { return mode >= 2; } bool anyRunning() { return mt_cpu_running() || mt_gpu_running(); } void cycle(int dir) { if (anyRunning()) return; mode = (mode + dir + 4) % 4; modeVal->setText(modeName(mode)); updateBar(); } void onToggle() { if (anyRunning()) stopAny(); else startAny(); } void startAny() { rowA->setText("-"); rowB->setText("-"); rowC->setText("-"); switch (mode) { case 0: mt_cpu_start(0); break; case 1: mt_cpu_start(1); break; case 2: mt_gpu_start(0); break; case 3: mt_gpu_start(1); break; } } void stopAny() { if (mt_cpu_running()) mt_cpu_stop(); if (mt_gpu_running()) mt_gpu_stop(); } void syncToggle(bool running) { if (running == lastRunning) return; lastRunning = running; toggle->setText(running ? "Stop" : "Start"); if (!running) statusL->setText("Stopped"); } int mode = 0; bool lastRunning = false; brls::Label *modeVal, *statusL, *rowA, *rowB, *rowC; brls::Button *toggle; brls::Box *bar; brls::Rectangle *barFill, *barTrack; }; class CpuStressTab : public brls::Box { public: CpuStressTab() { this->setAxis(brls::Axis::COLUMN); this->setGrow(1.0f); this->setPadding(40.0f, 60.0f, 40.0f, 60.0f); auto *modeRow = new brls::Box(brls::Axis::ROW); modeRow->setMarginBottom(10.0f); auto *ml = new brls::Label(); ml->setText("Mode"); ml->setGrow(1.0f); modeRow->addView(ml); modeVal = new brls::Label(); modeVal->setText(modeName(mode)); modeRow->addView(modeVal); this->addView(modeRow); auto *hint = new brls::Label(); hint->setText("Use L / R to select the CPU stress mode. Press A to run."); hint->setFontSize(15.0f); hint->setTextColor(nvgRGB(150, 150, 150)); hint->setMarginBottom(14.0f); this->addView(hint); toggle = new brls::Button(); toggle->setText("Start"); toggle->registerClickAction([this](brls::View *) { onToggle(); return true; }); this->addView(toggle); this->registerAction("Prev mode", brls::ControllerButton::BUTTON_LB, [this](brls::View *) { cycle(-1); return true; }); this->registerAction("Next mode", brls::ControllerButton::BUTTON_RB, [this](brls::View *) { cycle(1); return true; }); statusL = new brls::Label(); statusL->setText("Stopped"); statusL->setMarginTop(10.0f); statusL->setMarginBottom(8.0f); this->addView(statusL); auto *h = new brls::Header(); h->setTitle("Info"); this->addView(h); rowA = makeRow(this, "Iterations"); rowB = makeRow(this, "Mismatches"); rowC = makeRow(this, "Threads"); } ~CpuStressTab() override { if (cpu_stress_running()) cpu_stress_stop(); } void willDisappear(bool resetState = false) override { if (cpu_stress_running()) cpu_stress_stop(); brls::Box::willDisappear(resetState); } void frame(brls::FrameContext *ctx) override { cpu_stress_status_t s; cpu_stress_get(&s); if (cpu_stress_running() || lastRunning) { rowA->setText(fstru("%llu", (unsigned long long)s.iters)); rowB->setText(fstru("%llu", (unsigned long long)s.mismatches)); rowC->setText(fstru("%llu", (unsigned long long)s.threads)); if (cpu_stress_running()) statusL->setText(s.mismatches ? "Errors found! Running..." : "Running..."); } syncToggle(cpu_stress_running() != 0); brls::Box::frame(ctx); } private: static const char *modeName(int m) { switch (m) { case 0: return "Matrixprod"; case 1: return "Hanoi (verify)"; } return ""; } void cycle(int dir) { if (cpu_stress_running()) return; mode = (mode + dir + 2) % 2; modeVal->setText(modeName(mode)); } void onToggle() { if (cpu_stress_running()) cpu_stress_stop(); else { rowA->setText("-"); rowB->setText("-"); rowC->setText("-"); cpu_stress_start(mode); } } void syncToggle(bool running) { if (running == lastRunning) return; lastRunning = running; toggle->setText(running ? "Stop" : "Start"); if (!running) statusL->setText("Stopped"); } int mode = 0; bool lastRunning = false; brls::Label *modeVal, *statusL, *rowA, *rowB, *rowC; brls::Button *toggle; }; class CreditsTab : public brls::Box { public: CreditsTab() { this->setAxis(brls::Axis::COLUMN); this->setGrow(1.0f); this->setPadding(40.0f, 60.0f, 40.0f, 60.0f); auto *title = new brls::Label(); title->setText("Benchmark Toolbox"); title->setFontSize(26.0f); this->addView(title); auto *by = new brls::Label(); by->setText("by Souldbminer and Lightos_, licensed under the GPLv2"); by->setFontSize(16.0f); by->setTextColor(nvgRGB(150, 150, 150)); this->addView(by); auto *h = new brls::Header(); h->setTitle("Credits"); this->addView(h); makeRow(this, "Memtester")->setText("Simon Kirby, Charles Cazabon, KazushiMe & CTCaer"); makeRow(this, "FurMark")->setText("StanislavPetrovV & AnxietyTimmy"); makeRow(this, "GPU Test")->setText("NaGaa95"); makeRow(this, "Membench")->setText("Siarhei Siamashka, KazushiMe & Lineon"); makeRow(this, "Stress-ng")->setText("ColinIanKing & Lineon"); auto *note = new brls::Label(); note->setText("Thanks to all the original authors."); note->setFontSize(15.0f); note->setTextColor(nvgRGB(150, 150, 150)); note->setMarginTop(18.0f); this->addView(note); } }; class AppFrame : public brls::TabFrame { public: AppFrame() { box = dynamic_cast(this->getView("brls/applet_frame/header_stats")); if (box) { box->setJustifyContent(brls::JustifyContent::FLEX_END); box->setAlignItems(brls::AlignItems::CENTER); const float fs = 13.0f; for (int i = 0; i < 3; i++) { grp[i].load = statCell(box, fs); if (i) grp[i].load->setMarginLeft(18.0f); statSep(box, fs); grp[i].clock = statCell(box, fs); statSep(box, fs); grp[i].temp = statCell(box, fs); } } hocclk_init(); update(); } void frame(brls::FrameContext *ctx) override { if (box && ++tick >= 12) { tick = 0; update(); } brls::TabFrame::frame(ctx); } private: void setGrp(StatCells &g, const char *name, unsigned loadOrBw, bool isRam, uint32_t hz, int32_t mc) { char b[48]; if (isRam) std::snprintf(b, sizeof b, "%s %u.%u GB/s", name, loadOrBw / 1000u, (loadOrBw % 1000u) / 100u); else std::snprintf(b, sizeof b, "%s %u%%", name, loadOrBw); g.load->setText(b); fmtClock1(g.clock, hz); fmtTemp(g.temp, mc); } void update() { if (!box) return; HocClkContext c; if (!hocclk_get(&c)) { grp[0].load->setText("hoc:clk N/A"); grp[0].clock->setText("-"); grp[0].temp->setText("-"); grp[1].load->setText("-"); grp[1].clock->setText("-"); grp[1].temp->setText("-"); grp[2].load->setText("-"); grp[2].clock->setText("-"); grp[2].temp->setText("-"); return; } setGrp(grp[0], "CPU", c.stable.partLoad[3] / 10, false, c.stable.realFreqs[0], c.stable.temps[5]); setGrp(grp[1], "GPU", c.stable.partLoad[2] / 10, false, c.stable.realFreqs[1], c.stable.temps[6]); setGrp(grp[2], "RAM", c.stable.partLoad[6], true, c.stable.realFreqs[2], c.stable.temps[7]); } brls::Box *box = nullptr; StatCells grp[3]; int tick = 0; }; class MainActivity : public brls::Activity { public: brls::View *createContentView() override { auto *tab = new AppFrame(); tab->setTitle("Benchmark Toolbox"); tab->setIconFromRes("img/logo.png"); tab->addTab("System Info", [] { return new SysInfoTab(); }); tab->addHeader("Combined"); tab->addTab("Black Hole", [] { return new FurmarkTab(3, "CPU+GPU black-hole."); }); tab->addHeader("CPU"); tab->addTab("CPU Stress", [] { return new CpuStressTab(); }); tab->addTab("CPU Ray Trace", [] { return new FurmarkTab(4, "CPU Path Tracer"); }); tab->addHeader("GPU"); tab->addTab("GPU Test", [] { return new StressTab(); }); tab->addTab("Furmark", [] { return new FurmarkTab(0, "FurMark for Switch (48 step)"); }); tab->addTab("GPU Path Trace", [] { return new FurmarkTab(2, "GPU Path Tracer"); }); tab->addHeader("RAM"); tab->addTab("Memtester", [] { return new MemtesterTab(); }); tab->addTab("Membench", [] { return new BenchTab(); }); tab->addTab("Furmark RAM", [] { return new FurmarkTab(1, "FurMark with extra ram stress"); }); tab->addTab("CPU RAM", [] { return new FurmarkTab(5, "CPU RT with extra RAM stress"); }); tab->addSeparator(); tab->addTab("Credits", [] { return new CreditsTab(); }); return tab; } }; int main(int argc, char *argv[]) { (void)argc; (void)argv; brls::Logger::setLogLevel(brls::LogLevel::INFO); if (!brls::Application::init()) { brls::Logger::error("Unable to init borealis application"); return EXIT_FAILURE; } brls::Application::createWindow("Benchmark Toolbox"); brls::Application::setGlobalQuit(true); brls::Application::pushActivity(new MainActivity()); while (brls::Application::mainLoop()) ; // Global quit (+) can return from the main loop without destroying the // activity, leaving background workers (and their threads / large RAM // allocations) live across _exit. Tear them down first. if (run_furmark_running()) run_furmark_stop(); if (mt_gpu_running()) mt_gpu_stop(); if (mt_cpu_running()) mt_cpu_stop(); if (cpu_stress_running()) cpu_stress_stop(); _exit(EXIT_SUCCESS); }