Is Your Application Really Using Persistent Memory? Here’s How to Tell.

Is Your Application Really Using Persistent Memory? Here’s How to Tell.

Persistent memory (PMEM), especially when accessed via technologies like CXL, promises the best of both worlds: DRAM-like speed with the durability of an SSD. When you set up a filesystem like XFS or EXT4 in FSDAX (File System Direct Access) mode on a PMEM device, you’re paving a superhighway for your applications, allowing them to map files directly into their address space and bypass the kernel’s page cache entirely.

But here’s the crucial question: after all the setup and configuration, how do you prove that your application’s data is physically residing on the PMEM device and not just in regular RAM? I’ve run into this question myself, so I wrote a small Python script to get a definitive answer using SQLite3 as an example application. However, before we proceed with the script, let’s examine how you can verify this manually.

How Virtual-to-Physical Address Mapping Works

Your application doesn’t see the computer’s actual hardware memory. Instead, it operates in a private virtual address space managed by the operating system. When your code accesses a memory address, the CPU’s Memory Management Unit (MMU) translates that virtual address into a physical address—the real location on the RAM or PMEM chip.

This mapping allows you to determine where your data truly resides. On Linux, you can perform this translation manually for any running application using files in the /proc filesystem.

Let’s walk through an example. Imagine you have a running process with PID 12345 and you want to inspect a virtual address 0x7f265c63a000 within it. You will need root privileges to complete this task.

1. Find the Virtual Address Range in /proc/<PID>/maps

First, look at the memory map for your process to confirm what’s mapped at that address.

$ sudo cat /proc/12345/maps | grep my_test_file

# Output might look like this:
7f265c63a000-7f265c64a000 rw-p 00000000 08:01 1234567 /mnt/pmem/my_test_file.db

This confirms that the virtual address 0x7f265c63a000 is the start of a memory region mapped to our test file.

2. Calculate the Pagemap Offset

The /proc/12345/pagemap file contains the translation data. To find the entry for our virtual address, we calculate its offset within that file. Assuming a standard page size of 4096 bytes (0x1000 in hex):

  • Formula: offset = (virtual_address / page_size) * 8
  • Calculation: offset = (0x7f265c63a000 / 4096) * 8 = 17501331488

3. Read the Pagemap Entry

Now, use a tool like dd to seek to that offset in the pagemap file and read the 8-byte entry.

$ sudo dd if=/proc/12345/pagemap bs=8 skip=17501331488 count=1 | xxd -g 8

# Output will be the 8-byte entry in hex:
00000000: 86000002058c0100

Our 8-byte pagemap entry is 0x86000002058c0100.

4. Extract the Page Frame Number (PFN)

The pagemap entry is a 64-bit value with several fields. The most important for us is the Page Frame Number (PFN), which is stored in bits 0-54.

  • Pagemap Entry: 0x86000002058c0100
  • Bit 63 (Present): 1 (The page is present in physical RAM/PMEM)
  • Bits 0-54 (PFN): To get the PFN, we mask the entry with 0x7FFFFFFFFFFFFF. The result is 0x2058c01.

Our Page Frame Number is 0x2058c01.

5. Calculate the Physical Address

The final step is to convert the PFN into a physical address.

  • Formula: physical_address = (PFN * page_size) + (virtual_address % page_size)
  • Calculation: physical_address = (0x2058c01 * 4096) + (0x7f265c63a000 % 4096) = 0x2058c01000

The physical address is 0x2058c01000.

6. Compare with /proc/iomem

Finally, check if this physical address falls within a range marked as “Persistent Memory”.

$ cat /proc/iomem | grep "Persistent Memory"

# Output might look like this:
  2050000000-284fffffff : Persistent Memory

Our calculated physical address 0x2058c01000 is indeed within the 0x205... to 0x284... range. We’ve manually confirmed the page is on PMEM! As you can see, this is a robust but tedious process, which is why automating it is so helpful.

Automating the Check with a Python Script

To make this process easy, the script I developed, sqlite_pmem_test.py , automates those exact steps.

  1. Find PMEM Ranges: First, it parses /proc/iomem to identify the physical address ranges that the kernel has reserved for “Persistent Memory”. This gives us a map of where PMEM is located in the system’s physical address space.
  2. Memory-Map a File: The script then creates a test file on the desired storage path (e.g., /mnt/pmem/test.db) and uses the mmap system call to map it into the script’s own virtual address space.
  3. Force Mapping: It “touches” each page of the mapped file to ensure the kernel establishes the virtual-to-physical mapping.
  4. Translate and Verify: This is the magic step. For each page of the mapped file, the script reads /proc/self/pagemap to translate its virtual address into a physical address. It then checks if this physical address falls within the PMEM ranges discovered in the first step.

