Slide 1

Slide 1 text

The (Ruby) Sims (part 1)

Slide 2

Slide 2 text

Introduction

Slide 3

Slide 3 text

@bryanl

Slide 4

Slide 4 text

No content

Slide 5

Slide 5 text

No content

Slide 6

Slide 6 text

No content

Slide 7

Slide 7 text

No content

Slide 8

Slide 8 text

No content

Slide 9

Slide 9 text

No content

Slide 10

Slide 10 text

No content

Slide 11

Slide 11 text

CootieSim2012

Slide 12

Slide 12 text

Why RUBY?

Slide 13

Slide 13 text

Stochastic vs Deterministic

Slide 14

Slide 14 text

Define inputs Compute Analyze output

Slide 15

Slide 15 text

SIMULATION_LENGTH = 100 PEOPLE_COUNT = 100 def create_people(people_count); end def report; end def simulate_to(count) 1.upto(count) {|i| yield i } end people = create_people(PEOPLE_COUNT) simulate_to(SIMULATION_LENGTH) do |iteration| # mish and mash people end report

Slide 16

Slide 16 text

class Simulator def initialize(length, count) # ... end end s = Simulator.new 3650, 100 Define inputs

Slide 17

Slide 17 text

class Simulator def simulate(iteration) create_pairs(iteration) transmit(iteration) progress_infections(iteration) end end Compute

Slide 18

Slide 18 text

s = Simulator.new 3650, 100 s.run s.infected_people.each do |p| i = p.infections.to_a d = p.diseases.to_a puts "#{p} #{i} #{d}" end Analyze output

Slide 19

Slide 19 text

Breakdown

Slide 20

Slide 20 text

What’s in a day?

Slide 21

Slide 21 text

Create new pair

Slide 22

Slide 22 text

def create_pairs(iteration) @pairs += people_not_in_pairs(iteration) .shuffle .each_slice(2) .map{|x| Pair.new iteration, x} end

Slide 23

Slide 23 text

Transmit cooties

Slide 24

Slide 24 text

class Simulation def transmit(iteration) current_pairs(iteration).each{|pair| pair.contact(iteration)} end end class Pair def contact(iteration) @alpha.infect(iteration, @beta) @beta.infect(iteration, @alpha) end end class Person def infect(iteration, person); end def acquire(infection); end end

Slide 25

Slide 25 text

Track infection progress

Slide 26

Slide 26 text

class Person def progress_infections(iteration) @infections.each do |infection| if rand <= infection.chance_to_acquire_disease unless has_disease? infection.disease @diseases << infection.disease.new(iteration) end end end end end

Slide 27

Slide 27 text

... This isn’t going to be fast

Slide 28

Slide 28 text

28.23s user 0.10s system 99% cpu 28.333 total

Slide 29

Slide 29 text

but why?

Slide 30

Slide 30 text

%self total self wait child calls name 30.32 386.26 117.53 0.00 268.72 21904 Array#each 28.08 180.05 108.88 0.00 71.18 78738195 Comparable#between? 21.74 84.29 84.29 0.00 0.00 78738195 Pair#duration 18.36 71.18 71.18 0.00 0.00 157476390 Fixnum#<=> 0.29 2.11 1.11 0.00 1.06 414957 Set#each 0.13 1.15 0.50 0.00 0.65 365100 Person#infected? 0.13 2.36 0.50 0.00 1.86 365000 Person#infect 0.12 0.65 0.48 0.00 0.17 365100 Set#empty?

Slide 31

Slide 31 text

O(n)

Slide 32

Slide 32 text

module Enumerable # create a thread and execute in parallel def parallel_each(&block) # create thread yield # cleanup end end

Slide 33

Slide 33 text

gem install peach (YMMV)

Slide 34

Slide 34 text

No content

Slide 35

Slide 35 text

100 people

Slide 36

Slide 36 text

3650 iterations

Slide 37

Slide 37 text

365,000 “actions”

Slide 38

Slide 38 text

3,650,000 @ 1,000 36,500,000 @ 10,000 365,000,000 @ 100,000 3,650,000,000 @ 1,000,000

Slide 39

Slide 39 text

How do we make it faster?

Slide 40

Slide 40 text

You can’t!!!

Slide 41

Slide 41 text

1. Run less code 2. Do more things at once

Slide 42

Slide 42 text

MRI 1.9

Slide 43

Slide 43 text

No content

