sunburst 0.2.0 → 0.3.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/exe/sunburst +88 -24
- data/ext/stats/stats.c +7 -5
- data/lib/sunburst/sunburst.rb +31 -3
- data/lib/sunburst/version.rb +1 -1
- metadata +2 -4
- data/README.md +0 -78
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9ecfac43448912f08b86571fecabeb676b11902524428b542973b83f535eeb71
|
4
|
+
data.tar.gz: 85668f8a6cb4a40f48e9e6f24c43dae60cf07b68a9ab1b6d4f5559b2eb8f0d71
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: '09483bbbc6011547a6cbc1a691363545d5c7002dbfca9c593fde20bb4083df5995e449e02d319bd65054967b164417a2cc2662cca41541c647ab745f67e776fe'
|
7
|
+
data.tar.gz: 42c5ce9d7ba09046ddb22c27cb8de6ac64c64a488b0a52a3cb52357aa2d1fc3f4029e8772fa3543c6725ac5ada1258c4876564c0fb7ddd07ab2593d84d2e0463
|
data/exe/sunburst
CHANGED
@@ -1,4 +1,6 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
# Frozen_String_Literal: true
|
3
|
+
|
2
4
|
$-v = nil
|
3
5
|
STDOUT.sync = STDIN.sync = true
|
4
6
|
require 'sunburst'
|
@@ -15,13 +17,16 @@ def help
|
|
15
17
|
Arguments:
|
16
18
|
\s\s\s\s--time=N\s\s\s\s\s\s\s\s\s\sRun the program for N seconds
|
17
19
|
\s\s\s\s-h | --help\s\s\s\s\s\s\sShow this help section
|
20
|
+
\s\s\s\s-p | --progress\s\s\sShow realtime stats of the process
|
18
21
|
\s\s\s\s--humanize\s\s\s\s\s\s\s\sHuman readable memory units
|
19
22
|
|
20
23
|
Example:
|
21
24
|
\s\s\s\ssunburst echo hello world --time=0.05 --humanize
|
22
25
|
\s\s\s\ssunburst "echo hello world" --time=0.05 --humanize
|
23
26
|
\s\s\s\ssunburst "ruby -e 'while true do end'" --time=3 --humanize
|
24
|
-
\s\s\s\ssunburst "ruby -e 'p :Hello'" --time=3
|
27
|
+
\s\s\s\ssunburst "ruby -e 'p :Hello'" --time=3
|
28
|
+
\s\s\s\ssunburst "while : ; do : ; done" --time=3 --humanize --progress
|
29
|
+
|
25
30
|
EOF
|
26
31
|
|
27
32
|
exit 0
|
@@ -32,6 +37,20 @@ def splitter(sub = 8)
|
|
32
37
|
puts ?\n, ?-.*(width - sub).center(width)
|
33
38
|
end
|
34
39
|
|
40
|
+
def convert_bytes(mem)
|
41
|
+
if mem >= 10 ** 12
|
42
|
+
"#{"%06.3f" % mem.fdiv(10 ** 12)} TB"
|
43
|
+
elsif mem >= 10 ** 9
|
44
|
+
"#{"%06.3f" % mem.fdiv(10 ** 9)} GB"
|
45
|
+
elsif mem >= 10 ** 6
|
46
|
+
"#{"%06.3f" % mem.fdiv(10 ** 6)} MB"
|
47
|
+
elsif mem >= 10 ** 3
|
48
|
+
"#{"%06.3f" % mem.fdiv(10 ** 3)} KB"
|
49
|
+
else
|
50
|
+
"#{"%06.3f" % mem} Bytes"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
35
54
|
help if ARGV.any? { |x| x[/^\-(\-help|h)$/] }
|
36
55
|
|
37
56
|
time_arg = ARGV.find { |x| x[/^\-\-time=[0-9]+\.?[0-9]*$/] }
|
@@ -42,20 +61,49 @@ _human_readable = ARGV.find { |x| x[/^\-\-humanize$/] }
|
|
42
61
|
ARGV.delete(_human_readable) if _human_readable
|
43
62
|
human_readable = _human_readable
|
44
63
|
|
64
|
+
_progress = ARGV.find { |x| x[/^\-(\-progress|p)$/] }
|
65
|
+
ARGV.delete(_progress) if _progress
|
66
|
+
progress = _progress
|
67
|
+
|
45
68
|
command = ARGV.join(' ')
|
46
69
|
|
47
70
|
help if command.empty?
|
48
71
|
|
49
72
|
puts %Q(:: Running "#{command}" for #{time || 'infinite'} seconds)
|
50
73
|
|
51
|
-
|
52
74
|
begin
|
53
|
-
|
75
|
+
message = if progress
|
76
|
+
"\e[4mLogging Stats, Ignoring Standard Output and Error\e[0m"
|
77
|
+
else
|
78
|
+
"\e[4mLogging Standard Output and Error\e[0m"
|
79
|
+
end
|
54
80
|
|
55
|
-
message = "\e[4mLogging Standard Output and Error\e[0m"
|
56
81
|
puts "\e[38;2;243;156;18m#{message.center(Sunburst.win_width + 6)}\e[0m"
|
57
82
|
|
58
|
-
data =
|
83
|
+
data = if progress
|
84
|
+
if human_readable
|
85
|
+
Sunburst.measure(command: command, time: time, sleep_time: 0.0001) { |exec_t, cpu_t, mem, threads, state|
|
86
|
+
print "\e[2K:: "\
|
87
|
+
"Exec T: #{"%05.2f" % exec_t}s | "\
|
88
|
+
"CPU T: #{"%05.2f" % cpu_t}s | "\
|
89
|
+
"Mem: #{convert_bytes(mem)} | "\
|
90
|
+
"Threads: #{threads} | "\
|
91
|
+
"State: #{state}\r"
|
92
|
+
}
|
93
|
+
else
|
94
|
+
Sunburst.measure(command: command, time: time, sleep_time: 0.0001) { |exec_t, cpu_t, mem, threads, state|
|
95
|
+
print "\e[2K:: "\
|
96
|
+
"Exec T: #{"%05.2f" % exec_t} | "\
|
97
|
+
"CPU T: #{"%05.2f" % cpu_t} | "\
|
98
|
+
"Mem: #{"%2d" % mem} | "\
|
99
|
+
"Threads: #{threads} | "\
|
100
|
+
"State: #{state}\r"
|
101
|
+
}
|
102
|
+
end
|
103
|
+
else
|
104
|
+
Sunburst.measure(command: command, time: time, sleep_time: 0.0001)
|
105
|
+
end
|
106
|
+
|
59
107
|
print "\e[38;2;243;156;18m"
|
60
108
|
splitter()
|
61
109
|
print "\e[0m"
|
@@ -64,7 +112,7 @@ begin
|
|
64
112
|
cpu_time = data[:cpu_time]
|
65
113
|
percent_time = cpu_time.*(100).fdiv(exec_time)
|
66
114
|
|
67
|
-
style = "\e[1;"
|
115
|
+
style = +"\e[1;"
|
68
116
|
style << if percent_time > 75
|
69
117
|
"38;2;230;80;70m"
|
70
118
|
elsif percent_time > 50
|
@@ -76,13 +124,13 @@ begin
|
|
76
124
|
end
|
77
125
|
|
78
126
|
puts ":: Total Execution Time: #{data[:execution_time]} seconds\e[0m"
|
79
|
-
puts ":: CPU Time: #{style}#{data[:cpu_time]}\e[0m second#{?s if data[:cpu_time] != 1} (#{percent_time.round(3)}% exec time)"
|
127
|
+
puts ":: Total CPU Time: #{style}#{data[:cpu_time]}\e[0m second#{?s if data[:cpu_time] != 1} (#{percent_time.round(3)}% exec time)"
|
80
128
|
|
81
129
|
mem = data[:memory]
|
82
130
|
if mem
|
83
131
|
percent_mem = mem.*(100).fdiv(Sunburst.total_ram)
|
84
132
|
|
85
|
-
style = "\e[1;"
|
133
|
+
style = +"\e[1;"
|
86
134
|
style << if percent_mem > 50
|
87
135
|
"38;2;230;80;70m"
|
88
136
|
elsif percent_mem > 30
|
@@ -94,28 +142,44 @@ begin
|
|
94
142
|
end
|
95
143
|
|
96
144
|
if human_readable
|
97
|
-
mem_text =
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
145
|
+
mem_text = convert_bytes(mem)
|
146
|
+
|
147
|
+
puts ":: Memory Usage During Exit: #{style}#{mem_text}\e[0m (#{percent_mem.round(3)}% system mem)"
|
148
|
+
else
|
149
|
+
puts ":: Memory Usage During Exit: #{style}#{mem} bytes\e[0m (#{percent_mem.round(3)}% system mem)"
|
150
|
+
end
|
151
|
+
else
|
152
|
+
puts ":: The memory Usage Can't be Logged."
|
153
|
+
end
|
154
|
+
|
155
|
+
max_mem = data[:max_memory]
|
156
|
+
if max_mem
|
157
|
+
percent_mem = max_mem.*(100).fdiv(Sunburst.total_ram)
|
158
|
+
|
159
|
+
style = +"\e[1;"
|
160
|
+
style << if percent_mem > 50
|
161
|
+
"38;2;230;80;70m"
|
162
|
+
elsif percent_mem > 30
|
163
|
+
"38;2;45;125;255m"
|
164
|
+
elsif percent_mem > 10
|
165
|
+
"38;2;255;225;0m"
|
166
|
+
else
|
167
|
+
"38;2;40;175;95m"
|
168
|
+
end
|
169
|
+
|
170
|
+
if human_readable
|
171
|
+
mem_text = convert_bytes(max_mem)
|
172
|
+
|
173
|
+
puts ":: Max Memory Usage: #{style}#{mem_text}\e[0m (#{percent_mem.round(3)}% system mem)"
|
110
174
|
else
|
111
|
-
puts ":: Memory
|
175
|
+
puts ":: Max Memory Usage: #{style}#{max_mem} bytes\e[0m (#{percent_mem.round(3)}% system mem)"
|
112
176
|
end
|
113
177
|
else
|
114
|
-
puts ":: The memory
|
178
|
+
puts ":: The max memory Usage can't be logged."
|
115
179
|
end
|
116
180
|
|
117
181
|
max_threads = data[:max_threads]
|
118
|
-
style = "\e[1;"
|
182
|
+
style = +"\e[1;"
|
119
183
|
style << if max_threads > 16
|
120
184
|
"38;2;230;80;70m"
|
121
185
|
elsif max_threads > 8
|
data/ext/stats/stats.c
CHANGED
@@ -40,27 +40,29 @@ VALUE ps_stat(volatile VALUE obj, volatile VALUE pid) {
|
|
40
40
|
|
41
41
|
// For this info
|
42
42
|
// follow https://man7.org/linux/man-pages/man5/proc.5.html
|
43
|
+
char state[1] ;
|
43
44
|
int ppid, processor ;
|
44
45
|
long unsigned utime, stime ;
|
45
46
|
long num_threads ;
|
46
47
|
|
47
48
|
char status = fscanf(
|
48
|
-
f, "%*llu (%*[^)]%*[)]
|
49
|
+
f, "%*llu (%*[^)]%*[)] %1s "
|
49
50
|
"%d %*d %*d %*d %*d %*u "
|
50
51
|
"%*lu %*lu %*lu %*lu %lu %lu "
|
51
52
|
"%*ld %*ld %*ld %*ld %ld",
|
52
|
-
&ppid, &utime, &stime, &num_threads
|
53
|
+
&state, &ppid, &utime, &stime, &num_threads
|
53
54
|
) ;
|
54
55
|
|
55
56
|
fclose(f) ;
|
56
57
|
|
57
|
-
if (status !=
|
58
|
+
if (status != 5) return rb_ary_new() ;
|
58
59
|
|
59
|
-
return rb_ary_new_from_args(
|
60
|
+
return rb_ary_new_from_args(5,
|
60
61
|
INT2NUM(ppid),
|
61
62
|
ULONG2NUM(utime),
|
62
63
|
ULONG2NUM(stime),
|
63
|
-
LONG2NUM(num_threads)
|
64
|
+
LONG2NUM(num_threads),
|
65
|
+
rb_str_new(state, 1)
|
64
66
|
) ;
|
65
67
|
}
|
66
68
|
|
data/lib/sunburst/sunburst.rb
CHANGED
@@ -11,30 +11,53 @@ module Sunburst
|
|
11
11
|
end
|
12
12
|
|
13
13
|
def self.measure(command:, time: nil, sleep_time: 0.001)
|
14
|
+
progress = block_given?
|
15
|
+
|
14
16
|
r = {
|
15
17
|
execution_time: nil, cpu_time: nil,
|
16
|
-
memory: nil, max_threads: nil
|
18
|
+
memory: nil, max_threads: nil,
|
19
|
+
max_memory: nil, state: nil, last_state: nil
|
17
20
|
}
|
18
21
|
|
19
22
|
IO.popen(command) { |x|
|
20
23
|
time1 = Sunburst.clock_monotonic
|
21
24
|
pid = x.pid
|
22
25
|
|
23
|
-
t =
|
26
|
+
t = if progress
|
27
|
+
Thread.new { }
|
28
|
+
else
|
29
|
+
Thread.new { print x.readpartial(4096) until x.eof? }
|
30
|
+
end
|
24
31
|
|
25
32
|
last_mem = 0
|
26
33
|
max_threads = 0
|
34
|
+
max_mem = 0
|
35
|
+
last_state = nil
|
27
36
|
|
28
37
|
while true
|
29
38
|
_last_mem = Sunburst.get_mem(pid)
|
30
39
|
|
31
40
|
break if (time && Sunburst.clock_monotonic - time1 > time) || _last_mem == 0
|
32
41
|
last_mem = _last_mem
|
42
|
+
max_mem = last_mem if max_mem < _last_mem
|
33
43
|
|
34
44
|
# Get stats
|
35
45
|
stats = get_stats(pid)
|
36
46
|
_threads = stats[3]
|
37
47
|
max_threads = _threads if max_threads < _threads
|
48
|
+
last_state = stats[4]
|
49
|
+
|
50
|
+
cpu_time = stats[1].+(stats[2]).fdiv(Sunburst::TICKS)
|
51
|
+
|
52
|
+
if progress
|
53
|
+
yield(
|
54
|
+
Sunburst.clock_monotonic.-(time1),
|
55
|
+
stats[1].+(stats[2]).fdiv(Sunburst::TICKS),
|
56
|
+
_last_mem * Sunburst::PAGESIZE,
|
57
|
+
_threads,
|
58
|
+
last_state
|
59
|
+
)
|
60
|
+
end
|
38
61
|
|
39
62
|
sleep(sleep_time)
|
40
63
|
end
|
@@ -48,18 +71,23 @@ module Sunburst
|
|
48
71
|
_threads = stats[3]
|
49
72
|
max_threads = _threads if max_threads < _threads
|
50
73
|
|
51
|
-
# Get Memory Usage
|
52
74
|
_last_mem = Sunburst.get_mem(pid)
|
75
|
+
max_mem = _last_mem if max_mem < _last_mem
|
53
76
|
last_mem = _last_mem unless _last_mem == 0
|
54
77
|
|
78
|
+
state = stats[4]
|
79
|
+
|
55
80
|
t.kill
|
56
81
|
Process.kill(9, pid)
|
57
82
|
|
58
83
|
r[:cpu_time] = cpu_time
|
59
84
|
r[:max_threads] = max_threads unless max_threads == 0
|
60
85
|
r[:memory] = last_mem * Sunburst::PAGESIZE if last_mem > 0
|
86
|
+
r[:max_memory] = max_mem * Sunburst::PAGESIZE if last_mem > 0
|
61
87
|
|
62
88
|
r[:execution_time] = time2.-(time1).truncate(5)
|
89
|
+
r[:state] = state
|
90
|
+
r[:last_state] = last_state
|
63
91
|
}
|
64
92
|
|
65
93
|
r
|
data/lib/sunburst/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sunburst
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sourav Goswami
|
@@ -18,11 +18,9 @@ executables:
|
|
18
18
|
- sunburst
|
19
19
|
extensions:
|
20
20
|
- ext/stats/extconf.rb
|
21
|
-
extra_rdoc_files:
|
22
|
-
- README.md
|
21
|
+
extra_rdoc_files: []
|
23
22
|
files:
|
24
23
|
- LICENCE
|
25
|
-
- README.md
|
26
24
|
- bin/setup
|
27
25
|
- exe/sunburst
|
28
26
|
- ext/stats/extconf.rb
|
data/README.md
DELETED
@@ -1,78 +0,0 @@
|
|
1
|
-
# Sunburst
|
2
|
-
Sunburst lets you run a command for a given time.
|
3
|
-
When the time expires, the program will be SIGKILLed.
|
4
|
-
Sunburst will then report the total CPU time and last known memory usage
|
5
|
-
of the program.
|
6
|
-
|
7
|
-
For example:
|
8
|
-
|
9
|
-
```
|
10
|
-
$ sunburst "while : ; do echo hi ; sleep 1 ; done" --time=3
|
11
|
-
:: Running "while : ; do echo hi ; sleep 1 ; done" for 3.0 seconds
|
12
|
-
Logging Standard Output and Error
|
13
|
-
hi
|
14
|
-
hi
|
15
|
-
hi
|
16
|
-
|
17
|
-
----------------------------------------------------------------------
|
18
|
-
:: Total Execution Time: 3.00097 seconds
|
19
|
-
:: CPU Time: 0.0 seconds (0.0% exec time)
|
20
|
-
:: Memory usage: 577536 bytes (0.007% system mem)
|
21
|
-
:: Max Threads: 1
|
22
|
-
```
|
23
|
-
|
24
|
-
Or
|
25
|
-
|
26
|
-
```
|
27
|
-
$ sunburst "while : ; do : ; done" --time=3
|
28
|
-
:: Running "while : ; do : ; done" for 3.0 seconds
|
29
|
-
Logging Standard Output and Error
|
30
|
-
|
31
|
-
----------------------------------------------------------------------
|
32
|
-
:: Total Execution Time: 3.00097 seconds
|
33
|
-
:: CPU Time: 2.97 seconds (98.968% exec time)
|
34
|
-
:: Memory usage: 360448 bytes (0.004% system mem)
|
35
|
-
:: Max Threads: 1
|
36
|
-
```
|
37
|
-
|
38
|
-
## Installation
|
39
|
-
Add this line to your application's Gemfile:
|
40
|
-
|
41
|
-
```ruby
|
42
|
-
gem 'sunburst'
|
43
|
-
```
|
44
|
-
|
45
|
-
And then execute:
|
46
|
-
|
47
|
-
```
|
48
|
-
$ bundle install
|
49
|
-
```
|
50
|
-
|
51
|
-
Or install it yourself as:
|
52
|
-
```
|
53
|
-
$ gem install sunburst
|
54
|
-
```
|
55
|
-
|
56
|
-
## Usage
|
57
|
-
Run sunbust -h for instruction.
|
58
|
-
|
59
|
-
```
|
60
|
-
Arguments:
|
61
|
-
--time=N Run the program for N seconds
|
62
|
-
-h | --help Show this help section
|
63
|
-
--humanize Human readable memory units
|
64
|
-
|
65
|
-
Example:
|
66
|
-
sunburst echo hello world --time=0.05 --humanize
|
67
|
-
sunburst "echo hello world" --time=0.05 --humanize
|
68
|
-
sunburst "ruby -e 'while true do end'" --time=3 --humanize
|
69
|
-
sunburst "ruby -e 'p :Hello'" --time=3 --humanize
|
70
|
-
```
|
71
|
-
|
72
|
-
If no time is specified, it will run until the command exits.
|
73
|
-
|
74
|
-
## Contributing
|
75
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/Souravgoswami/sunburst.
|
76
|
-
|
77
|
-
## License
|
78
|
-
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|