sys-proctable 0.9.1-universal-linux

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,175 @@
1
+ require 'rake'
2
+ require 'rake/clean'
3
+ require 'rake/testtask'
4
+ require 'rbconfig'
5
+ include Config
6
+
7
+ CLEAN.include(
8
+ '**/*.core', # Core dump files
9
+ '**/*.gem', # Gem files
10
+ '**/*.rbc', # Rubinius
11
+ '**/*.o', # C object file
12
+ '**/*.log', # Ruby extension build log
13
+ '**/Makefile', # C Makefile
14
+ '**/conftest.dSYM', # OS X build directory
15
+ "**/*.#{CONFIG['DLEXT']}" # C shared object
16
+ )
17
+
18
+ desc 'Build the sys-proctable library for C versions of sys-proctable'
19
+ task :build => [:clean] do
20
+ case Config::CONFIG['host_os']
21
+ when /bsd/i
22
+ dir = 'ext/bsd'
23
+ when /darwin/i
24
+ dir = 'ext/darwin'
25
+ when /hpux/i
26
+ dir = 'ext/hpux'
27
+ end
28
+
29
+ unless Config::CONFIG['host_os'] =~ /win32|mswin|dos|cygwin|mingw|windows|linux|sunos|solaris/i
30
+ Dir.chdir(dir) do
31
+ ruby 'extconf.rb'
32
+ sh 'make'
33
+ cp 'proctable.' + Config::CONFIG['DLEXT'], 'sys'
34
+ end
35
+ end
36
+ end
37
+
38
+ desc 'Install the sys-proctable library'
39
+ task :install => [:build] do
40
+ file = nil
41
+ dir = File.join(Config::CONFIG['sitelibdir'], 'sys')
42
+
43
+ Dir.mkdir(dir) unless File.exists?(dir)
44
+
45
+ case Config::CONFIG['host_os']
46
+ when /mswin|win32|msdos|cygwin|mingw|windows/i
47
+ file = 'lib/windows/sys/proctable.rb'
48
+ when /linux/i
49
+ file = 'lib/linux/sys/proctable.rb'
50
+ when /sunos|solaris/i
51
+ file = 'lib/sunos/sys/proctable.rb'
52
+ when /bsd/i
53
+ Dir.chdir('ext/bsd'){ sh 'make install' }
54
+ when /darwin/i
55
+ Dir.chdir('ext/darwin'){ sh 'make install' }
56
+ when /hpux/i
57
+ Dir.chdir('ext/hpux'){ sh 'make install' }
58
+ end
59
+
60
+ cp(file, dir, :verbose => true) if file
61
+ end
62
+
63
+ desc 'Uninstall the sys-proctable library'
64
+ task :uninstall do
65
+ case Config::CONFIG['host_os']
66
+ when /win32|mswin|dos|cygwin|mingw|windows|linux|sunos|solaris/i
67
+ dir = File.join(Config::CONFIG['sitelibdir'], 'sys')
68
+ file = File.join(dir, 'proctable.rb')
69
+ else
70
+ dir = File.join(Config::CONFIG['sitearchdir'], 'sys')
71
+ file = File.join(dir, 'proctable.' + Config::CONFIG['DLEXT'])
72
+ end
73
+
74
+ rm(file)
75
+ end
76
+
77
+ desc 'Run the benchmark suite'
78
+ task :bench => [:build] do
79
+ sh "ruby -Ilib benchmarks/bench_ps.rb"
80
+ end
81
+
82
+ desc 'Run the example program'
83
+ task :example => [:build] do
84
+ sh 'ruby -Ilib -Iext examples/example_ps.rb'
85
+ end
86
+
87
+ desc 'Run the test suite'
88
+ Rake::TestTask.new do |t|
89
+ task :test => :build
90
+ t.libs << 'test' << '.'
91
+
92
+ case Config::CONFIG['host_os']
93
+ when /mswin|msdos|cygwin|mingw|windows/i
94
+ t.test_files = FileList['test/test_sys_proctable_windows.rb']
95
+ t.libs << 'lib/windows'
96
+ when /linux/i
97
+ t.test_files = FileList['test/test_sys_proctable_linux.rb']
98
+ t.libs << 'lib/linux'
99
+ when /sunos|solaris/i
100
+ t.test_files = FileList['test/test_sys_proctable_sunos.rb']
101
+ t.libs << 'lib/sunos'
102
+ when /darwin/i
103
+ t.libs << 'ext/darwin'
104
+ t.test_files = FileList['test/test_sys_proctable_darwin.rb']
105
+ when /bsd/i
106
+ t.libs << 'ext/bsd'
107
+ t.test_files = FileList['test/test_sys_proctable_bsd.rb']
108
+ when /hpux/i
109
+ t.libs << 'ext/hpux'
110
+ t.test_files = FileList['test/test_sys_proctable_hpux.rb']
111
+ end
112
+ end
113
+
114
+ namespace :gem do
115
+ desc 'Create a gem'
116
+ task :create => [:clean] do
117
+ spec = eval(IO.read('sys-proctable.gemspec'))
118
+
119
+ # I've had to manually futz with the spec here in some cases
120
+ # in order to get the universal platform settings I want because
121
+ # of some bugginess in Rubygems' platform.rb.
122
+ #
123
+ case Config::CONFIG['host_os']
124
+ when /bsd/i
125
+ spec.platform = Gem::Platform.new('universal-bsd')
126
+ spec.files << 'ext/bsd/sys/proctable.c'
127
+ spec.extra_rdoc_files << 'ext/bsd/sys/proctable.c'
128
+ spec.test_files << 'test/test_sys_proctable_bsd.rb'
129
+ spec.extensions = ['ext/bsd/extconf.rb']
130
+ when /darwin/i
131
+ spec.platform = Gem::Platform.new('universal-darwin')
132
+ spec.files << 'ext/darwin/sys/proctable.c'
133
+ spec.extra_rdoc_files << 'ext/darwin/sys/proctable.c'
134
+ spec.test_files << 'test/test_sys_proctable_darwin.rb'
135
+ spec.extensions = ['ext/darwin/extconf.rb']
136
+ when /hpux/i
137
+ spec.platform = Gem::Platform.new('universal-hpux')
138
+ spec.files << 'ext/hpux/sys/proctable.c'
139
+ spec.extra_rdoc_files << 'ext/hpux/sys/proctable.c'
140
+ spec.test_files << 'test/test_sys_proctable_hpux.rb'
141
+ spec.extensions = ['ext/hpux/extconf.rb']
142
+ when /linux/i
143
+ spec.platform = Gem::Platform.new('universal-linux')
144
+ spec.require_paths = ['lib', 'lib/linux']
145
+ spec.files += ['lib/linux/sys/proctable.rb']
146
+ spec.test_files << 'test/test_sys_proctable_linux.rb'
147
+ when /sunos|solaris/i
148
+ spec.platform = Gem::Platform.new('universal-solaris10.0')
149
+ spec.platform.version = nil
150
+ spec.require_paths = ['lib', 'lib/sunos']
151
+ spec.files += ['lib/sunos/sys/proctable.rb']
152
+ spec.test_files << 'test/test_sys_proctable_sunos.rb'
153
+ when /mswin|win32|dos|cygwin|mingw|windows/i
154
+ spec.platform = Gem::Platform::CURRENT
155
+ spec.platform.cpu = 'universal'
156
+ spec.platform.version = nil
157
+ spec.require_paths = ['lib', 'lib/windows']
158
+ spec.files += ['lib/windows/sys/proctable.rb']
159
+ spec.test_files << 'test/test_sys_proctable_windows.rb'
160
+ end
161
+
162
+ # https://github.com/rubygems/rubygems/issues/147
163
+ spec.original_platform = spec.platform
164
+
165
+ Gem::Builder.new(spec).build
166
+ end
167
+
168
+ desc 'Install the sys-proctable library as a gem'
169
+ task :install => [:create] do
170
+ gem_name = Dir['*.gem'].first
171
+ sh "gem install #{gem_name}"
172
+ end
173
+ end
174
+
175
+ task :default => :test
@@ -0,0 +1,21 @@
1
+ ########################################################################
2
+ # bench_ps.rb
3
+ #
4
+ # Benchmark program to show overall speed and compare the block form
5
+ # versus the non-block form. You should run this benchmark via the
6
+ # 'rake bench' Rake task.
7
+ ########################################################################
8
+ require 'benchmark'
9
+ require 'sys/proctable'
10
+
11
+ MAX = 10
12
+
13
+ Benchmark.bm do |bench|
14
+ bench.report("Block form"){
15
+ MAX.times{ Sys::ProcTable.ps{} }
16
+ }
17
+
18
+ bench.report("Non-block form"){
19
+ MAX.times{ Sys::ProcTable.ps }
20
+ }
21
+ end
@@ -0,0 +1,47 @@
1
+ = Description
2
+ A simple 'top' interface for Ruby
3
+
4
+ = Prerequisites
5
+ Requires the "sys/proctable" package (which should be installed along
6
+ with this package).
7
+
8
+ = Synopsis
9
+ require "sys/top"
10
+
11
+ Sys::Top.top(5).each{ |ps|
12
+ p ps
13
+ }
14
+
15
+ = Constants
16
+ VERSION
17
+ Returns the version number of this package as a String.
18
+
19
+ = Class Methods
20
+ Sys::Top.top(number=10, field="pctcpu")
21
+ Returns an array of ProcTableStruct's. The size of the array (i.e. the
22
+ number of processes) that it returns is based on +number+, and sorted by
23
+ +pctcpu+. By default, the size and field values are 10 and "pctcpu",
24
+ respectively.
25
+
26
+ = Notes
27
+ Not all fields are available on all platforms. Please check your
28
+ platform specific documentation for which fields are available.
29
+
30
+ = Bugs
31
+ None that I'm aware of. Please log bug reports on the project page at
32
+ http://www.rubyforge.org/projects/sysutils
33
+
34
+ = License
35
+ Artistic 2.0
36
+
37
+ = Copyright
38
+ (C) 2004-2009 Daniel J. Berger
39
+ All Rights Reserved.
40
+
41
+ = Warranty
42
+ This package is provided "as is" and without any express or
43
+ implied warranties, including, without limitation, the implied
44
+ warranties of merchantability and fitness for a particular purpose.
45
+
46
+ = Author
47
+ Daniel J. Berger
@@ -0,0 +1,20 @@
1
+ #######################################################################
2
+ # example_ps.rb
3
+ #
4
+ # Generic test program that demonstrates the use of ProcTable.ps. You
5
+ # can run this via the 'rake example' task.
6
+ #
7
+ # Modify as you see fit
8
+ #######################################################################
9
+ require 'sys/proctable'
10
+ include Sys
11
+
12
+ puts "VERSION: " + ProcTable::VERSION
13
+ sleep 2
14
+
15
+ ProcTable.ps{ |s|
16
+ ProcTable.fields.each{ |field|
17
+ puts "#{field}: " + s.send(field).to_s
18
+ }
19
+ puts '=' * 30
20
+ }
@@ -0,0 +1,281 @@
1
+ # The Sys module serves as a namespace only.
2
+ module Sys
3
+
4
+ # The ProcTable class encapsulates process table information.
5
+ class ProcTable
6
+
7
+ # Error typically raised if the ProcTable.ps method fails.
8
+ class Error < StandardError; end
9
+
10
+ # There is no constructor
11
+ private_class_method :new
12
+
13
+ # The version of the sys-proctable library
14
+ VERSION = '0.9.1'
15
+
16
+ private
17
+
18
+ @mem_total = IO.read("/proc/meminfo")[/MemTotal.*/].split[1].to_i * 1024 rescue nil
19
+ @boot_time = IO.read("/proc/stat")[/btime.*/].split.last.to_i rescue nil
20
+
21
+ @fields = [
22
+ 'cmdline', # Complete command line
23
+ 'cwd', # Current working directory
24
+ 'environ', # Environment
25
+ 'exe', # Actual pathname of the executed command
26
+ 'fd', # File descriptors open by process
27
+ 'root', # Root directory of process
28
+ 'pid', # Process ID
29
+ 'comm', # Filename of executable
30
+ 'state', # Single character state abbreviation
31
+ 'ppid', # Parent process ID
32
+ 'pgrp', # Process group
33
+ 'session', # Session ID
34
+ 'tty_nr', # TTY (terminal) associated with the process
35
+ 'tpgid', # Group ID of the TTY
36
+ 'flags', # Kernel flags
37
+ 'minflt', # Number of minor faults
38
+ 'cminflt', # Number of minor faults of waited-for children
39
+ 'majflt', # Number of major faults
40
+ 'cmajflt', # Number of major faults of waited-for children
41
+ 'utime', # Number of user mode jiffies
42
+ 'stime', # Number of kernel mode jiffies
43
+ 'cutime', # Number of children's user mode jiffies
44
+ 'cstime', # Number of children's kernel mode jiffies
45
+ 'priority', # Nice value plus 15
46
+ 'nice', # Nice value
47
+ 'itrealvalue', # Time in jiffies before next SIGALRM
48
+ 'starttime', # Time in jiffies since system boot
49
+ 'vsize', # Virtual memory size in bytes
50
+ 'rss', # Resident set size
51
+ 'rlim', # Current limit on the rss in bytes
52
+ 'startcode', # Address above which program text can run
53
+ 'endcode', # Address below which program text can run
54
+ 'startstack', # Address of the startstack
55
+ 'kstkesp', # Kernel stack page address
56
+ 'kstkeip', # Kernel instruction pointer
57
+ 'signal', # Bitmap of pending signals
58
+ 'blocked', # Bitmap of blocked signals
59
+ 'sigignore', # Bitmap of ignored signals
60
+ 'sigcatch', # Bitmap of caught signals
61
+ 'wchan', # Channel in which the process is waiting
62
+ 'nswap', # Number of pages swapped
63
+ 'cnswap', # Cumulative nswap for child processes
64
+ 'exit_signal', # Signal to be sent to parent when process dies
65
+ 'processor', # CPU number last executed on
66
+ 'rt_priority', # Real time scheduling priority
67
+ 'policy', # Scheduling policy
68
+ 'name', # Process name
69
+ 'uid', # Real user ID
70
+ 'euid', # Effective user ID
71
+ 'gid', # Real group ID
72
+ 'egid', # Effective group ID
73
+ 'pctcpu', # Percent of CPU usage (custom field)
74
+ 'pctmem' # Percent of Memory usage (custom field)
75
+ ]
76
+
77
+ public
78
+
79
+ ProcTableStruct = Struct.new('ProcTableStruct', *@fields)
80
+
81
+ # In block form, yields a ProcTableStruct for each process entry that you
82
+ # have rights to. This method returns an array of ProcTableStruct's in
83
+ # non-block form.
84
+ #
85
+ # If a +pid+ is provided, then only a single ProcTableStruct is yielded or
86
+ # returned, or nil if no process information is found for that +pid+.
87
+ #
88
+ # Example:
89
+ #
90
+ # # Iterate over all processes
91
+ # ProcTable.ps do |proc_info|
92
+ # p proc_info
93
+ # end
94
+ #
95
+ # # Print process table information for only pid 1001
96
+ # p ProcTable.ps(1001)
97
+ #
98
+ #--
99
+ # It's possible that a process could terminate while gathering
100
+ # information for that process. When that happens, this library
101
+ # will simply skip to the next record. In short, this library will
102
+ # either return all information for a process, or none at all.
103
+ #
104
+ def self.ps(pid=nil)
105
+ array = block_given? ? nil : []
106
+ struct = nil
107
+
108
+ raise TypeError unless pid.is_a?(Fixnum) if pid
109
+
110
+ Dir.foreach("/proc"){ |file|
111
+ next if file =~ /\D/ # Skip non-numeric directories
112
+ next unless file.to_i == pid if pid
113
+
114
+ struct = ProcTableStruct.new
115
+
116
+ # Get /proc/<pid>/cmdline information. Strip out embedded nulls.
117
+ begin
118
+ data = IO.read("/proc/#{file}/cmdline").tr("\000", ' ').strip
119
+ struct.cmdline = data
120
+ rescue
121
+ next # Process terminated, on to the next process
122
+ end
123
+
124
+ # Get /proc/<pid>/cwd information
125
+ struct.cwd = File.readlink("/proc/#{file}/cwd") rescue nil
126
+
127
+ # Get /proc/<pid>/environ information. Environment information
128
+ # is represented as a Hash, with the environment variable as the
129
+ # key and its value as the hash value.
130
+ struct.environ = {}
131
+
132
+ begin
133
+ IO.read("/proc/#{file}/environ").split("\0").each{ |str|
134
+ key, value = str.split('=')
135
+ struct.environ[key] = value
136
+ }
137
+ rescue Errno::EACCES, Errno::ESRCH
138
+ # Ignore and move on.
139
+ end
140
+
141
+ # Get /proc/<pid>/exe information
142
+ struct.exe = File.readlink("/proc/#{file}/exe") rescue nil
143
+
144
+ # Get /proc/<pid>/fd information. File descriptor information
145
+ # is represented as a Hash, with the fd as the key, and its
146
+ # symlink as the value.
147
+ struct.fd = {}
148
+
149
+ begin
150
+ Dir["/proc/#{file}/fd/*"].each do |fd|
151
+ struct.fd[File.basename(fd)] = File.readlink(fd) rescue nil
152
+ end
153
+ rescue
154
+ # Ignore and move on
155
+ end
156
+
157
+ # Get /proc/<pid>/root information
158
+ struct.root = File.readlink("/proc/#{file}/root") rescue nil
159
+
160
+ # Get /proc/<pid>/stat information
161
+ stat = IO.read("/proc/#{file}/stat") rescue next
162
+
163
+ # Deal with spaces in comm name. Courtesy of Ara Howard.
164
+ re = %r/\([^\)]+\)/
165
+ comm = stat[re]
166
+ comm.tr!(' ', '-')
167
+ stat[re] = comm
168
+
169
+ stat = stat.split
170
+
171
+ struct.pid = stat[0].to_i
172
+ struct.comm = stat[1].tr('()','') # Remove parens
173
+ struct.state = stat[2]
174
+ struct.ppid = stat[3].to_i
175
+ struct.pgrp = stat[4].to_i
176
+ struct.session = stat[5].to_i
177
+ struct.tty_nr = stat[6].to_i
178
+ struct.tpgid = stat[7].to_i
179
+ struct.flags = stat[8].to_i
180
+ struct.minflt = stat[9].to_i
181
+ struct.cminflt = stat[10].to_i
182
+ struct.majflt = stat[11].to_i
183
+ struct.cmajflt = stat[12].to_i
184
+ struct.utime = stat[13].to_i
185
+ struct.stime = stat[14].to_i
186
+ struct.cutime = stat[15].to_i
187
+ struct.cstime = stat[16].to_i
188
+ struct.priority = stat[17].to_i
189
+ struct.nice = stat[18].to_i
190
+ # Skip 19
191
+ struct.itrealvalue = stat[20].to_i
192
+ struct.starttime = stat[21].to_i
193
+ struct.vsize = stat[22].to_i
194
+ struct.rss = stat[23].to_i
195
+ struct.rlim = stat[24].to_i
196
+ struct.startcode = stat[25].to_i
197
+ struct.endcode = stat[26].to_i
198
+ struct.startstack = stat[27].to_i
199
+ struct.kstkesp = stat[28].to_i
200
+ struct.kstkeip = stat[29].to_i
201
+ struct.signal = stat[30].to_i
202
+ struct.blocked = stat[31].to_i
203
+ struct.sigignore = stat[32].to_i
204
+ struct.sigcatch = stat[33].to_i
205
+ struct.wchan = stat[34].to_i
206
+ struct.nswap = stat[35].to_i
207
+ struct.cnswap = stat[36].to_i
208
+ struct.exit_signal = stat[37].to_i
209
+ struct.processor = stat[38].to_i
210
+ struct.rt_priority = stat[39].to_i
211
+ struct.policy = stat[40].to_i
212
+
213
+ # Get /proc/<pid>/status information (name, uid, euid, gid, egid)
214
+ IO.foreach("/proc/#{file}/status") do |line|
215
+ case line
216
+ when /Name:\s*?(\w+)/
217
+ struct.name = $1
218
+ when /Uid:\s*?(\d+)\s*?(\d+)/
219
+ struct.uid = $1.to_i
220
+ struct.euid = $2.to_i
221
+ when /Gid:\s*?(\d+)\s*?(\d+)/
222
+ struct.gid = $1.to_i
223
+ struct.egid = $2.to_i
224
+ end
225
+ end
226
+
227
+ # If cmdline is empty use comm instead
228
+ struct.cmdline = struct.comm if struct.cmdline.empty?
229
+
230
+ # Manually calculate CPU and memory usage
231
+ struct.pctcpu = get_pctcpu(struct.utime, struct.starttime)
232
+ struct.pctmem = get_pctmem(struct.rss)
233
+
234
+ struct.freeze # This is read-only data
235
+
236
+ if block_given?
237
+ yield struct
238
+ else
239
+ array << struct
240
+ end
241
+ }
242
+
243
+ pid ? struct : array
244
+ end
245
+
246
+ # Returns an array of fields that each ProcTableStruct will contain. This
247
+ # may be useful if you want to know in advance what fields are available
248
+ # without having to perform at least one read of the /proc table.
249
+ #
250
+ # Example:
251
+ #
252
+ # Sys::ProcTable.fields.each{ |field|
253
+ # puts "Field: #{field}"
254
+ # }
255
+ #
256
+ def self.fields
257
+ @fields
258
+ end
259
+
260
+ private
261
+
262
+ # Calculate the percentage of memory usage for the given process.
263
+ #
264
+ def self.get_pctmem(rss)
265
+ return nil unless @mem_total
266
+ page_size = 4096
267
+ rss_total = rss * page_size
268
+ sprintf("%3.2f", (rss_total.to_f / @mem_total) * 100).to_f
269
+ end
270
+
271
+ # Calculate the percentage of CPU usage for the given process.
272
+ #
273
+ def self.get_pctcpu(utime, start_time)
274
+ return nil unless @boot_time
275
+ hertz = 100.0
276
+ utime = (utime * 10000).to_f
277
+ stime = (start_time.to_f / hertz) + @boot_time
278
+ sprintf("%3.2f", (utime / 10000.0) / (Time.now.to_i - stime)).to_f
279
+ end
280
+ end
281
+ end