Skip to content

Commit

Permalink
Change CPU usage implementation to use ivars
Browse files Browse the repository at this point in the history
  • Loading branch information
j8r committed Jul 30, 2018
1 parent 7a1739d commit 8570b47
Show file tree
Hide file tree
Showing 10 changed files with 142 additions and 124 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,9 @@ app = Hardware::PID.new "firefox" # Take the first matching PID
loop do
sleep 1
cpu.used.to_i #=> 17
pid.cpu_used #=> 1.5
app.cpu_used.to_i #=> 4
cpu.usage.to_i #=> 17
pid.cpu_usage #=> 1.5
app.cpu_usage.to_i #=> 4
end
```
## Development
Expand Down
2 changes: 1 addition & 1 deletion shard.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: hardware
version: 0.3.1
version: 0.4.0

authors:
- bararchy <[email protected]>
Expand Down
9 changes: 6 additions & 3 deletions spec/cpu_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,18 @@ require "./spec_helper"
describe Hardware::CPU do
cpu = Hardware::CPU.new
it "parses '/proc/stat'" do
cpu.info.should be_a NamedTuple(used: Int32, idle: Int32, total: Int32)
cpu.stat.should be_a Array(Int32)
end

it "checks the percentage used" do
Hardware::CPU.previous_info.should be_a NamedTuple(used: Int32, idle: Int32, total: Int32)
cpu.previous_used.should be_a Int32
cpu.previous_idle_wait.should be_a Int32
end

it "checks the percentage used" do
sleep 0.1
(0 <= cpu.used <= 100).should be_true
usage = cpu.usage
usage.should be >= 0
usage.should be <= 100
end
end
8 changes: 6 additions & 2 deletions spec/memory_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,14 @@ describe Hardware::Memory do
end

it "checks the percentage available" do
(1 < memory.percent(used: false) <= 100).should be_true
percent = memory.percent(used: false)
percent.should be > 1
percent.should be <= 100
end

it "checks the percentage used" do
(1 < memory.percent(used: true) <= 100).should be_true
percent = memory.percent(used: true)
percent.should be > 1
percent.should be <= 100
end
end
4 changes: 2 additions & 2 deletions spec/net_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ describe Hardware::Net do
net = Hardware::Net.new

it "checks some types" do
net.in_octets.should be_a Int64
net.out_octets.should be_a Int64
net.in_octets.should be > 0_i64
net.out_octets.should be > 0_i64
end
end
29 changes: 15 additions & 14 deletions spec/pid_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ require "./spec_helper"
describe Hardware::PID do
describe "class methods" do
it "tests .all " do
Hardware::PID.all { |pid| pid.should be_a Hardware::PID }
Hardware::PID.all &.should be_a Hardware::PID
end

it "tests .get_pids of the current process" do
Expand All @@ -17,7 +17,7 @@ describe Hardware::PID do

describe "instance methods" do
it "creates a Hardware::PID based on a name" do
Hardware::PID.new("crystal-run-spec.tmp", cpu_time: false, cpu_total: false).pid.should eq Process.pid
Hardware::PID.new("crystal-run-spec.tmp", cpu_total: false).pid.should eq Process.pid
end

pid = Hardware::PID.new
Expand All @@ -29,7 +29,7 @@ describe Hardware::PID do
end

it "parses exe" do
File.basename(pid.exe.not_nil!).should eq "crystal-run-spec.tmp"
File.basename(pid.exe).should eq "crystal-run-spec.tmp"
end

it "parses command" do
Expand All @@ -40,39 +40,40 @@ describe Hardware::PID do
describe "cpu_time" do
pid1 = Hardware::PID.new(pid: 1)
it "without children" do
(1 < pid1.cpu_time).should be_true
pid1.cpu_time.should be > 1
end

it "with children" do
(1 < pid1.cpu_time(children: true)).should be_true
pid1.cpu_time(children: true).should be > 1
end
end

describe "cpu_used with updates" do
describe "cpu_usage" do
pid1 = Hardware::PID.new(pid: 1)

it "percentage" do
# Simulate CPU use if no activity
pid1.cpu_time_previous = pid1.cpu_time - 9
sleep 0.1
(1 < pid1.cpu_used <= 100).should be_true
usage = pid1.cpu_usage
usage.should be > 0_f32
usage.should be <= 100_f32
end

it "cpu_total_previous equal to cpu_total_current" do
pid1.cpu_total_previous.should eq Hardware::PID.cpu_total_current
end
end
describe "cpu_used with no updates" do
describe "cpu_usage with no updates" do
Hardware::PID.cpu_total_current = -1
pid1 = Hardware::PID.new(pid: 1, cpu_time: false, cpu_total: false)
pid1 = Hardware::PID.new(pid: 1, cpu_total: false)
pid1.cpu_time_previous = -1

it "type" do
pid1.cpu_used.should be_a Float32
pid1.cpu_usage.should be_a Float32
end

it "cpu_time_previous not updated" do
pid1.cpu_time_previous.should eq -1
it "cpu_time_previous" do
pid1.cpu_time_previous.should be > 1
end

it "cpu_total_current not updated" do
Expand All @@ -85,7 +86,7 @@ describe Hardware::PID do
end
end

it "returns memory used" { (1 < pid.memory).should be_true }
it "returns memory usage" { pid.memory.should be > 1 }

it "parses name" { pid.name.should eq "crystal-run-spec.tmp" }

Expand Down
2 changes: 1 addition & 1 deletion src/hardware.cr
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
require "./hardware/**"

module Hardware
VERSION = "0.3.1"
VERSION = "0.4.0"
end
49 changes: 29 additions & 20 deletions src/hardware/cpu.cr
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,37 @@
# cpu = Hardware::CPU.new
# loop do
# sleep 1
# cpu.used.to_i # => 17
# cpu.usage.to_i # => 17
# end
# ```
struct Hardware::CPU
# Returns the previous used, idle and total CPU time. Used to store the previous CPU time informations to calculate the percentage in`.used`.
class_property previous_info : NamedTuple(used: Int32, idle: Int32, total: Int32) = {used: 0, idle: 0, total: 0}
@stat = Array(Int32).new
# Previous used CPU time
getter previous_used : Int32 = 0
# Previous idle CPU time
getter previous_idle_wait : Int32 = 0
# Returns a parsed `/proc/stat`
getter stat : Array(Int32)

