block_cache: Use an object_cache for the cache_notifications.

cache_listeners are (following packagefs changes) the second-most
allocated object during the boot process, with 20799 on a
*minimum* image. Since they are used so extensively in BFS I/O,
making them object_cached for both performance and memory reasons
seems to make a lot of sense.

Change-Id: I6ef6c3e811c0c4189fea45ee7920131796c9e7c8
Reviewed-on: https://review.haiku-os.org/c/1577
Reviewed-by: Adrien Destugues <pulkomandy@gmail.com>
Reviewed-by: Stephan Aßmus <superstippi@gmx.de>
This commit is contained in:
Augustin Cavalier 2019-07-10 19:21:14 -04:00 committed by waddlesplash
parent 7a2f744859
commit 0e6ece91c8

View File

@ -114,6 +114,9 @@ typedef DoublyLinkedList<cached_block,
&cached_block::link> > block_list;
struct cache_notification : DoublyLinkedListLinkImpl<cache_notification> {
static inline void* operator new(size_t size);
static inline void operator delete(void* block);
int32 transaction_id;
int32 events_pending;
int32 events;
@ -124,6 +127,38 @@ struct cache_notification : DoublyLinkedListLinkImpl<cache_notification> {
typedef DoublyLinkedList<cache_notification> NotificationList;
static object_cache* sCacheNotificationCache;
struct cache_listener;
typedef DoublyLinkedListLink<cache_listener> listener_link;
struct cache_listener : cache_notification {
listener_link link;
};
typedef DoublyLinkedList<cache_listener,
DoublyLinkedListMemberGetLink<cache_listener,
&cache_listener::link> > ListenerList;
void*
cache_notification::operator new(size_t size)
{
// We can't really know whether something is a cache_notification or a
// cache_listener at runtime, so we just use one object_cache for both
// with the size set to that of the (slightly larger) cache_listener.
// In practice, the vast majority of cache_notifications are really
// cache_listeners, so this is a more than acceptable trade-off.
ASSERT(size <= sizeof(cache_listener));
return object_cache_alloc(sCacheNotificationCache, 0);
}
void
cache_notification::operator delete(void* block)
{
object_cache_free(sCacheNotificationCache, block, 0);
}
struct BlockHash {
typedef off_t KeyType;
typedef cached_block ValueType;
@ -219,18 +254,6 @@ private:
cached_block* _GetUnusedBlock();
};
struct cache_listener;
typedef DoublyLinkedListLink<cache_listener> listener_link;
struct cache_listener : cache_notification {
listener_link link;
};
typedef DoublyLinkedList<cache_listener,
DoublyLinkedListMemberGetLink<cache_listener,
&cache_listener::link> > ListenerList;
struct cache_transaction {
cache_transaction();
@ -963,7 +986,7 @@ add_transaction_listener(block_cache* cache, cache_transaction* transaction,
}
}
cache_listener* listener = new(std::nothrow) cache_listener;
cache_listener* listener = new cache_listener;
if (listener == NULL)
return B_NO_MEMORY;
@ -2662,6 +2685,11 @@ block_cache_init(void)
if (sBlockCache == NULL)
return B_NO_MEMORY;
sCacheNotificationCache = create_object_cache("cache notifications",
sizeof(cache_listener), 8, NULL, NULL, NULL);
if (sCacheNotificationCache == NULL)
return B_NO_MEMORY;
new (&sCaches) DoublyLinkedList<block_cache>;
// manually call constructor