Slide 44

Slide 44 text

Thread.new

Slide 45

Slide 45 text

No content

Slide 46

Slide 46 text

JRuby

Slide 47

Slide 47 text

No content

Slide 48

Slide 48 text

Thread.new

Slide 49

Slide 49 text

No content

Slide 50

Slide 50 text

JRuby’s sweetspot is Hotspot

Slide 51

Slide 51 text

11.34s user 0.37s system 116% cpu 10.064 total

Slide 52

Slide 52 text

Doing more than one thing at once with MRI

Slide 53

Slide 53 text

Queues

Slide 54

Slide 54 text

redis backed

Slide 55

Slide 55 text

resque

Slide 56

Slide 56 text

sidekiq

Slide 57

Slide 57 text

memory backed

Slide 58

Slide 58 text

girl_friday

Slide 59

Slide 59 text

memory backed

Slide 60

Slide 60 text

rabbitmq

Slide 61

Slide 61 text

db backed

Slide 62

Slide 62 text

rabbitmq

Slide 63

Slide 63 text

socket based concurrency

Slide 64

Slide 64 text

Ømq

Slide 65

Slide 65 text

dcell (part 2)

Slide 66

Slide 66 text

statistics

Slide 67

Slide 67 text

mean median variance standard deviation σ

Slide 68

Slide 68 text

How do i randomly pick an integer from 1-6?

Slide 69

Slide 69 text

gem install vose

Slide 70

Slide 70 text

v = Vose::AliasMethod.new [1,1,1,1,1,1] (1..10000).map{v.next}.inject(Hash.new{0}){ |m,n| m[n]+=1; m} (1..10000).map{rand(1..6)} .inject(Hash.new{0}){|m,n| m[n]+=1; m} VS

Slide 71

Slide 71 text

What if the die is weighted?

Slide 72

Slide 72 text

v = Vose::AliasMethod.new [1.2,1,1,1,1,1] (1..10000).map{v.next}.inject(Hash.new{0}){ |m,n| m[n]+=1; m} ????? VS

Slide 73

Slide 73 text

graphing

Slide 74

Slide 74 text

Trends

Slide 75

Slide 75 text

No content

Slide 76

Slide 76 text

No content

Slide 77

Slide 77 text

library(ggplot2) runtime.csv <- read.csv("runtime.csv", header=T) mygg<- qplot(iteration, time, data=runtime.csv); mygg<- mygg + stat_smooth(method="lm") ggsave("runtime.png") dev.off() R

Slide 78

Slide 78 text

Visualization

Slide 79

Slide 79 text

No content

Slide 80

Slide 80 text

digraph g { "person59" -> "person5"; "person23" -> "person18"; "person72" -> "person23"; "person78" -> "person44"; "person78" -> "person59"; "person59" -> "person72"; "person1" -> "person78"; "person83" -> "person81"; "person59" -> "person83"; "person59" -> "person92"; }; Graphviz

Slide 81

Slide 81 text

Building a simulator

Slide 82

Slide 82 text

No content

Slide 83

Slide 83 text

No content

Slide 84

Slide 84 text

No content

Slide 85

Slide 85 text

?!

Slide 86

Slide 86 text

Shared Cooties?

Slide 87

Slide 87 text

Making it fast

Slide 88

Slide 88 text

Be kind to MRI’s GC

Slide 89

Slide 89 text

Run more than one process

Slide 90

Slide 90 text

Look outside of MRI

Slide 91

Slide 91 text

irb(main):003:0> rand 1..7 TypeError: can't convert Range into Integer from org/jruby/RubyKernel.java:1580:in `rand' from (irb):3:in `evaluate' from org/jruby/RubyKernel.java:1070:in `eval' from org/jruby/RubyKernel.java:1395:in `loop' from org/jruby/RubyKernel.java:1178:in `catch' from org/jruby/RubyKernel.java:1178:in `catch' from /Users/bryan/.rbenv/versions/jruby-1.7.0-preview2/bin/irb:13:in `(root)' JRuby 1.7 pre2

Slide 92

Slide 92 text

irb(main):001:0> rand 1..7 => 3 MRI 1.9.3

Slide 93

Slide 93 text

other languages?

Slide 94

Slide 94 text

The Ruby compromise

Slide 95

Slide 95 text

Exploring CootieSim2012

Slide 96

Slide 96 text

Thanks! @thunderboltlabs @bryanl