# How witr Tracks Process Start Times and Restart Counts: A Deep Dive into the Source Code

> Discover how witr tracks process start times and restart counts by analyzing kernel timestamps and service manager data. Understand the source code behind this essential monitoring.

- Repository: [Pranshu Parmar/witr](https://github.com/pranshuparmar/witr)
- Tags: deep-dive
- Published: 2026-08-09

---

**witr tracks process start times by reading kernel-level timestamps from `/proc/[pid]/stat` on Linux and native APIs on Windows/macOS, while restart counts are fetched from service managers like systemd and launchd, storing both values in a `model.Process` struct for downstream analysis.**

The open-source process monitoring tool witr (available at `pranshuparmar/witr`) provides detailed visibility into running processes by capturing metadata directly from the operating system. Understanding how witr track process start times and restart counts reveals the platform-specific implementations that power its monitoring capabilities, from parsing Linux kernel statistics to querying service manager databases.

## Tracking Process Start Times Across Platforms

witr populates the `StartedAt` field in `model.Process` by using platform-specific methods to determine when a process was created.

### Linux: Converting Kernel Ticks to Wall-Clock Time

On Linux, witr reads `/proc/[pid]/stat` to extract the process creation timestamp. The implementation in [`internal/proc/process_linux.go`](https://github.com/pranshuparmar/witr/blob/main/internal/proc/process_linux.go) parses the 22nd field (`starttime`), which contains the number of clock ticks since system boot.

```go
// internal/proc/process_linux.go
startTicks, _ := strconv.ParseInt(fields[19], 10, 64)   // fields[19] is the 22‑nd field

```

The [`internal/proc/boot_linux.go`](https://github.com/pranshuparmar/witr/blob/main/internal/proc/boot_linux.go) file provides helper functions to convert these ticks into a usable `time.Time`. First, it retrieves the system boot time from `/proc/stat` and the tick frequency via `ticksPerSecond()`. Then, `startTimeFromTicks` performs the conversion:

```go
// internal/proc/boot_linux.go
func startTimeFromTicks(boot time.Time, startTicks int64, hz int) time.Time {
    // guard against divide‑by‑zero and overflow, then:
    //   start = boot + (startTicks / hz) seconds
    //   plus any remainder converted to nanoseconds.
}

```

### Windows: Reading FILETIME from Process Handles

Windows does not expose `/proc`. Instead, witr calls the native API `GetProcessTimes` via [`internal/proc/peb_windows.go`](https://github.com/pranshuparmar/witr/blob/main/internal/proc/peb_windows.go), which returns a `FILETIME` containing the creation time.

```go
// internal/proc/peb_windows.go
func getProcessStartTime(handle syscall.Handle) time.Time {
    var creation, exit, kernel, user windows.Filetime
    windows.GetProcessTimes(handle, &creation, &exit, &kernel, &user)
    return time.Unix(0, creation.Nanoseconds())
}

```

### macOS: Using proc_pidinfo System Calls

For macOS (darwin), witr uses the same PEB abstraction pattern found in [`peb_windows.go`](https://github.com/pranshuparmar/witr/blob/main/peb_windows.go), wrapping the `proc_pidinfo` system call within `getProcessStartTime` to obtain the process creation timestamp.

## Tracking Restart Counts via Service Managers

The `RestartCount` field represents how many times the service or unit owning the process has been restarted. witr normalizes this value from platform-specific service managers.

### Systemd on Linux: Querying the NRestarts Property

For systemd-managed services, [`internal/source/systemd_linux.go`](https://github.com/pranshuparmar/witr/blob/main/internal/source/systemd_linux.go) queries the DBus property **`NRestarts`** of the unit that owns the process.

```go
// internal/source/systemd_linux.go (excerpt)
func (s *systemdSource) RestartCount(pid int) (int, error) {
    // Resolve the unit name from the cgroup, then ask systemd via DBus:
    //   property := "NRestarts"
    //   value := getUint32Property(unit, property)
    // Return the parsed integer.
}

```

### Launchd on macOS: Detecting Keepalive Behavior

On macOS, [`internal/source/launchd_darwin.go`](https://github.com/pranshuparmar/witr/blob/main/internal/source/launchd_darwin.go) checks the `keepalive` flag. If `keepalive` is configured as "Yes (restarts if killed)", witr treats the restart count as **≥ 1** and reports a generic "restarted" warning.

### Aggregating Restart Data in the Analysis Pipeline

During the ancestry walk in [`internal/pipeline/analyze.go`](https://github.com/pranshuparmar/witr/blob/main/internal/pipeline/analyze.go), witr records the highest restart count encountered in the process tree:

```go
// internal/pipeline/analyze.go (excerpt)
restartCount := 0
for _, proc := range ancestry {
    if count, ok := proc.RestartCount(); ok && count > restartCount {
        restartCount = count
    }
}
result := model.Process{
    // …
    RestartCount: restartCount,
    Warnings:     source.Warnings(ancestry, restartCount, src.Type),
}

```

The [`internal/source/detect.go`](https://github.com/pranshuparmar/witr/blob/main/internal/source/detect.go) file contains the `Warnings` helper that flags services exceeding a threshold (default **5** restarts).

## Practical Code Examples

### Reading Process Start Time on Linux

```go
pid := 1234
proc, err := proc.ReadProcess(pid)      // reads /proc files
if err != nil { panic(err) }

fmt.Printf("PID %d started at %s\n", pid, proc.StartedAt.Format(time.RFC3339))

```

### Querying Restart Count from Systemd

```go
src, _ := source.Detect(pid)            // selects the appropriate source impl
count, _ := src.RestartCount(pid)

if count > 0 {
    fmt.Printf("Process %d belongs to a service that restarted %d times\n", pid, count)
}

```

### Full Process Record with Warnings

```go
proc, _ := proc.ReadProcess(pid)
source := source.Detect(pid)
restartCount, _ := source.RestartCount(pid)

warnings := source.Warnings([]model.Process{proc}, restartCount, source.Type())
fmt.Printf("%+v\nWarnings: %v\n", proc, warnings)

```

## Summary

- **Start times** are derived from low-level OS data: kernel tick counts on Linux via [`internal/proc/process_linux.go`](https://github.com/pranshuparmar/witr/blob/main/internal/proc/process_linux.go) and [`boot_linux.go`](https://github.com/pranshuparmar/witr/blob/main/boot_linux.go), and native process-creation timestamps on Windows/macOS via [`peb_windows.go`](https://github.com/pranshuparmar/witr/blob/main/peb_windows.go).
- **Restart counts** come from the underlying service manager (systemd's `NRestarts` property or launchd's `keepalive` flag) and are normalized into a single integer.
- The **analysis pipeline** in [`internal/pipeline/analyze.go`](https://github.com/pranshuparmar/witr/blob/main/internal/pipeline/analyze.go) aggregates the maximum restart count across process ancestry and generates warnings when thresholds are exceeded.
- Both values are stored in the `model.Process` struct for consumption by output formatters and monitoring warnings.

## Frequently Asked Questions

### How does witr calculate process start times on Linux systems?

witr reads the 22nd field (`starttime`) from `/proc/[pid]/stat`, which provides clock ticks since boot. It then converts these ticks to wall-clock time using the system boot time from `/proc/stat` and the tick frequency, as implemented in [`internal/proc/boot_linux.go`](https://github.com/pranshuparmar/witr/blob/main/internal/proc/boot_linux.go).

### Where does witr obtain restart count information for systemd services?

witr queries the systemd DBus interface for the `NRestarts` property of the unit owning the process, as implemented in [`internal/source/systemd_linux.go`](https://github.com/pranshuparmar/witr/blob/main/internal/source/systemd_linux.go). This value indicates how many times systemd has automatically restarted the service.

### What file contains the logic for aggregating restart counts across process ancestry?

The aggregation logic resides in [`internal/pipeline/analyze.go`](https://github.com/pranshuparmar/witr/blob/main/internal/pipeline/analyze.go), which walks the process tree and records the highest restart count encountered. It also invokes the warning generator from [`internal/source/detect.go`](https://github.com/pranshuparmar/witr/blob/main/internal/source/detect.go) when counts exceed configured thresholds.

### How does witr handle restart detection on macOS without systemd?

On macOS, witr uses [`internal/source/launchd_darwin.go`](https://github.com/pranshuparmar/witr/blob/main/internal/source/launchd_darwin.go) to check the `keepalive` flag in the launchd configuration. If the service is configured to restart automatically, witr reports it as having been restarted, though it does not expose a numeric count as it does with systemd's `NRestarts`.