# Swift-system-clock: low-level no-overhead clock for Swift

**URL:** <https://forums.swift.org/t/swift-system-clock-low-level-no-overhead-clock-for-swift/89367>\
**Category:** Development\
**Tags:** system-library\
**Created:** [September 3, 2026, 5:12pm UTC](https://forums.swift.org/t/swift-system-clock-low-level-no-overhead-clock-for-swift/89367 "2026-09-03T17:12:50Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![MahdiBM](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/mahdibm/32/45271_2.png) [@MahdiBM](https://forums.swift.org/u/MahdiBM)\
**Post date:** [September 3, 2026, 5:12pm UTC](https://forums.swift.org/t/swift-system-clock-low-level-no-overhead-clock-for-swift/89367/1 "2026-09-03T17:12:50Z")

</div>

I've just tagged [v1.0.0-beta.1](https://github.com/swift-dns/swift-system-clock/releases/tag/v1.0.0-beta.1) of [GitHub - swift-dns/swift-system-clock: Low-level no-overhead system clock for Swift · GitHub](https://github.com/swift-dns/swift-system-clock).

This package is helpful for the users who have needs that stdlib's `Continuous/SuspendingClock`s don't satisfy.

Examples:

- Sometimes a mere `continuous` clock is too expensive to call and you'd like to trade accuracy for speed. Maybe you're just stamping a log-line. In that case you can use a `continuousCoarse` clock.
- Or maybe you'd like to count the time your process has been running on CPU cores, even if it means the clock calls can be much more expensive.

Example usage:

```swift
import SystemClock

let clock = SystemClock.processUserTime
let elapsed: CompactDuration = clock.measure {
    expensiveWork()
}

let now = SystemClock.realtime.now

```

This post is an intro for swift-system-clock. For more info see the [library's README](https://github.com/swift-dns/swift-system-clock/blob/main/README.md).

## Goals

### Swift Interface to use any OS-provided clock

Swift's own Clocks only support "continuous" or "suspending", while you can access "walltime" clocks via other means as well.

To achieve this goal, there are interfaces so you can either use the predefined clocks:

```swift
/// Currently one of: realtime, realtimeCoarse, continuous, continuousCoarse,
/// suspending, suspendingCoarse, processCPUTime, threadCPUTime
/// processUserTime, threadUserTime, processSystemTime, threadSystemTime
let myClock = SystemClock.continuousCoarse

```

Or if you prefer the clock to talk with `Swift.Duration` instead of the library's `CompactDuration`:

```swift
let myClock = GenericSystemClock<Swift.Duration>.continuousCoarse

```

### Easy to use, even while multiple platforms are supported

In swift-system-clock, you can simply declare a `SystemClock` and forget about different platforms. It'll "just work" everywhere as well as the platform supports.

If a power user requires so, they can manually specify what clocks to use on each platform:

```swift
let processCPUTimeClock = SystemClock(
    darwin: .processCPUTime,
    linux: .processCPUTime,
    windows: .processTime,
    freebsd: .processCPUTime,
    openbsd: .processCPUTime,
    wasi: .monotonic,
    fallback: .monotonic
)

```

- Every Apple platform takes `darwin`. Android takes `linux`.
- Unidentified platforms or platforms with no libc will take `fallback` which uses `std::chrono` clocks. Just like stdlib does.

Most of the **code related to a platform is only compiled when targeting that specific platform**. So while the library provides the flexibility, it comes at almost no cost.

### Needs to actually work

In short, Codecov shows **90+% test coverage**.  
**There is CI for each platform of `Darwin` (`Apple` platforms), `Linux` (Including `Android`), `Windows`, `FreeBSD`, `WASI`, and more.**  
`OpenBSD` support is not tested as Swift has yet to support `OpenBSD`.

### No overhead

There are benchmarks to confirm the library **imposes almost no overhead** compared to just manually calling the C APIs.  
Furthermore, most of the code related to a platform is only compiled when targeting that specific platform.

The following is the comparison against Swift's own stdlib primitives.  
More info in the [performance section of the README](https://github.com/swift-dns/swift-system-clock/blob/main/README.md#performance).

#### Against Darwin

| Benchmark | `SystemClock` (ns/op) | Standard Library (ns/op) | Speedup |
| --- | --- | --- | --- |
| `continuous.now` | 10.6 ns | 24.9 ns | 2.35x |
| `suspending.now` | 10.8 ns | 24.3 ns | 2.25x |

#### Against glibc

| Benchmark | `SystemClock` (ns/op) | Standard Library (ns/op) | Speedup |
| --- | --- | --- | --- |
| `continuous.now` | 27.5 ns | 29.8 ns | 1.08x |
| `suspending.now` | 27.5 ns | 29.5 ns | 1.07x |

### Make it easier to decide on a clock

Last but not least, each clock-id on each platform describes the behavior of the clock.  
This is to enable you to more-easily choose the appropriate clock for the task at hand.

Of course clocks can vary not only platform-by-platform, but also artchitecture-by-architecture, and CPU-by-CPU, so optimally you should also do your own measurements.

However the "property tables" like the followings, are meant to ease the decision without having to consult man pages which are sometimes vague, and sometimes miss the info.

All these info were measured on actual hardware.

> **Where did you measure these?**
>
> - `macOS` was measured on an M1 Pro (arm64 Apple silicon) under macOS 27, bare metal.
> - `Windows` on an Intel Core i7-10750H (x86\_64) under Windows 11, bare metal.
> - `Linux` on Ubuntu 24.04 (kernel 6.8, `HZ=1000`) in a dedicated-core AMD EPYC Milan x86\_64 VM from Hetzner.
> - `FreeBSD` 15.1 and `OpenBSD` 7.9 in arm64 QEMU virtual machines on the same Mac, where `kern.hz` is 100.
> - `WASI` on the same Mac under wasmtime 48 (primary source), Node 26 (uvwasi), Bun 1.3 and WasmKit 0.1.6.

Examples:

#### Darwin's `realtime` (`CLOCK_REALTIME`):

> Measures Wall time, counted from 1970-01-01 UTC
> 
> | **Property** | **Value** |
> | --- | --- |
> | Reacts to OS time changes | ❌ Yes |
> | Reacts to NTP changes | ❌ Yes |
> | Counts system suspension times | ❌ Yes |
> | Advances while thread is de-scheduled | ❌ Yes |
> | Might appear to go backwards | ❌ Yes |
> | Reads a cached value | ✅ No |
> | Max staleness | ✅ None |
> | Warm read cost | ~ 12ns @ 4GHz |
> | Cold read cost | ~ 200ns @ 4GHz |
> | Step granularity | 1µs |

#### Linux's `boottime` (`CLOCK_BOOTTIME`)

> Measures Elapsed time, since the machine booted
> 
> | **Property** | **Value** |
> | --- | --- |
> | Reacts to OS time changes | ✅ No |
> | Reacts to NTP changes | ❌ Yes |
> | Counts system suspension times | ❌ Yes |
> | Advances while thread is de-scheduled | ❌ Yes |
> | Might appear to go backwards | ✅ No |
> | Reads a cached value | ✅ No |
> | Max staleness | ✅ None |
> | Warm read cost | ~ 25ns @ 4GHz |
> | Cold read cost | ~ 11.2µs @ 4GHz |
> | Step granularity | 20ns |

#### Linux's `processUserTime` (`RUSAGE_SELF`)

> Measures CPU time this process spent running its own code
> 
> | Property | Value |
> | --- | --- |
> | Reacts to OS time changes | ✅ No |
> | Reacts to NTP changes | ✅ No |
> | Counts system suspension times | ✅ No |
> | Advances while thread is de-scheduled | ✅ No |
> | Might appear to go backwards | ✅ No |
> | Reads a cached value | ✅ No |
> | Max staleness | ❌ ~ 1ms @ HZ 1000 |
> | Warm read cost | ~ 220ns + ~ 12ns/thread @ 4GHz |
> | Cold read cost | ~ 4µs @ 4GHz |
> | Step granularity | 1µs |

## Implementation

Underneath, this library simply calls [clock\_gettime(2)](https://man7.org/linux/man-pages/man2/clock_gettime.2.html) libc functions, and in few cases some other functions such as [getrusage(2)](https://man7.org/linux/man-pages/man2/getrusage.2.html).

`SystemClock` is defined as:

```swift
typealias SystemClock = GenericSystemClock<CompactDuration>

```

`CompactDuration` is similar to `Swift.Duration` but it only counts `nanoseconds`, as there are little usecases for a higher-than-nanoseconds-precision clock in practice.  
Currently no clock actually provides values with higher precision than just nanoseconds..

Generally speaking, this library has similar behavior to stdlib.  
For example `SystemClock.continuous/suspending` behave pretty similar to stdlib's counterparts on all platforms.  
Or if you're on an unknown platform, this library will fall back to `std::chrono`, just like stdlib does.

## Personal Motivation

My biggest personal motivation is in benchmarking.

While a couple clocks are most what benchmarks need, sometimes you need to specify what exact clock makes sense in your specific case.

With swift-system-clock, a package like [ordo-one/benchmark](https://github.com/ordo-one/benchmark) can be extended to simply take any clock you want, and measure via that. To be clear it doesn't need to make things any more difficult and confusing for non-power-users and the APIs can reflect that.

I currently maintain a (personal) fork of ordo-one/benchmark with some extra features and fixes on top since I use it a lot and felt the need for those features, some of which save me hours of time each week.  
I'm considering reworking my fork into a more-robust benchmarking toolkit. We'll see.
