RSSAmplifier

Blog

Clojure Goes Fast

High-performance Clojure made simple.

clojure-goes-fast.comRSS feed ↗24 posts

Latest posts

Tracking memory usage with clj-memory-meter.trace

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…

clj-async-profiler 1.4.0: custom tooltips, easy diffing, new index page

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…

clj-async-profiler 1.3.0: new sidebar and snappier rendering

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…

System-wide user.clj with tools.deps

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…

Performance tidbit: runtime type checks

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…

clj-async-profiler 1.1.0: right-click menu and startup profiling

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…

Clojure's deadly sin

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…

Project Valhalla vs. ray tracer: will it go faster?

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…

Profiling tool: async-profiler

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…

Benchmarking tool: Criterium

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…

Using JMH with Clojure - part 1

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.

clj-async-profiler 1.0.0: fast HTML rendering and dynamic transforms

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,…

clj-async-profiler 0.4.0: diffgraphs and UI

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…

Shenandoah GC in production: experience report

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…

clj-async-profiler: tips, tricks, new features

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…

Latency tool: jvm-hiccup-meter

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…

Java arrays and unchecked math

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…

Introspection tool: object memory meter

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…

Introspection tools: Java decompilers

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…

Clojure's slow start — what's inside?

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…

Bookshelf: "Clojure High Performance Programming"

Full name: Shantanu Kumar, "Clojure High Performance Programming", 2013.

Performance nemesis: reflection

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…

Profiling tool: VisualVM

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…

New site: Clojure goes fast!

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…