Permalink
Browse files

Use finalizer to free GLPK problem.

  • Loading branch information...
1 parent 720dfb9 commit 034c984954e2101871ef05138d7a3acecb96fa9d @wtaysom committed Jan 3, 2012
Showing with 100 additions and 119 deletions.
  1. +23 −10 lib/rglpk.rb
  2. +50 −1 test/helper.rb
  3. +2 −1 test/test_all.rb
  4. +7 −44 test/test_brief_example.rb
  5. +18 −63 test/test_memory_prof.rb
View
@@ -68,14 +68,15 @@ def initialize
@rows = RowArray.new
@cols = ColArray.new
Glpk_wrapper.glp_create_index(@lp)
+
+ ObjectSpace.define_finalizer(self, self.class.finalizer(@lp))
end
- def destroy!
- Glpk_wrapper.glp_delete_prob(@lp)
-
- Glpk_wrapper.delete_intArray(@_ia)
- Glpk_wrapper.delete_intArray(@_ja)
- Glpk_wrapper.delete_doubleArray(@_ar)
+ def self.finalizer(lp)
+ proc do
+ Glpk_wrapper.glp_delete_index(lp)
+ Glpk_wrapper.glp_delete_prob(lp)
+ end
end
def name=(n)
@@ -125,6 +126,7 @@ def del_rows(a)
r = Glpk_wrapper.new_intArray(a.size + 1)
a.each_with_index{|n, i| Glpk_wrapper.intArray_setitem(r, i + 1, n)}
Glpk_wrapper.glp_del_rows(@lp, a.size, r)
+ Glpk_wrapper.delete_intArray(r)
a.each do |n|
@rows.send(:delete_at, n)
@@ -143,6 +145,7 @@ def del_cols(a)
r = Glpk_wrapper.new_intArray(a.size + 1)
a.each_with_index{|n, i| Glpk_wrapper.intArray_setitem(r, i + 1, n)}
Glpk_wrapper.glp_del_cols(@lp, a.size, r)
+ Glpk_wrapper.delete_intArray(r)
a.each do |n|
@cols.send(:delete_at, n)
@@ -170,11 +173,11 @@ def set_matrix(v)
Glpk_wrapper.doubleArray_setitem(ar, y + 1, x)
end
- @_ia = ia
- @_ja = ja
- @_ar = ar
-
Glpk_wrapper.glp_load_matrix(@lp, v.size, ia, ja, ar)
+
+ Glpk_wrapper.delete_intArray(ia)
+ Glpk_wrapper.delete_intArray(ja)
+ Glpk_wrapper.delete_doubleArray(ar)
end
private
@@ -273,6 +276,9 @@ def set(v)
Glpk_wrapper.doubleArray_setitem(val, y + 1, x)}
Glpk_wrapper.glp_set_mat_row(@p.lp, @i, v.size, ind, val)
+
+ Glpk_wrapper.delete_intArray(ind)
+ Glpk_wrapper.delete_doubleArray(val)
end
def get
@@ -285,6 +291,8 @@ def get
j = Glpk_wrapper.intArray_getitem(ind, i + 1)
row[j - 1] = v
end
+ Glpk_wrapper.delete_intArray(ind)
+ Glpk_wrapper.delete_doubleArray(val)
row
end
@@ -353,6 +361,9 @@ def set(v)
Glpk_wrapper.doubleArray_setitem(val, y + 1, x)}
Glpk_wrapper.glp_set_mat_col(@p.lp, @j, v.size, ind, val)
+
+ Glpk_wrapper.delete_intArray(ind)
+ Glpk_wrapper.delete_doubleArray(val)
end
def get
@@ -365,6 +376,8 @@ def get
j = Glpk_wrapper.intArray_getitem(ind, i + 1)
col[j - 1] = v
end
+ Glpk_wrapper.delete_intArray(ind)
+ Glpk_wrapper.delete_doubleArray(val)
col
end
View
@@ -2,4 +2,53 @@
require 'test/unit'
$LOAD_PATH << './ext'
-require here+'/../lib/rglpk'
+require here+'/../lib/rglpk'
+
+module Examples
+ def brief_example
+ # The same Brief Example as found in section 1.3 of
+ # glpk-4.44/doc/glpk.pdf.
+ #
+ # maximize
+ # z = 10 * x1 + 6 * x2 + 4 * x3
+ #
+ # subject to
+ # p: x1 + x2 + x3 <= 100
+ # q: 10 * x1 + 4 * x2 + 5 * x3 <= 600
+ # r: 2 * x1 + 2 * x2 + 6 * x3 <= 300
+ #
+ # where all variables are non-negative
+ # x1 >= 0, x2 >= 0, x3 >= 0
+ #
+ p = Rglpk::Problem.new
+ p.name = "sample"
+ p.obj.dir = Rglpk::GLP_MAX
+
+ rows = p.add_rows(3)
+ rows[0].name = "p"
+ rows[0].set_bounds(Rglpk::GLP_UP, 0, 100)
+ rows[1].name = "q"
+ rows[1].set_bounds(Rglpk::GLP_UP, 0, 600)
+ rows[2].name = "r"
+ rows[2].set_bounds(Rglpk::GLP_UP, 0, 300)
+
+ cols = p.add_cols(3)
+ cols[0].name = "x1"
+ cols[0].set_bounds(Rglpk::GLP_LO, 0.0, 0.0)
+ cols[1].name = "x2"
+ cols[1].set_bounds(Rglpk::GLP_LO, 0.0, 0.0)
+ cols[2].name = "x3"
+ cols[2].set_bounds(Rglpk::GLP_LO, 0.0, 0.0)
+
+ p.obj.coefs = [10, 6, 4]
+
+ p.set_matrix([
+ 1, 1, 1,
+ 10, 4, 5,
+ 2, 2, 6
+ ])
+
+ p.simplex
+ p
+ end
+end
View
@@ -3,4 +3,5 @@
require here+'/helper'
require here+'/test_basic'
require here+'/test_problem_kind'
-require here+'/test_brief_example'
+require here+'/test_brief_example'
+require here+'/test_memory_prof'
@@ -1,50 +1,13 @@
require File.expand_path('helper', File.dirname(__FILE__))
-class TestExample < Test::Unit::TestCase
- def test_example
- # The same Brief Example as found in section 1.3 of
- # glpk-4.44/doc/glpk.pdf.
- #
- # maximize
- # z = 10 * x1 + 6 * x2 + 4 * x3
- #
- # subject to
- # p: x1 + x2 + x3 <= 100
- # q: 10 * x1 + 4 * x2 + 5 * x3 <= 600
- # r: 2 * x1 + 2 * x2 + 6 * x3 <= 300
- #
- # where all variables are non-negative
- # x1 >= 0, x2 >= 0, x3 >= 0
- #
- p = Rglpk::Problem.new
- p.name = "sample"
- p.obj.dir = Rglpk::GLP_MAX
+class TestBriefExample < Test::Unit::TestCase
+ include Examples
+
+ def test_brief_example
+ p = brief_example
+ cols = p.cols
+ rows = p.rows
- rows = p.add_rows(3)
- rows[0].name = "p"
- rows[0].set_bounds(Rglpk::GLP_UP, 0, 100)
- rows[1].name = "q"
- rows[1].set_bounds(Rglpk::GLP_UP, 0, 600)
- rows[2].name = "r"
- rows[2].set_bounds(Rglpk::GLP_UP, 0, 300)
-
- cols = p.add_cols(3)
- cols[0].name = "x1"
- cols[0].set_bounds(Rglpk::GLP_LO, 0.0, 0.0)
- cols[1].name = "x2"
- cols[1].set_bounds(Rglpk::GLP_LO, 0.0, 0.0)
- cols[2].name = "x3"
- cols[2].set_bounds(Rglpk::GLP_LO, 0.0, 0.0)
-
- p.obj.coefs = [10, 6, 4]
-
- p.set_matrix([
- 1, 1, 1,
- 10, 4, 5,
- 2, 2, 6
- ])
-
- p.simplex
z = p.obj.get
x1 = cols[0].get_prim
x2 = cols[1].get_prim
@@ -1,75 +1,30 @@
require File.expand_path('helper', File.dirname(__FILE__))
class TestMemoryProf < Test::Unit::TestCase
+ include Examples
+
def test_memory_prof
- while true
+ 5.times do
1000.times do |i|
- _test_example
+ brief_example
end
- out = `ps aux | grep "ruby test/test_memory_prof.rb"`
- puts out.split("\n")[0]
+ change = change_to_real_memory_in_kb
+ assert (change < 10000), "memory leak #{change}kb"
end
end
- def _test_example
- # The same Brief Example as found in section 1.3 of
- # glpk-4.44/doc/glpk.pdf.
- #
- # maximize
- # z = 10 * x1 + 6 * x2 + 4 * x3
- #
- # subject to
- # p: x1 + x2 + x3 <= 100
- # q: 10 * x1 + 4 * x2 + 5 * x3 <= 600
- # r: 2 * x1 + 2 * x2 + 6 * x3 <= 300
- #
- # where all variables are non-negative
- # x1 >= 0, x2 >= 0, x3 >= 0
- #
- p = Rglpk::Problem.new
- p.name = "sample"
- p.obj.dir = Rglpk::GLP_MAX
-
- rows = p.add_rows(3)
- rows[0].name = "p"
- rows[0].set_bounds(Rglpk::GLP_UP, 0, 100)
- rows[1].name = "q"
- rows[1].set_bounds(Rglpk::GLP_UP, 0, 600)
- rows[2].name = "r"
- rows[2].set_bounds(Rglpk::GLP_UP, 0, 300)
-
- cols = p.add_cols(3)
- cols[0].name = "x1"
- cols[0].set_bounds(Rglpk::GLP_LO, 0.0, 0.0)
- cols[1].name = "x2"
- cols[1].set_bounds(Rglpk::GLP_LO, 0.0, 0.0)
- cols[2].name = "x3"
- cols[2].set_bounds(Rglpk::GLP_LO, 0.0, 0.0)
-
- p.obj.coefs = [10, 6, 4]
-
- p.set_matrix([
- 1, 1, 1,
- 10, 4, 5,
- 2, 2, 6
- ])
-
- p.simplex
- z = p.obj.get
- x1 = cols[0].get_prim
- x2 = cols[1].get_prim
- x3 = cols[2].get_prim
-
- result = "z = %g; x1 = %g; x2 = %g; x3 = %g" % [z, x1, x2, x3]
- assert_equal "z = 733.333; x1 = 33.3333; x2 = 66.6667; x3 = 0", result
- assert_equal Rglpk::GLP_NU, rows[0].get_stat
- assert_equal 100, rows[0].get_prim
- assert_equal 3.333333333333333, rows[0].get_dual
- # File.delete("test.lp") rescue Errno::ENOENT
- # p.write_lp("test.lp")
- # assert File.exists?("test.lp")
-
- p.destroy!
+ def real_memory_in_kb
+ # "=" after "rss" strips the header line.
+ `ps -p #{Process.pid} -o rss=`.to_i
+ end
+
+ def change_to_real_memory_in_kb
+ GC.start
+ r = real_memory_in_kb
+ @change_to_real_memory_in_kb__prev ||= r
+ r - @change_to_real_memory_in_kb__prev
+ ensure
+ @change_to_real_memory_in_kb__prev = r
end
end

0 comments on commit 034c984

Please sign in to comment.