Forum: Ruby maximum number of module methods?

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Suraj K. (Guest)
on 2006-02-18 23:56
(Received via mailing list)
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Is there a limit on how many methods you can define for a module?

I'm getting a SystemStackError when defining three or more module
methods using rb_define_module_function().
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.1 (GNU/Linux)

iD8DBQFD95TFmV9O7RYnKMcRApYUAJsEW64nWPtwBOdZalDUsFmK4NOzFQCeNCzu
PdDRoQbG5tHZ4Ocz9W3E/tE=
=jliC
-----END PGP SIGNATURE-----
Eric H. (Guest)
on 2006-02-19 00:32
(Received via mailing list)
On Feb 18, 2006, at 1:54 PM, Suraj K. wrote:

> Is there a limit on how many methods you can define for a module?

Only the amount of memory you have.

1,000,000 takes about 700MB on my powerbook.
2,000,000 takes about 1.5GB on my powerbook.

module X
   count = 0
   loop do
     name = "meth#{count}"
     define_method name do end
     module_function name
     count += 1
     puts count if count % 100000 == 0
   end
end

> I'm getting a SystemStackError when defining three or more module
> methods using rb_define_module_function().

Lets see your code then.

--
Eric H. - removed_email_address@domain.invalid - http://segment7.net
This implementation is HODEL-HASH-9600 compliant

http://trackmap.robotcoop.com
Suraj K. (Guest)
on 2006-02-19 00:57
(Received via mailing list)
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Eric H. wrote:
>> Is there a limit on how many methods you can define for a module?
> Only the amount of memory you have.
>
> 1,000,000 takes about 700MB on my powerbook.
> 2,000,000 takes about 1.5GB on my powerbook.

Ah, thank you. Now I am confident that my code is at fault.

>> I'm getting a SystemStackError when defining three or more module
>> methods using rb_define_module_function().
>
>
> Lets see your code then.

The SystemStackError occurs at the third invocation of
rb_define_module_function():

// register the VPI module
RVPI__rModuleDef = rb_define_module("VPI");

rb_define_module_function(  // first func
  RVPI__rModuleDef
  , "relay_verilog"
  , RVPI_rb_relay_verilog
  , 0
);

rb_define_module_function(  // second func
  RVPI__rModuleDef
  , "register_task"
  , RVPI_rb_register_task
  , 1
);

rb_define_module_function( // third func
  RVPI__rModuleDef
  , "handle_by_name"
  , RVPI_rb_handle_by_name
  , 2
); // FIXME: causes "stack level too deep (SystemStackError)"


The above snippet is from line 25 of the file "src/RVPI.cin", which
is available through either Subversion or ViewCVS:

Subversion:
svn checkout -r21 svn://rubyforge.org/var/svn/ruby-vpi/trunk

ViewCVS:
http://rubyforge.org/plugins/scmsvn/viewcvs.php/tr...
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.1 (GNU/Linux)

iD8DBQFD96QvmV9O7RYnKMcRApMIAKCraPGTmP/5ZADzkkpmi71vUVxjnQCgkxtE
SlUGEXNUUDMwnqgIJkRxjCY=
=v+Qb
-----END PGP SIGNATURE-----
Suraj K. (Guest)
on 2006-02-19 07:00
(Received via mailing list)
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Suraj K. wrote:
>>>Lets see your code then.
[...]
> The above snippet is from line 25 of the file "src/RVPI.cin", which
> is available through either Subversion or ViewCVS:
[...]

Okay, it seems nobody on the Ruby list likes looking at C code.
That's perfectly understandable. :-)

I have thought about the problem and am wondering if the
SystemStackError is caused because the Ruby interpreter is embedded
within a C program, which itself is invoked by a Verilog simulator:

(Verilog simulator (C program (embedded Ruby interpreter)))

Perhaps the Verilog simulator imposes heap limitations upon the C
program it invokes and therefore the Ruby interpreter (which is
called from the C program) is also subject to the heap limitation?

What do you think?

