how is page size determined in virtual address space?
Linux uses a virtual memory system where all of the addresses are virtual addresses and not physical addresses. These virtual addresses are converted into physical addresses by the processor. To make this translation easier, virtual and physical memory are divided into pages. Each of these pages is given a unique number; the page frame number. Some page sizes can be 2 KB, 4 KB, etc. But how is this page size number determined? Is it influenced by the size of the architecture? For example, a 32-bit bus will have 4 GB address space.
4 Answers 4
You can find out a system’s default page size by querying its configuration via the getconf command:
NOTE: The above units are typically in bytes, so the 4096 equates to 4096 bytes or 4kB.
This is hardwired in the Linux kernel’s source here:
Example
$ more /usr/src/kernels/3.13.9-100.fc19.x86_64/include/asm-generic/page.h . . /* PAGE_SHIFT determines the page size */ #define PAGE_SHIFT 12 #ifdef __ASSEMBLY__ #define PAGE_SIZE (1
How does shifting give you 4096?
When you shift bits, you're performing a binary multiplication by 2. So in effect a shifting of bits to the left ( 1
Modern hardware supports 2MB, and some 1GB, pagesizes. Can "PAGE_SHIFT" be set to 21 for 2MB pages as the default for the kernel build?
@sim, wondering why are bit manipulations used here ? i read that compiler usually converts multiplications into bit manipulations, hence giving same performance.
@InAFlash usually isn't good enough. also it's clearer here, not to mention this is exponentiation, not multiplication
The hardware (specifically, the MMU, which is part of the CPU) determines what page sizes are possible. There is no relation to the processor register size and only an indirect relation to the address space size (in that the MMU determines both).
Almost all architectures support a 4kB page size. Some architectures support larger pages (and a few also support smaller pages), but 4kB is a very widespread default.
Linux supports two page sizes:
- Normal-sized pages, which I believe are 4kB by default on all architectures, though some architectures allow other values, e.g. 16kB on ARM64 or 8kB, 16kB or 64kB on IA64. These correspond to the deepest level of descriptors on the MMU (what Linux calls PTE).
- Huge pages, if compiled in ( CONFIG_HUGETLB_PAGE is necessary, and CONFIG_HUGETLBFS as well for most uses). This corresponds to the second-deepest level of MMU descriptors (what Linux calls PMD) (or at least it usually does, I don't know if this holds on all architectures).
The page size is a compromise between memory usage, memory usage and speed.
- A larger page size means more waste when a page is partially used, so the system runs out of memory sooner.
- A deeper MMU descriptor level means more kernel memory for page tables.
- A deeper MMU descriptor level means more time spent in page table traversal.
The gains of larger page sizes are tiny for most applications, whereas the cost is substantial. This is why most systems use only normal-sized pages.
You can query the (normal) page size on your system with the getconf utility or the C function sysconf .
Using huge pages requires mounting the hugetlbfs filesystem and mmap ping files there.
Размер страницы в линукс
#include int getpagesize(void); Требования макроса тестирования свойств для glibc (см. feature_test_macros(7)): getpagesize(): Начиная с glibc 2.12:
_BSD_SOURCE ||
!(_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600)
До glibc 2.12: _BSD_SOURCE || _XOPEN_SOURCE >= 500 || _XOPEN_SOURCE && _XOPEN_SOURCE_EXTENDED
ОПИСАНИЕ
Вызов getpagesize() возвращает количество байтов в странице памяти, где «страница» представляет собой блок фиксированной длины, единица измерения при выделения памяти и файлового отображения, выполняемого с помощью mmap(2).
СООТВЕТСТВИЕ СТАНДАРТАМ
SVr4, 4.4BSD, SUSv2. В SUSv2 вызов getpagesize() отмечен как УСТАРЕВШИЙ, и был удалён из POSIX.1-2001; в HP-UX такого вызова нет.
ЗАМЕЧАНИЯ
#include long sz = sysconf(_SC_PAGESIZE);
(большинство систем позволяют использовать _SC_PAGE_SIZE вместо _SC_PAGESIZE.) В Linux системный вызов getpagesize() есть не на всех архитектурах. Если он есть, то он возвращает символ ядра PAGE_SIZE, чьё значение зависит от архитектуры и модели компьютера. Как правило, создаваемые двоичные файлы используются для всей архитектуры, а не для конкретной одной модели. Поэтому рекомендуется определять PAGE_SIZE не на стадии компиляции из файла заголовка, а при выполнении программы с помощью данной функции, по крайней мере на тех архитектурах (таких как sun), где зависимость от модели существует. В этом случае в библиотечные вызовы glibc 2.0 завершатся неудачно, так как её getpagesize() возвращает статически определённое значение и не использует системный вызов. В glibc 2.1 это исправлено.
How to get page size programmatically within Linux kernel module code
Are you saying the PAGE_SIZE is configurable for the IA64 architecture, and not fixed? I thought PAGE_SIZE was fixed for a given architecture (e.g. always 4096 for x86).
7 Answers 7
Try using the getconf utility, which will allow you to retrieve the page size, in bytes, easily.
I don't think this answers the OP's question, but it's helpful info since sysconf(_SC_PAGESIZE) appears to return 4K on linuxia64 (while mprotect fails on a page not aligned on a 16K boundary).
Works on my Ubuntu 18.04 machine, but not in an embedded Linux board I have. The embedded Linux board says: bash: getconf: command not found . Note that the embedded Linux board uses Busybox. This answer works on my embedded Linux board instead.
One approximate method is to read /proc/meminfo and check Mapped size ( on mine its 52544 kB as of now ) and then check nr_mapped in /proc/vmstat ( on mine its 131136 as of now ). Finally PAGE_SIZE = Mapped/nr_mapped . Sometimes this gives you an accurate value ( as in the current example I've quoted ) and sometimes its approximate but very close. Hope this helps!
@MCP On my machine the Mapped/nr_mapped = 379512KB/94878 = 4KB . And getconf PAGESIZE gives 4096. They do match. Could you share what you saw?
Assuming kB: echo "$(( $(grep Mapped: /proc/meminfo | awk '< print $2 >') * 1024 / $(grep nr_mapped /proc/vmstat | awk '< print $2 >') ))"
One way to find the page size is to obtain it from smaps for a process.
cd /proc/1 grep -i pagesize smaps
KernelPageSize: 4 kB MMUPageSize: 4 kB
Curiously using your trick I see 4 kB on an ARM, but inside arch/arm/include/asm/page.h of the running kernel it's #define PAGE_SIZE (_AC(1,UL) << PAGE_SHIFT) and evidently it is 1024 Bytes when checking from my driver, as already suggested by the define page.h . What gives?<>
This does work on my embedded Linux board as well, unlike getconf PAGESIZE which does not. It also works on Ubuntu, but note that for the grep part of the command you must use sudo grep .
If you are trying to build a kernel module, you will need to have at least the kernel headers that are configured for the kernel the module will run on. Those will define the page size macros you need. If you don't have the correctly configured headers, the kernel will refuse to load your module.
And there is nothing wrong with compiling a module on one machine to run on another, even if it's a different architecture. You just need to build against the correct kernel source.
It is not an issue about kernel sources. It is about loading a module compiled on a machine, to run into another machine (Both have the same kernel version but configured differently). I don't want to re-compile against the new configuration because PAGE_SIZE changed. I am looking to get that parameter from the kernel as an API, not as a MACRO (which is solved at compile time).