<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.snu.edu.in/index.php?action=history&amp;feed=atom&amp;title=Magus02%2FNUMA</id>
	<title>Magus02/NUMA - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.snu.edu.in/index.php?action=history&amp;feed=atom&amp;title=Magus02%2FNUMA"/>
	<link rel="alternate" type="text/html" href="https://wiki.snu.edu.in/index.php?title=Magus02/NUMA&amp;action=history"/>
	<updated>2026-11-04T19:44:30Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.35.9</generator>
	<entry>
		<id>https://wiki.snu.edu.in/index.php?title=Magus02/NUMA&amp;diff=1187&amp;oldid=prev</id>
		<title>Deepak: Created page with &quot;{{DISPLAYTITLE:NUMA Architecture — Magus02 HPC}} &lt;div style=&quot;background:#0d1b2a;border:1px solid #1e3a5a;border-radius:8px;padding:12px 18px;margin-bottom:20px;font-size:13p...&quot;</title>
		<link rel="alternate" type="text/html" href="https://wiki.snu.edu.in/index.php?title=Magus02/NUMA&amp;diff=1187&amp;oldid=prev"/>
		<updated>2026-04-20T06:45:23Z</updated>

		<summary type="html">&lt;p&gt;Created page with &amp;quot;{{DISPLAYTITLE:NUMA Architecture — Magus02 HPC}} &amp;lt;div style=&amp;quot;background:#0d1b2a;border:1px solid #1e3a5a;border-radius:8px;padding:12px 18px;margin-bottom:20px;font-size:13p...&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;{{DISPLAYTITLE:NUMA Architecture — Magus02 HPC}}&lt;br /&gt;
