CINXE.COM

NVIDIA HPC Compilers User's Guide — NVIDIA HPC Compilers User's Guide 25.1 documentation

<!DOCTYPE html> <html class="writer-html5" lang="en" > <head> <meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>NVIDIA HPC Compilers User&#39;s Guide &mdash; NVIDIA HPC Compilers User&#39;s Guide 25.1 documentation</title> <link rel="stylesheet" href="_static/pygments.css" type="text/css" /> <link rel="stylesheet" href="_static/css/theme.css" type="text/css" /> <link rel="stylesheet" href="_static/copybutton.css" type="text/css" /> <link rel="stylesheet" href="_static/design-style.b7bb847fb20b106c3d81b95245e65545.min.css" type="text/css" /> <link rel="stylesheet" href="_static/omni-style.css" type="text/css" /> <link rel="stylesheet" href="_static/api-styles.css" type="text/css" /> <link rel="shortcut icon" href="_static/favicon.ico"/> <!--[if lt IE 9]> <script src="_static/js/html5shiv.min.js"></script> <![endif]--> <script data-url_root="./" id="documentation_options" src="_static/documentation_options.js"></script> <script src="_static/jquery.js"></script> <script src="_static/underscore.js"></script> <script src="_static/doctools.js"></script> <script src="_static/mermaid-init.js"></script> <script src="_static/clipboard.min.js"></script> <script src="_static/copybutton.js"></script> <script src="_static/design-tabs.js"></script> <script src="_static/geoip/geoip.js"></script> <script src="_static/js/theme.js"></script> <link rel="index" title="Index" href="genindex.html" /> <link rel="search" title="Search" href="search.html" /> <link rel="prev" title="Contents" href="contents.html" /> <script src="//assets.adobedtm.com/5d4962a43b79/c1061d2c5e7b/launch-191c2462b890.min.js"></script> </head> <body class="wy-body-for-nav"> <div class="wy-grid-for-nav"> <nav data-toggle="wy-nav-shift" class="wy-nav-side"> <div class="wy-side-scroll"> <div class="wy-side-nav-search" > <a href="contents.html"> <img src="_static/acc-comp-logo.png" class="logo" alt="Logo"/> </a> <div role="search"> <form id="rtd-search-form" class="wy-form" action="search.html" method="get"> <input type="text" name="q" placeholder="Search docs" /> <input type="hidden" name="check_keywords" value="yes" /> <input type="hidden" name="area" value="default" /> </form> </div> </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> <ul class="current"> <li class="toctree-l1 current"><a class="current reference internal" href="#">1. Getting Started</a><ul> <li class="toctree-l2"><a class="reference internal" href="#overview">1.1. Overview</a></li> <li class="toctree-l2"><a class="reference internal" href="#creating-an-example">1.2. Creating an Example</a></li> <li class="toctree-l2"><a class="reference internal" href="#invoking-the-command-level-nvidia-hpc-compilers">1.3. Invoking the Command-level NVIDIA HPC Compilers</a><ul> <li class="toctree-l3"><a class="reference internal" href="#command-line-syntax">1.3.1. Command-line Syntax</a></li> <li class="toctree-l3"><a class="reference internal" href="#command-line-options">1.3.2. Command-line Options</a></li> </ul> </li> <li class="toctree-l2"><a class="reference internal" href="#filename-conventions">1.4. Filename Conventions</a><ul> <li class="toctree-l3"><a class="reference internal" href="#input-files">1.4.1. Input Files</a></li> <li class="toctree-l3"><a class="reference internal" href="#output-files">1.4.2. Output Files</a></li> </ul> </li> <li class="toctree-l2"><a class="reference internal" href="#fortran-c-and-c-data-types">1.5. Fortran, C++ and C Data Types</a></li> <li class="toctree-l2"><a class="reference internal" href="#platform-specific-considerations">1.6. Platform-specific considerations</a><ul> <li class="toctree-l3"><a class="reference internal" href="#using-the-nvidia-hpc-compilers-on-linux">1.6.1. Using the NVIDIA HPC Compilers on Linux</a></li> </ul> </li> <li class="toctree-l2"><a class="reference internal" href="#site-specific-customization-of-the-compilers">1.7. Site-Specific Customization of the Compilers</a><ul> <li class="toctree-l3"><a class="reference internal" href="#use-siterc-files">1.7.1. Use siterc Files</a></li> <li class="toctree-l3"><a class="reference internal" href="#using-user-rc-files">1.7.2. Using User rc Files</a></li> </ul> </li> <li class="toctree-l2"><a class="reference internal" href="#common-development-tasks">1.8. Common Development Tasks</a></li> </ul> </li> <li class="toctree-l1"><a class="reference internal" href="#use-command-line-options">2. Use Command-line Options</a><ul> <li class="toctree-l2"><a class="reference internal" href="#command-line-option-overview">2.1. Command-line Option Overview</a><ul> <li class="toctree-l3"><a class="reference internal" href="#command-line-options-syntax">2.1.1. Command-line Options Syntax</a></li> <li class="toctree-l3"><a class="reference internal" href="#command-line-suboptions">2.1.2. Command-line Suboptions</a></li> <li class="toctree-l3"><a class="reference internal" href="#command-line-conflicting-options">2.1.3. Command-line Conflicting Options</a></li> </ul> </li> <li class="toctree-l2"><a class="reference internal" href="#help-with-command-line-options">2.2. Help with Command-line Options</a></li> <li class="toctree-l2"><a class="reference internal" href="#getting-started-with-performance">2.3. Getting Started with Performance</a><ul> <li class="toctree-l3"><a class="reference internal" href="#using-fast">2.3.1. Using -fast</a></li> <li class="toctree-l3"><a class="reference internal" href="#other-performance-related-options">2.3.2. Other Performance-Related Options</a></li> </ul> </li> <li class="toctree-l2"><a class="reference internal" href="#frequently-used-options">2.4. Frequently-used Options</a></li> <li class="toctree-l2"><a class="reference internal" href="#floating-point-subnormal">2.5. Floating-point Subnormal</a></li> </ul> </li> <li class="toctree-l1"><a class="reference internal" href="#multicore-cpu-optimization">3. Multicore CPU Optimization</a><ul> <li class="toctree-l2"><a class="reference internal" href="#overview-of-optimization">3.1. Overview of Optimization</a><ul> <li class="toctree-l3"><a class="reference internal" href="#local-optimization">3.1.1. Local Optimization</a></li> <li class="toctree-l3"><a class="reference internal" href="#global-optimization">3.1.2. Global Optimization</a></li> <li class="toctree-l3"><a class="reference internal" href="#loop-optimization-unrolling-vectorization-and-parallelization">3.1.3. Loop Optimization: Unrolling, Vectorization and Parallelization</a></li> <li class="toctree-l3"><a class="reference internal" href="#interprocedural-analysis-ipa-and-optimization">3.1.4. Interprocedural Analysis (IPA) and Optimization</a></li> <li class="toctree-l3"><a class="reference internal" href="#function-inlining">3.1.5. Function Inlining</a></li> </ul> </li> <li class="toctree-l2"><a class="reference internal" href="#getting-started-with-optimization">3.2. Getting Started with Optimization</a><ul> <li class="toctree-l3"><a class="reference internal" href="#help">3.2.1. -help</a></li> <li class="toctree-l3"><a class="reference internal" href="#minfo">3.2.2. -Minfo</a></li> <li class="toctree-l3"><a class="reference internal" href="#mneginfo">3.2.3. -Mneginfo</a></li> <li class="toctree-l3"><a class="reference internal" href="#dryrun">3.2.4. -dryrun</a></li> <li class="toctree-l3"><a class="reference internal" href="#v">3.2.5. -v</a></li> </ul> </li> <li class="toctree-l2"><a class="reference internal" href="#local-and-global-optimization">3.3. Local and Global Optimization</a><ul> <li class="toctree-l3"><a class="reference internal" href="#msafeptr">3.3.1. -Msafeptr</a></li> <li class="toctree-l3"><a class="reference internal" href="#o">3.3.2. -O</a></li> </ul> </li> <li class="toctree-l2"><a class="reference internal" href="#loop-unrolling-using-munroll">3.4. Loop Unrolling using -Munroll</a></li> <li class="toctree-l2"><a class="reference internal" href="#vectorization-using-mvect">3.5. Vectorization using -Mvect</a><ul> <li class="toctree-l3"><a class="reference internal" href="#vectorization-sub-options">3.5.1. Vectorization Sub-options</a></li> <li class="toctree-l3"><a class="reference internal" href="#vectorization-example-using-simd-instructions">3.5.2. Vectorization Example Using SIMD Instructions</a></li> </ul> </li> <li class="toctree-l2"><a class="reference internal" href="#interprocedural-analysis-and-optimization-using-mipa">3.6. Interprocedural Analysis and Optimization using -Mipa</a><ul> <li class="toctree-l3"><a class="reference internal" href="#building-a-program-without-ipa-single-step">3.6.1. Building a Program Without IPA – Single Step</a></li> <li class="toctree-l3"><a class="reference internal" href="#building-a-program-without-ipa-several-steps">3.6.2. Building a Program Without IPA – Several Steps</a></li> <li class="toctree-l3"><a class="reference internal" href="#building-a-program-without-ipa-using-make">3.6.3. Building a Program Without IPA Using Make</a></li> <li class="toctree-l3"><a class="reference internal" href="#building-a-program-with-ipa">3.6.4. Building a Program with IPA</a></li> <li class="toctree-l3"><a class="reference internal" href="#building-a-program-with-ipa-single-step">3.6.5. Building a Program with IPA – Single Step</a></li> <li class="toctree-l3"><a class="reference internal" href="#building-a-program-with-ipa-several-steps">3.6.6. Building a Program with IPA – Several Steps</a></li> <li class="toctree-l3"><a class="reference internal" href="#building-a-program-with-ipa-using-make">3.6.7. Building a Program with IPA Using Make</a></li> <li class="toctree-l3"><a class="reference internal" href="#questions-about-ipa">3.6.8. Questions about IPA</a></li> </ul> </li> </ul> </li> <li class="toctree-l1"><a class="reference internal" href="#using-function-inlining">4. Using Function Inlining</a><ul> <li class="toctree-l2"><a class="reference internal" href="#automatic-function-inlining-in-c-and-c">4.1. Automatic function inlining in C++ and C</a></li> <li class="toctree-l2"><a class="reference internal" href="#invoking-procedure-inlining">4.2. Invoking Procedure Inlining</a></li> <li class="toctree-l2"><a class="reference internal" href="#using-an-inline-library">4.3. Using an Inline Library</a></li> <li class="toctree-l2"><a class="reference internal" href="#creating-an-inline-library">4.4. Creating an Inline Library</a><ul> <li class="toctree-l3"><a class="reference internal" href="#working-with-inline-libraries">4.4.1. Working with Inline Libraries</a></li> <li class="toctree-l3"><a class="reference internal" href="#dependencies">4.4.2. Dependencies</a></li> <li class="toctree-l3"><a class="reference internal" href="#updating-inline-libraries-makefiles">4.4.3. Updating Inline Libraries – Makefiles</a></li> </ul> </li> <li class="toctree-l2"><a class="reference internal" href="#error-detection-during-inlining">4.5. Error Detection during Inlining</a></li> <li class="toctree-l2"><a class="reference internal" href="#examples">4.6. Examples</a></li> <li class="toctree-l2"><a class="reference internal" href="#restrictions-on-inlining">4.7. Restrictions on Inlining</a></li> </ul> </li> <li class="toctree-l1"><a class="reference internal" href="#using-gpus">5. Using GPUs</a><ul> <li class="toctree-l2"><a class="reference internal" href="#id1">5.1. Overview</a></li> <li class="toctree-l2"><a class="reference internal" href="#terminology">5.2. Terminology</a></li> <li class="toctree-l2"><a class="reference internal" href="#execution-model">5.3. Execution Model</a><ul> <li class="toctree-l3"><a class="reference internal" href="#host-functions">5.3.1. Host Functions</a></li> </ul> </li> <li class="toctree-l2"><a class="reference internal" href="#memory-model">5.4. Memory Model</a><ul> <li class="toctree-l3"><a class="reference internal" href="#separate-host-and-accelerator-memory-considerations">5.4.1. Separate Host and Accelerator Memory Considerations</a><ul> <li class="toctree-l4"><a class="reference internal" href="#accelerator-memory">5.4.1.1. Accelerator Memory</a></li> <li class="toctree-l4"><a class="reference internal" href="#staging-memory-buffer">5.4.1.2. Staging Memory Buffer</a></li> <li class="toctree-l4"><a class="reference internal" href="#cache-management">5.4.1.3. Cache Management</a></li> <li class="toctree-l4"><a class="reference internal" href="#environment-variables-controlling-device-memory-management">5.4.1.4. Environment Variables Controlling Device Memory Management</a></li> </ul> </li> <li class="toctree-l3"><a class="reference internal" href="#managed-and-unified-memory-modes">5.4.2. Managed and Unified Memory Modes</a><ul> <li class="toctree-l4"><a class="reference internal" href="#managed-memory-mode">5.4.2.1. Managed Memory Mode</a></li> <li class="toctree-l4"><a class="reference internal" href="#unified-memory-mode">5.4.2.2. Unified Memory Mode</a></li> </ul> </li> <li class="toctree-l3"><a class="reference internal" href="#memory-pool-allocator">5.4.3. Memory Pool Allocator</a></li> <li class="toctree-l3"><a class="reference internal" href="#interception-of-deallocations">5.4.4. Interception of Deallocations</a></li> <li class="toctree-l3"><a class="reference internal" href="#command-line-options-selecting-compiler-memory-modes">5.4.5. Command-line Options Selecting Compiler Memory Modes</a></li> </ul> </li> <li class="toctree-l2"><a class="reference internal" href="#fortran-pointers-in-device-code">5.5. Fortran pointers in device code</a></li> <li class="toctree-l2"><a class="reference internal" href="#calling-routines-in-a-compute-kernel">5.6. Calling routines in a compute kernel</a></li> <li class="toctree-l2"><a class="reference internal" href="#supported-processors-and-gpus">5.7. Supported Processors and GPUs</a></li> <li class="toctree-l2"><a class="reference internal" href="#cuda-versions">5.8. CUDA Versions</a></li> <li class="toctree-l2"><a class="reference internal" href="#compute-capability">5.9. Compute Capability</a></li> <li class="toctree-l2"><a class="reference internal" href="#ptx-jit-compilation">5.10. PTX JIT Compilation</a></li> </ul> </li> <li class="toctree-l1"><a class="reference internal" href="#using-openacc">6. Using OpenACC</a><ul> <li class="toctree-l2"><a class="reference internal" href="#openacc-programming-model">6.1. OpenACC Programming Model</a><ul> <li class="toctree-l3"><a class="reference internal" href="#levels-of-parallelism">6.1.1. Levels of Parallelism</a></li> <li class="toctree-l3"><a class="reference internal" href="#enable-openacc-directives">6.1.2. Enable OpenACC Directives</a></li> <li class="toctree-l3"><a class="reference internal" href="#openacc-support">6.1.3. OpenACC Support</a></li> <li class="toctree-l3"><a class="reference internal" href="#openacc-extensions">6.1.4. OpenACC Extensions</a></li> </ul> </li> <li class="toctree-l2"><a class="reference internal" href="#compiling-an-openacc-program">6.2. Compiling an OpenACC Program</a><ul> <li class="toctree-l3"><a class="reference internal" href="#no-acc">6.2.1. -[no]acc</a></li> <li class="toctree-l3"><a class="reference internal" href="#gpu">6.2.2. -gpu</a></li> </ul> </li> <li class="toctree-l2"><a class="reference internal" href="#openacc-for-multicore-cpus">6.3. OpenACC for Multicore CPUs</a></li> <li class="toctree-l2"><a class="reference internal" href="#openacc-with-cuda-unified-memory">6.4. OpenACC with CUDA Unified Memory</a></li> <li class="toctree-l2"><a class="reference internal" href="#openacc-error-handling">6.5. OpenACC Error Handling</a></li> <li class="toctree-l2"><a class="reference internal" href="#openacc-and-cuda-graphs">6.6. OpenACC and CUDA Graphs</a></li> <li class="toctree-l2"><a class="reference internal" href="#host-and-device-trip-count-options">6.7. Host and Device Trip Count Options</a><ul> <li class="toctree-l3"><a class="reference internal" href="#when-to-use-gpu-tripcount-device-or-gpu-tripcount-host">6.7.1. When to Use <code class="docutils literal notranslate"><span class="pre">-gpu=tripcount:device</span></code> or <code class="docutils literal notranslate"><span class="pre">-gpu=tripcount:host</span></code></a></li> </ul> </li> <li class="toctree-l2"><a class="reference internal" href="#environment-variables">6.8. Environment Variables</a></li> <li class="toctree-l2"><a class="reference internal" href="#profiling-accelerator-kernels">6.9. Profiling Accelerator Kernels</a></li> <li class="toctree-l2"><a class="reference internal" href="#openacc-runtime-libraries">6.10. OpenACC Runtime Libraries</a><ul> <li class="toctree-l3"><a class="reference internal" href="#runtime-library-definitions">6.10.1. Runtime Library Definitions</a></li> <li class="toctree-l3"><a class="reference internal" href="#runtime-library-routines">6.10.2. Runtime Library Routines</a></li> </ul> </li> <li class="toctree-l2"><a class="reference internal" href="#supported-intrinsics">6.11. Supported Intrinsics</a><ul> <li class="toctree-l3"><a class="reference internal" href="#supported-fortran-intrinsics-summary-table">6.11.1. Supported Fortran Intrinsics Summary Table</a></li> <li class="toctree-l3"><a class="reference internal" href="#supported-c-intrinsics-summary-table">6.11.2. Supported C Intrinsics Summary Table</a></li> </ul> </li> </ul> </li> <li class="toctree-l1"><a class="reference internal" href="#using-openmp">7. Using OpenMP</a><ul> <li class="toctree-l2"><a class="reference internal" href="#id2">7.1. Environment Variables</a></li> <li class="toctree-l2"><a class="reference internal" href="#fallback-mode">7.2. Fallback Mode</a></li> <li class="toctree-l2"><a class="reference internal" href="#loop">7.3. Loop</a></li> <li class="toctree-l2"><a class="reference internal" href="#openmp-subset">7.4. OpenMP Subset</a></li> <li class="toctree-l2"><a class="reference internal" href="#using-metadirective">7.5. Using metadirective</a></li> <li class="toctree-l2"><a class="reference internal" href="#mapping-target-constructs-to-cuda-streams">7.6. Mapping target constructs to CUDA streams</a></li> <li class="toctree-l2"><a class="reference internal" href="#noncontiguous-array-sections">7.7. Noncontiguous Array Sections</a></li> <li class="toctree-l2"><a class="reference internal" href="#openmp-with-cuda-unified-memory">7.8. OpenMP with CUDA Unified Memory</a></li> <li class="toctree-l2"><a class="reference internal" href="#multiple-device-support">7.9. Multiple Device Support</a></li> <li class="toctree-l2"><a class="reference internal" href="#interoperability-with-cuda">7.10. Interoperability with CUDA</a></li> <li class="toctree-l2"><a class="reference internal" href="#interoperability-with-other-openmp-compilers">7.11. Interoperability with Other OpenMP Compilers</a></li> <li class="toctree-l2"><a class="reference internal" href="#gnu-stl">7.12. GNU STL</a></li> </ul> </li> <li class="toctree-l1"><a class="reference internal" href="#using-stdpar">8. Using Stdpar</a><ul> <li class="toctree-l2"><a class="reference internal" href="#gpu-memory-modes">8.1. GPU Memory Modes</a></li> <li class="toctree-l2"><a class="reference internal" href="#stdpar-c">8.2. Stdpar C++</a><ul> <li class="toctree-l3"><a class="reference internal" href="#introduction-to-stdpar-c">8.2.1. Introduction to Stdpar C++</a></li> <li class="toctree-l3"><a class="reference internal" href="#nvc-compiler-parallel-algorithms-support">8.2.2. NVC++ Compiler Parallel Algorithms Support</a><ul> <li class="toctree-l4"><a class="reference internal" href="#enabling-parallel-algorithms-with-the-stdpar-option">8.2.2.1. Enabling Parallel Algorithms with the -stdpar Option</a></li> </ul> </li> <li class="toctree-l3"><a class="reference internal" href="#stdpar-c-simple-example">8.2.3. Stdpar C++ Simple Example</a></li> <li class="toctree-l3"><a class="reference internal" href="#openacc-implementation-of-parallel-algorithms">8.2.4. OpenACC Implementation of Parallel Algorithms</a></li> <li class="toctree-l3"><a class="reference internal" href="#coding-guidelines-for-gpu-accelerating-parallel-algorithms">8.2.5. Coding Guidelines for GPU-accelerating Parallel Algorithms</a><ul> <li class="toctree-l4"><a class="reference internal" href="#parallel-algorithms-and-device-function-annotations">8.2.5.1. Parallel Algorithms and Device Function Annotations</a></li> <li class="toctree-l4"><a class="reference internal" href="#data-management-in-parallel-algorithms">8.2.5.2. Data Management in Parallel Algorithms</a></li> <li class="toctree-l4"><a class="reference internal" href="#parallel-algorithms-and-function-pointers">8.2.5.3. Parallel Algorithms and Function Pointers</a></li> <li class="toctree-l4"><a class="reference internal" href="#random-access-iterators">8.2.5.4. Random Access Iterators</a></li> <li class="toctree-l4"><a class="reference internal" href="#interoperability-with-the-c-standard-library">8.2.5.5. Interoperability with the C++ Standard Library</a></li> <li class="toctree-l4"><a class="reference internal" href="#no-exceptions-in-gpu-code">8.2.5.6. No Exceptions in GPU Code</a></li> </ul> </li> <li class="toctree-l3"><a class="reference internal" href="#nvc-experimental-features">8.2.6. NVC++ Experimental Features</a><ul> <li class="toctree-l4"><a class="reference internal" href="#multi-dimensional-spans">8.2.6.1. Multi-dimensional Spans</a></li> <li class="toctree-l4"><a class="reference internal" href="#senders-and-receivers">8.2.6.2. Senders and Receivers</a></li> <li class="toctree-l4"><a class="reference internal" href="#linear-algebra">8.2.6.3. Linear Algebra</a></li> </ul> </li> <li class="toctree-l3"><a class="reference internal" href="#stdpar-c-larger-example-lulesh">8.2.7. Stdpar C++ Larger Example: LULESH</a></li> <li class="toctree-l3"><a class="reference internal" href="#interoperability-with-openacc">8.2.8. Interoperability with OpenACC</a><ul> <li class="toctree-l4"><a class="reference internal" href="#data-management-directives">8.2.8.1. Data Management Directives</a></li> <li class="toctree-l4"><a class="reference internal" href="#external-device-function-annotations">8.2.8.2. External Device Function Annotations</a></li> </ul> </li> <li class="toctree-l3"><a class="reference internal" href="#getting-started-with-parallel-algorithms-for-gpus">8.2.9. Getting Started with Parallel Algorithms for GPUs</a><ul> <li class="toctree-l4"><a class="reference internal" href="#supported-nvidia-gpus">8.2.9.1. Supported NVIDIA GPUs</a></li> <li class="toctree-l4"><a class="reference internal" href="#supported-cuda-versions">8.2.9.2. Supported CUDA Versions</a></li> </ul> </li> </ul> </li> <li class="toctree-l2"><a class="reference internal" href="#stdpar-fortran">8.3. Stdpar Fortran</a><ul> <li class="toctree-l3"><a class="reference internal" href="#calling-routines-in-do-concurrent-on-the-gpu">8.3.1. Calling Routines in DO CONCURRENT on the GPU</a></li> <li class="toctree-l3"><a class="reference internal" href="#gpu-data-management">8.3.2. GPU Data Management</a></li> <li class="toctree-l3"><a class="reference internal" href="#id3">8.3.3. Interoperability with OpenACC</a></li> <li class="toctree-l3"><a class="reference internal" href="#interoperability-with-cuda-fortran">8.3.4. Interoperability with CUDA Fortran</a></li> </ul> </li> </ul> </li> <li class="toctree-l1"><a class="reference internal" href="#pcast">9. PCAST</a><ul> <li class="toctree-l2"><a class="reference internal" href="#id5">9.1. Overview</a></li> <li class="toctree-l2"><a class="reference internal" href="#pcast-with-a-golden-file">9.2. PCAST with a “Golden” File</a></li> <li class="toctree-l2"><a class="reference internal" href="#pcast-with-openacc">9.3. PCAST with OpenACC</a></li> <li class="toctree-l2"><a class="reference internal" href="#limitations">9.4. Limitations</a></li> <li class="toctree-l2"><a class="reference internal" href="#id6">9.5. Environment Variables</a></li> </ul> </li> <li class="toctree-l1"><a class="reference internal" href="#using-mpi">10. Using MPI</a><ul> <li class="toctree-l2"><a class="reference internal" href="#using-open-mpi-on-linux">10.1. Using Open MPI on Linux</a></li> <li class="toctree-l2"><a class="reference internal" href="#using-mpi-compiler-wrappers">10.2. Using MPI Compiler Wrappers</a></li> <li class="toctree-l2"><a class="reference internal" href="#testing-and-benchmarking">10.3. Testing and Benchmarking</a></li> </ul> </li> <li class="toctree-l1"><a class="reference internal" href="#creating-and-using-libraries">11. Creating and Using Libraries</a><ul> <li class="toctree-l2"><a class="reference internal" href="#using-builtin-math-functions-in-c-and-c">11.1. Using builtin Math Functions in C++ and C</a></li> <li class="toctree-l2"><a class="reference internal" href="#using-system-library-routines">11.2. Using System Library Routines</a></li> <li class="toctree-l2"><a class="reference internal" href="#creating-and-using-shared-object-files-on-linux">11.3. Creating and Using Shared Object Files on Linux</a><ul> <li class="toctree-l3"><a class="reference internal" href="#procedure-to-create-a-use-a-shared-object-file">11.3.1. Procedure to create a use a shared object file</a></li> <li class="toctree-l3"><a class="reference internal" href="#ldd-command">11.3.2. ldd Command</a></li> </ul> </li> <li class="toctree-l2"><a class="reference internal" href="#using-lib3f">11.4. Using LIB3F</a></li> <li class="toctree-l2"><a class="reference internal" href="#lapack-blas-and-ffts">11.5. LAPACK, BLAS and FFTs</a></li> <li class="toctree-l2"><a class="reference internal" href="#linking-with-scalapack">11.6. Linking with ScaLAPACK</a></li> <li class="toctree-l2"><a class="reference internal" href="#the-c-standard-template-library">11.7. The C++ Standard Template Library</a></li> <li class="toctree-l2"><a class="reference internal" href="#nvidia-performance-libraries-nvpl">11.8. NVIDIA Performance Libraries (NVPL)</a></li> <li class="toctree-l2"><a class="reference internal" href="#linking-with-the-nvmalloc-library">11.9. Linking with the nvmalloc Library</a></li> </ul> </li> <li class="toctree-l1"><a class="reference internal" href="#id7">12. Environment Variables</a><ul> <li class="toctree-l2"><a class="reference internal" href="#setting-environment-variables">12.1. Setting Environment Variables</a><ul> <li class="toctree-l3"><a class="reference internal" href="#setting-environment-variables-on-linux">12.1.1. Setting Environment Variables on Linux</a></li> </ul> </li> <li class="toctree-l2"><a class="reference internal" href="#hpc-compiler-related-environment-variables">12.2. HPC Compiler Related Environment Variables</a></li> <li class="toctree-l2"><a class="reference internal" href="#hpc-compilers-environment-variables">12.3. HPC Compilers Environment Variables</a><ul> <li class="toctree-l3"><a class="reference internal" href="#fortranopt">12.3.1. FORTRANOPT</a></li> <li class="toctree-l3"><a class="reference internal" href="#fort-fmt-recl">12.3.2. FORT_FMT_RECL</a></li> <li class="toctree-l3"><a class="reference internal" href="#gmon-out-prefix">12.3.3. GMON_OUT_PREFIX</a></li> <li class="toctree-l3"><a class="reference internal" href="#ld-library-path">12.3.4. LD_LIBRARY_PATH</a></li> <li class="toctree-l3"><a class="reference internal" href="#manpath">12.3.5. MANPATH</a></li> <li class="toctree-l3"><a class="reference internal" href="#no-stop-message">12.3.6. NO_STOP_MESSAGE</a></li> <li class="toctree-l3"><a class="reference internal" href="#path">12.3.7. PATH</a></li> <li class="toctree-l3"><a class="reference internal" href="#nvcompiler-fpu-state">12.3.8. NVCOMPILER_FPU_STATE</a></li> <li class="toctree-l3"><a class="reference internal" href="#nvcompiler-term">12.3.9. NVCOMPILER_TERM</a></li> <li class="toctree-l3"><a class="reference internal" href="#nvcompiler-term-debug">12.3.10. NVCOMPILER_TERM_DEBUG</a></li> <li class="toctree-l3"><a class="reference internal" href="#pwd">12.3.11. PWD</a></li> <li class="toctree-l3"><a class="reference internal" href="#static-random-seed">12.3.12. STATIC_RANDOM_SEED</a></li> <li class="toctree-l3"><a class="reference internal" href="#tmp">12.3.13. TMP</a></li> <li class="toctree-l3"><a class="reference internal" href="#tmpdir">12.3.14. TMPDIR</a></li> </ul> </li> <li class="toctree-l2"><a class="reference internal" href="#using-environment-modules-on-linux">12.4. Using Environment Modules on Linux</a></li> <li class="toctree-l2"><a class="reference internal" href="#stack-traceback-and-jit-debugging">12.5. Stack Traceback and JIT Debugging</a></li> </ul> </li> <li class="toctree-l1"><a class="reference internal" href="#distributing-files-deployment">13. Distributing Files - Deployment</a><ul> <li class="toctree-l2"><a class="reference internal" href="#deploying-applications-on-linux">13.1. Deploying Applications on Linux</a><ul> <li class="toctree-l3"><a class="reference internal" href="#runtime-library-considerations">13.1.1. Runtime Library Considerations</a></li> <li class="toctree-l3"><a class="reference internal" href="#bit-linux-considerations">13.1.2. 64-bit Linux Considerations</a></li> <li class="toctree-l3"><a class="reference internal" href="#linux-redistributable-files">13.1.3. Linux Redistributable Files</a></li> <li class="toctree-l3"><a class="reference internal" href="#restrictions-on-linux-portability">13.1.4. Restrictions on Linux Portability</a></li> <li class="toctree-l3"><a class="reference internal" href="#licensing-for-redistributable-redist-files">13.1.5. Licensing for Redistributable (REDIST) Files</a></li> </ul> </li> </ul> </li> <li class="toctree-l1"><a class="reference internal" href="#inter-language-calling">14. Inter-language Calling</a><ul> <li class="toctree-l2"><a class="reference internal" href="#overview-of-calling-conventions">14.1. Overview of Calling Conventions</a></li> <li class="toctree-l2"><a class="reference internal" href="#inter-language-calling-considerations">14.2. Inter-language Calling Considerations</a></li> <li class="toctree-l2"><a class="reference internal" href="#functions-and-subroutines">14.3. Functions and Subroutines</a></li> <li class="toctree-l2"><a class="reference internal" href="#upper-and-lower-case-conventions-underscores">14.4. Upper and Lower Case Conventions, Underscores</a></li> <li class="toctree-l2"><a class="reference internal" href="#compatible-data-types">14.5. Compatible Data Types</a><ul> <li class="toctree-l3"><a class="reference internal" href="#fortran-named-common-blocks">14.5.1. Fortran Named Common Blocks</a></li> </ul> </li> <li class="toctree-l2"><a class="reference internal" href="#argument-passing-and-return-values">14.6. Argument Passing and Return Values</a><ul> <li class="toctree-l3"><a class="reference internal" href="#passing-by-value-val">14.6.1. Passing by Value (%VAL)</a></li> <li class="toctree-l3"><a class="reference internal" href="#character-return-values">14.6.2. Character Return Values</a></li> <li class="toctree-l3"><a class="reference internal" href="#complex-return-values">14.6.3. Complex Return Values</a></li> </ul> </li> <li class="toctree-l2"><a class="reference internal" href="#array-indices">14.7. Array Indices</a></li> <li class="toctree-l2"><a class="reference internal" href="#id8">14.8. Examples</a><ul> <li class="toctree-l3"><a class="reference internal" href="#example-fortran-calling-c">14.8.1. Example – Fortran Calling C</a></li> <li class="toctree-l3"><a class="reference internal" href="#example-c-calling-fortran">14.8.2. Example - C Calling Fortran</a></li> <li class="toctree-l3"><a class="reference internal" href="#example-c-calling-c">14.8.3. Example – C++ Calling C</a></li> <li class="toctree-l3"><a class="reference internal" href="#id9">14.8.4. Example – C Calling C ++</a></li> <li class="toctree-l3"><a class="reference internal" href="#id10">14.8.5. Example – Fortran Calling C++</a></li> <li class="toctree-l3"><a class="reference internal" href="#id11">14.8.6. Example – C++ Calling Fortran</a></li> </ul> </li> </ul> </li> <li class="toctree-l1"><a class="reference internal" href="#programming-considerations-for-64-bit-environments">15. Programming Considerations for 64-Bit Environments</a><ul> <li class="toctree-l2"><a class="reference internal" href="#data-types-in-the-64-bit-environment">15.1. Data Types in the 64-Bit Environment</a><ul> <li class="toctree-l3"><a class="reference internal" href="#c-and-c-data-types">15.1.1. C++ and C Data Types</a></li> <li class="toctree-l3"><a class="reference internal" href="#fortran-data-types">15.1.2. Fortran Data Types</a></li> </ul> </li> <li class="toctree-l2"><a class="reference internal" href="#large-static-data-in-linux">15.2. Large Static Data in Linux</a></li> <li class="toctree-l2"><a class="reference internal" href="#large-dynamically-allocated-data">15.3. Large Dynamically Allocated Data</a></li> <li class="toctree-l2"><a class="reference internal" href="#bit-array-indexing">15.4. 64-Bit Array Indexing</a></li> <li class="toctree-l2"><a class="reference internal" href="#compiler-options-for-64-bit-programming">15.5. Compiler Options for 64-bit Programming</a></li> <li class="toctree-l2"><a class="reference internal" href="#practical-limitations-of-large-array-programming">15.6. Practical Limitations of Large Array Programming</a></li> <li class="toctree-l2"><a class="reference internal" href="#medium-memory-model-and-large-array-in-c">15.7. Medium Memory Model and Large Array in C</a></li> <li class="toctree-l2"><a class="reference internal" href="#medium-memory-model-and-large-array-in-fortran">15.8. Medium Memory Model and Large Array in Fortran</a></li> <li class="toctree-l2"><a class="reference internal" href="#large-array-and-small-memory-model-in-fortran">15.9. Large Array and Small Memory Model in Fortran</a></li> </ul> </li> <li class="toctree-l1"><a class="reference internal" href="#c-and-c-inline-assembly-and-intrinsics">16. C++ and C Inline Assembly and Intrinsics</a><ul> <li class="toctree-l2"><a class="reference internal" href="#inline-assembly">16.1. Inline Assembly</a></li> <li class="toctree-l2"><a class="reference internal" href="#extended-inline-assembly">16.2. Extended Inline Assembly</a><ul> <li class="toctree-l3"><a class="reference internal" href="#output-operands">16.2.1. Output Operands</a></li> <li class="toctree-l3"><a class="reference internal" href="#input-operands">16.2.2. Input Operands</a></li> <li class="toctree-l3"><a class="reference internal" href="#clobber-list">16.2.3. Clobber List</a></li> <li class="toctree-l3"><a class="reference internal" href="#additional-constraints">16.2.4. Additional Constraints</a></li> <li class="toctree-l3"><a class="reference internal" href="#simple-constraints">16.2.5. Simple Constraints</a></li> <li class="toctree-l3"><a class="reference internal" href="#machine-constraints">16.2.6. Machine Constraints</a></li> <li class="toctree-l3"><a class="reference internal" href="#multiple-alternative-constraints">16.2.7. Multiple Alternative Constraints</a></li> <li class="toctree-l3"><a class="reference internal" href="#constraint-modifiers">16.2.8. Constraint Modifiers</a></li> </ul> </li> <li class="toctree-l2"><a class="reference internal" href="#operand-aliases">16.3. Operand Aliases</a></li> <li class="toctree-l2"><a class="reference internal" href="#assembly-string-modifiers">16.4. Assembly String Modifiers</a></li> <li class="toctree-l2"><a class="reference internal" href="#extended-asm-macros">16.5. Extended Asm Macros</a></li> <li class="toctree-l2"><a class="reference internal" href="#intrinsics">16.6. Intrinsics</a></li> </ul> </li> </ul> </div> </div> </nav> <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > <i data-toggle="wy-nav-top" class="fa fa-bars"></i> <a href="contents.html">NVIDIA HPC Compilers User's Guide</a> </nav> <div class="wy-nav-content"> <div class="rst-content"> <div role="navigation" aria-label="Page navigation"> <ul class="wy-breadcrumbs"> <li><a href="contents.html" class="icon icon-home"></a> &raquo;</li> <li>NVIDIA HPC Compilers User's Guide</li> <li class="wy-breadcrumbs-aside"> </li> <li class="wy-breadcrumbs-aside"> <span>v25.1 |</span> <a href="../../pdf/hpc251ug.pdf" class="reference external">PDF</a> <span>|</span> <a href="https://docs.nvidia.com/hpc-sdk/archive/index.html" class="reference external">Archive</a> <span>&nbsp;</span> </li> </ul> <hr/> </div> <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> <div itemprop="articleBody"> <span class="target" id="nvc"></span><p class="rubric-h1 rubric">NVIDIA HPC Compilers User’s Guide</p> <p class="rubric-h1 rubric">Preface</p> <p>This guide is part of a set of manuals that describe how to use the NVIDIA HPC Fortran, C++ and C compilers. These compilers include the <em>NVFORTRAN</em>, <em>NVC++</em> and <em>NVC</em> compilers. They work in conjunction with an assembler, linker, libraries and header files on your target system, and include a CUDA toolchain, libraries and header files for GPU computing. You can use the NVIDIA HPC compilers to develop, optimize and parallelize applications for NVIDIA GPUs and x86-64 and Arm Server multicore CPUs.</p> <p>The <em>NVIDIA HPC Compilers User’s Guide</em> provides operating instructions for the NVIDIA HPC compilers command-level development environment. The <em>NVIDIA HPC Compilers Reference Manual</em> contains details concerning the NVIDIA compilers’ interpretation of the Fortran, C++ and C language standards, implementation of language extensions, and command-level compilation. Users are expected to have previous experience with or knowledge of the Fortran, C++ and C programming languages. These guides do not teach the Fortran, C++ or C programming languages.</p> <p class="rubric-h2 rubric">Audience Description</p> <p>This manual is intended for scientists and engineers using the NVIDIA HPC compilers. To use these compilers, you should be aware of the role of high-level languages, such as Fortran, C++ and C as well as parallel programming models such as CUDA, OpenACC and OpenMP in the software development process, and you should have some level of understanding of programming. The NVIDIA HPC compilers are available on a variety of NVIDIA GPUs and x86-64 and Arm CPU-based platforms and operating systems. You need to be familiar with the basic commands available on your system.</p> <p class="rubric-h2 rubric" id="standards">Compatibility and Conformance to Standards</p> <p>Your system needs to be running a properly installed and configured version of the NVIDIA HPC compilers. For information on installing NVIDIA HPC compilers, refer to the Release Notes and Installation Guide included with your software.</p> <p>For further information, refer to the following:</p> <ul class="simple"> <li><p><em>American National Standard Programming Language FORTRAN</em>, ANSI X3. -1978 (1978).</p></li> <li><p><em>ISO/IEC 1539-1 : 1991, Information technology – Programming Languages – Fortran</em>, Geneva, 1991 (Fortran 90).</p></li> <li><p><em>ISO/IEC 1539-1 : 1997, Information technology – Programming Languages – Fortran</em>, Geneva, 1997 (Fortran 95).</p></li> <li><p><em>ISO/IEC 1539-1 : 2004, Information technology – Programming Languages – Fortran</em>, Geneva, 2004 (Fortran 2003).</p></li> <li><p><em>ISO/IEC 1539-1 : 2010, Information technology – Programming Languages – Fortran</em>, Geneva, 2010 (Fortran 2008).</p></li> <li><p><em>ISO/IEC 1539-1 : 2018, Information technology – Programming Languages – Fortran</em>, Geneva, 2018 (Fortran 2018).</p></li> <li><p><em>Fortran 95 Handbook Complete ISO/ANSI Reference</em>, Adams et al, The MIT Press, Cambridge, Mass, 1997.</p></li> <li><p><em>The Fortran 2003 Handbook</em>, Adams et al, Springer, 2009.</p></li> <li><p><em>OpenACC Application Program Interface</em>, Version 2.7, November 2018, <a class="reference external" href="http://www.openacc.org">http://www.openacc.org</a>.</p></li> <li><p><em>OpenMP Application Program Interface</em>, Version 5.0, November 2018, <a class="reference external" href="http://www.openmp.org">http://www.openmp.org</a>.</p></li> <li><p><em>Programming in VAX Fortran</em>, Version 4.0, Digital Equipment Corporation (September, 1984).</p></li> <li><p><em>IBM VS Fortran</em>, IBM Corporation, Rev. GC26-4119.</p></li> <li><p>Military Standard, Fortran, DOD Supplement to American National Standard Programming Language Fortran, ANSI x.3-1978, MIL-STD-1753 (November 9, 1978).</p></li> <li><p><em>American National Standard Programming Language C</em>, ANSI X3.159-1989.</p></li> <li><p>ISO/IEC 9899:1990, Information technology – Programming Languages – C, Geneva, 1990 (C90).</p></li> <li><p>ISO/IEC 9899:1999, Information technology – Programming Languages – C, Geneva, 1999 (C99).</p></li> <li><p>ISO/IEC 9899:2011, Information Technology – Programming Languages – C, Geneva, 2011 (C11).</p></li> <li><p>ISO/IEC 14882:2011, Information Technology – Programming Languages – C++, Geneva, 2011 (C++11).</p></li> <li><p>ISO/IEC 14882:2014, Information Technology – Programming Languages – C++, Geneva, 2014 (C++14).</p></li> <li><p>ISO/IEC 14882:2017, Information Technology – Programming Languages – C++, Geneva, 2017 (C++17).</p></li> </ul> <p class="rubric-h2 rubric" id="nv-ug-organization">Organization</p> <p>This guide contains the essential information on how to use the NVIDIA HPC compilers and is divided into these sections:</p> <p><a class="reference internal" href="#gs-nv"><span class="std std-ref">Getting Started</span></a> provides an introduction to the NVIDIA HPC compilers and describes their use and overall features.</p> <p><a class="reference internal" href="#cmdln-options-use"><span class="std std-ref">Use Command-line Options</span></a> provides an overview of the command-line options as well as task-related lists of options.</p> <p><a class="reference internal" href="#opt-parallel"><span class="std std-ref">Multicore CPU Optimization</span></a> describes multicore CPU optimizations and related compiler options.</p> <p><a class="reference internal" href="#fn-inline-use"><span class="std std-ref">Using Function Inlining</span></a> describes how to use function inlining and shows how to create an inline library.</p> <p><a class="reference internal" href="#openmp-use"><span class="std std-ref">Using OpenMP</span></a> describes how to use OpenMP for multicore CPU programming.</p> <p><a class="reference internal" href="#acc-use"><span class="std std-ref">Using OpenACC</span></a> describes how to use an NVIDIA GPU and gives an introduction to using OpenACC.</p> <p><a class="reference internal" href="#stdpar-use"><span class="std std-ref">Using Stdpar</span></a> describes how to use C++/Fortran Standard Language Parallelism for programming an NVIDIA GPU or multicore CPU.</p> <p><a class="reference internal" href="#pcast"><span class="std std-ref">PCAST</span></a> describes how to use the Parallel Compiler Assisted Testing features of the HPC Compilers.</p> <p><a class="reference internal" href="#mpi-use"><span class="std std-ref">Using MPI</span></a> describes how to use MPI with the NVIDIA HPC compilers.</p> <p><a class="reference internal" href="#lib-create-use"><span class="std std-ref">Creating and Using Libraries</span></a> discusses NVIDIA HPC compiler support libraries, shared object files, and environment variables that affect the behavior of the compilers.</p> <p><a class="reference internal" href="#env-vars-use"><span class="std std-ref">Environment Variables</span></a> describes the environment variables that affect the behavior of the NVIDIA HPC compilers.</p> <p><a class="reference internal" href="#deploy-dist-files"><span class="std std-ref">Distributing Files – Deployment</span></a> describes the deployment of your files once you have built, debugged and compiled them successfully.</p> <p><a class="reference internal" href="#intr-lang-call"><span class="std std-ref">Inter-language Calling</span></a> provides examples showing how to place C language calls in a Fortran program and Fortran language calls in a C program.</p> <p><a class="reference internal" href="#prog-64bits"><span class="std std-ref">Programming Considerations for 64-Bit Environments</span></a> discusses issues of which programmers should be aware when targeting 64-bit processors.</p> <p><a class="reference internal" href="#inline-asm-intrin-c-cpp"><span class="std std-ref">C++ and C Inline Assembly and Intrinsics</span></a> describes how to use inline assembly code in C++ and C programs, as well as how to use intrinsic functions that map directly to assembly machine instructions.</p> <p class="rubric-h2 rubric" id="hw-sw-constraints">Hardware and Software Constraints</p> <p>This guide describes versions of the NVIDIA HPC compilers that target NVIDIA GPUs and x86-64 and Arm CPUs. Details concerning environment-specific values and defaults and system-specific features or limitations are presented in the release notes delivered with the NVIDIA HPC compilers.</p> <p class="rubric-h2 rubric" id="doc-conventions">Conventions</p> <p>This guide uses the following conventions:</p> <dl class="simple"> <dt><em>italic</em></dt><dd><p>is used for emphasis.</p> </dd> <dt><code class="docutils literal notranslate"><span class="pre">Constant</span> <span class="pre">Width</span></code></dt><dd><p>is used for filenames, directories, arguments, options, examples, and for language statements in the text, including assembly language statements.</p> </dd> <dt><strong>Bold</strong></dt><dd><p>is used for commands.</p> </dd> <dt>[ item1 ]</dt><dd><p>in general, square brackets indicate optional items. In this case item1 is optional. In the context of p/t-sets, square brackets are required to specify a p/t-set.</p> </dd> <dt>{ item2 | item 3 }</dt><dd><p>braces indicate that a selection is required. In this case, you must select either item2 or item3.</p> </dd> <dt>filename …</dt><dd><p>ellipsis indicate a repetition. Zero or more of the preceding item may occur. In this example, multiple filenames are allowed.</p> </dd> <dt><code class="docutils literal notranslate"><span class="pre">FORTRAN</span></code></dt><dd><p>Fortran language statements are shown in the text of this guide using a reduced fixed point size.</p> </dd> <dt><code class="docutils literal notranslate"><span class="pre">C++</span> <span class="pre">and</span> <span class="pre">C</span></code></dt><dd><p>C++ and C language statements are shown in the test of this guide using a reduced fixed point size.</p> </dd> </dl> <p class="rubric-h2 rubric" id="doc-conventions-more">Terms</p> <p>A number of terms related to systems, processors, compilers and tools are used throughout this guide. For example:</p> <table class="table-no-stripes docutils align-default"> <colgroup> <col style="width: 24%" /> <col style="width: 30%" /> <col style="width: 24%" /> <col style="width: 22%" /> </colgroup> <tbody> <tr class="row-odd"><td><p>accelerator</p></td> <td><p>FMA</p></td> <td><p>-mcmodel=medium</p></td> <td><p>shared library</p></td> </tr> <tr class="row-even"><td><p>AVX</p></td> <td><p>host</p></td> <td><p>-mcmodel=small</p></td> <td><p>SIMD</p></td> </tr> <tr class="row-odd"><td><p>CUDA</p></td> <td><p>hyperthreading (HT)</p></td> <td><p>MPI</p></td> <td><p>SSE</p></td> </tr> <tr class="row-even"><td><p>device</p></td> <td><p>large arrays</p></td> <td><p>MPICH</p></td> <td><p>static linking</p></td> </tr> <tr class="row-odd"><td><p>driver</p></td> <td><p>linux86-64</p></td> <td><p>NUMA</p></td> <td><p>x86-64</p></td> </tr> <tr class="row-even"><td><p>DWARF</p></td> <td><p>LLVM</p></td> <td><p>OpenPOWER</p></td> <td><p>Arm</p></td> </tr> <tr class="row-odd"><td><p>dynamic library</p></td> <td><p>multicore</p></td> <td><p>ppc64le</p></td> <td><p>Aarch64</p></td> </tr> </tbody> </table> <p>The following table lists the NVIDIA HPC compilers and their corresponding commands:</p> <table class="table-no-stripes docutils align-default" id="id12"> <caption><span class="caption-text">Table 1. NVIDIA HPC Compilers and Commands</span><a class="headerlink" href="#id12" title="Permalink to this table"></a></caption> <colgroup> <col style="width: 26%" /> <col style="width: 60%" /> <col style="width: 15%" /> </colgroup> <thead> <tr class="row-odd"><th class="head"><p>Compiler or Tool</p></th> <th class="head"><p>Language or Function</p></th> <th class="head"><p>Command</p></th> </tr> </thead> <tbody> <tr class="row-even"><td><p>NVFORTRAN</p></td> <td><p>ISO/ANSI Fortran 2003</p></td> <td><p>nvfortran</p></td> </tr> <tr class="row-odd"><td><p>NVC++</p></td> <td><p>ISO/ANSI C++17 with GNU compatibility</p></td> <td><p>nvc++</p></td> </tr> <tr class="row-even"><td><p>NVC</p></td> <td><p>ISO/ANSI C11</p></td> <td><p>nvc</p></td> </tr> </tbody> </table> <p>In general, the designation <em>NVFORTRAN</em> is used to refer to the NVIDIA Fortran compiler, and <em>nvfortran</em> is used to refer to the command that invokes the compiler. A similar convention is used for each of the NVIDIA HPC compilers.</p> <p>For simplicity, examples of command-line invocation of the compilers generally reference the <code class="docutils literal notranslate"><span class="pre">nvfortran</span></code> command, and most source code examples are written in Fortran. Use of <em>NVC++</em> and <em>NVC</em> is consistent with <em>NVFORTRAN</em>, though there are command-line options and features of these compilers that do not apply to <em>NVFORTRAN</em>, and vice versa.</p> <p>There are a wide variety of x86-64 CPUs in use. Most of these CPUs are forward-compatible, but not backward-compatible, meaning that code compiled to target a given processor will not necessarily execute correctly on a previous-generation processor.</p> <p>A table listing the processor options that NVIDIA HPC compilers support is available in the Release Notes. The table also includes the features utilized by the compilers that distinguish them from a compatibility standpoint.</p> <p>In this manual, the convention is to use “x86-64” to specify the group of CPUs that are x86-compatible, 64-bit enabled, and run a 64-bit operating system. x86-64 processors can differ in terms of their support for various prefetch, SSE and AVX instructions. Where such distinctions are important with respect to a given compiler option or feature, it is explicitly noted in this manual.</p> <p class="rubric-h2 rubric">Related Publications</p> <p>The following documents contain additional information related to the NVIDIA HPC compilers.</p> <ul class="simple"> <li><p><em>System V Application Binary Interface Processor Supplement</em> by AT&amp;T UNIX System Laboratories, Inc. (Prentice Hall, Inc.).</p></li> <li><p><em>System V Application Binary Interface X86-64 Architecture Processor Supplement</em>.</p></li> <li><p><em>Fortran 95 Handbook Complete ISO/ANSI Reference</em>, Adams et al, The MIT Press, Cambridge, Mass, 1997.</p></li> <li><p><em>Programming in VAX Fortran, Version 4.0</em>, Digital Equipment Corporation (September, 1984).</p></li> <li><p><em>IBM VS Fortran</em>, IBM Corporation, Rev. GC26-4119.</p></li> <li><p><em>The C Programming Language</em> by Kernighan and Ritchie (Prentice Hall).</p></li> <li><p><em>C: A Reference Manual</em> by Samuel P. Harbison and Guy L. Steele Jr. (Prentice Hall, 1987).</p></li> <li><p><em>The Annotated C++ Reference Manual</em> by Margaret Ellis and Bjarne Stroustrup, AT&amp;T Bell Laboratories, Inc. (Addison-Wesley Publishing Co., 1990).</p></li> </ul> <section id="getting-started"> <span id="gs-nv"></span><h1><span class="section-number">1. </span>Getting Started<a class="headerlink" href="#getting-started" title="Permalink to this headline"></a></h1> <p>This section describes how to use the NVIDIA HPC compilers.</p> <section id="overview"> <h2><span class="section-number">1.1. </span>Overview<a class="headerlink" href="#overview" title="Permalink to this headline"></a></h2> <p>The command used to invoke a compiler, such as the nvfortran command, is called a <em>compiler driver</em>. The compiler driver controls the following phases of compilation: preprocessing, compiling, assembling, and linking. Once a file is compiled and an executable file is produced, you can execute, debug, or profile the program on your system.</p> <p>In general, using an NVIDIA HPC compiler involves three steps:</p> <ol class="arabic simple"> <li><p>Produce program source code in a file containing a .f extension or another appropriate extension, as described in <a class="reference internal" href="#fn-conv-input"><span class="std std-ref">Input Files</span></a>. This program may be one that you have written or one that you are modifying.</p></li> <li><p>Compile the program using the appropriate compiler command.</p></li> <li><p>Execute, debug, or profile the executable file on your system.</p></li> </ol> <p>You might also want to deploy your application, though this is not a required step.</p> <p>The NVIDIA HPC compilers allow many variations on these general program development steps. These variations include the following:</p> <ul class="simple"> <li><p>Stop the compilation after preprocessing, compiling or assembling to save and examine intermediate results.</p></li> <li><p>Provide options to the driver that control compiler optimization or that specify various features or limitations.</p></li> <li><p>Include as input intermediate files such as preprocessor output, compiler output, or assembler output.</p></li> </ul> <span class="target" id="example-hello"></span></section> <section id="creating-an-example"> <h2><span class="section-number">1.2. </span>Creating an Example<a class="headerlink" href="#creating-an-example" title="Permalink to this headline"></a></h2> <p>Let’s look at a simple example of using the NVIDIA Fortran compiler to create, compile, and execute a program that prints:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>hello </pre></div> </div> <ol class="arabic"> <li><p>Create your program. For this example, suppose you enter the following simple Fortran program in the file <code class="docutils literal notranslate"><span class="pre">hello.f</span></code>:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>print *, &quot;hello&quot; end </pre></div> </div> </li> <li><p>Compile the program. When you created your program, you called it <code class="docutils literal notranslate"><span class="pre">hello.f</span></code>. In this example, we compile it from a shell command prompt using the default <code class="docutils literal notranslate"><span class="pre">nvfortran</span></code> driver option. Use the following syntax:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ nvfortran hello.f </pre></div> </div> <p>By default, the executable output is placed in the file <code class="docutils literal notranslate"><span class="pre">a.out</span></code>. However, you can specify an output file name by using the <code class="docutils literal notranslate"><span class="pre">o</span></code> option.</p> <p>To place the executable output in the file hello, use this command:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ nvfortran -o hello hello.f </pre></div> </div> </li> <li><p>Execute the program. To execute the resulting hello program, simply type the filename at the command prompt and press the <strong>Return</strong> or <strong>Enter</strong> key on your keyboard:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ hello </pre></div> </div> <p>Below is the expected output:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>hello </pre></div> </div> </li> </ol> </section> <section id="invoking-the-command-level-nvidia-hpc-compilers"> <h2><span class="section-number">1.3. </span>Invoking the Command-level NVIDIA HPC Compilers<a class="headerlink" href="#invoking-the-command-level-nvidia-hpc-compilers" title="Permalink to this headline"></a></h2> <p>To translate and link a Fortran, C, or C++ program, the <code class="docutils literal notranslate"><span class="pre">nvfortran</span></code>, <code class="docutils literal notranslate"><span class="pre">nvc</span></code> and <code class="docutils literal notranslate"><span class="pre">nvc++</span></code> commands do the following:</p> <ol class="arabic simple"> <li><p>Preprocess the source text file.</p></li> <li><p>Check the syntax of the source text.</p></li> <li><p>Generate an assembly language file.</p></li> <li><p>Pass control to the subsequent assembly and linking steps.</p></li> </ol> <section id="command-line-syntax"> <h3><span class="section-number">1.3.1. </span>Command-line Syntax<a class="headerlink" href="#command-line-syntax" title="Permalink to this headline"></a></h3> <p>The compiler command-line syntax, using nvfortran as an example, is:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>nvfortran [options] [path]filename [...] </pre></div> </div> <p>Where:</p> <dl class="simple"> <dt>options</dt><dd><p>is one or more command-line options, all of which are described in detail in <a class="reference internal" href="#cmdln-options-use"><span class="std std-ref">Use Command-line Options</span></a>.</p> </dd> <dt>path</dt><dd><p>is the pathname to the directory containing the file named by filename. If you do not specify the path for a filename, the compiler uses the current directory. You must specify the path separately for each filename not in the current directory.</p> </dd> <dt>filename</dt><dd><p>is the name of a source file, preprocessed source file, assembly-language file, object file, or library to be processed by the compilation system. You can specify more than one [path]filename.</p> </dd> </dl> </section> <section id="command-line-options"> <h3><span class="section-number">1.3.2. </span>Command-line Options<a class="headerlink" href="#command-line-options" title="Permalink to this headline"></a></h3> <p>The command-line options control various aspects of the compilation process. For a complete alphabetical listing and a description of all the command-line options, refer to <a class="reference internal" href="#cmdln-options-use"><span class="std std-ref">Use Command-Line Options</span></a>.</p> <p>The following list provides important information about proper use of command-line options.</p> <ul> <li><p>Command-line options and their arguments are case sensitive.</p></li> <li><p>The compiler drivers recognize characters preceded by a hyphen (-) as command-line options. For example, the <code class="docutils literal notranslate"><span class="pre">-Mlist</span></code> option specifies that the compiler creates a listing file.</p> <div class="admonition note"> <p class="admonition-title">Note</p> <p>The convention for the text of this manual is to show command-line options using a dash instead of a hyphen; for example, you see <code class="docutils literal notranslate"><span class="pre">-Mlist</span></code>.</p> </div> </li> <li><p>The order of options and the filename is flexible. That is, you can place options before and after the filename argument on the command line. However, the placement of some options is significant, such as the -l option, in which the order of the filenames determines the search order.</p> <div class="admonition note"> <p class="admonition-title">Note</p> <p>If two or more options contradict each other, the last one in the command line takes precedence.</p> </div> </li> <li><p>You may write linker options into a text file prefixed with the ‘&#64;’ symbol, e.g. <code class="docutils literal notranslate"><span class="pre">&#64;file</span></code>, and pass that file to the compiler as an option. The contents of <code class="docutils literal notranslate"><span class="pre">&#64;file</span></code> are passed to the linker.</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ echo &quot;foo.o bar.o&quot; &gt; ./option_file.rsp $ nvc++ @./option_files.rsp </pre></div> </div> <p>The above will pass “foo.o bar.o” to the compiler as linker arguments.</p> </li> </ul> </section> </section> <section id="filename-conventions"> <h2><span class="section-number">1.4. </span>Filename Conventions<a class="headerlink" href="#filename-conventions" title="Permalink to this headline"></a></h2> <p>The NVIDIA HPC compilers use the filenames that you specify on the command line to find and to create input and output files. This section describes the input and output filename conventions for the phases of the compilation process.</p> <span class="target" id="fn-conv-input"></span><section id="input-files"> <h3><span class="section-number">1.4.1. </span>Input Files<a class="headerlink" href="#input-files" title="Permalink to this headline"></a></h3> <p>You can specify assembly-language files, preprocessed source files, Fortran/C/C++ source files, object files, and libraries as inputs on the command line. The compiler driver determines the type of each input file by examining the filename extensions.</p> <p>The drivers use the following conventions:</p> <dl class="simple"> <dt><code class="docutils literal notranslate"><span class="pre">filename.f</span></code></dt><dd><p>indicates a Fortran source file.</p> </dd> <dt><code class="docutils literal notranslate"><span class="pre">filename.F</span></code></dt><dd><p>indicates a Fortran source file that can contain macros and preprocessor directives (to be preprocessed).</p> </dd> <dt><code class="docutils literal notranslate"><span class="pre">filename.FOR</span></code></dt><dd><p>indicates a Fortran source file that can contain macros and preprocessor directives (to be preprocessed).</p> </dd> <dt><code class="docutils literal notranslate"><span class="pre">filename.F90</span></code></dt><dd><p>indicates a Fortran 90/95 source file that can contain macros and preprocessor directives (to be preprocessed).</p> </dd> <dt><code class="docutils literal notranslate"><span class="pre">filename.F95</span></code></dt><dd><p>indicates a Fortran 90/95 source file that can contain macros and preprocessor directives (to be preprocessed).</p> </dd> <dt><code class="docutils literal notranslate"><span class="pre">filename.f90</span></code></dt><dd><p>indicates a Fortran 90/95 source file that is in freeform format.</p> </dd> <dt><code class="docutils literal notranslate"><span class="pre">filename.f95</span></code></dt><dd><p>indicates a Fortran 90/95 source file that is in freeform format.</p> </dd> <dt><code class="docutils literal notranslate"><span class="pre">filename.cuf</span></code></dt><dd><p>indicates a Fortran 90/95 source file in free format with CUDA Fortran extensions.</p> </dd> <dt><code class="docutils literal notranslate"><span class="pre">filename.CUF</span></code></dt><dd><p>indicates a Fortran 90/95 source file in free format with CUDA Fortran extensions and that can contain macros and preprocessor directives (to be preprocessed).</p> </dd> <dt><code class="docutils literal notranslate"><span class="pre">filename.c</span></code></dt><dd><p>indicates a C source file that can contain macros and preprocessor directives (to be preprocessed).</p> </dd> <dt><code class="docutils literal notranslate"><span class="pre">filename.C</span></code></dt><dd><p>indicates a C++ source file that can contain macros and preprocessor directives (to be preprocessed).</p> </dd> <dt><code class="docutils literal notranslate"><span class="pre">filename.i</span></code></dt><dd><p>indicates a preprocessed C or C++ source file.</p> </dd> <dt><code class="docutils literal notranslate"><span class="pre">filename.cc</span></code></dt><dd><p>indicates a C++ source file that can contain macros and preprocessor directives (to be preprocessed).</p> </dd> <dt><code class="docutils literal notranslate"><span class="pre">filename.cpp</span></code></dt><dd><p>indicates a C++ source file that can contain macros and preprocessor directives (to be preprocessed).</p> </dd> <dt><code class="docutils literal notranslate"><span class="pre">filename.s</span></code></dt><dd><p>indicates an assembly-language file.</p> </dd> <dt><code class="docutils literal notranslate"><span class="pre">filename.o</span></code></dt><dd><p>(Linux) indicates an object file.</p> </dd> <dt><code class="docutils literal notranslate"><span class="pre">filename.a</span></code></dt><dd><p>(Linux) indicates a library of object files.</p> </dd> <dt><code class="docutils literal notranslate"><span class="pre">filename.so</span></code></dt><dd><p>(Linux only) indicates a library of shared object files.</p> </dd> </dl> <p>The driver passes files with <code class="docutils literal notranslate"><span class="pre">.s</span></code> extensions to the assembler and files with <code class="docutils literal notranslate"><span class="pre">.o</span></code>, <code class="docutils literal notranslate"><span class="pre">.so</span></code> and <code class="docutils literal notranslate"><span class="pre">.a</span></code> extensions to the linker. Input files with unrecognized extensions, or no extension, are also passed to the linker.</p> <p>Files with a <code class="docutils literal notranslate"><span class="pre">.F</span></code> (Capital F) or <code class="docutils literal notranslate"><span class="pre">.FOR</span></code> suffix are first preprocessed by the Fortran compilers and the output is passed to the compilation phase. The Fortran preprocessor functions like cpp for C programs, but is built in to the Fortran compilers rather than implemented through an invocation of cpp. This design ensures consistency in the preprocessing step regardless of the type or revision of operating system under which you are compiling.</p> <p>Any input files not needed for a particular phase of processing are not processed. For example, if on the command line you specify an assembly-language file (<code class="docutils literal notranslate"><span class="pre">filename.s</span></code>) and the <code class="docutils literal notranslate"><span class="pre">-S</span></code> option to stop before the assembly phase, the compiler takes no action on the assembly language file. Processing stops after compilation and the assembler does not run. In this scenario, the compilation must have been completed in a previous pass which created the <code class="docutils literal notranslate"><span class="pre">.s</span></code> file. For a complete description of the <code class="docutils literal notranslate"><span class="pre">-S</span></code> option, refer to <a class="reference internal" href="#fn-conv-output"><span class="std std-ref">Output Files</span></a>.</p> <p>In addition to specifying primary input files on the command line, code within other files can be compiled as part of include files using the INCLUDE statement in a Fortran source file or the preprocessor #include directive in Fortran source files that use a <code class="docutils literal notranslate"><span class="pre">.F</span></code> extension or C++ and C source files.</p> <p>When linking a program with a library, the linker extracts only those library components that the program needs. The compiler drivers link in several libraries by default. For more information about libraries, refer to <a class="reference internal" href="#lib-create-use"><span class="std std-ref">Create and Use Libraries</span></a>.</p> <span class="target" id="fn-conv-output"></span></section> <section id="output-files"> <h3><span class="section-number">1.4.2. </span>Output Files<a class="headerlink" href="#output-files" title="Permalink to this headline"></a></h3> <p>By default, an executable output file produced by one of the NVIDIA HPC compilers is placed in the file <code class="docutils literal notranslate"><span class="pre">a.out</span></code>. As the <a class="reference internal" href="#example-hello"><span class="std std-ref">Hello example</span></a> shows, you can use the <code class="docutils literal notranslate"><span class="pre">-o</span></code> option to specify the output file name.</p> <p>If you use option <code class="docutils literal notranslate"><span class="pre">-F</span></code> (Fortran only), <code class="docutils literal notranslate"><span class="pre">-P</span></code> (C/C++ only), <code class="docutils literal notranslate"><span class="pre">-S</span></code> or <code class="docutils literal notranslate"><span class="pre">-c</span></code>, the compiler produces a file containing the output of the last completed phase for each input file, as specified by the option supplied.</p> <p>The output file is a preprocessed source file, an assembly-language file, or an unlinked object file respectively. Similarly, the <code class="docutils literal notranslate"><span class="pre">-E</span></code> option does not produce a file, but displays the preprocessed source file on the standard output. Using any of these options, the <code class="docutils literal notranslate"><span class="pre">-o</span></code> option is valid only if you specify a single input file. If no errors occur during processing, you can use the files created by these options as input to a future invocation of any of the NVIDIA compiler drivers.</p> <p>The following table lists the stop-after options and the output files that the compilers create when you use these options. It also indicates the accepted input files.</p> <table class="table-no-stripes docutils align-default" id="id13"> <caption><span class="caption-text">Table 2. Option Descriptions</span><a class="headerlink" href="#id13" title="Permalink to this table"></a></caption> <colgroup> <col style="width: 8%" /> <col style="width: 9%" /> <col style="width: 56%" /> <col style="width: 27%" /> </colgroup> <thead> <tr class="row-odd"><th class="head"><p>Option</p></th> <th class="head"><p>Stop After</p></th> <th class="head"><p>Input</p></th> <th class="head"><p>Output</p></th> </tr> </thead> <tbody> <tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">-E</span></code></p></td> <td><p>preprocessing</p></td> <td><p>Source files</p></td> <td><p>preprocessed file to standard out</p></td> </tr> <tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">-F</span></code></p></td> <td><p>preprocessing</p></td> <td><p>Source files. This option is not valid for nvc or nvc++.</p></td> <td><p>preprocessed file (<code class="docutils literal notranslate"><span class="pre">.f</span></code>)</p></td> </tr> <tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">-P</span></code></p></td> <td><p>preprocessing</p></td> <td><p>Source files. This option is not valid for nvfortran.</p></td> <td><p>preprocessed file (<code class="docutils literal notranslate"><span class="pre">.i</span></code>)</p></td> </tr> <tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">-S</span></code></p></td> <td><p>compilation</p></td> <td><p>Source files or preprocessed files</p></td> <td><p>assembly-language file (<code class="docutils literal notranslate"><span class="pre">.s</span></code>)</p></td> </tr> <tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">-c</span></code></p></td> <td><p>assembly</p></td> <td><p>Source files, or preprocessed files, or assembly-language files</p></td> <td><p>unlinked object file (<code class="docutils literal notranslate"><span class="pre">.o</span></code> or <code class="docutils literal notranslate"><span class="pre">.obj</span></code>)</p></td> </tr> <tr class="row-odd"><td><p>none</p></td> <td><p>linking</p></td> <td><p>Source files, or preprocessed files, assembly-language files, object files, or libraries</p></td> <td><p>executable file (<code class="docutils literal notranslate"><span class="pre">a.out</span></code>)</p></td> </tr> </tbody> </table> <p>If you specify multiple input files or do not specify an object filename, the compiler uses the input filenames to derive corresponding default output filenames of the following form, where <em>filename</em> is the input filename without its extension:</p> <dl class="simple"> <dt><code class="docutils literal notranslate"><span class="pre">filename.f</span></code></dt><dd><p>indicates a preprocessed file, if you compiled a Fortran file using the <code class="docutils literal notranslate"><span class="pre">-⁠F</span></code> option.</p> </dd> <dt><code class="docutils literal notranslate"><span class="pre">filename.i</span></code></dt><dd><p>indicates a preprocessed file, if you compiled using the <code class="docutils literal notranslate"><span class="pre">-⁠P</span></code> option.</p> </dd> <dt><code class="docutils literal notranslate"><span class="pre">filename.lst</span></code></dt><dd><p>indicates a listing file from the <code class="docutils literal notranslate"><span class="pre">-⁠Mlist</span></code> option.</p> </dd> <dt><code class="docutils literal notranslate"><span class="pre">filename.o</span></code> or <code class="docutils literal notranslate"><span class="pre">filename.obj</span></code></dt><dd><p>indicates a object file from the <code class="docutils literal notranslate"><span class="pre">-⁠c</span></code> option.</p> </dd> <dt><code class="docutils literal notranslate"><span class="pre">filename.s</span></code></dt><dd><p>indicates an assembly-language file from the <code class="docutils literal notranslate"><span class="pre">-⁠S</span></code> option.</p> </dd> </dl> <div class="admonition note"> <p class="admonition-title">Note</p> <p>Unless you specify otherwise, the destination directory for any output file is the current working directory. If the file exists in the destination directory, the compiler overwrites it.</p> </div> <p>The following example demonstrates the use of output filename extensions.</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ nvfortran -c proto.f proto1.F </pre></div> </div> <p>This produces the output files <code class="docutils literal notranslate"><span class="pre">proto.o</span></code> and <code class="docutils literal notranslate"><span class="pre">proto1.o</span></code>, which are binary object files. Prior to compilation, the file <code class="docutils literal notranslate"><span class="pre">proto1.F</span></code> is preprocessed because it has a <code class="docutils literal notranslate"><span class="pre">.F</span></code> filename extension.</p> </section> </section> <section id="fortran-c-and-c-data-types"> <h2><span class="section-number">1.5. </span>Fortran, C++ and C Data Types<a class="headerlink" href="#fortran-c-and-c-data-types" title="Permalink to this headline"></a></h2> <p>The NVIDIA Fortran, C++ and C compilers recognize scalar and aggregate data types. A scalar data type holds a single value, such as the integer value 42 or the real value 112.6. An aggregate data type consists of one or more scalar data type objects, such as an array of integer values.</p> </section> <section id="platform-specific-considerations"> <h2><span class="section-number">1.6. </span>Platform-specific considerations<a class="headerlink" href="#platform-specific-considerations" title="Permalink to this headline"></a></h2> <p>The NVIDIA HPC Compilers are supported on x86-64 and 64-bit Arm multicore CPUs running Linux.</p> <section id="using-the-nvidia-hpc-compilers-on-linux"> <h3><span class="section-number">1.6.1. </span>Using the NVIDIA HPC Compilers on Linux<a class="headerlink" href="#using-the-nvidia-hpc-compilers-on-linux" title="Permalink to this headline"></a></h3> <p><strong>Linux Header Files</strong></p> <p>The Linux system header files contain many GNU gcc extensions. The NVIDIA HPC C++ and C compilers support many of these extensions and can compile most programs that the GNU compilers can compile. A few header files not interoperable with the NVIDIA compilers have been rewritten.</p> <p>If you are using the NVIDIA HPC C++ or C compilers, please make sure that the supplied versions of these include files are found before the system versions. This hierarchy happens by default unless you explicitly add a -I option that references one of the system <code class="docutils literal notranslate"><span class="pre">include</span></code> directories.</p> </section> </section> <section id="site-specific-customization-of-the-compilers"> <h2><span class="section-number">1.7. </span>Site-Specific Customization of the Compilers<a class="headerlink" href="#site-specific-customization-of-the-compilers" title="Permalink to this headline"></a></h2> <p>If you are using the NVIDIA HPC Compilers and want all your users to have access to specific libraries or other files, there are special files that allow you to customize the compilers for your site.</p> <section id="use-siterc-files"> <h3><span class="section-number">1.7.1. </span>Use siterc Files<a class="headerlink" href="#use-siterc-files" title="Permalink to this headline"></a></h3> <p>The NVIDIA HPC Compiler command-level drivers utilize a file named <code class="docutils literal notranslate"><span class="pre">siterc</span></code> to enable site-specific customization of the behavior of the NVIDIA compilers. The <code class="docutils literal notranslate"><span class="pre">siterc</span></code> file is located in the <code class="docutils literal notranslate"><span class="pre">bin</span></code> subdirectory of the NVIDIA HPC Compilers installation directory. Using <code class="docutils literal notranslate"><span class="pre">siterc</span></code>, you can control how the compiler drivers invoke the various components in the compilation tool chain.</p> </section> <section id="using-user-rc-files"> <h3><span class="section-number">1.7.2. </span>Using User rc Files<a class="headerlink" href="#using-user-rc-files" title="Permalink to this headline"></a></h3> <p>In addition to the siterc file, user <code class="docutils literal notranslate"><span class="pre">rc</span></code> files can reside in a given user’s home directory, as specified by the user’s HOME environment variable. You can use these files to control the respective NVIDIA HPC Compilers. All of these files are optional.</p> <p>On Linux, these files are named <code class="docutils literal notranslate"><span class="pre">.mynvfortranrc</span></code>, <code class="docutils literal notranslate"><span class="pre">.mynvcrc</span></code>, and <code class="docutils literal notranslate"><span class="pre">.mynvc++rc</span></code>.</p> <p>The following examples show how you can use these rc files to tailor a given installation for a particular purpose on <code class="docutils literal notranslate"><span class="pre">Linux_x86_64</span></code> targets. The process is similar with obvious substitutions for <code class="docutils literal notranslate"><span class="pre">aarch64</span></code> targets.</p> <table class="table-no-stripes docutils align-default" id="id14"> <caption><span class="caption-text">Table 3. Examples of Using siterc and User rc Files</span><a class="headerlink" href="#id14" title="Permalink to this table"></a></caption> <colgroup> <col style="width: 46%" /> <col style="width: 54%" /> </colgroup> <thead> <tr class="row-odd"><th class="head"><p>To do this…</p></th> <th class="head"><p>Add the line shown to the indicated file(s)</p></th> </tr> </thead> <tbody> <tr class="row-even"><td><p>Make available to all linux compilations the libraries found in /opt/newlibs/64</p></td> <td><p><code class="docutils literal notranslate"><span class="pre">set</span> <span class="pre">SITELIB=/opt/newlibs/64;</span></code> to /opt/nv/Linux_x86_64/25.1/compilers/bin/siterc</p></td> </tr> <tr class="row-odd"><td><p>Add to all linux compilations a new library path: /opt/local/fast</p></td> <td><p><code class="docutils literal notranslate"><span class="pre">append</span> <span class="pre">SITELIB=/opt/local/fast;</span></code> to /opt/nv/Linux_x86_64/25.1/compilers/bin/siterc</p></td> </tr> <tr class="row-even"><td><p>With linux compilations, change -Mmpi to link in /opt/mympi/64/libmpix.a</p></td> <td><p><code class="docutils literal notranslate"><span class="pre">set</span> <span class="pre">MPILIBDIR=/opt/mympi/64;</span> <span class="pre">set</span> <span class="pre">MPILIBNAME=mpix;</span></code> to /opt/nv/Linux_x86_64/25.1/compilers/bin/siterc</p></td> </tr> <tr class="row-odd"><td><p>Build a Fortran executable for linux that resolves shared objects in the relative directory ./REDIST</p></td> <td><p><code class="docutils literal notranslate"><span class="pre">set</span> <span class="pre">RPATH=./REDIST;</span></code> to ~/.mynvfortranrc</p></td> </tr> </tbody> </table> </section> </section> <section id="common-development-tasks"> <h2><span class="section-number">1.8. </span>Common Development Tasks<a class="headerlink" href="#common-development-tasks" title="Permalink to this headline"></a></h2> <p>Now that you have a brief introduction to the compiler, let’s look at some common development tasks that you might wish to perform.</p> <ul class="simple"> <li><p>When you compile code you can specify a number of options on the command line that define specific characteristics related to how the program is compiled and linked, typically enhancing or overriding the default behavior of the compiler. For a list of the most common command line options and information on all the command line options, refer to <a class="reference internal" href="#cmdln-options-use"><span class="std std-ref">Use Command-line Options</span></a>.</p></li> <li><p>Code optimization for multicore CPUs allows the compiler to organize your code for efficient execution. While possibly increasing compilation time and making the code more difficult to debug, these techniques typically produce code that runs significantly faster than code that does not use them. For more information on optimization refer to <a class="reference internal" href="#opt-parallel"><span class="std std-ref">Multicore CPU Optimization</span></a>.</p></li> <li><p>Function inlining, a special type of optimization, replaces a call to a function or a subroutine with the body of the function or subroutine. This process can speed up execution by eliminating parameter passing and the function or subroutine call and return overhead. In addition, function inlining allows the compiler to optimize the function with the rest of the code. However, function inlining may also result in much larger code size with no increase in execution speed. For more information on function inlining, refer to <a class="reference internal" href="#fn-inline-use"><span class="std std-ref">Using Function Inlining</span></a>.</p></li> <li><p>A library is a collection of functions or subprograms used to develop software. Libraries contain “helper” code and data, which provide services to independent programs, allowing code and data to be shared and changed in a modular fashion. The functions and programs in a library are grouped for ease of use and linking. When creating your programs, it is often useful to incorporate standard libraries or proprietary ones. For more information on this topic, refer to <a class="reference internal" href="#lib-create-use"><span class="std std-ref">Creating and Using Libraries</span></a>.</p></li> <li><p>Environment variables define a set of dynamic values that can affect the way running processes behave on a computer. It is often useful to use these variables to set and pass information that alters the default behavior of the NVIDIA HPC Compilers and the executables which they generate. For more information on these variables, refer to <a class="reference internal" href="#env-vars-use"><span class="std std-ref">Environment Variables</span></a>.</p></li> <li><p>Deployment, though possibly an infrequent task, can present some unique issues related to concerns of porting the code to other systems. Deployment, in this context, involves distribution of a specific file or set of files that are already compiled and configured. The distribution must occur in such a way that the application executes accurately on another system which may not be configured exactly the same as the system on which the code was created. For more information on what you might need to know to successfully deploy your code, refer to <a class="reference internal" href="#deploy-dist-files"><span class="std std-ref">Distributing Files – Deployment</span></a>.</p></li> <li><p>An intrinsic is a function available in a given language whose implementation is handled specially by the compiler. Intrinsics make using processor-specific enhancements easier because they provide a C++ and C language interface to assembly instructions. In doing so, the compiler manages details that the user would normally have to be concerned with, such as register names, register allocations, and memory locations of data.</p></li> </ul> </section> </section> <section id="use-command-line-options"> <span id="cmdln-options-use"></span><h1><span class="section-number">2. </span>Use Command-line Options<a class="headerlink" href="#use-command-line-options" title="Permalink to this headline"></a></h1> <p>A command line option allows you to control specific behavior when a program is compiled and linked. This section describes the syntax for properly using command-line options and provides a brief overview of a few of the more common options.</p> <section id="command-line-option-overview"> <h2><span class="section-number">2.1. </span>Command-line Option Overview<a class="headerlink" href="#command-line-option-overview" title="Permalink to this headline"></a></h2> <p>Before looking at all the command-line options, first become familiar with the syntax for these options. There are a large number of options available to you, yet most users only use a few of them. So, start simple and progress into using the more advanced options.</p> <p>By default, the NVIDIA HPC Compilers generate code that is optimized for the type of processor on which compilation is performed, the compilation host. Before adding options to your command-line, review <a class="reference internal" href="#cmdln-options-help"><span class="std std-ref">Help with Command-line Options</span></a> and <a class="reference internal" href="#freq-used-options"><span class="std std-ref">Frequently-used Options</span></a>.</p> <section id="command-line-options-syntax"> <h3><span class="section-number">2.1.1. </span>Command-line Options Syntax<a class="headerlink" href="#command-line-options-syntax" title="Permalink to this headline"></a></h3> <p>On a command-line, options need to be preceded by a hyphen (-). If the compiler does not recognize an option, you get an unknown switch error. The error can be downgraded to a warning by adding the <code class="docutils literal notranslate"><span class="pre">-noswitcherror</span></code> option.</p> <p>This document uses the following notation when describing options:</p> <dl class="simple"> <dt>[item]</dt><dd><p>Square brackets indicate that the enclosed item is optional.</p> </dd> <dt>{item | item}</dt><dd><p>Braces indicate that you must select one and only one of the enclosed items. A vertical bar (|) separates the choices.</p> </dd> </dl> <dl class="simple"> <dt>…</dt><dd><p>Horizontal ellipses indicate that zero or more instances of the preceding item are valid.</p> </dd> </dl> </section> <section id="command-line-suboptions"> <h3><span class="section-number">2.1.2. </span>Command-line Suboptions<a class="headerlink" href="#command-line-suboptions" title="Permalink to this headline"></a></h3> <p>Some options accept several suboptions. You can specify these suboptions either by using the full option statement multiple times or by using a comma-separated list for the suboptions.</p> <p>The following two command lines are equivalent:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>nvfortran -Mvect=simd -Mvect=noaltcode </pre></div> </div> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>nvfortran -Mvect=simd,noaltcode </pre></div> </div> </section> <section id="command-line-conflicting-options"> <h3><span class="section-number">2.1.3. </span>Command-line Conflicting Options<a class="headerlink" href="#command-line-conflicting-options" title="Permalink to this headline"></a></h3> <p>Some options have an opposite or negated counterpart. For example, both <code class="docutils literal notranslate"><span class="pre">-Mvect</span></code> and <code class="docutils literal notranslate"><span class="pre">-Mnovect</span></code> are available. <code class="docutils literal notranslate"><span class="pre">-Mvect</span></code> enables vectorization and <code class="docutils literal notranslate"><span class="pre">-Mnovect</span></code> disables it. If you used both of these commands on a command line, they would conflict.</p> <div class="admonition note"> <p class="admonition-title">Note</p> <p>When you use conflicting options on a command line, the last encountered option takes precedence over any previous one.</p> </div> <p>The conflicting options rule is important for a number of reasons.</p> <ul class="simple"> <li><p>Some options, such as <code class="docutils literal notranslate"><span class="pre">-fast</span></code>, include other options. Therefore, it is possible for you to be unaware that you have conflicting options.</p></li> <li><p>You can use this rule to create makefiles that apply specific flags to a set of files, as shown in the following example.</p></li> </ul> <p><strong>Example: Makefiles with Options</strong></p> <p>In this makefile fragment, CCFLAGS uses vectorization. CCNOVECTFLAGS uses the flags defined for CCFLAGS but disables vectorization.</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>CCFLAGS=c -Mvect=simd CCNOVECTFLAGS=$(CCFLAGS) -Mnovect </pre></div> </div> <span class="target" id="cmdln-options-help"></span></section> </section> <section id="help-with-command-line-options"> <h2><span class="section-number">2.2. </span>Help with Command-line Options<a class="headerlink" href="#help-with-command-line-options" title="Permalink to this headline"></a></h2> <p>If you are just getting started with the NVIDIA HPC Compilers, it is helpful to know which options are available, when to use them, and which options most users find effective.</p> <p><strong>Using -help</strong></p> <p>The <code class="docutils literal notranslate"><span class="pre">-help</span></code> option is useful because it provides information about all options supported by a given compiler.</p> <p>You can use <code class="docutils literal notranslate"><span class="pre">-help</span></code> in one of three ways:</p> <ul> <li><p>Use <code class="docutils literal notranslate"><span class="pre">-help</span></code> with no parameters to obtain a list of all the available options with a brief one-line description of each.</p></li> <li><p>Add a parameter to <code class="docutils literal notranslate"><span class="pre">-help</span></code> to restrict the output to information about a specific option. The syntax for this usage is:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>-help &lt;command line option&gt; </pre></div> </div> <p>Suppose you use the following command to restrict the output to information about the -fast option:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ nvfortran -help -fast </pre></div> </div> <p>The output you see is similar to:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>-fast Common optimizations; includes -O2 -Munroll=c:1 -Mnoframe -Mlre </pre></div> </div> <p>In the following example, we add the <code class="docutils literal notranslate"><span class="pre">-help</span></code> parameter to restrict the output to information about the help command. The usage information for <code class="docutils literal notranslate"><span class="pre">-help</span></code> shows how groups of options can be listed or examined according to function.</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ nvfortran -help -help -help[=groups|asm|debug|language|linker|opt|other|overall|phase|prepro| suffix|switch|target|variable] </pre></div> </div> </li> <li><p>Add a parameter to <code class="docutils literal notranslate"><span class="pre">-help</span></code> to restrict the output to a specific set of options or to a building process. The syntax for this usage is this:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>-help=&lt;subgroup&gt; </pre></div> </div> </li> </ul> </section> <section id="getting-started-with-performance"> <h2><span class="section-number">2.3. </span>Getting Started with Performance<a class="headerlink" href="#getting-started-with-performance" title="Permalink to this headline"></a></h2> <p>This section provides a quick overview of a few of the command-line options that are useful in improving multicore CPU performance.</p> <section id="using-fast"> <h3><span class="section-number">2.3.1. </span>Using -fast<a class="headerlink" href="#using-fast" title="Permalink to this headline"></a></h3> <p>The NVIDIA HPC Compilers implement a wide range of options that allow users a fine degree of control on each optimization phase. When it comes to optimization of code, the quickest way to start is to use the option <code class="docutils literal notranslate"><span class="pre">-fast</span></code>. These options create a generally optimal set of flags. They incorporate optimization options to enable use of vector streaming SIMD instructions for 64-bit targets. They enable vectorization with SIMD instructions, cache alignment, and flush to zero mode.</p> <div class="admonition note"> <p class="admonition-title">Note</p> <p>The contents of the <code class="docutils literal notranslate"><span class="pre">-fast</span></code> option are host-dependent. Further, you should use these options on both compile and link command lines.</p> </div> <p>The following table shows the typical <code class="docutils literal notranslate"><span class="pre">-fast</span></code> options.</p> <table class="table-no-stripes docutils align-default" id="id15"> <caption><span class="caption-text">Table 4. Typical -fast Options</span><a class="headerlink" href="#id15" title="Permalink to this table"></a></caption> <colgroup> <col style="width: 19%" /> <col style="width: 81%" /> </colgroup> <thead> <tr class="row-odd"><th class="head"><p>Use this option…</p></th> <th class="head"><p>To do this…</p></th> </tr> </thead> <tbody> <tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">-O2</span></code></p></td> <td><p>Specifies a code optimization level of 2.</p></td> </tr> <tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">-Munroll=c:1</span></code></p></td> <td><p>Unrolls loops, executing multiple instances of the original loop during each iteration.</p></td> </tr> <tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">-Mnoframe</span></code></p></td> <td><p>Do not generate code to set up a stack frame. <strong>Note:</strong> With this option, a stack trace does not work.</p></td> </tr> <tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">-Mlre</span></code></p></td> <td><p>Enable loop-carried redundancy elimination.</p></td> </tr> <tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">-Mpre</span></code></p></td> <td><p>Enable partial redundancy elimination</p></td> </tr> </tbody> </table> <p>On most modern CPUs the <code class="docutils literal notranslate"><span class="pre">-fast</span></code> also includes the options shown in this table:</p> <table class="table-no-stripes docutils align-default" id="id16"> <caption><span class="caption-text">Table 5. Additional -fast Options</span><a class="headerlink" href="#id16" title="Permalink to this table"></a></caption> <colgroup> <col style="width: 29%" /> <col style="width: 71%" /> </colgroup> <thead> <tr class="row-odd"><th class="head"><p>Use this option…</p></th> <th class="head"><p>To do this…</p></th> </tr> </thead> <tbody> <tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">-Mvect=simd</span></code></p></td> <td><p>Generates packed SIMD instructions.</p></td> </tr> <tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">-Mcache_align</span></code></p></td> <td><p>Aligns long objects on cache-line boundaries.</p></td> </tr> <tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">-Mflushz</span></code></p></td> <td><p>Sets flush-to-zero mode.</p></td> </tr> <tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">-M[no]vect</span></code></p></td> <td><p>Controls automatic vector pipelining.</p></td> </tr> </tbody> </table> <p>To see the specific behavior of <code class="docutils literal notranslate"><span class="pre">-fast</span></code> for your target, use the following command:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ nvfortran -help -fast </pre></div> </div> </section> <section id="other-performance-related-options"> <h3><span class="section-number">2.3.2. </span>Other Performance-Related Options<a class="headerlink" href="#other-performance-related-options" title="Permalink to this headline"></a></h3> <p>While <code class="docutils literal notranslate"><span class="pre">-fast</span></code> is designed to be the quickest route to best performance, it is limited to routine boundaries. Depending on the nature and writing style of the source code, the compiler often can perform further optimization by knowing the global context of usage of a given routine. For instance, determining the possible value range of actual parameters of a routine could enable a loop to be vectorized; similarly, determining static occurrence of calls helps to decide which routine is beneficial to inline.</p> <p>These types of global optimizations are under control of Interprocedural Analysis (IPA) in NVIDIA HPC Compilers. Option <code class="docutils literal notranslate"><span class="pre">-Mipa</span></code> enables Interprocedural Analysis. <code class="docutils literal notranslate"><span class="pre">-Mipa=fast</span></code> is the recommended option to get best performances for global optimization. You can also add the suboption <code class="docutils literal notranslate"><span class="pre">inline</span></code> to enable automatic global inlining across files. You might consider using <code class="docutils literal notranslate"><span class="pre">-Mipa=fast,inline</span></code>. This option for interprocedural analysis and global optimization can improve performance.</p> <p>For more information on optimization, refer to <a class="reference internal" href="#opt-parallel"><span class="std std-ref">Multicore CPU Optimization</span></a>. For specific information about these options, refer to the ‘Optimization Controls’ section of the <a class="reference external" href="../hpc-compilers-ref-guide/index.html">HPC Compilers Reference Guide</a>.</p> <span class="target" id="freq-used-options"></span></section> </section> <section id="frequently-used-options"> <h2><span class="section-number">2.4. </span>Frequently-used Options<a class="headerlink" href="#frequently-used-options" title="Permalink to this headline"></a></h2> <p>In addition to overall performance, there are a number of other options that many users find useful when getting started. The following table provides a brief summary of these options.</p> <table class="table-no-stripes docutils align-default" id="id17"> <caption><span class="caption-text">Table 6. Commonly Used Command-Line Options</span><a class="headerlink" href="#id17" title="Permalink to this table"></a></caption> <colgroup> <col style="width: 8%" /> <col style="width: 92%" /> </colgroup> <thead> <tr class="row-odd"><th class="head"><p>Use this option…</p></th> <th class="head"><p>To do this…</p></th> </tr> </thead> <tbody> <tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">-acc</span></code></p></td> <td><p>Enable parallelization using OpenACC directives. By default the compilers will parallelize and offload OpenACC regions to an NVIDIA GPU. Use <code class="docutils literal notranslate"><span class="pre">-acc=multicore</span></code> to parallelize OpenACC regions for execution on all the cores of a multicore CPU.</p></td> </tr> <tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">-fast</span></code></p></td> <td><p>This option creates a generally optimal set of flags for targets that support SIMD capability. It incorporates optimization options to enable use of vector streaming SIMD instructions, cache alignment and flushz.</p></td> </tr> <tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">-g</span></code></p></td> <td><p>Instructs the compiler to include symbolic debugging information in the object module; sets the optimization level to zero unless a <code class="docutils literal notranslate"><span class="pre">-O</span></code> option is present on the command line. Conversely, to prevent the generation of DWARF information, use the <code class="docutils literal notranslate"><span class="pre">-Mnodwarf</span></code> option.</p></td> </tr> <tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">-gopt</span></code></p></td> <td><p>Instructs the compiler to include symbolic debugging information in the object file, and to generate optimized code identical to that generated when <code class="docutils literal notranslate"><span class="pre">-g</span></code> is not specified.</p></td> </tr> <tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">-gpu</span></code></p></td> <td><p>Control the type of GPU for which code is generated, the version of CUDA to be targeted, and several other aspects of GPU code generation.</p></td> </tr> <tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">-help</span></code></p></td> <td><p>Provides information about available options.</p></td> </tr> <tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">-mcmodel=medium</span></code></p></td> <td><p>Enables medium=model code generation for 64-bit targets, which is useful when the data space of the program exceeds 4GB.</p></td> </tr> <tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">-mp</span></code></p></td> <td><p>Enable parallelization using OpenMP directives. By default the compilers will parallelize OpenMP regions for execution on all the cores of a multicore CPU. Use <code class="docutils literal notranslate"><span class="pre">-mp=gpu</span></code> to parallelize OpenMP regions for offload to an NVIDIA GPU.</p></td> </tr> <tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">-Mconcur</span></code></p></td> <td><p>Instructs the compiler to enable auto-concurrentization of loops. If specified, the compiler uses multiple CPU cores to execute loops that it determines to be parallelizable; thus, loop iterations are split to execute optimally in a multithreaded execution context.</p></td> </tr> <tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">-Minfo</span></code></p></td> <td><p>Instructs the compiler to produce information on standard error.</p></td> </tr> <tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">-Minline</span></code></p></td> <td><p>Enables function inlining.</p></td> </tr> <tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">-Mipa=fast,inline</span></code></p></td> <td><p>Enables interprocedural analysis and optimization. Also enables automatic procedure inlining.</p></td> </tr> <tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">-Mkeepasm</span></code></p></td> <td><p>Keeps the generated assembly files.</p></td> </tr> <tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">-Munroll</span></code></p></td> <td><p>Invokes the loop unroller to unroll loops, executing multiple instances of the loop during each iteration. This also sets the optimization level to 2 if the level is set to less than 2, or if no -O or -g options are supplied.</p></td> </tr> <tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">-M[no]vect</span></code></p></td> <td><p>Enables [Disables] the code vectorizer.</p></td> </tr> <tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">--[no_]exceptions</span></code></p></td> <td><p>Removes exception handling from user code. For C++, declares that the functions in this file generate no C++ exceptions, allowing more optimal code generation.</p></td> </tr> <tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">-o</span></code></p></td> <td><p>Names the output file.</p></td> </tr> <tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">-O</span> <span class="pre">&lt;level&gt;</span></code></p></td> <td><p>Specifies code optimization level where &lt;level&gt; is 0, 1, 2, 3, or 4.</p></td> </tr> <tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">-stdpar</span></code></p></td> <td><p>Enable parallelization and offloading of Standard C++ and Fortran parallel constructs to NVIDIA GPUs; default is -stdpar=gpu.</p></td> </tr> <tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">-tp</span> <span class="pre">&lt;target&gt;</span></code></p></td> <td><p>Specify a CPU target other than the compilation host CPU.</p></td> </tr> <tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">-Wl,</span> <span class="pre">&lt;option&gt;</span></code></p></td> <td><p>Compiler driver passes the specified options to the linker.</p></td> </tr> </tbody> </table> </section> <section id="floating-point-subnormal"> <h2><span class="section-number">2.5. </span>Floating-point Subnormal<a class="headerlink" href="#floating-point-subnormal" title="Permalink to this headline"></a></h2> <p>Starting with the 22.7 release of the NVIDIA HPC SDK the default setting of how floating-point denormal (IEEE 754 terminology “subnormal”) values are processed at runtime across both x86_64 and aarch64 processors has been changed to be more consistent.</p> <p>Denormal values can be both operands to, and results of, floating-point operations. The x86_64 ISA differentiate between the two categories, operands and results, and use the terminology “daz” denormals are zeros for operands, and “flushz” flush to zero for results. The Arm V8 ISA as defined can differentiate between the two categories, but currently the processors that NVIDIA HPC SDK support only have a single setting for both operands and results and is defined as “fz” in the floating-point status and control register.</p> <p>The NVIDIA HPC SDK C, C++, and Fortran compilers have command line switches <code class="docutils literal notranslate"><span class="pre">-M[no]daz</span></code> and <code class="docutils literal notranslate"><span class="pre">-M[no]flushz</span></code>, which when specified for the C/C++ main function or the Fortran main program affect how denormals are handled by the processor at runtime. The values of these two command line switches are passed to the runtime library to configure the floating-point status and control register at program startup.</p> <p>NVIDIA HPC SDK supports x86_64 processors from both Intel and AMD, and ArmV8.1 and later processors. The following table summarizes the default settings of the <code class="docutils literal notranslate"><span class="pre">-Mdaz</span></code> and <code class="docutils literal notranslate"><span class="pre">-Mflushz</span></code> command line switches pre and post the 22.7 release.</p> <table class="table-no-stripes docutils align-default" id="id18"> <caption><span class="caption-text">Table 7. Default settings of <code class="docutils literal notranslate"><span class="pre">-Mdaz</span></code> and <code class="docutils literal notranslate"><span class="pre">-Mflushz</span></code></span><a class="headerlink" href="#id18" title="Permalink to this table"></a></caption> <colgroup> <col style="width: 33%" /> <col style="width: 33%" /> <col style="width: 33%" /> </colgroup> <thead> <tr class="row-odd"><th class="head"></th> <th class="head"><p>Pre 22.7 defaults</p></th> <th class="head"><p>22.7 defaults</p></th> </tr> </thead> <tbody> <tr class="row-even"><td><p>Intel</p></td> <td><p><code class="docutils literal notranslate"><span class="pre">-Mdaz</span></code></p> <p><code class="docutils literal notranslate"><span class="pre">-Mnoflushz</span></code></p> </td> <td><p><code class="docutils literal notranslate"><span class="pre">-Mdaz</span></code></p> <p><code class="docutils literal notranslate"><span class="pre">-Mflushz</span></code></p> </td> </tr> <tr class="row-odd"><td><p>AMD</p></td> <td><p><code class="docutils literal notranslate"><span class="pre">-Mnodaz</span></code></p> <p><code class="docutils literal notranslate"><span class="pre">-Mnoflushz</span></code></p> </td> <td><p><code class="docutils literal notranslate"><span class="pre">-Mdaz</span></code></p> <p><code class="docutils literal notranslate"><span class="pre">-Mflushz</span></code></p> </td> </tr> <tr class="row-even"><td><p>Arm processors</p></td> <td><p><code class="docutils literal notranslate"><span class="pre">-Mnodaz</span></code></p></td> <td><p><code class="docutils literal notranslate"><span class="pre">-Mdaz</span></code></p></td> </tr> </tbody> </table> <p>With the NVIDIA HPC SDK 22.7 release, the default handling of denormals operands and results is to treat them as zero, as if the main function/program were compiled with <code class="docutils literal notranslate"><span class="pre">-Mdaz-Mflushz</span></code>. Consequently, these changes can potentially affect applications that are dependent on subnormal values being non-zero.</p> <p>Along with the change to the default treatment of denormal values, users now have the ability to configure the floating-point status and control register through the <code class="docutils literal notranslate"><span class="pre">NVCOMPILER_FPU_STATE</span></code> environment variable — effectively overriding how the program was originally compiled. For further information, see the description of the <a class="reference internal" href="#env-vars-nv-fpu-state"><span class="std std-ref">NVCOMPILER_FPU_STATE</span></a> environment variable.</p> <span class="target" id="opt-parallel"></span></section> </section> <section id="multicore-cpu-optimization"> <h1><span class="section-number">3. </span>Multicore CPU Optimization<a class="headerlink" href="#multicore-cpu-optimization" title="Permalink to this headline"></a></h1> <p>Source code that is readable, maintainable, and produces correct results is not always organized for efficient execution. Normally, the first step in the program development process involves producing code that executes and produces the correct results. This first step usually involves compiling without much worry about optimization. After code is compiled and debugged, code optimization and parallelization become an issue.</p> <p>Invoking one of the NVIDIA HPC Compiler commands with certain options instructs the compiler to generate optimized code. Optimization is not always performed since it increases compilation time and may make debugging difficult. However, optimization produces more efficient code that usually runs significantly faster than code that is not optimized.</p> <p>The compilers optimize code according to the specified optimization level. You can use a number of options to specify the optimization levels, including <code class="docutils literal notranslate"><span class="pre">-⁠O</span></code>, <code class="docutils literal notranslate"><span class="pre">-⁠Mvect</span></code>, <code class="docutils literal notranslate"><span class="pre">-⁠Mipa</span></code> and <code class="docutils literal notranslate"><span class="pre">-⁠Mconcur</span></code>. In addition, you can use several of the <code class="docutils literal notranslate"><span class="pre">-⁠M&lt;nvflag&gt;</span></code> switches to control specific types of optimization.</p> <p>This chapter describes the overall effect of the optimization options supported by the NVIDIA HPC Compilers, and basic usage of several options.</p> <section id="overview-of-optimization"> <h2><span class="section-number">3.1. </span>Overview of Optimization<a class="headerlink" href="#overview-of-optimization" title="Permalink to this headline"></a></h2> <p>In general, optimization involves using transformations and replacements that generate more efficient code. This is done by the compiler and involves replacements that are independent of the particular target processor’s architecture as well as replacements that take advantage of the architecture, instruction set and registers.</p> <p>For discussion purposes, we categorize optimization:</p> <ul class="simple"> <li><p><a class="reference internal" href="#opt-local"><span class="std std-ref">Local Optimization</span></a></p></li> <li><p><a class="reference internal" href="#opt-global"><span class="std std-ref">Global Optimization</span></a></p></li> <li><p><a class="reference internal" href="#opt-loop"><span class="std std-ref">Loop Optimization</span></a></p></li> <li><p><a class="reference internal" href="#opt-ipa"><span class="std std-ref">Interprocedural Analysis (IPA) and Optimization</span></a></p></li> <li><p><a class="reference internal" href="#opt-func-inline"><span class="std std-ref">Optimization Through Function Inlining</span></a></p></li> </ul> <section id="local-optimization"> <h3><span class="section-number">3.1.1. </span>Local Optimization<a class="headerlink" href="#local-optimization" title="Permalink to this headline"></a></h3> <p>A basic block is a sequence of statements in which the flow of control enters at the beginning and leaves at the end without the possibility of branching, except at the end. Local optimization is performed on a block-by-block basis within a program’s basic blocks.</p> <p>The NVIDIA HPC Compilers perform many types of local optimization including: algebraic identity removal, constant folding, common sub-expression elimination, redundant load and store elimination, scheduling, strength reduction, and peephole optimizations.</p> <span class="target" id="opt-global"></span></section> <section id="global-optimization"> <h3><span class="section-number">3.1.2. </span>Global Optimization<a class="headerlink" href="#global-optimization" title="Permalink to this headline"></a></h3> <p>This optimization is performed on a subprogram/function over all its basic blocks. The optimizer performs control-flow and data-flow analysis for an entire program unit. All loops, including those formed by ad hoc branches such as IFs or GOTOs, are detected and optimized.</p> <p>Global optimization includes: constant propagation, copy propagation, dead store elimination, global register allocation, invariant code motion, and induction variable elimination.</p> <span class="target" id="opt-loop"></span></section> <section id="loop-optimization-unrolling-vectorization-and-parallelization"> <h3><span class="section-number">3.1.3. </span>Loop Optimization: Unrolling, Vectorization and Parallelization<a class="headerlink" href="#loop-optimization-unrolling-vectorization-and-parallelization" title="Permalink to this headline"></a></h3> <p>The performance of certain classes of loops may be improved through vectorization or unrolling options. Vectorization transforms loops to improve memory access performance and make use of packed SSEvector instructions which perform the same operation on multiple data items concurrently. Unrolling replicates the body of loops to reduce loop branching overhead and provide better opportunities for local optimization, vectorization and scheduling of instructions. Performance for loops on systems with multiple processors may also improve using the parallelization features of the NVIDIA HPC Compilers.</p> <span class="target" id="opt-ipa"></span></section> <section id="interprocedural-analysis-ipa-and-optimization"> <h3><span class="section-number">3.1.4. </span>Interprocedural Analysis (IPA) and Optimization<a class="headerlink" href="#interprocedural-analysis-ipa-and-optimization" title="Permalink to this headline"></a></h3> <p>Interprocedural analysis (IPA) allows use of information across function call boundaries to perform optimizations that would otherwise be unavailable. For example, if the actual argument to a function is in fact a constant in the caller, it may be possible to propagate that constant into the callee and perform optimizations that are not valid if the dummy argument is treated as a variable. A wide range of optimizations are enabled or improved by using IPA, including but not limited to data alignment optimizations, argument removal, constant propagation, pointer disambiguation, pure function detection, F90/F95 array shape propagation, data placement, empty function removal, automatic function inlining, inlining of functions from pre-compiled libraries, and interprocedural optimization of functions from pre-compiled libraries.</p> <span class="target" id="opt-func-inline"></span></section> <section id="function-inlining"> <h3><span class="section-number">3.1.5. </span>Function Inlining<a class="headerlink" href="#function-inlining" title="Permalink to this headline"></a></h3> <p>This optimization allows a call to a function to be replaced by a copy of the body of that function. This optimization will sometimes speed up execution by eliminating the function call and return overhead. Function inlining may also create opportunities for other types of optimization. Function inlining is not always beneficial. When used improperly it may increase code size and generate less efficient code.</p> </section> </section> <section id="getting-started-with-optimization"> <h2><span class="section-number">3.2. </span>Getting Started with Optimization<a class="headerlink" href="#getting-started-with-optimization" title="Permalink to this headline"></a></h2> <p>The first concern should be getting the program to execute and produce correct results. To get the program running, start by compiling and linking without optimization. Add -O0 to the compile line to select no optimization; or add -g to debug the program easily and isolate any coding errors exposed during porting.</p> <p>To get started quickly with optimization, a good set of options to use with any of the NVIDIA HPC compilers is -fast. For example:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ nvfortran -fast -Mipa=fast,inline prog.f </pre></div> </div> <p>For all of the NVIDIA HPC Fortran, C++ and C compilers, the <code class="docutils literal notranslate"><span class="pre">-⁠fast</span> <span class="pre">-⁠Mipa=fast,inline</span></code> options generally produce code that is well-optimized without the possibility of significant slowdowns due to pathological cases.</p> <ul class="simple"> <li><p>The``-⁠fast`` option is an aggregate option that includes a number of individual NVIDIA compiler options; which compiler options are included depends on the target for which compilation is performed.</p></li> <li><p>The <code class="docutils literal notranslate"><span class="pre">-⁠Mipa=fast,inline</span></code> option invokes interprocedural analysis (IPA), including several IPA suboptions. The inline suboption enables automatic inlining with IPA. If you do not wish to use automatic inlining, you can compile with <code class="docutils literal notranslate"><span class="pre">-⁠Mipa=fast</span></code> and use several IPA suboptions without inlining.</p></li> </ul> <p>These aggregate options incorporate a generally optimal set of flags for targets that support SIMD capability, including vectorization with SIMD instructions, cache alignment, and flushz.</p> <p>The following table shows the typical <code class="docutils literal notranslate"><span class="pre">-⁠fast</span></code> options.</p> <table class="table-no-stripes docutils align-default" id="id19"> <caption><span class="caption-text">Table 8. Typical <code class="docutils literal notranslate"><span class="pre">-fast</span></code> Options</span><a class="headerlink" href="#id19" title="Permalink to this table"></a></caption> <colgroup> <col style="width: 15%" /> <col style="width: 85%" /> </colgroup> <thead> <tr class="row-odd"><th class="head"><p>Use this option…</p></th> <th class="head"><p>To do this…</p></th> </tr> </thead> <tbody> <tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">-O2</span></code></p></td> <td><p>Specifies a code optimization level of 2 and -Mvect=SIMD.</p></td> </tr> <tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">-Munroll=c:1</span></code></p></td> <td><p>Unrolls loops, executing multiple instances of the original loop during each iteration.</p></td> </tr> <tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">-Mnoframe</span></code></p></td> <td><p>Indicates to not generate code to set up a stack frame. <strong>Note</strong> With this option, a stack trace does not work.</p></td> </tr> <tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">-Mlre</span></code></p></td> <td><p>Indicates loop-carried redundancy elimination.</p></td> </tr> <tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">-Mautoinline</span></code></p></td> <td><p>Enables automatic function inlining in C &amp; C++.</p></td> </tr> <tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">-Mpre</span></code></p></td> <td><p>Indicates partial redundancy elimination</p></td> </tr> </tbody> </table> <p>On modern multicore CPUs the <code class="docutils literal notranslate"><span class="pre">-fast</span></code> also typically includes the options shown in the following table:</p> <table class="table-no-stripes docutils align-default" id="id20"> <caption><span class="caption-text">Table 9. Additional <code class="docutils literal notranslate"><span class="pre">-fast</span></code> Options</span><a class="headerlink" href="#id20" title="Permalink to this table"></a></caption> <colgroup> <col style="width: 29%" /> <col style="width: 71%" /> </colgroup> <thead> <tr class="row-odd"><th class="head"><p>Use this option…</p></th> <th class="head"><p>To do this…</p></th> </tr> </thead> <tbody> <tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">-Mvect=simd</span></code></p></td> <td><p>Generates packed SSE and AVX instructions.</p></td> </tr> <tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">-Mcache_align</span></code></p></td> <td><p>Aligns long objects on cache-line boundaries.</p></td> </tr> <tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">-Mflushz</span></code></p></td> <td><p>Sets flush-to-zero mode.</p></td> </tr> </tbody> </table> <p>By experimenting with individual compiler options on a file-by-file basis, further significant performance gains can sometimes be realized. However, depending on the coding style, individual optimizations can sometimes cause slowdowns, and must be used carefully to ensure performance improvements.</p> <p>There are other useful command line options related to optimization and parallelization, such as <a class="reference internal" href="#opt-gs-help"><span class="std std-ref">-help</span></a>, <a class="reference internal" href="#opt-gs-minfo"><span class="std std-ref">-Minfo</span></a>, <a class="reference internal" href="#opt-gs-mneginfo"><span class="std std-ref">-Mneginfo</span></a>, <a class="reference internal" href="#opt-gs-dryrun"><span class="std std-ref">-dryrun</span></a>, and <a class="reference internal" href="#opt-gs-v"><span class="std std-ref">-v</span></a>.</p> <span class="target" id="opt-gs-help"></span><section id="help"> <h3><span class="section-number">3.2.1. </span>-help<a class="headerlink" href="#help" title="Permalink to this headline"></a></h3> <p>As described in <a class="reference internal" href="#cmdln-options-help"><span class="std std-ref">Help with Command-Line Options</span></a>, you can see a specification of any command-line option by invoking any of the NVIDIA HPC Compilers with <code class="docutils literal notranslate"><span class="pre">-help</span></code> in combination with the option in question, without specifying any input files.</p> <p>For example, you might want information on <code class="docutils literal notranslate"><span class="pre">-O</span></code>:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ nvfortran -help -O </pre></div> </div> <p>The resulting output is similar to this:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>-O Set opt level. All -O1 optimizations plus traditional scheduling and global scalar optimizations performed </pre></div> </div> <p>Or you can see the full functionality of <code class="docutils literal notranslate"><span class="pre">-help</span></code> itself, which can return information on either an individual option or groups of options:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ nvfortran -help -help </pre></div> </div> <p>The resulting output is similar to this:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>-help[=groups|asm|debug|language|linker|opt|other|overall| phase|prepro|suffix|switch|target|variable] Show compiler switches </pre></div> </div> <span class="target" id="opt-gs-minfo"></span></section> <section id="minfo"> <h3><span class="section-number">3.2.2. </span>-Minfo<a class="headerlink" href="#minfo" title="Permalink to this headline"></a></h3> <p>You can use the <code class="docutils literal notranslate"><span class="pre">-Minfo</span></code> option to display compile-time optimization listings. When this option is used, the NVIDIA HPC Compilers issue informational messages to standard error (stderr) as compilation proceeds. From these messages, you can determine which loops are optimized using unrolling, SIMD vectorization, parallelization, GPU offloading, interprocedural optimizations and various miscellaneous optimizations. You can also see where and whether functions are inlined.</p> <span class="target" id="opt-gs-mneginfo"></span></section> <section id="mneginfo"> <h3><span class="section-number">3.2.3. </span>-Mneginfo<a class="headerlink" href="#mneginfo" title="Permalink to this headline"></a></h3> <p>You can use the <code class="docutils literal notranslate"><span class="pre">-Mneginfo</span></code> option to display informational messages to standard error (stderr) that explain why certain optimizations are inhibited.</p> <span class="target" id="opt-gs-dryrun"></span></section> <section id="dryrun"> <h3><span class="section-number">3.2.4. </span>-dryrun<a class="headerlink" href="#dryrun" title="Permalink to this headline"></a></h3> <p>The <code class="docutils literal notranslate"><span class="pre">-⁠dryrun</span></code> option can be useful as a diagnostic tool if you need to see the steps used by the compiler driver to preprocess, compile, assemble and link in the presence of a given set of command line inputs. When you specify the <code class="docutils literal notranslate"><span class="pre">-⁠dryrun</span></code> option, these steps are printed to standard error (stderr) but are not actually performed. For example, you can use this option to inspect the default and user-specified libraries that are searched during the link phase, and the order in which they are searched by the linker.</p> <span class="target" id="opt-gs-v"></span></section> <section id="v"> <h3><span class="section-number">3.2.5. </span>-v<a class="headerlink" href="#v" title="Permalink to this headline"></a></h3> <p>The <code class="docutils literal notranslate"><span class="pre">-v</span></code> option is similar to <a class="reference internal" href="#opt-gs-dryrun"><span class="std std-ref">-dryrun</span></a>, except each compilation step is performed and not simply printed.</p> <span class="target" id="opt-local"></span></section> </section> <section id="local-and-global-optimization"> <h2><span class="section-number">3.3. </span>Local and Global Optimization<a class="headerlink" href="#local-and-global-optimization" title="Permalink to this headline"></a></h2> <p>This section describes local and global optimization.</p> <section id="msafeptr"> <h3><span class="section-number">3.3.1. </span>-Msafeptr<a class="headerlink" href="#msafeptr" title="Permalink to this headline"></a></h3> <p>The <code class="docutils literal notranslate"><span class="pre">-⁠Msafeptr</span></code> option can significantly improve performance of C++ and C programs in which there is known to be no pointer aliasing. For obvious reasons, this command-line option must be used carefully. There are a number of suboptions for <code class="docutils literal notranslate"><span class="pre">-⁠Msafeptr</span></code>:</p> <ul class="simple"> <li><p><code class="docutils literal notranslate"><span class="pre">-Msafeptr=all</span></code> – All pointers are safe. Equivalent to the default setting: <code class="docutils literal notranslate"><span class="pre">-⁠Msafeptr</span></code>.</p></li> <li><p><code class="docutils literal notranslate"><span class="pre">-Msafeptr=arg</span></code> – Function formal argument pointers are safe. Equivalent to <code class="docutils literal notranslate"><span class="pre">-⁠Msafeptr=dummy</span></code>.</p></li> <li><p><code class="docutils literal notranslate"><span class="pre">-Msafeptr=global</span></code> – Global pointers are safe.</p></li> <li><p><code class="docutils literal notranslate"><span class="pre">-Msafeptr=local</span></code> – Local pointers are safe. Equivalent to <code class="docutils literal notranslate"><span class="pre">-⁠Msafeptr=auto</span></code>.</p></li> <li><p><code class="docutils literal notranslate"><span class="pre">-Msafeptr=static</span></code> – Static local pointers are safe.</p></li> </ul> <p>If your C++ or C program has pointer aliasing and you also want automating inlining, then compiling with <code class="docutils literal notranslate"><span class="pre">-⁠Mipa=fast</span></code> or <code class="docutils literal notranslate"><span class="pre">-⁠Mipa=fast,inline</span></code> includes pointer aliasing optimizations. IPA may be able to optimize some of the alias references in your program and leave intact those that cannot be safely optimizied.</p> </section> <section id="o"> <h3><span class="section-number">3.3.2. </span>-O<a class="headerlink" href="#o" title="Permalink to this headline"></a></h3> <p>Using the NVIDIA HPC Compiler commands with the <code class="docutils literal notranslate"><span class="pre">-O</span></code>&lt;level&gt; option (the capital O is for Optimize), you can specify any integer level from 0 to 4.</p> <p><strong>-O0</strong></p> <p>Level zero specifies no optimization. A basic block is generated for each language statement. At this level, the compiler generates a basic block for each statement.</p> <p>Performance will almost always be slowest using this optimization level. This level is useful for the initial execution of a program. It is also useful for debugging, since there is a direct correlation between the program text and the code generated. To enable debugging, include <code class="docutils literal notranslate"><span class="pre">-g</span></code> on your compile line.</p> <p><strong>-O1</strong></p> <p>Level one specifies local optimization. Scheduling of basic blocks is performed. Register allocation is performed.</p> <p>Local optimization is a good choice when the code is very irregular, such as code that contains many short statements containing IF statements and does not contain loops (DO or DO WHILE statements ). Although this case rarely occurs, for certain types of code, this optimization level may perform better than level-two (-O2).</p> <p><strong>-O</strong></p> <p>When no level is specified, level two global optimizations are performed, including traditional scalar optimizations, induction recognition, and loop invariant motion. No SIMD vectorization is enabled.</p> <p><strong>-O2</strong></p> <p>Level two specifies global optimization. This level performs all level-one local optimization as well as level two global optimization described in <code class="docutils literal notranslate"><span class="pre">-O</span></code>. In addition, more advanced optimizations such as SIMD code generation, cache alignment, and partial redundancy elimination are enabled.</p> <p><strong>-O3</strong></p> <p>Level three specifies aggressive global optimization. This level performs all level-one and level-two optimizations and enables more aggressive hoisting and scalar replacement optimizations that may or may not be profitable.</p> <p><strong>-O4</strong></p> <p>Level four performs all level-one, level-two, and level-three optimizations and enables hoisting of guarded invariant floating point expressions.</p> <p><strong>Types of Optimizations</strong></p> <p>The NVIDIA HPC Compilers perform many different types of local optimizations, including but not limited to:</p> <ul class="simple"> <li><p>Algebraic identity removal</p></li> <li><p>Constant folding</p></li> <li><p>Common subexpression elimination</p></li> <li><p>Local register optimization</p></li> <li><p>Peephole optimizations</p></li> <li><p>Redundant load and store elimination</p></li> <li><p>Strength reductions</p></li> </ul> <p>Level-two optimization (<code class="docutils literal notranslate"><span class="pre">-⁠O2</span></code> or <code class="docutils literal notranslate"><span class="pre">-⁠O</span></code>) specifies global optimization. The <code class="docutils literal notranslate"><span class="pre">-⁠fast</span></code> option generally specifies global optimization; however, the <code class="docutils literal notranslate"><span class="pre">-⁠fast</span></code> switch varies from release to release, depending on a reasonable selection of switches for any one particular release. The <code class="docutils literal notranslate"><span class="pre">-⁠O</span></code> or <code class="docutils literal notranslate"><span class="pre">-⁠O2</span></code> level performs all level-one local optimizations as well as global optimizations. Control flow analysis is applied and global registers are allocated for all functions and subroutines. Loop regions are given special consideration. This optimization level is a good choice when the program contains loops, the loops are short, and the structure of the code is regular.</p> <p>The NVIDIA HPC Compilers perform many different types of global optimizations, including but not limited to:</p> <ul class="simple"> <li><p>Branch to branch elimination</p></li> <li><p>Constant propagation</p></li> <li><p>Copy propagation</p></li> <li><p>Dead store elimination</p></li> <li><p>Global register allocation</p></li> <li><p>Induction variable elimination</p></li> <li><p>Invariant code motion</p></li> </ul> <p>You can explicitly select the optimization level on the command line. For example, the following command line specifies level-two optimization which results in global optimization:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ nvfortran -O2 prog.f </pre></div> </div> <p>The default optimization level changes depending on which options you select on the command line. For example, when you select the <code class="docutils literal notranslate"><span class="pre">-⁠g</span></code> debugging option, the default optimization level is set to level-zero (<code class="docutils literal notranslate"><span class="pre">-⁠O0</span></code>). However, if you need to debug optimized code, you can use the <code class="docutils literal notranslate"><span class="pre">-⁠gopt</span></code> option to generate debug information without perturbing optimization. For a description of the default levels, refer to Default Optimization Levels.</p> <p>The <code class="docutils literal notranslate"><span class="pre">-⁠fast</span></code> option includes <code class="docutils literal notranslate"><span class="pre">-⁠O2</span></code> on all targets. If you want to override the default for <code class="docutils literal notranslate"><span class="pre">-⁠fast</span></code> with <code class="docutils literal notranslate"><span class="pre">-⁠O3</span></code> while maintaining all other elements of <code class="docutils literal notranslate"><span class="pre">-⁠fast</span></code>, simply compile as follows:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ nvfortran -fast -O3 prog.f </pre></div> </div> </section> </section> <section id="loop-unrolling-using-munroll"> <h2><span class="section-number">3.4. </span>Loop Unrolling using -Munroll<a class="headerlink" href="#loop-unrolling-using-munroll" title="Permalink to this headline"></a></h2> <p>This optimization unrolls loops, which reduces branch overhead, and can improve execution speed by creating better opportunities for instruction scheduling. A loop with a constant count may be completely unrolled or partially unrolled. A loop with a non-constant count may also be unrolled. A candidate loop must be an innermost loop containing one to four blocks of code.</p> <p>The following example shows the use of the <code class="docutils literal notranslate"><span class="pre">-Munroll</span></code> option:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ nvfortran -Munroll prog.f </pre></div> </div> <p>The <code class="docutils literal notranslate"><span class="pre">-Munroll</span></code> option is included as part of <code class="docutils literal notranslate"><span class="pre">-fast</span></code> on all targets. The loop unroller expands the contents of a loop and reduces the number of times a loop is executed. Branching overhead is reduced when a loop is unrolled two or more times, since each iteration of the unrolled loop corresponds to two or more iterations of the original loop; the number of branch instructions executed is proportionately reduced. When a loop is unrolled completely, the loop’s branch overhead is eliminated altogether.</p> <p>Loop unrolling may be beneficial for the instruction scheduler. When a loop is completely unrolled or unrolled two or more times, opportunities for improved scheduling may be presented. The code generator can take advantage of more possibilities for instruction grouping or filling instruction delays found within the loop.</p> <p><strong>Examples Showing Effect of Unrolling</strong></p> <p>The following side-by-side examples show the effect of code unrolling on a segment that computes a dot product.</p> <div class="admonition note"> <p class="admonition-title">Note</p> <p>This example is only meant to represent how the compiler can transform the loop; it is not meant to imply that the programmer needs to manually change code. In fact, manually unrolling your code can sometimes inhibit the compiler’s analysis and optimization.</p> </div> <table class="table-no-stripes docutils align-default" id="id21"> <caption><span class="caption-text">Table 10. Example of Effect of Code Unrolling</span><a class="headerlink" href="#id21" title="Permalink to this table"></a></caption> <colgroup> <col style="width: 50%" /> <col style="width: 50%" /> </colgroup> <thead> <tr class="row-odd"><th class="head"><p>Dot Product Code</p></th> <th class="head"><p>Unrolled Dot Product Code</p></th> </tr> </thead> <tbody> <tr class="row-even"><td><div class="highlight-fortran notranslate"><div class="highlight"><pre><span></span><span class="kt">REAL</span><span class="o">*</span><span class="mi">4</span><span class="w"> </span><span class="n">A</span><span class="p">(</span><span class="mi">100</span><span class="p">),</span><span class="w"> </span><span class="n">B</span><span class="p">(</span><span class="mi">100</span><span class="p">),</span><span class="w"> </span><span class="n">Z</span><span class="w"></span> <span class="w"> </span><span class="kt">INTEGER </span><span class="n">I</span><span class="w"></span> <span class="w"> </span><span class="k">DO </span><span class="n">I</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="mi">100</span><span class="w"></span> <span class="w"> </span><span class="n">Z</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Z</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">A</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">B</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="k">END DO</span> <span class="k">END</span><span class="w"></span> </pre></div> </div> </td> <td><div class="highlight-fortran notranslate"><div class="highlight"><pre><span></span><span class="kt">REAL</span><span class="o">*</span><span class="mi">4</span><span class="w"> </span><span class="n">A</span><span class="p">(</span><span class="mi">100</span><span class="p">),</span><span class="w"> </span><span class="n">B</span><span class="p">(</span><span class="mi">100</span><span class="p">),</span><span class="w"> </span><span class="n">Z</span><span class="w"></span> <span class="w"> </span><span class="kt">INTEGER </span><span class="n">I</span><span class="w"></span> <span class="w"> </span><span class="k">DO </span><span class="n">I</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="mi">100</span><span class="p">,</span><span class="w"> </span><span class="mi">2</span><span class="w"></span> <span class="w"> </span><span class="n">Z</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Z</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">A</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">B</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="n">Z</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Z</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">A</span><span class="p">(</span><span class="n">i</span><span class="o">+</span><span class="mi">1</span><span class="p">)</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">B</span><span class="p">(</span><span class="n">i</span><span class="o">+</span><span class="mi">1</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="k">END DO</span> <span class="k">END</span><span class="w"></span> </pre></div> </div> </td> </tr> </tbody> </table> <p>Using the -Minfo option, the compiler informs you when a loop is being unrolled. For example, a message similar to the following, indicating the line number, and the number of times the code is unrolled, displays when a loop is unrolled:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>dot: 5, Loop unrolled 5 times </pre></div> </div> <p>Using the c:&lt;m&gt; and n:&lt;m&gt; sub-options to <code class="docutils literal notranslate"><span class="pre">-⁠Munroll</span></code>, or using <code class="docutils literal notranslate"><span class="pre">-⁠Mnounroll</span></code>, you can control whether and how loops are unrolled on a file-by-file basis. For more information on <code class="docutils literal notranslate"><span class="pre">-⁠Munroll</span></code>, refer to <a class="reference internal" href="#cmdln-options-use"><span class="std std-ref">Use Command-line Options</span></a>.</p> </section> <section id="vectorization-using-mvect"> <h2><span class="section-number">3.5. </span>Vectorization using -Mvect<a class="headerlink" href="#vectorization-using-mvect" title="Permalink to this headline"></a></h2> <p>The <code class="docutils literal notranslate"><span class="pre">-⁠Mvect</span></code> option is included as part of <code class="docutils literal notranslate"><span class="pre">-⁠fast</span></code> on all multicore CPU targets. If your program contains computationally-intensive loops, the <code class="docutils literal notranslate"><span class="pre">-⁠Mvect</span></code> option may be helpful. If in addition you specify <code class="docutils literal notranslate"><span class="pre">-⁠Minfo</span></code>, and your code contains loops that can be vectorized, the compiler reports relevant information on the optimizations applied.</p> <p>When an NVIDIA HPC Compiler command is invoked with the <code class="docutils literal notranslate"><span class="pre">-⁠Mvect</span></code> option, the vectorizer scans code searching for loops that are candidates for high-⁠level transformations such as loop distribution, loop interchange, cache tiling, and idiom recognition (replacement of a recognizable code sequence, such as a reduction loop, with optimized code sequences or function calls). When the vectorizer finds vectorization opportunities, it internally rearranges or replaces sections of loops (the vectorizer changes the code generated; your source code’s loops are not altered). In addition to performing these loop transformations, the vectorizer produces extensive data dependence information for use by other phases of compilation and detects opportunities to use vector or packed SIMD instructions on processors where these are supported.</p> <p>The <code class="docutils literal notranslate"><span class="pre">-⁠Mvect</span></code> option can speed up code which contains well-behaved countable loops which operate on large floating point arrays in Fortran and their C++ and C counterparts. However, it is possible that some codes will show a decrease in performance when compiled with the <code class="docutils literal notranslate"><span class="pre">-⁠Mvect</span></code> option due to the generation of conditionally executed code segments, inability to determine data alignment, and other code generation factors. For this reason, it is recommended that you check carefully whether particular program units or loops show improved performance when compiled with this option enabled.</p> <section id="vectorization-sub-options"> <h3><span class="section-number">3.5.1. </span>Vectorization Sub-options<a class="headerlink" href="#vectorization-sub-options" title="Permalink to this headline"></a></h3> <p>The vectorizer performs high-level loop transformations on countable loops. A loop is countable if the number of iterations is set only before loop execution and cannot be modified during loop execution. Some of the vectorizer transformations can be controlled by arguments to the <code class="docutils literal notranslate"><span class="pre">-Mvect</span></code> command line option. The following sections describe the arguments that affect the operation of the vectorizer. In addition, some of these vectorizer operations can be controlled from within code using directives and pragmas.</p> <p>The vectorizer performs the following operations:</p> <ul class="simple"> <li><p>Loop interchange</p></li> <li><p>Loop splitting</p></li> <li><p>Loop fusion</p></li> <li><p>Generation of SIMD instructions on CPUs where these are supported</p></li> <li><p>Generation of prefetch instructions on processors where these are supported</p></li> <li><p>Loop iteration peeling to maximize vector alignment</p></li> <li><p>Alternate code generation</p></li> </ul> <p>The following table lists and briefly describes some of the <code class="docutils literal notranslate"><span class="pre">-Mvect</span></code> suboptions.</p> <table class="table-no-stripes docutils align-default" id="id22"> <caption><span class="caption-text">Table 11. -Mvect Suboptions</span><a class="headerlink" href="#id22" title="Permalink to this table"></a></caption> <colgroup> <col style="width: 9%" /> <col style="width: 91%" /> </colgroup> <thead> <tr class="row-odd"><th class="head"><p>Use this option …</p></th> <th class="head"><p>To instruct the vectorizer to do this …</p></th> </tr> </thead> <tbody> <tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">-Mvect=altcode</span></code></p></td> <td><p>Generate appropriate code for vectorized loops.</p></td> </tr> <tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">-Mvect=[no]assoc</span></code></p></td> <td><dl class="simple"> <dt>Perform[disable] associativity conversions that can change the results of a computation due to a round-off error. For example, a typical optimization is to change one arithmetic operation to another arithmetic operation that is mathematically correct,</dt><dd><p>but can be computationally different and generate faster code. This option is provided to enable or disable this transformation, since a round-off error for such associativity conversions may produce unacceptable results.</p> </dd> </dl> </td> </tr> <tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">-Mvect=fuse</span></code></p></td> <td><p>Enable loop fusion.</p></td> </tr> <tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">-Mvect=gather</span></code></p></td> <td><p>Enable vectorization of indirect array references.</p></td> </tr> <tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">-Mvect=idiom</span></code></p></td> <td><p>Enable idiom recognition.</p></td> </tr> <tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">-Mvect=levels:&lt;n&gt;</span></code></p></td> <td><p>Set the maximum next level of loops to optimize.</p></td> </tr> <tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">-Mvect=nocond</span></code></p></td> <td><p>Disable vectorization of loops with conditions.</p></td> </tr> <tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">-Mvect=partial</span></code></p></td> <td><p>Enable partial loop vectorization via inner loop distribution.</p></td> </tr> <tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">-Mvect=prefetch</span></code></p></td> <td><p>Automatically generate prefetch instructions when vectorizable loops are encountered, even in cases where SSESIMD instructions are not generated.</p></td> </tr> <tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">-Mvect=short</span></code></p></td> <td><p>Enable short vector operations.</p></td> </tr> <tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">-Mvect=simd</span></code></p></td> <td><p>Automatically generate packed SSE (Streaming SIMD Extensions)SIMD, and prefetch instructions when vectorizable loops are encountered. SIMD instructions, first introduced on Pentium III and AthlonXP processors, operate on single-precision floating-point data.</p></td> </tr> <tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">-Mvect=sizelimit:n</span></code></p></td> <td><p>Limit the size of vectorized loops.</p></td> </tr> <tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">-Mvect=sse</span></code></p></td> <td><p>Equivalent to -Mvect=simd.</p></td> </tr> <tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">-Mvect=uniform</span></code></p></td> <td><p>Perform consistent optimizations in both vectorized and residual loops. Be aware that this may affect the performance of the residual loop.</p></td> </tr> </tbody> </table> <div class="admonition note"> <p class="admonition-title">Note</p> <p>Inserting <code class="docutils literal notranslate"><span class="pre">no</span></code> in front of an option disables the option. For example, to disable the generation of SIMD instructions, compile with -Mvect=nosimd.</p> </div> </section> <section id="vectorization-example-using-simd-instructions"> <h3><span class="section-number">3.5.2. </span>Vectorization Example Using SIMD Instructions<a class="headerlink" href="#vectorization-example-using-simd-instructions" title="Permalink to this headline"></a></h3> <p>One of the most important vectorization options is <code class="docutils literal notranslate"><span class="pre">-Mvect=simd</span></code>. When you use this option, the compiler automatically generates SIMD vector instructions, where possible, when targeting processors on which these instructions are supported. This process can improve performance by several factors compared with the equivalent scalar code. All of the NVIDIA HPC Fortran, C++ and C compilers support this capability.</p> <p>In the program in <a class="reference internal" href="#vect-exam-simd-vect-use-simd-exam"><span class="std std-ref">Vector operation using SIMD instructions</span></a>, the vectorizer recognizes the vector operation in subroutine ‘loop’ when either compiler switch <code class="docutils literal notranslate"><span class="pre">-Mvect=simd</span></code> or <code class="docutils literal notranslate"><span class="pre">-fast</span></code> is used. This example shows the compilation, informational messages, and runtime results using SIMD instructions on an Intel Core i7 7800X Skylake system, along with issues that affect SIMD performance.</p> <p>Loops vectorized using SIMD instructions operate much more efficiently when processing vectors that are aligned to a cache-line boundary. You can cause unconstrained data objects of size 16 bytes or greater to be cache-aligned by compiling with the <code class="docutils literal notranslate"><span class="pre">-Mcache_align</span></code> switch. An unconstrained data object is a data object that is not a common block member and not a member of an aggregate data structure.</p> <div class="admonition note"> <p class="admonition-title">Note</p> <p>For stack-based local variables to be properly aligned, the main program or function must be compiled with -Mcache_align.</p> </div> <p>The <code class="docutils literal notranslate"><span class="pre">-Mcache_align</span></code> switch has no effect on the alignment of Fortran allocatable or automatic arrays. If you have arrays that are constrained, such as vectors that are members of Fortran common blocks, you must specifically pad your data structures to ensure proper cache alignment. You can use <code class="docutils literal notranslate"><span class="pre">-Mcache_align</span></code> for only the beginning address of each common block to be cache-aligned.</p> <p>The following examples show the results of compiling the sample code in <a class="reference internal" href="#vect-exam-simd-vect-use-simd-exam"><span class="std std-ref">Vector operation using SIMD instructions</span></a> both with and without the option <code class="docutils literal notranslate"><span class="pre">-Mvect=simd</span></code>.</p> <p class="title sectiontitle rubric" id="vect-exam-simd-vect-use-simd-exam">Vector operation using SIMD instructions</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>program vector_op parameter (N = 9999) real*4 x(N), y(N), z(N), W(N) do i = 1, n y(i) = i z(i) = 2*i w(i) = 4*i enddo do j = 1, 200000 call loop(x,y,z,w,1.0e0,N) enddo print *, x(1),x(771),x(3618),x(6498),x(9999) end </pre></div> </div> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>subroutine loop(a,b,c,d,s,n) integer i, n real*4 a(n), b(n), c(n), d(n),s do i = 1, n a(i) = b(i) + c(i) - s * d(i) enddo end </pre></div> </div> <p>Assume the preceding program is compiled as follows, where <code class="docutils literal notranslate"><span class="pre">-Mvect=nosimd</span></code> disables SIMD vectorization:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ nvfortran -fast -Mvect=nosimd -Minfo vadd.f -Mfree -o vadd vector_op: 4, Loop unrolled 16 times Generated 1 prefetches in scalar loop 9, Loop not vectorized/parallelized: contains call loop: 18, Loop unrolled 8 times FMA (fused multiply-add) instruction(s) generated </pre></div> </div> <p>The following output shows a sample result if the generated executable is run and timed on an Intel Core i7 7800X Skylake system:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ /bin/time vadd -1.000000 -771.0000 -3618.000 -6498.000 -9999.000 0.99user 0.01system 0:01.18elapsed 84%CPU (0avgtext+0avgdata 3120maxresident)k 7736inputs+0outputs (4major+834minor)pagefaults 0swaps </pre></div> </div> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ /bin/time vadd -1.000000 -771.0000 -3618.000 -6498.000 -9999.000 2.31user 0.00system 0:02.57elapsed 89%CPU (0avgtext+0avgdata 6976maxresident)k 8192inputs+0outputs (4major+149minor)pagefaults 0swaps </pre></div> </div> <p>Now, recompile with vectorization enabled, and you see results similar to these:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ nvfortran -fast -Minfo vadd.f -Mfree -o vadd vector_op: 4, Loop not vectorized: may not be beneficial Unrolled inner loop 8 times Residual loop unrolled 7 times (completely unrolled) Generated 1 prefetches in scalar loop 9, Loop not vectorized/parallelized: contains call loop: 18, Generated 2 alternate versions of the loop Generated vector simd code for the loop Generated 3 prefetch instructions for the loop Generated vector simd code for the loop Generated 3 prefetch instructions for the loop Generated vector simd code for the loop Generated 3 prefetch instructions for the loop FMA (fused multiply-add) instruction(s) generated </pre></div> </div> <p>Notice the informational messages for the loop at line 18. The first line of the message indicates that two alternate versions of the loop were generated. The loop count and alignments of the arrays determine which of these versions is executed. The next several lines indicate the loop was vectorized and that prefetch instructions have been generated for three loads to minimize latency of data transfers from main memory.</p> <p>Executing again, you should see results similar to the following:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ /bin/time vadd-simd -1.000000 -771.0000 -3618.000 -6498.000 -9999.000 0.27user 0.00system 0:00.29elapsed 93%CPU (0avgtext+0avgdata 3124maxresident)k 0inputs+0outputs (0major+838minor)pagefaults 0swaps </pre></div> </div> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ /bin/time vadd-simd -1.000000 -771.0000 -3618.000 -6498.000 -9999.000 0.62user 0.00system 0:00.65elapsed 95%CPU (0avgtext+0avgdata 6976maxresident)k 0inputs+0outputs (0major+151minor)pagefaults 0swaps </pre></div> </div> <p>The SIMD result is 3.7 times faster than the equivalent non-SIMD version of the program.</p> <p>Speed-up realized by a given loop or program can vary widely based on a number of factors:</p> <ul class="simple"> <li><p>When the vectors of data are resident in the data cache, performance improvement using SIMD instructions is most effective.</p></li> <li><p>If data is aligned properly, performance will be better in general than when using SIMD operations on unaligned data.</p></li> <li><p>If the compiler can guarantee that data is aligned properly, even more efficient sequences of SIMD instructions can be generated.</p></li> <li><p>The efficiency of loops that operate on single-precision data can be higher. SIMD instructions can operate on four single-precision elements concurrently, but only two double-precision elements.</p></li> </ul> <div class="admonition note"> <p class="admonition-title">Note</p> <p>Compiling with <code class="docutils literal notranslate"><span class="pre">-Mvect=simd</span></code> can result in numerical differences from the executables generated with less optimization. Certain vectorizable operations, for example dot products, are sensitive to order of operations and the associative transformations necessary to enable vectorization (or parallelization).</p> </div> </section> </section> <section id="interprocedural-analysis-and-optimization-using-mipa"> <h2><span class="section-number">3.6. </span>Interprocedural Analysis and Optimization using -Mipa<a class="headerlink" href="#interprocedural-analysis-and-optimization-using-mipa" title="Permalink to this headline"></a></h2> <p>The NVIDIA HPC Fortran, C++ and C compilers use interprocedural analysis (IPA) that results in minimal changes to makefiles and the standard edit-build-run application development cycle. Other than adding <code class="docutils literal notranslate"><span class="pre">-Mipa</span></code> to the command line, no other changes are required. For reference and background, the process of building a program without IPA is described later in this section, followed by the minor modifications required to use IPA with the NVIDIA compilers. While the NVC compiler is used here to show how IPA works, similar capabilities apply to each of the NVIDIA HPC Fortran, C++ and C compilers.</p> <section id="building-a-program-without-ipa-single-step"> <h3><span class="section-number">3.6.1. </span>Building a Program Without IPA – Single Step<a class="headerlink" href="#building-a-program-without-ipa-single-step" title="Permalink to this headline"></a></h3> <p>Using the nvc command-level compiler driver, multiple source files can be compiled and linked into a single executable with one command. The following example compiles and links three source files:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ nvc -o a.out file1.c file2.c file3.c </pre></div> </div> <p>In actuality, the nvc driver executes several steps to produce the assembly code and object files corresponding to each source file, and subsequently to link the object files together into a single executable file. This command is roughly equivalent to the following commands performed individually:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ nvc -S -o file1.s file1.c $ as -o file1.o file1.s $ nvc -S -o file2.s file2.c $ as -o file2.o file2.s $ nvc -S -o file3.s file3.c $ as -o file3.o file3.s $ nvc -o a.out file1.o file2.o file3.o </pre></div> </div> <p>If any of the three source files is edited, the executable can be rebuilt with the same command line:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ nvc -o a.out file1.c file2.c file3.c </pre></div> </div> <div class="admonition note"> <p class="admonition-title">Note</p> <p>This always works as intended, but has the side-effect of recompiling all of the source files, even if only one has changed. For applications with a large number of source files, this can be time-consuming and inefficient.</p> </div> </section> <section id="building-a-program-without-ipa-several-steps"> <h3><span class="section-number">3.6.2. </span>Building a Program Without IPA – Several Steps<a class="headerlink" href="#building-a-program-without-ipa-several-steps" title="Permalink to this headline"></a></h3> <p>It is also possible to use individual nvc commands to compile each source file into a corresponding object file, and one to link the resulting object files into an executable:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ nvc -c file1.c $ nvc -c file2.c $ nvc -c file3.c $ nvc -o a.out file1.o file2.o file3.o </pre></div> </div> <p>The nvc driver invokes the compiler and assembler as required to process each source file, and invokes the linker for the final link command. If you modify one of the source files, the executable can be rebuilt by compiling just that file and then relinking:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ nvc -c file1.c $ nvc -o a.out file1.o file2.o file3.o </pre></div> </div> </section> <section id="building-a-program-without-ipa-using-make"> <h3><span class="section-number">3.6.3. </span>Building a Program Without IPA Using Make<a class="headerlink" href="#building-a-program-without-ipa-using-make" title="Permalink to this headline"></a></h3> <p>The program compilation and linking process can be simplified greatly using the <code class="docutils literal notranslate"><span class="pre">make</span></code> utility on systems where it is supported. Suppose you create a <code class="docutils literal notranslate"><span class="pre">makefile</span></code> containing the following lines:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>a.out: file1.o file2.o file3.o nvc $(OPT) -o a.out file1.o file2.o file3.o file1.o: file1.c nvc $(OPT) -c file1.c file2.o: file2.c nvc $(OPT) -c file2.c file3.o: file3.c nvc $(OPT) -c file3.c </pre></div> </div> <p>It is then possible to type a single make command:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ make </pre></div> </div> <p>The <code class="docutils literal notranslate"><span class="pre">make</span></code> utility determines which object files are out of date with respect to their corresponding source files, and invokes the compiler to recompile only those source files and to relink the executable. If you subsequently edit one or more source files, the executable can be rebuilt with the minimum number of recompilations using the same single <code class="docutils literal notranslate"><span class="pre">make</span></code> command.</p> </section> <section id="building-a-program-with-ipa"> <h3><span class="section-number">3.6.4. </span>Building a Program with IPA<a class="headerlink" href="#building-a-program-with-ipa" title="Permalink to this headline"></a></h3> <p>Interprocedural analysis and optimization (IPA) by the NVIDIA HPC Compilers alters the standard and <code class="docutils literal notranslate"><span class="pre">make</span></code> utility command-level interfaces as little as possible. IPA occurs in three phases:</p> <ul class="simple"> <li><p><strong>Collection</strong>: Create a summary of each function or procedure, collecting the useful information for interprocedural optimizations. This is done during the compile step if the <code class="docutils literal notranslate"><span class="pre">-⁠Mipa</span></code> switch is present on the command line; summary information is collected and stored in the object file.</p></li> <li><p><strong>Propagation</strong>: Process all the object files to propagate the interprocedural summary information across function and file boundaries. This is done during the link step, when all the object files are combined, if the <code class="docutils literal notranslate"><span class="pre">-⁠Mipa</span></code> switch is present on the link command line.</p></li> <li><p><strong>Recompile/Optimization</strong>: Recompile each of the object files with the propagated interprocedural information, producing a specialized object file. This process is also performed during the link step when the <code class="docutils literal notranslate"><span class="pre">-⁠Mipa</span></code> switch is present on the link command line.</p></li> </ul> <p>When linking with <code class="docutils literal notranslate"><span class="pre">-⁠Mipa</span></code>, the NVIDIA HPC Compilers automatically regenerate IPA-optimized versions of each object file, essentially recompiling each file. If there are IPA-optimized objects from a previous build, the compilers will minimize the recompile time by reusing those objects if they are still valid. They will still be valid if the IPA-optimized object is newer than the original object file, and the propagated IPA information for that file has not changed since it was optimized.</p> <p>After each object file has been recompiled, the regular linker is invoked to build the application with the IPA-optimized object files. The IPA-optimized object files are saved in the same directory as the original object files, for use in subsequent program builds.</p> </section> <section id="building-a-program-with-ipa-single-step"> <h3><span class="section-number">3.6.5. </span>Building a Program with IPA – Single Step<a class="headerlink" href="#building-a-program-with-ipa-single-step" title="Permalink to this headline"></a></h3> <p>By adding the <code class="docutils literal notranslate"><span class="pre">-Mipa</span></code> command line switch, several source files can be compiled and linked with interprocedural optimizations with one command:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ nvc -Mipa=fast -o a.out file1.c file2.c file3.c </pre></div> </div> <p>Just like compiling without <code class="docutils literal notranslate"><span class="pre">-Mipa</span></code>, the driver executes several steps to produce the assembly and object files to create the executable:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ nvc -Mipa=fast -S -o file1.s file1.c $ as -o file1.o file1.s $ nvc -Mipa=fast -S -o file2.s file2.c $ as -o file2.o file2.s $ nvc -Mipa=fast -S -o file3.s file3.c $ as -o file3.o file3.s $ nvc -Mipa=fast -o a.out file1.o file2.o file3.o </pre></div> </div> <p>In the last step, an IPA linker is invoked to read all the IPA summary information and perform the interprocedural propagation. The IPA linker reinvokes the compiler on each of the object files to recompile them with interprocedural information. This creates three new objects with mangled names:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>file1_ipa5_a.out.oo.o, file2_ipa5_a.out.oo.o, file3_ipa5_a.out.oo.o </pre></div> </div> <p>The system linker is then invoked to link these IPA-optimized objects into the final executable. Later, if one of the three source files is edited, the executable can be rebuilt with the same command line:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ nvc -Mipa=fast -o a.out file1.c file2.c file3.c </pre></div> </div> <p>This works, but again has the side-effect of compiling each source file, and recompiling each object file at link time.</p> </section> <section id="building-a-program-with-ipa-several-steps"> <h3><span class="section-number">3.6.6. </span>Building a Program with IPA – Several Steps<a class="headerlink" href="#building-a-program-with-ipa-several-steps" title="Permalink to this headline"></a></h3> <p>Just by adding the <code class="docutils literal notranslate"><span class="pre">-Mipa</span></code> command-line switch, it is possible to use individual nvc commands to compile each source file, followed by a command to link the resulting object files into an executable:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ nvc -Mipa=fast -c file1.c $ nvc -Mipa=fast -c file2.c $ nvc -Mipa=fast -c file3.c $ nvc -Mipa=fast -o a.out file1.o file2.o file3.o </pre></div> </div> <p>The nvc driver invokes the compiler and assembler as required to process each source file, and invokes the IPA linker for the final link command. If you modify one of the source files, the executable can be rebuilt by compiling just that file and then relinking:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ nvc -Mipa=fast -c file1.c $ nvc -Mipa=fast -o a.out file1.o file2.o file3.o </pre></div> </div> <p>When the IPA linker is invoked, it will determine that the IPA-optimized object for <code class="docutils literal notranslate"><span class="pre">file1.o</span></code> (<code class="docutils literal notranslate"><span class="pre">file1_ipa5_a.out.oo.o</span></code>) is stale, since it is older than the object <code class="docutils literal notranslate"><span class="pre">file1.o</span></code>; and hence it needs to be rebuilt, and reinvokes the compiler to generate it. In addition, depending on the nature of the changes to the source file <code class="docutils literal notranslate"><span class="pre">file1.c</span></code>, the interprocedural optimizations previously performed for <code class="docutils literal notranslate"><span class="pre">file2</span></code> and <code class="docutils literal notranslate"><span class="pre">file3</span></code> may now be inaccurate. For instance, IPA may have propagated a constant argument value in a call from a function in <code class="docutils literal notranslate"><span class="pre">file1.c</span></code> to a function in <code class="docutils literal notranslate"><span class="pre">file2.c</span></code>; if the value of the argument has changed, any optimizations based on that constant value are invalid. The IPA linker determines which, if any, of the previously created IPA-optimized objects need to be regenerated; and, as appropriate, reinvokes the compiler to regenerate them. Only those objects that are stale or which have new or different IPA information are regenerated. This approach saves compile time.</p> </section> <section id="building-a-program-with-ipa-using-make"> <h3><span class="section-number">3.6.7. </span>Building a Program with IPA Using Make<a class="headerlink" href="#building-a-program-with-ipa-using-make" title="Permalink to this headline"></a></h3> <p>As shown earlier, programs can be built with IPA using the make utility. Just add the command-line switch -<code class="docutils literal notranslate"><span class="pre">Mipa</span></code>, as shown here:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>OPT=-Mipa=fast a.out: file1.o file2.o file3.o nvc $(OPT) -o a.out file1.o file2.o file3.o file1.o: file1.c nvc $(OPT) -c file1.c file2.o: file2.c nvc $(OPT) -c file2.c file3.o: file3.c nvc $(OPT) -c file3.c </pre></div> </div> <p>Using the single make command invokes the compiler to generate any of the object files that are out-of-date, then invokes nvc to link the objects into the executable. At link time, nvc calls the IPA linker to regenerate any stale or invalid IPA-optimized objects.</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ make </pre></div> </div> </section> <section id="questions-about-ipa"> <h3><span class="section-number">3.6.8. </span>Questions about IPA<a class="headerlink" href="#questions-about-ipa" title="Permalink to this headline"></a></h3> <p><strong>Question:</strong> Why is the object file so large?</p> <p><strong>Answer:</strong> An object file created with <code class="docutils literal notranslate"><span class="pre">-⁠Mipa</span></code> contains several additional sections. One is the summary information used to drive the interprocedural analysis. In addition, the object file contains the compiler internal representation of the source file, so the file can be recompiled at link time with interprocedural optimizations. There may be additional information when inlining is enabled. The total size of the object file may be 5-10 times its original size. The extra sections are not added to the final executable.</p> <p><strong>Question:</strong> What if I compile with <code class="docutils literal notranslate"><span class="pre">-⁠Mipa</span></code> and link without <code class="docutils literal notranslate"><span class="pre">-⁠Mipa</span></code>?</p> <p><strong>Answer:</strong> The NVIDIA HPC Compilers generate a legal object file, even when the source file is compiled with <code class="docutils literal notranslate"><span class="pre">-⁠Mipa</span></code>. If you compile with <code class="docutils literal notranslate"><span class="pre">-⁠Mipa</span></code> and link without <code class="docutils literal notranslate"><span class="pre">-⁠Mipa</span></code>, the linker is invoked on the original object files. A legal executable is generated. While this executable does not have the benefit of interprocedural optimizations, any other optimizations do apply.</p> <p><strong>Question:</strong> What if I compile without <code class="docutils literal notranslate"><span class="pre">-⁠Mipa</span></code> and link with <code class="docutils literal notranslate"><span class="pre">-⁠Mipa</span></code>?</p> <p><strong>Answer:</strong> At link time, the IPA linker must have summary information about all the functions or routines used in the program. This information is created only when a file is compiled with <code class="docutils literal notranslate"><span class="pre">-⁠Mipa</span></code>. If you compile a file without <code class="docutils literal notranslate"><span class="pre">-⁠Mipa</span></code> and then try to get interprocedural optimizations by linking with <code class="docutils literal notranslate"><span class="pre">-⁠Mipa</span></code>, the IPA linker will issue a message that some routines have no IPA summary information, and will proceed to run the system linker using the original object files. If some files were compiled with <code class="docutils literal notranslate"><span class="pre">-⁠Mipa</span></code> and others were not, it will determine the safest approximation of the IPA summary information for those files not compiled with <code class="docutils literal notranslate"><span class="pre">-⁠Mipa</span></code>, and use that to recompile the other files using interprocedural optimizations.</p> <p><strong>Question:</strong> Can I build multiple applications in the same directory with <code class="docutils literal notranslate"><span class="pre">-⁠Mipa</span></code>?</p> <p><strong>Answer:</strong> Yes. Suppose you have three source files: <code class="docutils literal notranslate"><span class="pre">main1.c</span></code>, <code class="docutils literal notranslate"><span class="pre">main2.c</span></code>, and <code class="docutils literal notranslate"><span class="pre">sub.c</span></code>, where <code class="docutils literal notranslate"><span class="pre">sub.c</span></code> is shared between the two applications. Suppose you build the first application with <code class="docutils literal notranslate"><span class="pre">-⁠Mipa</span></code>, using this command:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ nvc -Mipa=fast -o app1 main1.c sub.c </pre></div> </div> <p>The IPA linker creates two IPA-optimized object files and uses them to build the first application.</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>main1_ipa4_app1.oo sub_ipa4_app1.oo </pre></div> </div> <p>Now suppose you build the second application using this command:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ nvc -Mipa=fast -o app2 main2.c sub.c </pre></div> </div> <p>The IPA linker creates two more IPA-optimized object files:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>main2_ipa4_app2.oo sub_ipa4_app2.oo </pre></div> </div> <div class="admonition note"> <p class="admonition-title">Note</p> <p>There are now three object files for sub.c: the original sub.o, and two IPA-optimized objects, one for each application in which it appears.</p> </div> <p><strong>Question:</strong> How is the mangled name for the IPA-optimized object files generated?</p> <p><strong>Answer:</strong> The mangled name has ‘_ipa’ appended, followed by the decimal number of the length of the executable file name, followed by an underscore and the executable file name itself. The suffix is changed to .oo so that linking *.o does not pull in the IPA-optimized objects. If the IPA linker determines that the file would not benefit from any interprocedural optimizations, it does not have to recompile the file at link time, and uses the original object.</p> <p><strong>Question:</strong> Can I use parallel make environments (e.g., pmake) with IPA?</p> <p><strong>Answer:</strong> No. IPA is not compatible with parallel make environments.</p> <span class="target" id="fn-inline-use"></span></section> </section> </section> <section id="using-function-inlining"> <h1><span class="section-number">4. </span>Using Function Inlining<a class="headerlink" href="#using-function-inlining" title="Permalink to this headline"></a></h1> <p>Function inlining replaces a call to a function or a subroutine with the body of the function or subroutine. This can speed up execution by eliminating parameter passing and function/subroutine call and return overhead. It also allows the compiler to optimize the function with the rest of the code. Note that using function inlining indiscriminately can result in much larger code size and no increase in execution speed.</p> <p>The NVIDIA HPC compilers provide two categories of inlining:</p> <ul class="simple"> <li><p><strong>Automatic function inlining</strong> – In C++ and C, you can inline static functions with the <code class="docutils literal notranslate"><span class="pre">inline</span></code> keyword by using the <code class="docutils literal notranslate"><span class="pre">-⁠Mautoinline</span></code> option, which is included with <code class="docutils literal notranslate"><span class="pre">-⁠fast</span></code>.</p></li> <li><p><strong>Function inlining</strong> – You can inline functions which were extracted to the inline libraries in Fortran, C++ and C. There are two ways of enabling function inlining: with and without the <code class="docutils literal notranslate"><span class="pre">lib</span></code> suboption. For the latter, you create inline libraries, for example using the <code class="docutils literal notranslate"><span class="pre">nvfortran</span></code> compiler driver and the <code class="docutils literal notranslate"><span class="pre">-⁠o</span></code> and <code class="docutils literal notranslate"><span class="pre">-⁠Mextract</span></code> options.</p></li> </ul> <p>There are important restrictions on inlining. Inlining only applies to certain types of functions. Refer to <a class="reference internal" href="#fn-inline-restrictions"><span class="std std-ref">Restrictions on Inlining</span></a> for more details on function inlining limitations.</p> <p>This section describes how to use the following options related to function inlining:</p> <div class="line-block"> <div class="line"><code class="docutils literal notranslate"><span class="pre">-Mautoinline</span></code></div> <div class="line"><code class="docutils literal notranslate"><span class="pre">-Mextract</span></code></div> <div class="line"><code class="docutils literal notranslate"><span class="pre">-Minline</span></code></div> <div class="line"><code class="docutils literal notranslate"><span class="pre">-Mnoinline</span></code></div> <div class="line"><code class="docutils literal notranslate"><span class="pre">-Mrecursive</span></code></div> </div> <section id="automatic-function-inlining-in-c-and-c"> <h2><span class="section-number">4.1. </span>Automatic function inlining in C++ and C<a class="headerlink" href="#automatic-function-inlining-in-c-and-c" title="Permalink to this headline"></a></h2> <p>To enable automatic function inlining in C++ and C for static functions with the <code class="docutils literal notranslate"><span class="pre">inline</span></code> keyword, use the <code class="docutils literal notranslate"><span class="pre">-⁠Mautoinline</span></code> option (included in <code class="docutils literal notranslate"><span class="pre">-⁠fast</span></code>). Use <code class="docutils literal notranslate"><span class="pre">-⁠Mnoautoinline</span></code> to disable it.</p> <p>These <code class="docutils literal notranslate"><span class="pre">-⁠Mautoinline</span></code> suboptions let you determine the selection criteria, where <code class="docutils literal notranslate"><span class="pre">n</span></code> loosely corresponds to the number of lines in the procedure:</p> <dl class="simple"> <dt>maxsize:<code class="docutils literal notranslate"><span class="pre">n</span></code></dt><dd><p>Automatically inline functions size <code class="docutils literal notranslate"><span class="pre">n</span></code> and less</p> </dd> <dt>totalsize:<code class="docutils literal notranslate"><span class="pre">n</span></code></dt><dd><p>Limit automatic inlining to total size of <code class="docutils literal notranslate"><span class="pre">n</span></code></p> </dd> </dl> </section> <section id="invoking-procedure-inlining"> <h2><span class="section-number">4.2. </span>Invoking Procedure Inlining<a class="headerlink" href="#invoking-procedure-inlining" title="Permalink to this headline"></a></h2> <p>To invoke the procedure inliner, use the <code class="docutils literal notranslate"><span class="pre">-⁠Minline</span></code> option. If you do not specify an inline library, the compiler performs a special prepass on all source files named on the compiler command line before it compiles any of them. This pass extracts procedures that meet the requirements for inlining and puts them in a temporary inline library for use by the compilation pass.</p> <p>Several <code class="docutils literal notranslate"><span class="pre">-⁠Minline</span></code> suboptions let you determine the selection criteria for procedures to be inlined. These suboptions include:</p> <dl> <dt>except:<code class="docutils literal notranslate"><span class="pre">func</span></code></dt><dd><p>Inlines all eligible procedures except <code class="docutils literal notranslate"><span class="pre">func</span></code>, a procedure in the source text. You can use a comma-separated list to specify multiple procedure.</p> </dd> <dt>[name:]``func``</dt><dd><p>Inlines all procedures in the source text whose name matches <code class="docutils literal notranslate"><span class="pre">func</span></code>. You can use a comma-separated list to specify multiple procedures.</p> </dd> <dt>[maxsize:]``n``</dt><dd><p>A numeric option is assumed to be a size. Procedures of size <code class="docutils literal notranslate"><span class="pre">n</span></code> or less are inlined, where <code class="docutils literal notranslate"><span class="pre">n</span></code> loosely corresponds to the number of lines in the procedure. If both <code class="docutils literal notranslate"><span class="pre">n</span></code> and <code class="docutils literal notranslate"><span class="pre">func</span></code> are specified, then procedures matching the given name(s) or meeting the size requirements are inlined.</p> </dd> <dt>reshape</dt><dd><p>Fortran subprograms with array arguments are not inlined by default if the array shape does not match the shape in the caller. Use this option to override the default.</p> </dd> <dt>smallsize:<code class="docutils literal notranslate"><span class="pre">n</span></code></dt><dd><p>Always inline procedures of size smaller than <code class="docutils literal notranslate"><span class="pre">n</span></code> regardless of other size limits.</p> </dd> <dt>totalsize:<code class="docutils literal notranslate"><span class="pre">n</span></code></dt><dd><p>Stop inlining in a procedure when the procedure’s total size with inlining reaches the <code class="docutils literal notranslate"><span class="pre">n</span></code> specified.</p> </dd> <dt>[lib:]``file.ext``</dt><dd><p>Instructs the inliner to inline the procedures within the library file <code class="docutils literal notranslate"><span class="pre">file.ext</span></code>. If no inline library is specified, procedures are extracted from a temporary library created during an extract prepass.</p> <div class="admonition tip"> <p class="admonition-title">Tip</p> <p>Create the library file using the <code class="docutils literal notranslate"><span class="pre">-Mextract</span></code> option.</p> </div> </dd> </dl> <p>If you specify both a procedure name and a maxsize n, the compiler inlines procedures that match the procedure name <em>or</em> have n or fewer statements.</p> <p>If a name is used without a keyword, then a name with a period is assumed to be an inline library and a name without a period is assumed to be a procedure name. If a number is used without a keyword, the number is assumed to be a size.</p> <p>Inlining can be disabled with <code class="docutils literal notranslate"><span class="pre">-Mnoinline</span></code>.</p> <p>In the following example, the compiler inlines procedures with fewer than approximately 100 statements in the source file <code class="docutils literal notranslate"><span class="pre">myprog.f</span></code> and writes the executable code in the default output file <code class="docutils literal notranslate"><span class="pre">a.out</span></code>.</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ nvfortran -Minline=maxsize:100 myprog.f </pre></div> </div> </section> <section id="using-an-inline-library"> <h2><span class="section-number">4.3. </span>Using an Inline Library<a class="headerlink" href="#using-an-inline-library" title="Permalink to this headline"></a></h2> <p>If you specify one or more inline libraries on the command line with the <code class="docutils literal notranslate"><span class="pre">-Minline</span></code> option, the compiler does not perform an initial extract pass. The compiler selects functions to inline from the specified inline library. If you also specify a size or function name, all functions in the inline library meeting the selection criteria are selected for inline expansion at points in the source text where they are called.</p> <p>If you do not specify a function name or a size limitation for the <code class="docutils literal notranslate"><span class="pre">-Minline</span></code> option, the compiler tries to inline every function in the inline library that matches a function in the source text.</p> <p>In the following example, the compiler inlines the function <code class="docutils literal notranslate"><span class="pre">proc</span></code> from the inline library <code class="docutils literal notranslate"><span class="pre">lib.il</span></code> and writes the executable code in the default output file <code class="docutils literal notranslate"><span class="pre">a.out</span></code>.</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ nvfortran -Minline=name:proc,lib:lib.il myprog.f </pre></div> </div> <p>The following command line is equivalent to the preceding line, with the exception that in the following example does not use the keywords <code class="docutils literal notranslate"><span class="pre">name:</span></code> and <code class="docutils literal notranslate"><span class="pre">lib:</span></code>. You typically use keywords to avoid name conflicts when you use an inline library name that does not contain a period. Otherwise, without the keywords, a period informs the compiler that the file on the command line is an inline library.</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ nvfortran -Minline=proc,lib.il myprog.f </pre></div> </div> <span class="target" id="fn-inline-create-lib"></span></section> <section id="creating-an-inline-library"> <h2><span class="section-number">4.4. </span>Creating an Inline Library<a class="headerlink" href="#creating-an-inline-library" title="Permalink to this headline"></a></h2> <p>You can create or update an inline library using the <code class="docutils literal notranslate"><span class="pre">-⁠Mextract</span></code> command-line option. If you do not specify selection criteria with the <code class="docutils literal notranslate"><span class="pre">-⁠Mextract</span></code> option, the compiler attempts to extract all procedures.</p> <p>Several <code class="docutils literal notranslate"><span class="pre">-⁠Mextract</span></code> options let you determine the selection criteria for creating or updating an inline library. These selection criteria include:</p> <dl> <dt><code class="docutils literal notranslate"><span class="pre">func</span></code></dt><dd><p>Extracts the procedure <code class="docutils literal notranslate"><span class="pre">func</span></code>. you can use a comma-separated list to specify multiple procedures.</p> </dd> <dt>[name:]<code class="docutils literal notranslate"><span class="pre">func</span></code></dt><dd><p>Extracts the procedure whose name matches <code class="docutils literal notranslate"><span class="pre">func</span></code>, a procedure in the source text.</p> </dd> <dt>[size:]<code class="docutils literal notranslate"><span class="pre">n</span></code></dt><dd><p>Limits the size of the extracted procedures to those with a statement count less than or equal to <code class="docutils literal notranslate"><span class="pre">n</span></code>, the specified size.</p> <div class="admonition note"> <p class="admonition-title">Note</p> <p>The size n may not exactly equal the number of statements in a selected procedure; the size parameter is merely a rough gauge.</p> </div> </dd> <dt>[lib:]<code class="docutils literal notranslate"><span class="pre">ext.lib</span></code></dt><dd><p>Stores the extracted information in the library directory <code class="docutils literal notranslate"><span class="pre">ext.lib</span></code>.</p> <p>If no inline library is specified, procedures are extracted to a temporary library created during an extract prepass for use during the compilation stage.</p> </dd> </dl> <p>When you use the <code class="docutils literal notranslate"><span class="pre">-⁠Mextract</span></code> option, only the extract phase is performed; the compile and link phases are not performed. The output of an extract pass is a library of procedures available for inlining. This output is placed in the inline library file specified on the command line with the <code class="docutils literal notranslate"><span class="pre">-⁠o</span></code> filename specification. If the library file exists, new information is appended to it. If the file does not exist, it is created. You can use a command similar to the following:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ nvfortran -Mextract=lib:lib.il myfunc.f </pre></div> </div> <p>You can use the <code class="docutils literal notranslate"><span class="pre">-⁠Minline</span></code> option with the <code class="docutils literal notranslate"><span class="pre">-⁠Mextract</span></code> option. In this case, the extracted library of procedures can have other procedures inlined into the library. Using both options enables you to obtain more than one level of inlining. In this situation, if you do not specify a library with the <code class="docutils literal notranslate"><span class="pre">-⁠Minline</span></code> option, the inline process consists of two extract passes. The first pass is a hidden pass implied by the <code class="docutils literal notranslate"><span class="pre">-⁠Minline</span></code> option, during which the compiler extracts procedures and places them into a temporary library. The second pass uses the results of the first pass but puts its results into the library that you specify with the <code class="docutils literal notranslate"><span class="pre">-⁠o</span></code> option.</p> <section id="working-with-inline-libraries"> <h3><span class="section-number">4.4.1. </span>Working with Inline Libraries<a class="headerlink" href="#working-with-inline-libraries" title="Permalink to this headline"></a></h3> <p>An inline library is implemented as a directory with each inline function in the library stored as a file using an encoded form of the inlinable function.</p> <p>A special file named <code class="docutils literal notranslate"><span class="pre">TOC</span></code> in the inline library directory serves as a table of contents for the inline library. This is a printable, ASCII file which you can examine to locate information about the library contents, such as names and sizes of functions, the source file from which they were extracted, the version number of the extractor which created the entry, and so on.</p> <p>Libraries and their elements can be manipulated using ordinary system commands.</p> <ul class="simple"> <li><p>Inline libraries can be copied or renamed.</p></li> <li><p>Elements of libraries can be deleted or copied from one library to another.</p></li> <li><p>The <cite>ls</cite> or <cite>dir</cite> command can be used to determine the last-change date of a library entry.</p></li> </ul> </section> <section id="dependencies"> <h3><span class="section-number">4.4.2. </span>Dependencies<a class="headerlink" href="#dependencies" title="Permalink to this headline"></a></h3> <p>When a library is created or updated using one of the NVIDIA HPC compilers, the last-change date of the library directory is updated. This allows a library to be listed as a dependence in a makefile and ensures that the necessary compilations are performed when a library is changed.</p> </section> <section id="updating-inline-libraries-makefiles"> <h3><span class="section-number">4.4.3. </span>Updating Inline Libraries – Makefiles<a class="headerlink" href="#updating-inline-libraries-makefiles" title="Permalink to this headline"></a></h3> <p>If you use inline libraries you must be certain that they remain up-to-date with the source files into which they are inlined. One way to assure inline libraries are updated is to include them in a makefile.</p> <p>The makefile fragment in the following example assumes the file <code class="docutils literal notranslate"><span class="pre">utils.f</span></code> contains a number of small functions used in the files <code class="docutils literal notranslate"><span class="pre">parser.f</span></code> and <code class="docutils literal notranslate"><span class="pre">alloc.f</span></code>.</p> <p>This portion of the makefile:</p> <ul class="simple"> <li><p>Maintains the inline library <code class="docutils literal notranslate"><span class="pre">utils.il</span></code>.</p></li> <li><p>Updates the library whenever you change <code class="docutils literal notranslate"><span class="pre">utils.f</span></code> or one of the include files it uses.</p></li> <li><p>Compiles <code class="docutils literal notranslate"><span class="pre">parser.f</span></code> and <code class="docutils literal notranslate"><span class="pre">alloc.f</span></code> whenever you update the library.</p></li> </ul> <p><strong>Sample Makefile</strong></p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>SRC = mydir FC = nvfortran FFLAGS = -O2 main.o: $(SRC)/main.f $(SRC)/global.h $(FC) $(FFLAGS) -c $(SRC)/main.f utils.o: $(SRC)/utils.f $(SRC)/global.h $(SRC)/utils.h $(FC) $(FFLAGS) -c $(SRC)/utils.f utils.il: $(SRC)/utils.f $(SRC)/global.h $(SRC)/utils.h $(FC) $(FFLAGS) -Mextract=15 -o utils.il $(SRC)/utils.f parser.o: $(SRC)/parser.f $(SRC)/global.h utils.il $(FC) $(FFLAGS) -Minline=utils.il -c $(SRC)/parser.f alloc.o: $(SRC)/alloc.f $(SRC)/global.h utils.il $(FC) $(FFLAGS) -Minline=utils.il -c $(SRC)/alloc.f myprog: main.o utils.o parser.o alloc.o $(FC) -o myprog main.o utils.o parser.o alloc.o </pre></div> </div> </section> </section> <section id="error-detection-during-inlining"> <h2><span class="section-number">4.5. </span>Error Detection during Inlining<a class="headerlink" href="#error-detection-during-inlining" title="Permalink to this headline"></a></h2> <p>You can specify the <code class="docutils literal notranslate"><span class="pre">-Minfo=inline</span></code> option to request inlining information from the compiler when you invoke the inliner. For example:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ nvfortran -Minline=mylib.il -Minfo=inline myext.f </pre></div> </div> </section> <section id="examples"> <h2><span class="section-number">4.6. </span>Examples<a class="headerlink" href="#examples" title="Permalink to this headline"></a></h2> <p>Assume the program <code class="docutils literal notranslate"><span class="pre">dhry</span></code> consists of a single source file <code class="docutils literal notranslate"><span class="pre">dhry.f</span></code>. The following command line builds an executable file for <code class="docutils literal notranslate"><span class="pre">dhry</span></code> in which proc7 is inlined wherever it is called:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ nvfortran dhry.f -Minline=proc7 </pre></div> </div> <p>The following command lines build an executable file for <code class="docutils literal notranslate"><span class="pre">dhry</span></code> in which proc7 plus any functions of approximately 10 or fewer statements are inlined (one level only).</p> <div class="admonition note"> <p class="admonition-title">Note</p> <p>The specified functions are inlined only if they are previously placed in the inline library, <code class="docutils literal notranslate"><span class="pre">temp.il</span></code>, during the extract phase.</p> </div> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ nvfortran dhry.f -Mextract=lib:temp.il $ nvfortran dhry.f -Minline=10,proc7,temp.il </pre></div> </div> <p>Using the same source file <code class="docutils literal notranslate"><span class="pre">dhry.f</span></code>, the following example builds an executable for <code class="docutils literal notranslate"><span class="pre">dhry</span></code> in which all functions of roughly ten or fewer statements are inlined. Two levels of inlining are performed. This means that if function A calls function B, and B calls C, and both B and C are inlinable, then the version of B which is inlined into A will have had C inlined into it.</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ nvfortran dhry.f -Minline=maxsize:10 </pre></div> </div> <span class="target" id="fn-inline-restrictions"></span></section> <section id="restrictions-on-inlining"> <h2><span class="section-number">4.7. </span>Restrictions on Inlining<a class="headerlink" href="#restrictions-on-inlining" title="Permalink to this headline"></a></h2> <p>The following Fortran subprograms cannot be extracted:</p> <ul class="simple"> <li><p>Main or BLOCK DATA programs.</p></li> <li><p>Subprograms containing alternate return, assigned GO TO, DATA, SAVE, or EQUIVALENCE statements.</p></li> <li><p>Subprograms containing FORMAT statements.</p></li> <li><p>Subprograms containing multiple entries.</p></li> </ul> <p>A Fortran subprogram is not inlined if any of the following applies:</p> <ul class="simple"> <li><p>It is referenced in a statement function.</p></li> <li><p>A common block mismatch exists; in other words, the caller must contain all common blocks specified in the callee, and elements of the common blocks must agree in name, order, and type (except that the caller’s common block can have additional members appended to the end of the common block).</p></li> <li><p>An argument mismatch exists; in other words, the number and type (size) of actual and formal parameters must be equal.</p></li> <li><p>A name clash exists, such as a call to subroutine <code class="docutils literal notranslate"><span class="pre">xyz</span></code> in the extracted subprogram and a variable named <code class="docutils literal notranslate"><span class="pre">xyz</span></code> in the caller.</p></li> </ul> <p>The following types of C and C++ functions cannot be inlined:</p> <ul class="simple"> <li><p>Functions which accept a variable number of arguments</p></li> </ul> <p>Certain C/C++ functions can only be inlined into the file that contains their definition:</p> <ul class="simple"> <li><p>Static functions</p></li> <li><p>Functions which call a static function</p></li> <li><p>Functions which reference a static variable</p></li> </ul> </section> </section> <section id="using-gpus"> <h1><span class="section-number">5. </span>Using GPUs<a class="headerlink" href="#using-gpus" title="Permalink to this headline"></a></h1> <p>An NVIDIA GPU can be used as an accelerator to which a CPU can offload data and executable kernels to perform compute-intensive calculations. This section gives an overview of options for programming NVIDIA GPUs with NVIDIA’s HPC Compilers and covers topics that affect GPU programming when using one or more of the GPU programming models.</p> <section id="id1"> <h2><span class="section-number">5.1. </span>Overview<a class="headerlink" href="#id1" title="Permalink to this headline"></a></h2> <p>With the NVIDIA HPC Compilers you can program NVIDIA GPUs using certain standard language constructs, OpenACC directives, OpenMP directives, or CUDA Fortran language extensions. GPU programming with standard language constructs or directives allows you to create high-level GPU-accelerated programs without the need to explicitly initialize the GPU, manage data or program transfers between the host and GPU, or initiate GPU startup and shutdown. Rather, all of these details are implicit in the programming model and are managed by the NVIDIA HPC SDK Fortran, C++ and C compilers. GPU programming with CUDA extensions gives you access to all NVIDIA GPU features and full control over data management and offloading of compute-intensive loops and kernels.</p> <p>The NVC++ compiler supports automatic offload of C++17 Parallel Algorithms invocations to NVIDIA GPUs under control of the <code class="docutils literal notranslate"><span class="pre">-stdpar</span></code> compiler option. See the Blog post <em>Accelerating Standard C++ with GPUs</em> for details on using this feature. The NVFORTRAN compiler supports automatic offload to NVIDIA GPUs of certain Fortran array intrinsics and patterns of array syntax, including use of Volta and Ampere architecture Tensor Cores for appropriate intrinsics. See the Blog post <em>Bringing Tensor Cores to Standard Fortran</em> for details on using this feature.</p> <p>The NVFORTRAN compiler supports CUDA programming in Fortran. See the <em>NVIDIA CUDA Fortran Programming Guide</em> for complete details on how to use CUDA Fortran. The NVCC compiler supports CUDA programming in C and C++ in combination with a host C++ compiler on your system. See the <em>CUDA C++ Programming Guide</em> for an introduction and overview of how to use NVCC and CUDA C++.</p> <p>The NVFORTRAN, NVC++ and NVC compilers all support directive-based programming of NVIDIA GPUs using OpenACC. OpenACC is an accelerator programming model that is portable across operating systems and various host CPUs and types of accelerators, including both NVIDIA GPUs and multicore CPUs. OpenACC directives allow a programmer to migrate applications incrementally to accelerator targets using standards-compliant Fortran, C++ or C that remains completely portable to other compilers and systems. It allows the programmer to augment information available to the compilers, including specification of data local to an accelerator region, guidance on mapping of loops onto an accelerator, and similar performance-related details.</p> <p>The NVFORTRAN, NVC++, and NVC compilers support a subset of the OpenMP Application Program Interface for CPUs and GPUs. OpenMP applications properly structured for GPUs, meaning they expose massive parallelism and have relatively little or no synchronization in GPU-side code segments, should compile and execute with performance on par with or close to equivalent OpenACC. Codes that are not well-structured for GPUs may perform poorly but should execute correctly.</p> <p>In user-directed accelerator programming the user specifies the regions of a host program to be targeted for offloading to an accelerator. The bulk of a user’s program, as well as regions containing constructs that are not supported on the targeted accelerator, are executed on the host.</p> </section> <section id="terminology"> <h2><span class="section-number">5.2. </span>Terminology<a class="headerlink" href="#terminology" title="Permalink to this headline"></a></h2> <p>Clear and consistent terminology is important in describing any programming model. This section provides definitions of the terms required for you to effectively use this section and the associated programming model.</p> <dl class="simple"> <dt>Accelerator</dt><dd><p>a parallel processor, such as a GPU or a CPU running in multicore mode, to which a CPU can offload data and executable kernels to perform compute-intensive calculations.</p> </dd> <dt>Compute intensity</dt><dd><p>for a given loop, region, or program unit, the ratio of the number of arithmetic operations performed on computed data divided by the number of memory transfers required to move that data between two levels of a memory hierarchy.</p> </dd> <dt>Compute region</dt><dd><p>a structured block defined by a compute construct. A <em>compute construct</em> is a structured block containing loops which are compiled for the accelerator. A compute region may require device memory to be allocated and data to be copied from host to device upon region entry, and data to be copied from device to host memory and device memory deallocated upon exit. The dynamic range of a compute construct, including any code in procedures called from within the construct, is the compute region. In this release, compute regions may not contain other compute regions or data regions.</p> </dd> <dt>Construct</dt><dd><p>a structured block identified by the programmer or implicitly defined by the language. Certain actions may occur when program execution reaches the start and end of a construct, such as device memory allocation or data movement between the host and device memory. Loops in a compute construct are targeted for execution on the accelerator. The dynamic range of a construct including any code in procedures called from within the construct, is called a <em>region</em>.</p> </dd> <dt>CUDA</dt><dd><p>stands for Compute Unified Device Architecture; CUDA C++ and Fortran language extensions and API calls can be used to explicitly control and program an NVIDIA GPU.</p> </dd> <dt>Data region</dt><dd><p>a region defined by a data construct, or an implicit data region for a function or subroutine containing directives. Data regions typically require device memory to be allocated and data to be copied from host to device memory upon entry, and data to be copied from device to host memory and device memory deallocated upon exit. Data regions may contain other data regions and compute regions.</p> </dd> <dt>Device</dt><dd><p>a general reference to any type of accelerator.</p> </dd> <dt>Device memory</dt><dd><p>memory attached to an accelerator which is physically separate from the host memory.</p> </dd> <dt>Directive</dt><dd><p>in C, a #pragma, or in Fortran, a specially formatted comment statement that is interpreted by a compiler to augment information about or specify the behavior of the program.</p> </dd> <dt>DMA</dt><dd><p>Direct Memory Access, a method to move data between physically separate memories; this is typically performed by a DMA engine, separate from the host CPU, that can access the host physical memory as well as an IO device or GPU physical memory.</p> </dd> <dt>GPU</dt><dd><p>a Graphics Processing Unit; one type of accelerator device.</p> </dd> <dt>Host</dt><dd><p>the main CPU that in this context has an attached accelerator device. The host CPU controls the program regions and data loaded into and executed on the device.</p> </dd> <dt>Loop trip count</dt><dd><p>the number of times a particular loop executes.</p> </dd> <dt>Private data</dt><dd><p>with respect to an iterative loop, data which is used only during a particular loop iteration. With respect to a more general region of code, data which is used within the region but is not initialized prior to the region and is re-initialized prior to any use after the region.</p> </dd> <dt>Region</dt><dd><p>the dynamic range of a construct, including any procedures invoked from within the construct.</p> </dd> <dt>Structured block</dt><dd><p>in C++ or C, an executable statement, possibly compound, with a single entry at the top and a single exit at the bottom. In Fortran, a block of executable statements with a single entry at the top and a single exit at the bottom.</p> </dd> <dt>Vector operation</dt><dd><p>a single operation or sequence of operations applied uniformly to each element of an array.</p> </dd> <dt>Visible device copy</dt><dd><p>a copy of a variable, array, or subarray allocated in device memory, that is visible to the program unit being compiled.</p> </dd> </dl> </section> <section id="execution-model"> <h2><span class="section-number">5.3. </span>Execution Model<a class="headerlink" href="#execution-model" title="Permalink to this headline"></a></h2> <p>The execution model targeted by the NVIDIA HPC Compilers is host-directed execution with an attached accelerator device, such as a GPU. The bulk of a user application executes on the host. Compute intensive regions are offloaded to the accelerator device under control of the host. The accelerator device executes kernels, which may be as simple as a tightly-nested loop, or as complex as a subroutine, depending on the accelerator hardware.</p> <section id="host-functions"> <h3><span class="section-number">5.3.1. </span>Host Functions<a class="headerlink" href="#host-functions" title="Permalink to this headline"></a></h3> <p>Even in accelerator-targeted regions, the host must orchestrate the execution; it</p> <ul class="simple"> <li><p>allocates memory on the accelerator device</p></li> <li><p>initiates data transfer</p></li> <li><p>sends the kernel code to the accelerator</p></li> <li><p>passes kernel arguments</p></li> <li><p>queues the kernel</p></li> <li><p>waits for completion</p></li> <li><p>transfers results back to the host</p></li> <li><p>deallocates memory</p></li> </ul> <div class="admonition note"> <p class="admonition-title">Note</p> <p>In most cases, the host can queue a sequence of kernels to be executed on the device, one after the other.</p> </div> <span class="target" id="acc-mem-model"></span></section> </section> <section id="memory-model"> <h2><span class="section-number">5.4. </span>Memory Model<a class="headerlink" href="#memory-model" title="Permalink to this headline"></a></h2> <p>The most significant difference between a <em>host-only</em> program and a <em>host+accelerator</em> program is that the memory on the accelerator can be completely separate from host memory, which is the case on many GPUs. For example:</p> <ul class="simple"> <li><p>The host cannot read or write accelerator memory directly because it is not mapped into the virtual memory space of the host.</p></li> <li><p>All data movement between host memory and accelerator memory must be performed by the host through runtime library calls that explicitly move data between the separate memories.</p></li> <li><p>In general it is not valid for the compiler to assume the accelerator can read or write host memory directly. This is well-defined starting with the OpenACC 2.7 and OpenMP 5.0 specifications.</p></li> </ul> <p>The systems with the latest GPUs provide a unified single address space between CPU and GPU for some or all memory regions, as detailed in the <a class="reference internal" href="#acc-mem-unified"><span class="std std-ref">Managed and Unified Memory Modes</span></a> subsection below. In these systems data can be accessed from host and accelerator subprograms without the need for explicit data movement.</p> <p>The NVIDIA HPC Compilers support the following system memory modes:</p> <table class="table-no-stripes colwidths-given docutils align-default" id="id23"> <caption><span class="caption-text">Table 12. GPU Memory Modes</span><a class="headerlink" href="#id23" title="Permalink to this table"></a></caption> <colgroup> <col style="width: 20%" /> <col style="width: 60%" /> <col style="width: 20%" /> </colgroup> <thead> <tr class="row-odd"><th class="head"><p>Memory Mode</p></th> <th class="head"><p>Description</p></th> <th class="head"><p>Compiler flags</p></th> </tr> </thead> <tbody> <tr class="row-even"><td><p>Separate</p></td> <td><p>All data accessed in host and accelerator programs are in separate (CPU and GPU) memories. Data in the application need to be physically moved between CPU and GPU memory either by adding explicit annotations or by relying on a compiler to detect and migrate the data.</p></td> <td><p><code class="docutils literal notranslate"><span class="pre">-gpu=mem:separate</span></code></p></td> </tr> <tr class="row-odd"><td><p>Managed</p></td> <td><p>Dynamically allocated host data are placed in CUDA Managed Memory which is a unified single address space between host and accelerator programs and can therefore be accessed on device without explicit data movement. All other data (host, stack, or global data) remain in separate memory.</p></td> <td><p><code class="docutils literal notranslate"><span class="pre">-gpu=mem:managed</span></code></p></td> </tr> <tr class="row-even"><td><p>Unified</p></td> <td><p>All host data are placed in a unified single address space between the host and accelerator subprograms; no explicit data movements are required. This mode is intended for targets with full CUDA Unified Memory capability and it may utilize CUDA Managed Memory for dynamic allocations.</p></td> <td><p><code class="docutils literal notranslate"><span class="pre">-gpu=mem:unified</span></code></p></td> </tr> </tbody> </table> <p>If the memory mode is not selected explicitly by passing one of the above <code class="docutils literal notranslate"><span class="pre">-gpu=mem:*</span></code> options, the compiler selects a default memory mode. The default memory mode for Stdpar is explained in <a class="reference internal" href="#stdpar-use"><span class="std std-ref">Using Stdpar</span></a>. When Stdpar is not enabled, the default memory mode is Separate Memory. Memory modes may have specific semantics in each programming language and the compilers can sometimes implicitly determine the data movement that’s required. More details can be found in the subsections of each programming model.</p> <p>The following options <code class="docutils literal notranslate"><span class="pre">-gpu=[no]managed</span></code>, <code class="docutils literal notranslate"><span class="pre">-gpu=[no]unified</span></code> and <code class="docutils literal notranslate"><span class="pre">-gpu=pinned</span></code> are deprecated but still accepted. Refer to <a class="reference internal" href="#gpu-mem-flags"><span class="std std-ref">Command-line Options Selecting Compiler Memory Modes</span></a> for compatibility between the current and deprecated memory specific flags.</p> <p>The compiler implicitly defines the following macros corresponding to the memory mode it compiles for:</p> <ul class="simple"> <li><p>When the code is compiled for Separate Memory Mode, the compiler defines <code class="docutils literal notranslate"><span class="pre">__NVCOMPILER_GPU_SEPARATE_MEM</span></code> macro.</p></li> <li><p>When the code is compiled for Managed Memory Mode, the compiler defines <code class="docutils literal notranslate"><span class="pre">__NVCOMPILER_GPU_MANAGED_MEM</span></code> macro.</p></li> <li><p>When the code is compiled for Unified Memory Mode, the compiler defines <code class="docutils literal notranslate"><span class="pre">__NVCOMPILER_GPU_UNIFIED_MEM</span></code> macro. If CUDA Managed Memory is utilised, the compiler defines additionally <code class="docutils literal notranslate"><span class="pre">__NVCOMPILER_GPU_MANAGED_MEM</span></code>.</p></li> </ul> <p>When a binary is compiled for one memory mode it may need to be run on a system with specific memory capabilities as follows:</p> <ul class="simple"> <li><p>Applications compiled for Separate Memory Mode can run on any CUDA platforms.</p></li> <li><p>Applications compiled for Managed Memory Mode must be run on platforms with CUDA Managed Memory or full CUDA Unified Memory capabilities.</p></li> <li><p>Applications compiled for Unified Memory Mode must be run on platforms with full CUDA Unified Memory.</p></li> </ul> <div class="admonition note"> <p class="admonition-title">Note</p> <p>Memory allocated in the accelerator subprogram can’t be accessed or deallocated from the host.</p> </div> <section id="separate-host-and-accelerator-memory-considerations"> <h3><span class="section-number">5.4.1. </span>Separate Host and Accelerator Memory Considerations<a class="headerlink" href="#separate-host-and-accelerator-memory-considerations" title="Permalink to this headline"></a></h3> <p>The programmer must be aware of the potentially separate memories for many reasons, including but not limited to:</p> <ul class="simple"> <li><p>Memory bandwidth between host memory and accelerator memory determines the compute intensity required to effectively accelerate a given region of code.</p></li> <li><p>Limited size of accelerator memory may prohibit offloading of regions of code that operate on very large amounts of data.</p></li> </ul> <section id="accelerator-memory"> <h4><span class="section-number">5.4.1.1. </span>Accelerator Memory<a class="headerlink" href="#accelerator-memory" title="Permalink to this headline"></a></h4> <p>On the accelerator side, current GPUs implement a weak memory model. In particular, they do not support memory coherence between threads unless those threads are parallel only at the synchronous level and the memory operations are separated by an explicit barrier. Otherwise, if one thread updates a memory location and another reads the same location, or two threads store a value to the same location, the hardware does not guarantee the results. While the results of running such a program might be inconsistent, it is not accurate to say that the results are incorrect. By definition, such programs are defined as being in error. While a compiler can detect some potential errors of this nature, it is nonetheless possible to write an accelerator region that produces inconsistent numerical results.</p> <p>Stack data in accelerator subprograms are allocated per thread. Stack data from one thread are not accessible by the other threads.</p> </section> <section id="staging-memory-buffer"> <h4><span class="section-number">5.4.1.2. </span>Staging Memory Buffer<a class="headerlink" href="#staging-memory-buffer" title="Permalink to this headline"></a></h4> <p>Memory transfers between the accelerator and host may not always be asynchronous with respect to the host, even if the chosen programming model (for instance, OpenACC) declares that. This limitation may be due to the specific GPU and host memory architectures.</p> <p>In order to help the host program proceed while a memory transfer to or from the accelerator is underway, the NVIDIA HPC Compilers Runtime maintains a designated staging memory area, also known as a pinned buffer. This memory area is registered with the CUDA API, which makes it suitable for asynchronous memory transfers between the GPU and the host. When an asynchronous memory transfer is started, the data being transferred is staged through the pinned buffer. Multiple asynchronous operations on the same data can be issued - in that case, the runtime system will operate on the data staged in the pinned buffer, not on the original host memory. When the host program issues an explicit or implicit synchronization request, the data is moved from the pinned buffer to its destination transparently to the application.</p> <p>The runtime has the discretion to enable or disable the pinned buffer depending on the host and GPU memory architecture. Also, the size of the pinned buffer is determined by the runtime system as appropriate. The user can control some of these decisions using environment variables at the start of the application. Please refer to <a class="reference internal" href="#env-vars-memory"><span class="std std-ref">Environment Variables Controlling Device Memory Management</span></a> to learn more.</p> </section> <section id="cache-management"> <h4><span class="section-number">5.4.1.3. </span>Cache Management<a class="headerlink" href="#cache-management" title="Permalink to this headline"></a></h4> <p>Some current GPUs have a software-managed cache, some have hardware-managed caches, and most have hardware caches that can be used only in certain situations and are limited to read-only data. In low-level programming models such as CUDA, it is up to the programmer to manage these caches. The OpenACC programming model provides directives the programmer can use as hints to the compiler for cache management.</p> <span class="target" id="env-vars-memory"></span></section> <section id="environment-variables-controlling-device-memory-management"> <h4><span class="section-number">5.4.1.4. </span>Environment Variables Controlling Device Memory Management<a class="headerlink" href="#environment-variables-controlling-device-memory-management" title="Permalink to this headline"></a></h4> <p>This section summarizes the environment variables that NVIDIA HPC Compilers use to control device memory management.</p> <p>The following table contains the environment variables that are currently supported and provides a brief description of each.</p> <table class="table-no-stripes docutils align-default" id="id24"> <caption><span class="caption-text">Table 13. Memory Management Environment Variables</span><a class="headerlink" href="#id24" title="Permalink to this table"></a></caption> <colgroup> <col style="width: 9%" /> <col style="width: 91%" /> </colgroup> <thead> <tr class="row-odd"><th class="head"><p>Environment Variable</p></th> <th class="head"><p>Use</p></th> </tr> </thead> <tbody> <tr class="row-even"><td><p>NVCOMPILER_ACC_BUFFERSIZE</p></td> <td><p>For NVIDIA CUDA devices, this defines the size of the pinned buffer used to transfer data between host and device.</p></td> </tr> <tr class="row-odd"><td><p>NVCOMPILER_ACC_CUDA_CTX_SCHED</p></td> <td><p>For NVIDIA CUDA devices, sets flags to be used when creating a new CUDA context. By default, the <code class="docutils literal notranslate"><span class="pre">CU_CTX_SCHED_YIELD</span></code> flag is used. Please refer to the <a class="reference external" href="https://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__CTX.html#group__CUDA__CTX">CUDA Toolkit Documentation</a> for the detailed description of the <code class="docutils literal notranslate"><span class="pre">cuCtxCreate</span></code> function and the possible flag values.</p></td> </tr> <tr class="row-even"><td><p>NVCOMPILER_ACC_CUDA_HEAPSIZE</p></td> <td><p>For NVIDIA CUDA devices, sets the heap size limit for <code class="docutils literal notranslate"><span class="pre">malloc()</span></code> when called on device.</p></td> </tr> <tr class="row-odd"><td><p>NVCOMPILER_ACC_CUDA_MAX_L2_FETCH_GRANULARITY</p></td> <td><p>For NVIDIA CUDA devices, sets the maximum L2 cache fetch granularity size in bytes. A correct value is an integer between 0 and 128.</p></td> </tr> <tr class="row-even"><td><p>NVCOMPILER_ACC_CUDA_MEMALLOCASYNC</p></td> <td><p>For NVIDIA CUDA devices, when set to a non-zero integer value, enables CUDA asynchronous memory allocations from the default CUDA memory pool as descibed in the <a class="reference external" href="https://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MALLOC__ASYNC.html">CUDA Toolkit Documentation</a>. By default, an internal NVIDIA HPC Runtime memory pool is used instead.</p></td> </tr> <tr class="row-odd"><td><p>NVCOMPILER_ACC_CUDA_MEMALLOCASYNC_POOLSIZE</p></td> <td><p>For NVIDIA CUDA devices, sets the size of the default CUDA memory pool for asynchronous allocations if the <code class="docutils literal notranslate"><span class="pre">NVCOMPILER_ACC_CUDA_MEMALLOCASYNC</span></code> environment variable is also set to a non-zero integer value.</p></td> </tr> <tr class="row-even"><td><p>NVCOMPILER_ACC_CUDA_NOCOPY</p></td> <td><p>Disables the use of the pinned buffer when transferring user data between host and NVIDIA CUDA devices. When this variable is set to a non-zero integer value, user data will be transferred directly bypassing the pinned buffer. Asynchronous execution of such data transfers can be limited when this setting is in effect.</p></td> </tr> <tr class="row-odd"><td><p>NVCOMPILER_ACC_CUDA_PIN</p></td> <td><p>For NVIDIA CUDA devices, enables host memory pinning at data directives. When host memory is pinned, data transfers to and from the device can be asynchronous, which can potentially improve program performance. A non-zero integer value enables this mechanism. A value of <code class="docutils literal notranslate"><span class="pre">2</span></code> or greater additionally disallows unpinning the host data after it is pinned. A value of <code class="docutils literal notranslate"><span class="pre">3</span></code> or greater also enables pinning the whole array referenced in a data directive (provided that the size of the array is known), rather than its subarray specified in the data directive. By default, host data referenced at data directives is not pinned unless directed by the compiler at compile-time; refer to <a class="reference internal" href="#gpu-mem-flags"><span class="std std-ref">Command-line Options Selecting Compiler Memory Modes</span></a> for more information about the compile-time memory modes.</p></td> </tr> <tr class="row-even"><td><p>NVCOMPILER_ACC_CUDA_PINSIZE</p></td> <td><p>For NVIDIA CUDA devices, sets the host memory pinning granularity. If host memory pinning is enabled with the <code class="docutils literal notranslate"><span class="pre">NVCOMPILER_ACC_CUDA_PIN</span></code> environment variable, the runtime will attempt to use this setting to pin larger regions of memory at once, thus potentially lowering the cost of pinning memory when the program needs to pin multiple data regions separately. The maximum allowed value is 1 MB. By default, single byte pinning granularity is used.</p></td> </tr> <tr class="row-odd"><td><p>NVCOMPILER_ACC_CUDA_PRINTFIFOSIZE</p></td> <td><p>For NVIDIA CUDA devices, sets the buffer size for formatted output calls on device. In particular, it controls the buffer size for the <code class="docutils literal notranslate"><span class="pre">printf</span></code> C function.</p></td> </tr> <tr class="row-even"><td><p>NVCOMPILER_ACC_CUDA_STACKSIZE</p></td> <td><p>For NVIDIA CUDA devices, sets the stack size limit for device threads.</p></td> </tr> <tr class="row-odd"><td><p>NVCOMPILER_ACC_DEV_MEMORY</p></td> <td><p>For NVIDIA CUDA devices, when set to a valid non-zero size value, enables the use of a device memory pool and sets its size. By default, the device memory pool is not used.</p></td> </tr> <tr class="row-even"><td><p>NVCOMPILER_ACC_MEM_MANAGE</p></td> <td><p>For NVIDIA CUDA devices, when set to the integer value 0, disables the use of an internal device memory manager. By default, the device memory manager is enabled. It maintains a list of deallocated chunks of device memory in an attempt to efficiently reuse them for future allocations.</p></td> </tr> </tbody> </table> <span class="target" id="acc-mem-unified"></span></section> </section> <section id="managed-and-unified-memory-modes"> <h3><span class="section-number">5.4.2. </span>Managed and Unified Memory Modes<a class="headerlink" href="#managed-and-unified-memory-modes" title="Permalink to this headline"></a></h3> <p>The NVIDIA HPC Compilers support interoperability with <a class="reference external" href="https://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#unified-memory-programming">CUDA Unified Memory</a>. This feature is available with the x86-64 and Arm Server compilers. Unified memory provides a single address space for CPU and GPU; data movement between CPU and GPU memories is implicitly handled by the NVIDIA CUDA driver.</p> <p>Whenever data is accessed on the CPU or the GPU, it could trigger a data transfer if the last time it was accessed was not on the same device. In some cases, page thrashing may occur and impact performance. An introduction to CUDA Unified Memory is available on <a class="reference external" href="https://devblogs.nvidia.com/parallelforall/unified-memory-cuda-beginners">Parallel Forall</a>.</p> <section id="managed-memory-mode"> <h4><span class="section-number">5.4.2.1. </span>Managed Memory Mode<a class="headerlink" href="#managed-memory-mode" title="Permalink to this headline"></a></h4> <p>In Managed Memory Mode, all Fortran, C++ and C explicit allocation statements (e.g. <code class="docutils literal notranslate"><span class="pre">allocate</span></code>, <code class="docutils literal notranslate"><span class="pre">new</span></code>, and <code class="docutils literal notranslate"><span class="pre">malloc</span></code>, respectively) in a program unit are replaced by equivalent CUDA managed data allocation calls that place the data in CUDA Managed Memory. The result is that OpenACC and OpenMP data clauses and directives are not needed to manage data movement. They are essentially ignored and can be omitted. For Stdpar this is the minimal required memory mode since there are no specific annotations for data used in the parallel region.</p> <p>To enable Managed Memory Mode, add the option <code class="docutils literal notranslate"><span class="pre">-gpu=mem:managed</span></code> to the compiler and linker command lines.</p> <p>When a program allocates managed memory, it allocates host pinned memory as well as device memory thus making allocate and free operations somewhat more expensive and data transfers somewhat faster. A memory pool allocator is used to mitigate the overhead of the allocate and deallocate operations. More details can be found in <a class="reference internal" href="#gpu-mem-poolallocator"><span class="std std-ref">Memory Pool Allocator</span></a>.</p> <p>Managed Memory Mode has the following limitations:</p> <ul class="simple"> <li><p>Use of managed memory applies only to dynamically-allocated data.</p></li> <li><p>Given an allocatable aggregate with a member that points to local, global, or static data, compiling with <code class="docutils literal notranslate"><span class="pre">-gpu=mem:managed</span></code> and attempting to access memory through that pointer from the compute kernel will cause a failure at runtime.</p></li> <li><p>C++ virtual functions are not supported.</p></li> <li><p>The <code class="docutils literal notranslate"><span class="pre">-gpu=mem:managed</span></code> compiler option must be used to compile the files in which variables (accessed from GPU) are allocated, even if there is no code to accelerate on the GPU in the source file.</p></li> <li><p>When linking multiple translation units, the application must ensure that all data are deallocated using the scheme corresponding to their allocation. For example if the data are allocated in managed memory the deallocation must be performed using CUDA API calls for managed memory. More details and extra compiler support is detailed in <a class="reference internal" href="#gpu-mem-intercept"><span class="std std-ref">Interception of Deallocations</span></a>.</p></li> </ul> <p>Managed Memory Mode has the following additional limitations when used with NVIDIA Kepler GPUs:</p> <ul class="simple"> <li><p>Data motion on Kepler GPUs is achieved through fast pinned asynchronous data transfers; from the program’s perspective, however, the transfers are synchronous.</p></li> <li><p>The NVIDIA HPC Compiler Runtime enforces synchronous execution of kernels when <code class="docutils literal notranslate"><span class="pre">-gpu=mem:managed</span></code> is used on a system with a Kepler GPU. This situation may result in slower performance because of the extra synchronizations and decreased overlap between CPU and GPU.</p></li> <li><p>The total amount of managed memory is limited to the amount of available device memory on Kepler GPUs.</p></li> </ul> <p><strong>Memory Allocations/Deallocations Automatically Changed to Managed Memory</strong></p> <p>When the compiler utilizes CUDA Managed Memory capability either with <code class="docutils literal notranslate"><span class="pre">-gpu=mem:managed</span></code> or <code class="docutils literal notranslate"><span class="pre">-gpu=mem:unified</span></code>, the following explicit allocations/deallocations are automatically changed into <code class="docutils literal notranslate"><span class="pre">cudaMallocManaged</span></code>/<code class="docutils literal notranslate"><span class="pre">cudaFree</span></code>-type allocations/deallocations:</p> <ul> <li><p>For C++:</p> <ul> <li><p>All calls to global <code class="docutils literal notranslate"><span class="pre">operator</span> <span class="pre">new</span></code> and <code class="docutils literal notranslate"><span class="pre">operator</span> <span class="pre">delete</span></code> that allocate or deallocate memory, such as:</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="k">operator</span><span class="w"> </span><span class="k">new</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="kt">size_t</span><span class="w"> </span><span class="n">size</span><span class="p">)</span><span class="w"></span> <span class="k">operator</span><span class="w"> </span><span class="k">new</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="kt">size_t</span><span class="w"> </span><span class="n">size</span><span class="p">,</span><span class="w"> </span><span class="k">const</span><span class="w"> </span><span class="n">std</span><span class="o">::</span><span class="n">nothrow_t</span><span class="w"> </span><span class="o">&amp;</span><span class="n">nothrow_value</span><span class="p">)</span><span class="w"></span> <span class="k">operator</span><span class="w"> </span><span class="k">new</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="kt">size_t</span><span class="w"> </span><span class="n">size</span><span class="p">,</span><span class="w"> </span><span class="n">std</span><span class="o">::</span><span class="n">align_val_t</span><span class="w"> </span><span class="n">align</span><span class="p">)</span><span class="w"></span> <span class="k">operator</span><span class="w"> </span><span class="k">new</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="kt">size_t</span><span class="w"> </span><span class="n">size</span><span class="p">,</span><span class="w"> </span><span class="n">std</span><span class="o">::</span><span class="n">align_val_t</span><span class="w"> </span><span class="n">align</span><span class="p">,</span><span class="w"> </span><span class="k">const</span><span class="w"> </span><span class="n">std</span><span class="o">::</span><span class="n">nothrow_t</span><span class="w"> </span><span class="o">&amp;</span><span class="n">nothrow_value</span><span class="p">)</span><span class="w"></span> <span class="k">operator</span><span class="w"> </span><span class="k">delete</span><span class="p">(</span><span class="kt">void</span><span class="w"> </span><span class="o">*</span><span class="n">p</span><span class="p">)</span><span class="w"></span> <span class="k">operator</span><span class="w"> </span><span class="k">delete</span><span class="p">(</span><span class="kt">void</span><span class="w"> </span><span class="o">*</span><span class="n">p</span><span class="p">,</span><span class="w"> </span><span class="n">std</span><span class="o">::</span><span class="kt">size_t</span><span class="w"> </span><span class="n">size</span><span class="p">)</span><span class="w"></span> <span class="k">operator</span><span class="w"> </span><span class="k">delete</span><span class="p">(</span><span class="kt">void</span><span class="w"> </span><span class="o">*</span><span class="n">p</span><span class="p">,</span><span class="w"> </span><span class="n">std</span><span class="o">::</span><span class="n">align_val_t</span><span class="w"> </span><span class="n">align</span><span class="p">)</span><span class="w"></span> <span class="k">operator</span><span class="w"> </span><span class="k">delete</span><span class="p">(</span><span class="kt">void</span><span class="w"> </span><span class="o">*</span><span class="n">p</span><span class="p">,</span><span class="w"> </span><span class="n">std</span><span class="o">::</span><span class="kt">size_t</span><span class="w"> </span><span class="n">size</span><span class="p">,</span><span class="w"> </span><span class="n">std</span><span class="o">::</span><span class="n">align_val_t</span><span class="w"> </span><span class="n">align</span><span class="p">)</span><span class="w"></span> <span class="k">operator</span><span class="w"> </span><span class="k">delete</span><span class="p">(</span><span class="kt">void</span><span class="w"> </span><span class="o">*</span><span class="n">p</span><span class="p">,</span><span class="w"> </span><span class="k">const</span><span class="w"> </span><span class="n">std</span><span class="o">::</span><span class="n">nothrow_t</span><span class="w"> </span><span class="o">&amp;</span><span class="n">nothrow_value</span><span class="p">)</span><span class="w"></span> <span class="k">operator</span><span class="w"> </span><span class="k">delete</span><span class="p">(</span><span class="kt">void</span><span class="w"> </span><span class="o">*</span><span class="n">p</span><span class="p">,</span><span class="w"> </span><span class="n">std</span><span class="o">::</span><span class="n">align_val_t</span><span class="w"> </span><span class="n">align</span><span class="p">,</span><span class="w"> </span><span class="k">const</span><span class="w"> </span><span class="n">std</span><span class="o">::</span><span class="n">nothrow_t</span><span class="w"> </span><span class="o">&amp;</span><span class="n">nothrow_value</span><span class="p">)</span><span class="w"></span> </pre></div> </div> </li> <li><p>All the array forms of the above overloads.</p></li> <li><p>All calls to <code class="docutils literal notranslate"><span class="pre">malloc</span></code>/<code class="docutils literal notranslate"><span class="pre">free</span></code> functions.</p></li> </ul> </li> <li><p>For C: all calls to <code class="docutils literal notranslate"><span class="pre">malloc</span></code>/<code class="docutils literal notranslate"><span class="pre">free</span></code> functions.</p></li> <li><p>For Fortran:</p> <ul class="simple"> <li><p>All allocations of automatic arrays.</p></li> <li><p>all <code class="docutils literal notranslate"><span class="pre">allocate</span></code>/<code class="docutils literal notranslate"><span class="pre">deallocate</span></code> statements with allocatable arrays or pointer variables.</p></li> </ul> </li> </ul> </section> <section id="unified-memory-mode"> <h4><span class="section-number">5.4.2.2. </span>Unified Memory Mode<a class="headerlink" href="#unified-memory-mode" title="Permalink to this headline"></a></h4> <p>In Unified Memory Mode, the requirements for the program are further relaxed compared to Managed Memory Mode. Specifically, not only is dynamically allocated system memory accessible on the GPU, but global and local memory are also accessible.</p> <p>To enable this feature, add the option <code class="docutils literal notranslate"><span class="pre">-gpu=mem:unified</span></code> to the compiler and linker command lines.</p> <p>Programs compiled with <code class="docutils literal notranslate"><span class="pre">-gpu=mem:unified</span></code> must be run on systems that support full CUDA Unified Memory capability. At this time, full CUDA Unified Memory is supported on NVIDIA Grace Hopper Superchip systems and Linux x86-64 systems running with the Heterogeneous Memory Management (HMM) feature enabled in the Linux kernel. Details about these platforms are available in the following blog posts on the NVIDIA website: <a class="reference external" href="https://developer.nvidia.com/blog/simplifying-gpu-programming-for-hpc-with-the-nvidia-grace-hopper-superchip">Simplifying GPU Programming for HPC with NVIDIA Grace Hopper Superchip</a> and <a class="reference external" href="https://developer.nvidia.com/blog/simplifying-gpu-application-development-with-heterogeneous-memory-management">Simplifying GPU Application Development with Heterogeneous Memory Management</a>.</p> <p>In Unified Memory Mode, the compiler assumes that any system memory is accessible on the GPU. Even so, the compiler may generate managed memory allocations for explicit data allocations when it considers them beneficial for program performance. If you would like to enforce or prohibit the use of managed memory for dynamic allocations pass <code class="docutils literal notranslate"><span class="pre">-gpu=mem:unified:[no]managedalloc</span></code> to compilation and linking.</p> <p>Unified Memory Mode has the following limitations:</p> <ul class="simple"> <li><p>Unified memory support for OpenACC, OpenMP and Stdpar Fortran is not mix-and-match; all object files containing OpenACC/OpenMP directives or Fortran <code class="docutils literal notranslate"><span class="pre">DO</span> <span class="pre">CONCURRENT</span></code> constructs must be compiled and linked with <code class="docutils literal notranslate"><span class="pre">-gpu=mem:unified</span></code> to ensure correct execution.</p></li> <li><p>C++ virtual functions are not supported.</p></li> </ul> <p><strong>Transitioning to Unified Memory Mode</strong></p> <p>Applications transitioning to architectures that support Unified Memory Mode can be recompiled with <code class="docutils literal notranslate"><span class="pre">-gpu=mem:unified</span></code> without any code modifications.</p> <p>The programmer should be aware that in Unified Memory Mode, the whole program state becomes essentially shared between the CPU and the GPU. By implication, modifications to program variables made on the GPU are visible on the CPU. That is, the GPU does not operate on a copy of the data even if the program contains respective directives, but instead the GPU operates directly on the data in system memory. To understand the importance of this idea, consider the following OpenACC C program:</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="kt">int</span><span class="w"> </span><span class="n">x</span><span class="p">[</span><span class="n">N</span><span class="p">];</span><span class="w"></span> <span class="kt">void</span><span class="w"> </span><span class="nf">foo</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="cp">#pragma acc enter data create(x[0:N])</span> <span class="w"> </span><span class="cp">#pragma acc parallel loop</span> <span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="kt">int</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="n">N</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="o">++</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="n">x</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">i</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="p">}</span><span class="w"></span> <span class="p">}</span><span class="w"></span> </pre></div> </div> <p>When compiled in Separate Memory Mode, in the <code class="docutils literal notranslate"><span class="pre">foo()</span></code> function a copy of the array <code class="docutils literal notranslate"><span class="pre">x</span></code> is created in GPU memory and initialized as written in the <code class="docutils literal notranslate"><span class="pre">loop</span></code> construct. When <code class="docutils literal notranslate"><span class="pre">-gpu=mem:unified</span></code> is added, however, the compiler ignores the <code class="docutils literal notranslate"><span class="pre">acc</span> <span class="pre">enter</span> <span class="pre">data</span></code> construct, and the <code class="docutils literal notranslate"><span class="pre">loop</span></code> construct initializes the array <code class="docutils literal notranslate"><span class="pre">x</span></code> in system memory.</p> <p>Another implication of which to be aware, <em>asynchronous</em> code execution on the GPU can introduce race conditions over access to program data. More details about code patterns to avoid when writing application sources for Unified Memory Mode can be found in the sections about specific programming models of this guide e.g. OpenACC, OpenMP, or CUDA Fortran.</p> <span class="target" id="gpu-mem-poolallocator"></span></section> </section> <section id="memory-pool-allocator"> <h3><span class="section-number">5.4.3. </span>Memory Pool Allocator<a class="headerlink" href="#memory-pool-allocator" title="Permalink to this headline"></a></h3> <p>Dynamic memory allocations may be made using <code class="docutils literal notranslate"><span class="pre">cudaMallocManaged()</span></code>, a routine which has higher overhead than allocating non-managed memory using <code class="docutils literal notranslate"><span class="pre">cudaMalloc()</span></code>. The more calls to <code class="docutils literal notranslate"><span class="pre">cudaMallocManaged()</span></code>, the more significant the impact on performance.</p> <p>To mitigate the overhead of <code class="docutils literal notranslate"><span class="pre">cudaMallocManaged()</span></code> or other CUDA allocation API calls, there is a pool allocator enabled by default in the presence of the <code class="docutils literal notranslate"><span class="pre">-gpu=mem:managed</span></code>, <code class="docutils literal notranslate"><span class="pre">-gpu=mem:separate:pinnedalloc</span></code>, or <code class="docutils literal notranslate"><span class="pre">-gpu=mem:unified</span></code> compiler options. It can be disabled, or its behavior modified, using these environment variables:</p> <table class="table-no-stripes docutils align-default" id="id25"> <caption><span class="caption-text">Table 14. Pool Allocator Environment Variables</span><a class="headerlink" href="#id25" title="Permalink to this table"></a></caption> <colgroup> <col style="width: 9%" /> <col style="width: 91%" /> </colgroup> <thead> <tr class="row-odd"><th class="head"><p>Environment Variable</p></th> <th class="head"><p>Use</p></th> </tr> </thead> <tbody> <tr class="row-even"><td><p>NVCOMPILER_ACC_POOL_ALLOC</p></td> <td><p>Disable the pool allocator. The pool allocator is enabled by default; to disable it, set NVCOMPILER_ACC_POOL_ALLOC to 0.</p></td> </tr> <tr class="row-odd"><td><p>NVCOMPILER_ACC_POOL_SIZE</p></td> <td><p>Set the of the pool. The default size is 1GB but other sizes (i.e., 2GB, 100MB, 500KB, etc.) can be used. The actual pool size is set such that the size is the nearest, smaller number in the Fibonacci series compared to the provided or default size. If necessary, the pool allocator will add more pools but only up to the NVCOMPILER_ACC_POOL_THRESHOLD value.</p></td> </tr> <tr class="row-even"><td><p>NVCOMPILER_ACC_POOL_ALLOC_MAXSIZE</p></td> <td><p>Set the maximum size for allocations. The default maximum size for allocations is 500MB but another size (i.e., 100KB, 10MB, 250MB, etc.) can be used as long as it is greater than or equal to 16B.</p></td> </tr> <tr class="row-odd"><td><p>NVCOMPILER_ACC_POOL_ALLOC_MINSIZE</p></td> <td><p>Set the minimum size for allocation blocks. The default size is 128B but other sizes can be used. The size must be greater than or equal to 16B.</p></td> </tr> <tr class="row-even"><td><p>NVCOMPILER_ACC_POOL_THRESHOLD</p></td> <td><p>Set the percentage of total device memory that the pool allocator can occupy. Values from 0 to 100 are accepted. The default value is 50, corresponding to 50% of device memory.</p></td> </tr> </tbody> </table> <div class="admonition note"> <p class="admonition-title">Note</p> <p>Note that where the size is specified if the unit suffix (B, KB, MB or GB) is ommited, the value is set by default in bytes.</p> </div> <span class="target" id="gpu-mem-intercept"></span></section> <section id="interception-of-deallocations"> <h3><span class="section-number">5.4.4. </span>Interception of Deallocations<a class="headerlink" href="#interception-of-deallocations" title="Permalink to this headline"></a></h3> <p>While NVIDIA HPC Compilers facilitate the use of managed or pinned memory automatically, the application must ensure that memory is deallocated using the API which “matches” the API used to allocate said memory. For example, if <code class="docutils literal notranslate"><span class="pre">cudaMallocManaged</span></code> is used to allocate, then <code class="docutils literal notranslate"><span class="pre">cudaFree</span></code> must be used to deallocate; if <code class="docutils literal notranslate"><span class="pre">cudaMallocHost</span></code> is used for allocations, <code class="docutils literal notranslate"><span class="pre">cudaFreeHost</span></code> must be used for deallocations. Understanding this requirement is particularly important when third party or standard libraries are used; these libraries may have been compiled without any memory mode settings which sets up a situation where the deallocation routines in the libraries may not match the allocations made. When data is deallocated with an unmatching API call, the application may exhibit undefined behavior including crashing. To mitigate this issue, the compiler supports an interception mode in which calls to the standard deallocation function (e.g. free in C, delete in C++, or deallocate in Fortran) are inspected by the runtime and, if the memory is not detected as being system-allocated, the runtime replaces the standard deallocation function with the deallocation API corresponding to the allocation scheme in use. To activate this interception mode, use the <code class="docutils literal notranslate"><span class="pre">-gpu=interceptdeallocations</span></code> compiler flag. The interception is enabled by default for Stdpar in the presence of managed memory allocations. To deactivate the interception use the <code class="docutils literal notranslate"><span class="pre">-gpu=nointerceptdeallocations</span></code> compiler switch. This interception can incur extra runtime overhead.</p> <span class="target" id="gpu-mem-flags"></span></section> <section id="command-line-options-selecting-compiler-memory-modes"> <h3><span class="section-number">5.4.5. </span>Command-line Options Selecting Compiler Memory Modes<a class="headerlink" href="#command-line-options-selecting-compiler-memory-modes" title="Permalink to this headline"></a></h3> <p>The following table maps the new memory model flags to their deprecated equivalents.</p> <table class="table-no-stripes colwidths-given docutils align-default" id="id26"> <caption><span class="caption-text">Table 15. Command-line Options Corresponding to Compiler Memory Modes</span><a class="headerlink" href="#id26" title="Permalink to this table"></a></caption> <colgroup> <col style="width: 29%" /> <col style="width: 29%" /> <col style="width: 43%" /> </colgroup> <thead> <tr class="row-odd"><th class="head"><p>Current Flags</p></th> <th class="head"><p>Deprecated Flags</p></th> <th class="head"><p>Brief Description</p></th> </tr> </thead> <tbody> <tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">-gpu=mem:managed</span></code></p></td> <td><p><code class="docutils literal notranslate"><span class="pre">-gpu=managed</span></code></p></td> <td><p>Managed Memory Mode</p></td> </tr> <tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">-gpu=mem:managed</span> <span class="pre">-stdpar</span></code></p></td> <td><p><code class="docutils literal notranslate"><span class="pre">-gpu=nounified</span> <span class="pre">-stdpar</span></code></p></td> <td><p>Managed Memory Mode</p></td> </tr> <tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">-gpu=mem:unified</span></code></p></td> <td><p><code class="docutils literal notranslate"><span class="pre">-gpu=unified</span></code></p></td> <td><p>Unified Memory Mode</p></td> </tr> <tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">-gpu=mem:unified:managedalloc</span></code></p></td> <td><p><code class="docutils literal notranslate"><span class="pre">-gpu=unified,managed</span></code></p></td> <td><p>Unified Memory Mode, all dynamically allocated data are implicitly in CUDA Managed Memory.</p></td> </tr> <tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">-gpu=mem:unified:nomanagedalloc</span></code></p></td> <td><p><code class="docutils literal notranslate"><span class="pre">-gpu=unified,nomanaged</span></code></p></td> <td><p>Unified Memory Mode, CUDA Managed Memory is not used implicitly.</p></td> </tr> <tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">-gpu=mem:separate</span></code></p></td> <td><p><code class="docutils literal notranslate"><span class="pre">-gpu=nomanaged</span></code></p></td> <td><p>Separate Memory Mode</p></td> </tr> <tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">-gpu=mem:separate</span></code></p></td> <td><p><code class="docutils literal notranslate"><span class="pre">-gpu=nounified</span></code></p></td> <td><p>Separate Memory Mode</p></td> </tr> <tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">-gpu=mem:separate</span></code></p></td> <td><p><code class="docutils literal notranslate"><span class="pre">-gpu=nomanaged,nounified</span></code></p></td> <td><p>Separate Memory Mode</p></td> </tr> <tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">-gpu=mem:separate:pinnedalloc</span></code></p></td> <td><p><code class="docutils literal notranslate"><span class="pre">-gpu=pinned</span></code></p></td> <td><p>Separate Memory Mode, dynamically allocated data are in CPU pinned memory implicitly.</p></td> </tr> </tbody> </table> </section> </section> <section id="fortran-pointers-in-device-code"> <h2><span class="section-number">5.5. </span>Fortran pointers in device code<a class="headerlink" href="#fortran-pointers-in-device-code" title="Permalink to this headline"></a></h2> <p>A Fortran pointer variable is implemented with a pointer and a descriptor, where the descriptor (often called a “dope vector”) holds the array bounds and strides for each dimension, among other information, such as the size for each element and whether the pointer is associated. A Fortran scalar pointer has no bounds information, but does have a minimal descriptor. In Fortran, referring to the pointer variable always refers to the pointer target. There is no syntax to explicitly refer to the pointer and descriptor that implement the pointer variable.</p> <p>Fortran allocatable arrays and variables are implemented much the same way as pointer arrays and variables. Much of the discussion below applies both to allocatables and pointers.</p> <p>In OpenACC and OpenMP, when a pointer variable reference appears in a data clause, it’s the pointer target that gets allocated or moved to device memory. The pointer and descriptor are neither allocated nor moved.</p> <p>When a pointer variable is declared in a module declaration section and appears in an <code class="docutils literal notranslate"><span class="pre">!$acc</span> <span class="pre">declare</span> <span class="pre">create()</span></code> or <code class="docutils literal notranslate"><span class="pre">!$omp</span> <span class="pre">declare</span> <span class="pre">target</span> <span class="pre">to()</span></code> directive, then the pointer and descriptor are statically allocated in device memory. When the pointer variable appears in a data clause, the pointer target is allocated or copied to the device, and the pointer and descriptor are ‘attached’ to the device copy of the data. If the pointer target is already present in device memory, no new memory is allocated or copied, but the pointer and descriptor are still ‘attached’, making the pointer valid in device memory. An important side effect of adding <code class="docutils literal notranslate"><span class="pre">declare</span> <span class="pre">create</span></code> in the module declaration section is that when the program executes an ‘allocate’ statement for the pointer (or allocatable), memory is allocated in both CPU and device memory. This means the newly allocated data is already present in device memory. To get values from CPU to device memory or back, you’ll have to use <code class="docutils literal notranslate"><span class="pre">update</span></code> directives.</p> <p>When a pointer variable is used in an OpenACC or OpenMP compute construct, the compiler creates a private copy of the pointer and descriptor for each thread, unless the pointer variable was in a module as described above. The private pointer and descriptor will contain information about the device copy of the pointer target. In the compute construct, the pointer variables may be used pretty much as they can in host code outside a compute construct. However, there are some limitations. The program can do a pointer assignment to the pointer, changing the pointer, but that will only change the private pointer for that thread. The modified pointer in the compute construct will not change the corresponding pointer and descriptor in host memory.</p> </section> <section id="calling-routines-in-a-compute-kernel"> <h2><span class="section-number">5.6. </span>Calling routines in a compute kernel<a class="headerlink" href="#calling-routines-in-a-compute-kernel" title="Permalink to this headline"></a></h2> <p>Using explicit interfaces is a common occurrence when writing Fortran applications. Here are some cases where doing so is required for GPU programming.</p> <ul class="simple"> <li><p>Explicit interfaces are required when using OpenACC <code class="docutils literal notranslate"><span class="pre">routine</span> <span class="pre">bind</span></code> or OpenMP <code class="docutils literal notranslate"><span class="pre">declare</span> <span class="pre">variant</span></code>.</p></li> <li><p>Fortran <code class="docutils literal notranslate"><span class="pre">do</span> <span class="pre">concurrent</span></code> requires routines to be <code class="docutils literal notranslate"><span class="pre">pure</span></code> which creates the need for an explicit interface.</p></li> </ul> </section> <section id="supported-processors-and-gpus"> <h2><span class="section-number">5.7. </span>Supported Processors and GPUs<a class="headerlink" href="#supported-processors-and-gpus" title="Permalink to this headline"></a></h2> <p>This NVIDIA HPC Compilers release supports x86-64 and Arm Server CPUs. Cross-compilation across the different families of CPUs is not supported, but you can use the <code class="docutils literal notranslate"><span class="pre">-⁠tp=&lt;target&gt;</span></code> flag as documented in the man pages to specify a target processor within a family.</p> <p>To direct the compilers to generate code for NVIDIA GPUs, use the <code class="docutils literal notranslate"><span class="pre">-⁠acc</span></code> flag to enable OpenACC directives, the <code class="docutils literal notranslate"><span class="pre">-⁠mp=gpu</span></code> flag to enable OpenMP directives, the <code class="docutils literal notranslate"><span class="pre">-⁠stdpar</span></code> flag for standard language parallelism, and the <code class="docutils literal notranslate"><span class="pre">-cuda</span></code> flag for CUDA Fortran. Use the <code class="docutils literal notranslate"><span class="pre">-⁠gpu</span></code> flag to select specific options for GPU code generation. You can then use the generated code on any supported system with CUDA installed that has a CUDA-enabled GeForce, Quadro, or Tesla card.</p> <p>For more information on these flags as they relate to accelerator technology, refer to <a class="reference internal" href="#acc-cmdln-opts"><span class="std std-ref">Compiling an OpenACC Program</span></a>.</p> <p>For a complete list of supported CUDA GPUs, refer to the NVIDIA website at: <a class="reference external" href="http://www.nvidia.com/object/cuda_learn_products.html">http://www.nvidia.com/object/cuda_learn_products.html</a></p> <span class="target" id="cuda-toolkit-versions"></span></section> <section id="cuda-versions"> <h2><span class="section-number">5.8. </span>CUDA Versions<a class="headerlink" href="#cuda-versions" title="Permalink to this headline"></a></h2> <p>The NVIDIA HPC compilers use components from NVIDIA’s CUDA Toolkit to build programs for execution on an NVIDIA GPU. The NVIDIA HPC SDK puts the CUDA Toolkit components into an HPC SDK installation sub-directory; the HPC SDK currently bundles two versions of recently-released Toolkits.</p> <p>You can compile a program for an NVIDIA GPU on any system supported by the HPC compilers. You will be able to run that program only on a system with an NVIDIA GPU and an installed NVIDIA CUDA driver. NVIDIA HPC SDK products do not contain CUDA device drivers. You must download and install the appropriate <a class="reference external" href="http://www.nvidia.com/cuda">CUDA Driver from NVIDIA</a>.</p> <p>The NVIDIA HPC SDK utility <code class="docutils literal notranslate"><span class="pre">nvaccelinfo</span></code> prints the driver version as its first line of output. You can use it to find out which version of the CUDA Driver is installed on your system.</p> <p>The NVIDIA HPC SDK 25.1 includes components from the following versions of the CUDA Toolkit:</p> <ul class="simple"> <li><p>CUDA 11.8</p></li> <li><p>CUDA 12.4</p></li> </ul> <p>If you are compiling a program for GPU execution on a system <em>without</em> an installed CUDA driver, the compiler selects the version of the CUDA Toolkit to use based on the value of the <code class="docutils literal notranslate"><span class="pre">DEFCUDAVERSION</span></code> variable contained in a file called <code class="docutils literal notranslate"><span class="pre">localrc</span></code> which is created during installation of the HPC SDK.</p> <p>If you are compiling a program for GPU execution on a system <em>with</em> an installed CUDA driver, the compiler detects the version of the CUDA driver and selects the appropriate CUDA Toolkit version to use from those bundled with the HPC SDK.</p> <p>The compilers look for a CUDA Toolkit version in the /opt/nvidia/hpc_sdk/<em>target</em>/25.1/cuda directory that matches the version of the CUDA Driver installed on the system. If an exact match is not found, the compiler searches for the closest match. For CUDA Driver versions 11.2 through 11.8, the compiler will use the CUDA 11.8 Toolkit. For CUDA Driver versions 12.0 and later, the compiler will use the newest CUDA 12.x Toolkit.</p> <p>You can change the compiler’s default selection of CUDA Toolkit version using a compiler option. Add the <code class="docutils literal notranslate"><span class="pre">cudaX.Y</span></code> sub-option to <code class="docutils literal notranslate"><span class="pre">-gpu</span></code> where <code class="docutils literal notranslate"><span class="pre">X.Y</span></code> denotes the CUDA version. Using a compiler option changes the CUDA Toolkit version for one invocation of the compiler. For example, to compile an OpenACC C file with the CUDA 11.8 Toolkit you would use:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>nvc -acc -gpu=cuda11.8 </pre></div> </div> <span class="target" id="compute-cap"></span></section> <section id="compute-capability"> <h2><span class="section-number">5.9. </span>Compute Capability<a class="headerlink" href="#compute-capability" title="Permalink to this headline"></a></h2> <p>The compilers can generate code for NVIDIA GPU compute capabilities 3.5 through 8.6. The compilers construct a default list of compute capabilities that matches the compute capabilities supported by the GPUs found on the system used in compilation. If there are no GPUs detected, the compilers generate code for every supported compute capability.</p> <p>You can override the default by specifying one or more compute capabilities using either command-line options or an <code class="docutils literal notranslate"><span class="pre">rcfile</span></code>.</p> <p>To change the default with a command-line option, provide a comma-separated list of compute capabilities to the <code class="docutils literal notranslate"><span class="pre">-gpu</span></code> option.</p> <p>To change the default with an <code class="docutils literal notranslate"><span class="pre">rcfile</span></code>, set the <code class="docutils literal notranslate"><span class="pre">DEFCOMPUTECAP</span></code> value to a blank-separated list of compute capabilities in the siterc file located in your installation’s bin directory:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>set DEFCOMPUTECAP=60 70; </pre></div> </div> <p>Alternatively, if you don’t have permissions to change the <code class="docutils literal notranslate"><span class="pre">siterc</span></code> file, you can add the <code class="docutils literal notranslate"><span class="pre">DEFCOMPUTECAP</span></code> definition to a separate <code class="docutils literal notranslate"><span class="pre">.mynvrc</span></code> file in your home directory.</p> <p>The generation of device code can be time consuming, so you may notice an increase in compile time as the number of compute capabilities increases.</p> </section> <section id="ptx-jit-compilation"> <h2><span class="section-number">5.10. </span>PTX JIT Compilation<a class="headerlink" href="#ptx-jit-compilation" title="Permalink to this headline"></a></h2> <p>As of HPC SDK 22.9, support for PTX JIT compilation is enabled in all compilers for relocatable device code mode. This means that applications built with <code class="docutils literal notranslate"><span class="pre">-gpu=rdc</span></code> (that is, with relocatable device code enabled, which is the default mode) are forward-compatible with newer GPUs thanks to the embedded PTX code. The embedded PTX code is dynamically compiled when the application runs on a GPU architecture newer than the architecture specified at compile time.</p> <p>The support for PTX JIT compilation is enabled automatically, which means that you do not need to change the compiler invocation command lines for your existing projects.</p> <p class="title sectiontitle rubric" id="use-scenarios">Use scenarios</p> <ul class="simple"> <li><p>As an example, you can compile your application targeting the Ampere GPU without having to worry about the Hopper GPU architecture. Once the application runs on a Hopper GPU, it will seamlessly use the embedded PTX code.</p></li> <li><p>In CUDA Fortran, or with the CUDA Interoperability mode enabled, you can mix in object files compiled with the CUDA NVCC compiler containing PTX code. This PTX code from NVCC will be handled by the JIT compiler alongside the PTX code contained in object files produced by the HPC SDK compilers. When using the CUDA NVCC compiler, the relocatable device code generation must be enabled explicitly using the NVCC <code class="docutils literal notranslate"><span class="pre">--relocatable-device-code</span></code> true switch, as explained in the <a class="reference external" href="https://docs.nvidia.com/cuda/cuda-compiler-driver-nvcc/index.html#using-separate-compilation-in-cuda">CUDA Compiler Driver guide</a>. More information is available in the <a class="reference internal" href="#openmp-interop-cuda"><span class="std std-ref">Interoperability with CUDA</span></a> section of this guide and in the <a class="reference external" href="../cuda-fortran-prog-guide/index.html">CUDA Fortran Programming Guide</a>.</p></li> </ul> <p>By default, the compiler will choose the compute capability that matches the GPU on the system where the code is being compiled. For code that is going to run on the system where it is compiled, we recommend letting the compiler set the compute capability.</p> <p>When the default won’t work, we recommend compiling applications for a range of compute capabilities that the application is expected to run against, for example, using the <code class="docutils literal notranslate"><span class="pre">-gpu=ccall</span></code> compiler option. When running the application on a system that supports one of those compute capabilities, the CUDA driver minor version is allowed to be less than the version of the CUDA toolkit used at compile time, as covered in section <a class="reference internal" href="#cuda-toolkit-versions"><span class="std std-ref">CUDA Versions</span></a>.</p> <p class="title sectiontitle rubric" id="performance-considerations">Performance considerations</p> <p>PTX JIT compilation, when it occurs, can have a start-up overhead for the application. The JIT compiler keeps a cached copy of the produced device code, which reduces the overhead on subsequent runs. Please refer to the <a class="reference external" href="https://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#just-in-time-compilation">CUDA Programming Guide</a> for detailed information about how the JIT compiler works.</p> <p class="title sectiontitle rubric" id="known-limitations">Known limitations</p> <p>In general, in order for PTX JIT compilation to work, the CUDA driver installed on the deployment system must be at least of the version that matches the CUDA toolkit used to compile the application. This requirement is stricter than those explained in section <a class="reference internal" href="#cuda-toolkit-versions"><span class="std std-ref">CUDA Versions</span></a>.</p> <p>For example, as explained in that section, the compilers will use the CUDA 11.8 toolkit that is shipped as part of the HPC SDK toolkit when the CUDA driver installed in the system is at least 11.2. However, while the CUDA 11.2 driver is commonly sufficient to run the application, it will not be able to compile the PTX code produced by the CUDA 11.8 toolkit. This means that any deployment system where the PTX JIT compilation is expected to be used must have at least the CUDA 11.8 driver installed. Please refer to the <a class="reference external" href="https://docs.nvidia.com/deploy/cuda-compatibility/index.html#application-considerations">CUDA Compatibility</a> guide for further information about the CUDA Driver compatibility with CUDA Toolkits.</p> <p>When the application is expected to run on a newer GPU architecture than specified at compile time, we recommend having a CUDA driver installed on the deployment system matching the CUDA toolkit used to build the application. One way to achieve that is to use the <code class="docutils literal notranslate"><span class="pre">NVHPC_CUDA_HOME</span></code> environment variable at compile time to provide a specific CUDA toolkit.</p> <p>Below are a few examples of how the PTX version incompatibility can be diagnosed and fixed. As a general rule, if the CUDA driver is unable to run the application due to incompatible PTX, the application will terminate with an error message indicating the cause. OpenACC and OpenMP applications will in most cases suggest compiler flags to target the current CUDA installation.</p> <p class="title sectiontitle rubric" id="openacc">OpenACC</p> <p>Consider this program that we will compile for Volta GPU and attempt to run on an Ampere GPU, on a system that has CUDA 11.5 installed:</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="cp">#include</span><span class="w"> </span><span class="cpf">&lt;stdio.h&gt;</span><span class="cp"></span> <span class="cp">#define N 1000</span> <span class="kt">int</span><span class="w"> </span><span class="n">array</span><span class="p">[</span><span class="n">N</span><span class="p">];</span><span class="w"></span> <span class="kt">int</span><span class="w"> </span><span class="nf">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span> <span class="cp">#pragma acc parallel loop copy(array[0:N])</span> <span class="w"> </span><span class="k">for</span><span class="p">(</span><span class="kt">int</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="n">N</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="o">++</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="n">array</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mf">3.0</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="p">}</span><span class="w"></span> <span class="w"> </span><span class="n">printf</span><span class="p">(</span><span class="s">&quot;Success!</span><span class="se">\n</span><span class="s">&quot;</span><span class="p">);</span><span class="w"></span> <span class="p">}</span><span class="w"></span> </pre></div> </div> <p>When we build the program, HPC SDK will choose the CUDA 11.8 toolkit that is included as the default. When we attempt to run it, it fails because code generated with 11.8 does not work with the 11.5 driver:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ nvc -acc -gpu=cc70 app.c $ ./a.out Accelerator Fatal Error: This file was compiled: -acc=gpu -gpu=cc70 Rebuild this file with -gpu=cc80 to use NVIDIA Tesla GPU 0 File: /tmp/app.c Function: main:3 Line: 3 </pre></div> </div> <p>From the error message it follows that the system is unable to execute the Volta GPU instructions on the current system. The embedded Volta PTX could not be compiled, which implies a CUDA driver incompatibility. A way to fix this is to use the installed CUDA 11.5 toolkit at compile time:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ export NVHPC_CUDA_HOME=/usr/local/cuda-11.5 $ nvc -acc -gpu=cc70 app.c $ ./a.out Success! </pre></div> </div> <p class="title sectiontitle rubric" id="openmp">OpenMP</p> <p>Likewise, an OpenMP program will compile but not run:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>#include &lt;stdio.h&gt; #define N 1000 int array[N]; int main() { #pragma omp target loop for(int i = 0; i &lt; N; i++) { array[i] = 0; } printf(&quot;Success!\n&quot;); } </pre></div> </div> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ nvc -mp=gpu -gpu=cc70 app.c $ ./a.out Accelerator Fatal Error: Failed to find device function &#39;nvkernel_main_F1L3_2&#39;! File was compiled with: -gpu=cc70 Rebuild this file with -gpu=cc80 to use NVIDIA Tesla GPU 0 File: /tmp/app.c Function: main:3 Line: 3 </pre></div> </div> <p>We can also fix it by having <code class="docutils literal notranslate"><span class="pre">NVHPC_CUDA_HOME</span></code> point at the matching CUDA toolkit location:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ export NVHPC_CUDA_HOME=/usr/local/cuda-11.5 $ nvc -acc -gpu=cc70 app.c $ ./a.out Success! </pre></div> </div> <p class="title sectiontitle rubric" id="c">C++</p> <p>In contrast to OpenACC and OpenMP applications that simply terminate when PTX JIT encounters an insufficient CUDA driver version, C++ applications throw a system exception when there is a PTX incompatibility:</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="cp">#include</span><span class="w"> </span><span class="cpf">&lt;vector&gt;</span><span class="cp"></span> <span class="cp">#include</span><span class="w"> </span><span class="cpf">&lt;algorithm&gt;</span><span class="cp"></span> <span class="cp">#include</span><span class="w"> </span><span class="cpf">&lt;execution&gt;</span><span class="cp"></span> <span class="cp">#include</span><span class="w"> </span><span class="cpf">&lt;iostream&gt;</span><span class="cp"></span> <span class="cp">#include</span><span class="w"> </span><span class="cpf">&lt;assert.h&gt;</span><span class="cp"></span> <span class="kt">int</span><span class="w"> </span><span class="nf">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span><span class="w"> </span><span class="n">x</span><span class="p">(</span><span class="mi">1000</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span><span class="p">);</span><span class="w"></span> <span class="w"> </span><span class="n">x</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">-20</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="k">auto</span><span class="w"> </span><span class="n">result</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">std</span><span class="o">::</span><span class="n">count</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">execution</span><span class="o">::</span><span class="n">par</span><span class="p">,</span><span class="w"> </span><span class="n">x</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span><span class="w"> </span><span class="n">x</span><span class="p">.</span><span class="n">end</span><span class="p">(),</span><span class="w"> </span><span class="mi">-20</span><span class="p">);</span><span class="w"></span> <span class="w"> </span><span class="n">assert</span><span class="p">(</span><span class="n">result</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="mi">1</span><span class="p">);</span><span class="w"></span> <span class="w"> </span><span class="n">std</span><span class="o">::</span><span class="n">cout</span><span class="w"> </span><span class="o">&lt;&lt;</span><span class="w"> </span><span class="s">&quot;Success!&quot;</span><span class="w"> </span><span class="o">&lt;&lt;</span><span class="w"> </span><span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span><span class="w"></span> <span class="p">}</span><span class="w"></span> </pre></div> </div> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ nvc++ -stdpar -gpu=cc70 app.cpp $ ./a.out terminate called after throwing an instance of &#39;thrust::system::system_error&#39; what(): after reduction step 1: cudaErrorUnsupportedPtxVersion: the provided PTX was compiled with an unsupported toolchain. Aborted (core dumped) </pre></div> </div> <p>The exception message contains a direct reference to an incompatible PTX, which in turn implies an mismatch between the CUDA toolkit and the CUDA driver version.</p> <p>We can fix it similarly by setting <code class="docutils literal notranslate"><span class="pre">NVHPC_CUDA_HOME</span></code>:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ export NVHPC_CUDA_HOME=/usr/local/cuda-11.5 $ nvc++ -stdpar -gpu=cc70 app.cpp $ ./a.out Success! </pre></div> </div> <span class="target" id="acc-use"></span></section> </section> <section id="using-openacc"> <h1><span class="section-number">6. </span>Using OpenACC<a class="headerlink" href="#using-openacc" title="Permalink to this headline"></a></h1> <p>This chapter gives an overview of directive-based OpenACC programming in which compiler directives are used to specify regions of code in Fortran, C and C++ programs to be offloaded from a <em>host</em> CPU to an NVIDIA GPU. For complete details on using OpenACC with NVIDIA GPUs, see the <a class="reference external" href="../openacc-gs/index.html">OpenACC Getting Started Guide</a>.</p> <section id="openacc-programming-model"> <h2><span class="section-number">6.1. </span>OpenACC Programming Model<a class="headerlink" href="#openacc-programming-model" title="Permalink to this headline"></a></h2> <p>With the emergence of GPU architectures in high performance computing, programmers want the ability to program using a familiar, high level programming model that provides both high performance and portability to a wide range of computing architectures. OpenACC emerged in 2011 as a programming model that uses high-level compiler directives to expose parallelism in the code and parallelizing compilers to build the code for a variety of parallel accelerators.</p> <p>This chapter will not attempt to describe OpenACC itself. For that, please refer to the OpenACC specification on the OpenACC <a class="reference external" href="http://www.openacc.org">www.openacc.org</a> website. Here, we will discuss differences between the OpenACC specification and its implementation by the NVIDIA HPC Compilers.</p> <p>Other resources to help you with your parallel programming including video tutorials, course materials, code samples, a best practices guide and more are available on the OpenACC website.</p> <section id="levels-of-parallelism"> <h3><span class="section-number">6.1.1. </span>Levels of Parallelism<a class="headerlink" href="#levels-of-parallelism" title="Permalink to this headline"></a></h3> <p>OpenACC supports three levels of parallelism:</p> <ul class="simple"> <li><p>an outer <em>doall</em> (fully parallel) loop level</p></li> <li><p>a <em>workgroup</em> or <em>threadblock</em> (worker parallel) loop level</p></li> <li><p>an inner <em>synchronous</em> (SIMD or vector) loop level</p></li> </ul> <p>Each level can be multidimensional with 2 or 3 dimensions, but the domain must be strictly rectangular. The <em>synchronous</em> level may not be fully implemented with SIMD or vector operations, so explicit synchronization is supported and required across this level. No synchronization is supported between parallel threads across the <em>doall</em> level.</p> <p>The OpenACC execution model on the device side exposes these levels of parallelism and the programmer is required to understand the difference between, for example, a fully parallel loop and a loop that is vectorizable but requires synchronization across iterations. All fully parallel loops can be scheduled for any of <em>doall</em>, <em>workgroup</em> or <em>synchronous</em> parallel execution, but by definition SIMD vector loops that require synchronization can only be scheduled for synchronous parallel execution.</p> </section> <section id="enable-openacc-directives"> <h3><span class="section-number">6.1.2. </span>Enable OpenACC Directives<a class="headerlink" href="#enable-openacc-directives" title="Permalink to this headline"></a></h3> <p>NVIDIA HPC compilers enable OpenACC directives with the <code class="docutils literal notranslate"><span class="pre">-acc</span></code> and <code class="docutils literal notranslate"><span class="pre">-gpu</span></code> command line options. For more information on these options refer to <a class="reference internal" href="#acc-cmdln-opts"><span class="std std-ref">Compiling an OpenACC Program</span></a>.</p> <p><strong>_OPENACC macro</strong></p> <p>The <code class="docutils literal notranslate"><span class="pre">_OPENACC</span></code> macro name is defined to have a value <code class="docutils literal notranslate"><span class="pre">yyyymm</span></code> where <cite>yyyy</cite> is the year and <cite>mm</cite> is the month designation of the version of the OpenACC directives supported by the implementation. For example, the version for November, 2017 is 201711. All OpenACC compilers define this macro when OpenACC directives are enabled.</p> </section> <section id="openacc-support"> <h3><span class="section-number">6.1.3. </span>OpenACC Support<a class="headerlink" href="#openacc-support" title="Permalink to this headline"></a></h3> <p>The NVIDIA HPC Compilers implement most features of OpenACC 2.7 as defined in <em>The OpenACC Application Programming Interface</em>, Version 2.7, November 2018, <a class="reference external" href="http://www.openacc.org">http://www.openacc.org</a>, with the exception that the following OpenACC 2.7 features are not supported:</p> <ul class="simple"> <li><p>nested parallelism</p></li> <li><p>declare link</p></li> <li><p>enforcement of the <code class="docutils literal notranslate"><span class="pre">cache</span></code> clause restriction that all references to listed variables must lie within the region being cached</p></li> <li><p>Subarrays and composite variables in <code class="docutils literal notranslate"><span class="pre">reduction</span></code> clauses</p></li> <li><p>The <code class="docutils literal notranslate"><span class="pre">self</span></code> clause</p></li> <li><p>The <code class="docutils literal notranslate"><span class="pre">default</span></code> clause on data constructs</p></li> </ul> </section> <section id="openacc-extensions"> <h3><span class="section-number">6.1.4. </span>OpenACC Extensions<a class="headerlink" href="#openacc-extensions" title="Permalink to this headline"></a></h3> <p>The NVIDIA Fortran compiler supports an extension to the <code class="docutils literal notranslate"><span class="pre">collapse</span></code> clause on the <code class="docutils literal notranslate"><span class="pre">loop</span></code> construct. The OpenACC specification defines <code class="docutils literal notranslate"><span class="pre">collapse</span></code>:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>collapse(n) </pre></div> </div> <p>NVIDIA Fortran supports the use of the identifier <code class="docutils literal notranslate"><span class="pre">force</span></code> within <code class="docutils literal notranslate"><span class="pre">collapse</span></code>:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>collapse(force:n) </pre></div> </div> <p>Using <code class="docutils literal notranslate"><span class="pre">collapse(force:n)</span></code> instructs the compiler to enforce collapsing parallel loops that are not perfectly nested.</p> <span class="target" id="acc-cmdln-opts"></span></section> </section> <section id="compiling-an-openacc-program"> <h2><span class="section-number">6.2. </span>Compiling an OpenACC Program<a class="headerlink" href="#compiling-an-openacc-program" title="Permalink to this headline"></a></h2> <p>Several compiler options are applicable specifically when working with OpenACC. These options include <code class="docutils literal notranslate"><span class="pre">-acc</span></code>, <code class="docutils literal notranslate"><span class="pre">-gpu</span></code>, and <code class="docutils literal notranslate"><span class="pre">-Minfo</span></code>.</p> <section id="no-acc"> <h3><span class="section-number">6.2.1. </span>-[no]acc<a class="headerlink" href="#no-acc" title="Permalink to this headline"></a></h3> <p>Enable [disable] OpenACC directives. The following suboptions may be used following an equals sign (“=”), with multiple sub-options separated by commas:</p> <dl class="simple"> <dt>gpu</dt><dd><p>OpenACC directives are compiled for GPU execution only.</p> </dd> <dt>host</dt><dd><p>Compile for serial execution on the host CPU.</p> </dd> <dt>multicore</dt><dd><p>Compile for parallel execution on the host CPU.</p> </dd> <dt>legacy</dt><dd><p>Suppress warnings about deprecated NVIDIA accelerator directives.</p> </dd> <dt>[no]autopar</dt><dd><p>Enable [disable] loop autoparallelization within acc parallel. The default is to autoparallelize, that is, to enable loop autoparallelization.</p> </dd> <dt>[no]routineseq</dt><dd><p>Compile every routine for the devicee. The default behavior is to not treat every routine as a seq directive.</p> </dd> <dt>strict</dt><dd><p>Instructs the compiler to issue warnings for non-OpenACC accelerator directives.</p> </dd> <dt>sync</dt><dd><p>Ignore async clauses</p> </dd> <dt>verystrict</dt><dd><p>Instructs the compiler to fail with an error for any non-OpenACC accelerator directive.</p> </dd> <dt>[no]wait</dt><dd><p>Wait for each device kernel to finish. Kernel launching is blocked by default unless the async clause is used.</p> </dd> </dl> <p class="title sectiontitle rubric" id="default">Default</p> <p>By default OpenACC directives are compiled for GPU and sequential CPU host execution (i.e. equivalent to explicitly setting <code class="docutils literal notranslate"><span class="pre">-acc=gpu,host</span></code>).</p> <p class="title sectiontitle rubric" id="usage">Usage</p> <p>The following command-line requests that OpenACC directives be enabled and that an error be issued for any non-OpenACC accelerator directive.</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ nvfortran -acc=verystrict prog.f </pre></div> </div> <p class="title sectiontitle rubric" id="predefined-macros">Predefined Macros</p> <p>The following macros corresponding to the target compiled for are added implicitly:</p> <ul class="simple"> <li><p><code class="docutils literal notranslate"><span class="pre">__NVCOMPILER_OPENACC_GPU</span></code> when the OpenACC directives are compiled for GPU.</p></li> <li><p><code class="docutils literal notranslate"><span class="pre">__NVCOMPILER_OPENACC_MULTICORE</span></code> when the OpenACC directives are compiled for multicore CPU.</p></li> <li><p><code class="docutils literal notranslate"><span class="pre">__NVCOMPILER_OPENACC_HOST</span></code> when the OpenACC directives are compiled for serial execution on CPU.</p></li> </ul> </section> <section id="gpu"> <h3><span class="section-number">6.2.2. </span>-gpu<a class="headerlink" href="#gpu" title="Permalink to this headline"></a></h3> <p>Used in combination with the -acc, -cuda, -mp, and -stdpar flags to specify options for GPU code generation. The following sub-options may be used following an equals sign (“=”), with multiple sub-options separated by commas:</p> <dl class="simple"> <dt>autocompare</dt><dd><p>Automatically compare CPU vs GPU results at execution time: implies redundant</p> </dd> <dt>ccXY</dt><dd><p>Generate code for a device with compute capability X.Y. Multiple compute capabilities can be specified, and one version will be generated for each. By default, the compiler will detect the compute capability for each installed GPU. Use -help -gpu to see the valid compute capabilities for your installation.</p> </dd> <dt>ccall</dt><dd><p>Generate code for all compute capabilities supported by this platform and by the selected or default CUDA Toolkit.</p> </dd> <dt>ccall-major</dt><dd><p>Compile for all major supported compute capabilities.</p> </dd> <dt>ccnative</dt><dd><p>Detects the visible GPUs on the system and generates codes for them. If no device is available, the compute capability matching NVCC’s default will be used.</p> </dd> <dt>cudaX.Y</dt><dd><p>Use CUDA X.Y Toolkit compatibility, where installed</p> </dd> <dt>[no]debug</dt><dd><p>Enable [disable] debug information generation in device code</p> </dd> <dt>deepcopy</dt><dd><p>Enable full deep copy of aggregate data structures in OpenACC; Fortran only</p> </dd> <dt>fastmath</dt><dd><p>Use routines from the fast math library</p> </dd> <dt>[no]flushz</dt><dd><p>Enable [disable] flush-to-zero mode for floating point computations on the GPU</p> </dd> <dt>[no]fma</dt><dd><p>Generate [do not generate] fused multiply-add instructions on the GPU; default at <code class="docutils literal notranslate"><span class="pre">-O1</span></code>. This can be used in conjunction with the global <code class="docutils literal notranslate"><span class="pre">-M[no]fma</span></code> option to explicitly enable/disable FMAs on the CPU or GPU.</p> </dd> <dt>[no]implicitsections</dt><dd><p>Change [do not change] array element references in a data clause into an array section. In C++, the <code class="docutils literal notranslate"><span class="pre">implicitsections</span></code> option will change <code class="docutils literal notranslate"><span class="pre">update</span> <span class="pre">device(a[n])</span></code> to <code class="docutils literal notranslate"><span class="pre">update</span> <span class="pre">device(a[0:n])</span></code>. In Fortran, it will change <code class="docutils literal notranslate"><span class="pre">enter</span> <span class="pre">data</span> <span class="pre">copyin(a(n))</span></code> to <code class="docutils literal notranslate"><span class="pre">enter</span> <span class="pre">data</span> <span class="pre">copyin(a(:n))</span></code>. The default behavior, <code class="docutils literal notranslate"><span class="pre">noimplicitsections</span></code>, can also be changed using rcfiles; for example, one could add <code class="docutils literal notranslate"><span class="pre">set</span> <span class="pre">IMPLICITSECTIONS=0;</span></code> to siterc or another rcfile.</p> </dd> <dt>[no]interceptdeallocations</dt><dd><p>Intercept [do not intercept] calls to standard library memory deallocations (e.g. <code class="docutils literal notranslate"><span class="pre">free</span></code>) and call the corresponding CUDA memory deallocation version if address is in pinned or managed memory, regular version otherwise.</p> </dd> <dt>keep</dt><dd><p>Keep the kernel files (.cubin, .ptx, source)</p> </dd> <dt>[no]lineinfo</dt><dd><p>Enable [disable] GPU line information generation</p> </dd> <dt>loadcache:{L1|L2}</dt><dd><p>Choose what hardware level cache to use for global memory loads; options include the default, <code class="docutils literal notranslate"><span class="pre">L1</span></code>, or <code class="docutils literal notranslate"><span class="pre">L2</span></code></p> </dd> <dt>[no]managed</dt><dd><p>Allocate [do not allocate] any dynamically allocated data in CUDA Managed memory. Use <code class="docutils literal notranslate"><span class="pre">-gpu=nomanaged</span></code> with <code class="docutils literal notranslate"><span class="pre">-stdpar</span></code> to prevent that flag’s implicit use of <code class="docutils literal notranslate"><span class="pre">-gpu=managed</span></code> when CUDA Managed memory capability is detected. This option is deprecated.</p> </dd> <dt>maxregcount:n</dt><dd><p>Specify the maximum number of registers to use on the GPU; leaving this blank indicates no limit</p> </dd> <dt>mem:{separate|managed|unified}</dt><dd><p>Select GPU memory mode for the generated binary. This controls CUDA memory capability to be utilised such as separate GPU memory only (<code class="docutils literal notranslate"><span class="pre">separate</span></code>), GPU Managed Memory for the dynamically allocated data (<code class="docutils literal notranslate"><span class="pre">managed</span></code>), or system memory aka full CUDA Unified Memory (<code class="docutils literal notranslate"><span class="pre">unified</span></code>). Use of Managed or Unified Memory facilitates simpler programming by eliminating the need to detect all data to be copied into and outside of the code region executing on the GPU.</p> </dd> <dt>pinned</dt><dd><p>Use CUDA Pinned Memory. This option is deprecated.</p> </dd> <dt>ptxinfo</dt><dd><p>Print PTX info</p> </dd> <dt>[no]rdc</dt><dd><p>Generate [do not generate] relocatable device code.</p> </dd> <dt>redundant</dt><dd><p>Redundant CPU/GPU execution</p> </dd> <dt>safecache</dt><dd><p>Allow variable-sized array sections in cache directives; compiler assumes they fit into CUDA shared memory</p> </dd> <dt>sm_XY</dt><dd><p>Generate code for a device with compute capability X.Y. Multiple compute capabilities can be specified, and one version will be generated for each. By default, the compiler will detect the compute capability for each installed GPU. Use -help -gpu to see the valid compute capabilities for your installation.</p> </dd> <dt>stacklimit:&lt;l&gt;nostacklimit</dt><dd><p>Sets the limit (l) of stack variables in a procedure or kernel, in KB. This option is deprecated.</p> </dd> <dt>tripcount:{host|device|[no]check|[no]warn}</dt><dd><p>Determine whether the trip count values for loops in compute constructs are calculated on the host (default) or the device. Also can be used to enable [disable] runtime checks and compile-time warnings related to using host vs. device trip count values.</p> </dd> <dt>[no]unified</dt><dd><p>Compile [do not compile] for CUDA Unified memory capability, where system memory is accessible from the GPU. This mode utilizes system and managed memory for dynamically allocated data unless explicit behavior is set through <code class="docutils literal notranslate"><span class="pre">-gpu=[no]managed</span></code>. Use <code class="docutils literal notranslate"><span class="pre">-gpu=nounified</span></code> with <code class="docutils literal notranslate"><span class="pre">-stdpar</span></code> to prevent that flag’s implicit use of <code class="docutils literal notranslate"><span class="pre">-gpu=unified</span></code> when CUDA Unified memory capability is detected. This option must appear in both the compile and link lines. This option is deprecated.</p> </dd> <dt>[no]unroll</dt><dd><p>Enable [disable] automatic inner loop unrolling; default at <code class="docutils literal notranslate"><span class="pre">-O3</span></code></p> </dd> <dt>zeroinit</dt><dd><p>Initialize allocated device memory with zero</p> </dd> </dl> <p class="title sectiontitle rubric" id="usage-1">Usage</p> <p>In the following example, the compiler generates code for NVIDIA GPUs with compute capabilities 6.0 and 7.0.</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ nvfortran -acc -gpu=cc60,cc70 myprog.f </pre></div> </div> <p>The compiler automatically invokes the necessary software tools to create the kernel code and embeds the kernels in the object file.</p> <p>To link in the appropriate GPU libraries, you must link an OpenACC program with the <code class="docutils literal notranslate"><span class="pre">-acc</span></code> flag, and similarly for -cuda, -mp, or -stdpar.</p> <p class="title sectiontitle rubric" id="dwarf-debugging-formats">DWARF Debugging Formats</p> <p>Use the <code class="docutils literal notranslate"><span class="pre">-g</span></code> option to enable generation of full DWARF information on both the host and device; in the absence of other optimization flags, <code class="docutils literal notranslate"><span class="pre">-g</span></code> sets the optimization level to zero. If a <code class="docutils literal notranslate"><span class="pre">-O</span></code> option raises the optimization level to one or higher, only GPU line information is generated in device code even when <code class="docutils literal notranslate"><span class="pre">-g</span></code> is specified. To enforce full DWARF generation for device code at optimization levels above zero, use the <code class="docutils literal notranslate"><span class="pre">debug</span></code> sub-option to <code class="docutils literal notranslate"><span class="pre">-gpu</span></code>. Conversely, to prevent the generation of dwarf information for device code, use the <code class="docutils literal notranslate"><span class="pre">nodebug</span></code> sub-option to <code class="docutils literal notranslate"><span class="pre">-gpu</span></code>. Both <code class="docutils literal notranslate"><span class="pre">debug</span></code> and <code class="docutils literal notranslate"><span class="pre">nodebug</span></code> can be used independently of <code class="docutils literal notranslate"><span class="pre">-g</span></code>.</p> </section> </section> <section id="openacc-for-multicore-cpus"> <h2><span class="section-number">6.3. </span>OpenACC for Multicore CPUs<a class="headerlink" href="#openacc-for-multicore-cpus" title="Permalink to this headline"></a></h2> <p>The NVIDIA OpenACC compilers support the option <code class="docutils literal notranslate"><span class="pre">-acc=multicore</span></code>, to set the target accelerator for OpenACC programs to the host multicore CPU. This will compile OpenACC compute regions for parallel execution across the cores of the host processor or processors. The host multicore CPU will be treated as a shared-memory accelerator, so the data clauses (<code class="docutils literal notranslate"><span class="pre">copy</span></code>, <code class="docutils literal notranslate"><span class="pre">copyin</span></code>, <code class="docutils literal notranslate"><span class="pre">copyout</span></code>, <code class="docutils literal notranslate"><span class="pre">create</span></code>) will be ignored and no data copies will be executed.</p> <p>By default, <code class="docutils literal notranslate"><span class="pre">-acc=multicore</span></code> will generate code that will use all the available cores of the processor. If the compute region specifies a value in the <code class="docutils literal notranslate"><span class="pre">num_gangs</span></code> clause, the minimum of the <code class="docutils literal notranslate"><span class="pre">num_gangs</span></code> value and the number of available cores will be used. At runtime, the number of cores can be limited by setting the environment variable <code class="docutils literal notranslate"><span class="pre">ACC_NUM_CORES</span></code> to a constant integer value. The number of cores can also be set with the <code class="docutils literal notranslate"><span class="pre">void</span> <span class="pre">acc_set_num_cores(int</span> <span class="pre">numcores)</span></code> runtime call. If an OpenACC compute construct appears lexically within an OpenMP parallel construct, the OpenACC compute region will generate sequential code. If an OpenACC compute region appears dynamically within an OpenMP region or another OpenACC compute region, the program may generate many more threads than there are cores, and may produce poor performance.</p> <p>The <code class="docutils literal notranslate"><span class="pre">-acc=multicore</span></code> option differs from the <code class="docutils literal notranslate"><span class="pre">-acc=host</span></code> option in that <code class="docutils literal notranslate"><span class="pre">-acc=host</span></code> generates sequential host CPU code for the OpenACC compute regions.</p> <span class="target" id="acc-openacc-unified-mem"></span></section> <section id="openacc-with-cuda-unified-memory"> <h2><span class="section-number">6.4. </span>OpenACC with CUDA Unified Memory<a class="headerlink" href="#openacc-with-cuda-unified-memory" title="Permalink to this headline"></a></h2> <p>When developing OpenACC source for a target supporting CUDA Unified Memory, you can take advantage of a simplified approach to programming because there is no need for data clauses and directives, either in full or in part, depending on the exact memory capability the target supports and the compiler options used.</p> <p>The discussion in this section assumes you have become familiar with the Separate, Managed, and Unified Memory Modes covered in the <a class="reference internal" href="#acc-mem-model"><span class="std std-ref">Memory Model</span></a> and <a class="reference internal" href="#acc-mem-unified"><span class="std std-ref">Managed and Unified Memory Modes</span></a> sections.</p> <p>In Managed Memory Mode, only dynamically-allocated data are implicitly managed by the CUDA runtime; OpenACC data clauses and directives are therefore not needed for movement of this “managed” data. Data clauses and directives are still required to handle static data (C static and extern variables, Fortran module, common block and save variables) and function local data.</p> <p>In Unified Memory Mode, all data is managed by the CUDA runtime. Explicit data clauses and directives are no longer required to indicate which data should reside in GPU memory. All variables are accessible from the OpenACC compute regions executing on the GPU. The NVHPC compiler implementation closely adheres to the shared memory mode detailed in the OpenACC specification, meaning that <code class="docutils literal notranslate"><span class="pre">copy</span></code>, <code class="docutils literal notranslate"><span class="pre">copyin</span></code>, <code class="docutils literal notranslate"><span class="pre">copyout</span></code>, and <code class="docutils literal notranslate"><span class="pre">create</span></code> clauses will not result in any device allocation or data transfer. The <code class="docutils literal notranslate"><span class="pre">device_resident</span></code> clause is still honored as in discrete memory mode and results in an allocation of data only accessible from device code. Device memory can also be allocated or deallocated in OpenACC programs in Unified Memory Mode by using the <code class="docutils literal notranslate"><span class="pre">acc_malloc</span></code> or <code class="docutils literal notranslate"><span class="pre">acc_free</span></code> API calls.</p> <p><strong>Understanding Data Movement</strong></p> <p>In the absence of visible data clauses or directives, when the compiler encounters a compute construct it attempts to determine what data is required for correct execution of the region on the GPU. When the compiler is unable to determine the size and shape of data needing to be accessible on the device, it behaves as follows:</p> <ul class="simple"> <li><p>In Separate Memory Mode, the compiler emits an error requesting an explicit data clause be added to specify size/shape of the data to be copied.</p></li> <li><p>In Managed Memory Mode (<code class="docutils literal notranslate"><span class="pre">-gpu=mem:managed</span></code>), the compiler assumes the data is allocated in managed memory and thus is accessible from the device; if this assumption is wrong, if the data was defined globally or is located on the CPU stack, the program may fail at runtime.</p></li> <li><p>In Unified Memory Mode (<code class="docutils literal notranslate"><span class="pre">-gpu=mem:unified</span></code>), all data is accessible from the device making information about size and shape unnecessary.</p></li> </ul> <p>Take the following example in C:</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="kt">void</span><span class="w"> </span><span class="nf">set</span><span class="p">(</span><span class="kt">int</span><span class="o">*</span><span class="w"> </span><span class="n">ptr</span><span class="p">,</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">i</span><span class="p">,</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">j</span><span class="p">,</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">dim</span><span class="p">){</span><span class="w"></span> <span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">idx</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">dim</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">j</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="n">ptr</span><span class="p">[</span><span class="n">idx</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">someval</span><span class="p">(</span><span class="n">i</span><span class="p">,</span><span class="w"> </span><span class="n">j</span><span class="p">);</span><span class="w"></span> <span class="p">}</span><span class="w"></span> <span class="kt">void</span><span class="w"> </span><span class="nf">fill2d</span><span class="p">(</span><span class="kt">int</span><span class="o">*</span><span class="w"> </span><span class="n">ptr</span><span class="p">,</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">dim</span><span class="p">){</span><span class="w"></span> <span class="cp">#pragma acc parallel loop</span> <span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="kt">int</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="n">dim</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="o">++</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="kt">int</span><span class="w"> </span><span class="n">j</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="n">j</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="n">dim</span><span class="p">;</span><span class="w"> </span><span class="n">j</span><span class="o">++</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="n">set</span><span class="p">(</span><span class="n">ptr</span><span class="p">,</span><span class="w"> </span><span class="n">i</span><span class="p">,</span><span class="w"> </span><span class="n">j</span><span class="p">,</span><span class="w"> </span><span class="n">dim</span><span class="p">);</span><span class="w"></span> <span class="p">}</span><span class="w"></span> </pre></div> </div> <p>In Separate Memory Mode, the only way to guarantee correctness for this example is to change the line with the <code class="docutils literal notranslate"><span class="pre">acc</span></code> directive as follows:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>#pragma acc parallel loop create(ptr[0:dim*dim]) copyout(ptr[0:dim*dim]) </pre></div> </div> <p>This change explicitly instructs the OpenACC implementation about the precise data segment used within the parallel loop.</p> <p>In Unified Memory Mode, that is, by compiling with <code class="docutils literal notranslate"><span class="pre">-acc</span> <span class="pre">-gpu=mem:unified</span></code> and executing on a platform with unified memory capability, the <code class="docutils literal notranslate"><span class="pre">create</span></code> and <code class="docutils literal notranslate"><span class="pre">copyout</span></code> clauses are not required.</p> <p>The next example, in Fortran, illustrates how a global variable can be accessed in an OpenACC routine without requiring any explicit annotation.</p> <div class="highlight-fortran notranslate"><div class="highlight"><pre><span></span><span class="k">module </span><span class="n">m</span><span class="w"></span> <span class="kt">integer</span><span class="w"> </span><span class="kd">::</span><span class="w"> </span><span class="n">globmin</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">1234</span><span class="w"></span> <span class="k">contains</span> <span class="k">subroutine </span><span class="n">findmin</span><span class="p">(</span><span class="n">a</span><span class="p">)</span><span class="w"></span> <span class="c">!$acc routine seq</span> <span class="w"> </span><span class="kt">integer</span><span class="p">,</span><span class="w"> </span><span class="k">intent</span><span class="p">(</span><span class="n">in</span><span class="p">)</span><span class="w"> </span><span class="kd">::</span><span class="w"> </span><span class="n">a</span><span class="p">(:)</span><span class="w"></span> <span class="w"> </span><span class="kt">integer</span><span class="w"> </span><span class="kd">::</span><span class="w"> </span><span class="n">i</span><span class="w"></span> <span class="w"> </span><span class="k">do </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="n">size</span><span class="p">(</span><span class="n">a</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">a</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="p">.</span><span class="n">lt</span><span class="p">.</span><span class="w"> </span><span class="n">globmin</span><span class="p">)</span><span class="w"> </span><span class="k">then</span> <span class="k"> </span><span class="n">globmin</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">a</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="k">endif</span> <span class="k"> end do</span> <span class="k">end subroutine</span> <span class="k">end module </span><span class="n">m</span><span class="w"></span> </pre></div> </div> <p>Compile the example above for Unified Memory Mode:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>nvfortran -acc -gpu=mem:unified example.f90 </pre></div> </div> <p>The source does not need any OpenACC directives to access module variable <code class="docutils literal notranslate"><span class="pre">globmin</span></code>, to either read or update its value, in the routine invoked from CPU and GPU. Moreover, any access to <code class="docutils literal notranslate"><span class="pre">globmin</span></code> will be made to the same exact instance of the variable from CPU and GPU; its value is synchronized automatically. In Separate or Managed Memory Modes, such behavior can only be achieved with a combination of OpenACC <code class="docutils literal notranslate"><span class="pre">declare</span></code> and <code class="docutils literal notranslate"><span class="pre">update</span></code> directives in the source code.</p> <p>In most cases, migrating existing OpenACC applications written for Separate Memory Mode should be a seamless process requiring no source changes. Some data access patterns, however, may lead to different results produced during application execution in Unified Memory Mode.</p> <p>Applications which rely on having separate data copies in GPU memory to conduct temporary computations on the GPU – without maintaining data synchronization with the CPU – pose a challenge for migration to Unified Memory.</p> <p>For the following Fortran example, the value of variable <code class="docutils literal notranslate"><span class="pre">c</span></code> after the last loop will differ depending on whether the example is compiled with or without <code class="docutils literal notranslate"><span class="pre">-gpu=mem:unified</span></code>.</p> <div class="highlight-fortran notranslate"><div class="highlight"><pre><span></span><span class="n">b</span><span class="p">(:)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">...</span><span class="w"></span> <span class="n">c</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="w"></span> <span class="c">!$acc kernels copyin(b) copyout(a)</span> <span class="c">!$acc loop</span> <span class="k">do </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="n">N</span><span class="w"></span> <span class="w"> </span><span class="n">b</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">b</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">i</span><span class="w"></span> <span class="k">end do</span><span class="w"></span> <span class="c">!$acc loop</span> <span class="k">do </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="n">N</span><span class="w"></span> <span class="w"> </span><span class="n">a</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">b</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">i</span><span class="w"></span> <span class="k">end do</span><span class="w"></span> <span class="c">!$acc end kernels</span> <span class="k">do </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="n">N</span><span class="w"></span> <span class="w"> </span><span class="n">c</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">c</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">a</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">b</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="w"></span> <span class="k">end do</span><span class="w"></span> </pre></div> </div> <p>Without Unified Memory, array <code class="docutils literal notranslate"><span class="pre">b</span></code> is copied into the GPU memory at the beginning of the OpenACC <code class="docutils literal notranslate"><span class="pre">kernels</span></code> region. It is then updated in the GPU memory and used to compute elements of array <code class="docutils literal notranslate"><span class="pre">a</span></code>. As instructed by the data clause <code class="docutils literal notranslate"><span class="pre">copyin(b)</span></code>, <code class="docutils literal notranslate"><span class="pre">b</span></code> is not copied back to the CPU memory at the end of the <code class="docutils literal notranslate"><span class="pre">kernels</span></code> region and therefore its initial value is used in the computation of <code class="docutils literal notranslate"><span class="pre">c</span></code>. With <code class="docutils literal notranslate"><span class="pre">-acc</span> <span class="pre">-gpu=mem:unified</span></code>, the updated value of <code class="docutils literal notranslate"><span class="pre">b</span></code> in the first loop is automatically visible in the last loop leading to a different value of <code class="docutils literal notranslate"><span class="pre">c</span></code> at its end.</p> <p><strong>Implications of Asynchronous Execution</strong></p> <p>Additional complexities can arise when dealing with asynchronous execution, particularly when CPU-GPU shared data is accessed within <code class="docutils literal notranslate"><span class="pre">async</span></code> compute regions instead of using an independent data copy on GPU. The programmer should be especially careful about accessing local variables in asynchronous GPU code. Unless the GPU code execution is explicitly synchronized before the end of the scope in which local variables are defined, the GPU can access stale data thus resulting in undefined behavior. Consider the following OpenACC C example, where a local array is used to hold temporary data on the GPU:</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="kt">void</span><span class="w"> </span><span class="nf">bar</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">x</span><span class="p">[</span><span class="n">N</span><span class="p">];</span><span class="w"></span> <span class="w"> </span><span class="cp">#pragma acc enter data create(x[0:N]) async</span> <span class="w"> </span><span class="cp">#pragma acc parallel loop async</span> <span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="kt">int</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="n">N</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="o">++</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="n">x</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">i</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="p">...</span><span class="w"></span> <span class="w"> </span><span class="cp">#pragma acc exit data delete(x[0:N]) async</span> <span class="p">}</span><span class="w"></span> </pre></div> </div> <p>When compiled for Separate Memory Mode, the <code class="docutils literal notranslate"><span class="pre">bar()</span></code> function creates a copy of the array <code class="docutils literal notranslate"><span class="pre">x</span></code> in GPU memory and initializes it as written in the <code class="docutils literal notranslate"><span class="pre">loop</span></code> construct. That copy is eventually deleted. In Unified Memory Mode, however, the compiler ignores the <code class="docutils literal notranslate"><span class="pre">acc</span> <span class="pre">enter</span> <span class="pre">data</span></code> and <code class="docutils literal notranslate"><span class="pre">acc</span> <span class="pre">exit</span> <span class="pre">data</span></code> directives, so the <code class="docutils literal notranslate"><span class="pre">loop</span></code> construct executed on the GPU accesses the array <code class="docutils literal notranslate"><span class="pre">x</span></code> in local CPU memory. Moreover, since all constructs in this example are made asynchronous, the access to <code class="docutils literal notranslate"><span class="pre">x</span></code> on the GPU leads to undefined behavior of the program because the variable <code class="docutils literal notranslate"><span class="pre">x</span></code> goes out of scope once the <code class="docutils literal notranslate"><span class="pre">bar()</span></code> function finishes.</p> <p><strong>Performance Considerations</strong></p> <p>In Unified Memory Mode, the OpenACC runtime may leverage data action information such as <code class="docutils literal notranslate"><span class="pre">create</span></code>/<code class="docutils literal notranslate"><span class="pre">delete</span></code> or <code class="docutils literal notranslate"><span class="pre">copyin</span></code>/<code class="docutils literal notranslate"><span class="pre">copyout</span></code> to communicate preferable data placement to the CUDA runtime by means of memory hint APIs as elaborated in the following blog post on the NVIDIA website: <a class="reference external" href="https://developer.nvidia.com/blog/simplifying-gpu-application-development-with-heterogeneous-memory-management">Simplifying GPU Application Development with Heterogeneous Memory Management</a>. Such actions originate either from explicit data clauses in the source code or via implicit data movement generated by the compiler. This approach can minimize the amount of automatic data migration and may let a developer fine-tune application performance. For the C example above, while adding the data clauses <code class="docutils literal notranslate"><span class="pre">create(ptr[0:dim*dim])</span></code> and <code class="docutils literal notranslate"><span class="pre">copyout(ptr[0:dim*dim])</span></code> becomes optional with <code class="docutils literal notranslate"><span class="pre">-gpu=mem:unified</span></code>, their uses in the OpenACC <code class="docutils literal notranslate"><span class="pre">parallel</span> <span class="pre">loop</span></code> directive may improve performance.</p> </section> <section id="openacc-error-handling"> <h2><span class="section-number">6.5. </span>OpenACC Error Handling<a class="headerlink" href="#openacc-error-handling" title="Permalink to this headline"></a></h2> <p>The OpenACC specification provides a mechanism to allow you to intercept errors triggered during execution on a GPU and execute a specific routine in response before the program exits. For example, if an MPI process fails while allocating memory on the GPU, the application may want to call <code class="docutils literal notranslate"><span class="pre">MPI_Abort</span></code> to shut down all the other processes before the program exits. This section explains how to take advantage of this feature.</p> <p>To intercept errors the application must give a callback routine to the OpenACC runtime. To provide the callback, the application calls <code class="docutils literal notranslate"><span class="pre">acc_set_error_routine</span></code> with a pointer to the callback routine.</p> <p>The interface is the following, where <code class="docutils literal notranslate"><span class="pre">err_msg</span></code> contains a description of the error:</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="k">typedef</span><span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="p">(</span><span class="o">*</span><span class="n">exitroutinetype</span><span class="p">)(</span><span class="kt">char</span><span class="w"> </span><span class="o">*</span><span class="n">err_msg</span><span class="p">);</span><span class="w"></span> <span class="k">extern</span><span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="nf">acc_set_error_routine</span><span class="p">(</span><span class="n">exitroutinetype</span><span class="w"> </span><span class="n">callback_routine</span><span class="p">);</span><span class="w"></span> </pre></div> </div> <p>When the OpenACC runtime detects a runtime error, it will invoke the <code class="docutils literal notranslate"><span class="pre">callback_routine</span></code>.</p> <div class="admonition note"> <p class="admonition-title">Note</p> <p>This feature is not the same as error recovery. If the callback routine returns to the application, the behavior is decidedly undefined.</p> </div> <p>Let’s look at this feature in more depth using an example.</p> <p>Take the MPI program below and run it with two processes. Process 0 tries to allocate a large array on the GPU, then sends a message to the second process to acknowledge the success of the operation. Process 1 waits for the acknowledgment and terminates upon receiving it.</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="cp">#include</span><span class="w"> </span><span class="cpf">&lt;stdio.h&gt;</span><span class="cp"></span> <span class="cp">#include</span><span class="w"> </span><span class="cpf">&lt;stdlib.h&gt;</span><span class="cp"></span> <span class="cp">#include</span><span class="w"> </span><span class="cpf">&quot;mpi.h&quot;</span><span class="cp"></span> <span class="cp">#define N 2147483648</span> <span class="kt">int</span><span class="w"> </span><span class="nf">main</span><span class="p">(</span><span class="kt">int</span><span class="w"> </span><span class="n">argc</span><span class="p">,</span><span class="w"> </span><span class="kt">char</span><span class="w"> </span><span class="o">**</span><span class="n">argv</span><span class="p">)</span><span class="w"></span> <span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">rank</span><span class="p">,</span><span class="w"> </span><span class="n">size</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="n">MPI_Init</span><span class="p">(</span><span class="o">&amp;</span><span class="n">argc</span><span class="p">,</span><span class="w"> </span><span class="o">&amp;</span><span class="n">argv</span><span class="p">);</span><span class="w"></span> <span class="w"> </span><span class="n">MPI_Comm_rank</span><span class="p">(</span><span class="n">MPI_COMM_WORLD</span><span class="p">,</span><span class="w"> </span><span class="o">&amp;</span><span class="n">rank</span><span class="p">);</span><span class="w"></span> <span class="w"> </span><span class="n">MPI_Comm_size</span><span class="p">(</span><span class="n">MPI_COMM_WORLD</span><span class="p">,</span><span class="w"> </span><span class="o">&amp;</span><span class="n">size</span><span class="p">);</span><span class="w"></span> <span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">ack</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="k">if</span><span class="p">(</span><span class="n">rank</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="mi">0</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="kt">float</span><span class="w"> </span><span class="o">*</span><span class="n">a</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="kt">float</span><span class="o">*</span><span class="p">)</span><span class="w"> </span><span class="n">malloc</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="kt">float</span><span class="p">)</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">N</span><span class="p">);</span><span class="w"></span> <span class="cp">#pragma acc enter data create(a[0:N])</span> <span class="cp">#pragma acc parallel loop independent</span> <span class="w"> </span><span class="k">for</span><span class="p">(</span><span class="kt">int</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="n">N</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="o">++</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="n">a</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">*</span><span class="mf">0.5</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="p">}</span><span class="w"></span> <span class="cp">#pragma acc exit data copyout(a[0:N])</span> <span class="w"> </span><span class="n">printf</span><span class="p">(</span><span class="s">&quot;I am process %d, I have initialized a vector of size %ld bytes on the GPU. Sending acknowledgment to process 1.&quot;</span><span class="p">,</span><span class="w"> </span><span class="n">rank</span><span class="p">,</span><span class="w"> </span><span class="n">N</span><span class="p">);</span><span class="w"></span> <span class="w"> </span><span class="n">ack</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">1</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="n">MPI_Send</span><span class="p">(</span><span class="o">&amp;</span><span class="n">ack</span><span class="p">,</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="n">MPI_INT</span><span class="p">,</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="n">MPI_COMM_WORLD</span><span class="p">);</span><span class="w"></span> <span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="k">if</span><span class="p">(</span><span class="n">rank</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="mi">1</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="n">MPI_Recv</span><span class="p">(</span><span class="o">&amp;</span><span class="n">ack</span><span class="p">,</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="n">MPI_INT</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="n">MPI_COMM_WORLD</span><span class="p">,</span><span class="w"> </span><span class="n">MPI_STATUS_IGNORE</span><span class="p">);</span><span class="w"></span> <span class="w"> </span><span class="n">printf</span><span class="p">(</span><span class="s">&quot;I am process %d, I have received the acknowledgment from process 0 that data in the GPU has been initialized.</span><span class="se">\n</span><span class="s">&quot;</span><span class="p">,</span><span class="w"> </span><span class="n">rank</span><span class="p">,</span><span class="w"> </span><span class="n">N</span><span class="p">);</span><span class="w"></span> <span class="w"> </span><span class="n">fflush</span><span class="p">(</span><span class="n">stdout</span><span class="p">);</span><span class="w"></span> <span class="w"> </span><span class="p">}</span><span class="w"></span> <span class="w"> </span><span class="c1">// do some more work</span> <span class="w"> </span><span class="n">MPI_Finalize</span><span class="p">();</span><span class="w"></span> <span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"></span> <span class="p">}</span><span class="w"></span> </pre></div> </div> <p>We compile the program with:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ mpicc -acc -o error_handling_mpi error_handling_mpi.c </pre></div> </div> <p>If we run this program with two MPI processes, the output will look like the following:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ mpirun -n 2 ./error_handling_mpi Out of memory allocating -8589934592 bytes of device memory total/free CUDA memory: 11995578368/11919294464 Present table dump for device[1]: NVIDIA Tesla GPU 0, compute capability 3.7, threadid=1 ...empty... call to cuMemAlloc returned error 2: Out of memory ------------------------------------------------------- Primary job terminated normally, but 1 process returned a non-zero exit code.. Per user-direction, the job has been aborted. ------------------------------------------------------- -------------------------------------------------------------------------- mpirun detected that one or more processes exited with non-zero status, thus causing the job to be terminated. </pre></div> </div> <p>Process 0 failed while allocating memory on the GPU and terminated unexpectedly with an error. In this case <code class="docutils literal notranslate"><span class="pre">mpirun</span></code> was able to identify that one of the processes failed, so it shut down the remaining process and terminated the application. A simple two-process program like this is straightforward to debug. In a real world application though, with hundreds or thousands of processes, having a process exit prematurely may cause the application to hang indefinitely. Therefore it would be ideal to catch the failure of a process, control the termination of the other processes, and provide a useful error message.</p> <p>We can use the OpenACC error handling feature to improve the previous program and correctly terminate the application in case of failure of an MPI process.</p> <p>In the following sample code, we have added an error handling callback routine that will shut down the other processes if a process encounters an error while executing on the GPU. Process 0 tries to allocate a large array into the GPU and, if the operation is successful, process 0 will send an acknowledgment to process 1. Process 0 calls the OpenACC function <code class="docutils literal notranslate"><span class="pre">acc_set_error_routine</span></code> to set the function <code class="docutils literal notranslate"><span class="pre">handle_gpu_errors</span></code> as an error handling callback routine. This routine prints a message and calls <code class="docutils literal notranslate"><span class="pre">MPI_Abort</span></code> to shut down all the MPI processes. If process 0 successfully allocates the array on the GPU, process 1 will receive the acknowledgment. Otherwise, if process 0 fails, it will terminate itself and trigger the call to <code class="docutils literal notranslate"><span class="pre">handle_gpu_errors</span></code>. Process 1 is then terminated by the code executed in the callback routine.</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="cp">#include</span><span class="w"> </span><span class="cpf">&lt;stdio.h&gt;</span><span class="cp"></span> <span class="cp">#include</span><span class="w"> </span><span class="cpf">&lt;stdlib.h&gt;</span><span class="cp"></span> <span class="cp">#include</span><span class="w"> </span><span class="cpf">&quot;mpi.h&quot;</span><span class="cp"></span> <span class="cp">#define N 2147483648</span> <span class="k">typedef</span><span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="p">(</span><span class="o">*</span><span class="n">exitroutinetype</span><span class="p">)(</span><span class="kt">char</span><span class="w"> </span><span class="o">*</span><span class="n">err_msg</span><span class="p">);</span><span class="w"></span> <span class="k">extern</span><span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="nf">acc_set_error_routine</span><span class="p">(</span><span class="n">exitroutinetype</span><span class="w"> </span><span class="n">callback_routine</span><span class="p">);</span><span class="w"></span> <span class="kt">void</span><span class="w"> </span><span class="nf">handle_gpu_errors</span><span class="p">(</span><span class="kt">char</span><span class="w"> </span><span class="o">*</span><span class="n">err_msg</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="n">printf</span><span class="p">(</span><span class="s">&quot;GPU Error: %s&quot;</span><span class="p">,</span><span class="w"> </span><span class="n">err_msg</span><span class="p">);</span><span class="w"></span> <span class="w"> </span><span class="n">printf</span><span class="p">(</span><span class="s">&quot;Exiting...</span><span class="se">\n\n</span><span class="s">&quot;</span><span class="p">);</span><span class="w"></span> <span class="w"> </span><span class="n">MPI_Abort</span><span class="p">(</span><span class="n">MPI_COMM_WORLD</span><span class="p">,</span><span class="w"> </span><span class="mi">1</span><span class="p">);</span><span class="w"></span> <span class="w"> </span><span class="n">exit</span><span class="p">(</span><span class="mi">-1</span><span class="p">);</span><span class="w"></span> <span class="p">}</span><span class="w"></span> <span class="kt">int</span><span class="w"> </span><span class="nf">main</span><span class="p">(</span><span class="kt">int</span><span class="w"> </span><span class="n">argc</span><span class="p">,</span><span class="w"> </span><span class="kt">char</span><span class="w"> </span><span class="o">**</span><span class="n">argv</span><span class="p">)</span><span class="w"></span> <span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">rank</span><span class="p">,</span><span class="w"> </span><span class="n">size</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="n">MPI_Init</span><span class="p">(</span><span class="o">&amp;</span><span class="n">argc</span><span class="p">,</span><span class="w"> </span><span class="o">&amp;</span><span class="n">argv</span><span class="p">);</span><span class="w"></span> <span class="w"> </span><span class="n">MPI_Comm_rank</span><span class="p">(</span><span class="n">MPI_COMM_WORLD</span><span class="p">,</span><span class="w"> </span><span class="o">&amp;</span><span class="n">rank</span><span class="p">);</span><span class="w"></span> <span class="w"> </span><span class="n">MPI_Comm_size</span><span class="p">(</span><span class="n">MPI_COMM_WORLD</span><span class="p">,</span><span class="w"> </span><span class="o">&amp;</span><span class="n">size</span><span class="p">);</span><span class="w"></span> <span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">ack</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="k">if</span><span class="p">(</span><span class="n">rank</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="mi">0</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="kt">float</span><span class="w"> </span><span class="o">*</span><span class="n">a</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="kt">float</span><span class="o">*</span><span class="p">)</span><span class="w"> </span><span class="n">malloc</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="kt">float</span><span class="p">)</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">N</span><span class="p">);</span><span class="w"></span> <span class="w"> </span><span class="n">acc_set_error_routine</span><span class="p">(</span><span class="o">&amp;</span><span class="n">handle_gpu_errors</span><span class="p">);</span><span class="w"></span> <span class="cp">#pragma acc enter data create(a[0:N])</span> <span class="cp">#pragma acc parallel loop independent</span> <span class="w"> </span><span class="k">for</span><span class="p">(</span><span class="kt">int</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="n">N</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="o">++</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="n">a</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">*</span><span class="mf">0.5</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="p">}</span><span class="w"></span> <span class="cp">#pragma acc exit data copyout(a[0:N])</span> <span class="w"> </span><span class="n">printf</span><span class="p">(</span><span class="s">&quot;I am process %d, I have initialized a vector of size %ld bytes on the GPU. Sending acknowledgment to process 1.&quot;</span><span class="p">,</span><span class="w"> </span><span class="n">rank</span><span class="p">,</span><span class="w"> </span><span class="n">N</span><span class="p">);</span><span class="w"></span> <span class="w"> </span><span class="n">fflush</span><span class="p">(</span><span class="n">stdout</span><span class="p">);</span><span class="w"></span> <span class="w"> </span><span class="n">ack</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">1</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="n">MPI_Send</span><span class="p">(</span><span class="o">&amp;</span><span class="n">ack</span><span class="p">,</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="n">MPI_INT</span><span class="p">,</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="n">MPI_COMM_WORLD</span><span class="p">);</span><span class="w"></span> <span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="k">if</span><span class="p">(</span><span class="n">rank</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="mi">1</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="n">MPI_Recv</span><span class="p">(</span><span class="o">&amp;</span><span class="n">ack</span><span class="p">,</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="n">MPI_INT</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="n">MPI_COMM_WORLD</span><span class="p">,</span><span class="w"> </span><span class="n">MPI_STATUS_IGNORE</span><span class="p">);</span><span class="w"></span> <span class="w"> </span><span class="n">printf</span><span class="p">(</span><span class="s">&quot;I am process %d, I have received the acknowledgment from process 0 that data in the GPU has been initialized.</span><span class="se">\n</span><span class="s">&quot;</span><span class="p">,</span><span class="w"> </span><span class="n">rank</span><span class="p">,</span><span class="w"> </span><span class="n">N</span><span class="p">);</span><span class="w"></span> <span class="w"> </span><span class="n">fflush</span><span class="p">(</span><span class="n">stdout</span><span class="p">);</span><span class="w"></span> <span class="w"> </span><span class="p">}</span><span class="w"></span> <span class="w"> </span><span class="c1">// more work</span> <span class="w"> </span><span class="n">MPI_Finalize</span><span class="p">();</span><span class="w"></span> <span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"></span> <span class="p">}</span><span class="w"></span> </pre></div> </div> <p>Again, we compile the program with:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ mpicc -acc -o error_handling_mpi error_handling_mpi.c </pre></div> </div> <p>We run the program with two MPI processes and obtain the output below:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ mpirun -n 2 ./error_handling_mpi Out of memory allocating -8589934592 bytes of device memory total/free CUDA memory: 11995578368/11919294464 Present table dump for device[1]: NVIDIA Tesla GPU 0, compute capability 3.7, threadid=1 ...empty... GPU Error: call to cuMemAlloc returned error 2: Out of memory Exiting... -------------------------------------------------------------------------- MPI_ABORT was invoked on rank 0 in communicator MPI_COMM_WORLD with errorcode 1. </pre></div> </div> <p>This time the error on the GPU was intercepted by the application which managed it with the error handling callback routine. In this case the routine printed some information about the problem and called <code class="docutils literal notranslate"><span class="pre">MPI_Abort</span></code> to terminate the remaining processes and avoid any unexpected behavior from the application.</p> </section> <section id="openacc-and-cuda-graphs"> <h2><span class="section-number">6.6. </span>OpenACC and CUDA Graphs<a class="headerlink" href="#openacc-and-cuda-graphs" title="Permalink to this headline"></a></h2> <p>NVIDIA provides an optimized model for work submission onto GPUs called CUDA Graphs. A graph is a series of operations, such as kernel launches and other stream-oriented tasks, connected by their dependencies. A graph can be defined once, “captured”, then launched repeatedly. This has potential benefits in reducing launch latencies and other overheads associated with kernel setup.</p> <p>A complete write-up explaining CUDA Graphs and the CUDA API for graph definition, instantiation, and execution can be found in Chapter 3 of the CUDA C Programming Guide. In OpenACC, we currently expose just the minimal set of operations to allow capture and replay of a graph containing OpenACC compute regions and data directives. The code executed between a “begin capture” call, <code class="docutils literal notranslate"><span class="pre">accx_begin_capture_async()</span></code>, and the “end capture” call, <code class="docutils literal notranslate"><span class="pre">accx_end_capture_async()</span></code>, is called the capture region.</p> <p>The CUDA graph API captures (or records) all the device work between accx_begin_capture_async and accx_end_capture_async. The host code in the capture region will be executed once normally, with the exception that no device work is actually executed on the device. Instead, a graph object is created that can be used to replay the captured work multiple times.</p> <div class="admonition note"> <p class="admonition-title">Note</p> <p>Graph capture is similar to a closure concept in many programming languages, like lambda-functions in C++. In lambda-function terms, CUDA graphs capture all the variables by value. That means that all the FIRSTPRIVATE scalars, array shapes, and those derived types, arrays and scalar addresses for data resident on the GPU, are baked into the graph object and cannot be altered. The device data behind the pointers, of course, can be updated by the graph execution normally, and updated by the host between replays.</p> </div> <p>It is important to understand both what can and cannot be captured within a CUDA Graph capture region:</p> <ul> <li><p>Asynchronous data directives, including <code class="docutils literal notranslate"><span class="pre">data</span> <span class="pre">create</span></code>, can be captured. The OpenACC runtime will use the stream-ordered <code class="docutils literal notranslate"><span class="pre">cudaMallocAsync()</span></code> call in the capture region for variables which need allocation in data clauses, an API call allowed in CUDA Graphs.</p></li> <li><p>Asynchronous compute regions, preferably ACC <code class="docutils literal notranslate"><span class="pre">parallel</span></code> regions, can be captured. For ACC <code class="docutils literal notranslate"><span class="pre">kernels</span></code> regions, verify that no work is performed on the host. Host compute sections cannot be captured.</p></li> <li><p>Asynchronous ACC <code class="docutils literal notranslate"><span class="pre">update</span> <span class="pre">host</span> <span class="pre">(self)</span></code> and <code class="docutils literal notranslate"><span class="pre">update</span> <span class="pre">device</span></code> directives can be captured. The host and device addresses which are captured must be valid during the graph replay/execution.</p></li> <li><p>Since only the device work is captured and replayed, any data dependencies between the host and device inside the capture region are erroneous. For example, downloading data from the device, processing it on host and uploading it back to the device within the capture region is invalid.</p></li> <li><p>Host code, even host code containing conditionals, can occur within a capture region. Note though that the path taken through the host code will be the path captured by the graph, i.e. the conditionals must likely be consistent during the replay for correct results. Host code which updates host variables, such as <code class="docutils literal notranslate"><span class="pre">i=i+1</span></code> will not be captured in the graph, which might affect proper indexing into device-side arrays or other kernel arguments.</p></li> <li><p>Similarly, device work initiated in host code loops can be captured in the CUDA Graph. The graph will not contain a notion of looping, just the sequence of device operations submitted to the device during the loop.</p></li> <li><p>Subroutine and function calls within a capture region, which contain further compute regions or other work which runs on the device, are captured. Care must be taken that the device data addresses passed to the kernels are valid throughout graph execution, and don’t come and go based on stack addresses or something similar.</p></li> <li><p>Codes which double-buffer, or ping-pong between source and destination arrays that are input on odd iterations and output on even iterations (for example, the snippet shown below), can be accommodated by capturing two graphs: one per even iteration, one per odd iteration.</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="kt">int</span><span class="o">*</span><span class="w"> </span><span class="n">src</span><span class="p">;</span><span class="w"></span> <span class="kt">int</span><span class="o">*</span><span class="w"> </span><span class="n">dest</span><span class="p">;</span><span class="w"></span> <span class="k">while</span><span class="w"> </span><span class="p">(</span><span class="n">err</span><span class="w"> </span><span class="o">&gt;</span><span class="w"> </span><span class="n">tolerance</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="kt">int</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="n">N</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="o">++</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="n">dest</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">foo</span><span class="p">(</span><span class="n">src</span><span class="p">[</span><span class="n">i</span><span class="p">]);</span><span class="w"></span> <span class="w"> </span><span class="p">}</span><span class="w"></span> <span class="w"> </span><span class="n">err</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">bar</span><span class="p">(</span><span class="n">dest</span><span class="p">);</span><span class="w"></span> <span class="w"> </span><span class="kt">int</span><span class="o">*</span><span class="w"> </span><span class="n">tmp</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">dest</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="n">dest</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">src</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="n">src</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">tmp</span><span class="p">;</span><span class="w"></span> <span class="p">}</span><span class="w"></span> </pre></div> </div> </li> <li><p>Many CUDA library calls, like cublas, etc. can occur in a captured region. Setup for the library calls, such as creating handles, and computing and allocating workspace requirements, should be done before the capture region.</p></li> <li><p>Graph capturing is thread-safe with respect to each async queue. Host threads can independently capture graphs using different async queues.</p></li> <li><p>When <code class="docutils literal notranslate"><span class="pre">-gpu=tripcount:device</span></code> is used, loop trip counts can vary between runs of the same captured graph, as long as the trip count is updated on the device.</p></li> </ul> <p>The OpenACC API follows the basic portion of the CUDA Graph API fairly closely. The major difference is OpenACC includes the <code class="docutils literal notranslate"><span class="pre">cudaGraphInstantiate()</span></code> call as part of the end capture function.</p> <p>From Fortran, the graph type is defined in the OpenACC module:</p> <div class="highlight-fortran notranslate"><div class="highlight"><pre><span></span><span class="k">type</span><span class="p">,</span><span class="w"> </span><span class="k">bind</span><span class="p">(</span><span class="n">c</span><span class="p">)</span><span class="w"> </span><span class="kd">::</span><span class="w"> </span><span class="n">acc_graph_t</span><span class="w"></span> <span class="w"> </span><span class="k">type</span><span class="p">(</span><span class="kt">c_ptr</span><span class="p">)</span><span class="w"> </span><span class="kd">::</span><span class="w"> </span><span class="n">graph</span><span class="w"></span> <span class="w"> </span><span class="k">type</span><span class="p">(</span><span class="kt">c_ptr</span><span class="p">)</span><span class="w"> </span><span class="kd">::</span><span class="w"> </span><span class="n">graph_exec</span><span class="w"></span> <span class="k">end type </span><span class="n">acc_graph_t</span><span class="w"></span> </pre></div> </div> <p>These subroutines are available in the OpenACC runtime. Here, pGraph is type(acc_graph_t) and async is just the asynchronous queue value:</p> <div class="highlight-fortran notranslate"><div class="highlight"><pre><span></span><span class="k">subroutine </span><span class="n">accx_async_begin_capture</span><span class="p">(</span><span class="w"> </span><span class="n">async</span><span class="w"> </span><span class="p">)</span><span class="w"></span> <span class="k">subroutine </span><span class="n">accx_async_end_capture</span><span class="p">(</span><span class="w"> </span><span class="n">async</span><span class="p">,</span><span class="w"> </span><span class="n">pGraph</span><span class="w"> </span><span class="p">)</span><span class="w"></span> <span class="k">subroutine </span><span class="n">accx_graph_launch</span><span class="p">(</span><span class="w"> </span><span class="n">pGraph</span><span class="p">,</span><span class="w"> </span><span class="n">async</span><span class="w"> </span><span class="p">)</span><span class="w"></span> <span class="k">subroutine </span><span class="n">accx_graph_delete</span><span class="p">(</span><span class="w"> </span><span class="n">pGraph</span><span class="w"> </span><span class="p">)</span><span class="w"></span> <span class="k">type</span><span class="p">(</span><span class="kt">c_ptr</span><span class="p">)</span><span class="w"> </span><span class="k">function </span><span class="n">accx_get_graph</span><span class="p">(</span><span class="w"> </span><span class="n">pGraph</span><span class="w"> </span><span class="p">)</span><span class="w"></span> <span class="k">type</span><span class="p">(</span><span class="kt">c_ptr</span><span class="p">)</span><span class="w"> </span><span class="k">function </span><span class="n">accx_get_graph_exec</span><span class="p">(</span><span class="w"> </span><span class="n">pGraph</span><span class="w"> </span><span class="p">)</span><span class="w"></span> </pre></div> </div> <p>From C, the graph type is defined in OpenACC.h:</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="k">typedef</span><span class="w"> </span><span class="k">struct</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="o">*</span><span class="n">graph</span><span class="p">;</span><span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="o">*</span><span class="n">graph_exec</span><span class="p">;</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="n">acc_graph_t</span><span class="p">;</span><span class="w"></span> </pre></div> </div> <p>These void functions are available in the OpenACC runtime:</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="k">extern</span><span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="nf">accx_async_begin_capture</span><span class="p">(</span><span class="kt">long</span><span class="w"> </span><span class="n">async</span><span class="p">);</span><span class="w"></span> <span class="k">extern</span><span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="nf">accx_async_end_capture</span><span class="p">(</span><span class="kt">long</span><span class="w"> </span><span class="n">async</span><span class="p">,</span><span class="w"> </span><span class="n">acc_graph_t</span><span class="w"> </span><span class="o">*</span><span class="n">pgraph</span><span class="p">);</span><span class="w"></span> <span class="k">extern</span><span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="nf">accx_graph_launch</span><span class="p">(</span><span class="n">acc_graph_t</span><span class="w"> </span><span class="o">*</span><span class="n">pgraph</span><span class="p">,</span><span class="w"> </span><span class="kt">long</span><span class="w"> </span><span class="n">async</span><span class="p">);</span><span class="w"></span> <span class="k">extern</span><span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="nf">accx_graph_delete</span><span class="p">(</span><span class="n">acc_graph_t</span><span class="w"> </span><span class="o">*</span><span class="n">pgraph</span><span class="p">);</span><span class="w"></span> <span class="k">extern</span><span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="o">*</span><span class="nf">accx_get_graph</span><span class="p">(</span><span class="n">acc_graph_t</span><span class="w"> </span><span class="o">*</span><span class="n">pgraph</span><span class="p">);</span><span class="w"></span> <span class="k">extern</span><span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="o">*</span><span class="nf">accx_get_graph_exec</span><span class="p">(</span><span class="n">acc_graph_t</span><span class="w"> </span><span class="o">*</span><span class="n">pgraph</span><span class="p">);</span><span class="w"></span> </pre></div> </div> <p>We will use a simple Fortran example code which demonstrates some of the modifications needed to use CUDA Graphs from OpenACC. The original serial code for a conjugate gradient iterative solver:</p> <div class="highlight-fortran notranslate"><div class="highlight"><pre><span></span><span class="k">subroutine </span><span class="n">RunCG</span><span class="p">(</span><span class="n">N</span><span class="p">,</span><span class="w"> </span><span class="n">A</span><span class="p">,</span><span class="w"> </span><span class="n">b</span><span class="p">,</span><span class="w"> </span><span class="n">x</span><span class="p">,</span><span class="w"> </span><span class="n">tol</span><span class="p">,</span><span class="w"> </span><span class="n">max_iter</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="k">implicit none</span> <span class="k"> </span><span class="kt">integer</span><span class="p">,</span><span class="w"> </span><span class="k">intent</span><span class="p">(</span><span class="n">in</span><span class="p">)</span><span class="w"> </span><span class="kd">::</span><span class="w"> </span><span class="n">N</span><span class="p">,</span><span class="w"> </span><span class="n">max_iter</span><span class="w"></span> <span class="w"> </span><span class="kt">real</span><span class="p">(</span><span class="n">WP</span><span class="p">),</span><span class="w"> </span><span class="k">intent</span><span class="p">(</span><span class="n">in</span><span class="p">)</span><span class="w"> </span><span class="kd">::</span><span class="w"> </span><span class="n">A</span><span class="p">(</span><span class="n">N</span><span class="p">,</span><span class="w"> </span><span class="n">N</span><span class="p">),</span><span class="w"> </span><span class="n">b</span><span class="p">(</span><span class="n">N</span><span class="p">),</span><span class="w"> </span><span class="n">tol</span><span class="w"></span> <span class="w"> </span><span class="kt">real</span><span class="p">(</span><span class="n">WP</span><span class="p">),</span><span class="w"> </span><span class="k">intent</span><span class="p">(</span><span class="n">inout</span><span class="p">)</span><span class="w"> </span><span class="kd">::</span><span class="w"> </span><span class="n">x</span><span class="p">(</span><span class="n">N</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="kt">real</span><span class="p">(</span><span class="n">WP</span><span class="p">)</span><span class="w"> </span><span class="kd">::</span><span class="w"> </span><span class="n">alpha</span><span class="p">,</span><span class="w"> </span><span class="n">rr0</span><span class="p">,</span><span class="w"> </span><span class="n">rr</span><span class="w"></span> <span class="w"> </span><span class="kt">real</span><span class="p">(</span><span class="n">WP</span><span class="p">),</span><span class="w"> </span><span class="k">allocatable</span><span class="w"> </span><span class="kd">::</span><span class="w"> </span><span class="n">Ax</span><span class="p">(:),</span><span class="w"> </span><span class="n">r</span><span class="p">(:),</span><span class="w"> </span><span class="n">p</span><span class="p">(:)</span><span class="w"></span> <span class="w"> </span><span class="kt">integer</span><span class="w"> </span><span class="kd">::</span><span class="w"> </span><span class="n">it</span><span class="p">,</span><span class="w"> </span><span class="n">i</span><span class="w"></span> <span class="w"> </span><span class="k">allocate</span><span class="p">(</span><span class="n">Ax</span><span class="p">(</span><span class="n">N</span><span class="p">),</span><span class="w"> </span><span class="n">r</span><span class="p">(</span><span class="n">N</span><span class="p">),</span><span class="w"> </span><span class="n">p</span><span class="p">(</span><span class="n">N</span><span class="p">))</span><span class="w"></span> <span class="w"> </span><span class="k">call </span><span class="n">symmatvec</span><span class="p">(</span><span class="n">N</span><span class="p">,</span><span class="w"> </span><span class="n">N</span><span class="p">,</span><span class="w"> </span><span class="n">A</span><span class="p">,</span><span class="w"> </span><span class="n">x</span><span class="p">,</span><span class="w"> </span><span class="n">Ax</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="k">do </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="n">N</span><span class="w"></span> <span class="w"> </span><span class="n">r</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">b</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">Ax</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="n">p</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">r</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="k">enddo</span> <span class="k"> </span><span class="n">rr0</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">dot</span><span class="p">(</span><span class="n">N</span><span class="p">,</span><span class="w"> </span><span class="n">r</span><span class="p">,</span><span class="w"> </span><span class="n">r</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="k">do </span><span class="n">it</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="n">max_iter</span><span class="w"></span> <span class="w"> </span><span class="k">call </span><span class="n">symmatvec</span><span class="p">(</span><span class="n">N</span><span class="p">,</span><span class="w"> </span><span class="n">N</span><span class="p">,</span><span class="w"> </span><span class="n">A</span><span class="p">,</span><span class="w"> </span><span class="n">p</span><span class="p">,</span><span class="w"> </span><span class="n">Ax</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="n">alpha</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">rr0</span><span class="w"> </span><span class="o">/</span><span class="w"> </span><span class="n">dot</span><span class="p">(</span><span class="n">N</span><span class="p">,</span><span class="w"> </span><span class="n">p</span><span class="p">,</span><span class="w"> </span><span class="n">Ax</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="k">do </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="n">N</span><span class="w"></span> <span class="w"> </span><span class="n">x</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">x</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">alpha</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">p</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="n">r</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">r</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">alpha</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">Ax</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="k">enddo</span> <span class="k"> </span><span class="n">rr</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">dot</span><span class="p">(</span><span class="n">N</span><span class="p">,</span><span class="w"> </span><span class="n">r</span><span class="p">,</span><span class="w"> </span><span class="n">r</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="k">print</span><span class="o">*</span><span class="p">,</span><span class="w"> </span><span class="s2">&quot;Iteration &quot;</span><span class="p">,</span><span class="w"> </span><span class="n">it</span><span class="p">,</span><span class="w"> </span><span class="s2">&quot; residual: &quot;</span><span class="p">,</span><span class="w"> </span><span class="nb">sqrt</span><span class="p">(</span><span class="n">rr</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="nb">sqrt</span><span class="p">(</span><span class="n">rr</span><span class="p">)</span><span class="w"> </span><span class="o">&lt;=</span><span class="w"> </span><span class="n">tol</span><span class="p">)</span><span class="w"> </span><span class="k">then</span> <span class="k"> deallocate</span><span class="p">(</span><span class="n">Ax</span><span class="p">,</span><span class="w"> </span><span class="n">r</span><span class="p">,</span><span class="w"> </span><span class="n">p</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="k">return</span> <span class="k"> endif</span> <span class="k"> do </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="n">N</span><span class="w"></span> <span class="w"> </span><span class="n">p</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">r</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="p">(</span><span class="n">rr</span><span class="w"> </span><span class="o">/</span><span class="w"> </span><span class="n">rr0</span><span class="p">)</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">p</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="k">enddo</span> <span class="k"> </span><span class="n">rr0</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">rr</span><span class="w"></span> <span class="w"> </span><span class="k">enddo</span> <span class="k"> deallocate</span><span class="p">(</span><span class="n">Ax</span><span class="p">,</span><span class="w"> </span><span class="n">r</span><span class="p">,</span><span class="w"> </span><span class="n">p</span><span class="p">)</span><span class="w"></span> <span class="k">end subroutine </span><span class="n">RunCG</span><span class="w"></span> </pre></div> </div> <p>For this exercise we wish to put the <code class="docutils literal notranslate"><span class="pre">do</span> <span class="pre">it</span> <span class="pre">=</span> <span class="pre">1,max_iter</span></code> work for each iteration into a CUDA graph. Step one is to port the code to OpenACC, keeping in mind that we want to use asynchronous queues. We annotate the dot function with OpenACC directives like this:</p> <div class="highlight-fortran notranslate"><div class="highlight"><pre><span></span><span class="k">function </span><span class="n">dot</span><span class="p">(</span><span class="n">N</span><span class="p">,</span><span class="w"> </span><span class="n">x</span><span class="p">,</span><span class="w"> </span><span class="n">y</span><span class="p">)</span><span class="w"> </span><span class="k">result</span><span class="p">(</span><span class="n">r</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="kt">integer</span><span class="p">,</span><span class="w"> </span><span class="k">intent</span><span class="p">(</span><span class="n">in</span><span class="p">)</span><span class="w"> </span><span class="kd">::</span><span class="w"> </span><span class="n">N</span><span class="w"></span> <span class="w"> </span><span class="kt">real</span><span class="p">(</span><span class="n">WP</span><span class="p">),</span><span class="w"> </span><span class="k">intent</span><span class="p">(</span><span class="n">in</span><span class="p">)</span><span class="w"> </span><span class="kd">::</span><span class="w"> </span><span class="n">x</span><span class="p">(</span><span class="n">N</span><span class="p">),</span><span class="w"> </span><span class="n">y</span><span class="p">(</span><span class="n">N</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="kt">integer</span><span class="w"> </span><span class="kd">::</span><span class="w"> </span><span class="n">i</span><span class="w"></span> <span class="w"> </span><span class="kt">real</span><span class="p">(</span><span class="n">WP</span><span class="p">)</span><span class="w"> </span><span class="kd">::</span><span class="w"> </span><span class="n">r</span><span class="w"></span> <span class="w"> </span><span class="n">r</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mf">0.d0</span><span class="w"></span> <span class="w"> </span><span class="c">!$acc parallel loop present(x, y) reduction(+:r) async(1)</span> <span class="w"> </span><span class="k">do </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="n">N</span><span class="w"></span> <span class="w"> </span><span class="n">r</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">r</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">x</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">y</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="k">enddo</span><span class="w"></span> <span class="w"> </span><span class="c">!$acc wait(1)</span> <span class="k">end function </span><span class="n">dot</span><span class="w"></span> </pre></div> </div> <p>We write the symmetric matrix multiply like this:</p> <div class="highlight-fortran notranslate"><div class="highlight"><pre><span></span><span class="k">subroutine </span><span class="n">symmatvec</span><span class="p">(</span><span class="n">M</span><span class="p">,</span><span class="w"> </span><span class="n">N</span><span class="p">,</span><span class="w"> </span><span class="n">AT</span><span class="p">,</span><span class="w"> </span><span class="n">x</span><span class="p">,</span><span class="w"> </span><span class="n">Ax</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="k">implicit none</span> <span class="k"> </span><span class="kt">integer</span><span class="p">,</span><span class="w"> </span><span class="k">intent</span><span class="p">(</span><span class="n">in</span><span class="p">)</span><span class="w"> </span><span class="kd">::</span><span class="w"> </span><span class="n">M</span><span class="p">,</span><span class="w"> </span><span class="n">N</span><span class="w"></span> <span class="w"> </span><span class="kt">real</span><span class="p">(</span><span class="n">WP</span><span class="p">),</span><span class="w"> </span><span class="k">intent</span><span class="p">(</span><span class="n">in</span><span class="p">)</span><span class="w"> </span><span class="kd">::</span><span class="w"> </span><span class="n">AT</span><span class="p">(</span><span class="n">N</span><span class="p">,</span><span class="w"> </span><span class="n">M</span><span class="p">),</span><span class="w"> </span><span class="n">x</span><span class="p">(</span><span class="n">N</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="kt">real</span><span class="p">(</span><span class="n">WP</span><span class="p">),</span><span class="w"> </span><span class="k">intent</span><span class="p">(</span><span class="n">out</span><span class="p">)</span><span class="w"> </span><span class="kd">::</span><span class="w"> </span><span class="n">Ax</span><span class="p">(</span><span class="n">M</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="kt">integer</span><span class="w"> </span><span class="kd">::</span><span class="w"> </span><span class="n">i</span><span class="p">,</span><span class="w"> </span><span class="n">j</span><span class="w"></span> <span class="w"> </span><span class="kt">real</span><span class="p">(</span><span class="n">WP</span><span class="p">)</span><span class="w"> </span><span class="kd">::</span><span class="w"> </span><span class="n">s</span><span class="w"></span> <span class="w"> </span><span class="c">! Note: Since A is symmetric, we can use the &quot;transpose&quot;</span> <span class="w"> </span><span class="c">! for better memory access here</span> <span class="w"> </span><span class="c">!$acc parallel loop gang present(AT, x, Ax) async(1)</span> <span class="w"> </span><span class="k">do </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="n">M</span><span class="w"></span> <span class="w"> </span><span class="n">s</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mf">0.d0</span><span class="w"></span> <span class="w"> </span><span class="c">!$acc loop vector reduction(+:s)</span> <span class="w"> </span><span class="k">do </span><span class="n">j</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="n">N</span><span class="w"></span> <span class="w"> </span><span class="n">s</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">s</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">AT</span><span class="p">(</span><span class="n">j</span><span class="p">,</span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">x</span><span class="p">(</span><span class="n">j</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="k">end do</span> <span class="k"> </span><span class="n">Ax</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">s</span><span class="w"></span> <span class="w"> </span><span class="k">end do</span> <span class="k">end subroutine</span><span class="w"></span> </pre></div> </div> <p>And now our main loop of the conjugate gradient solver looks like this:</p> <div class="highlight-fortran notranslate"><div class="highlight"><pre><span></span><span class="k">do </span><span class="n">it</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="n">max_iter</span><span class="w"></span> <span class="w"> </span><span class="k">call </span><span class="n">symmatvec</span><span class="p">(</span><span class="n">N</span><span class="p">,</span><span class="w"> </span><span class="n">N</span><span class="p">,</span><span class="w"> </span><span class="n">A</span><span class="p">,</span><span class="w"> </span><span class="n">p</span><span class="p">,</span><span class="w"> </span><span class="n">Ax</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="n">alpha</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">rr0</span><span class="w"> </span><span class="o">/</span><span class="w"> </span><span class="n">dot</span><span class="p">(</span><span class="n">N</span><span class="p">,</span><span class="w"> </span><span class="n">p</span><span class="p">,</span><span class="w"> </span><span class="n">Ax</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="c">!$acc parallel loop gang vector async(1)</span> <span class="w"> </span><span class="k">do </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="n">N</span><span class="w"></span> <span class="w"> </span><span class="n">x</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">x</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">alpha</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">p</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="n">r</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">r</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">alpha</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">Ax</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="k">enddo</span> <span class="k"> </span><span class="n">rr</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">dot</span><span class="p">(</span><span class="n">N</span><span class="p">,</span><span class="w"> </span><span class="n">r</span><span class="p">,</span><span class="w"> </span><span class="n">r</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="k">print</span><span class="o">*</span><span class="p">,</span><span class="w"> </span><span class="s2">&quot;Iteration &quot;</span><span class="p">,</span><span class="w"> </span><span class="n">it</span><span class="p">,</span><span class="w"> </span><span class="s2">&quot; residual: &quot;</span><span class="p">,</span><span class="w"> </span><span class="nb">sqrt</span><span class="p">(</span><span class="n">rr</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="nb">sqrt</span><span class="p">(</span><span class="n">rr</span><span class="p">)</span><span class="w"> </span><span class="o">&lt;=</span><span class="w"> </span><span class="n">tol</span><span class="p">)</span><span class="w"> </span><span class="k">exit</span><span class="w"></span> <span class="w"> </span><span class="c">!$acc parallel loop gang vector async(1)</span> <span class="w"> </span><span class="k">do </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="n">N</span><span class="w"></span> <span class="w"> </span><span class="n">p</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">r</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="p">(</span><span class="n">rr</span><span class="w"> </span><span class="o">/</span><span class="w"> </span><span class="n">rr0</span><span class="p">)</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">p</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="k">enddo</span> <span class="k"> </span><span class="n">rr0</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">rr</span><span class="w"></span> <span class="k">enddo</span><span class="w"></span> </pre></div> </div> <p>Step 2 is to prepare the code for running under CUDA Graphs. There is a lot of host code executing in the main loop. While the <code class="docutils literal notranslate"><span class="pre">dot()</span></code> function runs on the GPU, the rest of the statement <code class="docutils literal notranslate"><span class="pre">alpha</span> <span class="pre">=</span> <span class="pre">rr0</span> <span class="pre">/</span> <span class="pre">dot(...)</span></code> runs on the host. Similarly, the 2nd <code class="docutils literal notranslate"><span class="pre">dot()</span></code> call returns its value to the host. The print statement occurs on the host, as does the residual check. Finally, this iteration’s value for rr is moved to rr0 in the last statement of the loop, on the host.</p> <p>The dot product is tricky. We wish to compute the dot product on the GPU, and leave the result on the GPU, so the reduction variable must be present on the GPU. Here, we change the function call to a subroutine, and remove the initialization which is outside of the parallel region:</p> <div class="highlight-fortran notranslate"><div class="highlight"><pre><span></span><span class="k">subroutine </span><span class="n">dot</span><span class="p">(</span><span class="n">N</span><span class="p">,</span><span class="w"> </span><span class="n">x</span><span class="p">,</span><span class="w"> </span><span class="n">y</span><span class="p">,</span><span class="w"> </span><span class="n">r</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="k">implicit none</span> <span class="k"> </span><span class="kt">integer</span><span class="p">,</span><span class="w"> </span><span class="k">intent</span><span class="p">(</span><span class="n">in</span><span class="p">)</span><span class="w"> </span><span class="kd">::</span><span class="w"> </span><span class="n">N</span><span class="w"></span> <span class="w"> </span><span class="kt">real</span><span class="p">(</span><span class="n">WP</span><span class="p">),</span><span class="w"> </span><span class="k">intent</span><span class="p">(</span><span class="n">in</span><span class="p">)</span><span class="w"> </span><span class="kd">::</span><span class="w"> </span><span class="n">x</span><span class="p">(</span><span class="n">N</span><span class="p">),</span><span class="w"> </span><span class="n">y</span><span class="p">(</span><span class="n">N</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="kt">integer</span><span class="w"> </span><span class="kd">::</span><span class="w"> </span><span class="n">i</span><span class="w"></span> <span class="w"> </span><span class="kt">real</span><span class="p">(</span><span class="n">WP</span><span class="p">)</span><span class="w"> </span><span class="kd">::</span><span class="w"> </span><span class="n">r</span><span class="w"></span> <span class="w"> </span><span class="c">!$acc parallel loop present(x, y, r) reduction(+:r) async(1)</span> <span class="w"> </span><span class="k">do </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="n">N</span><span class="w"></span> <span class="w"> </span><span class="n">r</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">r</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">x</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">y</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="k">enddo</span> <span class="k">end subroutine </span><span class="n">dot</span><span class="w"></span> </pre></div> </div> <p>We add one serial kernel to do some of the swapping between rr0 and rr, as well as zeroing out the scalar that will hold the dot product reduction, and move the print and check outside of the GPU capture region, replaced by a update host operation. The finished loop, complete with graph control, looks like this:</p> <div class="highlight-fortran notranslate"><div class="highlight"><pre><span></span><span class="k">do </span><span class="n">it</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="n">max_iter</span><span class="w"></span> <span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">it</span><span class="w"> </span><span class="p">.</span><span class="n">eq</span><span class="p">.</span><span class="w"> </span><span class="mi">1</span><span class="p">)</span><span class="w"> </span><span class="k">then</span><span class="w"> </span><span class="c">! First time capture</span> <span class="w"> </span><span class="k">call </span><span class="n">accx_async_begin_capture</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="k">call </span><span class="n">symmatvec</span><span class="p">(</span><span class="n">N</span><span class="p">,</span><span class="w"> </span><span class="n">N</span><span class="p">,</span><span class="w"> </span><span class="n">A</span><span class="p">,</span><span class="w"> </span><span class="n">p</span><span class="p">,</span><span class="w"> </span><span class="n">Ax</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="k">call </span><span class="n">dot</span><span class="p">(</span><span class="n">N</span><span class="p">,</span><span class="w"> </span><span class="n">p</span><span class="p">,</span><span class="w"> </span><span class="n">Ax</span><span class="p">,</span><span class="w"> </span><span class="n">rden</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="c">!$acc serial async(1)</span> <span class="w"> </span><span class="n">rr0</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">rr</span><span class="w"></span> <span class="w"> </span><span class="n">alpha</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">rr0</span><span class="w"> </span><span class="o">/</span><span class="w"> </span><span class="n">rden</span><span class="w"></span> <span class="w"> </span><span class="n">rden</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mf">0.0d0</span><span class="w"></span> <span class="w"> </span><span class="n">rr</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mf">0.0d0</span><span class="w"></span> <span class="w"> </span><span class="c">!$acc end serial</span> <span class="w"> </span><span class="c">!$acc parallel loop gang vector async(1)</span> <span class="w"> </span><span class="k">do </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="n">N</span><span class="w"></span> <span class="w"> </span><span class="n">x</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">x</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">alpha</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">p</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="n">r</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">r</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">alpha</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">Ax</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="k">enddo</span> <span class="k"> call </span><span class="n">dot</span><span class="p">(</span><span class="n">N</span><span class="p">,</span><span class="w"> </span><span class="n">r</span><span class="p">,</span><span class="w"> </span><span class="n">r</span><span class="p">,</span><span class="w"> </span><span class="n">rr</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="c">!$acc update host(rr) async(1)</span> <span class="w"> </span><span class="c">!$acc parallel loop gang vector async(1)</span> <span class="w"> </span><span class="k">do </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="n">N</span><span class="w"></span> <span class="w"> </span><span class="n">p</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">r</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="p">(</span><span class="n">rr</span><span class="w"> </span><span class="o">/</span><span class="w"> </span><span class="n">rr0</span><span class="p">)</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">p</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="k">enddo</span> <span class="k"> call </span><span class="n">accx_async_end_capture</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="n">graph</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="k">endif</span><span class="w"></span> <span class="w"> </span><span class="c">! Always launch, then wait</span> <span class="w"> </span><span class="k">call </span><span class="n">accx_graph_launch</span><span class="p">(</span><span class="n">graph</span><span class="p">,</span><span class="w"> </span><span class="mi">1</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="c">!$acc wait(1)</span> <span class="w"> </span><span class="n">rra</span><span class="p">(</span><span class="n">it</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">rr</span><span class="w"></span> <span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="nb">sqrt</span><span class="p">(</span><span class="n">rr</span><span class="p">)</span><span class="w"> </span><span class="o">&lt;=</span><span class="w"> </span><span class="n">tol</span><span class="p">)</span><span class="w"> </span><span class="k">exit</span> <span class="k">enddo</span><span class="w"></span> </pre></div> </div> <p>Step 3 is to compile, run, and profile the result. No special compiler options are needed besides -acc=gpu. When running, you may be advised to set the <code class="docutils literal notranslate"><span class="pre">NVCOMPILER_ACC_USE_GRAPH</span></code> environment variable. This is currently necessary to properly set the OpenACC runtime for graph capture. Failure to abide by the guidelines above may result in wrong answers, which can be hard to debug. See the following sections on how to use environment variables to help. A common issue is that the pointers passed to the device kernels during graph playback will be the same every time. Make sure that is the case between iterations in the code without graph capture.</p> <p>The Nsight Systems tool has very good support for profiling CUDA graphs. The timeline view will provide information on whether you have reduced the launch overhead gaps between the GPU kernels. <a class="reference internal" href="#openacc-cuda-graphs-nsys-cg-report1-timeline-fig"><span class="std std-ref">Figure 1</span></a> shows a timeline of the iterations of the original OpenACC loop:</p> <figure class="align-center" id="openacc-cuda-graphs-nsys-cg-report1-timeline-fig"> <img alt="_images/nsys-cg-report1-timeline.png" src="_images/nsys-cg-report1-timeline.png" /> <figcaption> <p><span class="caption-text">Figure 1. Nsight Systems Report1 Timeline</span><a class="headerlink" href="#openacc-cuda-graphs-nsys-cg-report1-timeline-fig" title="Permalink to this image"></a></p> </figcaption> </figure> <p><a class="reference internal" href="#openacc-cuda-graphs-nsys-cg-report2-timeline-fig"><span class="std std-ref">Figure 2</span></a> shows a timeline of the iterations when using CUDA Graphs. When the size N is less than a few thousand, launch latency becomes a major contributor to the overall time and here we can see about a 2x speedup:</p> <figure class="align-center" id="openacc-cuda-graphs-nsys-cg-report2-timeline-fig"> <img alt="_images/nsys-cg-report2-timeline.png" src="_images/nsys-cg-report2-timeline.png" /> <figcaption> <p><span class="caption-text">Figure 2. Nsight Systems Report2 Timeline</span><a class="headerlink" href="#openacc-cuda-graphs-nsys-cg-report2-timeline-fig" title="Permalink to this image"></a></p> </figcaption> </figure> <p>You can see a more-detailed trace of the CUDA Graph components by adding the <code class="docutils literal notranslate"><span class="pre">--cuda-graph-trace=node</span></code> option to the nsys profile command.</p> <p>The above loop demonstrates several of the guidelines outlined at the top of this section, namely, capturing compute regions, whether at the top level or in subprogram units, capturing data movement, and restructuring code regions to minimize or eliminate the host code within a capture region. And the minimal API to begin capture, end capture, then launch the captured graph.</p> </section> <section id="host-and-device-trip-count-options"> <h2><span class="section-number">6.7. </span>Host and Device Trip Count Options<a class="headerlink" href="#host-and-device-trip-count-options" title="Permalink to this headline"></a></h2> <p>The <code class="docutils literal notranslate"><span class="pre">-gpu=tripcount</span></code> option controls whether the trip counts for loops in a compute construct, such as <code class="docutils literal notranslate"><span class="pre">acc</span> <span class="pre">parallel</span> <span class="pre">loop</span></code>, are calculated on the host or on the device. The default behavior of the NVHPC compilers is to use the values calculated on the host, though the OpenACC specification states that trip count values should be calculated on the device. We have chosen to maintain, as-is, the default behavior so as not to interfere with existing applications that currently depend on it for correctness. To ensure compliance with the specification, please use the <code class="docutils literal notranslate"><span class="pre">-gpu=tripcount:device</span></code> option. To maintain the default behavior, please use <code class="docutils literal notranslate"><span class="pre">-gpu=tripcount:host</span></code> or do not specify a <code class="docutils literal notranslate"><span class="pre">-gpu=tripcount</span></code> option.</p> <p>To emit a warning at compile-time that an OpenACC program may be using host values for trip counts, use <code class="docutils literal notranslate"><span class="pre">-gpu=tripcount:warn</span></code>, or use <code class="docutils literal notranslate"><span class="pre">-gpu=tripcount:nowarn</span></code> to disable these warnings.</p> <p>To check at runtime whether the host and device values for trip counts are the same, use <code class="docutils literal notranslate"><span class="pre">-gpu=tripcount:check</span></code>. Set the environment variable <code class="docutils literal notranslate"><span class="pre">NVCOMPILER_ACC_CHECK_TRIPCOUNT</span></code> to enable reporting of any differences discovered. To disable these checks, use <code class="docutils literal notranslate"><span class="pre">-gpu=tripcount:nocheck</span></code>.</p> <section id="when-to-use-gpu-tripcount-device-or-gpu-tripcount-host"> <h3><span class="section-number">6.7.1. </span>When to Use <code class="docutils literal notranslate"><span class="pre">-gpu=tripcount:device</span></code> or <code class="docutils literal notranslate"><span class="pre">-gpu=tripcount:host</span></code><a class="headerlink" href="#when-to-use-gpu-tripcount-device-or-gpu-tripcount-host" title="Permalink to this headline"></a></h3> <p>Consider the following example code snippet:</p> <div class="highlight-fortran notranslate"><div class="highlight"><pre><span></span><span class="kt">real</span><span class="w"> </span><span class="kd">::</span><span class="w"> </span><span class="k">array</span><span class="p">(</span><span class="mi">1000</span><span class="p">,</span><span class="w"> </span><span class="mi">10</span><span class="p">)</span><span class="w"></span> <span class="kt">integer</span><span class="w"> </span><span class="kd">::</span><span class="w"> </span><span class="n">i</span><span class="p">,</span><span class="w"> </span><span class="n">j</span><span class="p">,</span><span class="w"> </span><span class="n">n</span><span class="p">,</span><span class="w"> </span><span class="n">m</span><span class="w"></span> <span class="c">!$acc data create(n, m) copy(array)</span> <span class="c">!$acc kernels</span> <span class="n">n</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">1000</span><span class="w"></span> <span class="n">m</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">10</span><span class="w"></span> <span class="c">!$acc end kernels</span> <span class="c">!$acc parallel loop defualt(none) collapse(2)</span> <span class="k">do </span><span class="n">j</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span><span class="n">m</span><span class="w"></span> <span class="w"> </span><span class="k">do </span><span class="n">i</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span><span class="n">n</span><span class="w"></span> <span class="w"> </span><span class="k">array</span><span class="p">(</span><span class="n">i</span><span class="p">,</span><span class="w"> </span><span class="n">j</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">i</span><span class="o">+</span><span class="n">j</span><span class="w"></span> <span class="w"> </span><span class="k">end do</span> <span class="k">end do</span><span class="w"></span> </pre></div> </div> <p>The trip count variables <code class="docutils literal notranslate"><span class="pre">n</span></code> and <code class="docutils literal notranslate"><span class="pre">m</span></code> are created on the device, and then their values are set on the device in the <code class="docutils literal notranslate"><span class="pre">acc</span> <span class="pre">kernels</span></code> construct. Their values are not set on the host. Therefore, when the parallel loop is run on the device, if the host values for <code class="docutils literal notranslate"><span class="pre">n</span></code> and <code class="docutils literal notranslate"><span class="pre">m</span></code> are used, the loop will not run for the correct number of iterations. In this and similar cases, to ensure the correctness of the program, <code class="docutils literal notranslate"><span class="pre">-gpu=tripcount:device</span></code> should be used.</p> <p>In cases where the values of <code class="docutils literal notranslate"><span class="pre">n</span></code> and <code class="docutils literal notranslate"><span class="pre">m</span></code> are set on the host, it is sufficient to rely on the default behavior or to specify <code class="docutils literal notranslate"><span class="pre">-gpu=tripcount:host</span></code>. There are two ways to verify whether or not the program’s correctness may be affected by the use of <code class="docutils literal notranslate"><span class="pre">-gpu=tripcount:device</span></code> versus <code class="docutils literal notranslate"><span class="pre">-gpu=tripcount:host</span></code>. The <code class="docutils literal notranslate"><span class="pre">-gpu=tripcount:check</span></code> option can be used to detect discrepancies between host and device values for trip counts at runtime, and the <code class="docutils literal notranslate"><span class="pre">-gpu=tripcount:warn</span></code> option can be used to issue compile-time warnings that host values for trip counts may be used.</p> <p>Note: For CUDA Graphs, <code class="docutils literal notranslate"><span class="pre">-gpu=tripcount:device</span></code> allows trip counts to vary between runs for captured graphs on the device, as long as the trip count is updated on the device. This behavior can affect the correctness of CUDA Graphs, and some applications may require this option to use CUDA Graphs correctly.</p> <span class="target" id="env-vars"></span></section> </section> <section id="environment-variables"> <h2><span class="section-number">6.8. </span>Environment Variables<a class="headerlink" href="#environment-variables" title="Permalink to this headline"></a></h2> <p>This section summarizes the environment variables that NVIDIA OpenACC supports. These environment variables are user-setable environment variables that control behavior of accelerator-enabled programs at execution. These environment variables must comply with these rules:</p> <ul class="simple"> <li><p>The names of the environment variables must be upper case.</p></li> <li><p>The values of environment variables are case insensitive and may have leading and trailing white space.</p></li> <li><p>The behavior is implementation-defined if the values of the environment variables change after the program has started, even if the program itself modifies the values.</p></li> </ul> <p>The following table contains the environment variables that are currently supported and provides a brief description of each.</p> <table class="table-no-stripes docutils align-default" id="id27"> <caption><span class="caption-text">Table 16. Supported Environment Variables</span><a class="headerlink" href="#id27" title="Permalink to this table"></a></caption> <colgroup> <col style="width: 8%" /> <col style="width: 92%" /> </colgroup> <thead> <tr class="row-odd"><th class="head"><p>Use this environment variable…</p></th> <th class="head"><p>To do this…</p></th> </tr> </thead> <tbody> <tr class="row-even"><td><p>NVCOMPILER_ACC_CHECK_TRIPCOUNT</p></td> <td><p>Enable output for checking differences between host and device trip counts when <code class="docutils literal notranslate"><span class="pre">-gpu=tripcount:check</span></code> is used.</p></td> </tr> <tr class="row-odd"><td><p>NVCOMPILER_ACC_CUDA_PROFSTOP</p></td> <td><p>Set to 1 (or any positive value) to tell the runtime environment to insert an ‘atexit(cuProfilerStop)’ call upon exit. This behavior may be desired in the case where a profile is incomplete or where a message is issued to call cudaProfilerStop().</p></td> </tr> <tr class="row-even"><td><p>NVCOMPILER_ACC_DEVICE_NUM</p></td> <td><p>Sets the default device number to use. NVCOMPILER_ACC_DEVICE_NUM. Specifies the default device number to use when executing accelerator regions. The value of this environment variable must be a nonnegative integer between zero and the number of devices attached to the host.</p></td> </tr> <tr class="row-odd"><td><p>ACC_DEVICE_NUM</p></td> <td><p>Legacy name. Superseded by NVCOMPILER_ACC_DEVICE_NUM.</p></td> </tr> <tr class="row-even"><td><p>NVCOMPILER_ACC_DEVICE_TYPE</p></td> <td><p>Sets the default device type to use for OpenACC regions. NVCOMPILER_ACC_DEVICE_TYPE. Specifies which accelerator device to use when executing accelerator regions when the program has been compiled to use more than one different type of device. The value of this environment variable is implementation-defined, and in the NVIDIA OpenACC implementation may be the strings NVIDIA, MULTICORE or HOST</p></td> </tr> <tr class="row-odd"><td><p>ACC_DEVICE_TYPE</p></td> <td><p>Legacy name. Superseded by NVCOMPILER_ACC_DEVICE_TYPE.</p></td> </tr> <tr class="row-even"><td><p>NVCOMPILER_ACC_GANGLIMIT</p></td> <td><p>For NVIDIA CUDA devices, this defines the maximum number of gangs (CUDA thread blocks) that will be launched by a kernel.</p></td> </tr> <tr class="row-odd"><td><p>NVCOMPILER_ACC_NOTIFY</p></td> <td><p>With no argument, a debug message will be written to stderr for each kernel launch and/or data transfer. When set to an integer value, the value is used as a bit mask to print information about: 1: kernel launches</p> <p>2: data transfers</p> <p>4: region entry/exit</p> <p>8: wait operations or synchronizations with the device</p> <p>16: device memory allocates and deallocates</p> </td> </tr> <tr class="row-even"><td><p>NVCOMPILER_ACC_PROFLIB</p></td> <td><p>Enables 3rd party tools interface using the new profiler dynamic library interface.</p></td> </tr> <tr class="row-odd"><td><p>NVCOMPILER_ACC_SYNCHRONOUS</p></td> <td><p>Disables asynchronous launches and data movement.</p></td> </tr> <tr class="row-even"><td><p>NVCOMPILER_ACC_TIME</p></td> <td><p>Enables a lightweight profiler to measure data movement and accelerator kernel execution time and print a summary at the end of program execution.</p></td> </tr> </tbody> </table> </section> <section id="profiling-accelerator-kernels"> <h2><span class="section-number">6.9. </span>Profiling Accelerator Kernels<a class="headerlink" href="#profiling-accelerator-kernels" title="Permalink to this headline"></a></h2> <p><strong>Support for Profiler/Trace Tool Interface</strong></p> <p>The NVIDIA HPC Compilers support the OpenACC Profiler/Trace Tools Interface. This is the interface used by the NVIDIA profilers to collect performance measurements of OpenACC programs.</p> <p><strong>Using NVCOMPILER_ACC_TIME</strong></p> <p>Setting the environment variable NVCOMPILER_ACC_TIME to a nonzero value enables collection and printing of simple timing information about the accelerator regions and generated kernels.</p> <div class="admonition note"> <p class="admonition-title">Note</p> <p>Turn off all CUDA Profilers (NVIDIA’s Visual Profiler, NVPROF, CUDA_PROFILE, etc) when enabling NVCOMPILER_ACC_TIME, they use the same library to gather performance data and cannot be used concurently.</p> </div> <p><strong>Accelerator Kernel Timing Data</strong></p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>bb04.f90 s1 15: region entered 1 times time(us): total=1490738 init=1489138 region=1600 kernels=155 data=1445 w/o init: total=1600 max=1600 min=1600 avg=1600 18: kernel launched 1 times time(us): total=155 max=155 min=155 avg=155 </pre></div> </div> <p>In this example, a number of things are occurring:</p> <ul class="simple"> <li><p>For each accelerator region, the file name bb04.f90 and subroutine or function name s1 is printed, with the line number of the accelerator region, which in the example is 15.</p></li> <li><p>The library counts how many times the region is entered (1 in the example) and the microseconds spent in the region (in this example 1490738), which is split into initialization time (in this example 1489138) and execution time (in this example 1600).</p></li> <li><p>The execution time is then divided into kernel execution time and data transfer time between the host and GPU.</p></li> <li><p>For each kernel, the line number is given, (18 in the example), along with a count of kernel launches, and the total, maximum, minimum, and average time spent in the kernel, all of which are 155 in this example.</p></li> </ul> </section> <section id="openacc-runtime-libraries"> <h2><span class="section-number">6.10. </span>OpenACC Runtime Libraries<a class="headerlink" href="#openacc-runtime-libraries" title="Permalink to this headline"></a></h2> <p>This section provides an overview of the user-callable functions and library routines that are available for use by programmers to query the accelerator features and to control behavior of accelerator-enabled programs at runtime.</p> <div class="admonition note"> <p class="admonition-title">Note</p> <p>In Fortran, none of the OpenACC runtime library routines may be called from a PURE or ELEMENTAL procedure.</p> </div> <section id="runtime-library-definitions"> <h3><span class="section-number">6.10.1. </span>Runtime Library Definitions<a class="headerlink" href="#runtime-library-definitions" title="Permalink to this headline"></a></h3> <p>There are separate runtime library files for Fortran, and for C++ and C.</p> <p><strong>C++ and C Runtime Library Files</strong></p> <p>In C++ and C, prototypes for the runtime library routines are available in a header file named <code class="docutils literal notranslate"><span class="pre">accel.h</span></code>. All the library routines are <code class="docutils literal notranslate"><span class="pre">extern</span></code> functions with ‘C’ linkage. This file defines:</p> <ul class="simple"> <li><p>The prototypes of all routines in this section.</p></li> <li><p>Any data types used in those prototypes, including an enumeration type to describe types of accelerators.</p></li> </ul> <p><strong>Fortran Runtime Library Files</strong></p> <p>In Fortran, interface declarations are provided in a Fortran include file named <code class="docutils literal notranslate"><span class="pre">accel_lib.h</span></code> and in a Fortran module named <code class="docutils literal notranslate"><span class="pre">accel_lib</span></code>. These files define:</p> <ul class="simple"> <li><p>Interfaces for all routines in this section.</p></li> <li><p>Integer parameters to define integer kinds for arguments to those routines.</p></li> <li><p>Integer parameters to describe types of accelerators.</p></li> </ul> </section> <section id="runtime-library-routines"> <h3><span class="section-number">6.10.2. </span>Runtime Library Routines<a class="headerlink" href="#runtime-library-routines" title="Permalink to this headline"></a></h3> <p><a class="reference internal" href="#acc-openacc-lib-routines-acc-openacc-lib-routines-tbl"><span class="std std-ref">Table 17</span></a> lists and briefly describes the runtime library routines supported by the NVIDIA HPC Compilers in addition to the standard OpenACC runtine API routines.</p> <table class="table-no-stripes docutils align-default" id="acc-openacc-lib-routines-acc-openacc-lib-routines-tbl"> <caption><span class="caption-text">Table 17. Accelerator Runtime Library Routines</span><a class="headerlink" href="#acc-openacc-lib-routines-acc-openacc-lib-routines-tbl" title="Permalink to this table"></a></caption> <colgroup> <col style="width: 21%" /> <col style="width: 79%" /> </colgroup> <thead> <tr class="row-odd"><th class="head"><p>This Runtime Library Routine…</p></th> <th class="head"><p>Does this…</p></th> </tr> </thead> <tbody> <tr class="row-even"><td><p>acc_allocs</p></td> <td><p>Returns the number of arrays allocated in data or compute regions.</p></td> </tr> <tr class="row-odd"><td><p>acc_bytesalloc</p></td> <td><p>Returns the total bytes allocated by data or compute regions.</p></td> </tr> <tr class="row-even"><td><p>acc_bytesin</p></td> <td><p>Returns the total bytes copied in to the accelerator by data or compute regions.</p></td> </tr> <tr class="row-odd"><td><p>acc_bytesout</p></td> <td><p>Returns the total bytes copied out from the accelerator by data or compute regions.</p></td> </tr> <tr class="row-even"><td><p>acc_copyins</p></td> <td><p>Returns the number of arrays copied in to the accelerator by data or compute regions.</p></td> </tr> <tr class="row-odd"><td><p>acc_copyouts</p></td> <td><p>Returns the number of arrays copied out from the accelerator by data or compute regions.</p></td> </tr> <tr class="row-even"><td><p>acc_disable_time</p></td> <td><p>Tells the runtime to stop profiling accelerator regions and kernels.</p></td> </tr> <tr class="row-odd"><td><p>acc_enable_time</p></td> <td><p>Tells the runtime to start profiling accelerator regions and kernels, if it is not already doing so.</p></td> </tr> <tr class="row-even"><td><p>acc_exec_time</p></td> <td><p>Returns the number of microseconds spent on the accelerator executing kernels.</p></td> </tr> <tr class="row-odd"><td><p>acc_frees</p></td> <td><p>Returns the number of arrays freed or deallocated in data or compute regions.</p></td> </tr> <tr class="row-even"><td><p>acc_get_device</p></td> <td><p>Returns the type of accelerator device used to run the next accelerator region, if one is selected.</p></td> </tr> <tr class="row-odd"><td><p>acc_get_device_num</p></td> <td><p>Returns the number of the device being used to execute an accelerator region.</p></td> </tr> <tr class="row-even"><td><p>acc_get_free_memory</p></td> <td><p>Returns the total available free memory on the attached accelerator device.</p></td> </tr> <tr class="row-odd"><td><p>acc_get_memory</p></td> <td><p>Returns the total memory on the attached accelerator device.</p></td> </tr> <tr class="row-even"><td><p>acc_get_num_devices</p></td> <td><p>Returns the number of accelerator devices of the given type attached to the host.</p></td> </tr> <tr class="row-odd"><td><p>acc_kernels</p></td> <td><p>Returns the number of accelerator kernels launched since the start of the program.</p></td> </tr> <tr class="row-even"><td><p>acc_present_dump</p></td> <td><p>Summarizes all data present on the current device.</p></td> </tr> <tr class="row-odd"><td><p>acc_present_dump_all</p></td> <td><p>Summarizes all data present on all devices.</p></td> </tr> <tr class="row-even"><td><p>acc_regions</p></td> <td><p>Returns the number of accelerator regions entered since the start of the program.</p></td> </tr> <tr class="row-odd"><td><p>acc_total_time</p></td> <td><p>Returns the number of microseconds spent in accelerator compute regions and in moving data for accelerator data regions.</p></td> </tr> </tbody> </table> </section> </section> <section id="supported-intrinsics"> <h2><span class="section-number">6.11. </span>Supported Intrinsics<a class="headerlink" href="#supported-intrinsics" title="Permalink to this headline"></a></h2> <p>An intrinsic is a function available in a given language whose implementation is handled specifically by the compiler. Typically, an intrinsic substitutes a sequence of automatically-generated instructions for the original function call. Since the compiler has an intimate knowledge of the intrinsic function, it can better integrate it and optimize it for the situation.</p> <p>Intrinsics make the use of processor-specific enhancements easier because they provide a language interface to assembly instructions. In doing so, the compiler manages things that the user would normally have to be concerned with, such as register names, register allocations, and memory locations of data.</p> <p>This section contains an overview of the Fortran and C intrinsics that the accelerator supports.</p> <section id="supported-fortran-intrinsics-summary-table"> <h3><span class="section-number">6.11.1. </span>Supported Fortran Intrinsics Summary Table<a class="headerlink" href="#supported-fortran-intrinsics-summary-table" title="Permalink to this headline"></a></h3> <p><a class="reference internal" href="#acc-fort-intrin-sum-acc-fort-intrin-sum-tbl"><span class="std std-ref">Table 18</span></a> is an alphabetical summary of the supported Fortran intrinsics that the accelerator supports. These functions are specific to Fortran 90/95 unless otherwise specified.</p> <p>In most cases support is provided for all the data types for which the intrinsic is valid. When support is available for only certain data types, the middle column of the table specifies which ones, using the following codes:</p> <table class="table-no-stripes docutils align-default" id="acc-fort-intrin-sum-acc-fort-intrin-sum-tbl"> <colgroup> <col style="width: 19%" /> <col style="width: 39%" /> <col style="width: 43%" /> </colgroup> <tbody> <tr class="row-odd"><td><p>I for integer</p></td> <td><p>S for single precision real D for double precision real</p></td> <td><p>C for single precision complex Z for double precision complex</p></td> </tr> </tbody> </table> <table class="table-no-stripes docutils align-default" id="id28"> <caption><span class="caption-text">Table 18. Supported Fortran Intrinsics</span><a class="headerlink" href="#id28" title="Permalink to this table"></a></caption> <colgroup> <col style="width: 16%" /> <col style="width: 9%" /> <col style="width: 75%" /> </colgroup> <thead> <tr class="row-odd"><th class="head"><p>This intrinsic</p></th> <th class="head"></th> <th class="head"><p>Return value</p></th> </tr> </thead> <tbody> <tr class="row-even"><td><p>ABS</p></td> <td><p>I,S,D</p></td> <td><p>absolute value of the argument.</p></td> </tr> <tr class="row-odd"><td><p>ACOS</p></td> <td></td> <td><p>arccosine of the specified argument.</p></td> </tr> <tr class="row-even"><td><p>AINT</p></td> <td></td> <td><p>truncation of the argument to a whole number.</p></td> </tr> <tr class="row-odd"><td><p>ANINT</p></td> <td></td> <td><p>nearest whole number of the real argument.</p></td> </tr> <tr class="row-even"><td><p>ASIN</p></td> <td></td> <td><p>arcsine of the argument.</p></td> </tr> <tr class="row-odd"><td><p>ATAN</p></td> <td></td> <td><p>arctangent of the argument.</p></td> </tr> <tr class="row-even"><td><p>ATAN2</p></td> <td></td> <td><p>angle in radians of the complex value first-argument + i*second-argument.</p></td> </tr> <tr class="row-odd"><td><p>COS</p></td> <td><p>S,D,C,Z</p></td> <td><p>cosine of the argument.</p></td> </tr> <tr class="row-even"><td><p>COSH</p></td> <td></td> <td><p>hyperbolic cosine of the argument.</p></td> </tr> <tr class="row-odd"><td><p>DBLE</p></td> <td><p>S,D</p></td> <td><p>conversion of the argument to double precision real.</p></td> </tr> <tr class="row-even"><td><p>DPROD</p></td> <td></td> <td><p>double precision product of two single precision arguments.</p></td> </tr> <tr class="row-odd"><td><p>EXP</p></td> <td><p>S,D,C,Z</p></td> <td><p>natural exponential value of the argument.</p></td> </tr> <tr class="row-even"><td><p>IAND</p></td> <td></td> <td><p>result of logical AND of the two integer arguments.</p></td> </tr> <tr class="row-odd"><td><p>IEOR</p></td> <td></td> <td><p>result of the boolean exclusive OR of the two integer arguments.</p></td> </tr> <tr class="row-even"><td><p>INT</p></td> <td><p>I,S,D</p></td> <td><p>conversion of the argument to integer type.</p></td> </tr> <tr class="row-odd"><td><p>IOR</p></td> <td></td> <td><p>result of the boolean inclusive OR of the two integer arguments.</p></td> </tr> <tr class="row-even"><td><p>LOG</p></td> <td><p>S,D,C,Z</p></td> <td><p>base-e (natural logarithm) of the argument.</p></td> </tr> <tr class="row-odd"><td><p>LOG10</p></td> <td></td> <td><p>base-10 logarithm of the argument.</p></td> </tr> <tr class="row-even"><td><p>MAX</p></td> <td></td> <td><p>maximum value of the arguments.</p></td> </tr> <tr class="row-odd"><td><p>MIN</p></td> <td></td> <td><p>minimum value of the arguments.</p></td> </tr> <tr class="row-even"><td><p>MOD</p></td> <td><p>I</p></td> <td><p>remainder of the first argument divided by the second argument.</p></td> </tr> <tr class="row-odd"><td><p>NINT</p></td> <td></td> <td><p>nearest integer of the real argument.</p></td> </tr> <tr class="row-even"><td><p>NOT</p></td> <td></td> <td><p>logical complement of the integer argument.</p></td> </tr> <tr class="row-odd"><td><p>REAL</p></td> <td><p>I,S,D</p></td> <td><p>conversion of the argument to real.</p></td> </tr> <tr class="row-even"><td><p>SIGN</p></td> <td></td> <td><p>absolute value of first argument times the sign of second argument.</p></td> </tr> <tr class="row-odd"><td><p>SIN</p></td> <td><p>S,D,C,Z</p></td> <td><p>sine of the argument.</p></td> </tr> <tr class="row-even"><td><p>SINH</p></td> <td></td> <td><p>hyperbolic sine of the argument.</p></td> </tr> <tr class="row-odd"><td><p>SQRT</p></td> <td><p>S,D,C,Z</p></td> <td><p>square root of the argument.</p></td> </tr> <tr class="row-even"><td><p>TAN</p></td> <td></td> <td><p>tangent of the argument.</p></td> </tr> <tr class="row-odd"><td><p>TANH</p></td> <td></td> <td><p>hyperbolic tangent of the argument.</p></td> </tr> </tbody> </table> </section> <section id="supported-c-intrinsics-summary-table"> <h3><span class="section-number">6.11.2. </span>Supported C Intrinsics Summary Table<a class="headerlink" href="#supported-c-intrinsics-summary-table" title="Permalink to this headline"></a></h3> <p>This section contains two alphabetical summaries – one for double functions and a second for float functions. These lists contain only those C intrinsics that the accelerator supports.</p> <table class="table-no-stripes docutils align-default" id="id29"> <caption><span class="caption-text">Table 19. Supported C Intrinsic Double Functions</span><a class="headerlink" href="#id29" title="Permalink to this table"></a></caption> <colgroup> <col style="width: 18%" /> <col style="width: 82%" /> </colgroup> <thead> <tr class="row-odd"><th class="head"><p>This intrinsic</p></th> <th class="head"><p>Return value</p></th> </tr> </thead> <tbody> <tr class="row-even"><td><p>acos</p></td> <td><p>arccosine of the argument.</p></td> </tr> <tr class="row-odd"><td><p>asin</p></td> <td><p>arcsine of the argument.</p></td> </tr> <tr class="row-even"><td><p>atan</p></td> <td><p>arctangent of the argument.</p></td> </tr> <tr class="row-odd"><td><p>atan2</p></td> <td><p>arctangent of y/x, where y is the first argument, x the second.</p></td> </tr> <tr class="row-even"><td><p>cos</p></td> <td><p>cosine of the argument.</p></td> </tr> <tr class="row-odd"><td><p>cosh</p></td> <td><p>hyperbolic cosine of the argument.</p></td> </tr> <tr class="row-even"><td><p>exp</p></td> <td><p>exponential value of the argument.</p></td> </tr> <tr class="row-odd"><td><p>fabs</p></td> <td><p>absolute value of the argument.</p></td> </tr> <tr class="row-even"><td><p>fmax</p></td> <td><p>maximum value of the two arguments</p></td> </tr> <tr class="row-odd"><td><p>fmin</p></td> <td><p>minimum value of the two arguments</p></td> </tr> <tr class="row-even"><td><p>log</p></td> <td><p>natural logarithm of the argument.</p></td> </tr> <tr class="row-odd"><td><p>log10</p></td> <td><p>base-10 logarithm of the argument.</p></td> </tr> <tr class="row-even"><td><p>pow</p></td> <td><p>value of the first argument raised to the power of the second argument.</p></td> </tr> <tr class="row-odd"><td><p>sin</p></td> <td><p>value of the sine of the argument.</p></td> </tr> <tr class="row-even"><td><p>sinh</p></td> <td><p>hyperbolic sine of the argument.</p></td> </tr> <tr class="row-odd"><td><p>sqrt</p></td> <td><p>square root of the argument.</p></td> </tr> <tr class="row-even"><td><p>tan</p></td> <td><p>tangent of the argument.</p></td> </tr> <tr class="row-odd"><td><p>tanh</p></td> <td><p>hyperbolic tangent of the argument.</p></td> </tr> </tbody> </table> <table class="table-no-stripes docutils align-default" id="id30"> <caption><span class="caption-text">Table 20. Supported C Intrinsic Float Functions</span><a class="headerlink" href="#id30" title="Permalink to this table"></a></caption> <colgroup> <col style="width: 18%" /> <col style="width: 82%" /> </colgroup> <thead> <tr class="row-odd"><th class="head"><p>This intrinsic</p></th> <th class="head"><p>Return value</p></th> </tr> </thead> <tbody> <tr class="row-even"><td><p>acosf</p></td> <td><p>arccosine of the argument.</p></td> </tr> <tr class="row-odd"><td><p>asinf</p></td> <td><p>arcsine of the argument.</p></td> </tr> <tr class="row-even"><td><p>atanf</p></td> <td><p>arctangent of the argument.</p></td> </tr> <tr class="row-odd"><td><p>atan2f</p></td> <td><p>arctangent of y/x, where y is the first argument, x the second.</p></td> </tr> <tr class="row-even"><td><p>cosf</p></td> <td><p>cosine of the argument.</p></td> </tr> <tr class="row-odd"><td><p>coshf</p></td> <td><p>hyperbolic cosine of the argument.</p></td> </tr> <tr class="row-even"><td><p>expf</p></td> <td><p>exponential value of the argument.</p></td> </tr> <tr class="row-odd"><td><p>fabsf</p></td> <td><p>absolute value of the argument.</p></td> </tr> <tr class="row-even"><td><p>logf</p></td> <td><p>natural logarithm of the argument.</p></td> </tr> <tr class="row-odd"><td><p>log10f</p></td> <td><p>base-10 logarithm of the argument.</p></td> </tr> <tr class="row-even"><td><p>powf</p></td> <td><p>value of the first argument raised to the power of the second argument.</p></td> </tr> <tr class="row-odd"><td><p>sinf</p></td> <td><p>value of the sine of the argument.</p></td> </tr> <tr class="row-even"><td><p>sinhf</p></td> <td><p>hyperbolic sine of the argument.</p></td> </tr> <tr class="row-odd"><td><p>sqrtf</p></td> <td><p>square root of the argument.</p></td> </tr> <tr class="row-even"><td><p>tanf</p></td> <td><p>tangent of the argument.</p></td> </tr> <tr class="row-odd"><td><p>tanhf</p></td> <td><p>hyperbolic tangent of the argument.</p></td> </tr> </tbody> </table> <span class="target" id="openmp-use"></span></section> </section> </section> <section id="using-openmp"> <h1><span class="section-number">7. </span>Using OpenMP<a class="headerlink" href="#using-openmp" title="Permalink to this headline"></a></h1> <p>OpenMP is a specification for a set of compiler directives, an applications programming interface (API), and a set of environment variables that can be used to specify parallel execution in Fortran, C++, and C programs. For general information about using OpenMP and to obtain a copy of the OpenMP specification, refer to the <a class="reference external" href="https://www.openmp.org">OpenMP organization’s website</a>.</p> <p>The NVFORTRAN, NVC++, and NVC compilers support a subset of the OpenMP Application Program Interface for CPUs and GPUs. In defining this subset, we have focused on OpenMP 5.0 features that will enable CPU and GPU targeting for OpenMP applications with a goal of encouraging programming practices that are portable and scalable. For features that are to be avoided, wherever possible, the directives and API calls related to those features are parsed and ignored to maximize portability. Where ignoring such features is not possible, or could result in ambiguous or incorrect execution, the compilers emit appropriate error messages at compile- or run-time.</p> <p>OpenMP applications properly structured for GPUs, meaning they expose massive parallelism and have relatively little or no synchronization in GPU-side code segments, should compile and execute with performance on par with or close to equivalent OpenACC. Codes that are not well-structured for GPUs may perform poorly but should execute correctly.</p> <p>Use the <code class="docutils literal notranslate"><span class="pre">-mp</span></code> compiler switch to enable processing of OpenMP directives and pragmas. The most important sub-options to <code class="docutils literal notranslate"><span class="pre">-mp</span></code> are the following:</p> <ul class="simple"> <li><p><code class="docutils literal notranslate"><span class="pre">gpu</span></code>: OpenMP directives are compiled for GPU execution plus multicore CPU fallback; this feature is supported on NVIDIA V100 or later GPUs.</p></li> <li><p><code class="docutils literal notranslate"><span class="pre">multicore</span></code>: OpenMP directives are compiled for multicore CPU execution only; this sub-option is the default.</p></li> </ul> <p class="title sectiontitle rubric" id="predefined-macros-1">Predefined Macros</p> <p>The following macros corresponding to the offload target compiled for are added implicitly:</p> <ul class="simple"> <li><p><code class="docutils literal notranslate"><span class="pre">__NVCOMPILER_OPENMP_GPU</span></code> when OpenMP target directives are compiled for GPU.</p></li> <li><p><code class="docutils literal notranslate"><span class="pre">__NVCOMPILER_OPENMP_MULTICORE</span></code> when OpenMP target directives are compiled for multicore CPU.</p></li> </ul> <section id="id2"> <h2><span class="section-number">7.1. </span>Environment Variables<a class="headerlink" href="#id2" title="Permalink to this headline"></a></h2> <p>The OpenMP specification includes many environment variables related to program execution.</p> <p class="title sectiontitle rubric" id="thread-affinity">Thread affinity</p> <p>One important environment variable is <code class="docutils literal notranslate"><span class="pre">OMP_PROC_BIND</span></code>. It controls the OpenMP CPU thread affinity policy. When thread affinity is disabled, the operating system is free to move threads between the available CPU cores. When thread affinity is enabled, each thread is bound to a subset of the available CPU cores. The environment variable <code class="docutils literal notranslate"><span class="pre">OMP_PLACES</span></code> can be used to specify how a subset of the available CPU cores is determined for each thread. When set to a valid value, this environment variable will enable thread affinity and override the default thread affinity policy.</p> <p>Binding threads to certain CPU cores is often beneficial for application performance, because that can improve the CPU cache hit rate and limit memory transactions between different NUMA nodes. Therefore, it is important to consider enabling thread affinity for your application.</p> <p>The default value of <code class="docutils literal notranslate"><span class="pre">OMP_PROC_BIND</span></code> is <code class="docutils literal notranslate"><span class="pre">false</span></code>. Thus, thread affinity is disabled by default. This is a conservative setting that allows certain classes of applications (such as OpenMP + MPI) to create multiple processes without taking special care of the thread affinity policy to avoid binding threads in different processes to the same CPU cores.</p> <p>The following table explains the simplest possible values of <code class="docutils literal notranslate"><span class="pre">OMP_PROC_BIND</span></code>. For the comprehensive explanation of <code class="docutils literal notranslate"><span class="pre">OMP_PROC_BIND</span></code> and <code class="docutils literal notranslate"><span class="pre">OMP_PLACES</span></code>, please refer to the OpenMP specification.</p> <table class="table-no-stripes docutils align-default"> <colgroup> <col style="width: 9%" /> <col style="width: 91%" /> </colgroup> <thead> <tr class="row-odd"><th class="head"><p>Value</p></th> <th class="head"><p>Behavior</p></th> </tr> </thead> <tbody> <tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">OMP_PROC_BIND=false</span></code></p></td> <td><p>Thread affinity is disabled unless <code class="docutils literal notranslate"><span class="pre">OMP_PLACES</span></code> is set to a valid value. When thread affinity is disabled, the operating system is free to assign threads to any available CPU core at any time of the application execution. This is the default value.</p></td> </tr> <tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">OMP_PROC_BIND=true</span></code></p></td> <td><p>Thread affinity is enabled. Unless <code class="docutils literal notranslate"><span class="pre">OMP_PLACES</span></code> is set, the implementation attempts to assign threads optimally to CPU cores to maximize the cache hit rate and minimize the number of memory transactions between NUMA nodes.</p></td> </tr> </tbody> </table> <p class="title sectiontitle rubric" id="device-offload">Device offload</p> <p>Another important environment variable to understand is <code class="docutils literal notranslate"><span class="pre">OMP_TARGET_OFFLOAD</span></code>. Use this environment variable to affect the behavior of execution on host and device including host fallback. The following table explains the behavior determined by each of the values to which you can set this environment variable.</p> <table class="table-no-stripes docutils align-default"> <colgroup> <col style="width: 29%" /> <col style="width: 71%" /> </colgroup> <thead> <tr class="row-odd"><th class="head"><p>Value</p></th> <th class="head"><p>Behavior</p></th> </tr> </thead> <tbody> <tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">OMP_TARGET_OFFLOAD=DEFAULT</span></code></p></td> <td><p>Try to execute on a GPU; if a supported GPU is not available, fallback to the host</p></td> </tr> <tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">OMP_TARGET_OFFLOAD=DISABLED</span></code></p></td> <td><p>Do not execute on the GPU even if one is available; execute on the host</p></td> </tr> <tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">OMP_TARGET_OFFLOAD=MANDATORY</span></code></p></td> <td><p>Execute on a GPU or terminate the program</p></td> </tr> </tbody> </table> <p class="title sectiontitle rubric" id="number-of-teams-on-device">Number of teams on device</p> <p>When an application offloads an <code class="docutils literal notranslate"><span class="pre">omp</span> <span class="pre">target</span> <span class="pre">teams</span></code> construct to the GPU, the number of teams is calculated automatically unless the construct has a <code class="docutils literal notranslate"><span class="pre">num_teams</span></code> clause. The automatic setting of the number of teams can be limited to a maximum value provided by the <code class="docutils literal notranslate"><span class="pre">OMP_NUM_TEAMS</span></code> environment variable. The same maximum value can also be set by the application at run time with the function <code class="docutils literal notranslate"><span class="pre">omp_set_num_teams</span></code>.</p> <table class="table-no-stripes docutils align-default"> <colgroup> <col style="width: 44%" /> <col style="width: 56%" /> </colgroup> <thead> <tr class="row-odd"><th class="head"><p>Value</p></th> <th class="head"><p>Behavior</p></th> </tr> </thead> <tbody> <tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">OMP_NUM_TEAMS=&lt;positive_integer&gt;</span></code></p></td> <td><p>Maximum number of teams on device</p></td> </tr> </tbody> </table> <p>For the comprehensive explanation of <code class="docutils literal notranslate"><span class="pre">OMP_NUM_TEAMS</span></code>, please refer to the OpenMP specification.</p> <p class="title sectiontitle rubric" id="number-of-threads-in-teams">Number of threads in teams</p> <p>An <code class="docutils literal notranslate"><span class="pre">omp</span> <span class="pre">target</span> <span class="pre">teams</span></code> construct offloaded to the GPU creates a league of teams each consisting of a certain number of threads. The number of threads is the same for all teams in the league, and is calculated automatically unless the construct has a <code class="docutils literal notranslate"><span class="pre">thread_limit</span></code> clause.</p> <p>The environment variable <code class="docutils literal notranslate"><span class="pre">OMP_TEAMS_THREAD_LIMIT</span></code> can be used to limit the maximum number of threads in teams. The same maximum value can be set by the application with the runtime function <code class="docutils literal notranslate"><span class="pre">omp_set_teams_thread_limit</span></code>.</p> <p>For NVIDIA GPUs, we recommend using values that are multiples of 32 (which is the size of the GPU thread warp). That equally applies to the <code class="docutils literal notranslate"><span class="pre">OMP_TEAMS_THREAD_LIMIT</span></code> environment variable, the <code class="docutils literal notranslate"><span class="pre">omp_set_teams_thread_limit</span></code> function and the <code class="docutils literal notranslate"><span class="pre">thread_limit</span></code> clause. For any other value, the actual limit on the number of threads per team will likely be rounded down to the nearest multiple of 32. The same guidance applies to the <code class="docutils literal notranslate"><span class="pre">num_threads</span></code> clause as well.</p> <table class="table-no-stripes docutils align-default"> <colgroup> <col style="width: 44%" /> <col style="width: 56%" /> </colgroup> <thead> <tr class="row-odd"><th class="head"><p>Value</p></th> <th class="head"><p>Behavior</p></th> </tr> </thead> <tbody> <tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">OMP_TEAMS_THREAD_LIMIT=&lt;positive_integer&gt;</span></code></p></td> <td><p>Maximum number of threads in teams</p></td> </tr> </tbody> </table> <p>For the comprehensive explanation of <code class="docutils literal notranslate"><span class="pre">OMP_TEAMS_THREAD_LIMIT</span></code>, please refer to the OpenMP specification.</p> <p class="title sectiontitle rubric" id="forcing-the-number-of-device-teams-and-threads">Forcing the number of device teams and threads</p> <p>In certain situations, for instance for debugging or performance tuning, it may be desirable to specify an exact number of teams and threads on the GPU. While OpenMP offers a number of convenient ways to control that, e.g. the <code class="docutils literal notranslate"><span class="pre">num_teams</span></code> and <code class="docutils literal notranslate"><span class="pre">thread_limit</span></code> clauses, as well as the environment variables described above, they do not guarantee an exact teams and threads configuration.</p> <p>The NVIDIA HPC OpenMP Runtime supports the <code class="docutils literal notranslate"><span class="pre">NVCOMPILER_OMP_CUDA_GRID</span></code> environment variable. When set, it requests the runtime to use the exact number of teams and threads per team when running OpenMP compute constructs on the GPU. Essentially, its effect is to use a specific CUDA grid configuration for any kernel, bypassing runtime and compiler guidance.</p> <table class="table-no-stripes docutils align-default"> <colgroup> <col style="width: 24%" /> <col style="width: 76%" /> </colgroup> <thead> <tr class="row-odd"><th class="head"><p>Value</p></th> <th class="head"><p>Behavior</p></th> </tr> </thead> <tbody> <tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">NVCOMPILER_OMP_CUDA_GRID=&lt;num_blocks&gt;,&lt;num_threads&gt;</span></code></p></td> <td><p>The <code class="docutils literal notranslate"><span class="pre">&lt;num_blocks&gt;</span></code> and <code class="docutils literal notranslate"><span class="pre">&lt;num_threads&gt;</span></code> must be positive integers. They are used to form a CUDA grid when running GPU kernels associated with <code class="docutils literal notranslate"><span class="pre">omp</span> <span class="pre">target</span></code> compute constructs.</p></td> </tr> </tbody> </table> <p>However, even with an exact CUDA grid specified, the runtime may still use a corrected configuration if that is necessary for a successful kernel launch.</p> <p>Please refer to the <a class="reference external" href="https://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html">CUDA C++ Programming Guide</a> for the detailed explanation of how the CUDA kernel execution configurations work.</p> </section> <section id="fallback-mode"> <h2><span class="section-number">7.2. </span>Fallback Mode<a class="headerlink" href="#fallback-mode" title="Permalink to this headline"></a></h2> <p>The HPC compilers support host fallback of OpenMP <code class="docutils literal notranslate"><span class="pre">target</span></code> regions when no GPU is present or <code class="docutils literal notranslate"><span class="pre">OMP_TARGET_OFFLOAD</span></code> is set to <code class="docutils literal notranslate"><span class="pre">DISABLED</span></code>. Execution should always be correct but the performance of the target region may not always be optimal when run on the host. OpenMP target regions prescriptively structured for optimal execution on GPUs may not perform well when run on the dissimilar architecture of the CPU. To provide performance portability between host and device, we recommend use of the <code class="docutils literal notranslate"><span class="pre">loop</span></code> construct.</p> <p><strong>firstprivates with nowait not supported for host execution</strong></p> <p>There is currently a limitation on the use of the <code class="docutils literal notranslate"><span class="pre">nowait</span></code> clause on target regions intended for execution on the host (-mp or -mp=gpu with <code class="docutils literal notranslate"><span class="pre">OMP_TARGET_OFFLOAD=DISABLED</span></code>). If the target region references variables having the <code class="docutils literal notranslate"><span class="pre">firstprivate</span></code> data-sharing attribute, their concurrent updates are not guaranteed to be safe. To work around this limitation, when running on the host, we recommend avoiding the <code class="docutils literal notranslate"><span class="pre">nowait</span></code> clause on such target regions or equivalently using the <code class="docutils literal notranslate"><span class="pre">taskwait</span></code> construct immediately following the region.</p> </section> <section id="loop"> <h2><span class="section-number">7.3. </span>Loop<a class="headerlink" href="#loop" title="Permalink to this headline"></a></h2> <p>The HPC compilers support the <code class="docutils literal notranslate"><span class="pre">loop</span></code> construct with an extension to the default binding thread set mechanism specified by OpenMP in order to allow the compilers the freedom to analyze loops and dependencies to generate highly parallel code for CPU and GPU targets. In other words, the compilers map <code class="docutils literal notranslate"><span class="pre">loop</span></code> to either teams or to threads, as the compiler chooses, unless the user explicitly specifies otherwise. The mapping selected is specific to each target architecture even within the same executable (i.e., GPU offload and host fallback) thereby facilitating performance portability.</p> <p>The shape of the parallelism offered by NVIDIA’s GPUs, consisting of thread blocks and three dimensions of threads therein, differs from the multi-threaded vector parallelism of modern CPUs. The following table summarizes the OpenMP mapping to NVIDIA GPUs and multicore CPUs:</p> <table class="table-no-stripes docutils align-default"> <colgroup> <col style="width: 24%" /> <col style="width: 36%" /> <col style="width: 40%" /> </colgroup> <thead> <tr class="row-odd"><th class="head"><p>Construct</p></th> <th class="head"><p>CPU</p></th> <th class="head"><p>GPU</p></th> </tr> </thead> <tbody> <tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">!$omp</span> <span class="pre">target</span></code></p></td> <td></td> <td><p>starts offload</p></td> </tr> <tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">!$omp</span> <span class="pre">teams</span></code></p></td> <td><p>single team</p></td> <td><p>CUDA thread blocks in grid</p></td> </tr> <tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">!$omp</span> <span class="pre">parallel</span></code></p></td> <td><p>CPU threads</p></td> <td><p>CUDA threads within thread block</p></td> </tr> <tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">!$omp</span> <span class="pre">simd</span></code></p></td> <td><p>hint for vector instructions</p></td> <td><p>simdlen(1)</p></td> </tr> </tbody> </table> <p>HPC programs need to leverage all available parallelism to achieve performance. The programmer can attempt to become an expert in the intricacies of each target architecture and use that knowledge to structure programs accordingly. This prescriptive model can be successful but tends to increase source code complexity and often requires restructuring for each new target architecture. Here’s an example where a programmer explicitly requests the steps the compiler should take to map parallelism to two targets:</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="cp">#ifdef TARGET_GPU</span> <span class="w"> </span><span class="cp">#pragma omp target teams distribute reduction(max:error)</span> <span class="cp">#else</span> <span class="w"> </span><span class="cp">#pragma omp parallel for reduction(max:error)</span> <span class="cp">#endif</span> <span class="k">for</span><span class="p">(</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">j</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">1</span><span class="p">;</span><span class="w"> </span><span class="n">j</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="n">n</span><span class="mi">-1</span><span class="p">;</span><span class="w"> </span><span class="n">j</span><span class="o">++</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span> <span class="cp">#ifdef TARGET_GPU</span> <span class="w"> </span><span class="cp">#pragma omp parallel for reduction(max:error)</span> <span class="cp">#endif</span> <span class="w"> </span><span class="k">for</span><span class="p">(</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">1</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="n">m</span><span class="mi">-1</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="o">++</span><span class="w"> </span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="n">Anew</span><span class="p">[</span><span class="n">j</span><span class="p">][</span><span class="n">i</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mf">0.25f</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="p">(</span><span class="w"> </span><span class="n">A</span><span class="p">[</span><span class="n">j</span><span class="p">][</span><span class="n">i</span><span class="o">+</span><span class="mi">1</span><span class="p">]</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">A</span><span class="p">[</span><span class="n">j</span><span class="p">][</span><span class="n">i</span><span class="mi">-1</span><span class="p">]</span><span class="w"></span> <span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">A</span><span class="p">[</span><span class="n">j</span><span class="mi">-1</span><span class="p">][</span><span class="n">i</span><span class="p">]</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">A</span><span class="p">[</span><span class="n">j</span><span class="o">+</span><span class="mi">1</span><span class="p">][</span><span class="n">i</span><span class="p">]);</span><span class="w"></span> <span class="w"> </span><span class="n">error</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">fmaxf</span><span class="p">(</span><span class="w"> </span><span class="n">error</span><span class="p">,</span><span class="w"> </span><span class="n">fabsf</span><span class="p">(</span><span class="n">Anew</span><span class="p">[</span><span class="n">j</span><span class="p">][</span><span class="n">i</span><span class="p">]</span><span class="o">-</span><span class="n">A</span><span class="p">[</span><span class="n">j</span><span class="p">][</span><span class="n">i</span><span class="p">]));</span><span class="w"></span> <span class="w"> </span><span class="p">}</span><span class="w"></span> <span class="p">}</span><span class="w"></span> </pre></div> </div> <p>An alternative is for the programmer to focus on exposing parallelism in a program and allowing a compiler to do the mapping onto the target architectures. The HPC compilers’ implementation of <code class="docutils literal notranslate"><span class="pre">loop</span></code> supports this descriptive model. In this example, the programmer specifies the loop regions to be parallelized by the compiler and the compilers parallelize <code class="docutils literal notranslate"><span class="pre">loop</span></code> across teams and threads:</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="cp">#pragma omp target teams loop reduction(max:error)</span> <span class="k">for</span><span class="p">(</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">j</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">1</span><span class="p">;</span><span class="w"> </span><span class="n">j</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="n">n</span><span class="mi">-1</span><span class="p">;</span><span class="w"> </span><span class="n">j</span><span class="o">++</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="cp">#pragma omp loop reduction(max:error)</span> <span class="w"> </span><span class="k">for</span><span class="p">(</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">1</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="n">m</span><span class="mi">-1</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="o">++</span><span class="w"> </span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="n">Anew</span><span class="p">[</span><span class="n">j</span><span class="p">][</span><span class="n">i</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mf">0.25f</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="p">(</span><span class="w"> </span><span class="n">A</span><span class="p">[</span><span class="n">j</span><span class="p">][</span><span class="n">i</span><span class="o">+</span><span class="mi">1</span><span class="p">]</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">A</span><span class="p">[</span><span class="n">j</span><span class="p">][</span><span class="n">i</span><span class="mi">-1</span><span class="p">]</span><span class="w"></span> <span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">A</span><span class="p">[</span><span class="n">j</span><span class="mi">-1</span><span class="p">][</span><span class="n">i</span><span class="p">]</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">A</span><span class="p">[</span><span class="n">j</span><span class="o">+</span><span class="mi">1</span><span class="p">][</span><span class="n">i</span><span class="p">]);</span><span class="w"></span> <span class="w"> </span><span class="n">error</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">fmaxf</span><span class="p">(</span><span class="w"> </span><span class="n">error</span><span class="p">,</span><span class="w"> </span><span class="n">fabsf</span><span class="p">(</span><span class="n">Anew</span><span class="p">[</span><span class="n">j</span><span class="p">][</span><span class="n">i</span><span class="p">]</span><span class="o">-</span><span class="n">A</span><span class="p">[</span><span class="n">j</span><span class="p">][</span><span class="n">i</span><span class="p">]));</span><span class="w"></span> <span class="w"> </span><span class="p">}</span><span class="w"></span> <span class="p">}</span><span class="w"></span> </pre></div> </div> <p>The programmer’s tuning tool with <code class="docutils literal notranslate"><span class="pre">loop</span></code> is the <code class="docutils literal notranslate"><span class="pre">bind</span></code> clause. The following table extends the previous mapping example:</p> <table class="table-no-stripes docutils align-default"> <colgroup> <col style="width: 23%" /> <col style="width: 36%" /> <col style="width: 41%" /> </colgroup> <thead> <tr class="row-odd"><th class="head"><p>Construct</p></th> <th class="head"><p>CPU</p></th> <th class="head"><p>GPU</p></th> </tr> </thead> <tbody> <tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">!$omp</span> <span class="pre">loop</span> <span class="pre">bind(teams)</span></code></p></td> <td><p>threads</p></td> <td><p>CUDA thread blocks and threads</p></td> </tr> <tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">!$omp</span> <span class="pre">loop</span> <span class="pre">bind(parallel)</span></code></p></td> <td><p>threads</p></td> <td><p>CUDA threads</p></td> </tr> <tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">!$omp</span> <span class="pre">loop</span> <span class="pre">bind(thread)</span></code></p></td> <td><p>single thread (useful for vector instructions)</p></td> <td><p>single thread</p></td> </tr> </tbody> </table> <p>Orphaned <code class="docutils literal notranslate"><span class="pre">loop</span></code> constructs within a single file are supported; a binding region of either <code class="docutils literal notranslate"><span class="pre">parallel</span></code> or <code class="docutils literal notranslate"><span class="pre">thread</span></code> must be specified with such loops via the <code class="docutils literal notranslate"><span class="pre">bind</span></code> clause. The compilers support <code class="docutils literal notranslate"><span class="pre">loop</span></code> regions containing procedure calls as long as the callee does not contain OpenMP directives.</p> <p>Here are a few additional examples using <code class="docutils literal notranslate"><span class="pre">loop</span></code>. We also show examples of the type of information the compiler would provide when using the <code class="docutils literal notranslate"><span class="pre">-Minfo</span></code> compiler option.</p> <p>Use of <code class="docutils literal notranslate"><span class="pre">loop</span></code> in Fortran:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>!$omp target teams loop do n1loc_blk = 1, n1loc_blksize do igp = 1, ngpown do ig_blk = 1, ig_blksize do ig = ig_blk, ncouls, ig_blksize do n1_loc = n1loc_blk, ntband_dist, n1loc_blksize !expensive computation codes enddo enddo enddo enddo enddo $ nvfortran test.f90 -mp=gpu -Minfo=mp 42, !$omp target teams loop 42, Generating &quot;nvkernel_MAIN__F1L42_1&quot; GPU kernel Generating Tesla code 43, Loop parallelized across teams ! blockidx%x 44, Loop run sequentially 45, Loop run sequentially 46, Loop run sequentially 47, Loop parallelized across threads(128) ! threadidx%x 42, Generating Multicore code 43, Loop parallelized across threads </pre></div> </div> <p>Use of <code class="docutils literal notranslate"><span class="pre">loop</span></code>, <code class="docutils literal notranslate"><span class="pre">collapse</span></code>, and <code class="docutils literal notranslate"><span class="pre">bind</span></code>:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>!$omp target teams loop collapse(3) do n1loc_blk = 1, n1loc_blksize do igp = 1, ngpown do ig_blk = 1, ig_blksize !$omp loop bind(parallel) collapse(2) do ig = ig_blk, ncouls, ig_blksize do n1_loc = n1loc_blk, ntband_dist, n1loc_blksize !expensive computation codes enddo enddo enddo enddo enddo $ nvfortran test.f90 -mp=gpu -Minfo=mp 42, !$omp target teams loop 42, Generating &quot;nvkernel_MAIN__F1L42_1&quot; GPU kernel Generating Tesla code 43, Loop parallelized across teams collapse(3) ! blockidx%x 44, ! blockidx%x collapsed 45, ! blockidx%x collapsed 47, Loop parallelized across threads(128) collapse(2) ! threadidx%x 48, ! threadidx%x collapsed 42, Generating Multicore code 43, Loop parallelized across threads </pre></div> </div> <p>Use of <code class="docutils literal notranslate"><span class="pre">loop</span></code>, <code class="docutils literal notranslate"><span class="pre">collapse</span></code>, and <code class="docutils literal notranslate"><span class="pre">bind(thread)</span></code>:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>!$omp target teams loop collapse(3) do n1loc_blk = 1, n1loc_blksize do igp = 1, ngpown do ig_blk = 1, ig_blksize !$omp loop bind(thread) collapse(2) do ig = ig_blk, ncouls, ig_blksize do n1_loc = n1loc_blk, ntband_dist, n1loc_blksize ! expensive computation codes enddo enddo enddo enddo enddo $ nvfortran test.f90 -mp=gpu -Minfo=mp 42, !$omp target teams loop 42, Generating &quot;nvkernel_MAIN__F1L42_1&quot; GPU kernel Generating Tesla code 43, Loop parallelized across teams, threads(128) collapse(3) ! blockidx%x threadidx%x 44, ! blockidx%x threadidx%x collapsed 45, ! blockidx%x threadidx%x collapsed 47, Loop run sequentially 48, collapsed 42, Generating Multicore code 43, Loop parallelized across threads </pre></div> </div> </section> <section id="openmp-subset"> <h2><span class="section-number">7.4. </span>OpenMP Subset<a class="headerlink" href="#openmp-subset" title="Permalink to this headline"></a></h2> <p>This section contains the subset of OpenMP 5.0 features that the HPC compilers support. We have attempted to define this subset of features to be those that enable, where possible, OpenMP-for-GPU application performance that closely mirrors the success NVIDIA has seen with OpenACC. Almost every feature supported on NVIDIA GPUs is also supported on multicore CPUs, although the reverse is not true. Most constructs from OpenMP 3.1 and OpenMP 4.5 that apply to multicore CPUs are supported for CPU targets, and some features from OpenMP 5.0 are supported as well.</p> <p>OpenMP target offload to NVIDIA GPUs is supported on NVIDIA V100 or later GPUs.</p> <p>The section numbers below correspond to the section numbers in the OpenMP Application Programming Interface Version 5.0 November 2018 document.</p> <p><strong>2. Directives</strong></p> <p><strong>2.3 Variant Directives</strong></p> <p><strong>2.3.4 Metadirectives</strong></p> <p>The <code class="docutils literal notranslate"><span class="pre">target_device</span></code>/<code class="docutils literal notranslate"><span class="pre">device</span></code> context selector is supported with the <code class="docutils literal notranslate"><span class="pre">kind</span></code>(<code class="docutils literal notranslate"><span class="pre">host</span></code>|<code class="docutils literal notranslate"><span class="pre">nohost</span></code>|<code class="docutils literal notranslate"><span class="pre">cpu</span></code>|<code class="docutils literal notranslate"><span class="pre">gpu</span></code>) and <code class="docutils literal notranslate"><span class="pre">arch</span></code>(<code class="docutils literal notranslate"><span class="pre">nvtpx</span></code>|<code class="docutils literal notranslate"><span class="pre">nvptx64</span></code>) trait selectors. The <code class="docutils literal notranslate"><span class="pre">arch</span></code> trait property <code class="docutils literal notranslate"><span class="pre">nvptx</span></code> is an alias for <code class="docutils literal notranslate"><span class="pre">nvptx64</span></code>; any other <code class="docutils literal notranslate"><span class="pre">arch</span></code> trait properties are treated as not matching or are ignored. The <code class="docutils literal notranslate"><span class="pre">isa</span></code> selector is treated as not matching or is ignored; no support is provided to select a context based on NVIDIA GPU compute capability.</p> <p>The <code class="docutils literal notranslate"><span class="pre">implementation</span></code> context selector is supported with the <code class="docutils literal notranslate"><span class="pre">vendor(nvidia)</span></code> trait selector.</p> <p>The <code class="docutils literal notranslate"><span class="pre">user</span></code> context selector is supported with the <code class="docutils literal notranslate"><span class="pre">condition(expression)</span></code> trait selector including dynamic <code class="docutils literal notranslate"><span class="pre">user</span></code> traits.</p> <p>The syntax <code class="docutils literal notranslate"><span class="pre">begin</span></code>/<code class="docutils literal notranslate"><span class="pre">end</span> <span class="pre">metadirective</span></code> is not supported.</p> <p><strong>2.3.5 Declare Variant Directive</strong></p> <p>The <code class="docutils literal notranslate"><span class="pre">device</span></code> context selector is supported with the <code class="docutils literal notranslate"><span class="pre">kind</span></code>(<code class="docutils literal notranslate"><span class="pre">host</span></code>|<code class="docutils literal notranslate"><span class="pre">nohost</span></code>|<code class="docutils literal notranslate"><span class="pre">cpu</span></code>|<code class="docutils literal notranslate"><span class="pre">gpu</span></code>) and <code class="docutils literal notranslate"><span class="pre">arch</span></code>(<code class="docutils literal notranslate"><span class="pre">nvtpx</span></code>|<code class="docutils literal notranslate"><span class="pre">nvptx64</span></code>) trait selectors. The <code class="docutils literal notranslate"><span class="pre">arch</span></code> trait property <code class="docutils literal notranslate"><span class="pre">nvptx</span></code> is an alias for <code class="docutils literal notranslate"><span class="pre">nvptx64</span></code>; any other <code class="docutils literal notranslate"><span class="pre">arch</span></code> trait properties are treated as not matching or are ignored. The <code class="docutils literal notranslate"><span class="pre">isa</span></code> selector is also treated as not matching or is ignored; no support is provided to select a context based on NVIDIA GPU compute capability.</p> <p>The <code class="docutils literal notranslate"><span class="pre">implementation</span></code> context selector is supported with the <code class="docutils literal notranslate"><span class="pre">vendor(nvidia)</span></code> trait selector; all other implementation trait selectors are treated as not matching.</p> <p>The syntax <code class="docutils literal notranslate"><span class="pre">begin</span></code>/<code class="docutils literal notranslate"><span class="pre">end</span> <span class="pre">declare</span> <span class="pre">variant</span></code> is supported for C/C++.</p> <p><strong>2.4 Requires Directive</strong></p> <p>The <code class="docutils literal notranslate"><span class="pre">requires</span></code> directive has limited support. The requirement clauses <code class="docutils literal notranslate"><span class="pre">unified_address</span></code> and <code class="docutils literal notranslate"><span class="pre">unified_shared_memory</span></code> are accepted but have no effect. To activate OpenMP unified shared memory programming a command-line option needs to be passed in (refer to <a class="reference internal" href="#openmp-unified-mem"><span class="std std-ref">OpenMP with CUDA Unified Memory</span></a> for more details).</p> <p><strong>2.5 Internal Control Variables</strong></p> <p>ICV support is as follows.</p> <ul class="simple"> <li><p><code class="docutils literal notranslate"><span class="pre">dyn-var</span></code>, <code class="docutils literal notranslate"><span class="pre">nthread-var</span></code>, <code class="docutils literal notranslate"><span class="pre">thread-limit-var</span></code>, <code class="docutils literal notranslate"><span class="pre">max-active-levels-var</span></code>, <code class="docutils literal notranslate"><span class="pre">active-levels-var</span></code>, <code class="docutils literal notranslate"><span class="pre">levels-var</span></code>, <code class="docutils literal notranslate"><span class="pre">run-sched-var</span></code>, <code class="docutils literal notranslate"><span class="pre">dyn-sched-var</span></code>, and <code class="docutils literal notranslate"><span class="pre">stacksize-var</span></code> are supported</p></li> <li><p><code class="docutils literal notranslate"><span class="pre">place-partition-var</span></code>, <code class="docutils literal notranslate"><span class="pre">bind-var</span></code>, <code class="docutils literal notranslate"><span class="pre">wait-policy-var</span></code>, <code class="docutils literal notranslate"><span class="pre">display-affinity-var</span></code>, <code class="docutils literal notranslate"><span class="pre">default-device-var</span></code>, and <code class="docutils literal notranslate"><span class="pre">target-offload-var</span></code> are supported only on the CPU</p></li> <li><p><code class="docutils literal notranslate"><span class="pre">affinity-format-var</span></code> is supported only on the CPU; its value is immutable</p></li> <li><p><code class="docutils literal notranslate"><span class="pre">max-task-priority-var</span></code>, <code class="docutils literal notranslate"><span class="pre">def-allocator-var</span></code> are not supported</p></li> <li><p><code class="docutils literal notranslate"><span class="pre">cancel-var</span></code> is not supported; it always returns false</p></li> </ul> <p><strong>2.6 Parallel Construct</strong></p> <p>Support for <code class="docutils literal notranslate"><span class="pre">parallel</span></code> construct clauses is as follows.</p> <ul class="simple"> <li><p>The <code class="docutils literal notranslate"><span class="pre">num_threads</span></code>, <code class="docutils literal notranslate"><span class="pre">default</span></code>, <code class="docutils literal notranslate"><span class="pre">private</span></code>, <code class="docutils literal notranslate"><span class="pre">firstprivate</span></code>, and <code class="docutils literal notranslate"><span class="pre">shared</span></code> clauses are supported</p></li> <li><p>The <code class="docutils literal notranslate"><span class="pre">reduction</span></code> clause is supported as described in 2.19.5</p></li> <li><p>The <code class="docutils literal notranslate"><span class="pre">if</span></code> and <code class="docutils literal notranslate"><span class="pre">copyin</span></code> clauses are supported only for CPU targets; the compiler emits an error for GPU targets</p></li> <li><p>The <code class="docutils literal notranslate"><span class="pre">proc_bind</span></code> clause is supported only for CPU targets; it is ignored for GPU targets</p></li> <li><p>The <code class="docutils literal notranslate"><span class="pre">allocate</span></code> clause is ignored</p></li> </ul> <p><strong>2.7 Teams Construct</strong></p> <p>The <code class="docutils literal notranslate"><span class="pre">teams</span></code> construct is supported only when nested within a <code class="docutils literal notranslate"><span class="pre">target</span></code> construct that contains no statements, declarations, or directives outside the <code class="docutils literal notranslate"><span class="pre">teams</span></code> construct, or as a combined <code class="docutils literal notranslate"><span class="pre">target</span></code><code class="docutils literal notranslate"><span class="pre">teams</span></code> construct. The <code class="docutils literal notranslate"><span class="pre">teams</span></code> construct is supported for GPU targets. If the <code class="docutils literal notranslate"><span class="pre">target</span></code> construct falls back to CPU mode, the number of teams is one. Support for <code class="docutils literal notranslate"><span class="pre">teams</span></code> construct clauses is as follows.</p> <ul class="simple"> <li><p>The <code class="docutils literal notranslate"><span class="pre">num_teams</span></code>, <code class="docutils literal notranslate"><span class="pre">thread_limit</span></code>, <code class="docutils literal notranslate"><span class="pre">default</span></code>, <code class="docutils literal notranslate"><span class="pre">private</span></code>, and <code class="docutils literal notranslate"><span class="pre">firstprivate</span></code> clauses are supported</p></li> <li><p>The <code class="docutils literal notranslate"><span class="pre">reduction</span></code> clause is supported as described in 2.19.5</p></li> <li><p>The <code class="docutils literal notranslate"><span class="pre">shared</span></code> clause is supported for CPU targets and is supported for GPU targets in unified-memory mode</p></li> <li><p>The <code class="docutils literal notranslate"><span class="pre">allocate</span></code> clause is ignored</p></li> </ul> <p><strong>2.8 Worksharing Constructs</strong></p> <p><strong>2.8.1 Sections Construct</strong></p> <p>The <code class="docutils literal notranslate"><span class="pre">sections</span></code> construct is supported only for CPU targets; the compiler emits an error for GPU targets. Support for <code class="docutils literal notranslate"><span class="pre">sections</span></code> construct clauses is as follows.</p> <ul class="simple"> <li><p>The <code class="docutils literal notranslate"><span class="pre">private</span></code> and <code class="docutils literal notranslate"><span class="pre">firstprivate</span></code> clauses are supported</p></li> <li><p>The <code class="docutils literal notranslate"><span class="pre">reduction</span></code> clause is supported as described in 2.19.5</p></li> <li><p>The <code class="docutils literal notranslate"><span class="pre">lastprivate</span></code> clause is supported; the optional <code class="docutils literal notranslate"><span class="pre">lastprivate</span></code> modifier is not supported</p></li> <li><p>The <code class="docutils literal notranslate"><span class="pre">allocate</span></code> clause is ignored</p></li> </ul> <p><strong>2.8.2 Single Construct</strong></p> <p>Support for <code class="docutils literal notranslate"><span class="pre">single</span></code> construct clauses is as follows.</p> <ul class="simple"> <li><p>The <code class="docutils literal notranslate"><span class="pre">private</span></code>, <code class="docutils literal notranslate"><span class="pre">firstprivate</span></code>, and <code class="docutils literal notranslate"><span class="pre">nowait</span></code> clauses are supported</p></li> <li><p>The <code class="docutils literal notranslate"><span class="pre">copyprivate</span></code> clause is supported only for CPU targets; the compiler emits an error for GPU targets</p></li> <li><p>The <code class="docutils literal notranslate"><span class="pre">allocate</span></code> clause is ignored</p></li> </ul> <p><strong>2.8.3 Workshare Construct</strong></p> <p>The <code class="docutils literal notranslate"><span class="pre">workshare</span></code> construct is supported in Fortran only for CPU targets; the compiler emits an error for GPU targets.</p> <p><strong>2.9 Loop-Related Constructs</strong></p> <p><strong>2.9.2 Worksharing-Loop Construct (for/do)</strong></p> <p>Support for worksharing <code class="docutils literal notranslate"><span class="pre">for</span></code> and <code class="docutils literal notranslate"><span class="pre">do</span></code> construct clauses is as follows.</p> <ul class="simple"> <li><p>The <code class="docutils literal notranslate"><span class="pre">private</span></code>, <code class="docutils literal notranslate"><span class="pre">firstprivate</span></code>, and <code class="docutils literal notranslate"><span class="pre">collapse</span></code> clauses are supported</p></li> <li><p>The <code class="docutils literal notranslate"><span class="pre">reduction</span></code> clause is supported as described in 2.19.5</p></li> <li><p>The <code class="docutils literal notranslate"><span class="pre">schedule</span></code> clause is supported; the optional modifiers are not supported</p></li> <li><p>The <code class="docutils literal notranslate"><span class="pre">lastprivate</span></code> clause is supported; the optional <code class="docutils literal notranslate"><span class="pre">lastprivate</span></code> modifier is not supported</p></li> <li><p>The <code class="docutils literal notranslate"><span class="pre">ordered</span></code> clause is supported only for CPU targets; <code class="docutils literal notranslate"><span class="pre">ordered(n)</span></code> clause is not supported</p></li> <li><p>The <code class="docutils literal notranslate"><span class="pre">linear</span></code> clause is not supported</p></li> <li><p>The <code class="docutils literal notranslate"><span class="pre">order(concurrent)</span></code> clause is ignored</p></li> <li><p>The <code class="docutils literal notranslate"><span class="pre">allocate</span></code> clause is ignored</p></li> </ul> <p><strong>2.9.3 SIMD Directives</strong></p> <p>The <code class="docutils literal notranslate"><span class="pre">simd</span></code> construct can be used to provide tuning hints for CPU targets; the <code class="docutils literal notranslate"><span class="pre">simd</span></code> construct is ignored for GPU targets. Support for <code class="docutils literal notranslate"><span class="pre">simd</span></code> construct clauses is as follows.</p> <ul class="simple"> <li><p>The <code class="docutils literal notranslate"><span class="pre">reduction</span></code> clause is supported as described in 2.19.5</p></li> <li><p>The <code class="docutils literal notranslate"><span class="pre">lastprivate</span></code> clause is supported; the optional <code class="docutils literal notranslate"><span class="pre">lastprivate</span></code> modifier is not supported</p></li> <li><p>The <code class="docutils literal notranslate"><span class="pre">if</span></code>, <code class="docutils literal notranslate"><span class="pre">simdlen</span></code>, and <code class="docutils literal notranslate"><span class="pre">linear</span></code> clauses are not supported</p></li> <li><p>The <code class="docutils literal notranslate"><span class="pre">safelen</span></code>, <code class="docutils literal notranslate"><span class="pre">aligned</span></code>, <code class="docutils literal notranslate"><span class="pre">nontemporal</span></code>, and <code class="docutils literal notranslate"><span class="pre">order(concurrent)</span></code> clauses are ignored</p></li> </ul> <p>The composite <code class="docutils literal notranslate"><span class="pre">for</span></code><code class="docutils literal notranslate"><span class="pre">simd</span></code> and <code class="docutils literal notranslate"><span class="pre">do</span></code><code class="docutils literal notranslate"><span class="pre">simd</span></code> constructs are supported for CPU targets; they are treated as <code class="docutils literal notranslate"><span class="pre">for</span></code> and <code class="docutils literal notranslate"><span class="pre">do</span></code> directives for GPU targets. Supported <code class="docutils literal notranslate"><span class="pre">simd</span></code> clauses are supported on the composite constructs for the CPU. Any <code class="docutils literal notranslate"><span class="pre">simd</span></code> clauses are ignored for GPU targets.</p> <p>The <code class="docutils literal notranslate"><span class="pre">declare</span></code><code class="docutils literal notranslate"><span class="pre">simd</span></code> directive is ignored.</p> <p><strong>2.9.4 Distribute Directives</strong></p> <p>The <code class="docutils literal notranslate"><span class="pre">distribute</span></code> construct is supported within a <code class="docutils literal notranslate"><span class="pre">teams</span></code> construct. Support for <code class="docutils literal notranslate"><span class="pre">distribute</span></code> construct clauses is as follows:</p> <ul class="simple"> <li><p>The <code class="docutils literal notranslate"><span class="pre">private</span></code>, <code class="docutils literal notranslate"><span class="pre">firstprivate</span></code>, <code class="docutils literal notranslate"><span class="pre">collapse</span></code>, and <code class="docutils literal notranslate"><span class="pre">dist_schedule(static</span> <span class="pre">[</span> <span class="pre">,chunksize])</span></code> clauses are supported</p></li> <li><p>The <code class="docutils literal notranslate"><span class="pre">lastprivate</span></code> clause is not supported</p></li> <li><p>The <code class="docutils literal notranslate"><span class="pre">allocate</span></code> clause is ignored</p></li> </ul> <p>The <code class="docutils literal notranslate"><span class="pre">distribute</span> <span class="pre">simd</span></code> construct is treated as a <code class="docutils literal notranslate"><span class="pre">distribute</span></code> construct and is supported for GPU targets; valid supported <code class="docutils literal notranslate"><span class="pre">distribute</span></code> clauses are accepted; <code class="docutils literal notranslate"><span class="pre">simd</span></code> clauses are ignored. The <code class="docutils literal notranslate"><span class="pre">distribute</span></code><code class="docutils literal notranslate"><span class="pre">simd</span></code> construct is not supported for CPU targets.</p> <p>The <code class="docutils literal notranslate"><span class="pre">distribute</span></code><code class="docutils literal notranslate"><span class="pre">parallel</span></code><code class="docutils literal notranslate"><span class="pre">for</span></code> or <code class="docutils literal notranslate"><span class="pre">distribute</span></code><code class="docutils literal notranslate"><span class="pre">parallel</span></code><code class="docutils literal notranslate"><span class="pre">do</span></code> constructs are supported for GPU targets. Valid supported <code class="docutils literal notranslate"><span class="pre">distribute</span></code> and <code class="docutils literal notranslate"><span class="pre">parallel</span></code> and <code class="docutils literal notranslate"><span class="pre">for</span></code> or <code class="docutils literal notranslate"><span class="pre">do</span></code> clauses are accepted. The <code class="docutils literal notranslate"><span class="pre">distribute</span></code><code class="docutils literal notranslate"><span class="pre">parallel</span></code><code class="docutils literal notranslate"><span class="pre">for</span></code> or <code class="docutils literal notranslate"><span class="pre">distribute</span></code><code class="docutils literal notranslate"><span class="pre">parallel</span></code><code class="docutils literal notranslate"><span class="pre">do</span></code> constructs are not supported for CPU targets.</p> <p>The <code class="docutils literal notranslate"><span class="pre">distribute</span> <span class="pre">parallel</span> <span class="pre">`for</span> <span class="pre">simd</span></code> or <code class="docutils literal notranslate"><span class="pre">distribute</span> <span class="pre">parallel</span> <span class="pre">do</span> <span class="pre">simd</span></code> constructs are treated as <code class="docutils literal notranslate"><span class="pre">distribute</span> <span class="pre">parallel</span> <span class="pre">for</span></code> or <code class="docutils literal notranslate"><span class="pre">distribute</span> <span class="pre">parallel</span> <span class="pre">do</span></code> constructs and are supported for GPU targets. These are not supported for CPU targets.</p> <p><strong>2.9.5 Loop Construct</strong></p> <p>Support for <code class="docutils literal notranslate"><span class="pre">loop</span></code> construct clauses is as follows.</p> <ul class="simple"> <li><p>The <code class="docutils literal notranslate"><span class="pre">private</span></code>, <code class="docutils literal notranslate"><span class="pre">bind</span></code>, and <code class="docutils literal notranslate"><span class="pre">collapse</span></code> clauses are supported</p></li> <li><p>The <code class="docutils literal notranslate"><span class="pre">reduction</span></code> clause is supported as described in 2.19.5</p></li> <li><p>The <code class="docutils literal notranslate"><span class="pre">order(concurrent)</span></code> clause is assumed</p></li> <li><p>The <code class="docutils literal notranslate"><span class="pre">lastprivate</span></code> clause is not supported</p></li> </ul> <p><strong>2.10 Tasking Constructs</strong></p> <p><strong>2.10.1 Task Construct</strong></p> <p>The <code class="docutils literal notranslate"><span class="pre">task</span></code> construct is supported for CPU targets. The compiler emits an error when it encounters <code class="docutils literal notranslate"><span class="pre">task</span></code> within a <code class="docutils literal notranslate"><span class="pre">target</span></code> construct. Support for <code class="docutils literal notranslate"><span class="pre">task</span></code> construct clauses is as follows:</p> <ul class="simple"> <li><p>The <code class="docutils literal notranslate"><span class="pre">if</span></code>, <code class="docutils literal notranslate"><span class="pre">final</span></code>, <code class="docutils literal notranslate"><span class="pre">default</span></code> , <code class="docutils literal notranslate"><span class="pre">private</span></code>, <code class="docutils literal notranslate"><span class="pre">firstprivate</span></code>, and <code class="docutils literal notranslate"><span class="pre">shared</span></code> clauses are supported</p></li> <li><p>The <code class="docutils literal notranslate"><span class="pre">depend([dependmodifier,]</span> <span class="pre">dependtype</span> <span class="pre">:</span> <span class="pre">list)</span></code> clause is supported as described in 2.17.11</p></li> </ul> <p><strong>2.10.4 Taskyield Construct</strong></p> <p>The <code class="docutils literal notranslate"><span class="pre">taskyield</span></code> construct is supported for CPU targets; it is ignored for GPU targets.</p> <p><strong>2.11 Memory Management Directives</strong></p> <p>The memory management allocators, memory management API routines, and memory management directives are not supported</p> <p><strong>2.12 Device Directives</strong></p> <p><strong>2.12.1 Device Initialization</strong></p> <p>Depending on how the program is compiled and linked, device initialization may occur at the first <code class="docutils literal notranslate"><span class="pre">target</span></code> construct or API routine call, or may occur implicitly at program startup.</p> <p><strong>2.12.2 Target Data Construct</strong></p> <p>The <code class="docutils literal notranslate"><span class="pre">target</span> <span class="pre">data</span></code> construct is supported for GPU targets. Support for <code class="docutils literal notranslate"><span class="pre">target</span> <span class="pre">data</span></code> construct clauses is as follows.</p> <ul class="simple"> <li><p>The <code class="docutils literal notranslate"><span class="pre">if</span></code>, <code class="docutils literal notranslate"><span class="pre">device</span></code>, <code class="docutils literal notranslate"><span class="pre">use_device_ptr</span></code>, and <code class="docutils literal notranslate"><span class="pre">use_device_addr</span></code> clauses are supported</p></li> <li><p>The <code class="docutils literal notranslate"><span class="pre">map</span></code> clause is supported as described in 2.19.7</p></li> </ul> <p><strong>2.12.3 Target Enter Data Construct</strong></p> <p>The <code class="docutils literal notranslate"><span class="pre">target</span> <span class="pre">enter</span> <span class="pre">data</span></code> construct is supported for GPU targets. Support for <code class="docutils literal notranslate"><span class="pre">enter</span> <span class="pre">data</span></code> construct clauses is as follows.</p> <ul class="simple"> <li><p>The <code class="docutils literal notranslate"><span class="pre">if</span></code>, <code class="docutils literal notranslate"><span class="pre">device</span></code>, and <code class="docutils literal notranslate"><span class="pre">nowait</span></code> clauses are supported</p></li> <li><p>The <code class="docutils literal notranslate"><span class="pre">map</span></code> clause is supported as described in 2.19.7.</p></li> <li><p>The <code class="docutils literal notranslate"><span class="pre">depend([dependmodifier,]</span> <span class="pre">dependtype</span> <span class="pre">:</span> <span class="pre">list)</span></code> clause is supported as described in 2.17.11</p></li> </ul> <p><strong>2.12.4 Target Exit Data Construct</strong></p> <p>The <code class="docutils literal notranslate"><span class="pre">target</span> <span class="pre">exit</span> <span class="pre">data</span></code> construct is supported for GPU targets. Support for <code class="docutils literal notranslate"><span class="pre">exit</span> <span class="pre">data</span></code> construct clauses is as follows.</p> <ul class="simple"> <li><p>The <code class="docutils literal notranslate"><span class="pre">if</span></code>, <code class="docutils literal notranslate"><span class="pre">device</span></code>, and <code class="docutils literal notranslate"><span class="pre">nowait</span></code> clauses are supported</p></li> <li><p>The <code class="docutils literal notranslate"><span class="pre">map</span></code> clause is supported as described in 2.19.7.</p></li> <li><p>The <code class="docutils literal notranslate"><span class="pre">depend([dependmodifier,]</span> <span class="pre">dependtype</span> <span class="pre">:</span> <span class="pre">list)</span></code> clause is supported as described in 2.17.11</p></li> </ul> <p><strong>2.12.5 Target Construct</strong></p> <p>The <code class="docutils literal notranslate"><span class="pre">target</span></code> construct is supported for GPU targets. If there is no GPU or GPU offload is otherwise disabled, execution falls back to CPU mode. Support for <code class="docutils literal notranslate"><span class="pre">target</span></code> construct clauses is as follows:</p> <ul class="simple"> <li><p>The <code class="docutils literal notranslate"><span class="pre">if</span></code>, <code class="docutils literal notranslate"><span class="pre">private</span></code>, <code class="docutils literal notranslate"><span class="pre">firstprivate</span></code>, <code class="docutils literal notranslate"><span class="pre">is_device_ptr</span></code>, and <code class="docutils literal notranslate"><span class="pre">nowait</span></code> clauses are supported</p></li> <li><p>The <code class="docutils literal notranslate"><span class="pre">device</span></code> clause is supported without the device-modifier <code class="docutils literal notranslate"><span class="pre">ancestor</span></code> keyword</p></li> <li><p>The <code class="docutils literal notranslate"><span class="pre">map</span></code> clause is supported as described in 2.19.7</p></li> <li><p>The <code class="docutils literal notranslate"><span class="pre">defaultmap</span></code> clause is supported using OpenMP 5.0 semantics</p></li> <li><p>The <code class="docutils literal notranslate"><span class="pre">depend([dependmodifier,]</span> <span class="pre">dependtype</span> <span class="pre">:</span> <span class="pre">list)</span></code> clause is supported as described in 2.17.11</p></li> <li><p>The <code class="docutils literal notranslate"><span class="pre">allocate</span></code> and <code class="docutils literal notranslate"><span class="pre">uses_allocate</span></code> clauses are ignored</p></li> </ul> <p><strong>2.12.6 Target Update Construct</strong></p> <p>The <code class="docutils literal notranslate"><span class="pre">target</span> <span class="pre">update</span></code> construct is supported for GPU targets. Support for <code class="docutils literal notranslate"><span class="pre">target</span> <span class="pre">update</span></code> construct clauses is as follows.</p> <ul class="simple"> <li><p>The <code class="docutils literal notranslate"><span class="pre">if</span></code>, <code class="docutils literal notranslate"><span class="pre">device</span></code>, and <code class="docutils literal notranslate"><span class="pre">nowait</span></code> clauses are supported.</p></li> <li><p>The <code class="docutils literal notranslate"><span class="pre">to</span></code> and <code class="docutils literal notranslate"><span class="pre">from</span></code> clauses are supported without <code class="docutils literal notranslate"><span class="pre">mapper</span></code> or <code class="docutils literal notranslate"><span class="pre">mapid</span></code></p></li> <li><p>The <code class="docutils literal notranslate"><span class="pre">depend([dependmodifier,]</span> <span class="pre">dependtype</span> <span class="pre">:</span> <span class="pre">list)</span></code> clause is supported as described in 2.17.11</p></li> </ul> <p>Array sections are supported in <code class="docutils literal notranslate"><span class="pre">to</span></code> and <code class="docutils literal notranslate"><span class="pre">from</span></code> clauses, including noncontiguous array sections. Array section strides are not supported. If the array section is noncontiguous, the OpenMP runtime may have to use multiple host-to-device or device-to-host data transfer operations, which increases the overhead. If the host data is in host-pinned memory, then <code class="docutils literal notranslate"><span class="pre">update</span></code> data transfers with the <code class="docutils literal notranslate"><span class="pre">nowait</span></code> clause are asynchronous. This means the data transfer for a <code class="docutils literal notranslate"><span class="pre">target</span> <span class="pre">update</span> <span class="pre">to</span> <span class="pre">nowait</span></code> may not occur immediately or synchronously with the program thread, and any changes to the data may affect the transfer, until a synchronizing operation is reached. Similarly, a <code class="docutils literal notranslate"><span class="pre">target</span> <span class="pre">update</span> <span class="pre">from</span> <span class="pre">nowait</span></code> may not occur immediately or synchronously with the program thread, and the downloaded data may not be available until a synchronizing operation is reached. If the host data is not in host-pinned memory, then <code class="docutils literal notranslate"><span class="pre">update</span></code> data transfers with the <code class="docutils literal notranslate"><span class="pre">nowait</span></code> clause may require that the data transfer operation use an intermediate pinned buffer managed by the OpenMP runtime library, and that a memory copy operation on the host between the program memory and the pinned buffer may be needed before starting or before finishing the transfer operation, which affects overhead and performance. To learn more about the pinned buffer, please refer to <cite>Staging Memory Buffer &lt;acc-mem-pinned-buffer&gt;</cite>.</p> <p><strong>2.12.7 Declare Target Construct</strong></p> <p>The <code class="docutils literal notranslate"><span class="pre">declare</span> <span class="pre">target</span></code> construct is supported for GPU targets.</p> <ul class="simple"> <li><p><code class="docutils literal notranslate"><span class="pre">declare</span> <span class="pre">target</span> <span class="pre">...</span> <span class="pre">end</span> <span class="pre">declare</span> <span class="pre">target</span></code> is supported</p></li> <li><p><code class="docutils literal notranslate"><span class="pre">declare</span> <span class="pre">target(list)</span></code> is supported</p></li> <li><p>The <code class="docutils literal notranslate"><span class="pre">to(list)</span></code> clause is supported</p></li> <li><p>The <code class="docutils literal notranslate"><span class="pre">device_type</span></code> clause is supported for C/C++</p></li> </ul> <p>A function or procedure that is referenced in a function or procedure that appears in a <code class="docutils literal notranslate"><span class="pre">declare</span> <span class="pre">target</span> <span class="pre">to</span></code> clause (explicitly or implicitly) is treated as if its name had implicitly appeared in a <code class="docutils literal notranslate"><span class="pre">declare</span> <span class="pre">target</span> <span class="pre">to</span></code> clause.</p> <p><strong>2.13 Combined Constructs</strong></p> <p>Combined constructs are supported to the extent that the component constructs are themselves supported.</p> <p><strong>2.14 Clauses on Combined and Composite Constructs</strong></p> <p>Clauses on combined constructs are supported to the extent that the clauses are supported on the component constructs.</p> <p><strong>2.16 Master Construct</strong></p> <p>The <code class="docutils literal notranslate"><span class="pre">master</span></code> construct is supported for CPU and GPU targets.</p> <p><strong>2.17 Synchronization Constructs and Clauses</strong></p> <p><strong>2.17.1 Critical Construct</strong></p> <p>The <code class="docutils literal notranslate"><span class="pre">critical</span></code> construct is supported only for CPU targets; the compiler emits an error for GPU targets.</p> <p><strong>2.17.2 Barrier Construct</strong></p> <p>The <code class="docutils literal notranslate"><span class="pre">barrier</span></code> construct is supported.</p> <p><strong>2.17.3 Implicit Barriers</strong></p> <p>Implicit barriers are implemented.</p> <p><strong>2.17.4 Implementation-Specific Barriers</strong></p> <p>There may be implementation-specific barriers, and they may be different for CPU targets than for GPU targets.</p> <p><strong>2.17.5 Taskwait Construct</strong></p> <p>The <code class="docutils literal notranslate"><span class="pre">taskwait</span></code> construct is supported only for CPU targets; it is ignored for GPU targets.</p> <ul class="simple"> <li><p>The <code class="docutils literal notranslate"><span class="pre">depend([dependmodifier,]</span> <span class="pre">dependtype</span> <span class="pre">:</span> <span class="pre">list)</span></code> clause is supported as described in 2.17.11</p></li> </ul> <p><strong>2.17.6 Taskgroup Construct</strong></p> <p>The <code class="docutils literal notranslate"><span class="pre">taskgroup</span></code> construct is supported only for CPU targets. It is ignored for GPU targets.</p> <p><strong>2.17.7 Atomic Construct</strong></p> <p>Support for <code class="docutils literal notranslate"><span class="pre">atomic</span></code> construct clauses is as follows.</p> <ul class="simple"> <li><p>The <code class="docutils literal notranslate"><span class="pre">read</span></code>, <code class="docutils literal notranslate"><span class="pre">write</span></code>, <code class="docutils literal notranslate"><span class="pre">update</span></code>, and <code class="docutils literal notranslate"><span class="pre">capture</span></code> clauses are supported.</p></li> <li><p>The memory order clauses <code class="docutils literal notranslate"><span class="pre">seq_cst</span></code>, <code class="docutils literal notranslate"><span class="pre">acq_rel</span></code>, <code class="docutils literal notranslate"><span class="pre">release</span></code>, <code class="docutils literal notranslate"><span class="pre">acquire</span></code>, <code class="docutils literal notranslate"><span class="pre">relaxed</span></code> are not supported</p></li> <li><p>The <code class="docutils literal notranslate"><span class="pre">hint</span></code> clause is ignored</p></li> </ul> <p><strong>2.17.8 Flush Construct</strong></p> <p>The <code class="docutils literal notranslate"><span class="pre">flush</span></code> construct is supported only for CPU targets.</p> <p><strong>2.17.9 Ordered Construct and Ordered Directive</strong></p> <p>The <code class="docutils literal notranslate"><span class="pre">ordered</span></code> block construct is supported only for CPU targets.</p> <p><strong>2.17.11 Depend Clause</strong></p> <p>The <code class="docutils literal notranslate"><span class="pre">depend</span></code> clause is supported on CPU targets. It is not supported on GPU targets. The dependence types <code class="docutils literal notranslate"><span class="pre">in</span></code>, <code class="docutils literal notranslate"><span class="pre">out</span></code>, and <code class="docutils literal notranslate"><span class="pre">inout</span></code> are supported. The dependence types <code class="docutils literal notranslate"><span class="pre">mutexinoutset</span></code> and <code class="docutils literal notranslate"><span class="pre">depobj</span></code>, dependence modifier <code class="docutils literal notranslate"><span class="pre">iterator(iters)</span></code>, <code class="docutils literal notranslate"><span class="pre">depend(source)</span></code>, and <code class="docutils literal notranslate"><span class="pre">depend(sink:vector)</span></code> are not supported.</p> <p><strong>2.19 Data Environment</strong></p> <p><strong>2.19.2 Threadprivate Directive</strong></p> <p>The <code class="docutils literal notranslate"><span class="pre">threadprivate</span></code> directive is supported only for CPU targets. It is not supported for GPU targets; references to <code class="docutils literal notranslate"><span class="pre">threadprivate</span></code> variables in device code are not supported.</p> <p><strong>2.19.5 Reduction Clauses and Directives</strong></p> <p>The <code class="docutils literal notranslate"><span class="pre">reduction</span></code> clause is supported. The optional modifier is not supported.</p> <p><strong>2.19.6 Data Copying Clauses</strong></p> <p>The data copying <code class="docutils literal notranslate"><span class="pre">copyin</span></code> and <code class="docutils literal notranslate"><span class="pre">copyprivate</span></code> clauses are supported only for CPU targets; the compiler emits a compile-time error for GPU targets.</p> <p><strong>2.19.7 Data Mapping Attribute Rules, Clauses, and Directives</strong></p> <ul class="simple"> <li><p>The <code class="docutils literal notranslate"><span class="pre">map([[mapmod[,]...]</span> <span class="pre">maptype:]</span> <span class="pre">datalist)</span></code> clause is supported. Of the map-type-modifiers, <code class="docutils literal notranslate"><span class="pre">always</span></code> is supported, <code class="docutils literal notranslate"><span class="pre">close</span></code> is ignored, and <code class="docutils literal notranslate"><span class="pre">mapper(mapid)</span></code> is not supported.</p></li> <li><p>The <code class="docutils literal notranslate"><span class="pre">defaultmap</span></code> clause is supported using OpenMP 5.0 semantics.</p></li> </ul> <p><strong>2.20 Nesting of Regions</strong></p> <p>For constructs supported in this subset, restrictions on nesting of regions is observed. Additionally, nested parallel regions on CPU are not supported and nested teams or parallel regions in a target region are not supported.</p> <p><strong>Runtime Library Routines</strong></p> <p><strong>3.2 Execution Environment Routines</strong></p> <p>The following execution environment runtime API routines are supported.</p> <ul class="simple"> <li><p><code class="docutils literal notranslate"><span class="pre">omp_set_num_threads</span></code>, <code class="docutils literal notranslate"><span class="pre">omp_get_num_threads</span></code>, <code class="docutils literal notranslate"><span class="pre">omp_get_max_threads</span></code>, <code class="docutils literal notranslate"><span class="pre">omp_get_thread_num</span></code>, <code class="docutils literal notranslate"><span class="pre">omp_get_thread_limit</span></code>, <code class="docutils literal notranslate"><span class="pre">omp_get_supported_active_levels</span></code>, <code class="docutils literal notranslate"><span class="pre">omp_set_max_active_levels</span></code>, <code class="docutils literal notranslate"><span class="pre">omp_get_max_active_levels</span></code>, <code class="docutils literal notranslate"><span class="pre">omp_get_level</span></code>, <code class="docutils literal notranslate"><span class="pre">omp_get_ancestor_thread_num</span></code>, <code class="docutils literal notranslate"><span class="pre">omp_get_team_size</span></code>, <code class="docutils literal notranslate"><span class="pre">omp_get_num_teams</span></code>, <code class="docutils literal notranslate"><span class="pre">omp_get_team_num</span></code>, <code class="docutils literal notranslate"><span class="pre">omp_is_initial_device</span></code></p></li> </ul> <p>The following execution environment runtime API routines are supported only on the CPU.</p> <ul class="simple"> <li><p><code class="docutils literal notranslate"><span class="pre">omp_get_num_procs</span></code>, <code class="docutils literal notranslate"><span class="pre">omp_set_dynamic</span></code>, <code class="docutils literal notranslate"><span class="pre">omp_get_dynamic</span></code>, <code class="docutils literal notranslate"><span class="pre">omp_set_schedule</span></code>, <code class="docutils literal notranslate"><span class="pre">omp_get_schedule</span></code>, <code class="docutils literal notranslate"><span class="pre">omp_in_final</span></code>, <code class="docutils literal notranslate"><span class="pre">omp_get_proc_bind</span></code>, <code class="docutils literal notranslate"><span class="pre">omp_get_num_places</span></code>, <code class="docutils literal notranslate"><span class="pre">omp_get_affinity_format</span></code>, <code class="docutils literal notranslate"><span class="pre">omp_set_default_device</span></code>, <code class="docutils literal notranslate"><span class="pre">omp_get_default_device</span></code>, <code class="docutils literal notranslate"><span class="pre">omp_get_num_devices</span></code>, <code class="docutils literal notranslate"><span class="pre">omp_get_device_num</span></code>, <code class="docutils literal notranslate"><span class="pre">omp_get_initial_device</span></code></p></li> </ul> <p>The following execution environment runtime API routines have limited support.</p> <ul class="simple"> <li><p><code class="docutils literal notranslate"><span class="pre">omp_get_cancellation</span></code>, <code class="docutils literal notranslate"><span class="pre">omp_get_nested</span></code>; supported only on the CPU; the value returned is always false</p></li> <li><p><code class="docutils literal notranslate"><span class="pre">omp_display_affinity</span></code>, <code class="docutils literal notranslate"><span class="pre">omp_capture_affinity</span></code>; supported only on the CPU; the format specifier is ignored</p></li> <li><p><code class="docutils literal notranslate"><span class="pre">omp_set_nested</span></code>; supported only on the CPU, the value is ignored</p></li> </ul> <p>The following execution environment runtime API routines are not supported.</p> <ul class="simple"> <li><p><code class="docutils literal notranslate"><span class="pre">omp_get_place_num_procs</span></code>, <code class="docutils literal notranslate"><span class="pre">omp_get_place_proc_ids</span></code>, <code class="docutils literal notranslate"><span class="pre">omp_get_place_num</span></code>, <code class="docutils literal notranslate"><span class="pre">omp_get_partition_num_places</span></code>, <code class="docutils literal notranslate"><span class="pre">omp_get_partition_place_nums</span></code>, <code class="docutils literal notranslate"><span class="pre">omp_set_affinity_format</span></code>, <code class="docutils literal notranslate"><span class="pre">omp_get_max_task_priority</span></code>, <code class="docutils literal notranslate"><span class="pre">omp_pause_resource</span></code>, <code class="docutils literal notranslate"><span class="pre">omp_pause_resource_all</span></code></p></li> </ul> <p><strong>3.3 Lock Routines</strong></p> <p>Lock runtime API routines are not supported on the GPU. The following lock runtime API routines are supported on the CPU.</p> <ul class="simple"> <li><p><code class="docutils literal notranslate"><span class="pre">omp_init_lock</span></code>, <code class="docutils literal notranslate"><span class="pre">omp_init_nest_lock</span></code>, <code class="docutils literal notranslate"><span class="pre">omp_destroy_lock</span></code>, <code class="docutils literal notranslate"><span class="pre">omp_destroy_nest_lock</span></code>, <code class="docutils literal notranslate"><span class="pre">omp_set_lock</span></code>, <code class="docutils literal notranslate"><span class="pre">omp_set_nest_lock</span></code>, <code class="docutils literal notranslate"><span class="pre">omp_unset_lock</span></code>, <code class="docutils literal notranslate"><span class="pre">omp_unset_nest_lock</span></code>, <code class="docutils literal notranslate"><span class="pre">omp_test_lock</span></code>, <code class="docutils literal notranslate"><span class="pre">omp_test_nest_lock</span></code></p></li> </ul> <p>The following lock runtime API routines are not supported.</p> <ul class="simple"> <li><p><code class="docutils literal notranslate"><span class="pre">omp_init_lock_with_hint</span></code>, <code class="docutils literal notranslate"><span class="pre">omp_init_nest_lock_with_hint</span></code></p></li> </ul> <p><strong>3.4 Timing Routines</strong></p> <p>The following timing runtime API routines are supported.</p> <ul class="simple"> <li><p><code class="docutils literal notranslate"><span class="pre">omp_get_wtime</span></code>, <code class="docutils literal notranslate"><span class="pre">omp_get_wtick</span></code></p></li> </ul> <p><strong>3.6 Device Memory Routines</strong></p> <p>The following device memory routines are supported only on the CPU.</p> <ul class="simple"> <li><p><code class="docutils literal notranslate"><span class="pre">omp_target_is_present</span></code>, <code class="docutils literal notranslate"><span class="pre">omp_target_associate_ptr</span></code>, <code class="docutils literal notranslate"><span class="pre">omp_target_disassociate_ptr</span></code></p></li> <li><p><code class="docutils literal notranslate"><span class="pre">omp_target_memcpy</span></code> and <code class="docutils literal notranslate"><span class="pre">omp_target_memcpy_rect</span></code> are only supported when copying to and from the same device.</p></li> </ul> <p>The following device memory routines are supported on the CPU; we extend OpenMP to support these in target regions on a GPU, but only allocation and deallocation on the same device is supported.</p> <ul class="simple"> <li><p><code class="docutils literal notranslate"><span class="pre">omp_target_alloc</span></code>, <code class="docutils literal notranslate"><span class="pre">omp_target_free</span></code></p></li> </ul> <p><strong>3.7 Memory Management Routines</strong></p> <p>The following memory management routines are supported.</p> <ul class="simple"> <li><p><code class="docutils literal notranslate"><span class="pre">omp_alloc</span></code>, <code class="docutils literal notranslate"><span class="pre">omp_free</span></code></p></li> </ul> <p>The following memory management routines are not supported.</p> <ul class="simple"> <li><p><code class="docutils literal notranslate"><span class="pre">omp_init_allocator</span></code>, <code class="docutils literal notranslate"><span class="pre">omp_destroy_allocator</span></code>, <code class="docutils literal notranslate"><span class="pre">omp_set_default_allocator</span></code>, <code class="docutils literal notranslate"><span class="pre">omp_get_default_allocator</span></code></p></li> </ul> <p><strong>6 Environment Variables</strong></p> <p>The following environment variables have limited support.</p> <ul class="simple"> <li><p><code class="docutils literal notranslate"><span class="pre">OMP_SCHEDULE</span></code>, <code class="docutils literal notranslate"><span class="pre">OMP_NUM_THREADS</span></code>, <code class="docutils literal notranslate"><span class="pre">OMP_NUM_TEAMS</span></code>, <code class="docutils literal notranslate"><span class="pre">OMP_DYNAMIC</span></code>, <code class="docutils literal notranslate"><span class="pre">OMP_PROC_BIND</span></code>, <code class="docutils literal notranslate"><span class="pre">OMP_PLACES</span></code>, <code class="docutils literal notranslate"><span class="pre">OMP_STACKSIZE</span></code>, <code class="docutils literal notranslate"><span class="pre">OMP_WAIT_POLICY</span></code>, <code class="docutils literal notranslate"><span class="pre">OMP_MAX_ACTIVE_LEVELS</span></code>, <code class="docutils literal notranslate"><span class="pre">OMP_NESTED</span></code>, <code class="docutils literal notranslate"><span class="pre">OMP_THREAD_LIMIT</span></code>, <code class="docutils literal notranslate"><span class="pre">OMP_TEAMS_THREAD_LIMIT</span></code>, <code class="docutils literal notranslate"><span class="pre">OMP_DISPLAY_ENV</span></code>, <code class="docutils literal notranslate"><span class="pre">OMP_DISPLAY_AFFINITY</span></code>, <code class="docutils literal notranslate"><span class="pre">OMP_DEFAULT_DEVICE</span></code>, and <code class="docutils literal notranslate"><span class="pre">OMP_TARGET_OFFLOAD</span></code> are supported on CPU.</p></li> <li><p><code class="docutils literal notranslate"><span class="pre">OMP_CANCELLATION</span></code> and <code class="docutils literal notranslate"><span class="pre">OMP_MAX_TASK_PRIORITY</span></code> are ignored.</p></li> <li><p><code class="docutils literal notranslate"><span class="pre">OMP_AFFINITY_FORMAT</span></code>, <code class="docutils literal notranslate"><span class="pre">OMP_TOOL</span></code>, <code class="docutils literal notranslate"><span class="pre">OMP_TOOL_LIBRARIES</span></code>, <code class="docutils literal notranslate"><span class="pre">OMP_DEBUG</span></code>, and <code class="docutils literal notranslate"><span class="pre">OMP_ALLOCATOR</span></code> are not supported</p></li> </ul> </section> <section id="using-metadirective"> <h2><span class="section-number">7.5. </span>Using metadirective<a class="headerlink" href="#using-metadirective" title="Permalink to this headline"></a></h2> <p>This section contains limitations affecting <code class="docutils literal notranslate"><span class="pre">metadirective</span></code> along with a few guidelines for its use.</p> <p>The Fortran compiler does not support variants leading to an OpenMP directive for which a corresponding <code class="docutils literal notranslate"><span class="pre">end</span></code> directive is required.</p> <p>Nesting <code class="docutils literal notranslate"><span class="pre">user</span></code> conditions, while legal, may create situations that the HPC Compilers do not handle gracefully. To avoid potential problems, use <code class="docutils literal notranslate"><span class="pre">device</span></code> traits inside <code class="docutils literal notranslate"><span class="pre">user</span></code> conditions instead. The following example illustrates this best practice.</p> <p>Avoid nesting dynamic <code class="docutils literal notranslate"><span class="pre">user</span></code> conditions like this:</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="cp">#pragma omp metadirective \</span> <span class="cp"> when( user={condition(use_offload)} : target teams distribute) \</span> <span class="cp"> default( parallel for schedule(static) )</span> <span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="n">N</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="o">++</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="p">...</span><span class="w"></span> <span class="cp">#pragma omp metadirective \</span> <span class="cp"> when( user={condition(use_offload)} : parallel for)</span> <span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="n">j</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="n">j</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="n">N</span><span class="p">;</span><span class="w"> </span><span class="n">j</span><span class="o">++</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="p">...</span><span class="w"></span> <span class="w"> </span><span class="p">}</span><span class="w"></span> <span class="w"> </span><span class="p">...</span><span class="w"></span> <span class="w"> </span><span class="p">}</span><span class="w"></span> </pre></div> </div> <p>Instead, use <code class="docutils literal notranslate"><span class="pre">target_device</span></code> and <code class="docutils literal notranslate"><span class="pre">device</span></code> traits within dynamic <code class="docutils literal notranslate"><span class="pre">user</span></code> conditions like this:</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="cp">#pragma omp metadirective \</span> <span class="cp"> when( target_device={kind(gpu)}, user={condition(use_offload)} : target teams distribute) \</span> <span class="cp"> default( parallel for schedule(static) )</span> <span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="n">N</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="o">++</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="p">...</span><span class="w"></span> <span class="cp">#pragma omp metadirective \</span> <span class="cp"> when( device={kind(gpu)} : parallel for)</span> <span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="n">j</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="n">j</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="n">N</span><span class="p">;</span><span class="w"> </span><span class="n">j</span><span class="o">++</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="p">...</span><span class="w"></span> <span class="w"> </span><span class="p">}</span><span class="w"></span> <span class="w"> </span><span class="p">...</span><span class="w"></span> <span class="w"> </span><span class="p">}</span><span class="w"></span> </pre></div> </div> <p>The HPC compilers do not support nesting <code class="docutils literal notranslate"><span class="pre">metadirective</span></code> inside a <code class="docutils literal notranslate"><span class="pre">target</span></code> construct applying to a syntactic block leading to a <code class="docutils literal notranslate"><span class="pre">teams</span></code> variant. Some examples:</p> <p>The compilers will emit an error given the following code:</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="cp">#pragma omp target map(to:v1,v2) map(from:v3)</span> <span class="p">{</span><span class="w"></span> <span class="cp">#pragma omp metadirective \</span> <span class="cp">when( device={arch(&quot;nvptx&quot;)} : teams distribute parallel for) \</span> <span class="cp">default( parallel for)</span> <span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="kt">int</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="n">N</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="o">++</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="n">v3</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">v1</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">v2</span><span class="p">[</span><span class="n">i</span><span class="p">];</span><span class="w"></span> <span class="w"> </span><span class="p">}</span><span class="w"></span> <span class="p">}</span><span class="w"></span> </pre></div> </div> <p>The compilers will always match <code class="docutils literal notranslate"><span class="pre">device={arch(&quot;nvptx&quot;)}</span></code> given the following code:</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="cp">#pragma omp target map(to:v1,v2) map(from:v3)</span> <span class="cp">#pragma omp metadirective \</span> <span class="cp">when( device={arch(&quot;nvptx&quot;)} : teams distribute parallel for) \</span> <span class="cp">default( parallel for)</span> <span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="kt">int</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="n">N</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="o">++</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="n">v3</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">v1</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">v2</span><span class="p">[</span><span class="n">i</span><span class="p">];</span><span class="w"></span> <span class="w"> </span><span class="p">}</span><span class="w"></span> </pre></div> </div> <p>The compilers match <code class="docutils literal notranslate"><span class="pre">device={&quot;arch&quot;)</span></code> for GPU code, and <code class="docutils literal notranslate"><span class="pre">default</span></code> for host fallback, given the following code:</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="cp">#pragma omp target teams distribute map(to:v1,v2) map(from:v3)</span> <span class="k">for</span><span class="w"> </span><span class="p">(...)</span><span class="w"></span> <span class="p">{</span><span class="w"></span> <span class="cp">#pragma omp metadirective \</span> <span class="cp">when( device={arch(&quot;nvptx&quot;)} : parallel for) \</span> <span class="cp">default( simd )</span> <span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="kt">int</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="n">N</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="o">++</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="n">v3</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">v1</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">v2</span><span class="p">[</span><span class="n">i</span><span class="p">];</span><span class="w"></span> <span class="w"> </span><span class="p">}</span><span class="w"></span> <span class="p">}</span><span class="w"></span> </pre></div> </div> </section> <section id="mapping-target-constructs-to-cuda-streams"> <h2><span class="section-number">7.6. </span>Mapping target constructs to CUDA streams<a class="headerlink" href="#mapping-target-constructs-to-cuda-streams" title="Permalink to this headline"></a></h2> <p>An OpenMP target task generating construct is executed on the GPU in a CUDA stream. The following are target task generating constructs:</p> <ul class="simple"> <li><p><code class="docutils literal notranslate"><span class="pre">target</span> <span class="pre">enter</span> <span class="pre">data</span></code></p></li> <li><p><code class="docutils literal notranslate"><span class="pre">target</span> <span class="pre">exit</span> <span class="pre">data</span></code></p></li> <li><p><code class="docutils literal notranslate"><span class="pre">target</span> <span class="pre">update</span></code></p></li> <li><p><code class="docutils literal notranslate"><span class="pre">target</span></code></p></li> </ul> <p>This section explains how these target constructs are mapped to CUDA streams. The relationship with the OpenACC queues is also explained below.</p> <p>Keep in mind that the <code class="docutils literal notranslate"><span class="pre">target</span> <span class="pre">data</span></code> construct does not generate a task and is not necessarily executed in a CUDA stream. It also cannot have the <code class="docutils literal notranslate"><span class="pre">depend</span></code> and <code class="docutils literal notranslate"><span class="pre">nowait</span></code> clauses, thus its behavior cannot be directly controlled by the user application. The rest of this section does not cover the behavior of the <code class="docutils literal notranslate"><span class="pre">target</span> <span class="pre">data</span></code> construct.</p> <p>Any task-generating target construct can have <code class="docutils literal notranslate"><span class="pre">depend</span></code> and <code class="docutils literal notranslate"><span class="pre">nowait</span></code> clauses. The NVIDIA OpenMP Runtime takes these clauses as a guidance for how to map the construct to a specific CUDA stream. Below is a breakdown of how the clauses affect the mapping decisions.</p> <p><strong>‘target’ without ‘depend’, without ‘nowait’</strong></p> <p>For these constructs, the per-thread default CUDA stream is normally used. The stream is unique for each host thread, so target regions created by different host threads will execute independently in different streams according to the CUDA rules described in <a class="reference external" href="https://docs.nvidia.com/cuda/cuda-runtime-api/stream-sync-behavior.html">CUDA Runtime API</a>; see the rules in the “Per-thread default stream” section.</p> <p>The OpenACC queue <code class="docutils literal notranslate"><span class="pre">acc_async_sync</span></code> is initially associated with the same per-thread default CUDA stream. The user is allowed to change the association by calling <code class="docutils literal notranslate"><span class="pre">acc_set_cuda_stream(acc_async_sync,</span> <span class="pre">stream)</span></code>. This will change accordingly the stream used for <code class="docutils literal notranslate"><span class="pre">target</span></code> without <code class="docutils literal notranslate"><span class="pre">nowait</span></code>.</p> <p>The CUDA stream handle can be directly obtained via the <code class="docutils literal notranslate"><span class="pre">ompx_get_cuda_stream(int</span> <span class="pre">device,</span> <span class="pre">int</span> <span class="pre">nowait)</span></code> function, with the <code class="docutils literal notranslate"><span class="pre">nowait</span></code> parameter set to 0. The per-thread default stream can be obtained with the CUDA handle <code class="docutils literal notranslate"><span class="pre">CU_STREAM_PER_THREAD</span></code> or <code class="docutils literal notranslate"><span class="pre">cudaStreamPerThread</span></code>.</p> <p>Here is an example of how a custom CUDA stream can be used to substitute the default stream:</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="k">extern</span><span class="w"> </span><span class="n">__global__</span><span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="n">kernel</span><span class="p">(</span><span class="kt">int</span><span class="w"> </span><span class="o">*</span><span class="n">data</span><span class="p">);</span><span class="w"></span> <span class="w"> </span><span class="n">CUstream</span><span class="w"> </span><span class="n">stream</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="n">cuStreamCreate</span><span class="p">(</span><span class="o">&amp;</span><span class="n">stream</span><span class="p">,</span><span class="w"> </span><span class="n">CU_STREAM_DEFAULT</span><span class="p">);</span><span class="w"></span> <span class="w"> </span><span class="n">acc_set_cuda_stream</span><span class="p">(</span><span class="n">acc_async_sync</span><span class="p">,</span><span class="w"> </span><span class="n">stream</span><span class="p">);</span><span class="w"></span> <span class="cp">#pragma omp target enter data map(to:data[:N])</span> <span class="cp">#pragma omp target data use_device_ptr(data)</span> <span class="w"> </span><span class="n">kernel</span><span class="o">&lt;&lt;&lt;</span><span class="n">N</span><span class="o">/</span><span class="mi">32</span><span class="p">,</span><span class="w"> </span><span class="mi">32</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="n">stream</span><span class="o">&gt;&gt;&gt;</span><span class="p">(</span><span class="n">data</span><span class="p">);</span><span class="w"></span> <span class="cp">#pragma omp target teams distribute parallel for</span> <span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="kt">int</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="n">N</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="o">++</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="n">data</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">++</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="p">}</span><span class="w"></span> <span class="cp">#pragma omp target exit data map(from:data[:N])</span> </pre></div> </div> <p>Note there is no explicit stream synchronization after the CUDA <code class="docutils literal notranslate"><span class="pre">kernel</span></code> is launched. The stream is synchronized automatically at the <code class="docutils literal notranslate"><span class="pre">target</span></code> constructs that follow.</p> <p><strong>‘target’ with ‘depend’, without ‘nowait’</strong></p> <p>For this construct, the runtime will block the current thread until all dependencies listed in the <code class="docutils literal notranslate"><span class="pre">depend</span></code> clause are resolved. Then, the <code class="docutils literal notranslate"><span class="pre">target</span></code> construct will be executed in the default per-thread CUDA stream as described in the previous section (that is, as if there is no <code class="docutils literal notranslate"><span class="pre">depend</span></code> clause).</p> <p><strong>‘target’ with ‘nowait’, without ‘depend’</strong></p> <p>By default, the runtime will select a CUDA stream for each new <code class="docutils literal notranslate"><span class="pre">target</span> <span class="pre">nowait</span></code> construct. The selected stream may be the same that was used for a prior <code class="docutils literal notranslate"><span class="pre">target</span> <span class="pre">nowait</span></code> construct. That is, there is no guarantee of uniqueness of the selected stream.</p> <p>This is different from the OpenACC model that uses the same CUDA stream associated with the <code class="docutils literal notranslate"><span class="pre">acc_async_noval</span></code> queue for any asynchronous construct with the <code class="docutils literal notranslate"><span class="pre">async</span></code> clause without an argument. To change this behavior, the user can call the <code class="docutils literal notranslate"><span class="pre">ompx_set_cuda_stream_auto(int</span> <span class="pre">enable)</span></code> function with the <code class="docutils literal notranslate"><span class="pre">enable</span></code> parameter set to 0. In this case, the CUDA stream associated with the <code class="docutils literal notranslate"><span class="pre">acc_async_noval</span></code> OpenACC queue will be used for all OpenMP <code class="docutils literal notranslate"><span class="pre">target</span> <span class="pre">nowait</span></code> constructs. Another way to enable this behavior is to set the environment variable <code class="docutils literal notranslate"><span class="pre">NVCOMPILER_OMP_AUTO_STREAMS</span></code> to <code class="docutils literal notranslate"><span class="pre">FALSE</span></code>.</p> <p>To access the stream used for the next <code class="docutils literal notranslate"><span class="pre">target</span> <span class="pre">nowait</span></code> construct, the user can call the <code class="docutils literal notranslate"><span class="pre">ompx_get_cuda_stream(int</span> <span class="pre">device,</span> <span class="pre">int</span> <span class="pre">nowait)</span></code> function, with the <code class="docutils literal notranslate"><span class="pre">nowait</span></code> parameter set to 1.</p> <p><strong>‘target’ with both ‘depend’ and ‘nowait’</strong></p> <p>The decision on which CUDA stream to use in this case relies on previously scheduled target and host tasks sharing a subset of the dependencies listed in the <code class="docutils literal notranslate"><span class="pre">depend</span></code> clause:</p> <ul class="simple"> <li><p>If the target construct has only one dependency, which is of the type <code class="docutils literal notranslate"><span class="pre">inout</span></code> or <code class="docutils literal notranslate"><span class="pre">out</span></code>, and that dependency maps to a previously scheduled <code class="docutils literal notranslate"><span class="pre">target</span> <span class="pre">depend(...)</span> <span class="pre">nowait</span></code> construct, and the same device is used for both target constructs, then the CUDA stream which the previous target task was scheduled to will be used.</p></li> <li><p>Otherwise, a CUDA stream will be selected for this target construct according to the stream selection policy.</p></li> </ul> <p>Note that target constructs with a single <code class="docutils literal notranslate"><span class="pre">in</span></code> dependency can be scheduled on a newly selected CUDA stream. This is to allow parallel execution of multiple <code class="docutils literal notranslate"><span class="pre">target</span> <span class="pre">nowait</span></code> constructs that depend on data produced by another previously scheduled <code class="docutils literal notranslate"><span class="pre">target</span> <span class="pre">nowait</span></code> construct.</p> <p>Here is a simplified example of how a <code class="docutils literal notranslate"><span class="pre">target</span></code> construct, a CUDA library function and a CUDA kernel can be executed on the GPU in the same stream asynchronously with respect to the host thread:</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="k">extern</span><span class="w"> </span><span class="n">__global__</span><span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="n">kernel</span><span class="p">(</span><span class="kt">int</span><span class="w"> </span><span class="o">*</span><span class="n">data</span><span class="p">);</span><span class="w"></span> <span class="n">cudaStream_t</span><span class="w"> </span><span class="n">stream</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="n">cudaStream_t</span><span class="p">)</span><span class="n">ompx_get_cuda_stream</span><span class="p">(</span><span class="n">omp_get_default_device</span><span class="p">(),</span><span class="w"> </span><span class="mi">1</span><span class="p">);</span><span class="w"></span> <span class="n">cufftSetStream</span><span class="p">(</span><span class="n">cufft_plan</span><span class="p">,</span><span class="w"> </span><span class="n">stream</span><span class="p">);</span><span class="w"></span> <span class="cp">#pragma omp target enter data map(to:data[:N]) depend(inout:stream) nowait</span> <span class="cp">#pragma omp target data use_device_ptr(data)</span> <span class="w"> </span><span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="n">kernel</span><span class="o">&lt;&lt;&lt;</span><span class="n">N</span><span class="o">/</span><span class="mi">32</span><span class="p">,</span><span class="w"> </span><span class="mi">32</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="n">stream</span><span class="o">&gt;&gt;&gt;</span><span class="p">(</span><span class="n">data</span><span class="p">);</span><span class="w"></span> <span class="w"> </span><span class="n">cufftExecC2C</span><span class="p">(</span><span class="n">cufft_plan</span><span class="p">,</span><span class="w"> </span><span class="n">data</span><span class="p">,</span><span class="w"> </span><span class="n">data</span><span class="p">,</span><span class="w"> </span><span class="n">CUFFT_FORWARD</span><span class="p">);</span><span class="w"></span> <span class="w"> </span><span class="p">}</span><span class="w"></span> <span class="cp">#pragma omp target teams distribute parallel for depend(inout:stream) nowait</span> <span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="kt">int</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="n">N</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="o">++</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="n">data</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">++</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="p">}</span><span class="w"></span> <span class="cp">#pragma omp target exit data map(from:data[:N]) depend(inout:stream) nowait</span> </pre></div> </div> <p>Note that the <code class="docutils literal notranslate"><span class="pre">stream</span></code> variable holds the CUDA stream handle and also serves as the dependency for the <code class="docutils literal notranslate"><span class="pre">target</span></code> constructs. This dependency enforces the order of execution and also guarantees the target constructs are on the same stream that was returned from the <code class="docutils literal notranslate"><span class="pre">ompx_get_cuda_stream</span></code> function call.</p> <p><strong>NVIDIA OpenMP API to access and control CUDA streams</strong></p> <p>NVIDIA OpenMP Runtime provides the following API to access CUDA streams and to control their use.</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="kt">void</span><span class="w"> </span><span class="o">*</span><span class="nf">ompx_get_cuda_stream</span><span class="p">(</span><span class="kt">int</span><span class="w"> </span><span class="n">device</span><span class="p">,</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">nowait</span><span class="p">);</span><span class="w"></span> </pre></div> </div> <p>This function returns the handle of the CUDA stream that will be used for the next <code class="docutils literal notranslate"><span class="pre">target</span></code> construct:</p> <ul class="simple"> <li><p>If the <code class="docutils literal notranslate"><span class="pre">nowait</span></code> parameter is set to 0, it returns the CUDA stream associated with the OpenACC queue <code class="docutils literal notranslate"><span class="pre">acc_async_sync</span></code>, which is initially mapped to the default per-thread CUDA stream;</p></li> <li><p>Otherwise, it returns a CUDA stream which will be used for the next <code class="docutils literal notranslate"><span class="pre">target</span> <span class="pre">nowait</span></code> construct that cannot be mapped to an existing stream according to the rules for the <code class="docutils literal notranslate"><span class="pre">depend</span></code> clause.</p></li> </ul> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="kt">void</span><span class="w"> </span><span class="nf">ompx_set_cuda_stream_auto</span><span class="p">(</span><span class="kt">int</span><span class="w"> </span><span class="n">enable</span><span class="p">);</span><span class="w"></span> </pre></div> </div> <p>This function sets the policy for how CUDA streams are selected for <code class="docutils literal notranslate"><span class="pre">target</span> <span class="pre">nowait</span></code> constructs:</p> <ul class="simple"> <li><p>If the <code class="docutils literal notranslate"><span class="pre">enable</span></code> parameter is set to a non-zero value, an internally selected CUDA stream will be used for each <code class="docutils literal notranslate"><span class="pre">target</span> <span class="pre">nowait</span></code> construct that follows. This is the default behavior;</p></li> <li><p>Otherwise, the CUDA stream associated with the OpenACC queue <code class="docutils literal notranslate"><span class="pre">acc_async_noval</span></code> will be used for all <code class="docutils literal notranslate"><span class="pre">target</span> <span class="pre">nowait</span></code> constructs that follow. This becomes the default behavior if the environment variable <code class="docutils literal notranslate"><span class="pre">NVCOMPILER_OMP_AUTO_STREAMS</span></code> is set to <code class="docutils literal notranslate"><span class="pre">FALSE</span></code>.</p></li> </ul> <p>The setting is done only for the host thread which calls this function.</p> </section> <section id="noncontiguous-array-sections"> <h2><span class="section-number">7.7. </span>Noncontiguous Array Sections<a class="headerlink" href="#noncontiguous-array-sections" title="Permalink to this headline"></a></h2> <p>Array sections can be used in <code class="docutils literal notranslate"><span class="pre">to</span></code> and <code class="docutils literal notranslate"><span class="pre">from</span></code> clauses, including noncontiguous array sections. The noncontiguous array section must be specified in a single <code class="docutils literal notranslate"><span class="pre">map</span></code> clause; it cannot be split between multiple directives. Although this feature may become a part of a future OpenMP specification, at this time it is an NVIDIA HPC compilers extension.</p> <span class="target" id="openmp-unified-mem"></span></section> <section id="openmp-with-cuda-unified-memory"> <h2><span class="section-number">7.8. </span>OpenMP with CUDA Unified Memory<a class="headerlink" href="#openmp-with-cuda-unified-memory" title="Permalink to this headline"></a></h2> <p>This section will focus on OpenMP unified shared memory programming, and assume users are familiar with Separate, Managed, and Unified Memory Modes explained in the <a class="reference internal" href="#acc-mem-model"><span class="std std-ref">Memory Model</span></a> and <a class="reference internal" href="#acc-mem-unified"><span class="std std-ref">Managed and Unified Memory Modes</span></a> sections. OpenMP unified shared memory corresponds to Unified Memory Mode in NVHPC Compilers and it can be enabled with <code class="docutils literal notranslate"><span class="pre">-gpu=mem:unified</span></code> flag. Source code with <code class="docutils literal notranslate"><span class="pre">requires</span> <span class="pre">unified_shared_memory</span></code> directive is accepted but requires <code class="docutils literal notranslate"><span class="pre">-gpu=mem:unified</span></code> flag to activate Unified Memory Mode.</p> <p>In Unified Memory Mode, <code class="docutils literal notranslate"><span class="pre">map</span></code> clauses on <code class="docutils literal notranslate"><span class="pre">target</span></code> constructs are optional. Additionally, <code class="docutils literal notranslate"><span class="pre">declare</span> <span class="pre">target</span></code> directives are optional for variables with static storage duration accessed inside functions to which such directive is applied. The OpenMP unified shared memory eases accelerator programming on the GPUs removing the need for data management and only requiring to express the parallelism in the compute regions.</p> <p>In Unified Memory Mode, all data is managed by the CUDA runtime. Explicit data <code class="docutils literal notranslate"><span class="pre">map</span></code> clauses which manage the data movement across the host and devices become optional. All variables are accessible from the OpenMP offload compute regions executing on the GPU. The <code class="docutils literal notranslate"><span class="pre">map</span></code> clause with <code class="docutils literal notranslate"><span class="pre">alloc</span></code>, <code class="docutils literal notranslate"><span class="pre">to</span></code>, <code class="docutils literal notranslate"><span class="pre">from</span></code>, and <code class="docutils literal notranslate"><span class="pre">tofrom</span></code> type will not result in any device allocation or data transfer. The OpenMP runtime, however, may leverage such clauses to communicate preferable data placement to the CUDA runtime by means of memory hint APIs as elaborated in the following blog post on the NVIDIA website: <a class="reference external" href="https://developer.nvidia.com/blog/simplifying-gpu-application-development-with-heterogeneous-memory-management">Simplifying GPU Application Development with Heterogeneous Memory Management</a>. Device memory can be allocated or deallocated in OpenMP programs in Unified Memory Mode by using the <code class="docutils literal notranslate"><span class="pre">omp_target_alloc</span></code> and <code class="docutils literal notranslate"><span class="pre">omp_target_free</span></code> API calls. Please, note that the memory allocated through <code class="docutils literal notranslate"><span class="pre">omp_target_alloc</span></code> cannot be accessed by the host.</p> <p><strong>Understanding Data Movement</strong></p> <p>When the compiler encounters a compute construct without visible <code class="docutils literal notranslate"><span class="pre">target</span> <span class="pre">data</span></code> directives or <code class="docutils literal notranslate"><span class="pre">map</span></code> clauses, it attempts to determine what data is required for correct execution of the region on the GPU. When the compiler is unable to determine the size and shape of data needing to be accessible on the device, it behaves as follows:</p> <ul class="simple"> <li><p>In Separate Memory Mode, the compiler may not be able to alert you to the need for an explicit data clause specifying size and/or shape of data being copied to/from the GPU. In this case, the default length of one may be used. This may cause illegal memory access errors at runtime on the GPU devices.</p></li> <li><p>In Managed Memory Mode (<code class="docutils literal notranslate"><span class="pre">-gpu=mem:managed</span></code>), the compiler assumes the data is allocated in managed memory and thus is accessible from the device; if this assumption is wrong, for example, if the data was defined globally or is located on the CPU stack, the program may fail at runtime.</p></li> <li><p>In Unified Memory Mode (<code class="docutils literal notranslate"><span class="pre">-gpu=mem:unified</span></code>), all data is accessible from the device making information about size and shape unnecessary.</p></li> </ul> <p>Take the following example in C:</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="cp">#pragma omp declare target</span> <span class="kt">void</span><span class="w"> </span><span class="nf">set</span><span class="p">(</span><span class="kt">int</span><span class="o">*</span><span class="w"> </span><span class="n">ptr</span><span class="p">,</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">i</span><span class="p">,</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">j</span><span class="p">,</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">dim</span><span class="p">){</span><span class="w"></span> <span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">idx</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">dim</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">j</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="n">ptr</span><span class="p">[</span><span class="n">idx</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">someval</span><span class="p">(</span><span class="n">i</span><span class="p">,</span><span class="w"> </span><span class="n">j</span><span class="p">);</span><span class="w"></span> <span class="p">}</span><span class="w"></span> <span class="cp">#pragma omp end declare target</span> <span class="kt">void</span><span class="w"> </span><span class="nf">fill2d</span><span class="p">(</span><span class="kt">int</span><span class="o">*</span><span class="w"> </span><span class="n">ptr</span><span class="p">,</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">dim</span><span class="p">){</span><span class="w"></span> <span class="cp">#pragma omp target teams distribute parallel for</span> <span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="kt">int</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="n">dim</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="o">++</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="kt">int</span><span class="w"> </span><span class="n">j</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="n">j</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="n">dim</span><span class="p">;</span><span class="w"> </span><span class="n">j</span><span class="o">++</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="n">set</span><span class="p">(</span><span class="n">ptr</span><span class="p">,</span><span class="w"> </span><span class="n">i</span><span class="p">,</span><span class="w"> </span><span class="n">j</span><span class="p">,</span><span class="w"> </span><span class="n">dim</span><span class="p">);</span><span class="w"></span> <span class="p">}</span><span class="w"></span> </pre></div> </div> <p>In Separate Memory Mode, the only way to guarantee correctness for this example is to specify an array section in the <code class="docutils literal notranslate"><span class="pre">target</span></code> construct as follows:</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="cp">#pragma omp target teams distribute parallel for map(from: ptr[0:dim*dim])</span> </pre></div> </div> <p>This change explicitly instructs the OpenMP implementation about the precise data segment used within the target for loop.</p> <p>In Unified Memory Mode, the <code class="docutils literal notranslate"><span class="pre">map</span></code> clause is not required.</p> <p>The next example, in Fortran, illustrates how a global variable can be accessed in an OpenMP routine without requiring any explicit annotation.</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="k">module</span><span class="w"> </span><span class="n">m</span><span class="w"></span> <span class="n">integer</span><span class="w"> </span><span class="o">::</span><span class="w"> </span><span class="n">globmin</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">1234</span><span class="w"></span> <span class="n">contains</span><span class="w"></span> <span class="n">subroutine</span><span class="w"> </span><span class="n">findmin</span><span class="p">(</span><span class="n">a</span><span class="p">)</span><span class="w"></span> <span class="o">!</span><span class="n">$omp</span><span class="w"> </span><span class="n">declare</span><span class="w"> </span><span class="n">target</span><span class="w"></span> <span class="w"> </span><span class="n">integer</span><span class="p">,</span><span class="w"> </span><span class="n">intent</span><span class="p">(</span><span class="n">in</span><span class="p">)</span><span class="w"> </span><span class="o">::</span><span class="w"> </span><span class="n">a</span><span class="p">(</span><span class="o">:</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="n">integer</span><span class="w"> </span><span class="o">::</span><span class="w"> </span><span class="n">i</span><span class="w"></span> <span class="w"> </span><span class="k">do</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="n">size</span><span class="p">(</span><span class="n">a</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">a</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="p">.</span><span class="n">lt</span><span class="p">.</span><span class="w"> </span><span class="n">globmin</span><span class="p">)</span><span class="w"> </span><span class="n">then</span><span class="w"></span> <span class="w"> </span><span class="n">globmin</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">a</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="n">endif</span><span class="w"></span> <span class="w"> </span><span class="n">end</span><span class="w"> </span><span class="k">do</span><span class="w"></span> <span class="n">end</span><span class="w"> </span><span class="n">subroutine</span><span class="w"></span> <span class="n">end</span><span class="w"> </span><span class="k">module</span><span class="w"> </span><span class="n">m</span><span class="w"></span> </pre></div> </div> <p>Compile the example above for Unified Memory Mode:</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="n">nvfortran</span><span class="w"> </span><span class="o">-</span><span class="n">mp</span><span class="o">=</span><span class="n">gpu</span><span class="w"> </span><span class="o">-</span><span class="n">gpu</span><span class="o">=</span><span class="n">mem</span><span class="o">:</span><span class="n">unified</span><span class="w"> </span><span class="n">example</span><span class="p">.</span><span class="n">f90</span><span class="w"></span> </pre></div> </div> <p>The source does not need any OpenMP directives to access module variable <code class="docutils literal notranslate"><span class="pre">globmin</span></code>, to either read or update its value, in the routine invoked from CPU and GPU. Moreover, any access to <code class="docutils literal notranslate"><span class="pre">globmin</span></code> will be made to the same exact instance of the variable from CPU and GPU; its value is synchronized automatically. In Separate or Managed Memory Modes, such behavior can only be achieved with a combination of OpenMP <code class="docutils literal notranslate"><span class="pre">declare</span> <span class="pre">target</span></code> and <code class="docutils literal notranslate"><span class="pre">target</span> <span class="pre">update</span></code> directives in the source code.</p> <p>Migrating existing OpenMP applications written for Separate Memory Mode should, in most cases, be a seamless process requiring no source changes. Some data access patterns, however, may lead to different results produced during application execution in Unified Memory Mode. Applications which rely on having separate data copies in GPU memory to conduct temporary computations on the GPU – without maintaining data synchronization with the CPU – pose a challenge for migration to unified memory. For the following Fortran example, the value of variable <code class="docutils literal notranslate"><span class="pre">c</span></code> after the last loop will differ depending on whether the example is compiled with or without <code class="docutils literal notranslate"><span class="pre">-gpu=mem:unified</span></code>.</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="n">b</span><span class="p">(</span><span class="o">:</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">...</span><span class="w"></span> <span class="n">c</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="w"></span> <span class="o">!</span><span class="n">$omp</span><span class="w"> </span><span class="n">target</span><span class="w"> </span><span class="n">data</span><span class="w"> </span><span class="n">map</span><span class="p">(</span><span class="n">to</span><span class="o">:</span><span class="w"> </span><span class="n">b</span><span class="p">)</span><span class="w"> </span><span class="n">map</span><span class="p">(</span><span class="n">from</span><span class="o">:</span><span class="w"> </span><span class="n">a</span><span class="p">)</span><span class="w"></span> <span class="o">!</span><span class="n">$omp</span><span class="w"> </span><span class="n">target</span><span class="w"> </span><span class="n">distribute</span><span class="w"> </span><span class="n">teams</span><span class="w"> </span><span class="n">parallel</span><span class="w"> </span><span class="k">for</span><span class="w"></span> <span class="k">do</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="n">N</span><span class="w"></span> <span class="w"> </span><span class="n">b</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">b</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">i</span><span class="w"></span> <span class="n">end</span><span class="w"> </span><span class="k">do</span><span class="w"></span> <span class="o">!</span><span class="n">$omp</span><span class="w"> </span><span class="n">target</span><span class="w"> </span><span class="n">distribute</span><span class="w"> </span><span class="n">teams</span><span class="w"> </span><span class="n">parallel</span><span class="w"> </span><span class="k">for</span><span class="w"></span> <span class="k">do</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="n">N</span><span class="w"></span> <span class="w"> </span><span class="n">a</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">b</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">i</span><span class="w"></span> <span class="n">end</span><span class="w"> </span><span class="k">do</span><span class="w"></span> <span class="o">!</span><span class="n">$omp</span><span class="w"> </span><span class="n">end</span><span class="w"> </span><span class="n">target</span><span class="w"> </span><span class="n">data</span><span class="w"></span> <span class="k">do</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="n">N</span><span class="w"></span> <span class="w"> </span><span class="n">c</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">c</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">a</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">b</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="w"></span> <span class="n">end</span><span class="w"> </span><span class="k">do</span><span class="w"></span> </pre></div> </div> <p>Without Unified Memory, array <code class="docutils literal notranslate"><span class="pre">b</span></code> is copied into the GPU memory at the beginning of the OpenMP <code class="docutils literal notranslate"><span class="pre">target</span> <span class="pre">data</span></code> region. It is then updated in the GPU memory and used to compute elements of array <code class="docutils literal notranslate"><span class="pre">a</span></code>. As instructed by the data clause <code class="docutils literal notranslate"><span class="pre">map(to:b)</span></code>, <code class="docutils literal notranslate"><span class="pre">b</span></code> is not copied back to the CPU memory at the end of the <code class="docutils literal notranslate"><span class="pre">target</span> <span class="pre">data</span></code> region and therefore its initial value is used in the computation of <code class="docutils literal notranslate"><span class="pre">c</span></code>. With <code class="docutils literal notranslate"><span class="pre">-mp=gpu</span> <span class="pre">-gpu=mem:unified</span></code>, the updated value of <code class="docutils literal notranslate"><span class="pre">b</span></code> in the first loop is automatically visible in the last loop leading to a different value of <code class="docutils literal notranslate"><span class="pre">c</span></code> at its end.</p> <p>Additional complications may arise from the asynchronous execution as the use of unified shared memory may require extra synchronizations to avoid data races.</p> </section> <section id="multiple-device-support"> <h2><span class="section-number">7.9. </span>Multiple Device Support<a class="headerlink" href="#multiple-device-support" title="Permalink to this headline"></a></h2> <p>A program can use multiple devices on a single node.</p> <p>This functionality is supported using the <code class="docutils literal notranslate"><span class="pre">omp_set_default_device</span></code> API call and the <code class="docutils literal notranslate"><span class="pre">device()</span></code> clause on the <code class="docutils literal notranslate"><span class="pre">target</span></code> constructs. Our experience is that most programs use MPI parallelism with each MPI rank selecting a single GPU to which to offload. Some programs assign multiple MPI ranks to each GPU, in order to keep the GPU fully occupied, though the fixed memory size of the GPU limits how effective this strategy can be. Similarly, other programs use OpenMP thread parallelism on the CPU, with each thread selecting a single GPU to which to offload.</p> <span class="target" id="openmp-interop-cuda"></span></section> <section id="interoperability-with-cuda"> <h2><span class="section-number">7.10. </span>Interoperability with CUDA<a class="headerlink" href="#interoperability-with-cuda" title="Permalink to this headline"></a></h2> <p>The HPC Compilers support interoperability of OpenMP and CUDA to the same extent they support CUDA interoperability with OpenACC.</p> <p>If OpenMP and CUDA code coexist in the same program, the OpenMP runtime and the CUDA runtime use the same CUDA context on each GPU. To enable this coexistence, use the compilation and linking option <code class="docutils literal notranslate"><span class="pre">-cuda</span></code>. CUDA-allocated data is available for use inside OpenMP target regions with the OpenMP analog <code class="docutils literal notranslate"><span class="pre">is_device_ptr</span></code> to OpenACC’s <code class="docutils literal notranslate"><span class="pre">deviceptr()</span></code> clause.</p> <p>OpenMP-allocated data is available for use inside CUDA kernels directly if the data was allocated with the <code class="docutils literal notranslate"><span class="pre">omp_target_alloc()</span></code> API call; if the OpenMP data was created with a <code class="docutils literal notranslate"><span class="pre">target</span> <span class="pre">data</span> <span class="pre">map</span></code> clause, it can be made available for use inside CUDA kernels using the <code class="docutils literal notranslate"><span class="pre">target</span> <span class="pre">data</span> <span class="pre">use_device_addr()</span></code> clause. Calling a CUDA device function inside an OpenMP target region is supported, as long as the CUDA function is a scalar function, that is, does not use CUDA shared memory or any inter-thread synchronization. Calling an OpenMP <code class="docutils literal notranslate"><span class="pre">declare</span> <span class="pre">target</span></code> function inside a CUDA kernel is supported as long as the <code class="docutils literal notranslate"><span class="pre">declare</span> <span class="pre">target</span></code> function has no OpenMP constructs or API calls.</p> </section> <section id="interoperability-with-other-openmp-compilers"> <h2><span class="section-number">7.11. </span>Interoperability with Other OpenMP Compilers<a class="headerlink" href="#interoperability-with-other-openmp-compilers" title="Permalink to this headline"></a></h2> <p>OpenMP CPU-parallel object files compiled with NVIDIA’s HPC compilers are interoperable with OpenMP CPU-parallel object files compiled by other compilers using the KMPC OpenMP runtime interface. Compilers supporting KMPC OpenMP include Intel and CLANG. The HPC compilers support a GNU OpenMP interface layer as well which provides OpenMP CPU-parallel interoperability with the GNU compilers.</p> <p>For OpenMP GPU computation, there is no similar formal or informal standard library interface for launching GPU compute constructs or managing GPU memory. There is also no standard way to manage the device context in such a way as to interoperate between multiple offload libraries. The HPC compilers therefore do not support interoperability of device compute offload operations and similar operations generated with another compiler.</p> </section> <section id="gnu-stl"> <h2><span class="section-number">7.12. </span>GNU STL<a class="headerlink" href="#gnu-stl" title="Permalink to this headline"></a></h2> <p>When using nvc++ on Linux, the GNU STL is thread-safe to the extent listed in the GNU documentation as required by the C++11 standard. If an STL thread-safe issue is suspected, the suspect code can be run sequentially inside of an OpenMP region using <code class="docutils literal notranslate"><span class="pre">#pragma</span> <span class="pre">omp</span> <span class="pre">critical</span></code> sections.</p> <span class="target" id="stdpar-use"></span></section> </section> <section id="using-stdpar"> <h1><span class="section-number">8. </span>Using Stdpar<a class="headerlink" href="#using-stdpar" title="Permalink to this headline"></a></h1> <p>This chapter describes the NVIDIA HPC Compiler support for standard language parallelism, also known as Stdpar:</p> <ul class="simple"> <li><p>ISO C++ standard library parallel algorithms with <code class="docutils literal notranslate"><span class="pre">nvc++</span></code></p></li> <li><p>ISO Fortran <code class="docutils literal notranslate"><span class="pre">do</span> <span class="pre">concurrent</span></code> loop construct with <code class="docutils literal notranslate"><span class="pre">nvfortran</span></code></p></li> </ul> <p>Use the <code class="docutils literal notranslate"><span class="pre">-stdpar</span></code> compiler option to enable parallel execution with standard parallelism. The sub-options to <code class="docutils literal notranslate"><span class="pre">-stdpar</span></code> are the following:</p> <ul class="simple"> <li><p><code class="docutils literal notranslate"><span class="pre">gpu</span></code>: compile for parallel execution on GPU; this sub-option is the default. This feature is supported on the NVIDIA Pascal architecture and newer.</p></li> <li><p><code class="docutils literal notranslate"><span class="pre">multicore</span></code>: compile for multicore CPU execution.</p></li> </ul> <p>By default, NVC++ auto-detects and generates GPU code for the type of GPU that is installed on the system on which the compiler is running. To generate code for a specific GPU architecture, which may be necessary when the application is compiled and run on different systems, add the <code class="docutils literal notranslate"><span class="pre">-gpu=ccXX</span></code> command-line option. More details can be found in <a class="reference internal" href="#compute-cap"><span class="std std-ref">Compute Capability</span></a>.</p> <p class="title sectiontitle rubric" id="predefined-macros-2">Predefined Macros</p> <p>The following macros corresponding to the parallel execution target compiled for are added implicitly:</p> <ul class="simple"> <li><p><code class="docutils literal notranslate"><span class="pre">__NVCOMPILER_STDPAR_GPU</span></code> for parallel execution on GPU.</p></li> <li><p><code class="docutils literal notranslate"><span class="pre">__NVCOMPILER_STDPAR_MULTICORE</span></code> for parallel execution on multicore CPU.</p></li> </ul> <section id="gpu-memory-modes"> <h2><span class="section-number">8.1. </span>GPU Memory Modes<a class="headerlink" href="#gpu-memory-modes" title="Permalink to this headline"></a></h2> <p>When compiling for GPU execution, Stdpar utilizes <a class="reference internal" href="#acc-mem-unified"><span class="std std-ref">Managed and Unified Memory Modes</span></a> for managing data accessed from the sequential code running on CPU and from the parallel code on GPU.</p> <p>The compiler detects the memory capability of the system on which the compiler is running and uses that information to enable the correct memory mode as follows:</p> <ul class="simple"> <li><p>When compiled on the platform with full CUDA Unified Memory capability, <code class="docutils literal notranslate"><span class="pre">-stdpar</span></code> implies <code class="docutils literal notranslate"><span class="pre">-gpu=mem:unified</span></code>.</p></li> <li><p>When compiled on the platform with CUDA Managed Memory capability only, <code class="docutils literal notranslate"><span class="pre">-stdpar</span></code> implies <code class="docutils literal notranslate"><span class="pre">-gpu=mem:managed</span></code>.</p></li> </ul> <p>To compile code for a specific Memory Mode regardless of the memory capability of the system on which you are compiling, add the desired <code class="docutils literal notranslate"><span class="pre">-gpu=mem:unified</span></code> or <code class="docutils literal notranslate"><span class="pre">-gpu=mem:managed</span></code> option.</p> <p>Stdpar with Separate Memory Mode can only be supported when the data are fully managed through features of other programming models e.g. OpenACC.</p> <p>All restrictions on variables used on the GPU in standard language parallel code in Managed Memory Mode have been removed when using Unified Memory Mode.</p> <p>If the compiler utilises CUDA Managed Memory automatically, the interception of deallocations is enabled implicitly at runtime. This is to prevent deallocating the data with unmatching API which may lead to undefined behavior. The interception incurs some runtime overhead and may be unnecessary if allocatations and deallocations for all data in the application are performed using the matching APIs. The interception can be disabled using dedicated command-line options detailed in <a class="reference internal" href="#gpu-mem-intercept"><span class="std std-ref">Interception of Deallocations</span></a>. More details about the memory modes supported by the NVIDIA HPC Compilers and dedicated command-line options can be found in <a class="reference internal" href="#acc-mem-model"><span class="std std-ref">Memory Model</span></a>.</p> <span class="target" id="stdpar-cpp"></span></section> <section id="stdpar-c"> <h2><span class="section-number">8.2. </span>Stdpar C++<a class="headerlink" href="#stdpar-c" title="Permalink to this headline"></a></h2> <p>The NVIDIA HPC C++ compiler, NVC++, supports C++ Standard Language Parallelism (Stdpar) for execution on NVIDIA GPUs and multicore CPUs. As mentioned previously, use the NVC++ command-line option <code class="docutils literal notranslate"><span class="pre">-stdpar</span></code> to enable GPU accelerated C++ Parallel Algorithms. The following sections go into more detail about the NVC++ support for the ISO C++ Standard Library Parallel Algorithms.</p> <section id="introduction-to-stdpar-c"> <h3><span class="section-number">8.2.1. </span>Introduction to Stdpar C++<a class="headerlink" href="#introduction-to-stdpar-c" title="Permalink to this headline"></a></h3> <p>The C++17 Standard introduced higher-level parallelism features that allow users to request parallelization of Standard Library algorithms.</p> <p>This higher-level parallelism is expressed by adding an execution policy as the first parameter to any algorithm that supports execution policies. Most of the existing Standard C++ algorithms were enhanced to support execution policies. C++17 defined several new parallel algorithms, including the useful <a class="reference external" href="https://en.cppreference.com/w/cpp/algorithm/reduce">std::reduce</a> and <a class="reference external" href="https://en.cppreference.com/w/cpp/algorithm/transform_reduce">std::transform_reduce</a>.</p> <p>C++17 defines three <a class="reference external" href="https://en.cppreference.com/w/cpp/algorithm/execution_policy_tag">execution policies</a>:</p> <ul class="simple"> <li><p><code class="docutils literal notranslate"><span class="pre">std::execution::seq:</span></code> Sequential execution. No parallelism is allowed.</p></li> <li><p><code class="docutils literal notranslate"><span class="pre">std::execution::par:</span></code> Parallel execution on one or more threads.</p></li> <li><p><code class="docutils literal notranslate"><span class="pre">std::execution::par_unseq:</span></code> Parallel execution on one or more threads, with each thread possibly vectorized.</p></li> </ul> <p>When you use an execution policy other than <code class="docutils literal notranslate"><span class="pre">std::execution::seq</span></code>, you are communicating two important things to the compiler:</p> <ul class="simple"> <li><p>You prefer but do not require that the algorithm be run in parallel. A conforming C++17 implementation may ignore the hint and run the algorithm sequentially, but a performance-oriented implementation takes the hint and executes in parallel when possible and prudent.</p></li> <li><p>The algorithm is safe to run in parallel. For the <code class="docutils literal notranslate"><span class="pre">std::execution::par</span></code> and <code class="docutils literal notranslate"><span class="pre">std::execution::par_unseq</span></code> policies, any user-provided code—such as iterators, lambdas, or function objects passed into the algorithm—must not introduce data races if run concurrently on separate threads. For the <code class="docutils literal notranslate"><span class="pre">std::execution::par_unseq</span></code> policy, any user-provided code must not introduce data races or deadlocks if multiple calls are interleaved on the same thread, which is what happens when a loop is vectorized. For more information about potential deadlocks, see the <a class="reference external" href="https://en.cppreference.com/w/cpp/language/memory_model#Progress_guarantee">forward progress guarantees</a> provided by the parallel policies or watch <a class="reference external" href="https://www.youtube.com/watch?v=FJIn1YhPJJc">CppCon 2018: Bryce Adelstein Lelbach “The C++ Execution Model”</a>.</p></li> </ul> <p>The C++ Standard grants compilers great freedom to choose if, when, and how to execute algorithms in parallel as long as the forward progress guarantees the user requests are honored. For example, <code class="docutils literal notranslate"><span class="pre">std::execution::par_unseq</span></code> may be implemented with vectorization and <code class="docutils literal notranslate"><span class="pre">std::execution::par</span></code> may be implemented with a CPU thread pool. It is also possible to execute parallel algorithms on a GPU, which is a good choice for invocations with sufficient parallelism to take advantage of the processing power and memory bandwidth of NVIDIA GPU processors.</p> </section> <section id="nvc-compiler-parallel-algorithms-support"> <h3><span class="section-number">8.2.2. </span>NVC++ Compiler Parallel Algorithms Support<a class="headerlink" href="#nvc-compiler-parallel-algorithms-support" title="Permalink to this headline"></a></h3> <p>NVC++ supports C++ Standard Language Parallelism with the parallel execution policies <code class="docutils literal notranslate"><span class="pre">std::execution::par</span></code> or <code class="docutils literal notranslate"><span class="pre">std::execution::par_unseq</span></code> for execution on GPUs or multicore CPUs.</p> <p>Lambdas, including generic lambdas, are fully supported in parallel algorithm invocations. No language extensions or non-standard libraries are required to enable GPU acceleration. All data movement between host memory and GPU device memory is performed implicitly and automatically under the control of <a class="reference internal" href="#acc-mem-unified"><span class="std std-ref">Managed and Unified Memory Modes</span></a>.</p> <p>It’s straightforward to automatically GPU accelerate C++ Parallel Algorithms with NVC++. However, there are some restrictions and limitations you need to be aware of as explained below.</p> <section id="enabling-parallel-algorithms-with-the-stdpar-option"> <h4><span class="section-number">8.2.2.1. </span>Enabling Parallel Algorithms with the -stdpar Option<a class="headerlink" href="#enabling-parallel-algorithms-with-the-stdpar-option" title="Permalink to this headline"></a></h4> <p>GPU acceleration of C⁠+⁠+ Parallel Algorithms is enabled with the <code class="docutils literal notranslate"><span class="pre">-⁠stdpar=gpu</span></code> command-line option to NVC++. If <code class="docutils literal notranslate"><span class="pre">-⁠stdpar=gpu</span></code> is specified (or <code class="docutils literal notranslate"><span class="pre">-⁠stdpar</span></code> without an argument), almost all algorithms that use a parallel execution policy are compiled for offloading to run in parallel on an NVIDIA GPU:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>nvc++ -stdpar=gpu program.cpp -o program </pre></div> </div> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>nvc++ -stdpar program.cpp -o program </pre></div> </div> <p>In addition, the GPU acceleration sub-option can be further specialized using <code class="docutils literal notranslate"><span class="pre">-⁠stdpar=gpu:acc</span></code>. This option directs the compiler to use its OpenACC implementation to GPU-accelerate a subset of algorithm with a parallel execution policy:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>nvc++ -stdpar=gpu:acc program.cpp -o program </pre></div> </div> <p>More details about the OpenACC support of Stdpar C++ is provided in <a class="reference external" href="index.html#stdpar-cpp-impl-openacc">OpenACC Implementation of Parallel Algorithms</a>.</p> <p>Acceleration of C⁠+⁠+ Parallel Algorithms with multicore CPUs is enabled with the <code class="docutils literal notranslate"><span class="pre">-⁠stdpar=multicore</span></code> command-line option to NVC⁠+⁠+. If <code class="docutils literal notranslate"><span class="pre">-⁠stdpar=multicore</span></code> specified, almost all algorithms that use a parallel execution policy are compiled to run on a multicore CPU:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>nvc++ -stdpar=multicore program.cpp -o program </pre></div> </div> <p>When either <code class="docutils literal notranslate"><span class="pre">-⁠stdpar=gpu,multicore</span></code> or <code class="docutils literal notranslate"><span class="pre">-⁠stdpar=gpu:acc,multicore</span></code> command-line options are specified to NVC++, the parallel algorithms code is compiled for both GPU and multicore CPU. When the execution platform has any GPU the binary executes on the GPU and otherwise on the multicore CPU.</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>nvc++ -stdpar=gpu,multicore program.cpp -o program </pre></div> </div> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>nvc++ -stdpar=gpu:acc,multicore program.cpp -o program </pre></div> </div> </section> </section> <section id="stdpar-c-simple-example"> <h3><span class="section-number">8.2.3. </span>Stdpar C++ Simple Example<a class="headerlink" href="#stdpar-c-simple-example" title="Permalink to this headline"></a></h3> <p>Here are a few simple examples to get a feel for how the C++ Parallel Algorithms work.</p> <p>From the early days of C++, sorting items stored in an appropriate container has been relatively easy using a single call like the following:</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="n">std</span><span class="o">::</span><span class="n">sort</span><span class="p">(</span><span class="n">employees</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span><span class="w"> </span><span class="n">employees</span><span class="p">.</span><span class="n">end</span><span class="p">(),</span><span class="w"></span> <span class="w"> </span><span class="n">CompareByLastName</span><span class="p">());</span><span class="w"></span> </pre></div> </div> <p>Assuming the comparison class <code class="docutils literal notranslate"><span class="pre">CompareByLastName</span></code> is thread-safe, which is true for most comparison functions, parallelizing this sort is simple with C++ Parallel Algorithms. Include <code class="docutils literal notranslate"><span class="pre">&lt;execution&gt;</span></code> and add an execution policy to the function call:</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="nl">std</span><span class="p">:</span><span class="n">sort</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">execution</span><span class="o">::</span><span class="n">par</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="n">employees</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span><span class="w"> </span><span class="n">employees</span><span class="p">.</span><span class="n">end</span><span class="p">(),</span><span class="w"></span> <span class="w"> </span><span class="n">CompareByLastName</span><span class="p">());</span><span class="w"></span> </pre></div> </div> <p>Calculating the sum of all the elements in a container is also simple with the <code class="docutils literal notranslate"><span class="pre">std::accumulate</span></code> algorithm. Prior to C++17, transforming the data in some way while taking the sum was somewhat awkward. For example, to compute the average age of your employees, you might write the following code:</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="kt">int</span><span class="w"> </span><span class="n">ave_age</span><span class="w"> </span><span class="o">=</span><span class="w"></span> <span class="w"> </span><span class="n">std</span><span class="o">::</span><span class="n">accumulate</span><span class="p">(</span><span class="n">employees</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span><span class="w"> </span><span class="n">employees</span><span class="p">.</span><span class="n">end</span><span class="p">(),</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="p">[](</span><span class="kt">int</span><span class="w"> </span><span class="n">sum</span><span class="p">,</span><span class="w"> </span><span class="k">const</span><span class="w"> </span><span class="n">Employee</span><span class="o">&amp;</span><span class="w"> </span><span class="n">emp</span><span class="p">){</span><span class="w"></span> <span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="n">sum</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">emp</span><span class="p">.</span><span class="n">age</span><span class="p">();</span><span class="w"></span> <span class="w"> </span><span class="p">})</span><span class="w"></span> <span class="w"> </span><span class="o">/</span><span class="w"> </span><span class="n">employees</span><span class="p">.</span><span class="n">size</span><span class="p">();</span><span class="w"></span> </pre></div> </div> <p>The <code class="docutils literal notranslate"><span class="pre">std::transform_reduce</span></code> algorithm introduced in C++17 makes it simple to parallelize this code. It also results in cleaner code by separating the reduction operation, in this case <code class="docutils literal notranslate"><span class="pre">std::plus</span></code>, from the transformation operation, in this case <code class="docutils literal notranslate"><span class="pre">emp.age():</span></code></p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="kt">int</span><span class="w"> </span><span class="n">ave_age</span><span class="w"> </span><span class="o">=</span><span class="w"></span> <span class="w"> </span><span class="n">std</span><span class="o">::</span><span class="n">transform_reduce</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">execution</span><span class="o">::</span><span class="n">par_unseq</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="n">employees</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span><span class="w"> </span><span class="n">employees</span><span class="p">.</span><span class="n">end</span><span class="p">(),</span><span class="w"></span> <span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="n">std</span><span class="o">::</span><span class="n">plus</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span><span class="p">(),</span><span class="w"></span> <span class="w"> </span><span class="p">[](</span><span class="k">const</span><span class="w"> </span><span class="n">Employee</span><span class="o">&amp;</span><span class="w"> </span><span class="n">emp</span><span class="p">){</span><span class="w"></span> <span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="n">emp</span><span class="p">.</span><span class="n">age</span><span class="p">();</span><span class="w"></span> <span class="w"> </span><span class="p">})</span><span class="w"></span> <span class="w"> </span><span class="o">/</span><span class="w"> </span><span class="n">employees</span><span class="p">.</span><span class="n">size</span><span class="p">();</span><span class="w"></span> </pre></div> </div> </section> <section id="openacc-implementation-of-parallel-algorithms"> <h3><span class="section-number">8.2.4. </span>OpenACC Implementation of Parallel Algorithms<a class="headerlink" href="#openacc-implementation-of-parallel-algorithms" title="Permalink to this headline"></a></h3> <p>NVC++ has an experimental GPU support for a subset of algorithms with parallel execution policies <code class="docutils literal notranslate"><span class="pre">std::par</span></code> and <code class="docutils literal notranslate"><span class="pre">std::par_unseq</span></code> accelerated through the OpenACC implementation. This feature, enabled with the <code class="docutils literal notranslate"><span class="pre">-stdpar=gpu:acc</span></code> option, may result in better application performance on the GPU and faster compilation speed.</p> <p>The following subset of algorithms have OpenACC implementation support:</p> <ul class="simple"> <li><p><code class="docutils literal notranslate"><span class="pre">std::for_each</span></code></p></li> <li><p><code class="docutils literal notranslate"><span class="pre">std::for_each_n</span></code></p></li> <li><p><code class="docutils literal notranslate"><span class="pre">std::transform</span></code></p></li> </ul> <p>The following algorithms have OpenACC implementation support for scalar data types and the standard <code class="docutils literal notranslate"><span class="pre">std::plus</span></code> reduction operation:</p> <ul class="simple"> <li><p><code class="docutils literal notranslate"><span class="pre">std::reduce</span></code></p></li> <li><p><code class="docutils literal notranslate"><span class="pre">std::transform_reduce</span></code></p></li> </ul> <p>The remainder of the parallel algorithms are parallelized using the default GPU implementation as if <code class="docutils literal notranslate"><span class="pre">-stdpar=gpu</span></code> was specified.</p> <p>When the code is compiled for GPU with the OpenACC acceleration <code class="docutils literal notranslate"><span class="pre">__NVCOMPILER_STDPAR_OPENACC_GPU</span></code> macro is defined implicitly.</p> </section> <section id="coding-guidelines-for-gpu-accelerating-parallel-algorithms"> <h3><span class="section-number">8.2.5. </span>Coding Guidelines for GPU-accelerating Parallel Algorithms<a class="headerlink" href="#coding-guidelines-for-gpu-accelerating-parallel-algorithms" title="Permalink to this headline"></a></h3> <p>GPUs are not simply CPUs with more threads. To effectively take advantage of the massive parallelism and memory bandwidth available on GPUs, it is typical for GPU programming models to put some limitations on code executed on the GPU. The NVC++ implementation of C++ Parallel Algorithms is no exception in this regard. The sections which follow detail the limitations that apply in the current release.</p> <section id="parallel-algorithms-and-device-function-annotations"> <h4><span class="section-number">8.2.5.1. </span>Parallel Algorithms and Device Function Annotations<a class="headerlink" href="#parallel-algorithms-and-device-function-annotations" title="Permalink to this headline"></a></h4> <p>Functions to be executed on the GPU within parallel algorithms do not need any <code class="docutils literal notranslate"><span class="pre">__device__</span></code> annotations or other special markings to be compiled for GPU execution. The NVC++ compiler walks the call graph for each source file and automatically infers which functions must be compiled for GPU execution.</p> <p>However, this only works when the compiler can see the function definition in the same source file where the function is called. This is true for most inline functions and template functions but may fail when functions are defined in a different source file or linked in from an external library. You need to be aware of this when formulating parallel algorithms invocations that you expect to be offloaded and accelerated on NVIDIA GPUs.</p> <p>When calling an externally defined function from within a parallel algorithm region, such functions require some form of device annotations from other GPU programming models e.g. OpenACC routine directive (refer to <a class="reference internal" href="#stdpar-cpp-interop-openacc-routine"><span class="std std-ref">External Device Function Annotations</span></a> for more information).</p> <span class="target" id="stdpar-cpp-unified-memory"></span></section> <section id="data-management-in-parallel-algorithms"> <h4><span class="section-number">8.2.5.2. </span>Data Management in Parallel Algorithms<a class="headerlink" href="#data-management-in-parallel-algorithms" title="Permalink to this headline"></a></h4> <p>When offloading parallel algorithms to a GPU, it’s essential to consider how data is accessed from the parallel region. Some GPUs may not access certain segments of the CPU’s address space. Developers targeting platforms without unified shared memory or those seeking to optimize performance must be aware of these memory distinctions, as they may affect the folowing types of data accessed in parallel algorithm regions:</p> <ul class="simple"> <li><p>Pointer data passed into lambda functions within the parallel algorithm.</p></li> <li><p>Data captured by reference in lambda functions or pointer data captured by value.</p></li> <li><p>Variables with static storage duration referenced inside the parallel algorithm.</p></li> </ul> <p>To avoid memory access violations, developers must ensure that all of the above data is accessible to the GPU before the parallel algorithm is executed.</p> <p>Stdpar C++ only supports <a class="reference internal" href="#acc-mem-unified"><span class="std std-ref">Managed and Unified Memory Modes</span></a> which allow data being accessed from CPU and GPU. Through support in both the CUDA device driver and the NVIDIA GPU hardware, the CUDA Unified Memory manager automatically moves some types of data based on usage.</p> <p>Stdpar with Separate Memory Mode can only be supported when the data are fully managed through the OpenACC data directives, refer to <a class="reference internal" href="#stdpar-cpp-interop-openacc"><span class="std std-ref">Interoperability with OpenACC</span></a>.</p> <p>Since object-oriented design is fundamental to C++, special consideration must be given to composite data types with pointer or reference members. The data referenced or pointed to may not be stored contiguously within the composite data type. Moreover, such data might not even be allocated in the same memory segment as the composite type itself. As a result, when accessing both the composite data type and its referenced or pointed-to data from parallel algorithms, the developer must ensure that the member data is also made accessible to the GPU. These considerations should also be taken into account when standard library containers are used in the parallel algorithms as the containers frequently contain member pointers to their elements.</p> <p>The discussion in this section assumes familiarity with the Managed and Unified Memory Modes covered in <a class="reference internal" href="#acc-mem-model"><span class="std std-ref">Memory Model</span></a> and <a class="reference internal" href="#acc-mem-unified"><span class="std std-ref">Managed and Unified Memory Modes</span></a>. The code executing within the parallel algorithm is referred to as the accelerator subprogram. In contrast to the code executing outside of the parallel algorithm which is referred to as the host subprogram.</p> <p><strong>Managed Memory Mode</strong></p> <p>When Stdpar code is compiled with Managed Memory Mode (as default mode or by passing <code class="docutils literal notranslate"><span class="pre">-gpu=mem:managed</span></code>) only data dynamically allocated on the heap in CPU code can be managed automatically. CPU and GPU automatic storage (stack memory) and static storage (global or static data) cannot be automatically managed. Likewise, data that is dynamically allocated in program units not compiled by <code class="docutils literal notranslate"><span class="pre">nvc++</span></code> with the <code class="docutils literal notranslate"><span class="pre">-stdpar</span></code> option is not automatically managed by CUDA Unified Memory even though it is on the CPU heap. The compiler utilizes CUDA Managed Memory for dynamic allocations to make data accessible from CPU and GPU. As managed memory allocation calls can incur higher runtime overhead than standard allocator calls, the implementation uses memory pools for performance reasons by default as detailed in <cite>Memory Pool Allocator &lt;gpu-mem-poolallocator&gt;</cite>.</p> <p>The Managed Memory Mode is intended for binaries run on targets with CUDA Managed Memory capability only. Any pointer that is dereferenced and any C++ object that is referenced within a parallel algorithm invocation must refer to data on the CPU heap that is allocated in a program unit compiled by <code class="docutils literal notranslate"><span class="pre">nvc++</span></code> with <code class="docutils literal notranslate"><span class="pre">-stdpar</span></code>. Dereferencing a pointer to a CPU stack or a global object will result in a memory violation in GPU code.</p> <p><strong>Unified Memory Mode</strong></p> <p>When Unified Memory is the default memory mode or is selected explicitly on the command line by passing <code class="docutils literal notranslate"><span class="pre">-gpu=mem:unified</span></code>, there are no restrictions on variables accessed in the parallel algorithms. Therefore, all CPU data (either residing on stack, heap, or globally) are simply accessible in the parallel algorithm functions. Note that memory dynamically allocated in GPU code is only visible from GPU code and can never be accessed by the CPU regardless of the CUDA Unified Memory capability.</p> <p>When compiling a binary for platforms with full CUDA Unified Memory capability, only those source files using features from the standard parallel algorithms library must be compiled by <code class="docutils literal notranslate"><span class="pre">nvc++</span></code> with the <code class="docutils literal notranslate"><span class="pre">-stdpar</span></code> option. There is no requirement that the code dynamically allocating memory accessed on GPU is also compiled in such a way.</p> <p>Unified Memory Mode may utilize CUDA Managed Memory for dynamic allocation, more details can be found in <a class="reference internal" href="#acc-mem-unified"><span class="std std-ref">Managed and Unified Memory Modes</span></a>.</p> <p><strong>Summary</strong></p> <p>The following table provides a key summary of important command-line options selecting memory modes and the impact of memory modes on the Stdpar features.</p> <table class="table-no-stripes docutils align-default" id="id31"> <caption><span class="caption-text">Table 21. Stdpar C++ Feature Differences for Memory Modes</span><a class="headerlink" href="#id31" title="Permalink to this table"></a></caption> <colgroup> <col style="width: 25%" /> <col style="width: 22%" /> <col style="width: 25%" /> <col style="width: 28%" /> </colgroup> <tbody> <tr class="row-odd"><td><p><strong>Command-line options</strong></p></td> <td><p><strong>Dynamically allocated variables</strong> <strong>outside of parallel algorithm region</strong></p></td> <td><p><strong>Automatic or static storage variables</strong> <strong>outside of parallel algorithm region</strong></p></td> <td><p><strong>Dynamic allocator</strong></p></td> </tr> <tr class="row-even"><td><p>No memory-specific flags passed, compiling on target with CUDA Managed Memory only</p></td> <td><p>Can be accessed within parallel region code</p></td> <td><p>Cannot be accessed within parallel algorithm code</p></td> <td><p>cudaMallocManaged</p></td> </tr> <tr class="row-odd"><td><p>No memory-specific flags passed, compiling on target with full CUDA Unified Memory</p></td> <td><p>Can be accessed within parallel region code</p></td> <td><p>Can be accessed within parallel algorithm code</p></td> <td><p>cudaMallocManaged or system allocators: new/malloc (compiler picks the most suitable allocator)</p></td> </tr> <tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">-gpu=mem:managed</span></code></p></td> <td><p>Can be accessed within parallel region code</p></td> <td><p>Cannot be accessed within parallel algorithm code</p></td> <td><p>cudaMallocManaged</p></td> </tr> <tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">-gpu=mem:unified</span></code></p></td> <td><p>Can be accessed within parallel region code</p></td> <td><p>Can be accessed within parallel algorithm code</p></td> <td><p>cudaMallocManaged or system allocators: new/malloc (compiler picks the most suitable allocator)</p></td> </tr> <tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">-gpu=mem:unified:managedalloc</span></code></p></td> <td><p>Can be accessed within parallel region code</p></td> <td><p>Can be accessed within parallel algorithm code</p></td> <td><p>cudaMallocManaged</p></td> </tr> <tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">-gpu=mem:unified:nomanagedalloc</span></code></p></td> <td><p>Can be accessed within parallel region code</p></td> <td><p>Can be accessed within parallel algorithm code</p></td> <td><p>System allocators: new/malloc</p></td> </tr> </tbody> </table> <p><strong>Examples</strong></p> <p>For example, <code class="docutils literal notranslate"><span class="pre">std::vector</span></code> uses dynamically allocated memory, which is accessible from the GPU when using Stdpar. Iterating over the contents of a <code class="docutils literal notranslate"><span class="pre">std::vector</span></code> in a parallel algorithm works as expected when compiling with either <code class="docutils literal notranslate"><span class="pre">-gpu=mem:managed</span></code> or <code class="docutils literal notranslate"><span class="pre">-gpu=mem:unified</span></code>:</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span><span class="w"> </span><span class="n">v</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">...;</span><span class="w"></span> <span class="n">std</span><span class="o">::</span><span class="n">sort</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">execution</span><span class="o">::</span><span class="n">par</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="n">v</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span><span class="w"> </span><span class="n">v</span><span class="p">.</span><span class="n">end</span><span class="p">());</span><span class="w"> </span><span class="c1">// Okay, accesses heap memory.</span> </pre></div> </div> <p>On the other hand, <code class="docutils literal notranslate"><span class="pre">std::array</span></code> performs no dynamic allocations. Its contents are stored within the <code class="docutils literal notranslate"><span class="pre">std::array</span></code> object itself, which is often on a CPU stack. Iterating over the contents of a <code class="docutils literal notranslate"><span class="pre">std::array</span></code> will not work on systems with only CUDA Managed Memory support unless the <code class="docutils literal notranslate"><span class="pre">std::array</span></code> itself is allocated on the heap and the code is compiled with <code class="docutils literal notranslate"><span class="pre">-gpu=mem:managed</span></code>:</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="n">std</span><span class="o">::</span><span class="n">array</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span><span class="w"> </span><span class="mi">1024</span><span class="o">&gt;</span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">...;</span><span class="w"></span> <span class="n">std</span><span class="o">::</span><span class="n">sort</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">execution</span><span class="o">::</span><span class="n">par</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="n">a</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span><span class="w"> </span><span class="n">a</span><span class="p">.</span><span class="n">end</span><span class="p">());</span><span class="w"> </span><span class="c1">// Fails on targets with CUDA Managed</span> <span class="w"> </span><span class="c1">// Memory capability only, array is on</span> <span class="w"> </span><span class="c1">// a CPU stack inaccessible from GPU.</span> <span class="w"> </span><span class="c1">// Works correctly on targets whith full</span> <span class="w"> </span><span class="c1">// CUDA Unified Memory support.</span> </pre></div> </div> <p>The above example works as expected when run on a target supporting full CUDA Unified Memory capability.</p> <p>When executing on targets with CUDA Managed Memory capability only, pay particular attention to lambda captures, especially capturing data objects by reference, which may contain non-obvious pointer dereferences:</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="kt">void</span><span class="w"> </span><span class="nf">saxpy</span><span class="p">(</span><span class="kt">float</span><span class="o">*</span><span class="w"> </span><span class="n">x</span><span class="p">,</span><span class="w"> </span><span class="kt">float</span><span class="o">*</span><span class="w"> </span><span class="n">y</span><span class="p">,</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">N</span><span class="p">,</span><span class="w"> </span><span class="kt">float</span><span class="w"> </span><span class="n">a</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="n">std</span><span class="o">::</span><span class="n">transform</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">execution</span><span class="o">::</span><span class="n">par_unseq</span><span class="p">,</span><span class="w"> </span><span class="n">x</span><span class="p">,</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">N</span><span class="p">,</span><span class="w"> </span><span class="n">y</span><span class="p">,</span><span class="w"> </span><span class="n">y</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="p">[</span><span class="o">&amp;</span><span class="p">](</span><span class="kt">float</span><span class="w"> </span><span class="n">xi</span><span class="p">,</span><span class="w"> </span><span class="kt">float</span><span class="w"> </span><span class="n">yi</span><span class="p">){</span><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">xi</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">yi</span><span class="p">;</span><span class="w"> </span><span class="p">});</span><span class="w"></span> <span class="p">}</span><span class="w"></span> </pre></div> </div> <p>In the earlier example, the containing function parameter <code class="docutils literal notranslate"><span class="pre">a</span></code> is captured by reference. The code within the body of the lambda, which is running on the GPU, tries to access <code class="docutils literal notranslate"><span class="pre">a</span></code>, which is in the CPU stack memory. This attempt results in a memory violation and undefined behavior. In this case, the problem can easily be fixed by changing the lambda to capture by value:</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="kt">void</span><span class="w"> </span><span class="nf">saxpy</span><span class="p">(</span><span class="kt">float</span><span class="o">*</span><span class="w"> </span><span class="n">x</span><span class="p">,</span><span class="w"> </span><span class="kt">float</span><span class="o">*</span><span class="w"> </span><span class="n">y</span><span class="p">,</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">N</span><span class="p">,</span><span class="w"> </span><span class="kt">float</span><span class="w"> </span><span class="n">a</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="n">std</span><span class="o">::</span><span class="n">transform</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">execution</span><span class="o">::</span><span class="n">par_unseq</span><span class="p">,</span><span class="w"> </span><span class="n">x</span><span class="p">,</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">N</span><span class="p">,</span><span class="w"> </span><span class="n">y</span><span class="p">,</span><span class="w"> </span><span class="n">y</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="p">[</span><span class="o">=</span><span class="p">](</span><span class="kt">float</span><span class="w"> </span><span class="n">xi</span><span class="p">,</span><span class="w"> </span><span class="kt">float</span><span class="w"> </span><span class="n">yi</span><span class="p">){</span><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">xi</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">yi</span><span class="p">;</span><span class="w"> </span><span class="p">});</span><span class="w"></span> <span class="p">}</span><span class="w"></span> </pre></div> </div> <p>With this one-character change, the lambda makes a copy of <code class="docutils literal notranslate"><span class="pre">a</span></code>, which is then copied to the GPU, and there are no attempts to reference CPU stack memory from GPU code. Such code will run correctly without requiring modifications on targets with full CUDA Unified Memory capability.</p> <p>If <code class="docutils literal notranslate"><span class="pre">std::vector</span></code> is accessed through a subscript operator from the device this would require such a vector object to be accessible from the parallel code executing on the GPU. This means that the <code class="docutils literal notranslate"><span class="pre">std::vector</span></code> needs to be allocated dynamically in order to make it accessible from the GPU when compiled for the systems with only CUDA Managed Memory support.</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span><span class="w"> </span><span class="n">v</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">...;</span><span class="w"></span> <span class="n">std</span><span class="o">::</span><span class="n">for_each</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">execution</span><span class="o">::</span><span class="n">par</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="n">idx</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span><span class="w"> </span><span class="n">idx</span><span class="p">.</span><span class="n">end</span><span class="p">(),</span><span class="w"> </span><span class="p">[</span><span class="o">&amp;</span><span class="p">](</span><span class="k">auto</span><span class="w"> </span><span class="n">i</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="p">{</span><span class="n">v</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">1</span><span class="p">;});</span><span class="w"> </span><span class="c1">// Fails on targets with CUDA Managed</span> <span class="w"> </span><span class="c1">// Memory capability only, vector object is on</span> <span class="w"> </span><span class="c1">// a CPU stack inaccessible from GPU.</span> <span class="w"> </span><span class="c1">// Works correctly on targets with full</span> <span class="w"> </span><span class="c1">// CUDA Unified Memory support.</span> </pre></div> </div> <p>An alternative approach to managing the content of the <code class="docutils literal notranslate"><span class="pre">std::vector</span></code> on systems with CUDA Managed Memory support only would be to obtain a pointer to its elements data region using <code class="docutils literal notranslate"><span class="pre">data()</span></code> member.</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span><span class="w"> </span><span class="n">v</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">...;</span><span class="w"></span> <span class="kt">int</span><span class="o">*</span><span class="w"> </span><span class="n">vdataptr</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">v</span><span class="p">.</span><span class="n">data</span><span class="p">();</span><span class="w"></span> <span class="n">std</span><span class="o">::</span><span class="n">for_each</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">execution</span><span class="o">::</span><span class="n">par</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="n">idx</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span><span class="w"> </span><span class="n">idx</span><span class="p">.</span><span class="n">end</span><span class="p">(),</span><span class="w"> </span><span class="p">[</span><span class="o">&amp;</span><span class="p">](</span><span class="k">auto</span><span class="w"> </span><span class="n">i</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="p">{</span><span class="n">vdataptr</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">1</span><span class="p">;});</span><span class="w"> </span><span class="c1">// Works, vector elements are in heap</span> <span class="w"> </span><span class="c1">// memory</span> </pre></div> </div> <p>Whether <code class="docutils literal notranslate"><span class="pre">-gpu=mem:unified</span></code> is enabled by default or passed explicitly on the command line, parallel algorithms can access global variables and accesses to global variables from CPU and GPU are kept in sync. Extra care should be taken when accessing global variables within parallel algorithms, as simultaneous updates in different iterations running on the GPU can lead to data races. The following example illustrates the safe update of a global variable in the parallel algorithm since the update only occurs in one iteration.</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="kt">int</span><span class="w"> </span><span class="n">globvar</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">123</span><span class="p">;</span><span class="w"></span> <span class="kt">void</span><span class="w"> </span><span class="nf">foo</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="k">auto</span><span class="w"> </span><span class="n">r</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">std</span><span class="o">::</span><span class="n">views</span><span class="o">::</span><span class="n">iota</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="n">N</span><span class="p">);</span><span class="w"></span> <span class="w"> </span><span class="n">std</span><span class="o">::</span><span class="n">for_each</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">execution</span><span class="o">::</span><span class="n">par_unseq</span><span class="p">,</span><span class="w"> </span><span class="n">r</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span><span class="w"> </span><span class="n">r</span><span class="p">.</span><span class="n">end</span><span class="p">(),</span><span class="w"></span> <span class="w"> </span><span class="p">[](</span><span class="k">auto</span><span class="w"> </span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">i</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="n">N</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="mi">1</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="n">globvar</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="mi">345</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="p">});</span><span class="w"></span> <span class="w"> </span><span class="c1">// globvar is equal to 468.</span> <span class="p">}</span><span class="w"></span> </pre></div> </div> </section> <section id="parallel-algorithms-and-function-pointers"> <h4><span class="section-number">8.2.5.3. </span>Parallel Algorithms and Function Pointers<a class="headerlink" href="#parallel-algorithms-and-function-pointers" title="Permalink to this headline"></a></h4> <p>Functions compiled to run on either the CPU or the GPU must be compiled into two different versions, one with the CPU machine instructions and one with the GPU machine instructions.</p> <p>In the current implementation, a function pointer either points to the CPU or the GPU version of the functions. This causes problems if you attempt to pass function pointers between CPU and GPU code. You might inadvertently pass a pointer to the CPU version of the function to GPU code. In the future, it may be possible to automatically and seamlessly support the use of function pointers across CPU and GPU code boundaries, but it is not supported in the current implementation.</p> <p>Function pointers can’t be passed to Parallel Algorithms to be run on the GPU, and functions may not be called through a function pointer within GPU code. For example, the following code example won’t work correctly:</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="kt">void</span><span class="w"> </span><span class="nf">square</span><span class="p">(</span><span class="kt">int</span><span class="o">&amp;</span><span class="w"> </span><span class="n">x</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">x</span><span class="p">;</span><span class="w"> </span><span class="p">}</span><span class="w"></span> <span class="kt">void</span><span class="w"> </span><span class="nf">square_all</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;&amp;</span><span class="w"> </span><span class="n">v</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="n">std</span><span class="o">::</span><span class="n">for_each</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">execution</span><span class="o">::</span><span class="n">par_unseq</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="n">v</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span><span class="w"> </span><span class="n">v</span><span class="p">.</span><span class="n">end</span><span class="p">(),</span><span class="w"> </span><span class="o">&amp;</span><span class="n">square</span><span class="p">);</span><span class="w"></span> <span class="p">}</span><span class="w"></span> </pre></div> </div> <p>It passes a pointer to the CPU version of the function square to a parallel <code class="docutils literal notranslate"><span class="pre">for_each</span></code> algorithm invocation. When the algorithm is parallelized and offloaded to the GPU, the program fails to resolve the function pointer to the GPU version of <code class="docutils literal notranslate"><span class="pre">square</span></code>.</p> <p>You can often solve this issue by using a function object, which is an object with a function call operator. The function object’s call operator is resolved at compile time to the GPU version of the function, instead of being resolved at run time to the incorrect CPU version of the function as in the previous example. For example, the following code example works:</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="k">struct</span><span class="w"> </span><span class="nc">squared</span><span class="w"> </span><span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="nf">operator</span><span class="p">()(</span><span class="kt">int</span><span class="o">&amp;</span><span class="w"> </span><span class="n">x</span><span class="p">)</span><span class="w"> </span><span class="k">const</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">x</span><span class="p">;</span><span class="w"> </span><span class="p">}</span><span class="w"></span> <span class="p">};</span><span class="w"></span> <span class="kt">void</span><span class="w"> </span><span class="nf">square_all</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;&amp;</span><span class="w"> </span><span class="n">v</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="n">std</span><span class="o">::</span><span class="n">for_each</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">execution</span><span class="o">::</span><span class="n">par_unseq</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="n">v</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span><span class="w"> </span><span class="n">v</span><span class="p">.</span><span class="n">end</span><span class="p">(),</span><span class="w"> </span><span class="n">squared</span><span class="p">{});</span><span class="w"></span> <span class="p">}</span><span class="w"></span> </pre></div> </div> <p>Another possible workaround is to change the function to a lambda, because a lambda is implemented as a nameless function object:</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="kt">void</span><span class="w"> </span><span class="nf">square_all</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;&amp;</span><span class="w"> </span><span class="n">v</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="n">std</span><span class="o">::</span><span class="n">for_each</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">execution</span><span class="o">::</span><span class="n">par_unseq</span><span class="p">,</span><span class="w"> </span><span class="n">v</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span><span class="w"> </span><span class="n">v</span><span class="p">.</span><span class="n">end</span><span class="p">(),</span><span class="w"></span> <span class="w"> </span><span class="p">[](</span><span class="kt">int</span><span class="o">&amp;</span><span class="w"> </span><span class="n">x</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">x</span><span class="p">;</span><span class="w"> </span><span class="p">});</span><span class="w"></span> <span class="p">}</span><span class="w"></span> </pre></div> </div> <p>If the function in question is too big to be converted to a function object or a lambda, then it should be possible to wrap the call to the function in a lambda:</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="kt">void</span><span class="w"> </span><span class="nf">compute</span><span class="p">(</span><span class="kt">int</span><span class="o">&amp;</span><span class="w"> </span><span class="n">x</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="c1">// Assume lots and lots of code here.</span> <span class="p">}</span><span class="w"></span> <span class="kt">void</span><span class="w"> </span><span class="nf">compute_all</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;&amp;</span><span class="w"> </span><span class="n">v</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="n">std</span><span class="o">::</span><span class="n">for_each</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">execution</span><span class="o">::</span><span class="n">par_unseq</span><span class="p">,</span><span class="w"> </span><span class="n">v</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span><span class="w"> </span><span class="n">v</span><span class="p">.</span><span class="n">end</span><span class="p">(),</span><span class="w"></span> <span class="w"> </span><span class="p">[](</span><span class="kt">int</span><span class="o">&amp;</span><span class="w"> </span><span class="n">x</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">compute</span><span class="p">(</span><span class="n">x</span><span class="p">);</span><span class="w"> </span><span class="p">});</span><span class="w"></span> <span class="p">}</span><span class="w"></span> </pre></div> </div> <p>No function pointers are used in this example.</p> <p>The restriction on calling a function through a function pointer unfortunately means passing polymorphic objects from CPU code to GPU-accelerated Parallel Algorithms is not currently supported, as virtual tables are implemented using function pointers.</p> </section> <section id="random-access-iterators"> <h4><span class="section-number">8.2.5.4. </span>Random Access Iterators<a class="headerlink" href="#random-access-iterators" title="Permalink to this headline"></a></h4> <p>The C++ Standard requires that the iterators passed to most C++ Parallel Algorithms be forward iterators. However, C++ Parallel Algorithms on GPUs only works with random access iterators. Passing a forward iterator or a bidirectional iterator to a GPU/CPU-accelerated Parallel Algorithm results in a compilation error. Passing raw pointers or Standard Library random access iterators to the algorithms has the best performance, but most other random-access iterators work correctly.</p> </section> <section id="interoperability-with-the-c-standard-library"> <h4><span class="section-number">8.2.5.5. </span>Interoperability with the C++ Standard Library<a class="headerlink" href="#interoperability-with-the-c-standard-library" title="Permalink to this headline"></a></h4> <p>Large parts of the C++ Standard Library can be used with stdpar on GPUs.</p> <ul class="simple"> <li><p><code class="docutils literal notranslate"><span class="pre">std::atomic&lt;T&gt;</span></code> objects within GPU code work provided that <code class="docutils literal notranslate"><span class="pre">T</span></code> is a four-byte or eight-byte integer type.</p></li> <li><p>Math functions that operate on floating-point types—such as <code class="docutils literal notranslate"><span class="pre">sin</span></code>, <code class="docutils literal notranslate"><span class="pre">cos</span></code>, <code class="docutils literal notranslate"><span class="pre">log</span></code>, and most of the other functions declared in <code class="docutils literal notranslate"><span class="pre">&lt;cmath&gt;</span></code> —can be used in GPU code and resolve to the same implementations that are used in CUDA C++ programs.</p></li> <li><p><code class="docutils literal notranslate"><span class="pre">std::complex</span></code>, <code class="docutils literal notranslate"><span class="pre">std::tuple</span></code>, <code class="docutils literal notranslate"><span class="pre">std::pair</span></code>, <code class="docutils literal notranslate"><span class="pre">std::optional</span></code>, <code class="docutils literal notranslate"><span class="pre">std::variant</span></code>, and <code class="docutils literal notranslate"><span class="pre">&lt;type_traits&gt;</span></code>, are supported and work as expected in GPU code.</p></li> </ul> <p>The parts of the C++ Standard Library that aren’t supported in GPU code include I/O functions and in general any function that accesses the CPU operating system. As a special case, basic <code class="docutils literal notranslate"><span class="pre">printf</span></code> calls can be used within GPU code and leverage the same implementation that is used in NVIDIA CUDA C++.</p> </section> <section id="no-exceptions-in-gpu-code"> <h4><span class="section-number">8.2.5.6. </span>No Exceptions in GPU Code<a class="headerlink" href="#no-exceptions-in-gpu-code" title="Permalink to this headline"></a></h4> <p>As with most other GPU programming models, throwing and catching C++ exceptions is not supported within Parallel Algorithm invocations that are offloaded to the GPU.</p> <p>Unlike some other GPU programming models where try/catch blocks and throw expressions are compilation errors, exception code does compile but with non-standard behavior. Catch clauses are ignored, and throw expressions abort the GPU kernel if actually executed. Exceptions in CPU code work without restrictions.</p> </section> </section> <section id="nvc-experimental-features"> <h3><span class="section-number">8.2.6. </span>NVC++ Experimental Features<a class="headerlink" href="#nvc-experimental-features" title="Permalink to this headline"></a></h3> <p>nvc++ experimental features are enabled with the –experimental–stdpar compiler flag. Experimental feature headers are exposed via the <code class="docutils literal notranslate"><span class="pre">&lt;experimental/...&gt;</span></code> namespaces and limited support for these features is available in older C++ versions. Table 1 lists all experimental features available and the minimum language version required to use them.</p> <table class="table-no-stripes docutils align-default" id="id32"> <caption><span class="caption-text">Table 22. Experimental features information</span><a class="headerlink" href="#id32" title="Permalink to this table"></a></caption> <colgroup> <col style="width: 31%" /> <col style="width: 9%" /> <col style="width: 11%" /> <col style="width: 24%" /> <col style="width: 25%" /> </colgroup> <thead> <tr class="row-odd"><th class="head"><p>Feature</p></th> <th class="head"><p>Recommended</p></th> <th class="head"><p>Limited support</p></th> <th class="head"><p>Standard proposal</p></th> <th class="head"><p>Other notes</p></th> </tr> </thead> <tbody> <tr class="row-even"><td><p>Multi-dimensional spans (mdspan)</p></td> <td><p>C++23</p></td> <td><p>C++17</p></td> <td><p><a class="reference external" href="http://wg21.link/p0009">P0009</a></p></td> <td><p><a class="reference external" href="https://github.com/NVIDIA/libcudacxx">https://github.com/NVIDIA/libcudacxx</a></p></td> </tr> <tr class="row-odd"><td><p>Slices of multi-dimensional spans (submdspan)</p></td> <td><p>C++23</p></td> <td><p>C++17</p></td> <td><p><a class="reference external" href="http://wg21.link/p2630">P2630</a></p></td> <td><p><a class="reference external" href="https://github.com/NVIDIA/libcudacxx">https://github.com/NVIDIA/libcudacxx</a></p></td> </tr> <tr class="row-even"><td><p>Multi-dimensional arrays (mdarray)</p></td> <td><p>C++23</p></td> <td><p>C++17</p></td> <td><p><a class="reference external" href="http://wg21.link/p1684">P1684</a></p></td> <td><p><a class="reference external" href="https://github.com/kokkos/mdspan">https://github.com/kokkos/mdspan</a></p></td> </tr> <tr class="row-odd"><td><p>Senders and receivers</p></td> <td><p>C++23</p></td> <td><p>C++20</p></td> <td><p><a class="reference external" href="http://wg21.link/p2300">P2300</a></p></td> <td><p><a class="reference external" href="https://github.com/NVIDIA/stdexec">https://github.com/NVIDIA/stdexec</a></p></td> </tr> <tr class="row-even"><td><p>Linear algebra</p></td> <td><p>C++23</p></td> <td><p>C++17</p></td> <td><p><a class="reference external" href="http://wg21.link/p1673">P1673</a></p></td> <td><p><a class="reference external" href="https://github.com/kokkos/stdblas">https://github.com/kokkos/stdblas</a></p></td> </tr> </tbody> </table> <section id="multi-dimensional-spans"> <h4><span class="section-number">8.2.6.1. </span>Multi-dimensional Spans<a class="headerlink" href="#multi-dimensional-spans" title="Permalink to this headline"></a></h4> <p>Multi-dimensional spans (<code class="docutils literal notranslate"><span class="pre">std::mdspan</span></code>) enable customizable multi-dimensional access to data. This feature was added to C++23 (see <a class="reference external" href="http://wg21.link/p0009">P0009</a> and follow-on papers). <a class="reference external" href="https://github.com/kokkos/mdspan/wiki/A-Gentle-Introduction-to-mdspan">A Gentle Introduction to mdspan</a> gives a tutorial. The reference mdspan implementation <a class="reference external" href="https://github.com/kokkos/mdspan">https://github.com/kokkos/mdspan</a> also has many useful examples.</p> <p>nvc++ provides an implementation available in the <code class="docutils literal notranslate"><span class="pre">&lt;experimental/mdspan&gt;</span></code> namespace that works with C++17 or newer. It enables applications that are not targeting the C++23 version of the standard to use mdspan.</p> <p>nvc++ also provides the <a class="reference external" href="http://wg21.link/p0009r17">P0009R17</a> version of submdspan, which only works for the mdspan layouts in C++23; that is, it does not implement C++26 submdspan (<a class="reference external" href="http://wg21.link/p2630">P2630</a>) yet.</p> <p>C++23’s mdspan uses <code class="docutils literal notranslate"><span class="pre">operator[]</span></code> for array access. For example, if <code class="docutils literal notranslate"><span class="pre">A</span></code> is a rank-2 mdspan, and <code class="docutils literal notranslate"><span class="pre">i</span></code> and <code class="docutils literal notranslate"><span class="pre">j</span></code> are integers, then <code class="docutils literal notranslate"><span class="pre">A[i,</span> <span class="pre">j]</span></code> accesses the element of <code class="docutils literal notranslate"><span class="pre">A</span></code> at row <code class="docutils literal notranslate"><span class="pre">i</span></code> and column <code class="docutils literal notranslate"><span class="pre">j</span></code>. Before C++23, <code class="docutils literal notranslate"><span class="pre">operator[]</span></code> was only allowed to take one argument. C++23 changed the language to permit any number of arguments (zero or more). nvc++ does not support this new language feature. As a result, the implementation of mdspan provided by nvc++ permits use of <code class="docutils literal notranslate"><span class="pre">operator()</span></code> as a fall-back (e.g., <code class="docutils literal notranslate"><span class="pre">A(i,</span> <span class="pre">j)</span></code> instead of <code class="docutils literal notranslate"><span class="pre">A[i,</span> <span class="pre">j]</span></code>). Users may enable this fall-back manually, by defining the macro <code class="docutils literal notranslate"><span class="pre">MDSPAN_USE_PAREN_OPERATOR</span></code> to <code class="docutils literal notranslate"><span class="pre">1</span></code> before including any mdspan headers.</p> <p>The following example (<a class="reference external" href="https://godbolt.org/z/6eG93o7YW">godbolt</a>):</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="cp">#include</span><span class="w"> </span><span class="cpf">&lt;experimental/mdspan&gt;</span><span class="cp"></span> <span class="cp">#include</span><span class="w"> </span><span class="cpf">&lt;iostream&gt;</span><span class="cp"></span> <span class="k">namespace</span><span class="w"> </span><span class="nn">stdex</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nn">std</span><span class="o">::</span><span class="nn">experimental</span><span class="p">;</span><span class="w"></span> <span class="kt">int</span><span class="w"> </span><span class="nf">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="n">std</span><span class="o">::</span><span class="n">array</span><span class="w"> </span><span class="n">d</span><span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="mi">5</span><span class="p">,</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="mi">3</span><span class="p">,</span><span class="w"> </span><span class="mi">8</span><span class="p">,</span><span class="w"> </span><span class="mi">4</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="mi">2</span><span class="p">,</span><span class="w"> </span><span class="mi">7</span><span class="p">,</span><span class="w"> </span><span class="mi">6</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="p">};</span><span class="w"></span> <span class="w"> </span><span class="n">stdex</span><span class="o">::</span><span class="n">mdspan</span><span class="w"> </span><span class="n">m</span><span class="p">{</span><span class="n">d</span><span class="p">.</span><span class="n">data</span><span class="p">(),</span><span class="w"> </span><span class="n">stdex</span><span class="o">::</span><span class="n">extents</span><span class="p">{</span><span class="mi">3</span><span class="p">,</span><span class="w"> </span><span class="mi">3</span><span class="p">}};</span><span class="w"></span> <span class="w"> </span><span class="k">static_assert</span><span class="p">(</span><span class="n">m</span><span class="p">.</span><span class="n">rank</span><span class="p">()</span><span class="o">==</span><span class="mi">2</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;Rank is two&quot;</span><span class="p">);</span><span class="w"></span> <span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="kt">size_t</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="n">m</span><span class="p">.</span><span class="n">extent</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span><span class="w"> </span><span class="o">++</span><span class="n">i</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="kt">size_t</span><span class="w"> </span><span class="n">j</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="n">j</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="n">m</span><span class="p">.</span><span class="n">extent</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span><span class="w"> </span><span class="o">++</span><span class="n">j</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="n">std</span><span class="o">::</span><span class="n">cout</span><span class="w"> </span><span class="o">&lt;&lt;</span><span class="w"> </span><span class="s">&quot;m(&quot;</span><span class="w"> </span><span class="o">&lt;&lt;</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">&lt;&lt;</span><span class="w"> </span><span class="s">&quot;, &quot;</span><span class="w"> </span><span class="o">&lt;&lt;</span><span class="w"> </span><span class="n">j</span><span class="w"> </span><span class="o">&lt;&lt;</span><span class="w"> </span><span class="s">&quot;) == &quot;</span><span class="w"> </span><span class="o">&lt;&lt;</span><span class="w"> </span><span class="n">m</span><span class="p">(</span><span class="n">i</span><span class="p">,</span><span class="w"> </span><span class="n">j</span><span class="p">)</span><span class="w"> </span><span class="o">&lt;&lt;</span><span class="w"> </span><span class="s">&quot;</span><span class="se">\n</span><span class="s">&quot;</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"></span> <span class="p">}</span><span class="w"></span> </pre></div> </div> <p>is compiled as follows</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>nvc++ -std=c++17 -o example example.cpp </pre></div> </div> <p>and outputs</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>m(0, 0) == 0 m(0, 1) == 5 m(0, 2) == 1 m(1, 0) == 3 m(1, 1) == 8 m(1, 2) == 4 m(2, 0) == 2 m(2, 1) == 7 m(2, 2) == 6 </pre></div> </div> </section> <section id="senders-and-receivers"> <h4><span class="section-number">8.2.6.2. </span>Senders and Receivers<a class="headerlink" href="#senders-and-receivers" title="Permalink to this headline"></a></h4> <p><a class="reference external" href="http://wg21.link/p2300">P2300 - std::execution</a> proposes a model of asynchronous programming for adoption into the C++26 Standard. For an introduction to this feature, see <a class="reference external" href="https://wg21.link/P2300#design-user">Design - user side</a> section of the proposal. The NVIDIA implementation of Senders and receivers is <a class="reference external" href="https://github.com/NVIDIA/stdexec">open source</a> and its repository contains many <a class="reference external" href="https://github.com/NVIDIA/stdexec/tree/main/examples">useful examples.</a> nvc++ provides access to the NVIDIA implementation which works in C++20 or newer. Since the proposal is still evolving, our implementation is not stable. It is experimental in nature and will change to follow the proposal closely without any warning. The NVIDIA implementation is structured as follows:</p> <table class="table-no-stripes docutils align-default"> <colgroup> <col style="width: 19%" /> <col style="width: 13%" /> <col style="width: 67%" /> </colgroup> <thead> <tr class="row-odd"><th class="head"><p>Includes</p></th> <th class="head"><p>Namespace</p></th> <th class="head"><p>Description</p></th> </tr> </thead> <tbody> <tr class="row-even"><td><p>&lt;stdexec/…&gt;</p></td> <td><p>::stdexec</p></td> <td><p>Approved for C++ standard</p></td> </tr> <tr class="row-odd"><td><p>&lt;sexec/…&gt;</p></td> <td><p>::exec</p></td> <td><p>Generic additions and extensions</p></td> </tr> <tr class="row-even"><td><p>&lt;nvexec/…&gt;</p></td> <td><p>::nvexec</p></td> <td><p>NVIDIA-specific extensions and customizations</p></td> </tr> </tbody> </table> <p>The following example (<a class="reference external" href="https://godbolt.org/z/axbhYs7vj">godbolt</a>) builds a task graph in which two different vectors, v0 and v1, are concurrently modified in bulk, using a CPU thread pool and a GPU stream context, respectively. This graph then transfers execution to the CPU thread pool, and adds both vectors into v2 on the CPU, returning the sum of all elements:</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="kt">int</span><span class="w"> </span><span class="nf">main</span><span class="p">()</span><span class="w"></span> <span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="c1">// Declare a pool of 8 worker CPU threads:</span> <span class="w"> </span><span class="n">exec</span><span class="o">::</span><span class="n">static_thread_pool</span><span class="w"> </span><span class="n">pool</span><span class="p">(</span><span class="mi">8</span><span class="p">);</span><span class="w"></span> <span class="w"> </span><span class="c1">// Declare a GPU stream context:</span> <span class="w"> </span><span class="n">nvexec</span><span class="o">::</span><span class="n">stream_context</span><span class="w"> </span><span class="n">stream_ctx</span><span class="p">{};</span><span class="w"></span> <span class="w"> </span><span class="c1">// Get a handle to the thread pool:</span> <span class="w"> </span><span class="k">auto</span><span class="w"> </span><span class="n">cpu_sched</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">pool</span><span class="p">.</span><span class="n">get_scheduler</span><span class="p">();</span><span class="w"></span> <span class="w"> </span><span class="k">auto</span><span class="w"> </span><span class="n">gpu_sched</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">stream_ctx</span><span class="p">.</span><span class="n">get_scheduler</span><span class="p">();</span><span class="w"></span> <span class="w"> </span><span class="c1">// Declare three dynamic array with N elements</span> <span class="w"> </span><span class="n">std</span><span class="o">::</span><span class="kt">size_t</span><span class="w"> </span><span class="n">N</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">5</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span><span class="w"> </span><span class="n">v0</span><span class="w"> </span><span class="p">{</span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="mi">1</span><span class="p">};</span><span class="w"></span> <span class="w"> </span><span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span><span class="w"> </span><span class="n">v1</span><span class="w"> </span><span class="p">{</span><span class="mi">2</span><span class="p">,</span><span class="w"> </span><span class="mi">2</span><span class="p">,</span><span class="w"> </span><span class="mi">2</span><span class="p">,</span><span class="w"> </span><span class="mi">2</span><span class="p">,</span><span class="w"> </span><span class="mi">2</span><span class="p">};</span><span class="w"></span> <span class="w"> </span><span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span><span class="w"> </span><span class="n">v2</span><span class="w"> </span><span class="p">{</span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span><span class="p">};</span><span class="w"></span> <span class="w"> </span><span class="c1">// Describe some work:</span> <span class="w"> </span><span class="k">auto</span><span class="w"> </span><span class="n">work</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">stdexec</span><span class="o">::</span><span class="n">when_all</span><span class="p">(</span><span class="w"></span> <span class="w"> </span><span class="c1">// Double v0 on the CPU</span> <span class="w"> </span><span class="n">stdexec</span><span class="o">::</span><span class="n">just</span><span class="p">()</span><span class="w"></span> <span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">exec</span><span class="o">::</span><span class="n">on</span><span class="p">(</span><span class="n">cpu_sched</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="n">stdexec</span><span class="o">::</span><span class="n">bulk</span><span class="p">(</span><span class="n">N</span><span class="p">,</span><span class="w"> </span><span class="p">[</span><span class="n">v0</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">v0</span><span class="p">.</span><span class="n">data</span><span class="p">()](</span><span class="n">std</span><span class="o">::</span><span class="kt">size_t</span><span class="w"> </span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="n">v0</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="w"> </span><span class="o">*=</span><span class="w"> </span><span class="mi">2</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="p">})),</span><span class="w"></span> <span class="w"> </span><span class="c1">// Triple v1 on the GPU</span> <span class="w"> </span><span class="n">stdexec</span><span class="o">::</span><span class="n">just</span><span class="p">()</span><span class="w"></span> <span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">exec</span><span class="o">::</span><span class="n">on</span><span class="p">(</span><span class="n">gpu_sched</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="n">stdexec</span><span class="o">::</span><span class="n">bulk</span><span class="p">(</span><span class="n">N</span><span class="p">,</span><span class="w"> </span><span class="p">[</span><span class="n">v1</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">v1</span><span class="p">.</span><span class="n">data</span><span class="p">()](</span><span class="n">std</span><span class="o">::</span><span class="kt">size_t</span><span class="w"> </span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="n">v1</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="w"> </span><span class="o">*=</span><span class="w"> </span><span class="mi">3</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="p">}))</span><span class="w"></span> <span class="w"> </span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">stdexec</span><span class="o">::</span><span class="n">transfer</span><span class="p">(</span><span class="n">cpu_sched</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="c1">// Add the two vectors into the output vector v2 = v0 + v1:</span> <span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">stdexec</span><span class="o">::</span><span class="n">bulk</span><span class="p">(</span><span class="n">N</span><span class="p">,</span><span class="w"> </span><span class="p">[</span><span class="o">&amp;</span><span class="p">](</span><span class="n">std</span><span class="o">::</span><span class="kt">size_t</span><span class="w"> </span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">v2</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">v0</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">v1</span><span class="p">[</span><span class="n">i</span><span class="p">];</span><span class="w"> </span><span class="p">})</span><span class="w"></span> <span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">stdexec</span><span class="o">::</span><span class="n">then</span><span class="p">([</span><span class="o">&amp;</span><span class="p">]</span><span class="w"> </span><span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">r</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="kt">size_t</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="n">N</span><span class="p">;</span><span class="w"> </span><span class="o">++</span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="n">r</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="n">v2</span><span class="p">[</span><span class="n">i</span><span class="p">];</span><span class="w"></span> <span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="n">r</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="p">});</span><span class="w"></span> <span class="w"> </span><span class="k">auto</span><span class="w"> </span><span class="p">[</span><span class="n">sum</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">stdexec</span><span class="o">::</span><span class="n">sync_wait</span><span class="p">(</span><span class="n">work</span><span class="p">).</span><span class="n">value</span><span class="p">();</span><span class="w"></span> <span class="w"> </span><span class="c1">// Print the results:</span> <span class="w"> </span><span class="n">std</span><span class="o">::</span><span class="n">printf</span><span class="p">(</span><span class="s">&quot;sum = %d</span><span class="se">\n</span><span class="s">&quot;</span><span class="p">,</span><span class="w"> </span><span class="n">sum</span><span class="p">);</span><span class="w"></span> <span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="kt">int</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="n">N</span><span class="p">;</span><span class="w"> </span><span class="o">++</span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="n">std</span><span class="o">::</span><span class="n">printf</span><span class="p">(</span><span class="s">&quot;v0[%d] = %d, v1[%d] = %d, v2[%d] = %d</span><span class="se">\n</span><span class="s">&quot;</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="n">i</span><span class="p">,</span><span class="w"> </span><span class="n">v0</span><span class="p">[</span><span class="n">i</span><span class="p">],</span><span class="w"> </span><span class="n">i</span><span class="p">,</span><span class="w"> </span><span class="n">v1</span><span class="p">[</span><span class="n">i</span><span class="p">],</span><span class="w"> </span><span class="n">i</span><span class="p">,</span><span class="w"> </span><span class="n">v2</span><span class="p">[</span><span class="n">i</span><span class="p">]);</span><span class="w"></span> <span class="w"> </span><span class="p">}</span><span class="w"></span> <span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"></span> <span class="p">}</span><span class="w"></span> </pre></div> </div> <p>is compiled as follows:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>nvc++ --stdpar=gpu --experimental-stdpar -std=c++20 -o example example.cpp </pre></div> </div> <p>and outputs:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>sum = 40 v0[0] = 2, v1[0] = 6, v2[0] = 8 v0[1] = 2, v1[1] = 6, v2[1] = 8 v0[2] = 2, v1[2] = 6, v2[2] = 8 v0[3] = 2, v1[3] = 6, v2[3] = 8 v0[4] = 2, v1[4] = 6, v2[4] = 8 </pre></div> </div> </section> <section id="linear-algebra"> <h4><span class="section-number">8.2.6.3. </span>Linear Algebra<a class="headerlink" href="#linear-algebra" title="Permalink to this headline"></a></h4> <p><a class="reference external" href="https://wg21.link/p1673">P1673 - A free function linear algebra interface based on the BLAS</a> proposes standardizing an idiomatic C++ interface based on std::mdspan for a subset of the Basic Linear Algebra Subroutines (BLAS) standard. For an introduction to this feature, see <a class="reference external" href="https://youtu.be/n7mBGDqSzlQ">P1673 (C++ linear algebra library) background &amp; motivation</a>. There are many useful examples available in $HPCSDK_HOME/examples/stdpar/stdblas and in the repository of the <a class="reference external" href="https://github.com/kokkos/stdBLAS/tree/main/examples">reference implementation</a>. A detailed documentation is available at $HPCSDK_HOME/compilers/include/experimental/__p1673_bits/README.md. nvc++ provides access to the NVIDIA implementation which works in C++17 or newer. Since the proposal is still evolving, our implementation is not stable. It is experimental in nature and will change to follow the proposal closely without any warning. To use the linear algebra library facilities, a suitable linear algebra library must be linked: cuBLAS for GPU execution via the -cudalib=cublas flag, and a CPU BLAS library for CPU execution. The HPC SDK bundles OpenBLAS which may be linked using the -lblas linker flag.</p> <table class="table-no-stripes docutils align-default"> <colgroup> <col style="width: 13%" /> <col style="width: 17%" /> <col style="width: 30%" /> <col style="width: 40%" /> </colgroup> <thead> <tr class="row-odd"><th class="head"><p>Execution</p></th> <th class="head"><p>BLAS library</p></th> <th class="head"><p>Architectures</p></th> <th class="head"><p>Compiler flags</p></th> </tr> </thead> <tbody> <tr class="row-even"><td><p>Multicore</p></td> <td><p>OpenBLAS</p></td> <td><p>x86_64, aarch64</p></td> <td><p><code class="docutils literal notranslate"><span class="pre">-stdpar=multicore</span> <span class="pre">-lblas</span></code></p></td> </tr> <tr class="row-odd"><td><p>GPU</p></td> <td><p>cuBLAS</p></td> <td><p>All</p></td> <td><p><code class="docutils literal notranslate"><span class="pre">-stdpar=gpu</span> <span class="pre">-cudalib=cublas</span></code></p></td> </tr> </tbody> </table> <p>The following example (<a class="reference external" href="https://godbolt.org/z/8cT537dfo">godbolt</a>):</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="cp">#include</span><span class="w"> </span><span class="cpf">&lt;experimental/mdspan&gt;</span><span class="cp"></span> <span class="cp">#include</span><span class="w"> </span><span class="cpf">&lt;experimental/linalg&gt;</span><span class="cp"></span> <span class="cp">#include</span><span class="w"> </span><span class="cpf">&lt;vector&gt;</span><span class="cp"></span> <span class="cp">#include</span><span class="w"> </span><span class="cpf">&lt;array&gt;</span><span class="cp"></span> <span class="k">namespace</span><span class="w"> </span><span class="nn">stdex</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nn">std</span><span class="o">::</span><span class="nn">experimental</span><span class="p">;</span><span class="w"></span> <span class="kt">int</span><span class="w"> </span><span class="nf">main</span><span class="p">()</span><span class="w"></span> <span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="k">constexpr</span><span class="w"> </span><span class="kt">size_t</span><span class="w"> </span><span class="n">N</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">4</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="k">constexpr</span><span class="w"> </span><span class="kt">size_t</span><span class="w"> </span><span class="n">M</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">2</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">double</span><span class="o">&gt;</span><span class="w"> </span><span class="n">A_vec</span><span class="p">(</span><span class="n">N</span><span class="o">*</span><span class="n">M</span><span class="p">);</span><span class="w"></span> <span class="w"> </span><span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">double</span><span class="o">&gt;</span><span class="w"> </span><span class="n">x_vec</span><span class="p">(</span><span class="n">M</span><span class="p">);</span><span class="w"></span> <span class="w"> </span><span class="n">std</span><span class="o">::</span><span class="n">array</span><span class="o">&lt;</span><span class="kt">double</span><span class="p">,</span><span class="w"> </span><span class="n">N</span><span class="o">&gt;</span><span class="w"> </span><span class="n">y_vec</span><span class="p">(</span><span class="n">N</span><span class="p">);</span><span class="w"></span> <span class="w"> </span><span class="n">stdex</span><span class="o">::</span><span class="n">mdspan</span><span class="w"> </span><span class="n">A</span><span class="p">(</span><span class="n">A_vec</span><span class="p">.</span><span class="n">data</span><span class="p">(),</span><span class="w"> </span><span class="n">N</span><span class="p">,</span><span class="w"> </span><span class="n">M</span><span class="p">);</span><span class="w"></span> <span class="w"> </span><span class="n">stdex</span><span class="o">::</span><span class="n">mdspan</span><span class="w"> </span><span class="n">x</span><span class="p">(</span><span class="n">x_vec</span><span class="p">.</span><span class="n">data</span><span class="p">(),</span><span class="w"> </span><span class="n">M</span><span class="p">);</span><span class="w"></span> <span class="w"> </span><span class="n">stdex</span><span class="o">::</span><span class="n">mdspan</span><span class="w"> </span><span class="n">y</span><span class="p">(</span><span class="n">y_vec</span><span class="p">.</span><span class="n">data</span><span class="p">(),</span><span class="w"> </span><span class="n">N</span><span class="p">);</span><span class="w"></span> <span class="w"> </span><span class="k">for</span><span class="p">(</span><span class="kt">int</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="n">A</span><span class="p">.</span><span class="n">extent</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span><span class="w"> </span><span class="o">++</span><span class="n">i</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="k">for</span><span class="p">(</span><span class="kt">int</span><span class="w"> </span><span class="n">j</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="n">j</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="n">A</span><span class="p">.</span><span class="n">extent</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span><span class="w"> </span><span class="o">++</span><span class="n">j</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="n">A</span><span class="p">(</span><span class="n">i</span><span class="p">,</span><span class="n">j</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mf">100.0</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">j</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="k">for</span><span class="p">(</span><span class="kt">int</span><span class="w"> </span><span class="n">j</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="n">j</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="n">x</span><span class="p">.</span><span class="n">extent</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span><span class="w"> </span><span class="o">++</span><span class="n">j</span><span class="p">)</span><span class="w"> </span><span class="n">x</span><span class="p">(</span><span class="n">j</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mf">1.0</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">j</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="k">for</span><span class="p">(</span><span class="kt">int</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="n">y</span><span class="p">.</span><span class="n">extent</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span><span class="w"> </span><span class="o">++</span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="n">y</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mf">-1.0</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">i</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="n">stdex</span><span class="o">::</span><span class="n">linalg</span><span class="o">::</span><span class="n">matrix_vector_product</span><span class="p">(</span><span class="n">A</span><span class="p">,</span><span class="w"> </span><span class="n">x</span><span class="p">,</span><span class="w"> </span><span class="n">y</span><span class="p">);</span><span class="w"> </span><span class="c1">// y = A * x</span> <span class="w"> </span><span class="c1">// y = 0.5 * y + 2 * A * x</span> <span class="w"> </span><span class="n">stdex</span><span class="o">::</span><span class="n">linalg</span><span class="o">::</span><span class="n">matrix_vector_product</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">execution</span><span class="o">::</span><span class="n">par</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="n">stdex</span><span class="o">::</span><span class="n">linalg</span><span class="o">::</span><span class="n">scaled</span><span class="p">(</span><span class="mf">2.0</span><span class="p">,</span><span class="w"> </span><span class="n">A</span><span class="p">),</span><span class="w"> </span><span class="n">x</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="n">stdex</span><span class="o">::</span><span class="n">linalg</span><span class="o">::</span><span class="n">scaled</span><span class="p">(</span><span class="mf">0.5</span><span class="p">,</span><span class="w"> </span><span class="n">y</span><span class="p">),</span><span class="w"> </span><span class="n">y</span><span class="p">);</span><span class="w"></span> <span class="w"> </span><span class="c1">// Print the results:</span> <span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="kt">int</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="n">N</span><span class="p">;</span><span class="w"> </span><span class="o">++</span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="n">std</span><span class="o">::</span><span class="n">printf</span><span class="p">(</span><span class="s">&quot;y[%d] = %f</span><span class="se">\n</span><span class="s">&quot;</span><span class="p">,</span><span class="w"> </span><span class="n">i</span><span class="p">,</span><span class="w"> </span><span class="n">y</span><span class="p">(</span><span class="n">i</span><span class="p">));</span><span class="w"></span> <span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"></span> <span class="p">}</span><span class="w"></span> </pre></div> </div> <p>is compiled as follows for GPU execution:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>nvc++ -std=c++17 -stdpar=gpu -cudalib=cublas -o example example.cpp </pre></div> </div> <p>And as follows for CPU execution:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>nvc++ -std=c++17 -stdpar=multicore -o example example.cpp -lblas </pre></div> </div> <p>and produces the same outputs in both cases:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>y[0] = 2.500000 y[1] = 252.500000 y[2] = 502.500000 y[3] = 752.500000 </pre></div> </div> </section> </section> <section id="stdpar-c-larger-example-lulesh"> <h3><span class="section-number">8.2.7. </span>Stdpar C++ Larger Example: LULESH<a class="headerlink" href="#stdpar-c-larger-example-lulesh" title="Permalink to this headline"></a></h3> <p>The <a class="reference external" href="https://github.com/LLNL/LULESH">LULESH hydrodynamics mini-app</a> was developed at Lawrence Livermore National Laboratory to stress test compilers and model performance of hydrodynamics applications. It is about 9,000 lines of C++ code, of which 2,800 lines are the core computation that should be parallelized.</p> <p>We ported LULESH to C++ Parallel Algorithms and made the port available on <a class="reference external" href="https://github.com/LLNL/LULESH/tree/2.0.2-dev/stdpar">LULESH’s GitHub repository</a>. To compile it, install the <a class="reference external" href="https://developer.nvidia.com/hpc-sdk">NVIDIA HPC SDK</a>, check out the 2.0.2-dev branch of the LULESH repository, go to the correct directory, and <code class="docutils literal notranslate"><span class="pre">run</span> <span class="pre">make</span></code>.</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>git clone --branch 2.0.2-dev https://github.com/LLNL/LULESH.git cd LULESH/stdpar/build make run </pre></div> </div> <p>While LULESH is too large to show the entire source code here, there are some key code sequences that demonstrate the use of stdpar.</p> <p>The LULESH code has many loops with large bodies and no loop-carried dependencies, making them good candidates for parallelization. Most of these were easily converted into calls to <code class="docutils literal notranslate"><span class="pre">std::for_each_n</span></code> with the <code class="docutils literal notranslate"><span class="pre">std::execution::par</span></code> policy, where the body of the lambda passed to <code class="docutils literal notranslate"><span class="pre">std::for_each_n</span></code> is identical to the original loop body.</p> <p>The function <code class="docutils literal notranslate"><span class="pre">CalcMonotonicQRegionForElems</span></code> is an example of this. The loop header written for OpenMP looks as follows:</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="cp">#pragma omp parallel for firstprivate(qlc_monoq, qqc_monoq, \</span> <span class="cp"> monoq_limiter_mult, monoq_max_slope, ptiny)</span> <span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="w"> </span><span class="n">Index_t</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="n">domain</span><span class="p">.</span><span class="n">regElemSize</span><span class="p">(</span><span class="n">r</span><span class="p">);</span><span class="w"> </span><span class="o">++</span><span class="n">i</span><span class="w"> </span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span> </pre></div> </div> <p>This loop header in the C++ Parallel Algorithms version becomes <a class="reference external" href="https://github.com/LLNL/LULESH/blob/2.0.2-dev/stdpar/src/lulesh.cc#L1555-L1756">the following</a>:</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="n">std</span><span class="o">::</span><span class="n">for_each_n</span><span class="p">(</span><span class="w"></span> <span class="w"> </span><span class="n">std</span><span class="o">::</span><span class="n">execution</span><span class="o">::</span><span class="n">par</span><span class="p">,</span><span class="w"> </span><span class="n">counting_iterator</span><span class="p">(</span><span class="mi">0</span><span class="p">),</span><span class="w"> </span><span class="n">domain</span><span class="p">.</span><span class="n">regElemSize</span><span class="p">(</span><span class="n">r</span><span class="p">),</span><span class="w"></span> <span class="w"> </span><span class="p">[</span><span class="o">=</span><span class="p">,</span><span class="w"> </span><span class="o">&amp;</span><span class="n">domain</span><span class="p">](</span><span class="n">Index_t</span><span class="w"> </span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span> </pre></div> </div> <p>The loop body, which in this case is almost 200 lines long, becomes the body of the lambda but is otherwise unchanged from the OpenMP version.</p> <p>In a number of places, an explicit <code class="docutils literal notranslate"><span class="pre">for</span></code> loop was changed to use C++ Parallel Algorithms that better express the intent of the code, such as the function <code class="docutils literal notranslate"><span class="pre">CalcPressureForElems</span></code>:</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="cp">#pragma omp parallel for firstprivate(length)</span> <span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="n">Index_t</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="n">length</span><span class="w"> </span><span class="p">;</span><span class="w"> </span><span class="o">++</span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="n">Real_t</span><span class="w"> </span><span class="n">c1s</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Real_t</span><span class="p">(</span><span class="mf">2.0</span><span class="p">)</span><span class="o">/</span><span class="n">Real_t</span><span class="p">(</span><span class="mf">3.0</span><span class="p">)</span><span class="w"> </span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="n">bvc</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">c1s</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="p">(</span><span class="n">compression</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">Real_t</span><span class="p">(</span><span class="mf">1.</span><span class="p">));</span><span class="w"></span> <span class="w"> </span><span class="n">pbvc</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">c1s</span><span class="p">;</span><span class="w"></span> <span class="p">}</span><span class="w"></span> </pre></div> </div> <p>This function was rewritten as <a class="reference external" href="https://github.com/LLNL/LULESH/blob/2.0.2-dev/stdpar/src/lulesh.cc#L1825-L1830">as follows</a>:</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="k">constexpr</span><span class="w"> </span><span class="n">Real_t</span><span class="w"> </span><span class="n">cls</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Real_t</span><span class="p">(</span><span class="mf">2.0</span><span class="p">)</span><span class="w"> </span><span class="o">/</span><span class="w"> </span><span class="n">Real_t</span><span class="p">(</span><span class="mf">3.0</span><span class="p">);</span><span class="w"></span> <span class="n">std</span><span class="o">::</span><span class="n">transform</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">execution</span><span class="o">::</span><span class="n">par</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="n">compression</span><span class="p">,</span><span class="w"> </span><span class="n">compression</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">length</span><span class="p">,</span><span class="w"> </span><span class="n">bvc</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="p">[</span><span class="o">=</span><span class="p">](</span><span class="n">Real_t</span><span class="w"> </span><span class="n">compression_i</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="n">cls</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="p">(</span><span class="n">compression_i</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">Real_t</span><span class="p">(</span><span class="mf">1.0</span><span class="p">));</span><span class="w"></span> <span class="w"> </span><span class="p">});</span><span class="w"></span> <span class="n">std</span><span class="o">::</span><span class="n">fill</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">execution</span><span class="o">::</span><span class="n">par</span><span class="p">,</span><span class="w"> </span><span class="n">pbvc</span><span class="p">,</span><span class="w"> </span><span class="n">pbvc</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">length</span><span class="p">,</span><span class="w"> </span><span class="n">cls</span><span class="p">);</span><span class="w"></span> </pre></div> </div> <span class="target" id="stdpar-cpp-interop-openacc"></span></section> <section id="interoperability-with-openacc"> <h3><span class="section-number">8.2.8. </span>Interoperability with OpenACC<a class="headerlink" href="#interoperability-with-openacc" title="Permalink to this headline"></a></h3> <p>A subset of OpenACC features can be used when compiling Stdpar code for GPUs. Such a subset is documented in this section. To activate OpenACC directives recognition with Stdpar code add -acc command line flag to nvc++.</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>nvc++ -stdpar -acc example.cpp </pre></div> </div> <p>OpenACC functionality is detailed in the OpenACC specification and the NVHPC compiler specific differences are detailed in <a class="reference internal" href="#acc-use"><span class="std std-ref">Using OpenACC</span></a> of this guide.</p> <p>Combining OpenACC features with Stdpar offers greater flexibility in how code is written. For instance, it allows external functions to be called from within parallel algorithms. Additionally, it provides opportunities for performance tuning, such as through explicit data management.</p> <section id="data-management-directives"> <h4><span class="section-number">8.2.8.1. </span>Data Management Directives<a class="headerlink" href="#data-management-directives" title="Permalink to this headline"></a></h4> <p>C++ parallel algorithms can be offloaded to the GPU when the data accessed in such algorithms is managed through the OpenACC directives. With data fully managed through the OpenACC directives, Stdpar code can run with all GPU Memory Modes including Separate Memory Mode (compiled with <code class="docutils literal notranslate"><span class="pre">-gpu=mem:separate</span></code>).</p> <p>The following data directives are supported:</p> <ul class="simple"> <li><p>OpenACC structured data construct directive</p></li> <li><p>OpenACC unstructured enter/exit data directives</p></li> <li><p>OpenACC host_data directive</p></li> <li><p>OpenACC update directive</p></li> </ul> <p>Only the data that are captured by reference or pointer-like data captured by values as well as pointer-like data passed as arguments in the parallel algorithm lambdas can be managed through OpenACC. Any non-pointer variables that are captured by value in the parallel algorithm lambda or non-pointer data passed in as lambda arguments are managed by the C++ implementation. A copy of such data is automatically created in the memory accessible from the GPU. For additional details refer to <a class="reference internal" href="#stdpar-cpp-unified-memory"><span class="std std-ref">Data Management in Parallel Algorithms</span></a>.</p> <p>OpenACC data management can serve two main purposes:</p> <ul class="simple"> <li><p><strong>Explicit Data Management:</strong> This is necessary for data that cannot be managed implicitly, such as on platforms without full CUDA Unified Memory support and when data is not allocated in the CUDA Managed Memory segment.</p></li> <li><p><strong>Performance Tuning:</strong> Even when data is located in the GPU-accessible memory, performance can be optimized via OpenACC features. Many OpenACC data directives and clauses provide hints to the CUDA device driver, which can improve implicit data management.</p></li> </ul> <p>Data management strategies may differ depending on the specific goals being pursued. These differences are outlined where applicable.</p> <p><strong>General Rules</strong></p> <p>All directives, except <code class="docutils literal notranslate"><span class="pre">host_data</span></code>, can be used for data management tasks such as allocating memory in the GPU and copying data between the CPU and the GPU. These directives can be used to ensure that the data is present on the device during the execution of parallel algorithms. The <code class="docutils literal notranslate"><span class="pre">host_data</span></code> construct, on the other hand, is used for address translation between CPU and GPU address spaces when data is accessed in parallel algorithms.</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="kt">int</span><span class="w"> </span><span class="n">n</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">get_n</span><span class="p">();</span><span class="w"></span> <span class="n">T</span><span class="o">*</span><span class="w"> </span><span class="n">in</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">T</span><span class="p">[</span><span class="n">nelem</span><span class="p">];</span><span class="w"></span> <span class="n">T</span><span class="o">*</span><span class="w"> </span><span class="n">out</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">T</span><span class="p">[</span><span class="n">nelem</span><span class="p">];</span><span class="w"></span> <span class="c1">// Data captured by the lambda are managed explicitly with OpenACC</span> <span class="cp">#pragma acc enter data copyin(n, in[0:nelem]) create(out[0:nelem])</span> <span class="cp">#pragma acc host_data use_device(n, in, out)</span> <span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="n">std</span><span class="o">::</span><span class="n">for_each</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">execution</span><span class="o">::</span><span class="n">par_unseq</span><span class="p">,</span><span class="w"> </span><span class="n">r</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span><span class="w"> </span><span class="n">r</span><span class="p">.</span><span class="n">end</span><span class="p">(),</span><span class="w"></span> <span class="w"> </span><span class="p">[</span><span class="o">&amp;</span><span class="p">,</span><span class="n">in</span><span class="p">,</span><span class="n">out</span><span class="p">](</span><span class="k">auto</span><span class="w"> </span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="n">out</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">in</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">n</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="p">});</span><span class="w"></span> <span class="p">}</span><span class="w"></span> <span class="cp">#pragma acc exit data copyout(out[0:nelem])</span> </pre></div> </div> <p>In the above example all data accessed from <code class="docutils literal notranslate"><span class="pre">std::for_each</span></code> through the lambda capture are managed explicitly through the OpenACC data directives. Since the data inside the parallel algorithms are either captured by reference or capturing a pointer, the application code must ensure that such data is accessible from the GPU. To make non-GPU resident data accessible in the parallel region, such a region must be enclosed into the <code class="docutils literal notranslate"><span class="pre">host_data</span></code> construct region with all variables that are managed explicitly via OpenACC runtime listed in the <code class="docutils literal notranslate"><span class="pre">use_device</span></code> clause. The data need to be present (copied or created) at the time the <code class="docutils literal notranslate"><span class="pre">host_data</span></code> directive is encountered/executed at runtime and the data must also be present for the duration of parallel algorithm execution. The implications of the above are such that lambdas accessing variables enclosed in <code class="docutils literal notranslate"><span class="pre">use_device</span></code> regions can not be additionally invoked from the host code (from outside the parallel region executing on the GPU) because the variable addresses from the GPU obtained through <code class="docutils literal notranslate"><span class="pre">host_data</span></code> may not be accessible on the CPU.</p> <div class="admonition note"> <p class="admonition-title">Note</p> <p>If the iterator in the above example would be a pointer type it would require explicit data management in addition to the data captured by the lambda.</p> </div> <p>If the example below is compiled for Separate Memory Mode (-gpu=mem:separate) calling <code class="docutils literal notranslate"><span class="pre">fn</span></code> from within a parallel <code class="docutils literal notranslate"><span class="pre">std::for_each</span></code> works fine but not from outside of any parallel algorithm function since the data resident on GPU would need to be accessed from the CPU.</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="kt">int</span><span class="w"> </span><span class="n">n</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">get_n</span><span class="p">();</span><span class="w"></span> <span class="n">T</span><span class="o">*</span><span class="w"> </span><span class="n">in</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">T</span><span class="p">[</span><span class="n">nelem</span><span class="p">];</span><span class="w"></span> <span class="n">T</span><span class="o">*</span><span class="w"> </span><span class="n">out</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">T</span><span class="p">[</span><span class="n">nelem</span><span class="p">];</span><span class="w"></span> <span class="cp">#pragma acc enter data copyin(n, in[0:nelem]) create(out[0:nelem])</span> <span class="cp">#pragma acc host_data use_device(n, in, out)</span> <span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="k">auto</span><span class="w"> </span><span class="n">fn</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">[</span><span class="o">&amp;</span><span class="p">,</span><span class="n">in</span><span class="p">,</span><span class="n">out</span><span class="p">](</span><span class="k">auto</span><span class="w"> </span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">out</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">in</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">n</span><span class="p">;};</span><span class="w"></span> <span class="w"> </span><span class="n">std</span><span class="o">::</span><span class="n">for_each</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">execution</span><span class="o">::</span><span class="n">par_unseq</span><span class="p">,</span><span class="w"> </span><span class="n">r</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span><span class="w"> </span><span class="n">r</span><span class="p">.</span><span class="n">end</span><span class="p">(),</span><span class="w"> </span><span class="n">fn</span><span class="p">);</span><span class="w"></span> <span class="w"> </span><span class="c1">// The following line would not be legal, fn accesses variables in GPU memory</span> <span class="w"> </span><span class="c1">//std::for_each(r.begin(), r.end(), fn);</span> <span class="p">}</span><span class="w"></span> <span class="cp">#pragma acc exit data copyout(out[0:nelem])</span> </pre></div> </div> <div class="admonition note"> <p class="admonition-title">Note</p> <p>The behavior of using <code class="docutils literal notranslate"><span class="pre">use_device</span></code> with non-pointer data type is such that all occurrences of non-pointer variables inside the <code class="docutils literal notranslate"><span class="pre">host_data</span></code> region are converted to using the addresses of the variable in the GPU address space before accessing that variable. This is essentially equivalent to translating original occurrences of such variable <code class="docutils literal notranslate"><span class="pre">var</span></code> into <code class="docutils literal notranslate"><span class="pre">dvar</span> <span class="pre">=</span> <span class="pre">*acc_device(&amp;var)</span></code>.</p> </div> <p><strong>Composite Data Types</strong></p> <p>Composite data types with pointer members can also be managed explicitly but require explicit deep copy to work correctly including pointer attach/detach.</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="k">struct</span><span class="w"> </span><span class="nc">S</span><span class="w"> </span><span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="kt">float</span><span class="w"> </span><span class="o">*</span><span class="n">ptr</span><span class="p">;</span><span class="w"></span> <span class="p">}</span><span class="w"></span> <span class="kt">int</span><span class="w"> </span><span class="n">idx</span><span class="p">[</span><span class="n">N</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span><span class="cm">/*...*/</span><span class="p">};</span><span class="w"></span> <span class="kt">float</span><span class="w"> </span><span class="n">arr</span><span class="p">[</span><span class="n">N</span><span class="p">];</span><span class="w"></span> <span class="n">S</span><span class="w"> </span><span class="n">s</span><span class="p">{</span><span class="n">arr</span><span class="p">};</span><span class="w"></span> <span class="c1">// Deep copying ptr member with OpenACC</span> <span class="cp">#pragma acc enter data copyin(s.ptr[0:N])</span> <span class="cp">#pragma acc enter data copyin(s, idx)</span> <span class="cp">#pragma acc data attach(s.ptr)</span> <span class="cp">#pragma acc host_data use_device(s, idx)</span> <span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="n">std</span><span class="o">::</span><span class="n">for_each_n</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">execution</span><span class="o">::</span><span class="n">par</span><span class="p">,</span><span class="w"> </span><span class="n">idx</span><span class="p">,</span><span class="w"> </span><span class="n">N</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="p">[</span><span class="o">&amp;</span><span class="p">](</span><span class="kt">int</span><span class="w"> </span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">s</span><span class="p">.</span><span class="n">ptr</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="mf">5.0</span><span class="p">;</span><span class="w"> </span><span class="p">});</span><span class="w"></span> <span class="p">}</span><span class="w"></span> <span class="cp">#pragma acc exit data copyout(s.ptr[0:N])</span> <span class="cp">#pragma acc exit data copyout(s)</span> </pre></div> </div> <p>When variable of struct <code class="docutils literal notranslate"><span class="pre">S</span></code> type in the above example is copied to the device, a deep copy is performed with the content pointed by <code class="docutils literal notranslate"><span class="pre">S.ptr</span></code> copied separately. The pointer attachment is used to ensure the address of the pointer is changed to the device memory equivalent before it is accessed from the GPU. Depending on the order of the copies, the pointer <code class="docutils literal notranslate"><span class="pre">attach</span></code> clause may not be required.</p> <div class="admonition note"> <p class="admonition-title">Note</p> <p>In the above example the pointer-like iterator <code class="docutils literal notranslate"><span class="pre">idx</span></code> is managed through the OpenACC directives in addition to the data captured by the lambda.</p> </div> <p><strong>Standard Containers</strong></p> <p>If the standard containers with non-contiguous storage must be used in host code with explicit data management to GPU memory, the only viable option is to access the raw data directly using the raw pointer to data (e.g. obtained via <code class="docutils literal notranslate"><span class="pre">data()</span></code> member of <code class="docutils literal notranslate"><span class="pre">std::vector</span></code>) unless the iterator over the data can be used.</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span><span class="w"> </span><span class="n">in</span><span class="p">(</span><span class="n">nelem</span><span class="p">);</span><span class="w"></span> <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span><span class="w"> </span><span class="n">out</span><span class="p">(</span><span class="n">nelem</span><span class="p">);</span><span class="w"></span> <span class="n">T</span><span class="w"> </span><span class="o">*</span><span class="n">inptr</span><span class="o">=</span><span class="n">in</span><span class="p">.</span><span class="n">data</span><span class="p">(),</span><span class="o">*</span><span class="n">outptr</span><span class="o">=</span><span class="n">out</span><span class="p">.</span><span class="n">data</span><span class="p">();</span><span class="w"></span> <span class="cp">#pragma acc data copyin(inptr[0:nelem]) copyout(outptr[0:nelem])</span> <span class="cp">#pragma acc host_data use_device(inptr,outptr)</span> <span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="n">std</span><span class="o">::</span><span class="n">for_each</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">execution</span><span class="o">::</span><span class="n">par_unseq</span><span class="p">,</span><span class="w"> </span><span class="n">r</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span><span class="w"> </span><span class="n">r</span><span class="p">.</span><span class="n">end</span><span class="p">(),</span><span class="w"></span> <span class="w"> </span><span class="p">[</span><span class="o">=</span><span class="p">](</span><span class="k">auto</span><span class="w"> </span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="n">outptr</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">inptr</span><span class="p">[</span><span class="n">i</span><span class="p">];</span><span class="w"></span> <span class="w"> </span><span class="p">});</span><span class="w"></span> <span class="p">}</span><span class="w"></span> </pre></div> </div> <p>In the above example vector elements are accessed through raw pointers to their elements obtained through <code class="docutils literal notranslate"><span class="pre">vector::data()</span></code> member, they are explicitly management through the OpenACC data clauses.</p> <p><strong>Static Storage Data</strong></p> <p>Global or static variables can be made accessible in the parallel algorithms using OpenACC data directives similarly to other variables.</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="kt">int</span><span class="w"> </span><span class="n">glob_arr</span><span class="p">[</span><span class="n">N</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span><span class="cm">/*...*/</span><span class="p">};</span><span class="w"></span> <span class="kt">void</span><span class="w"> </span><span class="nf">foo</span><span class="p">(){</span><span class="w"></span> <span class="cp">#pragma acc data copy(glob_arr)</span> <span class="cp">#pragma acc host_data use_device(glob_arr)</span> <span class="w"> </span><span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="n">std</span><span class="o">::</span><span class="n">for_each_n</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">execution</span><span class="o">::</span><span class="n">par</span><span class="p">,</span><span class="w"> </span><span class="n">glob_arr</span><span class="p">,</span><span class="w"> </span><span class="n">N</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="p">[](</span><span class="kt">int</span><span class="w"> </span><span class="o">&amp;</span><span class="n">e</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">e</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="mi">1</span><span class="p">;</span><span class="w"> </span><span class="p">});</span><span class="w"></span> <span class="w"> </span><span class="p">}</span><span class="w"></span> <span class="p">}</span><span class="w"></span> </pre></div> </div> <p>In the above example the global array <code class="docutils literal notranslate"><span class="pre">glob_arr</span></code> is updated on the GPU with help of OpenACC data directives.</p> <p><strong>Member Functions</strong></p> <p>When the data members are managed inside the member functions the implicit object pointer <code class="docutils literal notranslate"><span class="pre">this</span></code> needs to be explicitly managed for correctness as accessing members is always done through the dereference of the object itself.</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="k">struct</span><span class="w"> </span><span class="nc">S</span><span class="w"> </span><span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="kt">float</span><span class="w"> </span><span class="o">*</span><span class="n">ptr</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="nf">update_member</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span> <span class="cp">#pragma acc data copy(ptr[0:N], this)</span> <span class="cp">#pragma acc host_data use_device(ptr, this)</span> <span class="w"> </span><span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="n">std</span><span class="o">::</span><span class="n">for_each</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">execution</span><span class="o">::</span><span class="n">par</span><span class="p">,</span><span class="w"> </span><span class="n">ptr</span><span class="p">,</span><span class="w"> </span><span class="n">ptr</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">N</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="p">[</span><span class="o">=</span><span class="p">](</span><span class="kt">float</span><span class="w"> </span><span class="o">&amp;</span><span class="n">e</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">ptr</span><span class="p">[</span><span class="o">&amp;</span><span class="n">e</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">ptr</span><span class="p">]</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="mf">5.0</span><span class="p">;</span><span class="w"> </span><span class="p">});</span><span class="w"></span> <span class="w"> </span><span class="p">}</span><span class="w"></span> <span class="w"> </span><span class="p">}</span><span class="w"></span> <span class="p">};</span><span class="w"></span> </pre></div> </div> <p><strong>GPU Memory Mode Related Differences</strong></p> <p>In Separate Memory Mode all data must be managed explicitly via extra device allocations and <code class="docutils literal notranslate"><span class="pre">memcpy</span></code> between the host and device and the address translations. This also applies to variables with automatic or static storage duration in Managed Memory Mode.</p> <p>In Unified Memory Mode all data is automatically managed by the CUDA device driver. Additionally in Managed Memory Mode all dynamic allocations are managed by the CUDA device driver. Use of data clauses and directives can only propagate memory usage hints to the CUDA device driver which are used to improve the data management performance. More details can be found in Memory Model and <a class="reference internal" href="#acc-openacc-unified-mem"><span class="std std-ref">OpenACC with CUDA Unified Memory</span></a> .</p> <p>All the data managed by the CUDA device driver can benefit from the simplified uses of the OpenACC features, particularly:</p> <ul class="simple"> <li><p>Use of <code class="docutils literal notranslate"><span class="pre">host_data</span></code> directive is not required since the host and device address of data in unified shared memory is identical.</p></li> <li><p>Use of pointer attach or detach is not required since the host and device pointers in unified shared memory are identical.</p></li> </ul> <p>The following example illustrates simplified data managment with only OpenACC data construct enclosing the <code class="docutils literal notranslate"><span class="pre">std::for_each</span></code> with Unified Memory Mode.</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="kt">int</span><span class="w"> </span><span class="n">n</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">get_n</span><span class="p">();</span><span class="w"></span> <span class="n">T</span><span class="o">*</span><span class="w"> </span><span class="n">in</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">T</span><span class="p">[</span><span class="n">nelem</span><span class="p">];</span><span class="w"></span> <span class="n">T</span><span class="o">*</span><span class="w"> </span><span class="n">out</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">T</span><span class="p">[</span><span class="n">nelem</span><span class="p">];</span><span class="w"></span> <span class="cp">#pragma acc data copyin(in[0:nelem]) copyout(out[0:nelem])</span> <span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="n">std</span><span class="o">::</span><span class="n">for_each</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">execution</span><span class="o">::</span><span class="n">par_unseq</span><span class="p">,</span><span class="w"> </span><span class="n">r</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span><span class="w"> </span><span class="n">r</span><span class="p">.</span><span class="n">end</span><span class="p">(),</span><span class="w"></span> <span class="w"> </span><span class="p">[</span><span class="o">&amp;</span><span class="p">](</span><span class="k">auto</span><span class="w"> </span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="n">out</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">in</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">n</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="p">});</span><span class="w"></span> <span class="p">}</span><span class="w"></span> </pre></div> </div> <p>In the above example we leverage OpenACC explicit data management construct to indicate how data is used on GPU for the computation executed in <code class="docutils literal notranslate"><span class="pre">std::for_each</span></code>:</p> <ul class="simple"> <li><p><code class="docutils literal notranslate"><span class="pre">in</span></code> is moved into the GPU memory;</p></li> <li><p><code class="docutils literal notranslate"><span class="pre">out</span></code> is moved from the GPU memory.</p></li> </ul> <p>Both <code class="docutils literal notranslate"><span class="pre">in</span></code> and <code class="docutils literal notranslate"><span class="pre">out</span></code> are captured by reference and therefore their host address is used in the lambda of <code class="docutils literal notranslate"><span class="pre">std::for_each</span></code>. The scalar variable <code class="docutils literal notranslate"><span class="pre">n</span></code> is not managed. The use of <code class="docutils literal notranslate"><span class="pre">host_data</span></code> construct is not required.</p> <p>When standard containers are used in data directives and clauses, the underlying data collection can be managed too. For example, in order to indicate that elements of the <code class="docutils literal notranslate"><span class="pre">std::vector</span></code> are accessed from the GPU the application code must first retrieve the pointer to the array elements using its <code class="docutils literal notranslate"><span class="pre">data()</span></code> member. Then such pointers can be used in the regular data directives.</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span><span class="w"> </span><span class="n">in</span><span class="p">(</span><span class="n">nelem</span><span class="p">);</span><span class="w"></span> <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span><span class="w"> </span><span class="n">out</span><span class="p">(</span><span class="n">nelem</span><span class="p">);</span><span class="w"></span> <span class="n">T</span><span class="w"> </span><span class="o">*</span><span class="n">inptr</span><span class="o">=</span><span class="n">in</span><span class="p">.</span><span class="n">data</span><span class="p">(),</span><span class="w"> </span><span class="o">*</span><span class="n">outptr</span><span class="o">=</span><span class="n">out</span><span class="p">.</span><span class="n">data</span><span class="p">();</span><span class="w"></span> <span class="cp">#pragma acc data copyin(inptr[0:nelem]) copyout(outptr[0:nelem])</span> <span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="n">std</span><span class="o">::</span><span class="n">for_each</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">execution</span><span class="o">::</span><span class="n">par_unseq</span><span class="p">,</span><span class="w"> </span><span class="n">r</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span><span class="w"> </span><span class="n">r</span><span class="p">.</span><span class="n">end</span><span class="p">(),</span><span class="w"></span> <span class="w"> </span><span class="p">[</span><span class="o">&amp;</span><span class="p">](</span><span class="k">auto</span><span class="w"> </span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="n">out</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">in</span><span class="p">[</span><span class="n">i</span><span class="p">];</span><span class="w"></span> <span class="w"> </span><span class="p">});</span><span class="w"></span> <span class="p">}</span><span class="w"></span> </pre></div> </div> <p>The above example demonstrates the use of OpenACC data directives with a raw pointer to elements of <code class="docutils literal notranslate"><span class="pre">std::vector</span></code> which can improve memory performance for data in unified memory and the full deep copy of vector content using attach/detach is not required.</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="kt">int</span><span class="w"> </span><span class="n">n</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">get_n</span><span class="p">();</span><span class="w"></span> <span class="n">T</span><span class="o">*</span><span class="w"> </span><span class="n">in</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">T</span><span class="p">[</span><span class="n">nelem</span><span class="p">];</span><span class="w"></span> <span class="n">T</span><span class="o">*</span><span class="w"> </span><span class="n">out</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">T</span><span class="p">[</span><span class="n">nelem</span><span class="p">];</span><span class="w"></span> <span class="cp">#pragma acc enter data copyin(n)</span> <span class="cp">#pragma acc host_data use_device(n)</span> <span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="n">std</span><span class="o">::</span><span class="n">for_each</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">execution</span><span class="o">::</span><span class="n">par_unseq</span><span class="p">,</span><span class="w"> </span><span class="n">r</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span><span class="w"> </span><span class="n">r</span><span class="p">.</span><span class="n">end</span><span class="p">(),</span><span class="w"></span> <span class="w"> </span><span class="p">[</span><span class="o">&amp;</span><span class="p">,</span><span class="w"> </span><span class="n">in</span><span class="p">,</span><span class="w"> </span><span class="n">out</span><span class="p">](</span><span class="k">auto</span><span class="w"> </span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="n">out</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">in</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">n</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="p">});</span><span class="w"></span> <span class="p">}</span><span class="w"></span> <span class="cp">#pragma acc enter data delete(n)</span> </pre></div> </div> <p>In the above example, <code class="docutils literal notranslate"><span class="pre">in</span></code> and <code class="docutils literal notranslate"><span class="pre">out</span></code> are dynamically allocated and managed by CUDA device driver with Managed Memory Mode, <code class="docutils literal notranslate"><span class="pre">n</span></code> is on the stack and therefore managed explicitly via OpenACC directives.</p> <span class="target" id="stdpar-cpp-interop-openacc-routine"></span></section> <section id="external-device-function-annotations"> <h4><span class="section-number">8.2.8.2. </span>External Device Function Annotations<a class="headerlink" href="#external-device-function-annotations" title="Permalink to this headline"></a></h4> <p>Using OpenACC routine directive annotations allows calling external device functions.</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="c1">// In file1.cpp</span> <span class="k">extern</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="nf">foo</span><span class="p">();</span><span class="w"></span> <span class="kt">void</span><span class="w"> </span><span class="nf">bar</span><span class="p">()</span><span class="w"></span> <span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="n">std</span><span class="o">::</span><span class="n">for_each</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">execution</span><span class="o">::</span><span class="n">par_unseq</span><span class="p">,</span><span class="w"> </span><span class="n">r</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span><span class="w"> </span><span class="n">r</span><span class="p">.</span><span class="n">end</span><span class="p">(),</span><span class="w"></span> <span class="w"> </span><span class="p">[</span><span class="o">=</span><span class="p">](</span><span class="k">auto</span><span class="w"> </span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="n">ou</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">foo</span><span class="p">();</span><span class="w"></span> <span class="w"> </span><span class="p">});</span><span class="w"></span> <span class="p">}</span><span class="w"></span> <span class="c1">// In file2.cpp</span> <span class="cp">#pragma acc routine</span> <span class="kt">int</span><span class="w"> </span><span class="nf">foo</span><span class="p">(){</span><span class="w"></span> <span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="mi">4</span><span class="p">;</span><span class="w"></span> <span class="p">}</span><span class="w"></span> </pre></div> </div> <p>The above code can be compiled/linked as follows:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>nvc++ -stdpar file1.cpp nvc++ -acc file2.cpp nvc++ -stdpar -acc file1.o file2.o </pre></div> </div> </section> </section> <section id="getting-started-with-parallel-algorithms-for-gpus"> <h3><span class="section-number">8.2.9. </span>Getting Started with Parallel Algorithms for GPUs<a class="headerlink" href="#getting-started-with-parallel-algorithms-for-gpus" title="Permalink to this headline"></a></h3> <p>To get started, download and install the <a class="reference external" href="https://developer.nvidia.com/hpc-sdk">NVIDIA HPC SDK</a> on your x86-64 or Arm CPU-based system running a supported version of Linux.</p> <p>The NVIDIA HPC SDK is freely downloadable and includes a perpetual use license for all NVIDIA Registered Developers, including access to future release updates as they are issued. After you have the NVIDIA HPC SDK installed on your system, the nvc++ compiler is available under the <code class="docutils literal notranslate"><span class="pre">/opt/nvidia/hpc_sdk</span></code> directory structure.</p> <ul class="simple"> <li><p>To use the compilers including nvc++ on a Linux/x86-64 system, add the directory <code class="docutils literal notranslate"><span class="pre">/opt/nvidia/hpc_sdk/Linux_x86_64/25.1/compilers/bin</span></code> to your path.</p></li> <li><p>On an Arm CPU-based system, replace <code class="docutils literal notranslate"><span class="pre">Linux_x86_64</span></code> with <code class="docutils literal notranslate"><span class="pre">Linux_aarch64</span></code>.</p></li> </ul> <section id="supported-nvidia-gpus"> <h4><span class="section-number">8.2.9.1. </span>Supported NVIDIA GPUs<a class="headerlink" href="#supported-nvidia-gpus" title="Permalink to this headline"></a></h4> <p>The NVC++ compiler can automatically offload C++ Parallel Algorithms to NVIDIA GPUs based on the Volta architecture or newer. These architectures include features – such as independent thread scheduling and hardware optimizations for CUDA Unified Memory – that were specifically designed to support high-performance, general-purpose parallel programming models like the C++ Parallel Algorithms.</p> <p>The NVC++ compiler provides limited support for C++ Parallel Algorithms on the Pascal architecture, which does not have the <a class="reference external" href="https://devblogs.nvidia.com/inside-volta/">independent thread scheduling</a> necessary to properly support the <code class="docutils literal notranslate"><span class="pre">std::execution::par</span></code> policy. When compiling for the Pascal architecture (-gpu=cc60), NVC++ compiles algorithms with the <code class="docutils literal notranslate"><span class="pre">std::execution::par</span></code> policy for serial execution on the CPU. Only algorithms with the <code class="docutils literal notranslate"><span class="pre">std::execution::par_unseq</span></code> policy will be scheduled to run on Pascal GPUs.</p> </section> <section id="supported-cuda-versions"> <h4><span class="section-number">8.2.9.2. </span>Supported CUDA Versions<a class="headerlink" href="#supported-cuda-versions" title="Permalink to this headline"></a></h4> <p>The NVC++ compiler is built on CUDA libraries and technologies and uses CUDA to accelerate C++ Parallel Algorithms on NVIDIA GPUs. A GPU-accelerated system on which NVC++-compiled applications are to be run must have a CUDA 11.2 or newer device driver installed.</p> <p>The NVIDIA HPC SDK compilers ship with an integrated CUDA toolchain, header files, and libraries to use during compilation, so it is not necessary to have a CUDA Toolkit installed on the system.</p> <p>When <code class="docutils literal notranslate"><span class="pre">-stdpar</span></code> is specified, NVC++ compiles using the CUDA toolchain version that best matches the CUDA driver installed on the system on which compilation is performed. To compile using a different version of the CUDA toolchain, use the <code class="docutils literal notranslate"><span class="pre">-gpu=cudaX.Y</span></code> option. For example, use the <code class="docutils literal notranslate"><span class="pre">-gpu=cuda11.8</span></code> option to specify that your program should be compiled for a CUDA 11.8 system using the CUDA 11.8 toolchain.</p> </section> </section> </section> <section id="stdpar-fortran"> <h2><span class="section-number">8.3. </span>Stdpar Fortran<a class="headerlink" href="#stdpar-fortran" title="Permalink to this headline"></a></h2> <p>Fortran 2008 introduced the <code class="docutils literal notranslate"><span class="pre">do</span> <span class="pre">concurrent</span></code> (DC) loop construct signaling that loop iterations have no interdependencies. With <code class="docutils literal notranslate"><span class="pre">-stdpar</span></code> such loop iterations will be executed in parallel on the GPU when <code class="docutils literal notranslate"><span class="pre">-stdpar</span></code> (or <code class="docutils literal notranslate"><span class="pre">-stdpar=gpu</span></code>) is passed to <code class="docutils literal notranslate"><span class="pre">nvfortran</span></code> or using CPU threads when <code class="docutils literal notranslate"><span class="pre">-stdpar=multicore</span></code> is passed to <code class="docutils literal notranslate"><span class="pre">nvfortran</span></code>. More details can be found in the following blog post on the NVIDIA website: <a class="reference external" href="https://developer.nvidia.com/blog/accelerating-fortran-do-concurrent-with-gpus-and-the-nvidia-hpc-sdk">Accelerating Fortran DO CONCURRENT with GPUs and the NVIDIA HPC SDK</a>.</p> <section id="calling-routines-in-do-concurrent-on-the-gpu"> <h3><span class="section-number">8.3.1. </span>Calling Routines in DO CONCURRENT on the GPU<a class="headerlink" href="#calling-routines-in-do-concurrent-on-the-gpu" title="Permalink to this headline"></a></h3> <p>When compiling for the GPU, calling routines in the body of <code class="docutils literal notranslate"><span class="pre">do</span> <span class="pre">concurrent</span></code> loop can be constrained. PURE routines can generally be called inside the <code class="docutils literal notranslate"><span class="pre">do</span> <span class="pre">concurrent</span></code> loop body. The compiler detects that such routines are to be compiled for the GPU target. External routines, however, can’t be called from within the DC loop unless they are explicitly annotated with the OpenACC routine directive (refer to <cite>Interoperability with OpenACC &lt;stdpar-fortran-interop-openacc&gt;</cite>) or CUDA device attribute (refer to <a class="reference internal" href="#stdpar-fortran-interop-cuf"><span class="std std-ref">Interoperability with CUDA Fortran</span></a>).</p> <p>The following example will compile successfully.</p> <div class="highlight-fortran notranslate"><div class="highlight"><pre><span></span><span class="k">module </span><span class="n">m</span><span class="w"></span> <span class="k">contains</span> <span class="k">pure subroutine </span><span class="n">foo</span><span class="p">()</span><span class="w"></span> <span class="k">return</span> <span class="k">end subroutine</span> <span class="k">end module </span><span class="n">m</span><span class="w"></span> <span class="k">program </span><span class="n">dc</span><span class="w"></span> <span class="k">use </span><span class="n">m</span><span class="w"></span> <span class="k">implicit none</span> <span class="kt">integer</span><span class="w"> </span><span class="kd">::</span><span class="w"> </span><span class="n">i</span><span class="w"></span> <span class="k">do</span><span class="w"> </span><span class="k">concurrent</span><span class="w"> </span><span class="p">(</span><span class="n">i</span><span class="o">=</span><span class="mi">1</span><span class="p">:</span><span class="mi">10</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="k">call </span><span class="n">foo</span><span class="p">()</span><span class="w"></span> <span class="k">enddo</span> <span class="k">end program</span><span class="w"></span> </pre></div> </div> <p>The following example, however, doesn’t compile unless <code class="docutils literal notranslate"><span class="pre">foo</span></code> is either</p> <ul class="simple"> <li><p>annotated with <code class="docutils literal notranslate"><span class="pre">!$acc</span> <span class="pre">routine</span></code>,</p></li> <li><p>or attributed with <code class="docutils literal notranslate"><span class="pre">attributes(device)</span></code> and compiled as Stdpar and CUDA Fortran.</p></li> </ul> <div class="highlight-fortran notranslate"><div class="highlight"><pre><span></span><span class="k">program </span><span class="n">dc</span><span class="w"></span> <span class="k">implicit none</span> <span class="k">interface</span> <span class="k"> pure subroutine </span><span class="n">foo</span><span class="p">()</span><span class="w"></span> <span class="w"> </span><span class="k">end subroutine </span><span class="n">foo</span><span class="w"></span> <span class="k">end interface</span> <span class="kt">integer</span><span class="w"> </span><span class="kd">::</span><span class="w"> </span><span class="n">i</span><span class="w"></span> <span class="k">do</span><span class="w"> </span><span class="k">concurrent</span><span class="w"> </span><span class="p">(</span><span class="n">i</span><span class="o">=</span><span class="mi">1</span><span class="p">:</span><span class="mi">10</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="k">call </span><span class="n">foo</span><span class="p">()</span><span class="w"></span> <span class="k">enddo</span> <span class="k">end program</span><span class="w"></span> </pre></div> </div> </section> <section id="gpu-data-management"> <h3><span class="section-number">8.3.2. </span>GPU Data Management<a class="headerlink" href="#gpu-data-management" title="Permalink to this headline"></a></h3> <p>If <code class="docutils literal notranslate"><span class="pre">-gpu=mem:managed</span></code> is enabled by default or is explicitly passed on the command line, some data accesses in <code class="docutils literal notranslate"><span class="pre">do</span> <span class="pre">concurrent</span></code> loops are invalid. For example, accessing global variables in the routines called from the <code class="docutils literal notranslate"><span class="pre">do</span> <span class="pre">concurrent</span></code> loop does not perform expected value updates in the CPU code.</p> <p>Additionally, there are rare instances where the compiler cannot accurately determine variable sizes for implicit data movements between CPU and GPU. As demonstrated in the following example, <code class="docutils literal notranslate"><span class="pre">a</span></code> is an assumed-size array, and its access region inside the DC construct cannot be determined at compile time because the element index positions are taken from another array <code class="docutils literal notranslate"><span class="pre">b</span></code> initialized outside of the routine. Such code does not update <code class="docutils literal notranslate"><span class="pre">a</span></code> as expected and may result in a memory violation and undefined behavior.</p> <div class="highlight-fortran notranslate"><div class="highlight"><pre><span></span><span class="k">subroutine </span><span class="n">r</span><span class="p">(</span><span class="n">a</span><span class="p">,</span><span class="w"> </span><span class="n">b</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="kt">integer</span><span class="w"> </span><span class="kd">::</span><span class="w"> </span><span class="n">a</span><span class="p">(</span><span class="o">*</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="kt">integer</span><span class="w"> </span><span class="kd">::</span><span class="w"> </span><span class="n">b</span><span class="p">(:)</span><span class="w"></span> <span class="w"> </span><span class="k">do</span><span class="w"> </span><span class="k">concurrent</span><span class="w"> </span><span class="p">(</span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="n">size</span><span class="p">(</span><span class="n">b</span><span class="p">))</span><span class="w"></span> <span class="w"> </span><span class="n">a</span><span class="p">(</span><span class="n">b</span><span class="p">(</span><span class="n">i</span><span class="p">))</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">i</span><span class="w"></span> <span class="w"> </span><span class="k">enddo</span> <span class="k">end subroutine</span><span class="w"></span> </pre></div> </div> <p>There are no limitations on the variable accessed in <code class="docutils literal notranslate"><span class="pre">do</span> <span class="pre">concurrent</span></code> loops described above when the code is compiled with <code class="docutils literal notranslate"><span class="pre">-gpu=mem:unified</span></code>, whether this option is enabled by default or explicitly via an option on the command line.</p> </section> <section id="id3"> <h3><span class="section-number">8.3.3. </span>Interoperability with OpenACC<a class="headerlink" href="#id3" title="Permalink to this headline"></a></h3> <p>OpenACC features can be used when compiling Stdpar code for GPUs. To activate OpenACC directives recognition with Stdpar code add <code class="docutils literal notranslate"><span class="pre">-acc</span></code> command line flag to <code class="docutils literal notranslate"><span class="pre">nvfortran</span></code>.</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>nvfortran -stdpar -acc example.f90 </pre></div> </div> <p>OpenACC functionality and interoperability with DO-CONCURRENT loop is detailed in the OpenACC specification and the NVIDIA HPC compiler specific differences are detailed in <a class="reference internal" href="#acc-use"><span class="std std-ref">Using OpenACC</span></a> of this guide.</p> <p>Using OpenACC features can enhance functionality of DC-loop for example with the following:</p> <ul class="simple"> <li><p>Explicit data management to improve performance of CPU-GPU implicit data movements or even leverage separate memory compiling on the GPU when compiling with <code class="docutils literal notranslate"><span class="pre">-gpu=mem:separate</span></code> passed in.</p></li> <li><p>Tuning DC-loop execution on the GPU e.g. GPU kernels launch configuration.</p></li> <li><p>Executing DC-loops asynchronously.</p></li> <li><p>Calling external routines from within DC-loops.</p></li> <li><p>Atomic operations in DC-loops.</p></li> </ul> <p><strong>Examples</strong></p> <p>Some examples of using OpenACC directives with DC-loops are provided below.</p> <p>The following example demonstrates how the data accessed inside the DC-loop are fully managed in the OpenACC data construct.</p> <div class="highlight-fortran notranslate"><div class="highlight"><pre><span></span><span class="c">!$acc data copyin(b) copyout(a)</span> <span class="k">do</span><span class="w"> </span><span class="k">concurrent</span><span class="w"> </span><span class="p">(</span><span class="n">j</span><span class="o">=</span><span class="mi">1</span><span class="p">:</span><span class="n">N</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="k">do </span><span class="n">i</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span><span class="n">K</span><span class="w"></span> <span class="w"> </span><span class="n">a</span><span class="p">(</span><span class="n">j</span><span class="p">,</span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">b</span><span class="p">(</span><span class="n">j</span><span class="p">,</span><span class="n">i</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="k">end do</span> <span class="k">end do</span><span class="w"></span> <span class="c">!$acc end data</span> </pre></div> </div> <p>While in the above example the data construct is used for GPU data management, the same effect can be achieved with the use of data clauses on the compute construct enclosing DC-loop.</p> <p>The following example shows how the scheduling of DC loop on the GPU is controlled through the clauses on the compute construct.</p> <div class="highlight-fortran notranslate"><div class="highlight"><pre><span></span><span class="c">!$acc parallel loop num_gangs(50000) vector_length(32)</span> <span class="k">do</span><span class="w"> </span><span class="k">concurrent</span><span class="w"> </span><span class="p">(</span><span class="n">i</span><span class="o">=</span><span class="mi">1</span><span class="p">:</span><span class="n">K</span><span class="p">,</span><span class="n">j</span><span class="o">=</span><span class="mi">1</span><span class="p">:</span><span class="n">N</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="n">a</span><span class="p">(</span><span class="n">j</span><span class="p">,</span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="kt">real</span><span class="p">(</span><span class="n">j</span><span class="p">)</span><span class="w"></span> <span class="k">end do</span><span class="w"></span> </pre></div> </div> <p>Use of OpenACC async clause on the compute constructs can be utilised to perform computations in DC-loop asynchronously.</p> <div class="highlight-fortran notranslate"><div class="highlight"><pre><span></span><span class="c">!$acc parallel loop async</span> <span class="k">do</span><span class="w"> </span><span class="k">concurrent</span><span class="w"> </span><span class="p">(</span><span class="n">j</span><span class="o">=</span><span class="mi">1</span><span class="p">:</span><span class="n">N</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="n">a</span><span class="p">(</span><span class="n">j</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">j</span><span class="w"></span> <span class="k">end do</span> <span class="n">b</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">foo</span><span class="p">()</span><span class="w"></span> <span class="cp">#pragma acc wait</span> <span class="n">c</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">sum</span><span class="p">(</span><span class="n">a</span><span class="p">)</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">b</span><span class="w"></span> </pre></div> </div> <p>In the previous example, array <code class="docutils literal notranslate"><span class="pre">a</span></code> is filled in with values asynchronously in DC-loop.</p> <span class="target" id="stdpar-fortran-interop-cuf"></span></section> <section id="interoperability-with-cuda-fortran"> <h3><span class="section-number">8.3.4. </span>Interoperability with CUDA Fortran<a class="headerlink" href="#interoperability-with-cuda-fortran" title="Permalink to this headline"></a></h3> <p>CUDA Fortran features can also be used when compiling Stdpar code for GPUs. To recognize CUDA Fortran features in your source code, compile with the <code class="docutils literal notranslate"><span class="pre">-cuda</span></code> command line flag using <code class="docutils literal notranslate"><span class="pre">nvfortran</span></code>.</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>nvfortran -stdpar -cuda example.f90 </pre></div> </div> <p>Using CUDA Fortran extensions can enhance the functionality of a do concurrent (DC) loop and Stdpar program, for several cases:</p> <ul class="simple"> <li><p>Explicit data locality, accessing CUDA Fortran attributed arrays or other data with the device, managed, unified, or constant attributes from within DC-loops.</p></li> <li><p>Tuning DC-loop execution on the GPU e.g. controlling the GPU kernels launch configuration.</p></li> <li><p>Executing DC-loops asynchronously using a specific CUDA stream.</p></li> <li><p>Calling external, user-defined CUDA device routines from within DC-loops.</p></li> <li><p>Using CUDA Atomic operations in DC-loops, or other CUDA-specific device-side runtime library calls.</p></li> <li><p>Inserting CUDA Runtime API calls for memory tuning hints outside of DC-loops.</p></li> </ul> <p><strong>Examples</strong></p> <p>Some examples of using CUDA Fortran features with DC-loops are provided below. The following example demonstrates how a DC-loop can access CUDA Fortran device data, run on a specific CUDA stream, call the CUDA Runtime API for creating a stream, and hide non-standard features behind the CUF sentinel for code portability.</p> <div class="highlight-fortran notranslate"><div class="highlight"><pre><span></span><span class="c">!@cuf use cudafor</span> <span class="c">!@cuf integer(kind=cuda_stream_kind) :: istrm</span> <span class="w"> </span><span class="kt">real</span><span class="p">,</span><span class="w"> </span><span class="k">allocatable</span><span class="w"> </span><span class="kd">::</span><span class="w"> </span><span class="n">a</span><span class="p">(:,:),</span><span class="w"> </span><span class="n">b</span><span class="p">(:,:)</span><span class="w"></span> <span class="c">!@cuf attributes(device) :: a ! A is device array only, not unified/managed</span> <span class="w"> </span><span class="p">.</span><span class="w"> </span><span class="p">.</span><span class="w"> </span><span class="p">.</span><span class="w"></span> <span class="c">!@cuf istat = cudaStreamCreate(istrm)</span> <span class="w"> </span><span class="p">.</span><span class="w"> </span><span class="p">.</span><span class="w"> </span><span class="p">.</span><span class="w"></span> <span class="w"> </span><span class="n">a</span><span class="p">(:,:)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mf">0.0</span><span class="w"></span> <span class="w"> </span><span class="p">.</span><span class="w"> </span><span class="p">.</span><span class="w"> </span><span class="p">.</span><span class="w"></span> <span class="c">!$cuf kernel do(1) &lt;&lt;&lt; *, *, stream=istrm&gt;&gt;&gt;</span> <span class="w"> </span><span class="k">do</span><span class="w"> </span><span class="k">concurrent</span><span class="w"> </span><span class="p">(</span><span class="n">j</span><span class="o">=</span><span class="mi">1</span><span class="p">:</span><span class="n">N</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="k">do </span><span class="n">i</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span><span class="n">K</span><span class="w"></span> <span class="w"> </span><span class="n">a</span><span class="p">(</span><span class="n">j</span><span class="p">,</span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">a</span><span class="p">(</span><span class="n">j</span><span class="p">,</span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mf">2.0</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">b</span><span class="p">(</span><span class="n">j</span><span class="p">,</span><span class="n">i</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="k">end do</span> <span class="k"> end do</span><span class="w"></span> </pre></div> </div> <p>This program demonstrates how to call low-level CUDA device functions from within a DC-loop. The function can be written in either CUDA Fortran or CUDA C++, depending on the interface. The CUDA C function must be compiled for relocatable device code. This can be used for accessing features in CUDA and NVIDIA GPUs not readily available in directive-based models or standard languages.</p> <div class="highlight-fortran notranslate"><div class="highlight"><pre><span></span><span class="k">module </span><span class="n">mcuda</span><span class="w"></span> <span class="w"> </span><span class="k">contains</span> <span class="k"> </span><span class="n">attributes</span><span class="p">(</span><span class="n">host</span><span class="p">,</span><span class="n">device</span><span class="p">)</span><span class="w"> </span><span class="k">pure </span><span class="kt">integer </span><span class="k">function </span><span class="n">std_dbg</span><span class="p">(</span><span class="n">itype</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="kt">integer</span><span class="p">,</span><span class="w"> </span><span class="k">value</span><span class="w"> </span><span class="kd">::</span><span class="w"> </span><span class="n">itype</span><span class="w"></span> <span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">itype</span><span class="p">.</span><span class="n">eq</span><span class="p">.</span><span class="mi">1</span><span class="p">)</span><span class="w"> </span><span class="k">then</span> <span class="k"> </span><span class="n">std_dbg</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">threadIdx</span><span class="p">%</span><span class="n">x</span><span class="w"></span> <span class="w"> </span><span class="k">else if</span><span class="w"> </span><span class="p">(</span><span class="n">itype</span><span class="p">.</span><span class="n">eq</span><span class="p">.</span><span class="mi">2</span><span class="p">)</span><span class="w"> </span><span class="k">then</span> <span class="k"> </span><span class="n">std_dbg</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">blockIdx</span><span class="p">%</span><span class="n">x</span><span class="w"></span> <span class="w"> </span><span class="k">else</span> <span class="k"> </span><span class="n">std_dbg</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="n">blockIdx</span><span class="p">%</span><span class="n">x</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span><span class="o">*</span><span class="n">blockDim</span><span class="p">%</span><span class="n">x</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">threadIdx</span><span class="p">%</span><span class="n">x</span><span class="w"></span> <span class="w"> </span><span class="k">end if</span> <span class="k"> end function</span> <span class="k">end module</span> <span class="k">program </span><span class="n">test</span><span class="w"></span> <span class="k">use </span><span class="n">mcuda</span><span class="w"></span> <span class="kt">integer</span><span class="p">,</span><span class="w"> </span><span class="k">parameter</span><span class="w"> </span><span class="kd">::</span><span class="w"> </span><span class="n">N</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">2000</span><span class="w"></span> <span class="kt">integer</span><span class="p">,</span><span class="w"> </span><span class="k">allocatable</span><span class="w"> </span><span class="kd">::</span><span class="w"> </span><span class="n">a</span><span class="p">(:),</span><span class="w"> </span><span class="n">b</span><span class="p">(:),</span><span class="w"> </span><span class="n">c</span><span class="p">(:)</span><span class="w"></span> <span class="k">allocate</span><span class="p">(</span><span class="n">a</span><span class="p">(</span><span class="n">N</span><span class="p">),</span><span class="n">b</span><span class="p">(</span><span class="n">N</span><span class="p">),</span><span class="n">c</span><span class="p">(</span><span class="n">N</span><span class="p">))</span><span class="w"></span> <span class="k">do</span><span class="w"> </span><span class="k">concurrent</span><span class="w"> </span><span class="p">(</span><span class="n">j</span><span class="o">=</span><span class="mi">1</span><span class="p">:</span><span class="n">N</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="n">a</span><span class="p">(</span><span class="n">j</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">std_dbg</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="n">b</span><span class="p">(</span><span class="n">j</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">std_dbg</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="n">c</span><span class="p">(</span><span class="n">j</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">std_dbg</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span><span class="w"></span> <span class="k">end do</span> <span class="k">print</span><span class="w"> </span><span class="o">*</span><span class="p">,</span><span class="n">a</span><span class="p">(</span><span class="mi">1</span><span class="p">),</span><span class="n">a</span><span class="p">(</span><span class="n">N</span><span class="o">/</span><span class="mi">2</span><span class="p">),</span><span class="n">a</span><span class="p">(</span><span class="n">N</span><span class="p">)</span><span class="w"></span> <span class="k">print</span><span class="w"> </span><span class="o">*</span><span class="p">,</span><span class="n">b</span><span class="p">(</span><span class="mi">1</span><span class="p">),</span><span class="n">b</span><span class="p">(</span><span class="n">N</span><span class="o">/</span><span class="mi">2</span><span class="p">),</span><span class="n">b</span><span class="p">(</span><span class="n">N</span><span class="p">)</span><span class="w"></span> <span class="k">print</span><span class="w"> </span><span class="o">*</span><span class="p">,</span><span class="n">c</span><span class="p">(</span><span class="mi">1</span><span class="p">),</span><span class="n">c</span><span class="p">(</span><span class="n">N</span><span class="o">/</span><span class="mi">2</span><span class="p">),</span><span class="n">c</span><span class="p">(</span><span class="n">N</span><span class="p">)</span><span class="w"></span> <span class="k">end</span><span class="w"></span> </pre></div> </div> <p>Many functions from the CUDA Fortran <code class="docutils literal notranslate"><span class="pre">cudadevice</span></code> module are available within do concurrent loops, not just atomics. This code snippet shows two uses:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>real :: tmp(4), x, y ... block; use cudadevice do concurrent (i=1:K,j=1:N) x = real(j) + a(i,j) y = atomicAdd(b(1,j), x) end do do concurrent (j=1:N) x = real(j) tmp(1:4) = __ldca(a(1:4,j)) tmp(1:4) = tmp(1:4) + x call __stwt(b(1:4,j), tmp) end do end block </pre></div> </div> </section> </section> </section> <section id="pcast"> <span id="id4"></span><h1><span class="section-number">9. </span>PCAST<a class="headerlink" href="#pcast" title="Permalink to this headline"></a></h1> <p>Parallel Compiler Assisted Software Testing (PCAST) is a set of API calls and compiler directives useful in testing program correctness. Numerical results produced by a program can diverge when parts of the program are mapped onto a GPU, when new or additional compiler options are used, or when changes are made to the program itself. PCAST can help you determine where these divergences begin, and pinpoint the changes that cause them. It is useful in other situations as well, including when using new libraries, determining whether parallel execution is safe, or porting programs from one ISA or type of processor to another.</p> <section id="id5"> <h2><span class="section-number">9.1. </span>Overview<a class="headerlink" href="#id5" title="Permalink to this headline"></a></h2> <p>PCAST Comparisons can be performed in two ways. The first saves the initial run’s data into a file through the <code class="docutils literal notranslate"><span class="pre">pcast_compare</span></code> call or directive. Add the calls or directives to your application where you want intermediate results to be compared. Then, execute the program to save the “golden” results where the values are known to be correct. During subsequent runs of the program, the same pcast_compare calls or directives will compare the computed intermediate results to the saved “golden” results and report the differences.</p> <p>The second approach works in conjunction with the NVIDIA OpenACC implementation to compare GPU computation against the same program running on a CPU. In this case, all compute constructs are performed redundantly, both on the CPU and GPU. GPU results are compared against the CPU results, and differences reported. This is essentially like the first case where the CPU-calculated values are treated as the “golden” results. GPU to CPU comparisons can be done implicitly at the end of data regions with the <code class="docutils literal notranslate"><span class="pre">autocompare</span></code> flag or explicitly after kernels with the <code class="docutils literal notranslate"><span class="pre">acc_compare</span></code> call or directive.</p> <p>With the autocompare flag, OpenACC regions will run redundantly on the CPU and GPU. On an OpenACC region exit where data is to be downloaded from device to host, PCAST will compare the values calculated on the CPU with those calculated in the GPU. Comparisons done with <code class="docutils literal notranslate"><span class="pre">autocompare</span></code> or <code class="docutils literal notranslate"><span class="pre">acc_compare</span></code> are handled in memory and do not write results to an intermediate file.</p> <p>The following table outlines the supported data types that can be used with PCAST. Short, integer, long, and half precision data types are not supported with <code class="docutils literal notranslate"><span class="pre">ABS</span></code>, <code class="docutils literal notranslate"><span class="pre">REL</span></code>, <code class="docutils literal notranslate"><span class="pre">ULP</span></code>, or <code class="docutils literal notranslate"><span class="pre">IEEE</span></code> options; only a bit-for-bit comparison is supported.</p> <p>For floating-point types, PCAST can calculate absolute, relative, and unit-last-place differences. Absolute differences measures only the absolute value of the difference (subtraction) between two values, i.e. <em>abs(A-B)</em>. Relative differences are calculated as a ratio between the difference of values, <em>A-B</em>, and the previous value <em>A</em>; <em>abs((A-B)/A)</em>. Unit-least precision (Unit-last place) is a measure of the smallest distance between two values <em>A</em> and <em>B</em>. With the <code class="docutils literal notranslate"><span class="pre">ULP</span></code> option set, PCAST will report if the calculated ULP between two numbers is greater than some threshold.</p> <table class="table-no-stripes docutils align-default" id="pcast-overview-pcast-supported-types-table"> <caption><span class="caption-text">Table 23. Supported Types for Tolerance Measurements</span><a class="headerlink" href="#pcast-overview-pcast-supported-types-table" title="Permalink to this table"></a></caption> <colgroup> <col style="width: 30%" /> <col style="width: 46%" /> <col style="width: 6%" /> <col style="width: 6%" /> <col style="width: 6%" /> <col style="width: 7%" /> </colgroup> <thead> <tr class="row-odd"><th class="head"><p>C/C++ Type</p></th> <th class="head"><p>Fortran Type</p></th> <th class="head"><p>ABS</p></th> <th class="head"><p>REL</p></th> <th class="head"><p>ULP</p></th> <th class="head"><p>IEEE</p></th> </tr> </thead> <tbody> <tr class="row-even"><td><p>float</p></td> <td><p>real, real(4)</p></td> <td><p>Yes</p></td> <td><p>Yes</p></td> <td><p>Yes</p></td> <td><p>Yes</p></td> </tr> <tr class="row-odd"><td><p>double</p></td> <td><p>double precision, real(8)</p></td> <td><p>Yes</p></td> <td><p>Yes</p></td> <td><p>Yes</p></td> <td><p>Yes</p></td> </tr> <tr class="row-even"><td><p>float _Complex</p></td> <td><p>complex, complex(4)</p></td> <td><p>Yes</p></td> <td><p>Yes</p></td> <td><p>Yes</p></td> <td><p>Yes</p></td> </tr> <tr class="row-odd"><td><p>double _Complex</p></td> <td><p>complex(8)</p></td> <td><p>Yes</p></td> <td><p>Yes</p></td> <td><p>Yes</p></td> <td><p>Yes</p></td> </tr> <tr class="row-even"><td><p>-</p></td> <td><p>real(2)</p></td> <td><p>No</p></td> <td><p>No</p></td> <td><p>No</p></td> <td><p>No</p></td> </tr> <tr class="row-odd"><td><p>(un)signed short</p></td> <td><p>integer(2)</p></td> <td><p>N/A</p></td> <td><p>N/A</p></td> <td><p>N/A</p></td> <td><p>N/A</p></td> </tr> <tr class="row-even"><td><p>(un)signed int</p></td> <td><p>integer, integer(4)</p></td> <td><p>N/A</p></td> <td><p>N/A</p></td> <td><p>N/A</p></td> <td><p>N/A</p></td> </tr> <tr class="row-odd"><td><p>(un)signed long</p></td> <td><p>integer(8)</p></td> <td><p>N/A</p></td> <td><p>N/A</p></td> <td><p>N/A</p></td> <td><p>N/A</p></td> </tr> </tbody> </table> </section> <section id="pcast-with-a-golden-file"> <h2><span class="section-number">9.2. </span>PCAST with a “Golden” File<a class="headerlink" href="#pcast-with-a-golden-file" title="Permalink to this headline"></a></h2> <p>The run-time call <code class="docutils literal notranslate"><span class="pre">pcast_compare</span></code> highlights differences between successive program runs. It has two modes of operation, depending on the presence of a data file named <em>pcast_compare.dat</em> by default. If the file does not exist, <code class="docutils literal notranslate"><span class="pre">pcast_compare</span></code> assumes this is the first “golden” run. It will create the file and fill it with the computed data at each call to <code class="docutils literal notranslate"><span class="pre">pcast_compare</span></code>. If the file exists, <code class="docutils literal notranslate"><span class="pre">pcast_compare</span></code> assumes it is a test run. It will read the file and compare the computed data with the saved data from the file. The default behavior is to consider the first 50 differences to be a reportable error, no matter how small.</p> <p>By default, the <code class="docutils literal notranslate"><span class="pre">pcast_compare.dat</span></code> file is in the same directory as the executable. The behavior of <code class="docutils literal notranslate"><span class="pre">pcast_compare</span></code>, and other comparison parameters, can be changed at runtime with the PCAST_COMPARE environment variable discussed in the <a class="reference internal" href="#pcast-env-vars"><span class="std std-ref">Environment Variables</span></a> section.</p> <p>The signature of <code class="docutils literal notranslate"><span class="pre">pcast_compare</span></code> for C++ and C is:</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="kt">void</span><span class="w"> </span><span class="nf">pcast_compare</span><span class="p">(</span><span class="kt">void</span><span class="o">*</span><span class="p">,</span><span class="w"> </span><span class="kt">char</span><span class="o">*</span><span class="p">,</span><span class="w"> </span><span class="kt">size_t</span><span class="p">,</span><span class="w"> </span><span class="kt">char</span><span class="o">*</span><span class="p">,</span><span class="w"> </span><span class="kt">char</span><span class="o">*</span><span class="p">,</span><span class="w"> </span><span class="kt">char</span><span class="o">*</span><span class="p">,</span><span class="w"> </span><span class="kt">int</span><span class="p">);</span><span class="w"></span> </pre></div> </div> <p>The signature of <code class="docutils literal notranslate"><span class="pre">pcast_compare</span></code> for Fortran is:</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="n">subroutine</span><span class="w"> </span><span class="n">pcast_compare</span><span class="p">(</span><span class="n">a</span><span class="p">,</span><span class="w"> </span><span class="n">datatype</span><span class="p">,</span><span class="w"> </span><span class="n">len</span><span class="p">,</span><span class="w"> </span><span class="n">varname</span><span class="p">,</span><span class="w"> </span><span class="n">filename</span><span class="p">,</span><span class="w"> </span><span class="n">funcname</span><span class="p">,</span><span class="w"> </span><span class="n">lineno</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="n">type</span><span class="p">(</span><span class="o">*</span><span class="p">),</span><span class="w"> </span><span class="n">dimension</span><span class="p">(..)</span><span class="w"> </span><span class="o">::</span><span class="w"> </span><span class="n">a</span><span class="w"></span> <span class="w"> </span><span class="n">character</span><span class="p">(</span><span class="o">*</span><span class="p">)</span><span class="w"> </span><span class="o">::</span><span class="w"> </span><span class="n">datatype</span><span class="p">,</span><span class="w"> </span><span class="n">varname</span><span class="p">,</span><span class="w"> </span><span class="n">filename</span><span class="p">,</span><span class="w"> </span><span class="n">funcname</span><span class="w"></span> <span class="w"> </span><span class="n">integer</span><span class="p">(</span><span class="mi">8</span><span class="p">),</span><span class="n">value</span><span class="w"> </span><span class="o">::</span><span class="w"> </span><span class="n">len</span><span class="w"></span> <span class="w"> </span><span class="n">integer</span><span class="p">(</span><span class="mi">4</span><span class="p">),</span><span class="n">value</span><span class="w"> </span><span class="o">::</span><span class="w"> </span><span class="n">lineno</span><span class="w"></span> </pre></div> </div> <p>The call takes seven arguments:</p> <ol class="arabic simple"> <li><p>The address of the data to be saved or compared.</p></li> <li><p>A string containing the data type.</p></li> <li><p>The number of elements to compare.</p></li> <li><p>A string treated as the variable name.</p></li> <li><p>A string treated as the source file name.</p></li> <li><p>A string treated as the function name.</p></li> <li><p>An integer treated as a line number.</p></li> </ol> <p>For example, the <code class="docutils literal notranslate"><span class="pre">pcast_compare</span></code> runtime call can be invoked like the following:</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="n">pcast_compare</span><span class="p">(</span><span class="n">a</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;float&quot;</span><span class="p">,</span><span class="w"> </span><span class="n">N</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;a&quot;</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;pcast_compare03.c&quot;</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;main&quot;</span><span class="p">,</span><span class="w"> </span><span class="mi">1</span><span class="p">);</span><span class="w"></span> </pre></div> </div> <div class="highlight-fortran notranslate"><div class="highlight"><pre><span></span><span class="k">call </span><span class="n">pcast_compare</span><span class="p">(</span><span class="n">a</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;real&#39;</span><span class="p">,</span><span class="w"> </span><span class="n">n</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;a&#39;</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;pcast_compare1.f90&#39;</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;program&#39;</span><span class="p">,</span><span class="w"> </span><span class="mi">9</span><span class="p">)</span><span class="w"></span> </pre></div> </div> <p>The caller should give meaningful names to the last four arguments. They can be anything, since they only serve to annotate the report. It is imperative that the identifiers are not modified between comparisons; comparisons must be called in the same order for each program run. If, for example, you are calling <code class="docutils literal notranslate"><span class="pre">pcast_compare</span></code> inside a loop, it is reasonable to set the last argument to be the loop index.</p> <p>There also exists a directive form of the <code class="docutils literal notranslate"><span class="pre">pcast_compare</span></code>, which is functionally the same as the runtime call. It can be used at any point in the program to compare the current value of data to that recorded in the golden file, same as the runtime call. There are two benefits to using the directive over the API call:</p> <ol class="arabic"> <li><p>The directive syntax is much simpler than the API syntax. Most of what the compare call needs to output data to the user can be gleaned by the compiler at compile-time (The type, variable name, file name, function name, and line number).</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="cp">#pragma nvidia compare(a[0:n])</span> </pre></div> </div> <p>as opposed to:</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="n">pcast_compare</span><span class="p">(</span><span class="n">a</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;float&quot;</span><span class="p">,</span><span class="w"> </span><span class="n">N</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;a&quot;</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;pcast_compare03.c&quot;</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;main&quot;</span><span class="p">,</span><span class="w"> </span><span class="mi">1</span><span class="p">);</span><span class="w"></span> </pre></div> </div> </li> <li><p>The directive is only enabled when the -Mpcast flag is set, so the source need not be changed when testing is complete. Consider the following usage examples:</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="cp">#pragma nvidia compare(a[0:N]) </span><span class="c1">// C++ and C</span> <span class="o">!</span><span class="n">$nvf</span><span class="w"> </span><span class="n">compare</span><span class="p">(</span><span class="n">a</span><span class="p">(</span><span class="mi">1</span><span class="o">:</span><span class="n">N</span><span class="p">))</span><span class="w"> </span><span class="o">!</span><span class="w"> </span><span class="n">Fortran</span><span class="w"></span> </pre></div> </div> </li> </ol> <p>The directive interface is given below in C++ or C style, and in Fortran. Note that for Fortran, <code class="docutils literal notranslate"><span class="pre">var-list</span></code> is a variable name, a subarray specification, an array element, or a composite variable member.</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="cp">#pragma nvidia compare (var-list) </span><span class="c1">// C++ and C</span> <span class="o">!</span><span class="n">$nvf</span><span class="w"> </span><span class="n">compare</span><span class="w"> </span><span class="p">(</span><span class="n">var</span><span class="o">-</span><span class="n">list</span><span class="p">)</span><span class="w"> </span><span class="o">!</span><span class="w"> </span><span class="n">Fortran</span><span class="w"></span> </pre></div> </div> <p>Let’s look at an example of</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="cp">#include</span><span class="w"> </span><span class="cpf">&lt;stdlib.h&gt;</span><span class="cp"></span> <span class="cp">#include</span><span class="w"> </span><span class="cpf">&lt;openacc.h&gt;</span><span class="cp"></span> <span class="kt">int</span><span class="w"> </span><span class="nf">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">size</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">1000</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">i</span><span class="p">,</span><span class="w"> </span><span class="n">t</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="kt">float</span><span class="w"> </span><span class="o">*</span><span class="n">a1</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="kt">float</span><span class="w"> </span><span class="o">*</span><span class="n">a2</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="n">a1</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="kt">float</span><span class="o">*</span><span class="p">)</span><span class="n">malloc</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="kt">float</span><span class="p">)</span><span class="o">*</span><span class="n">size</span><span class="p">);</span><span class="w"></span> <span class="w"> </span><span class="n">a2</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="kt">float</span><span class="o">*</span><span class="p">)</span><span class="n">malloc</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="kt">float</span><span class="p">)</span><span class="o">*</span><span class="n">size</span><span class="p">);</span><span class="w"></span> <span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="n">size</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="o">++</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="n">a1</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mf">1.0f</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="n">a2</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mf">2.0f</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="p">}</span><span class="w"></span> <span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="n">t</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="n">t</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="mi">5</span><span class="p">;</span><span class="w"> </span><span class="n">t</span><span class="o">++</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="k">for</span><span class="p">(</span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="n">size</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="o">++</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="n">a2</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="n">a1</span><span class="p">[</span><span class="n">i</span><span class="p">];</span><span class="w"></span> <span class="w"> </span><span class="p">}</span><span class="w"></span> <span class="w"> </span><span class="n">pcast_compare</span><span class="p">(</span><span class="n">a2</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;float&quot;</span><span class="p">,</span><span class="w"> </span><span class="n">size</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;a2&quot;</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;example.c&quot;</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;main&quot;</span><span class="p">,</span><span class="w"> </span><span class="mi">23</span><span class="p">);</span><span class="w"></span> <span class="w"> </span><span class="p">}</span><span class="w"></span> <span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"></span> <span class="p">}</span><span class="w"></span> </pre></div> </div> <p>Compile the example using these compiler options:</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="n">$</span><span class="w"> </span><span class="n">nvc</span><span class="w"> </span><span class="o">-</span><span class="n">fast</span><span class="w"> </span><span class="o">-</span><span class="n">o</span><span class="w"> </span><span class="n">a</span><span class="p">.</span><span class="n">out</span><span class="w"> </span><span class="n">example</span><span class="p">.</span><span class="n">c</span><span class="w"></span> </pre></div> </div> <p>Compiling with redundant or autocompare options are not required to use pcast_compare. Once again, running the compiled executable using the options below, results in the following output:</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="n">$</span><span class="w"> </span><span class="n">PCAST_COMPARE</span><span class="o">=</span><span class="n">summary</span><span class="p">,</span><span class="n">rel</span><span class="o">=</span><span class="mi">1</span><span class="w"> </span><span class="p">.</span><span class="o">/</span><span class="n">out</span><span class="p">.</span><span class="n">o</span><span class="w"></span> <span class="n">datafile</span><span class="w"> </span><span class="n">pcast_compare</span><span class="p">.</span><span class="n">dat</span><span class="w"> </span><span class="n">created</span><span class="w"> </span><span class="n">with</span><span class="w"> </span><span class="mi">5</span><span class="w"> </span><span class="n">blocks</span><span class="p">,</span><span class="w"> </span><span class="mi">5000</span><span class="w"> </span><span class="n">elements</span><span class="p">,</span><span class="w"> </span><span class="mi">20000</span><span class="w"> </span><span class="n">bytes</span><span class="w"></span> <span class="n">$</span><span class="w"> </span><span class="n">PCAST_COMPARE</span><span class="o">=</span><span class="n">summary</span><span class="p">,</span><span class="n">rel</span><span class="o">=</span><span class="mi">1</span><span class="w"> </span><span class="p">.</span><span class="o">/</span><span class="n">out</span><span class="p">.</span><span class="n">o</span><span class="w"></span> <span class="n">datafile</span><span class="w"> </span><span class="n">pcast_compare</span><span class="p">.</span><span class="n">dat</span><span class="w"> </span><span class="n">compared</span><span class="w"> </span><span class="n">with</span><span class="w"> </span><span class="mi">5</span><span class="w"> </span><span class="n">blocks</span><span class="p">,</span><span class="w"> </span><span class="mi">5000</span><span class="w"> </span><span class="n">elements</span><span class="p">,</span><span class="w"> </span><span class="mi">20000</span><span class="w"> </span><span class="n">bytes</span><span class="w"></span> <span class="n">no</span><span class="w"> </span><span class="n">errors</span><span class="w"> </span><span class="n">found</span><span class="w"></span> <span class="w"> </span><span class="n">relative</span><span class="w"> </span><span class="n">tolerance</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mf">0.100000</span><span class="p">,</span><span class="w"> </span><span class="n">rel</span><span class="o">=</span><span class="mi">1</span><span class="w"></span> </pre></div> </div> <p>Running the program for the first time, the data file “pcast_compare.dat” is created. Subsequent runs compare calculated data against this file. Use the <code class="docutils literal notranslate"><span class="pre">PCAST_COMPARE</span></code> environment variable to set the name of the file, or force the program to create a new file on the disk with <code class="docutils literal notranslate"><span class="pre">PCAST_COMPARE=create</span></code>.</p> <p>The same example above can be written with the compare directive. Notice how much more concise the directive is to the update host and <code class="docutils literal notranslate"><span class="pre">pcast_compare</span></code> calls.</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="cp">#include</span><span class="w"> </span><span class="cpf">&lt;stdlib.h&gt;</span><span class="cp"></span> <span class="cp">#include</span><span class="w"> </span><span class="cpf">&lt;openacc.h&gt;</span><span class="cp"></span> <span class="kt">int</span><span class="w"> </span><span class="nf">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">size</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">1000</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">i</span><span class="p">,</span><span class="w"> </span><span class="n">t</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="kt">float</span><span class="w"> </span><span class="o">*</span><span class="n">a1</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="kt">float</span><span class="w"> </span><span class="o">*</span><span class="n">a2</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="n">a1</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="kt">float</span><span class="o">*</span><span class="p">)</span><span class="n">malloc</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="kt">float</span><span class="p">)</span><span class="o">*</span><span class="n">size</span><span class="p">);</span><span class="w"></span> <span class="w"> </span><span class="n">a2</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="kt">float</span><span class="o">*</span><span class="p">)</span><span class="n">malloc</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="kt">float</span><span class="p">)</span><span class="o">*</span><span class="n">size</span><span class="p">);</span><span class="w"></span> <span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="n">size</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="o">++</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="n">a1</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mf">1.0f</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="n">a2</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mf">2.0f</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="p">}</span><span class="w"></span> <span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="n">t</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="n">t</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="mi">5</span><span class="p">;</span><span class="w"> </span><span class="n">t</span><span class="o">++</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="k">for</span><span class="p">(</span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="n">size</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="o">++</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="n">a2</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="n">a1</span><span class="p">[</span><span class="n">i</span><span class="p">];</span><span class="w"></span> <span class="w"> </span><span class="p">}</span><span class="w"></span> <span class="w"> </span><span class="cp">#pragma nvidia compare(a2[0:size])</span> <span class="w"> </span><span class="p">}</span><span class="w"></span> <span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"></span> <span class="p">}</span><span class="w"></span> </pre></div> </div> <p>With the directive, you will want to add “-Mpcast” to the compilation line to enable the directive. Other than that, the output from this program is identical to the runtime example above.</p> </section> <section id="pcast-with-openacc"> <h2><span class="section-number">9.3. </span>PCAST with OpenACC<a class="headerlink" href="#pcast-with-openacc" title="Permalink to this headline"></a></h2> <p>PCAST can also be used with the NVIDIA OpenACC implementation to compare GPU computation against the same program running on a CPU. In this case, all compute constructs are performed redundantly on both the CPU and GPU. The CPU results are considered to be the “golden master” copy which GPU results are compared against.</p> <p>There are two ways to perform comparisons with GPU-calculated results. The first is with the explicit call or directive <code class="docutils literal notranslate"><span class="pre">acc_compare</span></code>. To use <code class="docutils literal notranslate"><span class="pre">acc_compare</span></code>, you must compile with <code class="docutils literal notranslate"><span class="pre">-acc</span> <span class="pre">-gpu=redundant</span></code> to force the CPU and GPU to compute results redundantly. Then, insert calls to <code class="docutils literal notranslate"><span class="pre">acc_compare</span></code> or put an <code class="docutils literal notranslate"><span class="pre">acc</span> <span class="pre">compare</span></code> directive at points where you want to compare the GPU-computed values against those computed by the CPU.</p> <p>The second approach is to turn on autocompare mode by compiling with <code class="docutils literal notranslate"><span class="pre">-acc</span> <span class="pre">-gpu=autocompare</span></code>. In autocompare mode, PCAST will automatically perform a comparison at each point where data is moved from the device to the host. It does not require the programmer to add any additional directives or runtime calls; it’s a convenient way to do all comparisons at the end of a data region. If there are multiple compute kernels within a data region, and you’re only interested in one specific kernel, you should use the previously-mentioned <code class="docutils literal notranslate"><span class="pre">acc_compare</span></code> to target a specific kernel. Note that autocompare mode implies <code class="docutils literal notranslate"><span class="pre">-gpu=redundant</span></code>.</p> <p>During redundant execution, the compiler will generate both CPU and GPU code for each compute construct. At runtime, both the CPU and GPU versions will execute redundantly, with the CPU code reading and modifying values in system memory and the GPU reading and modifying values in device memory. Insert calls to <code class="docutils literal notranslate"><span class="pre">acc_compare()</span></code> calls (or the equivalent <code class="docutils literal notranslate"><span class="pre">acc</span> <span class="pre">compare</span></code> directive) at points where you want to compare the GPU-computed values against CPU-computed values. PCAST treats the values generated by the CPU code as the “golden” values. It will compare those results against GPU values. Unlike <code class="docutils literal notranslate"><span class="pre">pcast_compare</span></code>, <code class="docutils literal notranslate"><span class="pre">acc_compare</span></code> does not write to an intermediary file; the comparisons are done in-memory.</p> <p><code class="docutils literal notranslate"><span class="pre">acc_compare</span></code> only has two arguments: a pointer to the data to be compared, <em>hostptr</em>, and the number of elements to compare, <em>count</em>. The type can be inferred in the OpenACC runtime, so it doesn’t need to be specified. The C++ and C interface is given below:</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="kt">void</span><span class="w"> </span><span class="nf">acc_compare</span><span class="p">(</span><span class="kt">void</span><span class="w"> </span><span class="o">*</span><span class="p">,</span><span class="w"> </span><span class="kt">size_t</span><span class="p">);</span><span class="w"></span> </pre></div> </div> <p>And in Fortran:</p> <div class="highlight-fortran notranslate"><div class="highlight"><pre><span></span><span class="k">subroutine </span><span class="n">acc_compare</span><span class="p">(</span><span class="n">a</span><span class="p">)</span><span class="w"></span> <span class="k">subroutine </span><span class="n">acc_compare</span><span class="p">(</span><span class="n">a</span><span class="p">,</span><span class="w"> </span><span class="nb">len</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="k">type</span><span class="p">(</span><span class="o">*</span><span class="p">),</span><span class="w"> </span><span class="k">dimension</span><span class="p">(</span><span class="o">*</span><span class="p">)</span><span class="w"> </span><span class="kd">::</span><span class="w"> </span><span class="n">a</span><span class="w"></span> <span class="w"> </span><span class="kt">integer</span><span class="p">(</span><span class="mi">8</span><span class="p">),</span><span class="w"> </span><span class="k">value</span><span class="w"> </span><span class="kd">::</span><span class="w"> </span><span class="nb">len</span><span class="w"></span> </pre></div> </div> <p>You can call <code class="docutils literal notranslate"><span class="pre">acc_compare</span></code> on any variable or array that is present in device memory. You can also call <code class="docutils literal notranslate"><span class="pre">acc_compare_all</span></code> (no arguments) to compare all values that are present in device memory against the correponding values in host memory.</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="kt">void</span><span class="w"> </span><span class="n">acc_compare_all</span><span class="p">()</span><span class="w"></span> </pre></div> </div> <div class="highlight-fortran notranslate"><div class="highlight"><pre><span></span><span class="k">subroutine </span><span class="n">acc_compare_all</span><span class="p">()</span><span class="w"></span> </pre></div> </div> <p>Directive forms of the <code class="docutils literal notranslate"><span class="pre">acc_compare</span></code> calls exist. They work the same as the API calls and can be used in lieu of them. Similar to PCAST <code class="docutils literal notranslate"><span class="pre">compare</span></code> directives, <code class="docutils literal notranslate"><span class="pre">acc</span> <span class="pre">compare</span></code> directives are ignored when redundant or autocompare modes are not enabled on the compilation line.</p> <p>The <code class="docutils literal notranslate"><span class="pre">acc</span> <span class="pre">compare</span></code> directive takes one or more arguments, or the ‘all’ clause (which corresponds to <code class="docutils literal notranslate"><span class="pre">acc_compare_all()</span></code>. The interfaces are given below in C++ or C, and Fortran respectively. Argument “var-list” can be a variable name, a sub-array specification, and array element, or a composite variable member.</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="cp">#pragma acc compare [ (var-list) | all ]</span> </pre></div> </div> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$!acc compare [ (var-list) | all ] </pre></div> </div> <p>For example:</p> <div class="highlight-fortran notranslate"><div class="highlight"><pre><span></span><span class="cp">#pragma acc compare(a[0:N])</span> <span class="cp">#pragma acc compare all</span> <span class="c">!$acc compare(a, b)</span> <span class="c">!$acc compare(a(1:N))</span> <span class="c">!$acc compare all</span> </pre></div> </div> <p>Consider the following OpenACC program that uses the <code class="docutils literal notranslate"><span class="pre">acc_compare()</span></code> API call and an <code class="docutils literal notranslate"><span class="pre">acc</span> <span class="pre">compare</span></code> directive. This Fortran example uses real*4 and real*8 arrays.</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="n">program</span><span class="w"> </span><span class="n">main</span><span class="w"></span> <span class="w"> </span><span class="n">use</span><span class="w"> </span><span class="n">openacc</span><span class="w"></span> <span class="w"> </span><span class="n">implicit</span><span class="w"> </span><span class="n">none</span><span class="w"></span> <span class="w"> </span><span class="n">parameter</span><span class="w"> </span><span class="n">N</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">1000</span><span class="w"></span> <span class="w"> </span><span class="n">integer</span><span class="w"> </span><span class="o">::</span><span class="w"> </span><span class="n">i</span><span class="w"></span> <span class="w"> </span><span class="n">real</span><span class="w"> </span><span class="o">::</span><span class="w"> </span><span class="n">a</span><span class="p">(</span><span class="n">N</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="n">real</span><span class="o">*</span><span class="mi">4</span><span class="w"> </span><span class="o">::</span><span class="w"> </span><span class="n">b</span><span class="p">(</span><span class="n">N</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="n">real</span><span class="p">(</span><span class="mi">4</span><span class="p">)</span><span class="w"> </span><span class="o">::</span><span class="w"> </span><span class="n">c</span><span class="p">(</span><span class="n">N</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="kt">double</span><span class="w"> </span><span class="n">precision</span><span class="w"> </span><span class="o">::</span><span class="w"> </span><span class="n">d</span><span class="p">(</span><span class="n">N</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="n">real</span><span class="o">*</span><span class="mi">8</span><span class="w"> </span><span class="o">::</span><span class="w"> </span><span class="n">e</span><span class="p">(</span><span class="n">N</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="n">real</span><span class="p">(</span><span class="mi">8</span><span class="p">)</span><span class="w"> </span><span class="o">::</span><span class="w"> </span><span class="n">f</span><span class="p">(</span><span class="n">N</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="n">d</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mf">1.0</span><span class="n">d0</span><span class="w"></span> <span class="w"> </span><span class="n">e</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mf">0.1</span><span class="n">d0</span><span class="w"></span> <span class="w"> </span><span class="o">!</span><span class="n">$acc</span><span class="w"> </span><span class="n">data</span><span class="w"> </span><span class="n">copyout</span><span class="p">(</span><span class="n">a</span><span class="p">,</span><span class="w"> </span><span class="n">b</span><span class="p">,</span><span class="w"> </span><span class="n">c</span><span class="p">,</span><span class="w"> </span><span class="n">f</span><span class="p">)</span><span class="w"> </span><span class="n">copyin</span><span class="p">(</span><span class="n">d</span><span class="p">,</span><span class="w"> </span><span class="n">e</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="o">!</span><span class="n">$acc</span><span class="w"> </span><span class="n">parallel</span><span class="w"> </span><span class="n">loop</span><span class="w"></span> <span class="w"> </span><span class="k">do</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="n">N</span><span class="w"></span> <span class="w"> </span><span class="n">a</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mf">1.0</span><span class="w"></span> <span class="w"> </span><span class="n">b</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mf">2.0</span><span class="w"></span> <span class="w"> </span><span class="n">c</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mf">0.0</span><span class="w"></span> <span class="w"> </span><span class="n">enddo</span><span class="w"></span> <span class="w"> </span><span class="o">!</span><span class="n">$acc</span><span class="w"> </span><span class="n">end</span><span class="w"> </span><span class="n">parallel</span><span class="w"></span> <span class="w"> </span><span class="o">!</span><span class="n">$acc</span><span class="w"> </span><span class="n">compare</span><span class="p">(</span><span class="n">a</span><span class="p">(</span><span class="mi">1</span><span class="o">:</span><span class="n">N</span><span class="p">),</span><span class="w"> </span><span class="n">b</span><span class="p">(</span><span class="mi">1</span><span class="o">:</span><span class="n">N</span><span class="p">),</span><span class="w"> </span><span class="n">c</span><span class="p">(</span><span class="mi">1</span><span class="o">:</span><span class="n">N</span><span class="p">))</span><span class="w"></span> <span class="w"> </span><span class="o">!</span><span class="n">$acc</span><span class="w"> </span><span class="n">parallel</span><span class="w"> </span><span class="n">loop</span><span class="w"></span> <span class="w"> </span><span class="k">do</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="n">N</span><span class="w"></span> <span class="w"> </span><span class="n">f</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">d</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">e</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="n">enddo</span><span class="w"></span> <span class="w"> </span><span class="o">!</span><span class="n">$acc</span><span class="w"> </span><span class="n">end</span><span class="w"> </span><span class="n">parallel</span><span class="w"></span> <span class="w"> </span><span class="o">!</span><span class="n">$acc</span><span class="w"> </span><span class="n">compare</span><span class="p">(</span><span class="n">f</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="o">!</span><span class="n">$acc</span><span class="w"> </span><span class="n">parallel</span><span class="w"> </span><span class="n">loop</span><span class="w"></span> <span class="w"> </span><span class="k">do</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="n">N</span><span class="w"></span> <span class="w"> </span><span class="n">a</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mf">1.0</span><span class="w"></span> <span class="w"> </span><span class="n">b</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mf">1.0</span><span class="w"></span> <span class="w"> </span><span class="n">c</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mf">1.0</span><span class="w"></span> <span class="w"> </span><span class="n">enddo</span><span class="w"></span> <span class="w"> </span><span class="o">!</span><span class="n">$acc</span><span class="w"> </span><span class="n">end</span><span class="w"> </span><span class="n">parallel</span><span class="w"></span> <span class="w"> </span><span class="n">call</span><span class="w"> </span><span class="n">acc_compare</span><span class="p">(</span><span class="n">a</span><span class="p">,</span><span class="w"> </span><span class="n">N</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="n">call</span><span class="w"> </span><span class="n">acc_compare</span><span class="p">(</span><span class="n">b</span><span class="p">,</span><span class="w"> </span><span class="n">N</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="n">call</span><span class="w"> </span><span class="n">acc_compare</span><span class="p">(</span><span class="n">c</span><span class="p">,</span><span class="w"> </span><span class="n">N</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="o">!</span><span class="n">$acc</span><span class="w"> </span><span class="n">parallel</span><span class="w"> </span><span class="n">loop</span><span class="w"></span> <span class="w"> </span><span class="k">do</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="n">N</span><span class="w"></span> <span class="w"> </span><span class="n">f</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mf">1.0</span><span class="n">D0</span><span class="w"></span> <span class="w"> </span><span class="n">enddo</span><span class="w"></span> <span class="w"> </span><span class="o">!</span><span class="n">$acc</span><span class="w"> </span><span class="n">end</span><span class="w"> </span><span class="n">parallel</span><span class="w"></span> <span class="w"> </span><span class="n">call</span><span class="w"> </span><span class="n">acc_compare_all</span><span class="p">()</span><span class="w"></span> <span class="w"> </span><span class="o">!</span><span class="n">$acc</span><span class="w"> </span><span class="n">parallel</span><span class="w"> </span><span class="n">loop</span><span class="w"></span> <span class="w"> </span><span class="k">do</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="n">N</span><span class="w"></span> <span class="w"> </span><span class="n">a</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mf">3.14</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="n">b</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mf">3.14</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="n">c</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mf">3.14</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="n">f</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mf">3.14</span><span class="n">d0</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="n">enddo</span><span class="w"></span> <span class="w"> </span><span class="o">!</span><span class="n">$acc</span><span class="w"> </span><span class="n">end</span><span class="w"> </span><span class="n">parallel</span><span class="w"></span> <span class="w"> </span><span class="o">!</span><span class="w"> </span><span class="n">In</span><span class="w"> </span><span class="n">redundant</span><span class="w"> </span><span class="n">mode</span><span class="p">,</span><span class="w"> </span><span class="n">no</span><span class="w"> </span><span class="n">comparison</span><span class="w"> </span><span class="n">is</span><span class="w"> </span><span class="n">performed</span><span class="w"> </span><span class="n">here</span><span class="p">.</span><span class="w"> </span><span class="n">In</span><span class="w"></span> <span class="w"> </span><span class="o">!</span><span class="w"> </span><span class="n">autocompare</span><span class="w"> </span><span class="n">mode</span><span class="p">,</span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="n">comparison</span><span class="w"> </span><span class="n">is</span><span class="w"> </span><span class="n">made</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">a</span><span class="p">,</span><span class="w"> </span><span class="n">b</span><span class="p">,</span><span class="w"> </span><span class="n">c</span><span class="p">,</span><span class="w"> </span><span class="n">and</span><span class="w"> </span><span class="n">f</span><span class="w"> </span><span class="p">(</span><span class="n">but</span><span class="w"></span> <span class="w"> </span><span class="o">!</span><span class="w"> </span><span class="n">not</span><span class="w"> </span><span class="n">e</span><span class="w"> </span><span class="n">and</span><span class="w"> </span><span class="n">d</span><span class="p">),</span><span class="w"> </span><span class="n">since</span><span class="w"> </span><span class="n">they</span><span class="w"> </span><span class="n">are</span><span class="w"> </span><span class="n">copied</span><span class="w"> </span><span class="n">out</span><span class="w"> </span><span class="n">of</span><span class="w"> </span><span class="n">the</span><span class="w"> </span><span class="n">data</span><span class="w"> </span><span class="n">region</span><span class="p">.</span><span class="w"></span> <span class="w"> </span><span class="o">!</span><span class="n">$acc</span><span class="w"> </span><span class="n">end</span><span class="w"> </span><span class="n">data</span><span class="w"></span> <span class="w"> </span><span class="n">call</span><span class="w"> </span><span class="n">verify</span><span class="p">(</span><span class="n">N</span><span class="p">,</span><span class="w"> </span><span class="n">a</span><span class="p">,</span><span class="w"> </span><span class="n">b</span><span class="p">,</span><span class="w"> </span><span class="n">c</span><span class="p">,</span><span class="w"> </span><span class="n">f</span><span class="p">)</span><span class="w"></span> <span class="n">end</span><span class="w"> </span><span class="n">program</span><span class="w"></span> <span class="n">subroutine</span><span class="w"> </span><span class="n">verify</span><span class="p">(</span><span class="n">N</span><span class="p">,</span><span class="w"> </span><span class="n">a</span><span class="p">,</span><span class="w"> </span><span class="n">b</span><span class="p">,</span><span class="w"> </span><span class="n">c</span><span class="p">,</span><span class="w"> </span><span class="n">f</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="n">integer</span><span class="p">,</span><span class="w"> </span><span class="n">intent</span><span class="p">(</span><span class="n">in</span><span class="p">)</span><span class="w"> </span><span class="o">::</span><span class="w"> </span><span class="n">N</span><span class="w"></span> <span class="w"> </span><span class="n">real</span><span class="p">,</span><span class="w"> </span><span class="n">intent</span><span class="p">(</span><span class="n">in</span><span class="p">)</span><span class="w"> </span><span class="o">::</span><span class="w"> </span><span class="n">a</span><span class="p">(</span><span class="n">N</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="n">real</span><span class="o">*</span><span class="mi">4</span><span class="p">,</span><span class="w"> </span><span class="n">intent</span><span class="p">(</span><span class="n">in</span><span class="p">)</span><span class="w"> </span><span class="o">::</span><span class="w"> </span><span class="n">b</span><span class="p">(</span><span class="n">N</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="n">real</span><span class="p">(</span><span class="mi">4</span><span class="p">),</span><span class="w"> </span><span class="n">intent</span><span class="p">(</span><span class="n">in</span><span class="p">)</span><span class="w"> </span><span class="o">::</span><span class="w"> </span><span class="n">c</span><span class="p">(</span><span class="n">N</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="n">real</span><span class="p">(</span><span class="mi">8</span><span class="p">),</span><span class="w"> </span><span class="n">intent</span><span class="p">(</span><span class="n">in</span><span class="p">)</span><span class="w"> </span><span class="o">::</span><span class="w"> </span><span class="n">f</span><span class="p">(</span><span class="n">N</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="n">integer</span><span class="w"> </span><span class="o">::</span><span class="w"> </span><span class="n">i</span><span class="p">,</span><span class="w"> </span><span class="n">errcnt</span><span class="w"></span> <span class="w"> </span><span class="n">errcnt</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="w"></span> <span class="w"> </span><span class="k">do</span><span class="w"> </span><span class="n">i</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span><span class="n">N</span><span class="w"></span> <span class="w"> </span><span class="k">if</span><span class="p">(</span><span class="n">abs</span><span class="p">(</span><span class="n">a</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="mf">3.14e0</span><span class="p">)</span><span class="w"> </span><span class="p">.</span><span class="n">gt</span><span class="p">.</span><span class="w"> </span><span class="mf">1.0e-06</span><span class="p">)</span><span class="w"> </span><span class="n">then</span><span class="w"></span> <span class="w"> </span><span class="n">errcnt</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">errcnt</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mi">1</span><span class="w"></span> <span class="w"> </span><span class="n">endif</span><span class="w"></span> <span class="w"> </span><span class="n">end</span><span class="w"> </span><span class="k">do</span><span class="w"></span> <span class="w"> </span><span class="k">do</span><span class="w"> </span><span class="n">i</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span><span class="n">N</span><span class="w"></span> <span class="w"> </span><span class="k">if</span><span class="p">(</span><span class="n">abs</span><span class="p">(</span><span class="n">b</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="mf">3.14e0</span><span class="p">)</span><span class="w"> </span><span class="p">.</span><span class="n">gt</span><span class="p">.</span><span class="w"> </span><span class="mf">1.0e-06</span><span class="p">)</span><span class="w"> </span><span class="n">then</span><span class="w"></span> <span class="w"> </span><span class="n">errcnt</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">errcnt</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mi">1</span><span class="w"></span> <span class="w"> </span><span class="n">endif</span><span class="w"></span> <span class="w"> </span><span class="n">end</span><span class="w"> </span><span class="k">do</span><span class="w"></span> <span class="w"> </span><span class="k">do</span><span class="w"> </span><span class="n">i</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span><span class="n">N</span><span class="w"></span> <span class="w"> </span><span class="k">if</span><span class="p">(</span><span class="n">abs</span><span class="p">(</span><span class="n">c</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="mf">3.14e0</span><span class="p">)</span><span class="w"> </span><span class="p">.</span><span class="n">gt</span><span class="p">.</span><span class="w"> </span><span class="mf">1.0e-06</span><span class="p">)</span><span class="w"> </span><span class="n">then</span><span class="w"></span> <span class="w"> </span><span class="n">errcnt</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">errcnt</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mi">1</span><span class="w"></span> <span class="w"> </span><span class="n">endif</span><span class="w"></span> <span class="w"> </span><span class="n">end</span><span class="w"> </span><span class="k">do</span><span class="w"></span> <span class="w"> </span><span class="k">do</span><span class="w"> </span><span class="n">i</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span><span class="n">N</span><span class="w"></span> <span class="w"> </span><span class="k">if</span><span class="p">(</span><span class="n">abs</span><span class="p">(</span><span class="n">f</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="mf">3.14</span><span class="n">d0</span><span class="p">)</span><span class="w"> </span><span class="p">.</span><span class="n">gt</span><span class="p">.</span><span class="w"> </span><span class="mf">1.0</span><span class="n">d</span><span class="mo">-06</span><span class="p">)</span><span class="w"> </span><span class="n">then</span><span class="w"></span> <span class="w"> </span><span class="n">errcnt</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">errcnt</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mi">1</span><span class="w"></span> <span class="w"> </span><span class="n">endif</span><span class="w"></span> <span class="w"> </span><span class="n">end</span><span class="w"> </span><span class="k">do</span><span class="w"></span> <span class="w"> </span><span class="k">if</span><span class="p">(</span><span class="n">errcnt</span><span class="w"> </span><span class="o">/=</span><span class="w"> </span><span class="mi">0</span><span class="p">)</span><span class="w"> </span><span class="n">then</span><span class="w"></span> <span class="w"> </span><span class="n">write</span><span class="w"> </span><span class="p">(</span><span class="o">*</span><span class="p">,</span><span class="w"> </span><span class="o">*</span><span class="p">)</span><span class="w"> </span><span class="s">&quot;FAILED&quot;</span><span class="w"></span> <span class="w"> </span><span class="k">else</span><span class="w"></span> <span class="w"> </span><span class="n">write</span><span class="w"> </span><span class="p">(</span><span class="o">*</span><span class="p">,</span><span class="w"> </span><span class="o">*</span><span class="p">)</span><span class="w"> </span><span class="s">&quot;PASSED&quot;</span><span class="w"></span> <span class="w"> </span><span class="n">endif</span><span class="w"></span> <span class="n">end</span><span class="w"> </span><span class="n">subroutine</span><span class="w"> </span><span class="n">verify</span><span class="w"></span> </pre></div> </div> <p>The program can be compiled with the following command:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ nvfortran -fast -acc -gpu=redundant -Minfo=accel example.F90 main: 16, Generating copyout(a(:),b(:)) Generating copyin(e(:)) Generating copyout(f(:),c(:)) Generating copyin(d(:)) 18, Generating Tesla code 19, !$acc loop gang, vector(128) ! blockidx%x threadidx%x 26, Generating acc compare(c(:),b(:),a(:)) 28, Generating Tesla code 29, !$acc loop gang, vector(128) ! blockidx%x threadidx%x 34, Generating acc compare(f(:)) 36, Generating Tesla code 37, !$acc loop gang, vector(128) ! blockidx%x threadidx%x 48, Generating Tesla code 49, !$acc loop gang, vector(128) ! blockidx%x threadidx%x 56, Generating Tesla code 57, !$acc loop gang, vector(128) ! blockidx%x threadidx%x </pre></div> </div> <p>Here, you can see where the acc compare directives are generated on lines 26 and 34. The program can be run with the following command:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ ./a.out PASSED </pre></div> </div> <p>As you can see, no PCAST output is generated when the comparisons match. We can get more information with the summary option:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ PCAST_COMPARE=summary ./a.out PASSED compared 13 blocks, 13000 elements, 68000 bytes no errors found absolute tolerance = 0.00000000000000000e+00, abs=0 </pre></div> </div> <p>There are 13 blocks compared. Let’s count the blocks in the compare calls.</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>!$acc compare(a(1:N), b(1:N), c(1:N)) </pre></div> </div> <p>Compares three blocks, one each for a, b, and c.</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>!$acc compare(f) </pre></div> </div> <p>Compares one block for f.</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>call acc_compare(a, N) call acc_compare(b, N) call acc_compare(c, N) </pre></div> </div> <p>Each call compares one block for their respective array.</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>call acc_compare_all() </pre></div> </div> <p>Compares one block for each array present on the device (a, b, c, d, e, and f) for a total of 6 blocks.</p> <p>If the same example is compiled with autocompare, we’ll see four additional comparisons, since the four arrays that are copied out (with the copyout clause) are compared at the end of the data region.</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ nvfortran -fast -acc -gpu=autocompare example.F90 $ PCAST_COMPARE=summary ./a.out PASSED compared 17 blocks, 17000 elements, 88000 bytes no errors found absolute tolerance = 0.00000000000000000e+00, abs=0 </pre></div> </div> </section> <section id="limitations"> <h2><span class="section-number">9.4. </span>Limitations<a class="headerlink" href="#limitations" title="Permalink to this headline"></a></h2> <p>There are currently a few limitations with using PCAST that are worth keeping in mind.</p> <ul class="simple"> <li><p>Comparisons are not thread-safe. If you are using PCAST with multiple threads, ensure that only one thread is doing the comparisons. This is especially true if you are using PCAST with MPI. If you use <code class="docutils literal notranslate"><span class="pre">pcast_compare</span></code> with MPI, you must make sure that only one thread is writing to the comparison file. Or, use a script to set PCAST_COMPARE to encode the file name with the MPI rank.</p></li> <li><p>Comparisons must be done with like types; you cannot compare one type with another. It is not possible to, for example, check for differing results after changing from double precision to single. Comparisons are limited to those present in table <a class="reference internal" href="#pcast-overview-pcast-supported-types-table"><span class="std std-ref">Table 23</span></a>. Currently there is no support for structured or derived types.</p></li> <li><p>The <code class="docutils literal notranslate"><span class="pre">-gpu=mem:managed</span></code> or <code class="docutils literal notranslate"><span class="pre">-gpu=mem:unified</span></code> options are incompatible with autocompare and <code class="docutils literal notranslate"><span class="pre">acc_compare</span></code>. Both the CPU and GPU need to calculate result separately and to do so they must have their own working memory spaces.</p></li> <li><p>If you do any data movement on the device, you must account for it on the host. For example, if you are using CUDA-aware MPI or GPU-accelerated libraries that modify device data, then you must also make the host aware of the changes. In these cases it is helpful to use the <code class="docutils literal notranslate"><span class="pre">host_data</span></code> clause, which allows you to use device addresses within host code.</p></li> </ul> <span class="target" id="pcast-env-vars"></span></section> <section id="id6"> <h2><span class="section-number">9.5. </span>Environment Variables<a class="headerlink" href="#id6" title="Permalink to this headline"></a></h2> <p>Behavior of PCAST/Autocompare is controlled through the <code class="docutils literal notranslate"><span class="pre">PCAST_COMPARE</span></code> variable. Options can be specified in a comma-separated list: <code class="docutils literal notranslate"><span class="pre">PCAST_COMPARE=&lt;opt1&gt;,&lt;opt2&gt;,...</span></code></p> <p>If no options are specified, the default is to perform comparisons with <em>abs=0</em>. Comparison options are not mutually exclusive. PCAST can compare absolute differences with some <em>n=3</em> and relative differences with a different threshold, e.g. <em>n=5</em>; <em>PCAST_COMPARE=abs=3,rel=5,…</em>.</p> <p>You can specify either an absolute or relative location to be used with the datafile option. The parent directory should be owned by the same user executing the comparisons and the datafile should have the appropriate read/write permissions set.</p> <table class="table-no-stripes docutils align-default" id="id33"> <caption><span class="caption-text">Table 24. PCAST_COMPARE Options</span><a class="headerlink" href="#id33" title="Permalink to this table"></a></caption> <colgroup> <col style="width: 14%" /> <col style="width: 86%" /> </colgroup> <thead> <tr class="row-odd"><th class="head"><p>Option</p></th> <th class="head"><p>Description</p></th> </tr> </thead> <tbody> <tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">abs=n</span></code></p></td> <td><p>Compare absolute difference; tolerate differences up to 10^(-n), only applicable to floating point types. Default value is 0</p></td> </tr> <tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">create</span></code></p></td> <td><p>Specifies that this is the run that will produce the reference file (<code class="docutils literal notranslate"><span class="pre">pcast_compare</span></code> only)</p></td> </tr> <tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">compare</span></code></p></td> <td><p>Specifies that the current run will be compared with a reference file (<code class="docutils literal notranslate"><span class="pre">pcast_compare</span></code> only)</p></td> </tr> <tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">datafile=&quot;name&quot;</span></code></p></td> <td><p>Name of the file that data will be saved to, or compared against. If empty will use the default, <code class="docutils literal notranslate"><span class="pre">pcast_compare.dat</span></code> (<code class="docutils literal notranslate"><span class="pre">pcast_compare</span></code> only)</p></td> </tr> <tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">disable</span></code></p></td> <td><p>Calls to <code class="docutils literal notranslate"><span class="pre">pcast_compare</span></code>, <code class="docutils literal notranslate"><span class="pre">acc_compare</span></code>, <code class="docutils literal notranslate"><span class="pre">acc_compare_all</span></code>, and directives (<code class="docutils literal notranslate"><span class="pre">pcast</span> <span class="pre">compare</span></code>, <code class="docutils literal notranslate"><span class="pre">acc</span> <span class="pre">compare</span></code>, and <code class="docutils literal notranslate"><span class="pre">acc</span> <span class="pre">compare</span></code>) all immediately return from the runtime with no effect. Note that this doesn’t disable redundant execution; that will require a recompile.</p></td> </tr> <tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">ieee</span></code></p></td> <td><p>Compare IEEE NaN checks (only implemented for floats and doubles)</p></td> </tr> <tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">outputfile=&quot;name&quot;</span></code></p></td> <td><p>Save comparison output to a specific file. Default behavior is to output to stderr</p></td> </tr> <tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">patch</span></code></p></td> <td><p>Patch errors (outside tolerance) with correct values</p></td> </tr> <tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">patchall</span></code></p></td> <td><p>Patch all differences (inside and outside tolerance) with correct values</p></td> </tr> <tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">rel=n</span></code></p></td> <td><p>Compare relative difference; tolerated differences up to 10^(-n), only applicable to floating point types. Default value is 0.</p></td> </tr> <tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">report=n</span></code></p></td> <td><p>Report up to n (default of 50) passes/fails</p></td> </tr> <tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">reportall</span></code></p></td> <td><p>Report all passes and fails (overrides limit set in report=n)</p></td> </tr> <tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">reportpass</span></code></p></td> <td><p>Report passes; respects limit set with report=n</p></td> </tr> <tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">silent</span></code></p></td> <td><p>Suppress output - overrides all other output options, including summary and verbose</p></td> </tr> <tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">stop</span></code></p></td> <td><p>Stop at first differences</p></td> </tr> <tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">summary</span></code></p></td> <td><p>Print summary of comparisons at end of run</p></td> </tr> <tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">ulp=n</span></code></p></td> <td><p>Compare Unit of Least Precision difference (only for floats and doubles)</p></td> </tr> <tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">verbose</span></code></p></td> <td><p>Outputs more details of comparison (including patches)</p></td> </tr> <tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">verboseautocompare</span></code></p></td> <td><p>Outputs verbose reporting of what and where the host is comparing (autocompare only)</p></td> </tr> </tbody> </table> <span class="target" id="mpi-use"></span></section> </section> <section id="using-mpi"> <h1><span class="section-number">10. </span>Using MPI<a class="headerlink" href="#using-mpi" title="Permalink to this headline"></a></h1> <p>MPI (Message Passing Interface) is an industry-standard application programming interface designed for rapid data exchange between processors in a distributed-memory environment. MPI is computer software used in scalable computer systems that allows the processes of a parallel application to communicate with one another.</p> <p>The NVIDIA HPC SDK includes a pre-compiled version of Open MPI. You can build using alternate versions of MPI with the <code class="docutils literal notranslate"><span class="pre">-I</span></code>, <code class="docutils literal notranslate"><span class="pre">-L</span></code>, and <code class="docutils literal notranslate"><span class="pre">-l</span></code> options.</p> <p>This section describes how to use Open MPI with the NVIDIA HPC Compilers.</p> <section id="using-open-mpi-on-linux"> <h2><span class="section-number">10.1. </span>Using Open MPI on Linux<a class="headerlink" href="#using-open-mpi-on-linux" title="Permalink to this headline"></a></h2> <p>The NVIDIA HPC Compilers for Linux ship with a pre-compiled version of Open MPI that includes everything required to compile, execute and debug MPI programs using Open MPI.</p> <p>To build an application using Open MPI, use the Open MPI compiler wrappers: <code class="docutils literal notranslate"><span class="pre">mpicc</span></code>, <code class="docutils literal notranslate"><span class="pre">mpic⁠+⁠+</span></code> and <code class="docutils literal notranslate"><span class="pre">mpifort</span></code>. These wrappers automatically set up the compiler commands with the correct include file search paths, library directories, and link libraries.</p> <p>The following MPI example program uses Open MPI.</p> <pre class="literal-block">$ cd my_example_dir $ cp -r /opt/nvidia/hpc_sdk/Linux_x86_64/25.1/examples/MPI/samples/mpihello . $ cd mpihello $ export PATH=/opt/nvidia/hpc_sdk/Linux_x86_64/25.1/mpi/openmpi/bin:$PATH $ mpifort mpihello.f -o mpihello</pre> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ mpiexec mpihello Hello world! I&#39;m node 0 </pre></div> </div> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ mpiexec -np 4 mpihello Hello world! I&#39;m node 0 Hello world! I&#39;m node 2 Hello world! I&#39;m node 1 Hello world! I&#39;m node 3 </pre></div> </div> <p>To build an application using Open MPI for debugging, add -g to the compiler wrapper command line arguments.</p> </section> <section id="using-mpi-compiler-wrappers"> <h2><span class="section-number">10.2. </span>Using MPI Compiler Wrappers<a class="headerlink" href="#using-mpi-compiler-wrappers" title="Permalink to this headline"></a></h2> <p>When you use MPI compiler wrappers to build with the <code class="docutils literal notranslate"><span class="pre">-fpic</span></code> or <code class="docutils literal notranslate"><span class="pre">-mcmodel=medium</span></code> options, then you must specify <code class="docutils literal notranslate"><span class="pre">-fortranlibs</span></code> to link with the correct libraries. Here are a few examples:</p> <p>For a static link to the MPI libraries, use this command:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ mpifort hello.f </pre></div> </div> <p>For a dynamic link to the MPI libraries, use this command:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ mpifort hello.f -fortranlibs </pre></div> </div> <p>To compile with <code class="docutils literal notranslate"><span class="pre">-fpic</span></code>, which, by default, invokes dynamic linking, use this command:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ mpifort -fpic -fortranlibs hello.f </pre></div> </div> <p>To compile with <code class="docutils literal notranslate"><span class="pre">-mcmodel=medium</span></code>, use this command:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ mpifort -mcmodel=medium -fortranlibs hello.f </pre></div> </div> </section> <section id="testing-and-benchmarking"> <h2><span class="section-number">10.3. </span>Testing and Benchmarking<a class="headerlink" href="#testing-and-benchmarking" title="Permalink to this headline"></a></h2> <p>The /opt/nvidia/hpc_sdk/Linux_x86_64/25.1/examples/MPI directory contains various benchmarks and tests. Copy this directory into a local working directory by issuing the following command:</p> <pre class="literal-block">text % cp -r /opt/nvidia/hpc_sdk/Linux_x86_64/25.1/examples/MPI .</pre> <p>There are several example programs available in this directory.</p> <span class="target" id="lib-create-use"></span></section> </section> <section id="creating-and-using-libraries"> <h1><span class="section-number">11. </span>Creating and Using Libraries<a class="headerlink" href="#creating-and-using-libraries" title="Permalink to this headline"></a></h1> <p>A library is a collection of functions or subprograms that are grouped for reference and ease of linking. This section discusses issues related to NVIDIA-supplied compiler libraries. Specifically, it addresses the use of C++ and C builtin functions in place of the corresponding libc routines, creation of dynamically linked libraries, known as shared objects or shared libraries, and math libraries.</p> <div class="admonition note"> <p class="admonition-title">Note</p> <p>This section does not duplicate material related to using libraries for inlining which are described in <a class="reference internal" href="#fn-inline-create-lib"><span class="std std-ref">Creating an Inline Library</span></a>.</p> </div> <p>NVIDIA provides libraries that export C interfaces by using Fortran modules.</p> <section id="using-builtin-math-functions-in-c-and-c"> <h2><span class="section-number">11.1. </span>Using builtin Math Functions in C++ and C<a class="headerlink" href="#using-builtin-math-functions-in-c-and-c" title="Permalink to this headline"></a></h2> <p>The name of the math header file is <code class="docutils literal notranslate"><span class="pre">math.h</span></code>. Include the math header file in all of your source files that use a math library routine as in the following example, which calculates the inverse cosine of 3.5.</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>#include &lt;math.h&gt; #include &lt;stdio.h&gt; #define PI 3.1415926535 void main() { double x, y; x = PI/3.0; y = acos(0.5); printf(&#39;%f %f\n&#39;,x,y); } </pre></div> </div> <p>Including <code class="docutils literal notranslate"><span class="pre">math.h</span></code> causes the NVIDIA C++ and C compilers to use builtin functions, which are much more efficient than library calls. In particular, if you include <code class="docutils literal notranslate"><span class="pre">math.h</span></code>, the following intrinsics calls are processed using builtins:</p> <table class="table-no-stripes docutils align-default"> <colgroup> <col style="width: 16%" /> <col style="width: 19%" /> <col style="width: 16%" /> <col style="width: 13%" /> <col style="width: 16%" /> <col style="width: 19%" /> </colgroup> <tbody> <tr class="row-odd"><td><p>abs</p></td> <td><p>acosf</p></td> <td><p>asinf</p></td> <td><p>atan</p></td> <td><p>atan2</p></td> <td><p>atan2f</p></td> </tr> <tr class="row-even"><td><p>atanf</p></td> <td><p>cos</p></td> <td><p>cosf</p></td> <td><p>exp</p></td> <td><p>expf</p></td> <td><p>fabs</p></td> </tr> <tr class="row-odd"><td><p>fabsf</p></td> <td><p>fmax</p></td> <td><p>fmaxf</p></td> <td><p>fmin</p></td> <td><p>fminf</p></td> <td><p>log</p></td> </tr> <tr class="row-even"><td><p>log10</p></td> <td><p>log10f</p></td> <td><p>logf</p></td> <td><p>pow</p></td> <td><p>powf</p></td> <td><p>sin</p></td> </tr> <tr class="row-odd"><td><p>sinf</p></td> <td><p>sqrt</p></td> <td><p>sqrtf</p></td> <td><p>tan</p></td> <td><p>tanf</p></td> <td></td> </tr> </tbody> </table> </section> <section id="using-system-library-routines"> <h2><span class="section-number">11.2. </span>Using System Library Routines<a class="headerlink" href="#using-system-library-routines" title="Permalink to this headline"></a></h2> <p>Release 25.1 of the NVIDIA HPC Compilers runtime libraries makes use of Linux system libraries to implement, for example, OpenMP and Fortran I/O. The NVIDIA HPC Compilers runtime libraries make use of several additional system library routines.</p> <p>On 64-bit Linux systems, the system library routines used include these:</p> <table class="table-no-stripes docutils align-default"> <colgroup> <col style="width: 21%" /> <col style="width: 32%" /> <col style="width: 38%" /> <col style="width: 9%" /> </colgroup> <tbody> <tr class="row-odd"><td><p>aio_error</p></td> <td><p>aio_write</p></td> <td><p>pthread_mutex_init</p></td> <td><p>sleep</p></td> </tr> <tr class="row-even"><td><p>aio_read</p></td> <td><p>calloc</p></td> <td><p>pthread_mutex_lock</p></td> <td></td> </tr> <tr class="row-odd"><td><p>aio_return</p></td> <td><p>getrlimit</p></td> <td><p>pthread_mutex_unlock</p></td> <td></td> </tr> <tr class="row-even"><td><p>aio_suspend</p></td> <td><p>pthread_attr_init</p></td> <td><p>setrlimit</p></td> <td></td> </tr> </tbody> </table> </section> <section id="creating-and-using-shared-object-files-on-linux"> <h2><span class="section-number">11.3. </span>Creating and Using Shared Object Files on Linux<a class="headerlink" href="#creating-and-using-shared-object-files-on-linux" title="Permalink to this headline"></a></h2> <p>All of the NVIDIA HPC Fortran, C++ and C compilers support creation of shared object files. Unlike statically-linked object and library files, shared object files link and resolve references with an executable at runtime via a dynamic linker supplied with your operating system. The NVIDIA HPC Compilers must generate position independent code to support creation of shared objects by the linker. However, this is not the default. You must create object files with position independent code and shared object files that will include them.</p> <section id="procedure-to-create-a-use-a-shared-object-file"> <h3><span class="section-number">11.3.1. </span>Procedure to create a use a shared object file<a class="headerlink" href="#procedure-to-create-a-use-a-shared-object-file" title="Permalink to this headline"></a></h3> <p>The following steps describe how to create and use a shared object file.</p> <ol class="arabic"> <li><p>Create an object file with position independent code. To do this, compile your code with the appropriate NVIDIA HPC compiler using the <code class="docutils literal notranslate"><span class="pre">-⁠fpic</span></code> option, or one of the equivalent options, such as <code class="docutils literal notranslate"><span class="pre">-⁠fPIC</span></code>, <code class="docutils literal notranslate"><span class="pre">-⁠Kpic,</span></code> and <code class="docutils literal notranslate"><span class="pre">-⁠KPIC</span></code>, which are supported for compatibility with other systems. For example, use the following command to create an object file with position independent code using nvfortran:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>% nvfortran -c -fpic tobeshared.f </pre></div> </div> </li> <li><p>Produce a shared object file. To do this, use the appropriate NVIDIA HPC compiler to invoke the linker supplied with your system. It is customary to name such files using a <code class="docutils literal notranslate"><span class="pre">.so</span></code> filename extension. On Linux, you do this by passing the <code class="docutils literal notranslate"><span class="pre">-shared</span></code> option to the linker:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>% nvfortran -shared -o tobeshared.so tobeshared.o </pre></div> </div> <div class="admonition note"> <p class="admonition-title">Note</p> <p>Compilation and generation of the shared object can be performed in one step using both the -fpic option and the appropriate option for generation of a shared object file.</p> </div> </li> <li><p>Use a shared object file. To do this, use the appropriate NVIDIA HPC compiler to compile and link the program which will reference functions or subroutines in the shared object file, and list the shared object on the link line, as shown here:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>% nvfortran -o myprog myprog.f tobeshared.so </pre></div> </div> </li> <li><p>Make the executable available.</p> <p>You now have an executable <code class="docutils literal notranslate"><span class="pre">myprog</span></code> which does not include any code from functions or subroutines in <code class="docutils literal notranslate"><span class="pre">tobeshared.so</span></code>, but which can be executed and dynamically linked to that code. By default, when the program is linked to produce <code class="docutils literal notranslate"><span class="pre">myprog</span></code>, no assumptions are made on the location of <code class="docutils literal notranslate"><span class="pre">tobeshared.so</span></code>. Therefore, for <code class="docutils literal notranslate"><span class="pre">myprog</span></code> to execute correctly, you must initialize the environment variable <code class="docutils literal notranslate"><span class="pre">LD_LIBRARY_PATH</span></code> to include the directory containing <code class="docutils literal notranslate"><span class="pre">tobeshared.so</span></code>. If <code class="docutils literal notranslate"><span class="pre">LD_LIBRARY_PATH</span></code> is already initialized, it is important not to overwrite its contents. If you have placed <code class="docutils literal notranslate"><span class="pre">tobeshared.so</span></code> in directory <code class="docutils literal notranslate"><span class="pre">/home/myusername/bin</span></code>, you can initialize <code class="docutils literal notranslate"><span class="pre">LD_LIBRARY_PATH</span></code> to include that directory and preserve its existing contents, as shown in the following:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>% setenv LD_LIBRARY_PATH &quot;$LD_LIBRARY_PATH&quot;:/home/myusername/bin </pre></div> </div> <p>If you know that tobeshared.so always resides in a specific directory, you can create the executable myprog in a form that assumes this directory by using the -R link-time option. For example, you can link as follows:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>% nvfortran -o myprog myprof.f tobeshared.so -R/home/myusername/bin </pre></div> </div> <div class="admonition note"> <p class="admonition-title">Note</p> <p>As with the <code class="docutils literal notranslate"><span class="pre">-⁠L</span></code> option, there is no space between <code class="docutils literal notranslate"><span class="pre">-⁠R</span></code> and the directory name. If the -⁠R option is used, it is not necessary to initialize <code class="docutils literal notranslate"><span class="pre">LD_LIBRARY_PATH</span></code>.</p> </div> <p>In the previous example, the dynamic linker always looks in <code class="docutils literal notranslate"><span class="pre">/home/myusername/bin</span></code> to resolve references to <code class="docutils literal notranslate"><span class="pre">tobeshared.so</span></code>. By default, if the <code class="docutils literal notranslate"><span class="pre">LD_LIBRARY_PATH</span></code> environment variable is not set, the linker only searches <code class="docutils literal notranslate"><span class="pre">/usr/lib</span></code> and <code class="docutils literal notranslate"><span class="pre">/lib</span></code> for shared objects.</p> </li> </ol> </section> <section id="ldd-command"> <h3><span class="section-number">11.3.2. </span>ldd Command<a class="headerlink" href="#ldd-command" title="Permalink to this headline"></a></h3> <p>The <code class="docutils literal notranslate"><span class="pre">ldd</span></code> command is a useful tool when working with shared object files and executables that reference them. When applied to an executable, as shown in the following example, <code class="docutils literal notranslate"><span class="pre">ldd</span></code> lists all shared object files referenced in the executable along with the pathname of the directory from which they will be extracted.</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>% ldd myprog </pre></div> </div> <p>If the pathname is not hard-coded using the <code class="docutils literal notranslate"><span class="pre">-⁠R</span></code> option, and if <code class="docutils literal notranslate"><span class="pre">LD_LIBRARY_PATH</span></code> is not initialized, the pathname is listed as “not found”. For more information on <code class="docutils literal notranslate"><span class="pre">ldd</span></code>, its options and usage, see the online man page for <code class="docutils literal notranslate"><span class="pre">ldd</span></code>.</p> </section> </section> <section id="using-lib3f"> <h2><span class="section-number">11.4. </span>Using LIB3F<a class="headerlink" href="#using-lib3f" title="Permalink to this headline"></a></h2> <p>The NVFORTRAN compiler includes support for the de facto standard LIB3F library routines. See the Fortran Language Reference manual for a complete list of available routines in the NVIDIA implementation of LIB3F.</p> </section> <section id="lapack-blas-and-ffts"> <h2><span class="section-number">11.5. </span>LAPACK, BLAS and FFTs<a class="headerlink" href="#lapack-blas-and-ffts" title="Permalink to this headline"></a></h2> <p>The NVIDIA HPC SDK includes a BLAS and LAPACK library based on the customized OpenBLAS project source and built with the NVIDIA HPC Compilers. The LAPACK library is called <code class="docutils literal notranslate"><span class="pre">liblapack.a</span></code>. The BLAS library is called <code class="docutils literal notranslate"><span class="pre">libblas.a</span></code>.</p> <p>To use these libraries, simply link them in using the <code class="docutils literal notranslate"><span class="pre">-l</span></code> option when linking your main program:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>% nvfortran myprog.f -llapack -lblas </pre></div> </div> </section> <section id="linking-with-scalapack"> <h2><span class="section-number">11.6. </span>Linking with ScaLAPACK<a class="headerlink" href="#linking-with-scalapack" title="Permalink to this headline"></a></h2> <p>The ScaLAPACK libraries are automatically installed with each MPI library version which accompanies an NVIDIA HPC SDK installation. You can link with the ScaLAPACK libraries by specifying <code class="docutils literal notranslate"><span class="pre">-Mscalapack</span></code> on any of the MPI wrapper command lines. For example:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>% mpifort myprog.f -Mscalapack </pre></div> </div> <p>A pre-built version of the BLAS library is automatically added when the <code class="docutils literal notranslate"><span class="pre">-⁠Mscalapack</span></code> switch is specified. If you wish to use a different BLAS library, and still use the <code class="docutils literal notranslate"><span class="pre">-⁠Mscalapack</span></code> switch, then you can list the set of libraries explicitly on your link line.</p> <p>If the <code class="docutils literal notranslate"><span class="pre">-⁠Mnvpl</span></code> switch is also specified in addition to <code class="docutils literal notranslate"><span class="pre">-⁠Mscalapack</span></code>, then the NVPL ScaLAPACK library will be used.</p> </section> <section id="the-c-standard-template-library"> <h2><span class="section-number">11.7. </span>The C++ Standard Template Library<a class="headerlink" href="#the-c-standard-template-library" title="Permalink to this headline"></a></h2> <p>On Linux, the GNU-compatible nvc++ compiler uses the GNU g++ header files and Standard Template Library (STL) directly. The versions used are dependent on the version of the GNU compilers installed on your system, or specified when makelocalrc was run during installation of the NVIDIA HPC Compilers.</p> </section> <section id="nvidia-performance-libraries-nvpl"> <h2><span class="section-number">11.8. </span>NVIDIA Performance Libraries (NVPL)<a class="headerlink" href="#nvidia-performance-libraries-nvpl" title="Permalink to this headline"></a></h2> <p>The NVIDIA Performance Libraries (NVPL) are a suite of high performance mathematical libraries optimized for the NVIDIA Grace Arm architecture. These CPU-only libraries have no dependencies on CUDA or CTK, and are drop in replacements for standard C and Fortran mathematical APIs allowing HPC applications to achieve maximum performance on the Grace platform. They are available for Arm CPUs only. The NVPL includes the following math libraries: BLAS, FFT, LAPACK, RAND, ScaLAPACK, Sparse, and Tensor. Refer to the <a class="reference external" href="https://docs.nvidia.com/nvpl">NVPL documentation</a> for more information about these math libraries. The following section explains how to use them with the NVHPC compilers.</p> <p>To use the NVPL libraries, use the <code class="docutils literal notranslate"><span class="pre">-Mnvpl</span></code> option when linking your main program:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>% nvfortran myprog.f -Mnvpl </pre></div> </div> <p>You can link only the NVPL libraries your application needs using the sub-options to <code class="docutils literal notranslate"><span class="pre">-Mnvpl</span></code>. For example, if you only want the BLAS and FFT libraries from the NVPL, link as follows:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>% nvfortran myprog.f -Mnvpl=blas,fft </pre></div> </div> <p>Refer to the NVIDIA HPC Compilers Reference Guide for a complete list of supported options for the <code class="docutils literal notranslate"><span class="pre">-Mnvpl</span></code> flag.</p> <p><strong>ScaLAPACK</strong></p> <p>Similar to other ScaLAPACK libraries, the NVPL version is designed to be used with MPI. A straightforward way to access the NVPL ScaLAPACK library is to use an MPI wrapper (i.e., <code class="docutils literal notranslate"><span class="pre">mpicc</span></code>, <code class="docutils literal notranslate"><span class="pre">mpic++</span></code>, <code class="docutils literal notranslate"><span class="pre">mpifort</span></code>) and link with both <code class="docutils literal notranslate"><span class="pre">-⁠Mnvpl</span></code> and <code class="docutils literal notranslate"><span class="pre">-⁠Mscalapack</span></code>. For example:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>% mpic++ myprog.cpp -Mscalapack -Mnvpl </pre></div> </div> <p>If you choose not to use an MPI wrapper, you can satisfy ScaLAPACK’s dependency on libmpi.so by explicitly providing this library at link time.</p> <p>The NVPL ScaLAPACK interfaces are available for the following MPI variants: MPICH, Open MPI 3.x, Open MPI 4.x (including HPC-X), and Open MPI 5.x. The HPC SDK contains builds of Open MPI 3, Open MPI 4, and HPC-X; to take advantage of the NVPL’s ScaLAPACK interfaces for MPICH or Open MPI 5.x, you must supply your own build of these MPI libraries.</p> </section> <section id="linking-with-the-nvmalloc-library"> <h2><span class="section-number">11.9. </span>Linking with the nvmalloc Library<a class="headerlink" href="#linking-with-the-nvmalloc-library" title="Permalink to this headline"></a></h2> <p>The NVIDIA HPC SDK installation includes a custom host (system) memory allocation library based on the jemalloc memory allocator. This library replaces the system malloc(), free(), and other related functions used by the nvc, nvc++, and nvfortran runtime for dynamic heap allocations. You can link with this library by specifying -nvmalloc on any of the compiler command lines used for linking. For example:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>% nvc main.c -nvmalloc </pre></div> </div> <span class="target" id="env-vars-use"></span></section> </section> <section id="id7"> <h1><span class="section-number">12. </span>Environment Variables<a class="headerlink" href="#id7" title="Permalink to this headline"></a></h1> <p>Environment variables allow you to set and pass information that can alter the default behavior of the NVIDIA HPC compilers and the executables which they generate. This section includes explanations of the environment variables specific to the NVIDIA HPC Compilers. .</p> <ul class="simple"> <li><p>Standard OpenMP environment variables are used to control the behavior of OpenMP programs; these environment variables are described in the OpenMP Specification available online.</p></li> <li><p>Several NVIDIA-specific environment variables can be used to control the behavior of OpenACC programs. OpenACC-related environment variables are described in the OpenACC section: <a class="reference internal" href="#env-vars"><span class="std std-ref">Environment Variables</span></a> and the <a class="reference external" href="../openacc-gs/index.htm">OpenACC Getting Started Guide</a>.</p></li> </ul> <section id="setting-environment-variables"> <h2><span class="section-number">12.1. </span>Setting Environment Variables<a class="headerlink" href="#setting-environment-variables" title="Permalink to this headline"></a></h2> <p>Before we look at the environment variables that you might use with the HPC compilers and tools, let’s take a look at how to set environment variables. To illustrate how to set these variables in various environments, let’s look at how a user might initialize a Linux shell environment to enable use of the NVIDIA HPC Compilers.</p> <section id="setting-environment-variables-on-linux"> <h3><span class="section-number">12.1.1. </span>Setting Environment Variables on Linux<a class="headerlink" href="#setting-environment-variables-on-linux" title="Permalink to this headline"></a></h3> <p>Let’s assume that you want access to the NVIDIA products when you log in, and that you installed the NVIDIA HPC SDK in /opt/nvidia/hpc_sdk. For access at startup, you can add the following lines to your shell startup files on a Linux_x86_64 system.</p> <p><strong>For csh, use these commands:</strong></p> <pre class="literal-block">$ setenv NVHPCSDK /opt/nvidia/hpc_sdk $ setenv MANPATH &quot;$MANPATH&quot;:$NVHPCSDK/Linux_x86-64/25.1/compilers/man $ set path = ($NVHPCSDK/Linux_x86_64/25.1/compilers/bin $path)</pre> <p><strong>For bash, sh, zsh, or ksh, use these commands:</strong></p> <pre class="literal-block">$ NVHPCSDK=/opt/nvidia/hpc_sdk; export NVHPCSDK $ MANPATH=$MANPATH:$NVHPCSDK/Linux_x86_64/25.1/compilers/man; export MANPATH $ PATH=$NVHPCSDK/Linux_x86_64/25.1/compilers/bin:$PATH; export PATH</pre> <p>On a Linux/Arm Server system replace <code class="docutils literal notranslate"><span class="pre">Linux_x86_64</span></code> with <code class="docutils literal notranslate"><span class="pre">Linux_aarch64</span></code>.</p> </section> </section> <section id="hpc-compiler-related-environment-variables"> <h2><span class="section-number">12.2. </span>HPC Compiler Related Environment Variables<a class="headerlink" href="#hpc-compiler-related-environment-variables" title="Permalink to this headline"></a></h2> <p>The following table provides a listing of environment variables that affect the behavior of the NVIDIA HPC Compilers and the executables they generate.</p> <table class="table-no-stripes docutils align-default" id="env-vars-nv-related-env-vars-nv-related-tbl"> <caption><span class="caption-text">Table 25. NVIDIA HPC Compilers Environment Variable Summary</span><a class="headerlink" href="#env-vars-nv-related-env-vars-nv-related-tbl" title="Permalink to this table"></a></caption> <colgroup> <col style="width: 14%" /> <col style="width: 86%" /> </colgroup> <thead> <tr class="row-odd"><th class="head"><p>Environment Variable</p></th> <th class="head"><p>Description</p></th> </tr> </thead> <tbody> <tr class="row-even"><td><p>FORTRANOPT</p></td> <td><p>Allows the user to specify that the NVIDIA Fortran compiler should use VAX I/O or other custom I/O conventions.</p></td> </tr> <tr class="row-odd"><td><p>FORT_FMT_RECL</p></td> <td><p>Allows the user to change the default Fortran stdout (unit 6) line length before a line break occurs. Default: 80 bytes.</p></td> </tr> <tr class="row-even"><td><p>GMON_OUT_PREFIX</p></td> <td><p>Specifies the name of the output file for programs that are compiled and linked with the -pg option.</p></td> </tr> <tr class="row-odd"><td><p>LD_LIBRARY_PATH</p></td> <td><p>Specifies a colon-separated set of directories where libraries should first be searched, prior to searching the standard set of directories.</p></td> </tr> <tr class="row-even"><td><p>MANPATH</p></td> <td><p>Sets the directories that are searched for manual pages associated with the command that the user types.</p></td> </tr> <tr class="row-odd"><td><p>NO_STOP_MESSAGE</p></td> <td><p>If used, the execution of a plain STOP statement does not produce the message <code class="docutils literal notranslate"><span class="pre">FORTRAN</span> <span class="pre">STOP</span></code>.</p></td> </tr> <tr class="row-even"><td><p>PATH</p></td> <td><p>Determines which locations are searched for commands the user may type.</p></td> </tr> <tr class="row-odd"><td><p>NVCOMPILER_FPU_STATE</p></td> <td><p>Manages the initial state of the processor’s floating point control and status register at program startup.</p></td> </tr> <tr class="row-even"><td><p>NVCOMPILER_TERM</p></td> <td><p>Controls the stack traceback and just-in-time debugging functionality.</p></td> </tr> <tr class="row-odd"><td><p>NVCOMPILER_TERM_DEBUG</p></td> <td><p>Overrides the default behavior when <code class="docutils literal notranslate"><span class="pre">NVCOMPILER_TERM</span></code> is set to <code class="docutils literal notranslate"><span class="pre">debug</span></code>.</p></td> </tr> <tr class="row-even"><td><p>PWD</p></td> <td><p>Allows you to display the current directory.</p></td> </tr> <tr class="row-odd"><td><p>STATIC_RANDOM_SEED</p></td> <td><p>Forces the seed returned by <code class="docutils literal notranslate"><span class="pre">RANDOM_SEED</span></code> to be constant.</p></td> </tr> <tr class="row-even"><td><p>TMP</p></td> <td><p>Sets the directory to use for temporary files created during execution of the HPC compilers and tools; interchangeable with <code class="docutils literal notranslate"><span class="pre">TMPDIR</span></code>.</p></td> </tr> <tr class="row-odd"><td><p>TMPDIR</p></td> <td><p>Sets the directory to use for temporary files created during execution of the HPC compilers and tools.</p></td> </tr> </tbody> </table> </section> <section id="hpc-compilers-environment-variables"> <h2><span class="section-number">12.3. </span>HPC Compilers Environment Variables<a class="headerlink" href="#hpc-compilers-environment-variables" title="Permalink to this headline"></a></h2> <p>Use the environment variables listed in <a class="reference internal" href="#env-vars-nv-related-env-vars-nv-related-tbl"><span class="std std-ref">Table 25</span></a> to alter the default behavior of the NVIDIA HPC Compilers and the executables which they generate. This section provides more detailed descriptions about the variables in this table.</p> <section id="fortranopt"> <h3><span class="section-number">12.3.1. </span>FORTRANOPT<a class="headerlink" href="#fortranopt" title="Permalink to this headline"></a></h3> <p><code class="docutils literal notranslate"><span class="pre">FORTRANOPT</span></code> allows the user to adjust the behavior of the NVIDIA Fortran compiler.</p> <ul class="simple"> <li><p>If <code class="docutils literal notranslate"><span class="pre">FORTRANOPT</span></code> exists and contains the value <code class="docutils literal notranslate"><span class="pre">vaxio</span></code>, the record length in the open statement is in units of 4-byte words, and the $ edit descriptor only has an effect for lines beginning with a space or a plus sign (+).</p></li> <li><p>If <code class="docutils literal notranslate"><span class="pre">FORTRANOPT</span></code> exists and contains the value <code class="docutils literal notranslate"><span class="pre">format_relaxed</span></code>, an I/O item corresponding to a numerical edit descriptor (such as F, E, I, and so on) is not required to be a type implied by the descriptor.</p></li> <li><p>If <code class="docutils literal notranslate"><span class="pre">FORTRANOPT</span></code> exists and contains the value <code class="docutils literal notranslate"><span class="pre">no_minus_zero</span></code>, an I/O item corresponding to a numerical edit descriptor (such as F, E, I, and so on) equal to negative zero will be output as if it were positive zero.</p></li> <li><p>If <code class="docutils literal notranslate"><span class="pre">FORTRANOPT</span></code> exists and contains the value <code class="docutils literal notranslate"><span class="pre">crif</span></code>, a sequential formatted or list-directed record is allowed to be terminated with the character sequence <code class="docutils literal notranslate"><span class="pre">\\r\\n</span></code> (carriage return, newline). This approach is useful when reading records from a file produced on a Windows system.</p></li> </ul> <p>The following example causes the NVIDIA Fortran compiler to use VAX I/O conventions:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ setenv FORTRANOPT vaxio </pre></div> </div> </section> <section id="fort-fmt-recl"> <h3><span class="section-number">12.3.2. </span>FORT_FMT_RECL<a class="headerlink" href="#fort-fmt-recl" title="Permalink to this headline"></a></h3> <p>The <code class="docutils literal notranslate"><span class="pre">FORT_FMT_RECL</span></code> environment variable specifies the maximum line in bytes for Fortran formatted output to standard out (unit 6) before a newline will be generated.</p> <p>If the environment variable <code class="docutils literal notranslate"><span class="pre">FORT_FMT_RECL</span></code> is present, the Fortran runtime library will use the value specified as the number of bytes to output before a newline is generated.</p> <p>The default value of <code class="docutils literal notranslate"><span class="pre">FORT_FMT_RECL</span></code> is 80.</p> <ul> <li><p>In csh:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ setenv FORT_FMT_RECL length-in-bytes </pre></div> </div> </li> <li><p>In bash, sh, zsh, or ksh:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ FORT_FMT_RECL=length-in-bytes $ export FORT_FMT_RECL </pre></div> </div> </li> </ul> </section> <section id="gmon-out-prefix"> <h3><span class="section-number">12.3.3. </span>GMON_OUT_PREFIX<a class="headerlink" href="#gmon-out-prefix" title="Permalink to this headline"></a></h3> <p><code class="docutils literal notranslate"><span class="pre">GMON_OUT_PREFIX</span></code> specifies the name of the output file for programs that are compiled and linked with the <code class="docutils literal notranslate"><span class="pre">-pg</span></code> option. The default name is <code class="docutils literal notranslate"><span class="pre">gmon.out</span></code>.</p> <p>If <code class="docutils literal notranslate"><span class="pre">GMON_OUT_PREFIX</span></code> is set, the name of the output file has <code class="docutils literal notranslate"><span class="pre">GMON_OUT_PREFIX</span></code> as a prefix. Further, the suffix is the pid of the running process. The prefix and suffix are separated by a dot. For example, if the output file is <code class="docutils literal notranslate"><span class="pre">mygmon</span></code>, then the full filename may look something similar to this: <code class="docutils literal notranslate"><span class="pre">mygmon.0012348567</span></code>.</p> <p>The following example causes the NVIDIA Fortran compiler to use <code class="docutils literal notranslate"><span class="pre">nvout</span></code> as the output file for programs compiled and linked with the <code class="docutils literal notranslate"><span class="pre">-pg</span></code> option.</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ setenv GMON_OUT_PREFIX nvout </pre></div> </div> </section> <section id="ld-library-path"> <h3><span class="section-number">12.3.4. </span>LD_LIBRARY_PATH<a class="headerlink" href="#ld-library-path" title="Permalink to this headline"></a></h3> <p>The <code class="docutils literal notranslate"><span class="pre">LD_LIBRARY_PATH</span></code> variable is a colon-separated set of directories specifying where libraries should first be searched, prior to searching the standard set of directories. This variable is useful when debugging a new library or using a nonstandard library for special purposes.</p> <p>The following csh example adds the current directory to your <code class="docutils literal notranslate"><span class="pre">LD_LIBRARY_PATH</span></code> variable.</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ setenv LD_LIBRARY_PATH &quot;$LD_LIBRARY_PATH&quot;:&quot;./&quot; </pre></div> </div> </section> <section id="manpath"> <h3><span class="section-number">12.3.5. </span>MANPATH<a class="headerlink" href="#manpath" title="Permalink to this headline"></a></h3> <p>The <code class="docutils literal notranslate"><span class="pre">MANPATH</span></code> variable sets the directories that are searched for manual pages associated with the commands that the user types. When using NVIDIA HPC Compilers, it is important that you set your <code class="docutils literal notranslate"><span class="pre">PATH</span></code> to include the location of the compilers and then set the <code class="docutils literal notranslate"><span class="pre">MANPATH</span></code> variable to include the man pages associated with the products.</p> <p>The following csh example targets the Linux_x86_64 version of the compilers and enables access to the manual pages associated with them. The settings are similar for Linux_aarch64 targets:</p> <pre class="literal-block">$ set path = (/opt/nvidia/hpc_sdk/Linux_x86_64/25.1/compilers/bin $path) $ setenv MANPATH &quot;$MANPATH&quot;:/opt/nvidia/hpc_sdk/Linux_x86_64/25.1/compilers/man</pre> </section> <section id="no-stop-message"> <h3><span class="section-number">12.3.6. </span>NO_STOP_MESSAGE<a class="headerlink" href="#no-stop-message" title="Permalink to this headline"></a></h3> <p>If the <code class="docutils literal notranslate"><span class="pre">NO_STOP_MESSAGE</span></code> variable exists, the execution of a plain <code class="docutils literal notranslate"><span class="pre">STOP</span></code> statement does not produce the message FORTRAN STOP. The default behavior of the NVIDIA Fortran compiler is to issue this message.</p> </section> <section id="path"> <h3><span class="section-number">12.3.7. </span>PATH<a class="headerlink" href="#path" title="Permalink to this headline"></a></h3> <p>The <code class="docutils literal notranslate"><span class="pre">PATH</span></code> variable determines the directories that are searched for commands that the user types. When using the NVIDIA HPC compilers, it is important that you set your <code class="docutils literal notranslate"><span class="pre">PATH</span></code> to include the location of the compilers.</p> <p>The following csh example initializes path settings to use the Linux_x86_64 versions of the NVIDIA HPC Compilers. Settings for Linux_aarch64 are done similarly:</p> <pre class="literal-block">$ set path = (/opt/nvidia/hpc_sdk/Linux_x86_64/25.1/compilers/bin $path)</pre> <span class="target" id="env-vars-nv-fpu-state"></span></section> <section id="nvcompiler-fpu-state"> <h3><span class="section-number">12.3.8. </span>NVCOMPILER_FPU_STATE<a class="headerlink" href="#nvcompiler-fpu-state" title="Permalink to this headline"></a></h3> <p>The <code class="docutils literal notranslate"><span class="pre">NVCOMPILER_FPU_STATE</span></code> environment variable manages the initial state of the processor’s floating point control and status register. <code class="docutils literal notranslate"><span class="pre">NVCOMPILER_FPU_STATE</span></code> eliminates the need to compile the main entry point (c/c++/Fortran) of programs with <code class="docutils literal notranslate"><span class="pre">-M[no]daz</span></code>, <code class="docutils literal notranslate"><span class="pre">-M[no]flushz</span></code>, or <code class="docutils literal notranslate"><span class="pre">-Ktrap=</span></code> command line options, as those options can now be specified at runtime.</p> <div class="admonition note"> <p class="admonition-title">Note</p> <p>Linux only</p> <p>If the environment variable NVCOMPILER_FPU_STATE is present, all settings from the command line options <code class="docutils literal notranslate"><span class="pre">-M[no]daz</span></code>, <code class="docutils literal notranslate"><span class="pre">-M[no]flushz</span></code>, or <code class="docutils literal notranslate"><span class="pre">-Ktrap=</span></code> are ignored and the FPU is initialized according to the options specified. NVCOMPILER_FPU_STATE with no options resets the floating-point control and status register to the system defaults.</p> </div> <p>The value of <code class="docutils literal notranslate"><span class="pre">NVCOMPILER_FPU_STATE</span></code> is a comma-separated list of options. The commands for setting the environment variable follow.</p> <ul> <li><p>In csh:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ setenv NVCOMPILER_FPU_STATE option[,option...] </pre></div> </div> </li> <li><p>In bash, sh, zsh, or ksh:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ NVCOMPILER_FPU_STATE=option[,option...] $ export NVCOMPILER_FPU_STATE </pre></div> </div> </li> </ul> <p><a class="reference internal" href="#env-vars-nv-fpu-state-env-vars-nv-fpu-state-vals"><span class="std std-ref">Table 26</span></a> lists the supported values for <code class="docutils literal notranslate"><span class="pre">option</span></code>.</p> <p>By default, these options are taken from the compiler command line options <code class="docutils literal notranslate"><span class="pre">-M[no]daz</span></code>, <code class="docutils literal notranslate"><span class="pre">-M[no]flushz</span></code>, and <code class="docutils literal notranslate"><span class="pre">-Ktrap=</span></code>.</p> <table class="table-no-stripes docutils align-default" id="env-vars-nv-fpu-state-env-vars-nv-fpu-state-vals"> <caption><span class="caption-text">Table 26. Supported NVCOMPILER_FPU_STATE options</span><a class="headerlink" href="#env-vars-nv-fpu-state-env-vars-nv-fpu-state-vals" title="Permalink to this table"></a></caption> <colgroup> <col style="width: 9%" /> <col style="width: 91%" /> </colgroup> <tbody> <tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">fp</span></code></p></td> <td><p>Shorthand for inv,divz,ovf</p></td> </tr> <tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">inv</span></code></p></td> <td><p>Raise exception on floating-point invalid operation (infinity - infinity, infinity / infinity, 0 / 0, …)</p></td> </tr> <tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">invalid</span></code></p></td> <td><p>Alias for inv</p></td> </tr> <tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">denorm</span></code></p></td> <td><p>Raise exception with floating-point denormalized operands (x86_64 only)</p></td> </tr> <tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">divz</span></code></p></td> <td><p>Raise exception on floating-point divide-by-zero</p></td> </tr> <tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">zero</span></code></p></td> <td><p>Alias for divz</p></td> </tr> <tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">ovf</span></code></p></td> <td><p>Raise exception on floating-point overflow in result</p></td> </tr> <tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">overflow</span></code></p></td> <td><p>Alias for ovf</p></td> </tr> <tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">unf</span></code></p></td> <td><p>Raise exception on floating-point underflow in result</p></td> </tr> <tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">underflow</span></code></p></td> <td><p>Alias for unf</p></td> </tr> <tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">inexact</span></code></p></td> <td><p>Raise exception on floating-point inexact result</p></td> </tr> <tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">daz</span></code></p></td> <td><p>Convert denormal source operands to zero</p></td> </tr> <tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">nodaz</span></code></p></td> <td><p>Do not convert denormal source operands to zero</p></td> </tr> <tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">ftz</span></code></p></td> <td><p>Flush underflow results to zero</p></td> </tr> <tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">flushz</span></code></p></td> <td><p>Alias for ftz</p></td> </tr> <tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">noftz</span></code></p></td> <td><p>Do not flush underflow results to zero</p></td> </tr> <tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">noflushz</span></code></p></td> <td><p>Alias for noftz</p></td> </tr> <tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">print</span></code></p></td> <td><p>Print to stderr the state of floating point control and status register before and after processing of environment variable <code class="docutils literal notranslate"><span class="pre">NVCOMPILER_FPU_STATE</span></code></p></td> </tr> <tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">debug</span></code></p></td> <td><p>Alias for print</p></td> </tr> </tbody> </table> <span class="target" id="env-vars-nv-term"></span></section> <section id="nvcompiler-term"> <h3><span class="section-number">12.3.9. </span>NVCOMPILER_TERM<a class="headerlink" href="#nvcompiler-term" title="Permalink to this headline"></a></h3> <p>The <code class="docutils literal notranslate"><span class="pre">NVCOMPILER_TERM</span></code> environment variable controls the stack traceback and just-in-time debugging functionality. The runtime libraries use the value of <code class="docutils literal notranslate"><span class="pre">NVCOMPILER_TERM</span></code> to determine what action to take when a program abnormally terminates.</p> <p>The value of <code class="docutils literal notranslate"><span class="pre">NVCOMPILER_TERM</span></code> is a comma-separated list of options. The commands for setting the environment variable follow.</p> <ul> <li><p>In csh:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ setenv NVCOMPILER_TERM option[,option...] </pre></div> </div> </li> <li><p>In bash, sh, zsh, or ksh:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ NVCOMPILER_TERM=option[,option...] $ export NVCOMPILER_TERM </pre></div> </div> </li> </ul> <p>Table 27 lists the supported values for <code class="docutils literal notranslate"><span class="pre">option</span></code>. Following the table is a complete description of each option that indicates specifically how you might apply the option.</p> <p>By default, all of these options are disabled.</p> <table class="table-no-stripes docutils align-default" id="env-vars-nv-term-env-vars-nv-term-vals"> <caption><span class="caption-text">Table 27. Supported NVCOMPILER_TERM Values</span><a class="headerlink" href="#env-vars-nv-term-env-vars-nv-term-vals" title="Permalink to this table"></a></caption> <colgroup> <col style="width: 15%" /> <col style="width: 85%" /> </colgroup> <tbody> <tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">[no]debug</span></code></p></td> <td><p>Enables/disables just-in-time debugging (debugging invoked on error)</p></td> </tr> <tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">[no]trace</span></code></p></td> <td><p>Enables/disables stack traceback on error</p></td> </tr> <tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">[no]trace-⁠fp</span></code></p></td> <td><p>Enables/disables stack traceback and printing of SIMD registers (ymm/zmm) on error (Linux x86_64 only)</p></td> </tr> <tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">[no]signal</span></code></p></td> <td><p>Enables/disables establishment of signal handlers for common signals that cause program termination</p></td> </tr> <tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">[no]abort</span></code></p></td> <td><p>Enables/disables calling the system termination routine abort()</p></td> </tr> </tbody> </table> <p><strong>[no]debug</strong></p> <p>This enables/disables just-in-time debugging. The default is <code class="docutils literal notranslate"><span class="pre">nodebug</span></code>.</p> <p>When <code class="docutils literal notranslate"><span class="pre">NVCOMPILER_TERM</span></code> is set to <code class="docutils literal notranslate"><span class="pre">debug</span></code>, the command to which <code class="docutils literal notranslate"><span class="pre">NVCOMPILER_TERM_DEBUG</span></code> is set is invoked on error.</p> <p><strong>[no]trace</strong></p> <p>This enables/disables stack traceback on error.</p> <p><strong>[no]trace-fp</strong></p> <p>This enables/disables stack traceback and printing of SIMD registers (ymm/zmm) on error. (Linux x86_64 only)</p> <p><strong>[no]signal</strong></p> <p>This enables/disables establishing signal handlers for the most common signals that cause program termination. The default is <code class="docutils literal notranslate"><span class="pre">nosignal</span></code>. Setting <code class="docutils literal notranslate"><span class="pre">trace</span></code> and <code class="docutils literal notranslate"><span class="pre">debug</span></code> automatically enables <code class="docutils literal notranslate"><span class="pre">signal</span></code>. Specifically setting <code class="docutils literal notranslate"><span class="pre">nosignal</span></code> allows you to override this behavior.</p> <p><strong>[no]abort</strong></p> <p>This enables/disables calling the system termination routine abort(). The default is <code class="docutils literal notranslate"><span class="pre">noabort</span></code>. When <code class="docutils literal notranslate"><span class="pre">noabort</span></code> is in effect the process terminates by calling <code class="docutils literal notranslate"><span class="pre">_exit(127)</span></code>.</p> <p>On Linux, when <code class="docutils literal notranslate"><span class="pre">abort</span></code> is in effect, the abort routine creates a core file and exits with code 127.</p> <p>A few runtime errors just print an error message and call <code class="docutils literal notranslate"><span class="pre">exit(127)</span></code>, regardless of the status of <code class="docutils literal notranslate"><span class="pre">NVCOMPILER_TERM</span></code>. These are mainly errors such as specifying an invalid environment variable value where a traceback would not be useful.</p> <p>If it appears that abort() does not generate core files on a Linux system, be sure to unlimit the coredumpsize. You can do this in these ways:</p> <ul> <li><p>Using csh:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ limit coredumpsize unlimited $ setenv NVCOMPILER_TERM abort </pre></div> </div> </li> <li><p>Using bash, sh, zsh, or ksh:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ ulimit -c unlimited $ export NVCOMPILER_TERM=abort </pre></div> </div> </li> </ul> <p>To debug a core file with gdb, invoke gdb with the –core option. For example, to view a core file named “core” for a program named “a.out”:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ gdb --core=core a.out </pre></div> </div> <p>For more information on why to use this variable, refer to <a class="reference internal" href="#env-vars-stack-trace-jit-dbg"><span class="std std-ref">Stack Traceback and JIT Debugging</span></a>.</p> </section> <section id="nvcompiler-term-debug"> <h3><span class="section-number">12.3.10. </span>NVCOMPILER_TERM_DEBUG<a class="headerlink" href="#nvcompiler-term-debug" title="Permalink to this headline"></a></h3> <p>The <code class="docutils literal notranslate"><span class="pre">NVCOMPILER_TERM_DEBUG</span></code> variable may be set to override the default behavior when <code class="docutils literal notranslate"><span class="pre">NVCOMPILER_TERM</span></code> is set to <code class="docutils literal notranslate"><span class="pre">debug</span></code>.</p> <p>The value of <code class="docutils literal notranslate"><span class="pre">NVCOMPILER_TERM_DEBUG</span></code> should be set to the command line used to invoke the program. For example:</p> <p>… code:: text</p> <blockquote> <div><p>gdb –quiet –pid %d</p> </div></blockquote> <p>The first occurrence of <code class="docutils literal notranslate"><span class="pre">%d</span></code> in the <code class="docutils literal notranslate"><span class="pre">NVCOMPILER_TERM_DEBUG</span></code> string is replaced by the process id. The program named in the <code class="docutils literal notranslate"><span class="pre">NVCOMPILER_TERM_DEBUG</span></code> string must be found on the current <code class="docutils literal notranslate"><span class="pre">PATH</span></code> or specified with a full path name.</p> </section> <section id="pwd"> <h3><span class="section-number">12.3.11. </span>PWD<a class="headerlink" href="#pwd" title="Permalink to this headline"></a></h3> <p>The PWD variable allows you to display the current directory.</p> </section> <section id="static-random-seed"> <h3><span class="section-number">12.3.12. </span>STATIC_RANDOM_SEED<a class="headerlink" href="#static-random-seed" title="Permalink to this headline"></a></h3> <p>You can use <code class="docutils literal notranslate"><span class="pre">STATIC_RANDOM_SEED</span></code> to force the seed returned by the Fortran 90/95 <code class="docutils literal notranslate"><span class="pre">RANDOM_SEED</span></code> intrinsic to be constant. The first call to <code class="docutils literal notranslate"><span class="pre">RANDOM_SEED</span></code> without arguments resets the random seed to a default value, then advances the seed by a variable amount based on time. Subsequent calls to <code class="docutils literal notranslate"><span class="pre">RANDOM_SEED</span></code> without arguments reset the random seed to the same initial value as the first call. Unless the time is exactly the same, each time a program is run a different random number sequence is generated. Setting the environment variable <code class="docutils literal notranslate"><span class="pre">STATIC_RANDOM_SEED</span></code> to <code class="docutils literal notranslate"><span class="pre">YES</span></code> forces the seed returned by <code class="docutils literal notranslate"><span class="pre">RANDOM_SEED</span></code> to be constant, thereby generating the same sequence of random numbers at each execution of the program.</p> </section> <section id="tmp"> <h3><span class="section-number">12.3.13. </span>TMP<a class="headerlink" href="#tmp" title="Permalink to this headline"></a></h3> <p>You can use <code class="docutils literal notranslate"><span class="pre">TMP</span></code> to specify the directory to use for placement of any temporary files created during execution of the NVIDIA HPC Compilers. This variable is interchangeable with <code class="docutils literal notranslate"><span class="pre">TMPDIR</span></code>.</p> </section> <section id="tmpdir"> <h3><span class="section-number">12.3.14. </span>TMPDIR<a class="headerlink" href="#tmpdir" title="Permalink to this headline"></a></h3> <p>You can use <code class="docutils literal notranslate"><span class="pre">TMPDIR</span></code> to specify the directory to use for placement of any temporary files created during execution of the NVIDIA HPC Compilers.</p> </section> </section> <section id="using-environment-modules-on-linux"> <h2><span class="section-number">12.4. </span>Using Environment Modules on Linux<a class="headerlink" href="#using-environment-modules-on-linux" title="Permalink to this headline"></a></h2> <p>On Linux, if you use the Environment Modules package, that is, the <code class="docutils literal notranslate"><span class="pre">module</span> <span class="pre">load</span></code> command, the NVIDIA HPC Compilers include a script to set up the appropriate module files. The install script will generate environment module files for you as part of the set up process.</p> <p>Assuming your installation base directory is <code class="docutils literal notranslate"><span class="pre">/opt/nvidia/hpc_sdk</span></code>, the environment modules will be installed under <code class="docutils literal notranslate"><span class="pre">/opt/nvidia/hpc_sdk/modulefiles</span></code>. There will be three sets of module files:</p> <ol class="arabic"> <li><p>nvhpc</p> <p>Adds environment variable settings for the NVIDIA HPC Compilers, CUDA libraries, and additional libraries such as MPI, NCCL, and NVSHMEM.</p> </li> <li><p>nvhpc-nompi</p> <p>Adds environment variable settings for the NVIDIA HPC Compilers, CUDA libraries, and additional libraries such as NCCL and NVSHMEM. This will not include MPI, if you wish to use an alternate MPI implementation.</p> </li> <li><p>nvhpc-byo-compilers</p> <p>Adds environment variable settings for the CUDA libraries and additional libraries such as NCCL and NVSHMEM. This will not include the NVIDIA HPC Compilers nor MPI, if you wish to use alternate compilers and MPI.</p> </li> </ol> <p>You can load the nvhpc environment module for the 20.11 release as follows:</p> <pre class="literal-block">$ module load nvhpc/25.1</pre> <p>To see what versions of nvhpc are available on this system, use this command:</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="n">$</span><span class="w"> </span><span class="k">module</span><span class="w"> </span><span class="n">avail</span><span class="w"> </span><span class="n">nvhpc</span><span class="w"></span> </pre></div> </div> <p>The <code class="docutils literal notranslate"><span class="pre">module</span> <span class="pre">load</span></code> command sets or modifies the environment variables as indicated in the following table.</p> <table class="table-no-stripes docutils align-default"> <colgroup> <col style="width: 17%" /> <col style="width: 83%" /> </colgroup> <thead> <tr class="row-odd"><th class="head"><p>This Environment Variable…</p></th> <th class="head"><p>Is set or modified by the module load command</p></th> </tr> </thead> <tbody> <tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">CC</span></code></p></td> <td><p>Full path to nvc (nvhpc and nvhpc-nompi only)</p></td> </tr> <tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">CPATH</span></code></p></td> <td><p>Prepends the math libraries include directory, the MPI include directory (nvhpc only), and NCCL and NVSHMEM include directories</p></td> </tr> <tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">CPP</span></code></p></td> <td><p>C preprocessor, normally cpp (nvhpc and nvhpc-nompi only)</p></td> </tr> <tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">CXX</span></code></p></td> <td><p>Path to nvc++ (nvhpc and nvhpc-nompi only)</p></td> </tr> <tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">FC</span></code></p></td> <td><p>Full path to nvfortran (nvhpc and nvhpc-nompi only)</p></td> </tr> <tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">F90</span></code></p></td> <td><p>Full path to nvfortran (nvhpc and nvhpc-nompi only)</p></td> </tr> <tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">F77</span></code></p></td> <td><p>Full path to nvfortran (nvhpc and nvhpc-nompi only)</p></td> </tr> <tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">LD_LIBRARY_PATH</span></code></p></td> <td><p>Prepends the CUDA library directory, the NVIDIA HPC Compilers library directory (nvhpc and nvhpc-nompi only), math libraries library directory, MPI library directory (nvhpc only), and NCCL and NVSHMEM library directories</p></td> </tr> <tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">MANPATH</span></code></p></td> <td><p>Prepends the NVIDIA HPC Compilers man page directory (nvhpc and nvhpc-nompi only)</p></td> </tr> <tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">OPAL_PREFIX</span></code></p></td> <td><p>Full path to the MPI directory (nvhpc only), e.g. /opt/nvidia/hpc_sdk/Linux_x86_64/25.1/comm_libs/mpi</p></td> </tr> <tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">PATH</span></code></p></td> <td><p>Prepends the CUDA bin directory, the MPI bin directory (nvhpc only), and the NVIDIA HPC Compilers bin directory (nvhpc and nvhpc-nompi only)</p></td> </tr> </tbody> </table> <div class="admonition note"> <p class="admonition-title">Note</p> <p>NVIDIA does not provide support for the Environment Modules package. For more information about the package, go to: <a class="reference external" href="http://modules.sourceforge.net">http://modules.sourceforge.net</a>.</p> </div> <span class="target" id="env-vars-stack-trace-jit-dbg"></span></section> <section id="stack-traceback-and-jit-debugging"> <h2><span class="section-number">12.5. </span>Stack Traceback and JIT Debugging<a class="headerlink" href="#stack-traceback-and-jit-debugging" title="Permalink to this headline"></a></h2> <p>When a programming error results in a runtime error message or an application exception, a program will usually exit, perhaps with an error message. The NVIDIA HPC Compilers runtime library includes a mechanism to override this default action and instead print a stack traceback, start a debugger, or, on Linux, create a core file for post-mortem debugging.</p> <p>The stack traceback and just-in-time debugging functionality is controlled by an environment variable, <code class="docutils literal notranslate"><span class="pre">NVCOMPILER_TERM</span></code>, described in <a class="reference internal" href="#env-vars-nv-term"><span class="std std-ref">NVCOMPILER_TERM</span></a>. The runtime libraries use the value of <code class="docutils literal notranslate"><span class="pre">NVCOMPILER_TERM</span></code> to determine what action to take when a program abnormally terminates.</p> <p>When the NVIDIA HPC Compilers runtime library detects an error or catches a signal, it calls the routine <code class="docutils literal notranslate"><span class="pre">nvcompiler_stop_here()</span></code> prior to generating a stack traceback or starting the debugger. The <code class="docutils literal notranslate"><span class="pre">nvcompiler_stop_here()</span></code> routine is a convenient spot to set a breakpoint when debugging a program.</p> <span class="target" id="deploy-dist-files"></span></section> </section> <section id="distributing-files-deployment"> <h1><span class="section-number">13. </span>Distributing Files - Deployment<a class="headerlink" href="#distributing-files-deployment" title="Permalink to this headline"></a></h1> <p>Once you have successfully built, debugged and tuned your application, you may want to distribute it to users who need to run it on a variety of systems. This section addresses how to effectively distribute applications built using NVIDIA HPC Compilers. The application must be installed in such a way that it executes accurately on a system other than the one on which it was built, and which may be configured differently.</p> <section id="deploying-applications-on-linux"> <h2><span class="section-number">13.1. </span>Deploying Applications on Linux<a class="headerlink" href="#deploying-applications-on-linux" title="Permalink to this headline"></a></h2> <p>To successfully deploy your application on Linux, some of the issues to consider include:</p> <ul class="simple"> <li><p>Runtime Libraries</p></li> <li><p>64-bit Linux Systems</p></li> <li><p>Redistribution of Files</p></li> </ul> <section id="runtime-library-considerations"> <h3><span class="section-number">13.1.1. </span>Runtime Library Considerations<a class="headerlink" href="#runtime-library-considerations" title="Permalink to this headline"></a></h3> <p>On Linux systems, the system runtime libraries can be linked to an application either statically or dynamically. For example, for the C runtime library, <code class="docutils literal notranslate"><span class="pre">libc</span></code>, you can use either the static version <code class="docutils literal notranslate"><span class="pre">libc.a</span></code> or the shared object version <code class="docutils literal notranslate"><span class="pre">libc.so</span></code>. If the application is intended to run on Linux systems other than the one on which it was built, it is generally safer to use the shared object version of the library. This approach ensures that the application uses a version of the library that is compatible with the system on which the application is running. Further, it works best when the application is linked on a system that has an equivalent or earlier version of the system software than the system on which the application will be run.</p> <div class="admonition note"> <p class="admonition-title">Note</p> <p>Building on a newer system and running the application on an older system may not produce the desired output.</p> </div> <p>To use the shared object version of a library, the application must also link to shared object versions of the NVIDIA HPC Compilers runtime libraries. To execute an application built in such a way on a system on which NVIDIA HPC Compilers are <em>not</em> installed, those shared objects must be available.To build using the shared object versions of the runtime libraries, use the <code class="docutils literal notranslate"><span class="pre">-Bdynamic</span></code> option, as shown here:</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="n">$</span><span class="w"> </span><span class="n">nvfortran</span><span class="w"> </span><span class="o">-</span><span class="n">Bdynamic</span><span class="w"> </span><span class="n">myprog</span><span class="p">.</span><span class="n">f90</span><span class="w"></span> </pre></div> </div> </section> <section id="bit-linux-considerations"> <h3><span class="section-number">13.1.2. </span>64-bit Linux Considerations<a class="headerlink" href="#bit-linux-considerations" title="Permalink to this headline"></a></h3> <p>On 64-bit Linux systems, 64-bit applications that use the <code class="docutils literal notranslate"><span class="pre">-⁠mcmodel=medium</span></code> option sometimes cannot be successfully linked statically. Therefore, users with executables built with the <code class="docutils literal notranslate"><span class="pre">-⁠mcmodel=medium</span></code> option may need to use shared libraries, linking dynamically. Also, runtime libraries built using the <code class="docutils literal notranslate"><span class="pre">-⁠fpic</span></code> option use 32-bit offsets, so they sometimes need to reside near other runtime <code class="docutils literal notranslate"><span class="pre">libs</span></code> in a shared area of Linux program memory.</p> <div class="admonition note"> <p class="admonition-title">Note</p> <p>If your application is linked dynamically using shared objects, then the shared object versions of the NVIDIA HPC Compilers runtime are required.</p> </div> </section> <section id="linux-redistributable-files"> <h3><span class="section-number">13.1.3. </span>Linux Redistributable Files<a class="headerlink" href="#linux-redistributable-files" title="Permalink to this headline"></a></h3> <p>The method for installing the shared object versions of the runtime libraries required for applications built with NVIDIA HPC Compilers is manual distribution.</p> <p>When the NVIDIA HPC Compilers are installed, there are directories that have a name that begins with <code class="docutils literal notranslate"><span class="pre">REDIST</span></code>; these directories contain the redistributed shared object libraries. These may be redistributed by licensed NVIDIA HPC Compilers users under the terms of the End-User License Agreement.</p> </section> <section id="restrictions-on-linux-portability"> <h3><span class="section-number">13.1.4. </span>Restrictions on Linux Portability<a class="headerlink" href="#restrictions-on-linux-portability" title="Permalink to this headline"></a></h3> <p>You cannot expect to be able to run an executable on any given Linux machine. Portability depends on the system you build on as well as how much your program uses system routines that may have changed from Linux release to Linux release. For example, an area of significant change between some versions of Linux is in <code class="docutils literal notranslate"><span class="pre">libpthread.so</span></code> and <code class="docutils literal notranslate"><span class="pre">libnuma.so</span></code>. NVIDIA HPC Compilers use these dynamically linked libraries for the options <code class="docutils literal notranslate"><span class="pre">-acc</span></code> (OpenACC), <code class="docutils literal notranslate"><span class="pre">-mp</span></code> (OpenMP) and <code class="docutils literal notranslate"><span class="pre">-Mconcur</span></code> (multicore auto-parallel). Statically linking these libraries may not be possible, or may result in failure at execution.</p> <p>Typically, portability is supported for forward execution, meaning running a program on the same or a later version of Linux. But not for backward compatibility, that is, running on a prior release. For example, a user who compiles and links a program under RHEL 7.2 should not expect the program to run without incident on a RHEL 5.2 system, an earlier Linux version. It <em>may</em> run, but it is less likely. Developers might consider building applications on earlier Linux versions for wider usage. Dynamic linking of Linux and gcc system routines on the platform executing the program can also reduce problems.</p> </section> <section id="licensing-for-redistributable-redist-files"> <h3><span class="section-number">13.1.5. </span>Licensing for Redistributable (REDIST) Files<a class="headerlink" href="#licensing-for-redistributable-redist-files" title="Permalink to this headline"></a></h3> <p>The files in the REDIST directories may be redistributed under the terms of the End-User License Agreement for the product in which they were included.</p> <span class="target" id="intr-lang-call"></span></section> </section> </section> <section id="inter-language-calling"> <h1><span class="section-number">14. </span>Inter-language Calling<a class="headerlink" href="#inter-language-calling" title="Permalink to this headline"></a></h1> <p>This section describes inter-language calling conventions for C, C++, and Fortran programs using the HPC compilers. Fortran 2003 ISO_C_Binding provides a mechanism to support the interoperability with C. This includes the <code class="docutils literal notranslate"><span class="pre">iso_c_binding</span></code> intrinsic module, binding labels, and the BIND attribute. Additional interoperability with C is available with Fortran 2018 and the <code class="docutils literal notranslate"><span class="pre">ISO_Fortran_binding.h</span></code> C header file. nvfortran supports both the <code class="docutils literal notranslate"><span class="pre">iso_c_binding</span></code> and the <code class="docutils literal notranslate"><span class="pre">ISO_Fortan_Binding.h</span></code> header file. In the absence of these mechanisms, the following sections describe how to call a Fortran function or subroutine from a C or C++ program and how to call a C or C++ function from a Fortran program.</p> <p>This section provides examples that use the following options related to inter-language calling.</p> <ul class="simple"> <li><p><code class="docutils literal notranslate"><span class="pre">-c</span></code></p></li> <li><p><code class="docutils literal notranslate"><span class="pre">-Mnomain</span></code></p></li> <li><p><code class="docutils literal notranslate"><span class="pre">-Miface</span></code></p></li> <li><p><code class="docutils literal notranslate"><span class="pre">-Mupcase</span></code></p></li> </ul> <section id="overview-of-calling-conventions"> <h2><span class="section-number">14.1. </span>Overview of Calling Conventions<a class="headerlink" href="#overview-of-calling-conventions" title="Permalink to this headline"></a></h2> <p>This section includes information on the following topics:</p> <ul class="simple"> <li><p>Functions and subroutines in Fortran, C, and C++</p></li> <li><p>Naming and case conversion conventions</p></li> <li><p>Compatible data types</p></li> <li><p>Argument passing and special return values</p></li> <li><p>Arrays and indexes</p></li> </ul> <p>The sections <a class="reference internal" href="#intr-lang-call-consider"><span class="std std-ref">Inter-language Calling Considerations</span></a> through <a class="reference internal" href="#intr-lang-exam-cpp-fort"><span class="std std-ref">Example – C++ Calling Fortran</span></a> describe how to perform inter-language calling using the Linux or Win64 convention.</p> <span class="target" id="intr-lang-call-consider"></span></section> <section id="inter-language-calling-considerations"> <h2><span class="section-number">14.2. </span>Inter-language Calling Considerations<a class="headerlink" href="#inter-language-calling-considerations" title="Permalink to this headline"></a></h2> <p>In general, when argument data types and function return values agree, you can call a C or C++ function from Fortran as well as call a Fortran function from C or C++. When data types for arguments do not agree, you may need to develop custom mechanisms to handle them. For example, the Fortran <code class="docutils literal notranslate"><span class="pre">COMPLEX</span></code> type has a matching type in C99 but does not have a matching type in C89; however, it is still possible to provide inter-language calls but there are no general calling conventions for such cases.</p> <ul> <li><p>If a C++ function contains objects with constructors and destructors, calling such a function from either C or Fortran is not possible unless the initialization in the main program is performed from a C++ program in which constructors and destructors are properly initialized.</p></li> <li><p>In general, you can call a C or Fortran function from C++ without problems as long as you use the extern “C” keyword to declare the function in the C++ program. This declaration prevents name mangling for the C function name. If you want to call a C++ function from C or Fortran, you also have to use the extern “C” keyword to declare the C++ function. This keeps the C++ compiler from mangling the name of the function.</p></li> <li><p>You can use the __cplusplus macro to allow a program or header file to work for both C and C++. For example, the following defines in the header file stdio.h allow this file to work for both C and C++.</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="cp">#ifndef _STDIO_H</span> <span class="cp">#define _STDIO_H</span> <span class="cp">#ifdef __cplusplus</span> <span class="k">extern</span><span class="w"> </span><span class="s">&quot;C&quot;</span><span class="w"> </span><span class="p">{</span><span class="w"></span> <span class="cp">#endif </span><span class="cm">/* __cplusplus */</span><span class="cp"></span> <span class="p">.</span><span class="w"></span> <span class="p">.</span><span class="w"> </span><span class="cm">/* Functions and data types defined... */</span><span class="w"></span> <span class="p">.</span><span class="w"></span> <span class="cp">#ifdef __cplusplus</span> <span class="p">}</span><span class="w"></span> <span class="cp">#endif </span><span class="cm">/* __cplusplus */</span><span class="cp"></span> <span class="cp">#endif</span> </pre></div> </div> </li> <li><p>C++ member functions cannot be declared <code class="docutils literal notranslate"><span class="pre">extern</span></code>, since their names will always be mangled. Therefore, C++ member functions cannot be called from C or Fortran.</p></li> </ul> <span class="target" id="intr-lang-funcs-subs"></span></section> <section id="functions-and-subroutines"> <h2><span class="section-number">14.3. </span>Functions and Subroutines<a class="headerlink" href="#functions-and-subroutines" title="Permalink to this headline"></a></h2> <p>Fortran, C, and C++ define functions and subroutines differently.</p> <p>For a Fortran program calling a C or C++ function, observe the following return value convention:</p> <ul class="simple"> <li><p>When a C or C++ function returns a value, call it from Fortran as a function.</p></li> <li><p>When a C or C++ function does not return a value, call it as a subroutine.</p></li> </ul> <p>For a C/C++ program calling a Fortran function, the call should return a similar type. <a class="reference internal" href="#intr-lang-data-types-intr-lang-data-types-tbl"><span class="std std-ref">Table 28</span></a>, <a class="reference internal" href="#intr-lang-data-types-intr-lang-data-types-tbl"><span class="std std-ref">Fortran and C/C++ Data Type Compatibility</span></a>, lists compatible types. If the call is to a Fortran subroutine, or a Fortran <code class="docutils literal notranslate"><span class="pre">CHARACTER</span></code> function, or a Fortran <code class="docutils literal notranslate"><span class="pre">COMPLEX</span></code> function, call it from C/C++ as a function that returns void. The exception to this convention is when a Fortran subroutine has alternate returns; call such a subroutine from C/C++ as a function returning <code class="docutils literal notranslate"><span class="pre">int</span></code> whose value is the value of the integer expression specified in the alternate <code class="docutils literal notranslate"><span class="pre">RETURN</span></code> statement.</p> </section> <section id="upper-and-lower-case-conventions-underscores"> <h2><span class="section-number">14.4. </span>Upper and Lower Case Conventions, Underscores<a class="headerlink" href="#upper-and-lower-case-conventions-underscores" title="Permalink to this headline"></a></h2> <p>By default on Linux and Win64 systems, all Fortran symbol names are converted to lower case. C and C++ are case sensitive, so upper-case function names stay upper-case. When you use inter-language calling, you can either name your C/C++ functions with lower-case names, or invoke the Fortran compiler command with the option <code class="docutils literal notranslate"><span class="pre">-Mupcase</span></code>, in which case it will not convert symbol names to lower-case.</p> <p>When programs are compiled using one of the HPC Fortran compilers on Linux and Win64 systems, an underscore is appended to Fortran global names (names of functions, subroutines and common blocks). This mechanism distinguishes Fortran name space from C/C++ name space. Use these naming conventions:</p> <ul class="simple"> <li><p>If you call a C/C++ function from Fortran, you should rename the C/C++ function by appending an underscore or use <code class="docutils literal notranslate"><span class="pre">bind(c)</span></code> in the Fortran program.</p></li> <li><p>If you call a Fortran function from C/C++, you should append an underscore to the Fortran function name in the calling program.</p></li> </ul> </section> <section id="compatible-data-types"> <h2><span class="section-number">14.5. </span>Compatible Data Types<a class="headerlink" href="#compatible-data-types" title="Permalink to this headline"></a></h2> <p><a class="reference internal" href="#intr-lang-data-types-intr-lang-data-types-tbl"><span class="std std-ref">Table 28</span></a> shows compatible data types between Fortran and C/C++. <a class="reference internal" href="#intr-lang-data-types-intr-lang-data-types-repr-tbl"><span class="std std-ref">Table 29</span></a>, <a class="reference internal" href="#intr-lang-data-types-intr-lang-data-types-repr-tbl"><span class="std std-ref">Fortran and C/C++ Representation of the COMPLEX Type</span></a> shows how the Fortran <code class="docutils literal notranslate"><span class="pre">COMPLEX</span></code> type may be represented in C/C++.</p> <div class="admonition tip"> <p class="admonition-title">Tip</p> <p>If you can make your function/subroutine parameters as well as your return values match types, you should be able to use inter-language calling.</p> </div> <table class="table-no-stripes docutils align-default" id="intr-lang-data-types-intr-lang-data-types-tbl"> <caption><span class="caption-text">Table 28. Fortran and C/C++ Data Type Compatibility</span><a class="headerlink" href="#intr-lang-data-types-intr-lang-data-types-tbl" title="Permalink to this table"></a></caption> <colgroup> <col style="width: 43%" /> <col style="width: 36%" /> <col style="width: 21%" /> </colgroup> <thead> <tr class="row-odd"><th class="head"><p>Fortran Type (lower case)</p></th> <th class="head"><p>C/C++ Type</p></th> <th class="head"><p>Size (bytes)</p></th> </tr> </thead> <tbody> <tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">character</span> <span class="pre">x</span></code></p></td> <td><p><code class="docutils literal notranslate"><span class="pre">char</span> <span class="pre">x</span></code></p></td> <td><p>1</p></td> </tr> <tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">character*n</span> <span class="pre">x</span></code></p></td> <td><p><code class="docutils literal notranslate"><span class="pre">char</span> <span class="pre">x[n]</span></code></p></td> <td><p>n</p></td> </tr> <tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">real</span> <span class="pre">x</span></code></p></td> <td><p><code class="docutils literal notranslate"><span class="pre">float</span> <span class="pre">x</span></code></p></td> <td><p>4</p></td> </tr> <tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">real*4</span> <span class="pre">x</span></code></p></td> <td><p><code class="docutils literal notranslate"><span class="pre">float</span> <span class="pre">x</span></code></p></td> <td><p>4</p></td> </tr> <tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">real*8</span> <span class="pre">x</span></code></p></td> <td><p><code class="docutils literal notranslate"><span class="pre">double</span> <span class="pre">x</span></code></p></td> <td><p>8</p></td> </tr> <tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">double</span> <span class="pre">precision</span></code></p></td> <td><p><code class="docutils literal notranslate"><span class="pre">double</span> <span class="pre">x</span></code></p></td> <td><p>8</p></td> </tr> <tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">integer</span> <span class="pre">x</span></code></p></td> <td><p><code class="docutils literal notranslate"><span class="pre">int</span> <span class="pre">x</span></code></p></td> <td><p>4</p></td> </tr> <tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">integer*1</span> <span class="pre">x</span></code></p></td> <td><p><code class="docutils literal notranslate"><span class="pre">signed</span> <span class="pre">char</span> <span class="pre">x</span></code></p></td> <td><p>1</p></td> </tr> <tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">integer*2</span> <span class="pre">x</span></code></p></td> <td><p><code class="docutils literal notranslate"><span class="pre">short</span> <span class="pre">x</span></code></p></td> <td><p>2</p></td> </tr> <tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">integer*4</span> <span class="pre">x</span></code></p></td> <td><p><code class="docutils literal notranslate"><span class="pre">int</span> <span class="pre">x</span></code></p></td> <td><p>4</p></td> </tr> <tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">integer*8</span> <span class="pre">x</span></code></p></td> <td><p><code class="docutils literal notranslate"><span class="pre">long</span> <span class="pre">long</span> <span class="pre">x</span></code></p></td> <td><p>8</p></td> </tr> <tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">logical</span> <span class="pre">x</span></code></p></td> <td><p><code class="docutils literal notranslate"><span class="pre">int</span> <span class="pre">x</span></code></p></td> <td><p>4</p></td> </tr> <tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">logical*1</span> <span class="pre">x</span></code></p></td> <td><p><code class="docutils literal notranslate"><span class="pre">char</span> <span class="pre">x</span></code></p></td> <td><p>1</p></td> </tr> <tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">logical*2</span> <span class="pre">x</span></code></p></td> <td><p><code class="docutils literal notranslate"><span class="pre">short</span> <span class="pre">x</span></code></p></td> <td><p>2</p></td> </tr> <tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">logical*4</span></code></p></td> <td><p><code class="docutils literal notranslate"><span class="pre">int</span> <span class="pre">x</span></code></p></td> <td><p>4</p></td> </tr> <tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">logical*8</span></code></p></td> <td><p><code class="docutils literal notranslate"><span class="pre">long</span> <span class="pre">x</span></code></p></td> <td><p>8</p></td> </tr> </tbody> </table> <table class="table-no-stripes docutils align-default" id="intr-lang-data-types-intr-lang-data-types-repr-tbl"> <caption><span class="caption-text">Table 29. Fortran and C/C++ Representation of the COMPLEX Type</span><a class="headerlink" href="#intr-lang-data-types-intr-lang-data-types-repr-tbl" title="Permalink to this table"></a></caption> <colgroup> <col style="width: 33%" /> <col style="width: 38%" /> <col style="width: 28%" /> </colgroup> <thead> <tr class="row-odd"><th class="head"><p>Fortran Type (lower case)</p></th> <th class="head"><p>C/C++ Type</p></th> <th class="head"><p>Size (bytes)</p></th> </tr> </thead> <tbody> <tr class="row-even"><td rowspan="2"><p><code class="docutils literal notranslate"><span class="pre">complex</span> <span class="pre">x</span></code></p></td> <td><p><code class="docutils literal notranslate"><span class="pre">struct</span> <span class="pre">{float</span> <span class="pre">r,i;}</span> <span class="pre">x;</span></code></p></td> <td><p>8</p></td> </tr> <tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">float</span> <span class="pre">complex</span> <span class="pre">x;</span></code></p></td> <td><p>8</p></td> </tr> <tr class="row-even"><td rowspan="2"><p><code class="docutils literal notranslate"><span class="pre">complex*8</span> <span class="pre">x</span></code></p></td> <td><p><code class="docutils literal notranslate"><span class="pre">struct</span> <span class="pre">{float</span> <span class="pre">r,i;}</span> <span class="pre">x;</span></code></p></td> <td><p>8</p></td> </tr> <tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">float</span> <span class="pre">complex</span> <span class="pre">x;</span></code></p></td> <td><p>8</p></td> </tr> <tr class="row-even"><td rowspan="2"><p><code class="docutils literal notranslate"><span class="pre">double</span> <span class="pre">complex</span> <span class="pre">x</span></code></p></td> <td><p><code class="docutils literal notranslate"><span class="pre">struct</span> <span class="pre">{double</span> <span class="pre">dr,di;}</span> <span class="pre">x;</span></code></p></td> <td><p>16</p></td> </tr> <tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">double</span> <span class="pre">complex</span> <span class="pre">x;</span></code></p></td> <td><p>16</p></td> </tr> <tr class="row-even"><td rowspan="2"><p><code class="docutils literal notranslate"><span class="pre">complex</span> <span class="pre">\*16</span> <span class="pre">x</span></code></p></td> <td><p><code class="docutils literal notranslate"><span class="pre">struct</span> <span class="pre">{double</span> <span class="pre">dr,di;}</span> <span class="pre">x;</span></code></p></td> <td><p>16</p></td> </tr> <tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">double</span> <span class="pre">complex</span> <span class="pre">x;</span></code></p></td> <td><p>16</p></td> </tr> </tbody> </table> <div class="admonition note"> <p class="admonition-title">Note</p> <p>For C/C++, the <code class="docutils literal notranslate"><span class="pre">complex</span></code> type implies C99 or later.</p> </div> <section id="fortran-named-common-blocks"> <h3><span class="section-number">14.5.1. </span>Fortran Named Common Blocks<a class="headerlink" href="#fortran-named-common-blocks" title="Permalink to this headline"></a></h3> <p>A named Fortran common block can be represented in C/C++ by a structure whose members correspond to the members of the common block. The name of the structure in C/C++ must have the added underscore. For example, here is a Fortran common block:</p> <div class="highlight-fortran notranslate"><div class="highlight"><pre><span></span><span class="kt">INTEGER </span><span class="n">I</span><span class="w"></span> <span class="kt">COMPLEX </span><span class="n">C</span><span class="w"></span> <span class="kt">DOUBLE COMPLEX </span><span class="n">CD</span><span class="w"></span> <span class="kt">DOUBLE PRECISION </span><span class="n">D</span><span class="w"></span> <span class="k">COMMON</span><span class="w"> </span><span class="o">/</span><span class="n">COM</span><span class="o">/</span><span class="w"> </span><span class="n">i</span><span class="p">,</span><span class="w"> </span><span class="n">c</span><span class="p">,</span><span class="w"> </span><span class="n">cd</span><span class="p">,</span><span class="w"> </span><span class="n">d</span><span class="w"></span> </pre></div> </div> <p>This Fortran Common Block is represented in C with the following equivalent:</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="k">extern</span><span class="w"> </span><span class="k">struct</span><span class="w"> </span><span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">i</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="k">struct</span><span class="w"> </span><span class="p">{</span><span class="kt">float</span><span class="w"> </span><span class="n">real</span><span class="p">,</span><span class="w"> </span><span class="n">imag</span><span class="p">;}</span><span class="w"> </span><span class="n">c</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="k">struct</span><span class="w"> </span><span class="p">{</span><span class="kt">double</span><span class="w"> </span><span class="n">real</span><span class="p">,</span><span class="w"> </span><span class="n">imag</span><span class="p">;}</span><span class="w"> </span><span class="n">cd</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="kt">double</span><span class="w"> </span><span class="n">d</span><span class="p">;</span><span class="w"></span> <span class="p">}</span><span class="w"> </span><span class="n">com_</span><span class="p">;</span><span class="w"></span> </pre></div> </div> <p>This same Fortran Common Block is represented in C++ with the following equivalent:</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="k">extern</span><span class="w"> </span><span class="s">&quot;C&quot;</span><span class="w"> </span><span class="k">struct</span><span class="w"> </span><span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">i</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="k">struct</span><span class="w"> </span><span class="p">{</span><span class="kt">float</span><span class="w"> </span><span class="n">real</span><span class="p">,</span><span class="w"> </span><span class="n">imag</span><span class="p">;}</span><span class="w"> </span><span class="n">c</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="k">struct</span><span class="w"> </span><span class="p">{</span><span class="kt">double</span><span class="w"> </span><span class="n">real</span><span class="p">,</span><span class="w"> </span><span class="n">imag</span><span class="p">;}</span><span class="w"> </span><span class="n">cd</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="kt">double</span><span class="w"> </span><span class="n">d</span><span class="p">;</span><span class="w"></span> <span class="p">}</span><span class="w"> </span><span class="n">com_</span><span class="p">;</span><span class="w"></span> </pre></div> </div> <div class="admonition tip"> <p class="admonition-title">Tip</p> <p>For global or external data sharing, <code class="docutils literal notranslate"><span class="pre">extern</span> <span class="pre">&quot;C&quot;</span></code> is not required.</p> </div> </section> </section> <section id="argument-passing-and-return-values"> <h2><span class="section-number">14.6. </span>Argument Passing and Return Values<a class="headerlink" href="#argument-passing-and-return-values" title="Permalink to this headline"></a></h2> <p>In Fortran, arguments are passed by reference, that is, the address of the argument is passed, rather than the argument itself. In C/C++, arguments are passed by value, except for strings and arrays, which are passed by reference. Due to the flexibility provided in C/C++, you can work around these differences. Solving the parameter passing differences generally involves intelligent use of the <code class="docutils literal notranslate"><span class="pre">&amp;</span></code> and <code class="docutils literal notranslate"><span class="pre">*</span></code> operators in argument passing when C/C++ calls Fortran and in argument declarations when Fortran calls C/C++.</p> <p>For strings declared in Fortran as type <code class="docutils literal notranslate"><span class="pre">CHARACTER</span></code>, an argument representing the length of the string is also passed to a calling function.</p> <p>On Linux systems, the compiler places the length argument(s) at the end of the parameter list, following the other formal arguments.</p> <p>The length argument is passed by value, not by reference.</p> <section id="passing-by-value-val"> <h3><span class="section-number">14.6.1. </span>Passing by Value (%VAL)<a class="headerlink" href="#passing-by-value-val" title="Permalink to this headline"></a></h3> <p>When passing parameters from a Fortran subprogram to a C/C++ function, it is possible to pass by value using the <code class="docutils literal notranslate"><span class="pre">%VAL</span></code> function. If you enclose a Fortran parameter with <code class="docutils literal notranslate"><span class="pre">%VAL()</span></code>, the parameter is passed by value. For example, the following call passes the integer <code class="docutils literal notranslate"><span class="pre">i</span></code> and the logical <code class="docutils literal notranslate"><span class="pre">bvar</span></code> by value.</p> <div class="highlight-fortran notranslate"><div class="highlight"><pre><span></span><span class="kt">integer</span><span class="o">*</span><span class="mi">1</span><span class="w"> </span><span class="n">i</span><span class="w"></span> <span class="kt">logical</span><span class="o">*</span><span class="mi">1</span><span class="w"> </span><span class="n">bvar</span><span class="w"></span> <span class="k">call </span><span class="n">cvalue</span><span class="w"> </span><span class="p">(%</span><span class="n">VAL</span><span class="p">(</span><span class="n">i</span><span class="p">),</span><span class="w"> </span><span class="p">%</span><span class="n">VAL</span><span class="p">(</span><span class="n">bvar</span><span class="p">))</span><span class="w"></span> </pre></div> </div> </section> <section id="character-return-values"> <h3><span class="section-number">14.6.2. </span>Character Return Values<a class="headerlink" href="#character-return-values" title="Permalink to this headline"></a></h3> <p><a class="reference internal" href="#intr-lang-funcs-subs"><span class="std std-ref">Functions and Subroutines</span></a> describes the general rules for return values for C/C++ and Fortran inter-language calling. There is a special return value to consider. When a Fortran function returns a character, two arguments need to be added at the beginning of the C/C++ calling function’s argument list:</p> <ul class="simple"> <li><p>The address of the return character or characters</p></li> <li><p>The length of the return character</p></li> </ul> <p>The following example illustrates the extra parameters, <code class="docutils literal notranslate"><span class="pre">tmp</span></code> and <code class="docutils literal notranslate"><span class="pre">10</span></code>, supplied by the caller:</p> <p class="title sectiontitle rubric" id="character-return-parameters">Character Return Parameters</p> <div class="highlight-fortran notranslate"><div class="highlight"><pre><span></span><span class="c">! Fortran function returns a character</span> <span class="kt">CHARACTER</span><span class="o">*</span><span class="p">(</span><span class="o">*</span><span class="p">)</span><span class="w"> </span><span class="k">FUNCTION </span><span class="n">CHF</span><span class="p">(</span><span class="n">C1</span><span class="p">,</span><span class="n">I</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="kt">CHARACTER</span><span class="o">*</span><span class="p">(</span><span class="o">*</span><span class="p">)</span><span class="w"> </span><span class="n">C1</span><span class="w"></span> <span class="w"> </span><span class="kt">INTEGER </span><span class="n">I</span><span class="w"></span> <span class="k">END</span><span class="w"></span> </pre></div> </div> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="cm">/* C declaration of Fortran function */</span><span class="w"></span> <span class="k">extern</span><span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="nf">chf_</span><span class="p">();</span><span class="w"></span> <span class="kt">char</span><span class="w"> </span><span class="n">tmp</span><span class="p">[</span><span class="mi">10</span><span class="p">];</span><span class="w"></span> <span class="kt">char</span><span class="w"> </span><span class="n">c1</span><span class="p">[</span><span class="mi">9</span><span class="p">];</span><span class="w"></span> <span class="kt">int</span><span class="w"> </span><span class="n">i</span><span class="p">;</span><span class="w"></span> <span class="n">chf_</span><span class="p">(</span><span class="n">tmp</span><span class="p">,</span><span class="w"> </span><span class="mi">10</span><span class="p">,</span><span class="w"> </span><span class="n">c1</span><span class="p">,</span><span class="w"> </span><span class="o">&amp;</span><span class="n">i</span><span class="p">,</span><span class="w"> </span><span class="mi">9</span><span class="p">);</span><span class="w"></span> </pre></div> </div> <p>If the Fortran function is declared to return a character value of constant length, for example <code class="docutils literal notranslate"><span class="pre">CHARACTER*4</span> <span class="pre">FUNCTION</span> <span class="pre">CHF()</span></code>, the second extra parameter representing the length must still be supplied, but is not used.</p> <div class="admonition note"> <p class="admonition-title">Note</p> <p>The value of the character function is not automatically NULL-terminated.</p> </div> </section> <section id="complex-return-values"> <h3><span class="section-number">14.6.3. </span>Complex Return Values<a class="headerlink" href="#complex-return-values" title="Permalink to this headline"></a></h3> <p>When a Fortran function returns a complex value, an argument needs to be added at the beginning of the C/C++ calling function’s argument list; this argument is the address of the complex return value. <a class="reference internal" href="#intr-lang-arg-cmplx-rtn-val-complx-rtn-val-exam"><span class="std std-ref">COMPLEX Return Values</span></a> illustrates the extra parameter, <code class="docutils literal notranslate"><span class="pre">cplx</span></code>, supplied by the caller.</p> <p class="title sectiontitle rubric" id="intr-lang-arg-cmplx-rtn-val-complx-rtn-val-exam">COMPLEX Return Values</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="n">COMPLEX</span><span class="w"> </span><span class="n">FUNCTION</span><span class="w"> </span><span class="n">CF</span><span class="p">(</span><span class="n">C</span><span class="p">,</span><span class="w"> </span><span class="n">I</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="n">INTEGER</span><span class="w"> </span><span class="n">I</span><span class="w"></span> <span class="w"> </span><span class="p">.</span><span class="w"> </span><span class="p">.</span><span class="w"> </span><span class="p">.</span><span class="w"></span> <span class="n">END</span><span class="w"></span> </pre></div> </div> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="k">extern</span><span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="nf">cf_</span><span class="p">();</span><span class="w"></span> <span class="k">typedef</span><span class="w"> </span><span class="k">struct</span><span class="w"> </span><span class="p">{</span><span class="kt">float</span><span class="w"> </span><span class="n">real</span><span class="p">,</span><span class="w"> </span><span class="n">imag</span><span class="p">;}</span><span class="w"> </span><span class="n">cplx</span><span class="p">;</span><span class="w"></span> <span class="n">cplx</span><span class="w"> </span><span class="n">c1</span><span class="p">;</span><span class="w"></span> <span class="kt">int</span><span class="w"> </span><span class="n">i</span><span class="p">;</span><span class="w"></span> <span class="n">cf_</span><span class="p">(</span><span class="o">&amp;</span><span class="n">c1</span><span class="p">,</span><span class="w"> </span><span class="o">&amp;</span><span class="n">i</span><span class="p">);</span><span class="w"></span> </pre></div> </div> </section> </section> <section id="array-indices"> <h2><span class="section-number">14.7. </span>Array Indices<a class="headerlink" href="#array-indices" title="Permalink to this headline"></a></h2> <p>C/C++ arrays and Fortran arrays use different default initial array index values. By default, arrays in C/C++ start at 0 and arrqays in Fortran start at 1. If you adjust your array comparisons so that a Fortran second element is compared to a C/C++ first element, and adjust similarly for other elements, you should not have problems working with this difference. If this is not satisfactory, you can declare your Fortran arrays to start at zero.</p> <p>Another difference between Fortran and C/C++ arrays is the storage method used. Fortran uses column-major order and C/C++ uses row-major order. For one-dimensional arrays, this poses no problems. For two-dimensional arrays, where there are an equal number of rows and columns, row and column indexes can simply be reversed. For arrays other than single dimensional arrays, and square two-dimensional arrays, inter-language function mixing is not recommended.</p> </section> <section id="id8"> <h2><span class="section-number">14.8. </span>Examples<a class="headerlink" href="#id8" title="Permalink to this headline"></a></h2> <p>This section contains examples that illustrate inter-language calling.</p> <section id="example-fortran-calling-c"> <h3><span class="section-number">14.8.1. </span>Example – Fortran Calling C<a class="headerlink" href="#example-fortran-calling-c" title="Permalink to this headline"></a></h3> <div class="admonition note"> <p class="admonition-title">Note</p> <p>There are other solutions to calling C from Fortran than the one presented in this section. For example, you can use the <code class="docutils literal notranslate"><span class="pre">iso_c_binding</span></code> intrinsic module which NVIDIA does support. For more information on this module and for examples of how to use it, search the web using the keyword iso_c_binding.</p> </div> <p><a class="reference internal" href="#intr-lang-exam-fort-c-intr-lang-fort-c-exam-subr"><span class="std std-ref">C function f2c_func_</span></a> shows a C function that is called by the Fortran main program shown in <a class="reference internal" href="#intr-lang-exam-fort-c-intr-lang-fort-c-exam"><span class="std std-ref">Fortran Main Program f2c_main.f</span></a>. Notice that each argument is defined as a pointer, since Fortran passes by reference. Also notice that the C function name uses all lower-case and a trailing “_”.</p> <p class="title sectiontitle rubric" id="intr-lang-exam-fort-c-intr-lang-fort-c-exam">Fortran Main Program f2c_main.f</p> <div class="highlight-fortran notranslate"><div class="highlight"><pre><span></span><span class="kt">logical</span><span class="o">*</span><span class="mi">1</span><span class="w"> </span><span class="n">bool1</span><span class="w"></span> <span class="w"> </span><span class="kt">character </span><span class="n">letter1</span><span class="w"></span> <span class="w"> </span><span class="kt">integer</span><span class="o">*</span><span class="mi">4</span><span class="w"> </span><span class="n">numint1</span><span class="p">,</span><span class="w"> </span><span class="n">numint2</span><span class="w"></span> <span class="w"> </span><span class="kt">real </span><span class="n">numfloat1</span><span class="w"></span> <span class="w"> </span><span class="kt">double precision </span><span class="n">numdoub1</span><span class="w"></span> <span class="w"> </span><span class="kt">integer</span><span class="o">*</span><span class="mi">2</span><span class="w"> </span><span class="n">numshor1</span><span class="w"></span> <span class="w"> </span><span class="k">external </span><span class="n">f2c_func</span><span class="w"></span> <span class="w"> </span><span class="k">call </span><span class="n">f2c_func</span><span class="p">(</span><span class="n">bool1</span><span class="p">,</span><span class="w"> </span><span class="n">letter1</span><span class="p">,</span><span class="w"> </span><span class="n">numint1</span><span class="p">,</span><span class="w"> </span><span class="n">numint2</span><span class="p">,</span><span class="w"> </span><span class="n">numfloat1</span><span class="p">,</span><span class="w"> </span><span class="n">numdoub1</span><span class="p">,</span><span class="w"> </span><span class="n">numshor1</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="k">write</span><span class="p">(</span><span class="w"> </span><span class="o">*</span><span class="p">,</span><span class="w"> </span><span class="s2">&quot;(L2, A2, I5, I5, F6.1, F6.1, I5)&quot;</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">bool1</span><span class="p">,</span><span class="w"> </span><span class="n">letter1</span><span class="p">,</span><span class="w"> </span><span class="n">numint1</span><span class="p">,</span><span class="w"> </span><span class="n">numint2</span><span class="p">,</span><span class="w"> </span><span class="n">numfloat1</span><span class="p">,</span><span class="n">numdoub1</span><span class="p">,</span><span class="w"> </span><span class="n">numshor1</span><span class="w"></span> <span class="w"> </span><span class="k">end</span><span class="w"></span> </pre></div> </div> <p class="title sectiontitle rubric" id="intr-lang-exam-fort-c-intr-lang-fort-c-exam-subr">C function f2c_func_</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="cp">#define TRUE 0xff</span> <span class="cp">#define FALSE 0</span> <span class="kt">void</span><span class="w"> </span><span class="nf">f2c_func_</span><span class="p">(</span><span class="w"> </span><span class="n">bool1</span><span class="p">,</span><span class="w"> </span><span class="n">letter1</span><span class="p">,</span><span class="w"> </span><span class="n">numint1</span><span class="p">,</span><span class="w"> </span><span class="n">numint2</span><span class="p">,</span><span class="w"> </span><span class="n">numfloat1</span><span class="p">,</span>\ <span class="w"> </span><span class="n">numdoub1</span><span class="p">,</span><span class="w"> </span><span class="n">numshor1</span><span class="p">,</span><span class="w"> </span><span class="n">len_letter1</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="kt">char</span><span class="w"> </span><span class="o">*</span><span class="n">bool1</span><span class="p">,</span><span class="w"> </span><span class="o">*</span><span class="n">letter1</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="o">*</span><span class="n">numint1</span><span class="p">,</span><span class="w"> </span><span class="o">*</span><span class="n">numint2</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="kt">float</span><span class="w"> </span><span class="o">*</span><span class="n">numfloat1</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="kt">double</span><span class="w"> </span><span class="o">*</span><span class="n">numdoub1</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="kt">short</span><span class="w"> </span><span class="o">*</span><span class="n">numshor1</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">len_letter1</span><span class="p">;</span><span class="w"></span> <span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="o">*</span><span class="n">bool1</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">TRUE</span><span class="p">;</span><span class="w"> </span><span class="o">*</span><span class="n">letter1</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="sc">&#39;v&#39;</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="o">*</span><span class="n">numint1</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">11</span><span class="p">;</span><span class="w"> </span><span class="o">*</span><span class="n">numint2</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">-44</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="o">*</span><span class="n">numfloat1</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mf">39.6</span><span class="w"> </span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="o">*</span><span class="n">numdoub1</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mf">39.2</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="o">*</span><span class="n">numshor1</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">981</span><span class="p">;</span><span class="w"></span> <span class="p">}</span><span class="w"></span> </pre></div> </div> <p>Compile and execute the program <code class="docutils literal notranslate"><span class="pre">f2c_main.f</span></code> with the call to <code class="docutils literal notranslate"><span class="pre">f2c_func\_</span></code> using the following command lines:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ nvc -c f2c_func.c $ nvfortran f2c_func.o f2c_main.f </pre></div> </div> <p>Executing the <code class="docutils literal notranslate"><span class="pre">a.out</span></code> file should produce the following output:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>T v 11 -44 39.6 39.2 981 </pre></div> </div> </section> <section id="example-c-calling-fortran"> <h3><span class="section-number">14.8.2. </span>Example - C Calling Fortran<a class="headerlink" href="#example-c-calling-fortran" title="Permalink to this headline"></a></h3> <div class="admonition note"> <p class="admonition-title">Note</p> <p>There are other solutions to calling Fortran from C than the one presented in this section. For example, you can use the <code class="docutils literal notranslate"><span class="pre">ISO_Fortran_binding.h</span></code> C header file which NVIDIA does support. For more information on this header file and for examples of how to use it, search the web using the keyword ISO_Fortran_binding.</p> </div> <p>The example <a class="reference internal" href="#intr-lang-exam-c-fort-intr-lang-c-fort-exam"><span class="std std-ref">C Main Program c2f_main.c</span></a> shows a C main program that calls the Fortran subroutine shown in <a class="reference internal" href="#intr-lang-exam-c-fort-intr-lang-c-fort-exam-sub"><span class="std std-ref">Fortran Subroutine c2f_sub.f</span></a>.</p> <ul class="simple"> <li><p>Each call uses the &amp; operator to pass by reference.</p></li> <li><p>The call to the Fortran subroutine uses all lower-case and a trailing “_”.</p></li> </ul> <p class="title sectiontitle rubric" id="intr-lang-exam-c-fort-intr-lang-c-fort-exam">C Main Program c2f_main.c</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="kt">void</span><span class="w"> </span><span class="nf">main</span><span class="w"> </span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="kt">char</span><span class="w"> </span><span class="n">bool1</span><span class="p">,</span><span class="w"> </span><span class="n">letter1</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">numint1</span><span class="p">,</span><span class="w"> </span><span class="n">numint2</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="kt">float</span><span class="w"> </span><span class="n">numfloat1</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="kt">double</span><span class="w"> </span><span class="n">numdoub1</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="kt">short</span><span class="w"> </span><span class="n">numshor1</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="k">extern</span><span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="n">c2f_func_</span><span class="p">();</span><span class="w"></span> <span class="w"> </span><span class="n">c2f_sub_</span><span class="p">(</span><span class="o">&amp;</span><span class="n">bool1</span><span class="p">,</span><span class="o">&amp;</span><span class="n">letter1</span><span class="p">,</span><span class="o">&amp;</span><span class="n">numint1</span><span class="p">,</span><span class="o">&amp;</span><span class="n">numint2</span><span class="p">,</span><span class="o">&amp;</span><span class="n">numfloat1</span><span class="p">,</span><span class="o">&amp;</span><span class="n">numdoub1</span><span class="p">,</span><span class="o">&amp;</span><span class="n">numshor1</span><span class="p">,</span><span class="w"> </span><span class="mi">1</span><span class="p">);</span><span class="w"></span> <span class="w"> </span><span class="n">printf</span><span class="p">(</span><span class="s">&quot; %s %c %d %d %3.1f %.0f %d</span><span class="se">\n</span><span class="s">&quot;</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="n">bool1</span><span class="o">?</span><span class="s">&quot;TRUE&quot;</span><span class="o">:</span><span class="s">&quot;FALSE&quot;</span><span class="p">,</span><span class="w"> </span><span class="n">letter1</span><span class="p">,</span><span class="w"> </span><span class="n">numint1</span><span class="p">,</span><span class="w"> </span><span class="n">numint2</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="n">numfloat1</span><span class="p">,</span><span class="w"> </span><span class="n">numdoub1</span><span class="p">,</span><span class="w"> </span><span class="n">numshor1</span><span class="p">);</span><span class="w"></span> <span class="p">}</span><span class="w"></span> </pre></div> </div> <p class="title sectiontitle rubric" id="intr-lang-exam-c-fort-intr-lang-c-fort-exam-sub">Fortran Subroutine c2f_sub.f</p> <div class="highlight-fortran notranslate"><div class="highlight"><pre><span></span><span class="k">subroutine </span><span class="n">c2f_func</span><span class="w"> </span><span class="p">(</span><span class="w"> </span><span class="n">bool1</span><span class="p">,</span><span class="w"> </span><span class="n">letter1</span><span class="p">,</span><span class="w"> </span><span class="n">numint1</span><span class="p">,</span><span class="w"> </span><span class="n">numint2</span><span class="p">,</span><span class="w"></span> <span class="o">+</span><span class="w"> </span><span class="n">numfloat1</span><span class="p">,</span><span class="w"> </span><span class="n">numdoub1</span><span class="p">,</span><span class="w"> </span><span class="n">numshor1</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="kt">logical</span><span class="o">*</span><span class="mi">1</span><span class="w"> </span><span class="n">bool1</span><span class="w"></span> <span class="w"> </span><span class="kt">character </span><span class="n">letter1</span><span class="w"></span> <span class="w"> </span><span class="kt">integer </span><span class="n">numint1</span><span class="p">,</span><span class="w"> </span><span class="n">numint2</span><span class="w"></span> <span class="w"> </span><span class="kt">double precision </span><span class="n">numdoub1</span><span class="w"></span> <span class="w"> </span><span class="kt">real </span><span class="n">numfloat1</span><span class="w"></span> <span class="w"> </span><span class="kt">integer</span><span class="o">*</span><span class="mi">2</span><span class="w"> </span><span class="n">numshor1</span><span class="w"></span> <span class="w"> </span><span class="n">bool1</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">.</span><span class="n">true</span><span class="p">.</span><span class="w"></span> <span class="w"> </span><span class="n">letter1</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;v&quot;</span><span class="w"></span> <span class="w"> </span><span class="n">numint1</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">11</span><span class="w"></span> <span class="w"> </span><span class="n">numint2</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">-</span><span class="mi">44</span><span class="w"></span> <span class="w"> </span><span class="n">numdoub1</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">902</span><span class="w"></span> <span class="w"> </span><span class="n">numfloat1</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">3</span><span class="mf">9.6</span><span class="w"></span> <span class="w"> </span><span class="n">numshor1</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">299</span><span class="w"></span> <span class="w"> </span><span class="k">return</span> <span class="k">end</span><span class="w"></span> </pre></div> </div> <p>To compile this Fortran subroutine and C program, use the following commands:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ nvc -c c2f_main.c $ nvfortran -Mnomain c2f_main.o c2_sub.f </pre></div> </div> <p>Executing the resulting <code class="docutils literal notranslate"><span class="pre">a.out</span></code> file should produce the following output:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>TRUE v 11 -44 39.6 902 299 </pre></div> </div> </section> <section id="example-c-calling-c"> <h3><span class="section-number">14.8.3. </span>Example – C++ Calling C<a class="headerlink" href="#example-c-calling-c" title="Permalink to this headline"></a></h3> <p><a class="reference internal" href="#intr-lang-exam-cpp-c-intr-lang-cpp-c-exam"><span class="std std-ref">C++ Main Program cp2c_main.C Calling a C Function</span></a> shows a C++ main program that calls the C function shown in <a class="reference internal" href="#intr-lang-exam-cpp-c-intr-lang-cpp-c-exam-subr"><span class="std std-ref">Simple C Function c2cp_func.c</span></a>.</p> <p class="title sectiontitle rubric" id="intr-lang-exam-cpp-c-intr-lang-cpp-c-exam">C++ Main Program cp2c_main.C Calling a C Function</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="k">extern</span><span class="w"> </span><span class="s">&quot;C&quot;</span><span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="n">cp2c_func</span><span class="p">(</span><span class="kt">int</span><span class="w"> </span><span class="n">n</span><span class="p">,</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">m</span><span class="p">,</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="o">*</span><span class="n">p</span><span class="p">);</span><span class="w"></span> <span class="cp">#include</span><span class="w"> </span><span class="cpf">&lt;iostream&gt;</span><span class="cp"></span> <span class="n">main</span><span class="p">()</span><span class="w"></span> <span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">a</span><span class="p">,</span><span class="n">b</span><span class="p">,</span><span class="n">c</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="n">a</span><span class="o">=</span><span class="mi">8</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="n">b</span><span class="o">=</span><span class="mi">2</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="n">c</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="n">cout</span><span class="w"> </span><span class="o">&lt;&lt;</span><span class="w"> </span><span class="s">&quot;main: a = &quot;</span><span class="o">&lt;&lt;</span><span class="n">a</span><span class="o">&lt;&lt;</span><span class="s">&quot; b = &quot;</span><span class="o">&lt;&lt;</span><span class="n">b</span><span class="o">&lt;&lt;</span><span class="s">&quot;ptr c = &quot;</span><span class="o">&lt;&lt;</span><span class="n">hex</span><span class="o">&lt;&lt;&amp;</span><span class="n">c</span><span class="o">&lt;&lt;</span><span class="w"> </span><span class="n">endl</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="n">cp2c_func</span><span class="p">(</span><span class="n">a</span><span class="p">,</span><span class="n">b</span><span class="p">,</span><span class="o">&amp;</span><span class="n">c</span><span class="p">);</span><span class="w"></span> <span class="w"> </span><span class="n">cout</span><span class="w"> </span><span class="o">&lt;&lt;</span><span class="w"> </span><span class="s">&quot;main: res = &quot;</span><span class="o">&lt;&lt;</span><span class="n">c</span><span class="o">&lt;&lt;</span><span class="n">endl</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="p">}</span><span class="w"></span> </pre></div> </div> <p class="title sectiontitle rubric" id="intr-lang-exam-cpp-c-intr-lang-cpp-c-exam-subr">Simple C Function c2cp_func.c</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="kt">void</span><span class="w"> </span><span class="nf">cp2c_func</span><span class="p">(</span><span class="n">num1</span><span class="p">,</span><span class="w"> </span><span class="n">num2</span><span class="p">,</span><span class="w"> </span><span class="n">res</span><span class="p">)</span><span class="w"></span> <span class="kt">int</span><span class="w"> </span><span class="n">num1</span><span class="p">,</span><span class="w"> </span><span class="n">num2</span><span class="p">,</span><span class="w"> </span><span class="o">*</span><span class="n">res</span><span class="p">;</span><span class="w"></span> <span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="n">printf</span><span class="p">(</span><span class="s">&quot;func: a = %d b = %d ptr c = %x</span><span class="se">\n</span><span class="s">&quot;</span><span class="p">,</span><span class="n">num1</span><span class="p">,</span><span class="n">num2</span><span class="p">,</span><span class="n">res</span><span class="p">);</span><span class="w"></span> <span class="w"> </span><span class="o">*</span><span class="n">res</span><span class="o">=</span><span class="n">num1</span><span class="o">/</span><span class="n">num2</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="n">printf</span><span class="p">(</span><span class="s">&quot;func: res = %d</span><span class="se">\n</span><span class="s">&quot;</span><span class="p">,</span><span class="o">*</span><span class="n">res</span><span class="p">);</span><span class="w"></span> <span class="p">}</span><span class="w"></span> </pre></div> </div> <p>To compile this C function and C++ main program, use the following commands:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ nvc -c cp2c_func.c $ nvc++ cp2c_main.C cp2c_func.o </pre></div> </div> <p>Executing the resulting a.out file should produce the following output:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>main: a = 8 b = 2 ptr c = 0xbffffb94 func: a = 8 b = 2 ptr c = bffffb94 func: res = 4 main: res = 4 </pre></div> </div> </section> <section id="id9"> <h3><span class="section-number">14.8.4. </span>Example – C Calling C ++<a class="headerlink" href="#id9" title="Permalink to this headline"></a></h3> <p>The example in <a class="reference internal" href="#intr-lang-exam-c-cpp-intr-lang-c-cpp-exam"><span class="std std-ref">C Main Program c2cp_main.c Calling a C++ Function</span></a> shows a C main program that calls the C++ function shown in <a class="reference internal" href="#intr-lang-exam-c-cpp-intr-lang-c-cpp-extern-exam"><span class="std std-ref">Simple C++ Function c2cp_func.C with Extern C</span></a>.</p> <p class="title sectiontitle rubric" id="intr-lang-exam-c-cpp-intr-lang-c-cpp-exam">C Main Program c2cp_main.c Calling a C++ Function</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="k">extern</span><span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="nf">c2cp_func</span><span class="p">(</span><span class="kt">int</span><span class="w"> </span><span class="n">a</span><span class="p">,</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">b</span><span class="p">,</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="o">*</span><span class="n">c</span><span class="p">);</span><span class="w"></span> <span class="cp">#include</span><span class="w"> </span><span class="cpf">&lt;stdio.h&gt;</span><span class="cp"></span> <span class="n">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">a</span><span class="p">,</span><span class="n">b</span><span class="p">,</span><span class="n">c</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="n">a</span><span class="o">=</span><span class="mi">8</span><span class="p">;</span><span class="w"> </span><span class="n">b</span><span class="o">=</span><span class="mi">2</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="n">printf</span><span class="p">(</span><span class="s">&quot;main: a = %d b = %d ptr c = %x</span><span class="se">\n</span><span class="s">&quot;</span><span class="p">,</span><span class="n">a</span><span class="p">,</span><span class="n">b</span><span class="p">,</span><span class="o">&amp;</span><span class="n">c</span><span class="p">);</span><span class="w"></span> <span class="w"> </span><span class="n">c2cp_func</span><span class="p">(</span><span class="n">a</span><span class="p">,</span><span class="n">b</span><span class="p">,</span><span class="o">&amp;</span><span class="n">c</span><span class="p">);</span><span class="w"></span> <span class="w"> </span><span class="n">printf</span><span class="p">(</span><span class="s">&quot;main: res = %d</span><span class="se">\n</span><span class="s">&quot;</span><span class="p">,</span><span class="n">c</span><span class="p">);</span><span class="w"></span> <span class="w"> </span><span class="p">}</span><span class="w"></span> </pre></div> </div> <p class="title sectiontitle rubric" id="intr-lang-exam-c-cpp-intr-lang-c-cpp-extern-exam">Simple C++ Function c2cp_func.C with Extern C</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="cp">#include</span><span class="w"> </span><span class="cpf">&lt;iostream&gt;</span><span class="cp"></span> <span class="k">extern</span><span class="w"> </span><span class="s">&quot;C&quot;</span><span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="n">c2cp_func</span><span class="p">(</span><span class="kt">int</span><span class="w"> </span><span class="n">num1</span><span class="p">,</span><span class="kt">int</span><span class="w"> </span><span class="n">num2</span><span class="p">,</span><span class="kt">int</span><span class="w"> </span><span class="o">*</span><span class="n">res</span><span class="p">)</span><span class="w"></span> <span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="n">cout</span><span class="w"> </span><span class="o">&lt;&lt;</span><span class="w"> </span><span class="s">&quot;func: a = &quot;</span><span class="o">&lt;&lt;</span><span class="n">num1</span><span class="o">&lt;&lt;</span><span class="s">&quot; b = &quot;</span><span class="o">&lt;&lt;</span><span class="n">num2</span><span class="o">&lt;&lt;</span><span class="s">&quot;ptr c =&quot;</span><span class="o">&lt;&lt;</span><span class="n">res</span><span class="o">&lt;&lt;</span><span class="n">endl</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="o">*</span><span class="n">res</span><span class="o">=</span><span class="n">num1</span><span class="o">/</span><span class="n">num2</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="n">cout</span><span class="w"> </span><span class="o">&lt;&lt;</span><span class="w"> </span><span class="s">&quot;func: res = &quot;</span><span class="o">&lt;&lt;</span><span class="n">res</span><span class="o">&lt;&lt;</span><span class="n">endl</span><span class="p">;</span><span class="w"></span> <span class="p">}</span><span class="w"></span> </pre></div> </div> <p>To compile this C function and C++ main program, use the following commands:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ nvc -c c2cp_main.c $ nvc++ c2cp_main.o c2cp_func.C </pre></div> </div> <p>Executing the resulting a.out file should produce the following output:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>main: a = 8 b = 2 ptr c = 0xbffffb94 func: a = 8 b = 2 ptr c = bffffb94 func: res = 4 main: res = 4 </pre></div> </div> <div class="admonition note"> <p class="admonition-title">Note</p> <p>You cannot use the extern “C” form of declaration for an object’s member functions.</p> </div> </section> <section id="id10"> <h3><span class="section-number">14.8.5. </span>Example – Fortran Calling C++<a class="headerlink" href="#id10" title="Permalink to this headline"></a></h3> <p>The Fortran main program shown in <a class="reference internal" href="#intr-lang-exam-fort-cpp-lang-fort-cpp-exam"><span class="std std-ref">Fortran Main Program f2cp_main.f calling a C++ function</span></a> calls the C++ function shown in <a class="reference internal" href="#intr-lang-exam-fort-cpp-lang-fort-cpp-exam-subr"><span class="std std-ref">C++ function f2cp_func.C</span></a> .</p> <p>Notice:</p> <ul class="simple"> <li><p>Each argument is defined as a pointer in the C++ function, since Fortran passes by reference.</p></li> <li><p>The C++ function name uses all lower-case and a trailing “_”:</p></li> </ul> <p class="title sectiontitle rubric" id="intr-lang-exam-fort-cpp-lang-fort-cpp-exam">Fortran Main Program f2cp_main.f calling a C++ function</p> <div class="highlight-fortran notranslate"><div class="highlight"><pre><span></span><span class="w"> </span><span class="kt">logical</span><span class="o">*</span><span class="mi">1</span><span class="w"> </span><span class="n">bool1</span><span class="w"></span> <span class="w"> </span><span class="kt">character </span><span class="n">letter1</span><span class="w"></span> <span class="w"> </span><span class="kt">integer</span><span class="o">*</span><span class="mi">4</span><span class="w"> </span><span class="n">numint1</span><span class="p">,</span><span class="w"> </span><span class="n">numint2</span><span class="w"></span> <span class="w"> </span><span class="kt">real </span><span class="n">numfloat1</span><span class="w"></span> <span class="w"> </span><span class="kt">double precision </span><span class="n">numdoub1</span><span class="w"></span> <span class="w"> </span><span class="kt">integer</span><span class="o">*</span><span class="mi">2</span><span class="w"> </span><span class="n">numshor1</span><span class="w"></span> <span class="k">external </span><span class="n">f2cpfunc</span><span class="w"></span> <span class="k">call </span><span class="n">f2cp_func</span><span class="w"> </span><span class="p">(</span><span class="n">bool1</span><span class="p">,</span><span class="w"> </span><span class="n">letter1</span><span class="p">,</span><span class="w"> </span><span class="n">numint1</span><span class="p">,</span><span class="w"></span> <span class="o">+</span><span class="w"> </span><span class="n">numint2</span><span class="p">,</span><span class="w"> </span><span class="n">numfloat1</span><span class="p">,</span><span class="w"> </span><span class="n">numdoub1</span><span class="p">,</span><span class="w"> </span><span class="n">numshor1</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="k">write</span><span class="p">(</span><span class="w"> </span><span class="o">*</span><span class="p">,</span><span class="w"> </span><span class="s2">&quot;(L2, A2, I5, I5, F6.1, F6.1, I5)&quot;</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">bool1</span><span class="p">,</span><span class="w"> </span><span class="n">letter1</span><span class="p">,</span><span class="w"> </span><span class="n">numint1</span><span class="p">,</span><span class="w"> </span><span class="n">numint2</span><span class="p">,</span><span class="w"> </span><span class="n">numfloat1</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">numdoub1</span><span class="p">,</span><span class="w"> </span><span class="n">numshor1</span><span class="w"></span> <span class="k">end</span><span class="w"></span> </pre></div> </div> <p class="title sectiontitle rubric" id="intr-lang-exam-fort-cpp-lang-fort-cpp-exam-subr">C++ function f2cp_func.C</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="cp">#define TRUE 0xff</span> <span class="cp">#define FALSE 0</span> <span class="k">extern</span><span class="w"> </span><span class="s">&quot;C&quot;</span><span class="w"></span> <span class="p">{</span><span class="w"></span> <span class="k">extern</span><span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="nf">f2cp_func_</span><span class="w"> </span><span class="p">(</span><span class="w"></span> <span class="w"> </span><span class="kt">char</span><span class="w"> </span><span class="o">*</span><span class="n">bool1</span><span class="p">,</span><span class="w"> </span><span class="o">*</span><span class="n">letter1</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="o">*</span><span class="n">numint1</span><span class="p">,</span><span class="w"> </span><span class="o">*</span><span class="n">numint2</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="kt">float</span><span class="w"> </span><span class="o">*</span><span class="n">numfloat1</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="kt">double</span><span class="w"> </span><span class="o">*</span><span class="n">numdoub1</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="kt">short</span><span class="w"> </span><span class="o">*</span><span class="n">numshort1</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">len_letter1</span><span class="p">)</span><span class="w"></span> <span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="o">*</span><span class="n">bool1</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">TRUE</span><span class="p">;</span><span class="w"> </span><span class="o">*</span><span class="n">letter1</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="sc">&#39;v&#39;</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="o">*</span><span class="n">numint1</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">11</span><span class="p">;</span><span class="w"> </span><span class="o">*</span><span class="n">numint2</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">-44</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="o">*</span><span class="n">numfloat1</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mf">39.6</span><span class="p">;</span><span class="w"> </span><span class="o">*</span><span class="n">numdoub1</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mf">39.2</span><span class="p">;</span><span class="w"> </span><span class="o">*</span><span class="n">numshort1</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">981</span><span class="p">;</span><span class="w"></span> <span class="p">}</span><span class="w"></span> <span class="p">}</span><span class="w"></span> </pre></div> </div> <p>Assuming the Fortran program is in a file fmain.f, and the C++ function is in a file cpfunc.C, create an executable, using the following command lines:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ nvc++ -c f2cp_func.C $ nvfortran f2cp_func.o f2cp_main.f -c++libs </pre></div> </div> <p>Executing the a.out file should produce the following output:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>T v 11 -44 39.6 39.2 981 </pre></div> </div> <span class="target" id="intr-lang-exam-cpp-fort"></span></section> <section id="id11"> <h3><span class="section-number">14.8.6. </span>Example – C++ Calling Fortran<a class="headerlink" href="#id11" title="Permalink to this headline"></a></h3> <p><a class="reference internal" href="#intr-lang-exam-cpp-fort-intr-lang-cpp-fort-exam-subr"><span class="std std-ref">Fortran Subroutine cp2f_func.f</span></a> shows a Fortran subroutine called by the C++ main program shown in <a class="reference internal" href="#intr-lang-exam-cpp-fort-intr-lang-cpp-fort-exam"><span class="std std-ref">C++ main program cp2f_main.C</span></a>. Notice that each call uses the <code class="docutils literal notranslate"><span class="pre">&amp;</span></code> operator to pass by reference. Also notice that the call to the Fortran subroutine uses all lower-case and a trailing “<code class="docutils literal notranslate"><span class="pre">_</span></code>”:</p> <p class="title sectiontitle rubric" id="intr-lang-exam-cpp-fort-intr-lang-cpp-fort-exam">C++ main program cp2f_main.C</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="cp">#include</span><span class="w"> </span><span class="cpf">&lt;iostream&gt;</span><span class="cp"></span> <span class="k">extern</span><span class="w"> </span><span class="s">&quot;C&quot;</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="k">extern</span><span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="nf">cp2f_func_</span><span class="p">(</span><span class="kt">char</span><span class="w"> </span><span class="o">*</span><span class="p">,</span><span class="kt">char</span><span class="w"> </span><span class="o">*</span><span class="p">,</span><span class="kt">int</span><span class="w"> </span><span class="o">*</span><span class="p">,</span><span class="kt">int</span><span class="w"> </span><span class="o">*</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="kt">float</span><span class="w"> </span><span class="o">*</span><span class="p">,</span><span class="kt">double</span><span class="w"> </span><span class="o">*</span><span class="p">,</span><span class="kt">short</span><span class="w"> </span><span class="o">*</span><span class="p">);</span><span class="w"> </span><span class="p">}</span><span class="w"></span> <span class="n">main</span><span class="w"> </span><span class="p">()</span><span class="w"></span> <span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="kt">char</span><span class="w"> </span><span class="n">bool1</span><span class="p">,</span><span class="w"> </span><span class="n">letter1</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">numint1</span><span class="p">,</span><span class="w"> </span><span class="n">numint2</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="kt">float</span><span class="w"> </span><span class="n">numfloat1</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="kt">double</span><span class="w"> </span><span class="n">numdoub1</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="kt">short</span><span class="w"> </span><span class="n">numshor1</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="n">cp2f_func</span><span class="p">(</span><span class="o">&amp;</span><span class="n">bool1</span><span class="p">,</span><span class="o">&amp;</span><span class="n">letter1</span><span class="p">,</span><span class="o">&amp;</span><span class="n">numint1</span><span class="p">,</span><span class="o">&amp;</span><span class="n">numint2</span><span class="p">,</span><span class="o">&amp;</span><span class="n">numfloat1</span><span class="p">,</span><span class="w"> </span><span class="o">&amp;</span><span class="n">numdoub1</span><span class="p">,</span><span class="o">&amp;</span><span class="n">numshor1</span><span class="p">);</span><span class="w"></span> <span class="w"> </span><span class="n">cout</span><span class="w"> </span><span class="o">&lt;&lt;</span><span class="w"> </span><span class="s">&quot; bool1 = &quot;</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="n">bool1</span><span class="o">?</span><span class="n">cout</span><span class="w"> </span><span class="o">&lt;&lt;</span><span class="w"> </span><span class="s">&quot;TRUE &quot;</span><span class="o">:</span><span class="n">cout</span><span class="w"> </span><span class="o">&lt;&lt;</span><span class="w"> </span><span class="s">&quot;FALSE &quot;</span><span class="p">;</span><span class="w"> </span><span class="n">cout</span><span class="w"> </span><span class="o">&lt;&lt;</span><span class="n">endl</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="n">cout</span><span class="w"> </span><span class="o">&lt;&lt;</span><span class="w"> </span><span class="s">&quot; letter1 = &quot;</span><span class="w"> </span><span class="o">&lt;&lt;</span><span class="w"> </span><span class="n">letter1</span><span class="w"> </span><span class="o">&lt;&lt;</span><span class="n">endl</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="n">cout</span><span class="w"> </span><span class="o">&lt;&lt;</span><span class="w"> </span><span class="s">&quot; numint1 = &quot;</span><span class="w"> </span><span class="o">&lt;&lt;</span><span class="w"> </span><span class="n">numint1</span><span class="w"> </span><span class="o">&lt;&lt;</span><span class="n">endl</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="n">cout</span><span class="w"> </span><span class="o">&lt;&lt;</span><span class="w"> </span><span class="s">&quot; numint2 = &quot;</span><span class="w"> </span><span class="o">&lt;&lt;</span><span class="w"> </span><span class="n">numint2</span><span class="w"> </span><span class="o">&lt;&lt;</span><span class="n">endl</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="n">cout</span><span class="w"> </span><span class="o">&lt;&lt;</span><span class="w"> </span><span class="s">&quot; numfloat1 = &quot;</span><span class="w"> </span><span class="o">&lt;&lt;</span><span class="w"> </span><span class="n">numfloat1</span><span class="w"> </span><span class="o">&lt;&lt;</span><span class="n">endl</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="n">cout</span><span class="w"> </span><span class="o">&lt;&lt;</span><span class="w"> </span><span class="s">&quot; numdoub1 = &quot;</span><span class="w"> </span><span class="o">&lt;&lt;</span><span class="w"> </span><span class="n">numdoub1</span><span class="w"> </span><span class="o">&lt;&lt;</span><span class="n">endl</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="n">cout</span><span class="w"> </span><span class="o">&lt;&lt;</span><span class="w"> </span><span class="s">&quot; numshor1 = &quot;</span><span class="w"> </span><span class="o">&lt;&lt;</span><span class="w"> </span><span class="n">numshor1</span><span class="w"> </span><span class="o">&lt;&lt;</span><span class="n">endl</span><span class="p">;</span><span class="w"></span> <span class="p">}</span><span class="w"></span> </pre></div> </div> <p class="title sectiontitle rubric" id="intr-lang-exam-cpp-fort-intr-lang-cpp-fort-exam-subr">Fortran Subroutine cp2f_func.f</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="n">subroutine</span><span class="w"> </span><span class="nf">cp2f_func</span><span class="w"> </span><span class="p">(</span><span class="w"> </span><span class="n">bool1</span><span class="p">,</span><span class="w"> </span><span class="n">letter1</span><span class="p">,</span><span class="w"> </span><span class="n">numint1</span><span class="p">,</span><span class="w"></span> <span class="o">+</span><span class="w"> </span><span class="n">numint2</span><span class="p">,</span><span class="w"> </span><span class="n">numfloat1</span><span class="p">,</span><span class="w"> </span><span class="n">numdoub1</span><span class="p">,</span><span class="w"> </span><span class="n">numshor1</span><span class="p">)</span><span class="w"></span> <span class="n">logical</span><span class="o">*</span><span class="mi">1</span><span class="w"> </span><span class="n">bool1</span><span class="w"></span> <span class="n">character</span><span class="w"> </span><span class="n">letter1</span><span class="w"></span> <span class="n">integer</span><span class="w"> </span><span class="n">numint1</span><span class="p">,</span><span class="w"> </span><span class="n">numint2</span><span class="w"></span> <span class="kt">double</span><span class="w"> </span><span class="n">precision</span><span class="w"> </span><span class="n">numdoub1</span><span class="w"></span> <span class="n">real</span><span class="w"> </span><span class="n">numfloat1</span><span class="w"></span> <span class="n">integer</span><span class="o">*</span><span class="mi">2</span><span class="w"> </span><span class="n">numshor1</span><span class="w"></span> <span class="n">bool1</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">.</span><span class="nb">true</span><span class="p">.</span><span class="w"> </span><span class="p">;</span><span class="w"> </span><span class="n">letter1</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">&quot;v&quot;</span><span class="w"></span> <span class="n">numint1</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">11</span><span class="w"> </span><span class="p">;</span><span class="w"> </span><span class="n">numint2</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">-44</span><span class="w"></span> <span class="n">numdoub1</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">902</span><span class="w"> </span><span class="p">;</span><span class="w"> </span><span class="n">numfloat1</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mf">39.6</span><span class="w"> </span><span class="p">;</span><span class="w"> </span><span class="n">numshor1</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">299</span><span class="w"></span> <span class="k">return</span><span class="w"></span> <span class="n">end</span><span class="w"></span> </pre></div> </div> <p>To compile this Fortran subroutine and C++ program, use the following command lines:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ nvfortran -c cp2f_func.f $ nvc++ cp2f_func.o cp2f_main.C -fortranlibs </pre></div> </div> <p>Executing this C++ main should produce the following output:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>bool1 = TRUE letter1 = v numint1 = 11 numint2 = -44 numfloat1 = 39.6 numdoub1 = 902 numshor1 = 299 </pre></div> </div> <div class="admonition note"> <p class="admonition-title">Note</p> <p>You must explicitly link in the NVFORTRAN runtime support libraries when linking nvfortran-compiled program units into C++ or C main programs.</p> </div> <span class="target" id="prog-64bits"></span></section> </section> </section> <section id="programming-considerations-for-64-bit-environments"> <h1><span class="section-number">15. </span>Programming Considerations for 64-Bit Environments<a class="headerlink" href="#programming-considerations-for-64-bit-environments" title="Permalink to this headline"></a></h1> <p>NVIDIA provides 64-bit compilers for 64-bit Linux operating systems running on x86-64 (Linux_x86_64) and Arm Server (Linux_aarch64) architectures. You can use these compilers to create programs that use 64-bit memory addresses. The GNU toolchain on 64-bit Linux systems implements an option to control 32-bit vs 64-bit code generation, as described in <a class="reference internal" href="#prog-64bits-static-data-linux"><span class="std std-ref">Large Static Data in Linux</span></a>. This section describes the specifics of how to use the NVIDIA compilers to make use of 64-bit memory addressing.</p> <div class="admonition note"> <p class="admonition-title">Note</p> <p>The NVIDIA HPC compilers themselves are 64-bit applications which can only run on 64-bit CPUs running 64-bit Operating Systems.</p> </div> <p>This section describes how to use the following options related to 64-bit programming.</p> <ul class="simple"> <li><p><code class="docutils literal notranslate"><span class="pre">-fPIC</span></code></p></li> <li><p><code class="docutils literal notranslate"><span class="pre">-mcmodel=medium</span></code></p></li> <li><p><code class="docutils literal notranslate"><span class="pre">-Mlarge_arrays</span></code></p></li> <li><p><code class="docutils literal notranslate"><span class="pre">-i8</span></code></p></li> <li><p><code class="docutils literal notranslate"><span class="pre">-Mlargeaddressaware</span></code></p></li> </ul> <section id="data-types-in-the-64-bit-environment"> <h2><span class="section-number">15.1. </span>Data Types in the 64-Bit Environment<a class="headerlink" href="#data-types-in-the-64-bit-environment" title="Permalink to this headline"></a></h2> <p>The size of some data types can differ across 64-bit environments. This section describes the major differences.</p> <section id="c-and-c-data-types"> <h3><span class="section-number">15.1.1. </span>C++ and C Data Types<a class="headerlink" href="#c-and-c-data-types" title="Permalink to this headline"></a></h3> <p>On 64-bit Linux operating systems, the size of an int is 4 bytes, a long is 8 bytes, a long long is 8 bytes, and a pointer is 8 bytes.</p> </section> <section id="fortran-data-types"> <h3><span class="section-number">15.1.2. </span>Fortran Data Types<a class="headerlink" href="#fortran-data-types" title="Permalink to this headline"></a></h3> <p>In Fortran, the default size of the INTEGER type is 4 bytes. The <code class="docutils literal notranslate"><span class="pre">-i8</span></code> compiler option may be used to make the default size of all INTEGER data in the program 8 bytes.</p> <p>When using the <code class="docutils literal notranslate"><span class="pre">-Mlarge_arrays</span></code> option, described in <a class="reference internal" href="#prog-64bits-array-indexing"><span class="std std-ref">64-Bit Array Indexing</span></a>, any 4-byte INTEGER variables that are used to index arrays are silently promoted by the compiler to 8 bytes. This promotion can lead to unexpected consequences, so 8-byte INTEGER variables are recommended for array indexing when using the option <code class="docutils literal notranslate"><span class="pre">-Mlarge_arrays</span></code>.</p> <span class="target" id="prog-64bits-static-data-linux"></span></section> </section> <section id="large-static-data-in-linux"> <h2><span class="section-number">15.2. </span>Large Static Data in Linux<a class="headerlink" href="#large-static-data-in-linux" title="Permalink to this headline"></a></h2> <p>64-bit Linux operating systems support two different memory models. The default model used by the NVIDIA HPC compilers on Linux_x86_64 and Linux_aarch64 targets is the small memory model, which can be specified using -mcmodel=small. This is the 32-bit model, which limits the size of code plus statically allocated data, including system and user libraries, to 2GB. The medium memory model, specified by -mcmodel=medium, allows combined code and static data areas (.text and .bss sections) larger than 2GB. The <code class="docutils literal notranslate"><span class="pre">-mcmodel=medium</span></code> option must be used on both the compile command and the link command in order to take effect.</p> <p>There are implications to using <code class="docutils literal notranslate"><span class="pre">-mcmodel=medium</span></code>. The generated code requires increased addressing overhead to support the large data range. This can affect performance, though the compilers seek to minimize the added overhead through careful instruction selection and optimization.</p> <p>Linux_aarch64 does not support -mcmodel=medium. If the medium model is specified on the command-line, the compiler driver will automatically select the large model.</p> </section> <section id="large-dynamically-allocated-data"> <h2><span class="section-number">15.3. </span>Large Dynamically Allocated Data<a class="headerlink" href="#large-dynamically-allocated-data" title="Permalink to this headline"></a></h2> <p>Dynamically allocated data objects in programs compiled by the NVIDIA HPC compilers can be larger than 2GB. No special compiler options are required to enable this functionality. The size of the allocation is only limited by the system. However, to correctly access dynamically allocated arrays with more than 2G elements you should use the <code class="docutils literal notranslate"><span class="pre">-Mlarge_arrays</span></code> option, described in the following section.</p> <span class="target" id="prog-64bits-array-indexing"></span></section> <section id="bit-array-indexing"> <h2><span class="section-number">15.4. </span>64-Bit Array Indexing<a class="headerlink" href="#bit-array-indexing" title="Permalink to this headline"></a></h2> <p>The NVIDIA Fortran compilers provide an option, <code class="docutils literal notranslate"><span class="pre">-Mlarge_arrays</span></code>, that enables 64-bit indexing of arrays. This means that, as necessary, 64-bit INTEGER constants and variables are used to index arrays.</p> <div class="admonition note"> <p class="admonition-title">Note</p> <p>In the presence of <code class="docutils literal notranslate"><span class="pre">-Mlarge_arrays</span></code>, the compiler may silently promote 32-bit integers to 64 bits, which can have unexpected side effects.</p> </div> <p>On 64-bit Linux, the <code class="docutils literal notranslate"><span class="pre">-Mlarge_arrays</span></code> option also enables single static data objects larger than 2 GB. This option is the default in the presence of <code class="docutils literal notranslate"><span class="pre">-mcmodel=medium</span></code>.</p> </section> <section id="compiler-options-for-64-bit-programming"> <h2><span class="section-number">15.5. </span>Compiler Options for 64-bit Programming<a class="headerlink" href="#compiler-options-for-64-bit-programming" title="Permalink to this headline"></a></h2> <p>The usual switches that apply to 64-bit programmers seeking to increase the data range of their applications are in the following table.</p> <table class="table-no-stripes docutils align-default" id="id34"> <caption><span class="caption-text">Table 30. 64-bit Compiler Options</span><a class="headerlink" href="#id34" title="Permalink to this table"></a></caption> <colgroup> <col style="width: 7%" /> <col style="width: 37%" /> <col style="width: 56%" /> </colgroup> <thead> <tr class="row-odd"><th class="head"><p>Option</p></th> <th class="head"><p>Purpose</p></th> <th class="head"><p>Considerations</p></th> </tr> </thead> <tbody> <tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">-⁠mcmodel=medium</span></code></p></td> <td><p>Allow for data declarations larger than 2GB.</p></td> <td><p>Linux_aarch64 does not support -mcmodel=medium. If the medium model is specified on the command-line, the compiler driver will automatically select the large model.</p></td> </tr> <tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">-⁠Mlarge_arrays</span></code></p></td> <td><p>Perform all array-location-to-address calculations using 64-bit integer arithmetic.</p></td> <td><p>Slightly slower execution. Is implicit with <code class="docutils literal notranslate"><span class="pre">-mcmodel=medium</span></code>. Can be used with option <code class="docutils literal notranslate"><span class="pre">-mcmodel=small</span></code>.</p></td> </tr> <tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">-⁠fpic</span></code></p></td> <td><p>Position independent code. Necessary for shared libraries.</p></td> <td><p>Dynamic linking restricted to a 32-bit offset. External symbol references should refer to other shared lib routines, rather than the program calling them.</p></td> </tr> <tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">-⁠i8</span></code></p></td> <td><p>All INTEGER functions, data, and constants not explicitly declared INTEGER*4 are assumed to be INTEGER*8.</p></td> <td><p>Users should take care to explicitly declare INTEGER functions as INTEGER*4.</p></td> </tr> </tbody> </table> <p>The following table summarizes the limits of these programming models under the specified conditions. The compiler options you use vary by processor.</p> <table class="table-no-stripes docutils align-default" id="id35"> <caption><span class="caption-text">Table 31. Effects of Options on Memory and Array Sizes</span><a class="headerlink" href="#id35" title="Permalink to this table"></a></caption> <colgroup> <col style="width: 63%" /> <col style="width: 6%" /> <col style="width: 10%" /> <col style="width: 11%" /> <col style="width: 5%" /> <col style="width: 5%" /> </colgroup> <thead> <tr class="row-odd"><th class="head"><p>Condition</p></th> <th class="head" colspan="2"><p>Addr. Math</p></th> <th class="head" colspan="3"><p>Max Size Gbytes</p></th> </tr> </thead> <tbody> <tr class="row-even"><td></td> <td><p>A</p></td> <td><p>I</p></td> <td><p>AS</p></td> <td><p>DS</p></td> <td><p>TS</p></td> </tr> <tr class="row-odd"><td><p>64-bit addr limited by option <code class="docutils literal notranslate"><span class="pre">-mcmodel=small</span></code></p></td> <td><p>64</p></td> <td><p>32</p></td> <td><p>2</p></td> <td><p>2</p></td> <td><p>2</p></td> </tr> <tr class="row-even"><td><p>-fpic <em>incompatible with</em> <code class="docutils literal notranslate"><span class="pre">-mcmodel=medium</span></code></p></td> <td><p>64</p></td> <td><p>32</p></td> <td><p>2</p></td> <td><p>2</p></td> <td><p>2</p></td> </tr> <tr class="row-odd"><td><p>Enable full support for 64-bit data addressing</p></td> <td><p>64</p></td> <td><p>64</p></td> <td><p>&gt;2</p></td> <td><p>&gt;2</p></td> <td><p>&gt;2</p></td> </tr> </tbody> </table> <table class="table-no-stripes docutils align-default"> <colgroup> <col style="width: 6%" /> <col style="width: 94%" /> </colgroup> <tbody> <tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">A</span></code></p></td> <td><p>Address Type – size in bits of data used for address calculations, 64-bits.</p></td> </tr> <tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">I</span></code></p></td> <td><p>Index Arithmetic -bit-size of data used to index into arrays and other aggregate data structures. If 32-bit, total range of any single data object is limited to 2GB.</p></td> </tr> <tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">AS</span></code></p></td> <td><p>Maximum Array Size - the maximum size in gigabytes of any single data object.</p></td> </tr> <tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">DS</span></code></p></td> <td><p>Maximum Data Size - max size in gigabytes combined of all data objects in .bss</p></td> </tr> <tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">TS</span></code></p></td> <td><p>Maximum Total Size - max size in gigabytes, in aggregate, of all executable code and data objects in a running program.</p></td> </tr> </tbody> </table> </section> <section id="practical-limitations-of-large-array-programming"> <h2><span class="section-number">15.6. </span>Practical Limitations of Large Array Programming<a class="headerlink" href="#practical-limitations-of-large-array-programming" title="Permalink to this headline"></a></h2> <p>The 64-bit addressing capability of 64-bit Linux environments can cause unexpected issues when data sizes are enlarged significantly. The following table describes the most common occurrences of practical limitations of large array programming.</p> <table class="table-no-stripes docutils align-default" id="id36"> <caption><span class="caption-text">Table 32. 64-Bit Limitations</span><a class="headerlink" href="#id36" title="Permalink to this table"></a></caption> <colgroup> <col style="width: 15%" /> <col style="width: 85%" /> </colgroup> <tbody> <tr class="row-odd"><td><p>array initialization</p></td> <td><p>Initializing a large array with a data statement may result in very large assembly and object files, where a line of assembler source is required for each element in the initialized array. Compilation and linking can be very time consuming as well. To avoid this issue, consider initializing large arrays in a loop at runtime rather than in a data statement.</p></td> </tr> <tr class="row-even"><td><p>stack space</p></td> <td><p>Stack space can be a problem for data that is stack-based. On Linux, stack size is increased in your shell environment. If setting stacksize to unlimited is not large enough, try setting the size explicitly:</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="n">limit</span><span class="w"> </span><span class="n">stacksize</span><span class="w"> </span><span class="n">new_size</span><span class="w"> </span><span class="o">!</span><span class="w"> </span><span class="n">in</span><span class="w"> </span><span class="n">csh</span><span class="w"></span> </pre></div> </div> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="n">ulimit</span><span class="w"> </span><span class="o">-</span><span class="n">s</span><span class="w"> </span><span class="n">new_size</span><span class="w"> </span><span class="o">!</span><span class="w"> </span><span class="n">in</span><span class="w"> </span><span class="n">bash</span><span class="w"></span> </pre></div> </div> </td> </tr> <tr class="row-odd"><td><p>page swapping</p></td> <td><p>If your executable is much larger than the physical size of memory, page swapping can cause it to run dramatically slower; it may even fail. This is not a compiler problem. Try smaller data sets to determine whether or not a problem is due to page thrashing.</p></td> </tr> <tr class="row-even"><td><p>configured space</p></td> <td><p>Be sure your Linux system is configured with swap space sufficiently large to support the data sets used in your application(s). If your memory+swap space is not sufficiently large, your application will likely encounter a segmentation fault at runtime.</p></td> </tr> <tr class="row-odd"><td><p>support for large address offsets in object file format</p></td> <td><p>Arrays that are not dynamically allocated are limited by how the compiler can express the ‘distance’ between them when generating code. A field in the object file stores this ‘distance’ value, which is limited to 32-bits on Linux with <code class="docutils literal notranslate"><span class="pre">-mcmodel=small</span></code>. It is 64-bits on Linux with <code class="docutils literal notranslate"><span class="pre">-mcmodel=medium</span></code>.</p> <div class="admonition note"> <p class="admonition-title">Note</p> <p>Without the 64-bit offset support in the object file format, large arrays cannot be declared statically, or locally on the stack.</p> </div> </td> </tr> </tbody> </table> <span class="target" id="prog-64bits-lrg-ary-med-mem-c"></span></section> <section id="medium-memory-model-and-large-array-in-c"> <h2><span class="section-number">15.7. </span>Medium Memory Model and Large Array in C<a class="headerlink" href="#medium-memory-model-and-large-array-in-c" title="Permalink to this headline"></a></h2> <p>Consider the following example, where the aggregate size of the arrays exceeds 2GB.</p> <p class="title sectiontitle rubric" id="medium-memory-model-and-large-array-in-c-1">Medium Memory Model and Large Array in C</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="o">%</span><span class="w"> </span><span class="n">cat</span><span class="w"> </span><span class="n">bigadd</span><span class="p">.</span><span class="n">c</span><span class="w"></span> <span class="cp">#include</span><span class="w"> </span><span class="cpf">&lt;stdio.h&gt;</span><span class="cp"></span> <span class="cp">#define SIZE 600000000 </span><span class="cm">/* &gt; 2GB/4 */</span><span class="cp"></span> <span class="k">static</span><span class="w"> </span><span class="kt">float</span><span class="w"> </span><span class="n">a</span><span class="p">[</span><span class="n">SIZE</span><span class="p">],</span><span class="w"> </span><span class="n">b</span><span class="p">[</span><span class="n">SIZE</span><span class="p">];</span><span class="w"></span> <span class="kt">int</span><span class="w"></span> <span class="nf">main</span><span class="p">()</span><span class="w"></span> <span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="kt">long</span><span class="w"> </span><span class="kt">long</span><span class="w"> </span><span class="n">i</span><span class="p">,</span><span class="w"> </span><span class="n">n</span><span class="p">,</span><span class="w"> </span><span class="n">m</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="kt">float</span><span class="w"> </span><span class="n">c</span><span class="p">[</span><span class="n">SIZE</span><span class="p">];</span><span class="w"> </span><span class="cm">/* goes on stack */</span><span class="w"></span> <span class="w"> </span><span class="n">n</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">SIZE</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="n">m</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="n">n</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="mi">10000</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="n">a</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mi">1</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="n">b</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mf">2.0</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="p">(</span><span class="n">i</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mi">1</span><span class="p">);</span><span class="w"></span> <span class="w"> </span><span class="n">c</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">a</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">b</span><span class="p">[</span><span class="n">i</span><span class="p">];</span><span class="w"></span> <span class="w"> </span><span class="n">m</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">i</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="p">}</span><span class="w"></span> <span class="w"> </span><span class="n">printf</span><span class="p">(</span><span class="s">&quot;a[0]=%g b[0]=%g c[0]=%g</span><span class="se">\n</span><span class="s">&quot;</span><span class="p">,</span><span class="w"> </span><span class="n">a</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span><span class="w"> </span><span class="n">b</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span><span class="w"> </span><span class="n">c</span><span class="p">[</span><span class="mi">0</span><span class="p">]);</span><span class="w"></span> <span class="w"> </span><span class="n">printf</span><span class="p">(</span><span class="s">&quot;m=%lld a[%lld]=%g b[%lld]=%gc[%lld]=%g</span><span class="se">\n</span><span class="s">&quot;</span><span class="p">,</span><span class="n">m</span><span class="p">,</span><span class="n">m</span><span class="p">,</span><span class="n">a</span><span class="p">[</span><span class="n">m</span><span class="p">],</span><span class="n">m</span><span class="p">,</span><span class="n">b</span><span class="p">[</span><span class="n">m</span><span class="p">],</span><span class="n">m</span><span class="p">,</span><span class="n">c</span><span class="p">[</span><span class="n">m</span><span class="p">]);</span><span class="w"></span> <span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"></span> <span class="p">}</span><span class="w"></span> </pre></div> </div> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>% nvc -mcmodel=medium -o bigadd bigadd.c </pre></div> </div> <p>When SIZE is greater than 2G/4, and the arrays are of type float with 4 bytes per element, the size of each array is greater than 2GB. With nvc, using the -mcmodel=medium switch, a static data object can now be &gt; 2GB in size. If you execute with these settings in your environment, you may see the following:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>% bigadd Segmentation fault </pre></div> </div> <p>Execution fails because the stack size is not large enough. You can most likely correct this error by using the <code class="docutils literal notranslate"><span class="pre">limit</span> <span class="pre">stacksize</span></code> command to reset the stack size in your environment:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>% limit stacksize 3000M </pre></div> </div> <div class="admonition note"> <p class="admonition-title">Note</p> <p>The command <code class="docutils literal notranslate"><span class="pre">limit</span> <span class="pre">stacksize</span> <span class="pre">unlimited</span></code> probably does not provide as large a stack as we are using in the <a class="reference internal" href="#prog-64bits-lrg-ary-med-mem-c"><span class="std std-ref">this example</span></a>.</p> </div> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>% bigadd a[0]=1 b[0]=2 c[0]=3 n=599990000 a[599990000]=5.9999e+08 b[599990000]=1.19998e+09 c[599990000]=1.79997e+09 </pre></div> </div> </section> <section id="medium-memory-model-and-large-array-in-fortran"> <h2><span class="section-number">15.8. </span>Medium Memory Model and Large Array in Fortran<a class="headerlink" href="#medium-memory-model-and-large-array-in-fortran" title="Permalink to this headline"></a></h2> <p>The following example works with the NVFORTRAN compiler. It uses 64-bit addresses and index arithmetic when the <code class="docutils literal notranslate"><span class="pre">-mcmodel=medium</span></code> option is used.</p> <p>Consider the following example:</p> <p><strong>Medium Memory Model and Large Array in Fortran</strong></p> <div class="highlight-fortran notranslate"><div class="highlight"><pre><span></span><span class="p">%</span><span class="w"> </span><span class="n">cat</span><span class="w"> </span><span class="n">mat</span><span class="p">.</span><span class="n">f</span><span class="w"></span> <span class="k">program </span><span class="n">mat</span><span class="w"></span> <span class="w"> </span><span class="kt">integer </span><span class="n">i</span><span class="p">,</span><span class="w"> </span><span class="n">j</span><span class="p">,</span><span class="w"> </span><span class="n">k</span><span class="p">,</span><span class="w"> </span><span class="n">size</span><span class="p">,</span><span class="w"> </span><span class="n">l</span><span class="p">,</span><span class="w"> </span><span class="n">m</span><span class="p">,</span><span class="w"> </span><span class="n">n</span><span class="w"></span> <span class="w"> </span><span class="k">parameter</span><span class="w"> </span><span class="p">(</span><span class="n">size</span><span class="o">=</span><span class="mi">16000</span><span class="p">)</span><span class="w"> </span><span class="c">! &gt;2GB</span> <span class="w"> </span><span class="k">parameter</span><span class="w"> </span><span class="p">(</span><span class="n">m</span><span class="o">=</span><span class="n">size</span><span class="p">,</span><span class="n">n</span><span class="o">=</span><span class="n">size</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="kt">real</span><span class="o">*</span><span class="mi">8</span><span class="w"> </span><span class="n">a</span><span class="p">(</span><span class="n">m</span><span class="p">,</span><span class="n">n</span><span class="p">),</span><span class="n">b</span><span class="p">(</span><span class="n">m</span><span class="p">,</span><span class="n">n</span><span class="p">),</span><span class="n">c</span><span class="p">(</span><span class="n">m</span><span class="p">,</span><span class="n">n</span><span class="p">),</span><span class="n">d</span><span class="w"></span> <span class="w"> </span><span class="k">do </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="n">m</span><span class="w"></span> <span class="w"> </span><span class="k">do </span><span class="n">j</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="n">n</span><span class="w"></span> <span class="w"> </span><span class="n">a</span><span class="p">(</span><span class="n">i</span><span class="p">,</span><span class="n">j</span><span class="p">)</span><span class="o">=</span><span class="mi">1000</span><span class="mf">0.0D0</span><span class="o">*</span><span class="nb">dble</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="o">+</span><span class="nb">dble</span><span class="p">(</span><span class="n">j</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="n">b</span><span class="p">(</span><span class="n">i</span><span class="p">,</span><span class="n">j</span><span class="p">)</span><span class="o">=</span><span class="mi">2000</span><span class="mf">0.0D0</span><span class="o">*</span><span class="nb">dble</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="o">+</span><span class="nb">dble</span><span class="p">(</span><span class="n">j</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="k">enddo</span> <span class="k"> enddo</span><span class="w"></span> <span class="w"> </span><span class="c">!$omp parallel</span> <span class="w"> </span><span class="c">!$omp do</span> <span class="w"> </span><span class="k">do </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="n">m</span><span class="w"></span> <span class="w"> </span><span class="k">do </span><span class="n">j</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="n">n</span><span class="w"></span> <span class="w"> </span><span class="n">c</span><span class="p">(</span><span class="n">i</span><span class="p">,</span><span class="n">j</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">a</span><span class="p">(</span><span class="n">i</span><span class="p">,</span><span class="n">j</span><span class="p">)</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">b</span><span class="p">(</span><span class="n">i</span><span class="p">,</span><span class="n">j</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="k">enddo</span> <span class="k"> enddo</span><span class="w"></span> <span class="w"> </span><span class="c">!$omp do</span> <span class="w"> </span><span class="k">do </span><span class="n">i</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span><span class="n">m</span><span class="w"></span> <span class="w"> </span><span class="k">do </span><span class="n">j</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="n">n</span><span class="w"></span> <span class="w"> </span><span class="n">d</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">3000</span><span class="mf">0.0D0</span><span class="o">*</span><span class="nb">dble</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="o">+</span><span class="nb">dble</span><span class="p">(</span><span class="n">j</span><span class="p">)</span><span class="o">+</span><span class="nb">dble</span><span class="p">(</span><span class="n">j</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">d</span><span class="w"> </span><span class="p">.</span><span class="n">ne</span><span class="p">.</span><span class="w"> </span><span class="n">c</span><span class="p">(</span><span class="n">i</span><span class="p">,</span><span class="n">j</span><span class="p">))</span><span class="w"> </span><span class="k">then</span> <span class="k"> print</span><span class="w"> </span><span class="o">*</span><span class="p">,</span><span class="s2">&quot;err i=&quot;</span><span class="p">,</span><span class="n">i</span><span class="p">,</span><span class="s2">&quot;j=&quot;</span><span class="p">,</span><span class="n">j</span><span class="w"></span> <span class="w"> </span><span class="k">print</span><span class="w"> </span><span class="o">*</span><span class="p">,</span><span class="s2">&quot;c(i,j)=&quot;</span><span class="p">,</span><span class="n">c</span><span class="p">(</span><span class="n">i</span><span class="p">,</span><span class="n">j</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="k">print</span><span class="w"> </span><span class="o">*</span><span class="p">,</span><span class="s2">&quot;d=&quot;</span><span class="p">,</span><span class="n">d</span><span class="w"></span> <span class="w"> </span><span class="k">stop</span> <span class="k"> endif</span> <span class="k"> enddo</span> <span class="k"> enddo</span><span class="w"></span> <span class="w"> </span><span class="c">!$omp end parallel</span> <span class="w"> </span><span class="k">print</span><span class="w"> </span><span class="o">*</span><span class="p">,</span><span class="w"> </span><span class="s2">&quot;M =&quot;</span><span class="p">,</span><span class="n">M</span><span class="p">,</span><span class="s2">&quot;, N =&quot;</span><span class="p">,</span><span class="n">N</span><span class="w"></span> <span class="w"> </span><span class="k">print</span><span class="w"> </span><span class="o">*</span><span class="p">,</span><span class="w"> </span><span class="s2">&quot;c(M,N) = &quot;</span><span class="p">,</span><span class="w"> </span><span class="n">c</span><span class="p">(</span><span class="n">m</span><span class="p">,</span><span class="n">n</span><span class="p">)</span><span class="w"></span> <span class="k">end</span><span class="w"></span> </pre></div> </div> <p>When compiled with the NVFORTRAN compiler using <code class="docutils literal notranslate"><span class="pre">-mcmodel=medium</span></code>:</p> <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>% nvfortran -Mfree -mp -o mat mat.f -i8 -mcmodel=medium % setenv OMP_NUM_THREADS 2 % mat M = 16000 , N = 16000 c(M,N) = 480032000.0000000 </pre></div> </div> </section> <section id="large-array-and-small-memory-model-in-fortran"> <h2><span class="section-number">15.9. </span>Large Array and Small Memory Model in Fortran<a class="headerlink" href="#large-array-and-small-memory-model-in-fortran" title="Permalink to this headline"></a></h2> <p>The following example uses large, dynamically-allocated arrays. The code is divided into a main and subroutine so you could put the subroutine into a shared library. Dynamic allocation of large arrays saves space in the size of executable and saves time initializing data.</p> <p><strong>Large Array and Small Memory Model in Fortran</strong></p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="o">%</span><span class="w"> </span><span class="n">cat</span><span class="w"> </span><span class="n">mat_allo</span><span class="p">.</span><span class="n">f90</span><span class="w"></span> </pre></div> </div> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="n">program</span><span class="w"> </span><span class="n">mat_allo</span><span class="w"></span> <span class="w"> </span><span class="n">integer</span><span class="w"> </span><span class="n">i</span><span class="p">,</span><span class="w"> </span><span class="n">j</span><span class="w"></span> <span class="w"> </span><span class="n">integer</span><span class="w"> </span><span class="n">size</span><span class="p">,</span><span class="w"> </span><span class="n">m</span><span class="p">,</span><span class="w"> </span><span class="n">n</span><span class="w"></span> <span class="w"> </span><span class="n">parameter</span><span class="w"> </span><span class="p">(</span><span class="n">size</span><span class="o">=</span><span class="mi">16000</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="n">parameter</span><span class="w"> </span><span class="p">(</span><span class="n">m</span><span class="o">=</span><span class="n">size</span><span class="p">,</span><span class="n">n</span><span class="o">=</span><span class="n">size</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="kt">double</span><span class="w"> </span><span class="n">precision</span><span class="p">,</span><span class="w"> </span><span class="n">allocatable</span><span class="o">::</span><span class="n">a</span><span class="p">(</span><span class="o">:</span><span class="p">,</span><span class="o">:</span><span class="p">),</span><span class="n">b</span><span class="p">(</span><span class="o">:</span><span class="p">,</span><span class="o">:</span><span class="p">),</span><span class="n">c</span><span class="p">(</span><span class="o">:</span><span class="p">,</span><span class="o">:</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="n">allocate</span><span class="p">(</span><span class="n">a</span><span class="p">(</span><span class="n">m</span><span class="p">,</span><span class="n">n</span><span class="p">),</span><span class="w"> </span><span class="n">b</span><span class="p">(</span><span class="n">m</span><span class="p">,</span><span class="n">n</span><span class="p">),</span><span class="w"> </span><span class="n">c</span><span class="p">(</span><span class="n">m</span><span class="p">,</span><span class="n">n</span><span class="p">))</span><span class="w"></span> <span class="w"> </span><span class="k">do</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">100</span><span class="p">,</span><span class="w"> </span><span class="n">m</span><span class="p">,</span><span class="w"> </span><span class="mi">1</span><span class="w"></span> <span class="w"> </span><span class="k">do</span><span class="w"> </span><span class="n">j</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">100</span><span class="p">,</span><span class="w"> </span><span class="n">n</span><span class="p">,</span><span class="w"> </span><span class="mi">1</span><span class="w"></span> <span class="w"> </span><span class="n">a</span><span class="p">(</span><span class="n">i</span><span class="p">,</span><span class="n">j</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mf">10000.0</span><span class="n">D0</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">dble</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">dble</span><span class="p">(</span><span class="n">j</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="n">b</span><span class="p">(</span><span class="n">i</span><span class="p">,</span><span class="n">j</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mf">20000.0</span><span class="n">D0</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">dble</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">dble</span><span class="p">(</span><span class="n">j</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="n">enddo</span><span class="w"></span> <span class="w"> </span><span class="n">enddo</span><span class="w"></span> <span class="w"> </span><span class="n">call</span><span class="w"> </span><span class="n">mat_add</span><span class="p">(</span><span class="n">a</span><span class="p">,</span><span class="n">b</span><span class="p">,</span><span class="n">c</span><span class="p">,</span><span class="n">m</span><span class="p">,</span><span class="n">n</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="n">print</span><span class="w"> </span><span class="o">*</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;M =&quot;</span><span class="p">,</span><span class="n">m</span><span class="p">,</span><span class="s">&quot;,N =&quot;</span><span class="p">,</span><span class="n">n</span><span class="w"></span> <span class="w"> </span><span class="n">print</span><span class="w"> </span><span class="o">*</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;c(M,N) = &quot;</span><span class="p">,</span><span class="w"> </span><span class="n">c</span><span class="p">(</span><span class="n">m</span><span class="p">,</span><span class="n">n</span><span class="p">)</span><span class="w"></span> <span class="n">end</span><span class="w"></span> </pre></div> </div> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="n">subroutine</span><span class="w"> </span><span class="n">mat_add</span><span class="p">(</span><span class="n">a</span><span class="p">,</span><span class="n">b</span><span class="p">,</span><span class="n">c</span><span class="p">,</span><span class="n">m</span><span class="p">,</span><span class="n">n</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="n">integer</span><span class="w"> </span><span class="n">m</span><span class="p">,</span><span class="w"> </span><span class="n">n</span><span class="p">,</span><span class="w"> </span><span class="n">i</span><span class="p">,</span><span class="w"> </span><span class="n">j</span><span class="w"></span> <span class="w"> </span><span class="kt">double</span><span class="w"> </span><span class="n">precision</span><span class="w"> </span><span class="n">a</span><span class="p">(</span><span class="n">m</span><span class="p">,</span><span class="n">n</span><span class="p">),</span><span class="n">b</span><span class="p">(</span><span class="n">m</span><span class="p">,</span><span class="n">n</span><span class="p">),</span><span class="n">c</span><span class="p">(</span><span class="n">m</span><span class="p">,</span><span class="n">n</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="k">do</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="n">m</span><span class="w"></span> <span class="w"> </span><span class="k">do</span><span class="w"> </span><span class="n">j</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="n">n</span><span class="w"></span> <span class="w"> </span><span class="n">c</span><span class="p">(</span><span class="n">i</span><span class="p">,</span><span class="n">j</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">a</span><span class="p">(</span><span class="n">i</span><span class="p">,</span><span class="n">j</span><span class="p">)</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">b</span><span class="p">(</span><span class="n">i</span><span class="p">,</span><span class="n">j</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="n">enddo</span><span class="w"></span> <span class="w"> </span><span class="n">enddo</span><span class="w"></span> <span class="w"> </span><span class="k">return</span><span class="w"></span> <span class="n">end</span><span class="w"></span> </pre></div> </div> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="o">%</span><span class="w"> </span><span class="n">nvfortran</span><span class="w"> </span><span class="o">-</span><span class="n">o</span><span class="w"> </span><span class="n">mat_allo</span><span class="w"> </span><span class="n">mat_allo</span><span class="p">.</span><span class="n">f90</span><span class="w"> </span><span class="o">-</span><span class="n">i8</span><span class="w"> </span><span class="o">-</span><span class="n">Mlarge_arrays</span><span class="w"> </span><span class="o">-</span><span class="n">mp</span><span class="w"> </span><span class="o">-</span><span class="n">fast</span><span class="w"></span> </pre></div> </div> <span class="target" id="inline-asm-intrin-c-cpp"></span></section> </section> <section id="c-and-c-inline-assembly-and-intrinsics"> <h1><span class="section-number">16. </span>C++ and C Inline Assembly and Intrinsics<a class="headerlink" href="#c-and-c-inline-assembly-and-intrinsics" title="Permalink to this headline"></a></h1> <p>The examples in this section are shown using x86-64 assembly instructions. Inline assembly is supported on Arm Server platforms as well, but is not documented in detail in this section.</p> <span class="target" id="inline-asm"></span><section id="inline-assembly"> <h2><span class="section-number">16.1. </span>Inline Assembly<a class="headerlink" href="#inline-assembly" title="Permalink to this headline"></a></h2> <p>Inline Assembly lets you specify machine instructions inside a “C” function. The format for an inline assembly instruction is this:</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="p">{</span><span class="w"> </span><span class="k">asm</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">__asm__</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="p">(</span><span class="s">&quot;string&quot;</span><span class="p">);</span><span class="w"></span> </pre></div> </div> <p>The asm statement begins with the <em>asm</em> or <em>__asm__</em> keyword. The __asm__ keyword is typically used in header files that may be included in ISO “C” programs.</p> <p><em>string</em> is one or more machine specific instructions separated with a semi-colon (<em>;</em>) or newline (<em>\n</em>) character. These instructions are inserted directly into the compiler’s assembly-language output for the enclosing function.</p> <p>Some simple asm statements are:</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="k">asm</span><span class="w"> </span><span class="p">(</span><span class="s">&quot;cli&quot;</span><span class="p">);</span><span class="w"></span> <span class="k">asm</span><span class="w"> </span><span class="p">(</span><span class="s">&quot;sti&quot;</span><span class="p">);</span><span class="w"></span> </pre></div> </div> <p>These asm statements disable and enable system interrupts respectively.</p> <p>In the following example, the eax register is set to zero.</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="k">asm</span><span class="p">(</span><span class="w"> </span><span class="s">&quot;pushl %eax</span><span class="se">\n\t</span><span class="s">&quot;</span><span class="w"> </span><span class="s">&quot;movl $0, %eax</span><span class="se">\n\t</span><span class="s">&quot;</span><span class="w"> </span><span class="s">&quot;popl %eax&quot;</span><span class="p">);</span><span class="w"></span> </pre></div> </div> <p>Notice that eax is pushed on the stack so that it is it not clobbered. When the statement is done with eax, it is restored with the popl instruction.</p> <p>Typically a program uses macros that enclose asm statements. The following two examples use the interrupt constructs created previously in this section:</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="cp">#define disableInt __asm__ (&quot;cli&quot;);</span> <span class="cp">#define enableInt __asm__ (&quot;sti&quot;);</span> </pre></div> </div> </section> <section id="extended-inline-assembly"> <h2><span class="section-number">16.2. </span>Extended Inline Assembly<a class="headerlink" href="#extended-inline-assembly" title="Permalink to this headline"></a></h2> <p><a class="reference internal" href="#inline-asm"><span class="std std-ref">Inline Assembly</span></a> explains how to use inline assembly to specify machine specific instructions inside a “C” function. This approach works well for simple machine operations such as disabling and enabling system interrupts. However, inline assembly has three distinct limitations:</p> <ol class="arabic simple"> <li><p>The programmer must choose the registers required by the inline assembly.</p></li> <li><p>To prevent register clobbering, the inline assembly must include push and pop code for registers that get modified by the inline assembly.</p></li> <li><p>There is no easy way to access stack variables in an inline assembly statement.</p></li> </ol> <p><em>Extended Inline Assembly</em> was created to address these limitations. The format for extended inline assembly, also known as <em>extended asm</em>, is as follows:</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="p">{</span><span class="w"> </span><span class="k">asm</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">__asm__</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="p">[</span><span class="w"> </span><span class="k">volatile</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">__volatile__</span><span class="w"> </span><span class="p">]</span><span class="w"></span> <span class="p">(</span><span class="s">&quot;string&quot;</span><span class="w"> </span><span class="p">[</span><span class="o">:</span><span class="w"> </span><span class="p">[</span><span class="n">output</span><span class="w"> </span><span class="n">operands</span><span class="p">]]</span><span class="w"> </span><span class="p">[</span><span class="o">:</span><span class="w"> </span><span class="p">[</span><span class="n">input</span><span class="w"> </span><span class="n">operands</span><span class="p">]]</span><span class="w"> </span><span class="p">[</span><span class="o">:</span><span class="w"> </span><span class="p">[</span><span class="n">clobberlist</span><span class="p">]]);</span><span class="w"></span> </pre></div> </div> <ul> <li><p>Extended asm statements begin with the <em>asm</em> or <em>__asm__</em> keyword. Typically the <em>__asm__</em> keyword is used in header files that may be included by ISO “C” programs.</p></li> <li><p>An optional <em>volatile</em> or <em>__volatile__</em> keyword may appear after the <em>asm</em> keyword. This keyword instructs the compiler not to delete, move significantly, or combine with any other asm statement. Like __asm__, the __volatile__ keyword is typically used with header files that may be included by ISO “C” programs.</p></li> <li><p>“<em>string</em>” is one or more machine specific instructions separated with a semi-colon (<em>;</em>) or newline (<em>\n</em>) character. The string can also contain operands specified in the <em>[output operands]</em>, <em>[input operands]</em>, and <em>[clobber list]</em>. The instructions are inserted directly into the compiler’s assembly-language output for the enclosing function.</p></li> <li><p>The <em>[output operands]</em>, <em>[input operands]</em>, and <em>[clobber list]</em> items each describe the effect of the instruction for the compiler. For example:</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="k">asm</span><span class="p">(</span><span class="w"> </span><span class="s">&quot;movl %1, %%eax</span><span class="se">\n</span><span class="s">&quot;</span><span class="w"> </span><span class="s">&quot;movl %%eax, %0&quot;</span><span class="o">:</span><span class="s">&quot;=r&quot;</span><span class="w"> </span><span class="p">(</span><span class="n">x</span><span class="p">)</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="s">&quot;r&quot;</span><span class="w"> </span><span class="p">(</span><span class="n">y</span><span class="p">)</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="s">&quot;%eax&quot;</span><span class="w"> </span><span class="p">);</span><span class="w"></span> </pre></div> </div> <p>where</p> <ul class="simple"> <li><p>“=r” (x) is an output operand.</p></li> <li><p>“r” (y) is an input operand.</p></li> <li><p>“%eax” is the clobber list consisting of one register, “%eax”.</p></li> </ul> <p>The notation for the output and input operands is a constraint string surrounded by quotes, followed by an expression, and surrounded by parentheses. The constraint string describes how the input and output operands are used in the asm “string”. For example, “r” tells the compiler that the operand is a register. The “=” tells the compiler that the operand is write only, which means that a value is stored in an output operand’s expression at the end of the asm statement.</p> <p>Each operand is referenced in the asm “string” by a percent “%” and its number. The first operand is number 0, the second is number 1, the third is number 2, and so on. In the preceding example, “%0” references the output operand, and “%1” references the input operand. The asm “string” also contains “%%eax”, which references machine register “%eax”. Hard coded registers like “%eax” should be specified in the clobber list to prevent conflicts with other instructions in the compiler’s assembly-language output. <em>[output operands]</em>, <em>[input operands]</em>, and <em>[clobber list]</em> items are described in more detail in the following sections.</p> </li> </ul> <span class="target" id="inline-asm-output-operands"></span><section id="output-operands"> <h3><span class="section-number">16.2.1. </span>Output Operands<a class="headerlink" href="#output-operands" title="Permalink to this headline"></a></h3> <p>The <em>[output operands]</em> are an optional list of output constraint and expression pairs that specify the result(s) of the asm statement. An output constraint is a string that specifies how a result is delivered to the expression. For example, “=r” (x) says the output operand is a write-only register that stores its value in the “C” variable x at the end of the asm statement. An example follows:</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="kt">int</span><span class="w"> </span><span class="n">x</span><span class="p">;</span><span class="w"></span> <span class="kt">void</span><span class="w"> </span><span class="nf">example</span><span class="p">()</span><span class="w"></span> <span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="k">asm</span><span class="p">(</span><span class="w"> </span><span class="s">&quot;movl $0, %0&quot;</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="s">&quot;=r&quot;</span><span class="w"> </span><span class="p">(</span><span class="n">x</span><span class="p">)</span><span class="w"> </span><span class="p">);</span><span class="w"></span> <span class="p">}</span><span class="w"></span> </pre></div> </div> <p>The previous example assigns 0 to the “C” variable x. For the function in this example, the compiler produces the following assembly. If you want to produce an assembly listing, compile the example with the nvc -S compiler option:</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="nl">example</span><span class="p">:</span><span class="w"></span> <span class="p">..</span><span class="n">Dcfb0</span><span class="o">:</span><span class="w"></span> <span class="w"> </span><span class="n">pushq</span><span class="w"> </span><span class="o">%</span><span class="n">rbp</span><span class="w"></span> <span class="p">..</span><span class="n">Dcfi0</span><span class="o">:</span><span class="w"></span> <span class="w"> </span><span class="n">movq</span><span class="w"> </span><span class="o">%</span><span class="n">rsp</span><span class="p">,</span><span class="w"> </span><span class="o">%</span><span class="n">rbp</span><span class="w"></span> <span class="p">..</span><span class="n">Dcfi1</span><span class="o">:</span><span class="w"></span> <span class="p">..</span><span class="n">EN1</span><span class="o">:</span><span class="w"></span> <span class="cp">## lineno: 8</span> <span class="w"> </span><span class="n">movl</span><span class="w"> </span><span class="n">$0</span><span class="p">,</span><span class="w"> </span><span class="o">%</span><span class="n">eax</span><span class="w"></span> <span class="w"> </span><span class="n">movl</span><span class="w"> </span><span class="o">%</span><span class="n">eax</span><span class="p">,</span><span class="w"> </span><span class="n">x</span><span class="p">(</span><span class="o">%</span><span class="n">rip</span><span class="p">)</span><span class="w"></span> <span class="cp">## lineno: 0</span> <span class="w"> </span><span class="n">popq</span><span class="w"> </span><span class="o">%</span><span class="n">rbp</span><span class="w"></span> <span class="w"> </span><span class="n">ret</span><span class="w"></span> </pre></div> </div> <p>In the generated assembly shown, notice that the compiler generated two statements for the asm statement at line number 5. The compiler generated “<em>movl $0, %eax</em>” from the asm “<em>string</em>”. Also notice that <em>%eax</em> appears in place of “<em>%0</em>” because the compiler assigned the <em>%eax</em> register to variable <em>x</em>. Since item 0 is an output operand, the result must be stored in its expression (x).</p> <p>In addition to write-only output operands, there are read/write output operands designated with a “<strong>+</strong>” instead of a “<strong>=</strong>”. For example, “<em>+r</em>” (<em>x</em>) tells the compiler to initialize the output operand with variable x at the beginning of the asm statement.</p> <p>To illustrate this point, the following example increments variable x by 1:</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="kt">int</span><span class="w"> </span><span class="n">x</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span><span class="w"></span> <span class="kt">void</span><span class="w"> </span><span class="nf">example2</span><span class="p">()</span><span class="w"></span> <span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="k">asm</span><span class="p">(</span><span class="w"> </span><span class="s">&quot;addl $1, %0&quot;</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="s">&quot;+r&quot;</span><span class="w"> </span><span class="p">(</span><span class="n">x</span><span class="p">)</span><span class="w"> </span><span class="p">);</span><span class="w"></span> <span class="p">}</span><span class="w"></span> </pre></div> </div> <p>To perform the increment, the output operand must be initialized with variable x. The <em>read/write</em> constraint modifier (“+”) instructs the compiler to initialize the output operand with its expression. The compiler generates the following assembly code for the example2() function:</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="nl">example2</span><span class="p">:</span><span class="w"></span> <span class="p">..</span><span class="n">Dcfb0</span><span class="o">:</span><span class="w"></span> <span class="w"> </span><span class="n">pushq</span><span class="w"> </span><span class="o">%</span><span class="n">rbp</span><span class="w"></span> <span class="p">..</span><span class="n">Dcfi0</span><span class="o">:</span><span class="w"></span> <span class="w"> </span><span class="n">movq</span><span class="w"> </span><span class="o">%</span><span class="n">rsp</span><span class="p">,</span><span class="w"> </span><span class="o">%</span><span class="n">rbp</span><span class="w"></span> <span class="p">..</span><span class="n">Dcfi1</span><span class="o">:</span><span class="w"></span> <span class="p">..</span><span class="n">EN1</span><span class="o">:</span><span class="w"></span> <span class="cp">## lineno: 5</span> <span class="w"> </span><span class="n">movl</span><span class="w"> </span><span class="n">x</span><span class="p">(</span><span class="o">%</span><span class="n">rip</span><span class="p">),</span><span class="w"> </span><span class="o">%</span><span class="n">eax</span><span class="w"></span> <span class="w"> </span><span class="n">addl</span><span class="w"> </span><span class="n">$1</span><span class="p">,</span><span class="w"> </span><span class="o">%</span><span class="n">eax</span><span class="w"></span> <span class="w"> </span><span class="n">movl</span><span class="w"> </span><span class="o">%</span><span class="n">eax</span><span class="p">,</span><span class="w"> </span><span class="n">x</span><span class="p">(</span><span class="o">%</span><span class="n">rip</span><span class="p">)</span><span class="w"></span> <span class="cp">## lineno: 0</span> <span class="w"> </span><span class="n">popq</span><span class="w"> </span><span class="o">%</span><span class="n">rbp</span><span class="w"></span> <span class="w"> </span><span class="n">ret</span><span class="w"></span> </pre></div> </div> <p>From the example2() code, two extraneous moves are generated in the assembly: one movl for initializing the output register and a second movl to write it to variable x. To eliminate these moves, use a memory constraint type instead of a register constraint type, as shown in the following example:</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="kt">int</span><span class="w"> </span><span class="n">x</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span><span class="w"></span> <span class="kt">void</span><span class="w"> </span><span class="nf">example2</span><span class="p">()</span><span class="w"></span> <span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="k">asm</span><span class="p">(</span><span class="w"> </span><span class="s">&quot;addl $1, %0&quot;</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="s">&quot;+m&quot;</span><span class="w"> </span><span class="p">(</span><span class="n">x</span><span class="p">)</span><span class="w"> </span><span class="p">);</span><span class="w"></span> <span class="p">}</span><span class="w"></span> </pre></div> </div> <p>The compiler generates a memory reference in place of a memory constraint. This eliminates the two extraneous moves. Because the assembly uses a memory reference to variable x, it does not have to move x into a register prior to the asm statement; nor does it need to store the result after the asm statement. Additional constraint types are found in <a class="reference internal" href="#inline-asm-addl-constraints"><span class="std std-ref">Additional Constraints</span></a>.</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="nl">example2</span><span class="p">:</span><span class="w"></span> <span class="p">..</span><span class="n">Dcfb0</span><span class="o">:</span><span class="w"></span> <span class="w"> </span><span class="n">pushq</span><span class="w"> </span><span class="o">%</span><span class="n">rbp</span><span class="w"></span> <span class="p">..</span><span class="n">Dcfi0</span><span class="o">:</span><span class="w"></span> <span class="w"> </span><span class="n">movq</span><span class="w"> </span><span class="o">%</span><span class="n">rsp</span><span class="p">,</span><span class="w"> </span><span class="o">%</span><span class="n">rbp</span><span class="w"></span> <span class="p">..</span><span class="n">Dcfi1</span><span class="o">:</span><span class="w"></span> <span class="p">..</span><span class="n">EN1</span><span class="o">:</span><span class="w"></span> <span class="cp">## lineno: 5</span> <span class="w"> </span><span class="n">addl</span><span class="w"> </span><span class="n">$1</span><span class="p">,</span><span class="w"> </span><span class="n">x</span><span class="p">(</span><span class="o">%</span><span class="n">rip</span><span class="p">)</span><span class="w"></span> <span class="cp">## lineno: 0</span> <span class="w"> </span><span class="n">popq</span><span class="w"> </span><span class="o">%</span><span class="n">rbp</span><span class="w"></span> <span class="w"> </span><span class="n">ret</span><span class="w"></span> </pre></div> </div> <p>The examples thus far have used only one output operand. Because extended asm accepts a list of output operands, asm statements can have more than one result, as shown in the following example:</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="kt">void</span><span class="w"> </span><span class="nf">example4</span><span class="p">()</span><span class="w"></span> <span class="p">{</span><span class="w"></span> <span class="kt">int</span><span class="w"> </span><span class="n">x</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">y</span><span class="o">=</span><span class="mi">2</span><span class="p">;</span><span class="w"></span> <span class="k">asm</span><span class="p">(</span><span class="w"> </span><span class="s">&quot;addl $1, %1</span><span class="se">\n</span><span class="s">&quot;</span><span class="w"> </span><span class="s">&quot;addl %1, %0&quot;</span><span class="o">:</span><span class="w"> </span><span class="s">&quot;+r&quot;</span><span class="w"> </span><span class="p">(</span><span class="n">x</span><span class="p">),</span><span class="w"> </span><span class="s">&quot;+m&quot;</span><span class="w"> </span><span class="p">(</span><span class="n">y</span><span class="p">)</span><span class="w"> </span><span class="p">);</span><span class="w"></span> <span class="p">}</span><span class="w"></span> </pre></div> </div> <p>This example increments variable <em>y</em> by <em>1</em> then adds it to variable <em>x</em>. Multiple output operands are separated with a comma. The first output operand is item 0 (“%0”) and the second is item 1 (“%1”) in the asm <em>“string”</em>. The resulting values for <em>x</em> and <em>y</em> are <em>4</em> and <em>3</em> respectively.</p> </section> <section id="input-operands"> <h3><span class="section-number">16.2.2. </span>Input Operands<a class="headerlink" href="#input-operands" title="Permalink to this headline"></a></h3> <p>The <em>[input operands]</em> are an optional list of input constraint and expression pairs that specify what “C” values are needed by the asm statement. The input constraints specify how the data is delivered to the asm statement. For example, <em>“r” (x)</em> says that the input operand is a register that has a copy of the value stored in “C” variable <em>x</em>. Another example is <em>“m” (x)</em> which says that the input item is the <em>memory</em> location associated with variable <em>x</em>. Other constraint types are discussed in <a class="reference internal" href="#inline-asm-addl-constraints"><span class="std std-ref">Additional Constraints</span></a>. An example follows:</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="kt">void</span><span class="w"> </span><span class="nf">example5</span><span class="p">()</span><span class="w"></span> <span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">x</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">y</span><span class="o">=</span><span class="mi">2</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">z</span><span class="o">=</span><span class="mi">3</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="k">asm</span><span class="p">(</span><span class="w"> </span><span class="s">&quot;addl %2, %1</span><span class="se">\n</span><span class="s">&quot;</span><span class="w"> </span><span class="s">&quot;addl %2, %0&quot;</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="s">&quot;+r&quot;</span><span class="w"> </span><span class="p">(</span><span class="n">x</span><span class="p">),</span><span class="w"> </span><span class="s">&quot;+m&quot;</span><span class="w"> </span><span class="p">(</span><span class="n">y</span><span class="p">)</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="s">&quot;r&quot;</span><span class="w"> </span><span class="p">(</span><span class="n">z</span><span class="p">)</span><span class="w"> </span><span class="p">);</span><span class="w"></span> <span class="p">}</span><span class="w"></span> </pre></div> </div> <p>The previous example adds variable z, item 2, to variable x and variable y. The resulting values for x and y are 4 and 5 respectively.</p> <p>Another type of input constraint worth mentioning here is the <em>matching constraint</em>. A matching constraint is used to specify an operand that fills both an input as well as an output role. An example follows:</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="kt">int</span><span class="w"> </span><span class="n">x</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span><span class="w"></span> <span class="kt">void</span><span class="w"> </span><span class="nf">example6</span><span class="p">()</span><span class="w"></span> <span class="p">{</span><span class="w"></span> <span class="k">asm</span><span class="p">(</span><span class="w"> </span><span class="s">&quot;addl $1, %1&quot;</span><span class="w"></span> <span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="s">&quot;=r&quot;</span><span class="w"> </span><span class="p">(</span><span class="n">x</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="s">&quot;0&quot;</span><span class="w"> </span><span class="p">(</span><span class="n">x</span><span class="p">)</span><span class="w"> </span><span class="p">);</span><span class="w"></span> <span class="p">}</span><span class="w"></span> </pre></div> </div> <p>The previous example is equivalent to the <em>example2()</em> function shown in <a class="reference internal" href="#inline-asm-output-operands"><span class="std std-ref">Output Operands</span></a>. The constraint/expression pair, <em>“0” (x)</em>, tells the compiler to initialize output item <em>0</em> with variable <em>x</em> at the beginning of the <em>asm</em> statement. The resulting value for <em>x</em> is 2. Also note that “<em>%1</em>” in the asm <em>“string”</em> means the same thing as “<em>%0</em>” in this case. That is because there is only one operand with both an input and an output role.</p> <p>Matching constraints are very similar to the <em>read/write</em> output operands mentioned in <a class="reference internal" href="#inline-asm-output-operands"><span class="std std-ref">Output Operands</span></a>. However, there is one key difference between <em>read/write</em> output operands and <em>matching constraints</em>. The <em>matching constraint</em> can have an <em>input expression</em> that differs from its <em>output expression</em>.</p> <p>The following example uses different values for the input and output roles:</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="kt">int</span><span class="w"> </span><span class="n">x</span><span class="p">;</span><span class="w"></span> <span class="kt">int</span><span class="w"> </span><span class="n">y</span><span class="o">=</span><span class="mi">2</span><span class="p">;</span><span class="w"></span> <span class="kt">void</span><span class="w"> </span><span class="nf">example7</span><span class="p">()</span><span class="w"></span> <span class="p">{</span><span class="w"></span> <span class="k">asm</span><span class="p">(</span><span class="w"> </span><span class="s">&quot;addl $1, %1&quot;</span><span class="w"></span> <span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="s">&quot;=r&quot;</span><span class="w"> </span><span class="p">(</span><span class="n">x</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="s">&quot;0&quot;</span><span class="w"> </span><span class="p">(</span><span class="n">y</span><span class="p">)</span><span class="w"> </span><span class="p">);</span><span class="w"></span> <span class="p">}</span><span class="w"></span> </pre></div> </div> <p>The compiler generates the following assembly for example7():</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="nl">example7</span><span class="p">:</span><span class="w"></span> <span class="p">..</span><span class="n">Dcfb0</span><span class="o">:</span><span class="w"></span> <span class="w"> </span><span class="n">pushq</span><span class="w"> </span><span class="o">%</span><span class="n">rbp</span><span class="w"></span> <span class="p">..</span><span class="n">Dcfi0</span><span class="o">:</span><span class="w"></span> <span class="w"> </span><span class="n">movq</span><span class="w"> </span><span class="o">%</span><span class="n">rsp</span><span class="p">,</span><span class="w"> </span><span class="o">%</span><span class="n">rbp</span><span class="w"></span> <span class="p">..</span><span class="n">Dcfi1</span><span class="o">:</span><span class="w"></span> <span class="p">..</span><span class="n">EN1</span><span class="o">:</span><span class="w"></span> <span class="cp">## lineno: 8</span> <span class="w"> </span><span class="n">movl</span><span class="w"> </span><span class="n">y</span><span class="p">(</span><span class="o">%</span><span class="n">rip</span><span class="p">),</span><span class="w"> </span><span class="o">%</span><span class="n">eax</span><span class="w"></span> <span class="w"> </span><span class="n">addl</span><span class="w"> </span><span class="n">$1</span><span class="p">,</span><span class="w"> </span><span class="o">%</span><span class="n">eax</span><span class="w"></span> <span class="w"> </span><span class="n">movl</span><span class="w"> </span><span class="o">%</span><span class="n">eax</span><span class="p">,</span><span class="w"> </span><span class="n">x</span><span class="p">(</span><span class="o">%</span><span class="n">rip</span><span class="p">)</span><span class="w"></span> <span class="cp">## lineno: 0</span> <span class="w"> </span><span class="n">popq</span><span class="w"> </span><span class="o">%</span><span class="n">rbp</span><span class="w"></span> <span class="w"> </span><span class="n">ret</span><span class="w"></span> </pre></div> </div> <p>Variable <em>x</em> gets initialized with the value stored in <em>y</em>, which is <em>2</em>. After adding <em>1</em>, the resulting value for variable <em>x</em> is <em>3</em>.</p> <p>Because <em>matching constraints</em> perform an input role for an output operand, it does not make sense for the output operand to have the read/write (”<em>+</em>”) modifier. In fact, the compiler disallows <em>matching constraints</em> with read/write output operands. The output operand must have a write only (”<em>=</em>”) modifier.</p> </section> <section id="clobber-list"> <h3><span class="section-number">16.2.3. </span>Clobber List<a class="headerlink" href="#clobber-list" title="Permalink to this headline"></a></h3> <p>The <em>[clobber list]</em> is an optional list of strings that hold machine registers used in the asm “<em>string</em>”. Essentially, these strings tell the compiler which registers may be clobbered by the asm statement. By placing registers in this list, the programmer does not have to explicitly save and restore them as required in traditional inline assembly (described in <a class="reference internal" href="#inline-asm"><span class="std std-ref">Inline Assembly</span></a>). The compiler takes care of any required saving and restoring of the registers in this list.</p> <p>Each machine register in the [clobber list] is a string separated by a comma. The leading ‘%’ is optional in the register name. For example, “%eax” is equivalent to “eax”. When specifying the register inside the asm “string”, you must include two leading ‘%’ characters in front of the name (for example., “%%eax”). Otherwise, the compiler will behave as if a bad input/output operand was specified and generate an error message. An example follows:</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="kt">void</span><span class="w"> </span><span class="nf">example8</span><span class="p">()</span><span class="w"></span> <span class="p">{</span><span class="w"></span> <span class="kt">int</span><span class="w"> </span><span class="n">x</span><span class="p">;</span><span class="w"></span> <span class="kt">int</span><span class="w"> </span><span class="n">y</span><span class="o">=</span><span class="mi">2</span><span class="p">;</span><span class="w"></span> <span class="k">asm</span><span class="p">(</span><span class="w"> </span><span class="s">&quot;movl %1, %%eax</span><span class="se">\n</span><span class="s">&quot;</span><span class="w"></span> <span class="w"> </span><span class="s">&quot;movl %1, %%edx</span><span class="se">\n</span><span class="s">&quot;</span><span class="w"></span> <span class="w"> </span><span class="s">&quot;addl %%edx, %%eax</span><span class="se">\n</span><span class="s">&quot;</span><span class="w"></span> <span class="w"> </span><span class="s">&quot;addl %%eax, %0&quot;</span><span class="w"></span> <span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="s">&quot;=r&quot;</span><span class="w"> </span><span class="p">(</span><span class="n">x</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="s">&quot;0&quot;</span><span class="w"> </span><span class="p">(</span><span class="n">y</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="s">&quot;eax&quot;</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;edx&quot;</span><span class="w"> </span><span class="p">);</span><span class="w"></span> <span class="p">}</span><span class="w"></span> </pre></div> </div> <p>This code uses two hard-coded registers, eax and edx. It performs the equivalent of 3*y and assigns it to x, producing a result of 6.</p> <p>In addition to machine registers, the clobber list may contain the following special flags:</p> <dl class="simple"> <dt>“cc”</dt><dd><p>The asm statement may alter the control code register.</p> </dd> <dt>“memory”</dt><dd><p>The asm statement may modify memory in an unpredictable fashion.</p> </dd> </dl> <p>When the “memory” flag is present, the compiler does not keep memory values cached in registers across the asm statement and does not optimize stores or loads to that memory. For example:</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="k">asm</span><span class="p">(</span><span class="s">&quot;call MyFunc&quot;</span><span class="o">:::</span><span class="s">&quot;memory&quot;</span><span class="p">);</span><span class="w"></span> </pre></div> </div> <p>This asm statement contains a “memory” flag because it contains a call. The callee may otherwise clobber registers in use by the caller without the “memory” flag.</p> <p>The following function uses extended asm and the “cc” flag to compute a power of 2 that is less than or equal to the input parameter n.</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="cp">#pragma noinline</span> <span class="kt">int</span><span class="w"> </span><span class="nf">asmDivideConquer</span><span class="p">(</span><span class="kt">int</span><span class="w"> </span><span class="n">n</span><span class="p">)</span><span class="w"></span> <span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">ax</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">bx</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">1</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="k">asm</span><span class="w"> </span><span class="p">(</span><span class="w"></span> <span class="w"> </span><span class="s">&quot;LogLoop:n&quot;</span><span class="w"></span> <span class="w"> </span><span class="s">&quot;cmp %2, %1n&quot;</span><span class="w"></span> <span class="w"> </span><span class="s">&quot;jnle Donen&quot;</span><span class="w"></span> <span class="w"> </span><span class="s">&quot;inc %0n&quot;</span><span class="w"></span> <span class="w"> </span><span class="s">&quot;add %1,%1n&quot;</span><span class="w"></span> <span class="w"> </span><span class="s">&quot;jmp LogLoopn&quot;</span><span class="w"></span> <span class="w"> </span><span class="s">&quot;Done:n&quot;</span><span class="w"></span> <span class="w"> </span><span class="s">&quot;dec %0n&quot;</span><span class="w"></span> <span class="w"> </span><span class="o">:</span><span class="s">&quot;+r&quot;</span><span class="w"> </span><span class="p">(</span><span class="n">ax</span><span class="p">),</span><span class="w"> </span><span class="s">&quot;+r&quot;</span><span class="w"> </span><span class="p">(</span><span class="n">bx</span><span class="p">)</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="s">&quot;r&quot;</span><span class="w"> </span><span class="p">(</span><span class="n">n</span><span class="p">)</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="s">&quot;cc&quot;</span><span class="p">);</span><span class="w"></span> <span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="n">ax</span><span class="p">;</span><span class="w"></span> <span class="p">}</span><span class="w"></span> </pre></div> </div> <p>The ‘cc’ flag is used because the asm statement contains some control flow that may alter the control code register. The #pragma noinline statement prevents the compiler from inlining the asmDivideConquer() function. If the compiler inlines asmDivideConquer(), then it may illegally duplicate the labels LogLoop and Done in the generated assembly.</p> <span class="target" id="inline-asm-addl-constraints"></span></section> <section id="additional-constraints"> <h3><span class="section-number">16.2.4. </span>Additional Constraints<a class="headerlink" href="#additional-constraints" title="Permalink to this headline"></a></h3> <p>Operand constraints can be divided into four main categories:</p> <ul class="simple"> <li><p>Simple Constraints</p></li> <li><p>Machine Constraints</p></li> <li><p>Multiple Alternative Constraints</p></li> <li><p>Constraint Modifiers</p></li> </ul> </section> <section id="simple-constraints"> <h3><span class="section-number">16.2.5. </span>Simple Constraints<a class="headerlink" href="#simple-constraints" title="Permalink to this headline"></a></h3> <p>The simplest kind of constraint is a string of letters or characters, known as <em>Simple Constraints</em>, such as the “r” and “m” constraints introduced in <a class="reference internal" href="#inline-asm-output-operands"><span class="std std-ref">Output Operands</span></a>. Table 33 describes these constraints.</p> <table class="table-no-stripes docutils align-default" id="inline-asm-simple-constraints-inline-asm-simple-constraints-tbl"> <caption><span class="caption-text">Table 33. Simple Constraints</span><a class="headerlink" href="#inline-asm-simple-constraints-inline-asm-simple-constraints-tbl" title="Permalink to this table"></a></caption> <colgroup> <col style="width: 7%" /> <col style="width: 93%" /> </colgroup> <thead> <tr class="row-odd"><th class="head"><p>Constraint</p></th> <th class="head"><p>Description</p></th> </tr> </thead> <tbody> <tr class="row-even"><td><p>whitespace</p></td> <td><p>Whitespace characters are ignored.</p></td> </tr> <tr class="row-odd"><td><p>E</p></td> <td><p>An immediate floating point operand.</p></td> </tr> <tr class="row-even"><td><p>F</p></td> <td><p>Same as “E”.</p></td> </tr> <tr class="row-odd"><td><p>g</p></td> <td><p>Any general purpose register, memory, or immediate integer operand is allowed.</p></td> </tr> <tr class="row-even"><td><p>i</p></td> <td><p>An immediate integer operand.</p></td> </tr> <tr class="row-odd"><td><p>m</p></td> <td><p>A memory operand. Any address supported by the machine is allowed.</p></td> </tr> <tr class="row-even"><td><p>n</p></td> <td><p>Same as “i”.</p></td> </tr> <tr class="row-odd"><td><p>o</p></td> <td><p>Same as “m”.</p></td> </tr> <tr class="row-even"><td><p>p</p></td> <td><p>An operand that is a valid memory address. The expression associated with the constraint is expected to evaluate to an address (for example, “p” (&amp;x) ).</p></td> </tr> <tr class="row-odd"><td><p>r</p></td> <td><p>A general purpose register operand.</p></td> </tr> <tr class="row-even"><td><p>X</p></td> <td><p>Same as “g”.</p></td> </tr> <tr class="row-odd"><td><p>0,1,2,..9</p></td> <td><p>Matching Constraint. See <a class="reference internal" href="#inline-asm-output-operands"><span class="std std-ref">Output Operands</span></a> for a description.</p></td> </tr> </tbody> </table> <p>The following example uses the general or “g” constraint, which allows the compiler to pick an appropriate constraint type for the operand; the compiler chooses from a general purpose register, memory, or immediate operand. This code lets the compiler choose the constraint type for “y”.</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="kt">void</span><span class="w"> </span><span class="nf">example9</span><span class="p">()</span><span class="w"></span> <span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">x</span><span class="p">,</span><span class="w"> </span><span class="n">y</span><span class="o">=</span><span class="mi">2</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="k">asm</span><span class="p">(</span><span class="w"> </span><span class="s">&quot;movl %1, %0</span><span class="se">\n</span><span class="s">&quot;</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="s">&quot;=r&quot;</span><span class="w"></span> <span class="p">(</span><span class="n">x</span><span class="p">)</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="s">&quot;g&quot;</span><span class="w"> </span><span class="p">(</span><span class="n">y</span><span class="p">)</span><span class="w"> </span><span class="p">);</span><span class="w"></span> <span class="p">}</span><span class="w"></span> </pre></div> </div> <p>This technique can result in more efficient code. For example, when compiling example9() the compiler replaces the load and store of y with a constant 2. The compiler can then generate an immediate 2 for the y operand in the example. The assembly generated by nvc for our example is as follows:</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="nl">example9</span><span class="p">:</span><span class="w"></span> <span class="p">..</span><span class="n">Dcfb0</span><span class="o">:</span><span class="w"></span> <span class="w"> </span><span class="n">pushq</span><span class="w"> </span><span class="o">%</span><span class="n">rbp</span><span class="w"></span> <span class="p">..</span><span class="n">Dcfi0</span><span class="o">:</span><span class="w"></span> <span class="w"> </span><span class="n">movq</span><span class="w"> </span><span class="o">%</span><span class="n">rsp</span><span class="p">,</span><span class="w"> </span><span class="o">%</span><span class="n">rbp</span><span class="w"></span> <span class="p">..</span><span class="n">Dcfi1</span><span class="o">:</span><span class="w"></span> <span class="p">..</span><span class="n">EN1</span><span class="o">:</span><span class="w"></span> <span class="cp">## lineno: 3</span> <span class="w"> </span><span class="n">movl</span><span class="w"> </span><span class="n">$2</span><span class="p">,</span><span class="w"> </span><span class="o">%</span><span class="n">eax</span><span class="w"></span> <span class="cp">## lineno: 6</span> <span class="w"> </span><span class="n">popq</span><span class="w"> </span><span class="o">%</span><span class="n">rbp</span><span class="w"></span> <span class="w"> </span><span class="n">ret</span><span class="w"></span> </pre></div> </div> <p>In this example, notice the use of $2 for the “y” operand.</p> <p>Of course, if y is always 2, then the immediate value may be used instead of the variable with the “i” constraint, as shown here:</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="kt">void</span><span class="w"> </span><span class="nf">example10</span><span class="p">()</span><span class="w"></span> <span class="p">{</span><span class="w"></span> <span class="kt">int</span><span class="w"> </span><span class="n">x</span><span class="p">;</span><span class="w"></span> <span class="k">asm</span><span class="p">(</span><span class="w"> </span><span class="s">&quot;movl %1, %0</span><span class="se">\n</span><span class="s">&quot;</span><span class="w"></span> <span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="s">&quot;=r&quot;</span><span class="w"> </span><span class="p">(</span><span class="n">x</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="s">&quot;i&quot;</span><span class="w"> </span><span class="p">(</span><span class="mi">2</span><span class="p">)</span><span class="w"> </span><span class="p">);</span><span class="w"></span> <span class="p">}</span><span class="w"></span> </pre></div> </div> <p>Compiling example10() with nvc produces assembly similar to that produced for example9().</p> </section> <section id="machine-constraints"> <h3><span class="section-number">16.2.6. </span>Machine Constraints<a class="headerlink" href="#machine-constraints" title="Permalink to this headline"></a></h3> <p>Another category of constraints is <em>Machine Constraints</em>. The x86_64 architectures has several classes of registers. To choose a particular class of register, you can use the x86_64 machine constraints described in <a class="reference internal" href="#inline-asm-machine-constraints-inline-asm-machine-constraints-tbl"><span class="std std-ref">Table 34</span></a>.</p> <table class="table-no-stripes docutils align-default" id="inline-asm-machine-constraints-inline-asm-machine-constraints-tbl"> <caption><span class="caption-text">Table 34. x86_64 Machine Constraints</span><a class="headerlink" href="#inline-asm-machine-constraints-inline-asm-machine-constraints-tbl" title="Permalink to this table"></a></caption> <colgroup> <col style="width: 9%" /> <col style="width: 91%" /> </colgroup> <thead> <tr class="row-odd"><th class="head"><p>Constraint</p></th> <th class="head"><p>Description</p></th> </tr> </thead> <tbody> <tr class="row-even"><td><p>a</p></td> <td><p>a register (e.g., %al, %ax, %eax, %rax)</p></td> </tr> <tr class="row-odd"><td><p>A</p></td> <td><p>Specifies a or d registers. The d register holds the most significant bits and the a register holds the least significant bits.</p></td> </tr> <tr class="row-even"><td><p>b</p></td> <td><p>b register (e.g, %bl, %bx, %ebx, %rbx)</p></td> </tr> <tr class="row-odd"><td><p>c</p></td> <td><p>c register (e.g., %cl, %cx, %ecx, %rcx)</p></td> </tr> <tr class="row-even"><td><p>C</p></td> <td><p>Not supported.</p></td> </tr> <tr class="row-odd"><td><p>d</p></td> <td><p>d register (e.g., %dl, %dx, %edx, %rdx)</p></td> </tr> <tr class="row-even"><td><p>D</p></td> <td><p>di register (e.g., %dil, %di, %edi, %rdi)</p></td> </tr> <tr class="row-odd"><td><p>e</p></td> <td><p>Constant in range of 0xffffffff to 0x7fffffff</p></td> </tr> <tr class="row-even"><td><p>f</p></td> <td><p>Not supported.</p></td> </tr> <tr class="row-odd"><td><p>G</p></td> <td><p>Floating point constant in range of 0.0 to 1.0.</p></td> </tr> <tr class="row-even"><td><p>I</p></td> <td><p>Constant in range of 0 to 31 (e.g., for 32-bit shifts).</p></td> </tr> <tr class="row-odd"><td><p>J</p></td> <td><p>Constant in range of 0 to 63 (e.g., for 64-bit shifts)</p></td> </tr> <tr class="row-even"><td><p>K</p></td> <td><p>Constant in range of 0to 127.</p></td> </tr> <tr class="row-odd"><td><p>L</p></td> <td><p>Constant in range of 0 to 65535.</p></td> </tr> <tr class="row-even"><td><p>M</p></td> <td><p>Constant in range of 0 to 3 constant (e.g., shifts for lea instruction).</p></td> </tr> <tr class="row-odd"><td><p>N</p></td> <td><p>Constant in range of 0 to 255 (e.g., for out instruction).</p></td> </tr> <tr class="row-even"><td><p>q</p></td> <td><p>Same as “r” simple constraint.</p></td> </tr> <tr class="row-odd"><td><p>Q</p></td> <td><p>Same as “r” simple constraint.</p></td> </tr> <tr class="row-even"><td><p>R</p></td> <td><p>Same as “r” simple constraint.</p></td> </tr> <tr class="row-odd"><td><p>S</p></td> <td><p>si register (e.g., %sil, %si, %edi, %rsi)</p></td> </tr> <tr class="row-even"><td><p>t</p></td> <td><p>Not supported.</p></td> </tr> <tr class="row-odd"><td><p>u</p></td> <td><p>Not supported.</p></td> </tr> <tr class="row-even"><td><p>x</p></td> <td><p>XMM SSE register</p></td> </tr> <tr class="row-odd"><td><p>y</p></td> <td><p>Not supported.</p></td> </tr> <tr class="row-even"><td><p>Z</p></td> <td><p>Constant in range of 0 to 0x7fffffff.</p></td> </tr> </tbody> </table> <p>The following example uses the “x” or XMM register constraint to subtract c from b and store the result in a.</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="kt">double</span><span class="w"> </span><span class="nf">example11</span><span class="p">()</span><span class="w"></span> <span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="kt">double</span><span class="w"> </span><span class="n">a</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="kt">double</span><span class="w"> </span><span class="n">b</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mf">400.99</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="kt">double</span><span class="w"> </span><span class="n">c</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mf">300.98</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="k">asm</span><span class="w"> </span><span class="p">(</span><span class="w"> </span><span class="s">&quot;subpd %2, %0;&quot;</span><span class="w"></span> <span class="w"> </span><span class="o">:</span><span class="s">&quot;=x&quot;</span><span class="w"> </span><span class="p">(</span><span class="n">a</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="s">&quot;0&quot;</span><span class="w"> </span><span class="p">(</span><span class="n">b</span><span class="p">),</span><span class="w"> </span><span class="s">&quot;x&quot;</span><span class="w"> </span><span class="p">(</span><span class="n">c</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="p">);</span><span class="w"></span> <span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="n">a</span><span class="p">;</span><span class="w"></span> <span class="p">}</span><span class="w"></span> </pre></div> </div> <p>The generated assembly for this example is this:</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="nl">example11</span><span class="p">:</span><span class="w"></span> <span class="p">..</span><span class="n">Dcfb0</span><span class="o">:</span><span class="w"></span> <span class="w"> </span><span class="n">pushq</span><span class="w"> </span><span class="o">%</span><span class="n">rbp</span><span class="w"></span> <span class="p">..</span><span class="n">Dcfi0</span><span class="o">:</span><span class="w"></span> <span class="w"> </span><span class="n">movq</span><span class="w"> </span><span class="o">%</span><span class="n">rsp</span><span class="p">,</span><span class="w"> </span><span class="o">%</span><span class="n">rbp</span><span class="w"></span> <span class="p">..</span><span class="n">Dcfi1</span><span class="o">:</span><span class="w"></span> <span class="p">..</span><span class="n">EN1</span><span class="o">:</span><span class="w"></span> <span class="cp">## lineno: 4</span> <span class="w"> </span><span class="n">movsd</span><span class="w"> </span><span class="p">.</span><span class="n">C00128</span><span class="p">(</span><span class="o">%</span><span class="n">rip</span><span class="p">),</span><span class="w"> </span><span class="o">%</span><span class="n">xmm1</span><span class="w"></span> <span class="w"> </span><span class="n">movsd</span><span class="w"> </span><span class="p">.</span><span class="n">C00130</span><span class="p">(</span><span class="o">%</span><span class="n">rip</span><span class="p">),</span><span class="w"> </span><span class="o">%</span><span class="n">xmm2</span><span class="w"></span> <span class="w"> </span><span class="n">movapd</span><span class="w"> </span><span class="o">%</span><span class="n">xmm1</span><span class="p">,</span><span class="w"> </span><span class="o">%</span><span class="n">xmm0</span><span class="w"></span> <span class="w"> </span><span class="n">subpd</span><span class="w"> </span><span class="o">%</span><span class="n">xmm2</span><span class="p">,</span><span class="w"> </span><span class="o">%</span><span class="n">xmm0</span><span class="p">;</span><span class="w"></span> <span class="cp">## lineno: 10</span> <span class="cp">## lineno: 11</span> <span class="w"> </span><span class="n">popq</span><span class="w"> </span><span class="o">%</span><span class="n">rbp</span><span class="w"></span> <span class="w"> </span><span class="n">ret</span><span class="w"></span> </pre></div> </div> <p>If a specified register is not available, the nvc and nvc++ compilers issue an error message.</p> <span class="target" id="inline-asm-mult-alt-constraints"></span></section> <section id="multiple-alternative-constraints"> <h3><span class="section-number">16.2.7. </span>Multiple Alternative Constraints<a class="headerlink" href="#multiple-alternative-constraints" title="Permalink to this headline"></a></h3> <p>Sometimes a single instruction can take a variety of operand types. For example, the x86-64 permits register-to-memory and memory-to-register operations. To allow this flexibility in inline assembly, use <em>multiple alternative constraints</em>. An <em>alternative</em> is a series of constraints for each operand.</p> <p>To specify multiple alternatives, separate each alternative with a comma.</p> <table class="table-no-stripes docutils align-default" id="id37"> <caption><span class="caption-text">Table 35. Multiple Alternative Constraints</span><a class="headerlink" href="#id37" title="Permalink to this table"></a></caption> <colgroup> <col style="width: 16%" /> <col style="width: 84%" /> </colgroup> <thead> <tr class="row-odd"><th class="head"><p>Constraint</p></th> <th class="head"><p>Description</p></th> </tr> </thead> <tbody> <tr class="row-even"><td><p>,</p></td> <td><p>Separates each alternative for a particular operand.</p></td> </tr> <tr class="row-odd"><td><p>?</p></td> <td><p>Ignored</p></td> </tr> <tr class="row-even"><td><p>!</p></td> <td><p>Ignored</p></td> </tr> </tbody> </table> <p>The following example uses multiple alternatives for an add operation.</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="kt">void</span><span class="w"> </span><span class="nf">example13</span><span class="p">()</span><span class="w"></span> <span class="p">{</span><span class="w"></span> <span class="kt">int</span><span class="w"> </span><span class="n">x</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span><span class="w"></span> <span class="kt">int</span><span class="w"> </span><span class="n">y</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span><span class="w"></span> <span class="k">asm</span><span class="p">(</span><span class="w"> </span><span class="s">&quot;addl %1, %0</span><span class="se">\n</span><span class="s">&quot;</span><span class="w"></span> <span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="s">&quot;+ab,cd&quot;</span><span class="w"> </span><span class="p">(</span><span class="n">x</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="s">&quot;db,cam&quot;</span><span class="w"> </span><span class="p">(</span><span class="n">y</span><span class="p">)</span><span class="w"> </span><span class="p">);</span><span class="w"></span> <span class="p">}</span><span class="w"></span> </pre></div> </div> <p>The preceding <em>example13()</em> has two alternatives for each operand: “ab,cd” for the output operand and “db,cam” for the input operand. Each operand must have the same number of alternatives; however, each alternative can have any number of constraints (for example, the output operand in <em>example13()</em> has two constraints for its second alternative and the input operand has three for its second alternative).</p> <p>The compiler first tries to satisfy the left-most alternative of the first operand (for example, the output operand in <em>example13()</em>). When satisfying the operand, the compiler starts with the left-most constraint. If the compiler cannot satisfy an alternative with this constraint (for example, if the desired register is not available), it tries to use any subsequent constraints. If the compiler runs out of constraints, it moves on to the next alternative. If the compiler runs out of alternatives, it issues an error similar to the one mentioned in <em>example12()</em>. If an alternative is found, the compiler uses the same alternative for subsequent operands. For example, if the compiler chooses the “c” register for the output operand in example13(), then it will use either the “a” or “m” constraint for the input operand.</p> </section> <section id="constraint-modifiers"> <h3><span class="section-number">16.2.8. </span>Constraint Modifiers<a class="headerlink" href="#constraint-modifiers" title="Permalink to this headline"></a></h3> <p>Characters that affect the compiler’s interpretation of a constraint are known as <em>Constraint Modifiers</em>. Two constraint modifiers, the “=” and the “+”, were introduced in <a class="reference internal" href="#inline-asm-output-operands"><span class="std std-ref">Output Operands</span></a>. The following table summarizes each constraint modifier.</p> <table class="table-no-stripes docutils align-default" id="id38"> <caption><span class="caption-text">Table 36. Constraint Modifier Characters</span><a class="headerlink" href="#id38" title="Permalink to this table"></a></caption> <colgroup> <col style="width: 4%" /> <col style="width: 96%" /> </colgroup> <thead> <tr class="row-odd"><th class="head"><p>Constraint Modifier</p></th> <th class="head"><p>Description</p></th> </tr> </thead> <tbody> <tr class="row-even"><td><p>=</p></td> <td><p>This operand is write-only. It is valid for output operands only. If specified, the “=” must appear as the first character of the constraint string.</p></td> </tr> <tr class="row-odd"><td><p>+</p></td> <td><p>This operand is both read and written by the instruction. It is valid for output operands only. The output operand is initialized with its expression before the first instruction in the asm statement. If specified, the “+” must appear as the first character of the constraint string.</p></td> </tr> <tr class="row-even"><td><p>&amp;</p></td> <td><p>A constraint or an alternative constraint, as defined in <a class="reference internal" href="#inline-asm-mult-alt-constraints"><span class="std std-ref">Multiple Alternative Constraints</span></a>, containing an “&amp;” indicates that the output operand is an <em>early clobber operand</em>. This type operand is an output operand that may be modified before the asm statement finishes using all of the input operands. The compiler will not place this operand in a register that may be used as an input operand or part of any memory address.</p></td> </tr> <tr class="row-odd"><td><p>%</p></td> <td><p>Ignored.</p></td> </tr> <tr class="row-even"><td><p>#</p></td> <td><p>Characters following a “#” up to the first comma (if present) are to be ignored in the constraint.</p></td> </tr> <tr class="row-odd"><td><p>*</p></td> <td><p>The character that follows the “*” is to be ignored in the constraint.</p></td> </tr> </tbody> </table> <p>The “=” and “+” modifiers apply to the operand, regardless of the number of alternatives in the constraint string. For example, the “+” in the output operand of example13() appears once and applies to both alternatives in the constraint string. The “&amp;”, “#”, and “*” modifiers apply only to the alternative in which they appear.</p> <p>Normally, the compiler assumes that input operands are used before assigning results to the output operands. This assumption lets the compiler reuse registers as needed inside the asm statement. However, if the asm statement does not follow this convention, the compiler may indiscriminately clobber a result register with an input operand. To prevent this behavior, apply the early clobber “&amp;” modifier. An example follows:</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="kt">void</span><span class="w"> </span><span class="nf">example15</span><span class="p">()</span><span class="w"></span> <span class="p">{</span><span class="w"></span> <span class="kt">int</span><span class="w"> </span><span class="n">w</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span><span class="w"></span> <span class="kt">int</span><span class="w"> </span><span class="n">z</span><span class="p">;</span><span class="w"></span> <span class="k">asm</span><span class="p">(</span><span class="w"> </span><span class="s">&quot;movl $1, %0</span><span class="se">\n</span><span class="s">&quot;</span><span class="w"></span> <span class="w"> </span><span class="s">&quot;addl %2, %0</span><span class="se">\n</span><span class="s">&quot;</span><span class="w"></span> <span class="w"> </span><span class="s">&quot;movl %2, %1&quot;</span><span class="w"></span> <span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="s">&quot;=a&quot;</span><span class="w"> </span><span class="p">(</span><span class="n">w</span><span class="p">),</span><span class="w"> </span><span class="s">&quot;=r&quot;</span><span class="w"> </span><span class="p">(</span><span class="n">z</span><span class="p">)</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="s">&quot;r&quot;</span><span class="w"> </span><span class="p">(</span><span class="n">w</span><span class="p">)</span><span class="w"> </span><span class="p">);</span><span class="w"></span> <span class="p">}</span><span class="w"></span> </pre></div> </div> <p>The previous code example presents an interesting ambiguity because “w” appears both as an output and as an input operand. So, the value of “z” can be either 1 or 2, depending on whether the compiler uses the same register for operand 0 and operand 2. The use of constraint “r” for operand 2 allows the compiler to pick any general purpose register, so it may (or may not) pick register “a” for operand 2. This ambiguity can be eliminated by changing the constraint for operand 2 from “r” to “a” so the value of “z” will be 2, or by adding an early clobber “&amp;” modifier so that “z” will be 1. The following example shows the same function with an early clobber “&amp;” modifier:</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="kt">void</span><span class="w"> </span><span class="nf">example16</span><span class="p">()</span><span class="w"></span> <span class="p">{</span><span class="w"></span> <span class="kt">int</span><span class="w"> </span><span class="n">w</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span><span class="w"></span> <span class="kt">int</span><span class="w"> </span><span class="n">z</span><span class="p">;</span><span class="w"></span> <span class="k">asm</span><span class="p">(</span><span class="w"> </span><span class="s">&quot;movl $1, %0</span><span class="se">\n</span><span class="s">&quot;</span><span class="w"></span> <span class="w"> </span><span class="s">&quot;addl %2, %0</span><span class="se">\n</span><span class="s">&quot;</span><span class="w"></span> <span class="w"> </span><span class="s">&quot;movl %2, %1&quot;</span><span class="w"></span> <span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="s">&quot;=&amp;a&quot;</span><span class="w"> </span><span class="p">(</span><span class="n">w</span><span class="p">),</span><span class="w"> </span><span class="s">&quot;=r&quot;</span><span class="w"> </span><span class="p">(</span><span class="n">z</span><span class="p">)</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="s">&quot;r&quot;</span><span class="w"> </span><span class="p">(</span><span class="n">w</span><span class="p">)</span><span class="w"> </span><span class="p">);</span><span class="w"></span> <span class="p">}</span><span class="w"></span> </pre></div> </div> <p>Adding the early clobber “&amp;” forces the compiler not to use the “a” register for anything other than operand 0. Operand 2 will therefore get its own register with its own copy of “w”. The result for “z” in <em>example16()</em> is 1.</p> </section> </section> <section id="operand-aliases"> <h2><span class="section-number">16.3. </span>Operand Aliases<a class="headerlink" href="#operand-aliases" title="Permalink to this headline"></a></h2> <p>Extended asm specifies operands in assembly strings with a percent ‘%’ followed by the operand number. For example, “%0” references operand 0 or the output item “=&amp;a” (w) in function <em>example16()</em> in the previous example. Extended asm also supports operand aliasing, which allows use of a symbolic name instead of a number for specifying operands, as illustrated in this example:</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="kt">void</span><span class="w"> </span><span class="nf">example17</span><span class="p">()</span><span class="w"></span> <span class="p">{</span><span class="w"></span> <span class="kt">int</span><span class="w"> </span><span class="n">w</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="n">z</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span><span class="w"></span> <span class="k">asm</span><span class="p">(</span><span class="w"> </span><span class="s">&quot;movl $1, %[output1]</span><span class="se">\n</span><span class="s">&quot;</span><span class="w"></span> <span class="w"> </span><span class="s">&quot;addl %[input], %[output1]</span><span class="se">\n</span><span class="s">&quot;</span><span class="w"></span> <span class="w"> </span><span class="s">&quot;movl %[input], %[output2]&quot;</span><span class="w"></span> <span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="p">[</span><span class="n">output1</span><span class="p">]</span><span class="w"> </span><span class="s">&quot;=&amp;a&quot;</span><span class="w"> </span><span class="p">(</span><span class="n">w</span><span class="p">),</span><span class="w"> </span><span class="p">[</span><span class="n">output2</span><span class="p">]</span><span class="w"> </span><span class="s">&quot;=r&quot;</span><span class="w"></span> <span class="p">(</span><span class="n">z</span><span class="p">)</span><span class="w"></span> <span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="p">[</span><span class="n">input</span><span class="p">]</span><span class="w"> </span><span class="s">&quot;r&quot;</span><span class="w"> </span><span class="p">(</span><span class="n">w</span><span class="p">));</span><span class="w"></span> <span class="p">}</span><span class="w"></span> </pre></div> </div> <p>In <em>example18(),</em> “%0” and “%[output1]” both represent the output operand.</p> </section> <section id="assembly-string-modifiers"> <h2><span class="section-number">16.4. </span>Assembly String Modifiers<a class="headerlink" href="#assembly-string-modifiers" title="Permalink to this headline"></a></h2> <p>Special character sequences in the assembly string affect the way the assembly is generated by the compiler. For example, the “%” is an escape sequence for specifying an operand, “%%” produces a percent for hard coded registers, and “\n” specifies a new line. <a class="reference internal" href="#inline-asm-strg-modifiers-inline-asm-strg-modifiers-tbl"><span class="std std-ref">Table 37</span></a> summarizes these modifiers, known as <em>Assembly String Modifiers</em>.</p> <table class="table-no-stripes docutils align-default" id="inline-asm-strg-modifiers-inline-asm-strg-modifiers-tbl"> <caption><span class="caption-text">Table 37. Assembly String Modifier Characters</span><a class="headerlink" href="#inline-asm-strg-modifiers-inline-asm-strg-modifiers-tbl" title="Permalink to this table"></a></caption> <colgroup> <col style="width: 21%" /> <col style="width: 79%" /> </colgroup> <thead> <tr class="row-odd"><th class="head"><p>Modifier</p></th> <th class="head"><p>Description</p></th> </tr> </thead> <tbody> <tr class="row-even"><td><p>\</p></td> <td><p>Same as \ in printf format strings.</p></td> </tr> <tr class="row-odd"><td><p>%*</p></td> <td><p>Adds a ‘*’ in the assembly string.</p></td> </tr> <tr class="row-even"><td><p>%%</p></td> <td><p>Adds a ‘%’ in the assembly string.</p></td> </tr> <tr class="row-odd"><td><p>%A</p></td> <td><p>Adds a ‘*’ in front of an operand in the assembly string. (For example, %A0 adds a ‘*’ in front of operand 0 in the assembly output.)</p></td> </tr> <tr class="row-even"><td><p>%B</p></td> <td><p>Produces the byte op code suffix for this operand. (For example, %b0 produces ‘b’ on x86-64.)</p></td> </tr> <tr class="row-odd"><td><p>%L</p></td> <td><p>Produces the word op code suffix for this operand. (For example, %L0 produces ‘l’ on x86-64.)</p></td> </tr> <tr class="row-even"><td><p>%P</p></td> <td><p>If producing Position Independent Code (PIC), the compiler adds the PIC suffix for this operand. (For example, %P0 produces &#64;PLT on x86-64.)</p></td> </tr> <tr class="row-odd"><td><p>%Q</p></td> <td><p>Produces a quad word op code suffix for this operand if it is supported by the target. Otherwise, it produces a word op code suffix. (For example, %Q0 produces ‘q’ on x86-64.)</p></td> </tr> <tr class="row-even"><td><p>%S</p></td> <td><p>Produces ‘s’ suffix for this operand. (For example, %S0 produces ‘s’ on x86-64.)</p></td> </tr> <tr class="row-odd"><td><p>%T</p></td> <td><p>Produces ‘t’ suffix for this operand. (For example, %S0 produces ‘t’ on x86-64.)</p></td> </tr> <tr class="row-even"><td><p>%W</p></td> <td><p>Produces the half word op code suffix for this operand. (For example, %W0 produces ‘w’ on x86-64.)</p></td> </tr> <tr class="row-odd"><td><p>%a</p></td> <td><p>Adds open and close parentheses ( ) around the operand.</p></td> </tr> <tr class="row-even"><td><p>%b</p></td> <td><p>Produces the byte register name for an operand. (For example, if operand 0 is in register ‘a’, then %b0 will produce ‘%al’.)</p></td> </tr> <tr class="row-odd"><td><p>%c</p></td> <td><p>Cuts the ‘$’ character from an immediate operand.</p></td> </tr> <tr class="row-even"><td><p>%k</p></td> <td><p>Produces the word register name for an operand. (For example, if operand 0 is in register ‘a’, then %k0 will produce ‘%eax’.)</p></td> </tr> <tr class="row-odd"><td><p>%q</p></td> <td><p>Produces the quad word register name for an operand if the target supports quad word. Otherwise, it produces a word register name. (For example, if operand 0 is in register ‘a’, then %q0 produces %rax on x86-64.)</p></td> </tr> <tr class="row-even"><td><p>%w</p></td> <td><p>Produces the half word register name for an operand. (For example, if operand 0 is in register ‘a’, then %w0 will produce ‘%ax’.)</p></td> </tr> <tr class="row-odd"><td><p>%z</p></td> <td><p>Produces an op code suffix based on the size of an operand. (For example, ‘b’ for byte, ‘w’ for half word, ‘l’ for word, and ‘q’ for quad word.)</p></td> </tr> <tr class="row-even"><td><p>%+ %C %D %F %O %X %f %h %l %n %s %y</p></td> <td><p>Not supported.</p></td> </tr> </tbody> </table> <p>These modifiers begin with either a backslash “\” or a percent “%”.</p> <p>The modifiers that begin with a backslash “\” (e.g., “\n”) have the same effect as they do in a printf format string. The modifiers that are preceded with a “%” are used to modify a particular operand.</p> <p>These modifiers begin with either a backslash “\” or a percent “%” For example, “%b0” means, “produce the byte or 8 bit version of operand 0”. If operand 0 is a register, it will produce a byte register such as %al, %bl, %cl, and so on.</p> </section> <section id="extended-asm-macros"> <h2><span class="section-number">16.5. </span>Extended Asm Macros<a class="headerlink" href="#extended-asm-macros" title="Permalink to this headline"></a></h2> <p>As with traditional inline assembly, described in <a class="reference internal" href="#inline-asm"><span class="std std-ref">Inline Assembly</span></a>, extended asm can be used in a macro. For example, you can use the following macro to access the runtime stack pointer.</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="cp">#define GET_SP(x) \</span> <span class="cp">asm(&quot;mov %%sp, %0&quot;: &quot;=m&quot; (##x):: &quot;%sp&quot; );</span> <span class="kt">void</span><span class="w"> </span><span class="nf">example20</span><span class="p">()</span><span class="w"></span> <span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">stack_pointer</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="n">GET_SP</span><span class="p">(</span><span class="n">stack_pointer</span><span class="p">);</span><span class="w"></span> <span class="p">}</span><span class="w"></span> </pre></div> </div> <p>The GET_SP macro assigns the value of the stack pointer to whatever is inserted in its argument (for example, stack_pointer). Another C extension known as <em>statement expressions</em> is used to write the GET_SP macro another way:</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="cp">#define GET_SP2 ({ \</span> <span class="cp">void *my_stack_ptr; \</span> <span class="cp">asm(&quot;mov %%sp, %0&quot;: &quot;=m&quot; (my_stack_ptr) :: &quot;%sp&quot; ); \</span> <span class="cp">my_stack_ptr; \</span> <span class="cp">})</span> <span class="kt">void</span><span class="w"> </span><span class="nf">example21</span><span class="p">()</span><span class="w"></span> <span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">stack_pointer</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">GET_SP2</span><span class="p">;</span><span class="w"></span> <span class="p">}</span><span class="w"></span> </pre></div> </div> <p>The statement expression allows a body of code to evaluate to a single value. This value is specified as the last instruction in the statement expression. In this case, the value is the result of the asm statement, my_stack_ptr. By writing an asm macro with a statement expression, the asm result may be assigned directly to another variable (for example, void * stack_pointer = GET_SP2) or included in a larger expression, such as: void * stack_pointer = GET_SP2 - sizeof(long).</p> <p>Which style of macro to use depends on the application. If the asm statement needs to be a part of an expression, then a macro with a statement expression is a good approach. Otherwise, a traditional macro, like GET_SP(x), will probably suffice.</p> </section> <section id="intrinsics"> <h2><span class="section-number">16.6. </span>Intrinsics<a class="headerlink" href="#intrinsics" title="Permalink to this headline"></a></h2> <p>Inline intrinsic functions map to actual x86-64 machine instructions. Intrinsics are inserted inline to avoid the overhead of a function call. The compiler has special knowledge of intrinsics, so with use of intrinsics, better code may be generated as compared to extended inline assembly code.</p> <p>The NVIDIA HPC Compilers intrinsics library implements MMX, SSE, SS2, SSE3, SSSE3, SSE4a, ABM, and AVX instructions. The intrinsic functions are available to C and C++ programs. Unlike most functions which are in libraries, intrinsics are implemented internally by the compiler. A program can call the intrinsic functions from C/C++ source code after including the corresponding header file.</p> <p>The intrinsics are divided into header files as follows:</p> <table class="table-no-stripes docutils align-default" id="id39"> <caption><span class="caption-text">Table 38. Intrinsic Header File Organization</span><a class="headerlink" href="#id39" title="Permalink to this table"></a></caption> <colgroup> <col style="width: 26%" /> <col style="width: 23%" /> <col style="width: 2%" /> <col style="width: 26%" /> <col style="width: 23%" /> </colgroup> <thead> <tr class="row-odd"><th class="head"><p>Instructions</p></th> <th class="head"><p>Header File</p></th> <th class="head"></th> <th class="head"><p>Instructions</p></th> <th class="head"><p>Header File</p></th> </tr> </thead> <tbody> <tr class="row-even"><td><p>ABM</p></td> <td><p>intrin.h</p></td> <td></td> <td><p>SSE2</p></td> <td><p>emmintrin.h</p></td> </tr> <tr class="row-odd"><td><p>AVX</p></td> <td><p>immintrin.h</p></td> <td></td> <td><p>SSE3</p></td> <td><p>pmmintrin.h</p></td> </tr> <tr class="row-even"><td><p>MMX</p></td> <td><p>mmintrin.h</p></td> <td></td> <td><p>SSSE3</p></td> <td><p>tmmintrin.h</p></td> </tr> <tr class="row-odd"><td><p>SSE</p></td> <td><p>xmmintrin.h</p></td> <td></td> <td><p>SSE4a</p></td> <td><p>ammintrin.h</p></td> </tr> </tbody> </table> <p>The following is a simple example program that calls XMM intrinsics.</p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="cp">#include</span><span class="w"> </span><span class="cpf">&lt;xmmintrin.h&gt;</span><span class="cp"></span> <span class="kt">int</span><span class="w"> </span><span class="nf">main</span><span class="p">(){</span><span class="w"></span> <span class="w"> </span><span class="kr">__m128</span><span class="w"> </span><span class="n">__A</span><span class="p">,</span><span class="w"> </span><span class="n">__B</span><span class="p">,</span><span class="w"> </span><span class="n">result</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="n">__A</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">_mm_set_ps</span><span class="p">(</span><span class="mf">23.3</span><span class="p">,</span><span class="w"> </span><span class="mf">43.7</span><span class="p">,</span><span class="w"> </span><span class="mf">234.234</span><span class="p">,</span><span class="w"> </span><span class="mf">98.746</span><span class="p">);</span><span class="w"></span> <span class="w"> </span><span class="n">__B</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">_mm_set_ps</span><span class="p">(</span><span class="mf">15.4</span><span class="p">,</span><span class="w"> </span><span class="mf">34.3</span><span class="p">,</span><span class="w"> </span><span class="mf">4.1</span><span class="p">,</span><span class="w"> </span><span class="mf">8.6</span><span class="p">);</span><span class="w"></span> <span class="w"> </span><span class="n">result</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">_mm_add_ps</span><span class="p">(</span><span class="n">__A</span><span class="p">,</span><span class="n">__B</span><span class="p">);</span><span class="w"></span> <span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"></span> <span class="w"> </span><span class="p">}</span><span class="w"></span> </pre></div> </div> <p class="rubric-h1 rubric">Notices</p> <p class="rubric-h2 rubric">Notice</p> <p>ALL NVIDIA DESIGN SPECIFICATIONS, REFERENCE BOARDS, FILES, DRAWINGS, DIAGNOSTICS, LISTS, AND OTHER DOCUMENTS (TOGETHER AND SEPARATELY, “MATERIALS”) ARE BEING PROVIDED “AS IS.” NVIDIA MAKES NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.</p> <p>Information furnished is believed to be accurate and reliable. However, NVIDIA Corporation assumes no responsibility for the consequences of use of such information or for any infringement of patents or other rights of third parties that may result from its use. No license is granted by implication of otherwise under any patent rights of NVIDIA Corporation. Specifications mentioned in this publication are subject to change without notice. This publication supersedes and replaces all other information previously supplied. NVIDIA Corporation products are not authorized as critical components in life support devices or systems without express written approval of NVIDIA Corporation.</p> <p class="rubric-h2 rubric">Trademarks</p> <p>NVIDIA, the NVIDIA logo, CUDA, CUDA-X, GPUDirect, HPC SDK, NGC, NVIDIA Volta, NVIDIA DGX, NVIDIA Nsight, NVLink, NVSwitch, and Tesla are trademarks and/or registered trademarks of NVIDIA Corporation in the U.S. and other countries. Other company and product names may be trademarks of the respective companies with which they are associated.</p> </section> </section> </div> </div> <footer> <hr/> <div role="contentinfo"> <img src="_static/NVIDIA-LogoBlack.svg" class="only-light"/> <img src="_static/NVIDIA-LogoWhite.svg" class="only-dark"/> <p class="notices"> <a href="https://www.nvidia.com/en-us/about-nvidia/privacy-policy/" target="_blank">Privacy Policy</a> | <a href="https://www.nvidia.com/en-us/about-nvidia/privacy-center/" target="_blank">Manage My Privacy</a> | <a href="https://www.nvidia.com/en-us/preferences/start/" target="_blank">Do Not Sell or Share My Data</a> | <a href="https://www.nvidia.com/en-us/about-nvidia/terms-of-service/" target="_blank">Terms of Service</a> | <a href="https://www.nvidia.com/en-us/about-nvidia/accessibility/" target="_blank">Accessibility</a> | <a href="https://www.nvidia.com/en-us/about-nvidia/company-policies/" target="_blank">Corporate Policies</a> | <a href="https://www.nvidia.com/en-us/product-security/" target="_blank">Product Security</a> | <a href="https://www.nvidia.com/en-us/contact/" target="_blank">Contact</a> </p> <p> Copyright &#169; 2013-2025, NVIDIA Corporation &amp; affiliates. All rights reserved. </p> <p> <span class="lastupdated">Last updated on Jan 22, 2025. </span></p> </div> </footer> </div> </div> </section> </div> <script> jQuery(function () { SphinxRtdTheme.Navigation.enable(false); }); </script> <script type="text/javascript">if (typeof _satellite !== "undefined"){_satellite.pageBottom();}</script> </body> </html>

Pages: 1 2 3 4 5 6 7 8 9 10