Skip to content

Avoid initialization checks when accessing thread locals #44025

Closed
@ghost

Description

Thread locals are often slower than they need to be. For example, if we have:

thread_local! {
    static FOO: i32 = 777;
}

Every access of the form FOO.with(|foo| ...) will first check whether FOO is initialized, and then initialize it if this is the first access. On some (most?) platforms we can statically initialize thread locals with a constant expression (in this case the constant expression is 777).

A check on every access can be fairly costly, and we should try to avoid checks whenever possible. It is possible to avoid them by using #[thread_local] instead of thread_local!, but that is an unstable feature without a clear stabilization plan...

In #17954 @alexcrichton said:

I do not think we should strive to stabilize #[thread_local]. It's incredibly not portable which makes it not too useful for most software. We should strive to improve thread_local!. The feature to implement is for the compiler to understand whether the initialization expression is a constant expression or not. If it's a constant expression then we can bypass the None storage and "am I initialized checks", making it equivalent to raw #[thread_local]

@eddyb answered:

That's easy in the compiler but thread_local! is not implemented in the compiler.

@arielb1 suggests:

... But we could add an eager_thread_local! macro for that case.

@alexcrichton adds:

As for how to implement a "const expr detection" in a macro I'm not entirely sure. We could either move the implementation into the compiler (which I'd prefer to avoid) or take @arielb1's suggestion of a new macro or a variant of the current macro's syntax.

For example we could "perverse" the meaning via: thread_local!(const A: i32 = 3); where static in the macro means "lazily initialized, but any expression valid" and const means "must be a constant expression". I don't think this is a good idea, but an example of what we might do.

My question after all that would be:

Can we perhaps make the thread_local! macro expand to a special lang item that provides two implementations - one for the lazy initialization case and one for the static initialization zero-checks case? Then the compiler would choose one of them, depending on whether the initialization expression is a constant expression.

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-thread-localsArea: Thread local storage (TLS)C-enhancementCategory: An issue proposing an enhancement or a PR with one.I-slowIssue: Problems and improvements with respect to performance of generated code.T-libsRelevant to the library team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions