Remove CPU telemetry (background temperature/clock speed sampling)

The background thread that sampled CPU temperature and clock speed
during a run relied on undocumented, OS-specific interfaces: raw
AppleSMC keys on macOS, WMI ACPI thermal zones on Windows, and
/sys/class/thermal or /sys/class/hwmon on Linux. Testing on Apple
Silicon showed the SMC key scan can silently switch between different
physical sensors mid-run, producing discontinuous jumps in reported
temperature, and live per-core clock speed was never obtainable on
macOS through any public API. Disable the feature entirely rather
than ship unreliable data: drop the telemetry monitor thread, its
platform-specific sensor backends, and the telemetry field from
upload payloads. The pre-run background system-activity check
(--no-system-check) is unrelated and untouched.

Bump FB_VERSION to 0.4.2.
This commit is contained in:
2026-07-21 13:53:28 -05:00
parent ec7e75e105
commit 187c902b7a
4 changed files with 9 additions and 487 deletions
+1 -1
View File
@@ -175,5 +175,5 @@ jobs:
release/SHA256SUMS \ release/SHA256SUMS \
--repo "$GITHUB_REPOSITORY" \ --repo "$GITHUB_REPOSITORY" \
--title "Release $RELEASE_TAG" \ --title "Release $RELEASE_TAG" \
--notes "Hotfix: CPU telemetry (temperature and clock speed) recorded during benchmark runs was not working on Windows or macOS, showing empty temperature data points and a constant clock speed. Windows temperature now reads the ACPI thermal zone over WMI, and clock speed reads live per-core frequency via CallNtPowerInformation instead of a static registry value. macOS temperature now reads the SMC directly across Intel and Apple Silicon (M1-M5) Macs. macOS clock speed now reports as unavailable rather than the fixed nominal frequency it previously showed, since no live-frequency API exists on macOS." \ --notes "Removed CPU telemetry (background temperature and clock speed sampling during benchmark runs). It relied on undocumented, OS-specific interfaces (raw AppleSMC keys on macOS, WMI ACPI thermal zones on Windows, /sys/class/thermal and /sys/class/hwmon on Linux) that proved unstable and inconsistent across operating systems and hardware, and live per-core clock speed was never obtainable on macOS at all through any public API. Rather than ship telemetry data that can silently jump between physical sensors mid-run or simply not exist on a given platform, this release disables the feature entirely: fossbench.net no longer accepts or displays it, and the client no longer collects it. The one-time background system-activity check (CPU/memory/process sampling before a run) is unaffected and still available via --no-system-check." \
--generate-notes --generate-notes
+5 -6
View File
@@ -178,21 +178,20 @@ $(DIST)/fossbench-linux-ppc64le: $(DRIVER) $(DRIVER_DEPS) $(ASM_PPC64LE) | $(DIS
@echo "built $@" @echo "built $@"
$(DIST)/fossbench-macos-arm64: $(DRIVER) $(DRIVER_DEPS) $(ASM_ARM64) | $(DIST) $(DIST)/fossbench-macos-arm64: $(DRIVER) $(DRIVER_DEPS) $(ASM_ARM64) | $(DIST)
$(CC_MACOS_ARM64) -arch arm64 $(CFLAGS) $(PTHREAD) $(LDFLAGS) -o $@ $(DRIVER) $(ASM_ARM64) $(LDLIBS) -framework IOKit -framework CoreFoundation $(CC_MACOS_ARM64) -arch arm64 $(CFLAGS) $(PTHREAD) $(LDFLAGS) -o $@ $(DRIVER) $(ASM_ARM64) $(LDLIBS)
@echo "built $@" @echo "built $@"
$(DIST)/fossbench-macos-amd64: $(DRIVER) $(DRIVER_DEPS) $(ASM_AMD64) | $(DIST) $(DIST)/fossbench-macos-amd64: $(DRIVER) $(DRIVER_DEPS) $(ASM_AMD64) | $(DIST)
MACOSX_DEPLOYMENT_TARGET=$(MACOS_AMD64_MIN) $(CC_MACOS_AMD64) -arch x86_64 -mmacosx-version-min=$(MACOS_AMD64_MIN) $(CFLAGS) $(PTHREAD) $(LDFLAGS) -Wl,-no_fixup_chains -o $@ $(DRIVER) $(ASM_AMD64) $(LDLIBS) -framework IOKit -framework CoreFoundation MACOSX_DEPLOYMENT_TARGET=$(MACOS_AMD64_MIN) $(CC_MACOS_AMD64) -arch x86_64 -mmacosx-version-min=$(MACOS_AMD64_MIN) $(CFLAGS) $(PTHREAD) $(LDFLAGS) -Wl,-no_fixup_chains -o $@ $(DRIVER) $(ASM_AMD64) $(LDLIBS)
@echo "built $@" @echo "built $@"
# Windows builds are static and use WinHTTP. Temperature/clock telemetry # Windows builds are static and use WinHTTP.
# additionally needs WMI (ole32/oleaut32/wbemuuid) and PowrProf.
$(DIST)/fossbench-windows-amd64.exe: $(DRIVER) $(DRIVER_DEPS) $(ASM_AMD64) | $(DIST) $(DIST)/fossbench-windows-amd64.exe: $(DRIVER) $(DRIVER_DEPS) $(ASM_AMD64) | $(DIST)
$(CC_WINDOWS_AMD64) $(CFLAGS) $(PTHREAD) -static -o $@ $(DRIVER) $(ASM_AMD64) -lm -lwinhttp -ladvapi32 -lole32 -loleaut32 -lwbemuuid -lpowrprof $(CC_WINDOWS_AMD64) $(CFLAGS) $(PTHREAD) -static -o $@ $(DRIVER) $(ASM_AMD64) -lm -lwinhttp -ladvapi32
@echo "built $@" @echo "built $@"
$(DIST)/fossbench-windows-i386.exe: $(DRIVER) $(DRIVER_DEPS) $(SRC_I386) | $(DIST) $(DIST)/fossbench-windows-i386.exe: $(DRIVER) $(DRIVER_DEPS) $(SRC_I386) | $(DIST)
$(CC_WINDOWS_I386) -march=i386 $(WINDOWS_I386_XP_CFLAGS) $(CFLAGS) -static $(WINDOWS_I386_XP_LDFLAGS) -o $@ $(DRIVER) $(SRC_I386) -lm -lwinhttp -ladvapi32 -lole32 -loleaut32 -lwbemuuid -lpowrprof $(CC_WINDOWS_I386) -march=i386 $(WINDOWS_I386_XP_CFLAGS) $(CFLAGS) -static $(WINDOWS_I386_XP_LDFLAGS) -o $@ $(DRIVER) $(SRC_I386) -lm -lwinhttp -ladvapi32
@echo "built $@" @echo "built $@"
# Add a native rule if one was not already made above. # Add a native rule if one was not already made above.
+2 -457
View File
@@ -12,20 +12,6 @@
# include <tlhelp32.h> # include <tlhelp32.h>
# include <winhttp.h> # include <winhttp.h>
# include <process.h> # include <process.h>
# include <powrprof.h>
# include <wbemidl.h>
# include <oleauto.h>
/* Documented by Microsoft but not declared in MinGW's powrprof.h; including
* <ddk/ntpoapi.h> for it collides with definitions already pulled in by
* <windows.h>, so declare the same layout locally instead. */
typedef struct _PROCESSOR_POWER_INFORMATION {
ULONG Number;
ULONG MaxMhz;
ULONG CurrentMhz;
ULONG MhzLimit;
ULONG MaxIdleState;
ULONG CurrentIdleState;
} PROCESSOR_POWER_INFORMATION, *PPROCESSOR_POWER_INFORMATION;
#else #else
# include <pthread.h> # include <pthread.h>
# include <unistd.h> # include <unistd.h>
@@ -46,14 +32,13 @@ typedef struct _PROCESSOR_POWER_INFORMATION {
# include <sys/sysctl.h> # include <sys/sysctl.h>
# include <mach/mach_time.h> # include <mach/mach_time.h>
# include <mach/mach.h> # include <mach/mach.h>
# include <IOKit/IOKitLib.h>
#endif #endif
/* The server URL can be changed when building. */ /* The server URL can be changed when building. */
#ifndef FB_API_BASE_URL #ifndef FB_API_BASE_URL
# define FB_API_BASE_URL "http://fossbench.net" # define FB_API_BASE_URL "http://fossbench.net"
#endif #endif
#define FB_VERSION "0.4.0" #define FB_VERSION "0.4.2"
/* /*
* Native Integer Math and Memory Bandwidth are the only two *measured* * Native Integer Math and Memory Bandwidth are the only two *measured*
@@ -188,8 +173,6 @@ extern uint64_t fb_c_chase(void **ptrs, uint64_t steps);
# define REPEATS 3 /* Number of tries. */ # define REPEATS 3 /* Number of tries. */
#endif #endif
#define TELEMETRY_REFRESH_INTERVAL 0.5
/* Simple repeatable random numbers. */ /* Simple repeatable random numbers. */
static uint64_t rng_state = 0x853c49e6748fea9bULL; static uint64_t rng_state = 0x853c49e6748fea9bULL;
@@ -237,439 +220,6 @@ struct background_metrics {
int samples, available; int samples, available;
}; };
#define MAX_TELEMETRY_SAMPLES 1800
struct telemetry_sample {
uint64_t elapsed_ms;
double temperature_c, clock_mhz;
};
struct telemetry_monitor {
struct telemetry_sample samples[MAX_TELEMETRY_SAMPLES];
size_t count;
double started;
volatile int stop;
#if defined(_WIN32)
HANDLE thread;
#else
pthread_t thread;
#endif
};
static int read_number_file(const char *path, double *value)
{
FILE *f = fopen(path, "r");
int ok;
if (!f) return 0;
ok = fscanf(f, "%lf", value) == 1;
fclose(f);
return ok;
}
#if defined(__linux__)
static int read_text_file(const char *path, char *value, size_t cap)
{
FILE *f = fopen(path, "r");
if (!f || !fgets(value, (int)cap, f)) { if (f) fclose(f); return 0; }
fclose(f);
value[strcspn(value, "\r\n")] = '\0';
return 1;
}
static int cpu_sensor_name(const char *name)
{
return strstr(name, "cpu") || strstr(name, "CPU") || strstr(name, "package") ||
strstr(name, "Package") || strstr(name, "coretemp") || strstr(name, "k10temp") ||
strstr(name, "zenpower") || strstr(name, "x86_pkg_temp") || strstr(name, "soc_thermal");
}
#endif
#if defined(_WIN32)
/* Reads MSAcpi_ThermalZoneTemperature from the ACPI thermal zone WMI namespace.
* Only populated on hardware whose firmware exposes it; many laptops do not. */
static IWbemServices *wmi_connect_thermal_namespace(void)
{
IWbemLocator *locator = NULL;
IWbemServices *services = NULL;
BSTR namespace_path = NULL;
HRESULT hr;
hr = CoCreateInstance(&CLSID_WbemLocator, NULL, CLSCTX_INPROC_SERVER, &IID_IWbemLocator, (LPVOID *)&locator);
if (FAILED(hr) || !locator) return NULL;
namespace_path = SysAllocString(L"ROOT\\WMI");
if (!namespace_path) { locator->lpVtbl->Release(locator); return NULL; }
hr = locator->lpVtbl->ConnectServer(locator, namespace_path, NULL, NULL, NULL, 0, NULL, NULL, &services);
SysFreeString(namespace_path);
locator->lpVtbl->Release(locator);
if (FAILED(hr) || !services) return NULL;
hr = CoSetProxyBlanket((IUnknown *)services, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL,
RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE);
if (FAILED(hr)) { services->lpVtbl->Release(services); return NULL; }
return services;
}
static double wmi_query_temperature(IWbemServices *services)
{
IEnumWbemClassObject *enumerator = NULL;
BSTR language = NULL, query = NULL;
HRESULT hr;
double hottest = -1.0;
language = SysAllocString(L"WQL");
query = SysAllocString(L"SELECT CurrentTemperature FROM MSAcpi_ThermalZoneTemperature");
if (!language || !query) goto done;
hr = services->lpVtbl->ExecQuery(services, language, query,
WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &enumerator);
if (FAILED(hr) || !enumerator) goto done;
for (;;) {
IWbemClassObject *obj = NULL;
ULONG returned = 0;
VARIANT value;
hr = enumerator->lpVtbl->Next(enumerator, WBEM_INFINITE, 1, &obj, &returned);
if (FAILED(hr) || returned == 0) break;
VariantInit(&value);
/* CurrentTemperature is reported in tenths of a Kelvin. */
if (SUCCEEDED(obj->lpVtbl->Get(obj, L"CurrentTemperature", 0, &value, NULL, NULL))) {
double tenths_kelvin = 0.0;
if (value.vt == VT_I4) tenths_kelvin = (double)value.lVal;
else if (value.vt == VT_UI4) tenths_kelvin = (double)value.ulVal;
if (tenths_kelvin > 0.0) {
double celsius = tenths_kelvin / 10.0 - 273.15;
if (celsius > -50.0 && celsius <= 150.0 && celsius > hottest) hottest = celsius;
}
}
VariantClear(&value);
obj->lpVtbl->Release(obj);
}
enumerator->lpVtbl->Release(enumerator);
done:
if (query) SysFreeString(query);
if (language) SysFreeString(language);
return hottest;
}
#endif
#if defined(__APPLE__)
/* Talks to the AppleSMC user client directly; there is no public framework
* for this. Struct layout and command bytes come from the SMC protocol that
* has been stable across Intel and Apple Silicon Macs for over a decade. */
typedef struct {
char major, minor, build, reserved_;
uint16_t release;
} fb_smc_vers_t;
typedef struct {
uint16_t version, length;
uint32_t cpu_p_limit, gpu_p_limit, mem_p_limit;
} fb_smc_plimit_t;
typedef struct {
uint32_t data_size;
uint32_t data_type;
char data_attributes;
} fb_smc_key_info_t;
typedef struct {
uint32_t key;
fb_smc_vers_t vers;
fb_smc_plimit_t plimit;
fb_smc_key_info_t key_info;
char result, status, data8;
uint32_t data32;
unsigned char bytes[32];
} fb_smc_data_t;
#define FB_SMC_KERNEL_INDEX 2
#define FB_SMC_CMD_READ_BYTES 5
#define FB_SMC_CMD_READ_KEY_INFO 9
static uint32_t smc_key_from_string(const char *s)
{
return ((uint32_t)(unsigned char)s[0] << 24) | ((uint32_t)(unsigned char)s[1] << 16) |
((uint32_t)(unsigned char)s[2] << 8) | (uint32_t)(unsigned char)s[3];
}
static kern_return_t smc_call(io_connect_t conn, fb_smc_data_t *in, fb_smc_data_t *out)
{
size_t out_size = sizeof(*out);
return IOConnectCallStructMethod(conn, FB_SMC_KERNEL_INDEX, in, sizeof(*in), out, &out_size);
}
static int smc_read_temperature(io_connect_t conn, const char *key, double *out)
{
fb_smc_data_t in, info_out, read_out;
memset(&in, 0, sizeof(in));
memset(&info_out, 0, sizeof(info_out));
in.key = smc_key_from_string(key);
in.data8 = FB_SMC_CMD_READ_KEY_INFO;
if (smc_call(conn, &in, &info_out) != KERN_SUCCESS || info_out.key_info.data_size == 0)
return 0;
memset(&in, 0, sizeof(in));
memset(&read_out, 0, sizeof(read_out));
in.key = smc_key_from_string(key);
in.key_info.data_size = info_out.key_info.data_size;
in.data8 = FB_SMC_CMD_READ_BYTES;
if (smc_call(conn, &in, &read_out) != KERN_SUCCESS)
return 0;
if (info_out.key_info.data_type == smc_key_from_string("sp78") && info_out.key_info.data_size >= 2) {
int16_t raw = (int16_t)((read_out.bytes[0] << 8) | read_out.bytes[1]);
*out = raw / 256.0;
return 1;
}
if (info_out.key_info.data_type == smc_key_from_string("flt ") && info_out.key_info.data_size >= 4) {
float f;
memcpy(&f, read_out.bytes, sizeof(f));
*out = (double)f;
return 1;
}
return 0;
}
static io_connect_t smc_open(void)
{
io_service_t service;
io_connect_t conn = IO_OBJECT_NULL;
service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("AppleSMC"));
if (service == IO_OBJECT_NULL) return IO_OBJECT_NULL;
if (IOServiceOpen(service, mach_task_self(), 0, &conn) != KERN_SUCCESS) conn = IO_OBJECT_NULL;
IOObjectRelease(service);
return conn;
}
/* CPU-related SMC keys across Intel Macs and Apple Silicon M1-M5, gathered
* from publicly reverse-engineered sensor tables (e.g. exelban/stats,
* acidanthera/VirtualSMC). Coverage varies by exact model/chip revision. */
static const char *const smc_cpu_temp_keys[] = {
"TC0D", "TC0E", "TC0F", "TC0P",
"Tp00", "Tp01", "Tp04", "Tp05", "Tp08", "Tp09", "Tp0C", "Tp0D", "Tp0f", "Tp0G",
"Tp0H", "Tp0j", "Tp0K", "Tp0L", "Tp0m", "Tp0n", "Tp0O", "Tp0P", "Tp0p", "Tp0r",
"Tp0R", "Tp0T", "Tp0u", "Tp0U", "Tp0X", "Tp0a", "Tp0b", "Tp0d", "Tp0g", "Tp0y",
"Tp1h", "Tp1l", "Tp1p", "Tp1t",
"Tc0a", "Tc0b", "Tc0x", "Tc0z",
};
#endif
static double sample_cpu_temperature(void)
{
#if defined(__linux__)
DIR *dir = opendir("/sys/class/thermal");
struct dirent *entry;
double hottest = -1.0;
if (!dir) return -1.0;
while ((entry = readdir(dir)) != NULL) {
char path[512], type[128];
double value;
if (strncmp(entry->d_name, "thermal_zone", 12) != 0) continue;
snprintf(path, sizeof(path), "/sys/class/thermal/%s/type", entry->d_name);
if (!read_text_file(path, type, sizeof(type)) || !cpu_sensor_name(type)) continue;
snprintf(path, sizeof(path), "/sys/class/thermal/%s/temp", entry->d_name);
if (read_number_file(path, &value)) {
if (value > 1000.0) value /= 1000.0;
if (value >= 0.0 && value <= 150.0 && value > hottest) hottest = value;
}
}
closedir(dir);
if (hottest < 0.0) {
dir = opendir("/sys/class/hwmon");
if (!dir) return -1.0;
while ((entry = readdir(dir)) != NULL) {
char base[512], path[512], name[128];
DIR *sensor_dir;
struct dirent *sensor;
if (strncmp(entry->d_name, "hwmon", 5) != 0) continue;
snprintf(base, sizeof(base), "/sys/class/hwmon/%s", entry->d_name);
snprintf(path, sizeof(path), "%s/name", base);
if (!read_text_file(path, name, sizeof(name)) || !cpu_sensor_name(name)) continue;
sensor_dir = opendir(base);
if (!sensor_dir) continue;
while ((sensor = readdir(sensor_dir)) != NULL) {
size_t length = strlen(sensor->d_name);
double value;
if (strncmp(sensor->d_name, "temp", 4) != 0 || length < 7 || strcmp(sensor->d_name + length - 6, "_input") != 0) continue;
snprintf(path, sizeof(path), "%s/%s", base, sensor->d_name);
if (read_number_file(path, &value)) {
if (value > 1000.0) value /= 1000.0;
if (value >= 0.0 && value <= 150.0 && value > hottest) hottest = value;
}
}
closedir(sensor_dir);
}
closedir(dir);
}
return hottest;
#elif defined(_WIN32)
{
static int initialized = 0;
static IWbemServices *services = NULL;
if (!initialized) {
initialized = 1;
services = wmi_connect_thermal_namespace();
}
return services ? wmi_query_temperature(services) : -1.0;
}
#elif defined(__APPLE__)
{
static int initialized = 0;
static io_connect_t conn = IO_OBJECT_NULL;
double hottest = -1.0;
size_t i;
if (!initialized) {
initialized = 1;
conn = smc_open();
}
if (conn == IO_OBJECT_NULL) return -1.0;
for (i = 0; i < sizeof(smc_cpu_temp_keys) / sizeof(smc_cpu_temp_keys[0]); i++) {
double value;
if (smc_read_temperature(conn, smc_cpu_temp_keys[i], &value) &&
value > 0.0 && value <= 150.0 && value > hottest)
hottest = value;
}
return hottest;
}
#else
return -1.0;
#endif
}
static double sample_cpu_clock_mhz(void)
{
#if defined(__linux__)
DIR *dir = opendir("/sys/devices/system/cpu");
struct dirent *entry;
double total = 0.0;
long count = 0;
if (dir) {
while ((entry = readdir(dir)) != NULL) {
char path[512], *end;
double value;
if (strncmp(entry->d_name, "cpu", 3) != 0 || !isdigit((unsigned char)entry->d_name[3])) continue;
strtol(entry->d_name + 3, &end, 10);
if (*end) continue;
snprintf(path, sizeof(path), "/sys/devices/system/cpu/%s/cpufreq/scaling_cur_freq", entry->d_name);
if (read_number_file(path, &value) && value > 0.0) { total += value / 1000.0; count++; }
}
closedir(dir);
}
if (count) return total / (double)count;
{
FILE *f = fopen("/proc/cpuinfo", "r");
char line[256];
if (!f) return -1.0;
while (fgets(line, sizeof(line), f)) {
double value;
if (sscanf(line, "cpu MHz%*[^:]: %lf", &value) == 1 && value > 0.0) { total += value; count++; }
}
fclose(f);
}
return count ? total / (double)count : -1.0;
#elif defined(__APPLE__)
/* No public API reports live per-core frequency on macOS (none exists at
* all on Apple Silicon); sysctl hw.cpufrequency is a fixed nominal value,
* not a real-time reading, so report unavailable rather than a constant. */
return -1.0;
#elif defined(_WIN32)
{
PROCESSOR_POWER_INFORMATION info[64];
SYSTEM_INFO sysinfo;
DWORD count, i;
double total = 0.0;
GetSystemInfo(&sysinfo);
count = sysinfo.dwNumberOfProcessors;
if (count == 0) count = 1;
if (count > 64) count = 64;
if (CallNtPowerInformation(ProcessorInformation, NULL, 0, info,
count * sizeof(PROCESSOR_POWER_INFORMATION)) != 0)
return -1.0;
for (i = 0; i < count; i++) total += info[i].CurrentMhz;
return count ? total / (double)count : -1.0;
}
#else
return -1.0;
#endif
}
static void record_telemetry_sample(struct telemetry_monitor *monitor)
{
struct telemetry_sample *sample;
if (monitor->count >= MAX_TELEMETRY_SAMPLES) return;
sample = &monitor->samples[monitor->count++];
sample->elapsed_ms = (uint64_t)((now_seconds() - monitor->started) * 1000.0);
sample->temperature_c = sample_cpu_temperature();
sample->clock_mhz = sample_cpu_clock_mhz();
}
static void telemetry_sleep(void)
{
#if defined(_WIN32)
Sleep(25);
#else
usleep(25000);
#endif
}
#if defined(_WIN32)
static DWORD WINAPI telemetry_entry(LPVOID arg)
#else
static void *telemetry_entry(void *arg)
#endif
{
struct telemetry_monitor *monitor = (struct telemetry_monitor *)arg;
double next = monitor->started;
#if defined(_WIN32)
/* sample_cpu_temperature() lazily opens a WMI connection on first use,
* which requires this thread's COM apartment to be initialized first. */
CoInitializeEx(NULL, COINIT_MULTITHREADED);
#endif
while (!monitor->stop) {
double current = now_seconds();
if (current >= next) { record_telemetry_sample(monitor); next += TELEMETRY_REFRESH_INTERVAL; }
telemetry_sleep();
}
record_telemetry_sample(monitor);
#if defined(_WIN32)
CoUninitialize();
return 0;
#else
return NULL;
#endif
}
static int start_telemetry_monitor(struct telemetry_monitor *monitor, double started)
{
memset(monitor, 0, sizeof(*monitor));
monitor->started = started;
#if defined(_WIN32)
monitor->thread = CreateThread(NULL, 0, telemetry_entry, monitor, 0, NULL);
return monitor->thread != NULL;
#else
return pthread_create(&monitor->thread, NULL, telemetry_entry, monitor) == 0;
#endif
}
static void stop_telemetry_monitor(struct telemetry_monitor *monitor, int started)
{
if (!started) return;
monitor->stop = 1;
#if defined(_WIN32)
WaitForSingleObject(monitor->thread, INFINITE);
CloseHandle(monitor->thread);
#else
pthread_join(monitor->thread, NULL);
#endif
}
struct cpu_snapshot { uint64_t total, idle; }; struct cpu_snapshot { uint64_t total, idle; };
static int take_cpu_snapshot(struct cpu_snapshot *s) static int take_cpu_snapshot(struct cpu_snapshot *s)
@@ -1239,9 +789,7 @@ int fossbench_run(int verbose, int upload_mode, int system_check)
struct result real_multi[NTESTS], real_single[NTESTS]; struct result real_multi[NTESTS], real_single[NTESTS];
struct system_info system_info; struct system_info system_info;
struct background_metrics background; struct background_metrics background;
struct telemetry_monitor telemetry;
double benchmark_started; double benchmark_started;
int telemetry_started;
uint64_t duration_ms; uint64_t duration_ms;
size_t i; size_t i;
@@ -1262,7 +810,6 @@ int fossbench_run(int verbose, int upload_mode, int system_check)
} }
} }
benchmark_started = now_seconds(); benchmark_started = now_seconds();
telemetry_started = start_telemetry_monitor(&telemetry, benchmark_started);
printf("\n preparing workloads..."); printf("\n preparing workloads...");
fflush(stdout); fflush(stdout);
@@ -1313,7 +860,6 @@ int fossbench_run(int verbose, int upload_mode, int system_check)
} }
printf(" --------------------------------------------------------------------------\n"); printf(" --------------------------------------------------------------------------\n");
stop_telemetry_monitor(&telemetry, telemetry_started);
duration_ms = (uint64_t)((now_seconds() - benchmark_started) * 1000.0); duration_ms = (uint64_t)((now_seconds() - benchmark_started) * 1000.0);
printf(" %-24s %41.2fs\n", "TOTAL DURATION", (double)duration_ms / 1000.0); printf(" %-24s %41.2fs\n", "TOTAL DURATION", (double)duration_ms / 1000.0);
@@ -1344,8 +890,7 @@ int fossbench_run(int verbose, int upload_mode, int system_check)
fprintf(stderr, " Upload support is disabled in this build.\n"); fprintf(stderr, " Upload support is disabled in this build.\n");
#else #else
upload_results(&system_info, raw_multi, raw_single, upload_results(&system_info, raw_multi, raw_single,
real_multi, real_single, duration_ms, &background, real_multi, real_single, duration_ms, &background);
&telemetry);
#endif #endif
} }
} }
+1 -23
View File
@@ -157,8 +157,7 @@ static int upload_results(const struct system_info *info,
const struct result *raw_single, const struct result *raw_single,
const struct result *real_multi, const struct result *real_multi,
const struct result *real_single, uint64_t duration_ms, const struct result *real_single, uint64_t duration_ms,
const struct background_metrics *background, const struct background_metrics *background)
const struct telemetry_monitor *telemetry)
{ {
char host[256], port[16], path[512], payload[131072]; char host[256], port[16], path[512], payload[131072];
char auth_header[600], response_body[2048], claim_url[1024], result_url[1024]; char auth_header[600], response_body[2048], claim_url[1024], result_url[1024];
@@ -225,27 +224,6 @@ static int upload_results(const struct system_info *info,
if (n < 0 || (size_t)n >= sizeof payload - used) return 0; if (n < 0 || (size_t)n >= sizeof payload - used) return 0;
used += (size_t)n; used += (size_t)n;
if (!append_result_tests(payload, sizeof payload, &used, real_multi, real_single)) return 0; if (!append_result_tests(payload, sizeof payload, &used, real_multi, real_single)) return 0;
if (used + 3 >= sizeof payload) return 0;
n = snprintf(payload + used, sizeof payload - used, "],\"telemetry\":[");
if (n < 0 || (size_t)n >= sizeof payload - used) return 0;
used += (size_t)n;
{
size_t i;
for (i = 0; i < telemetry->count; i++) {
const struct telemetry_sample *sample = &telemetry->samples[i];
char temperature[32], clock[32];
if (sample->temperature_c < 0.0) strcpy(temperature, "null");
else snprintf(temperature, sizeof(temperature), "%.2f", sample->temperature_c);
if (sample->clock_mhz < 0.0) strcpy(clock, "null");
else snprintf(clock, sizeof(clock), "%.2f", sample->clock_mhz);
n = snprintf(payload + used, sizeof payload - used,
"%s{\"elapsed_ms\":%llu,\"temperature_c\":%s,\"clock_mhz\":%s}",
i ? "," : "", (unsigned long long)sample->elapsed_ms,
temperature, clock);
if (n < 0 || (size_t)n >= sizeof payload - used) return 0;
used += (size_t)n;
}
}
if (used + 4 >= sizeof payload) return 0; if (used + 4 >= sizeof payload) return 0;
memcpy(payload + used, "]}}", 4); memcpy(payload + used, "]}}", 4);
payload_len = (int)(used + 3); payload_len = (int)(used + 3);