[RFC] Enable thread specific cl::opt values for multi-threaded support

Hi Yevgeny,

Just to make sure I’m understanding this correctly: When a thread has a
non-null option context, then options set in the global context will
have no effect at all for that thread. Right? (That’s what I would
expect and what makes sense to me.)

Yes, but the global context has no effect on your thread only for those
options that have been changed in this thread’s context.
That is because a thread local copy of an option is created in the
current thread context when this option is set by this thread or another
thread with the same option context. If the option has not been set then
its global value is used.
For your case, I would suggest that you explicitly set a new thread
option context for every thread (or thread group) that uses LLVM. This
way the threads/groups will not affect each other and will use the
options in the copy-on-write way.

That’s not quite what we’d need, and we can’t control all threads –
Mesa is a library, and so we can’t control what other threads are doing.

That said, it may be possible to add what we need on top of what you’re
proposing without too much effort. Basically, we’d need the
ThreadOptionContext to be optionally “opaque” in the sense of hiding
global options.

Do you actually need the ThreadOptionContext to be “transparent” for
your use case, or is that just an accidental consequence of the current
implementation?

If all threads were bound to a non-null context then there would be no one which initialized the global options. This would result in unset default values. That is why we need the very first thread (that is used to load and initialize LLVM libraries) to have the ThreadOptionContext unset, so the default option values get into the default option storage. Then, I believe, it would be ok to force all threads to have non-null ThreadOptionContexts. In other words we need to identify the library loading thread and the initialization time period while the ThreadOptionContext must be null.
These are just my thoughts. I have not tried this use model.

If the global options are not used because every thread has a ThreadOptionContext, wouldn’t it work fine to leave the global values uninitialized since nothing is using them? They could be initialized on first use.

You are right, but on the first use where can the default values be found?
It seems I know how to force cl::opt initialization to be in the global context: we have to explicitly set the ThreadOptionContext to nullptr at the beginning of the the cl::opt constructor and restore it at the end - this way all applicators are applied with null context that is the default.

template <class… Mods>
explicit opt(const Mods &… Ms)
: Option(Optional, NotHidden), Parser(*this) {
auto SavedCtx = ContextValues::ThreadOptionContext;
SetThreadOptionContex(nullptr);
apply(this, Ms…);
SetThreadOptionContex(SavedCtx);
done();
}

Thanks.
-Yevgeny Rouban

Here are copies of some key comments from the patch
https://reviews.llvm.org/D53424 Enable thread specific cl::opt values for multi-threaded support
So, please continue discussion here.