Scientific Computing

C++ std::endl requires <ostream> header

C++ standard library (STL) improvements over time include paring down internal includes where possible as best practice and to improve compilation time. When user code accidentally relies on internal includes, it can lead to compilation errors when the internal includes are removed by the STL maintainers or external libraries. Tools like IWYU can help identify missing or unused include statements.

GCC 15 STL removed some superfluous <ostream> includes that may affect code using std::endl without including <ostream>. It’s a common mistake to assume that <iostream> includes std::endl. When checking code to ensure that std::endl code files include <ostream>, consider if the code could use \n newline instead to improve code performance by avoiding unnecessary stream flushing with std::endl. Part of checking if \n can be used instead of std::endl is to observe if downstream code requires the output buffer to be flushed – for example in interactive CTest runs.

Raspberry Pi power consumption

The Raspberry Pi 5 power management IC PMIC is the Renesas DA9091, a chip specifically designed for the Pi 5. The Raspberry Pi 3B+ and Raspberry Pi 4 PMIC is the MaxLinear MXL7704. Older Raspberry Pi models used custom circuitry or the APX803 instead of a COTS PMIC to handle sequencing of discrete DC power input to the Pi subsystems. It has been noted that damaging the PMIC can make the Raspberry Pi too difficult to repair.

A yellow lightning bolt is GPU-superimposed on the Raspberry Pi display output for low voltage. In general computing platform operation is not guaranteed with voltages out of tolerance. The SD card can become unreadable, the Pi may have random malfunctions, and corrupt data (bad writes) on the SD card. Raspberry Pi 4 and Pi 5 require a minimum 5 Volt 3.0 Amp power supply. Using peripherals can require higher current supply. The cable between the power supply and Raspberry Pi must be of good quality to minimize voltage drop and unstable operation. The USB-C power connector of the Raspberry Pi 4 and Pi 5 is markedly more robust than the micro-USB power connector of legacy Raspberry Pi models.

Raspberry Pi Low voltage alarm

If the DC input voltage falls below 4.65 volts (depending on Raspberry Pi model and firmware), the GPU superimposes a lightning bolt graphic on the display output. This may not be visible on a VNC remote desktop.

yellow lightning bolt

Measure Raspberry DC input voltage / current

The Raspberry Pi 5 added vcgencmd pmic_read_adc to read DC input voltage and the several generated voltages and currents consumed. On older Raspberry Pi models there is no built-in capability to measure the Raspberry Pi DC input voltage without adding an external ADC.

On the older Raspberry Pi (older than Pi 5) it may be possible to read the input voltage binary state (OK or low) from the Terminal, but we have not confirmed this. On the Raspberry Pi 1 B+ and Pi 2 it may be possible to read state of GPIO 35, depending on the hardware and firmware. On the Raspberry Pi 3 in may be possible to read GPU-driven LED status.

Mitigate inadequate power supply

When compiling programs with concerns about excessive power consumption, consider not compiling in parallel. For GNU Make, “make -j1” uses 1 CPU core. For Ninja compilation in parallel is default, so specify “ninja -j1” for one build thread. For meta-build systems limit build parallelism like CMake cmake --build build -j1 or Meson meson compile -j1

Related: Measure Raspberry Pi CPU temperature

Terminal text web browsers

lynx is a text web browser that allows browsing certain websites without need for a graphical display. Several other text-based web browsers for Terminal are available, and while they offer some measure of increased security due to their lacking JavaScript or easily disabling JS, there have been CVEs for these web browsers as well. With this type of browser using a custom engine, the web-browsing data bandwidth can be dramatically less than with general graphical web browsers as the graphics and JavaScript might simply be ignored and not downloaded. This orders of magnitude reduction in data usage can be useful for those with limited data plans or slow connections. This can be useful at remote arctic sites or on a satellite connection.

However, the lack of a general web browser backend engine like Chrome or Firefox can lead to many websites not rendering properly or at all. An alternative approach is to render the website remotely and send only rendered text over a secure connection like SSH. This achieves dramatic data bandwidth reduction to the remote site by rendering at a server with a normal full internet connection. An implementation of this approach using a headless Mozilla Firefox is browsh. Browsh keybindings or mouse can be used to browse the web in the Terminal. On Windows, Browsh can be installed by winget:

winget install browsh.browsh

Matlab prerelease practices

Matlab previously made prerelease users sign a non-disclosure agreement (NDA), which hindered users from giving feedback about significant changes or bugs. Developers of Matlab packages were likewise inhibited from updating their packages to work with new syntax or features. There was typically one prerelease and the official release would sometimes have large jumps between the prerelease and added, removed, or changed features. Each official release would have a few updates to fix bugs and add minor features. Each official release was a gamble as to its quality and support by third-party packages.

