Main loop busier than expected

Hi All

One of my colleagues has recently been using PowerTop to look at
processes running on his machine to see which ones are generating
‘wakeups’ (which stop the processor idling in low power mode):

Saving power with Linux on Intel hardware

One offender on his machine was a Ruby/Gtk program written by me. To
help isolate the problem, I created this test program:

=================================================================
#!/usr/bin/ruby

require ‘gtk2’

Gtk.init

window = Gtk::Window.new( Gtk::window::TOPLEVEL )
window.signal_connect(‘destroy’) { Gtk.main_quit }

b1 = Gtk::Button.new(‘Exit’)
b1.signal_connect(‘clicked’) { Gtk.main_quit }

window.add(b1)
window.show_all

Gtk.main

The program displays a button and when the button is pressed the program
exits. I expected that after window initialisation, the process would
essentially be idle. Instead, strace (on Ubuntu Linux) showed me that
it was looping through these system calls:

12:31:46 select(4, [3], [], [], {0, 0}) = 0 (Timeout)
12:31:46 ioctl(3, FIONREAD, [0]) = 0
12:31:46 gettimeofday({1190939506, 358}, NULL) = 0

The loop repeats about 20 times per second, so it is only using a tiny
amount of CPU - I’m just surprised that it’s using any.

By contract, I implemented the same program in Perl:

=================================================================
#!/usr/bin/perl -w

use strict;

use Gtk2 -init;

my $window = Gtk2::Window->new;
$window->signal_connect(destroy => sub { Gtk2->main_quit; });

my $b1 = Gtk2::Button->new(‘Exit’);
$b1->signal_connect(clicked => sub { Gtk2->main_quit; });

$window->add($b1);
$window->show_all;

Gtk2->main;

After window initialisation, strace showed that this program sat quietly
in a poll:

12:35:28 poll(

As long as I didn’t generate events via the keyboard or mouse etc, the
process was completely idle.

I was surprised by the difference in behaviour between the two language
bindings. Does anyone have an explanation?

Regards
Grant

I was surprised by the difference in behaviour between the two language
bindings. Does anyone have an explanation?

This is to not break support for ruby multi-threading. Choice was to
not block forever waiting for Gtk events in the Gtk mainloop, else
ruby threads won’t have any chance to be scheduled. I am not sure
about the other possible design choices, but as long as you want to
handle more than one event loop, you bump into polling because the
event loops won’t be able to cooperate at the syscall level. It would
be interesting to compare with the approach of Gtk2-Perl and pygtk,
but I don’t know them.


Guillaume C. - Guillaume Cottenceau

On Fri, 2007-09-28 at 10:44 +0200, Guillaume C. wrote:

I was surprised by the difference in behaviour between the two language
bindings. Does anyone have an explanation?

This is to not break support for ruby multi-threading. Choice was to
not block forever waiting for Gtk events in the Gtk mainloop, else
ruby threads won’t have any chance to be scheduled.

Ahh ok, that explains it. I believe the Perl threading model is quite
different from the Ruby model, but I haven’t had cause to use either.

It might be nice to have an option in Ruby Gtk so that programs which
know they won’t be using threads can tell the Gtk event loop it’s safe
to block forever.

Thanks for the prompt response.

Regards
Grant

Grant McLean wrote:

Ahh ok, that explains it. I believe the Perl threading model is quite
different from the Ruby model, but I haven’t had cause to use either.

It might be nice to have an option in Ruby Gtk so that programs which
know they won’t be using threads can tell the Gtk event loop it’s safe
to block forever.

Thanks for the prompt response.

There’s a ruby api call (rb_threadalone()) that could be used to work it
out - if it’s the only scheduled thread, then it would be safe to assume
from a ruby POV that it’s safe to block until glib/gtk notices an event.

But you always have at least two threads. A thread is created on entry
to the mainloop - in case signals are raised by native threads. If they
are, they are fed into this event handling thread which is used to
dispatch them back into ruby - so events raised on a different native
thread can be distinguished from within ruby code because they are also
raised on a different ruby thread.

I think the CPU thrashing should still be fixable - at some level it
should be possible to know if we are only waiting for IO events (ruby
does) - and thus that a blocking select() is ok*, but I don’t fully
understand the relationship between the glib mainloop and
ruby_thread_select.

TTFN,

Geoff.

  • The command below blocks on select waiting for IO:
    $ strace ruby -e ‘rd,wr = IO.pipe; t = Thread.new {p rd.read }; wr.puts
    STDIN.read; wr.close; t.join’