<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
    <title>jpnt</title>
    <subtitle>João Pinto&#39;s personal knowledge base and journal</subtitle>
    <link rel="self" type="application/atom+xml" href="https://joaopinto.xyz/atom.xml"/>
    <link rel="alternate" type="text/html" href="https://joaopinto.xyz"/>
    <generator uri="https://www.getzola.org/">Zola</generator>
    <updated>2026-10-07T00:00:00+00:00</updated>
    <id>https://joaopinto.xyz/atom.xml</id>
    <entry xml:lang="en">
        <title>Curriculum Vitae</title>
        <published>2026-10-07T00:00:00+00:00</published>
        <updated>2026-10-07T00:00:00+00:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://joaopinto.xyz/about/cv/"/>
        <id>https://joaopinto.xyz/about/cv/</id>
        
        <content type="html" xml:base="https://joaopinto.xyz/about/cv/">&lt;embed src=&quot;/about/cv.pdf&quot; type=&quot;application/pdf&quot; width=&quot;100%&quot; height=&quot;800px&quot; /&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Architecture</title>
        <published>2025-12-23T00:00:00+00:00</published>
        <updated>2025-12-23T00:00:00+00:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://joaopinto.xyz/systems/architecture/"/>
        <id>https://joaopinto.xyz/systems/architecture/</id>
        
        <content type="html" xml:base="https://joaopinto.xyz/systems/architecture/">&lt;ol&gt;