&amp;lt;div style=&amp;quot;background:#0d1b2a;border:1px solid #1e3a5a;border-radius:8px;padding:12px 18px;margin-bottom:20px;font-size:13px;font-family:monospace;color:#5ba3d9;&amp;quot;&amp;gt;&lt;br /&gt;
📍 [[Magus02/Knowledge_Base|Magus02 Knowledge Base]] → HPC User → NUMA Architecture&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
NUMA (Non-Uniform Memory Access) is the memory architecture used in Magus02's compute nodes. Understanding it helps you write programs that achieve maximum memory bandwidth and avoid hidden performance bottlenecks.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
== What is NUMA? ==&lt;br /&gt;
&lt;br /&gt;
A standard desktop computer has one CPU and one block of main memory — all memory accesses take roughly the same time. A '''NUMA system''' (like Magus02's nodes) has '''multiple CPU sockets''', each with its own local block of memory, connected by a high-speed interconnect.&lt;br /&gt;
&lt;br /&gt;
Key properties:&lt;br /&gt;
* Every core on every socket '''can access all memory''' — it is still a shared-memory system&lt;br /&gt;
* Accessing '''local memory''' (same socket) is '''fast'''&lt;br /&gt;
* Accessing '''remote memory''' (different socket, via interconnect) is '''slower'''&lt;br /&gt;
* The name &amp;quot;Non-Uniform Memory Access&amp;quot; reflects this difference in access latency&lt;br /&gt;
&lt;br /&gt;
=== Magus02 Node Topology ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width:100%;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;background:#0d1b2a;color:#94a8be;&amp;quot; | Node Type&lt;br /&gt;
! style=&amp;quot;background:#0d1b2a;color:#94a8be;&amp;quot; | Processor&lt;br /&gt;
! style=&amp;quot;background:#0d1b2a;color:#94a8be;&amp;quot; | Sockets&lt;br /&gt;
! style=&amp;quot;background:#0d1b2a;color:#94a8be;&amp;quot; | Cores/Socket&lt;br /&gt;
! style=&amp;quot;background:#0d1b2a;color:#94a8be;&amp;quot; | Local RAM/Socket&lt;br /&gt;
! style=&amp;quot;background:#0d1b2a;color:#94a8be;&amp;quot; | NUMA Domains&lt;br /&gt;
|-&lt;br /&gt;
| Compute Node || AMD EPYC 7763 || 2 || 64 || 256 GB || 2 (minimum; EPYC has up to 8 per chip)&lt;br /&gt;
|-&lt;br /&gt;
| High Memory Node || AMD EPYC 7543 || 2 || 32 || 512 GB || 2+&lt;br /&gt;
|-&lt;br /&gt;
| GPU Node || Intel Xeon Platinum 8368 || 2 || 32 || 256 GB || 2&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;background:#0d1a2a;border-left:4px solid #00c9ff;border-radius:6px;padding:14px 18px;margin:16px 0;font-size:14px;color:#94a8be;&amp;quot;&amp;gt;&lt;br /&gt;
💡 &amp;lt;strong&amp;gt;AMD EPYC specifics:&amp;lt;/strong&amp;gt; AMD EPYC &amp;quot;Milan&amp;quot; (7763) and &amp;quot;Rome&amp;quot; (7543) processors use a chiplet design with up to 8 internal NUMA domains per physical socket (called CCD or &amp;quot;core complex die&amp;quot;). This means even a single-socket view has multiple memory latency tiers. Use &amp;lt;code&amp;gt;numactl --hardware&amp;lt;/code&amp;gt; on a node to see the exact topology.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Check the NUMA topology of a node:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# From an interactive session on a compute node:&lt;br /&gt;
$ numactl --hardware&lt;br /&gt;
$ numactl --show&lt;br /&gt;
$ lstopo            # graphical topology (requires X11)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Why NUMA Matters for Your Code ==&lt;br /&gt;
&lt;br /&gt;
Two performance pitfalls arise from being NUMA-unaware:&lt;br /&gt;
&lt;br /&gt;
=== Pitfall 1: Thread Migration ===&lt;br /&gt;
&lt;br /&gt;
The Linux operating system is allowed to move threads between CPU cores to balance load. On a NUMA system, if a thread gets migrated from Socket 0 to Socket 1, it is now separated from its data (which was allocated on Socket 0's local memory). Every memory access then goes over the slow interconnect.&lt;br /&gt;
&lt;br /&gt;
'''Solution: Thread pinning''' — bind each thread to a fixed core so the OS cannot migrate it.&lt;br /&gt;
&lt;br /&gt;
=== Pitfall 2: Wrong Data Placement (First-Touch Policy) ===&lt;br /&gt;
&lt;br /&gt;
When memory is allocated in C/Fortran (e.g. with &amp;lt;code&amp;gt;malloc&amp;lt;/code&amp;gt; or array declaration), no physical memory is assigned yet — only virtual addresses. The operating system allocates the actual physical memory pages the first time each page is ''written'' (the &amp;quot;first touch&amp;quot;). Pages are placed in the local memory of the socket where the first-touching thread runs.&lt;br /&gt;
&lt;br /&gt;
If you initialise all your arrays in the main thread (on Socket 0) before spawning OpenMP threads, all memory lands on Socket 0. Threads on Socket 1 then always access remote memory — severely limiting bandwidth.&lt;br /&gt;
&lt;br /&gt;
'''Solution: Initialise data in parallel''', using the same thread distribution you will use for computation.&lt;br /&gt;
&lt;br /&gt;
=== NUMA-Aware Array Initialisation (OpenMP) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// WRONG — all data initialised by main thread → lands on Socket 0:&lt;br /&gt;
for (int i = 0; i &amp;lt; N; i++) {&lt;br /&gt;
    a[i] = 0.0;&lt;br /&gt;
    b[i] = i;&lt;br /&gt;
}&lt;br /&gt;
#pragma omp parallel for&lt;br /&gt;
for (int i = 0; i &amp;lt; N; i++) {&lt;br /&gt;
    a[i] = a[i] + b[i];   // threads on Socket 1 hit remote memory!&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// CORRECT — data initialised in parallel → distributed across sockets:&lt;br /&gt;
#pragma omp parallel for&lt;br /&gt;
for (int i = 0; i &amp;lt; N; i++) {&lt;br /&gt;
    a[i] = 0.0;            // first-touch by the thread that will compute it&lt;br /&gt;
    b[i] = i;&lt;br /&gt;
}&lt;br /&gt;
#pragma omp parallel for&lt;br /&gt;
for (int i = 0; i &amp;lt; N; i++) {&lt;br /&gt;
    a[i] = a[i] + b[i];   // each thread accesses its own local data&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Thread Pinning on Magus02 ==&lt;br /&gt;
&lt;br /&gt;
=== OpenMP Pinning ===&lt;br /&gt;
&lt;br /&gt;
Set these environment variables in your jobscript or before running your program:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Pin threads to cores, pack them close together (good for cache reuse):&lt;br /&gt;
export OMP_PLACES=cores&lt;br /&gt;
export OMP_PROC_BIND=close&lt;br /&gt;
&lt;br /&gt;
# Alternative: spread threads evenly across NUMA domains (good for bandwidth):&lt;br /&gt;
export OMP_PLACES=sockets&lt;br /&gt;
export OMP_PROC_BIND=spread&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== numactl — Manual Process Binding ===&lt;br /&gt;
&lt;br /&gt;
For serial or MPI programs, use &amp;lt;code&amp;gt;numactl&amp;lt;/code&amp;gt; to bind a process to specific NUMA nodes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Run program using only Socket 0's cores and memory:&lt;br /&gt;
$ numactl --cpunodebind=0 --membind=0 ./my_program&lt;br /&gt;
&lt;br /&gt;
# Run on Socket 1 only:&lt;br /&gt;
$ numactl --cpunodebind=1 --membind=1 ./my_program&lt;br /&gt;
&lt;br /&gt;
# Run using all cores but memory local to the running thread:&lt;br /&gt;
$ numactl --localalloc ./my_program&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== MPI Pinning ===&lt;br /&gt;
&lt;br /&gt;
See [[Magus02/MPI_Usage#Process_Binding|MPI Usage — Process Binding]] for binding MPI ranks to specific NUMA domains using Open MPI and Intel MPI options.&lt;br /&gt;
&lt;br /&gt;
== Checking Memory Bandwidth ==&lt;br /&gt;
&lt;br /&gt;
The performance difference between local and remote memory access can be significant (often 2–3×). You can benchmark it using the STREAM benchmark if available on the cluster:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ module load intel/oneapi&lt;br /&gt;
$ icc -O3 -qopenmp -march=native stream.c -o stream&lt;br /&gt;
$ OMP_NUM_THREADS=64 OMP_PROC_BIND=close ./stream&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&lt;br /&gt;
* [https://software.intel.com/en-us/articles/optimizing-applications-for-numa Intel: Optimizing Applications for NUMA]&lt;br /&gt;
* [[Magus02/OpenMP_Usage|OpenMP Usage — Thread Pinning]]&lt;br /&gt;
* [[Magus02/MPI_Usage|MPI Usage — Process Binding]]&lt;br /&gt;
* [[Magus02/Batch_Scheduler|Batch Scheduler — Hybrid Jobs]]&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-family:monospace;font-size:11px;color:#484f58;text-align:right;&amp;quot;&amp;gt;&lt;br /&gt;
[[Magus02/Knowledge_Base|↑ Back to Knowledge Base]] · Maintained by HPC Administration · wiki.snu.edu.in&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Deepak</name></author>
	</entry>
</feed>