# Unsafe functions performance

**URL:** <https://discourse.julialang.org/t/unsafe-functions-performance/7845>\
**Category:** Internals & Design\
**Created:** [December 19, 2017, 9:31am UTC](https://discourse.julialang.org/t/unsafe-functions-performance/7845 "2017-12-19T09:31:59Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![Liso](https://avatars.discourse-cdn.com/v4/letter/l/898d66/32.png) [@Liso](https://discourse.julialang.org/u/Liso)\
**Post date:** [December 19, 2017, 9:32am UTC](https://discourse.julialang.org/t/unsafe-functions-performance/7845/1 "2017-12-19T09:32:00Z")

</div>

I was trying to understand sizeof(s::String) functions to help @xiaodai to improve performance…

I was experimenting with undocumented hidden “len” field of String (it was present in Julia 0.6 and seems to be lost in Julia 0.7.0):

```julia
julia> sizof(a) = unsafe_load(Base.unsafe_convert(Ptr{UInt}, pointer(a)-8));

```

Benchmark results are impressive:

```julia
julia> @btime sizeof("abc")
  0.018 ns (0 allocations: 0 bytes)
3

julia> @btime sizof("abc")
  1.740 ns (0 allocations: 0 bytes)
0x0000000000000003

```

Why are unsafe functions 100 (!) times slower in this test?

---

<div class="post-metadata">

**Author:** ![maleadt](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/maleadt/32/10097_2.png) [@maleadt](https://discourse.julialang.org/u/maleadt)\
**Post date:** [December 19, 2017, 9:51am UTC](https://discourse.julialang.org/t/unsafe-functions-performance/7845/2 "2017-12-19T09:51:27Z")

</div>

Strange, even after adding alignment information (using `Base.pointerref(..., 1, 8)`) which then results in identical LLVM and native code, the performance discrepancy remains.

EDIT: on 0.6, both implementations are equally slow (ie. same as the slow time from OP).

---

<div class="post-metadata">

**Author:** ![kristoffer.carlsson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kristoffer.carlsson/32/22_2.png) [@kristoffer.carlsson](https://discourse.julialang.org/u/kristoffer.carlsson)\
**Post date:** [December 19, 2017, 10:30am UTC](https://discourse.julialang.org/t/unsafe-functions-performance/7845/3 "2017-12-19T10:30:24Z")

</div>

Probably some interaction with the testing framework? IPO and all that.

---

<div class="post-metadata">

**Author:** ![ScottPJones](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/scottpjones/32/146_2.png) [@ScottPJones](https://discourse.julialang.org/u/ScottPJones)\
**Post date:** [December 19, 2017, 10:44am UTC](https://discourse.julialang.org/t/unsafe-functions-performance/7845/4 "2017-12-19T10:44:40Z")

</div>

> [@Liso](#):
>
> julia\> sizof(a) = unsafe\_load(Base.unsafe\_convert(Ptr{UInt}, pointer(a)-8));

I think there’s something off with your testing, because the code generated (at least on master) is identical.

One, when `sizeof(str)` does exactly what you need here, and is generic, why do you want to peek at the internals?  
Also, why you are calling `Base.unsafe_convert`, which is for converting something, when you really just need to `reinterpret` the pointer, i.e. `reinterpret(Ptr{UInt}, pointer(a)-8)`?

> unsafe\_convert(T, x)
> 
> Convert x to a C argument of type T where the input x must be the return value of cconvert(T, …).

---

<div class="post-metadata">

**Author:** ![maleadt](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/maleadt/32/10097_2.png) [@maleadt](https://discourse.julialang.org/u/maleadt)\
**Post date:** [December 19, 2017, 11:02am UTC](https://discourse.julialang.org/t/unsafe-functions-performance/7845/5 "2017-12-19T11:02:51Z")

</div>

> [@kristoffer.carlsson](#):
>
> Probably some interaction with the testing framework? IPO and all that.

Yeah, 0.018 ns is pretty unrealistic of a measurement even for a simple pointer load. Trying to bisect now.

> [@ScottPJones](#):
>
> I think there’s something off with your testing, because the code generated (at least on master) is identical.

Yeah, no. I can reproduce it perfectly on master, so there’s probably something off with the testing infrastructure itself.

---

<div class="post-metadata">

**Author:** ![ScottPJones](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/scottpjones/32/146_2.png) [@ScottPJones](https://discourse.julialang.org/u/ScottPJones)\
**Post date:** [December 19, 2017, 11:28am UTC](https://discourse.julialang.org/t/unsafe-functions-performance/7845/6 "2017-12-19T11:28:39Z")

</div>

That’s why I like to look at raw numbers from `time_ns()` for benchmarking very small things! 🙂

---

<div class="post-metadata">

**Author:** ![maleadt](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/maleadt/32/10097_2.png) [@maleadt](https://discourse.julialang.org/u/maleadt)\
**Post date:** [December 19, 2017, 11:39am UTC](https://discourse.julialang.org/t/unsafe-functions-performance/7845/7 "2017-12-19T11:39:50Z")

</div>

In this case `time_ns` does indeed show consistent results (of ~19ns, but that’s to be expected since BenchmarkTools does multiple evals/sample). However, I’d advise against recommending it, because BenchmarkTools protects against so many other common pitfalls that are common with newcomers. `@btime` is a vastly better tool.

I’ve bisected the issue to 1669d532de7434108f1092f34361166737706ba5 from #24362, confirming @kristoffer.carlsson’s hunch 🙂

---

<div class="post-metadata">

**Author:** ![ScottPJones](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/scottpjones/32/146_2.png) [@ScottPJones](https://discourse.julialang.org/u/ScottPJones)\
**Post date:** [December 19, 2017, 12:27pm UTC](https://discourse.julialang.org/t/unsafe-functions-performance/7845/8 "2017-12-19T12:27:49Z")

</div>

I wasn’t intending to recommend it for novice users - in my case though, I’ve had 30+ years of extensive benchmarking experience, and for that reason I like to get all of the raw data and munge it myself (which Julia makes much nicer / easier than in any other language I’ve worked on before! 🙂 )

> [@maleadt](#):
>
> I’ve bisected the issue to 1669d532de7434108f1092f34361166737706ba5 from #24362, confirming @kristoffer.carlsson’s hunch 🙂

Good hunch!!!
