Skip to content

Commit

Permalink
sample: demand_paging: add a demo about ondemand section usage
Browse files Browse the repository at this point in the history
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 <npitre@baylibre.com>
  • Loading branch information
Nicolas Pitre authored and nashif committed Sep 12, 2024
1 parent 7e847ec commit db9e5ec
Show file tree
Hide file tree
Showing 5 changed files with 169 additions and 0 deletions.
10 changes: 10 additions & 0 deletions samples/subsys/demand_paging/CMakeLists.txt
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)
51 changes: 51 additions & 0 deletions samples/subsys/demand_paging/README.rst
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.
8 changes: 8 additions & 0 deletions samples/subsys/demand_paging/prj.conf
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
25 changes: 25 additions & 0 deletions samples/subsys/demand_paging/sample.yaml
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
75 changes: 75 additions & 0 deletions samples/subsys/demand_paging/src/main.c
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;
}

0 comments on commit db9e5ec

Please sign in to comment.