Files
totk-pc-recomp/runtime/sysinfo.c
T
Valiantsin DzerakhandClaude Opus 5.5 c7b290f2b0 Write the log of a game run to logs\totk.log next to totk.exe when stderr is not a file
A player who starts totk.exe from Explorer or a shortcut had no log to attach to a report: the log went only to stderr.
A game run whose stderr is not a file (a console or a pipe) now also writes logs\totk.log, keeps the four earlier
runs as totk.1.log to totk.4.log, and stops the file at 64 MiB. Runs whose stderr is a file (run_game.py, 2> file) and
the tool modes write no extra file. Lines from before the file opens (mem_init comes first so the CRT heap stays out of
the guest address space) wait in a static buffer.

Crash reports, fatal errors, IPC and SVC diagnostics, guest debug output and the boot: lines now go through
rt_logf / rt_log_raw, so they reach the file too. Open log folder in the menu opens the folder of the file.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 12:41:12 +03:00

94 lines
3.6 KiB
C

// What a bug report needs about the machine (sysinfo.h). The OS calls sit behind platform.h; the GPU and driver come
// from the Vulkan device the game renders on.
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#if defined(__x86_64__) || defined(__i386__)
#include <cpuid.h>
#endif
#include "cfg.h"
#include "host.h"
#include "platform/platform.h"
#include "sysinfo.h"
#include "vk.h"
void sysinfo_cpu_name(char *out, size_t n) {
out[0] = 0;
#if defined(__x86_64__) || defined(__i386__)
unsigned r[12];
if (__get_cpuid_max(0x80000000, NULL) < 0x80000004) return;
for (unsigned i = 0; i < 3; i++) __get_cpuid(0x80000002 + i, &r[i * 4], &r[i * 4 + 1], &r[i * 4 + 2], &r[i * 4 + 3]);
char b[49];
memcpy(b, r, 48);
b[48] = 0;
const char *p = b;
while (*p == ' ') p++;
snprintf(out, n, "%s", p);
for (char *e = out + strlen(out); e > out && e[-1] == ' '; e--) e[-1] = 0;
#endif
}
int sysinfo_log_folder(char *out, size_t n) {
const char *log = rt_log_path();
if (log) snprintf(out, n, "%s", log);
else if (!plat_stderr_path(out, n) && !plat_exe_path(out, n)) return 0;
char *s = strrchr(out, '\\'), *f = strrchr(out, '/');
if (f > s) s = f;
if (!s) return 0;
*s = 0;
return 1;
}
typedef struct { char *buf; size_t n, at; } Out;
static void put(Out *o, const char *fmt, ...) __attribute__((format(printf, 2, 3)));
static void put(Out *o, const char *fmt, ...) {
if (o->at + 1 >= o->n) return;
va_list ap;
va_start(ap, fmt);
int k = vsnprintf(o->buf + o->at, o->n - o->at, fmt, ap);
va_end(ap);
if (k > 0) o->at = o->at + (size_t)k < o->n ? o->at + (size_t)k : o->n - 1;
}
static void put_setting(const char *key, const char *value, int from_env, void *ctx) {
put(ctx, from_env ? " TOTK_%s=%s (environment)\n" : " %s = %s\n", key, value);
}
int sysinfo_text(char *buf, size_t n) {
if (!n) return 0;
Out o = {buf, n, 0};
buf[0] = 0;
char s[256];
put(&o, "TotK Recomp system info\n");
put(&o, "OS: %s\n", plat_os_version(s, sizeof s) ? s : "unknown");
sysinfo_cpu_name(s, sizeof s);
put(&o, "CPU: %s, %u logical processors\n", s[0] ? s : "unknown", plat_cpu_count());
float used, total, proc;
plat_mem_info(&used, &total, &proc);
if (total > 0) put(&o, "RAM: %.1f GB, %.1f GB in use, the game %.1f GB\n", total / 1024, used / 1024, proc / 1024);
VkCtx *c = vk_ctx();
if (c) {
VkPhysicalDeviceDriverProperties dp = {.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES};
VkPhysicalDeviceProperties2 p2 = {.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2, .pNext = &dp};
vkGetPhysicalDeviceProperties2(c->phys, &p2);
const VkPhysicalDeviceProperties *p = &p2.properties;
uint64_t vram = 0;
for (uint32_t h = 0; h < c->mem_props.memoryHeapCount; h++)
if (c->mem_props.memoryHeaps[h].flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) vram += c->mem_props.memoryHeaps[h].size;
put(&o, "GPU: %s (vendor 0x%04x, device 0x%04x), %.1f GB device-local memory\n", p->deviceName, p->vendorID,
p->deviceID, vram / 1073741824.0);
put(&o, "Driver: %s %s, driver version 0x%08x, Vulkan %u.%u.%u\n", dp.driverName, dp.driverInfo,
p->driverVersion, VK_API_VERSION_MAJOR(p->apiVersion), VK_API_VERSION_MINOR(p->apiVersion),
VK_API_VERSION_PATCH(p->apiVersion));
} else {
put(&o, "GPU: no Vulkan device yet\n");
}
put(&o, "Settings with a value:\n");
size_t before = o.at;
cfg_each_active(put_setting, &o);
if (o.at == before) put(&o, " none\n");
return (int)o.at;
}