sunburst 0.1.0 → 0.4.1
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 +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).
|