From 0902f6aee02d48e8268a916e5d17d2404bf226c5 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 16 Dec 2024 19:09:48 +0530 Subject: [PATCH] Use an arena allocator for the sprite position map --- kitty/arena.h | 80 +++++++++++++++++++++++++++++++++++++++++++++ kitty/fonts.c | 1 - kitty/glyph-cache.c | 66 ++++++++++++++++++++++--------------- kitty/glyph-cache.h | 14 +++++--- 4 files changed, 128 insertions(+), 33 deletions(-) create mode 100644 kitty/arena.h diff --git a/kitty/arena.h b/kitty/arena.h new file mode 100644 index 000000000..f69b0e9ea --- /dev/null +++ b/kitty/arena.h @@ -0,0 +1,80 @@ +/* + * arena.h + * Copyright (C) 2024 Kovid Goyal + * + * Distributed under terms of the GPL3 license. + */ + +#include "data-types.h" + +#ifndef MA_NAME +#error "Must define MA_NAME" +#endif + +#ifndef MA_BLOCK_SIZE +#define MA_BLOCK_SIZE 1u +#endif + +#define MA_CAT_( a, b ) a##b +#define MA_CAT( a, b ) MA_CAT_( a, b ) + +#ifndef MA_ARENA_NUM_BLOCKS +#define MA_ARENA_NUM_BLOCKS 4096u +#endif + +#define MA_TYPE_NAME MA_CAT(MA_NAME, MonotonicArena) +#define MA_BLOCK_TYPE_NAME MA_CAT(MA_NAME, MonotonicArenaBlock) + +typedef struct MA_BLOCK_TYPE_NAME { + void *buf; size_t used, capacity; +} MA_BLOCK_TYPE_NAME; + +typedef struct MA_TYPE_NAME { + MA_BLOCK_TYPE_NAME *blocks; + size_t count, capacity; +} MA_TYPE_NAME; + +static inline void +MA_CAT(MA_NAME, _free_all)(MA_TYPE_NAME *self) { + for (size_t i = 0; i < self->count; i++) free(self->blocks[i].buf); + free(self->blocks); + zero_at_ptr(self); +} + +static inline void* +MA_CAT(MA_NAME, _get)(MA_TYPE_NAME *self, size_t sz) { + size_t required_size = (sz / MA_BLOCK_SIZE) * MA_BLOCK_SIZE; + if (required_size < sz) required_size += MA_BLOCK_SIZE; + if (!self->count || (self->blocks[self->count-1].capacity - self->blocks[self->count-1].used) < required_size) { + size_t count = self->count + 1; + size_t block_sz = MAX(required_size, MA_ARENA_NUM_BLOCKS * MA_BLOCK_SIZE); + void *chunk = NULL; + if (MA_BLOCK_SIZE >= sizeof(void*) && MA_BLOCK_SIZE % sizeof(void*) == 0) { + if (posix_memalign(&chunk, MA_BLOCK_SIZE, block_sz) != 0) chunk = NULL; + } else chunk = malloc(block_sz); + if (!chunk) { return NULL; } +#ifdef MA_ZERO_MEMORY + memset(chunk, 0, block_sz); +#endif + if (count > self->capacity) { + size_t capacity = MAX(8u, 2 * self->capacity); + MA_BLOCK_TYPE_NAME *blocks = realloc(self->blocks, capacity * sizeof(MA_BLOCK_TYPE_NAME)); + if (!blocks) { free(chunk); return NULL; } + self->capacity = capacity; self->blocks = blocks; + } + self->blocks[count - 1] = (MA_BLOCK_TYPE_NAME){.capacity=block_sz, .buf=chunk}; + self->count = count; + } + char *ans = (char*)self->blocks[self->count-1].buf + self->blocks[self->count-1].used; + self->blocks[self->count-1].used += required_size; + return ans; +} + +#undef MA_NAME +#undef MA_BLOCK_SIZE +#undef MA_ARENA_NUM_BLOCKS +#undef MA_TYPE_NAME +#undef MA_BLOCK_TYPE_NAME +#undef MA_ZERO_MEMORY +#undef MA_CAT +#undef MA_CAT_ diff --git a/kitty/fonts.c b/kitty/fonts.c index 2e420f37f..eb0172079 100644 --- a/kitty/fonts.c +++ b/kitty/fonts.c @@ -483,7 +483,6 @@ free_font_groups(void) { free(font_groups); font_groups = NULL; font_groups_capacity = 0; num_font_groups = 0; } - free_glyph_cache_global_resources(); } static void diff --git a/kitty/glyph-cache.c b/kitty/glyph-cache.c index 8d557d208..c95301312 100644 --- a/kitty/glyph-cache.c +++ b/kitty/glyph-cache.c @@ -6,7 +6,6 @@ */ #include "glyph-cache.h" - typedef struct SpritePosKey { glyph_index ligature_index, count, cell_count, keysz_in_bytes; uint8_t scale, subscale, multicell_y, vertical_align; @@ -21,9 +20,17 @@ static uint64_t sprite_pos_map_hash(KEY_TY key); #define HASH_FN sprite_pos_map_hash static bool sprite_pos_map_cmpr(KEY_TY a, KEY_TY b); #define CMPR_FN sprite_pos_map_cmpr -static void free_const(const void* x) { free((void*)x); } -#define KEY_DTOR_FN free_const -#define VAL_DTOR_FN free_const +#define MA_NAME Key +#define MA_BLOCK_SIZE 16u +static_assert(MA_BLOCK_SIZE > sizeof(SpritePosKey) + 2, "increase arena block size"); +#define MA_ARENA_NUM_BLOCKS (2048u / MA_BLOCK_SIZE) +#include "arena.h" +#define MA_NAME Val +#define MA_BLOCK_SIZE sizeof(VAL_TY) +#define MA_ARENA_NUM_BLOCKS (2048u / MA_BLOCK_SIZE) +#define MA_ZERO_MEMORY +#include "arena.h" + #include "kitty-verstable.h" @@ -38,20 +45,17 @@ sprite_pos_map_cmpr(const SpritePosKey *a, const SpritePosKey *b) { } -static SpritePosKey *scratch = NULL; -static size_t scratch_key_capacity = 0; - - -void -free_glyph_cache_global_resources(void) { - free(scratch); scratch = NULL; scratch_key_capacity = 0; -} - +typedef struct HashTable { + sprite_pos_map table; + KeyMonotonicArena keys; + ValMonotonicArena vals; + struct { SpritePosKey *key; size_t capacity; } scratch; +} HashTable; SPRITE_POSITION_MAP_HANDLE create_sprite_position_hash_table(void) { - sprite_pos_map *ans = calloc(1, sizeof(sprite_pos_map)); - if (ans) vt_init(ans); + HashTable *ans = calloc(1, sizeof(HashTable)); + if (ans) vt_init(&ans->table); return (SPRITE_POSITION_MAP_HANDLE)ans; } @@ -60,15 +64,17 @@ find_or_create_sprite_position( SPRITE_POSITION_MAP_HANDLE map_, glyph_index *glyphs, glyph_index count, glyph_index ligature_index, glyph_index cell_count, uint8_t scale, uint8_t subscale, uint8_t multicell_y, uint8_t vertical_align, bool *created ) { - sprite_pos_map *map = (sprite_pos_map*)map_; + HashTable *ht = (HashTable*)map_; + sprite_pos_map *map = &ht->table; const size_t keysz_in_bytes = count * sizeof(glyph_index); - if (!scratch || keysz_in_bytes > scratch_key_capacity) { - const size_t newsz = sizeof(scratch[0]) + keysz_in_bytes + 64; - scratch = realloc(scratch, newsz); - if (!scratch) { scratch_key_capacity = 0; return NULL; } - scratch_key_capacity = newsz - sizeof(scratch[0]); - memset(scratch, 0, newsz); + if (!ht->scratch.key || keysz_in_bytes > ht->scratch.capacity) { + const size_t newsz = sizeof(ht->scratch.key[0]) + keysz_in_bytes + 64; + ht->scratch.key = realloc(ht->scratch.key, newsz); + if (!ht->scratch.key) { ht->scratch.capacity = 0; return NULL; } + ht->scratch.capacity = newsz - sizeof(ht->scratch.key[0]); + memset(ht->scratch.key, 0, newsz); } +#define scratch ht->scratch.key scratch->keysz_in_bytes = keysz_in_bytes; scratch->count = count; scratch->ligature_index = ligature_index; scratch->cell_count = cell_count; scratch->scale = scale; scratch->subscale = subscale; scratch->multicell_y = multicell_y; scratch->vertical_align = vertical_align; @@ -76,20 +82,26 @@ find_or_create_sprite_position( sprite_pos_map_itr n = vt_get(map, scratch); if (!vt_is_end(n)) { *created = false; return n.data->val; } - SpritePosition *val = calloc(1, sizeof(SpritePosition)); - SpritePosKey *key = malloc(sizeof(SpritePosKey) + scratch->keysz_in_bytes); - if (!val || !key) return NULL; + SpritePosKey *key = Key_get(&ht->keys, sizeof(SpritePosKey) + scratch->keysz_in_bytes); + if (!key) return NULL; + SpritePosition *val = Val_get(&ht->vals, sizeof(SpritePosition)); + if (!val) return NULL; memcpy(key, scratch, sizeof(scratch[0]) + scratch->keysz_in_bytes); if (vt_is_end(vt_insert(map, key, val))) return NULL; *created = true; return val; +#undef scratch } void free_sprite_position_hash_table(SPRITE_POSITION_MAP_HANDLE *map) { - sprite_pos_map **mapref = (sprite_pos_map**)map; + HashTable **mapref = (HashTable**)map; if (*mapref) { - vt_cleanup(*mapref); free(*mapref); *mapref = NULL; + vt_cleanup(&mapref[0]->table); + Key_free_all(&mapref[0]->keys); + Val_free_all(&mapref[0]->vals); + free(mapref[0]->scratch.key); + free(mapref[0]); mapref[0] = NULL; } } diff --git a/kitty/glyph-cache.h b/kitty/glyph-cache.h index 4a54dc559..f0eef8976 100644 --- a/kitty/glyph-cache.h +++ b/kitty/glyph-cache.h @@ -8,12 +8,16 @@ #include "data-types.h" -void free_glyph_cache_global_resources(void); - -typedef struct SpritePosition { - bool rendered, colored; - sprite_index idx; +typedef union SpritePosition { + struct { + sprite_index idx : sizeof(sprite_index) * 8; + bool rendered : 1; + bool colored : 1; + uint32_t : 30; + }; + uint64_t val; } SpritePosition; +static_assert(sizeof(SpritePosition) == sizeof(uint64_t), "Fix ordering of SpritePosition"); typedef struct {int x;} *SPRITE_POSITION_MAP_HANDLE;