Skip to content

Commit bb0070c

Browse files
committed
minor perf fixes, documentation and comment cleanup
1 parent d549f50 commit bb0070c

3 files changed

Lines changed: 35 additions & 52 deletions

File tree

PERFORMANCE.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,14 +35,13 @@ Hugepagesize: 2048 kB
3535

3636
If necessary you can adjust the value of `HUGE_PAGE_SZ` in `conf.h` to reflect the size on your system.
3737

38-
3938
## Caches and Memoization
4039

4140
There are a few important caches and memoization techniques used in IsoAlloc. These significantly improve the performance of alloc/free hot paths and keep the design as simple as possible.
4241

4342
### Zone Freelist Cache
4443

45-
Each zone contains an array of bitslots that represent free chunks in that zone. The allocation hot path searches this cache first in the hopes that the zone has a free chunk available that fits the allocation request. Allocating chunks from this cache is a lot faster than iterating through a zones bitmap for a free bitslot. This cache is refilled whenever it is low.
44+
Each zone contains an array of bitslots that represent free chunks in that zone. The allocation hot path searches this cache first in the hopes that the zone has a free chunk available that fits the allocation request. Allocating chunks from this cache is a lot faster than iterating through a zones bitmap for a free bitslot. This cache is refilled whenever it is low. Free'd chunks are added to this cache after they've been in the quarantine.
4645

4746
### Chunk to Zone Lookup
4847

include/iso_alloc_internal.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -526,6 +526,7 @@ INTERNAL_HIDDEN iso_alloc_zone_t *iso_new_zone(size_t size, bool internal);
526526
INTERNAL_HIDDEN iso_alloc_zone_t *_iso_new_zone(size_t size, bool internal);
527527
INTERNAL_HIDDEN iso_alloc_zone_t *iso_find_zone_bitmap_range(const void *p);
528528
INTERNAL_HIDDEN iso_alloc_zone_t *iso_find_zone_range(const void *p);
529+
INTERNAL_HIDDEN iso_alloc_zone_t *search_chunk_lookup_table(const void *p);
529530
INTERNAL_HIDDEN bit_slot_t iso_scan_zone_free_slot_slow(iso_alloc_zone_t *zone);
530531
INTERNAL_HIDDEN bit_slot_t iso_scan_zone_free_slot(iso_alloc_zone_t *zone);
531532
INTERNAL_HIDDEN bit_slot_t get_next_free_bit_slot(iso_alloc_zone_t *zone);
@@ -534,7 +535,7 @@ INTERNAL_HIDDEN bool is_pow2(uint64_t sz);
534535
INTERNAL_HIDDEN bool iso_does_zone_fit(iso_alloc_zone_t *zone, size_t size);
535536
INTERNAL_HIDDEN bool _is_zone_retired(iso_alloc_zone_t *zone);
536537
INTERNAL_HIDDEN bool _refresh_zone_mem_tags(iso_alloc_zone_t *zone);
537-
INTERNAL_HIDDEN void _iso_free_internal_unlocked(void *p, bool permanent, iso_alloc_zone_t *zone);
538+
INTERNAL_HIDDEN iso_alloc_zone_t *_iso_free_internal_unlocked(void *p, bool permanent, iso_alloc_zone_t *zone);
538539
INTERNAL_HIDDEN void flush_caches(void);
539540
INTERNAL_HIDDEN void iso_free_chunk_from_zone(iso_alloc_zone_t *zone, void *p, bool permanent);
540541
INTERNAL_HIDDEN void create_canary_chunks(iso_alloc_zone_t *zone);

src/iso_alloc.c

