diff --git a/.travis.yml b/.travis.yml index 2c9c8da..483ea23 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,7 @@ language: ruby +os: + - linux + - osx before_install: - gem install bundler -v 1.12.5 @@ -14,4 +17,4 @@ matrix: allow_failures: - rvm: ruby-head - rvm: rbx-19mode - - rvm: jruby-19mode \ No newline at end of file + - rvm: jruby-19mode diff --git a/CHANGELOG.md b/CHANGELOG.md index 33e2864..b372a37 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,10 @@ +## 0.2.4 + +- Use FFI to speed up memory lookup on Mac (darwin) by roughly 12x (#32) + ## 0.2.3 -- Silence BigDecimal deprecation warning under Ruby 2.5 (#26) +- Silence BigDecimal deprecation warning under Ruby 2.5 (#26) ## 0.2.2 @@ -25,4 +29,4 @@ ## 0.0.1 -- Initial \ No newline at end of file +- Initial diff --git a/get_process_mem.gemspec b/get_process_mem.gemspec index a53c403..b898eb7 100644 --- a/get_process_mem.gemspec +++ b/get_process_mem.gemspec @@ -18,6 +18,8 @@ Gem::Specification.new do |gem| gem.test_files = gem.files.grep(%r{^(test|spec|features)/}) gem.require_paths = ["lib"] + gem.add_dependency "ffi", "~> 1.0" + gem.add_development_dependency "sys-proctable", "~> 1.0" gem.add_development_dependency "rake", "~> 10.1" gem.add_development_dependency "test-unit", "~> 3.1.0" diff --git a/lib/get_process_mem.rb b/lib/get_process_mem.rb index 4ef9cfe..ad352eb 100644 --- a/lib/get_process_mem.rb +++ b/lib/get_process_mem.rb @@ -31,6 +31,20 @@ class GetProcessMem include Sys end + RUNS_ON_DARWIN = Gem.platforms.detect do |p| + p.is_a?(Gem::Platform) && p.os == 'darwin' + end + + if RUNS_ON_DARWIN + begin + require 'get_process_mem/darwin' + rescue LoadError => e + message = "Please add `ffi` to your Gemfile for darwin (macos) machines\n" + message << e.message + raise e, message + end + end + def initialize(pid = Process.pid) @status_file = Pathname.new "/proc/#{pid}/status" @process_file = Pathname.new "/proc/#{pid}/smaps" @@ -44,6 +58,7 @@ def linux? def bytes memory = linux_status_memory if linux? + memory ||= darwin_memory if RUNS_ON_DARWIN memory ||= ps_memory end @@ -102,4 +117,8 @@ def ps_memory KB_TO_BYTE * number_to_bigdecimal(mem == "" ? 0 : mem) end end + + def darwin_memory + Darwin.resident_size + end end diff --git a/lib/get_process_mem/darwin.rb b/lib/get_process_mem/darwin.rb new file mode 100644 index 0000000..2fd98cb --- /dev/null +++ b/lib/get_process_mem/darwin.rb @@ -0,0 +1,53 @@ +require 'ffi' + +class GetProcessMem + class Darwin + extend FFI::Library + ffi_lib 'c' + attach_function :mach_task_self, [], :__darwin_mach_port_t + attach_function :task_info, + [ + :__darwin_mach_port_t, + :int, # return selector + :pointer, #pointer to task info + :pointer, #pointer to int (size of structure / bytes filled out) + ], + :int + + class IntPtr < FFI::Struct + layout :value, :int + end + + class TaskInfo < FFI::Struct + layout :suspend_count, :int32, + :virtual_size, :uint64, + :resident_size, :uint64, + :user_time, :uint64, + :system_time, :uint64, + :policy, :int32 + end + + MACH_TASK_BASIC_INFO = 20 + MACH_TASK_BASIC_INFO_COUNT = TaskInfo.size / FFI.type_size(:uint) + + class << self + def resident_size + mach_task_info[:resident_size] + end + + private + + def mach_task_info + data = TaskInfo.new + out_count = IntPtr.new + out_count[:value] = MACH_TASK_BASIC_INFO_COUNT + result = task_info(mach_task_self, MACH_TASK_BASIC_INFO, data, out_count) + if result == 0 + data + else + raise "task_info returned #{result}" + end + end + end + end +end diff --git a/lib/get_process_mem/version.rb b/lib/get_process_mem/version.rb index e50e1e9..c42ff1b 100644 --- a/lib/get_process_mem/version.rb +++ b/lib/get_process_mem/version.rb @@ -1,3 +1,3 @@ class GetProcessMem - VERSION = "0.2.3" + VERSION = "0.2.4" end