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

Fix OncePerThread issue when building a sysimage using the current sysimage #57656

Open
wants to merge 4 commits into
base: master
Choose a base branch
from

Conversation

gbaraldi
Copy link
Member

@gbaraldi gbaraldi commented Mar 6, 2025

This is quite tricky to test unfortunately, but #57544 caught this and this fixes that

src/staticdata.c Outdated
@@ -3143,6 +3144,22 @@ static void jl_save_system_image_to_stream(ios_t *f, jl_array_t *mod_array,
}
jl_queue_for_serialization(&s, global_roots_list);
jl_queue_for_serialization(&s, global_roots_keyset);
precompile_field_replace_list = jl_alloc_svec(3);
Copy link
Member

Choose a reason for hiding this comment

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

Please add some comments explaining why this is necessary

@@ -3129,7 +3130,7 @@ static void jl_save_system_image_to_stream(ios_t *f, jl_array_t *mod_array,
jl_queue_for_serialization(&s, s.method_roots_list);
jl_serialize_reachable(&s);
}
// step 1.4: prune (garbage collect) special weak references from the jl_global_roots_list
// step 1.4: prune (garbage collect) special weak references from the jl_global_roots_list and field replace list
if (worklist == NULL) {
Copy link
Member

Choose a reason for hiding this comment

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

Why doesn't this issue apply to pkgimages?

Copy link
Member Author

Choose a reason for hiding this comment

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

pkgimages seal their own world so they their globals don't get compiled twice. The issue here is that on a normal sysimage you do inherit the world.

Copy link
Member

Choose a reason for hiding this comment

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

Is it not possible to load a pkgimage (and its globals) when building a sysimage?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, but those changes don't get saved

Copy link
Member

Choose a reason for hiding this comment

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

You mean that we copy the data from the pkgimage, instead of the in-memory objects?

I'm not sure that's true (or something else is going wrong). If you compile this package:

module OncePerFoo

const f = OncePerThread{Nothing}() do
    println(Core.stdout, "Running thread init...")
end

__init__() = (f(); println(Core.stdout, "Hello World!"))

f() # Executed during pre-compilation

end # module OncePerFoo

and then compile with juliac.jl --trim=no the following script:

module MyApp

using OncePerFoo

Base.@ccallable function main()::Cint
    OncePerFoo.f()
    return 0
end

OncePerFoo.f() # fire init during compilation time

end

the OncePerThread does not fire at runtime, even with this PR applied:

$ ./onceperfoo
Hello World!

Copy link
Member Author

Choose a reason for hiding this comment

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

Oh this is an interesting case and is very tricky. I didn't think of the case where we use packageimages to build a system image. This means we have to merge these from different package images

Copy link
Member

@topolarity topolarity Mar 6, 2025

Choose a reason for hiding this comment

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

Yeah, either that or the the fields need to be marked as "sticky" in the sysimage (i.e. they are auto-replaced with their original value from whatever image they were loaded from)

@topolarity
Copy link
Member

This is quite tricky to test unfortunately

It seems a bit laborious given that you have to compile multiple images, but the behavior seems 100% deterministic to me and very easy to trigger.

Is the main problem that we don't have an incremental sysimage build in CI right now?

@gbaraldi
Copy link
Member Author

gbaraldi commented Mar 6, 2025

Yeah, to test it you have to build an image with a once per thread in it.
Then using that image you initialize the OncePerThread and build another julia on top of it.
Finally with that image you test if it got cleared correctly

topolarity added a commit that referenced this pull request Mar 7, 2025
Both `--trim=no` and `--trim=safe` are supposed to be safe options by
default, so let's not get overzealous and throw out all the IR even
though we're not trimming

Allows `juliac.jl` to use/test the sysimage creation pipeline unrelated
to `--trim` support, as in
#57656 (comment)
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.

3 participants