From f76d160c69c760dad53350b5d06619f286e432e0 Mon Sep 17 00:00:00 2001 From: Rodrigo Arias Date: Thu, 16 Feb 2023 11:04:50 +0100 Subject: [PATCH] Copy Paraver configs to output directory --- src/emu/CMakeLists.txt | 1 + src/emu/pv/cfg.c | 165 +++++++++++++++++++++++++++++++++++++++ src/emu/pv/cfg.h | 9 +++ src/emu/recorder.c | 8 ++ test/macros.cmake | 4 + test/unit/CMakeLists.txt | 1 + test/unit/cfg.c | 29 +++++++ 7 files changed, 217 insertions(+) create mode 100644 src/emu/pv/cfg.c create mode 100644 src/emu/pv/cfg.h create mode 100644 test/unit/cfg.c diff --git a/src/emu/CMakeLists.txt b/src/emu/CMakeLists.txt index 26152bb..71133b3 100644 --- a/src/emu/CMakeLists.txt +++ b/src/emu/CMakeLists.txt @@ -34,6 +34,7 @@ add_library(emu STATIC pv/prf.c pv/prv.c pv/pvt.c + pv/cfg.c recorder.c system.c task.c diff --git a/src/emu/pv/cfg.c b/src/emu/pv/cfg.c new file mode 100644 index 0000000..62d075c --- /dev/null +++ b/src/emu/pv/cfg.c @@ -0,0 +1,165 @@ +/* Copyright (c) 2021-2023 Barcelona Supercomputing Center (BSC) + * SPDX-License-Identifier: GPL-3.0-or-later */ + +#define _POSIX_C_SOURCE 200112L + +#include "cfg.h" + +#include +#include +#include +#include +#include +#include + +#include "common.h" +#include "config.h" + +static int +copy_file(const char *src, const char *dst) +{ + char buffer[1024]; + + FILE *infile = fopen(src, "r"); + + if (infile == NULL) { + err("fopen(%s) failed:", src); + return -1; + } + + FILE *outfile = fopen(dst, "w"); + + if (outfile == NULL) { + err("fopen(%s) failed:", src); + return -1; + } + + size_t bytes; + while ((bytes = fread(buffer, 1, sizeof(buffer), infile)) > 0) + fwrite(buffer, 1, bytes, outfile); + + fclose(outfile); + fclose(infile); + + return 0; +} + +static int +copy_recursive(const char *src, const char *dst) +{ + DIR *dir; + int failed = 0; + + if ((dir = opendir(src)) == NULL) { + err("opendir '%s' failed:", src); + return -1; + } + + if (mkdir(dst, 0755) != 0) { + err("mkdir '%s' failed:", src); + return -1; + } + + /* Use the heap, as the recursion may exhaust the stack */ + char *newsrc = calloc(1, PATH_MAX); + if (newsrc == NULL) { + err("calloc failed:"); + return -1; + } + + char *newdst = calloc(1, PATH_MAX); + if (newdst == NULL) { + die("calloc failed:"); + return -1; + } + + struct dirent *dirent; + while ((dirent = readdir(dir)) != NULL) { + struct stat st; + + if (strcmp(dirent->d_name, ".") == 0) + continue; + + if (strcmp(dirent->d_name, "..") == 0) + continue; + + int n = snprintf(newsrc, PATH_MAX, "%s/%s", + src, dirent->d_name); + + if (n >= PATH_MAX) { + err("src path too long: %s/%s", src, dirent->d_name); + failed = 1; + continue; + } + + int m = snprintf(newdst, PATH_MAX, "%s/%s", + dst, dirent->d_name); + + if (m >= PATH_MAX) { + err("dst path too long: %s/%s", dst, dirent->d_name); + failed = 1; + continue; + } + + if (stat(newsrc, &st) != 0) { + err("stat '%s' failed:", newsrc); + failed = 1; + continue; + } + + if (S_ISDIR(st.st_mode)) { + if (copy_recursive(newsrc, newdst) != 0) { + failed = 1; + } + } else { + if (copy_file(newsrc, newdst) != 0) { + failed = 1; + } + } + } + + closedir(dir); + + free(newsrc); + free(newdst); + + if (failed) { + err("some files couldn't be copied"); + return -1; + } + + return 0; +} + +int +cfg_generate(const char *tracedir) +{ + /* TODO: generate the configuration files dynamically instead of + * copying them from a directory */ + + /* Allow override so we can run the tests without install */ + char *src = getenv("OVNI_CONFIG_DIR"); + + if (src == NULL) + src = OVNI_CONFIG_DIR; + + char dst[PATH_MAX]; + char *cfg = "cfg"; + if (snprintf(dst, PATH_MAX, "%s/%s", tracedir, cfg) >= PATH_MAX) { + err("path too long: %s/%s", tracedir, cfg); + return -1; + } + + struct stat st; + if (stat(dst, &st) == 0) { + err("directory '%s' already exists, skipping config copy", dst); + return -1; + } + + if (copy_recursive(src, dst) != 0) { + err("cannot copy config files: recursive copy failed"); + return -1; + } + + return 0; +} diff --git a/src/emu/pv/cfg.h b/src/emu/pv/cfg.h new file mode 100644 index 0000000..a6018f0 --- /dev/null +++ b/src/emu/pv/cfg.h @@ -0,0 +1,9 @@ +/* Copyright (c) 2021-2023 Barcelona Supercomputing Center (BSC) + * SPDX-License-Identifier: GPL-3.0-or-later */ + +#ifndef CFG_H +#define CFG_H + +int cfg_generate(const char *tracedir); + +#endif /* CFG_H */ diff --git a/src/emu/recorder.c b/src/emu/recorder.c index c1e9022..b61ea27 100644 --- a/src/emu/recorder.c +++ b/src/emu/recorder.c @@ -5,6 +5,8 @@ #include "recorder.h" +#include "pv/cfg.h" + int recorder_init(struct recorder *rec, const char *dir) { @@ -75,5 +77,11 @@ recorder_finish(struct recorder *rec) } } + /* TODO: Use configs per pvt */ + if (cfg_generate(rec->dir) != 0) { + err("cfg_generate failed"); + return -1; + } + return 0; } diff --git a/test/macros.cmake b/test/macros.cmake index a71b3e3..fb0e4a3 100644 --- a/test/macros.cmake +++ b/test/macros.cmake @@ -42,9 +42,13 @@ function(unit_test source) COMMAND "${OVNI_TEST_NAME}" WORKING_DIRECTORY "${OVNI_TEST_BUILD_DIR}") + list(APPEND OVNI_TEST_ENV + "OVNI_CONFIG_DIR=${CMAKE_SOURCE_DIR}/cfg") + set_tests_properties("${OVNI_TEST_NAME}" PROPERTIES RUN_SERIAL TRUE + ENVIRONMENT "${OVNI_TEST_ENV}" WORKING_DIRECTORY "${OVNI_TEST_BUILD_DIR}") endfunction(unit_test) diff --git a/test/unit/CMakeLists.txt b/test/unit/CMakeLists.txt index 070aadc..c266f34 100644 --- a/test/unit/CMakeLists.txt +++ b/test/unit/CMakeLists.txt @@ -14,6 +14,7 @@ unit_test(bay-hash-speed.c) unit_test(mux.c) unit_test(value.c) unit_test(prv.c) +unit_test(cfg.c) #unit_test(ovni_model.c) #unit_test(trace.c) #unit_test(emu.c) diff --git a/test/unit/cfg.c b/test/unit/cfg.c new file mode 100644 index 0000000..dfe297c --- /dev/null +++ b/test/unit/cfg.c @@ -0,0 +1,29 @@ +#define _GNU_SOURCE + +#include "emu/pv/cfg.h" +#include "common.h" + +#include +#include +#include +#include + +int main(void) +{ + char dir[] = "/tmp/ovni.trace.XXXXXX"; + if (mkdtemp(dir) == NULL) + die("mkdtemp failed:"); + + if (cfg_generate(dir) != 0) + die("cfg_generate failed"); + + /* Check that one configuration file is present */ + char cfg[PATH_MAX]; + sprintf(cfg, "%s/cfg/cpu/ovni/pid.cfg", dir); + + struct stat st; + if (stat(cfg, &st) != 0) + die("stat failed"); + + return 0; +}