<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Fernando Simões</title><link>https://frn.sh/</link><description>Recent content on Fernando Simões</description><generator>Hugo</generator><language>en-US</language><copyright>Copyright © Fernando Simões.</copyright><lastBuildDate>Thu, 01 Oct 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://frn.sh/index.xml" rel="self" type="application/rss+xml"/><item><title>Page table memory consumption</title><link>https://frn.sh/pagetables/</link><pubDate>Thu, 01 Oct 2026 00:00:00 +0000</pubDate><guid>https://frn.sh/pagetables/</guid><description>The other day I was reading Linus Torvalds punch some people over hashed page tables. His argument: in a tree, the entries of neighboring pages are adjacent, which means one cache-line fills several TLB entries at once. A hash table, on the other hand, scatters neighbors in buckets:
The fact is, you just don&amp;rsquo;t know what GOOD actually is.
I&amp;rsquo;ll tell you: t a good TLB fill should pre-populate the TLB with all the entries it can fit in one cache-line.</description></item><item><title>A 40ms Go GC pause caused by swap</title><link>https://frn.sh/go-gc/</link><pubDate>Sun, 13 Sep 2026 00:00:00 +0000</pubDate><guid>https://frn.sh/go-gc/</guid><description>I&amp;rsquo;m writing this so you don&amp;rsquo;t slap your forehead like I almost did when I decided to run swap in production to absorb memory spikes.
I had a cgroup with two processes: one is a Go process that calls io.ReadAll and then proto.Unmarshal, creating a blob and then a graph struct (which is marked as scan by Go&amp;rsquo;s allocator). The other process is an HTTP server that mostly stays quiet.</description></item><item><title>1193 backends on WALWrite, and lore</title><link>https://frn.sh/pgfsync/</link><pubDate>Sat, 18 Jul 2026 00:00:00 +0000</pubDate><guid>https://frn.sh/pgfsync/</guid><description>An interesting wait event table I found in production:
wait_event_type | wait_event | count ----------------+---------------+------- LWLock | WALWrite | 1193 IO | DataFileRead | 194 IO | DataFileWrite | 4 Lock | frozenid | 2 IO | WalSync | 1 1193 backends were waiting on WALWrite. This was a nasty production incident - we ran out of IOPS first, then an anti-wraparound autovacuum started running, which made everything worse: checkpoint lag and connections went through the roof.</description></item><item><title>A Node.js heap mystery</title><link>https://frn.sh/pmem/</link><pubDate>Sat, 21 Mar 2026 00:00:00 +0000</pubDate><guid>https://frn.sh/pmem/</guid><description>A Node.js app was consuming 665 MiB of memory. I didn&amp;rsquo;t know where it was coming from, so I started by looking at process.memoryUsage():
{ &amp;#34;rss&amp;#34;: 697303040, &amp;#34;heapTotal&amp;#34;: 135147520, &amp;#34;heapUsed&amp;#34;: 126842024, &amp;#34;external&amp;#34;: 25004037, &amp;#34;arrayBuffers&amp;#34;: 33762595 } heapTotal was only 129 MiB (!). heapUsed is included in heapTotal, so even if we add arrayBuffers, V8 was seeing 161.09 MiB. Not even close to those 665 MiB from RSS. So where is the rest?</description></item><item><title>Investigating 108,725 forks</title><link>https://frn.sh/tforks/</link><pubDate>Thu, 11 Dec 2025 00:00:00 +0000</pubDate><guid>https://frn.sh/tforks/</guid><description>One of the servers was hitting 90% CPU utilization. A few containers running, no alerts. I ssh&amp;rsquo;ed and found a process with cmd bash startup.sh that had been running for 28 minutes. I straced it for a few minutes:
% time seconds usecs/call calls errors syscall ------ ----------- ----------- --------- --------- ---------------- 75.36 52.698676 390 134819 26094 wait4 12.27 8.583416 78 108725 fork 7.42 5.190671 5 926332 rt_sigprocmask 2.69 1.881557 5 330523 165262 close 1.</description></item><item><title>Betting a coffee on a socket leak</title><link>https://frn.sh/response-body/</link><pubDate>Tue, 19 Aug 2025 00:00:00 +0000</pubDate><guid>https://frn.sh/response-body/</guid><description>I joined this company a while back and during my first week someone called me to take a look at a mysterious service that would start returning 502s a few days after being restarted. They were basically in a loop. Whenever it happened, someone had to go there and restart the service manually.
The service itself was really small, it only processed PDFs: a request arrived with an ID, the ID was used to download a PDF from AWS S3, make some changes in memory, and then upload it back to the bucket.</description></item><item><title>Sigterm a D state process</title><link>https://frn.sh/sigterm/</link><pubDate>Tue, 08 Apr 2025 00:00:00 +0000</pubDate><guid>https://frn.sh/sigterm/</guid><description>A kernel mystery I hit today: load average at 12 on a 2 vCPU machine during a production incident.
Linux load average counts three things: processes running on a CPU, processes waiting in the run queue, and processes in uninterruptible sleep - D state. From the kernel source:
The global load average is an exponentially decaying average of nr_running + nr_uninterruptible. Regular sleep doesn&amp;rsquo;t count, so if load average says 12, those 12 were either running, runnable, or in D.</description></item></channel></rss>