<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>icyveins7's blog</title><link>https://icyveins7.github.io/</link><description>Recent content on icyveins7's blog</description><generator>Hugo</generator><language>en-us</language><copyright>This work is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License.</copyright><lastBuildDate>Wed, 02 Sep 2026 20:00:00 +0800</lastBuildDate><atom:link href="https://icyveins7.github.io/index.xml" rel="self" type="application/rss+xml"/><item><title>Large pinned host allocations in CUDA</title><link>https://icyveins7.github.io/posts/2026/09/large-pinned-host-allocations-in-cuda/</link><pubDate>Wed, 02 Sep 2026 20:00:00 +0800</pubDate><guid>https://icyveins7.github.io/posts/2026/09/large-pinned-host-allocations-in-cuda/</guid><description>&lt;blockquote&gt;&#10;&lt;p&gt;Sometimes, you just can&amp;rsquo;t fit everything in VRAM.&lt;/p&gt;&#10;&lt;/blockquote&gt;&#10;&lt;p&gt;In most CUDA projects, the advice is usually to transfer all inputs, outputs, and temporary scratch space to the device. Working completely inside VRAM is &lt;em&gt;fast&lt;/em&gt;, and avoids both the complexity and the throughput hit that comes with over-PCIe transfers being scattered throughout your hot path.&lt;/p&gt;&#10;&lt;p&gt;All of this is correct, and I adhere to this myself as much as possible. Sometimes, though, you simply just can&amp;rsquo;t do this, and recently I was left with no choice and had to start migrating stuff back to host memory.&lt;/p&gt;</description></item><item><title>Occupancy-maxxing is just Starcraft</title><link>https://icyveins7.github.io/posts/2026/08/occupancy-maxxing-is-just-starcraft/</link><pubDate>Wed, 12 Aug 2026 20:00:00 +0800</pubDate><guid>https://icyveins7.github.io/posts/2026/08/occupancy-maxxing-is-just-starcraft/</guid><description>&lt;blockquote&gt;&#10;&lt;p&gt;If you can manage minerals and gas, you can manage CUDA threads and registers.&lt;/p&gt;&#10;&lt;/blockquote&gt;&#10;&lt;blockquote&gt;&#10;&lt;p&gt;CUDA is just resource management.&lt;/p&gt;&#10;&lt;/blockquote&gt;&#10;&lt;p&gt;Okay, of course there&amp;rsquo;s a lot more to squeezing CUDA kernel performance than &lt;em&gt;just resource management&lt;/em&gt;, but occupancy is very often the simplest thing to strive for, once you know how. And usually, if you&amp;rsquo;ve hit 100% occupancy, then unless you&amp;rsquo;ve done something heinous in your code, further optimizations are unlikely to budge your performance by large factors (aside from an entire algorithmic shift, but we won&amp;rsquo;t discuss that here).&lt;/p&gt;</description></item><item><title>Your left-right boundary search is actually a CUDA-friendly single scan</title><link>https://icyveins7.github.io/posts/2026/06/your-left-right-boundary-search-is-actually-a-cuda-friendly-single-scan/</link><pubDate>Fri, 26 Jun 2026 20:00:00 +0800</pubDate><guid>https://icyveins7.github.io/posts/2026/06/your-left-right-boundary-search-is-actually-a-cuda-friendly-single-scan/</guid><description>&lt;blockquote&gt;&#10;&lt;p&gt;At least, most of the time it is. As long as it fits the 1-2-1 pattern..&lt;/p&gt;&#10;&lt;/blockquote&gt;&#10;&lt;p&gt;Many segments can be boiled down to what I call a 1-2-1 pattern. For an array of input elements (I&amp;rsquo;ll just call them pixels, it&amp;rsquo;s shorter for me to type), a naive segment detection is to loop forwards until you hit an &lt;em&gt;activation&lt;/em&gt; pixel. This can internally be any condition you&amp;rsquo;d like; that is, any &lt;code&gt;if (...)&lt;/code&gt; is possible here as long as you operate only on the pixel you&amp;rsquo;re currently at. For simplicity, I&amp;rsquo;ll assume this is the &lt;code&gt;2&lt;/code&gt; pixel:&lt;/p&gt;</description></item><item><title>Avoid being baited by your printf statements in CUDA kernels</title><link>https://icyveins7.github.io/posts/2026/03/avoid-being-baited-by-your-printf-statements-in-cuda-kernels/</link><pubDate>Mon, 23 Mar 2026 20:00:00 +0800</pubDate><guid>https://icyveins7.github.io/posts/2026/03/avoid-being-baited-by-your-printf-statements-in-cuda-kernels/</guid><description>&lt;blockquote&gt;&#10;&lt;p&gt;Behaviour of printf on device is not the same as on host!&lt;/p&gt;&#10;&lt;/blockquote&gt;&#10;&lt;p&gt;If you&amp;rsquo;re a &lt;code&gt;printf&lt;/code&gt; aficionado like me, then you use &lt;code&gt;printf&lt;/code&gt; for debugging. A lot. In fact I previously wrote a small logger that uses &lt;code&gt;printf&lt;/code&gt; called &lt;a href="https://github.com/icyveins7/spfLogger"&gt;spfLogger&lt;/a&gt;. I do enjoy the flexibility of tuning every single width/precision with a few characters, and it&amp;rsquo;s something I haven&amp;rsquo;t yet seen C++ be able to emulate with as little irritation.&lt;/p&gt;&#10;&lt;blockquote&gt;&#10;&lt;p&gt;I haven&amp;rsquo;t gotten around to writing code using newer &lt;code&gt;std::format&lt;/code&gt; or &lt;code&gt;println&lt;/code&gt; yet, so the jury&amp;rsquo;s out on that.&lt;/p&gt;</description></item><item><title>Iterative algorithms with CUDA</title><link>https://icyveins7.github.io/posts/2025/11/iterative-algorithms-with-cuda/</link><pubDate>Sat, 29 Nov 2025 20:00:00 +0800</pubDate><guid>https://icyveins7.github.io/posts/2025/11/iterative-algorithms-with-cuda/</guid><description>&lt;blockquote&gt;&#10;&lt;p&gt;Because not everything can be made un-iterative..&lt;/p&gt;&#10;&lt;/blockquote&gt;&#10;&lt;p&gt;There&amp;rsquo;s a pretty large class of algorithms that have been developed for CPUs that involve, optimally, an iterative solver.&lt;/p&gt;&#10;&lt;p&gt;Usually, this is defined by some notion of &lt;em&gt;convergence&lt;/em&gt;; some variable is updated, and then at the end of each iteration it is checked to determine whether further iterations are required.&lt;/p&gt;&#10;&lt;p&gt;This is all fine and dandy in CPU-land, but in GPUs this almost always makes the flow awkward.&lt;/p&gt;</description></item><item><title>Build your own tools, gcc edition</title><link>https://icyveins7.github.io/posts/2025/10/build-your-own-tools-gcc-edition/</link><pubDate>Mon, 20 Oct 2025 20:00:00 +0800</pubDate><guid>https://icyveins7.github.io/posts/2025/10/build-your-own-tools-gcc-edition/</guid><description>&lt;blockquote&gt;&#10;&lt;p&gt;Not complicated, but always good to know the process.&lt;/p&gt;&#10;&lt;/blockquote&gt;&#10;&lt;p&gt;In this series (?) I&amp;rsquo;ll cover something I always wanted to write down: compiling the toolchains/compilers I use from source. This means, specifically, no using of package managers i.e. not allowed to &lt;code&gt;sudo apt install&lt;/code&gt; dependencies. Of course, this has its limits (&lt;em&gt;you need a compiler to compile gcc, and some OSes don&amp;rsquo;t come pre-installed with one&lt;/em&gt;). However, the premise here is to at least be familiar with the minimal required dependencies, and where to get them (at the time of writing), and then what to do to build everything.&lt;/p&gt;</description></item><item><title>Stumbling into a sweep line algorithm's edge case</title><link>https://icyveins7.github.io/posts/2025/09/stumbling-into-a-sweep-line-algorithms-edge-case/</link><pubDate>Wed, 10 Sep 2025 20:00:00 +0800</pubDate><guid>https://icyveins7.github.io/posts/2025/09/stumbling-into-a-sweep-line-algorithms-edge-case/</guid><description>&lt;blockquote&gt;&#10;&lt;p&gt;Mistakes that you should learn from, lesson 1..&lt;/p&gt;&#10;&lt;/blockquote&gt;&#10;&lt;p&gt;I recently wrote some code for interval merging. Every leetcoder can probably recite 15 algorithms to do this in their sleep, but I figured it out myself in this case, and in the process fell into an edge case.&lt;/p&gt;&#10;&lt;p&gt;Here&amp;rsquo;s to writing down your mistakes.&lt;/p&gt;&#10;&lt;h1 id="interval-merging"&gt;Interval merging&lt;/h1&gt;&#10;&lt;p&gt;The generic interval merging problem provides you with a list of start/stop pairs which denote individual intervals. Each interval is then to be merged with any other overlapping intervals; an overlap is defined by at least 1 element being shared between 2 intervals.&lt;/p&gt;</description></item><item><title>Some tips for integrating small bits of CUDA code into larger codebases</title><link>https://icyveins7.github.io/posts/2025/08/some-tips-for-integrating-small-bits-of-cuda-code-into-larger-codebases/</link><pubDate>Wed, 13 Aug 2025 20:00:00 +0800</pubDate><guid>https://icyveins7.github.io/posts/2025/08/some-tips-for-integrating-small-bits-of-cuda-code-into-larger-codebases/</guid><description>&lt;blockquote&gt;&#10;&lt;p&gt;Some lessons from general C++ come in handy here..&lt;/p&gt;&#10;&lt;/blockquote&gt;&#10;&lt;p&gt;In some recent work I integrated some CUDA code I developed into a larger existing codebase, written for the CPU. Essentially, my module(s) would accelerate and replace some existing functionality, but was only a small cog in the machine.&lt;/p&gt;&#10;&lt;p&gt;This is likely applicable to many others, so hopefully the lessons I document here will be concisely useful to those who chance upon this post.&lt;/p&gt;</description></item><item><title>Quickly sketching out a BlockQuickSelect</title><link>https://icyveins7.github.io/posts/2025/07/quickly-sketching-out-a-blockquickselect/</link><pubDate>Sun, 20 Jul 2025 20:00:00 +0800</pubDate><guid>https://icyveins7.github.io/posts/2025/07/quickly-sketching-out-a-blockquickselect/</guid><description>&lt;blockquote&gt;&#10;&lt;p&gt;I wrote a blockwide quickselect. That&amp;rsquo;s the post.&lt;/p&gt;&#10;&lt;/blockquote&gt;&#10;&lt;p&gt;As of today, NVIDIA&amp;rsquo;s &lt;code&gt;cub&lt;/code&gt; library has a few block-wide primitives to do sorting - like &lt;code&gt;BlockRadixSort&lt;/code&gt; - but none that do the equivalent for the $k$&amp;lsquo;th order statistic i.e the $k$-th smallest element.&lt;/p&gt;&#10;&lt;p&gt;This would be functionally equivalent to the CPU&amp;rsquo;s &lt;code&gt;std::nth_element&lt;/code&gt;, but that &lt;a href="https://en.cppreference.com/w/cpp/algorithm/nth_element.html"&gt;apparently uses Introselect&lt;/a&gt;, which is a tad too much for me to want to implement. I&amp;rsquo;m going to stick with the simpler &lt;a href="https://en.m.wikipedia.org/wiki/Quickselect"&gt;quickselect&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>Old dog, old C struct tricks</title><link>https://icyveins7.github.io/posts/2025/07/old-dog-old-c-struct-tricks/</link><pubDate>Mon, 14 Jul 2025 20:00:00 +0800</pubDate><guid>https://icyveins7.github.io/posts/2025/07/old-dog-old-c-struct-tricks/</guid><description>&lt;blockquote&gt;&#10;&lt;p&gt;Look at this code snippet and tell me with a straight face you didn&amp;rsquo;t think it was a memory leak at first either..&lt;/p&gt;&#10;&lt;/blockquote&gt;&#10;&lt;p&gt;A while ago I worked on some code which contained a container that looked like this:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;S&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; size_t sz;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; data[&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;];&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Set&lt;/span&gt;(size_t _sz, &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;_data){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; sz &lt;span style="color:#f92672"&gt;=&lt;/span&gt; _sz;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; memcpy(data, _data, &lt;span style="color:#66d9ef"&gt;sizeof&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt;)&lt;span style="color:#f92672"&gt;*&lt;/span&gt;sz);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you&amp;rsquo;re a modern programmer like me, you might be looking at this and thinking: &lt;em&gt;there&amp;rsquo;s no way this isn&amp;rsquo;t a flagrant memory violation in almost every case&lt;/em&gt;. Right? Well, it turns out this is something them old boys before C99 used to do.&lt;/p&gt;</description></item><item><title>Interesting Tidbits from GTC 2025: CUDA Graphs</title><link>https://icyveins7.github.io/posts/2025/03/interesting-tidbits-from-gtc-2025-cuda-graphs/</link><pubDate>Tue, 25 Mar 2025 20:00:00 +0800</pubDate><guid>https://icyveins7.github.io/posts/2025/03/interesting-tidbits-from-gtc-2025-cuda-graphs/</guid><description>&lt;blockquote&gt;&#10;&lt;p&gt;In the 2nd post of this series, I give a short introduction on something that is also not particularly new, but new to me - CUDA Graphs!&lt;/p&gt;&#10;&lt;/blockquote&gt;&#10;&lt;p&gt;As stated in my first post of this series, this topic isn&amp;rsquo;t particularly new per-se. Indeed, it looks like it has been out since 2019. But maybe CUDA graphs have increased in relevance now that GPUs are more powerful. As usual, a good starting reference is NVIDIA&amp;rsquo;s own &lt;a href="https://developer.nvidia.com/blog/cuda-graphs/"&gt;blogpost&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>Interesting Tidbits from GTC 2025: Asynchronicity Beyond Streams</title><link>https://icyveins7.github.io/posts/2025/03/interesting-tidbits-from-gtc-2025-asynchronicity-beyond-streams/</link><pubDate>Mon, 24 Mar 2025 20:00:00 +0800</pubDate><guid>https://icyveins7.github.io/posts/2025/03/interesting-tidbits-from-gtc-2025-asynchronicity-beyond-streams/</guid><description>&lt;blockquote&gt;&#10;&lt;p&gt;Some notes for CUDA programmers who haven&amp;rsquo;t kept up with the times; this first post covers in-kernel pipelining..&lt;/p&gt;&#10;&lt;/blockquote&gt;&#10;&lt;p&gt;I recently had the privilege of being sponsored to attend the March 2025 GTC in person. While the sessions were very largely dominated by AI-related things, I generally selected the CUDA-related ones, since they were more relevant to my work (and interests).&lt;/p&gt;&#10;&lt;p&gt;I&amp;rsquo;ll try to encapsulate some of the new things I learnt while I was there into a few major concepts. Note that most, if not all of these, are not shiny new CUDA features - some of them have been out for several years, but I just didn&amp;rsquo;t know about them, so I learnt about them there.&lt;/p&gt;</description></item><item><title>AtomicMinFloat; overloading integer-only atomics for floating-point numbers in CUDA</title><link>https://icyveins7.github.io/posts/2025/03/atomicminfloat-overloading-integer-only-atomics-for-floating-point-numbers-in-cuda/</link><pubDate>Sun, 16 Mar 2025 20:00:00 +0800</pubDate><guid>https://icyveins7.github.io/posts/2025/03/atomicminfloat-overloading-integer-only-atomics-for-floating-point-numbers-in-cuda/</guid><description>&lt;blockquote&gt;&#10;&lt;p&gt;Convincing you (and myself) that with some minor edits, we can still use atomicMin for floats in CUDA..&lt;/p&gt;&#10;&lt;/blockquote&gt;&#10;&lt;p&gt;CUDA has a set of atomic functions for &lt;em&gt;safely&lt;/em&gt; updating the same memory address with different threads. There&amp;rsquo;s a whole list of them in the programming guide &lt;a href="https://docs.nvidia.com/cuda/cuda-c-programming-guide/#atomic-functions"&gt;here&lt;/a&gt;.&lt;/p&gt;&#10;&lt;p&gt;However, for &lt;code&gt;atomicMin&lt;/code&gt; (and also &lt;code&gt;atomicMax&lt;/code&gt;), there isn&amp;rsquo;t an overload that works with &lt;code&gt;float&lt;/code&gt;s (or &lt;code&gt;double&lt;/code&gt;s , but who uses those in CUDA anyway..). For this discussion we&amp;rsquo;ll just focus on &lt;code&gt;atomicMin&lt;/code&gt;, but all the points we discuss can be inverted to explain &lt;code&gt;atomicMax&lt;/code&gt;.&lt;/p&gt;</description></item><item><title>Gotta go (randomly) fast, thrust vs cuRAND</title><link>https://icyveins7.github.io/posts/2025/03/gotta-go-randomly-fast-thrust-vs-curand/</link><pubDate>Mon, 10 Mar 2025 20:00:00 +0800</pubDate><guid>https://icyveins7.github.io/posts/2025/03/gotta-go-randomly-fast-thrust-vs-curand/</guid><description>&lt;blockquote&gt;&#10;&lt;p&gt;How fast can you generate (pseudo-)random numbers on the GPU?&#10;How fast can you generate (pseudo-)random numbers on the GPU?&lt;/p&gt;&#10;&lt;/blockquote&gt;&#10;&lt;p&gt;I recently had to answer this question. Well, not exactly this question, but this was a key part of it.&lt;/p&gt;&#10;&lt;p&gt;A quick google search will bring up two common methods (libraries) when trying to do this in CUDA: thrust and cuRAND. Thrust is known to be a lot easier to set up; no need to write the kernel code and nitty gritty details, so I started with that.&lt;/p&gt;</description></item><item><title>When circumstances don’t allow you to use unique_ptr</title><link>https://icyveins7.github.io/posts/2025/02/when-circumstances-dont-allow-you-to-use-unique_ptr/</link><pubDate>Sun, 23 Feb 2025 20:00:00 +0800</pubDate><guid>https://icyveins7.github.io/posts/2025/02/when-circumstances-dont-allow-you-to-use-unique_ptr/</guid><description>&lt;blockquote&gt;&#10;&lt;p&gt;Some background on my single header file memory manager and why I made it..&lt;/p&gt;&#10;&lt;/blockquote&gt;&#10;&lt;p&gt;Picture this. You are working on a codebase with some &lt;del&gt;lazy&lt;/del&gt; &lt;del&gt;inept&lt;/del&gt; questionable decisions from external forces. You are given a class to work on. For the purposes of this post let’s call it &lt;code&gt;MyClass&lt;/code&gt;.&lt;/p&gt;&#10;&lt;p&gt;The class will have its methods invoked in the following order:&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;&lt;code&gt;MyClass()&lt;/code&gt; i.e. the constructor.&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;setup(…)&lt;/code&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;run(…)&lt;/code&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;teardown()&lt;/code&gt;&lt;/li&gt;&#10;&lt;li&gt;Repeat 2-4 many times.&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;~MyClass()&lt;/code&gt; i.e. the destructor.&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p&gt;This class will be reused in multiple different scenarios repeatedly, with different input data.&lt;/p&gt;</description></item><item><title>Cross-platform trigonometric SIMD and how the C ABI confused me</title><link>https://icyveins7.github.io/posts/2025/01/cross-platform-trigonometric-simd-and-how-the-c-abi-confused-me/</link><pubDate>Thu, 30 Jan 2025 20:00:00 +0800</pubDate><guid>https://icyveins7.github.io/posts/2025/01/cross-platform-trigonometric-simd-and-how-the-c-abi-confused-me/</guid><description>&lt;blockquote&gt;&#10;&lt;p&gt;My small journey in discovering libmvec functions and the C problems I encountered..&lt;/p&gt;&#10;&lt;/blockquote&gt;&#10;&lt;p&gt;I was recently working on making an existing Windows-only library of SIMD functions cross-platform i.e. making everything work in Linux. Here I&amp;rsquo;m going to highlight some problems I encountered in the process; hopefully it will help someone if they encounter something similar too.&lt;/p&gt;&#10;&lt;h1 id="the-windows-msvc-function"&gt;The Windows (MSVC) function&lt;/h1&gt;&#10;&lt;p&gt;Intrinsics are usually tied to compiler implementations. The one that gave me issues was a bunch of trigonometric functions. Let&amp;rsquo;s use the SSE version that works on floats; in MSVC this was implemented as a simple&lt;/p&gt;</description></item><item><title>Esoteric Errors: 'hidden symbol is referenced by DSO'</title><link>https://icyveins7.github.io/posts/2024/10/esoteric-errors-hidden-symbol-is-referenced-by-dso/</link><pubDate>Fri, 18 Oct 2024 20:00:00 +0800</pubDate><guid>https://icyveins7.github.io/posts/2024/10/esoteric-errors-hidden-symbol-is-referenced-by-dso/</guid><description>&lt;blockquote&gt;&#10;&lt;p&gt;Hidden linkage isn&amp;rsquo;t something I&amp;rsquo;d encountered until now, so maybe this will help someone else too..&lt;/p&gt;&#10;&lt;/blockquote&gt;&#10;&lt;h1 id="a-new-series-of-posts"&gt;A new series of posts&lt;/h1&gt;&#10;&lt;p&gt;I recently started work on a new codebase - one that is very large and has multiple moving components, from a frontend desktop UI (not my business) to the hardware interface (also not my business) and the backend processing (this one&amp;rsquo;s my business).&lt;/p&gt;&#10;&lt;p&gt;The standard build process had been setup on a remote server, and most people were ok with the process of connecting to it with tangible amounts of latency, but I was not. So my stubborn ass decided to figure out how to build it myself on a local machine. In the process, I encountered a ridiculous number of build errors; they were using custom Makefiles, but they had been generated by some other tool (possibly from Windows, even though it was being built in Linux, since there was a Windows VS solution as well).&lt;/p&gt;</description></item><item><title>Who knew a simple logger class would be this complicated?</title><link>https://icyveins7.github.io/posts/2024/09/who-knew-a-simple-logger-class-would-be-this-complicated/</link><pubDate>Mon, 09 Sep 2024 20:00:00 +0800</pubDate><guid>https://icyveins7.github.io/posts/2024/09/who-knew-a-simple-logger-class-would-be-this-complicated/</guid><description>&lt;blockquote&gt;&#10;&lt;p&gt;Writing a printf-based C++ logger class was more of a journey than I originally thought..&lt;/p&gt;&#10;&lt;/blockquote&gt;&#10;&lt;p&gt;I recently had to work with a codebase where the build process was so convoluted it couldn’t be run and debugged from within a Visual Studio instance, &lt;em&gt;despite being a Visual Studio solution&lt;/em&gt;.&lt;/p&gt;&#10;&lt;p&gt;This was primarily because it had a bunch of Java components, which were mainly used for the UI, and that prevented it from being run as a standard C++ application within the debugger (or maybe you could? I couldn’t find a way..)&lt;/p&gt;</description></item><item><title>Some notes on 2D real-to-complex Fourier transforms</title><link>https://icyveins7.github.io/posts/2024/07/some-notes-on-2d-real-to-complex-fourier-transforms/</link><pubDate>Mon, 15 Jul 2024 20:00:00 +0800</pubDate><guid>https://icyveins7.github.io/posts/2024/07/some-notes-on-2d-real-to-complex-fourier-transforms/</guid><description>&lt;blockquote&gt;&#10;&lt;p&gt;IPP in particular has some very niche ways of packing R2C DFT output, but otherwise there&amp;rsquo;s a few pointers here to keep in mind for how they are implemented in most libraries.&lt;/p&gt;&#10;&lt;/blockquote&gt;&#10;&lt;p&gt;It&amp;rsquo;s pretty well known that the output of a Fourier transform of real inputs has symmetric properties. This is due to the fact that real waves consist of two conjugate pairs of complex exponentials.&lt;/p&gt;&#10;&lt;p&gt;What may be a bit less obvious (at least to me, when examining some programming libraries) is exactly how many useful output elements there are, and under which scenarios. In particular, I looked at IPP (which has some special packed structure), and cuFFT/NumPy/SciPy (which follow the FFTW structure I think).&lt;/p&gt;</description></item><item><title>CRTP, method chaining, and static polymorphism</title><link>https://icyveins7.github.io/posts/2024/05/crtp-method-chaining-and-static-polymorphism/</link><pubDate>Sat, 04 May 2024 20:00:00 +0800</pubDate><guid>https://icyveins7.github.io/posts/2024/05/crtp-method-chaining-and-static-polymorphism/</guid><description>&lt;blockquote&gt;&#10;&lt;p&gt;Yes, it&amp;rsquo;s yet another blogpost about CRTP and how it&amp;rsquo;d be useful..&lt;/p&gt;&#10;&lt;/blockquote&gt;&#10;&lt;h1 id="the-1st-issue-method-chaining"&gt;The 1st issue: method chaining&lt;/h1&gt;&#10;&lt;p&gt;Have you seen a billion other blogposts about CRTP? Yes, so have I. But maybe there&amp;rsquo;s a reason for all of them; it wasn&amp;rsquo;t really apparent when reading them previously why it would be useful and/or why I would ever need it.&lt;/p&gt;&#10;&lt;p&gt;But recently, while writing some simple templated code for &lt;a href="https://github.com/icyveins7/ufl"&gt;&lt;code&gt;ufl&lt;/code&gt;&lt;/a&gt;, I had the bright idea of trying to make method chaining possible for the class. That&amp;rsquo;s when my templated class and its derived friend implementation started to fall apart. I fixed this by using CRTP for the first time.&lt;/p&gt;</description></item><item><title>Some heuristic proofs for cyclostationary methods</title><link>https://icyveins7.github.io/posts/2024/04/some-heuristic-proofs-for-cyclostationary-methods/</link><pubDate>Tue, 16 Apr 2024 20:00:00 +0800</pubDate><guid>https://icyveins7.github.io/posts/2024/04/some-heuristic-proofs-for-cyclostationary-methods/</guid><description>&lt;blockquote&gt;&#10;&lt;p&gt;Carrier offset and baud rate estimation can be done blindly using cyclostationary (cyclic moment) methods, but why?&lt;/p&gt;&#10;&lt;/blockquote&gt;&#10;&lt;h1 id="introduction"&gt;Introduction&lt;/h1&gt;&#10;&lt;p&gt;In &lt;a href="https://github.com/icyveins7/reimage"&gt;ReImage&lt;/a&gt;, there are options to blindly estimate a signal&amp;rsquo;s baud rate or residual carrier offset. These require some working knowledge, and only work on some types of modulations like PSK. But why do they work, and how do we explain the peaks we see in the resulting spectra?&lt;/p&gt;&#10;&lt;p&gt;First, some terminology. Here I&amp;rsquo;ll often mention the exponents in a &lt;em&gt;CM&lt;/em&gt; XY form: this refers to applying an exponent onto a signal with a total of $X$, where $Y$ of that is the conjugate. These refer to the cyclic moments.&lt;/p&gt;</description></item><item><title>Getting rid of clangd's errors on Windows</title><link>https://icyveins7.github.io/posts/2024/03/getting-rid-of-clangds-errors-on-windows/</link><pubDate>Tue, 26 Mar 2024 20:00:00 +0800</pubDate><guid>https://icyveins7.github.io/posts/2024/03/getting-rid-of-clangds-errors-on-windows/</guid><description>&lt;blockquote&gt;&#10;&lt;p&gt;My first steps into migrating to neovim, some clangd problems and my solutions..&lt;/p&gt;&#10;&lt;/blockquote&gt;&#10;&lt;h1 id="kickstartnvim-brought-me-here"&gt;Kickstart.nvim brought me here&lt;/h1&gt;&#10;&lt;p&gt;I started using vim motions in VSCode a month or two ago, and decided to actually try to see if neovim would work for me. Honestly, I probably wouldn&amp;rsquo;t have gone down this path if &lt;a href="https://github.com/nvim-lua/kickstart.nvim"&gt;kickstart.nvim&lt;/a&gt; didn&amp;rsquo;t exist. But it does, and I tried it, and it looks like I&amp;rsquo;m here to stay.&lt;/p&gt;&#10;&lt;h1 id="clangd-as-my-first-lsp"&gt;clangd as my first LSP&lt;/h1&gt;&#10;&lt;p&gt;In kickstart.nvim&amp;rsquo;s template, &lt;code&gt;clangd&lt;/code&gt; is listed as an example LSP, so I decided to uncomment that line and try it out. I opened my &lt;a href="https://github.com/icyveins7/ffs"&gt;ffs&lt;/a&gt; repository at the time, and was immediately greeted with a flood of warnings on my code. This brings us to the first problem.&lt;/p&gt;</description></item><item><title>Clang and Eigen's alternatives to complex multiplication SIMD</title><link>https://icyveins7.github.io/posts/2024/03/clang-and-eigens-alternatives-to-complex-multiplication-simd/</link><pubDate>Mon, 11 Mar 2024 20:00:00 +0800</pubDate><guid>https://icyveins7.github.io/posts/2024/03/clang-and-eigens-alternatives-to-complex-multiplication-simd/</guid><description>&lt;blockquote&gt;&#10;&lt;p&gt;Clang isn&amp;rsquo;t much better than MSVC for complex number multiplication, while Eigen is equivalent to GCC but uses slightly different instructions.&lt;/p&gt;&#10;&lt;/blockquote&gt;&#10;&lt;h1 id="complex-number-multiplication-is-probably-not-common-enough"&gt;Complex Number Multiplication Is Probably Not Common Enough&lt;/h1&gt;&#10;&lt;p&gt;I think I might have bashed MSVC too much on the last post; trying to vectorise our simple 4-element complex number multiplication using clang with AVX instructions delivers &lt;a href="https://godbolt.org/z/35dGqTfKv"&gt;similarly poor results&lt;/a&gt;:&lt;/p&gt;&#10;&lt;pre tabindex="0"&gt;&lt;code&gt;#include &amp;lt;complex&amp;gt;&#10;&#10;void cmul(&#10; const std::complex&amp;lt;float&amp;gt;* __restrict__ x,&#10; const std::complex&amp;lt;float&amp;gt;* __restrict__ y,&#10; std::complex&amp;lt;float&amp;gt;* __restrict__ z&#10;){&#10; for (int i = 0; i &amp;lt; 4; ++i)&#10; z[i] = x[i] * y[i];&#10;}&#10;&#10;void mul(&#10; const float* __restrict__ x,&#10; const float* __restrict__ y,&#10; float* __restrict__ z&#10;){&#10; for (int i = 0; i &amp;lt; 8; ++i)&#10; z[i] = x[i] * y[i];&#10;}&#10;&lt;/code&gt;&lt;/pre&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;cmul(std::complex&amp;lt;float&amp;gt; const*, std::complex&amp;lt;float&amp;gt; const*, std::complex&amp;lt;float&amp;gt;*): # @cmul(std::complex&amp;lt;float&amp;gt; const*, std::complex&amp;lt;float&amp;gt; const*, std::complex&amp;lt;float&amp;gt;*)&#10; vmovsd xmm0, qword ptr [rdi] # xmm0 = mem[0],zero&#10; vmovsd xmm1, qword ptr [rsi] # xmm1 = mem[0],zero&#10; vbroadcastss xmm2, xmm0&#10; vmovshdup xmm0, xmm0 # xmm0 = xmm0[1,1,3,3]&#10; vshufps xmm3, xmm1, xmm1, 225 # xmm3 = xmm1[1,0,2,3]&#10; vmulps xmm0, xmm3, xmm0&#10; vfmaddsub231ps xmm0, xmm1, xmm2 # xmm0 = (xmm1 * xmm2) +/- xmm0&#10; vmovlps qword ptr [rdx], xmm0&#10; vmovsd xmm0, qword ptr [rdi + 8] # xmm0 = mem[0],zero&#10; vmovsd xmm1, qword ptr [rsi + 8] # xmm1 = mem[0],zero&#10; vbroadcastss xmm2, xmm0&#10; vmovshdup xmm0, xmm0 # xmm0 = xmm0[1,1,3,3]&#10; vshufps xmm3, xmm1, xmm1, 225 # xmm3 = xmm1[1,0,2,3]&#10; vmulps xmm0, xmm3, xmm0&#10; vfmaddsub231ps xmm0, xmm1, xmm2 # xmm0 = (xmm1 * xmm2) +/- xmm0&#10; vmovlps qword ptr [rdx + 8], xmm0&#10; vmovsd xmm0, qword ptr [rdi + 16] # xmm0 = mem[0],zero&#10; vmovsd xmm1, qword ptr [rsi + 16] # xmm1 = mem[0],zero&#10; vbroadcastss xmm2, xmm0&#10; vmovshdup xmm0, xmm0 # xmm0 = xmm0[1,1,3,3]&#10; vshufps xmm3, xmm1, xmm1, 225 # xmm3 = xmm1[1,0,2,3]&#10; vmulps xmm0, xmm3, xmm0&#10; vfmaddsub231ps xmm0, xmm1, xmm2 # xmm0 = (xmm1 * xmm2) +/- xmm0&#10; vmovlps qword ptr [rdx + 16], xmm0&#10; vmovsd xmm0, qword ptr [rdi + 24] # xmm0 = mem[0],zero&#10; vmovsd xmm1, qword ptr [rsi + 24] # xmm1 = mem[0],zero&#10; vbroadcastss xmm2, xmm0&#10; vmovshdup xmm0, xmm0 # xmm0 = xmm0[1,1,3,3]&#10; vshufps xmm3, xmm1, xmm1, 225 # xmm3 = xmm1[1,0,2,3]&#10; vmulps xmm0, xmm3, xmm0&#10; vfmaddsub231ps xmm0, xmm1, xmm2 # xmm0 = (xmm1 * xmm2) +/- xmm0&#10; vmovlps qword ptr [rdx + 24], xmm0&#10; ret&#10;mul(float const*, float const*, float*): # @mul(float const*, float const*, float*)&#10; vmovups ymm0, ymmword ptr [rsi]&#10; vmulps ymm0, ymm0, ymmword ptr [rdi]&#10; vmovups ymmword ptr [rdx], ymm0&#10; vzeroupper&#10; ret&#10;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Compiled with clang 18.1.0, with &lt;code&gt;-O3 -ffast-math -march=x86-64-v3&lt;/code&gt;, this still refuses to vectorise the &lt;code&gt;cmul&lt;/code&gt; function correctly, only using the &lt;code&gt;xmm&lt;/code&gt; registers. I included the normal real-valued float multiplication to check that clang is indeed able to vectorise that. Note that you still need the &lt;code&gt;__restrict__&lt;/code&gt; keywords for the vectorisation to work. Using &lt;code&gt;-ffast-math&lt;/code&gt; doesn&amp;rsquo;t seem to do anything for us in the real float vectorisation, but it does make the complex-valued vectorisation less verbose.&lt;/p&gt;</description></item><item><title>MSVC's terrible auto-vectoriser for AVX</title><link>https://icyveins7.github.io/posts/2024/02/msvcs-terrible-auto-vectoriser-for-avx/</link><pubDate>Sat, 24 Feb 2024 20:00:00 +0800</pubDate><guid>https://icyveins7.github.io/posts/2024/02/msvcs-terrible-auto-vectoriser-for-avx/</guid><description>&lt;blockquote&gt;&#10;&lt;p&gt;MSVC has extremely lackluster auto-vectorisation, so I handrolled intrinsic calls by backtranslating GCC&amp;rsquo;s output.&lt;/p&gt;&#10;&lt;/blockquote&gt;&#10;&lt;h1 id="the-motivation"&gt;The Motivation&lt;/h1&gt;&#10;&lt;p&gt;I recently decided I wanted to spend some time understanding intrinsics and SIMD at a deeper level.&lt;/p&gt;&#10;&lt;p&gt;In developing code for my project &lt;a href="https://github.com/icyveins7/ffs"&gt;&lt;code&gt;ffs&lt;/code&gt;&lt;/a&gt;, I wanted to make sure that the code was running with at least AVX instructions (because that&amp;rsquo;s my target architecture, and honestly very few computers don&amp;rsquo;t have AVX these days..).&lt;/p&gt;&#10;&lt;p&gt;This led me down a path of discovery; first I discovered the amazing-ness that is &lt;a href="https://godbolt.org"&gt;godbolt.org&lt;/a&gt;, then I joined their discord, where I then asked for some help with understanding basic .asm compiler output.&lt;/p&gt;</description></item><item><title>Getting IPP to work on non-Intel chips</title><link>https://icyveins7.github.io/posts/2024/02/getting-ipp-to-work-on-non-intel-chips/</link><pubDate>Mon, 19 Feb 2024 20:00:00 +0800</pubDate><guid>https://icyveins7.github.io/posts/2024/02/getting-ipp-to-work-on-non-intel-chips/</guid><description>&lt;blockquote&gt;&#10;&lt;p&gt;Intel Performance Primitives is not guaranteed to work on non-Intel chips, but there are some ways around it..&lt;/p&gt;&#10;&lt;/blockquote&gt;&#10;&lt;p&gt;Over the last year or so I&amp;rsquo;ve written a C++ wrapper of header-only templates around a library known as Intel Performance Primitives (IPP). I often use this for its signal processing library, which is - at least by my measurements - one of the fastest, if not the fastest one around. It also has the benefit of having almost everything I need in one place: FFT/DFTs, math array processing, low-pass filtering etc. You can see my templates at the &lt;a href="https://github.com/icyveins7/ipp_ext"&gt;&lt;code&gt;ipp_ext&lt;/code&gt;&lt;/a&gt; repository.&lt;/p&gt;</description></item><item><title>Is this thing on?</title><link>https://icyveins7.github.io/posts/2024/02/is-this-thing-on/</link><pubDate>Wed, 14 Feb 2024 20:00:00 +0800</pubDate><guid>https://icyveins7.github.io/posts/2024/02/is-this-thing-on/</guid><description>&lt;blockquote&gt;&#10;&lt;p&gt;Testing out this template..&lt;/p&gt;&#10;&lt;/blockquote&gt;&#10;&lt;p&gt;Are we live?&lt;/p&gt;&#10;&lt;p&gt;Seems like we are. Playing around with next-js for like the 2nd time in my life here..&lt;/p&gt;</description></item></channel></rss>