[cairo] [PATCH] scaled-font: fine-tune caching

Dmitri Vorobiev dmitri.vorobiev at movial.com
Mon Jun 14 06:40:39 PDT 2010


This patch implements the ideas outlined by Behdad Esfahbod in the following
mailing list message:

http://lists.cairographics.org/archives/cairo/2010-June/020065.html

Specifically, two things have been adjusted. First, the size of the look-up
table was reduced to 64. Second, cache codepath is now bypassed for strings
that are shorter than 16, not only for one-character strings. This allowed
us to reduce the LUT initialization overhead while still retaining the
advantage of caching for common-case string sizes.

We have experimented with different LUT sizes, and it came out that the size
of 64 is the best one in view of speed, at least for our language-neutral
benchmark, which generated random strings of printable ASCII characters.

Below is a table presenting benchmark results for different values of LUT
size:

===============================================================================
 Benchmark		| [1]	| [2]	| [3]	| [4]	| [5]	| [6]	| [7]
===============================================================================
8px text, 1 chars	| 0.41	| 0.41	| 0	| 0.41	| 0	| 0.41	| 0
8px text, 10 chars	| 2.13	| 2.21	| 3.76	| 2.19	| 2.82	| 2.09	| -1.88
8px text, 20 chars	| 2.97	| 3.04	| 2.36	| 3.01	| 1.35	| 2.98	| 0.34
12px text, 1 chars	| 0.94	| 0.94	| 0	| 0.95	| 1.06	| 0.94	| 0
12px text, 10 chars	| 4.73	| 4.89	| 3.38	| 4.9	| 3.59	| 4.82	| 1.9
12px text, 20 chars	| 6.32	| 6.42	| 1.58	| 6.46	| 2.22	| 6.32	| 0
16px text, 1 chars	| 1.75	| 1.76	| 0.57	| 1.77	| 1.14	| 1.76	| 0.57
16px text, 10 chars	| 8.13	| 8.45	| 3.94	| 8.43	| 3.69	| 8.44	| 3.81
16px text, 20 chars	| 10.41	| 10.69	| 2.69	| 10.64	| 2.21	| 10.65	| 2.31
24px text, 1 chars	| 3.3	| 3.3	| 0	| 3.32	| 0.61	| 3.3	| 0
24px text, 10 chars	| 14.68	| 14.97	| 1.98	| 14.97	| 1.98	| 14.87	| 1.29
24px text, 20 chars	| 17.93	| 18.01	| 0.45	| 18.06	| 0.73	| 17.81	| -0.67
96px text, 1 chars	| 23.65	| 23.38	| -1.14	| 23.74	| 0.38	| 23.65	| 0
96px text, 5 chars	| 50.52	| 51.34	| 1.62	| 51.48	| 1.9	| 51.41	| 1.76
96px text, 10 chars	| 57.5	| 58.11	| 1.06	| 58.27	| 1.34	| 58.04	| 0.94
===============================================================================

[1]: Git head, Mpix/s
[2]: {GLYPH_LUT_SIZE = 32, CACHING_THRESHOLD = 16}
[3]: Gain of {32, 16} w.r.t. Git head
[4]: {GLYPH_LUT_SIZE = 64, CACHING_THRESHOLD = 16}
[5]: Gain of {64, 16} w.r.t. Git head
[6]: {GLYPH_LUT_SIZE = 128, CACHING_THRESHOLD = 16}
[7]: Gain of {128, 16} w.r.t. Git head

The benchmark itself can be found from this mailing list message:

http://lists.cairographics.org/archives/cairo/2010-June/020064.html
---
 src/cairo-scaled-font.c |   61 ++++++++++++++++++++++++++++++++++------------
 1 files changed, 45 insertions(+), 16 deletions(-)

diff --git a/src/cairo-scaled-font.c b/src/cairo-scaled-font.c
index d70c555..418f90a 100644
--- a/src/cairo-scaled-font.c
+++ b/src/cairo-scaled-font.c
@@ -1570,9 +1570,9 @@ ZERO_EXTENTS:
 }
 slim_hidden_def (cairo_scaled_font_glyph_extents);
 
-#define GLYPH_LUT_SIZE 256
+#define GLYPH_LUT_SIZE 64
 static cairo_status_t