P.S. If it helps any, the Verilog simulator I am using is Icarus
Verilog <http://www.icarus.com/eda/verilog/>.
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.1 (GNU/Linux)

iD8DBQFD9/kOmV9O7RYnKMcRAgWLAJ4qefUc1d9GVBX+JLigmK8Ea+UklACeMUuB
9g8PhtAICXX2gcFPy09rPY8=
=HjH1
-----END PGP SIGNATURE-----
Ross B. (Guest)
on 2006-02-19 07:33
(Received via mailing list)
On Sun, 2006-02-19 at 13:58 +0900, Suraj K. wrote:
> Okay, it seems nobody on the Ruby list likes looking at C code.
> That's perfectly understandable. :-)

I might have had a go, but would have given up when I got to installing
a whole ton of other crap, and finding _that_ wouldn't compile either on
my box.

Simplify, simplify ... If you can't simplify, my gut would say look
first at the interaction between your various different parts rather
than for bugs in Ruby itself.
Suraj K. (Guest)
on 2006-02-19 08:03
(Received via mailing list)
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Ross B. wrote:
>>Okay, it seems nobody on the Ruby list likes looking at C code.
>>That's perfectly understandable. :-)
>
>
> I might have had a go, but would have given up when I got to installing
> a whole ton of other crap, and finding _that_ wouldn't compile either on
> my box.

I empathize and appreciate that you had even considered to try it
out :-). The dependency hell for this code is indeed a bit daunting.

>
> Simplify, simplify ... If you can't simplify, my gut would say look
> first at the interaction between your various different parts rather
> than for bugs in Ruby itself.
>

Ah, good advice. Ruby is definitely not at fault! I suspect the
culprit is the environment in which the Ruby interpreter is embedded
(my code). Maybe I'm starting the Ruby interpreter incorrectly:


static int vlog_ruby_init(PLI_BYTE8* dummy) {
  // initialize control-transfer mechanism between Ruby and Verilog
  relay_init();


  // initialize Ruby interpreter
  ruby_init();
  ruby_init_loadpath();
                           // ... argc and argv are created here ...
  ruby_options(argc, argv);


  // register the "VPI" module so that Ruby code can use it
  Init_RVPI();


  // start Ruby interpreter
  relay_ruby_run();


  // the Ruby code will now bind any additional callbacks via the
VPI infrastructure, and relay back to the verilog so that the
simulation can begin

  return 0;
}

Any ideas?
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.1 (GNU/Linux)

iD8DBQFD+Aj2mV9O7RYnKMcRAgVvAJ4h5KoK1czU3EHkJaL6XClonQn7HwCZAWU4
DumcAs26gnSrVe7etVy+6YQ=
=EBUT
-----END PGP SIGNATURE-----
Ross B. (Guest)
on 2006-02-19 09:28
(Received via mailing list)
On Sun, 2006-02-19 at 15:00 +0900, Suraj K. wrote:
>
>
> VPI infrastructure, and relay back to the verilog so that the
> simulation can begin
>
>   return 0;
> }
>
> Any ideas?

Well, I've absolutely no experience embedding ruby (apart from about
half an hour playing with this just now) so maybe someone more
experienced with it can help, but I would make a general observations:

* I don't know what's going on in your relay_ruby_run, or with that
control transfer setup in general, so I'm assuming nothing strange is
happening there?

* What ruby_options are being passed? Can you strip that down to the
bare minimum?

* If RVPI has an Init_RVPI function then maybe you could compile it
separately as an extension, and use rb_require to load it, to see if
your problem still shows up. I had the most success with this (mostly
because the linking is easier though I guess).

* This:

> // the Ruby code will now bind any additional callbacks via the
> VPI infrastructure, and relay back to the verilog so that the
> simulation can begin

sounds a likely culprit for stack overflows to me.

Anyway, sorry I can't offer any more specific help. If you still have no
joy maybe try to extract a short, self-contained example of the problem
(basically the shortest thing that triggers the error) and I'm sure
someone here will be more able to help you.