Thankfully, Mathworks loosened the prerelease restrictions to allow public discussion and implementation of prerelease features. Matlab prereleases are updated several times before the official release to help ensure features and fixes work across the diverse computing platforms Matlab supports. Kudos to Mathworks for having a more open prerelease process.

Git 2.49 can use Zlib-ng

Git 2.49 added the option to build with Zlib-ng, which can give a reported 25% compression speedup, which can be quite significant for large repositories. Rust also began to be integrated in Git code along with further “libification” of Git code for reusability and quality.

Install Gfortran or Flang compiler on macOS Homebrew

Homebrew can install Fortran compilers including GCC and LLVM Flang.

Gfortran

Gfortran comes with GCC Homebrew package:

brew install gcc

As a complete C / C++ / Fortran compiler package, Gfortran doesn’t require additional flags or environment variables.

To use GCC compilers, source a script like:

p=$(brew --prefix gcc)/bin
v=14

export CC=$p/gcc-$v CXX=$p/g++-$v FC=$p/gfortran-$v

where v=14 is the major version number of the GCC compiler installed. It may be necessary to set SDKROOT if the compiler fails to find the C++ standard library headers like cstring, cstddef, etc.

LLVM Flang

LLVM Flang is a separate package from the LLVM C/C++ compilers:

brew install flang

To use Flang compiler (works with Clang, AppleClang, GCC C-C++ compilers), source a script like:

export FC=$(brew --prefix flang)/bin/flang

To use LLVM Clang with Flang, source a script like:

p=$(brew --prefix llvm)/bin
export CC=$p/clang CXX=$p/clang++

export FC=$(brew --prefix flang)/bin/flang

Troubleshooting

When a new compiler version or macOS version or Xcode SDK is released, it may be necessary to adjust the environment variables or flags temporarily until Homebrew updates the package.

Some examples to try if needed:

  • LIBRARY_PATH for libSystem.tbd and libc++.tbd

    export LIBRARY_PATH=/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib
  • LDFLAGS to the C++ standard library

    export LDFLAGS=-lc++

SDKROOT may also be needed.

LLVM Flang Fortran compiler

Since 2015, NVIDIA has supported development of LLVM-based Flang Fortran compiler. The legacy non-LLVM Flang was based on the PGI compiler, with proprietary optimizations removed. However, the C-based decade-plus of cruft led Flang developers and management to a ground-up rewrite in modern C++. LLVM flang targets Fortran 2018 syntax and is implemented in modern C++ internally. Flang became part of LLVM 11.

Building the LLVM Flang Fortran compiler from source is a resource-intensive process made simple by this script.

Build system priority execution

When doing large builds on a computer that’s also used for interactive tasks (say, a developer laptop), the system may feel sluggish to the user while building. Likewise, running tests can take a lot of CPU time and make the system less responsive. To mitigate the high CPU usage, the run priority of the build system or test runner can be lowered. This does not help if the system is running out of RAM or has low disk IOPS, but it can help if the system is CPU-bound. Running at a lower priority can be more efficient than simply hard-limiting the number of CPU cores used by the build system or test runner.

These examples apply to virtually any build system such as CMake or Meson.

On Unix-like systems (Linux, macOS, BSD, …) use nice to control process priority.

nice -n 19 cmake --build build

nice -n 19 meson compile -C build
nice -n 19 ctest --test-dir build

nice -n 19 meson test -C build
nice -n
run task(s) with priority, where bigger positive numbers are lower priority, and more negative numbers are higher priority.

On Windows the start command can control process priority.

start /low cmake --build build

start /low meson compile -C build
start /low ctest --test-dir build

start /low meson test -C build
start /low
runs a program and its child processes at low priority.

Matlab buildtool subprojects

Matlab buildtool uses buildfile.m build plans that can each call other buildfile.m to stitch together Matlab subprojects from a top-level project. An example syntax for a top-level buildfile.m that invokes say Git submodule Matlab project is:

function plan = buildfile
plan = buildplan(localfunctions);
plan.DefaultTasks = "setup";
assert(~isMATLABReleaseOlderThan("R2024b"), "Subprojects with buildtool requires Matlab R2024b or newer")

end


function setupTask(context)

sub1 = fullfile(context.Plan.RootFolder, "MySubproject/buildfile.m")

% Matlab gitrepo() doesn't yet have the ability to run this command after cloning

if ~isfile(sub1)
  ok = system("git -C " + context.Plan.RootFolder + " submodule update --init --recursive");
  assert(ok == 0, "Failed to update MySubproject Git submodule");
end

buildtool("-buildFile", sub1, "setup")
% assumes that sub1 also has a task named setup that should be run

end