capture memory dump on test timeout

This commit is contained in:
nakst 2022-01-20 10:44:20 +00:00
parent d49ca458e2
commit b3d2028aa4
1 changed files with 83 additions and 19 deletions

View File

@ -16,11 +16,10 @@
#error Unknown target.
#endif
#include <stdint.h>
#include <stdarg.h>
#define CROSS_COMPILER_INDEX (11)
#include <stdint.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdbool.h>
#include <sys/stat.h>
@ -35,6 +34,10 @@
#include <pthread.h>
#include <sys/wait.h>
#include <spawn.h>
#include <semaphore.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/socket.h>
#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);
}