Skip to content
Snippets Groups Projects
  • akuesters's avatar
    Python wrapper: documentation (#799) · 1f4eacd2
    akuesters authored and Benjamin Cumming's avatar Benjamin Cumming committed
    Add docs for Python wrapper to ReadTheDocs:
    
    - Overview, Common Types, Hardware Management, Recipes, Domain Decomposition, Simulations, Metering
    - Installing Arbor: Optional Requirements (Python), Buidling and Installing (Python Frontend), and Installation (Python Module)
    
    Missing (, since not implemented yet): 
    
    - probes
    - arbor-sup 
    - hint maps in domain_decomposition
    - reset, events, empty schedule in event_generator
    Also does not cover unit testing (since doc is user-centric).
    
    Makes also defaults and units in wrapper consistent.
    
    Fixes  #766
    1f4eacd2
cpp_hardware.rst 14.08 KiB

Hardware Management

Arbor provides two library APIs for working with hardware resources:

  • The core libarbor is used to describe the hardware resources and their contexts for use in Arbor simulations.
  • The libarborenv provides an API for querying available hardware resources (e.g. the number of available GPUs), and initializing MPI.

libarborenv

The libarborenv API for querying and managing hardware resources is in the :cpp:any:`arbenv` namespace. This functionality is kept in a separate library to enforce separation of concerns, so that users have full control over how hardware resources are selected, either using the functions and types in libarborenv, or writing their own code for managing MPI, GPUs, and thread counts.

libarbor

The core Arbor library libarbor provides an API for:

  • prescribing which hardware resources are to be used by a simulation using :cpp:class:`arb::proc_allocation`.
  • opaque handles to hardware resources used by simulations called :cpp:class:`arb::context`.

Arbor contexts are created by calling :cpp:func:`make_context`, which returns an initialized context. There are two versions of :cpp:func:`make_context`, for creating contexts with and without distributed computation with MPI respectively.

Contexts can be queried for information about which features a context has enabled, whether it has a GPU, how many threads are in its thread pool, using helper functions.

Here are some simple examples of how to create a :cpp:class:`arb::context` using :cpp:func:`make_context`.

#include <arbor/context.hpp>

// Construct a context that uses 1 thread and no GPU or MPI.
auto context = arb::make_context();

// Construct a context that:
//  * uses 8 threads in its thread pool;
//  * does not use a GPU, regardless of whether one is available;
//  * does not use MPI.
arb::proc_allocation resources(8, -1);
auto context = arb::make_context(resources);

// Construct one that uses:
//  * 4 threads and the first GPU;
//  * MPI_COMM_WORLD for distributed computation.
arb::proc_allocation resources(4, 0);
auto mpi_context = arb::make_context(resources, MPI_COMM_WORLD)

Here is a more complicated example of creating a :cpp:class:`context` on a system where support for GPU and MPI support are conditional.

#include <arbor/context.hpp>
#include <arbor/version.hpp>   // for ARB_MPI_ENABLED

#include <arborenv/concurrency.hpp>
#include <arborenv/gpu_env.hpp>

int main(int argc, char** argv) {
    try {
        arb::proc_allocation resources;

        // try to detect how many threads can be run on this system
        resources.num_threads = arbenv::thread_concurrency();

        // override thread count if the user set ARB_NUM_THREADS
        if (auto nt = arbenv::get_env_num_threads()) {
            resources.num_threads = nt;
        }

#ifdef ARB_WITH_MPI
        // initialize MPI
        arbenv::with_mpi guard(argc, argv, false);

        // assign a unique gpu to this rank if available
        resources.gpu_id = arbenv::find_private_gpu(MPI_COMM_WORLD);

        // create a distributed context
        auto context = arb::make_context(resources, MPI_COMM_WORLD);
        root = arb::rank(context) == 0;
#else
        resources.gpu_id = arbenv::default_gpu();

        // create a local context
        auto context = arb::make_context(resources);
#endif

        // Print a banner with information about hardware configuration
        std::cout << "gpu:      " << (has_gpu(context)? "yes": "no") << "\n";
        std::cout << "threads:  " << num_threads(context) << "\n";
        std::cout << "mpi:      " << (has_mpi(context)? "yes": "no") << "\n";
        std::cout << "ranks:    " << num_ranks(context) << "\n" << std::endl;

        // run some simulations!
    }
    catch (std::exception& e) {
        std::cerr << "exception caught in ring miniapp: " << e.what() << "\n";
        return 1;
    }

    return 0;
}