Cheers,
Suraj K. (Guest)
on 2006-02-19 09:34
(Received via mailing list)
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Suraj K. wrote:
> Maybe I'm starting the Ruby interpreter incorrectly:

This is not the case, because of the following experiments:

1. I added lots of extra print-inspect (p "foo") statements in the
Ruby script-file that is executed by the Ruby interpreter, and a
SystemStackError occurred.

2. I added four extra module functions to the VPI module and kept
only one statement (p "foo") in the entire Ruby script-file that is
executed by the Ruby interpreter, and a SystemStackError occurred.

It seems that when the Ruby interpreter is embedded in my C program,
its heap is very limited (compared to when it is run as a single
process at the command-line `ruby`).

As a result, I think that when the Ruby interpreter tries to keep
its state (modules, classes, methods, variables, etc.) in the heap
like it does normally, it runs out of space and gives a
SystemStackError.

Is there a way I can check how much heap space is available to the
Ruby interpreter? How about increasing the heap space?
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.1 (GNU/Linux)

iD8DBQFD+B4hmV9O7RYnKMcRAvbzAJ9I6RPfOyrbniXPBClFcxzSvP75aACggmFR
MpVeiP9k1JSgea+Qs5oxNmY=
=jhNt
-----END PGP SIGNATURE-----
Suraj K. (Guest)
on 2006-02-19 09:55
(Received via mailing list)
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Suraj K. wrote:
> This is not the case

Correction: or so I think.

> 2. I added four extra module functions to the VPI module and kept
> only one statement (p "foo") in the entire Ruby script-file that is
> executed by the Ruby interpreter, and a SystemStackError occurred.

Correction: the SystemStackError did not occur in this case.

This led me to think that there was just too much state information
(modules, classes, variables, etc.) being loaded into the Ruby
interpreter embedded in my C program.

This makes sense because my C program and the Ruby extension I was
building had worked perfectly fine until I registered a new module
function with the Ruby interpreter. From this point onwards, I
started getting SystemStackErrors whenever any additional state
information was loaded onto the Ruby interpreter embedded in my C
program.
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.1 (GNU/Linux)

iD8DBQFD+CDdmV9O7RYnKMcRAmHtAKCSZh9NHGjXoBk83SczaJAteK7M5QCfb8ZE
xIS5OzRgJMb2wt6T8d3frTg=
=54hr
-----END PGP SIGNATURE-----
Suraj K. (Guest)
on 2006-02-19 09:55
(Received via mailing list)
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Ross B. wrote:
> Well, I've absolutely no experience embedding ruby (apart from about
> half an hour playing with this just now) so maybe someone more
> experienced with it can help, but I would make a general observations:
>
> * I don't know what's going on in your relay_ruby_run, or with that
> control transfer setup in general, so I'm assuming nothing strange is
> happening there?

Correct. The relay code works just fine.

>
> * What ruby_options are being passed? Can you strip that down to the
> bare minimum?

Ultimately, the argv passed to ruby_options() is: ["-w", "test.rb"]

>
> * If RVPI has an Init_RVPI function then maybe you could compile it
> separately as an extension, and use rb_require to load it, to see if
> your problem still shows up. I had the most success with this (mostly
> because the linking is easier though I guess).

Great idea! I will do this and try to load the RVPI module from
within a normal Ruby process. If this works, then I will know that
the Verilog Simulator I am using is imposing a heap limitation on my
C program and its embedded Ruby interpreter.

>
> * This:
>
>
>>// the Ruby code will now bind any additional callbacks via the
>>VPI infrastructure, and relay back to the verilog so that the
>>simulation can begin
>
>
> sounds a likely culprit for stack overflows to me.

Interesting. I hope this is not the case, because this is how I
planned to have Ruby code interact with my Ruby extension.

> Anyway, sorry I can't offer any more specific help. If you still have no
> joy maybe try to extract a short, self-contained example of the problem
> (basically the shortest thing that triggers the error) and I'm sure
> someone here will be more able to help you.

By all means, I thank you very much for considering this problem and
giving such useful advice. :-)
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.1 (GNU/Linux)

