Application startup performance

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi,

Profiling application startup performance, I noticed that libfontconfig accounted for a significant portion of the startup time, approx. 30% for a rather simple application like gedit.

My font directories, especially /usr/share/fonts/100dpi and /usr/share/fonts/75dpi contain each 1900 files after a default gentoo installation of X.org, residing on local storage.

I found two rather small optimizations to improve the startup time:
- assuming that readdir() will never return duplicate filenames within the very same directory. Hence FcStrSetAdd() can spare the duplicate check, which currently runs FcStrCmp() along a growing linear list of filenames. In fact, I have not found any duplicate string being entered to a FcStrSet at all for my system configuration. - _FcStrSetAppend() to not reallocate and memcmp element by element, but doing so for e. g. 64 elements at a time.

I've verified startup time using
- time gedit (average over 9 runs)
- callgrind and cachegrind
- oprofile


Applied optimizations:
- skip duplicate check in FcStrSetAppend for values originating from readdir() - grow FcStrSet in 64-element bulks for local FcStrSets (FcConfig layout unaltered)

Starting gedit is measured to

                        Unoptimized     Optimized
user[s]                         0,806         0,579
sys[s]                          0,062         0,062
Total Instr Fetch Cost: 1.658.683.750   895.069.820
Cachegrind D Refs:        513.917.619   312.000.436
Cachegrind Dl Misses:       8.605.632     4.954.639


The patch is attached. Comments and questions are welcome.

Thanks,
Patrick

--
--
Patrick Haller (patrick.haller@xxxxxxxxxxxxxxxxx)

>From 914760ca92a0335cd1ce9685249c664bccbd87fd Mon Sep 17 00:00:00 2001
From: Patrick Haller <patrick.haller@xxxxxxxxxxxxxxxxx>
Date: Sat, 9 Jan 2016 03:06:31 +0100
Subject: [PATCH] Optimizations in FcStrSet

Applied optimizations:
- skip duplicate check in FcStrSetAppend for values originating from readdir()
- grow FcStrSet in 64-element bulks for local FcStrSets (FcConfig layout unaltered)

Starting gedit is measured to

                        Unoptimized     Optimized
user[s]                         0,806         0,579
sys[s]                          0,062         0,062
Total Instr Fetch Cost: 1.658.683.750   895.069.820
Cachegrind D Refs:        513.917.619   312.000.436
Cachegrind Dl Misses:       8.605.632     4.954.639
---
 src/fccache.c |  2 +-
 src/fccfg.c   |  4 ++--
 src/fcdir.c   |  6 +++---
 src/fcint.h   | 11 +++++++++++
 src/fcstr.c   | 47 +++++++++++++++++++++++++++++++++--------------
 src/fcxml.c   |  2 +-
 6 files changed, 51 insertions(+), 21 deletions(-)

