roadrunner 4.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +3 -0
- data/README +3 -0
- data/Rakefile +41 -0
- data/bin/controller.rb +76 -0
- data/bin/hostmgr.rb +69 -0
- data/bin/nbd_prepare.sh +88 -0
- data/conf/servers.yaml +29 -0
- data/controller/dd.sh +92 -0
- data/controller/ioperf.rb +108 -0
- data/controller/mysql.rb +74 -0
- data/controller/mysql.sh +9 -0
- data/controller/svn.sh +49 -0
- data/controller/wrap.rb +23 -0
- data/lib/action.rb +14 -0
- data/lib/db.rb +51 -0
- data/lib/ended.rb +14 -0
- data/lib/init.rb +14 -0
- data/lib/model.rb +10 -0
- data/lib/report.rb +100 -0
- data/lib/roadrunner.rb +122 -0
- data/lib/rrhelper.rb +25 -0
- data/lib/rrmonitor.rb +174 -0
- data/lib/run.rb +113 -0
- data/log/dd.log +129 -0
- data/log/log.rb +17 -0
- data/log/stdout.log +4 -0
- data/log/stdout.log.20100421 +0 -0
- data/log/svn.log +502 -0
- data/test/baidu.rb +100 -0
- data/test/blog.rb +100 -0
- data/test/db/development.sqlite3 +0 -0
- data/test/download_processes.rb +38 -0
- data/test/fibonacci.rb +27 -0
- data/test/get163.rb +38 -0
- data/test/get19Lou.rb +39 -0
- data/test/getHawaii.rb +95 -0
- data/test/httpclient-rfuzz-vs-httparty.rb +31 -0
- data/test/mysql_processes.rb +66 -0
- data/test/pi.rb +37 -0
- data/test/pi_db.rb +41 -0
- data/test/pi_monitor.rb +45 -0
- data/test/prime.rb +33 -0
- data/test/prime_p.rb +36 -0
- data/test/test_db.rb +29 -0
- data/test/vbd_kv.rb +123 -0
- metadata +100 -0
data/lib/db.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
#
|
2
|
+
|
3
|
+
module RoadRunnerModule
|
4
|
+
|
5
|
+
module Dbhelper
|
6
|
+
|
7
|
+
def migrate(tables)
|
8
|
+
tables.each do |table|
|
9
|
+
case table
|
10
|
+
when "scenarios" then
|
11
|
+
unless ActiveRecord::Base.connection.tables.include?(table.to_s) then
|
12
|
+
ActiveRecord::Base.connection.create_table(table.to_sym) do |t|
|
13
|
+
t.column :name, :string, :limit => 256
|
14
|
+
t.column :create_at,:string, :limit => 32
|
15
|
+
t.column :script, :string,:limit => 10240
|
16
|
+
t.column :author, :string, :default => 'Anonymous'
|
17
|
+
t.column :author, :tps, :int
|
18
|
+
t.column :desc, :string
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
when "transactions" then
|
23
|
+
unless ActiveRecord::Base.connection.tables.include?(table.to_s) then
|
24
|
+
ActiveRecord::Base.connection.create_table(table.to_sym) do |t|
|
25
|
+
t.column :name,:string,:limit => 256
|
26
|
+
t.column :scenario_id,:string,:limit => 256
|
27
|
+
t.column :success_rate,:string, :limit => 8
|
28
|
+
t.column :create_at,:string, :limit => 32
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
when "records" then
|
34
|
+
unless ActiveRecord::Base.connection.tables.include?(table.to_s) then
|
35
|
+
ActiveRecord::Base.connection.create_table(table.to_sym) do |t|
|
36
|
+
t.column :cost, :string, :limit => 32
|
37
|
+
t.column :ts, :string, :limit => 32
|
38
|
+
t.column :seq, :int
|
39
|
+
t.column :stats,:int
|
40
|
+
t.column :transaction_id,:string,:limit => 256
|
41
|
+
t.column :create_at,:string, :limit => 32
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
module_function :migrate
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
data/lib/ended.rb
ADDED
data/lib/init.rb
ADDED
data/lib/model.rb
ADDED
data/lib/report.rb
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
#After roadRunner.run() executed,
|
2
|
+
#execute roadRunner.report() show the Performance report
|
3
|
+
|
4
|
+
module RoadRunnerModule
|
5
|
+
|
6
|
+
def report(label='',width=0)
|
7
|
+
p " Wait for moment,the report is collecting......"
|
8
|
+
content = if @rep
|
9
|
+
@succRates = getSuccessRate @transactions
|
10
|
+
<<-DOC
|
11
|
+
#{"Performance Reports".center(50, '*')}
|
12
|
+
#{label.ljust(width)}
|
13
|
+
#{Benchmark::Tms::CAPTION}
|
14
|
+
#{@rep.format}
|
15
|
+
#{'--'*32}
|
16
|
+
The Virtual User is #{@users}.
|
17
|
+
Total Execute #{@iterations*@users} Action(s).
|
18
|
+
Total Cost #{@rep.real} Second(s).
|
19
|
+
This Scenario's TPS : #{@tps}.
|
20
|
+
The longest action cost #{@longest || 0} seconds.
|
21
|
+
#{'Transaction Report'.center(50, '-')}
|
22
|
+
#{@transactions.inject("") { |str,k|
|
23
|
+
str += "#{k[0].to_s} : count => #{k[1].size} time(s) , cost => #{k[1].inject(0){|c,v|c+=v[:cost].to_f}.to_s[0..3]} sec(s) , success rate => #{@succRates[k[0]]}\n "
|
24
|
+
}.gsub(/\n$/,'')}
|
25
|
+
#{'--'*32}
|
26
|
+
User defined params as below:
|
27
|
+
#{@global}
|
28
|
+
#{"End of Reports".center(50, '*')}
|
29
|
+
DOC
|
30
|
+
else
|
31
|
+
"None Report before RoadRunner run."
|
32
|
+
end
|
33
|
+
puts content
|
34
|
+
self.log.info content
|
35
|
+
end
|
36
|
+
|
37
|
+
def save_report(opts={:author=>'Anonymous',:script=>""})
|
38
|
+
|
39
|
+
p " Saving report to database......"
|
40
|
+
opts={:author=>'Anonymous',:script=>""}.merge opts
|
41
|
+
if @data_write then
|
42
|
+
unless opts[:name] then
|
43
|
+
self.log.warn "scenario name may be needed."
|
44
|
+
require 'uuidtools' unless defined?UUID
|
45
|
+
# scenario || UUID.random_create.to_s is for debug
|
46
|
+
opts[:name] = opts[:name] || UUID.random_create.to_s
|
47
|
+
self.log.info "scenario is created as #{opts[:name]}"
|
48
|
+
end
|
49
|
+
# => scenario = Scenario.find_or_create_by_name(opts.merge({:create_at=>Time.now})).shift
|
50
|
+
scenario = Scenario.find_or_create_by_name(opts.merge({:create_at=>Time.now}))
|
51
|
+
scenario.tps+=@iterations*@users/@rep.real
|
52
|
+
|
53
|
+
# => if opts[:script] is set as <your script>.rb 's path
|
54
|
+
# => opts[:script] = __FILE__
|
55
|
+
# => then scenario.script will be set.
|
56
|
+
if FileTest.exist?(opts[:script]) then
|
57
|
+
scenario.script = ""
|
58
|
+
IO.foreach(opts[:script]){|x|scenario.script << x}
|
59
|
+
end
|
60
|
+
|
61
|
+
@succRates = @succRates || (getSuccessRate @transactions)
|
62
|
+
# k is transaction name ,
|
63
|
+
# v is reports in every transaction.
|
64
|
+
@transactions.each do |k,v|
|
65
|
+
transaction = Transaction.new({:name=>k,:create_at=>Time.now,:success_rate=>@succRates[k]})
|
66
|
+
v.each_index do |id|
|
67
|
+
transaction.records << Record.new(v[id].merge({:seq=>id,:ts=>v[id][:create_at].to_f-@strat_time.to_f}))
|
68
|
+
self.log.debug "v[#{id}] = #{v[id].inspect}"
|
69
|
+
end
|
70
|
+
scenario.transactions << transaction
|
71
|
+
end
|
72
|
+
begin
|
73
|
+
scenario.save!
|
74
|
+
p " Saved OK!"
|
75
|
+
rescue =>e
|
76
|
+
self.log.error e
|
77
|
+
p e
|
78
|
+
end
|
79
|
+
self.log.info "records has saved in DB."
|
80
|
+
else
|
81
|
+
p ' Error:You didn\'t connect any database.'
|
82
|
+
self.log.error 'You didn\'t connect any database.'
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def getSuccessRate(transactions)
|
87
|
+
result = {}
|
88
|
+
transactions.each do |h|
|
89
|
+
success,faile = 0,0
|
90
|
+
h[1].each do |r|
|
91
|
+
r[:stats]==0?success+=1:faile+=1
|
92
|
+
end
|
93
|
+
result[h[0]]=success.to_f/(success+faile)
|
94
|
+
end
|
95
|
+
result
|
96
|
+
end
|
97
|
+
|
98
|
+
private :getSuccessRate
|
99
|
+
|
100
|
+
end
|
data/lib/roadrunner.rb
ADDED
@@ -0,0 +1,122 @@
|
|
1
|
+
# Author : zheng.cuizh@gmail.com
|
2
|
+
# RoadRunner named lik LoadRunner which is a industry performance test tool of HP.
|
3
|
+
# I'm happy to user LR and Ruby,
|
4
|
+
# so i coded the RoadRunner.
|
5
|
+
# Using RR,you'll find somethings similar to LR.
|
6
|
+
|
7
|
+
$:.unshift File.dirname(__FILE__)
|
8
|
+
require 'rubygems'
|
9
|
+
require 'benchmark'
|
10
|
+
require 'logger'
|
11
|
+
require 'pp'
|
12
|
+
|
13
|
+
Dir[File.join(File.dirname(__FILE__),"*.rb")].select{|x|not (x =~ /.*model\.rb/ || x =~ /.*db\.rb/ || x =~ /.*roadrunner\.rb/)}.each { |x| require x }
|
14
|
+
|
15
|
+
class RoadRunner
|
16
|
+
|
17
|
+
include RoadRunnerModule
|
18
|
+
attr :iterations, true
|
19
|
+
attr :users,true
|
20
|
+
attr :global,true
|
21
|
+
attr :iterationId
|
22
|
+
attr :record
|
23
|
+
attr :userId
|
24
|
+
attr :mode,true
|
25
|
+
attr :log
|
26
|
+
attr :tps
|
27
|
+
alias_method :g,:global
|
28
|
+
alias_method :g=,:global=
|
29
|
+
|
30
|
+
def initialize(opts={})
|
31
|
+
# => DEBUG < INFO < WARN < ERROR < FATAL < UNKNOWN
|
32
|
+
opts = {:out=>File.join(File.dirname(__FILE__),'..','log',"stdout.log"),:frequency=>'daily',:size=>1048576,:level=>Logger::DEBUG}.merge opts
|
33
|
+
@users,@iterations,@longest,@userId,@iterationId=1,1,0,0,0
|
34
|
+
@initBlk,@actBlk,@endBlk=proc{},proc{},proc{}
|
35
|
+
@global,@transactions={},{}
|
36
|
+
@log=Logger.new(opts[:out],opts[:frequency],opts[:size])
|
37
|
+
@log.level=opts[:level]
|
38
|
+
# => mode : sequence<default>,thread|t,process|p
|
39
|
+
@mode='sequence'
|
40
|
+
|
41
|
+
@transaction_blk={}
|
42
|
+
|
43
|
+
if block_given? then
|
44
|
+
begin
|
45
|
+
gem 'active_record'
|
46
|
+
require 'active_record'
|
47
|
+
rescue Exception => e
|
48
|
+
require 'activerecord'
|
49
|
+
end
|
50
|
+
|
51
|
+
require 'db'
|
52
|
+
require "model"
|
53
|
+
|
54
|
+
session = {}
|
55
|
+
_session = yield session
|
56
|
+
session = _session if session == {}
|
57
|
+
|
58
|
+
begin
|
59
|
+
ActiveRecord::Base.establish_connection(
|
60
|
+
#
|
61
|
+
# === session defined in block :
|
62
|
+
#
|
63
|
+
# :adapter=>session[:adapter],
|
64
|
+
# :encoding=>session[:encoding],
|
65
|
+
# :database=>session[:database],
|
66
|
+
# :username=>session[:username],
|
67
|
+
# :password=>session[:password],
|
68
|
+
# :host=>session[:host]
|
69
|
+
#
|
70
|
+
session
|
71
|
+
)
|
72
|
+
self.log.info "connect db ok."
|
73
|
+
rescue =>ex
|
74
|
+
self.log.error "adapter:#{session[:adapter]}.connect db faile."
|
75
|
+
end
|
76
|
+
|
77
|
+
default_report_table = %w"scenarios transactions records"
|
78
|
+
|
79
|
+
unless @data_write = default_report_table.inject(true){|r,t| r = r && ActiveRecord::Base.connection.tables.include?(t)} then
|
80
|
+
self.log.warn "table rreports doesn't defined and will be created."
|
81
|
+
Dbhelper::migrate default_report_table
|
82
|
+
if @data_write = default_report_table.inject(true){|r,t| r = r && ActiveRecord::Base.connection.tables.include?(t)} then
|
83
|
+
self.log.info "create table #{default_report_table.inspect} successful."
|
84
|
+
else
|
85
|
+
self.log.error "create table #{default_report_table.inspect} fail."
|
86
|
+
end
|
87
|
+
end
|
88
|
+
require 'model' unless defined? Scenario
|
89
|
+
self.log.debug 'model Rreport is reqruired.'
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def transaction(name,&blk)
|
94
|
+
@transactions[name] || @transactions[name] = []
|
95
|
+
status = "AUTO"
|
96
|
+
# => Status is the last expression in the action block
|
97
|
+
rcost = Benchmark::realtime{status = yield} if block_given?
|
98
|
+
# => status's value is:
|
99
|
+
# => 0=>success
|
100
|
+
# => -1=>faile
|
101
|
+
case status
|
102
|
+
when false,'false','-1',-1 then status = -1
|
103
|
+
else status = 0
|
104
|
+
end
|
105
|
+
# {:stats=>status,:cost=>rcost,:create_at=>Time.now} is one record
|
106
|
+
@transactions[name] << {:stats=>status,:cost=>rcost,:create_at=>Time.now}
|
107
|
+
# => the below sentence cost a lot of system resource
|
108
|
+
# => if you run for production result,keep it annotated!!!
|
109
|
+
# self.log.debug @transactions[name].inspect
|
110
|
+
rcost
|
111
|
+
end
|
112
|
+
|
113
|
+
def register_transactions(name,&blk)
|
114
|
+
@transaction_blk[name]=blk
|
115
|
+
end
|
116
|
+
|
117
|
+
def method_missing(name,*args,&blk)
|
118
|
+
# self.transaction(name.to_s,&blk)
|
119
|
+
register_transactions(name,&blk)
|
120
|
+
end
|
121
|
+
|
122
|
+
end
|
data/lib/rrhelper.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# Rrhelper will include many helpful methods for RoadRunner
|
2
|
+
|
3
|
+
module RoadRunnerModule
|
4
|
+
|
5
|
+
def iterationId
|
6
|
+
if(@mode=='thread')then
|
7
|
+
@thread_pool[Thread.current][:iterationId]
|
8
|
+
else
|
9
|
+
@iterationId
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def userId
|
14
|
+
if(@mode=='thread')then
|
15
|
+
@thread_pool[Thread.current][:userId]
|
16
|
+
else
|
17
|
+
@userId
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
module Rrhelper
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
data/lib/rrmonitor.rb
ADDED
@@ -0,0 +1,174 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "net/ssh"
|
3
|
+
require 'fileutils'
|
4
|
+
|
5
|
+
module RoadRunnerModule
|
6
|
+
|
7
|
+
=begin
|
8
|
+
RRMonitor is used for Xnix system.
|
9
|
+
=end
|
10
|
+
|
11
|
+
class RRMonitor
|
12
|
+
def initialize(opt={:server=>"0.0.0.0", :username=>"admin", :password=>"123456"})
|
13
|
+
raise(ArgumentError,"Logger is needed!") unless opt[:log]
|
14
|
+
@log=opt[:log]
|
15
|
+
|
16
|
+
@server=opt[:server]
|
17
|
+
|
18
|
+
begin
|
19
|
+
@sess=Net::SSH.start(opt[:server], opt[:username], :password => opt[:password],:timeout => 120)
|
20
|
+
@log.info "#{opt[:server]} ssh connection OK."
|
21
|
+
rescue Exception => e
|
22
|
+
@log.error e
|
23
|
+
@log.error opt.inspect
|
24
|
+
raise e
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
@log.info("monitor initialize.".center(60,"*"))
|
29
|
+
@log.debug("monitor => #{self.inspect}")
|
30
|
+
|
31
|
+
@ts=( opt[:ts] || Time.now.to_i )
|
32
|
+
|
33
|
+
@path="#{File.join File.dirname(__FILE__),'..','log'}/monitor/#{@ts}"
|
34
|
+
@log.info "monitor local log path :#{@path}"
|
35
|
+
|
36
|
+
@rpath="~/.monit/#{@ts}"
|
37
|
+
@log.info "monitor remote log path(rpath) :#{@rpath}"
|
38
|
+
|
39
|
+
@sess.exec!("rm -rf #{@rpath}")
|
40
|
+
@sess.exec!("mkdir -p #{@rpath}")
|
41
|
+
|
42
|
+
@pids={}
|
43
|
+
end
|
44
|
+
|
45
|
+
=begin
|
46
|
+
run!(cmd) =>
|
47
|
+
the cmd will be execed at remote server(0),
|
48
|
+
and the stdout will write in log file.
|
49
|
+
|
50
|
+
cmd =>[
|
51
|
+
'ifstat',# network io
|
52
|
+
'iostat 3',# disk io
|
53
|
+
'vmstat 3',# memory info
|
54
|
+
'while((1>0));do sar -u -d 3 10; done',# disk and cpu info
|
55
|
+
'while((1>0));do sar -u -n DEV 3 10; done'# network and cpu info
|
56
|
+
]
|
57
|
+
|
58
|
+
"while((1>0));do #{cmd}; done" is needed for non-consist output cmd.
|
59
|
+
|
60
|
+
cmd sample =>
|
61
|
+
|
62
|
+
run!(["while((1>0));do /home/admin/apsara/build/debug64/bin/ku --command=getallpart --appname=blog1 --interactive=false|tail -n1; done"])
|
63
|
+
|
64
|
+
when exec!(cmd)
|
65
|
+
=>
|
66
|
+
exec!("while((1>0));do /home/admin/apsara/build/debug64/bin/ku --command=getallpart --appname=blog1 --interactive=false|tail -n1; done >> #{kupath} 2>/dev/null &")
|
67
|
+
=end
|
68
|
+
|
69
|
+
def run!(cmd=['ifstat','iostat 3','while((1>0));do sar -u -d 3 10; done','vmstat 3','while((1>0));do sar -u -n DEV 3 10; done'])
|
70
|
+
(@log.error "run!(cmd) cmd type require array.";exit) unless cmd.is_a?(Array)
|
71
|
+
(@log.error "run!(cmd) require commands.";exit) if cmd.none?
|
72
|
+
|
73
|
+
@cmd=cmd
|
74
|
+
|
75
|
+
begin
|
76
|
+
@log.info("RUN!".center(60,"*"))
|
77
|
+
@log.debug @server
|
78
|
+
cmd.each { |e| self.exec!(e)}
|
79
|
+
rescue Exception => e
|
80
|
+
@log.error("#{self.inspect} run error!")
|
81
|
+
@log.error(e.to_s)
|
82
|
+
# raise e
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
|
87
|
+
def exec!(cmd)
|
88
|
+
# >> cmd='while((1>0));do sar -u -d 3 10; # done';cmdpath="#{cmd.gsub(/([^a-zA-Z0-9\-])/,'_')}.log"
|
89
|
+
# => "while__1_0___do_sar_-u_-d_3_10__done.log"
|
90
|
+
|
91
|
+
# cmdpath="#{@rpath}/#{cmd.gsub(/[\s|\t|\$|\`|\(|\)|\&|\>|\<|\;|\||\'|\"]/,'_')}.log"
|
92
|
+
cmdpath="#{@rpath}/#{cmd.gsub(/[^a-zA-Z0-9\-]/,'_')}.log"
|
93
|
+
@cmdpath=cmdpath
|
94
|
+
|
95
|
+
@log.debug "#{cmd} path => #{cmdpath}"
|
96
|
+
@log.info "Start #{cmd}.".center(60,"*")
|
97
|
+
|
98
|
+
@log.debug("#{cmd} >> #{cmdpath} 2>/dev/null &")
|
99
|
+
@sess.exec!("#{cmd} >> #{cmdpath} 2>/dev/null &")
|
100
|
+
|
101
|
+
@pids[cmd]=@sess.exec!("echo $!")
|
102
|
+
@log.debug("#{cmd} pid => #{@pids[:ku]}")
|
103
|
+
end
|
104
|
+
|
105
|
+
def stop!
|
106
|
+
@pids.each do |key,value|
|
107
|
+
@sess.exec!("kill -9 #{value}")
|
108
|
+
@log.info("#{key} => #{value} stop!")
|
109
|
+
end
|
110
|
+
|
111
|
+
# if other user exec the same cmd,
|
112
|
+
# below cmd will kill all of the cmd.
|
113
|
+
|
114
|
+
# @sess.exec!(%q@ps axf|grep while|grep -v grep|awk '{printf "%s\n",$1}'|xargs kill -9@)
|
115
|
+
#
|
116
|
+
# @cmd.each { |e|
|
117
|
+
# @sess.exec!(%q@ps axf|grep "#{e}"|grep -v grep|awk '{printf "%s\n",$1}'|xargs kill -9@)
|
118
|
+
# }
|
119
|
+
|
120
|
+
@log.debug @server
|
121
|
+
@log.info("Monitor STOP!".center(60,"*"))
|
122
|
+
end
|
123
|
+
|
124
|
+
def collect
|
125
|
+
@log.debug "mkdir -p #{@path}/#{@server}"
|
126
|
+
%x{mkdir -p #{@path}/#{@server}}
|
127
|
+
|
128
|
+
path = @path.gsub('~',`echo ~`.gsub(/[\r\n]/,''))
|
129
|
+
@log.info "Collecting...".center(60,"*")
|
130
|
+
@log.debug "collect path => #{path}/#{@server}"
|
131
|
+
`scp -r admin@#{@server}:#{@rpath} #{path}/#{@server}`
|
132
|
+
@log.info "collected files => #{Dir[path+'/'+@server+'/**/*'].join($/)}"
|
133
|
+
end
|
134
|
+
|
135
|
+
#-----------------------------monit method--------------------------------#
|
136
|
+
|
137
|
+
def self.monit(servers,log,cmd=['ifstat','iostat 3','while((1>0));do sar -u -d 3 10; done','vmstat 3','while((1>0));do sar -u -n DEV 3 10; done'],ts="PerformanceTest")
|
138
|
+
|
139
|
+
case servers
|
140
|
+
when Hash
|
141
|
+
# do nothing
|
142
|
+
when String
|
143
|
+
File.open( servers ) { |yf|
|
144
|
+
begin
|
145
|
+
servers=YAML::load( yf )
|
146
|
+
rescue Exception => e
|
147
|
+
log.error("Servers' config YAML Load Error!Plz check your yaml file => #{servers}.#{$/}#{e.to_s}")
|
148
|
+
exit 1
|
149
|
+
end
|
150
|
+
}
|
151
|
+
end
|
152
|
+
|
153
|
+
_servers = {}
|
154
|
+
|
155
|
+
servers.each do |ip,obj|
|
156
|
+
_servers[ip] = RoadRunnerModule::RRMonitor.new({:server=>ip, :log=>log, :username=>obj[:username], :password=>obj[:password], :ts=>obj[:obj]||ts})
|
157
|
+
|
158
|
+
_servers[ip].run! cmd
|
159
|
+
end
|
160
|
+
|
161
|
+
yield
|
162
|
+
|
163
|
+
_servers.each do |k,v|
|
164
|
+
v.stop!
|
165
|
+
v.collect
|
166
|
+
end
|
167
|
+
|
168
|
+
end
|
169
|
+
|
170
|
+
end
|
171
|
+
|
172
|
+
end
|
173
|
+
|
174
|
+
|
data/lib/run.rb
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
#After roadRunner.run() executed,
|
2
|
+
#execute roadRunner.report() show the Performance report
|
3
|
+
|
4
|
+
module RoadRunnerModule
|
5
|
+
def run
|
6
|
+
@strat_time = Time.now
|
7
|
+
@initBlk.call
|
8
|
+
@thread_pool = {}
|
9
|
+
@counter = 0
|
10
|
+
|
11
|
+
@log.debug "Mode => #{@mode}"
|
12
|
+
iterationBlk = case @mode
|
13
|
+
when /thread/,/t/ then
|
14
|
+
proc {
|
15
|
+
@users.times do |userId|
|
16
|
+
@thread_pool[Thread.start(){
|
17
|
+
@iterations.times do |iterationId|
|
18
|
+
|
19
|
+
rcost = 0
|
20
|
+
@transaction_blk.each_pair{|k,v|
|
21
|
+
rcost = self.transaction(k,v)
|
22
|
+
}
|
23
|
+
|
24
|
+
# rcost = self.transaction('Action',&@actBlk)
|
25
|
+
self.log.debug "IterationID is #{self.iterationId};UserID is #{self.userId};This Action Cost #{rcost} seconds"
|
26
|
+
@longest = (@longest<rcost)?rcost:@longest
|
27
|
+
@thread_pool[Thread.current][:iterationId] = iterationId
|
28
|
+
end
|
29
|
+
@counter += 1
|
30
|
+
}]={:userId=>userId}
|
31
|
+
end
|
32
|
+
# @thread_pool.keys.each{|t|t.join}
|
33
|
+
while @counter != @users do
|
34
|
+
Thread.pass
|
35
|
+
end
|
36
|
+
}
|
37
|
+
when /process/,/p/ then
|
38
|
+
proc {
|
39
|
+
ppid=Process.pid
|
40
|
+
@log.info("Main Process pid => #{ppid}")
|
41
|
+
|
42
|
+
pids=[]
|
43
|
+
@users.times { |userId|
|
44
|
+
pids << Process.fork {
|
45
|
+
@userId=userId
|
46
|
+
@iterations.times do |iterationId|
|
47
|
+
@iterationId=iterationId
|
48
|
+
|
49
|
+
rcost = 0
|
50
|
+
@transaction_blk.each_pair{|k,v|
|
51
|
+
rcost = self.transaction(k,v)
|
52
|
+
}
|
53
|
+
|
54
|
+
# rcost = self.transaction('Action',&@actBlk)
|
55
|
+
@longest = (@longest<rcost)?rcost:@longest
|
56
|
+
end
|
57
|
+
@log.info("<PID:#{Process.pid}> going down.Longest job cost #{@longest}")
|
58
|
+
|
59
|
+
Process.kill("HUP", ppid)
|
60
|
+
}
|
61
|
+
}
|
62
|
+
|
63
|
+
switch=true
|
64
|
+
c=0
|
65
|
+
Signal.trap("HUP", proc { @log.info("One User(Process) done."); (switch = false;p "Main process<#{Process.pid}> going down.") if ((c+=1) == @users) })
|
66
|
+
|
67
|
+
@log.info "Waiting Processes => #{pids.inspect}"
|
68
|
+
|
69
|
+
p "Processes<#{pids.inspect}> working."
|
70
|
+
while switch
|
71
|
+
STDOUT.puts '.'
|
72
|
+
sleep 5
|
73
|
+
end
|
74
|
+
p $/
|
75
|
+
|
76
|
+
Process.waitall
|
77
|
+
@log.info "Processes down."
|
78
|
+
}
|
79
|
+
else
|
80
|
+
proc {
|
81
|
+
@iterations.times do |iterationId|
|
82
|
+
@iterationId=iterationId
|
83
|
+
@users.times do |userId|
|
84
|
+
@userId=userId
|
85
|
+
|
86
|
+
rcost = 0
|
87
|
+
@transaction_blk.each_pair{|k,v|
|
88
|
+
rcost = self.transaction(k,v)
|
89
|
+
}
|
90
|
+
|
91
|
+
# rcost = self.transaction('Action',&@actBlk)
|
92
|
+
|
93
|
+
# => the below sentence cost a lot of system resource
|
94
|
+
# => if you run for production result,keep it annotated!!!
|
95
|
+
# self.log.debug "IterationID is #{self.iterationId};UserID is #{self.userId};This Action Cost #{rcost} seconds"
|
96
|
+
@longest = (@longest<rcost)?rcost:@longest
|
97
|
+
end
|
98
|
+
end
|
99
|
+
}
|
100
|
+
end
|
101
|
+
|
102
|
+
p ' '+"RoadRunner".center(50, '*')
|
103
|
+
p ' *'+"---Run , on your way.".rjust(48, ' ')+'*'
|
104
|
+
p ' '+'*'*50
|
105
|
+
p
|
106
|
+
p " Running......"
|
107
|
+
@rep = Benchmark::measure(&iterationBlk)
|
108
|
+
p " Ending......"
|
109
|
+
@endBlk.call
|
110
|
+
|
111
|
+
@tps = @iterations*@users/@rep.real
|
112
|
+
end
|
113
|
+
end
|