JuliaLang / julia

The Julia Programming Language
https://julialang.org/
MIT License
45.61k stars 5.48k forks source link

Feature request: Utility to show the layout that a struct definition compiles into when desugared #44943

Open NHDaly opened 2 years ago

NHDaly commented 2 years ago

@dpsanders and I were wondering if there is a utility that works similar to @code_typed and friends but works on struct definitions, rather than on methods. We wanted to know how a certain struct will end up represented in memory, in order to improve performance, but it's currently very hard to tell.

One example use case: For instance, when a struct contains a field x::Union{Nothing,T}, we want to know what kind of struct layout gets generated. Our understanding is that for types where T will be heap-allocated, meaning x will be a pointer, julia can treat the ::Nothing case as essentially a null-pointer check, so it adds 0 space overhead. Whereas for types T that are inline-allocated/stack-allocated, this requires an extra bit somewhere to track whether x should be treated as the nothing case or the T case. (like a tagged union.)

But it would be great to be able to confirm that understanding by running something like @struct_layout S or @struct_llvm S or something like that!

NHDaly commented 1 week ago

Something like this file could be a start?: struct-layouts.jl.zip (Although, i think maybe/probably would actually want to JL_DLLEXPORT some C functions to expose this info, rather than duplicating it in julia?)

Here's what it currently outputs:

julia> struct_layout(MyStruct32{Int})
---- struct MyStruct32{Int64} <: Any
   0:   x::Int32                   #  size:  4
   4:     --padding--              #  size:  4
   8:   y::Union{Nothing, Int64}   #  size:  9
  17:     --padding--              #  size:  7
---- end                           # total: 24 bytes

julia> struct_layout(MyStruct32{Vector})
---- struct MyStruct32{Vector} <: Any
   0:   x::Int32                   #  size:  4
   4:     --padding--              #  size:  4
   8:   y::Union{Nothing, Vector}  #  size:  8
---- end                           # total: 16 bytes

Which I think is a helfpful start for understanding how structs get compiled. But it's still not really quite what I'm after... I think what I really want is something more like this? (But i don't actually know how to get this information):

julia> struct_layout(MyStruct32{Int})
---- struct MyStruct32{Int64} <: Any
  0:   x::Int32                   #  size:  4
  4:     --padding--              #  size:  4
  8:   y(#val)::Int64             #  size:  8
 16:   y(#tag)::Bool              #  size:  1
 17:     --padding--              #  size:  7
---- end                          # total: 24 bytes

julia> struct_layout(MyStruct32{Vector})
---- struct MyStruct32{Int64} <: Any
  0:   x::Int32                        #  size:  4
  4:     --padding--                   #  size:  4
  8:   y::Ptr{Union{Nothing, Vector}}  #  size:  8
---- end                               # total: 16 bytes

or something like that?

Or maybe I actually want both options? Sort of like having @code_typed vs @code_llvm, for structs? Or maybe an optimize= flag to choose between these?

NHDaly commented 1 week ago

CC: @IanButterworth since this seems up your alley as well. :)

gbaraldi commented 1 week ago

Have you seen https://github.com/tecosaur/About.jl

NHDaly commented 1 week ago

Oh yeah! Very cool.

I remember @tecosaur tagged me on slack like 6+ months ago, but i was very busy at the time and didn't get back to it 😞

That looks super cool, and I think it's a much nicer presentation than what I have. 💪 Nice work @tecosaur! 💪

I think though that the About package still doesn't get to the root of what this issue is asking for, and in order for it to be able to do that, we would need to expose some more information from Julia itself. But thanks, I'll file a ticket for this over there, and link back here. 😊

tecosaur commented 1 week ago

Thanks for the kind words, if we can get Julia to expose extra useful information like this I'd love to incorporate it with the display in About.jl 🙂