Scientific Computing

C, C++, Fortran GDB debugging

Debugging C, C++, and Fortran code with GNU Debugger “gdb” is akin to debugging Python with pdb. The popular VSCode IDE can use GDB for debugging C, C++, and Fortran code. This can be especially handy when using VSCode over SSH to a remote computer like an HPC.

Start GDB Fortran debugger: assuming executable myprog with arguments hello and 3:

gdb --args ./myprog hello 3

Run program in gdb (perhaps after setting breakpoints) with

r

A typical debugging task uses breakpoints. Breakpoints are where the debugger stops running until you type

c

Set breakpoints by functionName:lineNumber. Example: Set a breakpoint in function myfun on line 32

b myfun:32

For breakpoints in Fortran modules in this example line 32 of a module named mymod in function myfun:

b mymod::myfun:32

List all scope variables as two separate steps.

  1. local variables
  2. arguments to the function.

Variable type, size (bytes/element), and shape (elements/dim) are available for each variable “var” by

whatis var

Example: a Fortran iso_fortran_env real64 3-D array of size 220 x 23 x 83:

var = REAL(8) (220,23,83)

If “var” is a Fortran derived type, get the same information about each record (akin to “property”) of the derived type by:

whatis var%prop

Local variables are variables used only within the scope of the function–excluding arguments to the function.

info locals

List the names and values of all arguments to the current function:

info args

Example: in integer function myfun(a,b) or subroutine mysub(a,b), upon info args you’d see perhaps

a = 1.5
b = 0.2

If a or b are arrays or structs, array values are printed as well.

CMAKE_SYSTEM_NAME detect operating system

CMake OS name flags like APPLE and UNIX are terse and are frequently used. A possible downside is their have broad, overlapping meanings.

In contrast, CMAKE_SYSTEM_NAME has more fine-grained values.

However, it is often more convenient (if using care) to use terse variables that are not as specific:

if(CMAKE_VERSION VERSION_LESS 3.25 AND CMAKE_SYSTEM_NAME STREQUAL "Linux")
  set(LINUX true)
endif()

if(APPLE)
  # macOS
elseif(BSD)
  # FreeBSD, NetBSD, OpenBSD, etc.
elseif(LINUX)
  # Linux
elseif(UNIX)
  # Linux, BSD, etc. (including macOS if not trapped above)
elseif(WIN32)
  # Windows
else()
  message(FATAL_ERROR "Unsupported system: ${CMAKE_SYSTEM_NAME}")
endif()

There is not one “right” or “wrong” way.

CB radio vs. MURS vs. FRS road convoy

In North America and other areas of the world, license-free radio frequency bands used to communicate between vehicles include the 27 MHz CB band and 150 MHz MURS (or Canadian LADD). In the USA, 462 MHz GMRS requires a license to use an external antenna, and license-free FRS is limited to 2 watts with no external antenna allowed per 47 CFR 95.587 (b)1. MURS does allow an external antenna per 47 CFR 95.2741, but the maximum MURS transmit RF power is 2 watts per 47 CFR 95.2767.

In the USA, since the 1970s, CB channel 19 27.185 MHz AM has been a common ground for general communications and calling. For extended conversations, CB 19 users would switch to another channel to avoid tying up the calling channel. For FRS and MURS there generally aren’t enough users in a particular area to expect to get a random response while on the road.

For road convoy use, a radio communications priority is often to avoid annoyance from unwanted users and static while having adequate communication range. An example is charter buses, school field trips, sports groups, off-road vehicles, or other groups that travel together. In the USA the maximum power for FRS is 2 Watts with the antenna built into the radio. While FRS walkie talkies are available for about $15 each, they are not reliable car-to-car for more than about 1/4 mile due to interference and laying the walkie talkie down in the car. This is usually too short for convoy use, say if one person breaks down and the other person didn’t notice immediately, they may drive out of communication range before knowing it.