diff --git a/src/fccache.c b/src/fccache.c
index f2b09cb..b681a5e 100644
--- a/src/fccache.c
+++ b/src/fccache.c
@@ -590,7 +590,7 @@ FcCacheTimeValid (FcConfig *config, FcCache *cache, struct stat *dir_stat)
 static FcBool
 FcCacheDirsValid (FcConfig *config, FcCache *cache)
 {
-    FcStrSet *dirs = FcStrSetCreate ();
+    FcStrSet *dirs = FcStrSetCreateEx (FCSS_GROW_BY_64);
     FcBool ret = FcFalse;
     const FcChar8 *sysroot = FcConfigGetSysRoot (config);
     FcChar8 *d;
diff --git a/src/fccfg.c b/src/fccfg.c
index 5f8f644..9f8ee7c 100644
--- a/src/fccfg.c
+++ b/src/fccfg.c
@@ -2205,7 +2205,7 @@ FcConfigAppFontAddFile (FcConfig    *config,
 	    return FcFalse;
     }
 
-    subdirs = FcStrSetCreate ();
+    subdirs = FcStrSetCreateEx (FCSS_GROW_BY_64);
     if (!subdirs)
 	return FcFalse;
 
@@ -2252,7 +2252,7 @@ FcConfigAppFontAddDir (FcConfig	    *config,
 	    return FcFalse;
     }
 
-    dirs = FcStrSetCreate ();
+    dirs = FcStrSetCreateEx (FCSS_GROW_BY_64);
     if (!dirs)
 	return FcFalse;
 
diff --git a/src/fcdir.c b/src/fcdir.c
index f4807dd..a046eae 100644
--- a/src/fcdir.c
+++ b/src/fcdir.c
@@ -248,7 +248,7 @@ FcDirScanConfig (FcFontSet	*set,
 	goto bail;
     }
 
-    files = FcStrSetCreate ();
+    files = FcStrSetCreateEx (FCSS_ALLOW_DUPLICATES | FCSS_GROW_BY_64);
     if (!files)
     {
 	ret = FcFalse;
@@ -349,7 +349,7 @@ FcDirCacheScan (const FcChar8 *dir, FcConfig *config)
     if (!set)
 	goto bail;
 
-    dirs = FcStrSetCreate ();
+    dirs = FcStrSetCreateEx (FCSS_GROW_BY_64);
     if (!dirs)
 	goto bail1;
 
@@ -404,7 +404,7 @@ FcDirCacheRescan (const FcChar8 *dir, FcConfig *config)
 	d = FcStrdup (dir);
     if (FcStatChecksum (d, &dir_stat) < 0)
 	goto bail;
-    dirs = FcStrSetCreate ();
+    dirs = FcStrSetCreateEx (FCSS_GROW_BY_64);
     if (!dirs)
 	goto bail;
 
diff --git a/src/fcint.h b/src/fcint.h
index 8fa01d6..ee6cc99 100644
--- a/src/fcint.h
+++ b/src/fcint.h
@@ -339,11 +339,19 @@ struct _FcCharSet {
 					       FcCharLeaf))
 #define FcCharSetNumbers(c)	FcOffsetMember(c,numbers_offset,FcChar16)
 
+#define FCSS_DEFAULT            0 /* default behavior */
+#define FCSS_ALLOW_DUPLICATES   1 /* allows for duplicate strings in the set */
+#define FCSS_GROW_BY_64         2 /* grows buffer by 64 elements instead of 1 */
+
+#define FcStrSetHasControlBit(s,c)  (s->control & c)
+#define FcStrSetHasControlBits(s,c) ( (c) == (s->control & (c)) )
+
 struct _FcStrSet {
     FcRef	    ref;	/* reference count */
     int		    num;
     int		    size;
     FcChar8	    **strs;
+    unsigned int    control;    /* control bits for set behavior */
 };
 
 struct _FcStrList {
@@ -1113,6 +1121,9 @@ FcPrivate FcBool
 FcIsFsMtimeBroken (const FcChar8 *dir);
 
 /* fcstr.c */
+FcPrivate FcStrSet *
+FcStrSetCreateEx (unsigned int control);
+
 FcPrivate FcBool
 FcStrSetAddLangs (FcStrSet *strs, const char *languages);
 
diff --git a/src/fcstr.c b/src/fcstr.c
index 29a577d..b65492d 100644
--- a/src/fcstr.c
+++ b/src/fcstr.c
@@ -880,7 +880,7 @@ FcStrBuildFilename (const FcChar8 *path,
     if (!path)
 	return NULL;
 
-    sset = FcStrSetCreate ();
+    sset = FcStrSetCreateEx (FCSS_ALLOW_DUPLICATES | FCSS_GROW_BY_64);
     if (!sset)
 	return NULL;
 
@@ -1130,6 +1130,12 @@ FcStrCanonFilename (const FcChar8 *s)
 FcStrSet *
 FcStrSetCreate (void)
 {
+    return FcStrSetCreateEx (FCSS_DEFAULT);
+}
+
+FcStrSet *
+FcStrSetCreateEx (unsigned int control)
+{
     FcStrSet	*set = malloc (sizeof (FcStrSet));
     if (!set)
 	return 0;
@@ -1137,29 +1143,42 @@ FcStrSetCreate (void)
     set->num = 0;
     set->size = 0;
     set->strs = 0;
+    set->control = control;
     return set;
 }
 
 static FcBool
+_FcStrSetGrow (FcStrSet *set, int growElements)
+{
+    /* accommodate an additional NULL entry at the end of the array */
+    FcChar8 **strs = malloc ((set->size + growElements + 1) * sizeof (FcChar8 *));
+    if (!strs)
+        return FcFalse;
+    if (set->num)
+        memcpy (strs, set->strs, set->num * sizeof (FcChar8 *));
+    if (set->strs)
+        free (set->strs);
+    set->size = set->size + growElements;
+    set->strs = strs;
+    return FcTrue;
+}
+
+static FcBool
 _FcStrSetAppend (FcStrSet *set, FcChar8 *s)
 {
-    if (FcStrSetMember (set, s))
+    if (!FcStrSetHasControlBit (set, FCSS_ALLOW_DUPLICATES))
     {
-	FcStrFree (s);
-	return FcTrue;
+        if (FcStrSetMember (set, s))
+        {
+            FcStrFree (s);
+            return FcTrue;
+        }
     }
     if (set->num == set->size)
     {
-	FcChar8	**strs = malloc ((set->size + 2) * sizeof (FcChar8 *));
-
-	if (!strs)
-	    return FcFalse;
-	if (set->num)
-	    memcpy (strs, set->strs, set->num * sizeof (FcChar8 *));
-	if (set->strs)
-	    free (set->strs);
-	set->size = set->size + 1;
-	set->strs = strs;
+        int growElements = FcStrSetHasControlBit (set, FCSS_GROW_BY_64) ? 64 : 1;
+        if (!_FcStrSetGrow(set, growElements))
+            return FcFalse;
     }
     set->strs[set->num++] = s;
     set->strs[set->num] = 0;
diff --git a/src/fcxml.c b/src/fcxml.c
index 52a0668..cd8fff1 100644
--- a/src/fcxml.c
+++ b/src/fcxml.c
@@ -3158,7 +3158,7 @@ FcConfigParseAndLoadDir (FcConfig	*config,
     strcat ((char *) file, "/");
     base = file + strlen ((char *) file);
 
-    files = FcStrSetCreate ();
+    files = FcStrSetCreateEx (FCSS_GROW_BY_64);
     if (!files)
     {
 	ret = FcFalse;
-- 
2.7.0

_______________________________________________
Fontconfig mailing list
Fontconfig@xxxxxxxxxxxxxxxxxxxxx
http://lists.freedesktop.org/mailman/listinfo/fontconfig

[Index of Archives]     [Fedora Fonts]     [Fedora Users]     [Fedora Cloud]     [Kernel]     [Fedora Packaging]     [Fedora Desktop]     [PAM]     [Gimp Graphics Editor]     [Yosemite News]

  Powered by Linux