startup-time 1.1.1 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +7 -1
- data/README.md +6 -4
- data/lib/startup_time/app.rb +84 -44
- data/lib/startup_time/builder.rb +11 -10
- data/lib/startup_time/options.rb +29 -5
- data/lib/startup_time/registry.rb +10 -5
- data/lib/startup_time/services.rb +0 -4
- data/lib/startup_time/version.rb +1 -1
- metadata +16 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5edbc737357924e55026244d924546b02dd43c3f875c710a4174027abb0bfc82
|
4
|
+
data.tar.gz: 8c79da2fbbbf34be5dc0bae8115b33a7ccbe681493c4efea6f86028c20ad1f2b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d37390eae5748fde5435c8a261a7b6888f12c870424500124d6aa0d8ba6baa357c4de0846685013bb6f4cc3fac9b5470a4f167e265c775e1f2dcdcc520e7cb9a
|
7
|
+
data.tar.gz: 4eb78e5f8a43691d8f898b9fab7a23219e831c583836cf43fece6b3c9d1dc1d8af24170a0df7096a14a244cb4bdcb398035d7d8337a944606c0f964fa79abe97
|
data/CHANGELOG.md
CHANGED
@@ -1,7 +1,13 @@
|
|
1
|
+
## 1.2.0 - 2019-07-15
|
2
|
+
|
3
|
+
- add -t/--time option specifying the minimum length of time to run tests for
|
4
|
+
(default: 5s)
|
5
|
+
- format the ID -> group table as JSON if the --json option is provided
|
6
|
+
|
1
7
|
## 1.1.1 - 2019-07-13
|
2
8
|
|
3
9
|
- add QuickJS
|
4
|
-
-
|
10
|
+
- update deno version command
|
5
11
|
|
6
12
|
## 1.1.0 - 2019-02-27
|
7
13
|
|
data/README.md
CHANGED
@@ -49,8 +49,8 @@ $ startup-time --only jvm
|
|
49
49
|
# only run tests which finish quickly
|
50
50
|
$ startup-time --only fast --omit slow-compile
|
51
51
|
|
52
|
-
#
|
53
|
-
$ startup-time --
|
52
|
+
# minimum number of seconds to run the test suite for (default: 5)
|
53
|
+
$ startup-time --time 10
|
54
54
|
```
|
55
55
|
|
56
56
|
### Sample Output
|
@@ -106,7 +106,7 @@ USAGE:
|
|
106
106
|
|
107
107
|
OPTIONS:
|
108
108
|
|
109
|
-
-c, --count, --rounds INTEGER The number of times to run each
|
109
|
+
-c, --count, --rounds INTEGER The number of times to run each program
|
110
110
|
--clean Remove the build directory and exit
|
111
111
|
(targets will be recompiled on the next run)
|
112
112
|
-d, --dir PATH Specify the build directory
|
@@ -117,6 +117,8 @@ OPTIONS:
|
|
117
117
|
-o, --only LIST Only run the specified tests (comma-separated list of IDs/groups)
|
118
118
|
-O, --omit LIST Don't run the specified tests (comma-separated list of IDs/groups)
|
119
119
|
-q, --quiet Suppress all inessential output
|
120
|
+
-t, --time INTEGER The minimum number of seconds to run the test suite for
|
121
|
+
(minimum: 2, default: 5)
|
120
122
|
-v, --verbose Enable verbose logging
|
121
123
|
-V, --version Display the version and exit
|
122
124
|
```
|
@@ -142,7 +144,7 @@ OPTIONS:
|
|
142
144
|
|
143
145
|
## VERSION
|
144
146
|
|
145
|
-
1.
|
147
|
+
1.2.0
|
146
148
|
|
147
149
|
## COPYRIGHT AND LICENSE
|
148
150
|
|
data/lib/startup_time/app.rb
CHANGED
@@ -1,13 +1,14 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'benchmark'
|
4
|
+
require 'json'
|
4
5
|
require 'komenda'
|
5
6
|
require 'shellwords' # for Array#shelljoin
|
6
7
|
require 'tty/table'
|
7
8
|
|
8
|
-
# FIXME we only need bundler/setup here, but it appears
|
9
|
-
# Bundler object which (sometimes) confuses Komenda as well
|
10
|
-
# Gem::LoadError (for unicode-display_width)
|
9
|
+
# FIXME we only need bundler/setup here (for Bundler.with_clean_env), but it appears
|
10
|
+
# to create an incomplete Bundler object which (sometimes) confuses Komenda as well
|
11
|
+
# as causing a Gem::LoadError (for unicode-display_width)
|
11
12
|
#
|
12
13
|
# require 'bundler/setup'
|
13
14
|
require 'bundler'
|
@@ -20,10 +21,11 @@ module StartupTime
|
|
20
21
|
|
21
22
|
include FileUtils # for `sh`
|
22
23
|
include Util # for `which`
|
23
|
-
include Services.mixin %i[builder
|
24
|
+
include Services.mixin %i[builder selected_tests]
|
24
25
|
|
25
26
|
def initialize(args = ARGV)
|
26
27
|
@options = Options.new(args)
|
28
|
+
@json = @options.format == :json
|
27
29
|
@verbosity = @options.verbosity
|
28
30
|
@times = []
|
29
31
|
|
@@ -37,20 +39,15 @@ module StartupTime
|
|
37
39
|
# or print a help message) or the default command, which runs
|
38
40
|
# the selected benchmark-tests
|
39
41
|
def run
|
40
|
-
if @verbosity == :verbose
|
41
|
-
# used by StartupTime::App#time to dump the command line
|
42
|
-
require 'shellwords'
|
43
|
-
end
|
44
|
-
|
45
42
|
case @options.action
|
46
43
|
when :clean
|
47
44
|
builder.clean!
|
48
45
|
when :help
|
49
46
|
puts @options.usage
|
50
|
-
when :show_ids
|
51
|
-
puts render_ids_to_groups
|
52
47
|
when :version
|
53
48
|
puts VERSION
|
49
|
+
when :show_ids
|
50
|
+
render_ids_to_groups
|
54
51
|
else
|
55
52
|
benchmark
|
56
53
|
end
|
@@ -67,16 +64,55 @@ module StartupTime
|
|
67
64
|
def benchmark
|
68
65
|
builder.build!
|
69
66
|
|
70
|
-
|
71
|
-
|
67
|
+
# run a test if:
|
68
|
+
#
|
69
|
+
# - its interpreter exists
|
70
|
+
# - it's a compiled executable (i.e. its compiler exists)
|
71
|
+
#
|
72
|
+
# otherwise, skip it
|
73
|
+
runnable_tests = selected_tests.each_with_object([]) do |(id, test), tests|
|
74
|
+
args = Array(test[:command])
|
75
|
+
|
76
|
+
if args.length == 1 # native executable
|
77
|
+
compiler = test[:compiler] || id
|
78
|
+
path = File.absolute_path(args.first)
|
79
|
+
next unless File.exist?(path)
|
80
|
+
else # interpreter + source
|
81
|
+
compiler = args.first
|
82
|
+
path = which(compiler)
|
83
|
+
next unless path
|
84
|
+
end
|
85
|
+
|
86
|
+
tests << {
|
87
|
+
id: id,
|
88
|
+
test: test,
|
89
|
+
args: args,
|
90
|
+
compiler: compiler,
|
91
|
+
path: path,
|
92
|
+
}
|
93
|
+
end
|
94
|
+
|
95
|
+
if runnable_tests.empty?
|
96
|
+
puts '[]' if @json
|
97
|
+
return
|
98
|
+
end
|
99
|
+
|
100
|
+
spec = @options.spec
|
101
|
+
|
102
|
+
if spec.type == :duration
|
103
|
+
spec = spec.with(value: spec.value.to_f / runnable_tests.length)
|
104
|
+
end
|
105
|
+
|
106
|
+
runnable_tests.shuffle.each do |config|
|
107
|
+
config[:spec] = spec
|
108
|
+
time(config)
|
72
109
|
end
|
73
110
|
|
74
111
|
sorted = @times.sort_by { |result| result[:time] }
|
75
112
|
|
76
|
-
if @
|
77
|
-
require 'json'
|
113
|
+
if @json
|
78
114
|
puts sorted.to_json
|
79
|
-
|
115
|
+
else
|
80
116
|
pairs = sorted.map { |result| [result[:name], '%.02f' % result[:time]] }
|
81
117
|
table = TTY::Table.new(['Test', 'Time (ms)'], pairs)
|
82
118
|
puts unless @verbosity == :quiet
|
@@ -84,33 +120,20 @@ module StartupTime
|
|
84
120
|
end
|
85
121
|
end
|
86
122
|
|
87
|
-
#
|
88
|
-
# to group IDs (e.g. "compiled, jvm, slow")
|
123
|
+
# print a JSON or ASCII-table representation of the mapping from test IDs
|
124
|
+
# (e.g. "scala") to group IDs (e.g. ["compiled", "jvm", "slow"])
|
89
125
|
def render_ids_to_groups
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
# the test if either:
|
96
|
-
#
|
97
|
-
# - its interpreter exists
|
98
|
-
# - it's a compiled executable (i.e. its compiler exists)
|
99
|
-
#
|
100
|
-
# otherwise, skip the test
|
101
|
-
def time(id, test)
|
102
|
-
args = Array(test[:command])
|
103
|
-
|
104
|
-
if args.size == 1 # native executable
|
105
|
-
compiler = test[:compiler] || id
|
106
|
-
cmd = File.absolute_path(args.first)
|
107
|
-
return unless File.exist?(cmd)
|
108
|
-
else # interpreter + source
|
109
|
-
compiler = args.first
|
110
|
-
cmd = which(compiler)
|
111
|
-
return unless cmd
|
126
|
+
if @json
|
127
|
+
puts Registry.ids_to_groups(format: :json).to_json
|
128
|
+
else
|
129
|
+
table = TTY::Table.new(%w[Test Groups], Registry.ids_to_groups)
|
130
|
+
puts table.render
|
112
131
|
end
|
132
|
+
end
|
113
133
|
|
134
|
+
# takes a test configuration and measures how long it takes to execute the
|
135
|
+
# test
|
136
|
+
def time(id:, test:, args:, compiler:, path:, spec:)
|
114
137
|
# dump the compiler/interpreter's version if running in verbose mode
|
115
138
|
if @verbosity == :verbose
|
116
139
|
puts
|
@@ -133,7 +156,7 @@ module StartupTime
|
|
133
156
|
end
|
134
157
|
|
135
158
|
argv0 = args.shift
|
136
|
-
command = [
|
159
|
+
command = [path, *args]
|
137
160
|
|
138
161
|
unless @verbosity == :quiet
|
139
162
|
if @verbosity == :verbose
|
@@ -160,9 +183,26 @@ module StartupTime
|
|
160
183
|
# the bundler environment slows down ruby and breaks truffle-ruby,
|
161
184
|
# so make sure it's disabled for the benchmark
|
162
185
|
Bundler.with_clean_env do
|
163
|
-
|
164
|
-
|
165
|
-
|
186
|
+
if spec.type == :duration # how long to run the tests for
|
187
|
+
duration = spec.value
|
188
|
+
elapsed = 0
|
189
|
+
start = Time.now
|
190
|
+
|
191
|
+
loop do
|
192
|
+
time = Benchmark.realtime do
|
193
|
+
system([path, argv0], *args, out: File::NULL)
|
194
|
+
end
|
195
|
+
|
196
|
+
elapsed = Time.now - start
|
197
|
+
times << time
|
198
|
+
|
199
|
+
break if elapsed >= duration
|
200
|
+
end
|
201
|
+
else # how many times to run the tests
|
202
|
+
spec.value.times do
|
203
|
+
times << Benchmark.realtime do
|
204
|
+
system([path, argv0], *args, out: File::NULL)
|
205
|
+
end
|
166
206
|
end
|
167
207
|
end
|
168
208
|
end
|
data/lib/startup_time/builder.rb
CHANGED
@@ -108,12 +108,12 @@ module StartupTime
|
|
108
108
|
# absolute path (which may be mocked)
|
109
109
|
test = test.merge(compiler: compiler_path)
|
110
110
|
|
111
|
-
# pass the test object as the block's second
|
112
|
-
# instance of +Rake::TaskArguments+, a Hash-like
|
113
|
-
# access to the command-line arguments for a Rake
|
114
|
-
# "world" } for `rake greet[world]`. since we're not
|
115
|
-
# limited option-handling support, we have no use for
|
116
|
-
# simply replace it with the test data.
|
111
|
+
# pass the test object as the `file(...) { ... }` block's second
|
112
|
+
# argument. Rake passes an instance of +Rake::TaskArguments+, a Hash-like
|
113
|
+
# object which provides access to the command-line arguments for a Rake
|
114
|
+
# task e.g. { name: "world" } for `rake greet[world]`. since we're not
|
115
|
+
# relying on Rake's limited option-handling support, we have no use for
|
116
|
+
# that here, so we simply replace it with the test data.
|
117
117
|
wrapper = ->(task, _) { yield(task, test) }
|
118
118
|
|
119
119
|
# declare the prerequisites for the target file.
|
@@ -138,8 +138,8 @@ module StartupTime
|
|
138
138
|
end
|
139
139
|
|
140
140
|
# ensure each file in the source directory is mirrored to the build
|
141
|
-
# directory, and add each task which ensures this as a prerequisite
|
142
|
-
#
|
141
|
+
# directory, and add each task which ensures this as a prerequisite of the
|
142
|
+
# master task (:build)
|
143
143
|
def copy_source_files
|
144
144
|
Dir["#{SRC_DIR}/*.*"].each do |path|
|
145
145
|
filename = File.basename(path)
|
@@ -153,7 +153,7 @@ module StartupTime
|
|
153
153
|
end
|
154
154
|
|
155
155
|
# run a shell command (string) by substituting the compiler path, source
|
156
|
-
# file, and target file into the supplied template and executing the
|
156
|
+
# file, and target file into the supplied template string and executing the
|
157
157
|
# resulting command with the test's (optional) environment hash
|
158
158
|
def run(template, task, test)
|
159
159
|
replacements = {
|
@@ -192,11 +192,12 @@ module StartupTime
|
|
192
192
|
end
|
193
193
|
|
194
194
|
if java_native
|
195
|
-
javac = compile_if(:javac, force: true) do |task, test|
|
195
|
+
javac = compile_if(:javac, connect: false, force: true) do |task, test|
|
196
196
|
run('%{compiler} -d . %{source}', task, test)
|
197
197
|
end
|
198
198
|
|
199
199
|
if javac
|
200
|
+
task java_native => javac
|
200
201
|
task :build => java_native
|
201
202
|
end
|
202
203
|
else
|
data/lib/startup_time/options.rb
CHANGED
@@ -2,13 +2,17 @@
|
|
2
2
|
|
3
3
|
require 'env_paths'
|
4
4
|
require 'optparse'
|
5
|
+
require 'values'
|
5
6
|
|
6
7
|
module StartupTime
|
7
8
|
# StartupTime::Options - a struct-like interface to the app options set or
|
8
9
|
# overridden on the command line
|
9
10
|
class Options
|
10
11
|
BUILD_DIR = EnvPaths.get('startup-time', suffix: false).cache
|
11
|
-
|
12
|
+
DEFAULT_DURATION = 5
|
13
|
+
MINIMUM_DURATION = 2
|
14
|
+
|
15
|
+
Spec = Value.new(:type, :value)
|
12
16
|
|
13
17
|
attr_reader :action, :build_dir, :format, :rounds, :verbosity
|
14
18
|
|
@@ -17,14 +21,24 @@ module StartupTime
|
|
17
21
|
def initialize(args)
|
18
22
|
@action = :benchmark
|
19
23
|
@build_dir = BUILD_DIR
|
24
|
+
@duration = DEFAULT_DURATION
|
20
25
|
@format = :default
|
21
26
|
@parser = nil
|
22
|
-
@rounds =
|
27
|
+
@rounds = nil
|
28
|
+
@spec = nil
|
23
29
|
@verbosity = :default
|
24
30
|
|
25
31
|
parse! args
|
26
32
|
end
|
27
33
|
|
34
|
+
def spec
|
35
|
+
@spec ||= if @rounds
|
36
|
+
Spec.with(type: :count, value: @rounds)
|
37
|
+
else
|
38
|
+
Spec.with(type: :duration, value: @duration)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
28
42
|
# the usage message (string) generated by the option parser for this tool
|
29
43
|
def usage
|
30
44
|
@parser.to_s
|
@@ -41,7 +55,7 @@ module StartupTime
|
|
41
55
|
'--count',
|
42
56
|
'--rounds INTEGER',
|
43
57
|
Integer,
|
44
|
-
|
58
|
+
'The number of times to run each program'
|
45
59
|
) do |value|
|
46
60
|
@rounds = value
|
47
61
|
end
|
@@ -94,7 +108,7 @@ module StartupTime
|
|
94
108
|
'-o',
|
95
109
|
'--only LIST',
|
96
110
|
Array, # comma-separated strings
|
97
|
-
'Only
|
111
|
+
'Only run the specified tests (comma-separated list of IDs/groups)'
|
98
112
|
) do |values|
|
99
113
|
values.each { |value| registry.only(value.strip) }
|
100
114
|
end
|
@@ -103,7 +117,7 @@ module StartupTime
|
|
103
117
|
'-O',
|
104
118
|
'--omit LIST',
|
105
119
|
Array, # comma-separated strings
|
106
|
-
"Don't
|
120
|
+
"Don't run the specified tests (comma-separated list of IDs/groups)"
|
107
121
|
) do |values|
|
108
122
|
values.each { |value| registry.omit(value.strip) }
|
109
123
|
end
|
@@ -116,6 +130,16 @@ module StartupTime
|
|
116
130
|
@verbosity = :quiet
|
117
131
|
end
|
118
132
|
|
133
|
+
opts.on(
|
134
|
+
'-t',
|
135
|
+
'--time INTEGER',
|
136
|
+
Integer,
|
137
|
+
'Specify the minimum number of seconds to run tests for',
|
138
|
+
"(minimum: #{MINIMUM_DURATION}, default: #{DEFAULT_DURATION})"
|
139
|
+
) do |value|
|
140
|
+
@duration = [value, MINIMUM_DURATION].max
|
141
|
+
end
|
142
|
+
|
119
143
|
opts.on(
|
120
144
|
'-v',
|
121
145
|
'--verbose',
|
@@ -4,7 +4,6 @@ require 'active_support'
|
|
4
4
|
require 'active_support/core_ext/hash/indifferent_access'
|
5
5
|
require 'active_support/core_ext/hash/slice' # XXX in core since 2.5
|
6
6
|
require 'set'
|
7
|
-
require 'shellwords'
|
8
7
|
require 'yaml'
|
9
8
|
|
10
9
|
module StartupTime
|
@@ -35,10 +34,16 @@ module StartupTime
|
|
35
34
|
end
|
36
35
|
end
|
37
36
|
|
38
|
-
#
|
39
|
-
#
|
40
|
-
def self.ids_to_groups
|
41
|
-
|
37
|
+
# a hash which maps test IDs (e.g. "scala") to their corresponding group
|
38
|
+
# names (e.g. ["compiled", "jvm", "slow"])
|
39
|
+
def self.ids_to_groups(format: :ascii)
|
40
|
+
if format == :json
|
41
|
+
TESTS.entries.each_with_object({}) do |(id, test), target|
|
42
|
+
target[id] = test[:groups].sort
|
43
|
+
end
|
44
|
+
else # ASCII
|
45
|
+
TESTS.entries.map { |id, test| [id, test[:groups].sort.join(', ')] }
|
46
|
+
end
|
42
47
|
end
|
43
48
|
|
44
49
|
def initialize
|
@@ -8,10 +8,6 @@ module StartupTime
|
|
8
8
|
# the component responsible for managing the build directory
|
9
9
|
once(:builder) { Builder.new }
|
10
10
|
|
11
|
-
# a hash which maps test IDs (e.g. "scala") to group names
|
12
|
-
# (e.g. "compiled, jvm, slow")
|
13
|
-
once(:ids_to_groups) { Registry.ids_to_groups }
|
14
|
-
|
15
11
|
# an interface to the tests configured in resources/tests.yaml
|
16
12
|
once(:registry) { Registry.new }
|
17
13
|
|
data/lib/startup_time/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: startup-time
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- chocolateboy
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-07-
|
11
|
+
date: 2019-07-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -122,6 +122,20 @@ dependencies:
|
|
122
122
|
- - "~>"
|
123
123
|
- !ruby/object:Gem::Version
|
124
124
|
version: 0.4.0
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: values
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - "~>"
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '1.8'
|
132
|
+
type: :runtime
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - "~>"
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '1.8'
|
125
139
|
- !ruby/object:Gem::Dependency
|
126
140
|
name: wireless
|
127
141
|
requirement: !ruby/object:Gem::Requirement
|