<?xml version='1.0' encoding='UTF-8'?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><atom:link href="https://clojure-goes-fast.com/" rel="self" type="application/rss+xml"/><title>Clojure Goes Fast</title><link>https://clojure-goes-fast.com/</link><description>High-performance Clojure made simple.</description><lastBuildDate>Tue, 18 Feb 2025 17:26:25 +0200</lastBuildDate><generator>clj-rss</generator><item><guid>https://clojure-goes-fast.com/blog/tracking-memory-usage/</guid><link>https://clojure-goes-fast.com/blog/tracking-memory-usage/</link><title>Tracking memory usage with clj-memory-meter.trace</title><description>Automatic memory management is probably JVM's biggest selling point. You don't need to remember to clean up the stuff you've allocated — the garbage collector will take care of it for you. You can "leak" memory if you leave live references to allocated objects (e.g. store objects in static fields), making them unreclaimable by the GC. Thus, as long as you don't do that, you can treat memory as infinite and never run out of it. Right?Definitely not. Memory is a limited resource, and you can't fill it with more data than its capacity allows if all of that data is needed at the same time. So, it becomes crucial not only to know how much memory your data structures occupy but also the access patterns to those data structures. Does the algorithm process one item at a time or expect the whole list to be in memory at once? Is the result gradually written to disk, or is it accumulated in memory first? These questions may not matter when the data size is small and doesn't ever get close to memory limits. But when they do...</description><pubDate>Tue, 18 Feb 2025 13:00:00 +0200</pubDate></item><item><guid>https://clojure-goes-fast.com/blog/clj-async-profiler-140/</guid><link>https://clojure-goes-fast.com/blog/clj-async-profiler-140/</link><title>clj-async-profiler 1.4.0: custom tooltips, easy diffing, new index page</title><description>It's been a month since the 1.3.0 announcement, and I'm ready to present you with a new, better, and improved clj-async-profiler — 1.4.0. This version maintains the focus on improvements to user experience and visual appeal. Teamed up with my talented design advisor, we've revamped the index page and implemented new custom tooltips in the flamegraph. Read on to discover these and other changes in the 1.4.0 release.Custom tooltips</description><pubDate>Sun, 22 Sep 2024 14:00:00 +0300</pubDate></item><item><guid>https://clojure-goes-fast.com/blog/clj-async-profiler-130/</guid><link>https://clojure-goes-fast.com/blog/clj-async-profiler-130/</link><title>clj-async-profiler 1.3.0: new sidebar and snappier rendering</title><description>I'm excited to announce a fresh release of clj-async-profiler — 1.3.0. This new version brings a lot of visual changes, so it deserves a separate post describing all the improvements and design considerations. I'm a visual person, and I firmly believe that even the smallest experiences (either delightful or annoying) may greatly impact the overall productivity. That's why, in order to make meaningful improvements to the current UX, I asked for the help of a person with actual design skills, talent, and taste (and who is very dear to me). Settling on the new design wasn't a clear-cut task and involved a lot of back-and-forth, but I'm pleased with the result, and I hope you will be, too.Sidebar looks and user experience</description><pubDate>Tue, 10 Sep 2024 14:00:00 +0300</pubDate></item><item><guid>https://clojure-goes-fast.com/blog/performance-tidbit-instanceof/</guid><link>https://clojure-goes-fast.com/blog/performance-tidbit-instanceof/</link><title>Performance tidbit: runtime type checks</title><description>Clojure Goes Fast now offers consulting services. Get in touch if you need personalized help with your performance challenges.In this post, we'll analyze the cost of checking whether an instance belongs to a certain class or interface at runtime. While this operation is relatively fast, it might still contribute a significant amount of execution time if performed at the hottest paths of your program.</description><pubDate>Thu, 16 May 2024 17:00:00 +0300</pubDate></item><item><guid>https://clojure-goes-fast.com/blog/system-wide-user-clj/</guid><link>https://clojure-goes-fast.com/blog/system-wide-user-clj/</link><title>System-wide user.clj with tools.deps</title><description>Updated on 2024-07-11: changed the approach from passing eval-command with :main-opts to adding a :local/root directory to classpath. The old approach can be found at the end of the post.Ever since I converted from Leiningen and Boot to tools.deps, I've been missing a place to define devtime functions and helpers that would automatically be available in any REPL I start locally. Boot allows to put any code into profile.boot, Leiningen has a system-wide profiles.clj that is a bit more awkward for defining functions but it still can be done. I finally decided to recreate the same experience with tools.deps and got pretty close. The setup I came up with took a bit of effort to figure out, so I want to document all the steps and gotchas here and share this setup with you.</description><pubDate>Thu, 11 Jul 2024 12:00:00 +0300</pubDate></item><item><guid>https://clojure-goes-fast.com/blog/clj-async-profiler-110/</guid><link>https://clojure-goes-fast.com/blog/clj-async-profiler-110/</link><title>clj-async-profiler 1.1.0: right-click menu and startup profiling</title><description>Last year, I made a major release of clj-async-profiler, introducing dynamic transforms within the flamegraphs. This granted users the ability to arbitrarily modify the profiling data on the fly without regenerating a flamegraph. Such an instrument lets you get a better picture and uncover hidden performance gotchas. For example, a solid usecase for this feature would be exploring the flamegraph of a recursive function, which becomes much more palatable when folded. I personally use dynamic transforms all the time, and they aid me tremendously in deciphering the profiling results. However, I acknowledge that writing regular expressions manually may be intimidating if you are not very familiar with them, and plain tedious if you are.The release 1.1.0 makes a step towards more user-friendly transforms by adding a custom context menu to flamegraphs. You can now right-click any frame in the flamegraph to open a dedicated menu. Here's what it looks like:</description><pubDate>Tue, 17 Oct 2023 10:30:00 +0300</pubDate></item><item><guid>https://clojure-goes-fast.com/blog/clojures-deadly-sin/</guid><link>https://clojure-goes-fast.com/blog/clojures-deadly-sin/</link><title>Clojure's deadly sin</title><description>This article is about laziness in Clojure. It is intended to be a comprehensive and objective (however possible) critique of lazy sequences as a feature. In no way do I want this to be a judgment of the decision to make Clojure lazy. Clojure the language is by no means formulaic; creating it involved making a plethora of impactful choices. We can judge by Clojure's longevity that the total package has been a success, but it's only natural that some decisions proved to be more accurate than others. Finally, this is not meant to criticize the people behind Clojure. Hindsight doesn't need glasses; it is incredibly tough to write a language (let alone a successful one) and easy to pick on its perceived shortcomings. Yet, I'm still willing to do the latter because I believe my diatribe can be helpful.My goal is to align the Clojure community's stance on laziness. Times and times again, the developers find themselves grappling with the complexities of the lazy approach, attributing their struggles to the lack of understanding of the Clojure Way[1]. I want to prove that many things make up the Clojure Way, and laziness doesn't have to be a defining characteristic. I want programmers to reduce or eliminate their reliance on laziness and not feel guilty about it just because laziness has been deeply ingrained in Clojure since its inception.</description><pubDate>Thu, 27 Jul 2023 18:30:00 +0300</pubDate></item><item><guid>https://clojure-goes-fast.com/blog/valhalla-vs-ray-tracer/</guid><link>https://clojure-goes-fast.com/blog/valhalla-vs-ray-tracer/</link><title>Project Valhalla vs. ray tracer: will it go faster?</title><description>TL;DR: Project Valhalla is an effort make Java more efficient when dealing with primitive-like objects. While still being experimental, it significantly cuts down object allocations and achieves up to a 2x speed increase (on some platforms) in our example task. Yet, in its current state, Valhalla should be applied together with careful benchmarking because performance regressions are also possible. For more details, please read on.Recently, I've discovered this guide which walks you through implementing a toy ray tracer from scratch. I took the implementation written in Clojure by Jeaye Wilkerson and wrote my own in Java to see if the two would have comparable performance. As I went through the task, it became clear that the bulk of computational work involves performing math operations with geometric vectors. Considering that the JVM allocates these vector objects on the heap and then furiously garbage-collects them, I couldn't help but wonder if this is an excellent opportunity to showcase the potential of Project Valhalla. Equipped with this insight and my regular performance tools, I conducted a couple experiments, and now I'm ready to share the results with you.</description><pubDate>Mon, 03 Jul 2023 15:00:00 +0300</pubDate></item><item><guid>https://clojure-goes-fast.com/blog/clj-async-profiler-100/</guid><link>https://clojure-goes-fast.com/blog/clj-async-profiler-100/</link><title>clj-async-profiler 1.0.0: fast HTML rendering and dynamic transforms</title><description>The first stable release of clj-async-profiler marks a principal milestone for this project. Almost five years have passed since its creation, and during these years, I used clj-async-profiler almost daily to make the programs I write faster and better. New challenges presented new ideas for improving the profiler, which in turn materialized in such features as diffgraphs, stack transforms, demunging, etc. Today, I released clj-async-profiler 1.0.0, which comes with more goodies that will hopefully improve your experience of using the profiler. In this post, I want to highlight these changes and teach you how to make use of them in your workflow.Here's a brief list of changes before we dive deeper into each of them:</description><pubDate>Fri, 22 Jul 2022 10:30:00 +0300</pubDate></item><item><guid>https://clojure-goes-fast.com/blog/clj-async-profiler-040/</guid><link>https://clojure-goes-fast.com/blog/clj-async-profiler-040/</link><title>clj-async-profiler 0.4.0: diffgraphs and UI</title><description>If you are already a user of clj-async-profiler, an embeddable low-overhead perf-based profiler for Clojure and Java, then the new 0.4.0 version will bring you a couple of exciting features. If you are yet to try it, check the introductory post, and maybe it encourages you to add clj-async-profiler to your toolbelt of performance analysis tools.In this post, I will describe what's new in the latest version of the profiler.</description><pubDate>Mon, 03 Jun 2019 12:00:00 +0300</pubDate></item><item><guid>https://clojure-goes-fast.com/blog/shenandoah-in-production/</guid><link>https://clojure-goes-fast.com/blog/shenandoah-in-production/</link><title>Shenandoah GC in production: experience report</title><description>Update: I've made several edits to the post since Aleksey Shipilëv was kind enough to suggest many corrections and improvements.If you closely follow JVM development scene, you've probably noticed that the last few years have been a renaissance of Java garbage collectors. From G1 finally becoming a default garbage collector in Java 9 and onward, to Oracle's ZGC which takes inspiration from Azul's C4 pauseless garbage collector, to Shenandoah being developed by Red Hat, it is evident that:</description><pubDate>Tue, 07 May 2019 13:00:00 +0300</pubDate></item><item><guid>https://clojure-goes-fast.com/blog/clj-async-profiler-tips/</guid><link>https://clojure-goes-fast.com/blog/clj-async-profiler-tips/</link><title>clj-async-profiler: tips, tricks, new features</title><description>Today I released clj-async-profiler 0.3.0. This version contains a few new features and possibilities that warrant a dedicated blog post clarifying them. I will try to give you the taste of what you are able to do with this profiler and what mistakes should be avoided.If this is the first time you hear about clj-async-profiler check this introduction. It explains the motivation behind this profiler and how to start using it.</description><pubDate>Mon, 04 Feb 2019 12:00:00 +0200</pubDate></item><item><guid>https://clojure-goes-fast.com/blog/using-jmh-with-clojure-part1/</guid><link>https://clojure-goes-fast.com/blog/using-jmh-with-clojure-part1/</link><title>Using JMH with Clojure - part 1</title><description>Updated on 2023-06-09: added instructions for tools.deps, updated for Leiningen, removed Boot.Runnable code for this post can be found here.Hello, performance junkies, long time no see. Today we will learn to access the tool that every JVM gofaster should (mis)use at least once in their lives — Aleksey Shipilёv's Java Microbenchmarking Harness.</description><pubDate>Fri, 09 Jun 2023 11:00:00 +0300</pubDate></item><item><guid>https://clojure-goes-fast.com/blog/latency-tool-jvm-hiccup-meter/</guid><link>https://clojure-goes-fast.com/blog/latency-tool-jvm-hiccup-meter/</link><title>Latency tool: jvm-hiccup-meter</title><description>There is a class of operating systems called real-time operating systems (RTOS). They are typically applied in mission-critical applications where an unpredictable delay is equal to failure (think rockets, airplanes, military technology, high-frequency trading to some extent). The key characteristic of such systems is that they guarantee certain time bounds for execution. The latency coming from a system should be deterministic and usually very small. Of course, having to satisfy this guarantee puts strict constraints on the programming model. For example, dynamic memory allocation is often not available as it can potentially take a long time to succeed or even fail completely. Multitasking is either not allowed or very limited, with a specialized scheduler to manage it. The choice of hardware is narrower, and choosing the correct one is a careful process.Now that you know what a RTOS is, let's face the truth that neither Linux nor JVM belong to that category. We enjoy the capabilities that our systems provide, like malloc, automatic garbage collection, preemptive multitasking on process and thread levels. But for that we have to pay the price: a program running inside may be arbitrarily interrupted, be starved for CPU for indeterminate time, spin idly in various locks and safepoints. So, we accept that our programs may experience delays caused by the external environment.</description><pubDate>Mon, 02 Jul 2018 12:00:00 +0300</pubDate></item><item><guid>https://clojure-goes-fast.com/blog/java-arrays-and-unchecked-math/</guid><link>https://clojure-goes-fast.com/blog/java-arrays-and-unchecked-math/</link><title>Java arrays and unchecked math</title><description>The design of Clojure explicitly promotes usage of efficient data structures. Unlike some other functional languages where the standard libraries revolve around lists, Clojure puts vectors and maps front and forward.Clojure vectors are an excellent data structure for sequential data. They provide almost O(1) lookups and updates[1], so it is natural to use them for large collections where speed is essential. However, vectors still have their overhead and might not be the fit for the tightest and most demanding performance spots.</description><pubDate>Mon, 09 Apr 2018 18:00:00 +0300</pubDate></item><item><guid>https://clojure-goes-fast.com/blog/introspection-tool-object-memory-meter/</guid><link>https://clojure-goes-fast.com/blog/introspection-tool-object-memory-meter/</link><title>Introspection tool: object memory meter</title><description>Long gone are the days when computer programmers counted every byte used by their programs. Today, we enjoy multi-gigabyte or even terabyte RAM machines and are much less frugal about the memory footprint of our data structures and algorithms. The way we squander all this memory would probably give a poor chap from the 1980s running the original 64K IBM PC a heart attack. But we are fine now, the memory is cheap, and the added value we get is worth paying for.However, sometimes we end up in a situation where each couple of bytes counts. Perhaps, you are dealing with so many objects that the overhead of a single one becomes relevant. E.g., this applies to NLP where you often deal with large dictionaries with millions of records. Each extra byte in a record turns into an additional megabyte of consumed heap. Another example is a web server which keeps all user sessions in memory. The less space a session occupies, the more of those sessions you can fit onto the server simultaneously.</description><pubDate>Mon, 05 Mar 2018 12:40:00 +0200</pubDate></item><item><guid>https://clojure-goes-fast.com/blog/introspection-tools-java-decompilers/</guid><link>https://clojure-goes-fast.com/blog/introspection-tools-java-decompilers/</link><title>Introspection tools: Java decompilers</title><description>As you probably are already aware of, Clojure compiles down to JVM bytecode. The fact that Clojure is not an interpreted language but a compiled one makes the compilation output tangible. The resulting classes are something that we can scrutinize and understand. In this post, we will take a look at tools that help us decipher the arcane internals of JVM classfiles.Why you need this (and what it has to do with performance)</description><pubDate>Mon, 29 Jan 2018 16:40:00 +0200</pubDate></item><item><guid>https://clojure-goes-fast.com/blog/clojures-slow-start/</guid><link>https://clojure-goes-fast.com/blog/clojures-slow-start/</link><title>Clojure's slow start — what's inside?</title><description>It is not surprising that the question of Clojure's long startup time is raised time and time again on forums and social media. This topic concerns users who want to use Clojure as a scripting language, or who have a particular workflow which requires restarting the Clojure program often. Compared to languages like Python, Ruby, and JavaScript all of which have less than 100 millisecond startup time, Clojure's seconds or even tenth of seconds seem incredibly slow and wasteful.The nature of Clojure loading is not exactly a secret. A few years ago Nicholas Kariniemi profiled Clojure startup process and described his findings in the post "Why is Clojure bootstrapping so slow?". One of the points Nick brings forward is that JVM is not to blame for Clojure's slowness — after all, a HelloWorld in Java executes in 50 ms. This is only partly true, JVM's startup time is not a problem, but the JVM as a platform makes Clojure starting time worse. JVM is optimized towards running long-lived programs and invests a lot of time upfront when initializing the classes. That's why Clojure on JVM boots much slower than ClojureScript on NodeJS.</description><pubDate>Tue, 02 Jan 2018 13:30:00 +0200</pubDate></item><item><guid>https://clojure-goes-fast.com/blog/profiling-tool-async-profiler/</guid><link>https://clojure-goes-fast.com/blog/profiling-tool-async-profiler/</link><title>Profiling tool: async-profiler</title><description>Updated on 2023-06-09: bumped version numbers and usage examples.A more comprehensive clj-async-profiler documentation is available on Knowledge Base.Runnable code for this post can be found here.In the previous installment, we learned how to use VisualVM to profile your Clojure applications. VisualVM is an excellent profiler: beginner-friendly, has enough features but not bloated, all-in-all a good one to dip your toes into the waters of profiling. However, VisualVM (and many other JVM profilers) suffer from safepoint bias. Long story short, most sampling profilers can get a snapshot of the stack only at the so-called safepoints — points of execution where the runtime can stop and look around. The placement of those safepoints is quite arbitrary, and it hampers the accuracy of profilers that have this problem.</description><pubDate>Fri, 09 Jun 2023 12:00:00 +0300</pubDate></item><item><guid>https://clojure-goes-fast.com/blog/bookshelf-kumar-clojure-highperf/</guid><link>https://clojure-goes-fast.com/blog/bookshelf-kumar-clojure-highperf/</link><title>Bookshelf: "Clojure High Performance Programming"</title><description>Full name: Shantanu Kumar, "Clojure High Performance Programming", 2013.</description><pubDate>Mon, 20 Nov 2017 12:00:00 +0200</pubDate></item><item><guid>https://clojure-goes-fast.com/blog/performance-nemesis-reflection/</guid><link>https://clojure-goes-fast.com/blog/performance-nemesis-reflection/</link><title>Performance nemesis: reflection</title><description>Imagine a very common situation — you need to write a string-processing function. Say, the input string contains a = character, and you have to grab everything to the left of it, drop all non-letter characters, and change the case of all letters inside. Like I said, totally common and makes plenty of sense.Anyway, you might start with a function that will generate a test string for you (you aren't gonna type the damn thing manually, are you?)</description><pubDate>Thu, 09 Nov 2017 12:00:00 +0200</pubDate></item><item><guid>https://clojure-goes-fast.com/blog/profiling-tool-jvisualvm/</guid><link>https://clojure-goes-fast.com/blog/profiling-tool-jvisualvm/</link><title>Profiling tool: VisualVM</title><description>If benchmarking is discovering out how long a piece of code takes to run as a whole, then profiling means figuring out how much time each function, method, or instruction spends. What do programmers use profilers for? The primary purpose, of course, is to optimize their code. But you don't want to go tweaking and rewriting your code blindly, spending time on optimizations that might not even matter. Profiling gives you exactly that. It identifies who are the primary contributors to your program's execution time. Once you know them, you can focus on revising them first as it will have the biggest effect.Many decent JVM profilers exist, but in this post, we will use the one called VisualVM. It is not the most accurate or feature-rich profiler out there, but it is free and actively developed. Actually, it is already included in your JDK distribution, so you can immediately launch it as jvisualvm in your terminal1. However, I recommend you grab the version from the official website since its release schedule is not tied to Java and it's more up-to-date there. If you install it from the site, you'll have to launch it differently (e.g., it is called "VisualVM" in Launchpad on MacOS).</description><pubDate>Thu, 28 Sep 2017 12:00:00 +0300</pubDate></item><item><guid>https://clojure-goes-fast.com/blog/benchmarking-tool-criterium/</guid><link>https://clojure-goes-fast.com/blog/benchmarking-tool-criterium/</link><title>Benchmarking tool: Criterium</title><description>Updated on 2023-06-09: revised numbers, added section about time+.Runnable code for this post can be found here.The most basic question a young performance acolyte may ask is "How long does it take to run my code"? Clojure is capable of answering such questions out of the box with the time macro. time takes a single expression and executes it. When the expression finishes running, it will print the time it took in milliseconds.</description><pubDate>Fri, 09 Jun 2023 12:00:00 +0300</pubDate></item><item><guid>https://clojure-goes-fast.com/blog/initial-commit/</guid><link>https://clojure-goes-fast.com/blog/initial-commit/</link><title>New site: Clojure goes fast!</title><description>Make it work, make it right, make it fast. This adage has been around for many years now. Some developers follow this principle to prioritize their efforts. Others use it as an excuse why their software is dog slow. The third group runs counter to the advice and spends their time optimizing the code that will be eventually thrown away. But regardless of which camp you are in, there will be a time when you have to make your program quicker. If that time is now — then you've come to the right place.Clojure, of all programming languages, is excellent for such after-the-fact acceleration. REPL-driven development together with powerful JVM tools create a rapid optimization environment yet to be seen anywhere else. Clojure offers a great variety of approaches for both pinpointing the performance issues and properly solving them. And the power of REPL allows you to tightly combine these two steps so that no time is wasted on compiling/running drudgery.</description><pubDate>Fri, 22 Sep 2017 12:00:00 +0300</pubDate></item></channel></rss>