Skip to content

Commit e21f073

Browse files
committed
demand_paging: eviction/lru: add simulated LRU in software
This adds bits to simulate LRU in software for architectures that do not provide a native mean to figure out least recently used pages. Enabling this changes the eviction selection to clear the access flag if it is set and requeues the page frame for later consideration. Without this, the LRU would simply devolve into picking the earliest paged in frame for eviction. Signed-off-by: Daniel Leung <[email protected]>
1 parent 4077249 commit e21f073

File tree

2 files changed

+51
-4
lines changed

2 files changed

+51
-4
lines changed

subsys/demand_paging/eviction/Kconfig

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,3 +48,16 @@ config EVICTION_NRU_PERIOD
4848
pages that are capable of being paged out. At eviction time, if a page
4949
still has the accessed property, it will be considered as recently used.
5050
endif # EVICTION_NRU
51+
52+
if EVICTION_LRU
53+
54+
config EVICTION_LRU_SW_SIMULATED
55+
bool
56+
default y if X86
57+
help
58+
This is for architectures where hardware does not provide a native
59+
mean to figure out least recently used pages. Enabling this changes
60+
the eviction selection to clear the access flag if it is set and
61+
requeues the page frame for later consideration.
62+
63+
endif # EVICTION_LRU

subsys/demand_paging/eviction/lru.c

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -160,14 +160,48 @@ void k_mem_paging_eviction_accessed(uintptr_t phys)
160160

161161
struct k_mem_page_frame *k_mem_paging_eviction_select(bool *dirty_ptr)
162162
{
163-
uint32_t head_pf_idx = LRU_PF_HEAD;
163+
uint32_t pf_idx = LRU_PF_HEAD;
164+
struct k_mem_page_frame *pf;
165+
uintptr_t flags;
164166

165-
if (head_pf_idx == 0) {
167+
if (pf_idx == 0) {
166168
return NULL;
167169
}
168170

169-
struct k_mem_page_frame *pf = idx_to_pf(head_pf_idx);
170-
uintptr_t flags = arch_page_info_get(k_mem_page_frame_to_virt(pf), NULL, false);
171+
#ifndef CONFIG_EVICTION_LRU_SW_SIMULATED
172+
pf = idx_to_pf(pf_idx);
173+
flags = arch_page_info_get(k_mem_page_frame_to_virt(pf), NULL, false);
174+
#else
175+
do {
176+
/*
177+
* During page selection for eviction, if a page has access bit set,
178+
* clear the access bit and put it back at the end of queue.
179+
*
180+
* A subtle fail safe to avoid infinite loop is that the head of queue
181+
* when this function is entered will have its access bit cleared.
182+
* So when we have exhausted every page and looped back to that page,
183+
* it will be selected for eviction.
184+
*/
185+
pf = idx_to_pf(pf_idx);
186+
flags = arch_page_info_get(k_mem_page_frame_to_virt(pf), NULL, true);
187+
188+
if ((flags & ARCH_DATA_PAGE_ACCESSED) != ARCH_DATA_PAGE_ACCESSED) {
189+
/* Page has not been accessed recently, so select this. */
190+
break;
191+
}
192+
193+
/*
194+
* Page has been accessed recently.
195+
* Put the page frame back to the end of queue.
196+
* Use unlink() here since we do not need the extra logic inside remove().
197+
*/
198+
lru_pf_unlink(pf_idx);
199+
lru_pf_append(pf_idx);
200+
201+
/* Grab the new head of queue. */
202+
pf_idx = LRU_PF_HEAD;
203+
} while (pf_idx != 0);
204+
#endif /* !CONFIG_EVICTION_LRU_SW_SIMULATED */
171205

172206
__ASSERT(k_mem_page_frame_is_evictable(pf), "");
173207
*dirty_ptr = ((flags & ARCH_DATA_PAGE_DIRTY) != 0);

0 commit comments

Comments
 (0)