# Statistical Profiler Implementation in Maru: Platform-Specific Deep Dive

> Explore Maru's statistical profiler implementation. Discover how it uses SIGVTALRM to sample execution with Linux syscall or libc wrappers for diverse build environments.

- Repository: [Attila Lendvai/maru](https://github.com/attila-lendvai/maru)
- Tags: deep-dive
- Published: 2026-02-25

---

**Maru implements a lightweight statistical profiler that periodically samples program execution via SIGVTALRM signals, providing both a freestanding Linux syscall variant and a standard libc wrapper to accommodate different build environments.**

The **statistical profiler implementation** in the `attila-lendvai/maru` repository enables low-overhead performance analysis by interrupting execution at configurable intervals to capture the instruction pointer. This dual-architecture design allows the same profiling logic to operate in bare-metal Linux environments without C library dependencies as well as in conventional userspace applications. The system exposes a minimal API consisting of signal handler installation and timer configuration functions.

## Platform-Specific Architecture

Maru maintains parallel implementations selected at build time based on the target platform. Both versions deliver identical functionality but differ fundamentally in their system interface approach.

### Freestanding Linux Implementation

The freestanding variant resides in [`source/platforms/linux/profiler.c`](https://github.com/attila-lendvai/maru/blob/main/source/platforms/linux/profiler.c) and operates entirely without libc dependencies. This implementation invokes raw Linux syscalls directly through a custom `syscall6` assembly wrapper that marshals arguments into registers (`rax`, `rdi`, `rsi`, `rdx`, `r10`, `r8`, `r9`) before executing the `syscall` instruction.

To install the profiling handler, the code constructs a `struct k_sigaction` and invokes `rt_sigaction` using signal number 26 for **SIGVTALRM**. The implementation manually sets the `SA_RESTORER` flag (`0x4000000`) and provides a `sigreturn_trampoline` function:

```c
/* source/platforms/linux/profiler.c */
extern void install_profiler_handler(void (*handler)(int))
{
    struct k_sigaction kact;
    kact.k_sa_handler = handler;
    kact.sa_flags = 0x4000000;       /* SA_RESTORER */
    kact.sa_restorer = sigreturn_trampoline;
    k_sigemptyset(&kact.sa_mask);

    long sigset_size = (long)(KERNEL_SIGSET_WORDS * sizeof(kernel_sigword_t));

    syscall6(SYS_rt_sigaction,
             26,            /* SIGVTALRM */
             (long)&kact,
             0,             /* oldact */
             sigset_size,
             0, 0);
}

```

The timer configuration uses `setitimer` with `ITIMER_VIRTUAL` to trigger signals based on process execution time rather than wall-clock time. The `set_profiler_interval()` function accepts an integer specifying microseconds between samples:

```c
/* source/platforms/linux/profiler.c */
extern void set_profiler_interval(int microseconds)
{
    struct itimerval_k kv;

    if (microseconds == 0) {
        kv.it_interval.tv_sec = kv.it_interval.tv_usec = 0;
        kv.it_value.tv_sec   = kv.it_value.tv_usec   = 0;
    } else {
        kv.it_interval.tv_sec  = microseconds / 1000000;
        kv.it_interval.tv_usec = microseconds % 1000000;
        kv.it_value = kv.it_interval;
    }

    syscall6(SYS_setitimer,
             ITIMER_VIRTUAL,
             (long)&kv,
             0, 0, 0, 0);
}

```

### Standard libc Implementation

The libc-based implementation in [`source/platforms/libc/profiler.c`](https://github.com/attila-lendvai/maru/blob/main/source/platforms/libc/profiler.c) provides the same functionality through standard C library wrappers. This version significantly reduces code complexity by delegating signal management to `sigaction` and `setitimer`.

The handler installation uses the conventional `struct sigaction` approach:

```c
/* source/platforms/libc/profiler.c */
extern void install_profiler_handler(void (*handler)(int))
{
    struct sigaction sa;
    sa.sa_handler = handler;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;
    if (sigaction(SIGVTALRM, &sa, 0))
        perror("vtalrm");
}

```

Timer configuration follows identical logic but uses the libc `setitimer` wrapper:

```c
/* source/platforms/libc/profiler.c */
extern void set_profiler_interval(int microseconds)
{
    struct itimerval itv = { { 0, microseconds }, { 0, microseconds } };
    setitimer(ITIMER_VIRTUAL, &itv, NULL);
}

```

## Practical Usage Example

Applications integrate the profiler by implementing a sampling callback and invoking the configuration functions. The following example demonstrates the libc implementation:

```c
#include <stdio.h>
#include "profiler.h"

static void sample_handler(int sig)
{
    (void)sig;
    /* Record program counter or backtrace here */
    fprintf(stderr, "profile sample\n");
}

int main(void)
{
    /* Install the handler */
    install_profiler_handler(sample_handler);

    /* Sample every 100,000 microseconds (0.1 seconds) */
    set_profiler_interval(100000);

    /* Application work */
    for (volatile int i = 0; i < 10000000; ++i) {
        /* Busy loop */
    }

    /* Disable profiling */
    set_profiler_interval(0);
    return 0;
}

```

For freestanding builds, link against [`source/platforms/linux/profiler.c`](https://github.com/attila-lendvai/maru/blob/main/source/platforms/linux/profiler.c) instead and ensure your binary provides a `_start` entry point.

## Current Limitations and Status

The freestanding Linux implementation contains a `TODO` comment acknowledging that the code "doesn't work" and suffers from "accidental complexity." This indicates the profiler remains experimental, particularly for kernel-specific syscall implementations. The libc version maintains better stability but requires a functioning C library environment.

## Summary

- **Maru's statistical profiler** uses `SIGVTALRM` signals triggered by virtual timers to sample execution at microsecond intervals.
- **Dual implementations** support both freestanding Linux environments ([`source/platforms/linux/profiler.c`](https://github.com/attila-lendvai/maru/blob/main/source/platforms/linux/profiler.c)) and libc-based systems ([`source/platforms/libc/profiler.c`](https://github.com/attila-lendvai/maru/blob/main/source/platforms/libc/profiler.c)).
- **Core API** consists of `install_profiler_handler()` to register callbacks and `set_profiler_interval()` to configure sampling frequency.
- **Freestanding version** employs raw syscalls (`rt_sigaction`, `setitimer`) via a `syscall6` assembly wrapper to avoid C library dependencies.
- **Disabling the profiler** requires passing `0` to `set_profiler_interval()` to zero out the timer structures.

## Frequently Asked Questions

### How does Maru's statistical profiler work without a C library?

The freestanding implementation in [`source/platforms/linux/profiler.c`](https://github.com/attila-lendvai/maru/blob/main/source/platforms/linux/profiler.c) bypasses libc entirely by invoking raw Linux syscalls through a generic `syscall6` assembly function. This wrapper moves arguments into the correct registers and executes the `syscall` instruction directly, allowing signal handler installation and timer configuration in environments without standard library support.

### What signal does the Maru profiler use for sampling?

The profiler uses **SIGVTALRM** (signal number 26), triggered by `ITIMER_VIRTUAL` timers that count only when the process is executing. This virtual timer ensures profiling samples correlate with actual CPU time consumed rather than wall-clock time.

### How do I stop the profiler once it has started?

Pass `0` as the argument to `set_profiler_interval()`. Both implementations interpret zero as a disable command, clearing the `itimerval` structures and stopping the `SIGVTALRM` delivery.

### Why does Maru maintain two different profiler implementations?

The dual-architecture design accommodates different deployment targets. The libc version offers portability and simplicity for standard applications, while the freestanding Linux version enables profiling in minimal environments such as kernels, bootloaders, or sandboxed containers where linking against libc is undesirable or impossible.