To run it, you’ll need root privileges to access the pagemap interface.

The Results: Seeing is Believing

The script’s output makes it immediately apparent whether you’re hitting PMEM or not.

Case 1: The Wrong Path (A Standard SSD)

First, let’s run the script on a file located in a user’s home directory, which resides on a standard NVMe SSD. The storage is fast, but it’s not PMEM and doesn’t use DAX.

The data path in this scenario involves an extra step: the kernel reads the data from the SSD into its own memory buffer (the “page cache”) and then copies it into your application’s memory. The physical address your application sees is in regular DRAM, not on the storage device.

  Application Virtual Memory
  +--------------------------+
  |      mmap'd region       |   <-- Your app sees this
  | [virt: 0x71cffef8e000]   |
  +--------------------------+
              ^
              | Data Copy
              |
  +--------------------------+
  |   Kernel Page Cache      |   <-- Physical address is here
  |     (in DRAM)            |       [phys: 0x7e26ed000]
  +--------------------------+
              ^
              | I/O Read
              |
    +--------------------+
    |   NVMe SSD         |
    +--------------------+

The script confirms this indirect path. The physical addresses are in a standard DRAM range, not the PMEM range.

$ sudo ./testpmem.py $HOME
PMEM ranges: ['0x2050000000-0x284fffffff']
Touching each page to force mapping...

PAGE	[virtual addr]	physical addr	is_PMEM
00	    0x71cffef8e000	0x7e26ed000	    not-pmem
01	    0x71cffef8f000	0x80f441000	    not-pmem
...
15	    0x71cffef9d000	0x6394d7000	    not-pmem

Case 2: The Right Path (An FSDAX-Mounted PMEM Device)

Now, let’s run the same script but point it to a path on a filesystem mounted with the dax option. With Direct Access, the page cache is bypassed entirely. The application’s virtual memory is mapped directly to the physical addresses on the PMEM device.

  Application Virtual Memory
  +--------------------------+
  |      mmap'd region       |   <-- Your app sees this
  | [virt: 0x7321bf623000]   |
  +--------------------------+
              |
              | Direct Mapping (No Copy)
              |
  +--------------------------+
  |   Persistent Memory      |   <-- Physical address is here
  |      (PMEM Device)       |       [phys: 0x2058c01000]
  +--------------------------+

The difference is night and day. Every single physical address of the memory-mapped file now falls squarely within the system’s PMEM range (0x205... is between 0x205... and 0x284...). This is our proof!

$ sudo ./testpmem.py /mnt/pmem
PMEM ranges: ['0x2050000000-0x284fffffff']
Touching each page to force mapping...

PAGE	[virtual addr]	physical addr	is_PMEM
00	    0x7321bf623000	0x2058c01000	PMEM
01	    0x7321bf624000	0x2058c02000	PMEM
...
15	    0x7321bf632000	0x2052838000	PMEM

Why Is This Useful?

This simple test is invaluable for a few reasons:

  • Configuration Sanity Check: It provides undeniable proof that your storage, filesystem, and mount options are configured correctly to enable Direct Access.
  • Performance Debugging: If a database or other application isn’t delivering the performance you expect on a PMEM-enabled system, this is a great first step. If the script reports not-pmem, you’ve found a fundamental configuration flaw.
  • Application Development: As a developer, you can use this to ensure your application’s file I/O patterns are compatible with and correctly leveraging memory-mapped PMEM.

By taking a moment to verify the underlying physical mappings, you can be confident that you are fully harnessing the revolutionary speed of persistent memory.

Appendix: Script Usage

Download the script sqlite_pmem_test.py .

You can get a complete list of commands by running the script with the -h or --help flag. Note that the script must be run with sudo or as root to access /proc/self/pagemap.

Help Output

$ ./testpmem.py --help
usage: testpmem.py [-h] [--filesz FILESZ] [--pagesz PAGESZ] [--skip-init] [--show-pmem] [path]

Test PMEM mapping and physical address translation.

positional arguments:
  path                  Directory or file path for the database file. If a directory is given, 'test.db' will be created inside it. Default: /mnt/pmem/test.db

options:
  -h, --help            show this help message and exit
  --filesz FILESZ       Size of the test file in bytes (default: 65536)
  --pagesz PAGESZ       Page size in bytes (default: 4096)
  --skip-init           Skip file initialization if file exists
  --show-pmem           Show PMEM ranges and exit

Command Examples

  1. Just show the system’s PMEM ranges and exit:

