Category Archives: tech

2021 MacBook Pro (14-inch) Impressions

While working from home for most of 2020 and 2021 I’ve been using my 12-core (24-thread) Mac Pro for my usual C++ development. For the eventual return to the office (which is still a rather big question mark), I didn’t want returning there and working from a laptop to be such a huge step down, so of course I ordered one of the shiny new 2021 MacBook Pros. I went for the 14-inch for portability, as I’m mostly using it in clamshell-mode at my desk, and only occasionally when traveling (remember that?).

As I’m only really stressing the CPU, the 10-core “Pro” version with the small GPU is totally adequate, and the 32GB were enough memory to load all those cores when compiling. The extra memory bandwidth of the “Max” doesn’t help much when only loading the CPU.

The display is very nice (more dimming zones than the Pro Display XDR), but I hardly notice ProMotion (up to 120Hz refresh rate).

For some benchmarks, I compiled our largely C++ work project (using a different build system to Xcode — which seems to have trouble parallelizing large builds) on all cores (including hyper-threads on the Mac Pro):

  • 2019 Mac Pro (12-core, 24-thread; 96GB): 4m54secs
  • 2021 MacBook Pro (8+2-core, 32GB, 14-inch): 3m50secs
  • 2021 MacBook Pro (8+2-core, 32GB, 14-inch) low-power mode: 4m32secs

So that’s roughly 28% faster on the laptop. The fans become audible after ~2min on full load, but they aren’t as annoying as the ones on my previous 2018 i9 Intel MacBook Pro which spun up at the slightest provocation. The new MBP’s fans sound more like low-level white noise. With low-power mode enabled (which throttles the CPU), the fans do come on as well, but only spin at a barely audible level; resulting in a slow-down of 15% compared to normal operation (and still being faster than the Mac Pro).

Using clang on macOS to compile g++ / libstdc++ compatible binaries

clang++ by default compiles for system “native” C++ library. On macOS, that is LLVM’s libc++. But what happens if happen to have a lot of binaries (on in my case) libraries compiled with g++ using its own libdstdc++ library?

Why was I doing that in the first place? Work stuff is mostly Linux and therefore uses gcc, and the Apple-provided clang that ships with Xcode.app doesn’t support OpenMP, so I ended up building a lot of stuff with a homebrew-sourced gcc. But it turns out that gcc’s OpenMP support on macOS (in particular the implementation of the synchronization primitives in libgomp) is surprisingly slow (on Linux it’s much better). I ended up with a piece of OpenMP code whose performance was so bad, I need to cross check what the cause was, and so I installed a (non-Apple) clang with which I wanted to compile the code in question, but preferably without having to rebuild all my gcc-compiled (and therefore libstdc++-using) dependencies.

The following seems to work for a homebrew-installed gcc 9.3 and llvm (clang) 10:

CXX=/usr/local/opt/llvm/bin/clang++
CXXFLAGS="-stdlib=libstdc++ -stdlib++-isystem /usr/local/Cellar/gcc/9.3.0_1/include/c++/9.3.0/ -cxx-isystem /usr/local/Cellar/gcc/9.3.0_1/include/c++/9.3.0/x86_64-apple-darwin19"
LDFLAGS="-stdlib=libstdc++ -L /usr/local/Cellar/gcc/9.3.0_1/lib/gcc/9 -L /usr/local/opt/llvm/lib"

The last part of the link flags that add the library path back to the homebrew clang are only required so that that clang‘s OpenMP support can find its libomp support library.

This works unless you used something like libstdc++‘s implementation of std::call_once, because that needs internal symbols that are declared as __thread, which with how homebrew’s gcc is configurationed specifically or gcc on Darwin behaves generally used “emulated thread-local storage” (tls), which in turn requires mangling that __thread declared symbol differently 😔. clang even knows about that (see -femulated-tls), but when I tried to use that variant (which did indeed link without complaint) I got weird malloc errors in emutls functions, and it was easier for me to replace std::call_once with a hack than figuring out where those errors came from.

