<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Kemal Akkoyun on Medium]]></title>
        <description><![CDATA[Stories by Kemal Akkoyun on Medium]]></description>
        <link>https://medium.com/@kakkoyun?source=rss-febaa23a70e9------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*3FL0muvUYXza0HnAyNwujg.jpeg</url>
            <title>Stories by Kemal Akkoyun on Medium</title>
            <link>https://medium.com/@kakkoyun?source=rss-febaa23a70e9------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Fri, 19 Jun 2026 20:33:35 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@kakkoyun/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[Vibe Coding with Cursor: My R&D Week Adventure ]]></title>
            <link>https://medium.com/@kakkoyun/vibe-coding-with-cursor-my-r-d-week-adventure-28c5a7b92aff?source=rss-febaa23a70e9------2</link>
            <guid isPermaLink="false">https://medium.com/p/28c5a7b92aff</guid>
            <category><![CDATA[cursor]]></category>
            <category><![CDATA[vibe-coding]]></category>
            <category><![CDATA[ai]]></category>
            <dc:creator><![CDATA[Kemal Akkoyun]]></dc:creator>
            <pubDate>Wed, 12 Mar 2025 00:00:58 GMT</pubDate>
            <atom:updated>2025-05-08T21:00:08.084Z</atom:updated>
            <content:encoded><![CDATA[<blockquote><em>TL;DR: Spent a week building cool stuff with </em><a href="https://cursor.com"><em>Cursor</em></a><em>, an AI-powered IDE. Found it surprisingly effective for both coding and managing my </em><a href="https://www.buildingasecondbrain.com/"><em>second brain</em></a><em>. When your requirements are clear, it’s almost magical! ✨</em></blockquote><h3>The Setup: R&amp;D Week Vibes</h3><p>You know that feeling when R&amp;D week rolls around, and you’re caught between “I should learn something useful” and “I want to have fun”? Well, this time I decided to combine both by diving deep into <a href="https://cursor.com">Cursor</a>, an AI-powered code editor that’s been making waves in the developer community.</p><p>The mission was simple: Use Cursor for <strong>everything</strong> — from managing my notes to building small task-specific projects. And by everything, I mean <em>everything</em>.</p><h3>What Makes Cursor Different?</h3><p>Unlike traditional IDEs that just help you write code, Cursor feels more like having a pair programmer who actually gets your context. It’s built on top of VSCode (so you get all the good stuff you’re used to) but adds a layer of AI-powered features that make development feel more… vibey? 😎</p><h3>The Good Parts</h3><ol><li><strong>Context-Aware AI</strong>: The AI understands your project structure and can help with everything from code completion to refactoring. For example, when working on a React component, it automatically suggested appropriate hooks and state management patterns based on my component’s purpose. When your requirements are clear, it’s almost magical how it can scaffold projects and implement patterns!</li><li><a href="https://docs.cursor.com/context/rules-for-ai"><strong>Rules Feature</strong></a>: This is where things get interesting. You can create custom rules and context for different types of work, both at the project and global level. Think project-specific coding standards, documentation patterns, and even architecture guidelines.</li><li><a href="https://docs.cursor.com/beta/notepads"><strong>Notepads</strong></a>: Quick thoughts? Code snippets? The notepad feature is like having a smart scratchpad that understands code and can share context between different parts of your development workflow.</li></ol><h3>Second Brain Management: A Pleasant Surprise</h3><p>One of my unexpected discoveries was how well Cursor handles note-taking and <a href="https://www.buildingasecondbrain.com/">second brain</a> management. Here’s what made it click for me:</p><h3>The Rules Feature: A Game Changer</h3><p>The rules feature deserves its own spotlight. Cursor offers two powerful ways to customize AI behavior (note that the older .cursorrules file is being deprecated in favor of this new system):</p><ol><li><strong>Project Rules</strong> (.cursor/rules directory):</li></ol><ul><li>Semantic descriptions for specific use cases</li><li>File pattern matching with glob patterns</li><li>Automatic attachment when matching files are referenced</li><li>Chain multiple rules using @file references</li><li>Version controlled with your project</li><li>Create new rules via command palette (Cmd + Shift + P &gt; New Cursor Rule)</li></ul><ol><li><strong>Global Rules</strong> (Cursor Settings):</li></ol><ul><li>Applied across all projects</li><li>Perfect for consistent preferences</li><li>Control output language and response style</li><li>Set universal development guidelines</li></ul><p>Pro tip: Use project rules whenever possible — they’re more flexible, can be version controlled, and provide better granular control over different parts of your project.</p><p>I’ve set up different contexts for various types of work:</p><ul><li>Technical blog posts (with specific writing guidelines)</li><li>Project documentation (with architecture patterns)</li><li>Personal notes (with custom templates)</li><li>Code standards (with framework-specific rules)</li></ul><p>Each context comes with its own set of rules and AI behavior. It’s like having multiple specialized assistants at your disposal.</p><h3>Notepads: Beyond Simple Notes</h3><p>The Notepads feature (currently in beta) has been a revelation. Think of them as enhanced reference documents that go beyond regular .cursorrules. I use them for:</p><ol><li><strong>Dynamic Boilerplate Generation</strong>:</li></ol><ul><li>Templates for common code patterns</li><li>Project-specific scaffolding rules</li><li>Consistent code structure templates</li></ul><ol><li><strong>Architecture Documentation</strong>:</li></ol><ul><li>Frontend specifications</li><li>Backend design patterns</li><li>Data model documentation</li></ul><ol><li><strong>Development Guidelines</strong>:</li></ol><ul><li>Team conventions</li><li>Best practices</li><li>Project-specific rules</li></ul><p>The ability to share context between composers and chat interactions makes them incredibly powerful. Plus, you can attach files and use @ mentions to create a web of connected knowledge.</p><h3>Small Projects, Big Impact</h3><p>During the week, I worked on several small, task-specific projects. The workflow typically went like this:</p><ol><li>Create a new project with clear requirements</li><li>Set up project-specific rules and templates</li><li>Let the AI handle boilerplate and routine coding</li><li>Focus on architecture and edge cases</li></ol><p>The AI handled a lot of the repetitive work, letting me focus on the creative aspects of each project. The clearer my requirements were, the more magical the results became. ✨</p><h3>Lessons Learned</h3><ol><li><strong>AI-Powered Doesn’t Mean AI-Dependent</strong>: Cursor enhances your workflow without taking over.</li><li><strong>Rules Are Your Friend</strong>: Taking time to set up proper rules pays off immensely.</li><li><strong>Context is King</strong>: The more context you provide, the better the AI assistance becomes.</li><li><strong>Second Brain Benefits</strong>: It’s not just for coding; it’s a genuine knowledge management tool.</li><li><strong>Clear Requirements = Magic</strong>: The more precise your task definition, the better the results.</li></ol><h3>What’s Next?</h3><p>I’m planning to:</p><ul><li>Expand my rule sets for different types of work</li><li>Create more structured templates for common architectural patterns</li><li>Explore advanced AI features like multi-file refactoring</li><li>Share my rules and templates with the community</li></ul><h3>Conclusion</h3><p>R&amp;D weeks are about trying new things and finding better ways to work. This experiment with Cursor turned out to be more than just playing with a new tool — it’s changed how I think about IDE capabilities and knowledge management.</p><p>The combination of familiar VSCode features with AI assistance, especially the rules system, makes it a powerful tool for both coding and knowledge work. It’s not perfect (what is?), but it’s definitely earned its place in my daily toolkit.</p><blockquote><em>Remember: The best tools are the ones that enhance your natural workflow rather than forcing you to adapt to them. Cursor does this surprisingly well. 👍</em></blockquote><p><em>Originally published at </em><a href="https://kakkoyun.me/posts/2024-03-21-vibe-coding-with-cursor/"><em>https://kakkoyun.me</em></a><em> on March 12, 2025.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=28c5a7b92aff" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[FOSDEM 2025: Blimey, What a Weekend!]]></title>
            <link>https://medium.com/@kakkoyun/fosdem-2025-blimey-what-a-weekend-130b4b69c576?source=rss-febaa23a70e9------2</link>
            <guid isPermaLink="false">https://medium.com/p/130b4b69c576</guid>
            <category><![CDATA[fosdem]]></category>
            <dc:creator><![CDATA[Kemal Akkoyun]]></dc:creator>
            <pubDate>Tue, 04 Feb 2025 00:00:42 GMT</pubDate>
            <atom:updated>2025-05-08T20:58:25.914Z</atom:updated>
            <content:encoded><![CDATA[<h3>Another Year, Another FOSDEM</h3><p><strong>FOSDEM</strong>-the annual pilgrimage to <strong>Brussels</strong> for a weekend of open-source brilliance, hallway track magic, and the inevitable sleep deprivation. This year’s <strong>Free and Open Source Software Developers’ European Meeting</strong> was, as always, a whirlwind of ideas, people, and tech so bleeding-edge it practically needed bandages.</p><p>But for me? It was all about <strong>seeing friends</strong>. Catching up, syncing, and squeezing in as many conversations as humanly possible. As we always say-the <strong>hallway track is the real conference</strong>. I’m beyond grateful for the people I managed to see, and equally bummed about those I missed. But with a toddler waiting at home, even carving out this limited time was a logistical miracle.</p><h3>Saturday: Go, Go, Go… and the eBPF Black Hole<a href="https://kakkoyun.me/posts/fosdem-2025/#saturday-go-go-go-and-the-ebpf-black-hole">#</a></h3><p>Saturday kicked off with a deep dive into the <strong>Go DevRoom</strong>, before a (failed) mission to infiltrate the <strong>eBPF</strong> talks.</p><p>The <strong>Go DevRoom</strong> delivered as expected:</p><p>The <strong>eBPF DevRoom</strong>? Packed. Absolutely impenetrable. As someone put it on Twitter:</p><blockquote><em>“Nobody leaves #eBPF room at #FOSDEM, so nobody gets in. 🥲”</em></blockquote><p>Next year, I’m bringing a tent and camping outside the door.</p><h3>Sunday: Monitoring, Metrics, and Maybe Too Many Frites<a href="https://kakkoyun.me/posts/fosdem-2025/#sunday-monitoring-metrics-and-maybe-too-many-frites">#</a></h3><p>Sunday was all about observability, performance, and squeezing every bit of insight from running systems.</p><h4>Observability Overload<a href="https://kakkoyun.me/posts/fosdem-2025/#observability-overload">#</a></h4><p>The <strong>Monitoring and Observability DevRoom</strong> had a strong lineup:</p><h3>Community Vibes</h3><p>Like I said- <strong>FOSDEM</strong> is really about the people. The talks are great, but the real magic happens in the hallway track. Some of the best conversations weren’t planned; they just happened over coffee, between sessions, or during a frantic sprint between buildings.</p><p>I’m incredibly happy for the folks I got to see, and at the same time, I wish I had more time to catch up with everyone I missed. But life is about balance, and with a little one waiting at home, I had to make every moment count.</p><p>Oh, and the <strong>frites</strong>? Still undefeated.</p><h3>Bonus: Trains, Chaos, and a Race Against Time</h3><p>Because no trip is complete without <strong>public transport drama</strong>, my journey back home came with an extra dose of stress. Trains? Cancelled. Schedule? A mess. Plane? Hanging by a thread.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*tVR0DHYve5VvnG3O.jpeg" /></figure><p>Somehow, I made it. But FOSDEM weekend wouldn’t be complete without at least one unexpected adventure.</p><h3>Final Thoughts</h3><p><strong>FOSDEM 2025</strong> delivered. Again. Already looking forward to next year. If you’re into open source and haven’t experienced <strong>FOSDEM</strong>, sort it out.</p><p><em>Originally published at </em><a href="https://kakkoyun.me/posts/fosdem-2025/"><em>https://kakkoyun.me</em></a><em> on February 4, 2025.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=130b4b69c576" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Profiling Python with eBPF: A New Frontier in Performance Analysis]]></title>
            <link>https://medium.com/@kakkoyun/profiling-python-with-ebpf-a-new-frontier-in-performance-analysis-535ce459d25f?source=rss-febaa23a70e9------2</link>
            <guid isPermaLink="false">https://medium.com/p/535ce459d25f</guid>
            <category><![CDATA[python]]></category>
            <category><![CDATA[ebpf]]></category>
            <category><![CDATA[profiling]]></category>
            <dc:creator><![CDATA[Kemal Akkoyun]]></dc:creator>
            <pubDate>Mon, 12 Feb 2024 00:00:51 GMT</pubDate>
            <atom:updated>2025-05-08T20:56:36.058Z</atom:updated>
            <content:encoded><![CDATA[<p>Profiling Python applications can be challenging, especially in scenarios involving high-performance requirements or complex workloads. Existing tools often require code instrumentation, making them impractical for certain use cases. Enter <a href="https://ebpf.io/">eBPF</a> (Extended Berkeley Packet Filter)-a revolutionary Linux technology-and the open-source project <a href="https://parca.dev">Parca</a>, which together are reshaping the landscape of Python profiling.</p><p>In this post, I’ll explore how eBPF enables continuous profiling, discuss challenges like stack unwinding in Python, and demonstrate the power of modern profiling tools.</p><p>You can also watch my <a href="https://youtu.be/nNbU26CoMWA?si=t3Mh1z6XfNwa5r7M">full talk here</a> or refer to the <a href="https://kakkoyun.me/notes/presentations/FOSDEM24+-+Profiling+Python+with+eBPF+-+A+New+Frontier+in+Performance+Analysis">slides from the presentation</a>.</p><p>Profiling helps optimize performance and troubleshoot issues, such as CPU spikes, memory leaks, or out-of-memory (OOM) events. For instance:</p><ul><li><strong>Performance optimization:</strong> Identifying bottlenecks in code.</li><li><strong>Incident resolution:</strong> Determining which function or component caused a memory spike or CPU overload.</li></ul><p>Traditional Python profiling tools, like or , require application instrumentation, which isn’t always feasible-especially in production environments where code access might be restricted. This is where eBPF shines, offering non-intrusive, external profiling.</p><p>The Python ecosystem offers several profiling tools, each with unique strengths:</p><ul><li>: A built-in module for deterministic profiling.</li><li><a href="https://github.com/joerick/pyinstrument">pyinstrument</a>: A call stack profiler for Python.</li><li>: A sampling profiler for Python programs.</li><li>: Yet Another Python Profiler, supports multithreaded programs.</li><li>: A ptracing profiler for Python.</li><li>: A high-performance CPU and memory profiler.</li></ul><p>While these tools are valuable, many require code instrumentation or introduce significant overhead, making them less suitable for continuous profiling in production environments.</p><p>Originally designed for network packet filtering, <a href="https://ebpf.io/">eBPF</a> has evolved into a versatile event-driven system. It enables safe execution of custom programs inside the Linux kernel, using:</p><p>By leveraging eBPF with PMUs, profiling becomes faster and more efficient than traditional approaches.</p><p><a href="https://parca.dev">Parca</a> is an open-source project enabling continuous profiling. Its eBPF agent hooks into <a href="https://perf.wiki.kernel.org/index.php/Tutorial">perf events</a>, collects stack traces, and aggregates data for visualization. The process involves:</p><ol><li><strong>Hooking into CPU events</strong> to monitor active functions.</li><li><strong>Stack unwinding</strong> to trace function calls.</li><li><strong>Data aggregation and visualization</strong> in a web-based UI.</li></ol><p>Unlike traditional profilers, Parca introduces minimal runtime overhead, making it ideal for production workloads.</p><p>Profiling native code is straightforward: we unwind the stack by reading memory addresses from the CPU and resolving them into human-readable symbols using debug information (e.g., <a href="https://dwarfstd.org/">DWARF</a>).</p><p>For Python, stack unwinding is complex due to its interpreter-based execution. Python maintains execution state in custom data structures, such as:</p><ul><li><strong>Interpreter state:</strong> Tracks threads and their execution context.</li><li><strong>Thread state:</strong> A linked list of threads running in the interpreter.</li><li><strong>Frame state:</strong> Represents the current execution frame.</li></ul><p>To unwind Python stacks, we must traverse these structures, extract relevant information, and map them to human-readable symbols.</p><p>Here’s how Parca handles Python profiling:</p><ol><li><strong>Reverse Engineering the Python Runtime:</strong></li></ol><ul><li>Analyze Python’s internal structures (e.g., thread and frame states).</li><li>Identify offsets and symbols using tools like <a href="https://www.gnu.org/software/gdb/">GDB</a> or DWARF debuggers.</li></ul><ol><li><strong>Unwinding Python Stacks:</strong></li><li><strong>Mapping Symbols:</strong></li></ol><ul><li>Resolve function addresses to readable symbols.</li><li>Encode line numbers and function names for better traceability.</li></ul><ol><li><strong>Efficient Data Handling:</strong></li></ol><ul><li>Use eBPF maps for kernel-to-user space communication.</li><li>Optimize symbol resolution by caching frequently seen traces.</li></ul><p>The upcoming Python 3.13 release introduces a debug offset structure that simplifies stack unwinding. It provides precomputed offsets for key runtime fields, eliminating much of the manual reverse engineering required for earlier versions. This improvement marks a significant leap forward for tools like Parca.</p><p>Parca’s UI provides a comprehensive view of application performance:</p><ul><li><strong>Flame graphs</strong>: Visualize stack traces over time, highlighting bottlenecks.</li><li><strong>Filtering and Metadata</strong>: Focus on specific languages (e.g., Python) or layers (e.g., C libraries).</li><li><strong>Continuous Insights</strong>: Compare profiles across deployments to monitor performance regressions.</li></ul><p>For example, a flame graph might reveal inefficient recursion in a Python function, enabling developers to pinpoint and optimize the problematic code.</p><p>Parca supports profiling for Python versions from 2.7 to 3.11, with ongoing work for 3.12 and full support anticipated for 3.13. The project’s modular design allows quick adaptation to new Python runtime changes.</p><p>Profiling Python applications with eBPF and Parca represents a new frontier in performance analysis. By leveraging eBPF and continuous profiling, we can gain invaluable insights into our applications, enabling effective performance optimization. I encourage you to explore Parca, provide feedback, and contribute to the project-it’s a collaborative effort that can benefit us all as we tackle the challenges of modern software development.</p><p>Watch my <a href="https://youtu.be/nNbU26CoMWA?si=t3Mh1z6XfNwa5r7M">full talk</a> or check out the <a href="https://kakkoyun.me/notes/presentations/FOSDEM24+-+Profiling+Python+with+eBPF+-+A+New+Frontier+in+Performance+Analysis">presentation slides</a>. Explore Parca on <a href="https://github.com/parca-dev/parca">GitHub</a> and join the community. Your feedback helps improve the tooling and shape the future of observability.</p><p><em>Originally published at </em><a href="https://kakkoyun.me/posts/profiling-python-with-ebpf/"><em>https://kakkoyun.me</em></a><em> on February 12, 2024.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=535ce459d25f" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Fantastic Symbols and Where to Find Them — Part 2]]></title>
            <link>https://medium.com/@kakkoyun/fantastic-symbols-and-where-to-find-them-part-2-acbe2b3f775?source=rss-febaa23a70e9------2</link>
            <guid isPermaLink="false">https://medium.com/p/acbe2b3f775</guid>
            <category><![CDATA[debugging-javascript]]></category>
            <category><![CDATA[debugging]]></category>
            <category><![CDATA[javadebugging]]></category>
            <category><![CDATA[profiling]]></category>
            <category><![CDATA[debugging-python]]></category>
            <dc:creator><![CDATA[Kemal Akkoyun]]></dc:creator>
            <pubDate>Thu, 27 Jan 2022 15:01:51 GMT</pubDate>
            <atom:updated>2022-01-27T15:01:51.532Z</atom:updated>
            <content:encoded><![CDATA[<h3>Fantastic Symbols and Where to Find Them — Part 2</h3><p>How profilers and debuggers translate machine addresses to human-readable symbolic names</p><blockquote>Originally published on polarsignals.com/blog on 27.01.2022</blockquote><blockquote>This is a blog post series. If you haven’t read <a href="https://www.polarsignals.com/blog/posts/2022/01/13/fantastic-symbols-and-where-to-find-them">Part 1</a> we recommend you to do so first!</blockquote><p>In <a href="https://www.polarsignals.com/blog/posts/2022/01/13/fantastic-symbols-and-where-to-find-them">the first blog post</a>, we learned about the fantastic symbols (<a href="https://en.wikipedia.org/wiki/Debug_symbol">debug symbols</a>), how the symbolization process works and lastly, how to find the symbolic names of addresses in a compiled binary.</p><p>The actual location of the symbolic information depends on the programming language implementation the program is written in. We can categorize the programming language implementations into three groups: compiled languages (with or without a runtime), interpreted languages, and <a href="https://en.wikipedia.org/wiki/Just-in-time_compilation">JIT-compiled</a> languages.</p><p>In this post, we will continue our journey to find fantastic symbols. And we will look into where to find them for the other types of programming language implementations.</p><h3>JIT-compiled language implementations</h3><p>Examples of JIT-compiled languages include Java, .NET, Erlang, JavaScript (Node.js) and many others.</p><p><a href="https://en.wikipedia.org/wiki/Just-in-time_compilation">Just-In-Time</a> compiled languages compile the source code into <a href="https://en.wikipedia.org/wiki/Bytecode">bytecode</a>, which is then compiled into <a href="https://en.wikipedia.org/wiki/Machine_code">machine code</a> at runtime, often using direct feedback from runtime to guide compiler optimizations on the fly.</p><p>Because functions are compiled on the fly, there is no pre-built, discoverable symbol table in any object files. Instead, the symbol table is created on the fly. The symbol mappings (location to symbol) are usually stored in the <em>memory</em> of the <a href="https://en.wikipedia.org/wiki/Runtime_(program_lifecycle_phase)">runtime</a> or <a href="https://en.wikipedia.org/wiki/Virtual_machine">virtual machine</a> and used for rendering human-readable stack traces when it is needed <em>, e. g.</em> when an exception occurs, the runtime will use the symbol mappings to render a human-readable stack trace.</p><p>The good thing is that most of the runtimes provide supplemental symbol mappings for the just-in-time compiled code for Linux to use perf.</p><p>perf defines <a href="https://github.com/torvalds/linux/blob/master/tools/perf/Documentation/jit-interface.txt">an interface</a> to resolve symbols for dynamically generated code by a JIT compiler. These files usually can be found in /tmp/perf-$PID.map, where $PID is the process ID of the process of the runtime that is running on the system.</p><p>The runtimes usually don’t enable providing symbol mappings by default. You might need to change a configuration, run the virtual machine with a specific flag/environment variable or run an additional program to obtain these mappings. For example, JVM needs an agent to provide supplemental symbol mapping files, called <a href="https://github.com/jvm-profiling-tools/perf-map-agent">perf-map-agent</a>.</p><p>Let’s see an example perf map file for NodeJS. The runtimes out there output this file with <em>more or less</em> the same format, <a href="https://github.com/parca-dev/parca-agent/issues/139">more or less!</a></p><p>To generate a similar file for <a href="https://en.wikipedia.org/wiki/Node.js">Node.js</a>, we need to run node with --perf-basic-prof option.</p><pre><em># With Node.js &gt;=v0.11.15 the following command will create a map file for NodeJS:</em></pre><pre>node --perf-basic-prof your-app.js</pre><p>This will create a map file at /tmp/perf-&lt;pid&gt;.map that looks like this:</p><pre>3ef414c0 398 RegExp:[{(]</pre><pre>3ef418a0 398 RegExp:[})]</pre><pre>59ed4102 26 LazyCompile:~REPLServer.self.writer repl.js:514</pre><pre>59ed44ea 146 LazyCompile:~inspect internal/util/inspect.js:152</pre><pre>59ed4e4a 148 LazyCompile:~formatValue internal/util/inspect.js:456</pre><pre>59ed558a 25f LazyCompile:~formatPrimitive internal/util/inspect.js:768</pre><pre>59ed5d62 35 LazyCompile:~formatNumber internal/util/inspect.js:761</pre><pre>59ed5fca 5d LazyCompile:~stylizeWithColor internal/util/inspect.js:267</pre><pre>4edd2e52 65 LazyCompile:~Domain.exit domain.js:284</pre><pre>4edd30ea 14b LazyCompile:~lastIndexOf native array.js:618</pre><pre>4edd3522 35 LazyCompile:~online internal/repl.js:157</pre><pre>4edd37f2 ec LazyCompile:~setTimeout timers.js:388</pre><pre>4edd3cca b0 LazyCompile:~Timeout internal/timers.js:55</pre><pre>4edd40ba 55 LazyCompile:~initAsyncResource internal/timers.js:45</pre><pre>4edd42da f LazyCompile:~exports.active timers.js:151</pre><pre>4edd457a cb LazyCompile:~insert timers.js:167</pre><pre>4edd4962 50 LazyCompile:~TimersList timers.js:195</pre><pre>4edd4cea 37 LazyCompile:~append internal/linkedlist.js:29</pre><pre>4edd4f12 35 LazyCompile:~remove internal/linkedlist.js:15</pre><pre>4edd5132 d LazyCompile:~isEmpty internal/linkedlist.js:44</pre><pre>4edd529a 21 LazyCompile:~ok assert.js:345</pre><pre>4edd555a 68 LazyCompile:~innerOk assert.js:317</pre><pre>4edd59a2 27 LazyCompile:~processTimers timers.js:220</pre><pre>4edd5d9a 197 LazyCompile:~listOnTimeout timers.js:226</pre><pre>4edd6352 15 LazyCompile:~peek internal/linkedlist.js:9</pre><pre>4edd66ca a1 LazyCompile:~tryOnTimeout timers.js:292</pre><pre>4edd6a02 86 LazyCompile:~ontimeout timers.js:429</pre><pre>4edd7132 d7 LazyCompile:~process.kill internal/process/per_thread.js:173</pre><blockquote>Each line has START, SIZE and symbolname fields, separated with spaces. START and SIZE are hex numbers without 0x. symbolname is the rest of the line, so it could contain special characters.</blockquote><p>With the help of this mapping file, we have everything we need to symbolize the addresses in the stack trace. Of course, as always, this is just an oversimplification.</p><p>For example, these mappings might change as the runtime decides to recompile the bytecode. So we need to keep an eye on these files and keep track of the changes to resolve the address correctly with their most recent mapping.</p><p>Each runtime and virtual machine has its peculiarities that we need to adapt. But those are out of the scope of this post.</p><h3>Interpreted language implementations</h3><p>Examples of interpreted languages include Python, Ruby, and again many others. There are also languages that commonly use interpretation as a stage before <a href="https://en.wikipedia.org/wiki/Just-in-time_compilation">JIT compilation</a>, e. g. Java. Symbolization for this stage of compilation is similar to interpreted languages.</p><p>Interpreted language runtimes do not compile the program to machine code. Instead, interpreters and virtual machines parse and execute the source code using their <a href="https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop">REPL</a> routines. Or execute their own virtual processor. So they have their own way of executing functions and managing stacks.</p><p>If you observe (profile or debug) these runtimes using something like perf, you will see symbols for the runtime. However, you won&#39;t see the language-level context you might be expecting.</p><p>Moreover, the interpreter itself is probably written in a more low-level language like C or C++. And when you inspect the object file of the runtime/interpreter, the symbol table that you would find would show the internals of the interpreter, not the symbols from the provided source code.</p><h3>Finding the symbols for our runtime</h3><p>The runtime symbols are useful because they allow you to see the internal routines of the interpreter. e. g. how much time your program spends on garbage collection. And it’s mostly like the stack traces you would see in the debugger or profiler will have calls to the internals of the runtime. So these symbols are also helpful for debugging.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/794/0*HJ_CyueMrii0h_MI.png" /></figure><blockquote>Most of the runtimes are compiled with production mode, and they most likely lack the debug symbols in their release binaries. You might need to manually compile your runtime in debug mode to actually have them in the resulting binary. Some runtimes, such as Node.js, already have them in their productiondistributions.</blockquote><p>Lastly, to completely resolve the stack traces of the runtime, we might need to obtain the debug information for the linked libraries. If you remember from <a href="https://www.polarsignals.com/blog/posts/2022/01/13/fantastic-symbols-and-where-to-find-them">the first blog post</a>, debuginfo files can help us. Debuginfo files for software packages are available through package managers in Linux distributions. Usually for an available package called mypackage there exists a mypackage-dbgsym, mypackage-dbg or mypackage-debuginfopackage. There are also <a href="https://sourceware.org/elfutils/Debuginfod.html">public servers</a> that serve debug information. So we need to find the debuginfo files for the runtime we are using and all the linked libraries.</p><h3>Finding the symbols for our target program</h3><p>The symbols that we look for in our own program likely are stored in a memory table that is specific to the runtime. For example, in Python, the symbol mappings can be accessed using <a href="https://docs.python.org/3/library/symtable.html">symtable</a>.</p><p>As a result, you need to craft a specific routine for each interpreter runtime (in some cases, each version of that runtime) to obtain symbol information. Educated eyes might have already noticed, it’s not an easy undertaking considering the sheer amount of interpreted languages out there. For example, a very well known Ruby profiler, <a href="https://github.com/rbspy/rbspy/blob/master/ARCHITECTURE.md">rbspy</a>, generates code for reading internal structs of the Ruby runtime for each version.</p><p>If you were to write a general-purpose profiler, <em>like us</em>, you would need to write a special subroutine in your profiler for each runtime that you want to support.</p><h3>Again, don’t worry, we got you covered</h3><p>The good news is we got you covered. If you are using <a href="https://github.com/parca-dev/parca-agent">Parca Agent</a>, we already do <a href="https://www.parca.dev/docs/symbolization">the heavy lifting</a> for you to symbolize captured stack traces. And we keep extending our support for the different languages and runtimes. For example, Parca has already support for parsing perf JIT interface to resolve the symbols for collected stack traces.</p><p>Check <a href="https://www.parca.dev/">Parca</a> out and let us know what you think, on <a href="https://discord.gg/ZgUpYgpzXy">Discord</a> channel.</p><h3>Further reading</h3><ul><li><a href="https://github.com/torvalds/linux/blob/master/tools/perf/Documentation/jit-interface.txt">perf JIT Interface</a></li><li><a href="https://www.brendangregg.com/perf.html#JIT_Symbols">perf JIT Symbols</a></li><li><a href="https://joyeecheung.github.io/blog/2018/12/31/tips-and-tricks-node-core/">Node.js profiling tips and tricks</a></li><li><a href="https://www.brendangregg.com/blog/2014-09-17/node-flame-graphs-on-linux.html">Node.js Flamegraphs</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=acbe2b3f775" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Fantastic Symbols and Where to Find Them — Part 1]]></title>
            <link>https://medium.com/@kakkoyun/fantastic-symbols-and-where-to-find-them-part-1-eb27b8a3344d?source=rss-febaa23a70e9------2</link>
            <guid isPermaLink="false">https://medium.com/p/eb27b8a3344d</guid>
            <category><![CDATA[binary-analysis]]></category>
            <category><![CDATA[observability]]></category>
            <category><![CDATA[software-engineering]]></category>
            <category><![CDATA[reverse-engineering]]></category>
            <category><![CDATA[programming]]></category>
            <dc:creator><![CDATA[Kemal Akkoyun]]></dc:creator>
            <pubDate>Sat, 15 Jan 2022 08:51:50 GMT</pubDate>
            <atom:updated>2022-01-15T08:51:50.839Z</atom:updated>
            <content:encoded><![CDATA[<h3>Fantastic Symbols and Where to Find Them — Part 1</h3><p><em>Originally published on </em><a href="https://www.polarsignals.com/blog/"><em>polarsignals.com/blog</em></a><em> on 13.01.2022</em></p><p>Symbolization is a technique that allows you to translate machine memory addresses to human-readable symbol information (symbols).</p><p>Why do we need to read what programs do anyways? We usually do not need to translate everything to a human-readable format when things run smoothly. But when things go south, we need to understand what is going on under the hood. Symbolization is needed by introspection tools like <a href="https://en.wikipedia.org/wiki/Debugger">debuggers</a>, <a href="https://en.wikipedia.org/wiki/Profiling_(computer_programming)">profilers</a> and <a href="https://en.wikipedia.org/wiki/Core_dump">core dumps</a> or any other program that needs to trace the execution of another program. While a target program is executing on a machine, these types of programs capture the stack traces of the program that is being executed.</p><blockquote>A <a href="https://en.wikipedia.org/wiki/Stack_trace">stack trace</a> (also called stack backtrace or stack traceback) is a report of the active stack frames at a certain point in time during the execution of a program.</blockquote><p>In raw stack traces, the addresses of the functions that are being called are recorded. The addresses are hexadecimal numbers representing the memory return addresses of the functions. Symbols are needed to translate memory addresses into function and variable names precisely as in the program’s source code to be read by us humans. Without symbols, all we see are hexadecimal numbers representing the memory addresses that we have captured.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/772/0*8P5igQJNrbbkndf9.png" /></figure><p>It sounds simple enough, right? Well, it’s not. As with everything else about computers, it’s a bit of sorcery. It has its challenges, such as associating them with correct symbols, transforming addresses, and most importantly, actually finding the symbols! The strategies to get symbol information varies depending on the platform and the programming language implementation that the program is written in.</p><p><em>For the sake of simplicity, we will be focusing on Linux as the target platform and ignore Windows, macOS and many other platforms. Otherwise, I could end up writing a small size book in here :)</em></p><h3>Fantastic Symbols …</h3><p>A symbol (or debug symbol, to be precise) is a special kind of <a href="https://en.wikipedia.org/wiki/Symbol_(programming)">symbol</a> that attaches additional information to the symbol table of a program. This symbol information allows a debugger or a profiler to gain access to information from the program’s source code, such as the names of identifiers, including variables and functions. But where can we find these symbols?</p><h3>… and Where to Find Them</h3><p>The actual location of the symbolic information depends on the programming language implementation the program is written in. We can categorize the programming language implementations into three groups: compiled languages (with or without a runtime), interpreted languages, and <a href="https://en.wikipedia.org/wiki/Just-in-time_compilation">JIT-compiled</a> languages.</p><p>If the program is a compiled one, these may be compiled together with the binary file, distributed in a separate file, or discarded during the compilation and/or linking. Or, if the program is interpreted, these may be stored in the program itself. Let’s briefly look at where and how we can find these symbols depending on the programming language implementation.</p><h4>Compiled language implementations</h4><p>Examples of compiled languages include C, C++, Go, Rust and many others.</p><p>The compiled languages usually have a <a href="https://en.wikipedia.org/wiki/Symbol_table">symbol table</a> that contains all the symbols used in the program. The symbol table is usually compiled in the executable binary file. And the binary file is typically in the <a href="https://en.wikipedia.org/wiki/Executable_and_Linkable_Format">ELF</a> format (for Linux systems). Symbol tables are included in the ELF binary file, specifically for mapping the addresses to function names and object names. In rare cases, it is stored in a separate file, usually with the same name as the binary file, but with a different extension.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*TY2DYTnUYsPFlXz7.png" /></figure><p>The ELF format is not an easy one to describe in a couple of sentences. For the purpose of this article, we will focus on what we need to know about the ELF format. Each ELF file is made up of one ELF header, followed by file data. The ELF header is a fixed size and contains information about the data sections. The relevant part for us is the symbols can live in a special section called .symtab and .dynsym. .dynsym is the “dynamic symbol table” and it is a smaller version of the .symtab that only contains global symbols.</p><p>Contents of .dynsym and .symtab section using readelf -s /bin/go:</p><pre>Symbol table &#39;.dynsym&#39; contains 38 entries:</pre><pre>Num: Value Size Type Bind Vis Ndx Name</pre><pre>0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND</pre><pre>1: 00000000006355e0 99 FUNC GLOBAL DEFAULT 1 crosscall2</pre><pre>2: 00000000006355a0 55 FUNC GLOBAL DEFAULT 1 _cgo_panic</pre><pre>3: 0000000000465560 25 FUNC GLOBAL DEFAULT 1 _cgo_topofstack</pre><pre>4: 0000000000000000 0 OBJECT GLOBAL DEFAULT UND [...]@GLIBC_2.2.5 (6)</pre><pre>5: 0000000000000000 0 OBJECT GLOBAL DEFAULT UND [...]@GLIBC_2.2.5 (4)</pre><pre>6: 0000000000000000 0 OBJECT GLOBAL DEFAULT UND [...]@GLIBC_2.2.5 (4)</pre><pre>7: 0000000000000000 0 OBJECT GLOBAL DEFAULT UND [...]@GLIBC_2.2.5 (4)</pre><pre>8: 0000000000000000 0 OBJECT GLOBAL DEFAULT UND [...]@GLIBC_2.2.5 (4)</pre><pre>9: 0000000000000000 0 OBJECT GLOBAL DEFAULT UND [...]@GLIBC_2.2.5 (4)</pre><pre>10: 0000000000000000 0 OBJECT GLOBAL DEFAULT UND [...]@GLIBC_2.2.5 (4)</pre><pre>...</pre><pre>Symbol table &#39;.symtab&#39; contains 13199 entries:</pre><pre>Num: Value Size Type Bind Vis Ndx Name</pre><pre>0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND</pre><pre>1: 0000000000000000 0 FILE LOCAL DEFAULT ABS go.go</pre><pre>2: 0000000000401000 0 FUNC LOCAL DEFAULT 1 runtime.text</pre><pre>3: 0000000000401000 214 FUNC LOCAL DEFAULT 1 net(.text)</pre><pre>4: 00000000004010e0 214 FUNC LOCAL DEFAULT 1 runtime/cgo(.text)</pre><pre>5: 00000000004011c0 601 FUNC LOCAL DEFAULT 1 runtime/cgo(.text)</pre><pre>6: 0000000000401420 480 FUNC LOCAL DEFAULT 1 runtime/cgo(.text)</pre><pre>7: 0000000000401420 47 FUNC LOCAL HIDDEN 1 threadentry</pre><pre>8: 0000000000401600 70 FUNC LOCAL DEFAULT 1 runtime/cgo(.text)</pre><pre>9: 0000000000401646 5 FUNC LOCAL DEFAULT 1 runtime/cgo(.tex[...]</pre><pre>10: 0000000000401646 5 FUNC LOCAL HIDDEN 1 x_cgo_munmap.cold</pre><blockquote>Go has a unique table (of course). It stores its symbols in a section called <a href="https://pkg.go.dev/debug/gosym#LineTable">.gopclntab</a>. This is a table of functions, line numbers and addresses. Go does this because it needs to be able to render human-readable stack traces when a panic occurs in runtime;</blockquote><p>Note that addresses in the symbol table do not move during execution so that they can be read any time during the execution of the program. They can easily be loaded into memory independent of the running program and an observer can easily read them.</p><p>We assumed that the binary file is a statically linked executable until this point. However, this might not be the case. The binary file might be dynamically linked to other libraries. From now on, we will refer to these shared library files and executables (both in ELF format) as <a href="https://en.wikipedia.org/wiki/Object_file">object files</a>. Each object file can have its own symbol table.</p><p>We need to note that when we take a snapshot of the stack (a.k.a stack trace), it could include addresses from linked shared libraries and Kernel functions.</p><blockquote>Kernel-level software differs as it has its own dynamic symbol table in /proc/kallsyms, which is a file that contains all the symbols that are used in the kernel. And it can grow as the kernel modules are loaded.</blockquote><p>We can read the object files by using binary utilities such as <a href="https://en.wikipedia.org/wiki/Objdump">objdump</a>, <a href="https://en.wikipedia.org/wiki/Readelf">readelf</a> and <a href="https://en.wikipedia.org/wiki/Nm_(Unix)">nm</a>.</p><p>To read the .symtab:</p><pre>nm $FILE</pre><pre><em># or</em></pre><pre>objdump --syms $FILE</pre><pre><em># or</em></pre><pre>readelf -a $FILE</pre><p>To read the .dynsym:</p><pre>nm -D $FILE</pre><pre><em># or</em></pre><pre>objdump --dynamic-syms $FILE</pre><pre><em># or</em></pre><pre>readelf -a $FILE</pre><p>For the compiled languages, the symbol table is not the only source of symbols. There are also DWARFs!</p><h4>Debuginfo</h4><blockquote>ELFs and DWARFs, welcome to fairyland.</blockquote><p>Another way to obtain the symbols from an object file is to use the debug information or debuginfo in short. Same as the symbol table, this information can be compiled in the binary file, formatted in the <a href="https://en.wikipedia.org/wiki/DWARF">DWARF(Debugging With Attributed Record Formats)</a> or in a separate file.</p><p>DWARF is the debug information format most commonly used with ELF. It’s not necessarily tied to ELF, but the two were developed in tandem and work very well together. This information is split across different ELF sections (.debug_* and .zdebug_* for compressed ones), each with its own piece of information to relay. For our specific needs, we need to use the .debug_info section to find corresponding functions and .debug_line section to corresponding line numbers.</p><p>Debuginfo files for software packages are available through package managers in Linux distributions. Usually for an available package called mypackage there exists a mypackage-dbgsym, mypackage-dbg or mypackage-debuginfo package. There are also <a href="https://sourceware.org/elfutils/Debuginfod.html">public servers</a> that serve debug information.</p><h4>One Program to bring them all, and in the darkness bind them: addr2line</h4><blockquote>Wait, what?! Isn’t that from another fantasy book?</blockquote><p>Now that we have the symbol table or debug information, we can use addr2line (<em>address to line</em>) to get the source code location of a given address. <a href="https://linux.die.net/man/1/addr2line">addr2line</a> converts addresses back to function and line numbers.</p><p>Let’s see it in action addr2line -a 0x0000000000001154 -e &lt;objectFile&gt;:</p><p><em>For addr2line </em><em>&lt;objectFile&gt; can be any object file compiled with debug information or symbols. It can be an executable, a shared library or output of a strip operation.</em></p><p>Voilà!</p><pre>0x0000000000001154</pre><pre>main</pre><pre>/home/newt/Sandbox/hello-c/hello.c:14</pre><p>I used a simple C executable for this example. And we have got our symbol and attached source information for the corresponding address 🎉</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/500/0*W7iquZ0RS5Jo_ezJ.jpg" /></figure><p>I only wish we had compiled programming language implementations out there, then our job here could have been finished. But we are not. We need to keep digging. But for that, you need to wait for another week. As we hinted at in the title of this post, there will be a part 2! All the best franchises are sequels, right?! In part 2, we will see how interpreted languages and <a href="https://en.wikipedia.org/wiki/Just-in-time_compilation">Just-In-Time</a> compiled languages handle symbols.</p><p><em>Please stay tuned!</em></p><h3>Don’t worry we got you covered</h3><p>Even though we simplified things a bit here, if you want to write a program to utilize symbolization, you still have a lot of work to do. Many open-source tools out there already handle nitty-gritty details of symbolization, like <a href="https://www.brendangregg.com/perf.html">perf</a>.</p><p>The good news is we got you covered. If you are using <a href="https://github.com/parca-dev/parca-agent">Parca Agent</a>, we already do <a href="https://www.parca.dev/docs/symbolization">the heavy lifting</a> for you to symbolize captured stack traces. And we keep extending our support for the different languages and runtimes.</p><p>Check <a href="https://www.parca.dev/">Parca</a> out and let us know what you think, on <a href="https://discord.gg/ZgUpYgpzXy">Discord</a> channel.</p><h3>Further reading</h3><ul><li><a href="https://en.wikipedia.org/wiki/Debug_symbol">https://en.wikipedia.org/wiki/Debug_symbol</a></li><li><a href="https://www.brendangregg.com/bpf-performance-tools-book.html">https://www.brendangregg.com/bpf-performance-tools-book.html</a></li><li><a href="https://github.com/DataDog/go-profiler-notes/blob/main/stack-traces.md">https://github.com/DataDog/go-profiler-notes/blob/main/stack-traces.md</a></li><li><a href="https://www.brendangregg.com/perf.html">https://www.brendangregg.com/perf.html</a></li><li><a href="https://jvns.ca/blog/2018/01/09/resolving-symbol-addresses/">https://jvns.ca/blog/2018/01/09/resolving-symbol-addresses/</a></li></ul><h3>Sources</h3><ul><li><a href="https://en.wikipedia.org/wiki/File:Call_stack_layout.svg">Call Stack Layout</a></li><li><a href="https://github.com/corkami/pics/blob/28cb0226093ed57b348723bc473cea0162dad366/binary/elf101/elf101-64.svg">ELF Executable and Linkable Format diagram by Ange Albertini</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=eb27b8a3344d" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Making Drone Builds 10 Times Faster!]]></title>
            <link>https://medium.com/@kakkoyun/making-drone-builds-10-times-faster-138dbb7fe000?source=rss-febaa23a70e9------2</link>
            <guid isPermaLink="false">https://medium.com/p/138dbb7fe000</guid>
            <category><![CDATA[continuous-delivery]]></category>
            <category><![CDATA[continuous-integration]]></category>
            <category><![CDATA[go]]></category>
            <category><![CDATA[docker]]></category>
            <category><![CDATA[devops]]></category>
            <dc:creator><![CDATA[Kemal Akkoyun]]></dc:creator>
            <pubDate>Wed, 10 Apr 2019 00:00:00 GMT</pubDate>
            <atom:updated>2019-04-10T14:03:21.835Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*JPsfTwHZA3Myvr8u.png" /></figure><p>We open sourced <a href="https://github.com/meltwater/drone-cache">drone-cache</a>, a plugin for the popular Continuous Delivery platform <a href="https://drone.io/">Drone</a>. It allows you to cache dependencies and interim files between builds to reduce your build times. This post explains why we are using Drone, why we needed a cache plugin, and what I learned while trying to release drone-cache as open source software.</p><p>Read on for the story behind drone-cache or if you want to jump into action directly, go to the <a href="https://github.com/meltwater/drone-cache">github.com/meltwater/drone-cache</a>, and try it for yourself.</p><p><em>Originally published at </em><a href="https://underthehood.meltwater.com/blog/2019/04/10/making-drone-builds-10-times-faster/"><em>underthehood.meltwater.com</em></a><em> on April 10, 2019.</em></p><h3>Why are we using Drone?</h3><p>At Meltwater, we empower self-sufficient teams. Teams are free to choose their technology stacks. As a result, we have a diverse set of tools in our stack. In my team, we had been using a combination of <a href="https://travis-ci.com/">TravisCI</a>, <a href="https://circleci.com/">CircleCI</a> and <a href="https://jenkins.io/">Jenkins</a> as our <a href="https://en.wikipedia.org/wiki/CI/CD">CI/CD pipeline</a>.</p><p>In 2018, we decided to migrate to <a href="https://kubernetes.io/">Kubernetes</a>. In doing so, we wanted to simplify our toolchain and migrate to a more flexible, <a href="https://github.com/cncf/toc/blob/master/DEFINITION.md">cloud-native</a> and on-premise CI/CD pipeline solution. We ended up choosing <a href="https://drone.io/">Drone</a>, and with one year of experience under our belt, we are more than happy with it.</p><h3>How we made the builds faster</h3><p>My team lives and breaths the “<a href="https://en.wikipedia.org/wiki/Release_early,_release_often">release early, release often</a>” philosophy. We release and deploy our software to production several times a day. When we moved from CircleCI to Drone, our build times went up drastically.</p><p>Build times went up so much because, for each build, our package manager was downloading the Internet (you know, usual suspects are <a href="https://www.npmjs.com/">npm</a>, <a href="https://rubygems.org/">RubyGems</a>, etc.). This was not a problem with CircleCI because of their built-in caching facilities. So with our pace of continuous releases and increased build times, we got frustrated quickly.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/602/0*_QqIcEGedm8baP5O.png" /></figure><p>Since we had been spoiled with the wonderful caching features of CircleCI, we wanted the same features in Drone but they are not available by default. However, Drone offers <a href="http://plugins.drone.io/">plugins</a> which are “special Docker containers used to drop preconfigured tasks into a Pipeline”. We found tens of plugins related to caching in Drone.</p><p>We first tried <a href="https://github.com/Drillster/drone-volume-cache">drone-volume-cache</a>, but because volumes are local to the currently running Drone worker node, you cannot be sure your that next build will run on the same machine. Using a storage layer that could persist the cache between builds would be a better option. So we quickly abandoned this approach.</p><p>Our Drone deployment runs on <a href="https://aws.amazon.com/">AWS</a>, hence we looked for plugins that use <a href="https://aws.amazon.com/s3/">S3</a> as their storage. We found lots of them and decided to use <a href="https://github.com/bsm/drone-s3-cache">drone-s3-cache</a>. It’s a well-written, simple Go program which follows the Drone <a href="https://github.com/drone/drone-plugin-starter">plugin starter</a> conventions.</p><h3>Why did we decide to build our own caching plugin?</h3><p>After using <em>drone-s3-cache</em> for a couple of weeks, we needed to add another parameter to pass to S3. To do so we forked <a href="https://github.com/bsm/drone-s3-cache">drone-s3-cache</a> and modified it. We thought that nobody would need those minor changes. So rather than contributing back to upstream, we built a docker image of our own and pushed it to our private registry to use as a custom Drone plugin.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/848/0*XKoY3J-I-7TW2H0A.png" /></figure><p>Months later, I have received a feature request from one of my colleagues working in a different team, and I was surprised because I didn’t think other teams used drone-cache. When I checked, I realised that various teams throughout Meltwater heavily used it. Then we started to get similar messages and requests from other teams.</p><p>I received this message when I was looking for a problem to solve during our <a href="https://underthehood.meltwater.com/blog/2014/08/18/meltwhatever-innovation-day-at-meltwater/">internal</a> <a href="https://en.wikipedia.org/wiki/Hackathon">Hackathon</a>. What are the chances? So I decided to work on this plugin and add the requested feature. Building something to make life easy for fellow developers always gives me pure joy. Long story short, stars were aligned, and we decided to work on our fork and improve it.</p><p>I had not worked with Go much, but I always wanted to learn. Thanks to this plugin, I have also achieved this goal of mine. I changed, refactored and churned a lot of code. I experimented with a lot of different ideas. I have added features that nobody has asked for. I tried different things just for the sake of trying. That’s why when I decided to open source my changes, I realised I had re-written the plugin. So rather than sending a pull-request, I created a new repository. <a href="https://github.com/meltwater/drone-cache">drone-cache</a> has born!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/500/0*xUGudjwoWSu91uNz.png" /></figure><h3>How does it work?</h3><p>What does a Drone cache plugin actually have to accomplish? In Drone, each step in the build pipeline is a container which is thrown away after it serves its purpose. So a caching system has to persist current workspace files between builds. You can think of <a href="https://docs.drone.io/user-guide/pipeline/steps">workspace</a> as the root of your git repository. It is a mounted volume shared by all steps in your Drone build pipeline.</p><p>With drone-cache, after your initial pipeline run, a snapshot of your current workspace will be stored. Then you can restore that snapshot in your next build, which saves you time.</p><p>The best example would be to use this plugin with your package managers such as <a href="https://www.npmjs.com/">npm</a>, <a href="https://elixir-lang.org/getting-started/mix-otp/introduction-to-mix.html">Mix</a>, <a href="https://bundler.io/">Bundler</a> or <a href="https://maven.apache.org/">Maven</a>. With restored dependencies from a cache, commands such as <em>npm install</em> would only need to download new dependencies, rather than re-download every package on each build.</p><h3>What makes drone-cache different from other Drone caching solutions?</h3><p>The most useful feature of drone-cache is that you can provide <a href="https://github.com/meltwater/drone-cache/blob/master/docs/cache_key_templates.md">your own custom cache key templates</a>. This means you can store your cached files under keys which prescribes your use cases. For example, with a custom key generated from a checksum of a file (say <em>package.json</em>), you keep your cached files until you actually touch that file again.</p><p>All other caching solutions for drone offer only a single storage form for your cache. drone-cache in contrast offers 2 storage forms out of the box: an <strong>S3 bucket</strong> or a <strong>mounted volume</strong>. Even better, drone-cache provides a pluggable backend system, so you can implement your own storage backend.</p><p>Last but not least, drone-cache is a small CLI program, written in Go without any external OS dependencies. So even if you are not using Drone as your build system, you can still fork and tinker with drone-cache to make it fit your needs.</p><h3>What we have learned?</h3><p>Building a caching solution is hard. Especially, if every team in your company uses it every time they push something to their repositories. It is also fun because it means you have users who give you feedback from the beginning. With the help of my colleagues’ feedback and feature requests, we have crafted this plugin.</p><blockquote><em>There are only two hard things in Computer Science: cache invalidation and naming things.</em></blockquote><blockquote><em>Phil Karlton</em></blockquote><p>What could we have done better? As I have mentioned before, rather than forking and modifying a new code base, we could have contributed back to the original project. We could have applied “release early and often” philosophy to open sourcing this repository, and we would have collected feedback from the outside world as well. However we didn’t, that’s mostly on me. This is the first time I actually open sourced a project and contributed back to the community. So next time I will know better :)</p><p>In Meltwater we are using <em>drone-cache</em> in 20 teams and 120 components now. It works and gets things done for us. We have learned a lot while we build it. We hope this also solves similar problems of yours.</p><p>Please <a href="https://github.com/meltwater/drone-cache">try it</a> in your pipeline, give us feedback, feel free to open issues and send us pull-requests. Personally, I am also very interested to discuss your experiences with open sourcing in general, so if you have any thoughts on that, please share them in the comments below.</p><p><strong>Image Credits</strong></p><p>xkcd.com — How standards proliferate <a href="https://xkcd.com/927/">https://xkcd.com/927/</a></p><p><em>Originally published at </em><a href="https://underthehood.meltwater.com/blog/2019/04/10/making-drone-builds-10-times-faster/"><em>underthehood.meltwater.com</em></a><em> on April 10, 2019.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=138dbb7fe000" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>