This is useful for a quick check to see what physical address ranges are designated as persistent memory.

$ sudo ./testpmem.py --show-pmem
PMEM ranges: ['0x2050000000-0x284fffffff']
  1. Test a specific file path:

Instead of using the default, you can provide a full path to a file you want to test.

$ sudo ./testpmem.py /var/tmp/mytestfile.db
  1. Test a directory:

If you provide a directory, the script will create a file named test.db inside it for the test. This is the most common use case.

# Test a PMEM-mounted directory
$ sudo ./testpmem.py /mnt/pmem

# Test a standard directory on an SSD/HDD
$ sudo ./testpmem.py /home/user/test-location
  1. Skip file creation:

If the test file already exists and you don’t want the script to modify it, use –skip-init.

$ sudo ./testpmem.py --skip-init /mnt/pmem/test.db

Programming Persistent Memory: A Comprehensive Guide for Developers Book

Programming Persistent Memory: A Comprehensive Guide for Developers Book

After many months of hard work by everyone involved, I’m very pleased to announce that the book “Programming Persistent Memory: A Comprehensive Guide for Developers” is now available for download in digital PDF & ePUB formats from https://pmem.io/book , and Kindle & paperback through Amazon .

Beginner and experienced programmers will use this comprehensive guide to persistent memory programming. You will understand how persistent memory brings together several new software/hardware requirements, and offers great promise for better performance and faster application startup times―a huge leap forward in byte-addressable capacity compared with current DRAM offerings.
This revolutionary new technology gives applications significant performance and capacity improvements over existing technologies. It requires a new way of thinking and developing, which makes this highly disruptive to the IT/computing industry. The full spectrum of industry sectors that will benefit from this technology include, but are not limited to, in-memory and traditional databases, AI, analytics, HPC, virtualization, and big data.   
Programming Persistent Memory describes the technology and why it is exciting the industry. It covers the operating system and hardware requirements as well as how to create development environments using emulated or real persistent memory hardware. The book explains fundamental concepts; provides an introduction to persistent memory programming APIs for C, C++, JavaScript, and other languages; discusses RMDA with persistent memory; reviews security features; and presents many examples. Source code and examples that you can run on your own systems are included.
What You’ll Learn
- Understand what persistent memory is, what it does, and the value it brings to the industry
- Become familiar with the operating system and hardware requirements to use persistent memory
- Know the fundamentals of persistent memory programming: why it is different from current programming methods, and what developers need to keep in mind when programming for persistence
- Look at persistent memory application development by example using the Persistent Memory Development Kit (PMDK)
- Design and optimize data structures for persistent memory
- Study how real-world applications are modified to leverage persistent memory
- Utilize the tools available for persistent memory programming, application performance profiling, and debugging
Who This Book Is For
C, C++, Java, and Python developers, but will also be useful to software, cloud, and hardware architects across a broad spectrum of sectors, including cloud service providers, independent software vendors, high performance compute, artificial intelligence, data analytics, big data, etc. 

Read More
How To Enable Debug Logging in ipmctl

How To Enable Debug Logging in ipmctl

The ipmctl utility is used for configuring and managing Intel Optane Persistent Memory modules (DCPMM/PMem). It supports the functionality to:

  • Discover Persistent Memory on the server
  • Provision the persistent memory configuration
  • View and update the firmware on the persistent memory modules
  • Configure data-at-rest security
  • Track health and performance of the persistent memory modules
  • Debug and troubleshoot persistent memory modules

I wrote the IPMCTL User Guide showing how to use the tool, but what if ipmctl returns an error or something you’re not expecting? How do you debug the debugger? On Linux, ipmctl relies on libndctl to help perform communication to the BIOS and persistent memory modules themselves. This is a complicated stack involving multiple kernel drivers and the physical hardware itself. Anything along this path could be causing a problem.

Read More
Understanding STREAM: Benchmarking Memory Bandwidth for DRAM and CXL

Understanding STREAM: Benchmarking Memory Bandwidth for DRAM and CXL

In today’s Artificial Intelligence (AI), Machine Learning (ML), and high-performance computing (HPC) landscape, memory bandwidth is a critical factor in determining overall system performance. As workloads grow increasingly data-intensive, traditional DRAM-only setups are often insufficient, prompting the rise of new memory expansion technologies like Compute Express Link (CXL). To evaluate memory bandwidth across DRAM and CXL devices, we use a modified industry-standard tool called STREAM.

In this blog, we’ll explore what STREAM is, how it works, why it’s commonly used for benchmarking memory bandwidth, and how a modified version of STREAM can be used to measure performance in heterogeneous memory environments, including DRAM and CXL.

Read More