Numerics on OpenBSD

Mathematical display

Numerics on OpenBSD - Introduction

This is a short guide to using compilers and some scripting languages for numerical calculations on OpenBSD.

Not all languages and scripts are included, mostly because I don’t know about all of them.

(This guide is valid for OpenBSD release 7.1 and should be considered obsolete after October 2023 unless updated. It is mostly about the AMD64 and compatible platforms.)

OpenBSD as a numerical computation platform

This is not historically one of OpenBSD’s reputational strengths. Mostly it is known for security and excellent documentation.

Yet, many computational tools are available including recent releases:

It also has libraries such as boost, eigen, fftw, netcdf and others.

Numerical computations are sometime used with OpenBSD as part of a larger system such as an embedded computer or, for example, a web service using machine-learning or statistical calculations.

Some people use OpenBSD for development of numerical code or for calculating.

Compiled Languages

You can find numerical codes in all languages; here we focus on C/C++ using clang and GNU tools. We also describe a bit of Fortran.

Clang is included in “base” on AMD64, meaning it comes with the operating system. GNU languages are added with packages, including C, C++, Fortran and others.

Additional languages such as Forth, Go, Haskell, Ocaml and Rust are also available for various problems. These are not covered here.

Making compiled code go faster

OpenBSD on the AMD 64-bit platform (which also supports the Intel emulations known as EMT64) is configured to support all compatible processors including older ones. Newer processors have improved instruction sets, resulting in a variety of options for possibly gaining performance.

By default, the compiler will not optimize for your particular CPU. As a result, your code might go faster if you specify some compiler switches like -Ofast or -O3, or various loop-specific code-generation options. Or not: you will have to experiment.

CPU-model specific options are also available. The easiest way is -march=native.

Static linking may improve speed

Most compiled code automatically produces dynamic-linked executables. The executable file thus includes only the names of shared libraries (located in /usr/lib or /usr/local/lib). This reduces disk space use and forces convergence of library file versions to the same version. However it may be slower by up to 10%.

Using the --static option in compiler commands, or referencing static object libraries for most code may help speed. For example

libset="-I/usr/local/include -L/usr/local/lib"
boostset="-lboost_timer -lboost_chrono -lboost_system"
c++ -o test.x --static $libset $boostset test.cpp

This results in the essential parts of the three boost libraries (and default libraries) being included within the test.x executable.

See my examples page for further information.

Arithmetic varies with optimization

AMD64 platforms can use 80-bit floating-point arithmetic internally, and 64-bit arithmetic for double-precision values that are written to memory. Some compile options (vector instructions like SSE3, AVX, fast-math) may change the conversion of 80-bit numbers or avoid them altogether. Numerical results of calcuations with these options may therefore vary from calculations without these options.

Speed testing

Be careful when testing code changes or compiler changes for effectiveness when searching for faster programs. Here are some brief suggestions:

  1. Don’t believe the first run. Use the median timing of 5 to 11 runs.
  2. Beware of data caching effects. If the input data fits in memory then second and subsequent runs will not perform IO for it. You can decide if you care about this.
  3. Be prepared to reproduce older tests – use software code management tools and record and label each change including (Makefile) compiler switches.
  4. Don’t believe results from a virtual machine. While it may indicate approximate speed, remember the VM is shared with other programs and code and the VM speed will vary from moment to moment.
  5. In my experience -O3 is often the best optimization you can do, within a few percent. If more is needed, try -march=<cpumodel> especially for later models of Intel processors. -march=nosuchmodel gives a list of possibilities. Also, try -march=native -mcpu=native on GCC compilers.
  6. Beware of optimizations breaking correctness. Always compare results as well as elapsed times.
  7. Use well-known external libraries for standard functions like: array multiplication, differential equations, root finding, minimization, etc. These will be more reliable (accurate, stable) and faster.
  8. You may want to record many facts about your system for each run. This helps fix problems or reproduce that “magic run” that is too fast to believe. Record things like: software versions, disk space, environment variables, temperatures, date and time, etc.

Mixing clang and GNU languages

You can use C and Fortran code compiled with either compiler together in the same executable. We know this because code compiled with the GCC C compiler successfully links with the OpenBSD base (built with clang). Note only GCC Fortran (g95) is available as of OpenBSD 6.8.

C++ is not compatible across clang and GCC because the run-time libraries are not interchangeable. If you want to use C++ libraries from ports you have to use clang C++.

If you need to use GNU C++ then you will have to compile any needed C++ libraries with GNU C++ as well. Examples are: boost, tbb, uuid. If COMPILER_LIBCXX is in the ports Makefile for that library, then that library uses clang C++ and would have to be built separately with GCC (or avoided).

Scripting Languages

Most numerically useful interpreted or scripting languages are available.

Python 3.9 is available. A number of python packages are available to be added as you need them. Python virtual environments work as well.

Tools

Timing

Your shell (ksh) has a built-in “time” command; so does OpenBSD. Both report user and system CPU time; /usr/bin/time -l also reports memory and IO.

Source Reformatting

See style(9) for the OpenBSD style guide.

The clang-format -style="{BasedOnStyle: Mozilla, IndentWidth: 4}" command generates OpenBSD-like source from your ragged nasty C/C++ original. Recommended. See the manpage.

For Fortran, try fprettify available for Python 3.x. This program will change files in-place by default. See fprettify --help.

Source Code management

A software SCM tool provides a reliable way of tracking minor and major code changes to your software. You (and your teammates) record change events with the SCM tool as you create or test or revise code. The SCM tracks differences at each event and can report on these. The SCM can also reproduce older versions of files or sets of files, according to event ids, dates or named markers.

Use one of: CVS (included with OpenBSD), git (or got), or Subversion.

You can find lots of help online with a web search.

Testing

Numerical codes are difficult to test because of design issues (few or no subroutines or functions), numerical stability questions, lack of reference solutions for some problems, uncertain approximations or unknown assumptions. It’s not, however, impossible. Attention to accuracy and precision informs the user in addition to the numerical results.

The purpose of computation is insight, not numbers. –Hamming.

Test tools come in many shapes; here are some options:

  1. Coverage testing: using chosen input data the tool generates a report identifying which code segments were exercised, or not, by the test data. Unexercised code needs closer review, or further testing.
  2. Function testing: routines and functions can be exercised with selected parameters and results checked. This focuses testing on individual routines.
  3. Static code examination: these tools report on lines of source code with problematic syntax such as ‘==’ and ‘=’ confusion; misspelled variables; unreachable code, and so on.

Automated testing has additional benefits: it helps protect against bugs introduced by code changes (or compiler or operating system updates); it documents the tests for subsequent review; it serves as an educational tool for new programmers learning a large code base.

Glossary

AMD64
The AMD Athlon-64 processors and subsequent products and extensions. Intel EMT64 products are compatible.
Dynamic linking
References to a software library are included in the executable file. The file is therefore smaller; the library is found in one or two standard locations when the program is run. See ld(1).
Static linking
Code from a software library is included in the executable file. Contrast dynamic linking.
Security
Often viewed as a combination of Confidentiality (preserving limited access to data, code, plans, or means); Integrity (ensuring data, code and documents remain uncorrupted); and Availability (ensuring the data and code are usable when needed.)

Links:

OpenBSD Porting FAQ

OpenBSD FAQ


OpenBSD Numerics | OpenBSD Numerics - Parallelization
OpenBSD Numerics - Clusters | OpenBSD Numerics - Examples
OpenBSD Numerics - Experiences pages