pack: evict objects from the cache in groups of eight This drops the cache eviction below libcrypto and zlib in the perf output. The number has been chosen empirically.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
diff --git a/src/pack.c b/src/pack.c
index ddba5d6..d4ae290 100644
--- a/src/pack.c
+++ b/src/pack.c
@@ -116,29 +116,51 @@ static git_pack_cache_entry *cache_get(git_pack_cache *cache, git_off_t offset)
return entry;
}
+#define BASE_DELTA_EVICT_NR 8
+
/* Run with the cache lock held */
static void free_lowest_entry(git_pack_cache *cache)
{
- git_pack_cache_entry *lowest = NULL, *entry;
- khiter_t k, lowest_k;
+ git_pack_cache_entry *entry;
+ khiter_t k;
+
+ git_pack_cache_entry *lru[BASE_DELTA_EVICT_NR] = {NULL};
+ khiter_t lru_k[BASE_DELTA_EVICT_NR];
+ int i;
for (k = kh_begin(cache->entries); k != kh_end(cache->entries); k++) {
if (!kh_exist(cache->entries, k))
continue;
entry = kh_value(cache->entries, k);
- if (lowest == NULL || entry->last_usage < lowest->last_usage) {
- lowest_k = k;
- lowest = entry;
+
+ for (i = 0; i < BASE_DELTA_EVICT_NR; i++) {
+ if (lru[i] == NULL ||
+ (entry->last_usage < lru[i]->last_usage &&
+ entry->refcount.val == 0)) {
+ int j;
+
+ for (j = 0; j < i; j++) {
+ lru[j] = lru[j+1];
+ lru_k[j] = lru_k[j+1];
+ }
+
+ lru[i] = entry;
+ lru_k[i] = k;
+
+ /* jump out and try with the next entry */
+ break;
+ }
}
}
- if (!lowest) /* there's nothing to free */
- return;
-
- cache->memory_used -= lowest->raw.len;
- kh_del(off, cache->entries, lowest_k);
- free_cache_object(lowest);
+ for (i = 0; i < BASE_DELTA_EVICT_NR; i++) {
+ if (lru[i]) {
+ cache->memory_used -= lru[i]->raw.len;
+ kh_del(off, cache->entries, lru_k[i]);
+ free_cache_object(lru[i]);
+ }
+ }
}
static int cache_add(git_pack_cache *cache, git_rawobj *base, git_off_t offset)