-cairo_scaled_font_text_to_glyphs_internal_multiple (cairo_scaled_font_t		 *scaled_font,
+cairo_scaled_font_text_to_glyphs_internal_cached (cairo_scaled_font_t		 *scaled_font,
 						    double			  x,
 						    double			  y,
 						    const char			 *utf8,
@@ -1644,7 +1644,7 @@ cairo_scaled_font_text_to_glyphs_internal_multiple (cairo_scaled_font_t		 *scale
 }
 
 static cairo_status_t
-cairo_scaled_font_text_to_glyphs_internal_single (cairo_scaled_font_t	 *scaled_font,
+cairo_scaled_font_text_to_glyphs_internal_uncached (cairo_scaled_font_t	 *scaled_font,
 						  double		  x,
 						  double		  y,
 						  const char		 *utf8,
@@ -1652,19 +1652,47 @@ cairo_scaled_font_text_to_glyphs_internal_single (cairo_scaled_font_t	 *scaled_f
 						  cairo_text_cluster_t	**clusters,
 						  int			  num_chars)
 {
-    uint32_t unicode;
-    int num_bytes;
+    const char *p;
+    int i;
 
-    glyphs[0].x = x;
-    glyphs[0].y = y;
+    p = utf8;
+    for (i = 0; i < num_chars; i++) {
+	unsigned long g;
+	int num_bytes;
+	uint32_t unicode;
+	cairo_scaled_glyph_t *scaled_glyph;
+	cairo_status_t status;
 
-    num_bytes = _cairo_utf8_get_char_validated (utf8, &unicode);
-    glyphs[0].index =
-	scaled_font->backend->ucs4_to_index (scaled_font, unicode);
+	num_bytes = _cairo_utf8_get_char_validated (p, &unicode);
+	p += num_bytes;
 
-    if (clusters) {
-	(*clusters)[0].num_bytes  = num_bytes;
-	(*clusters)[0].num_glyphs = 1;
+	glyphs[i].x = x;
+	glyphs[i].y = y;
+
+	g = scaled_font->backend->ucs4_to_index (scaled_font, unicode);
+
+	/*
+	 * No advance needed for a single character string. So, let's speed up
+	 * one-character strings by skipping glyph lookup.
+	 */
+	if (num_chars > 1) {
+	    status = _cairo_scaled_glyph_lookup (scaled_font,
+					     g,
+					     CAIRO_SCALED_GLYPH_INFO_METRICS,
+					     &scaled_glyph);
+	    if (unlikely (status))
+		return status;
+
+	    x += scaled_glyph->metrics.x_advance;
+	    y += scaled_glyph->metrics.y_advance;
+	}
+
+	glyphs[i].index = g;
+
+	if (clusters) {
+	    (*clusters)[i].num_bytes  = num_bytes;
+	    (*clusters)[i].num_glyphs = 1;
+	}
     }
 
     return CAIRO_STATUS_SUCCESS;
@@ -1805,6 +1833,7 @@ cairo_scaled_font_text_to_glyphs_internal_single (cairo_scaled_font_t	 *scaled_f
  *
  * Since: 1.8
  **/
+#define CACHING_THRESHOLD 16
 cairo_status_t
 cairo_scaled_font_text_to_glyphs (cairo_scaled_font_t   *scaled_font,
 				  double		 x,
@@ -1958,15 +1987,15 @@ cairo_scaled_font_text_to_glyphs (cairo_scaled_font_t   *scaled_font,
 	*num_clusters = num_chars;
     }
 
-    if (num_chars > 1)
-	status = cairo_scaled_font_text_to_glyphs_internal_multiple (scaled_font,
+    if (num_chars > CACHING_THRESHOLD)
+	status = cairo_scaled_font_text_to_glyphs_internal_cached (scaled_font,
 								     x, y,
 								     utf8,
 								     *glyphs,
 								     clusters,
 								     num_chars);
     else
-	status = cairo_scaled_font_text_to_glyphs_internal_single (scaled_font,
+	status = cairo_scaled_font_text_to_glyphs_internal_uncached (scaled_font,
 								   x, y,
 								   utf8,
 								   *glyphs,
-- 
1.6.3.3



More information about the cairo mailing list