From 31fad5846516ee1e6135bd35f0478b93928a3759 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Thu, 15 Jul 2021 18:39:41 +0200 Subject: [PATCH] url-mode: use shm_get_many() If we have lots of URLs, we use up a *lot* of SHM buffers (and thus pools). Each and every one is a single mmap(), of at least 4K. Since all URL labels are created and destroyed at the same time, it makes sense to use a single pool for all buffers. To do this, we must now do two passes; first one to generate the actual string (label content), and to calculate the label sizes. Then we use this information to allocate all SHM buffers at once, from the same pool. Finally, we iterate the URLs again, this time to actually render them. --- CHANGELOG.md | 1 + render.c | 92 ++++++++++++++++++++++++++++++++++++++++++++-------- url-mode.c | 3 -- 3 files changed, 79 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 67cbc32a..b66079fc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -61,6 +61,7 @@ scrollback search is active. * Scrollback indicator being incorrectly rendered when window size is very small. +* Reduced memory usage in URL mode. ### Security diff --git a/render.c b/render.c index 37766232..8e66bf00 100644 --- a/render.c +++ b/render.c @@ -2886,6 +2886,10 @@ render_urls(struct terminal *term) struct wl_window *win = term->window; xassert(tll_length(win->urls) > 0); + const int scale = term->scale; + const int x_margin = 2 * scale; + const int y_margin = 1 * scale; + /* Calculate view start, counted from the *current* scrollback start */ const int scrollback_end = (term->grid->offset + term->rows) & (term->grid->num_rows - 1); @@ -2897,6 +2901,44 @@ render_urls(struct terminal *term) const bool show_url = term->urls_show_uri_on_jump_label; + /* + * There can potentially be a lot of URLs. + * + * Since each URL is a separate sub-surface, and requires its own + * SHM buffer, we may be allocating a lot of buffers. + * + * SHM buffers normally have their own, private SHM buffer + * pool. Each pool is mmapped, and thus allocates *at least* + * 4K. Since URL labels are typically small, we end up using an + * excessive amount of both virtual and physical memory. + * + * For this reason, we instead use shm_get_many(), which uses a + * single, shared pool for all buffers. + * + * To be able to use it, we need to have all the *all* the buffer + * dimensions up front. + * + * Thus, the first iteration through the URLs do the heavy + * lifting: builds the label contents and calculates both its + * position and size. But instead of rendering the label + * immediately, we store the calculated data, and then do a second + * pass, where we first get all our buffers, and then render to + * them. + */ + + /* Positioning data + label contents */ + struct { + const struct wl_url *url; + wchar_t *text; + int x; + int y; + } info[tll_length(win->urls)]; + + /* For shm_get_many() */ + struct buffer_description shm_desc[tll_length(win->urls)]; + + size_t render_count = 0; + tll_foreach(win->urls, it) { const struct url *url = it->item.url; const wchar_t *key = url->key; @@ -2953,6 +2995,7 @@ render_urls(struct terminal *term) /* Maximum width of label, in pixels */ const int max_width = term->width - term->margins.left - term->margins.right - x; + const int max_cols = max_width / term->cell_width; const size_t key_len = wcslen(key); @@ -2990,10 +3033,6 @@ render_urls(struct terminal *term) * Do it in a way such that we don’t cut the label in the * middle of a double-width character. */ - const int scale = term->scale; - const int x_margin = 2 * scale; - const int y_margin = 1 * scale; - const int max_cols = max_width / term->cell_width; int cols = 0; @@ -3021,23 +3060,48 @@ render_urls(struct terminal *term) const int height = (2 * y_margin + term->cell_height + scale - 1) / scale * scale; - struct buffer *buf = shm_get_buffer( - term->wl->shm, width, height, shm_cookie_url(url), false, 1); + info[render_count].url = &it->item; + info[render_count].text = xwcsdup(label); + info[render_count].x = x; + info[render_count].y = y; + + shm_desc[render_count].width = width; + shm_desc[render_count].height = height; + shm_desc[render_count].cookie = shm_cookie_url(url); + + render_count++; + } + + struct buffer *bufs[render_count]; + shm_get_many(term->wl->shm, render_count, shm_desc, bufs, 1); + + uint32_t fg = term->conf->colors.use_custom.jump_label + ? term->conf->colors.jump_label.fg + : term->colors.table[0]; + uint32_t bg = term->conf->colors.use_custom.jump_label + ? term->conf->colors.jump_label.bg + : term->colors.table[3]; + + for (size_t i = 0; i < render_count; i++) { + struct wl_surface *surf = info[i].url->surf.surf; + struct wl_subsurface *sub_surf = info[i].url->surf.sub; + + const wchar_t *label = info[i].text; + const int x = info[i].x; + const int y = info[i].y; + + xassert(surf != NULL); + xassert(sub_surf != NULL); wl_subsurface_set_position( sub_surf, (term->margins.left + x) / term->scale, (term->margins.top + y) / term->scale); - uint32_t fg = term->conf->colors.use_custom.jump_label - ? term->conf->colors.jump_label.fg - : term->colors.table[0]; - uint32_t bg = term->conf->colors.use_custom.jump_label - ? term->conf->colors.jump_label.bg - : term->colors.table[3]; - render_osd( - term, surf, sub_surf, buf, label, fg, bg, x_margin, y_margin); + term, surf, sub_surf, bufs[i], label, fg, bg, x_margin, y_margin); + + free(info[i].text); } } diff --git a/url-mode.c b/url-mode.c index 524b8d1b..a802cc6c 100644 --- a/url-mode.c +++ b/url-mode.c @@ -14,7 +14,6 @@ #include "grid.h" #include "render.h" #include "selection.h" -#include "shm.h" #include "spawn.h" #include "terminal.h" #include "uri.h" @@ -738,9 +737,7 @@ urls_reset(struct terminal *term) if (term->window != NULL) { tll_foreach(term->window->urls, it) { - const struct url *url = it->item.url; wayl_win_subsurface_destroy(&it->item.surf); - shm_purge(term->wl->shm, shm_cookie_url(url)); tll_remove(term->window->urls, it); } }