Compiler swallows `blackHole(_:)`

I'm trying to measure something, but I'm getting rug-pulled by the compiler. While I appreciate its attempts at making my code run faster, I need a reliable way of preventing it from erasing my benchmarks. I have tried using the following blackHole(_:) function, but I observed no change in behavior. Is there a tried and true benchmarking strategy?

@inline(never) func blackHole(_ value: some Any) { } // 😞

There's a _blackHole function in the standard library's tests that looks like this:

func _blackHolePtr<T>(_ x: UnsafePointer<T>) {
  _ = _getPointer(OpaquePointer(x))
}

public func _blackHole<T>(_ x: T) {
  var x = x
  _blackHolePtr(&x)
}

Where _getPointer isn't implemented in Swift. Perhaps sending the pointer to a C function is an important part of how this works.


I have noticed that @inline(never) is ignored if the function body is sufficiently short -- for example, this code:

@inline(never) func five() -> Int {
    return 5
}

print(five())

Compiles to a simple print(5) rather than calling the function, when optimizations are enabled.

Is your blackHole defined in a different module or package? If not, I speculate moving it to a separate module might help.

1 Like

Possibly helpful:

Hm. Using the function from a different module does not seem to help, in my case, but @_semantics("optimize.no.crossmodule") appears to prevent complete erasure. I assume SPM enables cross-module optimization by default? I saw it used in swift/.../TestsUtils.swift and adopted the underscored and stringly typed attribute in true cargo cult fashion. @_optimize(none) also seems to prevent complete erasure, but I'm unsure how it differs.

1 Like

How do we feel about exposing a public blackhole function in the standard library? This seems to come up every so often, and it's needlessly tricky to get right

5 Likes

I still think it is valuable for the compiler to provide built-in non-optimisable opaque functions for producing/consuming a value.

2 Likes