File: procfs.rb

package info (click to toggle)
ruby-vmstat 2.3.1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 344 kB
  • sloc: ruby: 1,136; ansic: 347; makefile: 3
file content (153 lines) | stat: -rw-r--r-- 5,558 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
module Vmstat
  # Implementation of performance metrics gathering for linux and other os with
  # the proc file system.
  module ProcFS
    # Grep from the man procfs about cpu data in stat file:
    # @example Format
    #     (num) user nice system idle iowait irq softirq steal
    # @example manpage
    #     iowait - time waiting for I/O to complete (since 2.5.41)  
    #     irq - time servicing interrupts (since 2.6.0-test4)
    #     softirq - time servicing softirqs (since 2.6.0-test4)
    #     Since Linux 2.6.11:
    #     steal - stolen time, which is the time spent in other operating 
    #             systems when running in a virtualized environment
    #     Since Linux 2.6.24:
    #     guest - which is the time spent running a virtual CPU for guest
    #             operating systems under the control of the Linux kernel.
    CPU_DATA = /cpu(\d+)#{'\s+(\d+)' * 4}/.freeze

    # Grep the network stats from the procfs.
    # @example Format (from /proc/net/dev)
    #   Inter-|   Receive                                                |  Transmit
    #    face |bytes    packets errs drop fifo frame compressed multicast|bytes    packets errs drop fifo colls carrier compressed
    # @example Data
    #   eth0:   33660     227    0    0    0     0          0         0    36584     167    0    0    0     0       0          0
    NET_DATA = /(\w+):#{'\s*(\d+)' * 16}/

    # Fetches the cpu statistics (usage counter for user, nice, system and idle)
    # @return [Array<Vmstat::Cpu>] the array of cpu counter
    # @example
    #   Vmstat.cpu # => [#<struct Vmstat::Cpu ...>, #<struct Vmstat::Cpu ...>]
    def cpu
      cpus = []
      procfs_file("stat") do |file|
        file.read.scan(CPU_DATA) do |i, user, nice, system, idle|
          cpus << Cpu.new(i.to_i, user.to_i, system.to_i, nice.to_i, idle.to_i)
        end
      end
      cpus
    end

    # Fetches the memory usage information.
    # @return [Vmstat::Memory] the memory data like free, used und total.
    # @example
    #   Vmstat.memory # => #<struct Vmstat::Memory ...>
    def memory
      @pagesize ||= Vmstat.pagesize
      has_available = false

      total = free = active = inactive = pageins = pageouts = available = 0
      procfs_file("meminfo") do |file|
        content = file.read(2048) # the requested information is in the first bytes

        content.scan(/(\w+):\s+(\d+) kB/) do |name, kbytes|
          pages = (kbytes.to_i * 1024) / @pagesize

          case name
            when "MemTotal" then total = pages
            when "MemFree" then free = pages
            when "MemAvailable"
                available = pages
                has_available = true
            when "Active" then active = pages
            when "Inactive" then inactive = pages
          end
        end
      end

      procfs_file("vmstat") do |file|
        content = file.read

        if content =~ /pgpgin\s+(\d+)/
          pageins = $1.to_i
        end

        if content =~ /pgpgout\s+(\d+)/
          pageouts = $1.to_i
        end
      end

      mem_klass = has_available ? LinuxMemory : Memory
      mem_klass.new(@pagesize, total-free-active-inactive, active,
                    inactive, free, pageins, pageouts).tap do |mem|
        mem.available = available if has_available
      end
    end

    # Fetches the information for all available network devices.
    # @return [Array<Vmstat::NetworkInterface>] the network device information
    # @example
    #   Vmstat.network_interfaces # => [#<struct Vmstat::NetworkInterface ...>, ...]
    def network_interfaces
      netifcs = []
      procfs_file("net", "dev") do |file|
        file.read.scan(NET_DATA) do |columns|
          type = case columns[0]
            when /^eth/ then NetworkInterface::ETHERNET_TYPE
            when /^lo/  then NetworkInterface::LOOPBACK_TYPE
          end

          netifcs << NetworkInterface.new(columns[0].to_sym, columns[1].to_i,
                                          columns[3].to_i,   columns[4].to_i,
                                          columns[9].to_i,   columns[11].to_i,
                                          type)
        end
      end
      netifcs
    end

    # Fetches the current process cpu and memory data.
    # @return [Vmstat::Task] the task data for the current process
    def task
      @pagesize ||= Vmstat.pagesize

      procfs_file("self", "stat") do |file|
        data = file.read.split(/ /)
        Task.new(data[22].to_i / @pagesize, data[23].to_i,
                 data[13].to_i * 1000, data[14].to_i * 1000)
      end
    end

    # Fetches the boot time of the system.
    # @return [Time] the boot time as regular time object.
    # @example
    #   Vmstat.boot_time # => 2012-10-09 18:42:37 +0200
    def boot_time
      raw = procfs_file("uptime") { |file| file.read }
      Time.now - raw.split(/\s/).first.to_f
    end

    # @return [String] the path to the proc file system
    # @example
    #   procfs_path # => "/proc"
    # @api private
    def procfs_path
      "/proc".freeze
    end

    # Opens a proc file system file handle and returns the handle in the
    # passed block. Closes the file handle.
    # @see File#open
    # @param [Array<String>] names parts of the path to the procfs file
    # @example
    #   procfs_file("net", "dev") { |file| }
    #   procfs_file("stat") { |file| }
    # @yieldparam [IO] file the file handle
    # @api private
    def procfs_file(*names, &block)
      path = File.join(procfs_path, *names)
      File.open(path, "r", &block)
    end
  end
end