From 4a9d61f75baf66c6c6fed350477d2a48ff3814e6 Mon Sep 17 00:00:00 2001 From: John Mark Bell Date: Sat, 29 Aug 2009 23:38:32 +0000 Subject: 1) Allocate css_style bytecode in 16 byte chunks 2) Cache unused css_style objects with chunks of size 16, 32, 48, and 64 bytes The above should reduce heap churn somewhat. Further improvements are possible: 1) Make the property parsers write the parsed values direct into the output bytecode, instead of into a temporary object which is then merged into the output. 2) Perform similar caching for css_rule and selector objects. 3) Shrink-wrap finalised output styles rather than leaving them oversized. 4) Perform measurement to determine the optimal chunk sizes (power-of-2 makes maths simple and 16 is plucked from thin air) and cache bucket count/sizes. svn path=/trunk/libcss/; revision=9502 --- src/stylesheet.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++--------- src/stylesheet.h | 3 ++- src/utils/utils.h | 4 +++ 3 files changed, 72 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/stylesheet.c b/src/stylesheet.c index 9afd5cc..e6d8ea7 100644 --- a/src/stylesheet.c +++ b/src/stylesheet.c @@ -162,6 +162,7 @@ css_error css_stylesheet_create(css_language_level level, */ css_error css_stylesheet_destroy(css_stylesheet *sheet) { + uint32_t bucket; css_rule *r, *s; if (sheet == NULL) @@ -185,6 +186,17 @@ css_error css_stylesheet_destroy(css_stylesheet *sheet) css_selector_hash_destroy(sheet->selectors); + /* Release cached free styles */ + for (bucket = 0; bucket != N_ELEMENTS(sheet->free_styles); bucket++) { + while (sheet->free_styles[bucket] != NULL) { + css_style *s = sheet->free_styles[bucket]; + + sheet->free_styles[bucket] = s->bytecode; + + sheet->alloc(s, 0, sheet->pw); + } + } + /* These two may have been destroyed when parsing completed */ if (sheet->parser_frontend != NULL) css_language_destroy(sheet->parser_frontend); @@ -228,6 +240,7 @@ css_error css_stylesheet_append_data(css_stylesheet *sheet, css_error css_stylesheet_data_done(css_stylesheet *sheet) { const css_rule *r; + uint32_t bucket; css_error error; if (sheet == NULL) @@ -247,6 +260,17 @@ css_error css_stylesheet_data_done(css_stylesheet *sheet) sheet->parser_frontend = NULL; sheet->parser = NULL; + /* Release cached free styles */ + for (bucket = 0; bucket != N_ELEMENTS(sheet->free_styles); bucket++) { + while (sheet->free_styles[bucket] != NULL) { + css_style *s = sheet->free_styles[bucket]; + + sheet->free_styles[bucket] = s->bytecode; + + sheet->alloc(s, 0, sheet->pw); + } + } + /* Determine if there are any pending imports */ for (r = sheet->rule_list; r != NULL; r = r->next) { const css_rule_import *i = (const css_rule_import *) r; @@ -565,13 +589,21 @@ css_error css_stylesheet_style_create(css_stylesheet *sheet, uint32_t len, css_style **style) { css_style *s; + const uint32_t alloclen = ((len + 15) & ~15); + const uint32_t bucket = (alloclen / N_ELEMENTS(sheet->free_styles)) - 1; if (sheet == NULL || len == 0 || style == NULL) return CSS_BADPARM; - s = sheet->alloc(NULL, sizeof(css_style) + len, sheet->pw); - if (s == NULL) - return CSS_NOMEM; + if (bucket < N_ELEMENTS(sheet->free_styles) && + sheet->free_styles[bucket] != NULL) { + s = sheet->free_styles[bucket]; + sheet->free_styles[bucket] = s->bytecode; + } else { + s = sheet->alloc(NULL, sizeof(css_style) + alloclen, sheet->pw); + if (s == NULL) + return CSS_NOMEM; + } /* DIY variable-sized data member */ s->bytecode = ((uint8_t *) s + sizeof(css_style)); @@ -593,10 +625,20 @@ css_error css_stylesheet_style_create(css_stylesheet *sheet, uint32_t len, */ css_error css_stylesheet_style_destroy(css_stylesheet *sheet, css_style *style) { + uint32_t alloclen, bucket; + if (sheet == NULL || style == NULL) return CSS_BADPARM; - sheet->alloc(style, 0, sheet->pw); + alloclen = ((style->length + 15) & ~15); + bucket = (alloclen / N_ELEMENTS(sheet->free_styles)) - 1; + + if (bucket < N_ELEMENTS(sheet->free_styles)) { + style->bytecode = sheet->free_styles[bucket]; + sheet->free_styles[bucket] = style; + } else { + sheet->alloc(style, 0, sheet->pw); + } return CSS_OK; } @@ -1067,20 +1109,31 @@ css_error css_stylesheet_rule_append_style(css_stylesheet *sheet, if (cur != NULL) { /* Already have a style, so append to the end of the bytecode */ - css_style *temp = sheet->alloc(cur, - sizeof(css_style) + cur->length + style->length, - sheet->pw); - if (temp == NULL) - return CSS_NOMEM; + const uint32_t reqlen = cur->length + style->length; + const uint32_t curlen = ((cur->length + 15) & ~15); + + if (curlen < reqlen) { + css_style *temp; + css_error error; - /* Ensure bytecode pointer is correct */ - temp->bytecode = ((uint8_t *) temp + sizeof(css_style)); + error = css_stylesheet_style_create(sheet, + reqlen, &temp); + if (error != CSS_OK) + return error; + + memcpy((uint8_t *) temp->bytecode, cur->bytecode, + cur->length); + temp->length = cur->length; + + css_stylesheet_style_destroy(sheet, cur); + + cur = temp; + } /** \todo Can we optimise the bytecode here? */ - memcpy((uint8_t *) temp->bytecode + temp->length, + memcpy((uint8_t *) cur->bytecode + cur->length, style->bytecode, style->length); - cur = temp; cur->length += style->length; /* Add this to the sheet's size */ diff --git a/src/stylesheet.h b/src/stylesheet.h index 1769bff..df095d9 100644 --- a/src/stylesheet.h +++ b/src/stylesheet.h @@ -24,7 +24,6 @@ typedef struct css_rule css_rule; typedef struct css_selector css_selector; -/** \todo would a parserutils_buffer be better here? */ typedef struct css_style { uint32_t length; /**< Length, in bytes, of bytecode */ void *bytecode; /**< Pointer to bytecode */ @@ -177,6 +176,8 @@ struct css_stylesheet { size_t size; /**< Size, in bytes */ + css_style *free_styles[4]; /**< Free styles: 16B buckets */ + css_url_resolution_fn resolve; /**< URL resolution function */ void *resolve_pw; /**< Private word */ diff --git a/src/utils/utils.h b/src/utils/utils.h index 1c380f8..26c9a08 100644 --- a/src/utils/utils.h +++ b/src/utils/utils.h @@ -30,6 +30,10 @@ #define UNUSED(x) ((x)=(x)) #endif +#ifndef N_ELEMENTS +#define N_ELEMENTS(x) (sizeof((x)) / sizeof((x)[0])) +#endif + css_fixed number_from_lwc_string(lwc_string *string, bool int_only, size_t *consumed); -- cgit v1.2.3