I found interesting function in utils.c:
gboolean utils_str_equal(const gchar *a, const gchar *b) { /* (taken from libexo from os-cillation) */ if (a == NULL && b == NULL) return TRUE; else if (a == NULL || b == NULL) return FALSE;
while (*a == *b++) if (*a++ == '\0') return TRUE;
return FALSE; }
This function is widely used in Geany code.
However: - it is not inline so there is no reason to keep this small while loop - it uses own while-loop to compare that is *slow* for big strings - GLib has similar g_strcmp0 function since 2.16
Using while-loop may confuse compiler which knows strcmp and may optimize this std call e.g. for constants. Furthermore strcmp is SSE-accelerated function which compares 128 bits per cycle while this implementstion may compare only 8 bits per cycle.
Replace this by inline (g_strcmp0(a, b) == 0). This is much faster and easier to read.
-- Best regards, Pavel Roschin aka RPG
Le 27/04/2014 22:28, Pavel Roschin a écrit :
I found interesting function in utils.c:
gboolean utils_str_equal(const gchar *a, const gchar *b) { [...]
while (*a == *b++) if (*a++ == '\0') return TRUE;
return FALSE; }
This function is widely used in Geany code.
However:
- it is not inline so there is no reason to keep this small while loop
- it uses own while-loop to compare that is *slow* for big strings
- GLib has similar g_strcmp0 function since 2.16
Using while-loop may confuse compiler which knows strcmp and may optimize this std call e.g. for constants. Furthermore strcmp is SSE-accelerated function which compares 128 bits per cycle while this implementstion may compare only 8 bits per cycle.
Ouch indeed. I just replaced the loop with a strcmp(), which performs roughly 5.4 times better (on a 64bits Linux) for dummy average strings. Thanks for spotting this.
Replace this by inline (g_strcmp0(a, b) == 0). This is much faster and easier to read.
Well, the problem is that utils_str_equal() is part of the plugin API, so we can't make it a macro expanding to a non-function without breaking API. Also, I don't think "g_strcmp0(a, b) == 0" is easier to read than "utils_str_equal(a, b)" -- OK strcmp() is obvious, but strcmp0() is not, and utils_str_equal() is quite explicit.
Also, my naive tests showing the strcmp() version being 5.4 times faster (from 22.8301s to 4.22474s) shows very little gain with calling g_strcmp0() (+.02, 42.1628s vs 41.242s) -- and I would think it probably depends on optimization/debug compiler options, since both implementations are very similar (maybe g_strcmp0() is a little better because it does some tests only in some branches, but OTOH the compiler can easily improve our branching to lower test hitting).
Regards, Colomban
On Sun, 27 Apr 2014 23:05:46 +0200 Colomban Wendling lists.ban@herbesfolles.org wrote:
Le 27/04/2014 22:28, Pavel Roschin a écrit :
I found interesting function in utils.c:
gboolean utils_str_equal(const gchar *a, const gchar *b)
- GLib has similar g_strcmp0 function since 2.16
Ouch indeed. I just replaced the loop with a strcmp(), which performs roughly 5.4 times better (on a 64bits Linux) for dummy average strings.
g_strcmp0() checks for NULL strings, like utils_str_equal(). strcmp() will give you a segfault on NULL argument(s).
Le 28/04/2014 20:30, Dimitar Zhekov a écrit :
On Sun, 27 Apr 2014 23:05:46 +0200 Colomban Wendling lists.ban@herbesfolles.org wrote:
Le 27/04/2014 22:28, Pavel Roschin a écrit :
I found interesting function in utils.c:
gboolean utils_str_equal(const gchar *a, const gchar *b)
- GLib has similar g_strcmp0 function since 2.16
Ouch indeed. I just replaced the loop with a strcmp(), which performs roughly 5.4 times better (on a 64bits Linux) for dummy average strings.
g_strcmp0() checks for NULL strings, like utils_str_equal(). strcmp() will give you a segfault on NULL argument(s).
https://github.com/geany/geany/commit/5eb526f9d0385fb62f83425c3ccdc13b3940d1...