# Creates a new `Hardware::CPU` based on the current memory state.
def initialize
@stat = update_stat
end

# Returns a parsed `/proc/stat`.
def stat : Array(Int32)
# Update the stats stored in `#stat`
def update_stat : Array(Int32)
@stat = File.read("/proc/stat").lines.first[5..-1].split(' ').map &.to_i
end

# Returns the CPU time used, which includes `idle` and `iowait`
def idle_wait : Int32
idle + iowait
end

# Returns the used CPU time, which includes `user`, `nice`, `system`, `irq`, `softirq` and `steal`
def used : Int32
user + nice + system + irq + softirq + steal
end

# Generate methods based on stat
{% begin %}{% i = 0 %}
{% for num in %w(user nice system idle iowait irq softirq steal guest guest_nice) %}
Expand All @@ -31,26 +45,21 @@ struct Hardware::CPU
{% i = i + 1 %}
{% end %}{% end %}

# Returns the current used, idle and total CPU time.
def info : NamedTuple(used: Int32, idle: Int32, total: Int32)
# update stat
stat
# Array: user nice system idle iowait irq softirq steal guest guest_nice
{
used: used = user + nice + system + irq + softirq + steal,
idle: idle_cpu = idle + iowait,
total: used + idle_cpu,
}
# Returns the total CPU time, the sum of `#idle` and `#used`
def total : Int32
idle_wait + used
end

# Returns the CPU used in percentage based on `.previous_info`.
def used(update = true) : Float32
current_info = info
def usage(update = true) : Float32
# Update stats
update_stat
current_used, current_idle_wait = used, idle_wait

# 100 * Usage / Total
result = (current_info[:used] - @@previous_info[:used]).to_f32 / (current_info[:total] - @@previous_info[:total]) * 100
result = (current_used - @previous_used).to_f32 / (current_used + current_idle_wait - @previous_used - @previous_idle_wait) * 100

@@previous_info = current_info if update
@previous_used, @previous_idle_wait = current_used, current_idle_wait if update
result
end
end
Loading

0 comments on commit 8570b47

Please sign in to comment.