-
Notifications
You must be signed in to change notification settings - Fork 6.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
sample: demand_paging: add a demo about ondemand section usage
This sample demonstrates how demand paging can be leveraged to deal with firmware bigger than the available RAM if XIP is not possible. Select code can be tagged to be loaded into memory on demand, and also be automatically evicted for more code to be executed when memory is exhausted. Signed-off-by: Nicolas Pitre <[email protected]>
- Loading branch information
Showing
5 changed files
with
169 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
# SPDX-License-Identifier: Apache-2.0 | ||
|
||
cmake_minimum_required(VERSION 3.20.0) | ||
|
||
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) | ||
project(demand_paging) | ||
|
||
target_include_directories(app PRIVATE ${ZEPHYR_BASE}/kernel/include) | ||
|
||
target_sources(app PRIVATE src/main.c) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
.. zephyr:code-sample:: demand-paging | ||
:name: Demand paging | ||
:relevant-api: mem-demand-paging | ||
|
||
Leverage demand paging to deal with code bigger than available RAM. | ||
|
||
Overview | ||
******** | ||
|
||
This sample demonstrates how demand paging can be leveraged to deal with | ||
firmware bigger than the available RAM if XIP is not possible. Select code | ||
can be tagged to be loaded into memory on demand, and also be automatically | ||
evicted for more code to be executed when memory is exhausted. | ||
|
||
Requirements | ||
************ | ||
|
||
This demo requires the presence of a supported hardware MMU and a backing | ||
store implementation with access to the compiled Zephyr binary. | ||
For demonstration purposes, the ondemand_semihost backing store is used on | ||
a QEMU ARM64 target with a hardcoded small RAM configuration. | ||
|
||
Building and Running | ||
******************** | ||
|
||
This application can be built and executed on QEMU as follows: | ||
|
||
.. zephyr-app-commands:: | ||
:zephyr-app: samples/subsys/demand_paging | ||
:host-os: unix | ||
:board: qemu_cortex_a53 | ||
:goals: run | ||
:compact: | ||
|
||
Sample Output | ||
============= | ||
|
||
.. code-block:: console | ||
*** Booting Zephyr OS build v3.7.0-2108-g5975c3785356 *** | ||
Calling huge body of code that doesn't fit in memory | ||
free memory pages: from 37 to 0, 987 page faults | ||
Calling it a second time | ||
free memory pages: from 0 to 0, 987 page faults | ||
Done. | ||
Exit QEMU by pressing :kbd:`CTRL+A` :kbd:`x`. | ||
|
||
To actually view the underlying demand paging subsystem at work, debug | ||
prints can be enabled using :kconfig:option:`CONFIG_LOG` and | ||
:kconfig:option:`CONFIG_KERNEL_LOG_LEVEL_DBG` in the config file. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
CONFIG_SRAM_SIZE=256 | ||
CONFIG_DEMAND_PAGING=y | ||
CONFIG_DEMAND_PAGING_ALLOW_IRQ=y | ||
CONFIG_DEMAND_PAGING_STATS=y | ||
CONFIG_DEMAND_MAPPING=y | ||
CONFIG_LINKER_USE_ONDEMAND_SECTION=y | ||
CONFIG_SEMIHOST=y | ||
CONFIG_BACKING_STORE_ONDEMAND_SEMIHOST=y |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
sample: | ||
description: On-Demand paging of firmware larger than available memory | ||
name: demand-paging | ||
common: | ||
tags: | ||
- kernel | ||
- mmu | ||
- demand_paging | ||
integration_platforms: | ||
- qemu_cortex_a53 | ||
harness: console | ||
harness_config: | ||
type: multi_line | ||
ordered: true | ||
regex: | ||
- "Calling huge body of code that doesn't fit in memory" | ||
- "free memory pages: from (.*) to 0, (.*) page faults" | ||
- "Calling it a second time" | ||
- "free memory pages: from 0 to 0, (.*) page faults" | ||
- "Done." | ||
tests: | ||
sample.demand_paging.ondemand_section: | ||
platform_allow: | ||
- qemu_cortex_a53 | ||
- qemu_cortex_a53/qemu_cortex_a53/smp |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
/* | ||
* Copyright (c) 2024 BayLibre SAS | ||
* | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
#include <zephyr/kernel.h> | ||
#include <zephyr/linker/sections.h> | ||
|
||
#include <mmu.h> /* for k_mem_num_pagefaults_get() */ | ||
|
||
/* | ||
* We want to artificially create a huge body of code hence the volatile | ||
* to prevent the compiler from optimizing everything down. | ||
*/ | ||
volatile long foo_val1; | ||
volatile long foo_val2; | ||
|
||
/* | ||
* This function is tagged with __ondemand_func to be placed in a special | ||
* "ondemand" segment by the linker. This means it is not loaded into memory | ||
* at boot time but rather page-by-page on demand when actually executed. | ||
* It is also subject to being evicted when memory reclamation occurs. | ||
*/ | ||
static void __ondemand_func huge_evictable_function(void) | ||
{ | ||
foo_val1 = 13131313; | ||
foo_val2 = 45454545; | ||
|
||
#define CODE \ | ||
foo_val1 *= foo_val2; \ | ||
foo_val2 += 1234567; \ | ||
foo_val1 -= 9876543210; \ | ||
__asm__ __volatile__ (".rep 1000; nop; .endr"); | ||
|
||
#define REPEAT_10(x) x x x x x x x x x x | ||
#define REPEAT_1000(x) REPEAT_10(REPEAT_10(REPEAT_10(x))) | ||
|
||
REPEAT_1000(CODE) | ||
|
||
#undef REPEAT_1000 | ||
#undef REPEAT_10 | ||
#undef CODE | ||
} | ||
|
||
int main(void) | ||
{ | ||
size_t free_pages_before, free_pages_after; | ||
unsigned long faults_before, faults_after; | ||
|
||
printk("Calling huge body of code that doesn't fit in memory\n"); | ||
free_pages_before = k_mem_free_get() / CONFIG_MMU_PAGE_SIZE; | ||
faults_before = k_mem_num_pagefaults_get(); | ||
|
||
huge_evictable_function(); | ||
|
||
free_pages_after = k_mem_free_get() / CONFIG_MMU_PAGE_SIZE; | ||
faults_after = k_mem_num_pagefaults_get(); | ||
printk("free memory pages: from %zd to %zd, %ld page faults\n", | ||
free_pages_before, free_pages_after, faults_after - faults_before); | ||
|
||
printk("Calling it a second time\n"); | ||
free_pages_before = k_mem_free_get() / CONFIG_MMU_PAGE_SIZE; | ||
faults_before = k_mem_num_pagefaults_get(); | ||
|
||
huge_evictable_function(); | ||
|
||
free_pages_after = k_mem_free_get() / CONFIG_MMU_PAGE_SIZE; | ||
faults_after = k_mem_num_pagefaults_get(); | ||
printk("free memory pages: from %zd to %zd, %ld page faults\n", | ||
free_pages_before, free_pages_after, faults_after - faults_before); | ||
|
||
printk("Done.\n"); | ||
return 0; | ||
} |