Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

layout optimization internal changes (support pointers inlining/unboxing into parents/codegen) [disabled] #33886

Merged
merged 1 commit into from
Dec 17, 2019

Conversation

vtjnash
Copy link
Sponsor Member

@vtjnash vtjnash commented Nov 18, 2019

This includes fairly general support for pointers inside immutable structs appearing in first class aggregates (FCA) throughout the system (e.g. gc, codegen, layout). Currently it's also pretty widely enabled, although we may want to disable it for the initial merge, then slowly enable larger pieces of it as we gain understanding of the effects on the ecosystem.

This replaces #18632. It solves the "fundamental problems" described in that PR with the following rules (these need to be added to the docs and NEWs):

  • If a struct declaration is self-referential (aka references_name), and thus couldn't qualify for isbits, it also doesn't qualify for inlining. This solves the problem with cycles.
  • It a struct declaration can be incompletely initialized (n_initialized != n_fields), it doesn't quality for inlining. This solves the problem of tracking #undef. This may be relaxed in the future by adding an extra byte to track this state, although I'm not particularly keen on doing the extra work to support this edge case.
  • Note that Union{T, S} will not inline ("union-split") if either T or S contains a pointer (wouldn't be legal to codegen this, and somewhat hard to describe to the gc)

I'm interested in folks thoughts on how they'd like to see this land. Should I merge the support for each component in a separate commit (without users until all is done), or just land this as one big commit but disabled? One PR or several? And specific pieces you'd like to see land first?

@nanosoldier runbenchmarks(ALL, vs=":master")

@vtjnash vtjnash added needs docs Documentation for this change is required needs news A NEWS entry is required for this change labels Nov 18, 2019
@JeffBezanson
Copy link
Sponsor Member

I would vote for merging all the code, with stack allocation of temporaries enabled, but new memory layouts disabled. That can be enabled in a separate commit, to make it easier to revert if it is too breaking.

@andyferris
Copy link
Member

Very cool! :) I look forward to trying this out.

Can I ask - what are "first-class aggregates"? Would this include Arrays of structs containing managed pointers?

It a struct declaration can be incompletely initialized (n_initialized != n_fields), it doesn't quality for inlining. This solves the problem of tracking #undef

This is interesting. How do you know if a given struct might contain undef? Has it got to do with the existance of certain inner constructors? Is it tracked by instance? Why is this necessary? (couldn't the GC just check if the pointer within the struct is null? similarly for codegen inserting undefined reference errors wherever necessary?)

Note that Union{T, S} will not inline ("union-split") if either T or S contains a pointer (wouldn't be legal to codegen this, and somewhat hard to describe to the gc)

Just gonna say... this is going to pessimize some missing code (also nothing/something else style of code, which includes iteration). But I get that it's hard to implement.

@nanosoldier
Copy link
Collaborator

Your benchmark job has completed - possible performance regressions were detected. A full report can be found here. cc @ararslan

@JeffBezanson
Copy link
Sponsor Member

Just gonna say... this is going to pessimize some missing code (also nothing/something else style of code, which includes iteration).

IIUC, it shouldn't be worse than it is currently.

@andyferris
Copy link
Member

IIUC, it shouldn't be worse than it is currently.

No, of course - I didn't mean to imply otherwise, but was just musing over common patterns like iteration and Union{Missing, T}.

@c42f
Copy link
Member

c42f commented Nov 21, 2019

How do you know if a given struct might contain undef? Has it got to do with the existance of certain inner constructors? Is it tracked by instance? Why is this necessary?

This is currently inferred during lowering by taking the minimum of the number of arguments to new() expressions within inner constructors. It is stored per data type in the DataType ninitialized field when the data type is created. It's used by codegen to avoid emitting checks for undef when we know the field is initialized (ie, when the field index is < ninitialized).

Includes codegen support for immutable objects that contain pointers
appearing on stack (well, in registers, since LLVM support of
non-integral addrspace pointers inside aggregates in memory is poor),
and includes layout support, so that most (non-self-referential)
immutable objects can be stored inline inside their parent allocation.

Currently fully disabled, aside from some optimizations and improvements
to object_id / isa tests.

Co-Authored-By: Oscar Blumberg <[email protected]>
@vtjnash vtjnash removed needs docs Documentation for this change is required needs news A NEWS entry is required for this change labels Dec 2, 2019
@vtjnash vtjnash changed the title [WIP] layout optimization: support pointers inlining (unboxing) into parents layout optimization internal changes (support pointers inlining/unboxing into parents/codegen) [disabled] Dec 2, 2019
return jl_islayout_inline(eltype, &fsz, &al);
}

// whether this type is unique'd by pointer
Copy link
Sponsor Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// whether this type is unique'd by pointer
// whether instances of this type can use pointer comparison for `===`

@andyferris
Copy link
Member

So... I seem to remember being able to put Expr(:new, ...) anywhere. (I think I made a new “inner” constructor to Dict once when experimenting... possibly outside of Base...). I’m assuming such an operation now becomes unsafe if it fills less slots than the “real” inner constructors?

@vtjnash
Copy link
Sponsor Member Author

vtjnash commented Dec 7, 2019

Nah, that’s always been unsafe and inadvisable.

@JeffBezanson JeffBezanson added this to the 1.4 milestone Dec 12, 2019
@JeffBezanson JeffBezanson merged commit 630a551 into master Dec 17, 2019
@JeffBezanson JeffBezanson deleted the jn/codegen-ptrbits branch December 17, 2019 17:45
@@ -177,14 +177,20 @@ false
isbitsunion(u::Union) = allocatedinline(u)
isbitsunion(x) = false

function _unsetindex!(A::Array{T}, i::Int) where {T}
@inbounds function _unsetindex!(A::Array{T}, i::Int) where {T}
Copy link
Sponsor Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does @inbounds on a function do?

Copy link
Sponsor Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Supposed to be @inline.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See #34127

KristofferC pushed a commit that referenced this pull request Apr 11, 2020
Includes codegen support for immutable objects that contain pointers
appearing on stack (well, in registers, since LLVM support of
non-integral addrspace pointers inside aggregates in memory is poor),
and includes layout support, so that most (non-self-referential)
immutable objects can be stored inline inside their parent allocation.

Currently fully disabled, aside from some optimizations and improvements
to object_id / isa tests.

Co-Authored-By: Oscar Blumberg <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

7 participants