Skip to content

Commit

Permalink
Initial project structure for procinfo Ruby/C extension
Browse files Browse the repository at this point in the history
  • Loading branch information
mbbx6spp committed Jul 17, 2013
1 parent 50ff7c2 commit 1405d45
Show file tree
Hide file tree
Showing 11 changed files with 201 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
*.bundle
*.so
*.o
ext/procinfo/Makefile
*.gem
5 changes: 5 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
source 'https://rubygems.org'

gem 'rake'
gem 'rake-compiler'

13 changes: 13 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
GEM
remote: https://rubygems.org/
specs:
rake (10.1.0)
rake-compiler (0.8.3)
rake

PLATFORMS
ruby

DEPENDENCIES
rake
rake-compiler
32 changes: 32 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# procinfo

A Ruby/C extension packaged as a gem that provides a more uniform interface
to \*NIX process information.

## Motivation

I really needed to be able to get current RSS and max RSS information (and
related process information) for a given process (which may or may not be
the current running process). No Ruby library (as far as I found offered a
consistent view of this information across the most \*NIX OSes).

## Related Works

`sys-proctable` is Ruby/C extension library that provides this to some
degree. I wanted to use a different approach to this library and lower
overhead, and compatibility of APIs exposed for all the supporting OSes.

However, the above mentioned library may offer what you need.

## License

This code is shared under the BSD 3-clause license. See LICENSE for
more information.

## Author(s)

* Susan Potter <me at susanpotter do net> (mbbx6spp on GitHub)

## Contributor(s)

N/A
37 changes: 37 additions & 0 deletions Rakefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
require 'rake/testtask'
require 'rake/clean'

NAME = 'procinfo'
EXT = RbConfig::CONFIG['DLEXT']

# rule to build the extension: this says
# that the extension should be rebuilt
# after any change to the files in ext
file "lib/#{NAME}/#{NAME}.#{EXT}" =>
Dir.glob("ext/#{NAME}/*{.rb,.c}") do
Dir.chdir("ext/#{NAME}") do
# this does essentially the same thing
# as what RubyGems does
ruby "extconf.rb"
sh "make"
end
cp "ext/#{NAME}/#{NAME}.#{EXT}", "lib/#{NAME}"
end

# make the :test task depend on the shared
# object, so it will be built automatically
# before running the tests
task :test => "lib/#{NAME}/#{NAME}.#{EXT}"

# use 'rake clean' and 'rake clobber' to
# easily delete generated files
CLEAN.include("ext/**/*{.o,.log,.#{EXT}}")
CLEAN.include('ext/**/Makefile')
CLOBBER.include("lib/**/*.#{EXT}")

Rake::TestTask.new do |t|
t.libs << 'test'
end

desc "Run tests"
task :default => :test
3 changes: 3 additions & 0 deletions bin/procinfo
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/usr/bin/env ruby


3 changes: 3 additions & 0 deletions ext/procinfo/extconf.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
require 'mkmf'

create_makefile('procinfo/procinfo')
78 changes: 78 additions & 0 deletions ext/procinfo/procinfo.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
#include <ruby.h>

#include <sys/resource.h>
#include <sys/wait.h>

static VALUE S_PROC_INFO = Qnil;

// signatures
void Init_procinfo(void);
static VALUE procinfo_stats(VALUE);
static VALUE _to_proc_stats_struct(const struct rusage *);
static VALUE _to_time_value(struct timeval);

static VALUE procinfo_stats(VALUE self) {
struct rusage usage;
if (getrusage(RUSAGE_SELF, &usage) == -1) {
rb_raise(rb_eRuntimeError, "getrusage call returned -1");
}

return _to_proc_stats_struct(&usage);
}

static VALUE _to_proc_stats_struct(const struct rusage *usage) {
VALUE user_time = _to_time_value(usage->ru_utime);
VALUE system_time = _to_time_value(usage->ru_stime);
VALUE max_rss = rb_int_new(usage->ru_maxrss);
VALUE shared_text_size = rb_int_new(usage->ru_ixrss);
VALUE unshared_data_size = rb_int_new(usage->ru_idrss);
VALUE unshared_stack_size = rb_int_new(usage->ru_isrss);
VALUE page_reclaims = rb_int_new(usage->ru_minflt);
VALUE page_faults = rb_int_new(usage->ru_majflt);
VALUE swaps = rb_int_new(usage->ru_nswap);
VALUE block_input_ops = rb_int_new(usage->ru_inblock);
VALUE block_output_ops = rb_int_new(usage->ru_oublock);
VALUE msgs_sent = rb_int_new(usage->ru_msgsnd);
VALUE msgs_recvd = rb_int_new(usage->ru_msgrcv);
VALUE signals_recvd = rb_int_new(usage->ru_nsignals);
VALUE voluntary_switches = rb_int_new(usage->ru_nvcsw);
VALUE involuntary_switches = rb_int_new(usage->ru_nivcsw);
return rb_struct_new(S_PROC_INFO,
user_time, // usage->ru_utime
system_time, // usage->ru_stime
max_rss, // usage->ru_maxrss
shared_text_size, // usage->ru_ixrss
unshared_data_size, // usage->ru_idrss
unshared_stack_size, // usage->ru_isrss
page_reclaims, // usage->ru_minflt
page_faults, // usage->ru_majflt
swaps, // usage->ru_nswap
block_input_ops, // usage->ru_inblock
block_output_ops, // usage->ru_oublock
msgs_sent, // usage->ru_msgsnd
msgs_recvd, // usage->ru_msgrcv
signals_recvd, // usage->ru_nsignals
voluntary_switches, // usage->ru_nvcsw
involuntary_switches, // usage->ru_nivcsw
NULL);
}

static VALUE _to_time_value(struct timeval t) {
double time = t.tv_sec + t.tv_usec / 1000000.0;
return rb_float_new(time);
}

// Initialization function to setup struct and module method
void Init_procinfo(void) {
VALUE M_PROCESS = rb_define_module("Process");
S_PROC_INFO = rb_struct_define("ProcStats",
"user_time", "system_time", "max_rss",
"shared_text_size", "unshared_data_size",
"unshared_stack_size", "page_reclaims", "page_faults",
"swaps", "block_input_ops", "block_output_ops",
"msgs_sent", "msgs_recvd", "signals_recvd",
"voluntary_switches", "involuntary_switches", NULL);

rb_const_set(M_PROCESS, rb_intern("ProcStats"), S_PROC_INFO);
rb_define_singleton_method(M_PROCESS, "stats", procinfo_stats, 0);
}
1 change: 1 addition & 0 deletions lib/procinfo.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
require 'procinfo/procinfo'
11 changes: 11 additions & 0 deletions procinfo.gemspec
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
Gem::Specification.new do |s|
s.name = 'procinfo'
s.version = '0.1.0'
s.authors = ['Susan Potter']
s.summary = 'Provide cross *NIX OS uniform interface to process info'
s.files = Dir.glob('lib/**/*.rb') +
Dir.glob("ext/**/*.{c,h,rb}")
s.extensions = ['ext/procinfo/extconf.rb']
s.executables = ['procinfo']

end
13 changes: 13 additions & 0 deletions test/test_procinfo.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
require 'test/unit'
require 'procinfo'

class ProcinfoTest < Test::Unit::TestCase
def test_stats
stats = Process.stats
puts stats.inspect
assert_equal Process::ProcStats, stats.class
assert stats.user_time > 0
assert stats.system_time > 0
assert stats.max_rss > 0
end
end

0 comments on commit 1405d45

Please sign in to comment.