scaled-font: fine-tune caching

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
This commit is contained in:
Dmitri Vorobiev 2010-06-14 16:40:39 +03:00 committed by Chris Wilson
parent 505a0456d2
commit 4a0bd91ff7

View file

@ -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,