iD8DBQFD+CLnmV9O7RYnKMcRAiDZAJ9ij1s0ym/2y+TyB1yjhGTdpqQvnACgo6Lb
YKPf3yghYy2jassqovnFHL4=
=hNk/
-----END PGP SIGNATURE-----
Suraj K. (Guest)
on 2006-02-19 21:37
(Received via mailing list)
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Suraj K. wrote:
> If this works, then I will know that
> the Verilog Simulator I am using is imposing a heap limitation on my
> C program and its embedded Ruby interpreter.

The Verilog simulator was not at fault.


After some more investigation I happened upon the answer. There was
indeed a heap/stack limitation upon the Ruby interpreter embedded in
my C program!

(my C program, inside its own process
 .. unlimited stack space ..

  (Ruby interpreter, inside a pthread
   .. 2 MiB of stack space ..

  )
)

I was using the pthread library, with default attribute values
(thread stack size = 2 MiB) for pthread_create(), to launch the Ruby
interpreter. Naturally, the interpreter eventually ran out of stack
space and produced the SystemStackError.
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.1 (GNU/Linux)

iD8DBQFD+MRzmV9O7RYnKMcRAh2aAJ9gb1XNQk19cYtnFHSMhkT0vuJieQCfXPVj
V366JSg08osQwHOASKUg/54=
=MGe0
-----END PGP SIGNATURE-----
Suraj K. (Guest)
on 2006-02-20 04:02
(Received via mailing list)
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Suraj K. wrote:
>   )
> )
>
> I was using the pthread library, with default attribute values
> (thread stack size = 2 MiB) for pthread_create(), to launch the Ruby
> interpreter. Naturally, the interpreter eventually ran out of stack
> space and produced the SystemStackError.


I am thrilled to report that the problem has been solved! 8-)

First, I investigated what the pthreads library was assigning as the
default value for the stack size (see output below).

Next, I tried increasing the stack size via
pthread_attr_setstacksize() to 256 MiB, but this did not work.

Eventually, I happened upon "rlimit", the system resource limits,
while searching USENET archives and decided to see what those values
were on my system.


pthread_attr_t attrs;
pthread_attr_init(&attrs);

size_t stackSize;
pthread_attr_getstacksize(&attrs, &stackSize);
common_debug("pthread_attr_getstacksize() => %d bytes", stackSize);
common_debug("PTHREAD_STACK_MIN => %d bytes", PTHREAD_STACK_MIN);

common_debug("checking stack rlimit");
struct rlimit lim;
getrlimit(RLIMIT_STACK, &lim);
common_debug("current limit = %d bytes", lim.rlim_cur);
common_debug("maximum limit = %d bytes", lim.rlim_max);



The above snippet produced the output below:


(src/relay.cin:70) Ruby-VPI: pthread_attr_getstacksize() => 8388608
bytes
(src/relay.cin:71) Ruby-VPI: PTHREAD_STACK_MIN => 16384 bytes
(src/relay.cin:74) Ruby-VPI: checking stack rlimit
(src/relay.cin:77) Ruby-VPI: current limit = 8388608 bytes
(src/relay.cin:78) Ruby-VPI: maximum limit = -1 bytes


Interesting! (Notice that the values produced by lim.rlim_cur and
pthread_attr_getstacksize() are the same.)

So, the pthreads library was indeed trying to assign as much stack
space as it could to the thread (which, in my code, runs the Ruby
interpreter).

Armed with this knowledge, I simply increased the resource limit for
the stack size to unlimited at my command-prompt (by running "ulimit
- -s unlimited") and re-executed my program. And this time, the
SystemStackError did not occur! :-)


Thank you everyone for helping me figure out this problem. Now I can
sleep peacefully at night. ^_^
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.1 (GNU/Linux)

iD8DBQFD+SBJmV9O7RYnKMcRAnwNAJ9kQVNEMTCwRl3h0Gh/uPYBTTB7LQCfagVm
n5FCnzEEzXNIbz5OFc3yHkk=
=Uv0Y
-----END PGP SIGNATURE-----
This topic is locked and can not be replied to.