Preferentially evict transient images before non-transient ones under storage pressure
Some checks failed
CI / Linux (python=3.13 cc=clang sanitize=1) (push) Has been cancelled
CI / Linux (python=3.11 cc=gcc sanitize=0) (push) Has been cancelled
CI / Linux (python=3.12 cc=gcc sanitize=1) (push) Has been cancelled
CI / Linux package (push) Has been cancelled
CI / Bundle test (macos-latest) (push) Has been cancelled
CI / Bundle test (ubuntu-latest) (push) Has been cancelled
CI / macOS Brew (push) Has been cancelled
CI / Test ./dev.sh and benchmark (push) Has been cancelled
Some checks failed
CI / Linux (python=3.13 cc=clang sanitize=1) (push) Has been cancelled
CI / Linux (python=3.11 cc=gcc sanitize=0) (push) Has been cancelled
CI / Linux (python=3.12 cc=gcc sanitize=1) (push) Has been cancelled
CI / Linux package (push) Has been cancelled
CI / Bundle test (macos-latest) (push) Has been cancelled
CI / Bundle test (ubuntu-latest) (push) Has been cancelled
CI / macOS Brew (push) Has been cancelled
CI / Test ./dev.sh and benchmark (push) Has been cancelled
This commit is contained in:
parent
d994a47fc8
commit
051a5b72e0
2 changed files with 25 additions and 3 deletions
|
|
@ -287,9 +287,12 @@ apply_storage_quota(GraphicsManager *self, size_t storage_limit, id_type current
|
||||||
if (!sorted) fatal("Out of memory");
|
if (!sorted) fatal("Out of memory");
|
||||||
Image **p = sorted;
|
Image **p = sorted;
|
||||||
iter_images(self) { *p++ = i.data->val; }
|
iter_images(self) { *p++ = i.data->val; }
|
||||||
#define oldest_img_first(a, b) ((*a)->atime < (*b)->atime)
|
#define transient_or_older_first(a, b) ( \
|
||||||
QSORT(Image*, sorted, num_images, oldest_img_first);
|
(*a)->root_frame.transient != (*b)->root_frame.transient ? \
|
||||||
#undef oldest_img_first
|
(*a)->root_frame.transient > (*b)->root_frame.transient : \
|
||||||
|
(*a)->atime < (*b)->atime)
|
||||||
|
QSORT(Image*, sorted, num_images, transient_or_older_first);
|
||||||
|
#undef transient_or_older_first
|
||||||
|
|
||||||
for (p = sorted; self->used_storage > storage_limit && num_images; p++, num_images--) remove_image(self, *p);
|
for (p = sorted; self->used_storage > storage_limit && num_images; p++, num_images--) remove_image(self, *p);
|
||||||
if (!num_images || !vt_size(&self->images_by_internal_id)) self->used_storage = 0; // sanity check
|
if (!num_images || !vt_size(&self->images_by_internal_id)) self->used_storage = 0; // sanity check
|
||||||
|
|
|
||||||
|
|
@ -1319,6 +1319,25 @@ def test_graphics_quota_enforcement(self):
|
||||||
self.ae(g.image_count, 0)
|
self.ae(g.image_count, 0)
|
||||||
self.assertEqual(g.disk_cache.total_size, 0)
|
self.assertEqual(g.disk_cache.total_size, 0)
|
||||||
|
|
||||||
|
def test_transient_image_preferential_eviction(self):
|
||||||
|
# Transient images should be evicted before non-transient ones when
|
||||||
|
# the storage quota is exceeded, regardless of insertion order.
|
||||||
|
s = self.create_screen()
|
||||||
|
g = s.grman
|
||||||
|
g.storage_limit = 36 * 2
|
||||||
|
li = make_send_command(s)
|
||||||
|
# Load a non-transient image first (older atime) and a transient image second.
|
||||||
|
self.assertEqual(li(a='T', i=1).code, 'OK')
|
||||||
|
self.assertEqual(li(a='T', i=2, N=1).code, 'OK')
|
||||||
|
self.assertEqual(g.image_count, 2)
|
||||||
|
# Adding a third image triggers the quota; the transient image (i=2) must be
|
||||||
|
# evicted first even though the non-transient image (i=1) is older.
|
||||||
|
self.assertEqual(li(a='T', i=3).code, 'OK')
|
||||||
|
self.assertEqual(g.image_count, 2)
|
||||||
|
self.assertIsNone(g.image_for_client_id(2), 'transient image should have been evicted')
|
||||||
|
self.assertIsNotNone(g.image_for_client_id(1), 'non-transient image should survive')
|
||||||
|
self.assertIsNotNone(g.image_for_client_id(3), 'newly added image should survive')
|
||||||
|
|
||||||
@unittest.skipIf(Image is None, 'PIL not available, skipping PNG tests')
|
@unittest.skipIf(Image is None, 'PIL not available, skipping PNG tests')
|
||||||
def test_cached_rgba_conversion(self):
|
def test_cached_rgba_conversion(self):
|
||||||
from kitty.render_cache import ImageRenderCacheForTesting
|
from kitty.render_cache import ImageRenderCacheForTesting
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue