Project

General

Profile

Actions

Bug #9039

closed

[PATCH] socket: avoid unnecessary ppoll/select on Linux (part 3)

Added by normalperson (Eric Wong) over 10 years ago. Updated about 10 years ago.

Status:
Closed
Assignee:
-
Target version:
-
ruby -v:
ruby 2.1.0dev (2013-10-20 trunk 43373) [x86_64-linux]
[ruby-core:57950]

Description

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

Updated by akr (Akira Tanaka) about 10 years ago

  • Status changed from Open to Closed
  • % Done changed from 0 to 100

Applied in changeset r44643.


Updated by usa (Usaku NAKAMURA) about 10 years ago

  • Backport changed from 1.9.3: UNKNOWN, 2.0.0: UNKNOWN to 1.9.3: REQUIRED, 2.0.0: REQUIRED, 2.1: REQUIRED

Updated by usa (Usaku NAKAMURA) about 10 years ago

  • Backport changed from 1.9.3: REQUIRED, 2.0.0: REQUIRED, 2.1: REQUIRED to 1.9.3: DONE, 2.0.0: REQUIRED, 2.1: REQUIRED

backported into ruby_1_9_3 at r44943.

Updated by usa (Usaku NAKAMURA) about 10 years ago

  • Backport changed from 1.9.3: DONE, 2.0.0: REQUIRED, 2.1: REQUIRED to 1.9.3: REJECTED, 2.0.0: REQUIRED, 2.1: REQUIRED

... but reverted from ruby_1_9_3 because it causes errors on CI.

Updated by normalperson (Eric Wong) about 10 years ago

wrote:

Issue #9039 has been updated by Usaku NAKAMURA.

Backport changed from 1.9.3: DONE, 2.0.0: REQUIRED, 2.1: REQUIRED to 1.9.3: REJECTED, 2.0.0: REQUIRED, 2.1: REQUIRED

... but reverted from ruby_1_9_3 because it causes errors on CI.

I misfiled this as a Bug instead of Feature, so no backport was
necessary. However, I'm curious what the errors were and which version of
Linux it happened under. Thanks.

Updated by naruse (Yui NARUSE) about 10 years ago

  • Backport changed from 1.9.3: REJECTED, 2.0.0: REQUIRED, 2.1: REQUIRED to 1.9.3: DONTNEED, 2.0.0: DONTNEED, 2.1: DONTNEED
Actions

Also available in: Atom PDF

Like0
Like0Like0Like0Like0Like0Like0