{"id":1257,"date":"2026-09-30T23:19:44","date_gmt":"2026-09-30T23:19:44","guid":{"rendered":"https:\/\/bestdedicatedwebhostingserver.com\/blog\/?p=1257"},"modified":"2026-09-30T23:19:44","modified_gmt":"2026-09-30T23:19:44","slug":"cpu-ccd-cache-locality-game-server-thread-placement","status":"publish","type":"post","link":"https:\/\/bestdedicatedwebhostingserver.com\/blog\/cpu-ccd-cache-locality-game-server-thread-placement\/","title":{"rendered":"CCD and Cache Locality: Why Two Threads on the Wrong Cores Cost 15% TPS"},"content":{"rendered":"<p class=\"wp-block-paragraph\">On modern AMD and Intel server CPUs, core numbering is not flat. AMD EPYC and Ryzen parts split into Core Complex Dies (CCDs), each with its own L3 cache slice and memory path; Intel split-core designs do something similar with their ring and tile topology. A game server process that spreads its threads across two CCDs pays an inter-CCD latency penalty on every shared-memory access. On a Minecraft or Valheim node, that penalty shows up directly as lost TPS. This article shows how to detect it and fix it with thread pinning.<\/p>\n\n<h2 class=\"wp-block-heading\">Why Cache Locality Matters for Game Servers<\/h2>\n\n<p class=\"wp-block-paragraph\">A game simulation loop touches hot data structures thousands of times per second: entity maps, chunk arrays, player state. When those structures fit inside one L3 slice (typically 32 MB per CCD on recent EPYC), the loop runs from cache. When two threads owning the same data structure run on different CCDs, every cross-thread access traverses the Infinity Fabric or mesh at 40-80 ns instead of 10-15 ns. Multiplied across a 20-tick loop with thousands of entity updates, the effect is a measurable drop in achievable tick rate.<\/p>\n\n<h2 class=\"wp-block-heading\">Detecting Cross-CCD Placement<\/h2>\n\n<p class=\"wp-block-paragraph\">Linux exposes the cache topology through sysfs. Run these commands on your node to map which cores share an L3 slice:<\/p>\n\n<ul class=\"wp-block-list\"><li><code>lscpu -e=CPU,CORE,SOCKET,NODE,CACHE<\/code> shows logical layout and NUMA nodes.<\/li><li><code>cat \/sys\/devices\/system\/cpu\/cpu0\/cache\/index3\/shared_cpu_list<\/code> lists cores sharing that L3 slice.<\/li><li><code>lstopo --of txt<\/code> (from hwloc) prints a readable tree of packages, CCDs, and caches.<\/li><li><code>numastat -p &lt;pid&gt;<\/code> reveals NUMA misses for a running server process.<\/li><\/ul>\n\n<p class=\"wp-block-paragraph\">If the JVM or game binary shows a thread group split across two different <code>shared_cpu_list<\/code> ranges, you have a locality problem.<\/p>\n\n<h2 class=\"wp-block-heading\">The Fix: Pin the Sim Thread to One CCD<\/h2>\n\n<p class=\"wp-block-paragraph\">The primary simulation thread and its GC or allocator threads should live on cores inside a single CCD. On a typical EPYC 8-core-per-CCD layout, that means pinning to cores 0-7 rather than letting the scheduler roam across 0-15. For a single instance, restrict the process to one CCD:<\/p>\n\n<ul class=\"wp-block-list\"><li><code>taskset -c 0-7 java -jar server.jar<\/code> binds the process to the first CCD.<\/li><li>In systemd, set <code>CPUAffinity=0-7<\/code> in the unit file.<\/li><li>For containers, use <code>cpuset.cpus=0-7<\/code> in the cgroup.<\/li><li>Match NUMA memory with <code>numactl --cpunodebind=0 --membind=0<\/code>.<\/li><\/ul>\n\n<h2 class=\"wp-block-heading\">Multi-Instance Placement Strategy<\/h2>\n\n<p class=\"wp-block-paragraph\">When you host several game instances on one machine, assign each instance its own CCD rather than interleaving them. Two Minecraft worlds each pinned to separate 8-core CCDs will outperform the same two worlds spread randomly across 16 cores, because neither instance evicts the other&#8217;s hot working set. This is the practical argument for owning a machine with many CCDs when you run a multi-game community.<\/p>\n\n<figure class=\"wp-block-table\"><table><thead><tr><th>Scenario<\/th><th>Placement<\/th><th>Relative TPS<\/th><\/tr><\/thead><tbody><tr><td>Single instance, one CCD<\/td><td>cores 0-7<\/td><td>100%<\/td><\/tr><tr><td>Single instance, two CCDs<\/td><td>cores 0-15<\/td><td>85-90%<\/td><\/tr><tr><td>Two instances, separate CCDs<\/td><td>0-7 and 8-15<\/td><td>100% \/ 100%<\/td><\/tr><tr><td>Two instances, interleaved<\/td><td>both on 0-15<\/td><td>78-85% each<\/td><\/tr><\/tbody><\/table><\/figure>\n\n<h2 class=\"wp-block-heading\">Measuring the Improvement<\/h2>\n\n<p class=\"wp-block-paragraph\">Record TPS and MSPT (milliseconds per tick) before and after pinning. A well-behaved server should hold 20 TPS with MSPT under 30 ms. If pinning to one CCD pushes MSPT from 45 ms to 34 ms, that improvement is the inter-CCD tax you were paying. Use <code>\/forge tps<\/code>, <code>\/spark tps<\/code>, or your server&#8217;s native timing command, and run each configuration for at least 30 minutes under representative player load.<\/p>\n\n<h2 class=\"wp-block-heading\">Interactions With Other Tuning<\/h2>\n\n<ul class=\"wp-block-list\"><li>Disable transparent hugepage migration across NUMA nodes if it causes periodic stalls (<code>echo 0 &gt; \/sys\/kernel\/mm\/transparent_hugepage\/khugepaged\/defrag<\/code>).<\/li><li>Set CPU governor to <code>performance<\/code> so pinned cores never idle down.<\/li><li>Keep GC threads on the same CCD as the heap owner to avoid cross-die allocation traffic.<\/li><li>Verify IRQ affinity: pin NIC interrupts away from the sim cores.<\/li><\/ul>\n\n<h2 class=\"wp-block-heading\">Bottom Line<\/h2>\n\n<p class=\"wp-block-paragraph\">Cache topology is invisible in a spec sheet but decisive in a tick loop. Before you buy more cores, check whether your current cores are sharing the right cache. Our <a href=\"https:\/\/bestdedicatedwebhostingserver.com\/\">bare-metal server lineup<\/a> exposes full core and cache topology so you can pin with confidence, and the <a href=\"https:\/\/bestdedicatedwebhostingserver.com\/blog\/cpu-pinning-numa-game-servers\/\">CPU pinning and NUMA guide<\/a> covers the memory-binding half of the problem.<\/p>","protected":false},"excerpt":{"rendered":"<p>On modern AMD and Intel server CPUs, core numbering is not flat. AMD EPYC and Ryzen parts split into Core Complex Dies (CCDs), each with its own L3 cache slice&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"iawp_total_views":1,"footnotes":""},"categories":[14],"tags":[],"class_list":["post-1257","post","type-post","status-publish","format-standard","hentry","category-hardware-tuning"],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v26.1 (Yoast SEO v26.1) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>CCD and Cache Locality: Why Two Threads on the Wrong Cores Cost 15% TPS - Best Dedicated Web Hosting Server Blog<\/title>\n<meta name=\"description\" content=\"On modern AMD and Intel server CPUs, core numbering is not flat. AMD EPYC and Ryzen parts split into Core Complex Dies (CCDs), each with its own L3 cache\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/bestdedicatedwebhostingserver.com\/blog\/cpu-ccd-cache-locality-game-server-thread-placement\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"CCD and Cache Locality: Why Two Threads on the Wrong Cores Cost 15% TPS\" \/>\n<meta property=\"og:description\" content=\"CCD and Cache Locality: Why Two Threads on the Wrong Cores Cost 15% TPS\" \/>\n<meta property=\"og:url\" content=\"https:\/\/bestdedicatedwebhostingserver.com\/blog\/cpu-ccd-cache-locality-game-server-thread-placement\/\" \/>\n<meta property=\"og:site_name\" content=\"Best Dedicated Web Hosting Server Blog\" \/>\n<meta property=\"article:published_time\" content=\"2026-09-30T23:19:44+00:00\" \/>\n<meta name=\"author\" content=\"bestdedicatedwebhostingserver\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@bestdedicatedwebhostingserver\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"bestdedicatedwebhostingserver\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"3 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/bestdedicatedwebhostingserver.com\/blog\/cpu-ccd-cache-locality-game-server-thread-placement\/\",\"url\":\"https:\/\/bestdedicatedwebhostingserver.com\/blog\/cpu-ccd-cache-locality-game-server-thread-placement\/\",\"name\":\"CCD and Cache Locality: Why Two Threads on the Wrong Cores Cost 15% TPS - Best Dedicated Web Hosting Server Blog\",\"isPartOf\":{\"@id\":\"https:\/\/bestdedicatedwebhostingserver.com\/blog\/#website\"},\"datePublished\":\"2026-09-30T23:19:44+00:00\",\"author\":{\"@id\":\"https:\/\/bestdedicatedwebhostingserver.com\/blog\/#\/schema\/person\/6eb5f9ea35033fe8e67df44397e089b1\"},\"description\":\"On modern AMD and Intel server CPUs, core numbering is not flat. AMD EPYC and Ryzen parts split into Core Complex Dies (CCDs), each with its own L3 cache\",\"breadcrumb\":{\"@id\":\"https:\/\/bestdedicatedwebhostingserver.com\/blog\/cpu-ccd-cache-locality-game-server-thread-placement\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/bestdedicatedwebhostingserver.com\/blog\/cpu-ccd-cache-locality-game-server-thread-placement\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/bestdedicatedwebhostingserver.com\/blog\/cpu-ccd-cache-locality-game-server-thread-placement\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/bestdedicatedwebhostingserver.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"CCD and Cache Locality: Why Two Threads on the Wrong Cores Cost 15% TPS\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/bestdedicatedwebhostingserver.com\/blog\/#website\",\"url\":\"https:\/\/bestdedicatedwebhostingserver.com\/blog\/\",\"name\":\"Best Dedicated Web Hosting Server Blog\",\"description\":\"\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/bestdedicatedwebhostingserver.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/bestdedicatedwebhostingserver.com\/blog\/#\/schema\/person\/6eb5f9ea35033fe8e67df44397e089b1\",\"name\":\"bestdedicatedwebhostingserver\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/bestdedicatedwebhostingserver.com\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/462a07aa37399bdb149e5f91dc3cd8906656bc4c7ed391a3b6f0199c5d2ab964?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/462a07aa37399bdb149e5f91dc3cd8906656bc4c7ed391a3b6f0199c5d2ab964?s=96&d=mm&r=g\",\"caption\":\"bestdedicatedwebhostingserver\"},\"sameAs\":[\"https:\/\/bestdedicatedwebhostingserver.com\/blog\",\"https:\/\/x.com\/bestdedicatedwebhostingserver\"],\"url\":\"https:\/\/bestdedicatedwebhostingserver.com\/blog\/author\/bestdedicatedwebhostingserver\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"CCD and Cache Locality: Why Two Threads on the Wrong Cores Cost 15% TPS - Best Dedicated Web Hosting Server Blog","description":"On modern AMD and Intel server CPUs, core numbering is not flat. AMD EPYC and Ryzen parts split into Core Complex Dies (CCDs), each with its own L3 cache","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/bestdedicatedwebhostingserver.com\/blog\/cpu-ccd-cache-locality-game-server-thread-placement\/","og_locale":"en_US","og_type":"article","og_title":"CCD and Cache Locality: Why Two Threads on the Wrong Cores Cost 15% TPS","og_description":"CCD and Cache Locality: Why Two Threads on the Wrong Cores Cost 15% TPS","og_url":"https:\/\/bestdedicatedwebhostingserver.com\/blog\/cpu-ccd-cache-locality-game-server-thread-placement\/","og_site_name":"Best Dedicated Web Hosting Server Blog","article_published_time":"2026-09-30T23:19:44+00:00","author":"bestdedicatedwebhostingserver","twitter_card":"summary_large_image","twitter_creator":"@bestdedicatedwebhostingserver","twitter_misc":{"Written by":"bestdedicatedwebhostingserver","Est. reading time":"3 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/bestdedicatedwebhostingserver.com\/blog\/cpu-ccd-cache-locality-game-server-thread-placement\/","url":"https:\/\/bestdedicatedwebhostingserver.com\/blog\/cpu-ccd-cache-locality-game-server-thread-placement\/","name":"CCD and Cache Locality: Why Two Threads on the Wrong Cores Cost 15% TPS - Best Dedicated Web Hosting Server Blog","isPartOf":{"@id":"https:\/\/bestdedicatedwebhostingserver.com\/blog\/#website"},"datePublished":"2026-09-30T23:19:44+00:00","author":{"@id":"https:\/\/bestdedicatedwebhostingserver.com\/blog\/#\/schema\/person\/6eb5f9ea35033fe8e67df44397e089b1"},"description":"On modern AMD and Intel server CPUs, core numbering is not flat. AMD EPYC and Ryzen parts split into Core Complex Dies (CCDs), each with its own L3 cache","breadcrumb":{"@id":"https:\/\/bestdedicatedwebhostingserver.com\/blog\/cpu-ccd-cache-locality-game-server-thread-placement\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/bestdedicatedwebhostingserver.com\/blog\/cpu-ccd-cache-locality-game-server-thread-placement\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/bestdedicatedwebhostingserver.com\/blog\/cpu-ccd-cache-locality-game-server-thread-placement\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/bestdedicatedwebhostingserver.com\/blog\/"},{"@type":"ListItem","position":2,"name":"CCD and Cache Locality: Why Two Threads on the Wrong Cores Cost 15% TPS"}]},{"@type":"WebSite","@id":"https:\/\/bestdedicatedwebhostingserver.com\/blog\/#website","url":"https:\/\/bestdedicatedwebhostingserver.com\/blog\/","name":"Best Dedicated Web Hosting Server Blog","description":"","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/bestdedicatedwebhostingserver.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/bestdedicatedwebhostingserver.com\/blog\/#\/schema\/person\/6eb5f9ea35033fe8e67df44397e089b1","name":"bestdedicatedwebhostingserver","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/bestdedicatedwebhostingserver.com\/blog\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/462a07aa37399bdb149e5f91dc3cd8906656bc4c7ed391a3b6f0199c5d2ab964?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/462a07aa37399bdb149e5f91dc3cd8906656bc4c7ed391a3b6f0199c5d2ab964?s=96&d=mm&r=g","caption":"bestdedicatedwebhostingserver"},"sameAs":["https:\/\/bestdedicatedwebhostingserver.com\/blog","https:\/\/x.com\/bestdedicatedwebhostingserver"],"url":"https:\/\/bestdedicatedwebhostingserver.com\/blog\/author\/bestdedicatedwebhostingserver\/"}]}},"_links":{"self":[{"href":"https:\/\/bestdedicatedwebhostingserver.com\/blog\/wp-json\/wp\/v2\/posts\/1257","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/bestdedicatedwebhostingserver.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/bestdedicatedwebhostingserver.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/bestdedicatedwebhostingserver.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/bestdedicatedwebhostingserver.com\/blog\/wp-json\/wp\/v2\/comments?post=1257"}],"version-history":[{"count":1,"href":"https:\/\/bestdedicatedwebhostingserver.com\/blog\/wp-json\/wp\/v2\/posts\/1257\/revisions"}],"predecessor-version":[{"id":1260,"href":"https:\/\/bestdedicatedwebhostingserver.com\/blog\/wp-json\/wp\/v2\/posts\/1257\/revisions\/1260"}],"wp:attachment":[{"href":"https:\/\/bestdedicatedwebhostingserver.com\/blog\/wp-json\/wp\/v2\/media?parent=1257"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/bestdedicatedwebhostingserver.com\/blog\/wp-json\/wp\/v2\/categories?post=1257"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/bestdedicatedwebhostingserver.com\/blog\/wp-json\/wp\/v2\/tags?post=1257"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}