Re: Ruby memory management (was: Ruby and the Engine APIs)
On Fri, Jan 30, 2015 at 10:40 AM, Darryl L. Pierce wrote: > On Wed, Jan 28, 2015 at 01:22:45PM -0500, Rafael Schloming wrote: > > > Also, have you been able to validate your testing strategy for > either/both > > of these POCs? Can you generate seg faults and/or valgrind warnings when > > you intentionally comment out the line of code that keeps the reference > > alive? > > The POC that uses manual wrapping of a C struct works correctly, > preventing objects from being reaped without leaking memory. > > I validated this by creating exhaustive (1M+) instances of both pure Ruby > and C structs that have been wrapped via the Data_Wrap_Struct, assigning > the Ruby object to the C struct so that only C held a reference to it, > then calling GC.start to reap objects and then checking that the > expected number of the pure Ruby objects still existed, via > ObjectSpace.each_object([class]).count. Accessing the C-help Ruby object > and doing functions such as class_eval on it worked without segmentation > faults. > > I then ensures that it wasn't a fluke by commenting out, in the function > that marks the Ruby object in C to keep it from being reaped, and > re-running the tests. The app *immediately* segfaults after trying to > class_eval the first Ruby object after garbage collection. > > So this path is the right one to follow. > This sounds promising, is there any way you could highlight the key bits to look at on the branch you pointed to? Maybe post it in a way that would permit line by line comments? (My git-fu isn't super strong, so if there's already a way to do this with what you posted I apologize for the request.) --Rafael
Re: Ruby memory management (was: Ruby and the Engine APIs)
On Wed, Jan 28, 2015 at 01:22:45PM -0500, Rafael Schloming wrote: > Also, have you been able to validate your testing strategy for either/both > of these POCs? Can you generate seg faults and/or valgrind warnings when > you intentionally comment out the line of code that keeps the reference > alive? The POC that uses manual wrapping of a C struct works correctly, preventing objects from being reaped without leaking memory. I validated this by creating exhaustive (1M+) instances of both pure Ruby and C structs that have been wrapped via the Data_Wrap_Struct, assigning the Ruby object to the C struct so that only C held a reference to it, then calling GC.start to reap objects and then checking that the expected number of the pure Ruby objects still existed, via ObjectSpace.each_object([class]).count. Accessing the C-help Ruby object and doing functions such as class_eval on it worked without segmentation faults. I then ensures that it wasn't a fluke by commenting out, in the function that marks the Ruby object in C to keep it from being reaped, and re-running the tests. The app *immediately* segfaults after trying to class_eval the first Ruby object after garbage collection. So this path is the right one to follow. -- Darryl L. Pierce, Sr. Software Engineer @ Red Hat, Inc. Delivering value year after year. Red Hat ranks #1 in value among software vendors. http://www.redhat.com/promo/vendor/ pgpjpMUrU8T1Y.pgp Description: PGP signature
Re: Ruby memory management (was: Ruby and the Engine APIs)
On Wed, Jan 28, 2015 at 01:10:28PM -0500, Rafael Schloming wrote: > On Wed, Jan 28, 2015 at 1:05 PM, Darryl L. Pierce > wrote: > > > On Wed, Jan 28, 2015 at 12:06:44PM -0500, Rafael Schloming wrote: > > > Why did you reject it then? > > > > Reject it? I don't recall rejecting any option. > > I meant why did you post about the global array thing and not this. Is > there some reason you think one is preferred to the other? I described it since it was the one different from what we discussed early based on the blog posts. -- Darryl L. Pierce, Sr. Software Engineer @ Red Hat, Inc. Delivering value year after year. Red Hat ranks #1 in value among software vendors. http://www.redhat.com/promo/vendor/ pgpldLHb8zHLD.pgp Description: PGP signature
Re: Ruby memory management (was: Ruby and the Engine APIs)
No, you posted about a POC involving keeping C references alive by putting them in a global array. I then commented that it sounded like it could be brittle and might be more complicated than just wrapping the pn_rubyref_t struct manually and directly integrating with ruby gc. You then said you had a POC that did that also. Is there a reason you didn't mention the latter POC first? Which POC is better in your estimation and why? Also, have you been able to validate your testing strategy for either/both of these POCs? Can you generate seg faults and/or valgrind warnings when you intentionally comment out the line of code that keeps the reference alive? --Rafael On Wed, Jan 28, 2015 at 1:12 PM, Darryl L. Pierce wrote: > On Wed, Jan 28, 2015 at 12:06:44PM -0500, Rafael Schloming wrote: > > Why did you reject it then? > > Are you referring to this? > > "Though, I was hoping we could avoid having to manually do things..." > > What I meant was that I would like to keep the work within the confines > of the Swig code. > > -- > Darryl L. Pierce, Sr. Software Engineer @ Red Hat, Inc. > Delivering value year after year. > Red Hat ranks #1 in value among software vendors. > http://www.redhat.com/promo/vendor/ > >
Re: Ruby memory management (was: Ruby and the Engine APIs)
On Wed, Jan 28, 2015 at 12:06:44PM -0500, Rafael Schloming wrote: > Why did you reject it then? Are you referring to this? "Though, I was hoping we could avoid having to manually do things..." What I meant was that I would like to keep the work within the confines of the Swig code. -- Darryl L. Pierce, Sr. Software Engineer @ Red Hat, Inc. Delivering value year after year. Red Hat ranks #1 in value among software vendors. http://www.redhat.com/promo/vendor/ pgp41pGyVkchT.pgp Description: PGP signature
Re: Ruby memory management (was: Ruby and the Engine APIs)
On Wed, Jan 28, 2015 at 1:05 PM, Darryl L. Pierce wrote: > On Wed, Jan 28, 2015 at 12:06:44PM -0500, Rafael Schloming wrote: > > Why did you reject it then? > > Reject it? I don't recall rejecting any option. > I meant why did you post about the global array thing and not this. Is there some reason you think one is preferred to the other? --Rafael
Re: Ruby memory management (was: Ruby and the Engine APIs)
On Wed, Jan 28, 2015 at 12:06:44PM -0500, Rafael Schloming wrote: > Why did you reject it then? Reject it? I don't recall rejecting any option. -- Darryl L. Pierce, Sr. Software Engineer @ Red Hat, Inc. Delivering value year after year. Red Hat ranks #1 in value among software vendors. http://www.redhat.com/promo/vendor/ pgp_t6ZoIcDDx.pgp Description: PGP signature
Re: Ruby memory management (was: Ruby and the Engine APIs)
Why did you reject it then? --Rafael On Wed, Jan 28, 2015 at 9:54 AM, Darryl L. Pierce wrote: > On Wed, Jan 28, 2015 at 09:19:29AM -0500, Rafael Schloming wrote: > > On Wed, Jan 28, 2015 at 9:06 AM, Darryl L. Pierce > > wrote: > > > > > On Wed, Jan 28, 2015 at 06:04:57AM -0500, Rafael Schloming wrote: > > > > On the face of it this sounds like it could be quite brittle and > probably > > > > more complicated than just forgetting about swig for the one > pn_rubyref_t > > > > struct and wrapping it manually. Did you attempt the latter option at > > > all? > > > > > > Yes, there is a POC of this on my branch as well. > > > > > > > Did it work? Can you send me a pointer to it? > > Yes, it works. It uses Data_Wrap_Struct to encapsulate the pn_rubyref_t > type, rb_gc_mark to mark any Ruby object held by that type against > reaping, and does appropriate alloc and free operations on instances of > the struct. > > https://github.com/mcpierce/Proton/tree/c-to-ruby-reference-gc-check > > -- > Darryl L. Pierce, Sr. Software Engineer @ Red Hat, Inc. > Delivering value year after year. > Red Hat ranks #1 in value among software vendors. > http://www.redhat.com/promo/vendor/ > >
Re: Ruby memory management (was: Ruby and the Engine APIs)
On Wed, Jan 28, 2015 at 09:19:29AM -0500, Rafael Schloming wrote: > On Wed, Jan 28, 2015 at 9:06 AM, Darryl L. Pierce > wrote: > > > On Wed, Jan 28, 2015 at 06:04:57AM -0500, Rafael Schloming wrote: > > > On the face of it this sounds like it could be quite brittle and probably > > > more complicated than just forgetting about swig for the one pn_rubyref_t > > > struct and wrapping it manually. Did you attempt the latter option at > > all? > > > > Yes, there is a POC of this on my branch as well. > > > > Did it work? Can you send me a pointer to it? Yes, it works. It uses Data_Wrap_Struct to encapsulate the pn_rubyref_t type, rb_gc_mark to mark any Ruby object held by that type against reaping, and does appropriate alloc and free operations on instances of the struct. https://github.com/mcpierce/Proton/tree/c-to-ruby-reference-gc-check -- Darryl L. Pierce, Sr. Software Engineer @ Red Hat, Inc. Delivering value year after year. Red Hat ranks #1 in value among software vendors. http://www.redhat.com/promo/vendor/ pgpRloAgXb9mC.pgp Description: PGP signature
Re: Ruby memory management (was: Ruby and the Engine APIs)
On Wed, Jan 28, 2015 at 9:06 AM, Darryl L. Pierce wrote: > On Wed, Jan 28, 2015 at 06:04:57AM -0500, Rafael Schloming wrote: > > On the face of it this sounds like it could be quite brittle and probably > > more complicated than just forgetting about swig for the one pn_rubyref_t > > struct and wrapping it manually. Did you attempt the latter option at > all? > > Yes, there is a POC of this on my branch as well. > Did it work? Can you send me a pointer to it? --Rafael
Re: Ruby memory management (was: Ruby and the Engine APIs)
On Wed, Jan 28, 2015 at 06:04:57AM -0500, Rafael Schloming wrote: > On the face of it this sounds like it could be quite brittle and probably > more complicated than just forgetting about swig for the one pn_rubyref_t > struct and wrapping it manually. Did you attempt the latter option at all? Yes, there is a POC of this on my branch as well. -- Darryl L. Pierce, Sr. Software Engineer @ Red Hat, Inc. Delivering value year after year. Red Hat ranks #1 in value among software vendors. http://www.redhat.com/promo/vendor/ pgphTZBbOghP3.pgp Description: PGP signature
Re: Ruby memory management (was: Ruby and the Engine APIs)
On Tue, Jan 27, 2015 at 5:35 PM, Darryl L. Pierce wrote: > On Fri, Jan 23, 2015 at 03:46:34PM -0500, Darryl L. Pierce wrote: > > +1 Though, I was hoping we could avoid having to manually do things... > > So I have a working POC that assigns a Ruby object to a C struct in such > a way as to keep the Ruby object from being reaped. The solution (for > now) stores the object in a hidden global array for such objects for as > long as they're held by the C structure and, when C is deleted or the > reference changed, the object is removed from the array and available > for reaping. > > I submitted a question to the Swig users mailing list, but that seems to > be pretty low traffic and effectively unmanned ATM. Only 15 posts there > in the last month and none of them have followups. > On the face of it this sounds like it could be quite brittle and probably more complicated than just forgetting about swig for the one pn_rubyref_t struct and wrapping it manually. Did you attempt the latter option at all? It's really important to get this part right. If this isn't done well, then the whole binding will be unstable. Whatever has been done here with the current ruby bindings seems to seg fault about once every 10 test runs or so. We really can't afford to repeat that. --Rafael
Re: Ruby memory management (was: Ruby and the Engine APIs)
On Fri, Jan 23, 2015 at 03:46:34PM -0500, Darryl L. Pierce wrote: > +1 Though, I was hoping we could avoid having to manually do things... So I have a working POC that assigns a Ruby object to a C struct in such a way as to keep the Ruby object from being reaped. The solution (for now) stores the object in a hidden global array for such objects for as long as they're held by the C structure and, when C is deleted or the reference changed, the object is removed from the array and available for reaping. I submitted a question to the Swig users mailing list, but that seems to be pretty low traffic and effectively unmanned ATM. Only 15 posts there in the last month and none of them have followups. -- Darryl L. Pierce, Sr. Software Engineer @ Red Hat, Inc. Delivering value year after year. Red Hat ranks #1 in value among software vendors. http://www.redhat.com/promo/vendor/ pgpAejYR2VHPv.pgp Description: PGP signature
Re: Ruby memory management (was: Ruby and the Engine APIs)
On Fri, Jan 23, 2015 at 03:25:33PM -0500, Rafael Schloming wrote: > On Fri, Jan 23, 2015 at 2:08 PM, Darryl L. Pierce > wrote: > > > On Fri, Jan 23, 2015 at 01:49:34PM -0500, Rafael Schloming wrote: > > > It does talk about what swig does, but it also talks about the other > > > direction: > > > > > > "If the C structure references other ruby objects, then the mark function > > > pointer must also be provided and must properly mark the other objects > > with > > > rb_gc_mark()" > > > > What I meant is it's not showing how to do that. Swig is the one that's > > generating that Ruby struct wrapping, but I haven't found (yet) if they > > expose to users a way to tap into that adn do what we want. > > > > If you can find a way for swig to let you control it that's great, but I > was thinking we could just wrap this one struct by hand. It shouldn't be a > whole lot of code for just that struct, and swig can still handle the rest > of them. +1 Though, I was hoping we could avoid having to manually do things... -- Darryl L. Pierce, Sr. Software Engineer @ Red Hat, Inc. Delivering value year after year. Red Hat ranks #1 in value among software vendors. http://www.redhat.com/promo/vendor/ pgpX0na7kqfSD.pgp Description: PGP signature
Re: Ruby memory management (was: Ruby and the Engine APIs)
On Fri, Jan 23, 2015 at 2:08 PM, Darryl L. Pierce wrote: > On Fri, Jan 23, 2015 at 01:49:34PM -0500, Rafael Schloming wrote: > > It does talk about what swig does, but it also talks about the other > > direction: > > > > "If the C structure references other ruby objects, then the mark function > > pointer must also be provided and must properly mark the other objects > with > > rb_gc_mark()" > > What I meant is it's not showing how to do that. Swig is the one that's > generating that Ruby struct wrapping, but I haven't found (yet) if they > expose to users a way to tap into that adn do what we want. > If you can find a way for swig to let you control it that's great, but I was thinking we could just wrap this one struct by hand. It shouldn't be a whole lot of code for just that struct, and swig can still handle the rest of them. --Rafael
Re: Ruby memory management (was: Ruby and the Engine APIs)
On Fri, Jan 23, 2015 at 01:49:34PM -0500, Rafael Schloming wrote: > It does talk about what swig does, but it also talks about the other > direction: > > "If the C structure references other ruby objects, then the mark function > pointer must also be provided and must properly mark the other objects with > rb_gc_mark()" What I meant is it's not showing how to do that. Swig is the one that's generating that Ruby struct wrapping, but I haven't found (yet) if they expose to users a way to tap into that adn do what we want. -- Darryl L. Pierce, Sr. Software Engineer @ Red Hat, Inc. Delivering value year after year. Red Hat ranks #1 in value among software vendors. http://www.redhat.com/promo/vendor/ pgpnb2qwpo8uP.pgp Description: PGP signature
Re: Ruby memory management (was: Ruby and the Engine APIs)
It does talk about what swig does, but it also talks about the other direction: "If the C structure references other ruby objects, then the mark function pointer must also be provided and must properly mark the other objects with rb_gc_mark()" --Rafael On Fri, Jan 23, 2015 at 1:24 PM, Darryl L. Pierce wrote: > On Fri, Jan 23, 2015 at 11:02:59AM -0500, Rafael Schloming wrote: > > > For more info on how to integrate with Ruby's GC you can read this > > article[1]. It's one of the few pieces of documentation I've found that > > actually explain how to keep a reference from C to a Ruby object. > > > > [1] > > > http://clalance.blogspot.com/2013/11/writing-ruby-extensions-in-c-part-13.html > > This blog post shows how to manually do what Swig is doing for us: > represent a C struct as something Ruby can touch, with hooks to release > memory when GC runs on the Ruby wrapper. But, sadly, it's not showing > what we need, which is how to assign a reference to a Ruby object to a C > struct and then have Ruby not GC that Ruby object. > > -- > Darryl L. Pierce, Sr. Software Engineer @ Red Hat, Inc. > Delivering value year after year. > Red Hat ranks #1 in value among software vendors. > http://www.redhat.com/promo/vendor/ > >
Re: Ruby memory management (was: Ruby and the Engine APIs)
On Fri, Jan 23, 2015 at 11:02:59AM -0500, Rafael Schloming wrote: > For more info on how to integrate with Ruby's GC you can read this > article[1]. It's one of the few pieces of documentation I've found that > actually explain how to keep a reference from C to a Ruby object. > > [1] > http://clalance.blogspot.com/2013/11/writing-ruby-extensions-in-c-part-13.html This blog post shows how to manually do what Swig is doing for us: represent a C struct as something Ruby can touch, with hooks to release memory when GC runs on the Ruby wrapper. But, sadly, it's not showing what we need, which is how to assign a reference to a Ruby object to a C struct and then have Ruby not GC that Ruby object. -- Darryl L. Pierce, Sr. Software Engineer @ Red Hat, Inc. Delivering value year after year. Red Hat ranks #1 in value among software vendors. http://www.redhat.com/promo/vendor/ pgptytdsND3ZS.pgp Description: PGP signature
Re: Ruby memory management (was: Ruby and the Engine APIs)
That sounds like progress, but from what you're describing I'm not sure you're actually testing C holding onto a reference to Ruby. As you say, swig is helping you out with the Ruby -> C direction, but we need to be able to make that void * reference actually point to a ruby object (that is not pointed to by any other ruby object) and still keep it alive. If you haven't had to integrate with the ruby GC system yet then there is a pretty good chance you aren't actually testing this. It can be a bit tricky to test for a couple reasons since a) you need to force the GC to run, and b) you need to ensure there are no other references to the ruby object that is being pointed to by the C object. In fact now that I think about it, you really probably want a negative test to ensure that your testing strategy is working, i.e. keep tweaking your test until you get valgrind warnings telling you that you're accessing freed memory. Then enable the GC integration, and verify that those valgrind warnings go away. For more info on how to integrate with Ruby's GC you can read this article[1]. It's one of the few pieces of documentation I've found that actually explain how to keep a reference from C to a Ruby object. [1] http://clalance.blogspot.com/2013/11/writing-ruby-extensions-in-c-part-13.html --Rafael On Fri, Jan 23, 2015 at 9:01 AM, Darryl L. Pierce wrote: > On Thu, Jan 22, 2015 at 12:08:52PM -0500, Rafael Schloming wrote: > > The most important thing to get worked out for this is the memory > > management semantics between C and Ruby. From what I can tell from your > > branch, it looks like you haven't done that yet. > > > My initial readings into how Ruby handles object references initially > lead me to believe that, with Swig, we're receiving some benefit > already WRT object management. Since Ruby uses mark and sweep rather > than reference counts, when a Ruby object (or an C object wrapped by > Swig as a Ruby object) goes out of reference then it'll get garbage > collected. But I won't lie: there might be some subtle detail I'm > missing here. > > I played around with this last night after your suggestion and wrote > some stuff on a side branch [1]. It's a simple test that uses the > following types: > > * pn_rubyref_t - C type in Proton that's wrapped by Swig; holds a void * > reference to any kind of object > * Farkle - a pure Ruby class > > I then wrote a simple app that creates 1M instances of rb_rubyref_t and > 1M instances of Farkle as assigns a Farkle to each rb_rubyref_t. It then > puts them each into an array, which is size limited to 100k entries (to > allow any GC to run while the app is going). > > I also added finalizer function to Farkle that just outputs some text when > the object is being garbage collected. > > What I see as the app runs is the output of the Farkle instances being > garbage collected while there are still instances being created. > > The app then ends by sleeping and then exiting. > > Before and after sleeping the app outputs the number of objects (via > ObjectSpace) exist for each type. Running it multiple times I see all of > the pn_rubyref_t and Farkle instances being cleaned up, no memory > leaks. > > I then changed things to make a circular reference between Farkle and > pn_rubyref_t. Re-ran the tests and still see the objects getting cleaned > up. I also ran top to keep an eye on memory usage for the ruby-mri > process. > > O_o (1) [J:0/1028] mcpierce@mcpierce-laptop:cmake (0.3-fedora) $ top -b | > grep ruby-mri > 19989 mcpierce 20 0 188964 23228 6380 S 53.3 0.3 0:00.55 > ruby-mri > 19989 mcpierce 20 0 202644 36892 6380 S 18.3 0.5 0:01.10 > ruby-mri > 19989 mcpierce 20 0 207492 41784 6380 R 19.9 0.5 0:01.70 > ruby-mri > 19989 mcpierce 20 0 227748 62108 6380 S 17.6 0.8 0:02.23 > ruby-mri > 19989 mcpierce 20 0 229796 64020 6380 R 22.3 0.8 0:02.90 > ruby-mri > 19989 mcpierce 20 0 233096 67188 6380 R 57.1 0.8 0:03.42 > ruby-mri > 19989 mcpierce 20 0 233096 67188 6380 S 0.7 0.8 0:03.44 > ruby-mri > 19989 mcpierce 20 0 233096 67188 6380 S 0.0 0.8 0:03.44 > ruby-mri > 19989 mcpierce 20 0 233096 67188 6380 S 0.0 0.8 0:03.44 > ruby-mri > 19989 mcpierce 20 0 233096 67188 6380 S 1.3 0.8 0:03.48 > ruby-mri > 19989 mcpierce 20 0 235340 69564 6380 R 48.5 0.9 0:04.94 > ruby-mri > 19989 mcpierce 20 0 235340 69564 6380 S 47.5 0.9 0:06.37 > ruby-mri > 19989 mcpierce 20 0 235340 69564 6380 R 50.5 0.9 0:07.89 > ruby-mri > 19989 mcpierce 20 0 235340 69564 6380 S 48.0 0.9 0:09.34 > ruby-mri > > I only show those lines since, after that point, the virtual memory > footprint didn't grow for the run os the apps run. > > > [1] https://github.com/mcpierce/Proton/tree/c-to-ruby-reference-gc-check > > -- > Darryl L. Pierce, Sr. Software Engineer @ Red Hat, Inc. > Delivering value year after year. > Red Hat ranks #1 in value among softwar