From b3d2028aa4ec4f455d5935485eb85adef02fa815 Mon Sep 17 00:00:00 2001 From: nakst <> Date: Thu, 20 Jan 2022 10:44:20 +0000 Subject: [PATCH] capture memory dump on test timeout --- util/build.c | 102 +++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 83 insertions(+), 19 deletions(-) diff --git a/util/build.c b/util/build.c index cdafe5b..d0f74b7 100644 --- a/util/build.c +++ b/util/build.c @@ -16,11 +16,10 @@ #error Unknown target. #endif -#include -#include - #define CROSS_COMPILER_INDEX (11) +#include +#include #include #include #include @@ -35,6 +34,10 @@ #include #include #include +#include +#include +#include +#include #include "../shared/crc.h" #define API_TESTS_FOR_RUNNER @@ -51,8 +54,9 @@ bool coloredOutput; bool encounteredErrors; bool interactiveMode; bool canBuildLuigi; -int emulatorTimeout; -bool emulatorDidTimeout; +volatile int emulatorTimeout; +volatile bool emulatorDidTimeout; +sem_t emulatorSemaphore; FILE *systemLog; char compilerPath[4096]; int argc; @@ -426,6 +430,59 @@ void Build(int optimise, bool compile) { (double) (endTime.tv_sec - startTime.tv_sec) + (double) (endTime.tv_nsec - startTime.tv_nsec) / 1000000000); } +void *TimeoutThread(void *) { + emulatorDidTimeout = false; + + struct timespec endTime; + clock_gettime(CLOCK_REALTIME, &endTime); + endTime.tv_sec += emulatorTimeout; + + while (sem_timedwait(&emulatorSemaphore, &endTime)) { + if (errno == ETIMEDOUT) { + emulatorDidTimeout = true; + break; + } + } + + if (emulatorDidTimeout) { + int fd = socket(AF_UNIX, SOCK_STREAM, 0); + if (fd == -1) perror("socket"); + struct sockaddr socketName = { AF_UNIX, "qemumon" }; + if (connect(fd, &socketName, sizeof(socketName) + 8) == -1) perror("connect"); + + const char *command1 = "dump-guest-memory -p bin/mem.dat\n"; + const char *command2 = "quit\n"; + + char input[100]; + int inputBytes; + + inputBytes = recv(fd, input, sizeof(input) - 1, 0); + if (inputBytes == -1) perror("recv"); + else printf("got \"%.*s\"\n", inputBytes, input); + + if (send(fd, command1, strlen(command1), 0) == -1) perror("send"); + + sleep(20); + + inputBytes = recv(fd, input, sizeof(input) - 1, 0); + if (inputBytes == -1) perror("recv"); + else printf("got \"%.*s\"\n", inputBytes, input); + + if (send(fd, command2, strlen(command2), 0) == -1) perror("send"); + + while (true) { + int inputBytes = recv(fd, input, sizeof(input) - 1, 0); + if (inputBytes == -1) perror("recv"); + else if (inputBytes == 0) break; + else printf("got \"%.*s\"\n", inputBytes, input); + } + + close(fd); + } + + return NULL; +} + #define LOG_VERBOSE (0) #define LOG_NORMAL (1) #define LOG_NONE (2) @@ -443,14 +500,6 @@ void Run(int emulator, int log, int debug) { switch (emulator) { case EMULATOR_QEMU_NO_GUI: /* fallthrough */ case EMULATOR_QEMU: { - char timeoutFlags[256]; - - if (emulatorTimeout) { - snprintf(timeoutFlags, sizeof(timeoutFlags), "timeout %ds ", emulatorTimeout); - } else { - timeoutFlags[0] = 0; - } - const char *biosFlags = ""; const char *drivePrefix = "-drive file=bin/drive"; @@ -542,20 +591,33 @@ void Run(int emulator, int log, int debug) { const char *displayFlags = emulator == EMULATOR_QEMU_NO_GUI ? " -display none " : ""; - int exitCode = CallSystemF("%s %s %s " QEMU_EXECUTABLE " %s%s %s -m %d %s -smp cores=%d -cpu Haswell " + char timeoutFlags[256]; + pthread_t timeoutThread; + + if (emulatorTimeout) { + sem_init(&emulatorSemaphore, 0, 0); + snprintf(timeoutFlags, sizeof(timeoutFlags), "-monitor unix:qemumon,server,nowait "); + pthread_create(&timeoutThread, NULL, TimeoutThread, NULL); + } else { + timeoutFlags[0] = 0; + } + + int exitCode = CallSystemF("%s %s " QEMU_EXECUTABLE " %s%s %s -m %d %s -smp cores=%d -cpu Haswell " " -device qemu-xhci,id=xhci -device usb-kbd,bus=xhci.0,id=mykeyboard -device usb-mouse,bus=xhci.0,id=mymouse " " -netdev user,id=u1 -device e1000,netdev=u1 -object filter-dump,id=f1,netdev=u1,file=bin/Logs/net.dat " - " %s %s %s %s %s %s %s %s ", - timeoutFlags, audioFlags, IsOptionEnabled("Emulator.RunWithSudo") ? "sudo " : "", drivePrefix, driveFlags, cdromFlags, + " %s %s %s %s %s %s %s %s %s ", + audioFlags, IsOptionEnabled("Emulator.RunWithSudo") ? "sudo " : "", drivePrefix, driveFlags, cdromFlags, atoi(GetOptionString("Emulator.MemoryMB")), debug ? (debug == DEBUG_NONE ? "-enable-kvm" : "-s -S") : "-s", - cpuCores, audioFlags2, logFlags, usbFlags, usbFlags2, secondaryDriveFlags, biosFlags, serialFlags, displayFlags); + cpuCores, audioFlags2, usbFlags, usbFlags2, secondaryDriveFlags, biosFlags, serialFlags, displayFlags, timeoutFlags, logFlags); bool printStartupErrorMessage = exitCode != 0; if (emulatorTimeout) { - emulatorDidTimeout = (exitCode >> 8) == 124; + sem_post(&emulatorSemaphore); + pthread_join(timeoutThread, NULL); if (emulatorDidTimeout) printStartupErrorMessage = false; + sem_destroy(&emulatorSemaphore); } if (printStartupErrorMessage) { @@ -1264,7 +1326,7 @@ void GetSource(const char *parameters, const char *checksum) { } void RunTests(int singleTest) { - // TODO Capture (and compress) emulator memory dump if a test causes a KernelPanic or EsPanic. + // TODO Capture emulator memory dump if a test causes a EsPanic. // TODO Using SMP/KVM if available in the optimised test runs. int successCount = 0, failureCount = 0; @@ -1289,6 +1351,7 @@ void RunTests(int singleTest) { if (optimisations) BuildAndRun(OPTIMISE_FULL, true, DEBUG_LATER, EMULATOR_QEMU_NO_GUI, LOG_NORMAL); else BuildAndRun(OPTIMISE_OFF, true, DEBUG_LATER, EMULATOR_QEMU_NO_GUI, LOG_NORMAL); emulatorTimeout = 0; + if (emulatorDidTimeout) CallSystemF("mv bin/mem.dat bin/Logs/mem_%d_%d.dat", optimisations, index); if (emulatorDidTimeout) encounteredErrors = false; if (encounteredErrors) { fprintf(stderr, "Compile errors, stopping tests.\n"); goto stopTests; } char *log = (char *) LoadFile("bin/Logs/qemu_serial1.txt", NULL); @@ -1310,6 +1373,7 @@ void RunTests(int singleTest) { stopTests:; fprintf(stderr, ColorHighlight "%d/%d tests succeeded." ColorNormal "\n", successCount, successCount + failureCount); fclose(testFailures); + unlink("root/Essence/Settings/API Tests/test.dat"); if (failureCount && automatedBuild) exit(1); }