[Fontconfig] [PATCH] Cache most recent regcomp() call in _FcStrRegexCmp().
Akira TAGOH
akira at tagoh.org
Tue May 7 02:14:39 PDT 2013
Okay, that makes sense. will do.
On Thu, May 2, 2013 at 6:51 AM, Behdad Esfahbod <behdad at behdad.org> wrote:
> On 13-05-01 05:29 PM, Nick Alcock wrote:
>>
>> 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).
>
> It's really strange that that function is called at all. Can you figure out
> why that is? Does your configuration have anything involving the "file" element?
>
> Akira, regardless, I think we should remove the Regex and replace it with Glob
> matching that is already in fccfg.c.
>
> I know you want to extend regex to other elements, but for files I think globs
> are just fine.
>
> behdad
>
>> 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;
>> }
>>
>
> --
> behdad
> http://behdad.org/
> _______________________________________________
> Fontconfig mailing list
> Fontconfig at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/fontconfig
--
Akira TAGOH
More information about the Fontconfig
mailing list