Differences

This shows you the differences between two versions of the page.

Link to this comparison view

ep:labs:04 [2025/03/24 19:16]
silvia.dragan [Introduction]
ep:labs:04 [2025/03/24 23:32] (current)
silvia.dragan
Line 19: Line 19:
  
 ===== Introduction ===== ===== Introduction =====
 +<​spoiler>​
 When talking about memory, one can be referring either to the CPU's cache or main memory (i.e., RAM). Since the former has been discussed (hopefully exhaustively) during other courses such as [[https://​ocw.cs.pub.ro/​courses/​asc|ASC]],​ today we'll be focusing on the latter. If you feel that there'​s still more for you to learn about the CPU cache, check out this very well-known [[https://​people.freebsd.org/​~lstewart/​articles/​cpumemory.pdf|article]]. With that out of the way, here's a few things to keep in mind moving forward: When talking about memory, one can be referring either to the CPU's cache or main memory (i.e., RAM). Since the former has been discussed (hopefully exhaustively) during other courses such as [[https://​ocw.cs.pub.ro/​courses/​asc|ASC]],​ today we'll be focusing on the latter. If you feel that there'​s still more for you to learn about the CPU cache, check out this very well-known [[https://​people.freebsd.org/​~lstewart/​articles/​cpumemory.pdf|article]]. With that out of the way, here's a few things to keep in mind moving forward:
  
-== Virtual Memory ​==+** Virtual Memory ​**
  
 Reminding you of this concept may be redundant at this point, but here goes. The programs that you are writing do **not** have direct access to the physical memory. All addresses that you are accessing from user space are translated to physical addresses by the Memory Management Unit (MMU) of the CPU. The MMU stores as many virtual -- physical address pairs as it can in its Translation Lookaside Buffer (TLB). When the TLB fills up, the least accessed addresses are flushed to make room for new ones. When a new virtual address is encountered,​ the CPU will look up its physical counterpart in a structure managed by the kernel. This structure is in fact a 4-level tree where each node is a list of 512 entries pointing to the next node. The leaf nodes yield the physical page address. Some of you might have already noticed something strange. an offset in the range [0; 511] can be represented using only 9 bits. Having a 4-level page table means that the offsets fit into 36 bits of the 64-bit virtual address. If we add the size of a page offset (12 bits), we're still 16 bits short. Good catch! Modern x64 CPUs, while technically using 64-bit addresses, don't support 2^64 bytes of addressable virtual memory. That being said almost nobody ever complained about this, since 2^48 is still more than anyone needs. Reminding you of this concept may be redundant at this point, but here goes. The programs that you are writing do **not** have direct access to the physical memory. All addresses that you are accessing from user space are translated to physical addresses by the Memory Management Unit (MMU) of the CPU. The MMU stores as many virtual -- physical address pairs as it can in its Translation Lookaside Buffer (TLB). When the TLB fills up, the least accessed addresses are flushed to make room for new ones. When a new virtual address is encountered,​ the CPU will look up its physical counterpart in a structure managed by the kernel. This structure is in fact a 4-level tree where each node is a list of 512 entries pointing to the next node. The leaf nodes yield the physical page address. Some of you might have already noticed something strange. an offset in the range [0; 511] can be represented using only 9 bits. Having a 4-level page table means that the offsets fit into 36 bits of the 64-bit virtual address. If we add the size of a page offset (12 bits), we're still 16 bits short. Good catch! Modern x64 CPUs, while technically using 64-bit addresses, don't support 2^64 bytes of addressable virtual memory. That being said almost nobody ever complained about this, since 2^48 is still more than anyone needs.
