linux_stat 2.0.1 → 2.2.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/README.md +54 -1042
- data/exe/linuxstat.rb +2 -2
- data/ext/procfs/procfs.c +1 -0
- data/ext/procfs/stat.h +29 -2
- data/ext/procfs/statm.h +25 -15
- data/lib/linux_stat/battery.rb +40 -7
- data/lib/linux_stat/os.rb +11 -5
- data/lib/linux_stat/process_info.rb +77 -57
- data/lib/linux_stat/version.rb +1 -1
- metadata +4 -4
data/exe/linuxstat.rb
CHANGED
@@ -150,9 +150,9 @@ execute.sort.each do |c|
|
|
150
150
|
disp_meth = "#{meth}"
|
151
151
|
disp_meth.concat(arg ? "(#{param})" : "(#{param})")
|
152
152
|
|
153
|
-
time =
|
153
|
+
time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
154
154
|
ret = arg ? e.send(meth, arg) : e.send(meth)
|
155
|
-
time2 =
|
155
|
+
time2 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
156
156
|
time = time2.-(time).*(1_000_000).round(3)
|
157
157
|
|
158
158
|
v = ret.inspect
|
data/ext/procfs/procfs.c
CHANGED
data/ext/procfs/stat.h
CHANGED
@@ -1,6 +1,9 @@
|
|
1
1
|
VALUE ps_state(VALUE obj, VALUE pid) {
|
2
|
+
int _pid = FIX2INT(pid) ;
|
3
|
+
if (_pid < 0) return rb_str_new_cstr("") ;
|
4
|
+
|
2
5
|
char _path[22] ;
|
3
|
-
sprintf(_path, "/proc/%
|
6
|
+
sprintf(_path, "/proc/%d/stat", _pid) ;
|
4
7
|
|
5
8
|
FILE *f = fopen(_path, "r") ;
|
6
9
|
if (!f) return rb_str_new_cstr("") ;
|
@@ -14,9 +17,33 @@ VALUE ps_state(VALUE obj, VALUE pid) {
|
|
14
17
|
return rb_str_new_cstr(_s) ;
|
15
18
|
}
|
16
19
|
|
20
|
+
VALUE ps_times(VALUE obj, VALUE pid) {
|
21
|
+
int _pid = FIX2INT(pid) ;
|
22
|
+
if (_pid < 0) return Qnil ;
|
23
|
+
|
24
|
+
char _path[22] ;
|
25
|
+
sprintf(_path, "/proc/%d/stat", _pid) ;
|
26
|
+
|
27
|
+
FILE *f = fopen(_path, "r") ;
|
28
|
+
if (!f) return Qnil ;
|
29
|
+
|
30
|
+
unsigned long utime, stime ;
|
31
|
+
|
32
|
+
char status = fscanf(f, "%*llu (%*[^)]%*[)] %*c %*d %*d %*d %*d %*d %*u %*lu %*lu %*lu %*lu %lu %lu", &utime, &stime) ;
|
33
|
+
fclose(f) ;
|
34
|
+
|
35
|
+
if (status != 2) return Qnil ;
|
36
|
+
double total_time = (utime + stime) / (float)sysconf(_SC_CLK_TCK);
|
37
|
+
|
38
|
+
return DBL2NUM(total_time) ;
|
39
|
+
}
|
40
|
+
|
17
41
|
VALUE ps_stat(VALUE obj, VALUE pid) {
|
42
|
+
int _pid = FIX2INT(pid) ;
|
43
|
+
if (_pid < 0) return rb_str_new_cstr("") ;
|
44
|
+
|
18
45
|
char _path[22] ;
|
19
|
-
sprintf(_path, "/proc/%
|
46
|
+
sprintf(_path, "/proc/%d/stat", _pid) ;
|
20
47
|
|
21
48
|
FILE *f = fopen(_path, "r") ;
|
22
49
|
|
data/ext/procfs/statm.h
CHANGED
@@ -1,13 +1,15 @@
|
|
1
1
|
#define PAGESIZE sysconf(_SC_PAGESIZE)
|
2
2
|
|
3
3
|
VALUE statm(VALUE obj, VALUE pid) {
|
4
|
-
|
5
|
-
sprintf(_path, "/proc/%lu/statm", FIX2UINT(pid)) ;
|
4
|
+
VALUE hash = rb_hash_new() ;
|
6
5
|
|
7
|
-
|
6
|
+
int _pid = FIX2INT(pid) ;
|
7
|
+
if (_pid < 0) return hash ;
|
8
8
|
|
9
|
-
|
9
|
+
char _path[22] ;
|
10
|
+
sprintf(_path, "/proc/%d/statm", _pid) ;
|
10
11
|
|
12
|
+
FILE *f = fopen(_path, "r") ;
|
11
13
|
if (!f) return hash ;
|
12
14
|
|
13
15
|
unsigned int _virtual, resident, shared ;
|
@@ -33,13 +35,15 @@ VALUE statm(VALUE obj, VALUE pid) {
|
|
33
35
|
}
|
34
36
|
|
35
37
|
VALUE statm_virtual(VALUE obj, VALUE pid) {
|
38
|
+
int _pid = FIX2INT(pid) ;
|
39
|
+
if (_pid < 0) return Qnil ;
|
40
|
+
|
36
41
|
char _path[22] ;
|
37
|
-
sprintf(_path, "/proc/%
|
42
|
+
sprintf(_path, "/proc/%d/statm", _pid) ;
|
38
43
|
|
39
44
|
FILE *f = fopen(_path, "r") ;
|
40
|
-
|
45
|
+
if (!f) return Qnil ;
|
41
46
|
|
42
|
-
if (!f) return hash ;
|
43
47
|
unsigned int _virtual ;
|
44
48
|
char status = fscanf(f, "%u", &_virtual) ;
|
45
49
|
fclose(f) ;
|
@@ -49,13 +53,15 @@ VALUE statm_virtual(VALUE obj, VALUE pid) {
|
|
49
53
|
}
|
50
54
|
|
51
55
|
VALUE statm_resident(VALUE obj, VALUE pid) {
|
56
|
+
int _pid = FIX2INT(pid) ;
|
57
|
+
if (_pid < 0) return Qnil ;
|
58
|
+
|
52
59
|
char _path[22] ;
|
53
|
-
sprintf(_path, "/proc/%
|
60
|
+
sprintf(_path, "/proc/%d/statm", _pid) ;
|
54
61
|
|
55
62
|
FILE *f = fopen(_path, "r") ;
|
56
|
-
|
63
|
+
if (!f) return Qnil ;
|
57
64
|
|
58
|
-
if (!f) return hash ;
|
59
65
|
unsigned int resident ;
|
60
66
|
char status = fscanf(f, "%*u %u", &resident) ;
|
61
67
|
fclose(f) ;
|
@@ -65,13 +71,15 @@ VALUE statm_resident(VALUE obj, VALUE pid) {
|
|
65
71
|
}
|
66
72
|
|
67
73
|
VALUE statm_shared(VALUE obj, VALUE pid) {
|
74
|
+
int _pid = FIX2INT(pid) ;
|
75
|
+
if (_pid < 0) return Qnil ;
|
76
|
+
|
68
77
|
char _path[22] ;
|
69
|
-
sprintf(_path, "/proc/%
|
78
|
+
sprintf(_path, "/proc/%d/statm", _pid) ;
|
70
79
|
|
71
80
|
FILE *f = fopen(_path, "r") ;
|
72
|
-
|
81
|
+
if (!f) return Qnil ;
|
73
82
|
|
74
|
-
if (!f) return hash ;
|
75
83
|
unsigned int shared ;
|
76
84
|
char status = fscanf(f, "%*u %*u %u", &shared) ;
|
77
85
|
fclose(f) ;
|
@@ -81,11 +89,13 @@ VALUE statm_shared(VALUE obj, VALUE pid) {
|
|
81
89
|
}
|
82
90
|
|
83
91
|
VALUE statm_memory(VALUE obj, VALUE pid) {
|
92
|
+
int _pid = FIX2INT(pid) ;
|
93
|
+
if (_pid < 0) return Qnil ;
|
94
|
+
|
84
95
|
char _path[22] ;
|
85
|
-
sprintf(_path, "/proc/%
|
96
|
+
sprintf(_path, "/proc/%d/statm", _pid) ;
|
86
97
|
|
87
98
|
FILE *f = fopen(_path, "r") ;
|
88
|
-
|
89
99
|
if (!f) return Qnil ;
|
90
100
|
|
91
101
|
unsigned int resident, shared ;
|
data/lib/linux_stat/battery.rb
CHANGED
@@ -105,11 +105,19 @@ module LinuxStat
|
|
105
105
|
#
|
106
106
|
# If the battery is not present or the information is not available, it will return nil.
|
107
107
|
def charge
|
108
|
-
@@charge_now_file ||= File.join(PATH, 'charge_now')
|
109
|
-
|
108
|
+
@@charge_now_file ||= if File.readable?(File.join(PATH, 'charge_now'))
|
109
|
+
File.join(PATH, 'charge_now').freeze
|
110
|
+
elsif File.readable?(File.join(PATH, 'energy_now'))
|
111
|
+
File.join(PATH, 'energy_now').freeze
|
112
|
+
end
|
113
|
+
|
114
|
+
@@charge_full_file ||= if File.readable?(File.join(PATH, 'charge_full'))
|
115
|
+
File.join(PATH, 'charge_full').freeze
|
116
|
+
elsif File.readable?(File.join(PATH, 'energy_full'))
|
117
|
+
File.join(PATH, 'energy_full').freeze
|
118
|
+
end
|
110
119
|
|
111
|
-
|
112
|
-
return nil unless @@charge_now_readable
|
120
|
+
return nil unless @@charge_now_file && @@charge_full_file
|
113
121
|
|
114
122
|
charge_now = IO.read(@@charge_now_file).to_i
|
115
123
|
charge_full = IO.read(@@charge_full_file).to_i
|
@@ -178,7 +186,14 @@ module LinuxStat
|
|
178
186
|
# For example, a sample output can be like this (taken on a test system):
|
179
187
|
#
|
180
188
|
# LinuxStat::Battery.devices_stat
|
181
|
-
# => {:AC=>{:type=>"Mains", :online=>1},
|
189
|
+
# => {:AC=>{:type=>"Mains", :online=>1},
|
190
|
+
# :BAT0=>{:model=>"DELL CYMGM77", :manufacturer=>"Samsung SDI",
|
191
|
+
# :type=>"Battery", :status=>"Full", :capacity=>100, :voltage_min_design=>11.4,
|
192
|
+
# :charge_full_design=>3.684, :charge_full_design_wh=>42.0,
|
193
|
+
# :voltage_now=>12.558, :charge_now=>2.087, :charge_now_wh=>26.21,
|
194
|
+
# :charge_full_wh=>23.79, :charge_percentage=>100.0},
|
195
|
+
# :hidpp_battery_0=>{:model=>"Wireless Keyboard", :manufacturer=>"Logitech",
|
196
|
+
# :type=>"Battery", :status=>"Discharging", :online=>1}}
|
182
197
|
#
|
183
198
|
# If you need info about lots of batteries, use this method.
|
184
199
|
# If the informations are not available, it will return empty Hash for each devices.
|
@@ -208,7 +223,16 @@ module LinuxStat
|
|
208
223
|
|
209
224
|
# charge now
|
210
225
|
cn_f = File.join(x, 'charge_now'.freeze).freeze
|
211
|
-
charge_now = File.readable?(cn_f)
|
226
|
+
charge_now = if File.readable?(cn_f)
|
227
|
+
IO.read(cn_f).to_i.fdiv(1_000_000)
|
228
|
+
else
|
229
|
+
en_f = File.join(x, 'energy_now'.freeze)
|
230
|
+
if File.readable?(en_f)
|
231
|
+
IO.read(en_f) .to_i.fdiv(1_000_000)
|
232
|
+
else
|
233
|
+
nil
|
234
|
+
end
|
235
|
+
end
|
212
236
|
|
213
237
|
# voltage min design
|
214
238
|
vmd_f = File.join(x, 'voltage_min_design'.freeze).freeze
|
@@ -220,7 +244,16 @@ module LinuxStat
|
|
220
244
|
|
221
245
|
# charge full
|
222
246
|
cf_f = File.join(x, 'charge_full'.freeze).freeze
|
223
|
-
charge_full = File.readable?(cf_f)
|
247
|
+
charge_full = if File.readable?(cf_f)
|
248
|
+
IO.read(cf_f).to_i.fdiv(1_000_000)
|
249
|
+
else
|
250
|
+
ef_f = File.join(x, 'energy_full'.freeze)
|
251
|
+
if File.readable?(ef_f)
|
252
|
+
IO.read(ef_f).to_i.fdiv(1_000_000)
|
253
|
+
else
|
254
|
+
nil
|
255
|
+
end
|
256
|
+
end
|
224
257
|
|
225
258
|
# status
|
226
259
|
s_f = File.join(x, 'status'.freeze).freeze
|
data/lib/linux_stat/os.rb
CHANGED
@@ -7,7 +7,11 @@ module LinuxStat
|
|
7
7
|
# Reads /etc/os-release and returns a Hash. For example:
|
8
8
|
# LinuxStat::OS.os_release
|
9
9
|
#
|
10
|
-
# => {:NAME=>"Arch Linux", :PRETTY_NAME=>"Arch Linux", :ID=>"arch", :BUILD_ID=>"rolling",
|
10
|
+
# => {:NAME=>"Arch Linux", :PRETTY_NAME=>"Arch Linux", :ID=>"arch", :BUILD_ID=>"rolling",
|
11
|
+
# :ANSI_COLOR=>"38;2;23;147;209", :HOME_URL=>"https://www.archlinux.org/",
|
12
|
+
# :DOCUMENTATION_URL=>"https://wiki.archlinux.org/",
|
13
|
+
# :SUPPORT_URL=>"https://bbs.archlinux.org/", :BUG_REPORT_URL=>"https://bugs.archlinux.org/",
|
14
|
+
# :LOGO=>"archlinux"}
|
11
15
|
#
|
12
16
|
# If the info isn't available, it will return an empty Hash.
|
13
17
|
#
|
@@ -127,7 +131,7 @@ module LinuxStat
|
|
127
131
|
#
|
128
132
|
# The return type is strictly Integer and doesn't fail.
|
129
133
|
def bits
|
130
|
-
@@bits ||= if
|
134
|
+
@@bits ||= if machine.end_with?('64') || RbConfig::CONFIG['host_cpu'].end_with?('64') || RUBY_PLATFORM.end_with?('64')
|
131
135
|
64
|
132
136
|
else
|
133
137
|
32
|
@@ -138,7 +142,7 @@ module LinuxStat
|
|
138
142
|
# Reads /proc/uptime and returns the system uptime:
|
139
143
|
# LinuxStat::OS.uptime
|
140
144
|
#
|
141
|
-
# => {:hour=>
|
145
|
+
# => {:hour=>16, :minute=>10, :second=>11, :jiffy=>20}
|
142
146
|
#
|
143
147
|
# Using uptime is 10x slower than using uptime_i
|
144
148
|
#
|
@@ -151,12 +155,14 @@ module LinuxStat
|
|
151
155
|
|
152
156
|
h = uptime_i / 3600
|
153
157
|
m = uptime_i % 3600 / 60
|
154
|
-
s =
|
158
|
+
s = uptime_i.%(60)
|
159
|
+
j = _uptime.-(uptime_i) * 100
|
155
160
|
|
156
161
|
{
|
157
162
|
hour: h,
|
158
163
|
minute: m,
|
159
|
-
second: s
|
164
|
+
second: s,
|
165
|
+
jiffy: j.to_i
|
160
166
|
}
|
161
167
|
end
|
162
168
|
|
@@ -283,7 +283,7 @@ module LinuxStat
|
|
283
283
|
uptime = LS::ProcFS.uptime_f
|
284
284
|
return {} unless uptime && !stat.empty?
|
285
285
|
|
286
|
-
utime, stime, starttime = *stat.values_at(
|
286
|
+
utime, stime, starttime = *stat.values_at(10, 11, 18).map(&:to_f)
|
287
287
|
uptime *= ticks
|
288
288
|
|
289
289
|
total_time = utime + stime
|
@@ -295,14 +295,14 @@ module LinuxStat
|
|
295
295
|
uptime = LS::ProcFS.uptime_f
|
296
296
|
return {} unless uptime && !stat.empty?
|
297
297
|
|
298
|
-
utime2, stime2, starttime2 = *stat.values_at(
|
298
|
+
utime2, stime2, starttime2 = *stat.values_at(10, 11, 18).map(&:to_f)
|
299
299
|
uptime *= ticks
|
300
300
|
|
301
301
|
total_time2 = utime2 + stime2
|
302
302
|
idle2 = uptime - starttime2 - total_time2
|
303
303
|
|
304
304
|
totald = idle2.+(total_time2).-(idle1 + total_time)
|
305
|
-
cpu_u = totald.-(idle2 - idle1).fdiv(totald).abs.*(100)./(
|
305
|
+
cpu_u = totald.-(idle2 - idle1).fdiv(totald).abs.*(100)./(LinuxStat::CPU.count)
|
306
306
|
|
307
307
|
{
|
308
308
|
cpu_usage: cpu_u > 100 ? 100.0 : cpu_u.round(2),
|
@@ -338,32 +338,10 @@ module LinuxStat
|
|
338
338
|
#
|
339
339
|
# This method is more efficient than running LinuxStat::ProcessInfo.cpu_stat()
|
340
340
|
def cpu_usage(pid: $$, sleep: ticks_to_ms_t5)
|
341
|
-
|
342
|
-
|
343
|
-
uptime = LS::ProcFS.uptime_f
|
344
|
-
return nil unless uptime && !stat.empty?
|
345
|
-
|
346
|
-
utime, stime, starttime = *stat.values_at(10, 11, 18).map(&:to_f)
|
347
|
-
uptime *= ticks
|
348
|
-
|
349
|
-
total_time = utime + stime
|
350
|
-
idle1 = uptime - starttime - total_time
|
351
|
-
|
352
|
-
sleep(sleep)
|
353
|
-
|
354
|
-
stat = LinuxStat::ProcFS.ps_stat(pid)
|
355
|
-
uptime = LS::ProcFS.uptime_f
|
356
|
-
return nil unless uptime && !stat.empty?
|
357
|
-
|
358
|
-
utime2, stime2, starttime2 = *stat.values_at(10, 11, 18).map(&:to_f)
|
359
|
-
uptime *= ticks
|
360
|
-
|
361
|
-
total_time2 = utime2 + stime2
|
362
|
-
idle2 = uptime - starttime2 - total_time2
|
341
|
+
u = cpu_usage_thread(pid, sleep)
|
342
|
+
return nil unless u
|
363
343
|
|
364
|
-
|
365
|
-
|
366
|
-
u = totald.-(idle2 - idle1).fdiv(totald).abs.*(100)./(cpu_count)
|
344
|
+
u /= LinuxStat::CPU.count
|
367
345
|
u > 100 ? 100.0 : u.round(2)
|
368
346
|
end
|
369
347
|
|
@@ -390,34 +368,10 @@ module LinuxStat
|
|
390
368
|
#
|
391
369
|
# But if the info isn't available, it will return nil.
|
392
370
|
def thread_usage(pid: $$, sleep: ticks_to_ms_t5)
|
393
|
-
|
394
|
-
|
395
|
-
uptime = LS::ProcFS.uptime_f
|
396
|
-
return nil unless uptime && !stat.empty?
|
397
|
-
|
398
|
-
utime, stime, starttime = *stat.values_at(10, 11, 18).map(&:to_f)
|
399
|
-
uptime *= ticks
|
400
|
-
|
401
|
-
total_time = utime + stime
|
402
|
-
idle1 = uptime - starttime - total_time
|
371
|
+
u = cpu_usage_thread(pid, sleep)
|
372
|
+
return nil unless u
|
403
373
|
|
404
|
-
|
405
|
-
|
406
|
-
stat = LinuxStat::ProcFS.ps_stat(pid)
|
407
|
-
uptime = LS::ProcFS.uptime_f
|
408
|
-
return nil unless uptime && !stat.empty?
|
409
|
-
|
410
|
-
utime2, stime2, starttime2 = *stat.values_at(10, 11, 18).map(&:to_f)
|
411
|
-
uptime *= ticks
|
412
|
-
|
413
|
-
total_time2 = utime2 + stime2
|
414
|
-
idle2 = uptime - starttime2 - total_time2
|
415
|
-
|
416
|
-
totald = idle2.+(total_time2).-(idle1 + total_time)
|
417
|
-
|
418
|
-
u = totald.-(idle2 - idle1).fdiv(totald).abs.*(100)
|
419
|
-
|
420
|
-
cpu_count_t100 = cpu_count * 100
|
374
|
+
cpu_count_t100 = LinuxStat::CPU.count * 100
|
421
375
|
u > cpu_count_t100 ? cpu_count_t100 : u.round(2)
|
422
376
|
end
|
423
377
|
|
@@ -655,6 +609,47 @@ module LinuxStat
|
|
655
609
|
LinuxStat::Nproc.count_cpu_for_pid(pid)
|
656
610
|
end
|
657
611
|
|
612
|
+
##
|
613
|
+
# = def cpu_times_i(pid = $$)
|
614
|
+
#
|
615
|
+
# Shows the CPU time used by the process.
|
616
|
+
#
|
617
|
+
# The return value is a Float.
|
618
|
+
# But if the info isn't available, it will return nil.
|
619
|
+
def cpu_time(pid = $$)
|
620
|
+
LinuxStat::ProcFS.ps_times(pid)
|
621
|
+
end
|
622
|
+
|
623
|
+
##
|
624
|
+
# = def cpu_times(pid = $$)
|
625
|
+
#
|
626
|
+
# Shows the CPU time used by the process.
|
627
|
+
#
|
628
|
+
# The return value is a Hash formatted like this:
|
629
|
+
# LS::ProcessInfo.cpu_times($$)
|
630
|
+
#
|
631
|
+
# => {:hour=>0, :minute=>39, :second=>12, :jiffy=>0.42}
|
632
|
+
#
|
633
|
+
# But if the info isn't available, it will return an empty Hash..
|
634
|
+
def cpu_times(pid = $$)
|
635
|
+
v = LinuxStat::ProcFS.ps_times(pid)
|
636
|
+
return {} unless v
|
637
|
+
|
638
|
+
v_i = v.to_i
|
639
|
+
|
640
|
+
hour = v_i / 3600
|
641
|
+
min = v_i % 3600 / 60
|
642
|
+
sec = v_i % 60
|
643
|
+
jiffy = v.-(v_i) * 100
|
644
|
+
|
645
|
+
{
|
646
|
+
hour: hour,
|
647
|
+
minute: min,
|
648
|
+
second: sec,
|
649
|
+
jiffy: jiffy.to_i
|
650
|
+
}
|
651
|
+
end
|
652
|
+
|
658
653
|
alias count_cpu nproc
|
659
654
|
|
660
655
|
private
|
@@ -674,8 +669,33 @@ module LinuxStat
|
|
674
669
|
@@pagesize ||= LinuxStat::Sysconf.pagesize.to_i
|
675
670
|
end
|
676
671
|
|
677
|
-
def
|
678
|
-
|
672
|
+
def cpu_usage_thread(pid, delay)
|
673
|
+
ticks = get_ticks
|
674
|
+
stat = LinuxStat::ProcFS.ps_stat(pid)
|
675
|
+
uptime = LS::ProcFS.uptime_f
|
676
|
+
return nil unless uptime && !stat.empty?
|
677
|
+
|
678
|
+
utime, stime, starttime = *stat.values_at(10, 11, 18).map(&:to_f)
|
679
|
+
uptime *= ticks
|
680
|
+
|
681
|
+
total_time = utime + stime
|
682
|
+
idle1 = uptime - starttime - total_time
|
683
|
+
|
684
|
+
sleep(delay)
|
685
|
+
|
686
|
+
stat = LinuxStat::ProcFS.ps_stat(pid)
|
687
|
+
uptime = LS::ProcFS.uptime_f
|
688
|
+
return nil unless uptime && !stat.empty?
|
689
|
+
|
690
|
+
utime2, stime2, starttime2 = *stat.values_at(10, 11, 18).map(&:to_f)
|
691
|
+
uptime *= ticks
|
692
|
+
|
693
|
+
total_time2 = utime2 + stime2
|
694
|
+
idle2 = uptime - starttime2 - total_time2
|
695
|
+
|
696
|
+
totald = idle2.+(total_time2).-(idle1 + total_time)
|
697
|
+
|
698
|
+
totald.-(idle2 - idle1).fdiv(totald).abs.*(100)
|
679
699
|
end
|
680
700
|
end
|
681
701
|
end
|