Skip to content

Commit

Permalink
Merge branch 'main' of [email protected]:jonathanhogg/flitter.git
Browse files Browse the repository at this point in the history
  • Loading branch information
jonathanhogg committed Jan 21, 2025
2 parents 9e91e7c + f2433a7 commit 25ea2c7
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 29 deletions.
5 changes: 4 additions & 1 deletion src/flitter/engine/control.py
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,10 @@ async def run(self):
logger.trace("State dictionary size: {} keys", len(self.state))
if run_program is not None and run_program.stack is not None:
logger.trace("VM stack size: {:d}", run_program.stack.size)
Model.flush_caches()
if Model.flush_caches():
count = gc.collect(2)
if count:
logger.trace("Collected {} objects (full collection)", count)
else:
gc.collect(0)

Expand Down
2 changes: 1 addition & 1 deletion src/flitter/model.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -541,7 +541,7 @@ cdef class Vector:
y = double_long(f=self.numbers[i]).l
_hash = HASH_UPDATE(_hash, y)
if not floor_floats:
self._hash = <int64_t>_hash
self._hash = _hash
return <int64_t>_hash

cpdef object match(self, int64_t n=0, type t=None, default=None):
Expand Down
2 changes: 1 addition & 1 deletion src/flitter/render/window/models.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ cdef int64_t DefaultSegments
cdef class Model:
cdef readonly uint64_t id
cdef readonly double touch_timestamp
cdef readonly double cache_timestamp
cdef readonly dict cache
cdef readonly set dependents
cdef readonly list buffer_caches

cpdef bint uncache(self, bint buffers)
cpdef void unload(self)
cpdef void check_for_changes(self)
cpdef bint is_smooth(self)
Expand Down
62 changes: 36 additions & 26 deletions src/flitter/render/window/models.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -47,27 +47,37 @@ cdef uint64_t MIX = HASH_UPDATE(HASH_START, HASH_STRING('mix'))

cdef class Model:
@staticmethod
def flush_caches(double min_age=300, int64_t min_size=2000):
def flush_caches(double max_age=300, int64_t max_size=2500):
cdef double now = perf_counter()
cdef double cutoff = now - min_age
cdef double cutoff = now - max_age
cdef Model model
cdef int64_t unload_count = 0
cdef int64_t count=len(ModelCache), unload_count=0, uncache_count=0
cdef list unloaded = []
while len(ModelCache) > min_size:
cdef bint aggressive = False
while True:
for model in ModelCache.values():
if model.touch_timestamp == 0:
model.touch_timestamp = now
if model.touch_timestamp <= cutoff and not model.dependents:
elif model.uncache(False):
uncache_count += 1
if (model.touch_timestamp <= cutoff or aggressive and model.touch_timestamp < now and count > max_size) and model.dependents is None:
unloaded.append(model)
count -= 1
if not unloaded:
break
if count > max_size and not aggressive:
aggressive = True
else:
break
while unloaded:
model = unloaded.pop()
del ModelCache[model.id]
model.unload()
del ModelCache[model.id]
unload_count += 1
if uncache_count:
logger.trace("Cleared object cache for {} models", uncache_count)
if unload_count:
logger.trace("Unloaded {} models from cache, {} remaining", unload_count, len(ModelCache))
return uncache_count + unload_count

@staticmethod
def by_id(uint64_t id):
Expand Down Expand Up @@ -102,14 +112,24 @@ cdef class Model:
raise NotImplementedError()

cpdef void unload(self):
assert not self.dependents
self.dependents = None
self.cache = None
if self.buffer_caches is not None:
self.uncache(True)

cpdef bint uncache(self, bint all):
cdef bint cleaned = False
if self.cache is not None:
if all or 'bounds' not in self.cache:
self.cache = None
cleaned = True
elif len(self.cache) > 1:
self.cache = {'bounds': self.cache['bounds']}
cleaned = True
cdef dict cache
if all and self.buffer_caches is not None:
for cache in self.buffer_caches:
if self.id in cache:
del cache[self.id]
del cache[self.id]
self.buffer_caches = None
cleaned = True
return cleaned

cpdef bint is_smooth(self):
raise NotImplementedError()
Expand Down Expand Up @@ -160,24 +180,17 @@ cdef class Model:

cpdef void remove_dependent(self, Model model):
self.dependents.remove(model)
if not self.dependents:
self.dependents = None

cpdef void invalidate(self):
self.uncache(True)
cdef Model model
cdef dict cache
if self.cache:
self.cache = None
if self.dependents is not None:
for model in self.dependents:
model.invalidate()
cdef object model_id
if self.buffer_caches is not None:
model_id = self.id
for cache in self.buffer_caches:
cache.pop(model_id)
self.buffer_caches = None

cpdef object get_trimesh(self):
self.cache_timestamp = perf_counter()
cdef PyObject* objptr
if self.cache is None:
self.cache = {}
Expand All @@ -188,7 +201,6 @@ cdef class Model:
return trimesh_model

cpdef object get_manifold(self):
self.cache_timestamp = perf_counter()
cdef PyObject* objptr
if self.cache is None:
self.cache = {}
Expand All @@ -199,7 +211,6 @@ cdef class Model:
return manifold

cpdef Vector get_bounds(self):
self.cache_timestamp = perf_counter()
cdef PyObject* objptr
if self.cache is None:
self.cache = {}
Expand All @@ -219,7 +230,6 @@ cdef class Model:
return bounds_vector

cpdef tuple get_buffers(self, object glctx, dict objects):
self.cache_timestamp = perf_counter()
cdef object model_id = self.id
cdef PyObject* objptr
if (objptr := PyDict_GetItem(objects, model_id)) != NULL:
Expand Down

0 comments on commit 25ea2c7

Please sign in to comment.