For CB radio, the maximum transmit power is 4 Watts. A mobile CB radio with FM and CTCSS (Radioddity CB-500) is about $94 currently. For CB mobile antenna, the Cobra HGA 1500, Cobra HGA 1000, K30, or Wilson Lil Wil antenna are each in the $35-$50 price range.

The limit of mobile-to-mobile communication range for CB, MURS, and FRS is primarily in the terrain and interference, not the 2 Watt vs. 4 Watt power. Pick a CB radio convoy channel that is not channel 6, 9, 11, 19, 26, or 28 to avoid interference from high-power users. For MURS, pick any free channel. For CB, MURS, and FRS use a CTCSS tone to avoid hearing other users on the same channel.

  • CB radio: choose whether to communicate with truckers or those with inexpensive AM / FM radios.
  • CB radio antenna length vs. range in open terrain and clear channel:
    • 28-36 inches length is about 3-5 miles.
    • 18-24 inches length is about 2-3 miles.
  • FRS range is about a half-mile.
  • MURS range is about 2-4 miles, but the radios are more expensive.
  • GMRS range is about 5-7 miles, but the radios require a license.

Communication range reference

Unfreeze lost SSH session

If an SSH session hasn’t been used for a while or the laptop goes to sleep, the SSH session typically disconnects. This leaves a frozen Terminal window that can’t be used. Usually the Ctrl c keyboard combo does not work.

To avoid having to close the Terminal window, unfreeze the SSH client so that the same Terminal window can be used to reconnect to the SSH session. This avoids needless rearranging when you’ve already got a desired tab/window layout for the Terminal.

In the Terminal windows, press these keys in sequence:

Enter ~ .

Python distutils removal

Python distutils was removed from Python 3.12 as proposed in PEP632. Setuptools 49.1.2 vendored distutils, but has experienced some friction in setuptools 50.x since so many packages monkeypatch distutils due to the little maintained status of distutils for several years.

With distutils deprecation in Python 3.10, migration to setuptools is a topic being worked on by major packages such as Numpy. Aside from major packages in the Scipy/Numpy stack, I don’t recall many current packages relying on distutils. However, there is code in some packages using import distutils that could break.

I applaud the decision to remove distutils from Python stdlib despite the fallout. The fallout is a symptom of the legacy baggage of Python’s packaging. Non-stdlib packages like setuptools are so much more nimble that sorely needed improvements can be made more rapidly.

Reference: bug report leading to PEP632

Compiler macro definitions

Compilers define macros that can be used to identify a compiler and platform from compiled code, such as C, C++, Fortran, et al. This can be used for platform-specific or compiler-specific code. If a significant amount of code is needed, it may be better to swap in different code files using the build system instead of lengthy #ifdef logic. There are numerous examples for C and C++ so here we focus on macros of Fortran compilers.

Gfortran compiler macros

Macro definitions are obtained in an OS-agnostic way by:

echo "" | gcc -dM -E - > macros.txt

echo "" | gfortran -dM -E - > macros.txt

that creates a file “macros.txt” containing all the compiler macros.

commonly used macros to detect operating system / compiler configuration include:

  • _WIN32 1
  • __linux__ 1
  • __unix__ 1
  • __APPLE__ 1

CAUTION: these macros are actually not available in the Gfortran compiled programs as they are in GCC. A workaround is to have the build system define these for the particular compiler, OS, etc.

Clang LLVM compiler macros

LLVM-based compilers (including AMD AOCC) macro definitions are obtained in an OS-agnostic way by:

echo "" | clang -dM -E - > macros.txt

that creates a file “macros.txt” containing all the compiler macros.

__VERSION__ and __clang_version__ contain string version information.

Intel oneAPI LLVM compiler macros

oneAPI macros set:

  • __INTEL_LLVM_COMPILER 1

to distinguish from oneAPI Classic compiler macros like __INTEL_COMPILER 1

Cray compiler macros

Detect Cray compiler wrapper with compiler macros such as

or use Cray PE environment variable CRAYPE_VERSION.

NVIDIA HPC compiler macros

Print compiler macros like:

