2013-04-11 100 views
2

我有一个shell脚本以百分比计算CPU使用率。 正如我想扩展功能,并希望在Ruby中这样做,而不是从Ruby调用shell脚本。这个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 

这是壳脚本:

#!/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" 

回答

1

ProGNOMmers已经指出你的索引错误,但我想指出,翻译成红宝石为你所做的已几乎没有好处。你的ruby代码读起来像丑陋一样丑陋,而且你还在为了获取/proc/stat而遭到炮击。通过使用ruby作为高级语言,您可以使其更具可读性,更少出错并且更高效。

下面是一个示例重写。我已经做了一些方法来将/ proc/stat行变成一个具有有意义名称的结构,所以不会再有数组索引问题出现,并且总是清楚您引用的是哪个计时器值。我已经使用File::readlinesEnumerable#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 
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! 

总之,解决的办法是递减红宝石IDLE_TIME指数:

... 
idle_time0 = result[3].to_i 
... 
idle_time = result[3].to_i 
...