From 922ce0ef39302a8d6d306a09295cbae857becbc4 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Fri, 19 Jan 2018 15:13:38 +0100 Subject: Improve persistent/weak value allocation performance When the persistent storage becomes fragmented, we would find the page with a hole in it, but we wouldn't put it to the front of the page list. So upon the next allocation we would begin iterating through firstPage again. This wasn't quite visible in callgrind as overall not many instructions were executed, but in perf this function showed up as hotspot because the search for free pages ends up with a lot of cache misses. In delegates_item_states.qml this was about ~7% of measured cycles with perf. Change-Id: I2bfa337ea9be14d1321756963c72d31336790a0a Done-with: Erik Task-number: QTBUG-65708 Reviewed-by: Lars Knoll --- src/qml/jsruntime/qv4persistent.cpp | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/qml/jsruntime/qv4persistent.cpp b/src/qml/jsruntime/qv4persistent.cpp index 987c322e47..75f7c95dde 100644 --- a/src/qml/jsruntime/qv4persistent.cpp +++ b/src/qml/jsruntime/qv4persistent.cpp @@ -68,6 +68,22 @@ Page *getPage(Value *val) { return reinterpret_cast(reinterpret_cast(val) & ~((quintptr)(WTF::pageSize() - 1))); } +QML_NEARLY_ALWAYS_INLINE void insertInFront(PersistentValueStorage *storage, Page *p) +{ + p->header.next = reinterpret_cast(storage->firstPage); + p->header.prev = reinterpret_cast(&storage->firstPage); + if (p->header.next) + p->header.next->header.prev = &p->header.next; + storage->firstPage = p; +} + +QML_NEARLY_ALWAYS_INLINE void unlink(Page *p) +{ + if (p->header.prev) + *p->header.prev = p->header.next; + if (p->header.next) + p->header.next->header.prev = p->header.prev; +} Page *allocatePage(PersistentValueStorage *storage) { @@ -78,19 +94,14 @@ Page *allocatePage(PersistentValueStorage *storage) p->header.engine = storage->engine; p->header.alloc = page; - p->header.next = reinterpret_cast(storage->firstPage); - p->header.prev = reinterpret_cast(&storage->firstPage); p->header.refCount = 0; p->header.freeList = 0; - if (p->header.next) - p->header.next->header.prev = &p->header.next; + insertInFront(storage, p); for (int i = 0; i < kEntriesPerPage - 1; ++i) { p->values[i].setEmpty(i + 1); } p->values[kEntriesPerPage - 1].setEmpty(-1); - storage->firstPage = p; - return p; } @@ -195,6 +206,12 @@ Value *PersistentValueStorage::allocate() Value *v = p->values + p->header.freeList; p->header.freeList = v->int_32(); + + if (p->header.freeList != -1 && p != firstPage) { + unlink(p); + insertInFront(this, p); + } + ++p->header.refCount; v->setRawValue(Encode::undefined()); @@ -248,10 +265,7 @@ ExecutionEngine *PersistentValueStorage::getEngine(Value *v) void PersistentValueStorage::freePage(void *page) { Page *p = static_cast(page); - if (p->header.prev) - *p->header.prev = p->header.next; - if (p->header.next) - p->header.next->header.prev = p->header.prev; + unlink(p); p->header.alloc.deallocate(); } -- cgit v1.2.3