Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
张重言
rails
提交
f7866cda
R
rails
项目概览
张重言
/
rails
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
R
rails
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
f7866cda
编写于
6月 15, 2008
作者:
J
Jeremy Kemper
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Extract Metric and Performer. Simplify and refactor.
上级
01a4af4a
变更
1
隐藏空白更改
内联
并排
Showing
1 changed file
with
212 addition
and
138 deletion
+212
-138
activesupport/lib/active_support/testing/performance.rb
activesupport/lib/active_support/testing/performance.rb
+212
-138
未找到文件。
activesupport/lib/active_support/testing/performance.rb
浏览文件 @
f7866cda
...
...
@@ -12,18 +12,22 @@ module Performance
DEFAULTS
=
{
:benchmark
=>
benchmark
,
:runs
=>
benchmark
?
20
:
4
,
:min_percent
=>
0.0
5
,
:metrics
=>
[
:process_time
,
:
memory
,
:allocation
s
],
:runs
=>
benchmark
?
10
:
1
,
:min_percent
=>
0.0
2
,
:metrics
=>
[
:process_time
,
:
wall_time
,
:cpu_time
,
:memory
,
:object
s
],
:formats
=>
[
:flat
,
:graph_html
,
:call_tree
],
:output
=>
'tmp/performance'
}
:output
=>
'tmp/performance'
}
def
self
.
included
(
base
)
base
.
extend
ClassMethods
base
.
class_inheritable_accessor
:profile_options
base
.
class_inheritable_hash
:profile_options
base
.
profile_options
=
DEFAULTS
.
dup
end
def
full_test_name
"
#{
self
.
class
.
name
}
#
#{
method_name
}
"
end
def
run
(
result
)
return
if
method_name
=~
/^default_test$/
...
...
@@ -31,153 +35,122 @@ def run(result)
@_result
=
result
run_warmup
self
.
class
.
measure_modes
.
each
do
|
measure_mode
|
data
=
run_profile
(
measure_mode
)
self
.
class
.
report_profile_total
(
data
,
measure_mode
)
self
.
class
.
record_results
(
full_test_name
,
data
,
measure_mode
)
result
.
add_run
profile_options
[
:metrics
].
each
do
|
metric_name
|
if
klass
=
Metrics
[
metric_name
.
to_sym
]
run_profile
(
klass
.
new
)
result
.
add_run
else
$stderr
.
puts
"Skipping unknown metric
#{
metric_name
.
inspect
}
. Expected :process_time, :wall_time, :cpu_time, :memory, or :objects."
end
end
yield
(
self
.
class
::
FINISHED
,
name
)
end
protected
def
full_test_name
"
#{
self
.
class
.
name
}
#
#{
@method_name
}
"
end
def
run_test
run_callbacks
:setup
setup
yield
def
run_test
(
metric
,
mode
)
run_callbacks
:setup
setup
metric
.
send
(
mode
)
{
__send__
@method_name
}
rescue
::
Test
::
Unit
::
AssertionFailedError
=>
e
add_failure
(
e
.
message
,
e
.
backtrace
)
rescue
StandardError
,
ScriptError
add_error
(
$!
)
ensure
begin
teardown
run_callbacks
:teardown
,
:enumerator
=>
:reverse_each
rescue
::
Test
::
Unit
::
AssertionFailedError
=>
e
add_failure
(
e
.
message
,
e
.
backtrace
)
rescue
StandardError
,
ScriptError
add_error
(
$!
)
ensure
begin
teardown
run_callbacks
:teardown
,
:enumerator
=>
:reverse_each
rescue
::
Test
::
Unit
::
AssertionFailedError
=>
e
add_failure
(
e
.
message
,
e
.
backtrace
)
rescue
StandardError
,
ScriptError
add_error
(
$!
)
end
end
end
protected
def
run_warmup
puts
print
full_test_name
run_test
do
bench
=
Benchmark
.
realtime
do
__send__
(
@method_name
)
end
puts
" (%.2fs warmup)"
%
bench
end
time
=
Metrics
::
Time
.
new
run_test
(
time
,
:benchmark
)
puts
"%s (%s warmup)"
%
[
full_test_name
,
time
.
format
(
time
.
total
)]
end
def
run_profile
(
me
asure_mode
)
RubyProf
.
benchmarking
=
profile_options
[
:benchmark
]
RubyProf
.
measure_mode
=
measure_mode
def
run_profile
(
me
tric
)
klass
=
profile_options
[
:benchmark
]
?
Benchmarker
:
Profiler
performer
=
klass
.
new
(
self
,
metric
)
print
' '
profile_options
[
:runs
].
times
do
|
i
|
run_test
do
begin
GC
.
disable
RubyProf
.
resume
{
__send__
(
@method_name
)
}
print
'.'
$stdout
.
flush
ensure
GC
.
enable
end
end
end
RubyProf
.
stop
end
module
ClassMethods
def
record_results
(
test_name
,
data
,
measure_mode
)
if
RubyProf
.
benchmarking?
record_benchmark
(
test_name
,
data
,
measure_mode
)
else
record_profile
(
test_name
,
data
,
measure_mode
)
end
performer
.
run
puts
performer
.
report
performer
.
record
end
def
report_profile_total
(
data
,
measure_mode
)
total_time
=
if
RubyProf
.
benchmarking?
data
else
data
.
threads
.
values
.
sum
(
0
)
do
|
method_infos
|
method_infos
.
sort
.
last
.
total_time
end
end
class
Performer
delegate
:profile_options
,
:full_test_name
,
:to
=>
:@harness
format
=
case
measure_mode
when
RubyProf
::
PROCESS_TIME
,
RubyProf
::
WALL_TIME
"%.2f seconds"
when
RubyProf
::
MEMORY
"%.2f bytes"
when
RubyProf
::
ALLOCATIONS
"%d allocations"
else
"%.2f
#{
measure_mode
}
"
end
def
initialize
(
harness
,
metric
)
@harness
,
@metric
=
harness
,
metric
end
total
=
format
%
total_time
puts
"
\n
#{
ActiveSupport
::
Testing
::
Performance
::
Util
.
metric_name
(
measure_mode
)
}
:
#{
total
}
\n
"
def
report
rate
=
@total
/
profile_options
[
:runs
]
'%20s: %s/run'
%
[
@metric
.
name
,
@metric
.
format
(
rate
)]
end
end
def
measure_modes
ActiveSupport
::
Testing
::
Performance
::
Util
.
measure_modes
(
profile_options
[
:metrics
])
class
Benchmarker
<
Performer
def
run
profile_options
[
:runs
].
times
{
@harness
.
run_test
(
@metric
,
:benchmark
)
}
@total
=
@metric
.
total
end
def
printer_classes
ActiveSupport
::
Testing
::
Performance
::
Util
.
printer_classes
(
profile_options
[
:formats
])
def
record
with_output_file
do
|
file
|
file
.
puts
[
full_test_name
,
@metric
.
name
,
@metric
.
total
,
profile_options
[
:runs
],
@metric
.
total
/
profile_options
[
:runs
],
Time
.
now
.
utc
.
xmlschema
,
Rails
::
VERSION
::
STRING
,
defined?
(
RUBY_ENGINE
)
?
RUBY_ENGINE
:
'ruby'
,
RUBY_VERSION
,
RUBY_PATCHLEVEL
,
RUBY_PLATFORM
].
join
(
','
)
end
end
private
def
record_benchmark
(
test_name
,
data
,
measure_mode
)
bench_filename
=
"
#{
profile_options
[
:output
]
}
/benchmarks.csv"
protected
HEADER
=
'test,metric,measurement,runs,average,created_at,rails_version,ruby_engine,ruby_version,ruby_patchlevel,ruby_platform'
if
new_file
=
!
File
.
exist?
(
bench_filename
)
FileUtils
.
mkdir_p
(
File
.
dirname
(
bench_filename
))
end
def
with_output_file
fname
=
"
#{
profile_options
[
:output
]
}
/benchmarks.csv"
File
.
open
(
bench_filename
,
'ab'
)
do
|
file
|
if
new_file
file
.
puts
'test,metric,measurement,runs,average,created_at,rails_version,ruby_engine,ruby_version,ruby_patchlevel,ruby_platform'
end
if
new
=
!
File
.
exist?
(
fname
)
FileUtils
.
mkdir_p
(
File
.
dirname
(
fname
))
end
file
.
puts
[
test_name
,
ActiveSupport
::
Testing
::
Performance
::
Util
.
metric_name
(
measure_mode
),
data
,
profile_options
[
:runs
],
data
/
profile_options
[
:runs
],
Time
.
now
.
utc
.
xmlschema
,
Rails
::
VERSION
::
STRING
,
defined?
(
RUBY_ENGINE
)
?
RUBY_ENGINE
:
'ruby'
,
RUBY_VERSION
,
RUBY_PATCHLEVEL
,
RUBY_PLATFORM
].
join
(
','
)
File
.
open
(
fname
,
'ab'
)
do
|
file
|
file
.
puts
(
HEADER
)
if
new
yield
file
end
end
end
class
Profiler
<
Performer
def
run
@runs
.
times
{
@harness
.
run_test
(
@metric
,
:profile
)
}
@data
=
RubyProf
.
stop
@total
=
@data
.
threads
.
values
.
sum
(
0
)
{
|
method_infos
|
method_infos
.
sort
.
last
.
total_time
}
end
def
record_profile
(
test_name
,
data
,
measure_mode
)
printer_classes
.
each
do
|
printer_class
|
fname
=
output_filename
(
test_name
,
printer_class
,
measure_mode
)
def
record
(
path
)
klasses
=
profile_options
[
:formats
].
map
{
|
f
|
RubyProf
.
const_get
(
"
#{
f
.
to_s
.
camelize
}
Printer"
)
}.
compact
FileUtils
.
mkdir_p
(
File
.
dirname
(
fname
))
File
.
open
(
fname
,
'wb'
)
do
|
file
|
printer_class
.
new
(
data
).
print
(
file
,
profile_printer_options
)
end
klasses
.
each
do
|
klass
|
fname
=
output_filename
(
metric
,
klass
)
FileUtils
.
mkdir_p
(
File
.
dirname
(
fname
))
File
.
open
(
fname
,
'wb'
)
do
|
file
|
klass
.
new
(
@data
).
print
(
file
,
profile_options
.
slice
(
:min_percent
))
end
end
end
# The report filename is test_name + measure_mode + report_type
def
output_filename
(
test_name
,
printer_class
,
measure_mode
)
protected
def
output_filename
(
metric
,
printer_class
)
suffix
=
case
printer_class
.
name
.
demodulize
when
'FlatPrinter'
;
'flat.txt'
...
...
@@ -187,39 +160,140 @@ def output_filename(test_name, printer_class, measure_mode)
else
printer_class
.
name
.
sub
(
/Printer$/
,
''
).
underscore
end
"
#{
profile_options
[
:output
]
}
/
#{
test_name
}
_
#{
ActiveSupport
::
Testing
::
Performance
::
Util
.
metric_name
(
measure_mode
)
}
_
#{
suffix
}
"
"
#{
profile_options
[
:output
]
}
/
#{
full_test_name
}
_
#{
metric
.
name
}
_
#{
suffix
}
"
end
end
module
Metrics
def
self
.
[]
(
name
)
klass
=
const_get
(
name
.
to_s
.
camelize
)
klass
if
klass
::
Mode
rescue
nil
end
class
Base
attr_reader
:total
def
profile_printer_options
profile_options
.
slice
(
:min_percent
)
def
initialize
@total
=
0
end
def
name
@name
||=
self
.
class
.
name
.
demodulize
.
underscore
end
end
module
Util
extend
self
def
benchmark
with_gc_stats
do
before
=
measure
yield
@total
+=
(
measure
-
before
)
end
end
def
metric_name
(
measure_mode
)
case
measure_mode
when
RubyProf
::
PROCESS_TIME
;
'process_time'
when
RubyProf
::
WALL_TIME
;
'wall_time'
when
RubyProf
::
MEMORY
;
'memory'
when
RubyProf
::
ALLOCATIONS
;
'allocations'
else
"measure
#{
measure_mode
}
"
def
profile
RubyProf
.
measure_mode
=
MODE
RubyProf
.
resume
{
yield
}
end
protected
if
GC
.
respond_to?
(
:enable_stats
)
def
with_gc_stats
GC
.
enable_stats
yield
ensure
GC
.
disable_stats
end
else
def
with_gc_stats
yield
end
end
end
def
measure_modes
(
metrics
)
ruby_prof_consts
(
metrics
.
map
{
|
m
|
m
.
to_s
.
upcase
})
class
Time
<
Base
def
measure
::
Time
.
now
.
to_f
end
def
format
(
measurement
)
if
measurement
<
2
'%d ms'
%
(
measurement
*
1000
)
else
'%.2f sec'
%
measurement
end
end
end
def
printer_classes
(
formats
)
ruby_prof_consts
(
formats
.
map
{
|
f
|
"
#{
f
.
to_s
.
camelize
}
Printer"
})
class
ProcessTime
<
Time
Mode
=
RubyProf
::
PROCESS_TIME
def
measure
RubyProf
.
measure_process_time
end
end
private
def
ruby_prof_consts
(
names
)
names
.
map
{
|
name
|
RubyProf
.
const_get
(
name
)
rescue
nil
}.
compact
class
WallTime
<
Time
Mode
=
RubyProf
::
WALL_TIME
def
measure
RubyProf
.
measure_wall_time
end
end
class
CpuTime
<
Time
Mode
=
RubyProf
::
CPU_TIME
def
initialize
(
*
args
)
# FIXME: yeah my CPU is 2.33 GHz
RubyProf
.
cpu_frequency
=
2.33e9
super
end
def
measure
RubyProf
.
measure_cpu_time
end
end
class
Memory
<
Base
Mode
=
RubyProf
::
MEMORY
if
RubyProf
.
respond_to?
(
:measure_memory
)
def
measure
RubyProf
.
measure_memory
end
elsif
GC
.
respond_to?
(
:allocated_size
)
def
measure
GC
.
allocated_size
end
elsif
GC
.
respond_to?
(
:malloc_allocated_size
)
def
measure
GC
.
malloc_allocated_size
end
end
def
format
(
measurement
)
'%.2f KB'
%
(
measurement
/
1024.0
)
end
end
class
Objects
<
Base
Mode
=
RubyProf
::
ALLOCATIONS
if
RubyProf
.
respond_to?
(
:measure_allocations
)
def
measure
RubyProf
.
measure_allocations
end
elsif
ObjectSpace
.
respond_to?
(
:allocated_objects
)
def
measure
ObjectSpace
.
allocated_objects
end
end
def
format
(
measurement
)
measurement
.
to_s
end
end
end
end
end
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录