Hi, I've been having an issue with my program running slow at points where it really just shouldn't. I've finally determined (I think) that the culprit is actually garbage collection being called. I want to have more control over GC. However, the problem is, I suspect that later on it could take 1 second or longer each time it runs, and I can't have my program being blocked for that long. One option is that I could put GC in a separate thread (I haven't tested whether this will cause stability issues). Another, I wondered, is whether or not GC could be called in a fiber somehow so that its execution load can be stretched out over 5 seconds or so as I deem appropriate? Other things I'll be doing will be seeing if I can find ways to reduce the number of objects I am creating, but I suspect that I will need to look at the above kinds of improvements even after this. Thanks!
on 2013-01-14 00:47
on 2013-01-14 01:36
On Mon, 14 Jan 2013 00:48:09 +0100, Na Na <lists@ruby-forum.com> wrote: > cause stability issues). Another, I wondered, is whether or not GC > could be called in a fiber somehow so that its execution load can be > stretched out over 5 seconds or so as I deem appropriate? > > Other things I'll be doing will be seeing if I can find ways to reduce > the number of objects I am creating, but I suspect that I will need to > look at the above kinds of improvements even after this. > > Thanks! You can't do any of that. Ruby has a stop-the-world mark-and-sweep garbage collector, which means that every time GC is called *everything* (all threads, fibers, whatever) has to stop executing while GC walks *all* of your objects (starting from constants, global variables and variables in active scopes) to mark them as used and then deallocates the rest. This process can't be paused or executed partially, nor can any Ruby code run while it's in progress, because modifying the object tree while GC is traversing it could cause Ruby to miss some of your objects, and mistakenly deallocate them when they're still used. Only thing you can do is call GC.start when you want the GC to happen.
on 2013-01-14 01:42
Aha. I realised that running it in a separate thread or fiber would mean it would miss some objects, but I was thinking that would mean it may not deallocate them when it should, which I didn't care so much about. I didn't think that it might cause some to be deallocated when they shouldn't! So I suppose my options are: * Call GC only when suits me, and put up with the slowness as a part of life * Reduce the number of objects I use * Tweak the GC settings so that it's needed to be called less frequently (but I suspect this will just postpone my issues) * Try ruby 2.0's GC * Use something other than ruby for my app (nowhere near an ideal option!)
on 2013-01-14 07:14
Subject: Re: Garbage Collection and Fibers Date: Mon 14 Jan 13 09:43:20AM +0900 Quoting Na Na (lists@ruby-forum.com): > * Reduce the number of objects I use I think this is the wisest option at your disposal. When a GC'ed language is embraced, you obtain great advantages, but at the cost of some compromises. You will of course need to refactor, but the result will be better, and you will learn a lot in the process. If you find yourself in the situation you describe, it means that you are constantly creating and throwing away lots of objects. Think about what can be reused. Divide your object logic between stuff that you often need and stuff you rarely use. Stuff used often is better created at beginning and never thrown away. What I generally do is create a main class for my application. The first code I write is its initialize method, which creates and assigns to instance variables the material I am supposed to always have available. > * Use something other than ruby for my app (nowhere near an ideal > option!) NOOOOOOOOOOOO!!!! 8-) Carlo
on 2013-01-14 08:14
On Jan 14, 2013, at 1:43 AM, Na Na <lists@ruby-forum.com> wrote: > * Tweak the GC settings so that it's needed to be called less frequently > (but I suspect this will just postpone my issues) > * Try ruby 2.0's GC > * Use something other than ruby for my app (nowhere near an ideal > option!) Don't forget option X: If you don't need extensions that are fundamentally incompatible, have a look at running the whole thing on JRuby. It uses the JVMs GC, which is much better and doesn't suffer from stop-the-world issues as much. It is also very compatible with MRI. Regards, Florian
on 2013-01-14 08:38
On Mon, Jan 14, 2013 at 8:12 AM, Florian Gilcher <flo@andersground.net> wrote: > > On Jan 14, 2013, at 1:43 AM, Na Na <lists@ruby-forum.com> wrote: >> * Reduce the number of objects I use I would certainly try to find out why it's slow or GC has so much to do. What type of application are we talking about? Is it really the number of garbage to collect which makes things slow or maybe low memory leading to paging (something usually not well taken by programs with GC since the GC needs to look at a lot of memory during its work). > Don't forget option X: If you don't need extensions that are fundamentally > incompatible, have a look at running the whole thing on JRuby. It uses the > JVMs GC, which is much better and doesn't suffer from stop-the-world > issues as much. It is also very compatible with MRI. I thought that was option J. :-) Additional benefit: OP gets real threads without GIL. Kind regards robert
on 2013-01-14 14:54
I have some silly preference against JRuby. For some reason I don't like java, and it's a purely aesthetic dislike. Not even anything to do with the look of the language! I did test JRuby out though. I'm using a perlin noise gem that's been built as a c extension, and it's quite fast. Unfortunately it didn't work with jruby, and a jruby compatible gem was significantly slower. I need this speed, and don't want to rewrite it myself in java (if that turns out to be fast enough anyway). I have heard that GC is improved in ruby 2.0. >You will of course need to refactor, but the result will be better, > and you will learn a lot in the process. This I think will be very true! I need to learn how to profile the Garbage Collector, and find out the hotspots where I'm doing a lot of objection creation and deletion. I have heard a rumour that using for-in rather than .each involves more object creation and deletion, but I don't know if that's true. It will be one of the things I'll be testing to see if it helps improve performance. > Is it really the > number of garbage to collect which makes things slow or maybe low > memory leading to paging I think your suggestion here is that system memory is running out, so garbage collection is using a hard drive based swap file. If that's what you mean, I suspect that's not the issue since I have 8GB memory on my system, my app seems to use < 500MB right now, and I don't think I have enough unrelated loaded apps. I'm on mac os x and 'free' doesn't seem to work to tell me memory usage, so I can't be sure :) I will keep this in mind though.
on 2013-01-14 23:41
On Mon, Jan 14, 2013 at 2:54 PM, Na Na <lists@ruby-forum.com> wrote: > I have heard a rumour that using for-in rather than .each involves more > object creation and deletion, but I don't know if that's true. It will > be one of the things I'll be testing to see if it helps improve > performance. That isn't true. The only difference between a for loop and an each loop is the different scoping. I can't see how iterating would create more objects either way. Can you share a source of that "rumor"? Kind regards robert
on 2013-01-14 23:54
At http://www.web-l.nl/posts/15-tuning-ruby-s-garbage... under option 2, the discussion led me to believe that the writer thought changing those from for-in to each would help. I did some reading for a description on the difference between those two, and it did indeed only mention scope as the difference. I couldn't understand why that would lead to additional object creation.
on 2013-01-15 00:38
On Mon, Jan 14, 2013 at 5:54 AM, Na Na <lists@ruby-forum.com> wrote: > I did test JRuby out though. I'm using a perlin noise gem that's been > built as a c extension, and it's quite fast. Unfortunately it didn't > work with jruby, and a jruby compatible gem was significantly slower. Just curious, what gem were you using for this? There are a number of things that can affect the performance of JRuby gems (e.g. binding to poor-quality Java code, using JI instead of writing a Java extension) It looks like you probably want a gem that wraps this: http://code.j3d.org/javadoc/org/j3d/texture/proced... I think you will have a lot easier time finding a fast way to generate Perlin noise on JRuby than you will finding better garbage collection solutions on MRI
on 2013-01-15 01:11
> I think you will have a lot easier time finding a fast way to generate > Perlin noise on JRuby than you will finding better garbage collection > solutions on MRI :( Why is it that MRI is inferior to JRuby? You'd think something coded in C would run faster. Edit: I can't remember which perlin noise gem I used with JRuby. But the one I used with MRI was written in C, so very fast.
on 2013-01-15 01:23
On Tue, 15 Jan 2013 01:11:28 +0100, Na Na <lists@ruby-forum.com> wrote: >> I think you will have a lot easier time finding a fast way to generate >> Perlin noise on JRuby than you will finding better garbage collection >> solutions on MRI > > :( > > Why is it that MRI is inferior to JRuby? You'd think something coded in > C would run faster. Because Java's GC (which JRuby depends on), as well as its entire runtime, has had thousands of man-hours put into optimising it. Compared to Java, MRI was written by a couple of guys in their free time. ;)
on 2013-01-15 23:36
On Mon, Jan 14, 2013 at 11:54 PM, Na Na <lists@ruby-forum.com> wrote: > At > http://www.web-l.nl/posts/15-tuning-ruby-s-garbage... > under option 2, the discussion led me to believe that the writer thought > changing those from for-in to each would help. First of all that's the opposite of what you wrote initially. Then the author doesn't really track down the "relief" to the different looping style (he also changed to "render @model"). > I did some reading for a description on the difference between those > two, and it did indeed only mention scope as the difference. I couldn't > understand why that would lead to additional object creation. Can you show a use case you have in mind? The only memory relevant issue I can see would be allocating and releasing of additional local variables - but not objects. Cheers robert
on 2013-01-16 00:29
On Mon, Jan 14, 2013 at 4:15 PM, Na Na <lists@ruby-forum.com> wrote: > I think it was this gem: http://rubygems.org/gems/perlin_noise That's a pure Ruby gem so it's not surprising it's slower than the C version. If I were you and I really wanted to give JRuby an honest shot, I'd try using the Perlin noise function from j3d: http://code.j3d.org/javadoc/org/j3d/texture/proced...
on 2013-01-16 15:29
> That's a pure Ruby gem so it's not surprising it's slower than the C > version. > > If I were you and I really wanted to give JRuby an honest shot, I'd try > using the Perlin noise function from j3d: > > http://code.j3d.org/javadoc/org/j3d/texture/proced... Is there a quick way to try this out? I'm trying with irb: require 'java' > java.org.j3d.texture.procedural.PerlinNoiseGenerator But that's replying: NameError: missing class or uppercase package name (`java.org.j3d.texture.procedural.PerlinNoiseGenerator') from org/jruby/javasupport/JavaUtilities.java:54:in `get_proxy_or_package_under_package' from file:/usr/local/rvm/rubies/jruby-1.7.1/lib/jruby.jar!/jruby/java/java_package_module_template.rb:10:in `method_missing' from (irb):14:in `evaluate' from org/jruby/RubyKernel.java:1066:in `eval' from org/jruby/RubyKernel.java:1392:in `loop' from org/jruby/RubyKernel.java:1174:in `catch' from org/jruby/RubyKernel.java:1174:in `catch' from /usr/local/rvm/rubies/jruby-1.7.1/bin/irb:13:in `(root)' Whereas another quick test trying something else works. I am completely unfamiliar with java. Is it easy to give a quick example of how to test this PerlinNoiseGenerator inline? Thanks
on 2013-01-18 07:26
> Just curious, what gem were you using for this? There are a number of > things that can affect the performance of JRuby gems (e.g. binding to > poor-quality Java code, using JI instead of writing a Java extension) If I use 'require' to bring in a jar file, and run the code from that, is that using JI instead of Java extension? I'm not quite sure on the distinction and the implication. I'm having great difficulty finding a suitable perlin/simplex noise replacement. But that might be something I'll just have to put up with for the advantages of jruby, if indeed those advantages are worth it :)
on 2013-01-21 19:21
On Wed, Jan 16, 2013 at 8:29 AM, Na Na <lists@ruby-forum.com> wrote: > Is there a quick way to try this out? I'm trying with irb: > require 'java' >> java.org.j3d.texture.procedural.PerlinNoiseGenerator You shouldn't have "java" in front of this. You might reference classes using Java::some.package.SomeClass but normally the packages "java", "javax", "org", and "com" have top-level access. I was able to get a PerlinNoiseGenerator constructed: irb(main):001:0> puts JRUBY_VERSION 1.7.3.dev => nil irb(main):002:0> require 'jars/j3d-org-all_1.1.0.jar' => true irb(main):003:0> pg = org.j3d.texture.procedural.PerlinNoiseGenerator.new => #<Java::OrgJ3dTextureProcedural::PerlinNoiseGenerator:0x2eed7d11> - Charlie
on 2013-01-21 19:33
On Mon, Jan 14, 2013 at 6:15 PM, Na Na <lists@ruby-forum.com> wrote:
> I think it was this gem: http://rubygems.org/gems/perlin_noise
I'd like to see the benchmark you ran that was slower on JRuby with
this gem. As Tony said, we would not yet expect pure Ruby to compete
with C, but I'd like to see if we can get it closer.
- Charlie
on 2013-01-22 00:03
Charles Nutter wrote in post #1093064: > I'd like to see the benchmark you ran that was slower on JRuby with > this gem. As Tony said, we would not yet expect pure Ruby to compete > with C, but I'd like to see if we can get it closer. > > - Charlie I actually haven't given the full story, here. The "perlin" noise c-extension was actually using simplex noise, which is faster than perlin noise. So the extension had two advantages over the gem I listed: a) Simplex noise (faster than perlin) b) Coded in c So it may be a bit hard to compare them. I didn't actually create benchmarks, unfortunately. There was a task I was performing within the program that ran noticeably slower.
Please log in before posting. Registration is free and takes only a minute.
Existing account
(Switch to SSL-encrypted connection)
NEW: Do you have a Google/GoogleMail or Yahoo account? No registration required!
Log in with Google account | Log in with Yahoo account
Log in with Google account | Log in with Yahoo account
No account? Register here.