Mac Pro History

  • 2006-08
    • 2.66 GHz 2×2-Core Xeon
    • 4 GB 667 MHz DDR2 ECC
    • ATI Radeon X1900 XT 512 MB
    • 500 GB Serial ATA 3 Gb/s drive
    • 16x SuperDrive DL
    • Airport Extreme & BT 2.0+EDR
  • 2013-12
    • 3.5 GHz 6-Core Xeon
    • 32 GB 1866 MHz DDR3 ECC
    • 2x AMD FirePro D700 6 GB GDDR5
    • 512 GB PCIe-based SSD
  • 2019-12
    • 3.3 GHz 12-Core Xeon
    • 96 GB 2933 MHz DDR4 ECC
    • Radeon Pro 580X 8 GB GDDR5
    • 1 TB SSD

Cores went up, (base-)speed went down slightly (although the average turbo-boosted speed should be higher). Memory per thread went up from 1 GB to 4 GB (hello huge C++ templates). The graphics card will be replaced by the AMD Radeon Pro W5700X once available.

SoundPusher

I’ve been on a bit of a coding spree during my time off work, and managed to make some progress on my old attempt to provide a virtual 5.1 sound-card that does real-time AC3 encoding to a digital output connection. This time around, I didn’t actually stop a third of the way in and it actually works (and quite well at that — at least on my system — if I may say so).

The code is on GitHub. If you’re interested helping with testing, feel free to get in touch.

For some internals, I reduced the number of components to two, as I eschewed AudioUnits (and thus the separate encoder) altogether. There’s now just the user-space LoopbackAudio driver (AudioServerPlugIn) and the SoundPusher application that reads from the loopback-driver, compresses that and then sends it to the real digital output stream. Latency is reasonable from my experiments, as is CPU usage.

Mechanical Keyboards for the Mac

Any odd USB keyboard will of course work with a Mac (with Mac OS X allowing you to swap the modifier keys as you see fit), but if you’re after a mechanical keyboard that also has the Mac-specific symbols printed on its keycaps, then your options are more limited:

  • There’s the Das Keyboard, which has an odd-dual USB pass-through arrangement as well as a glossy black plastic finish, which attracts fingerprints rather nicely.
  • Another option is the Tactile Pro, whose look and design I just don’t get on with at all.
  • If you want to go for a keyboard with Buckling Spring switches instead of the usual assortment of Cherry MXs, the only option is the Unicomp Spacesaver M.
  • A rather custom option is provided by the WASD Keyboards: They build you a keyboard with laser etched or engraved custom keycaps from your design (and they have a pre-made Mac layout).

I have a few more thoughts to offer on both the Spacesaver M as well as WASD V2 keyboards, as I bought one of each. Note: Noise is no consideration as these are my “home” keyboards.

Unicomp Spacesaver M

The keyboard feels heavy and very solid, although the finish of the plastic is not of very high quality. The seams are uneven and if you put pressure on the case, you can hear the plastic creaking. The design of the Mac-specific keycaps is rather slap-dash and not done with much care (no symbols for ⌘ or ⌥, odd alignment of symbols and text on the function keys). The ugly Unicomp logo fits right in (but you can order a cheap Black No LED Overlay from them — just lift and detach the existing one with a sharp thin blade and put the neutral one in its place).

All that being said, I do actually like the look of the black case with the dark grey modifier keys with the lighter keys.Unicomp Spacesaver M (black)

The switches themselves are really nice and I enjoy typing on them. They keys are comparatively high and have a good amount of stroke depth.

The key-mapping enables the Mac-specific shortcuts (Expose, Volume, Media Keys) on the F-keys by default, and you have to hold the Function (fn) key to get to the normal F-keys. You can lock (and unlock) the fn-key state by pressing Left-Shift + fn if you prefer to mainly use the F-keys directly (but you need to remember to redo this after every sleep / wake cycle).

The USB-interface takes a fair amount of time to wake up from a sleep-state (even longer if you used the keyboard itself to wake the computer), so you’ll usually to wait 3-4 seconds without key presses for the keyboard to re-initialise itself.

After a few weeks, my Spacesaver M developed problems with certain keys not registering (usually after Sleep), but replugging the keyboard seemed to fix it. After a while a (different) set of keys stopped responding altogether, and no amount of rebooting, replugging or shaking would fix it. After contacting Unicomp, they thankfully offered to ship me a replacement keyboard (even though their warranty statement specifically excludes warranty for internationally shipped products: Thanks, Jeanne!). The replacement worked fine for a while, but then developed very similar problems with a subset of keys no longer registering at the host.

