startup-time 1.1.1 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|