benchmark_toolbox: hanoi cpu test
This commit is contained in:
@@ -12,10 +12,10 @@ include $(DEVKITPRO)/libnx/switch_rules
|
|||||||
#---------------------------------------------------------------------------------
|
#---------------------------------------------------------------------------------
|
||||||
TARGET := Benchmark-Toolbox
|
TARGET := Benchmark-Toolbox
|
||||||
BUILD := build
|
BUILD := build
|
||||||
SOURCES := source source/furmark source/memtester
|
SOURCES := source source/furmark source/memtester source/cpustress
|
||||||
DATA := data
|
DATA := data
|
||||||
ICON := icon.jpg
|
ICON := icon.jpg
|
||||||
INCLUDES := source source/furmark source/memtester ../hoc-clk/common/include
|
INCLUDES := source source/furmark source/memtester source/cpustress ../hoc-clk/common/include
|
||||||
|
|
||||||
APP_TITLE := Benchmark Toolbox
|
APP_TITLE := Benchmark Toolbox
|
||||||
APP_AUTHOR := Horizon-OC
|
APP_AUTHOR := Horizon-OC
|
||||||
|
|||||||
178
Source/Benchmark-Toolbox/source/cpustress/cpu_stress.c
Normal file
178
Source/Benchmark-Toolbox/source/cpustress/cpu_stress.c
Normal file
@@ -0,0 +1,178 @@
|
|||||||
|
#include "cpu_stress.h"
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <switch.h>
|
||||||
|
|
||||||
|
#define CS_N 128
|
||||||
|
#define CS_THREADS 3
|
||||||
|
#define CS_PRIO 0x3B
|
||||||
|
#define CS_STACK 0x10000
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int core;
|
||||||
|
volatile uint64_t iters;
|
||||||
|
volatile uint64_t mismatches;
|
||||||
|
} cs_worker_t;
|
||||||
|
|
||||||
|
static Thread s_t[CS_THREADS];
|
||||||
|
static bool s_started[CS_THREADS];
|
||||||
|
static cs_worker_t s_w[CS_THREADS];
|
||||||
|
|
||||||
|
static volatile bool s_stop = false;
|
||||||
|
static volatile bool s_running = false;
|
||||||
|
static int s_mode = 0;
|
||||||
|
static volatile int s_nthreads = 0;
|
||||||
|
|
||||||
|
static volatile long double s_sink;
|
||||||
|
|
||||||
|
static void mwc_seed(uint32_t *w, uint32_t *z, int core) {
|
||||||
|
uint32_t mix = (uint32_t)core * 0x9e3779b9u;
|
||||||
|
uint32_t ww = 0xdeadbeefu ^ mix;
|
||||||
|
uint32_t zz = 0x12345678u ^ ~mix;
|
||||||
|
*w = ww ? ww : 0xdeadbeefu;
|
||||||
|
*z = zz ? zz : 0x12345678u;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint32_t mwc32(uint32_t *w, uint32_t *z) {
|
||||||
|
*z = 36969u * (*z & 65535u) + (*z >> 16);
|
||||||
|
*w = 18000u * (*w & 65535u) + (*w >> 16);
|
||||||
|
return (*z << 16) + *w;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void matrixprod(long double *a, long double *b, long double *r, uint32_t *w, uint32_t *z) {
|
||||||
|
const long double v = 1.0L / (long double)((uint32_t)~0u);
|
||||||
|
|
||||||
|
for (int i = 0; i < CS_N; i++) {
|
||||||
|
for (int j = 0; j < CS_N; j++) {
|
||||||
|
a[i * CS_N + j] = (long double)mwc32(w, z) * v;
|
||||||
|
b[i * CS_N + j] = (long double)mwc32(w, z) * v;
|
||||||
|
r[i * CS_N + j] = 0.0L;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < CS_N && !s_stop; i++) {
|
||||||
|
for (int j = 0; j < CS_N; j++) {
|
||||||
|
for (int k = 0; k < CS_N; k++)
|
||||||
|
r[i * CS_N + j] += a[i * CS_N + k] * b[k * CS_N + j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
long double sum = 0.0L;
|
||||||
|
for (int i = 0; i < CS_N; i++)
|
||||||
|
for (int j = 0; j < CS_N; j++)
|
||||||
|
sum += r[i * CS_N + j];
|
||||||
|
s_sink = sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t hanoi_rec(int n) {
|
||||||
|
if (n == 0)
|
||||||
|
return 1;
|
||||||
|
if (n == 1)
|
||||||
|
return 2;
|
||||||
|
return hanoi_rec(n - 1) + hanoi_rec(n - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hanoi_pass(void) {
|
||||||
|
uint32_t sum = 0;
|
||||||
|
for (int k = 19; k >= 0; k--)
|
||||||
|
sum += hanoi_rec(k);
|
||||||
|
return sum == 0xfffffu;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cs_worker(void *arg) {
|
||||||
|
cs_worker_t *c = (cs_worker_t *)arg;
|
||||||
|
uint32_t w, z;
|
||||||
|
mwc_seed(&w, &z, c->core);
|
||||||
|
|
||||||
|
long double *a = NULL, *b = NULL, *r = NULL;
|
||||||
|
if (s_mode == 0) {
|
||||||
|
size_t bytes = sizeof(long double) * CS_N * CS_N;
|
||||||
|
a = (long double *)malloc(bytes);
|
||||||
|
b = (long double *)malloc(bytes);
|
||||||
|
r = (long double *)malloc(bytes);
|
||||||
|
if (!a || !b || !r) {
|
||||||
|
free(a);
|
||||||
|
free(b);
|
||||||
|
free(r);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!s_stop) {
|
||||||
|
if (s_mode == 0) {
|
||||||
|
matrixprod(a, b, r, &w, &z);
|
||||||
|
} else {
|
||||||
|
if (!hanoi_pass())
|
||||||
|
c->mismatches++;
|
||||||
|
}
|
||||||
|
c->iters++;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(a);
|
||||||
|
free(b);
|
||||||
|
free(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cpu_stress_start(int mode) {
|
||||||
|
if (s_running)
|
||||||
|
return;
|
||||||
|
s_mode = mode;
|
||||||
|
s_stop = false;
|
||||||
|
s_running = true;
|
||||||
|
s_nthreads = CS_THREADS;
|
||||||
|
appletSetAutoSleepDisabled(true);
|
||||||
|
|
||||||
|
int started = 0;
|
||||||
|
for (int i = 0; i < CS_THREADS; i++) {
|
||||||
|
s_started[i] = false;
|
||||||
|
s_w[i].core = i;
|
||||||
|
s_w[i].iters = 0;
|
||||||
|
s_w[i].mismatches = 0;
|
||||||
|
if (R_FAILED(threadCreate(&s_t[i], cs_worker, &s_w[i], NULL, CS_STACK, CS_PRIO, i)))
|
||||||
|
continue;
|
||||||
|
if (R_SUCCEEDED(threadStart(&s_t[i]))) {
|
||||||
|
s_started[i] = true;
|
||||||
|
started++;
|
||||||
|
} else {
|
||||||
|
threadClose(&s_t[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (started == 0) {
|
||||||
|
s_running = false;
|
||||||
|
appletSetAutoSleepDisabled(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void cpu_stress_stop(void) {
|
||||||
|
s_stop = true;
|
||||||
|
for (int i = 0; i < CS_THREADS; i++) {
|
||||||
|
if (!s_started[i])
|
||||||
|
continue;
|
||||||
|
threadWaitForExit(&s_t[i]);
|
||||||
|
threadClose(&s_t[i]);
|
||||||
|
s_started[i] = false;
|
||||||
|
}
|
||||||
|
s_running = false;
|
||||||
|
appletSetAutoSleepDisabled(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
int cpu_stress_running(void) {
|
||||||
|
return s_running ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cpu_stress_get(cpu_stress_status_t *out) {
|
||||||
|
if (!out)
|
||||||
|
return;
|
||||||
|
uint64_t it = 0, mm = 0;
|
||||||
|
int n = s_nthreads;
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
it += s_w[i].iters;
|
||||||
|
mm += s_w[i].mismatches;
|
||||||
|
}
|
||||||
|
out->iters = it;
|
||||||
|
out->mismatches = mm;
|
||||||
|
out->threads = s_nthreads;
|
||||||
|
out->running = s_running ? 1 : 0;
|
||||||
|
}
|
||||||
23
Source/Benchmark-Toolbox/source/cpustress/cpu_stress.h
Normal file
23
Source/Benchmark-Toolbox/source/cpustress/cpu_stress.h
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint64_t iters;
|
||||||
|
uint64_t mismatches;
|
||||||
|
int threads;
|
||||||
|
int running;
|
||||||
|
} cpu_stress_status_t;
|
||||||
|
|
||||||
|
void cpu_stress_start(int mode);
|
||||||
|
void cpu_stress_stop(void);
|
||||||
|
int cpu_stress_running(void);
|
||||||
|
void cpu_stress_get(cpu_stress_status_t *out);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -13,6 +13,7 @@ extern "C" {
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "bench.h"
|
#include "bench.h"
|
||||||
|
#include "cpu_stress.h"
|
||||||
#include "gpu_bw.h"
|
#include "gpu_bw.h"
|
||||||
#include "gpu_stress.h"
|
#include "gpu_stress.h"
|
||||||
#include "hoc_clk.h"
|
#include "hoc_clk.h"
|
||||||
@@ -658,6 +659,125 @@ class MemtesterTab : public brls::Box {
|
|||||||
brls::Rectangle *barFill, *barTrack;
|
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("Live");
|
||||||
|
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 {
|
class CreditsTab : public brls::Box {
|
||||||
public:
|
public:
|
||||||
CreditsTab() {
|
CreditsTab() {
|
||||||
@@ -773,6 +893,7 @@ class MainActivity : public brls::Activity {
|
|||||||
tab->addTab("Membench", [] { return new BenchTab(); });
|
tab->addTab("Membench", [] { return new BenchTab(); });
|
||||||
tab->addTab("GPU Test", [] { return new StressTab(); });
|
tab->addTab("GPU Test", [] { return new StressTab(); });
|
||||||
tab->addTab("Memtester", [] { return new MemtesterTab(); });
|
tab->addTab("Memtester", [] { return new MemtesterTab(); });
|
||||||
|
tab->addTab("CPU Stress", [] { return new CpuStressTab(); });
|
||||||
tab->addSeparator();
|
tab->addSeparator();
|
||||||
tab->addTab("Furmark", [] { return new FurmarkTab(0, "FurMark for Switch (48 step)"); });
|
tab->addTab("Furmark", [] { return new FurmarkTab(0, "FurMark for Switch (48 step)"); });
|
||||||
tab->addTab("Furmark RAM", [] { return new FurmarkTab(1, "FurMark with extra ram stress"); });
|
tab->addTab("Furmark RAM", [] { return new FurmarkTab(1, "FurMark with extra ram stress"); });
|
||||||
@@ -813,6 +934,8 @@ int main(int argc, char *argv[]) {
|
|||||||
mt_gpu_stop();
|
mt_gpu_stop();
|
||||||
if (mt_cpu_running())
|
if (mt_cpu_running())
|
||||||
mt_cpu_stop();
|
mt_cpu_stop();
|
||||||
|
if (cpu_stress_running())
|
||||||
|
cpu_stress_stop();
|
||||||
|
|
||||||
_exit(EXIT_SUCCESS);
|
_exit(EXIT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user