Last weekend I finally found the time (and the needed 5.5mm nut) to open one of those keyboards up, and it turns out that the internal plastic ribbon cable, onto which the keyboard controller board (which is labelled Ruffian_V4_2) is directly screwed on top of, is not making full contact. The holes in the plastic have been partly ripped out and the alignment between the contacts on the backside of the controller board and cabling plastic sheet was misaligned. After a few attempts at reseating and realigning the controller board and the plastic sheet (and not screwing the board back in place too tightly because that prevented contact again) I seem to have repaired keyboards. I don’t know whether the connection between the plastic sheet and controller is that failure-prone, or whether international transport played a role, but my two keyboards (original + replacement) failed with exactly the same symptoms (and similar internal damage to the ribbon cable’s screw holes from the affixing of the controller board).

WASD V2 87-Key Custom Keyboard

After the Spacesaver M repeatedly failed (and before I figured out that I was able to repair them), I was looking for alternatives, and via Jeff Atwood’s CODE keyboard found out about WASD Keyboards. The CODE keyboard itself was of no particular interest to me, as it has Windows-keycaps as well as a backlight. It did have a configurable key-mapping, though (via DIP-switches).

Nonetheless, a closer look revealed that WASD will make a keyboard with anything you want printed on it (by giving them an Adobe Illustrator or PDF file from a defined template), and that their “normal” (non-CODE) keyboards have the same configurable keyboard controller. I had no interest in making my own custom layout, but they provide a very decent pre-made Mac-layout.

After some back and forth between the normal (102 keys) or tenkeyless (87 keys) version (which unfortunately are the same price — I’d have thought buying less plastic, switches and keys would’ve resulted in some savings…) and then a short interlude in the customs office, I obtained my custom keyboard with Cherry MX Blues:

WASD V2 87-Keys Mac

The design is very understated, with sharp edges and very little flourish or extraneous plastic. The case and finish is of a very high quality and I was positively surprised with the quality of the lettering; it does not look custom or one-off at all. After configuring the DIP switches (1 and 6 to ON for enabling the Mac-layout and the fn-key), it behaves like a proper Mac keyboard. In contrast to the Spacesaver M, the Function-keys only map to the function keys (and not any Mac specific functions) which I actually prefer. fn + insert / home / delete / end keys control media playback and fn + f13 acts as ⏏. Also nice is that the controller initialises very quickly after a USB-wake event.

The feel of the key-switches is nice (although the odd key initially seemed a bit reluctant to return back to its resting state after releasing it) but not quite as satisfying the Spacesaver M. It’s taken a bit more effort to get used to a keyboard without a number block than I would’ve though,  even though I work at a laptop all day at work. This is mainly because the subtle cue from my right pinky of the right side of the keyboard ending used to indicate the start of the number block, not the navigation keys.

In closing

Now that both keyboards are in a working state (as I’d ordered the WASD as a replacement after the replacement Spacesaver broke down and before I’d managed to repair them), I’m typing this on the WASD keyboard. I do actually prefer the feel of the buckling springs to the Cherry switches, but overall the WASD feels like it has much more care put into it, with a better finish and USB controller. That said, it is also a fair bit more expensive.  Both are enjoyable keyboards, but you should not order a Spacesaver M expecting a high quality plastic case and finish — you can expect high quality switches, though.

Code-Project: Virtual 5.1 Soundcard (Mac)

2015-12 Addendum: See SoundPusher for an update to (and new name for) this project.

As far as I’m aware there very few real-time 5.1 (Dolby Digital / AC-3) encoders for the Mac that integrate into the default CoreAudio HAL (and can thus be used by any application); I’ve only stumbled upon ac3jack, which builds on the multi-platform JACK Audio Connection Kit.
I thought it’d be interesting to learn something about CoreAudio and low-latency coding and thus decided to write such a system. Currently, this is split into 3 components:

  • CoreAudio AudioCodec for transforming LPCM into encoded AC-3. I’m using libavcodec as the encoder for this.
  • Audio driver presenting a virtual sound output to the system, and forwards that data as a provided sound input. The idea is to select the virtual output as default / system output, and then encode from the virtual input into the compressed format and forward that to a physical optical output.
    In 10.8 “Mountain Lion” you can write these sorts of plug-ins as sandboxed user-space components, which is quite neat (but not well documented at the moment).
  • A normal application / menu extra that takes raw sound from the virtual sound input, passes that to the AC-3 audio encoder, and then forwards the resulting stream to a physical digital output port.

The encoder seems to work; I’m currently working on the driver and then comes the user-space connector / configuration application.

Fun times! 😀