# Writable global const arrays

**URL:** <https://discourse.julialang.org/t/writable-global-const-arrays/30635>\
**Category:** Performance\
**Created:** [November 2, 2019, 6:02pm UTC](https://discourse.julialang.org/t/writable-global-const-arrays/30635 "2019-11-02T18:02:19Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![foobar\_lv2](https://avatars.discourse-cdn.com/v4/letter/f/ee59a6/32.png) [@foobar\_lv2](https://discourse.julialang.org/u/foobar_lv2)\
**Post date:** [November 2, 2019, 6:02pm UTC](https://discourse.julialang.org/t/writable-global-const-arrays/30635/1 "2019-11-02T18:02:19Z")

</div>

I tried to implement the xoshiro RNG for Base julia (cf [https://github.com/JuliaLang/julia/issues/27614](https://github.com/JuliaLang/julia/issues/27614)).

So, for this to work properly, I thought about using something like

```julia
const global_xorostate = zeros(UInt64, Threads.nthreads(), 5, 8)

```

In reality, that would wrap a `ccall(:posix_memalign, ...)`: Each thread gets 5 cache lines to play with.

Now I am already lost:

```julia
julia> f()=global_xorostate[1]
f (generic function with 1 method)

julia> @code_typed f()
CodeInfo(
1 ─ %1 = invoke Base.getindex(Main.global_xorostate::Array{UInt64,3}, 1::Int64)::UInt64
└── return %1
) => UInt64

julia> @code_native f()
	.text
; ┌ @ REPL[12]:1 within `f'
	pushq	%rax
	movabsq	$julia_getindex_16904, %rax
	movabsq	$139722737349536, %rdi # imm = 0x7F13BC2073A0
	movl	$1, %esi
	callq *%rax
	popq	%rcx
	retq
	nop

```

This should be a single memory load from a known address, because the compiler should know that `pointer_from_objref(global_xorostate)` cannot change, and it also should know that `pointer(global_xorostate)` cannot change, nor the size (because it is not one-dimensional).

So, my question: How do I tell julia 1.4/master that it is perfectly fine to chase these pointers at compile time instead of runtime? How do I get rid of the `invoke`?

Or should I try something else?

My problem with `struct` is that I don’t know how to force 64 byte alignment. A secondary problem is that I don’t know how to avoid an additional indirection through `Threads.threadid()` with structs. `Threads.threadid()` should only be used as an offset for loads of payload, not as an offset to load a pointer to payload. (I mostly know the desired assembly code, and my issue is how to coax julia into emitting that)

---

<div class="post-metadata">

**Author:** ![Elrod](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/elrod/32/22461_2.png) [@Elrod](https://discourse.julialang.org/u/Elrod)\
**Post date:** [November 2, 2019, 7:06pm UTC](https://discourse.julialang.org/t/writable-global-const-arrays/30635/2 "2019-11-02T19:06:59Z")

</div>

I overuse generated functions, and should really spend more time considering alternatives.  
That said

```julia
julia> @generated g() = :(unsafe_load($(pointer(global_xorostate))))
g (generic function with 1 method)

julia> @code_typed g()
CodeInfo(
1 ─ %1 = Base.pointerref(Ptr{UInt64} @0x00007f0e5575fd40, 1, 1)::UInt64
└── return %1
) => UInt64

julia> @code_native g()
	.text
	movabsq	$139699540065600, %rax # imm = 0x7F0E5575FD40
	movq	(%rax), %rax
	retq
	nop

```

Did you already consider and reject this approach?

Also, wouldn’t a simple pointer (like your `ccall(:posix_memalign, ...)`) produce the asm you wanted?

```julia
julia> align(x::T, a = 64) where {T} = reinterpret(T, (reinterpret(UInt,x) + a - 1) & (-a))

julia> const XORO_STATE_PTR = Base.unsafe_convert(Ptr{UInt64}, align(Libc.malloc(sizeof(UInt64) * Threads.nthreads() * 5 * 8 + 63), 64))
Ptr{UInt64} @0x000056418ca4af00

julia> reinterpret(UInt, XORO_STATE_PTR) % 64
0x0000000000000000

julia> h() = unsafe_load(XORO_STATE_PTR)
h (generic function with 1 method)

julia> h()
0x0000000000000000

julia> @code_typed h()
CodeInfo(
1 ─ %1 = Main.XORO_STATE_PTR::Core.Compiler.Const(Ptr{UInt64} @0x000056418ca4af00, false)
│ %2 = Base.pointerref(%1, 1, 1)::UInt64
└── return %2
) => UInt64

julia> @code_native h()
	.text
	movabsq	$94839532465920, %rax # imm = 0x56418CA4AF00
	movq	(%rax), %rax
	retq
	nop

```

You can of course force 64 byte alignment by just allocating extra memory, and then increment the pointer to the next multiple of 64.

There will be problems with functions like these in a module though, because that pointer will not be constant between module loads.

---

<div class="post-metadata">

**Author:** ![foobar\_lv2](https://avatars.discourse-cdn.com/v4/letter/f/ee59a6/32.png) [@foobar\_lv2](https://discourse.julialang.org/u/foobar_lv2)\
**Post date:** [November 2, 2019, 8:49pm UTC](https://discourse.julialang.org/t/writable-global-const-arrays/30635/3 "2019-11-02T20:49:32Z")

</div>

So the best way would be

```julia
julia> mutable struct ptrwrap
       ptr::Ptr{rng_instance}
       end

julia> const global_rng = ptrwrap(C_NULL)

```

and a `global_rng.ptr = call(:posix_memalign, ...)` in the ` __init__ ` function, plus a definition `default_rng() = convert(Ptr{rng_instance}, global_rng.ptr + (Threads.threadid() - 1%Int16)*320`?

Master hasn’t solved this issue either: There is a pesky `invoke` in `Base.default_rng()` as well (probably why `rand()` is so slow with multithreading).
