sunburst 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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).
|