regcomp() is not a notably fast function call. As the name suggests it is basically a compiler, and even for calls with literal strings it is a fairly intricate one. In particular it calls malloc() more than once, and malloc() itself is not a particularly fast function call, especially not when the arena is full. Under the circumstances, it is unfortunate that _FcStrRegexCmp() is called so very often by fontconfig. On my system (with ~5000 fonts, and a stripped-down fonts.conf), mapping a new Emacs frame makes twelve calls to FcFontMatch()... and those twelve calls proceed to call _FcStrRegexCmp() 175171 times, with a call to regcomp() every time! This then proceeds to invoke malloc() on the order of three million times. It is fairly easy to turn this into a pathological slowdown at runtime. My Emacsen are not small (arena sizes of a gigabyte-plus are common, with a highly fragmented heap), and in that situation those three million malloc() and free() calls can easily consume in excess of fifty seconds (though on a fresh startup it takes 'only' a quarter of a second or so). Since each call to FcFontMatch() in this pathological case (and probably in most other cases) calls _FcStrRegexCmp() with a constant argument, a trivial cache consisting of a single static variable suffices to reduce the number of calls to regcomp() to... eleven. (The precise method used may need a little rethinking for thread-safety, but the general principle, of reducing regcomp() calls via some variety of caching, appears to be essential.) --- src/fcstr.c | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) [Resent for the second time: if this doesn't get through I will consider the fontconfig list broken...] diff --git a/src/fcstr.c b/src/fcstr.c index 339a346..fa4560d 100644 --- a/src/fcstr.c +++ b/src/fcstr.c @@ -247,19 +247,32 @@ static FcBool _FcStrRegexCmp (const FcChar8 *s, const FcChar8 *regex, int cflags, int eflags) { int ret = -1; - regex_t reg; + static regex_t reg; + static FcChar8 *last; - if ((ret = regcomp (®, (const char *)regex, cflags)) != 0) + if (!regex || !last || FcStrCmp (regex, last) != 0) { - if (FcDebug () & FC_DBG_MATCHV) + if (last != NULL) { - char buf[512]; + regfree (®); + last = NULL; + } - regerror (ret, ®, buf, 512); - printf("Regexp compile error: %s\n", buf); + if ((ret = regcomp (®, (const char *)regex, cflags)) != 0) + { + if (FcDebug () & FC_DBG_MATCHV) + { + char buf[512]; + + regerror (ret, ®, buf, 512); + printf("Regexp compile error: %s\n", buf); + } + return FcFalse; } - return FcFalse; + FcFree (last); + last = FcStrdup (regex); } + ret = regexec (®, (const char *)s, 0, NULL, eflags); if (ret != 0) { @@ -271,7 +284,9 @@ _FcStrRegexCmp (const FcChar8 *s, const FcChar8 *regex, int cflags, int eflags) printf("Regexp exec error: %s\n", buf); } } - regfree (®); + + if (last == NULL) /* only on OOM */ + regfree (®); return ret == 0 ? FcTrue : FcFalse; } -- 1.8.2.1.162.ge277c5f _______________________________________________ Fontconfig mailing list Fontconfig@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/fontconfig