Commit 58a2cb38 authored by Ramon Nou's avatar Ramon Nou
Browse files

Merge branch 'rnou/2-add-more-parameters' into 'main'

Resolve "Add more parameters"

Closes #2

See merge request !2
parents 407e3f6e 2a2996ef
Loading
Loading
Loading
Loading
Loading

.gitignore

0 → 100644
+1 −0
Original line number Diff line number Diff line
build/
+2 −2
Original line number Diff line number Diff line
@@ -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
+12 −0
Original line number Diff line number Diff line
@@ -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

Readme.md

0 → 100644
+64 −0
Original line number Diff line number Diff line
# 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 <open|getpid> [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
+107 −42
Original line number Diff line number Diff line

#include <fcntl.h>
#include <iostream>
#include <cmath>
#include <sys/syscall.h>
#include <unistd.h>

#include <libsyscall_intercept_hook_point.h>

// 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[]) {
    // Check if the correct number of arguments is provided
    if (argc != 3) {
        std::cerr << "Usage: " << argv[0] << " --syscall <open|getpid>" << std::endl;
  // 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<int>(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") {

    struct timespec start, end;
    clock_gettime(CLOCK_MONOTONIC, &start);

      for (int j = 0; j < 1000; j++) {
        for (int i = 0; i < 100000; i++) {
    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;
      }
      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") {
  } 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++) {
    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);
        }
      }
    }

    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;
}