<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Storage on Yarang's Tech Lair</title><link>https://blog.fcoinfup.com/tags/storage/</link><description>Recent content in Storage on Yarang's Tech Lair</description><generator>Hugo -- gohugo.io</generator><language>en</language><lastBuildDate>Mon, 04 May 2026 20:49:16 +0900</lastBuildDate><atom:link href="https://blog.fcoinfup.com/tags/storage/index.xml" rel="self" type="application/rss+xml"/><item><title>Beyond Hardware Limits: Unraveling Disk Physical Structure with Microbenchmarking</title><link>https://blog.fcoinfup.com/post/beyond-hardware-limits-unraveling-disk-physical-structure-with-microbenchmarking/</link><pubDate>Mon, 04 May 2026 20:49:16 +0900</pubDate><guid>https://blog.fcoinfup.com/post/beyond-hardware-limits-unraveling-disk-physical-structure-with-microbenchmarking/</guid><description>&lt;h1 id="beyond-hardware-limits-unraveling-disk-physical-structure-with-microbenchmarking"&gt;Beyond Hardware Limits: Unraveling Disk Physical Structure with Microbenchmarking
&lt;/h1&gt;&lt;p&gt;Recently, an interesting 2019 article was brought back into the spotlight via Hacker News: &amp;ldquo;Discovering hard disk physical geometry through microbenchmarking.&amp;rdquo; In an era where high-performance SSDs are commonplace, why is it important to understand the physical structure of rotational media (HDDs)?&lt;/p&gt;
&lt;p&gt;In fact, the core of this article goes beyond the simple structure of a hard disk, focusing on &lt;strong&gt;&amp;ldquo;a methodology for inferring hardware&amp;rsquo;s internal operations through Observable Performance.&amp;rdquo;&lt;/strong&gt; This principle is applicable not only to analyzing the performance characteristics of modern NVMe SSDs with ZNS (Zoned Namespace) storage but also to low-power network devices like the recently discussed BYOMesh based on LoRa.&lt;/p&gt;
&lt;p&gt;In this post, we will practice the microbenchmarking technique of uncovering the hardware&amp;rsquo;s &amp;ldquo;Physical Geometry&amp;rdquo; by writing a simple code ourselves.&lt;/p&gt;
&lt;h2 id="why-microbenchmarking"&gt;Why Microbenchmarking?
&lt;/h2&gt;&lt;p&gt;Software developers can work without knowing complex hardware details thanks to the abstraction layers between the OS and hardware. However, this changes when developing systems that require high performance, such as e-commerce platforms handling high transaction volumes or analytical systems processing large amounts of data.&lt;/p&gt;
&lt;p&gt;It is difficult to accurately know the actual sector layout, cache memory size, or rotational latency using only OS commands like &lt;code&gt;fstat&lt;/code&gt; or &lt;code&gt;lsblk&lt;/code&gt;. At this point, &lt;strong&gt;microbenchmarking, which involves performing read/write operations and measuring the time taken, becomes the most powerful tool.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="fundamental-principles-of-benchmarking"&gt;Fundamental Principles of Benchmarking
&lt;/h2&gt;&lt;p&gt;The data access speed of a hard disk drive (HDD) is determined by the following three factors:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Seek Time:&lt;/strong&gt; The time it takes for the head to move to the relevant track (physical movement).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Rotational Latency:&lt;/strong&gt; The time until the sector containing the data rotates under the head.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Transfer Time:&lt;/strong&gt; The time to actually read the data.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;We will focus on &lt;strong&gt;&amp;lsquo;Seek Time&amp;rsquo;&lt;/strong&gt;. The further the head has to move, the longer it takes. By measuring the time difference between reading adjacent sectors and sectors far apart, we can infer the disk&amp;rsquo;s physical layout (track and cylinder structure).&lt;/p&gt;
&lt;h2 id="hands-on-exploring-disk-structure-with-python"&gt;Hands-on: Exploring Disk Structure with Python
&lt;/h2&gt;&lt;p&gt;Now, let&amp;rsquo;s use Python to measure the performance difference between random and sequential access. This code is a simple example to measure the cost of moving between the &amp;lsquo;Outer Zone&amp;rsquo; and &amp;lsquo;Inner Zone&amp;rsquo; of a disk.&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;&lt;strong&gt;Caution:&lt;/strong&gt; This script accesses actual disk devices (e.g., &lt;code&gt;/dev/sdX&lt;/code&gt;). &lt;strong&gt;Be sure to use a test disk with no data on it&lt;/strong&gt; or run it in a &lt;strong&gt;VM environment.&lt;/strong&gt; Accessing the wrong device can lead to data corruption.&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; os
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; time
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; sys
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Disk path to test (needs to be changed to a VM or separate test disk)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Example: &amp;#39;/dev/sdb&amp;#39; for Linux, &amp;#39;/dev/rdisk2&amp;#39; for macOS&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;DISK_PATH &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;/dev/sdb&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Read block size (4KB)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;BLOCK_SIZE &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4096&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Number of measurements&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ITERATIONS &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;benchmark_random_access&lt;/span&gt;(fd, size):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&amp;#34;Measures performance when accessing random locations&amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; total_bytes &lt;span style="color:#f92672"&gt;=&lt;/span&gt; os&lt;span style="color:#f92672"&gt;.&lt;/span&gt;path&lt;span style="color:#f92672"&gt;.&lt;/span&gt;getsize(DISK_PATH) &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; os&lt;span style="color:#f92672"&gt;.&lt;/span&gt;path&lt;span style="color:#f92672"&gt;.&lt;/span&gt;exists(DISK_PATH) &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; size
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; start_time &lt;span style="color:#f92672"&gt;=&lt;/span&gt; time&lt;span style="color:#f92672"&gt;.&lt;/span&gt;time()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; _ &lt;span style="color:#f92672"&gt;in&lt;/span&gt; range(ITERATIONS):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Calculate random offset (maintain block alignment)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; offset &lt;span style="color:#f92672"&gt;=&lt;/span&gt; os&lt;span style="color:#f92672"&gt;.&lt;/span&gt;urandom(&lt;span style="color:#ae81ff"&gt;8&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; offset_int &lt;span style="color:#f92672"&gt;=&lt;/span&gt; int&lt;span style="color:#f92672"&gt;.&lt;/span&gt;from_bytes(offset, &lt;span style="color:#e6db74"&gt;&amp;#39;big&amp;#39;&lt;/span&gt;) &lt;span style="color:#f92672"&gt;%&lt;/span&gt; (total_bytes &lt;span style="color:#f92672"&gt;-&lt;/span&gt; BLOCK_SIZE)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; aligned_offset &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (offset_int &lt;span style="color:#f92672"&gt;//&lt;/span&gt; BLOCK_SIZE) &lt;span style="color:#f92672"&gt;*&lt;/span&gt; BLOCK_SIZE
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; os&lt;span style="color:#f92672"&gt;.&lt;/span&gt;lseek(fd, aligned_offset, os&lt;span style="color:#f92672"&gt;.&lt;/span&gt;SEEK_SET)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; os&lt;span style="color:#f92672"&gt;.&lt;/span&gt;read(fd, BLOCK_SIZE)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; end_time &lt;span style="color:#f92672"&gt;=&lt;/span&gt; time&lt;span style="color:#f92672"&gt;.&lt;/span&gt;time()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; (end_time &lt;span style="color:#f92672"&gt;-&lt;/span&gt; start_time) &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1000&lt;/span&gt; &lt;span style="color:#75715e"&gt;# Convert to ms&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;benchmark_sequential_access&lt;/span&gt;(fd):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&amp;#34;Measures performance when accessing sequential locations&amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; start_time &lt;span style="color:#f92672"&gt;=&lt;/span&gt; time&lt;span style="color:#f92672"&gt;.&lt;/span&gt;time()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; _ &lt;span style="color:#f92672"&gt;in&lt;/span&gt; range(ITERATIONS):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; os&lt;span style="color:#f92672"&gt;.&lt;/span&gt;read(fd, BLOCK_SIZE)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; end_time &lt;span style="color:#f92672"&gt;=&lt;/span&gt; time&lt;span style="color:#f92672"&gt;.&lt;/span&gt;time()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; (end_time &lt;span style="color:#f92672"&gt;-&lt;/span&gt; start_time) &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1000&lt;/span&gt; &lt;span style="color:#75715e"&gt;# Convert to ms&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; __name__ &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;__main__&amp;#34;&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#f92672"&gt;not&lt;/span&gt; os&lt;span style="color:#f92672"&gt;.&lt;/span&gt;path&lt;span style="color:#f92672"&gt;.&lt;/span&gt;exists(DISK_PATH):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(&lt;span style="color:#e6db74"&gt;f&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;Error: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{&lt;/span&gt;DISK_PATH&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt; not found. Please update DISK_PATH.&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; sys&lt;span style="color:#f92672"&gt;.&lt;/span&gt;exit(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(&lt;span style="color:#e6db74"&gt;f&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;Benchmarking &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{&lt;/span&gt;DISK_PATH&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;...&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;try&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# It is recommended to use the O_DIRECT flag to minimize buffering when opening the file (Linux).&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Here, we proceed with the default mode for compatibility, but O_DIRECT is necessary for actual hardware access.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; fd &lt;span style="color:#f92672"&gt;=&lt;/span&gt; os&lt;span style="color:#f92672"&gt;.&lt;/span&gt;open(DISK_PATH, os&lt;span style="color:#f92672"&gt;.&lt;/span&gt;O_RDONLY &lt;span style="color:#f92672"&gt;|&lt;/span&gt; os&lt;span style="color:#f92672"&gt;.&lt;/span&gt;O_SYNC)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(&lt;span style="color:#e6db74"&gt;&amp;#34;1. Measuring Random Access (Simulating Head Seek)...&amp;#34;&lt;/span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Random access is slow due to continuous head movement&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; random_time &lt;span style="color:#f92672"&gt;=&lt;/span&gt; benchmark_random_access(fd, &lt;span style="color:#ae81ff"&gt;1024&lt;/span&gt;&lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1024&lt;/span&gt;&lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1024&lt;/span&gt;) &lt;span style="color:#75715e"&gt;# Assume 1GB&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(&lt;span style="color:#e6db74"&gt;f&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34; Random Access Time: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{&lt;/span&gt;random_time&lt;span style="color:#e6db74"&gt;:&lt;/span&gt;&lt;span style="color:#e6db74"&gt;.2f&lt;/span&gt;&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt; ms&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(&lt;span style="color:#e6db74"&gt;&amp;#34;2. Measuring Sequential Access (Minimal Head Movement)...&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Reset file pointer to the beginning&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; os&lt;span style="color:#f92672"&gt;.&lt;/span&gt;lseek(fd, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, os&lt;span style="color:#f92672"&gt;.&lt;/span&gt;SEEK_SET)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; sequential_time &lt;span style="color:#f92672"&gt;=&lt;/span&gt; benchmark_sequential_access(fd)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(&lt;span style="color:#e6db74"&gt;f&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34; Sequential Access Time: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{&lt;/span&gt;sequential_time&lt;span style="color:#e6db74"&gt;:&lt;/span&gt;&lt;span style="color:#e6db74"&gt;.2f&lt;/span&gt;&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt; ms&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;--- Analysis ---&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(&lt;span style="color:#e6db74"&gt;f&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;Performance Gap (Seek Cost): &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{&lt;/span&gt;random_time &lt;span style="color:#f92672"&gt;-&lt;/span&gt; sequential_time&lt;span style="color:#e6db74"&gt;:&lt;/span&gt;&lt;span style="color:#e6db74"&gt;.2f&lt;/span&gt;&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt; ms&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(&lt;span style="color:#e6db74"&gt;&amp;#34;The gap represents the time spent moving the disk head physically.&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; os&lt;span style="color:#f92672"&gt;.&lt;/span&gt;close(fd)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;except&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;PermissionError&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(&lt;span style="color:#e6db74"&gt;&amp;#34;Error: Permission denied. Try running with &amp;#39;sudo&amp;#39;.&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;except&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Exception&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; e:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(&lt;span style="color:#e6db74"&gt;f&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;Error: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{&lt;/span&gt;e&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="interpreting-and-utilizing-results"&gt;Interpreting and Utilizing Results
&lt;/h2&gt;&lt;p&gt;Running the code above, you will observe that random access is significantly slower than sequential access. This &amp;lsquo;Gap&amp;rsquo; is precisely the time spent on physical seeking and rotation.&lt;/p&gt;
&lt;p&gt;If you were to perform this measurement separately at the beginning of the disk (outer tracks) and at the end (inner tracks), you might discover that the outer tracks have a faster transfer rate than the inner tracks due to the disk&amp;rsquo;s &lt;strong&gt;Zone Bit Recording (ZBR)&lt;/strong&gt; structure. In the past, this was utilized to tune data placement to the front of the disk.&lt;/p&gt;
&lt;h2 id="modern-relevance-lessons-from-the-ssd-and-cloud-era"&gt;Modern Relevance: Lessons from the SSD and Cloud Era
&lt;/h2&gt;&lt;p&gt;Although spinning disk technology is becoming a thing of the past, the principle of &lt;strong&gt;&amp;ldquo;understanding a system&amp;rsquo;s internals through performance measurement&amp;rdquo;&lt;/strong&gt; remains unchanged.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;SSD Internal Parallelism:&lt;/strong&gt; SSDs internally operate multiple channels and planes in parallel. If performance dramatically increases when we induce sequential reads using multithreading, this can be a signal to infer the internal controller&amp;rsquo;s parallel processing capabilities.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cloud Storage I/O:&lt;/strong&gt; By capturing phenomena like the &amp;lsquo;Burst&amp;rsquo; followed by a &amp;lsquo;Baseline&amp;rsquo; drop in disk I/O performance on AWS or Azure through microbenchmarking, you can design cost-effective architectures.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="conclusion"&gt;Conclusion
&lt;/h2&gt;&lt;p&gt;The &amp;lsquo;Discovering hard disk physical geometry&amp;rsquo; article, which regained attention on Hacker News, goes beyond mere curiosity to remind us of &lt;strong&gt;the most fundamental stance in diagnosing system performance bottlenecks.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Instead of vaguely concluding &amp;ldquo;the disk is slow,&amp;rdquo; &lt;strong&gt;proving with data &amp;ldquo;where and why it is slow&amp;rdquo;&lt;/strong&gt; by running simple scripts yourself. This is the first step towards true performance tuning.&lt;/p&gt;
&lt;p&gt;We encourage you to run the benchmarking code written in today&amp;rsquo;s post in your development environment. Discovering unexpected hardware characteristics and directly observing their impact on system performance will be a very interesting experience.&lt;/p&gt;
&lt;h2 id="references"&gt;References
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://www.codesynthesis.com/~boris/blog/2019/04/17/geometry/" target="_blank" rel="noopener"
 &gt;Discovering hard disk physical geometry through microbenchmarking (2019)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://www.kernel.org/doc/html/latest/block/index.html" target="_blank" rel="noopener"
 &gt;Linux Block Layer internals&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description></item></channel></rss>