Line 39: Line 39:
 **Convenience:​** Many of the points made previously can be used to justify how convenient virtual memory. One thing to add would be that even the kernel uses it. The reason for this is the ability to remap physical devices at different addresses. ARM takes this a step further with its [[https://​developer.arm.com/​documentation/​102142/​0100/​Stage-2-translation|Two-Stage Address Translation]],​ allowing the Hypervisor (running at Exception Level 2) to fake the existence of certain devices or to more accurately emulate certain platforms. Note, however, that ARM communicates the layout of hardware components in the address space to the kernel via a Flattened Device Tree (FDT). E.g., [[https://​elixir.bootlin.com/​linux/​latest/​source/​arch/​arm64/​boot/​dts/​freescale/​imx8mn.dtsi#​L811|here]] the address and size of the **uart1** device is given by the **reg** property, containing a tuple representing the base address (0x30860000) and memory size that is reserved for said device (0x10000 -- 16 pages, not all used in reality). On x86-64, FDTs are not used; other systems are used to probe for available hardware. **Convenience:​** Many of the points made previously can be used to justify how convenient virtual memory. One thing to add would be that even the kernel uses it. The reason for this is the ability to remap physical devices at different addresses. ARM takes this a step further with its [[https://​developer.arm.com/​documentation/​102142/​0100/​Stage-2-translation|Two-Stage Address Translation]],​ allowing the Hypervisor (running at Exception Level 2) to fake the existence of certain devices or to more accurately emulate certain platforms. Note, however, that ARM communicates the layout of hardware components in the address space to the kernel via a Flattened Device Tree (FDT). E.g., [[https://​elixir.bootlin.com/​linux/​latest/​source/​arch/​arm64/​boot/​dts/​freescale/​imx8mn.dtsi#​L811|here]] the address and size of the **uart1** device is given by the **reg** property, containing a tuple representing the base address (0x30860000) and memory size that is reserved for said device (0x10000 -- 16 pages, not all used in reality). On x86-64, FDTs are not used; other systems are used to probe for available hardware.
  
-== Out Of Memory Killer ​==+** Out Of Memory Killer ​**
  
 What happens when you start running out of RAM on your system? The default behavior is that the kernel chooses one or more processes to kill, this freeing up some RAM. This is known as the Out Of Memory (OOM) Killer. In order to do this, each process is assigned an OOM score. A higher score is indicative of a higher change of getting killed once the OOM Killer is woken up. The primary factor that influences this score is the amount of memory used. Modifiers that raise this value include the niceness value of the process and the number of ''​fork()''​s. On the other hand, being privileged, having run for a long time or performing hardware I/O reduce the likelihood of being killed. Then comes the user's preference; writing a value to ''/​proc/<​pid>/​oom_score_adj''​ (within certain limits -- decided at kernel compile time) will also tip the scales, one way or another. Writing a value just below the inferior limit will instead categorically prevent the process from being chosen. All this being said, is there an alternative to killing processes? What happens when you start running out of RAM on your system? The default behavior is that the kernel chooses one or more processes to kill, this freeing up some RAM. This is known as the Out Of Memory (OOM) Killer. In order to do this, each process is assigned an OOM score. A higher score is indicative of a higher change of getting killed once the OOM Killer is woken up. The primary factor that influences this score is the amount of memory used. Modifiers that raise this value include the niceness value of the process and the number of ''​fork()''​s. On the other hand, being privileged, having run for a long time or performing hardware I/O reduce the likelihood of being killed. Then comes the user's preference; writing a value to ''/​proc/<​pid>/​oom_score_adj''​ (within certain limits -- decided at kernel compile time) will also tip the scales, one way or another. Writing a value just below the inferior limit will instead categorically prevent the process from being chosen. All this being said, is there an alternative to killing processes?
  
-== Swap Space ==+** Swap Space **
  
 The system can reserve a portion of the persistent storage devices (i.e., HDD, SSD, etc.) for the express purpose of storing RAM pages when memory starts running low. For a long time, a dedicated partition was needed to serve as swap space. Now, users can also create //swap files// on top of an existing file system and mount them as loopback devices for the swap partition. This allows easily resizing the swap space without modifying partitions. When the used memory value exceeds a certain value (high watermark), the kernel'​s [[https://​docs.kernel.org/​admin-guide/​mm/​damon/​reclaim.html|Page Frame Reclamation]] system begins copying the least recently used pages to swap. This goes on until the amount of used memory decreases below another certain value (low watermark). When a page is evicted to swap, the corresponding Page Table Entry (PTE) from the Page Tree is modified to indicate its location in swap, instead of its (previous) physical address in RAM. The system can reserve a portion of the persistent storage devices (i.e., HDD, SSD, etc.) for the express purpose of storing RAM pages when memory starts running low. For a long time, a dedicated partition was needed to serve as swap space. Now, users can also create //swap files// on top of an existing file system and mount them as loopback devices for the swap partition. This allows easily resizing the swap space without modifying partitions. When the used memory value exceeds a certain value (high watermark), the kernel'​s [[https://​docs.kernel.org/​admin-guide/​mm/​damon/​reclaim.html|Page Frame Reclamation]] system begins copying the least recently used pages to swap. This goes on until the amount of used memory decreases below another certain value (low watermark). When a page is evicted to swap, the corresponding Page Table Entry (PTE) from the Page Tree is modified to indicate its location in swap, instead of its (previous) physical address in RAM.
Line 50: Line 50:
 swap device present on your system will automatically disqualify any anonymous maps from being evicted. Knowing that most anonymous pages are part of memory allocation pools that are largely underutilized,​ swapping out (mostly) code pages from less utilized libraries can result in performance loss due to unnecessary I/O in the long run. swap device present on your system will automatically disqualify any anonymous maps from being evicted. Knowing that most anonymous pages are part of memory allocation pools that are largely underutilized,​ swapping out (mostly) code pages from less utilized libraries can result in performance loss due to unnecessary I/O in the long run.
  
 +</​spoiler>​
 ===== Tasks ===== ===== Tasks =====
  
-An archive containing all the files needed ​for the tasks can be found here: {{:ep:labs:labep_02.zip|}}+The skeleton ​for this lab can be found in this [[https://​github.com/​cs-pub-ro/​EP-labs|repository]]. Clone it locally before you start.
  
 {{namespace>:​ep:​labs:​04:​contents:​tasks&​nofooter&​noeditbutton}} {{namespace>:​ep:​labs:​04:​contents:​tasks&​nofooter&​noeditbutton}}
  
ep/labs/04.1742836581.txt.gz ยท Last modified: 2025/03/24 19:16 by silvia.dragan
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0