Open anton-malakhov opened 5 years ago
The case for C-friendly and dlopen-friendly API for global settings seems valid to me. If such a contribution is made, it will be considered :) The only high-level request I have for it is to make the API RAII-like, e.g.
tbb_control_handle TBB_set_global_control(tbb_global_parameter p, size_t value);
size_t TBB_get_global_control_active_value(tbb_global_parameter p);
void TBB_remove_global_control(tbb_control_handle h);
As for environment variables, the main issues with using those for libraries- and the main reasons why we did not add TBB_NUM_THREADS
in the first place and generally strive to avoid envirable creep in TBB - are:
These are not just artificial issues, but things learned hard way in the past with e.g. our OpenMP runtime. Any solution for external control over the number of threads used by TBB needs to be done in a way that addresses the first two:
The best idea I could come up with - and I still do not like it - is to extend tbb::global_control
with a parameter to specify the name of environment variable which value should be used to set max_allowed_parallelism
. In other words, it's just another way for a program to specify max_allowed_parallelism
. And I do not like it primarily because it could be attractive for library developers, causing the problems you have described.
Added after posting: note that the above idea is essentially just a syntax sugar for what an application or high-level component is already able to do: read an environment variable of choice and use its value to set tbb::global_control(max_allowed_parallelism)
.
Thus having no single point of controlling TBB settings leads to conflicts between independent components, which implement such control themselves.
In fact, such a single point of controlling the number of threads does exist - it's the process affinity mask which TBB respects. An application or a high-level component might even temporarily change this mask, initialize TBB, and restore the one that it wants to use for the whole process.
@akukanov is this issue still relevant?
The described issue has not been addressed, to the best of my knowledge. However, for the first part of the proposal – C API for global settings – I do not know if there is enough interest, and the second part – adding environment variables – would be a somewhat risky change in TBB behavior, which needs strong justification and careful consideration.
I am fine with closing the issue; it can always be re-opened or a new one created if needed.
Problem
As TBB is getting adopted wider as a composable parallelism solution outside of traditional C++ world, the need is growing in controlling its global settings for applications, which are not written in C++. For example, MKL (which has TBB threading layer) is a library with C interface and as such is used in C applications and libraries. In turn, MKL is used in many other languages and libraries, for example, Numpy and Julia. They don't necessary know or want to know anything about how threading is implemented and what is the user's choice of the threading layer at run-time while users&applications don't want to complicate their simple application scripts with a C++ code that interacts with TBB's global_control class. They all need a simpler way to interact with TBB's global settings. For C-based projects like Numpy and Julia-lang, there should be a way to control TBB's behavior in their sub-components using a C API. For scripting languages, the function names and usage model should be friendly to use with dynamic loading of C symbols like it is for
TBB_runtime_interface_version()
. For Python, thetbb4py
module provides a way (mostly) for a user or Python scripts to control TBB's global behavior. However, many projects do not have direct dependence on TBB, e.g. Numpy optionally depends on MKL, which in turn optionally depends on TBB, thus it doesn't want to introducetbb4py
as their hard-coded requirement. So, their ideal solution would be introduction of environment variables to control TBB defaults directly the same way as sklearn/joblib/loky suggests to do it for other threaded libraries: https://github.com/numpy/numpy/issues/11826#issuecomment-437291454. Environment variables allow to avoid complications with detection and dynamic loading of TBB symbols by passing global settings 'just in case' if TBB will be loaded later. Semantics of bothglobal_control
and envvars is global anyway and thus it looks quite natural to initializeglobal_control
's with default values from environment variables. Suggestion to introduce environment variables in applications/libraries, which use TBB directly, just introduces more problems than it solves. For example, MKL has these variables but it might not be the only component, which uses/controls TBB in an application, the other popular library, which uses TBB directly and co-exists along with Numpy is Numba. Thus having no single point of controlling TBB settings leads to conflicts between independent components, which implement such control themselves.Proposals
TBB_NUM_THREADS
andTBB_STACK_SIZE