<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>emre şahin's digital garden 🍃 - performance</title>
    <link>https://emresahin.net/tags/performance/</link>
    <description>Posts in the performance tag</description>
    <language>en</language>
    <managingEditor>contact@emresahin.net (Emre Şahin)</managingEditor>
    <lastBuildDate>Tue, 15 Sep 2026 19:46:32 +0000</lastBuildDate>
    <atom:link href="https://emresahin.net/tags/performance/rss.xml" rel="self" type="application/rss+xml"/>
    <item>
      <title>devlog 20</title>
      <published>2025-02-01T09:27:50+00:00</published>
      <updated>2025-02-01T09:27:50+00:00</updated>
      <author>Emre Şahin</author>
      <pubDate>Sat, 01 Feb 2025 09:27:50 +0000</pubDate>
      <link>https://emresahin.net/devlog-20/</link>
      <guid isPermaLink="true">https://emresahin.net/devlog-20/</guid>
      <description>🐢 We have an error in the publish action. Let’s fix it and rerun it. 🐇 There are two errors. One resulted from forgetting sudo when installing dependencies. The other was the incorrect name for the OpenSSL library. It should be libssl-dev instead of openssl-dev . Maybe we can link the command lis...</description>
      <category>devlog</category>
      <category>xvc</category>
      <category>once-cell</category>
      <category>xvc-config</category>
      <category>xvc-root</category>
      <category>rand</category>
      <category>libssl</category>
      <category>rust</category>
      <category>performance</category>
      <content:encoded><![CDATA[<p>🐢 We have an error in the publish action. Let’s fix it and rerun it.</p>
<p>🐇 There are two errors. One resulted from forgetting <code>sudo</code> when installing
dependencies. The other was the incorrect name for the OpenSSL library. It should be
<code>libssl-dev</code> instead of <code>openssl-dev</code>. Maybe we can link the command list in
the <a href="https://docs.rs/openssl/latest/openssl/#automatic">docs</a>.</p>
<p>🐢 Oops, yes, we should at least keep that in mind.</p>
<p>🐇 I’m checking the most popular crates. <a href="https://docs.rs/getrandom">getrandom</a>
retrieves a random number from the system. It looks much lighter than the <code>rand</code>
crate.</p>
<p>🦊 We can use <a href="https://docs.rs/once_cell">once_cell</a> to initialize
<code>XvcEntityCounter</code>. We currently
<a href="https://github.com/iesahin/xvc/blob/main/ecs/src/ecs/mod.rs#L102">use</a> <code>Once</code>
for this purpose.</p>
<p>🐇 I don’t think it will provide any better features.</p>
<p>🦊 For that case, yes, no better features. But the interface is something like:</p>
<pre><code class="language-rust">impl&lt;T&gt; OnceCell&lt;T&gt; {
    const fn new() -&gt; OnceCell&lt;T&gt; { ... }
    fn set(&amp;self, value: T) -&gt; Result&lt;(), T&gt; { ... }
    fn get(&amp;self) -&gt; Option&lt;&amp;T&gt; { ... }
}</code></pre>
<p>And this makes, for example, working with <code>XvcRoot</code> much easier. We are passing
<code>Arc&lt;RwLock&lt;XvcRootInner&gt;&gt;&gt;</code> everywhere. This is a heavy price when we only use
it in a read-only manner. We can prevent most of these, when we use a <code>read</code> lock, by using
<code>OnceCell</code>.</p>
<p>🐇 <code>XvcConfig</code> can benefit from this as well. We don’t update the config during runs.</p>
<p>🐢 Why do we want to assign it, though? We currently have a <code>config</code> field in
<code>XvcRootInner</code>, and we get a reference to it with the <code>config()</code> method.</p>
<p>🐇 Ok. Let’s skip this for now. No need to worry before measuring the performance impact.</p>]]></content:encoded>
    </item>
    <item>
      <title>LMAX Disruptor</title>
      <published>2024-01-25T09:01:54+00:00</published>
      <updated>2024-01-25T09:01:54+00:00</updated>
      <author>Emre Şahin</author>
      <pubDate>Thu, 25 Jan 2024 09:01:54 +0000</pubDate>
      <link>https://emresahin.net/lmax-disruptor/</link>
      <guid isPermaLink="true">https://emresahin.net/lmax-disruptor/</guid>
      <description>LMAX Disruptor The Disruptor is a concurrency framework created by LMAX to achieve very low latency and high throughput on their Java trading platform. LMAX found that using queues between system stages introduced latency, leading them to focus on optimizing this area. The Disruptor uses a lock-f...</description>
      <category>Development</category>
      <category>Summary</category>
      <category>Concurrency</category>
      <category>Summary</category>
      <category>Libraries</category>
      <category>Disruptor</category>
      <category>Concurrency</category>
      <category>Java</category>
      <category>Performance</category>
      <content:encoded><![CDATA[<p><a href="https://lmax-exchange.github.io/disruptor/">LMAX Disruptor</a></p>
<ul>
<li>The Disruptor is a concurrency framework created by LMAX to achieve very low latency and high throughput on their Java trading platform.</li>
<li>LMAX found that using queues between system stages introduced latency, leading them to focus on optimizing this area.</li>
<li>The Disruptor uses a lock-free “ring buffer” approach to avoid cache misses and locks at the CPU level, which are very costly.</li>
<li>The Disruptor is intended as a general-purpose solution for concurrent programming, not just for financial applications.</li>
<li>Applying the Disruptor pattern is not as simple as replacing all queues with the ring buffer; the user guide provides further guidance.</li>
<li>Various blogs, articles, technical papers, and performance tests explain the Disruptor’s inner workings.</li>
<li>A presentation and discussion group are also available for learning about the Disruptor from its creators.</li>
<li>Martin Fowler has reviewed the Disruptor’s use at LMAX.</li>
<li>The Disruptor is significantly faster than the ArrayBlockingQueue, as shown in the latency histogram.</li>
<li>More performance results are available comparing the Disruptor to other approaches.</li>
</ul>]]></content:encoded>
    </item>
    <item>
      <title>Object-Oriented Brain Damage</title>
      <published>2022-04-05T06:10:16+00:00</published>
      <updated>2022-04-05T06:10:16+00:00</updated>
      <author>Emre Şahin</author>
      <pubDate>Tue, 05 Apr 2022 06:10:16 +0000</pubDate>
      <link>https://emresahin.net/Object-Oriented-Brain-Damage/</link>
      <guid isPermaLink="true">https://emresahin.net/Object-Oriented-Brain-Damage/</guid>
      <description>So, this is the post that I’ve been thinking about for some time. I’m still surprised that it feels like swearing in church ; it shouldn’t be this hard (and this rare) to criticize object-oriented programming . What do I mean by OOP? Mainly the classical style, where you define classes with membe...</description>
      <category>Software Architecture</category>
      <category>Programming Paradigms</category>
      <category>OOP</category>
      <category>Object-Oriented Programming</category>
      <category>ORM</category>
      <category>Principle of Locality</category>
      <category>Python</category>
      <category>Performance</category>
      <category>Software Engineering</category>
      <content:encoded><![CDATA[<p>So, this is the post that I’ve been thinking about for some time. I’m still surprised that
it feels like <em>swearing in church</em>; it shouldn’t be this hard (and this rare)
to criticize <em>object-oriented programming</em>.</p>
<p>What do I mean by OOP? Mainly the <em>classical</em> style, where you define classes
with members and methods and use them to model the solution you’re working on.
It was supposed that this way was superior to the <em>procedural style</em>, where you
write procedures that modify global state. I believe the rage
against <em>procedural programming</em> was because of this <em>global state</em>.
Somehow, in all domains, we have to maintain state, and having a global
state makes the reusability of procedures/functions almost impossible.</p>
<p>I can understand how the reaction against <em>global state</em> led to something like
Java’s “everything is a class” creed. In order to contain global state, you
need classes that contain parts of it and interact through methods. The idea is
simple: if we forbid global state and keep partial state within <em>structs</em> (or classes),
and mutate it with methods, we get reusable software. Once upon a time, I believed
in this, too.</p>
<p>In an ideal world where we could write software in Smalltalk instead of
C++, I’d probably not write this post. Actually, this post isn’t about C++ or
Java, either. They have their places; they solve real problems and
were probably necessary steps to arrive at Go or Rust. We now
have better ideas thanks to the “everything should be a class” worldview.</p>
<p>The problem, in my experience, is applying these <em>classical</em> classes to
interpreted languages. In C++, although it became like a Leviathan with
arms for many different paradigms, there is some care for the <em>cost of
abstraction.</em> If you know the tool, you can get away with classes. Java also
seems to try to make <em>abstractions</em> cost zero. So if you use these languages,
it’s a matter of modeling, habit, or domain suitability. I still think, over
the long term, OOP increases the maintenance burden, but like most ideas in
our profession, this is not rigorously tested.</p>
<p>However, when it comes to <em>multi-paradigm</em> interpreted languages like Python,
<em>objects</em> begin to hurt. The problem, in my opinion, is that <em>object-oriented</em> design
is in conflict with the Principle of Locality.</p>
<p>The Principle of Locality (PoL) is probably the most important
<em>empirical</em> idea in software design. It’s directly related to the Pareto
Principle, Zipf’s Law, and other well-known notions. Our CPUs, disks, search
engines, and content delivery networks depend on it to cache artifacts for
reuse. We know it works because a CPU with a larger L1 cache is faster; we add
more caches to CPUs and disks to increase their speed.</p>
<p>The conflict between the PoL and OOP arises when classes include data
that is not directly related to the <em>problem at hand.</em> The problem at hand, for
example, might be finding the maximum of one million numbers or performing transformations
on some variables. But if these are members of a class, they bring unusable data
to the <em>locality.</em> If the variable I’m transforming is a member of a class, when
I access it through the object, all other members—be they 3, 30, or 300—are
also referenced. Thus, looping over objects ends up polluting the <em>locality</em>
with all other members of the class.</p>
<p>In compiled languages, the advantage of iterators over plain loops is to
overcome this. However, in interpreted languages, no one writes specific
iterators for their member variables. This means when I have:</p>
<pre><code class="language-python">
for obj in my_objects:
    obj.do_something(a)

</code></pre>
<p>All the members of <code>obj</code> are now in the loop. This is against the PoL.</p>
<p>Another problem I see with OOP is its <em>alienation</em> from the basic
elements of software. When you begin to work with objects that do not directly
correspond to anything in computer/software architecture, it becomes more or
less a castle in the clouds. You have to tie this castle—i.e., the <em>class
hierarchy</em>—somehow to the ground. The ground is the CPU, memory, disk, cache, etc.
Compilers may do a good job of this, or they may not, but this
detachment from the basic elements of computing machinery is the cause of what
I call <em>Object-Oriented Brain Damage.</em></p>
<p>When you begin to believe that the <em>objects</em> in your program are <em>real</em>, you
try to express your problem using more objects. Classes are like kipple. They
proliferate all the time. You add classes, then you add classes to create
classes, then you add some base class to derive classes, then you try to fix
these problems with patterns, and so on.</p>
<p>But this whole enterprise doesn’t have anything to do with the <em>real tools</em> we
have. Our tools are processors, memory, disks, screens, printers, etc. When
we detach the problem from these basics, it doesn’t become <em>more solvable.</em> We
only create an ideal version of our understanding that requires <em>additional</em>
attention to teach others, to document, etc.</p>
<p>It’s true that we need abstractions over the tools—we cannot just <em>read
bytes from disk</em>, <em>process in CPU</em>, and <em>print to screen</em>. These all
must be abstracted. But in my experience, OOP is not a good way to abstract
these tools. Instead, it tries to abstract the problem at hand in an arbitrary
way that is <em>supposed</em> to solve the problem. Yet this solution itself becomes a
problem that must be fit onto the <em>ground.</em></p>
<p>Databases and ORMs are good examples of this. Databases and
Entity-Relationship theory are well-understood abstractions. We know how to use
them across multiple CPUs, multiple disks, and multiple machines across multiple
continents. ORMs are not like this; they are <em>supposed</em> to correspond to
databases and provide that <em>cozy object-oriented feeling</em>. However, any system
that depends on ORMs learns that these are not <em>identical</em> to databases. They
don’t have the same capabilities and performance, and over the long run,
depending on an ORM causes more problems than just writing SQL
queries. Because an ORM does not consider the tools we have and their
limitations, it tries to fit an <em>idealistic</em> world view onto databases. When it
doesn’t scale, we think this <em>performance degradation</em> is <em>natural.</em></p>
<p>No, it’s not natural. When your models load whole rows from billions of
records just to access a single field for a calculation, you deplete the cache
space quickly, and it doesn’t scale. OOP might just be an <em>educational</em> tool,
but even in this regard, I believe it causes most of the brain damage we see in
enterprise software.</p>]]></content:encoded>
    </item>
    <item>
      <title>Premature Caching is the Root of All Evil</title>
      <published>2021-12-22T20:32:35+00:00</published>
      <updated>2021-12-22T20:32:35+00:00</updated>
      <author>Emre Şahin</author>
      <pubDate>Wed, 22 Dec 2021 20:32:35 +0000</pubDate>
      <link>https://emresahin.net/premature-caching/</link>
      <guid isPermaLink="true">https://emresahin.net/premature-caching/</guid>
      <description>I’m writing a Rust command line app in my spare time to learn the language. It involves some file system checks where I use fs::metadata . As everyone knows , accessing the disk is an expensive operation and must be kept to a minimum. I was thinking of using a HashMap::&lt;Path, Metadata&gt; to cache t...</description>
      <category>Development</category>
      <category>Software Engineering</category>
      <category>rust</category>
      <category>caching</category>
      <category>xvc</category>
      <category>optimization</category>
      <category>performance</category>
      <content:encoded><![CDATA[<p>I’m writing a Rust command line app in my spare time to learn the language. It
involves some file system checks where I use <code>fs::metadata</code>. As <em>everyone
knows</em>, accessing the disk is an <em>expensive</em> operation and must be kept to a
minimum. I was thinking of using a <code>HashMap::&lt;Path, Metadata&gt;</code> to cache the
results for paths.</p>
<p>I then came across the <a href="https://crates.io/cached">cached</a> crate. It caches the results of functions for
memoization. <em>This is exactly what I need</em>, I thought. Internally, it does what I
was planning to do.</p>
<p>Later, I noticed the possible bugs that could arise. I’m thinking of using the
function in a short-running process, so the metadata is not expected to change
during the run. For some reason, suppose the runtime of the process began to
get longer, or I decided to add a web server on top of it. At that time,
probably many moons from now, I’ll have forgotten the decision I made about
caches and my assumption that the metadata won’t change during the run. It
will cause some weird bugs when file timestamp changes aren’t detected.</p>
<p>No one will notice that I’m fixing bugs if they never appear, but I believe this
is the best kind of software engineering.</p>
<h2 id="commentary-2022-08-01">Commentary (2022-08-01)</h2>
<ul>
<li>It looks like my assumption that RAM is <em>significantly faster</em> than disk access may also be wrong.
SSDs are fast, and for parallel access, they may perform as fast as RAM.</li>
</ul>]]></content:encoded>
    </item>
  </channel>
</rss>