Lines changed: 32 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -528,18 +528,17 @@ INTERNAL_HIDDEN void _iso_alloc_destroy_zone_unlocked(iso_alloc_zone_t *zone, bo
528528
POISON_ZONE(zone);
529529
} else {
530530
if(replace == true) {
531-
/* The only time we ever destroy a default non-private zone
531+
/* The only time we ever destroy a non-private zone
532532
* is from the destructor so its safe unmap pages */
533533
int16_t zones_used = _root->zones_used;
534-
size_t size = zone->chunk_size;
535534

536535
/* _iso_new_zone() will use _root->zones_used to place
537536
* the new zone at the correct index in _root->zones.
538537
* We will restore this value after the new zone has
539538
* been created */
540539
_root->zones_used = zone->index;
541540
_unmap_zone(zone);
542-
_iso_new_zone(size, true);
541+
_iso_new_zone(zone->chunk_size, true);
543542
_root->zones_used = zones_used;
544543
} else {
545544
_unmap_zone(zone);
@@ -989,9 +988,7 @@ INTERNAL_HIDDEN iso_alloc_zone_t *iso_find_zone_fit(size_t size) {
989988
LOG_AND_ABORT("Lookup table should never contain private zones");
990989
}
991990

992-
bool fits = iso_does_zone_fit(zone, size);
993-
994-
if(fits == true) {
991+
if(iso_does_zone_fit(zone, size) == true) {
995992
return zone;
996993
}
997994

@@ -1027,9 +1024,7 @@ INTERNAL_HIDDEN iso_alloc_zone_t *iso_find_zone_fit(size_t size) {
10271024
for(; i < _root->zones_used; i++) {
10281025
zone = &_root->zones[i];
10291026

1030-
bool fits = iso_does_zone_fit(zone, size);
1031-
1032-
if(fits == true) {
1027+
if(iso_does_zone_fit(zone, size) == true) {
10331028
return zone;
10341029
}
10351030
}
@@ -1214,7 +1209,7 @@ INTERNAL_HIDDEN ASSUME_ALIGNED void *_iso_alloc_bitslot_from_zone(bit_slot_t bit
12141209
return p;
12151210
}
12161211

1217-
/* Populates the thread cache, requires the root is locked and zone is unmasked */
1212+
/* Does not require the root is locked */
12181213
INTERNAL_HIDDEN INLINE void populate_zone_cache(iso_alloc_zone_t *zone) {
12191214
if(UNLIKELY(zone->internal == false)) {
12201215
return;
@@ -1331,8 +1326,7 @@ INTERNAL_HIDDEN ASSUME_ALIGNED void *_iso_alloc(iso_alloc_zone_t *zone, size_t s
13311326
#endif
13321327

13331328
/* Allocation requests of SMALL_SZ_MAX bytes or larger are
1334-
* handled by the 'big allocation' path. If a zone was
1335-
* passed in we abort because its a misuse of the API */
1329+
* handled by the 'big allocation' path. */
13361330
if(LIKELY(size <= SMALL_SZ_MAX)) {
13371331
#if FUZZ_MODE
13381332
_verify_all_zones();
@@ -1344,9 +1338,7 @@ INTERNAL_HIDDEN ASSUME_ALIGNED void *_iso_alloc(iso_alloc_zone_t *zone, size_t s
13441338
* and this will speed up that operation */
13451339
for(size_t i = 0; i < zone_cache_count; i++) {
13461340
if(zone_cache[i].chunk_size >= size) {
1347-
bool fit = iso_does_zone_fit(zone_cache[i].zone, size);
1348-
1349-
if(fit == true) {
1341+
if(iso_does_zone_fit(zone_cache[i].zone, size) == true) {
13501342
zone = zone_cache[i].zone;
13511343
break;
13521344
}
@@ -1413,13 +1405,7 @@ INTERNAL_HIDDEN ASSUME_ALIGNED void *_iso_alloc(iso_alloc_zone_t *zone, size_t s
14131405

14141406
MASK_ZONE_PTRS(zone);
14151407
UNLOCK_ROOT();
1416-
1417-
/* Zones internal status cannot be converted, it's
1418-
* safe to access this bool after unlocking and
1419-
* then populating the zone cache */
1420-
if(zone->internal == false) {
1421-
populate_zone_cache(zone);
1422-
}
1408+
populate_zone_cache(zone);
14231409

14241410
return p;
14251411
} else {
@@ -1470,13 +1456,7 @@ INTERNAL_HIDDEN iso_alloc_big_zone_t *iso_find_big_zone(void *p) {
14701456
return NULL;
14711457
}
14721458

1473-
/* iso_find_zone_bitmap_range and iso_find_zone_range are
1474-
* logically identical functions that both return a zone
1475-
* for a pointer. The only difference is where the pointer
1476-
* addresses, a bitmap or user pages */
1477-
INTERNAL_HIDDEN iso_alloc_zone_t *iso_find_zone_bitmap_range(const void *restrict p) {
1478-
iso_alloc_zone_t *zone = NULL;
1479-
1459+
INTERNAL_HIDDEN iso_alloc_zone_t *search_chunk_lookup_table(const void *restrict p) {
14801460
/* The chunk lookup table is the fastest way to find a
14811461
* zone given a pointer to a chunk so we check it first */
14821462
uint16_t zone_index = chunk_lookup_table[ADDR_TO_CHUNK_TABLE(p)];
@@ -1485,7 +1465,16 @@ INTERNAL_HIDDEN iso_alloc_zone_t *iso_find_zone_bitmap_range(const void *restric
14851465
LOG_AND_ABORT("Pointer to zone lookup table corrupted at position %zu", ADDR_TO_CHUNK_TABLE(p));
14861466
}
14871467

1488-
zone = &_root->zones[zone_index];
1468+
return &_root->zones[zone_index];
1469+
}
1470+
1471+
/* iso_find_zone_bitmap_range and iso_find_zone_range are
1472+
* logically identical functions that both return a zone
1473+
* for a pointer. The only difference is where the pointer
1474+
* addresses, a bitmap or user pages */
1475+
INTERNAL_HIDDEN iso_alloc_zone_t *iso_find_zone_bitmap_range(const void *restrict p) {
1476+
iso_alloc_zone_t *zone = search_chunk_lookup_table(p);
1477+
14891478
void *bitmap_start = UNMASK_BITMAP_PTR(zone);
14901479

14911480
if(LIKELY(bitmap_start <= p && (bitmap_start + zone->bitmap_size) > p)) {
@@ -1495,7 +1484,7 @@ INTERNAL_HIDDEN iso_alloc_zone_t *iso_find_zone_bitmap_range(const void *restric
14951484
iso_alloc_zone_t *tmp_zone = NULL;
14961485

14971486
/* Now we check the MRU thread zone cache */
1498-
for(size_t i = 0; i < zone_cache_count; i++) {
1487+
for(int64_t i = 0; i < zone_cache_count; i++) {
14991488
tmp_zone = zone_cache[i].zone;
15001489
bitmap_start = UNMASK_BITMAP_PTR(tmp_zone);
15011490

@@ -1507,7 +1496,6 @@ INTERNAL_HIDDEN iso_alloc_zone_t *iso_find_zone_bitmap_range(const void *restric
15071496
/* Now we check all zones, this is the slowest path */
15081497
for(int64_t i = 0; i < _root->zones_used; i++) {
15091498
zone = &_root->zones[i];
1510-
15111499
bitmap_start = UNMASK_BITMAP_PTR(zone);
15121500

15131501
if(bitmap_start <= p && (bitmap_start + zone->bitmap_size) > p) {
@@ -1519,27 +1507,19 @@ INTERNAL_HIDDEN iso_alloc_zone_t *iso_find_zone_bitmap_range(const void *restric
15191507
}
15201508

15211509
INTERNAL_HIDDEN iso_alloc_zone_t *iso_find_zone_range(const void *restrict p) {
1522-
iso_alloc_zone_t *zone = NULL;
1523-
1524-
/* The chunk lookup table is the fastest way to find a
1525-
* zone given a pointer to a chunk so we check it first */
1526-
uint16_t zone_index = chunk_lookup_table[ADDR_TO_CHUNK_TABLE(p)];
1527-
1528-
if(UNLIKELY(zone_index > _root->zones_used)) {
1529-
LOG_AND_ABORT("Pointer to zone lookup table corrupted at position %zu", ADDR_TO_CHUNK_TABLE(p));
1530-
}
1531-
1532-
zone = &_root->zones[zone_index];
1510+
iso_alloc_zone_t *zone = search_chunk_lookup_table(p);
15331511
void *user_pages_start = UNMASK_USER_PTR(zone);
15341512

1513+
/* The chunk_lookup_table has a high hit rate. Most
1514+
* calls to this function will return here. */
15351515
if(LIKELY(user_pages_start <= p && (user_pages_start + ZONE_USER_SIZE) > p)) {
15361516
return zone;
15371517
}
15381518

15391519
iso_alloc_zone_t *tmp_zone = NULL;
15401520

15411521
/* Now we check the MRU thread zone cache */
1542-
for(size_t i = 0; i < zone_cache_count; i++) {
1522+
for(int64_t i = 0; i < zone_cache_count; i++) {
15431523
tmp_zone = zone_cache[i].zone;
15441524
user_pages_start = UNMASK_USER_PTR(tmp_zone);
15451525

@@ -1551,7 +1531,6 @@ INTERNAL_HIDDEN iso_alloc_zone_t *iso_find_zone_range(const void *restrict p) {
15511531
/* Now we check all zones, this is the slowest path */
15521532
for(int64_t i = 0; i < _root->zones_used; i++) {
15531533
zone = &_root->zones[i];
1554-
15551534
user_pages_start = UNMASK_USER_PTR(zone);
15561535

15571536
if(user_pages_start <= p && (user_pages_start + ZONE_USER_SIZE) > p) {
@@ -1788,7 +1767,6 @@ INTERNAL_HIDDEN void iso_free_chunk_from_zone(iso_alloc_zone_t *zone, void *rest
17881767
#endif
17891768

17901769
POISON_ZONE_CHUNK(zone, p);
1791-
populate_zone_cache(zone);
17921770
}
17931771

17941772
INTERNAL_HIDDEN void _iso_free_from_zone(void *p, iso_alloc_zone_t *zone, bool permanent) {
@@ -1924,14 +1902,17 @@ INTERNAL_HIDDEN void _iso_free_size(void *p, size_t size) {
19241902
}
19251903

19261904
_iso_free_internal_unlocked(p, false, zone);
1927-
19281905
UNLOCK_ROOT();
19291906
}
19301907

19311908
INTERNAL_HIDDEN void _iso_free_internal(void *p, bool permanent) {
19321909
LOCK_ROOT();
1933-
_iso_free_internal_unlocked(p, permanent, NULL);
1910+
iso_alloc_zone_t *zone = _iso_free_internal_unlocked(p, permanent, NULL);
19341911
UNLOCK_ROOT();
1912+
1913+
if(zone != NULL) {
1914+
populate_zone_cache(zone);
1915+
}
19351916
}
19361917

19371918
INTERNAL_HIDDEN bool _is_zone_retired(iso_alloc_zone_t *zone) {
@@ -1964,7 +1945,7 @@ INTERNAL_HIDDEN bool _refresh_zone_mem_tags(iso_alloc_zone_t *zone) {
19641945
return false;
19651946
}
19661947

1967-
INTERNAL_HIDDEN void _iso_free_internal_unlocked(void *p, bool permanent, iso_alloc_zone_t *zone) {
1948+
INTERNAL_HIDDEN iso_alloc_zone_t *_iso_free_internal_unlocked(void *p, bool permanent, iso_alloc_zone_t *zone) {
19681949
#if FUZZ_MODE
19691950
_verify_all_zones();
19701951
#endif
@@ -2011,6 +1992,7 @@ INTERNAL_HIDDEN void _iso_free_internal_unlocked(void *p, bool permanent, iso_al
20111992
_iso_alloc_ptr_search(p, true);
20121993
}
20131994
#endif
1995+
return zone;
20141996
} else {
20151997
iso_alloc_big_zone_t *big_zone = iso_find_big_zone(p);
20161998

@@ -2019,6 +2001,7 @@ INTERNAL_HIDDEN void _iso_free_internal_unlocked(void *p, bool permanent, iso_al
20192001
}
20202002

20212003
iso_free_big_zone(big_zone, permanent);
2004+
return NULL;
20222005
}
20232006
}
20242007

0 commit comments

Comments
 (0)