diff --git a/CMakeLists.txt b/CMakeLists.txt index 8b8f484..befa3a7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,6 +28,10 @@ if(NOT CMAKE_BUILD_TYPE) "Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel Asan UBsan." FORCE) endif(NOT CMAKE_BUILD_TYPE) +include(GNUInstallDirs) +set(OVNI_CONFIG_RELDIR "${CMAKE_INSTALL_DATADIR}/ovni") +set(OVNI_CONFIG_DIR "${CMAKE_INSTALL_PREFIX}/${OVNI_CONFIG_RELDIR}") + include(CheckIPOSupported) check_ipo_supported(RESULT ipo_available OUTPUT error LANGUAGES C) @@ -70,4 +74,4 @@ if(BUILD_TESTING) add_subdirectory(test) endif() -install(DIRECTORY cfg/ DESTINATION share/ovni) +install(DIRECTORY cfg/ DESTINATION "${OVNI_CONFIG_RELDIR}") diff --git a/doc/index.md b/doc/index.md index c76b124..27016b3 100644 --- a/doc/index.md +++ b/doc/index.md @@ -39,5 +39,5 @@ To start a trace follow these steps: directory containing the runtime trace. - Finally run the `ovniemu ovni` command to generate the Paraver traces. - Use the command `wxparaver ovni/cpu.prv` to load the CPU trace. -- Load the configurations from the `cfg/` directory that you are +- Load the configurations from the `ovni/cfg/` directory that you are interested in, to open a timeline view. diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 57fb4f0..30e8a2e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -8,6 +8,9 @@ add_library(ovni SHARED target_include_directories(ovni PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) +configure_file("config.h.in" "${CMAKE_CURRENT_BINARY_DIR}/config.h" ) +include_directories(${CMAKE_CURRENT_BINARY_DIR}) + add_executable(ovniemu chan.c emu.c diff --git a/src/config.h.in b/src/config.h.in new file mode 100644 index 0000000..cb7d8dd --- /dev/null +++ b/src/config.h.in @@ -0,0 +1,9 @@ +/* Copyright (c) 2022 Barcelona Supercomputing Center (BSC) + * SPDX-License-Identifier: GPL-3.0-or-later */ + +#ifndef OVNI_CONFIG_H +#define OVNI_CONFIG_H + +#cmakedefine OVNI_CONFIG_DIR "@OVNI_CONFIG_DIR@" + +#endif /* OVNI_CONFIG_H */ diff --git a/src/emu.c b/src/emu.c index 4347c52..e1463f9 100644 --- a/src/emu.c +++ b/src/emu.c @@ -13,9 +13,11 @@ #include #include #include +#include #include #include +#include "config.h" #include "chan.h" #include "emu.h" #include "ovni.h" @@ -1039,6 +1041,149 @@ emu_init(struct ovni_emu *emu, int argc, char *argv[]) emu->total_nthreads); } +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: %s\n", src, strerror(errno)); + return -1; + } + + FILE *outfile = fopen(dst, "w"); + + if (outfile == NULL) { + err("fopen(%s) failed: %s\n", src, strerror(errno)); + 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: %s\n", src, strerror(errno)); + failed = 1; + goto bay; + } + + if (mkdir(dst, 0755) != 0) { + err("mkdir \"%s\" failed: %s\n", src, strerror(errno)); + failed = 1; + goto bay; + } + + /* Use the heap, as the recursion may exhaust the stack */ + char *newsrc = calloc(1, PATH_MAX); + if (newsrc == NULL) + die("calloc failed\n"); + + char *newdst = calloc(1, PATH_MAX); + if (newdst == NULL) + die("calloc failed\n"); + + struct dirent *dirent; + while ((dirent = readdir(dir)) != NULL) { + struct stat st; + sprintf(newsrc, "%s/%s", src, dirent->d_name); + + 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("path too long \"%s/%s\"\n", src, dirent->d_name); + failed = 1; + continue; + } + + int m = snprintf(newdst, PATH_MAX, "%s/%s", + dst, dirent->d_name); + + if (m >= PATH_MAX) { + err("path too long \"%s/%s\"\n", dst, dirent->d_name); + failed = 1; + continue; + } + + if (stat(newsrc, &st) != 0) { + err("stat \"%s\" failed: %s\n", newsrc, + strerror(errno)); + 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); + +bay: + return -failed; +} + +static void +copy_configs(struct ovni_emu *emu) +{ + /* 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]; + if (snprintf(dst, PATH_MAX, "%s/cfg", emu->tracedir) >= PATH_MAX) { + err("cannot copy config files: path too long \"%s/cfg\"\n", + emu->tracedir); + return; + } + + struct stat st; + if (stat(dst, &st) == 0) { + err("existing cfg directory \"%s\", skipping config copy\n", dst); + if (emu->enable_linter) + die("cannot continue in linter mode\n"); + return; + } + + if (copy_recursive(src, dst) != 0) { + err("warning: cannot copy config files: recursive copy failed\n"); + if (emu->enable_linter) + die("cannot continue in linter mode\n"); + } +} + static void emu_post(struct ovni_emu *emu) { @@ -1048,6 +1193,8 @@ emu_post(struct ovni_emu *emu) write_row_cpu(emu); write_row_thread(emu); + + copy_configs(emu); } static void diff --git a/test/macros.cmake b/test/macros.cmake index e255828..da3d980 100644 --- a/test/macros.cmake +++ b/test/macros.cmake @@ -46,6 +46,9 @@ function(ovni_test source) list(APPEND OVNI_TEST_ENV "OVNI_CURRENT_DIR=${CMAKE_CURRENT_BINARY_DIR}") + list(APPEND OVNI_TEST_ENV + "OVNI_CONFIG_DIR=${CMAKE_SOURCE_DIR}/cfg") + if(OVNI_TEST_SORT) list(APPEND OVNI_TEST_ENV "OVNI_DO_SORT=1") endif()