From: usa@... Date: 2014-02-05T03:01:06+00:00 Subject: [ruby-core:60471] [ruby-trunk - Bug #9039] [PATCH] socket: avoid unnecessary ppoll/select on Linux (part 3) Issue #9039 has been updated by Usaku NAKAMURA. Backport changed from 1.9.3: UNKNOWN, 2.0.0: UNKNOWN to 1.9.3: REQUIRED, 2.0.0: REQUIRED, 2.1: REQUIRED ---------------------------------------- Bug #9039: [PATCH] socket: avoid unnecessary ppoll/select on Linux (part 3) https://bugs.ruby-lang.org/issues/9039#change-44937 * Author: Eric Wong * Status: Closed * Priority: Low * Assignee: * Category: * Target version: * ruby -v: ruby 2.1.0dev (2013-10-20 trunk 43373) [x86_64-linux] * Backport: 1.9.3: REQUIRED, 2.0.0: REQUIRED, 2.1: REQUIRED ---------------------------------------- It is safe on Linux to attempt using a socket without waiting on it in all cases. For some syscalls (e.g. accept/accept4), blocking on the syscall instead of relying on select/poll allows the kernel to use "wake-one" behavior and avoid the thundering herd problem. This is likely safe on all other *nix-like systems, so this whitelist can be expanded by interested parties. This is a follow-up to r36944 and r36946 Using the following script, performance and distribution of accepted socket between different processes is improved: ------------------------------8<------------------------------ require 'socket' usage = "Usage: #$0 SOCKET_PATH" path = ARGV.shift or abort usage s = UNIXServer.new(path) # cleanup after ourselves main_pid = $$ at_exit { File.unlink(path) if $$ == main_pid } $stderr.sync = $stdout.sync = true nproc = 16 stop = Time.now + 10 pipe = IO.pipe pids = nproc.times.map do fork do pipe[0].close $stdout.reopen(pipe[1]) loop do s.accept.close $stdout.syswrite "#$$\n" end end end pipe[1].close # show the number of sockets accepted by each pid spid = Process.spawn("sort | uniq -c | sort -k1,1n", in: pipe[0]) sleep 1 # wait for processes to spin up UNIXSocket.new(path).close until Time.now > stop pids.each { |x| Process.kill(:TERM, x) } s.close Process.waitall ------------------------------8<------------------------------ count PID ----------- before: 61166 26903 62257 26948 62320 26930 62839 26945 63084 26921 63273 26933 63523 26912 63690 26939 64051 26909 64284 26915 64846 26927 64959 26924 65157 26936 65477 26906 65541 26942 66355 26918 after: 72350 26550 73074 26544 73377 26553 73457 26559 73540 26580 73920 26562 74105 26541 74109 26574 74182 26577 74465 26535 74509 26556 74672 26538 74974 26565 75329 26568 75435 26547 75565 26571 So the difference is visible in both the number of accepted sockets and also the difference between the max/min per-process accept counts before: 66355 - 61166 = 5189 after: 75565 - 72350 = 3215 (Smaller difference is better, and the difference will probably be even smaller on servers which do processing on the socket) ---Files-------------------------------- 0001-socket-avoid-unnecessary-ppoll-select-on-Linux-part-.patch (5.49 KB) -- http://bugs.ruby-lang.org/