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

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


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("") 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.


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


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


Thanks for this link, it explained why our blackHole broke with Swift 5.8 - I can only echo @Karl that it would make sense to have this in the standard library, now we need to use an underscored attribute in our 'third party' source to maintain functionality. (fixing the resulting bug in our benchmark library...)

You can use @_optimize(none) instead of @inline(never).


Thanks @Slava_Pestov - worked nicely, back on track :-)