&lt;li&gt;No problem, no requirements.&lt;/li&gt;
&lt;li&gt;No requirements, no use cases.&lt;/li&gt;
&lt;li&gt;No use cases, no logical boundaries.&lt;/li&gt;
&lt;li&gt;No logical boundaries, no architecture.&lt;/li&gt;
&lt;li&gt;No architecture, no efficient solution.&lt;/li&gt;
&lt;li&gt;No efficient solution, the system falls apart.&lt;/li&gt;
&lt;/ol&gt;
&lt;h1 id=&quot;what-is-architecture&quot;&gt;What is architecture?&lt;/h1&gt;
&lt;p&gt;Software architecture is how you organize a system so it can change safely and meet its goals. That’s it.&lt;/p&gt;
&lt;p&gt;Most writing on architecture falls into two extremes. Either it’s abstract frameworks with diagrams that obscure more than they clarify. Or it’s “just build it bro” with no structure at all, leaving you to figure things out as you go. Both fail when the system needs to evolve.&lt;/p&gt;
&lt;p&gt;Architecture must reduce the cost of future change. It must keep coupling under control so modifying one part doesn’t break everything else. It must make failure predictable and deployments safe.&lt;/p&gt;
&lt;h1 id=&quot;where-to-start-requirements-and-use-cases&quot;&gt;Where to start: Requirements and use cases&lt;/h1&gt;
&lt;p&gt;Start here. Not with diagrams. Not with layers. Start with what the system is supposed to do.&lt;/p&gt;
&lt;p&gt;Requirements define the problem. Use cases show how actors interact with the system to accomplish goals. An actor can be a user, an external system, a scheduled job - anything that triggers behavior.&lt;/p&gt;
&lt;p&gt;If you skip this, you’re building based on guesses. Requirements and use cases ground everything in reality.&lt;/p&gt;
&lt;h1 id=&quot;functionalities-what-does-the-system-need-to-do&quot;&gt;Functionalities: What does the system need to do?&lt;/h1&gt;
&lt;p&gt;Once you know the requirements and use cases, list the functionalities. These are the things the system must actually do.&lt;/p&gt;
&lt;p&gt;For a web service that processes orders, functionalities might be:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Accept HTTP requests&lt;/li&gt;
&lt;li&gt;Validate input&lt;/li&gt;
&lt;li&gt;Check inventory&lt;/li&gt;
&lt;li&gt;Calculate pricing&lt;/li&gt;
&lt;li&gt;Process payment&lt;/li&gt;
&lt;li&gt;Update database&lt;/li&gt;
&lt;li&gt;Send confirmation email&lt;/li&gt;
&lt;li&gt;Return response&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Don’t organize these yet. Just list them. Get them out of your head and into writing. This is the “what.”&lt;/p&gt;
&lt;h1 id=&quot;logical-boundaries-who-does-what&quot;&gt;Logical boundaries: Who does what?&lt;/h1&gt;
&lt;p&gt;Now group functionalities into logical boundaries. A boundary is a responsibility assignment. Which functionalities belong together? Which should be separate?&lt;/p&gt;
&lt;p&gt;The key question: who does what?&lt;/p&gt;
&lt;p&gt;For the order processing service:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;HTTP Handler: accept requests, return responses&lt;/li&gt;
&lt;li&gt;Core Logic: validate input, check inventory, calculate pricing&lt;/li&gt;
&lt;li&gt;Database Client: update database&lt;/li&gt;
&lt;li&gt;Payment Service: process payment&lt;/li&gt;
&lt;li&gt;Email Service: send confirmation email&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Each boundary has a job. Boundaries should be cohesive - related things stay together. They should minimize coupling - a boundary shouldn’t need to know about internals of other boundaries.&lt;/p&gt;
&lt;p&gt;This is where diagrams help. Draw boxes and arrows. Show who talks to whom. Not for documentation, but to see if your boundaries make sense. If the diagram is a mess, your thinking is a mess.&lt;/p&gt;
&lt;h1 id=&quot;development-organizing-the-code&quot;&gt;Development: Organizing the code&lt;/h1&gt;
&lt;p&gt;Now translate boundaries into code. Modules, components, subsystems - these are different granularity levels of the same concept. A module is a small unit of code. A subsystem is a collection of modules. An API is the interface between them.&lt;/p&gt;
&lt;p&gt;What matters is that each logical boundary has a home in the codebase.&lt;/p&gt;
&lt;p&gt;Each boundary should have:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A clear interface&lt;/li&gt;
&lt;li&gt;Internal implementation hidden&lt;/li&gt;
&lt;li&gt;Minimal surface area&lt;/li&gt;
&lt;li&gt;Stable contract&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Deep modules are better than shallow ones. A deep module does a lot behind a small interface. &lt;code&gt;open()&lt;/code&gt;, &lt;code&gt;read()&lt;/code&gt;, &lt;code&gt;write()&lt;/code&gt;, &lt;code&gt;close()&lt;/code&gt; is the classic example. Shallow modules expose internal complexity and force you to understand it.&lt;/p&gt;
&lt;p&gt;The UNIX generalization principle exemplifies deep abstraction. “Everything is a file” reduces diverse operations—disk, network, terminals, pipes—to a unified interface. This hides substantial complexity behind a minimal surface, enabling composition and reducing cognitive load. A shallow alternative would expose separate APIs for each resource type, increasing complexity and reducing composability.&lt;/p&gt;
&lt;p&gt;Dependencies should flow one way. If A depends on B, B shouldn’t depend on A. Cycles are coupling traps.&lt;/p&gt;
&lt;p&gt;How you organize the code depends on use cases and requirements.&lt;/p&gt;
&lt;h1 id=&quot;deployment-how-does-it-run&quot;&gt;Deployment: How does it run&lt;/h1&gt;
&lt;p&gt;Architecture isn’t just code structure. It’s also how the system runs in reality.&lt;/p&gt;
&lt;p&gt;Single process. Multi-threaded. Multi-process. Distributed. Each adds complexity. Each adds capability.&lt;/p&gt;
&lt;p&gt;Start simple. A single process with a thread pool is enough for most small to medium services. Add processes or services only when you have a clear reason: isolation, independent scaling, different deployment cycles.&lt;/p&gt;
&lt;p&gt;Distributed systems are an order of magnitude harder. Don’t go there until you have to.&lt;/p&gt;
&lt;h1 id=&quot;diagrams-are-tools-not-architecture&quot;&gt;Diagrams are tools, not architecture&lt;/h1&gt;
&lt;p&gt;MBSE (Model-Based Systems Engineering) has a lot of formalism. Activity diagrams. Internal block diagrams. Sequence diagrams. State machines. Some of this is useful. Most is overkill.&lt;/p&gt;
&lt;p&gt;What’s useful:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Understanding the system&lt;/li&gt;
&lt;li&gt;Seeing communication paths&lt;/li&gt;
&lt;li&gt;Identifying actors and use cases&lt;/li&gt;
&lt;li&gt;Exploring logical boundaries&lt;/li&gt;
&lt;li&gt;Checking if your design makes sense&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;What’s not useful:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Treating diagrams as the deliverable&lt;/li&gt;
&lt;li&gt;Formalism for its own sake&lt;/li&gt;
&lt;li&gt;Every possible diagram type&lt;/li&gt;
&lt;li&gt;Analysis paralysis&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Draw diagrams to think. Then write code.&lt;/p&gt;
&lt;h1 id=&quot;what-lisp-taught-me&quot;&gt;What Lisp taught me&lt;/h1&gt;
&lt;p&gt;When I discovered Lisp it changed how I think about systems for the better.&lt;/p&gt;
&lt;p&gt;Lisp has code-as-data. Your code is a data structure you can manipulate. Macros let you extend the language itself. You’re not stuck with what the language gives you - you can adapt it to your problem.&lt;/p&gt;
&lt;p&gt;This made me realize: rigid architectures exist because languages are rigid. If you can shape the language to your domain, boundaries become more fluid. You can build DSLs that express your problem directly.&lt;/p&gt;
&lt;p&gt;I’m not saying “rewrite everything in Lisp.” I’m saying: the right abstraction level makes architecture simpler. Sometimes that’s a module. Sometimes that’s a language feature. Sometimes that’s a DSL.&lt;/p&gt;
&lt;h1 id=&quot;risk-driven-design&quot;&gt;Risk-driven design&lt;/h1&gt;
&lt;p&gt;How much design upfront? Risk-driven architecture says: design enough to address the main risks, then start building.&lt;/p&gt;
&lt;p&gt;Big Design Up Front is waste. No design at all is technical debt. The middle ground is “just enough.”&lt;/p&gt;
&lt;p&gt;Just enough means:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Requirements are clear&lt;/li&gt;
&lt;li&gt;Use cases are defined&lt;/li&gt;
&lt;li&gt;Functionalities are listed&lt;/li&gt;
&lt;li&gt;Logical boundaries make sense&lt;/li&gt;
&lt;li&gt;Major risks are addressed&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Then build. Adjust as you learn.&lt;/p&gt;
&lt;h1 id=&quot;proof-of-concepts-build-to-understand&quot;&gt;Proof of Concepts: Build to understand&lt;/h1&gt;
&lt;p&gt;Don’t design everything in your head. Build small, throwaway versions to validate assumptions.&lt;/p&gt;
&lt;p&gt;PoCs answer questions: Is this approach feasible? Does this library work as advertised? Is this performance achievable? Do these boundaries actually make sense?&lt;/p&gt;
&lt;p&gt;Get something working first. A single process. A simple version. Understand the problem by solving it poorly, then refine.&lt;/p&gt;
&lt;p&gt;Design decisions that look good on paper often break in reality. PoCs reveal the truth before you commit.&lt;/p&gt;
&lt;p&gt;Work in sprints. Focus on one PoC per sprint. Validate assumptions, get feedback, iterate. Don’t spend months designing. Build, measure, learn. Adjust architecture based on what you discover.&lt;/p&gt;
&lt;h1 id=&quot;trade-offs-multiple-solutions-exist&quot;&gt;Trade-offs: Multiple solutions exist&lt;/h1&gt;
&lt;p&gt;For any architectural problem, there are multiple valid solutions. Single process vs multi-process. SQL vs NoSQL. Monolith vs microservices. Sync vs async.&lt;/p&gt;
&lt;p&gt;The question isn’t “which is best?” The question is “what are the trade-offs?”&lt;/p&gt;
&lt;p&gt;Build a trade-off matrix. List options. Identify criteria: complexity, performance, operational cost, team capability, time to market. Score each option. Make the trade-offs explicit.&lt;/p&gt;
&lt;p&gt;No solution is free. Every choice has costs. Architecture is about choosing which costs you’re willing to pay.&lt;/p&gt;
&lt;h1 id=&quot;rest-take-breaks&quot;&gt;REST! Take breaks&lt;/h1&gt;
&lt;p&gt;When your brain is tired, it’s impossible to discern good solutions from bad ones.&lt;/p&gt;
&lt;p&gt;Architecture requires clear thinking. If you’re stuck, step away. Sleep on it. Go for a walk. Come back fresh.&lt;/p&gt;
&lt;p&gt;The best architecture insights often come when you’re not staring at the problem.&lt;/p&gt;
&lt;h1 id=&quot;books-that-helped&quot;&gt;Books that helped&lt;/h1&gt;
&lt;p&gt;&lt;strong&gt;Design It!&lt;/strong&gt; by Michael Keeling taught me collaborative design and risk-driven architecture. Architecture isn’t a solo activity. It presents as a survey a lot of material I’ve learned through the years in a concise manner.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Release It!&lt;/strong&gt; by Michael Nygard taught me that production reality is harsh. Circuit breakers, bulkheads, timeouts, these are not an after thought. Your software will be under attack from the moment you deploy.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A Philosophy of Software Design&lt;/strong&gt; by John Ousterhout taught me about deep modules and complexity hiding.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Art of UNIX Programming&lt;/strong&gt; taught me a lot about the great ideas from the creators of Unix.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Designing Data-Intensive Applications&lt;/strong&gt; by Martin Kleppmann taught me about reliability and trade-offs in data systems.&lt;/p&gt;
&lt;h1 id=&quot;the-paradox-i-lived-in&quot;&gt;The paradox I lived in&lt;/h1&gt;
&lt;p&gt;I spent a lot of time confused. MBSE says to model everything with diagrams. Pragmatic programmers say to just build. Lisp showed me that flexibility comes from the right tools, not more diagrams.&lt;/p&gt;
&lt;p&gt;Here’s what I’ve landed on:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Requirements and use cases are non-negotiable&lt;/li&gt;
&lt;li&gt;Functionalities come first, then boundaries&lt;/li&gt;
&lt;li&gt;Diagrams help you think, they’re not the architecture&lt;/li&gt;
&lt;li&gt;How you organize code depends on the problem&lt;/li&gt;
&lt;li&gt;Simple systems deserve simple architectures&lt;/li&gt;
&lt;li&gt;Add complexity only when needed&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Architecture is not a framework. It’s not a diagram. It’s how you organize decisions so the system can evolve without falling apart.&lt;/p&gt;
&lt;p&gt;Start with requirements. Define functionalities. Draw boundaries. Write code. Deploy. Iterate.&lt;/p&gt;
&lt;p&gt;Keep it simple. Ship it.&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>SSH Configuration</title>
        <published>2024-12-29T00:00:00+00:00</published>
        <updated>2024-12-29T00:00:00+00:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://joaopinto.xyz/networking/ssh/"/>
        <id>https://joaopinto.xyz/networking/ssh/</id>
        
        <content type="html" xml:base="https://joaopinto.xyz/networking/ssh/">&lt;h1 id=&quot;introduction&quot;&gt;Introduction&lt;/h1&gt;
