After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 641828 - Use g_signal_emit instead of g_signal_emit_by_name
Use g_signal_emit instead of g_signal_emit_by_name
Status: RESOLVED FIXED
Product: vala
Classification: Core
Component: Code Generator
unspecified
Other Linux
: Low minor
: ---
Assigned To: Vala maintainers
Vala maintainers
Depends on:
Blocks: 681356
 
 
Reported: 2011-02-08 11:29 UTC by pancake
Modified: 2016-10-12 20:27 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
vala: use g_signal_emit when possible (6.35 KB, patch)
2011-02-17 00:35 UTC, Marco Trevisan (Treviño)
none Details | Review
Use g_signal_emit where possible (9.63 KB, patch)
2016-10-11 19:36 UTC, Simon Werbeck
none Details | Review
Use g_signal_emit where possible (10.50 KB, patch)
2016-10-12 19:05 UTC, Simon Werbeck
committed Details | Review

Description pancake 2011-02-08 11:29:55 UTC
As discussed in the mailing list

  http://mail.gnome.org/archives/vala-list/2011-January/msg00187.html

The following patch (hacky on top of C code) results in  about 18% faster execution.

  http://gitorious.org/vala-object-benchmarks/vala-object-benchmarks/commit/e90927e4cb1d65ce692d295817d25cafc789c85f

What do you think about adding this in mainstream? or at least allowing the programmer to decide when to use one or another?
Comment 1 Marco Trevisan (Treviño) 2011-02-17 00:35:10 UTC
Created attachment 181093 [details] [review]
vala: use g_signal_emit when possible

Ok I was intrigued by this, so I started working on this...

I found that instead of using global guint values (then to be exported as external in other files), it was also possible use type-struct values to keep everything in the same place... Plus, this behavior can't be used always, since the signal_id can't be always exported and external bindings doesn't use it.

However, attached you can find my work, please test it with your benchmark (als if I've already did and it seems fine).

-------

As experienced in some benchmarks, the usage of g_signal_emit_by_name can cause
some performance loss. When possible emitting a signal in a vala class / interface
should be performed via g_signal_emit using the signal_id returned by g_signal_new.

However this is possible only when the used interface / class is compiled in the
same scope of the vala file that is emitting the signal.
In fact, to perform this some *_signal_id guid variables are added (avoiding name
clash with other default signals func pointers) to the type definition struct of
the class / interface and they are assigned to signals ID returned by g_signal_new.
Then when a signal should be emitted, if the signal has saved its signal_id,
g_signal_emit is called, using the reltive *_signal_id function.

This always works in all the cases I've tested, when emitting the signal in a
different file than the one where the class / interface is defined, their type
structs could be redefined in the *.c file.

Of course, when using *.vapi files and emitting signals on external objects the
standard g_signal_emit_by_name method is used.
Comment 2 Aleksander Wabik 2011-02-23 16:55:32 UTC
I confirm performance gains with this patch.
Comment 3 Aleksander Wabik 2011-02-26 14:11:20 UTC
To be more specific:

It gives significant speedup, on my computer it's like 1.025 to 0.86.

As I can see in the patch description, there are significant limitations. If the class comes from external vapi, old style (calling signal by name) will be used. Maybe some attributes can be used to control this? So for example:

- each signal ID is in the object's Type structure, and has some name, unless some attribute is used,
- CCode has_signal_id=false can be set in vapis on bindings to external libraries to indicate, that the particular signal's ID is not stored in the Type,
- maybe some CCode signal_id_name="foo" can be used to control how is the ID named in the Type struct?
- maybe even something like CCode signal_id_path="Namespace.[int|lass.static_member]" to be able to store signal ID anywhere you like?
Comment 4 Aleksander Wabik 2011-02-26 14:13:09 UTC
(In reply to comment #3)
correction of a typo:
> - maybe even something like CCode
> signal_id_path="Namespace.[int|Class.static_member]" to be able to store signal
> ID anywhere you like?
Comment 5 Simon Werbeck 2014-06-28 15:32:37 UTC
(In reply to comment #1)
> In fact, to perform this some *_signal_id guid variables are added (avoiding
> name
> clash with other default signals func pointers) to the type definition struct

Unfortunately we can't do that as it would break ABI, so accessing the ids directly seems impossible. I happened to stumble on a blog comment from ebassi on this matter.

http://arunchaganty.wordpress.com/2008/05/18/i-am-a-gobject/#comment-104

So it seems the proper way to do this would be:
 - for each class/iface emit an enum holding the signals and a *_LAST_SIGNAL value
 - for each class/iface emit a static array of size *_LAST_SIGNAL and use it for signal creation/emission

Also, if bug 681356 was fixed, it would be possible to generate emitters that make use of the signal ids.
Comment 6 Simon Werbeck 2016-10-11 19:36:17 UTC
Created attachment 337462 [details] [review]
Use g_signal_emit where possible

This includes basically the above, namely:

- An enumeration is generated, holding capitalized signal names.
- Signal ids are stored in a static array.
- When emitting a signal in the same file the signal was declared, g_signal_emit is invoked using the stored ids.
- Everywhere else g_signal_emit_by_name or the emitter is used as before.
Comment 7 Rico Tzschichholz 2016-10-12 17:52:13 UTC
The signal enum generation is broken for inherited signals from interfaces.


public interface Bar : GLib.Object {
	//[HasEmitter]
	public signal int bar (int i);
}

public class Foo : GLib.Object, Bar {
}

void main () {
	var f = new Foo ();

	f.bar.connect (i => i + 12);

	var res = f.bar (30);
	assert (res == 42);
}
Comment 8 Simon Werbeck 2016-10-12 19:05:06 UTC
Created attachment 337530 [details] [review]
Use g_signal_emit where possible

For interfaces, the LAST_SIGNAL value was generated before visiting the children, so the signal array had size zero. Also, there was no test case for interfaces with signals that could have caught this.
Comment 9 Rico Tzschichholz 2016-10-12 20:27:33 UTC
commit 3bbf223347d9280accb608c90672312d4bd30a05
Author: Simon Werbeck <simon.werbeck@gmail.com>
Date:   Wed Oct 5 19:01:44 2016 +0200

    codegen: Use g_signal_emit where possible