]> git.wh0rd.org - fontconfig.git/commitdiff
Reduce number of allocations during FcSortWalk().
authorChris Wilson <chris@chris-wilson.co.uk>
Wed, 23 Apr 2008 08:07:28 +0000 (09:07 +0100)
committerBehdad Esfahbod <behdad@behdad.org>
Sat, 14 Feb 2009 00:54:00 +0000 (16:54 -0800)
The current behaviour of FcSortWalk() is to create a new FcCharSet on
each iteration that is the union of the previous iteration with the next
FcCharSet in the font set. This causes the existing FcCharSet to be
reproduced in its entirety and then allocates fresh leaves for the new
FcCharSet. In essence the number of allocations is quadratic wrt the
number of fonts required.

By introducing a new method for merging a new FcCharSet with an existing
one we can change the behaviour to be effectively linear with the number
of fonts - allocating no more leaves than necessary to cover all the
fonts in the set.

For example, profiling 'gedit UTF-8-demo.txt'
    Allocator     nAllocs     nBytes
Before:
    FcCharSetFindLeafCreate 62886     2012352
    FcCharSetPutLeaf        9361     11441108
After:
    FcCharSetFindLeafCreate 1940     62080
    FcCharSetPutLeaf        281     190336

The savings are even more significant for applications like firefox-3.0b5
which need to switch between large number of fonts.
Before:
    FcCharSetFindLeafCreate 4461192     142758144
    FcCharSetPutLeaf     1124536     451574172
After:
    FcCharSetFindLeafCreate 80359     2571488
    FcCharSetPutLeaf     18940     9720522

Out of interest, the next most frequent allocations are
    FcPatternObjectAddWithBinding 526029    10520580
    tt_face_load_eblc     42103     2529892

src/fccharset.c
src/fcint.h
src/fcmatch.c

index d42d78f3df06835c8c54302f3a4fb1e3c18b63ae..98ced278703dfd7f1d3a109cc2dc6ef94dca9e7f 100644 (file)
@@ -452,6 +452,68 @@ FcCharSetUnion (const FcCharSet *a, const FcCharSet *b)
     return FcCharSetOperate (a, b, FcCharSetUnionLeaf, FcTrue, FcTrue);
 }
 
+FcCharSet *
+FcCharSetMerge (FcCharSet *a, const FcCharSet *b)
+{
+    FcCharSet      *fcs;
+    FcCharSetIter    ai, bi;
+
+    if (a == NULL) {
+       return FcCharSetCopy ((FcCharSet *) b);
+    } else if (a->ref == FC_REF_CONSTANT) {
+       fcs = FcCharSetCreate ();
+       if (fcs == NULL)
+           return NULL;
+    } else
+       fcs = a;
+
+    FcCharSetIterStart (a, &ai);
+    FcCharSetIterStart (b, &bi);
+    while (ai.leaf || bi.leaf)
+    {
+       if (ai.ucs4 < bi.ucs4)
+       {
+           if (!FcCharSetAddLeaf (fcs, ai.ucs4, ai.leaf))
+               goto bail;
+
+           FcCharSetIterNext (a, &ai);
+       }
+       else if (bi.ucs4 < ai.ucs4)
+       {
+           if (!FcCharSetAddLeaf (fcs, bi.ucs4, bi.leaf))
+               goto bail;
+
+           FcCharSetIterNext (b, &bi);
+       }
+       else
+       {
+           FcCharLeaf  leaf;
+
+           if (FcCharSetUnionLeaf (&leaf, ai.leaf, bi.leaf))
+           {
+               if (!FcCharSetAddLeaf (fcs, ai.ucs4, &leaf))
+                   goto bail;
+           }
+
+           FcCharSetIterNext (a, &ai);
+           FcCharSetIterNext (b, &bi);
+       }
+    }
+
+    if (fcs != a)
+       FcCharSetDestroy (a);
+
+    return fcs;
+
+bail:
+    FcCharSetDestroy (fcs);
+
+    if (fcs != a)
+       FcCharSetDestroy (a);
+
+    return NULL;
+}
+
 static FcBool
 FcCharSetSubtractLeaf (FcCharLeaf *result,
                       const FcCharLeaf *al,
index 370dd7e80fc7acc0a5476a787f85c2c7c5478c6b..9a768c24adccee044c54b8dad6d9310df17f9bbd 100644 (file)
@@ -641,6 +641,9 @@ FcNameParseCharSet (FcChar8 *string);
 FcPrivate FcCharLeaf *
 FcCharSetFindLeafCreate (FcCharSet *fcs, FcChar32 ucs4);
 
+FcPrivate FcCharSet *
+FcCharSetMerge (FcCharSet *a, const FcCharSet *b);
+
 FcPrivate FcBool
 FcCharSetSerializeAlloc(FcSerialize *serialize, const FcCharSet *cs);
 
index b3ee5c12c66e1ef16feb7917071304fd179f40a4..77b49cf181a2b41b004e463c4aea8a77c3ca0b38 100644 (file)
@@ -601,16 +601,9 @@ FcSortWalk (FcSortNode **n, int nnode, FcFontSet *fs, FcCharSet **cs, FcBool tri
            {
                 if (trim || build_cs)
                 {
-                    if (*cs)
-                    {
-                        ncs = FcCharSetUnion (ncs, *cs);
-                        if (!ncs)
-                            return FcFalse;
-                        FcCharSetDestroy (*cs);
-                    }
-                    else
-                        ncs = FcCharSetCopy (ncs);
-                    *cs = ncs;
+                   *cs = FcCharSetMerge (*cs, ncs);
+                   if (*cs == NULL)
+                       return FcFalse;
                 }
 
                FcPatternReference (node->pattern);