symengine icon indicating copy to clipboard operation
symengine copied to clipboard

Simplifing dependencies/maintenance by removing `RCP` types

Open oliverlee opened this issue 1 year ago • 8 comments

Would this project welcome a PR that replaces all RCP implementations with std::shared_ptr (and possibly allowing this to be swapped out with boost::local_shared_ptr)?

oliverlee avatar Sep 18 '24 16:09 oliverlee

I think the corresponding equivalent is boost::intrusive_ptr.

isuruf avatar Sep 18 '24 16:09 isuruf

Possibly? I'm not very familiar with the boost smart pointer library but I did see RCP and some analog to enable_shared_from_this.

oliverlee avatar Sep 18 '24 16:09 oliverlee

As @isuruf mentions the RCP is implemented as an intrusive shared pointer rather than an std::shared_ptr. This is for performance reasons. There is a compile time option to not have thread safety that would mimic the use of boost::local_shared_ptr. Since we have our own implementation I don't know if we still need the dependency to Teuchos.

rikardn avatar Sep 19 '24 08:09 rikardn

I have a branch where I started to add yet another RCP type (which would solve problems with reference counting when interacting from the python bindings). I haven't gotten around to reviving that work, but I hope to in the future.

bjodah avatar Sep 20 '24 09:09 bjodah

Is there a large performance hit from using std::shared_ptr?

Switching to a standard library implementation would decrease maintenance and possibly avoid reference counting issues from Python bindings. cppyy seems like it has out of the box support: https://github.com/search?q=repo%3Awlav%2Fcppyy%20shared_ptr&type=code

oliverlee avatar Sep 20 '24 15:09 oliverlee

I'm not convinced switching to std::shared_ptr would ease maintenance to any appreciable extent, and performance would suffer (benchmarks would be needed to quantify the slowdown though). But to me, those arguments are secondary. The header file I linked to contains information and links to nanobind's documentation that goes into great detail on the pros and cons of reference counting in c++ and its interplay with another reference counted language (in that case, python).

bjodah avatar Sep 21 '24 07:09 bjodah

Feel free to close this as it seems that there isn't much interest in switching over to standard library types.

However I do think think it would reduce the need to debug issues such as https://github.com/symengine/symengine/issues/2048, std::shared_ptr comes with utilities such as std::allocated_shared (which helps with https://github.com/symengine/symengine/issues/2051 if ever pursued) and will possibly become usable within constant expression context in C++26.

oliverlee avatar Sep 21 '24 22:09 oliverlee

I have only anecdotal numbers for the speedup of using intrusive reference counting. Around 10-20% faster for every reference increase or decrease (because of one less indirection) and as much as 50% faster for creation (due to one less heap allocation). Since symengine do so many creations and reference count incs/decs this would add up. Of course this has to be benchmarked properly to be certain. I am not entirely sure but I think the constant expression context issue should not be applicable to the intrusive counter since it is not needing a separate heap allocation, so it will be similar to unique_ptr in this respect.

rikardn avatar Sep 23 '24 08:09 rikardn