Skip to content

Commit 4cfb809

Browse files
benpeartGit for Windows Build Agent
authored andcommitted
fscache: teach fscache to use mempool
Now that the fscache is single threaded, take advantage of the mem_pool as the allocator to significantly reduce the cost of allocations and frees. With the reduced cost of free, in future patches, we can start freeing the fscache at the end of commands instead of just leaking it. Signed-off-by: Ben Peart <[email protected]> Signed-off-by: Johannes Schindelin <[email protected]>
1 parent f68c1f6 commit 4cfb809

File tree

1 file changed

+24
-21
lines changed

1 file changed

+24
-21
lines changed

compat/win32/fscache.c

Lines changed: 24 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include "../../abspath.h"
77
#include "../../trace.h"
88
#include "config.h"
9+
#include "../../mem-pool.h"
910

1011
static volatile long initialized;
1112
static DWORD dwTlsIndex;
@@ -20,6 +21,7 @@ static CRITICAL_SECTION mutex;
2021
struct fscache {
2122
volatile long enabled;
2223
struct hashmap map;
24+
struct mem_pool mem_pool;
2325
unsigned int lstat_requests;
2426
unsigned int opendir_requests;
2527
unsigned int fscache_requests;
@@ -129,11 +131,12 @@ static void fsentry_init(struct fsentry *fse, struct fsentry *list,
129131
/*
130132
* Allocate an fsentry structure on the heap.
131133
*/
132-
static struct fsentry *fsentry_alloc(struct fsentry *list, const char *name,
134+
static struct fsentry *fsentry_alloc(struct fscache *cache, struct fsentry *list, const char *name,
133135
size_t len)
134136
{
135137
/* overallocate fsentry and copy the name to the end */
136-
struct fsentry *fse = xmalloc(sizeof(struct fsentry) + len + 1);
138+
struct fsentry *fse =
139+
mem_pool_alloc(&cache->mem_pool, sizeof(*fse) + len + 1);
137140
/* init the rest of the structure */
138141
fsentry_init(fse, list, name, len);
139142
fse->next = NULL;
@@ -153,35 +156,29 @@ inline static void fsentry_addref(struct fsentry *fse)
153156
}
154157

155158
/*
156-
* Release the reference to an fsentry, frees the memory if its the last ref.
159+
* Release the reference to an fsentry.
157160
*/
158161
static void fsentry_release(struct fsentry *fse)
159162
{
160163
if (fse->list)
161164
fse = fse->list;
162165

163-
if (InterlockedDecrement(&(fse->u.refcnt)))
164-
return;
165-
166-
while (fse) {
167-
struct fsentry *next = fse->next;
168-
free(fse);
169-
fse = next;
170-
}
166+
InterlockedDecrement(&(fse->u.refcnt));
171167
}
172168

173169
/*
174170
* Allocate and initialize an fsentry from a WIN32_FIND_DATA structure.
175171
*/
176-
static struct fsentry *fseentry_create_entry(struct fsentry *list,
172+
static struct fsentry *fseentry_create_entry(struct fscache *cache,
173+
struct fsentry *list,
177174
const WIN32_FIND_DATAW *fdata)
178175
{
179176
char buf[MAX_PATH * 3];
180177
int len;
181178
struct fsentry *fse;
182179
len = xwcstoutf(buf, fdata->cFileName, ARRAY_SIZE(buf));
183180

184-
fse = fsentry_alloc(list, buf, len);
181+
fse = fsentry_alloc(cache, list, buf, len);
185182

186183
fse->st_mode = file_attr_to_st_mode(fdata->dwFileAttributes);
187184
fse->dirent.d_type = S_ISDIR(fse->st_mode) ? DT_DIR : DT_REG;
@@ -199,7 +196,7 @@ static struct fsentry *fseentry_create_entry(struct fsentry *list,
199196
* Dir should not contain trailing '/'. Use an empty string for the current
200197
* directory (not "."!).
201198
*/
202-
static struct fsentry *fsentry_create_list(const struct fsentry *dir,
199+
static struct fsentry *fsentry_create_list(struct fscache *cache, const struct fsentry *dir,
203200
int *dir_not_found)
204201
{
205202
wchar_t pattern[MAX_PATH + 2]; /* + 2 for '/' '*' */
@@ -238,14 +235,14 @@ static struct fsentry *fsentry_create_list(const struct fsentry *dir,
238235
}
239236

240237
/* allocate object to hold directory listing */
241-
list = fsentry_alloc(NULL, dir->dirent.d_name, dir->len);
238+
list = fsentry_alloc(cache, NULL, dir->dirent.d_name, dir->len);
242239
list->st_mode = S_IFDIR;
243240
list->dirent.d_type = DT_DIR;
244241

245242
/* walk directory and build linked list of fsentry structures */
246243
phead = &list->next;
247244
do {
248-
*phead = fseentry_create_entry(list, &fdata);
245+
*phead = fseentry_create_entry(cache, list, &fdata);
249246
phead = &(*phead)->next;
250247
} while (FindNextFileW(h, &fdata));
251248

@@ -257,7 +254,7 @@ static struct fsentry *fsentry_create_list(const struct fsentry *dir,
257254
if (err == ERROR_NO_MORE_FILES)
258255
return list;
259256

260-
/* otherwise free the list and return error */
257+
/* otherwise release the list and return error */
261258
fsentry_release(list);
262259
errno = err_win_to_posix(err);
263260
return NULL;
@@ -280,7 +277,9 @@ static void fscache_add(struct fscache *cache, struct fsentry *fse)
280277
*/
281278
static void fscache_clear(struct fscache *cache)
282279
{
283-
hashmap_clear_and_free(&cache->map, struct fsentry, ent);
280+
mem_pool_discard(&cache->mem_pool, 0);
281+
mem_pool_init(&cache->mem_pool, 0);
282+
hashmap_clear(&cache->map);
284283
hashmap_init(&cache->map, (hashmap_cmp_fn)fsentry_cmp, NULL, 0);
285284
cache->lstat_requests = cache->opendir_requests = 0;
286285
cache->fscache_misses = cache->fscache_requests = 0;
@@ -333,7 +332,7 @@ static struct fsentry *fscache_get(struct fscache *cache, struct fsentry *key)
333332
}
334333

335334
/* create the directory listing */
336-
fse = fsentry_create_list(key->list ? key->list : key, &dir_not_found);
335+
fse = fsentry_create_list(cache, key->list ? key->list : key, &dir_not_found);
337336

338337
/* leave on error (errno set by fsentry_create_list) */
339338
if (!fse) {
@@ -343,7 +342,7 @@ static struct fsentry *fscache_get(struct fscache *cache, struct fsentry *key)
343342
* empty, which for all practical matters is the same
344343
* thing as far as fscache is concerned).
345344
*/
346-
fse = fsentry_alloc(key->list->list,
345+
fse = fsentry_alloc(cache, key->list->list,
347346
key->list->dirent.d_name,
348347
key->list->len);
349348
fse->st_mode = 0;
@@ -422,6 +421,7 @@ int fscache_enable(size_t initial_size)
422421
* '4' was determined empirically by testing several repos
423422
*/
424423
hashmap_init(&cache->map, (hashmap_cmp_fn)fsentry_cmp, NULL, initial_size * 4);
424+
mem_pool_init(&cache->mem_pool, 0);
425425
if (!TlsSetValue(dwTlsIndex, cache))
426426
BUG("TlsSetValue error");
427427
}
@@ -453,7 +453,8 @@ void fscache_disable(void)
453453
"total requests/misses %u/%u\n",
454454
cache->lstat_requests, cache->opendir_requests,
455455
cache->fscache_requests, cache->fscache_misses);
456-
fscache_clear(cache);
456+
mem_pool_discard(&cache->mem_pool, 0);
457+
hashmap_clear(&cache->map);
457458
free(cache);
458459
}
459460

@@ -643,6 +644,8 @@ void fscache_merge(struct fscache *dest)
643644
while ((e = hashmap_iter_next(&iter)))
644645
hashmap_add(&dest->map, e);
645646

647+
mem_pool_combine(&dest->mem_pool, &cache->mem_pool);
648+
646649
dest->lstat_requests += cache->lstat_requests;
647650
dest->opendir_requests += cache->opendir_requests;
648651
dest->fscache_requests += cache->fscache_requests;

0 commit comments

Comments
 (0)