IAsyncEnumerable WithCancellation

I recently used IAsyncEnumerable in C# the first time. In this post, I will summarize some of my learnings based on .NET 9.

There is an excellent introduction to Iterating with Async Enumerables that introduces they key concepts from the iterators point of view and then details the internals of an async enumerator.

Key Concepts

IAsync­Enumerable<T> allows creating iterators that produce elements in an asynchronous fashion. Although it has been around for a few years, it is not commonly seen in application source code. Typically, iteration happens over a collection where elements are already computed, making synchronous iteration adequate, like iterating a list of integers. There are also cases where the elements of an iterator can computed synchronously, for example the runtime provides Enumerble.Range or Enumerable.Repeat iterators. Additionally, Select extension can project each element of a sequence into a new shape, like a Task<T>, then a consumer awaits these tasks to complete concurrently.

Find out more


HTTP2 Huffman Decoding

Introduction

HTTP2 headers can contain string literals that are Huffman encoded for compression. Before processing these headers, servers must first decode them according to RFC 7541.

A string literal in a header consists of three components:

  • A single bit flag indicating Huffman encoding

  • The length of the encoded data

  • The encoded data itself

Find out more


Notes on Code Coverage for .NET Applications

This post summarizes my learnings about code coverage visualization in SonarQube and GitLab.

Formats for GitLab and SonarQube

I'll detail different options for displaying code coverage for a C# (.NET) application in both tools. GitLab uses Cobertura coverage files. When such a file is uploaded as a job artifact, GitLab marks each line as covered or uncovered in a pull request (Merge Request in GitLab terms). GitLab also provides other coverage features that are not covered in this post.

SonarQube accepts several coverage formats. As of writing this post, for .NET applications it works with coverage files in these formats:

Find out more


Getting Started with ClrMD

What is ClrMD?

ClrMD or Microsoft.Diagnostics.Runtime NuGet package is a helpful tool to analyze crash dumps or debug applications at runtime.

This post discusses scenarios where this tool excels compared to other diagnostic tools. Its capabilities are comparable to WinDBG with the SOS extension or PerfView. As a NuGet package, it also provides common CLR abstractions enabling developers to build their own diagnostic tools.

In most investigations, the usual tools such as WinDBG + SOS, PerfView, Visual Studio's performance profiler, etc. provide clear insights into the application. However, in rare cases, a developer might want to write custom scripts or code for deeper analysis not available through standard commands or views. In these cases, ClrMD comes to the rescue.

Find out more


Constant Folding and Inlining

In .NET the JIT performs more-and-more optimization on the code using dynamic PGO, constant folding and inlining. While writing this post, I am using .NET 9 Runtime on x64 architecture, although many of the discussed optimizations are available in one or another form since .NET 7. The presented assembly code snippets generated by the runtime are all optimized, Tier1-OSR code using Dynamic PGO.

Constant-Folding is applied when a compiler 'sees' a constant expression and replaces it with the result of the expression. The C# compiler does it at compile time (ie. var i = 3 + 4; can be substituted with var i = 7). Some expressions involving readonly fields, environment specific parameters, architecture, CPU, etc. can only be folded at runtime. In this latter case the JIT compiler may perform the optimization.

Inlining is a technique where a method's invocation is replaced with the actual body of the method. This reduces the overhead of the method invocation, but it increases the overall code size (and memory consumption) at runtime. This optimization also allows further optimizations across the overall method at the callsite.

These two optimizations can work together to achieve an overall optimization that is only possible at runtime. In this blog post I will present one such case.

Find out more