&lt;p&gt;The Secure Shell (SSH) protocol is a cryptographic network protocol
designed for secure communication over an unsecured network. It is
widely used for remote login and command-line execution, replacing
older, insecure protocols like Telnet and rsh. This guide will explain
how to configure SSH and manage keys.&lt;/p&gt;
&lt;h2 id=&quot;how-to-use-ssh-keys&quot;&gt;How To Use SSH Keys&lt;/h2&gt;
&lt;p&gt;SSH key-based authentication is more secure and convenient than passwords.
The client creates a private key and sends a public key to the server.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Create a Key Pair on the Client&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Run the following command to generate a new SSH key pair:&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; ssh-keygen&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; ed25519&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 100&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; ~/.ssh/id_ed25519&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;your_email@example.com&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will create two files:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;id_ed25519&lt;/code&gt;: The private key (keep this secure!)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;id_ed25519.pub&lt;/code&gt;: The public key&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Copy Public Key to the Server&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Use the ssh-copy-id tool to copy your public key to the server:&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; ssh-copy-id&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; ~/.ssh/id_ed25519.pub&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; user@127.0.2.1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Alternatively, manually append the public key to the server’s &lt;code&gt;~/.ssh/authorized_keys&lt;/code&gt; file:&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; cat&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; ~/.ssh/id_ed25519.pub&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; ~/.ssh/authorized_keys&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; chmod&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 600&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; ~/.ssh/authorized_keys&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Start the SSH Authentication Agent&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Start the agent to manage your keys:&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; eval&lt;/span&gt;&lt;span&gt; $(&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;ssh-agent&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;s&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;Add Your Private Key to the Agent&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Load your private key into the SSH agent:&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; ssh-add&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; ~/.ssh/id_ed25519&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Verify that the key has been added:&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; ssh-add&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;l&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;ssh-daemon-sshd-configuration-file&quot;&gt;SSH Daemon (sshd) Configuration File&lt;/h2&gt;
&lt;p&gt;The SSH daemon settings can be fully configured through its file located
at /etc/ssh/sshd_config. Open it with a text editor:&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; vi /etc/ssh/sshd_config&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Recommended settings:&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;PermitRootLogin no&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;PubkeyAuthentication yes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;AuthorizedKeysFile .ssh/authorized_keys&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;PasswordAuthentication no&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After modifying the configuration, restart the SSH daemon to apply changes.&lt;/p&gt;
&lt;p&gt;If you are using systemd, use:&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; systemctl restart sshd&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;verify-ssh-connection&quot;&gt;Verify SSH Connection&lt;/h2&gt;
&lt;p&gt;After setting up your keys and configuration, test your connection to the server:&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; ssh&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; user@server_ip&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;troubleshooting-common-issues&quot;&gt;Troubleshooting Common Issues&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Permissions Errors&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Ensure the following permissions on your SSH-related files:&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; chmod&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 700&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; ~/.ssh&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; chmod&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 600&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; ~/.ssh/id_rsa&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; chmod&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 644&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; ~/.ssh/id_rsa.pub&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Debugging Connection Issues&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Use verbose mode to diagnose issues:&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; ssh&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;vvv&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; user@server_ip&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;</content>
        
    </entry>
    <entry xml:lang="en">
        <title>CPU Cache</title>
        <published>2024-10-28T00:00:00+00:00</published>
        <updated>2024-10-28T00:00:00+00:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://joaopinto.xyz/systems/cpu-cache/"/>
        <id>https://joaopinto.xyz/systems/cpu-cache/</id>
        
        <content type="html" xml:base="https://joaopinto.xyz/systems/cpu-cache/">&lt;h1 id=&quot;what-is-cpu-cache&quot;&gt;What is CPU cache&lt;/h1&gt;
&lt;p&gt;CPU cache is a small but high-speed memory located on or near the processor core.
It is designed to store frequently accessed data and instructions, allowing the CPU
to retrieve them far more quickly than from the main memory. Modern CPUs have multiple
levels of cache (L1, L2, and L3), each balancing size and speed to optimize data
access speed and overall system performance.&lt;/p&gt;
&lt;h1 id=&quot;why-cpu-cache&quot;&gt;Why CPU cache&lt;/h1&gt;
&lt;p&gt;The main purpose of CPU cache is to reduce the time it takes for the CPU to retrieve
data from main memory by storing recently or frequently accessed data closer to the CPU.
Since cache memory is significantly faster than main memory, using cache reduces the latency
associated with memory access. This reduction in latency boosts the CPU’s ability to process
instructions efficiently, minimizing bottlenecks that arise due to slower main memory access speeds.&lt;/p&gt;
&lt;h2 id=&quot;the-memory-hierarchy&quot;&gt;The memory hierarchy&lt;/h2&gt;
&lt;p&gt;Memory hierarchy refers to the structured arrangement of storage within a computer system, organized by speed, size, and cost.&lt;/p&gt;
&lt;p&gt;The hierarchy goes as follows (from fastest to slowest):&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Registers&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Fastest and smallest storage located within the CPU&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;L1i/d, L2 and L3 Cache&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Multi-level caches that provide fast access to frequently used data. L1 being
the fastest and L3 the slowest.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Main memory (RAM)&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Larger but slower memory used to store data and instructions currently in
use by the system.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Longterm storage (Flash, Spinning disk)&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Non-volatile storage that holds data long-term, access is slower compared
to RAM.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Remote storage (Internet)&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Usually slower than secondary storage due to the latency caused by the
overhead of the communications between computers.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;So, cache memory sits between the CPU and the main memory, serving as a fast
buffer that stores copies of frequently accessed intructions and data, thus
reducing the time it takes for the CPU to retrieve data.&lt;/p&gt;
&lt;h1 id=&quot;before-cpu-cache&quot;&gt;Before CPU cache&lt;/h1&gt;
&lt;p&gt;Before the introduction of CPU caches, processors had to fetch data directly
from main memory for every operation. This process was slow and inefficient due
to the significant speed difference between the CPU and main memory. As CPU speeds
increased this disparity became more pronounced leading to performance bottlenecks.&lt;/p&gt;
&lt;h1 id=&quot;comparison-of-speed&quot;&gt;Comparison of speed&lt;/h1&gt;
&lt;p&gt;Here’s a comparison of typical access times across different levels of the memory
hierarchy, note that this values are hardware dependant so this is just to give a general idea:&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Memory Type&lt;/th&gt;&lt;th&gt;Access Time&lt;/th&gt;&lt;th&gt;N cycles&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Registers&lt;/td&gt;&lt;td&gt;0.2 - 1 ns&lt;/td&gt;&lt;td&gt;1 cycle&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;L1 cache&lt;/td&gt;&lt;td&gt;0.5 - 3 ns&lt;/td&gt;&lt;td&gt;1 - 3 cycles&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;L2 cache&lt;/td&gt;&lt;td&gt;5 - 20 ns&lt;/td&gt;&lt;td&gt;15 - 60 cycles&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;L3 cache&lt;/td&gt;&lt;td&gt;10 - 40 ns&lt;/td&gt;&lt;td&gt;30 - 120 cycles&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Main memory (DRAM)&lt;/td&gt;&lt;td&gt;50 - 100 ns&lt;/td&gt;&lt;td&gt;150 - 300 cycles&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Solid-State drive&lt;/td&gt;&lt;td&gt;10 - 100 μs&lt;/td&gt;&lt;td&gt;30,000 - 300,000 cycles&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Hard-Disk drive&lt;/td&gt;&lt;td&gt;5 - 20 ms&lt;/td&gt;&lt;td&gt;15,000,000 - 60,000,000 cycles&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Cache memory provides much faster access times compared to main memory, which
is why it is crucial for reducing latency and improving the performance of the CPU.&lt;/p&gt;
&lt;h1 id=&quot;how-cpu-cache-works&quot;&gt;How CPU cache works&lt;/h1&gt;
&lt;h2 id=&quot;cache-lines-cache-hits-and-misses&quot;&gt;Cache lines, cache hits and misses&lt;/h2&gt;
&lt;p&gt;CPU cache operates by storing copies of data from frequently accessed main
memory locations. When the CPU needs to access data, it first checks whether
the data is available in the cache. If the data is found (&lt;strong&gt;cache hit&lt;/strong&gt;),
it is returned quickly. If the data is not found (&lt;strong&gt;cache miss&lt;/strong&gt;), the CPU must
fetch the data from the slower main memory.&lt;/p&gt;
&lt;p&gt;Modern CPUs don’t just fetch the exact data needed for a particular instruction
when accessing memory. Instead, they fetch an entire &lt;strong&gt;cache line&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;A cache line is a contiguous block of memory, typically ranging from 32 to 128
bytes in size, depending on the processor’s architecture. The idea is that when
one piece of data is accessed, the data adjacent to it is also likely to be
accessed soon (this is known as spatial locality).&lt;/p&gt;
&lt;p&gt;By fetching the entire cache line, the CPU increases the chances of future
accesses resulting in cache hits, thereby reducing the need for further memory accesses.&lt;/p&gt;
&lt;p&gt;For example, when accessing an element of an array, it is highly probable that
nearby elements will also be accessed shortly. By loading the entire cache line,
the CPU can serve future requests directly from the cache, which significantly
speeds up data retrieval.&lt;/p&gt;
&lt;p&gt;This strategy enhances the overall efficiency of the cache system by reducing
the number of cache misses, particularly the compulsory misses (those that occur
the first time a data item is accessed).&lt;/p&gt;
&lt;h2 id=&quot;cache-temporal-locality-and-spatial-locality&quot;&gt;Cache temporal locality and spatial locality&lt;/h2&gt;
&lt;p&gt;Cache performance is heavily influenced by the principles of temporal locality
and spatial locality:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Temporal Locality&lt;/strong&gt;: recently accessed data is likely to be accessed again
soon. Caches take advantage of temporal locality by storing recently accessed
data, anticipating that the CPU will need it again.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Spatial Locality&lt;/strong&gt;: data located near recently accessed data is likely to be
accessed soon. Caches utilize spatial locality by storing blocks of data that
include the requested information and adjacent memory addresses.&lt;/p&gt;
&lt;h2 id=&quot;the-3-c-s-of-cache-misses&quot;&gt;The 3 C’s of cache misses&lt;/h2&gt;
&lt;p&gt;Cache misses can be categorized into three types, known as the 3 C’s:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Compulsory Misses&lt;/strong&gt;: when data is accessed for the first time and must be loaded into the cache.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Capacity Misses&lt;/strong&gt;: when the cache is too small to hold all the data required
by the CPU, leading to some data being evicted and causing misses.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Conflict Misses&lt;/strong&gt;: these occur in set-associative or direct-mapped caches when
multiple data items compete for the same cache line, leading to evictions and misses&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;replacement-algorithms&quot;&gt;Replacement Algorithms&lt;/h2&gt;
&lt;p&gt;When the cache is full, something has to be trashed to make room for new data.
The choice depends on which replacement algorithm is used:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;FIFO&lt;/strong&gt;: The oldest data gets replaced. Not very good.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;LRU&lt;/strong&gt;: The data that hasn’t been used for the longest time gets replaced. Most
commonly used in multitasking environments.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;LFU&lt;/strong&gt;: The least accessed data gets replaced. Can be useful in some embedded scenarios
where a computer is frequently doing something.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Random&lt;/strong&gt;: A random block is replaced, which is the simplest and cheaper to implement.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;cpu-cache-address-and-tag&quot;&gt;CPU Cache Address and Tag&lt;/h2&gt;
&lt;p&gt;The cache address and tag system is used to quickly determine whether the data
the CPU needs is available (or not) in the cache. This process is fundamental to how
caches operate, and it works differently depending on the type of cache
organization algorithm (fully associative, direct mapped, or set-associative).&lt;/p&gt;
&lt;h2 id=&quot;fully-associative-vs-direct-mapped-vs-set-associative-cache&quot;&gt;Fully Associative vs Direct Mapped vs Set-Associative Cache&lt;/h2&gt;
&lt;p&gt;There are three main algorithms that determine how data is stored and retrieved:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Fully Associative Cache&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;How it works: Any memory block can be stored in any cache line, giving maximum flexibility in placement.&lt;/li&gt;
&lt;li&gt;Tag Comparison: The CPU compares the tag in every cache line to find a match, making this process complex and costly.&lt;/li&gt;
&lt;li&gt;Use Case: Used in small caches where flexibility and avoiding misses is more important than cost.&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;&lt;strong&gt;Direct Mapped Cache&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;How it works: Each memory block has only one possible location in the cache, determined by a part of its address.&lt;/li&gt;
&lt;li&gt;Tag Comparison: The CPU only checks the tag for that specific line, making comparison simple and fast.&lt;/li&gt;
&lt;li&gt;Drawback (Trashing): Frequent evictions can occur if multiple memory blocks map to the same line, reducing performance.&lt;/li&gt;
&lt;li&gt;Use Case: Cost-effective design, useful for simpler systems.&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;&lt;strong&gt;Set-Associative Cache&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;How it works: Cache is divided into “sets.” Each block of memory can be stored in any line within a designated set.&lt;/li&gt;
&lt;li&gt;Tag Comparison: The CPU checks tags of all lines in a set, providing flexibility with moderate complexity.&lt;/li&gt;
&lt;li&gt;Use Case: Most common in modern CPUs as it balances cost and performance.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;NOTE: At the hardware level, cache misses can be reduced by changing capacity, block size,
and/or N-set associativity.&lt;/p&gt;
&lt;h2 id=&quot;cpu-cache-flag-bits&quot;&gt;CPU Cache Flag Bits&lt;/h2&gt;
&lt;p&gt;Flag bits are used in each cache line to track the status of the data:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Valid Bit: Indicates if the data in the cache line is valid (usable).&lt;/li&gt;
&lt;li&gt;Dirty Bit: Shows if the data has been modified. If dirty, it needs to be written back to memory before replacement.&lt;/li&gt;
&lt;li&gt;LRU Bit(s): Used in caches with replacement policies to track the “least recently used” line, helping decide which data to evict when new data comes in.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;cache-write-policies&quot;&gt;Cache Write Policies&lt;/h2&gt;
&lt;p&gt;A cache write policy defines how data is written to the main memory once it is written to the cache.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Write-Through: Data is written to both the cache and main memory at the same time. This is simple and ensures consistency but can be slower.&lt;/li&gt;
&lt;li&gt;Write-Back: Data is written to the cache only and written to memory later, when it’s replaced. This is faster but needs the dirty bit to ensure modified data is written back.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;unified-vs-split-caches&quot;&gt;Unified vs Split Caches&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Unified Cache: Stores both instructions and data. This is more space-efficient but can lead to contention if instructions and data are frequently needed at the same time.&lt;/li&gt;
&lt;li&gt;Split Cache: Divides L1 cache into separate caches for instructions and data (L1i and L1d). This speeds up access by reducing contention but requires more cache space.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;overview-data-structure-alignment&quot;&gt;Overview: Data Structure Alignment&lt;/h2&gt;
&lt;p&gt;Aligned data means data is stored at memory addresses that match its size (e.g., 4-byte integer at an address divisible by 4). Proper alignment speeds up access and reduces cache misses because misaligned data might span multiple cache lines, increasing access time.&lt;/p&gt;
&lt;h2 id=&quot;overview-virtual-memory-effect-on-cpu-cache&quot;&gt;Overview: Virtual Memory Effect on CPU Cache&lt;/h2&gt;
&lt;p&gt;Virtual memory uses addresses mapped to physical memory, which can affect cache efficiency due to aliasing (where different virtual addresses refer to the same physical address). Techniques like TLBs (Translation Lookaside Buffers) and page coloring help manage this by keeping virtual memory organized and reducing unnecessary cache invalidations.&lt;/p&gt;
&lt;h2 id=&quot;overview-cpu-pipelining-effect-on-cpu-cache&quot;&gt;Overview: CPU Pipelining Effect on CPU Cache&lt;/h2&gt;
&lt;p&gt;In pipelined CPUs, each instruction phase (fetch, decode, execute) happens in parallel. If there’s a cache miss, it can stall the pipeline, slowing down all stages.&lt;/p&gt;
&lt;p&gt;Non-blocking caches help reduce stalls by allowing the pipeline to continue executing while fetching from memory.&lt;/p&gt;
&lt;h2 id=&quot;overview-cpu-branch-preduction-correlation-with-cpu-cache&quot;&gt;Overview: CPU Branch Preduction correlation with CPU Cache&lt;/h2&gt;
&lt;p&gt;Branch prediction can lead to cache pollution if predictions are incorrect. When the CPU loads instructions based on a predicted path that turns out to be wrong, it wastes cache space, potentially evicting useful data.&lt;/p&gt;
&lt;p&gt;Prefetching only high-confidence branches can help reduce this effect.&lt;/p&gt;
&lt;h2 id=&quot;example-e31-core-with-freertos-data-structures&quot;&gt;Example: E31 Core with FreeRTOS Data Structures:&lt;/h2&gt;
&lt;p&gt;In the SiFive E31 core running FreeRTOS, the operating system frequently accesses task control blocks (TCBs). When multiple tasks are running, frequently accessed TCBs stay in the cache, improving task-switching speed.&lt;/p&gt;
&lt;p&gt;Using small, aligned TCB structures ensures fewer cache misses and better cache utilization.&lt;/p&gt;
&lt;h1 id=&quot;references&quot;&gt;References&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;Harris, S. L., &amp;amp; Harris, D. M. (2021). Digital design and computer architecture: RISC-V edition. Morgan Kaufmann.&lt;/li&gt;
&lt;li&gt;Patterson, D. A., &amp;amp; Waterman, A. (2020). &lt;em&gt;Computer organization and design RISC-V edition: The hardware software interface&lt;/em&gt; (2nd ed.). Morgan Kaufmann.&lt;/li&gt;
&lt;li&gt;Hennessy, J. L., &amp;amp; Patterson, D. A. (2017). &lt;em&gt;Computer architecture: A quantitative approach&lt;/em&gt; (6th ed.). Morgan Kaufmann.&lt;/li&gt;
&lt;/ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Linux Audio Guide</title>
        <published>2024-08-18T00:00:00+00:00</published>
        <updated>2024-08-18T00:00:00+00:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://joaopinto.xyz/linux/audio/"/>
        <id>https://joaopinto.xyz/linux/audio/</id>
        
        <content type="html" xml:base="https://joaopinto.xyz/linux/audio/">&lt;h1 id=&quot;understanding-current-audio-solutions&quot;&gt;Understanding Current Audio Solutions&lt;/h1&gt;
&lt;p&gt;There are three commonly discussed audio abstraction layers in Linux:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Pulseaudio&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;Created as a modern replacement for Enlightenment Sound Daemon (ESD),
it provides advanced features like per-application volume control and network audio streaming.&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Jack&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;Designed as a professional audio server for Linux, it offers low-latency audio
processing and precise control over audio inputs and outputs, making it suitable
for professional audio work.&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Pipewire&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;The newest abstraction layer, Pipewire integrates seamlessly with both
Pulseaudio and Jack.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;understanding-the-stack&quot;&gt;Understanding the Stack&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;Kernel layer&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The kernel layer provides hardware abstraction. Advanced Linux Sound Architecture (ALSA)
is the primary component that interacts with sound cards and manages communication,
replacing the older Open Sound System (OSS). Thus, all three abstraction layers
previously refered must communicate with ALSA.&lt;/p&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Middleware/Backend layer&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;ALSA Library (libasound): Provides a userspace interface to interact with ALSA.&lt;/p&gt;
&lt;p&gt;Problem: ALSA is specific to Linux. What about other operating systems?&lt;/p&gt;
&lt;p&gt;Solution: The need for cross-platform support led to the creation of sound servers like Pulseaudio,
which works on UNIX like operating systems and even on Windows.&lt;/p&gt;
&lt;h1 id=&quot;so-which-one-do-i-use&quot;&gt;So which one do I use?&lt;/h1&gt;
&lt;p&gt;You might be asking if you really need sound servers/abtraction layers over ALSA
to get audio working on Linux. The short answer is: &lt;strong&gt;no&lt;/strong&gt;. The correct answer
is: &lt;strong&gt;you should use a sound server&lt;/strong&gt; (spoiler: PipeWire).&lt;/p&gt;
&lt;p&gt;End users can directly use ALSA if they wish and even have pseudo-pulseaudio emulation
with &lt;code&gt;apulse&lt;/code&gt; software.&lt;/p&gt;
&lt;p&gt;But, and this is according to my personal experience, it is highly recommended
that you use a sound server, specifically PipeWire and I will explain you why.&lt;/p&gt;
&lt;p&gt;By default, ALSA comes with a very poor configuration, and does not (by default) support
mixing of multiple streams. You can configure ALSA with various
plugins that enable this feature such as &lt;code&gt;dmix&lt;/code&gt;, &lt;code&gt;dsnoop&lt;/code&gt;, etc.&lt;/p&gt;
&lt;p&gt;It is a very tiresome thing to do because even if you apparently configure things
properly you will always come accross some problem sooner or later.&lt;/p&gt;
&lt;p&gt;Pulseaudio does one thing well: it sets a nice ALSA configuration by default,
using its own plugin called &lt;code&gt;pulse&lt;/code&gt;, which has multiple stream mixing without
having to configure a single thing.&lt;/p&gt;
&lt;p&gt;However (and once again I will speak from experience) when you start doing more
things such as bluetooth audio or want to re-route audio you will find yourself
stuck with pulseaudio, because when it was initally designed it did not prioritize
these things. If one wanted to do professional audio, one had to install JACK most
likely with pulseaudio already installed, this was a mess.&lt;/p&gt;
&lt;h1 id=&quot;pipewire&quot;&gt;PipeWire&lt;/h1&gt;
&lt;p&gt;PipeWire aims to replace both PulseAudio and JACK by providing a unified solution
for audio and video handling.&lt;/p&gt;
&lt;p&gt;It provides a handful of benefits such as:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;ALSA, PulseAudio and JACK compatibility&lt;/li&gt;
&lt;li&gt;Low-latency audio&lt;/li&gt;
&lt;li&gt;Simplified setup&lt;/li&gt;
&lt;li&gt;Bluetooth audio support&lt;/li&gt;
&lt;li&gt;Modular architecture&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Therefore, if you want the best possible audio experience on Linux, install PipeWire.&lt;/p&gt;
&lt;h2 id=&quot;pipewire-prerequisites&quot;&gt;PipeWire prerequisites&lt;/h2&gt;
&lt;p&gt;PipeWire requires three things to work properly:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;D-Bus user&lt;/strong&gt; session bus&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;for inter-process communication and session management&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;&lt;strong&gt;XDG_RUNTIME_DIR&lt;/strong&gt; environment variable&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;for creating a runtime directory to store temporary files and session-specific data&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Pipewire session and policy manager&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;wireplumber&lt;/code&gt; is the most commonly used&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;p&gt;NOTE: If your DE/WM/Wayland compositor is not configured to provide a D-Bus user session bus,
you have two options: run a dbus session alongside it&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; .xinitrc&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;exec&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; dbus-run-session&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; mywm&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;or enable the &lt;code&gt;dbus.socket&lt;/code&gt;/&lt;code&gt;dbus-broker.service&lt;/code&gt; user service (preferred if your
init provides one, e.g. systemd or runit) so the session bus is always available
regardless of how you start your WM/compositor.&lt;/p&gt;
&lt;p&gt;NOTE: To set &lt;code&gt;XDG_RUNTIME_DIR&lt;/code&gt; manually you may paste the following in your .profile:&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; .profile&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;if&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; -z&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt;XDG_RUNTIME_DIR&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt; ]&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	XDG_RUNTIME_DIR&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;/tmp/&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;-runtime-dir&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;	mkdir&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;pm&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 0700&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt;XDG_RUNTIME_DIR&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;	export&lt;/span&gt;&lt;span&gt; XDG_RUNTIME_DIR&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;pipewire-setup&quot;&gt;PipeWire setup&lt;/h2&gt;
&lt;p&gt;Install &lt;code&gt;pipewire&lt;/code&gt; and a PipeWire session manager &lt;code&gt;wireplumber&lt;/code&gt;. Additionally, I recommend
installing &lt;code&gt;alsa-pipewire&lt;/code&gt; to synchronize ALSA audio control with PipeWire’s.&lt;/p&gt;
&lt;p&gt;PipeWire runs as user services, not system services. You need to enable and
start 3 of them: &lt;code&gt;pipewire&lt;/code&gt;, &lt;code&gt;pipewire-pulse&lt;/code&gt; (the PulseAudio compatibility
layer) and &lt;code&gt;wireplumber&lt;/code&gt; (the session/policy manager).&lt;/p&gt;
&lt;p&gt;If you are using systemd, use:&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; systemctl&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;-user&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; enable&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;-now&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; pipewire&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; pipewire-pulse&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; wireplumber&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;bluetooth&quot;&gt;Bluetooth&lt;/h2&gt;
&lt;p&gt;Install &lt;code&gt;bluez&lt;/code&gt; and enable &lt;code&gt;bluetoothd&lt;/code&gt; to get access to bluetoothctl and other utilities,
PipeWire bluetooth support is built-in and works really well in my experience, with full
support for LDAC (A2DP sink) for my Sony WH-1000XM4.&lt;/p&gt;
&lt;h2 id=&quot;resources&quot;&gt;Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;https://docs.voidlinux.org/config/media/pipewire.html&lt;/li&gt;
&lt;li&gt;https://wiki.archlinux.org/title/PipeWire&lt;/li&gt;
&lt;li&gt;https://docs.voidlinux.org/config/bluetooth.html&lt;/li&gt;
&lt;li&gt;https://wiki.archlinux.org/title/Bluetooth&lt;/li&gt;
&lt;li&gt;https://pipewire.org/&lt;/li&gt;
&lt;/ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>inici(os)</title>
        <published>2024-06-02T00:00:00+00:00</published>
        <updated>2024-06-02T00:00:00+00:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://joaopinto.xyz/systems/inicios/"/>
        <id>https://joaopinto.xyz/systems/inicios/</id>
        
        <content type="html" xml:base="https://joaopinto.xyz/systems/inicios/">&lt;h1 id=&quot;introduction-the-problem&quot;&gt;Introduction: The Problem&lt;/h1&gt;
