我有一个shell脚本以百分比计算CPU使用率。 因为我想扩展功能,并希望在Ruby中执行此操作,而不是从Ruby调用shell脚本。
我试图在Ruby中重写代码,但最终输出存在差异。
shell代码输出介于5%和10%之间,Ruby代码的输出介于97.5%和97.8%之间。
这是Ruby代码:
result = `cat /proc/stat | grep '^cpu '`.split(" ")
result.delete("cpu")
idle_time0 = result[4].to_i
total_time0 = 0
result.each do |partial_time|
total_time0 += partial_time.to_i
end
sleep 0.5
result = `cat /proc/stat | grep '^cpu '`.split(" ")
result.delete("cpu")
idle_time = result[4].to_i
total_time = 0
result.each do |partial_time|
total_time += partial_time.to_i
end
diff_idle = idle_time - idle_time0
diff_total = total_time - total_time0
diff_usage = (1000*(diff_total - diff_idle)/(diff_total+5).to_f)/10.0
p diff_usage
这是shell脚本:
#!/bin/bash
CPU=(`cat /proc/stat | grep '^cpu '`) # Get the total CPU statistics.
unset CPU[0] # Discard the "cpu" prefix.
IDLE=${CPU[4]} # Get the idle CPU time.
# Calculate the total CPU time.
TOTAL=0
for VALUE in "${CPU[@]}"; do
let "TOTAL=$TOTAL+$VALUE"
done
# Remember the total and idle CPU times for the next check.
PREV_TOTAL="$TOTAL"
PREV_IDLE="$IDLE"
# Wait before checking again.
sleep 0.5
CPU=(`cat /proc/stat | grep '^cpu '`) # Get the total CPU statistics.
unset CPU[0] # Discard the "cpu" prefix.
IDLE=${CPU[4]} # Get the idle CPU time.
# Calculate the total CPU time.
TOTAL=0
for VALUE in "${CPU[@]}"; do
let "TOTAL=$TOTAL+$VALUE"
done
# Calculate the CPU usage since we last checked.
let "DIFF_IDLE=$IDLE-$PREV_IDLE"
let "DIFF_TOTAL=$TOTAL-$PREV_TOTAL"
let "DIFF_USAGE=(1000*($DIFF_TOTAL-$DIFF_IDLE)/$DIFF_TOTAL+5)/10"
echo -en "\rCPU: $DIFF_USAGE% \b\b"
答案 0 :(得分:1)
问题在于,在bash中取消设置数组值会产生奇怪的效果:
CPU=(`cat /proc/stat | grep '^cpu '`) # Get the total CPU statistics.
let COUNT=0
while [ $COUNT -lt "${#CPU[@]}" ]; do
echo "value at $COUNT: ${CPU[$COUNT]}"
let "COUNT=$COUNT+1"
done
unset CPU[0] # Discard the "cpu" prefix.
let COUNT=0
while [ $COUNT -lt "${#CPU[@]}" ]; do
echo "value at $COUNT: ${CPU[$COUNT]}"
let "COUNT=$COUNT+1"
done
输出:
value at 0: cpu
value at 1: 763993
value at 2: 116443
value at 3: 179513
value at 4: 22344343
value at 5: 536446
value at 6: 5
value at 7: 640
value at 8: 0
value at 9: 0
value at 10: 0
value at 0: # This should be 763993
value at 1: 763993 # and so on...
value at 2: 116443
value at 3: 179513
value at 4: 22344343
value at 5: 536446
value at 6: 5
value at 7: 640
value at 8: 0
value at 9: 0 # ...and the last 0 value is vanished!
无论如何,解决方案是减少ruby idle_time索引:
...
idle_time0 = result[3].to_i
...
idle_time = result[3].to_i
...
答案 1 :(得分:1)
ProGNOMmers已经指出了你的索引错误,但我想要注意的是,如你所做的那样转换为ruby几乎没有任何好处。你的ruby代码看起来像bash一样丑陋,而你仍然要两次炮轰以获得/proc/stat
。通过使用ruby作为高级语言,您可以使其更具可读性,更不容易出错且更高效。
这是重写的示例。我已经做了一个小方法来将/ proc / stat行转换为具有有意义名称的结构,因此不再有阵列索引问题可以进入,并且始终清楚您正在引用哪个计时器值。我使用File::readlines
和Enumerable#grep
来读取proc文件系统而不必外壳。我使用printf格式来获得你似乎正在寻找的百分位舍入效果。
#!/usr/bin/env ruby
# http://man7.org/linux/man-pages/man5/proc.5.html
CpuTimes = Struct.new :user, :nice, :system, :idle, :iowait, :irq,
:softirq, :steal, :guest, :guest_nice, :total
def get_cpu_times
parts = File.readlines('/proc/stat').grep(/^cpu /).first.split
times = parts[1..-1].map(&:to_i)
CpuTimes[ *times ].tap { |r| r[:total] = times.reduce(:+) }
end
c0 = get_cpu_times
sleep 0.5
c1 = get_cpu_times
idle = c1.idle - c0.idle
total = c1.total - c0.total
usage = total - idle
printf "CPU: %.1f%%", 100.0 * usage / total