[Fontconfig] [PATCH] Cache most recent regcomp() call in _FcStrRegexCmp().
Behdad Esfahbod
behdad at behdad.org
Wed May 1 14:51:02 PDT 2013
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/
More information about the Fontconfig
mailing list