echo "" | nvc -dM -E -
echo "" | nvc++ -dM -E -
echo "" | nvfortran -dM -E -

NVIDIA HPC macros include:

  • __NVCOMPILER
  • __NVCOMPILER_LLVM__

LLVM Flang compiler macros

LLVMFlang flang Fortran compiler macros include __flang__ 1


Other Fortran compiler macros that identify the compiler and platform can be found in CMake source code.

Fortran iostat integer codes

Fortran I/O operations like read() and write() have an optional iostat argument that can be used to capture error codes rather than stopping the program. Fortran iostat integer non-zero error codes don’t have language standard values. Functions like is_iostat_end() allow platform-independent standard identification of end-of-file conditions.

There generally aren’t tables published of compiler-specific iostat codes, besides the source code of the compiler itself. Intel oneAPI iostat integer codes are shared with other conditions in the Intel Fortran runtime library.

Git SSH Public key Authentication

Git hosting services including GitLab and GitHub can use Git over SSH for enhanced security.

Setup the file “~/.ssh/config” for Git SSH Public Key authentication like:

Host *
   IdentitiesOnly yes
   PubKeyAuthentication yes
   Port 22

Host gist.github.com
  User git
  IdentityFile ~/.ssh/github

Host github.com
  User git
  IdentityFile ~/.ssh/github

Host gitlab.com
  User git
  IdentityFile ~/.ssh/gitlab

if needed, set file permissions (non-Windows OS):

chmod 400 ~/.ssh/config

Create Git SSH key like:

ssh-keygen -t ed25519 -f ~/.ssh/github

For speed, consider Git pull over HTTPS, Git push over SSH.

If experencing errors like

ssh: connect to host github.com port 22: Connection timed out fatal: Could not read from remote repository.

Then port 22 may be blocked by the network – try using Git SSH on port 443.

Multiple accounts on same Git service

To use Git with SSH and multiple public keys e.g. for same Git server with multiple accounts, setup the file “~/.ssh/config” like:

Host github-work
    HostName github.com
    User git
    IdentityFile ~/.ssh/github-work

Host github-personal
    HostName github.com
    User git
    IdentityFile ~/.ssh/github-personal

Then clone the repository like:

git clone github-work:username/repo.git

# or

git clone github-personal:username/repo.git

To set the username and email distinct for this repo if desired, from that repo directory:

git config user.name "Your Name Here"
git config user.email your@email.invalid

PowerShell grep files

PowerShell has functionality somewhat like grep. Use regular expressions to find matching text in files and piped text using Select-String.

Grep files:

Get-ChildItem -Path . -Filter *.txt -Recurse | Select-String -Pattern 'foo'

Grep specific file:

Select-String -Path CMakeLists.txt -Pattern 'project'

Grep piped text:

cat CMakeLists.txt | Select-String -Pattern 'project'

Grep piped text with regex:

cat CMakeLists.txt | Select-String -Pattern 'project\s*\('

Make a grep() function in PowerShell by saving the following to a file “grep.ps1”. To use this function in PowerShell command line, source the file with . grep.ps1 and then use the function from the PowerShell command line like grep pattern filename. One could make this function fancier to be more grep-like.

function grep($pattern, $path) {
    Select-String -Path $path -Pattern $pattern
}

Visual Studio Code shell command install

On Windows, VS Code “code” shell command is enabled by default when installing VS Code:

winget install -e --id Microsoft.VisualStudioCode

The installer program adds to “Path” environment variable like:

%LOCALAPPDATA%\Programs\Microsoft VS Code\bin

That directory contains “code.cmd” that invokes “Code.exe” in the directory above. This technique avoids DLL Hell due to to the .dll files in the path above interfering with other programs if that folder was on Path.


For macOS, install VS Code by:

brew install --cask visual-studio-code

and then install the code shell command by pressing Shift P .


For Linux the keys are Shift Ctrl P . Start typing “shell command”. Select “Shell Command: Install ‘code’ command in PATH”. This allows starting VS Code from Terminal by typing code.