&lt;p&gt;The growing complexity and size of modern software is a significant issue, which
I have discussed previously in “Modern Software is a disaster”.&lt;/p&gt;
&lt;p&gt;Today, software tends to be bloated, with enormous and complex codebases that can
consist of tens of millions of lines of code and intricate dependency trees, often
just to perform simple tasks.&lt;/p&gt;
&lt;p&gt;It wasn’t always like this. In the past, when computers had limited processing
power, developers had less freedom and were compelled to solve problems in more
efficient ways.&lt;/p&gt;
&lt;h2 id=&quot;modern-software-design&quot;&gt;Modern Software Design&lt;/h2&gt;
&lt;p&gt;Modern software design is fundamentally flawed. Theories such as Object-Oriented
Design and Domain-Driven Design often fail in practice because they do not align
with how computers actually work. The domain should be the memory, and the design
should focus on code and data structures.&lt;/p&gt;
&lt;p&gt;These theories often introduce new problems, including maintainability issues,
poor performance, lack of security, and degraded user experience.&lt;/p&gt;
&lt;h2 id=&quot;kernel-design-drivers&quot;&gt;Kernel Design: Drivers&lt;/h2&gt;
&lt;p&gt;Whether developing monolithic or microkernels, much of the focus seems to be on
driver development rather than actual innovation.&lt;/p&gt;
&lt;p&gt;When something doesn’t work, the solution is often to write a new driver. This
approach creates a bottomless pit of complexity, as there will always be new
hardware to support, leading to more and more lines of code.&lt;/p&gt;
&lt;hr /&gt;
&lt;h1 id=&quot;rationale-how-to-solve-it&quot;&gt;Rationale: How to Solve it&lt;/h1&gt;
&lt;h2 id=&quot;proper-design-bottom-up-approach&quot;&gt;Proper Design: Bottom-up Approach&lt;/h2&gt;
&lt;p&gt;Many developers have the mindset of adding layers on top of existing systems to
fix problems. This approach is not inherently wrong but cannot be applied universally.&lt;/p&gt;
&lt;p&gt;An analogy is when something breaks, you have two choices: patch it up with duct
tape and hope it holds (and add more tape if it doesn’t), or evaluate why it broke
in the first place. Maybe the materials were unsuitable, or it was used incorrectly.
We might need to create a new component to handle the task properly.&lt;/p&gt;
&lt;p&gt;While this may seem simplistic, it illustrates that modern software often uses
tools that are not ideal for the job, leading to suboptimal solutions.&lt;/p&gt;
&lt;p&gt;To effectively solve these issues, we must evaluate our choices from the ground
up, avoiding unnecessary bloat.&lt;/p&gt;
&lt;h2 id=&quot;if-a-does-x-better-than-b-use-a&quot;&gt;If “A” does “X” better than “B”, use “A”&lt;/h2&gt;
&lt;p&gt;This principle is self-explanatory: we should use the best tool for the job. By
doing so, productivity is increased, and we avoid relying on multiple suboptimal
software projects.&lt;/p&gt;
&lt;p&gt;For example, if I want to display the contents of a file, I should use the best
tool available for that task. The same applies to editing a file, etc.&lt;/p&gt;
&lt;h2 id=&quot;keeping-it-stupid-simple-kiss&quot;&gt;Keeping It Stupid Simple (KISS)&lt;/h2&gt;
&lt;p&gt;A key principle in writing good software is to keep it simple. We should always
seek the simplest way to achieve our goals. The philophy is: “if something can
be simplified, it will get simplied”.&lt;/p&gt;
&lt;p&gt;This principle applies to both the design and implementation stages. For example,
instead of performing extensive computations, we might pre-calculate and store
data for quick access.&lt;/p&gt;
&lt;p&gt;It’s also crucial to stay focused when developing a feature and avoid adding
unnecessary functionalities. This aligns with the original UNIX design principles.&lt;/p&gt;
&lt;h2 id=&quot;how-many-loc-does-it-take-to-do-x&quot;&gt;How Many LOC Does It Take to Do “X”&lt;/h2&gt;
&lt;p&gt;Another important consideration is achieving functionality with the fewest lines
of code possible, without sacrificing readability or performance.&lt;/p&gt;
&lt;hr /&gt;
&lt;h1 id=&quot;os-specific&quot;&gt;OS Specific&lt;/h1&gt;
&lt;p&gt;These design philosophies still apply to other software, but here I am talking
specifically about Operating Systems.&lt;/p&gt;
&lt;h2 id=&quot;bare-bones-bootloader&quot;&gt;Bare-Bones Bootloader&lt;/h2&gt;
&lt;p&gt;Avoid multi-stage bootloaders and complex boot protocols (unless absolutely
necessary).&lt;/p&gt;
&lt;p&gt;No initial ram disk or anything similar. The goal is to boot as fast as possible
with as less drag as possible.&lt;/p&gt;
&lt;h2 id=&quot;modular-design&quot;&gt;Modular Design&lt;/h2&gt;
&lt;p&gt;This principle tells us to break the problem down in well-defined, independent
modules each with a single responsability and communicate through simple and
well-defined interfaces.&lt;/p&gt;
&lt;p&gt;We need to separate the kernel, filesystem, multitasking, hardware interaction,
etc. Set as a goal: a ridiculous low amount of lines of code to do “X”. The less
you write, the better (without sacrificing performance, of course).&lt;/p&gt;
&lt;h2 id=&quot;zero-drivers&quot;&gt;Zero Drivers&lt;/h2&gt;
&lt;p&gt;As previously mentioned, drivers are a major source of complexity in modern
operating systems. We could look to embedded systems for inspiration on how to
build an OS with zero drivers.&lt;/p&gt;
&lt;h2 id=&quot;restrictive-multitasking&quot;&gt;“Restrictive” multitasking&lt;/h2&gt;
&lt;p&gt;Multitasking is not inherently bad, but modern operating systems often run too
many tasks simultaneously. For a consumer/desktop OS, I might only want to run
2 or 3 tasks at a time. This allows us to simplify the pre-emptive multitasking
algorithm while still supporting multiple tasks when necessary.&lt;/p&gt;
&lt;h2 id=&quot;different-os-for-different-purposes&quot;&gt;Different OS for different purposes&lt;/h2&gt;
&lt;p&gt;I don’t want a general-purpose OS; I want an OS tailored to my specific use case.
For example, if I’m using it on a desktop, I don’t need it to function as a server
OS. This specialization simplifies the entire OS stack.&lt;/p&gt;
&lt;h2 id=&quot;small-os-layer&quot;&gt;Small OS layer&lt;/h2&gt;
&lt;p&gt;The OS layer should be as minimal as possible. While POSIX provides a standard
interface, it may be too large for what I intend.&lt;/p&gt;
&lt;p&gt;Only the essential features should be implemented in the kernel and non essential
features should be moved to userspace. In theory this simplifies kernel development
and improves security (which may be irrelevant considering other design choices).&lt;/p&gt;
&lt;p&gt;Use static linking for the kernel to avoid the complexity associated with dynamically
linking a kernel.&lt;/p&gt;
&lt;h2 id=&quot;single-user&quot;&gt;Single User&lt;/h2&gt;
&lt;p&gt;Focus on single-user environment. This provides a great oportunity to simplify
security and permission models.&lt;/p&gt;
&lt;hr /&gt;
&lt;h1 id=&quot;conclusion-thoughts-and-moving-forward&quot;&gt;Conclusion: thoughts and moving forward&lt;/h1&gt;
&lt;h2 id=&quot;arm-and-risc-v-a-new-oportunity&quot;&gt;ARM and RISC-V: a new oportunity&lt;/h2&gt;
&lt;p&gt;With the advent of new ARM SoCs and RISC-V processors, there is a tremendous
opportunity to apply these principles and develop more efficient operating systems.&lt;/p&gt;
&lt;p&gt;If I am aiming for “zero drivers”, my OS will be dependant on a specific computer,
which immediately removes thousands of esoteric hardware written in the kernel.&lt;/p&gt;
&lt;p&gt;If then a user wants to communicate with other external hardware, more software
will be developed; I dont consider it a “driver” simply because it wont be written
at the kernel space but instead at the user space.&lt;/p&gt;
&lt;p&gt;“But what does that solve?” You ask. Well, by writing this external modules outside
of the kernel to communicate with your hardware it means the kernel will always
remain slim with no extra driver bloat you dont need.&lt;/p&gt;
</content>
        
    </entry>
</feed>
