sunburst 0.1.0 → 0.4.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/exe/sunburst +176 -25
- data/ext/stats/stats.c +56 -13
- data/lib/sunburst/sunburst.rb +134 -7
- data/lib/sunburst/version.rb +1 -1
- metadata +4 -6
- data/README.md +0 -43
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 62930035c73348f9b91a1df8e2a94813772dff662770f86f52101f37cf436fea
|
4
|
+
data.tar.gz: a9eba0746892376fdb9cf49cb8ee63408b8a2b2061bfe466edf9d542a0ed83e4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: de1c87d3a1c8602ab28f16bffdf6a2b4d1d1fae473ee4b294110b61fe580760afb3faabe6d7b8eae63a69e61b7cfa6e43b25641bef0f0d808638211119c8f161
|
7
|
+
data.tar.gz: 2a2cdc0f891f1df34c533355a38875ae42e314b94d24c79dda270b4d2fe8f155b9a645b54c3ebe4931babfbc34bf7aa6a86dccc1160fad53c617e782958b4d5c
|
data/exe/sunburst
CHANGED
@@ -1,5 +1,9 @@
|
|
1
|
-
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# Frozen_String_Literal: true
|
3
|
+
|
4
|
+
$-v = true
|
2
5
|
STDOUT.sync = STDIN.sync = true
|
6
|
+
require 'sunburst'
|
3
7
|
|
4
8
|
def help
|
5
9
|
puts <<~EOF
|
@@ -13,18 +17,40 @@ def help
|
|
13
17
|
Arguments:
|
14
18
|
\s\s\s\s--time=N\s\s\s\s\s\s\s\s\s\sRun the program for N seconds
|
15
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
|
16
21
|
\s\s\s\s--humanize\s\s\s\s\s\s\s\sHuman readable memory units
|
17
22
|
|
18
23
|
Example:
|
19
24
|
\s\s\s\ssunburst echo hello world --time=0.05 --humanize
|
20
25
|
\s\s\s\ssunburst "echo hello world" --time=0.05 --humanize
|
21
26
|
\s\s\s\ssunburst "ruby -e 'while true do end'" --time=3 --humanize
|
22
|
-
\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
|
+
|
23
30
|
EOF
|
24
31
|
|
25
32
|
exit 0
|
26
33
|
end
|
27
34
|
|
35
|
+
def splitter(sub = 8)
|
36
|
+
width = Sunburst.win_width
|
37
|
+
puts ?\n, ?-.*(width - sub).center(width)
|
38
|
+
end
|
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
|
+
|
28
54
|
help if ARGV.any? { |x| x[/^\-(\-help|h)$/] }
|
29
55
|
|
30
56
|
time_arg = ARGV.find { |x| x[/^\-\-time=[0-9]+\.?[0-9]*$/] }
|
@@ -35,46 +61,171 @@ _human_readable = ARGV.find { |x| x[/^\-\-humanize$/] }
|
|
35
61
|
ARGV.delete(_human_readable) if _human_readable
|
36
62
|
human_readable = _human_readable
|
37
63
|
|
64
|
+
_progress = ARGV.find { |x| x[/^\-(\-progress|p)$/] }
|
65
|
+
ARGV.delete(_progress) if _progress
|
66
|
+
progress = _progress
|
67
|
+
|
38
68
|
command = ARGV.join(' ')
|
39
69
|
|
40
70
|
help if command.empty?
|
41
71
|
|
42
72
|
puts %Q(:: Running "#{command}" for #{time || 'infinite'} seconds)
|
43
|
-
puts ?- * Sunburst.win_width
|
44
73
|
|
45
74
|
begin
|
46
|
-
|
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
|
47
80
|
|
48
|
-
puts
|
49
|
-
puts ":: Total Execution Time: #{data[:execution_time]} seconds"
|
50
|
-
puts ":: CPU Time: #{data[:cpu_time]} second#{?s if data[:cpu_time] != 1}"
|
81
|
+
puts "\e[38;2;243;156;18m#{message.center(Sunburst.win_width + 6)}\e[0m"
|
51
82
|
|
52
|
-
|
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, cpu_u|
|
86
|
+
print "\e[2K\r:: "\
|
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} | "\
|
92
|
+
"CPU U: #{cpu_u}\e[s\r\e[u"
|
93
|
+
}
|
94
|
+
else
|
95
|
+
Sunburst.measure(command: command, time: time, sleep_time: 0.0001) { |exec_t, cpu_t, mem, threads, state, cpu_u|
|
96
|
+
print "\e[2K\r:: "\
|
97
|
+
"Exec T: #{"%05.2f" % exec_t} | "\
|
98
|
+
"CPU T: #{"%05.2f" % cpu_t} | "\
|
99
|
+
"Mem: #{"%2d" % mem} | "\
|
100
|
+
"Threads: #{threads} | "\
|
101
|
+
"State: #{state} | "\
|
102
|
+
"CPU U: #{cpu_u}\e[s\r\e[u"
|
103
|
+
}
|
104
|
+
end
|
105
|
+
else
|
106
|
+
Sunburst.measure(command: command, time: time, sleep_time: 0.0001)
|
107
|
+
end
|
108
|
+
|
109
|
+
print "\e[38;2;243;156;18m"
|
110
|
+
splitter()
|
111
|
+
print "\e[0m"
|
112
|
+
|
113
|
+
exec_time = data[:execution_time]
|
114
|
+
cpu_time = data[:cpu_time]
|
115
|
+
percent_time = exec_time == 0 ? 0 : cpu_time.*(100).fdiv(exec_time)
|
116
|
+
|
117
|
+
style = +"\e[1;"
|
118
|
+
style << if percent_time > 75
|
119
|
+
"38;2;230;80;70m"
|
120
|
+
elsif percent_time > 50
|
121
|
+
"38;2;45;125;255m"
|
122
|
+
elsif percent_time > 25
|
123
|
+
"38;2;255;225;0m"
|
124
|
+
else
|
125
|
+
"38;2;40;175;95m"
|
126
|
+
end
|
127
|
+
|
128
|
+
puts ":: Total Execution Time: #{data[:execution_time]} seconds\e[0m"
|
53
129
|
|
130
|
+
percent_time_mesg = exec_time == 0 ? 100 : percent_time
|
131
|
+
puts ":: Total CPU Time: #{style}#{cpu_time}\e[0m second#{?s if cpu_time != 1} (#{"%05.2f" % percent_time_mesg}% exec time)"
|
132
|
+
|
133
|
+
mem = data[:memory]
|
54
134
|
if mem
|
135
|
+
percent_mem = mem.*(100).fdiv(Sunburst.total_ram)
|
136
|
+
|
137
|
+
style = +"\e[1;"
|
138
|
+
style << if percent_mem > 50
|
139
|
+
"38;2;230;80;70m"
|
140
|
+
elsif percent_mem > 30
|
141
|
+
"38;2;45;125;255m"
|
142
|
+
elsif percent_mem > 10
|
143
|
+
"38;2;255;225;0m"
|
144
|
+
else
|
145
|
+
"38;2;40;175;95m"
|
146
|
+
end
|
147
|
+
|
55
148
|
if human_readable
|
56
|
-
mem_text =
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
149
|
+
mem_text = convert_bytes(mem)
|
150
|
+
|
151
|
+
puts ":: Memory Usage During Exit: #{style}#{mem_text}\e[0m (#{percent_mem.round(3)}% system mem)"
|
152
|
+
else
|
153
|
+
puts ":: Memory Usage During Exit: #{style}#{mem} bytes\e[0m (#{percent_mem.round(3)}% system mem)"
|
154
|
+
end
|
155
|
+
else
|
156
|
+
puts ":: The memory Usage Can't be Logged."
|
157
|
+
end
|
158
|
+
|
159
|
+
avg_mem = data[:avg_mem]
|
160
|
+
if avg_mem
|
161
|
+
if human_readable
|
162
|
+
puts ":: Avg. Memory Usage: #{style}#{convert_bytes(avg_mem)}\e[0m (#{percent_mem.round(3)}% system mem)"
|
163
|
+
else
|
164
|
+
puts ":: Avg. Memory Usage: #{style}#{avg_mem}\e[0m (#{percent_mem.round(3)}% system mem)"
|
165
|
+
end
|
166
|
+
else
|
167
|
+
puts ":: The Average Memory Usage can't be Logged."
|
168
|
+
end
|
169
|
+
|
170
|
+
max_mem = data[:max_memory]
|
171
|
+
if max_mem
|
172
|
+
percent_mem = max_mem.*(100).fdiv(Sunburst.total_ram)
|
173
|
+
|
174
|
+
style = +"\e[1;"
|
175
|
+
style << if percent_mem > 50
|
176
|
+
"38;2;230;80;70m"
|
177
|
+
elsif percent_mem > 30
|
178
|
+
"38;2;45;125;255m"
|
179
|
+
elsif percent_mem > 10
|
180
|
+
"38;2;255;225;0m"
|
181
|
+
else
|
182
|
+
"38;2;40;175;95m"
|
183
|
+
end
|
184
|
+
|
185
|
+
if human_readable
|
186
|
+
mem_text = convert_bytes(max_mem)
|
187
|
+
|
188
|
+
puts ":: Max Memory Usage: #{style}#{mem_text}\e[0m (#{percent_mem.round(3)}% system mem)"
|
69
189
|
else
|
70
|
-
puts ":: Memory
|
190
|
+
puts ":: Max Memory Usage: #{style}#{max_mem} bytes\e[0m (#{percent_mem.round(3)}% system mem)"
|
71
191
|
end
|
72
192
|
else
|
73
|
-
puts ":: The memory
|
193
|
+
puts ":: The max memory Usage can't be logged."
|
194
|
+
end
|
195
|
+
|
196
|
+
avg_cpu_usage = data[:avg_cpu_usage]
|
197
|
+
if avg_cpu_usage
|
198
|
+
puts ":: Avg. CPU Usage: #{style}#{avg_cpu_usage}\e[0m"
|
199
|
+
else
|
200
|
+
puts ":: The Avg. CPU Usage Can't be Logged"
|
201
|
+
end
|
202
|
+
|
203
|
+
max_cpu_usage = data[:max_cpu_usage]
|
204
|
+
if max_cpu_usage
|
205
|
+
puts ":: Max CPU Usage: #{style}#{max_cpu_usage}\e[0m"
|
206
|
+
else
|
207
|
+
puts ":: The Max CPU Usage Can't be Logged"
|
74
208
|
end
|
209
|
+
|
210
|
+
max_threads = data[:max_threads]
|
211
|
+
style = +"\e[1;"
|
212
|
+
style << if max_threads > 16
|
213
|
+
"38;2;230;80;70m"
|
214
|
+
elsif max_threads > 8
|
215
|
+
"38;2;45;125;255m"
|
216
|
+
elsif max_threads > 4
|
217
|
+
"38;2;255;225;0m"
|
218
|
+
else
|
219
|
+
"38;2;40;175;95m"
|
220
|
+
end
|
221
|
+
|
222
|
+
puts ":: Max Threads: #{style}#{max_threads}\e[0m"
|
223
|
+
|
75
224
|
rescue Errno::ENOENT
|
76
225
|
puts "sunburst: #{command}: command not found"
|
77
|
-
puts ?- * Sunburst.win_width
|
226
|
+
puts ?\n, ?- * Sunburst.win_width
|
227
|
+
rescue Interrupt
|
228
|
+
puts "\n\e[2KInterrupt Received"
|
78
229
|
rescue StandardError
|
79
|
-
puts
|
230
|
+
puts $!.full_message
|
80
231
|
end
|
data/ext/stats/stats.c
CHANGED
@@ -2,11 +2,12 @@
|
|
2
2
|
#include <unistd.h>
|
3
3
|
#include <time.h>
|
4
4
|
#include <sys/ioctl.h>
|
5
|
+
#include <sys/sysinfo.h>
|
5
6
|
|
6
7
|
unsigned int PAGESIZE ;
|
7
8
|
unsigned int TICKS ;
|
8
9
|
|
9
|
-
VALUE statm_memory(VALUE obj, VALUE pid) {
|
10
|
+
VALUE statm_memory(volatile VALUE obj, volatile VALUE pid) {
|
10
11
|
int _pid = FIX2INT(pid) ;
|
11
12
|
if (_pid < 0) return Qnil ;
|
12
13
|
|
@@ -26,41 +27,80 @@ VALUE statm_memory(VALUE obj, VALUE pid) {
|
|
26
27
|
return UINT2NUM(v) ;
|
27
28
|
}
|
28
29
|
|
29
|
-
VALUE
|
30
|
+
VALUE ps_stat(volatile VALUE obj, volatile VALUE pid) {
|
30
31
|
int _pid = FIX2INT(pid) ;
|
31
|
-
if (_pid < 0) return
|
32
|
+
if (_pid < 0) return rb_str_new_cstr("") ;
|
32
33
|
|
33
34
|
char _path[22] ;
|
34
35
|
sprintf(_path, "/proc/%d/stat", _pid) ;
|
35
36
|
|
36
37
|
FILE *f = fopen(_path, "r") ;
|
37
|
-
if (!f) return Qnil ;
|
38
38
|
|
39
|
-
|
39
|
+
if (!f) return rb_ary_new() ;
|
40
|
+
|
41
|
+
// For this info
|
42
|
+
// follow https://man7.org/linux/man-pages/man5/proc.5.html
|
43
|
+
char state[1] ;
|
44
|
+
int ppid, processor ;
|
45
|
+
long unsigned utime, stime ;
|
46
|
+
long num_threads ;
|
47
|
+
long long unsigned starttime ;
|
48
|
+
|
49
|
+
char status = fscanf(
|
50
|
+
f, "%*llu (%*[^)]%*[)] %1s "
|
51
|
+
"%d %*d %*d %*d %*d %*u "
|
52
|
+
"%*lu %*lu %*lu %*lu %lu %lu "
|
53
|
+
"%*ld %*ld %*ld %*ld %ld %*ld %ld",
|
54
|
+
&state, &ppid, &utime, &stime, &num_threads, &starttime
|
55
|
+
) ;
|
40
56
|
|
41
|
-
char status = fscanf(f, "%*llu (%*[^)]%*[)] %*c %*d %*d %*d %*d %*d %*u %*lu %*lu %*lu %*lu %lu %lu", &utime, &stime) ;
|
42
57
|
fclose(f) ;
|
43
58
|
|
44
|
-
if (status !=
|
45
|
-
|
59
|
+
if (status != 6) return rb_ary_new() ;
|
60
|
+
|
61
|
+
return rb_ary_new_from_args(6,
|
62
|
+
INT2NUM(ppid),
|
63
|
+
ULONG2NUM(utime),
|
64
|
+
ULONG2NUM(stime),
|
65
|
+
LONG2NUM(num_threads),
|
66
|
+
rb_str_new(state, 1),
|
67
|
+
ULL2NUM(starttime)
|
68
|
+
) ;
|
69
|
+
}
|
46
70
|
|
47
|
-
|
71
|
+
VALUE nProcessors(volatile VALUE obj) {
|
72
|
+
int coreCount = sysconf(_SC_NPROCESSORS_CONF) ;
|
73
|
+
return (coreCount == -1) ? Qnil : INT2NUM(coreCount) ;
|
48
74
|
}
|
49
75
|
|
50
|
-
VALUE clock_monotonic(VALUE obj) {
|
76
|
+
VALUE clock_monotonic(volatile VALUE obj) {
|
51
77
|
struct timespec tv ;
|
52
78
|
clock_gettime(CLOCK_MONOTONIC, &tv) ;
|
53
|
-
|
79
|
+
float time = tv.tv_sec + tv.tv_nsec / 1000000000.0 ;
|
54
80
|
|
55
81
|
return rb_float_new(time) ;
|
56
82
|
}
|
57
83
|
|
58
|
-
VALUE winWidth(VALUE obj) {
|
84
|
+
VALUE winWidth(volatile VALUE obj) {
|
59
85
|
struct winsize w ;
|
60
86
|
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) ;
|
61
87
|
return INT2NUM(w.ws_col) ;
|
62
88
|
}
|
63
89
|
|
90
|
+
VALUE totalRAM(volatile VALUE obj) {
|
91
|
+
struct sysinfo buf ;
|
92
|
+
char status = sysinfo(&buf) ;
|
93
|
+
|
94
|
+
if (status != 0) return Qnil ;
|
95
|
+
|
96
|
+
return rb_funcall(
|
97
|
+
ULONG2NUM(buf.totalram),
|
98
|
+
rb_intern("*"),
|
99
|
+
1,
|
100
|
+
ULONG2NUM(buf.mem_unit)
|
101
|
+
) ;
|
102
|
+
}
|
103
|
+
|
64
104
|
void Init_stats() {
|
65
105
|
PAGESIZE = sysconf(_SC_PAGESIZE) ;
|
66
106
|
TICKS = sysconf(_SC_CLK_TCK) ;
|
@@ -70,8 +110,11 @@ void Init_stats() {
|
|
70
110
|
rb_define_const(sunburst, "TICKS", UINT2NUM(TICKS)) ;
|
71
111
|
|
72
112
|
rb_define_module_function(sunburst, "get_mem", statm_memory, 1) ;
|
73
|
-
rb_define_module_function(sunburst, "get_times", ps_times, 1) ;
|
74
113
|
rb_define_module_function(sunburst, "clock_monotonic", clock_monotonic, 0) ;
|
75
114
|
|
76
115
|
rb_define_module_function(sunburst, "win_width", winWidth, 0) ;
|
116
|
+
rb_define_module_function(sunburst, "ps_stat", ps_stat, 1) ;
|
117
|
+
|
118
|
+
rb_define_module_function(sunburst, "total_ram", totalRAM, 0) ;
|
119
|
+
rb_define_module_function(sunburst, "nprocessors", nProcessors, 0) ;
|
77
120
|
}
|
data/lib/sunburst/sunburst.rb
CHANGED
@@ -1,41 +1,168 @@
|
|
1
1
|
module Sunburst
|
2
|
+
def self.get_stats(pid)
|
3
|
+
stats = Sunburst.ps_stat(pid)
|
4
|
+
|
5
|
+
if stats.empty?
|
6
|
+
Process.kill(9, pid)
|
7
|
+
fail RuntimeError, 'Something horribly wrong happened! Exiting.'
|
8
|
+
end
|
9
|
+
|
10
|
+
stats
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.calculate_cpu_usage(pid, sleep_time)
|
14
|
+
uptime_file = '/proc/uptime'.freeze
|
15
|
+
|
16
|
+
unless File.readable?(uptime_file)
|
17
|
+
sleep(sleep_time)
|
18
|
+
return nil
|
19
|
+
end
|
20
|
+
|
21
|
+
ticks = Sunburst::TICKS
|
22
|
+
stat = Sunburst.ps_stat(pid)
|
23
|
+
uptime = IO.read('/proc/uptime').to_f
|
24
|
+
|
25
|
+
if stat.empty?
|
26
|
+
sleep(sleep_time)
|
27
|
+
return nil
|
28
|
+
end
|
29
|
+
|
30
|
+
utime, stime, starttime = *stat.values_at(1, 2, 5).map(&:to_f)
|
31
|
+
uptime *= ticks
|
32
|
+
|
33
|
+
total_time = utime + stime
|
34
|
+
idle1 = uptime - starttime - total_time
|
35
|
+
|
36
|
+
sleep(sleep_time)
|
37
|
+
|
38
|
+
stat = Sunburst.ps_stat(pid)
|
39
|
+
uptime = IO.read('/proc/uptime').to_f
|
40
|
+
return nil if stat.empty?
|
41
|
+
|
42
|
+
utime2, stime2, starttime2 = *stat.values_at(1, 2, 5).map(&:to_f)
|
43
|
+
uptime *= ticks
|
44
|
+
|
45
|
+
total_time2 = utime2 + stime2
|
46
|
+
idle2 = uptime - starttime2 - total_time2
|
47
|
+
|
48
|
+
totald = idle2.+(total_time2).-(idle1 + total_time)
|
49
|
+
cpu_u = totald.-(idle2 - idle1).fdiv(totald).abs.*(100)./(Sunburst.nprocessors)
|
50
|
+
|
51
|
+
cpu_u > 100 ? 100.0 : cpu_u
|
52
|
+
end
|
53
|
+
|
2
54
|
def self.measure(command:, time: nil, sleep_time: 0.001)
|
3
|
-
|
55
|
+
progress = block_given?
|
56
|
+
|
57
|
+
r = {
|
58
|
+
execution_time: nil, cpu_time: nil,
|
59
|
+
memory: nil, max_threads: nil,
|
60
|
+
avg_mem: nil, max_memory: nil, state: nil, last_state: nil,
|
61
|
+
avg_cpu_usage: nil, max_cpu_usage: nil
|
62
|
+
}
|
4
63
|
|
5
64
|
IO.popen(command) { |x|
|
6
65
|
time1 = Sunburst.clock_monotonic
|
7
66
|
pid = x.pid
|
8
67
|
|
9
|
-
t =
|
10
|
-
|
68
|
+
t = if progress
|
69
|
+
Thread.new { }
|
70
|
+
else
|
71
|
+
Thread.new { print x.readpartial(4096) until x.eof? }
|
72
|
+
end
|
73
|
+
|
74
|
+
cpu_usage = 0
|
75
|
+
max_cpu_usage = 0
|
76
|
+
cpu_usage_sum = 0
|
77
|
+
cpu_usage_measure_count = 0
|
78
|
+
|
79
|
+
Thread.new {
|
80
|
+
while true
|
81
|
+
_cpu_usage = calculate_cpu_usage(pid, 0.25)
|
82
|
+
|
83
|
+
if _cpu_usage
|
84
|
+
cpu_usage = "%05.2f%%".freeze % _cpu_usage
|
85
|
+
cpu_usage_sum += _cpu_usage
|
86
|
+
cpu_usage_measure_count += 1
|
87
|
+
|
88
|
+
max_cpu_usage = _cpu_usage if _cpu_usage > max_cpu_usage
|
89
|
+
else
|
90
|
+
cpu_usage = ?X.freeze
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
11
94
|
}
|
12
95
|
|
13
96
|
last_mem = 0
|
97
|
+
max_threads = 0
|
98
|
+
max_mem = 0
|
99
|
+
last_state = nil
|
100
|
+
|
101
|
+
avg_mem = 0
|
102
|
+
mem_measure_count = 0
|
14
103
|
|
15
104
|
while true
|
16
105
|
_last_mem = Sunburst.get_mem(pid)
|
17
106
|
|
18
107
|
break if (time && Sunburst.clock_monotonic - time1 > time) || _last_mem == 0
|
19
108
|
last_mem = _last_mem
|
109
|
+
max_mem = last_mem if max_mem < _last_mem
|
110
|
+
|
111
|
+
avg_mem += _last_mem
|
112
|
+
mem_measure_count += 1
|
113
|
+
|
114
|
+
# Get stats
|
115
|
+
stats = get_stats(pid)
|
116
|
+
_threads = stats[3]
|
117
|
+
max_threads = _threads if max_threads < _threads
|
118
|
+
last_state = stats[4]
|
119
|
+
|
120
|
+
cpu_time = stats[1].+(stats[2]).fdiv(Sunburst::TICKS)
|
121
|
+
|
122
|
+
if progress
|
123
|
+
yield(
|
124
|
+
Sunburst.clock_monotonic.-(time1),
|
125
|
+
stats[1].+(stats[2]).fdiv(Sunburst::TICKS),
|
126
|
+
_last_mem * Sunburst::PAGESIZE,
|
127
|
+
_threads,
|
128
|
+
last_state,
|
129
|
+
cpu_usage
|
130
|
+
)
|
131
|
+
end
|
20
132
|
|
21
133
|
sleep(sleep_time)
|
22
134
|
end
|
23
135
|
|
24
136
|
time2 = Sunburst.clock_monotonic
|
25
137
|
|
26
|
-
# Get
|
27
|
-
|
138
|
+
# Get Stats
|
139
|
+
stats = get_stats(pid)
|
140
|
+
cpu_time = stats[1].+(stats[2]).fdiv(Sunburst::TICKS)
|
141
|
+
|
142
|
+
_threads = stats[3]
|
143
|
+
max_threads = _threads if max_threads < _threads
|
28
144
|
|
29
|
-
# Get Memory Usage
|
30
145
|
_last_mem = Sunburst.get_mem(pid)
|
146
|
+
max_mem = _last_mem if max_mem < _last_mem
|
31
147
|
last_mem = _last_mem unless _last_mem == 0
|
32
148
|
|
149
|
+
state = stats[4]
|
150
|
+
|
33
151
|
t.kill
|
34
152
|
Process.kill(9, pid)
|
35
153
|
|
36
|
-
r[:execution_time] = time2.-(time1).truncate(5)
|
37
154
|
r[:cpu_time] = cpu_time
|
155
|
+
r[:max_threads] = max_threads unless max_threads == 0
|
38
156
|
r[:memory] = last_mem * Sunburst::PAGESIZE if last_mem > 0
|
157
|
+
r[:max_memory] = max_mem * Sunburst::PAGESIZE if last_mem > 0
|
158
|
+
r[:avg_mem] = (avg_mem * Sunburst::PAGESIZE) / mem_measure_count if mem_measure_count > 0
|
159
|
+
|
160
|
+
r[:execution_time] = time2.-(time1).truncate(5)
|
161
|
+
r[:state] = state
|
162
|
+
r[:last_state] = last_state
|
163
|
+
|
164
|
+
r[:avg_cpu_usage] = sprintf("%05.2f%%", cpu_usage_sum / cpu_usage_measure_count) if cpu_usage_measure_count > 0
|
165
|
+
r[:max_cpu_usage] = sprintf("%05.2f%%", max_cpu_usage) if max_cpu_usage > 0
|
39
166
|
}
|
40
167
|
|
41
168
|
r
|
data/lib/sunburst/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sunburst
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1
|
4
|
+
version: 0.4.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sourav Goswami
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-09-22 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: Run a process for a given time, kill it with SIGKILL, report CPU time
|
14
14
|
and memory usage
|
@@ -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
|
@@ -49,7 +47,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
49
47
|
- !ruby/object:Gem::Version
|
50
48
|
version: '0'
|
51
49
|
requirements: []
|
52
|
-
rubygems_version: 3.2.
|
50
|
+
rubygems_version: 3.2.21
|
53
51
|
signing_key:
|
54
52
|
specification_version: 4
|
55
53
|
summary: Run a process for a given time, kill it with SIGKILL, report CPU time and
|
data/README.md
DELETED
@@ -1,43 +0,0 @@
|
|
1
|
-
# Sunburst
|
2
|
-
|
3
|
-
Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/sunburst`. To experiment with that code, run `bin/console` for an interactive prompt.
|
4
|
-
|
5
|
-
TODO: Delete this and the text above, and describe your gem
|
6
|
-
|
7
|
-
## Installation
|
8
|
-
|
9
|
-
Add this line to your application's Gemfile:
|
10
|
-
|
11
|
-
```ruby
|
12
|
-
gem 'sunburst'
|
13
|
-
```
|
14
|
-
|
15
|
-
And then execute:
|
16
|
-
|
17
|
-
$ bundle install
|
18
|
-
|
19
|
-
Or install it yourself as:
|
20
|
-
|
21
|
-
$ gem install sunburst
|
22
|
-
|
23
|
-
## Usage
|
24
|
-
|
25
|
-
TODO: Write usage instructions here
|
26
|
-
|
27
|
-
## Development
|
28
|
-
|
29
|
-
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
30
|
-
|
31
|
-
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
32
|
-
|
33
|
-
## Contributing
|
34
|
-
|
35
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/sunburst. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/[USERNAME]/sunburst/blob/master/CODE_OF_CONDUCT.md).
|
36
|
-
|
37
|
-
## License
|
38
|
-
|
39
|
-
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
40
|
-
|
41
|
-
## Code of Conduct
|
42
|
-
|
43
|
-
Everyone interacting in the Sunburst project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/sunburst/blob/master/CODE_OF_CONDUCT.md).
|