Writings about software development.
Solving Scheduling With Z3 from Rust
A translation of a Z3 example from Python to Rust
This post is a translation of a Z3 example from Python to Rust. It is not very inspired: Please read the original Python article 1 for more background. However, at the bottom of this page, I provide a few more links and resources with a few notes.
The Z3 crate does not have any examples, so it makes it a bit tough to get started. I found one article that explains how to use Z3 for scheduling tasks in Python.
Apple M1 Performance Cycles
A short update: I just published my second crate (a Rust package): https://crates.io/crates/macos-perf
I hope this can be used to accurately measure Rust code on M1 Apple devices.
Please try it, and provide feedback.
Example
Running the example code I provide gives the following results:
sudo cargo run --quiet --example main
PerformanceCounters {
cycles: 46148.1,
branches: 23053.4,
missed_branches: 2.4,
instructions: 162342.9,
}
We see the missed branches, cycles, branches taken and instructions. Unfortunately, none of this is documented by the vendor (Apple). But, Dougall Johnson wrote code to interact with the undocumented macOS syscalls. So, this is what my library uses.
Rust Serde Versioning
Serde is an amazing collection of Rust libraries for Serialization and Deserialization with many useful supported formats.
For example, I can convert a YAML file into a native Rust struct by just slapping a #[derive(Deserialize)] above the struct.
One challenge that I faced was reading YAML files of different schema versions.
One option is to use Option<T> for all fields which changed between versions. Generally speaking, this is probably the easiest and most suitable solution. However, when parsing is also used as a linter, this will not suffice. For example, we might have a version 1.0 that has fields a and b (both required). In version 2.0, only a remains and b is replaced by c.
Rust CLI Video Tutorial
A while back, I posted my first Rust Video. In it, I am showing how to write a simple command line application in Rust – including useful libraries.
The CLI is mimicking the GNU shuf utility: It randomly shuffles files of an input file.
Practical Tips for Advanced Git Bisect
Practical Notes on Advanced Git Bisect
This is an adaptation from my Twitter thread:
Git Bisect Thread
Recap of Bisect
I assume you’ve used or heard of git bisect. If you’ve neither heard off nor used git bisect before, then I encourage you to give it a try. Franziska Hinkelmann provides a good intro and a test repo to find a bug with git bisect.
Recap:
git bisect start BAD GOOD- <RUN TEST>
- label result with
git bisect goodor... bad(orskip) - Goto 2 until git bisect tells you it’s done.
This then does a binary search1 through all commits between the GOOD and the BAD commit. After each step you have to label the current commit with good, bad or skip. Because binary search halfs the search range in every step, the number of commits to check is approximately log2(N), where N is the number of commits between GOOD and BAD. This means you can check 1000 commits in just 10 steps!
Optimizing C++ Word Count
Yesterday’s post showed that the original C++ version is around 13 times slower than my non-optimized Rust version. Next, I’ll show how to get easily equivalent performance to Rust.
One problem that I immediately made out when first seeing the C++ version is
that it uses std::regex. std::regex is known to be horribly slow 1.
Just replacing the checking of the file name extension with the in-built
e.path().extension() != ".txt" speeds up from 373 ms to 52ms!
Swift Word Count
Yesterday, I wrote about implementing word-count in Rust. Having never written Swift before1, I wanted to try my hand at the same problem.
This is certainly not comparable to my Rust version or the C++ version 2. Doing this in Swift just consisted of constant googling and the result is certainly not what a proficient Swifter would write.
Getting started
I created a new Swift package, and built it in the command line. All three commands need no explanation:
Rust Word Count
Last week there were two posts on the reputation of C++. In a noble effort, Jussi Pakkanen showcased modern C++. Nothing fancy, just clean and readable code. Unfortunately, around ten years after C++11, the news that simple (and safe) C++ code is now the default has not spread everywhere.
Jason Moiron answered with Go code doing the same (article). Both programs find the ten most common words in all txt files, which can be recursively found in the current directory.
Sentry and C++
Crash Reporting
If your program is running on more than one machine or is used by others, you probably want to get some insight into when things fail. I believe this is commonly called “Crash Reporting”.
Such a crash reporting system will consist of a component to collect individual incidents and of a component to aggregate individual reports. For example, it will group common incidents by stack trace.
One public example of this, is Mozilla’s system (Socorro). Have a look here for statistics on all of Mozilla’s projects. Or here, for just the top ten Firefox crashes from a specific version:
Nushell vs Bash
After last week’s post on how Nushell can be used to convert unstructured data to structured data, I wondered how I would approach the task using traditional tooling. I wrote ‘Bash’ in the title, but what I precicesley mean is POSIX pipes and command line utilities typically found on a Unix-like environment (Linux, macOS, etc).
Again, the task is to convert weirdly structured text output (from sshping) to JSON for further processing or long term storage. For example, I might set up a cronjob to run analytics for my SSH connectivity. The results would be handy to have in JSON for later statistics.