The goal of this post is to look at the design of
sync.WaitGroup. This type is obviously subject to Go’s compatibility guarantee, so it won’t be changing. Nevertheless, the curious might be interested in a comparison with an alternate design, and those ideas might be useful elsewhere. This comparison is by looking at
sync.WaitGroup as one type of executor.
With concurrent code, non-determinism is often present. I knew this, but obviously did not internalize it. Tests of an optimization of sync.Once passed, but the code was incorrect. I got good feedback on the mailing list about what invariant I’d missed, but, additionally, I got feedback that the error could have caught by testing if I had run the test repeatedly.
For C++ development, I developed GCovHTML to generate reports on code coverage. For Go development, I use the builtin tool to generate these reports. The HTML reports generated by Go are nice in that that are a single file, but they do not include as much detail. To evaluate whether or not it would be feasible to process the profile data from Go using my tool, I investigated the format of the coverprofile output files. This turned up an interesting comparison in how Go tracks coverage data, and what that means for reporting.
To learn parts of LLVM related to machine code generation, I decided to follow through on a comment that a binary asset compiler could be written in a few hundred lines of C++. The goal of the program would be to provide fast and portable compilation of binary assets. The term compilation is used loosely here, it is more to wrap the asset into an object file, which can then be linked into a library or program. This project turned into a bit of code golf, and I implemented a second separate binary asset compiler. What follows is a comparison of the performance of these tools with other options.
A few people responded to the criticism of D1040 on reddit, and clearly there are at least a few people who are keen to see
std::embed move forward. The rebuttals were imprecise, which obviously makes understanding the commenters’ concerns more difficult. However, the discussion did clarify a few things for me.
One of the current proposals for changing C++ is D1040R4, which proposes adding a function called
std::embed, which can load binary assets during compilation. My initial reaction to the proposal was that the author’s must have missed the existing solutions to this problem. That was hubris (sorry). The authors have indeed considered existing solutions, and the proposal is well written, but the motivation for this feature needs more thought. It is not clear that the existing solutions are insufficient, or if moving that functionality into the compiler would be a benefit.
During the talk of proposals for new features for Go, such as simplifying error handling and generics, I found myself reaching for, and missing, a different tool. The proposals are not bad, but I use Go knowing that it is not an expressive language, and adjust accordingly. But working through a recent design, I found myself missing old-fashioned assertions. In particular, they can be used to document and enforce program invariants, such as preconditions or postconditions, in your code.
As a small improvement for this site, I wanted to add a favicon. Naively, I thought that this would be trivial. The logo is generated by a small script, and can easily be resized or converted to a different format. I had one small question, what is the best size?
The standard approach to reading files is some equivalent to calling the functions open, read (repeatedly), and close. This pattern repeats across languages1. However, for simply accessing a sequence of bytes, there is another approach that provides a much nicer API for reading files – memory mapped files. Instead of managing read buffers, one can use the operating system’s virtual memory management (VMM) to page in data as required. Here, I would like to show an implementation for C++.
If you study electronics, eventually you come to the chapter on diodes. Model 1: a diode is a switch that only lets current flow one way. Then you learn that it takes some forward voltage to turn the diode on. Model 2: a diode is a switch that closes only when the forward voltage is above a critical voltage. But of course, digital circuits are just analog circuits driven to extremes. Model 3: current through a diode can be modelled using the diode equation. Then you learn about parasitic series resistance (Model 4), and then various modes of breakdown (Model 5). All of this is just in DC. When looking at AC, there are additional models and additional parasitics to learn.
Determining alignment tolerances between directly aligned layers is, well, direct. These tolerances will be set by equipment capability1. However, unless you are planning to measure O(n²) values, indirect alignment tolerances require a little calculation. Unfortunately, I have seen this done incorrectly, using the root-mean-square (RMS) value.
Bitrot, it stalks all software. In this case, it stalked my previous blog platform. It was custom built using Go and PostgreSQL. Built during the earlier introduction of the package
database/sql, the platform uses a custom wrapper around