From: sam.saffron@... Date: 2018-04-29T23:50:19+00:00 Subject: [ruby-core:86767] [Ruby trunk Feature#14723] [WIP] sleepy GC Issue #14723 has been updated by sam.saffron (Sam Saffron). I really really like this, its a free performance boost with almost no downsides. I guess the simplest way of measuring it would be to run something like Discourse bench with and without the patch. In theory we should get better timings after the patch cause it decreases odds that the various GC processes will run when the interpreter wants to run Ruby. Implementation wise it seems like you only have it on rb_wait_for_single_fd, is there any way you can make this work with the pg gem? It just builds on libpq per: https://www.postgresql.org/docs/8.3/static/libpq-async.html so maybe you would need to expose an end point for libpq to "trigger" partial gc processes just when you send a query? ---------------------------------------- Feature #14723: [WIP] sleepy GC https://bugs.ruby-lang.org/issues/14723#change-71722 * Author: normalperson (Eric Wong) * Status: Open * Priority: Normal * Assignee: * Target version: ---------------------------------------- The idea is to use "idle time" when process is otherwise sleeping and using no CPU time to perform GC. It makes sense because real world traffic sees idle time due to network latency and waiting for user input. Right now, it's Linux-only. Future patches will affect other sleeping functions: IO.select, Kernel#sleep, Thread#join, Process.waitpid, etc... I don't know if this patch can be implemented for win32, right now it's just dummy functions and that will be somebody elses job. But all pthreads platforms should eventually benefit. Before this patch, the entropy-dependent script below takes 95MB consistently on my system. Now, depending on the amount of entropy on my system, it takes anywhere from 43MB to 75MB. I'm using /dev/urandom to simulate real-world network latency variations. There is no improvement when using /dev/zero because the process is never idle. require 'net/http' require 'digest/md5' Thread.abort_on_exception = true s = TCPServer.new('127.0.0.1', 0) len = 1024 * 1024 * 1024 th = Thread.new do c = s.accept c.readpartial(16384) c.write("HTTP/1.0 200 OK\r\nContent-Length: #{len}\r\n\r\n") IO.copy_stream('/dev/urandom', c, len) c.close end addr = s.addr Net::HTTP.start(addr[3], addr[1]) do |http| http.request_get('/') do |res| dig = Digest::MD5.new res.read_body { |buf| dig.update(buf) } puts dig.hexdigest end end The above script is also dependent on net/protocol using read_nonblock. Ordinary IO objects will need IO#nonblock=true to see benefits (because they never hit rb_wait_for_single_fd) * gc.c (rb_gc_inprogress): new function (rb_gc_step): ditto * internal.h: declare prototypes for new gc.c functions * thread_pthread.c (gvl_contended_p): new function * thread_win32.c (gvl_contended_p): ditto (dummy) * thread.c (rb_wait_for_single_fd w/ ppoll): use new functions to perform GC while GVL is uncontended and GC is lazy sweeping or incremental marking [ruby-core:86265] ``` 2 part patch broken out https://80x24.org/spew/20180429035007.6499-2-e@80x24.org/raw https://80x24.org/spew/20180429035007.6499-3-e@80x24.org/raw Also on my "sleepy-gc" git branch @ git://80x24.org/ruby.git ---Files-------------------------------- sleepy-gc-wip-v1.diff (5.37 KB) -- https://bugs.ruby-lang.org/ Unsubscribe: