From 90b66b34eb461c9151401166e8c140977f00c78c Mon Sep 17 00:00:00 2001 From: rnou Date: Tue, 11 Mar 2025 13:13:26 +0100 Subject: [PATCH 1/2] extra parameters and README --- .gitignore | 1 + CMakeLists.txt | 12 ++++ Readme.md | 0 src/opendevnull.cpp | 149 +++++++++++++++++++++++++++++++------------- 4 files changed, 120 insertions(+), 42 deletions(-) create mode 100644 .gitignore create mode 100644 Readme.md diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..567609b --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +build/ diff --git a/CMakeLists.txt b/CMakeLists.txt index cb4b6c7..db1b3c4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -48,6 +48,18 @@ target_sources(opendevnull src/opendevnull.cpp ) +# Include path from Syscall_intercept into opendevnull +target_include_directories(opendevnull + PRIVATE + ${Syscall_intercept_INCLUDE_DIR} +) + +# Link libraries +target_link_libraries( + opendevnull + Syscall_intercept::Syscall_intercept +) + target_link_libraries( eval_intercept Syscall_intercept::Syscall_intercept diff --git a/Readme.md b/Readme.md new file mode 100644 index 0000000..e69de29 diff --git a/src/opendevnull.cpp b/src/opendevnull.cpp index 3198caa..6957eb3 100644 --- a/src/opendevnull.cpp +++ b/src/opendevnull.cpp @@ -1,63 +1,128 @@ #include #include +#include #include #include -int main(int argc, char* argv[]) { - // Check if the correct number of arguments is provided - if (argc != 3) { - std::cerr << "Usage: " << argv[0] << " --syscall " << std::endl; +#include + +// Default number of repetitions +double reps = 1000.0 * 100000.0; +int repext = 1000; +int repint = 100000; +bool always_syscall = + false; // whether to call the original syscall after the hook +bool verbose = false; // whether to print debug messages + +int main(int argc, char *argv[]) { + // Parse command-line arguments + std::string syscall; + for (int i = 1; i < argc; ++i) { + std::string arg = argv[i]; + if (arg == "--syscall") { + if (i + 1 < argc) { + syscall = argv[++i]; + } else { + std::cerr << "Error: --syscall requires an argument" << std::endl; + return 1; + } + } else if (arg == "--reps") { + if (i + 1 < argc) { + reps = atof(argv[++i]); + if (reps <= 0) { + std::cerr << "Error: --reps requires a positive integer" << std::endl; + return 1; + } + } else { + std::cerr << "Error: --reps requires an argument" << std::endl; return 1; + } + } else if (arg == "--always_syscall") { + always_syscall = true; + } else if (arg == "--verbose") { + verbose = true; + } else { + std::cerr << "Error: Unknown option '" << arg << "'" << std::endl; + return 1; } + } + const int inner_loop_size = 1000000; // Size of the inner loop (1 million) + int repext = + static_cast(reps / inner_loop_size); // Outer loop iterations + int repint = inner_loop_size; // Inner loop iterations + double remainder = + std::fmod(reps, inner_loop_size); // Remaining iterations + // Validate that --syscall is provided + if (syscall.empty()) { + std::cerr << "Error: --syscall is required" << std::endl; + return 1; + } - // measure time to run in microseconds - - std::string option = argv[1]; - std::string syscall = argv[2]; - - double reps = 1000.0*100000.0; - // Handle the --syscall option - if (option == "--syscall") { - if (syscall == "open") { + // Handle the --syscall option + if (syscall == "open") { - struct timespec start, end; - clock_gettime(CLOCK_MONOTONIC, &start); - - for (int j = 0; j < 1000; j++) { - for (int i = 0; i < 100000; i++) { - int fd = openat(AT_FDCWD, "/dev/null", O_RDWR, 0); + struct timespec start, end; + clock_gettime(CLOCK_MONOTONIC, &start); - close(fd); + for (int i = 0; i < repext; ++i) { + for (int j = 0; j < repint; ++j) { + int fd = openat(AT_FDCWD, "/dev/null", O_RDWR, 0); + if (verbose) { + std::cout << "open() returned " << fd << std::endl; } + + close(fd); + } + } + for (int j = 0; j < remainder; ++j) { + int fd = openat(AT_FDCWD, "/dev/null", O_RDWR, 0); + if (verbose) { + std::cout << "open() returned " << fd << std::endl; } - clock_gettime(CLOCK_MONOTONIC, &end); - double time_taken = - (end.tv_sec - start.tv_sec) * 1e6 + (end.tv_nsec - start.tv_nsec) / 1e3; + close(fd); + } + + clock_gettime(CLOCK_MONOTONIC, &end); + double time_taken = + (end.tv_sec - start.tv_sec) * 1e6 + (end.tv_nsec - start.tv_nsec) / 1e3; + std::cout << "Mean time taken: " << time_taken / reps << " microseconds" + << std::endl; + } else if (syscall == "getpid") { + struct timespec start, end; + clock_gettime(CLOCK_MONOTONIC, &start); - std::cout << "Mean time taken: " << time_taken / reps << " microseconds" - << std::endl; + for (int i = 0; i < repext; ++i) { + for (int j = 0; j < repint; ++j) { + int ret = getpid(); + if (verbose) { + std::cout << "getpid() returned " << ret << std::endl; + } + if (always_syscall) { + syscall_no_intercept(SYS_getpid); + } + } } - else if (syscall == "getpid") { - struct timespec start, end; - clock_gettime(CLOCK_MONOTONIC, &start); - - for (int j = 0; j < 1000; j++) { - for (int i = 0; i < 100000; i++) { - int ret = getpid(); - } - } - clock_gettime(CLOCK_MONOTONIC, &end); - double time_taken = - (end.tv_sec - start.tv_sec) * 1e6 + (end.tv_nsec - start.tv_nsec) / 1e3; - - - std::cout << "Mean time taken: " << time_taken / reps << " microseconds" - << std::endl; - } + + for (int j = 0; j < remainder; ++j) { + int ret = getpid(); + if (verbose) { + std::cout << "getpid() returned " << ret << std::endl; + } + if (always_syscall) { + syscall_no_intercept(SYS_getpid); + } + } + + clock_gettime(CLOCK_MONOTONIC, &end); + double time_taken = + (end.tv_sec - start.tv_sec) * 1e6 + (end.tv_nsec - start.tv_nsec) / 1e3; + + std::cout << "Mean time taken: " << time_taken / reps << " microseconds" + << std::endl; } return 0; -- GitLab From 2a2996ef6151967f28177758bb369776f956f06f Mon Sep 17 00:00:00 2001 From: rnou Date: Tue, 11 Mar 2025 13:15:59 +0100 Subject: [PATCH 2/2] update readme, expand .ci --- .gitlab-ci.yml | 4 ++-- Readme.md | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 90a0ca0..01e7840 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -57,8 +57,8 @@ unit-test-job: # This job runs in the test stage. needs: ['build-job'] script: - ls -ltrh ${INSTALL_PATH} - - ${BUILD_PATH}/opendevnull --syscall getpid - - LD_PRELOAD=${BUILD_PATH}/libeval_intercept.so ${BUILD_PATH}/opendevnull --syscall getpid + - ${BUILD_PATH}/opendevnull --syscall getpid --reps 1 --verbose + - LD_PRELOAD=${BUILD_PATH}/libeval_intercept.so ${BUILD_PATH}/opendevnull --syscall getpid --reps 1 --verbose artifacts: expire_in: 1 week when: always diff --git a/Readme.md b/Readme.md index e69de29..7900f10 100644 --- a/Readme.md +++ b/Readme.md @@ -0,0 +1,64 @@ +# Syscall Timing Utility + +A tool for measuring and analyzing system call execution times on Linux systems. + +## Overview + +This project provides utilities to measure and analyze the timing of various system calls, helping developers understand performance characteristics and potential bottlenecks in system-level operations. + +## Prerequisites + +- Linux operating system +- CMake (version 3.13 or higher) +- C++17 compatible compiler +- syscall_intercept library + +## Installation + +```bash +mkdir build && cd build +cmake .. +make +make install +``` + +## Usage + +The project includes two main components: +- `eval_intercept`: A shared library for syscall interception +- `opendevnull`: An executable for timing syscalls + +### Running opendevnull + +```bash +./opendevnull --syscall [options] + +Options: + --reps N Number of repetitions (default: 100M) + --always_syscall Always execute the original syscall (only use with interception and getpid) + --verbose Enable debug output +``` + +## Example + +### Native syscall +```bash +./opendevnull --syscall getpid +Mean time taken: 0.329911 microseconds +``` + +### Intercepted syscall (syscall interception -> C hook -> native syscall) +```bash +LD_PRELOAD=./libeval_intercept.so ./opendevnull --syscall getpid --always_syscall +Mean time taken: 0.382829 microseconds +``` + +### Intercepted syscall (syscall interception -> C hook) , no kernel execution +```bash +LD_PRELOAD=./libeval_intercept.so ./opendevnull --syscall getpid +Mean time taken: 0.0408641 microseconds +``` + +## License + +This project is licensed under the MIT License - see the LICENSE file for details. \ No newline at end of file -- GitLab