Several tickets on trac have a potential solution that would require us to use global variables. Specifically, for ex:
Error handling (for CPPAD to propagate error code correctly and use jmi->jmi_log for printing messages):
https://trac.jmodelica.org/ticket/257
https://trac.jmodelica.org/ticket/1501
Memory management (reimplementation of malloc/free within FMU):
https://trac.jmodelica.org/ticket/1216
https://trac.jmodelica.org/ticket/1497
In both cases making a “jmi_t*” global would allow to solve the issue. However, global variables are a problem in the general case when several instances of the same JMU/FMU are loaded into a process. To make things even more general we need to assume that the process runs multiple threads concurrently and each thread has its own JMU/FMU.
I see two ways to proceed:
- With global vars:
The “current_jmi” pointer should be set by all the JMU/FMU functions that may result in memory allocation/error handling calls, such as ode_derivatives. The normal solution for the multi-threaded case is to use thread local storage. This however presents a portability issue: what thread library should be used?
Pthreads:
pthread_key_create(&key, 0) ; pthread_set_specific(key, current_jmi)
Openmp:
#pragma omp threadprivate(current_jmi)The best way is probably to have some callback into the calling process, e.g.:
setThreadLocalEnvironment(void*), void* getThreadLocalEnvironment(). If those callbacks are not present then serial execution is assumed. Note that the current standard does not have any provision/recommendations on multithreaded environment that I could find.If we take this approach than we should propose modification to the FMI standard (additional callbacks).
For error handling with CppAd our implementation of CPPAD_DISCRETE_FUNCTION() would be able to access jmi* for logging error messages. -
Not using global vars.
For memory management in FMU we would need to modify Sundials/Superlu/other libs so that jmi pointer is propagated to the routines that do memory allocation. One way is to introduce memory allocation callbacks for the libs.For error handling with CppAd we can either do some tricks like:
typedef union {
jmi_real_t val;
void* ptr;
} jmi_union_ptr_dbl_t;
And then send in jmi pointer as an argument to the tape. Even if possible – this is not very nice.
An alternative is to request a modification to the CppAd: ability to specify custom streams for output of PrintOp. Since this is a good general feature I plan to ask Brad Bell about it.
My current preference would be:
- Use global jmi_t pointer with memory allocation callbacks. Request fmiCallbackFunctions structure to be complemented with fmiReallocateMemory/setThreadLocalEnvironment. / getThreadLocalEnvironment. I’d also propose to add fmiReallocateMemory() to the existing interface. Lack of “reallocate” makes life more difficult when re-implementing all the memory allocation methods since one needs to allocate extra size_t to keep the size of memory block. In Jmodelica this feature should be optional, e.g., controlled by compiler flag. This is since malloc/free do exist on most platforms and an implementation via FMI would make it just slower.
- Use custom stream and CppAd PrintOp for error reporting. Note that there is a conditional version of Print in the latest version of CppAD. BTW how often do we update ThirdParty/CppAD? Note that this is only needed for JMU with CppAD (as of today, might change).
Comments?
/Iakov