Skip to content

Instantly share code, notes, and snippets.

@therealadam
Last active December 12, 2015 02:28
Show Gist options
  • Save therealadam/4698972 to your computer and use it in GitHub Desktop.
Save therealadam/4698972 to your computer and use it in GitHub Desktop.
I took producer.rb, added threads and made it two orders of magnitude slower. Thus was born, lol.rb. (NOW LOLFAST)
require 'thread'
require 'ffaker'
require 'json'
def new_message
text = Faker::HipsterIpsum.sentences(3)
metrics = {
temp: rand(110), # degrees F
mass: rand(100), # kilograms
speed: rand(70) # miles per hour
}
{metrics: metrics, body: text}
end
def send_message(socket, msg)
encoded = JSON.dump(messages: msg)
socket.write(encoded)
end
FRAME_SIZE = 100
if __FILE__ == $0
# s = Socket.new('localhost', 4242)
s = $stdout
messages = Queue.new
producer = Thread.new do
loop do
messages.push(new_message)
end
end
begin
loop do
frame = FRAME_SIZE.times.map { messages.pop }
send_message(s, frame)
end
ensure
s.close
producer.join
end
end
Using local file /Users/adam/.rbenv/versions/1.9.3-p327-perf/bin/ruby.
Using local file /tmp/profile.
Total: 1837 samples
754 41.0% 41.0% 1340 72.9% Enumerable#sort_by
317 17.3% 58.3% 1507 82.0% Range#each
299 16.3% 74.6% 299 16.3% garbage_collector
199 10.8% 85.4% 199 10.8% Float#<=>
81 4.4% 89.8% 81 4.4% Kernel.rand
34 1.9% 91.7% 71 3.9% Array#map
31 1.7% 93.4% 1496 81.4% Faker::Lorem#sentence
15 0.8% 94.2% 1433 78.0% Module#random_pick
15 0.8% 95.0% 15 0.8% String#initialize_copy
14 0.8% 95.8% 23 1.3% Kernel#rand
13 0.7% 96.5% 36 2.0% Kernel#dup
13 0.7% 97.2% 13 0.7% String#capitalize!
8 0.4% 97.6% 19 1.0% Kernel#initialize_dup
6 0.3% 97.9% 14 0.8% Array#join
6 0.3% 98.3% 6 0.3% File.file?
5 0.3% 98.5% 1524 83.0% Object#new_message
4 0.2% 98.7% 4 0.2% Array#[]
4 0.2% 99.0% 1430 77.8% Faker::HipsterIpsum#words
4 0.2% 99.2% 1504 81.9% Faker::Lorem#sentences
\342\230\201
# encoding: UTF-8
require 'socket'
require 'ffaker'
require 'json'
ZERO_LENGTH = 1024 * 8
def new_message
text = Faker::HipsterIpsum.sentences(3)
random = File.read('/dev/zero', ZERO_LENGTH)
metrics = {
temp: rand(110), # degrees F
mass: rand(100), # kilograms
speed: rand(70) # miles per hour
}
{metrics: metrics, random: random, body: text}
end
def send_message(socket, msg)
encoded = JSON.dump(messages: msg)
socket.write(encoded)
end
FRAME_SIZE = 100
if __FILE__ == $0
s = TCPSocket.new('localhost', 4242)
# s = $stdout
begin
loop do
frame = FRAME_SIZE.times.map { new_message }
send_message(s, frame)
end
ensure
s.close
end
end
require 'ffaker'
require 'json'
def new_message
text = Faker::HipsterIpsum.sentences(3)
metrics = {
temp: rand(110), # degrees F
mass: rand(100), # kilograms
speed: rand(70) # miles per hour
}
{metrics: metrics, body: text}
end
def send_message(socket, msg)
encoded = JSON.dump(messages: msg)
socket.write(encoded)
end
FRAME_SIZE = 100
if __FILE__ == $0
# s = Socket.new('localhost', 4242)
s = $stdout
begin
loop do
frame = FRAME_SIZE.times.map { new_message }
send_message(s, frame)
end
ensure
s.close
end
end
Using local file /Users/adam/.rbenv/versions/1.9.3-p327-perf/bin/ruby.
Using local file /tmp/profile.
Total: 947 samples
370 39.1% 39.1% 725 76.6% Enumerable#sort_by
195 20.6% 59.7% 818 86.4% Range#each
118 12.5% 72.1% 118 12.5% Float#<=>
64 6.8% 78.9% 64 6.8% garbage_collector
43 4.5% 83.4% 43 4.5% Kernel.rand
23 2.4% 85.9% 23 2.4% IO#write
13 1.4% 87.2% 13 1.4% Array#join
12 1.3% 88.5% 26 2.7% Kernel#dup
11 1.2% 89.7% 37 3.9% Array#map
11 1.2% 90.8% 816 86.2% Faker::Lorem#sentence
10 1.1% 91.9% 10 1.1% String#initialize_copy
9 1.0% 92.8% 10 1.1% Kernel#rand
7 0.7% 93.6% 15 1.6% JSON::Ext::Generator::State#generate
6 0.6% 94.2% 10 1.1% Kernel#eval
6 0.6% 94.8% 774 81.7% Module#random_pick
6 0.6% 95.5% 829 87.5% Object#new_message
6 0.6% 96.1% 6 0.6% String#capitalize!
5 0.5% 96.6% 779 82.3% Faker::ArrayUtils#random_pick
4 0.4% 97.0% 4 0.4% Range.allocate
\342\230\201
@therealadam
Copy link
Author

@JEG2 I didn't do anything beyond profiling it to see if the bottleneck was different. I think I should only have two threads: one for producing messages, and another for IO. IF I was IO-bound, I believe this would effectively circumvent the GIL. However, I'm clearly bound on generating ipsum text.

FWIW, I introduced framing/batching messages because without it the producer was painfully slow.

I added threads on a lark to see if it was marginally faster. My surprise is how much slower it is.

@therealadam
Copy link
Author

@JEG2 check out lolput.rb. I cheated and got a lot closer to my baseline benchmark. On my laptop, this produces does about 75-78 MB/s of throughput:

# Producer
$ cat /dev/zero | nc localhost 4242

# Consumer
$ nc localhost 4242 | pv > /dev/null

lolput.rb does 42-45 MB/s. It's now much closer to my baseline. Generating a string of zeroes in the kernel is FAST guys!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment