Skip to content

Commit 3553110

Browse files
mjguzikRyan Moeller
authored andcommitted
Combine zio caches if possible
This deduplicates 2 sets of caches which use the same allocation size. Memory savings fluctuate a lot, one sample result is FreeBSD running "make buildworld" saving ~180MB RAM in reduced page count associated with zio caches. Reviewed-by: Brian Behlendorf <[email protected]> Signed-off-by: Mateusz Guzik <[email protected]> Closes openzfs#11877
1 parent f0bc248 commit 3553110

File tree

1 file changed

+50
-24
lines changed

1 file changed

+50
-24
lines changed

module/zfs/zio.c

Lines changed: 50 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,19 @@ zio_init(void)
205205

206206
if (align != 0) {
207207
char name[36];
208+
if (cflags == data_cflags) {
209+
/*
210+
* Resulting kmem caches would be identical.
211+
* Save memory by creating only one.
212+
*/
213+
(void) snprintf(name, sizeof (name),
214+
"zio_buf_comb_%lu", (ulong_t)size);
215+
zio_buf_cache[c] = kmem_cache_create(name,
216+
size, align, NULL, NULL, NULL, NULL, NULL,
217+
cflags);
218+
zio_data_buf_cache[c] = zio_buf_cache[c];
219+
continue;
220+
}
208221
(void) snprintf(name, sizeof (name), "zio_buf_%lu",
209222
(ulong_t)size);
210223
zio_buf_cache[c] = kmem_cache_create(name, size,
@@ -235,37 +248,50 @@ zio_init(void)
235248
void
236249
zio_fini(void)
237250
{
238-
size_t c;
239-
kmem_cache_t *last_cache = NULL;
240-
kmem_cache_t *last_data_cache = NULL;
251+
size_t n = SPA_MAXBLOCKSIZE >> SPA_MINBLOCKSHIFT;
241252

242-
for (c = 0; c < SPA_MAXBLOCKSIZE >> SPA_MINBLOCKSHIFT; c++) {
243-
#ifdef _ILP32
244-
/*
245-
* Cache size limited to 1M on 32-bit platforms until ARC
246-
* buffers no longer require virtual address space.
247-
*/
248-
if (((c + 1) << SPA_MINBLOCKSHIFT) > zfs_max_recordsize)
249-
break;
250-
#endif
251253
#if defined(ZFS_DEBUG) && !defined(_KERNEL)
252-
if (zio_buf_cache_allocs[c] != zio_buf_cache_frees[c])
254+
for (size_t i = 0; i < n; i++) {
255+
if (zio_buf_cache_allocs[i] != zio_buf_cache_frees[i])
253256
(void) printf("zio_fini: [%d] %llu != %llu\n",
254-
(int)((c + 1) << SPA_MINBLOCKSHIFT),
255-
(long long unsigned)zio_buf_cache_allocs[c],
256-
(long long unsigned)zio_buf_cache_frees[c]);
257+
(int)((i + 1) << SPA_MINBLOCKSHIFT),
258+
(long long unsigned)zio_buf_cache_allocs[i],
259+
(long long unsigned)zio_buf_cache_frees[i]);
260+
}
257261
#endif
258-
if (zio_buf_cache[c] != last_cache) {
259-
last_cache = zio_buf_cache[c];
260-
kmem_cache_destroy(zio_buf_cache[c]);
262+
263+
/*
264+
* The same kmem cache can show up multiple times in both zio_buf_cache
265+
* and zio_data_buf_cache. Do a wasteful but trivially correct scan to
266+
* sort it out.
267+
*/
268+
for (size_t i = 0; i < n; i++) {
269+
kmem_cache_t *cache = zio_buf_cache[i];
270+
if (cache == NULL)
271+
continue;
272+
for (size_t j = i; j < n; j++) {
273+
if (cache == zio_buf_cache[j])
274+
zio_buf_cache[j] = NULL;
275+
if (cache == zio_data_buf_cache[j])
276+
zio_data_buf_cache[j] = NULL;
261277
}
262-
zio_buf_cache[c] = NULL;
278+
kmem_cache_destroy(cache);
279+
}
263280

264-
if (zio_data_buf_cache[c] != last_data_cache) {
265-
last_data_cache = zio_data_buf_cache[c];
266-
kmem_cache_destroy(zio_data_buf_cache[c]);
281+
for (size_t i = 0; i < n; i++) {
282+
kmem_cache_t *cache = zio_data_buf_cache[i];
283+
if (cache == NULL)
284+
continue;
285+
for (size_t j = i; j < n; j++) {
286+
if (cache == zio_data_buf_cache[j])
287+
zio_data_buf_cache[j] = NULL;
267288
}
268-
zio_data_buf_cache[c] = NULL;
289+
kmem_cache_destroy(cache);
290+
}
291+
292+
for (size_t i = 0; i < n; i++) {
293+
VERIFY3P(zio_buf_cache[i], ==, NULL);
294+
VERIFY3P(zio_data_buf_cache[i], ==, NULL);
269295
}
270296

271297
kmem_cache_destroy(zio_link_cache);

0 commit comments

Comments
 (0)