Welcome to the HPX documentation!¶
If you’re new to HPX you can get started with the Quick start guide. Don’t forget to read the Terminology section to learn about the most important concepts in HPX. The Examples give you a feel for how it is to write real HPX applications and the Manual contains detailed information about everything from building HPX to debugging it. There are links to blog posts and videos about HPX in Additional material.
If you can’t find what you’re looking for in the documentation, please:
open an issue on GitHub;
contact us on IRC, the HPX channel on the C++ Slack, or on our mailing list; or
read or ask questions tagged with HPX on StackOverflow.
See Citing HPX for details on how to cite HPX in publications. See HPX users for a list of institutions and projects using HPX.
What is HPX?¶
HPX is a C++ Standard Library for Concurrency and Parallelism. It implements all of the corresponding facilities as defined by the C++ Standard. Additionally, in HPX we implement functionalities proposed as part of the ongoing C++ standardization process. We also extend the C++ Standard APIs to the distributed case. HPX is developed by the STE||AR group (see People).
The goal of HPX is to create a high quality, freely available, open source implementation of a new programming model for conventional systems, such as classic Linux based Beowulf clusters or multi-socket highly parallel SMP nodes. At the same time, we want to have a very modular and well designed runtime system architecture which would allow us to port our implementation onto new computer system architectures. We want to use real-world applications to drive the development of the runtime system, coining out required functionalities and converging onto a stable API which will provide a smooth migration path for developers.
The API exposed by HPX is not only modeled after the interfaces defined by the C++11/14/17/20 ISO standard. It also adheres to the programming guidelines used by the Boost collection of C++ libraries. We aim to improve the scalability of today’s applications and to expose new levels of parallelism which are necessary to take advantage of the exascale systems of the future.
What’s so special about HPX?¶
HPX exposes a uniform, standards-oriented API for ease of programming parallel and distributed applications.
It enables programmers to write fully asynchronous code using hundreds of millions of threads.
HPX provides unified syntax and semantics for local and remote operations.
HPX makes concurrency manageable with dataflow and future based synchronization.
It implements a rich set of runtime services supporting a broad range of use cases.
HPX exposes a uniform, flexible, and extendable performance counter framework which can enable runtime adaptivity
It is designed to solve problems conventionally considered to be scaling-impaired.
HPX has been designed and developed for systems of any scale, from hand-held devices to very large scale systems.
It is the first fully functional implementation of the ParalleX execution model.
HPX is published under a liberal open-source license and has an open, active, and thriving developer community.
Why HPX?¶
Current advances in high performance computing (HPC) continue to suffer from the issues plaguing parallel computation. These issues include, but are not limited to, ease of programming, inability to handle dynamically changing workloads, scalability, and efficient utilization of system resources. Emerging technological trends such as multi-core processors further highlight limitations of existing parallel computation models. To mitigate the aforementioned problems, it is necessary to rethink the approach to parallelization models. ParalleX contains mechanisms such as multi-threading, parcels, global name space support, percolation and local control objects (LCO). By design, ParalleX overcomes limitations of current models of parallelism by alleviating contention, latency, overhead and starvation. With ParalleX, it is further possible to increase performance by at least an order of magnitude on challenging parallel algorithms, e.g., dynamic directed graph algorithms and adaptive mesh refinement methods for astrophysics. An additional benefit of ParalleX is fine-grained control of power usage, enabling reductions in power consumption.
ParalleX—a new execution model for future architectures¶
ParalleX is a new parallel execution model that offers an alternative to the conventional computation models, such as message passing. ParalleX distinguishes itself by:
Split-phase transaction model
Message-driven
Distributed shared memory (not cache coherent)
Multi-threaded
Futures synchronization
Synchronization for anonymous producer-consumer scenarios
Percolation (pre-staging of task data)
The ParalleX model is intrinsically latency hiding, delivering an abundance of variable-grained parallelism within a hierarchical namespace environment. The goal of this innovative strategy is to enable future systems delivering very high efficiency, increased scalability and ease of programming. ParalleX can contribute to significant improvements in the design of all levels of computing systems and their usage from application algorithms and their programming languages to system architecture and hardware design together with their supporting compilers and operating system software.
What is HPX?¶
High Performance ParalleX (HPX) is the first runtime system implementation of the ParalleX execution model. The HPX runtime software package is a modular, feature-complete, and performance-oriented representation of the ParalleX execution model targeted at conventional parallel computing architectures, such as SMP nodes and commodity clusters. It is academically developed and freely available under an open source license. We provide HPX to the community for experimentation and application to achieve high efficiency and scalability for dynamic adaptive and irregular computational problems. HPX is a C++ library that supports a set of critical mechanisms for dynamic adaptive resource management and lightweight task scheduling within the context of a global address space. It is solidly based on many years of experience in writing highly parallel applications for HPC systems.
The two-decade success of the communicating sequential processes (CSP) execution model and its message passing interface (MPI) programming model have been seriously eroded by challenges of power, processor core complexity, multi-core sockets, and heterogeneous structures of GPUs. Both efficiency and scalability for some current (strong scaled) applications and future Exascale applications demand new techniques to expose new sources of algorithm parallelism and exploit unused resources through adaptive use of runtime information.
The ParalleX execution model replaces CSP to provide a new computing paradigm embodying the governing principles for organizing and conducting highly efficient scalable computations greatly exceeding the capabilities of today’s problems. HPX is the first practical, reliable, and performance-oriented runtime system incorporating the principal concepts of the ParalleX model publicly provided in open source release form.
HPX is designed by the STE||AR Group (Systems Technology, Emergent Parallelism, and Algorithm Research) at Louisiana State University (LSU)’s Center for Computation and Technology (CCT) to enable developers to exploit the full processing power of many-core systems with an unprecedented degree of parallelism. STE||AR is a research group focusing on system software solutions and scientific application development for hybrid and many-core hardware architectures.
What makes our systems slow?¶
Estimates say that we currently run our computers at well below 100% efficiency. The theoretical peak performance (usually measured in FLOPS—floating point operations per second) is much higher than any practical peak performance reached by any application. This is particularly true for highly parallel hardware. The more hardware parallelism we provide to an application, the better the application must scale in order to efficiently use all the resources of the machine. Roughly speaking, we distinguish two forms of scalability: strong scaling (see Amdahl’s Law) and weak scaling (see Gustafson’s Law). Strong scaling is defined as how the solution time varies with the number of processors for a fixed total problem size. It gives an estimate of how much faster we can solve a particular problem by throwing more resources at it. Weak scaling is defined as how the solution time varies with the number of processors for a fixed problem size per processor. In other words, it defines how much more data can we process by using more hardware resources.
In order to utilize as much hardware parallelism as possible an application must exhibit excellent strong and weak scaling characteristics, which requires a high percentage of work executed in parallel, i.e., using multiple threads of execution. Optimally, if you execute an application on a hardware resource with N processors it either runs N times faster or it can handle N times more data. Both cases imply 100% of the work is executed on all available processors in parallel. However, this is just a theoretical limit. Unfortunately, there are more things that limit scalability, mostly inherent to the hardware architectures and the programming models we use. We break these limitations into four fundamental factors that make our systems SLOW:
Starvation occurs when there is insufficient concurrent work available to maintain high utilization of all resources.
Latencies are imposed by the time-distance delay intrinsic to accessing remote resources and services.
Overhead is work required for the management of parallel actions and resources on the critical execution path, which is not necessary in a sequential variant.
Waiting for contention resolution is the delay due to the lack of availability of oversubscribed shared resources.
Each of those four factors manifests itself in multiple and different ways; each of the hardware architectures and programming models expose specific forms. However, the interesting part is that all of them are limiting the scalability of applications no matter what part of the hardware jungle we look at. Hand-helds, PCs, supercomputers, or the cloud, all suffer from the reign of the 4 horsemen: Starvation, Latency, Overhead, and Contention. This realization is very important as it allows us to derive the criteria for solutions to the scalability problem from first principles, and it allows us to focus our analysis on very concrete patterns and measurable metrics. Moreover, any derived results will be applicable to a wide variety of targets.
Technology demands new response¶
Today’s computer systems are designed based on the initial ideas of John von Neumann, as published back in 1945, and later extended by the Harvard architecture. These ideas form the foundation, the execution model, of computer systems we use currently. However, a new response is required in the light of the demands created by today’s technology.
So, what are the overarching objectives for designing systems allowing for applications to scale as they should? In our opinion, the main objectives are:
Performance: as previously mentioned, scalability and efficiency are the main criteria people are interested in.
Fault tolerance: the low expected mean time between failures (MTBF) of future systems requires embracing faults, not trying to avoid them.
Power: minimizing energy consumption is a must as it is one of the major cost factors today, and will continue to rise in the future.
Generality: any system should be usable for a broad set of use cases.
Programmability: for programmer this is a very important objective, ensuring long term platform stability and portability.
What needs to be done to meet those objectives, to make applications scale better on tomorrow’s architectures? Well, the answer is almost obvious: we need to devise a new execution model—a set of governing principles for the holistic design of future systems—targeted at minimizing the effect of the outlined SLOW factors. Everything we create for future systems, every design decision we make, every criteria we apply, have to be validated against this single, uniform metric. This includes changes in the hardware architecture we prevalently use today, and it certainly involves new ways of writing software, starting from the operating system, runtime system, compilers, and at the application level. However, the key point is that all those layers have to be co-designed; they are interdependent and cannot be seen as separate facets. The systems we have today have been evolving for over 50 years now. All layers function in a certain way, relying on the other layers to do so. But we do not have the time to wait another 50 years for a new coherent system to evolve. The new paradigms are needed now—therefore, co-design is the key.
Governing principles applied while developing HPX¶
As it turn out, we do not have to start from scratch. Not everything has to be invented and designed anew. Many of the ideas needed to combat the 4 horsemen already exist, many for more than 30 years. All it takes is to gather them into a coherent approach. We’ll highlight some of the derived principles we think to be crucial for defeating SLOW. Some of those are focused on high-performance computing, others are more general.
Focus on latency hiding instead of latency avoidance¶
It is impossible to design a system exposing zero latencies. In an effort to come as close as possible to this goal many optimizations are mainly targeted towards minimizing latencies. Examples for this can be seen everywhere, such as low latency network technologies like InfiniBand, caching memory hierarchies in all modern processors, the constant optimization of existing MPI implementations to reduce related latencies, or the data transfer latencies intrinsic to the way we use GPGPUs today. It is important to note that existing latencies are often tightly related to some resource having to wait for the operation to be completed. At the same time it would be perfectly fine to do some other, unrelated work in the meantime, allowing the system to hide the latencies by filling the idle-time with useful work. Modern systems already employ similar techniques (pipelined instruction execution in the processor cores, asynchronous input/output operations, and many more). What we propose is to go beyond anything we know today and to make latency hiding an intrinsic concept of the operation of the whole system stack.
Embrace fine-grained parallelism instead of heavyweight threads¶
If we plan to hide latencies even for very short operations, such as fetching the contents of a memory cell from main memory (if it is not already cached), we need to have very lightweight threads with extremely short context switching times, optimally executable within one cycle. Granted, for mainstream architectures, this is not possible today (even if we already have special machines supporting this mode of operation, such as the Cray XMT). For conventional systems, however, the smaller the overhead of a context switch and the finer the granularity of the threading system, the better will be the overall system utilization and its efficiency. For today’s architectures we already see a flurry of libraries providing exactly this type of functionality: non-pre-emptive, task-queue based parallelization solutions, such as Intel Threading Building Blocks (TBB), Microsoft Parallel Patterns Library (PPL), Cilk++, and many others. The possibility to suspend a current task if some preconditions for its execution are not met (such as waiting for I/O or the result of a different task), seamlessly switching to any other task which can continue, and to reschedule the initial task after the required result has been calculated, which makes the implementation of latency hiding almost trivial.
Rediscover constraint-based synchronization to replace global barriers¶
The code we write today is riddled with implicit (and explicit) global barriers. By “global barriers,” we mean the synchronization of the control flow between several (very often all) threads (when using OpenMP) or processes (MPI). For instance, an implicit global barrier is inserted after each loop parallelized using OpenMP as the system synchronizes the threads used to execute the different iterations in parallel. In MPI each of the communication steps imposes an explicit barrier onto the execution flow as (often all) nodes have to be synchronized. Each of those barriers is like the eye of a needle the overall execution is forced to be squeezed through. Even minimal fluctuations in the execution times of the parallel threads (jobs) causes them to wait. Additionally, it is often only one of the executing threads that performs the actual reduce operation, which further impedes parallelism. A closer analysis of a couple of key algorithms used in science applications reveals that these global barriers are not always necessary. In many cases it is sufficient to synchronize a small subset of the threads. Any operation should proceed whenever the preconditions for its execution are met, and only those. Usually there is no need to wait for iterations of a loop to finish before you can continue calculating other things; all you need is to complete the iterations that produce the required results for the next operation. Good bye global barriers, hello constraint based synchronization! People have been trying to build this type of computing (and even computers) since the 1970s. The theory behind what they did is based on ideas around static and dynamic dataflow. There are certain attempts today to get back to those ideas and to incorporate them with modern architectures. For instance, a lot of work is being done in the area of constructing dataflow-oriented execution trees. Our results show that employing dataflow techniques in combination with the other ideas, as outlined herein, considerably improves scalability for many problems.
Adaptive locality control instead of static data distribution¶
While this principle seems to be a given for single desktop or laptop computers (the operating system is your friend), it is everything but ubiquitous on modern supercomputers, which are usually built from a large number of separate nodes (i.e., Beowulf clusters), tightly interconnected by a high-bandwidth, low-latency network. Today’s prevalent programming model for those is MPI, which does not directly help with proper data distribution, leaving it to the programmer to decompose the data to all of the nodes the application is running on. There are a couple of specialized languages and programming environments based on PGAS (Partitioned Global Address Space) designed to overcome this limitation, such as Chapel, X10, UPC, or Fortress. However, all systems based on PGAS rely on static data distribution. This works fine as long as this static data distribution does not result in heterogeneous workload distributions or other resource utilization imbalances. In a distributed system these imbalances can be mitigated by migrating part of the application data to different localities (nodes). The only framework supporting (limited) migration today is Charm++. The first attempts towards solving related problem go back decades as well, a good example is the Linda coordination language. Nevertheless, none of the other mentioned systems support data migration today, which forces the users to either rely on static data distribution and live with the related performance hits or to implement everything themselves, which is very tedious and difficult. We believe that the only viable way to flexibly support dynamic and adaptive locality control is to provide a global, uniform address space to the applications, even on distributed systems.
Prefer moving work to the data over moving data to the work¶
For the best performance it seems obvious to minimize the amount of bytes transferred from one part of the system to another. This is true on all levels. At the lowest level we try to take advantage of processor memory caches, thus, minimizing memory latencies. Similarly, we try to amortize the data transfer time to and from GPGPUs as much as possible. At high levels we try to minimize data transfer between different nodes of a cluster or between different virtual machines on the cloud. Our experience (well, it’s almost common wisdom) shows that the amount of bytes necessary to encode a certain operation is very often much smaller than the amount of bytes encoding the data the operation is performed upon. Nevertheless, we still often transfer the data to a particular place where we execute the operation just to bring the data back to where it came from afterwards. As an example let’s look at the way we usually write our applications for clusters using MPI. This programming model is all about data transfer between nodes. MPI is the prevalent programming model for clusters, and it is fairly straightforward to understand and to use. Therefore, we often write applications in a way that accommodates this model, centered around data transfer. These applications usually work well for smaller problem sizes and for regular data structures. The larger the amount of data we have to churn and the more irregular the problem domain becomes, the worse the overall machine utilization and the (strong) scaling characteristics become. While it is not impossible to implement more dynamic, data driven, and asynchronous applications using MPI, it is somewhat difficult to do so. At the same time, if we look at applications that prefer to execute the code close to the locality where the data was placed, i.e., utilizing active messages (for instance based on Charm++), we see better asynchrony, simpler application codes, and improved scaling.
Favor message driven computation over message passing¶
Today’s prevalently used programming model on parallel (multi-node) systems is MPI. It is based on message passing, as the name implies, which means that the receiver has to be aware of a message about to come in. Both codes, the sender and the receiver, have to synchronize in order to perform the communication step. Even the newer, asynchronous interfaces require explicitly coding the algorithms around the required communication scheme. As a result, everything but the most trivial MPI applications spends a considerable amount of time waiting for incoming messages, thus, causing starvation and latencies to impede full resource utilization. The more complex and more dynamic the data structures and algorithms become, the larger the adverse effects. The community discovered message-driven and data-driven methods of implementing algorithms a long time ago, and systems such as Charm++ have already integrated active messages demonstrating the validity of the concept. Message-driven computation allows for sending messages without requiring the receiver to actively wait for them. Any incoming message is handled asynchronously and triggers the encoded action by passing along arguments and—possibly—continuations. HPX combines this scheme with work-queue based scheduling as described above, which allows the system to almost completely overlap any communication with useful work, thereby minimizing latencies.
Quick start¶
This section is intended to get you to the point of running a basic HPX program as quickly as possible. To that end we skip many details but instead give you hints and links to more details along the way.
We assume that you are on a Unix system with access to reasonably recent
packages. You should have cmake and make available for the build system
(pkg-config is also supported, see Using HPX with pkg-config).
Getting HPX¶
Download a tarball of the latest release from HPX Downloads and
unpack it or clone the repository directly using git:
git clone https://github.com/STEllAR-GROUP/hpx.git
It is also recommended that you check out the latest stable tag:
git checkout 1.7.1
HPX dependencies¶
The minimum dependencies needed to use HPX are Boost and Portable Hardware Locality (HWLOC). If these
are not available through your system package manager, see
Installing Boost and Installing Hwloc for instructions on how
to build them yourself. In addition to Boost and Portable Hardware Locality (HWLOC), it is recommended
that you don’t use the system allocator, but instead use either tcmalloc
from google-perftools (default) or jemalloc for better performance. If you
would like to try HPX without a custom allocator at this point, you can
configure HPX to use the system allocator in the next step.
A full list of required and optional dependencies, including recommended versions, is available at Prerequisites.
Building HPX¶
Once you have the source code and the dependencies, set up a separate build directory and configure the project. Assuming all your dependencies are in paths known to CMake, the following gets you started:
# In the HPX source directory
mkdir build && cd build
cmake -DCMAKE_INSTALL_PREFIX=/install/path ..
make install
This will build the core HPX libraries and examples, and install them to your
chosen location. If you want to install HPX to system folders, simply leave out
the CMAKE_INSTALL_PREFIX option. This may take a while. To speed up the
process, launch more jobs by passing the -jN option to make.
Tip
Do not set only -j (i.e. -j without an explicit number of jobs)
unless you have a lot of memory available on your machine.
Tip
If you want to change CMake variables for your build, it is usually a good
idea to start with a clean build directory to avoid configuration problems.
It is especially important that you use a clean build directory when changing
between Release and Debug modes.
If your dependencies are in custom locations, you may need to tell CMake where to find them by passing one or more of the following options to CMake:
-DBOOST_ROOT=/path/to/boost
-DHWLOC_ROOT=/path/to/hwloc
-DTCMALLOC_ROOT=/path/to/tcmalloc
-DJEMALLOC_ROOT=/path/to/jemalloc
If you want to try HPX without using a custom allocator pass
-DHPX_WITH_MALLOC=system to CMake.
Important
If you are building HPX for a system with more than 64 processing units,
you must change the CMake variables HPX_WITH_MORE_THAN_64_THREADS (to
On) and HPX_WITH_MAX_CPU_COUNT (to a value at least as big as the
number of (virtual) cores on your system).
To build the tests, run make tests. To run the tests, run either make test
or use ctest for more control over which tests to run. You can run single
tests for example with ctest --output-on-failure -R
tests.unit.parallel.algorithms.for_loop or a whole group of tests with ctest
--output-on-failure -R tests.unit.
If you did not run make install earlier, do so now or build the
hello_world_1 example by running:
make hello_world_1
HPX executables end up in the bin directory in your build directory. You
can now run hello_world_1 and should see the following output:
./bin/hello_world_1
Hello World!
You’ve just run an example which prints Hello World! from the HPX runtime.
The source for the example is in examples/quickstart/hello_world_1.cpp. The
hello_world_distributed example (also available in the
examples/quickstart directory) is a distributed hello world program, which is
described in Remote execution with actions: Hello world. It provides a gentle introduction to
the distributed aspects of HPX.
Tip
Most build targets in HPX have two names: a simple name and
a hierarchical name corresponding to what type of example or
test the target is. If you are developing HPX it is often helpful to run
make help to get a list of available targets. For example, make help |
grep hello_world outputs the following:
... examples.quickstart.hello_world_2
... hello_world_2
... examples.quickstart.hello_world_1
... hello_world_1
... examples.quickstart.hello_world_distributed
... hello_world_distributed
It is also possible to build, for instance, all quickstart examples using make
examples.quickstart.
Installing and building HPX via vcpkg¶
You can download and install HPX using the vcpkg <https://github.com/Microsoft/vcpkg> dependency manager:
git clone https://github.com/Microsoft/vcpkg.git
cd vcpkg
./bootstrap-vcpkg.sh
./vcpkg integrate install
vcpkg install hpx
The HPX port in vcpkg is kept up to date by Microsoft team members and community contributors. If the version is out of date, please create an issue or pull request <https://github.com/Microsoft/vcpkg> on the vcpkg repository.
Hello, World!¶
The following CMakeLists.txt is a minimal example of what you need in order to
build an executable using CMake and HPX:
cmake_minimum_required(VERSION 3.17)
project(my_hpx_project CXX)
find_package(HPX REQUIRED)
add_executable(my_hpx_program main.cpp)
target_link_libraries(my_hpx_program HPX::hpx HPX::wrap_main HPX::iostreams_component)
Note
You will most likely have more than one main.cpp file in your project.
See the section on Using HPX with CMake-based projects for more details on how to use
add_hpx_executable.
Note
HPX::wrap_main is required if you are implicitly using main() as the
runtime entry point. See Re-use the main() function as the main HPX entry point for more information.
Note
HPX::iostreams_component is optional for a minimal project but lets us
use the HPX equivalent of std::cout, i.e., the HPX The HPX I/O-streams component
functionality in our application.
Create a new project directory and a CMakeLists.txt with the contents above.
Also create a main.cpp with the contents below.
// Including 'hpx/hpx_main.hpp' instead of the usual 'hpx/hpx_init.hpp' enables
// to use the plain C-main below as the direct main HPX entry point.
#include <hpx/hpx_main.hpp>
#include <hpx/iostream.hpp>
int main()
{
// Say hello to the world!
hpx::cout << "Hello World!\n" << hpx::flush;
return 0;
}
Then, in your project directory run the following:
mkdir build && cd build
cmake -DCMAKE_PREFIX_PATH=/path/to/hpx/installation ..
make all
./my_hpx_program
The program looks almost like a regular C++ hello world with the exception of
the two includes and hpx::cout. When you include hpx_main.hpp some
things will be done behind the scenes to make sure that main actually gets
launched on the HPX runtime. So while it looks almost the same you can now use
futures, async, parallel algorithms and more which make use of the HPX
runtime with lightweight threads. hpx::cout is a replacement for
std::cout to make sure printing never blocks a lightweight thread. You can
read more about hpx::cout in The HPX I/O-streams component. If you rebuild and run your
program now, you should see the familiar Hello World!:
./my_hpx_program
Hello World!
Note
You do not have to let HPX take over your main function like in the
example. You can instead keep your normal main function, and define a
separate hpx_main function which acts as the entry point to the HPX
runtime. In that case you start the HPX runtime explicitly by calling
hpx::init:
// Copyright (c) 2007-2012 Hartmut Kaiser
//
// SPDX-License-Identifier: BSL-1.0
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
///////////////////////////////////////////////////////////////////////////////
// The purpose of this example is to initialize the HPX runtime explicitly and
// execute a HPX-thread printing "Hello World!" once. That's all.
//[hello_world_2_getting_started
#include <hpx/hpx_init.hpp>
#include <hpx/iostream.hpp>
int hpx_main(int, char**)
{
// Say hello to the world!
hpx::cout << "Hello World!\n" << hpx::flush;
return hpx::finalize();
}
int main(int argc, char* argv[])
{
return hpx::init(argc, argv);
}
//]
You can also use hpx::start and hpx::stop for a
non-blocking alternative, or use hpx::resume and
hpx::suspend if you need to combine HPX with other runtimes.
See Starting the HPX runtime for more details on how to initialize and run the HPX runtime.
Caution
When including hpx_main.hpp the user-defined main gets renamed and
the real main function is defined by HPX. This means that the
user-defined main must include a return statement, unlike the real
main. If you do not include the return statement, you may end up with
confusing compile time errors mentioning user_main or even runtime
errors.
Writing task-based applications¶
So far we haven’t done anything that can’t be done using the C++ standard library. In this section we will give a short overview of what you can do with HPX on a single node. The essence is to avoid global synchronization and break up your application into small, composable tasks whose dependencies control the flow of your application. Remember, however, that HPX allows you to write distributed applications similarly to how you would write applications for a single node (see Why HPX? and Writing distributed HPX applications).
If you are already familiar with async and futures from the C++ standard
library, the same functionality is available in HPX.
The following terminology is essential when talking about task-based C++ programs:
lightweight thread: Essential for good performance with task-based programs. Lightweight refers to smaller stacks and faster context switching compared to OS threads. Smaller overheads allow the program to be broken up into smaller tasks, which in turns helps the runtime fully utilize all processing units.
async: The most basic way of launching tasks asynchronously. Returns afuture<T>.future<T>: Represents a value of typeTthat will be ready in the future. The value can be retrieved withget(blocking) and one can check if the value is ready withis_ready(non-blocking).shared_future<T>: Same asfuture<T>but can be copied (similar tostd::unique_ptrvsstd::shared_ptr).continuation: A function that is to be run after a previous task has run (represented by a future).
thenis a method offuture<T>that takes a function to run next. Used to build up dataflow DAGs (directed acyclic graphs).shared_futures help you split up nodes in the DAG and functions likewhen_allhelp you join nodes in the DAG.
The following example is a collection of the most commonly used functionality in HPX:
#include <hpx/hpx_main.hpp>
#include <hpx/include/lcos.hpp>
#include <hpx/include/parallel_generate.hpp>
#include <hpx/include/parallel_sort.hpp>
#include <hpx/iostream.hpp>
#include <random>
#include <vector>
void final_task(
hpx::future<hpx::tuple<hpx::future<double>, hpx::future<void>>>)
{
hpx::cout << "in final_task" << hpx::endl;
}
// Avoid ABI incompatibilities between C++11/C++17 as std::rand has exception
// specification in libstdc++.
int rand_wrapper()
{
return std::rand();
}
int main(int, char**)
{
// A function can be launched asynchronously. The program will not block
// here until the result is available.
hpx::future<int> f = hpx::async([]() { return 42; });
hpx::cout << "Just launched a task!" << hpx::endl;
// Use get to retrieve the value from the future. This will block this task
// until the future is ready, but the HPX runtime will schedule other tasks
// if there are tasks available.
hpx::cout << "f contains " << f.get() << hpx::endl;
// Let's launch another task.
hpx::future<double> g = hpx::async([]() { return 3.14; });
// Tasks can be chained using the then method. The continuation takes the
// future as an argument.
hpx::future<double> result = g.then([](hpx::future<double>&& gg) {
// This function will be called once g is ready. gg is g moved
// into the continuation.
return gg.get() * 42.0 * 42.0;
});
// You can check if a future is ready with the is_ready method.
hpx::cout << "Result is ready? " << result.is_ready() << hpx::endl;
// You can launch other work in the meantime. Let's sort a vector.
std::vector<int> v(1000000);
// We fill the vector synchronously and sequentially.
hpx::generate(hpx::execution::seq, std::begin(v), std::end(v),
&rand_wrapper);
// We can launch the sort in parallel and asynchronously.
hpx::future<void> done_sorting = hpx::parallel::sort(
hpx::execution::par( // In parallel.
hpx::execution::task), // Asynchronously.
std::begin(v), std::end(v));
// We launch the final task when the vector has been sorted and result is
// ready using when_all.
auto all = hpx::when_all(result, done_sorting).then(&final_task);
// We can wait for all to be ready.
all.wait();
// all must be ready at this point because we waited for it to be ready.
hpx::cout << (all.is_ready() ? "all is ready!" : "all is not ready...")
<< hpx::endl;
return hpx::finalize();
}
Try copying the contents to your main.cpp file and look at the output. It can
be a good idea to go through the program step by step with a debugger. You can
also try changing the types or adding new arguments to functions to make sure
you can get the types to match. The type of the then method can be especially
tricky to get right (the continuation needs to take the future as an argument).
Note
HPX programs accept command line arguments. The most important one is
--hpx:threads=N to set the number of OS threads used by
HPX. HPX uses one thread per core by default. Play around with the
example above and see what difference the number of threads makes on the
sort function. See Launching and configuring HPX applications for more details on
how and what options you can pass to HPX.
Tip
The example above used the construction hpx::when_all(...).then(...). For
convenience and performance it is a good idea to replace uses of
hpx::when_all(...).then(...) with dataflow. See
Dataflow: Interest calculator for more details on dataflow.
Tip
If possible, try to use the provided parallel algorithms instead of writing your own implementation. This can save you time and the resulting program is often faster.
Next steps¶
If you haven’t done so already, reading the Terminology section will help you get familiar with the terms used in HPX.
The Examples section contains small, self-contained walkthroughs of example HPX programs. The Local to remote: 1D stencil example is a thorough, realistic example starting from a single node implementation and going stepwise to a distributed implementation.
The Manual contains detailed information on writing, building and running HPX applications.
Terminology¶
This section gives definitions for some of the terms used throughout the HPX documentation and source code.
- Locality¶
A locality in HPX describes a synchronous domain of execution, or the domain of bounded upper response time. This normally is just a single node in a cluster or a NUMA domain in a SMP machine.
- Active Global Address Space¶
- AGAS¶
HPX incorporates a global address space. Any executing thread can access any object within the domain of the parallel application with the caveat that it must have appropriate access privileges. The model does not assume that global addresses are cache coherent; all loads and stores will deal directly with the site of the target object. All global addresses within a Synchronous Domain are assumed to be cache coherent for those processor cores that incorporate transparent caches. The Active Global Address Space used by HPX differs from research PGAS models. Partitioned Global Address Space is passive in their means of address translation. Copy semantics, distributed compound operations, and affinity relationships are some of the global functionality supported by AGAS.
- Process¶
The concept of the “process” in HPX is extended beyond that of either sequential execution or communicating sequential processes. While the notion of process suggests action (as do “function” or “subroutine”) it has a further responsibility of context, that is, the logical container of program state. It is this aspect of operation that process is employed in HPX. Furthermore, referring to “parallel processes” in HPX designates the presence of parallelism within the context of a given process, as well as the coarse grained parallelism achieved through concurrency of multiple processes of an executing user job. HPX processes provide a hierarchical name space within the framework of the active global address space and support multiple means of internal state access from external sources.
- Parcel¶
The Parcel is a component in HPX that communicates data, invokes an action at a distance, and distributes flow-control through the migration of continuations. Parcels bridge the gap of asynchrony between synchronous domains while maintaining symmetry of semantics between local and global execution. Parcels enable message-driven computation and may be seen as a form of “active messages”. Other important forms of message-driven computation predating active messages include dataflow tokens, the J-machine’s support for remote method instantiation, and at the coarse grained variations of Unix remote procedure calls, among others. This enables work to be moved to the data as well as performing the more common action of bringing data to the work. A parcel can cause actions to occur remotely and asynchronously, among which are the creation of threads at different system nodes or synchronous domains.
- Local Control Object¶
- Lightweight Control Object¶
- LCO¶
A local control object (sometimes called a lightweight control object) is a general term for the synchronization mechanisms used in HPX. Any object implementing a certain concept can be seen as an LCO. This concepts encapsulates the ability to be triggered by one or more events which when taking the object into a predefined state will cause a thread to be executed. This could either create a new thread or resume an existing thread.
The LCO is a family of synchronization functions potentially representing many classes of synchronization constructs, each with many possible variations and multiple instances. The LCO is sufficiently general that it can subsume the functionality of conventional synchronization primitives such as spinlocks, mutexes, semaphores, and global barriers. However due to the rich concept an LCO can represent powerful synchronization and control functionality not widely employed, such as dataflow and futures (among others), which open up enormous opportunities for rich diversity of distributed control and operation.
See Using LCOs for more details on how to use LCOs in HPX.
- Action¶
An action is a function that can be invoked remotely. In HPX a plain function can be made into an action using a macro. See Applying actions for details on how to use actions in HPX.
- Component¶
A component is a C++ object which can be accessed remotely. A component can also contain member functions which can be invoked remotely. These are referred to as component actions. See Writing components for details on how to use components in HPX.
Examples¶
The following sections analyze some examples to help you get familiar with the HPX style of programming. We start off with simple examples that utilize basic HPX elements and then begin to expose the reader to the more complex and powerful HPX concepts.
Asynchronous execution with hpx::async: Fibonacci¶
The Fibonacci sequence is a sequence of numbers starting with 0 and 1 where every subsequent number is the sum of the previous two numbers. In this example, we will use HPX to calculate the value of the n-th element of the Fibonacci sequence. In order to compute this problem in parallel, we will use a facility known as a future.
As shown in the Fig. 1 below, a future encapsulates a delayed computation. It acts as a proxy for a result initially not known, most of the time because the computation of the result has not completed yet. The future synchronizes the access of this value by optionally suspending any HPX-threads requesting the result until the value is available. When a future is created, it spawns a new HPX-thread (either remotely with a parcel or locally by placing it into the thread queue) which, when run, will execute the function associated with the future. The arguments of the function are bound when the future is created.
Fig. 1 Schematic of a future execution.¶
Once the function has finished executing, a write operation is performed on the future. The write operation marks the future as completed, and optionally stores data returned by the function. When the result of the delayed computation is needed, a read operation is performed on the future. If the future’s function hasn’t completed when a read operation is performed on it, the reader HPX-thread is suspended until the future is ready. The future facility allows HPX to schedule work early in a program so that when the function value is needed it will already be calculated and available. We use this property in our Fibonacci example below to enable its parallel execution.
Setup¶
The source code for this example can be found here:
fibonacci_local.cpp.
To compile this program, go to your HPX build directory (see HPX build system for information on configuring and building HPX) and enter:
make examples.quickstart.fibonacci_local
To run the program type:
./bin/fibonacci_local
This should print (time should be approximate):
fibonacci(10) == 55
elapsed time: 0.002430 [s]
This run used the default settings, which calculate the tenth element of the
Fibonacci sequence. To declare which Fibonacci value you want to calculate, use
the --n-value option. Additionally you can use the --hpx:threads
option to declare how many OS-threads you wish to use when running the program.
For instance, running:
./bin/fibonacci --n-value 20 --hpx:threads 4
Will yield:
fibonacci(20) == 6765
elapsed time: 0.062854 [s]
Walkthrough¶
Now that you have compiled and run the code, let’s look at how the code works.
Since this code is written in C++, we will begin with the main() function.
Here you can see that in HPX, main() is only used to initialize the
runtime system. It is important to note that application-specific command line
options are defined here. HPX uses Boost.Program Options for command line
processing. You can see that our programs --n-value option is set by calling
the add_options() method on an instance of
hpx::program_options::options_description. The default value of the
variable is set to 10. This is why when we ran the program for the first time
without using the --n-value option the program returned the 10th value of
the Fibonacci sequence. The constructor argument of the description is the text
that appears when a user uses the --hpx:help option to see what
command line options are available. HPX_APPLICATION_STRING is a macro that
expands to a string constant containing the name of the HPX application
currently being compiled.
In HPX main() is used to initialize the runtime system and pass the
command line arguments to the program. If you wish to add command line options
to your program you would add them here using the instance of the Boost class
options_description, and invoking the public member function
.add_options() (see Boost Documentation for more details). hpx::init
calls hpx_main() after setting up HPX, which is where the logic of our
program is encoded.
int main(int argc, char* argv[])
{
// Configure application-specific options
hpx::program_options::options_description desc_commandline(
"Usage: " HPX_APPLICATION_STRING " [options]");
desc_commandline.add_options()("n-value",
hpx::program_options::value<std::uint64_t>()->default_value(10),
"n value for the Fibonacci function");
// Initialize and run HPX
hpx::init_params init_args;
init_args.desc_cmdline = desc_commandline;
return hpx::init(argc, argv, init_args);
}
The hpx::init function in main() starts the runtime system, and
invokes hpx_main() as the first HPX-thread. Below we can see that the
basic program is simple. The command line option --n-value is read in, a
timer (hpx::chrono::high_resolution_timer) is set up to record the
time it takes to do the computation, the fibonacci function is invoked
synchronously, and the answer is printed out.
int hpx_main(hpx::program_options::variables_map& vm)
{
// extract command line argument, i.e. fib(N)
std::uint64_t n = vm["n-value"].as<std::uint64_t>();
{
// Keep track of the time required to execute.
hpx::chrono::high_resolution_timer t;
std::uint64_t r = fibonacci(n);
char const* fmt = "fibonacci({1}) == {2}\nelapsed time: {3} [s]\n";
hpx::util::format_to(std::cout, fmt, n, r, t.elapsed());
}
return hpx::finalize(); // Handles HPX shutdown
}
The fibonacci function itself is synchronous as the work done inside is
asynchronous. To understand what is happening we have to look inside the
fibonacci function:
std::uint64_t fibonacci(std::uint64_t n)
{
if (n < 2)
return n;
// Invoking the Fibonacci algorithm twice is inefficient.
// However, we intentionally demonstrate it this way to create some
// heavy workload.
hpx::future<std::uint64_t> n1 = hpx::async(fibonacci, n - 1);
hpx::future<std::uint64_t> n2 = hpx::async(fibonacci, n - 2);
return n1.get() +
n2.get(); // wait for the Futures to return their values
}
This block of code looks similar to regular C++ code. First, if (n < 2),
meaning n is 0 or 1, then we return 0 or 1 (recall the first element of the
Fibonacci sequence is 0 and the second is 1). If n is larger than 1 we spawn two
new tasks whose results are contained in n1 and n2. This is done using
hpx::async which takes as arguments a function (function pointer,
object or lambda) and the arguments to the function. Instead of returning a
std::uint64_t like fibonacci does, hpx::async returns a future of a
std::uint64_t, i.e. hpx::future<std::uint64_t>. Each of these futures
represents an asynchronous, recursive call to fibonacci. After we’ve created
the futures, we wait for both of them to finish computing, we add them together,
and return that value as our result. We get the values from the futures using
the get method. The recursive call tree will continue until n is equal to 0
or 1, at which point the value can be returned because it is implicitly known.
When this termination condition is reached, the futures can then be added up,
producing the n-th value of the Fibonacci sequence.
Note that calling get potentially blocks the calling HPX-thread, and lets
other HPX-threads run in the meantime. There are, however, more efficient ways
of doing this. examples/quickstart/fibonacci_futures.cpp contains many more
variations of locally computing the Fibonacci numbers, where each method makes
different tradeoffs in where asynchrony and parallelism is applied. To get
started, however, the method above is sufficient and optimizations can be
applied once you are more familiar with HPX. The example
Dataflow: Interest calculator presents dataflow, which is a way to more
efficiently chain together multiple tasks.
Asynchronous execution with hpx::async and actions: Fibonacci¶
This example extends the previous example by
introducing actions: functions that can be run remotely. In this
example, however, we will still only run the action locally. The mechanism to
execute actions stays the same: hpx::async. Later
examples will demonstrate running actions on remote localities
(e.g. Remote execution with actions: Hello world).
Setup¶
The source code for this example can be found here:
fibonacci.cpp.
To compile this program, go to your HPX build directory (see HPX build system for information on configuring and building HPX) and enter:
make examples.quickstart.fibonacci
To run the program type:
./bin/fibonacci
This should print (time should be approximate):
fibonacci(10) == 55
elapsed time: 0.00186288 [s]
This run used the default settings, which calculate the tenth element of the
Fibonacci sequence. To declare which Fibonacci value you want to calculate, use
the --n-value option. Additionally you can use the --hpx:threads
option to declare how many OS-threads you wish to use when running the program.
For instance, running:
./bin/fibonacci --n-value 20 --hpx:threads 4
Will yield:
fibonacci(20) == 6765
elapsed time: 0.233827 [s]
Walkthrough¶
The code needed to initialize the HPX runtime is the same as in the previous example:
int main(int argc, char* argv[])
{
// Configure application-specific options
hpx::program_options::options_description
desc_commandline("Usage: " HPX_APPLICATION_STRING " [options]");
desc_commandline.add_options()
( "n-value",
hpx::program_options::value<std::uint64_t>()->default_value(10),
"n value for the Fibonacci function")
;
// Initialize and run HPX
hpx::init_params init_args;
init_args.desc_cmdline = desc_commandline;
return hpx::init(argc, argv, init_args);
}
The hpx::init function in main() starts the runtime system, and
invokes hpx_main() as the first HPX-thread. The command line option
--n-value is read in, a timer
(hpx::chrono::high_resolution_timer) is set up to record the time it
takes to do the computation, the fibonacci action is invoked
synchronously, and the answer is printed out.
int hpx_main(hpx::program_options::variables_map& vm)
{
// extract command line argument, i.e. fib(N)
std::uint64_t n = vm["n-value"].as<std::uint64_t>();
{
// Keep track of the time required to execute.
hpx::chrono::high_resolution_timer t;
// Wait for fib() to return the value
fibonacci_action fib;
std::uint64_t r = fib(hpx::find_here(), n);
char const* fmt = "fibonacci({1}) == {2}\nelapsed time: {3} [s]\n";
hpx::util::format_to(std::cout, fmt, n, r, t.elapsed());
}
return hpx::finalize(); // Handles HPX shutdown
}
Upon a closer look we see that we’ve created a std::uint64_t to store the
result of invoking our fibonacci_action fib. This action will
launch synchronously (as the work done inside of the action will be
asynchronous itself) and return the result of the Fibonacci sequence. But wait,
what is an action? And what is this fibonacci_action? For starters,
an action is a wrapper for a function. By wrapping functions, HPX can
send packets of work to different processing units. These vehicles allow users
to calculate work now, later, or on certain nodes. The first argument to our
action is the location where the action should be run. In this
case, we just want to run the action on the machine that we are
currently on, so we use hpx::find_here. To
further understand this we turn to the code to find where fibonacci_action
was defined:
// forward declaration of the Fibonacci function
std::uint64_t fibonacci(std::uint64_t n);
// This is to generate the required boilerplate we need for the remote
// invocation to work.
HPX_PLAIN_ACTION(fibonacci, fibonacci_action);
A plain action is the most basic form of action. Plain
actions wrap simple global functions which are not associated with any
particular object (we will discuss other types of actions in
Components and actions: Accumulator). In this block of code the function fibonacci()
is declared. After the declaration, the function is wrapped in an action
in the declaration HPX_PLAIN_ACTION. This function takes two
arguments: the name of the function that is to be wrapped and the name of the
action that you are creating.
This picture should now start making sense. The function fibonacci() is
wrapped in an action fibonacci_action, which was run synchronously
but created asynchronous work, then returns a std::uint64_t representing the
result of the function fibonacci(). Now, let’s look at the function
fibonacci():
std::uint64_t fibonacci(std::uint64_t n)
{
if (n < 2)
return n;
// We restrict ourselves to execute the Fibonacci function locally.
hpx::naming::id_type const locality_id = hpx::find_here();
// Invoking the Fibonacci algorithm twice is inefficient.
// However, we intentionally demonstrate it this way to create some
// heavy workload.
fibonacci_action fib;
hpx::future<std::uint64_t> n1 =
hpx::async(fib, locality_id, n - 1);
hpx::future<std::uint64_t> n2 =
hpx::async(fib, locality_id, n - 2);
return n1.get() + n2.get(); // wait for the Futures to return their values
}
This block of code is much more straightforward and should look familiar from
the previous example. First, if (n < 2),
meaning n is 0 or 1, then we return 0 or 1 (recall the first element of the
Fibonacci sequence is 0 and the second is 1). If n is larger than 1 we spawn two
tasks using hpx::async. Each of these futures represents an
asynchronous, recursive call to fibonacci. As previously we wait for both
futures to finish computing, get the results, add them together, and return that
value as our result. The recursive call tree will continue until n is equal to 0
or 1, at which point the value can be returned because it is implicitly known.
When this termination condition is reached, the futures can then be added up,
producing the n-th value of the Fibonacci sequence.
Remote execution with actions: Hello world¶
This program will print out a hello world message on every OS-thread on every locality. The output will look something like this:
hello world from OS-thread 1 on locality 0
hello world from OS-thread 1 on locality 1
hello world from OS-thread 0 on locality 0
hello world from OS-thread 0 on locality 1
Setup¶
The source code for this example can be found here:
hello_world_distributed.cpp.
To compile this program, go to your HPX build directory (see HPX build system for information on configuring and building HPX) and enter:
make examples.quickstart.hello_world_distributed
To run the program type:
./bin/hello_world_distributed
This should print:
hello world from OS-thread 0 on locality 0
To use more OS-threads use the command line option --hpx:threads and
type the number of threads that you wish to use. For example, typing:
./bin/hello_world_distributed --hpx:threads 2
will yield:
hello world from OS-thread 1 on locality 0
hello world from OS-thread 0 on locality 0
Notice how the ordering of the two print statements will change with subsequent runs. To run this program on multiple localities please see the section How to use HPX applications with PBS.
Walkthrough¶
Now that you have compiled and run the code, let’s look at how the code works,
beginning with main():
// Here is the main entry point. By using the include 'hpx/hpx_main.hpp' HPX
// will invoke the plain old C-main() as its first HPX thread.
int main()
{
// Get a list of all available localities.
std::vector<hpx::naming::id_type> localities = hpx::find_all_localities();
// Reserve storage space for futures, one for each locality.
std::vector<hpx::lcos::future<void>> futures;
futures.reserve(localities.size());
for (hpx::naming::id_type const& node : localities)
{
// Asynchronously start a new task. The task is encapsulated in a
// future, which we can query to determine if the task has
// completed.
typedef hello_world_foreman_action action_type;
futures.push_back(hpx::async<action_type>(node));
}
// The non-callback version of hpx::lcos::wait_all takes a single parameter,
// a vector of futures to wait on. hpx::wait_all only returns when
// all of the futures have finished.
hpx::wait_all(futures);
return 0;
}
In this excerpt of the code we again see the use of futures. This time the
futures are stored in a vector so that they can easily be accessed.
hpx::wait_all is a family of functions that wait on for an
std::vector<> of futures to become ready. In this piece of code, we are
using the synchronous version of hpx::wait_all, which takes one
argument (the std::vector<> of futures to wait on). This function will not
return until all the futures in the vector have been executed.
In Asynchronous execution with hpx::async and actions: Fibonacci we used hpx::find_here to specify the
target of our actions. Here, we instead use
hpx::find_all_localities, which returns an std::vector<>
containing the identifiers of all the machines in the system, including the one
that we are on.
As in Asynchronous execution with hpx::async and actions: Fibonacci our futures are set using
hpx::async<>. The hello_world_foreman_action is declared
here:
// Define the boilerplate code necessary for the function 'hello_world_foreman'
// to be invoked as an HPX action.
HPX_PLAIN_ACTION(hello_world_foreman, hello_world_foreman_action);
Another way of thinking about this wrapping technique is as follows: functions (the work to be done) are wrapped in actions, and actions can be executed locally or remotely (e.g. on another machine participating in the computation).
Now it is time to look at the hello_world_foreman() function which was
wrapped in the action above:
void hello_world_foreman()
{
// Get the number of worker OS-threads in use by this locality.
std::size_t const os_threads = hpx::get_os_thread_count();
// Populate a set with the OS-thread numbers of all OS-threads on this
// locality. When the hello world message has been printed on a particular
// OS-thread, we will remove it from the set.
std::set<std::size_t> attendance;
for (std::size_t os_thread = 0; os_thread < os_threads; ++os_thread)
attendance.insert(os_thread);
// As long as there are still elements in the set, we must keep scheduling
// HPX-threads. Because HPX features work-stealing task schedulers, we have
// no way of enforcing which worker OS-thread will actually execute
// each HPX-thread.
while (!attendance.empty())
{
// Each iteration, we create a task for each element in the set of
// OS-threads that have not said "Hello world". Each of these tasks
// is encapsulated in a future.
std::vector<hpx::lcos::future<std::size_t>> futures;
futures.reserve(attendance.size());
for (std::size_t worker : attendance)
{
// Asynchronously start a new task. The task is encapsulated in a
// future, which we can query to determine if the task has
// completed. We give the task a hint to run on a particular worker
// thread, but no guarantees are given by the scheduler that the
// task will actually run on that worker thread.
hpx::execution::parallel_executor exec(
hpx::threads::thread_schedule_hint(
hpx::threads::thread_schedule_hint_mode::thread,
static_cast<std::int16_t>(worker)));
futures.push_back(hpx::async(exec, hello_world_worker, worker));
}
// Wait for all of the futures to finish. The callback version of the
// hpx::lcos::wait_each function takes two arguments: a vector of futures,
// and a binary callback. The callback takes two arguments; the first
// is the index of the future in the vector, and the second is the
// return value of the future. hpx::lcos::wait_each doesn't return until
// all the futures in the vector have returned.
hpx::lcos::local::spinlock mtx;
hpx::lcos::wait_each(hpx::unwrapping([&](std::size_t t) {
if (std::size_t(-1) != t)
{
std::lock_guard<hpx::lcos::local::spinlock> lk(mtx);
attendance.erase(t);
}
}),
futures);
}
}
Now, before we discuss hello_world_foreman(), let’s talk about the
hpx::wait_each function.
The version of hpx::lcos::wait_each invokes a callback function
provided by the user, supplying the callback function with the result of the
future.
In hello_world_foreman(), an std::set<> called attendance keeps
track of which OS-threads have printed out the hello world message. When the
OS-thread prints out the statement, the future is marked as ready, and
hpx::lcos::wait_each in hello_world_foreman(). If it is not
executing on the correct OS-thread, it returns a value of -1, which causes
hello_world_foreman() to leave the OS-thread id in attendance.
std::size_t hello_world_worker(std::size_t desired)
{
// Returns the OS-thread number of the worker that is running this
// HPX-thread.
std::size_t current = hpx::get_worker_thread_num();
if (current == desired)
{
// The HPX-thread has been run on the desired OS-thread.
char const* msg = "hello world from OS-thread {1} on locality {2}\n";
hpx::util::format_to(hpx::cout, msg, desired, hpx::get_locality_id())
<< std::flush;
return desired;
}
// This HPX-thread has been run by the wrong OS-thread, make the foreman
// try again by rescheduling it.
return std::size_t(-1);
}
Because HPX features work stealing task schedulers, there is no way to guarantee that an action will be scheduled on a particular OS-thread. This is why we must use a guess-and-check approach.
Components and actions: Accumulator¶
The accumulator example demonstrates the use of components. Components are C++ classes that expose methods as a type of HPX action. These actions are called component actions.
Components are globally named, meaning that a component action can be called remotely (e.g., from another machine). There are two accumulator examples in HPX.
In the Asynchronous execution with hpx::async and actions: Fibonacci and the Remote execution with actions: Hello world, we introduced plain actions, which wrapped global functions. The target of a plain action is an identifier which refers to a particular machine involved in the computation. For plain actions, the target is the machine where the action will be executed.
Component actions, however, do not target machines. Instead, they target component instances. The instance may live on the machine that we’ve invoked the component action from, or it may live on another machine.
The component in this example exposes three different functions:
reset()- Resets the accumulator value to 0.add(arg)- Addsargto the accumulators value.query()- Queries the value of the accumulator.
This example creates an instance of the accumulator, and then allows the user to enter commands at a prompt, which subsequently invoke actions on the accumulator instance.
Setup¶
The source code for this example can be found here:
accumulator_client.cpp.
To compile this program, go to your HPX build directory (see HPX build system for information on configuring and building HPX) and enter:
make examples.accumulators.accumulator
To run the program type:
./bin/accumulator_client
Once the program starts running, it will print the following prompt and then wait for input. An example session is given below:
commands: reset, add [amount], query, help, quit
> add 5
> add 10
> query
15
> add 2
> query
17
> reset
> add 1
> query
1
> quit
Walkthrough¶
Now, let’s take a look at the source code of the accumulator example. This
example consists of two parts: an HPX component library (a library that
exposes an HPX component) and a client application which uses the library.
This walkthrough will cover the HPX component library. The code for the client
application can be found here: accumulator_client.cpp.
An HPX component is represented by two C++ classes:
A server class - The implementation of the component’s functionality.
A client class - A high-level interface that acts as a proxy for an instance of the component.
Typically, these two classes both have the same name, but the server class
usually lives in different sub-namespaces (server). For example, the full
names of the two classes in accumulator are:
examples::server::accumulator(server class)examples::accumulator(client class)
The server class¶
The following code is from: accumulator.hpp.
All HPX component server classes must inherit publicly from the HPX
component base class: hpx::components::component_base
The accumulator component inherits from
hpx::components::locking_hook. This allows the runtime system to
ensure that all action invocations are serialized. That means that the system
ensures that no two actions are invoked at the same time on a given component
instance. This makes the component thread safe and no additional locking has to
be implemented by the user. Moreover, an accumulator component is a component
because it also inherits from hpx::components::component_base (the
template argument passed to locking_hook is used as its base class). The
following snippet shows the corresponding code:
class accumulator
: public hpx::components::locking_hook<
hpx::components::component_base<accumulator> >
Our accumulator class will need a data member to store its value in, so let’s declare a data member:
argument_type value_;
The constructor for this class simply initializes value_ to 0:
accumulator() : value_(0) {}
Next, let’s look at the three methods of this component that we will be exposing as component actions:
Here are the action types. These types wrap the methods we’re exposing. The wrapping technique is very similar to the one used in the Asynchronous execution with hpx::async and actions: Fibonacci and the Remote execution with actions: Hello world:
HPX_DEFINE_COMPONENT_ACTION(accumulator, reset);
HPX_DEFINE_COMPONENT_ACTION(accumulator, add);
HPX_DEFINE_COMPONENT_ACTION(accumulator, query);
The last piece of code in the server class header is the declaration of the action type registration code:
HPX_REGISTER_ACTION_DECLARATION(
examples::server::accumulator::reset_action,
accumulator_reset_action);
HPX_REGISTER_ACTION_DECLARATION(
examples::server::accumulator::add_action,
accumulator_add_action);
HPX_REGISTER_ACTION_DECLARATION(
examples::server::accumulator::query_action,
accumulator_query_action);
Note
The code above must be placed in the global namespace.
The rest of the registration code is in
accumulator.cpp
///////////////////////////////////////////////////////////////////////////////
// Add factory registration functionality.
HPX_REGISTER_COMPONENT_MODULE();
///////////////////////////////////////////////////////////////////////////////
typedef hpx::components::component<
examples::server::accumulator
> accumulator_type;
HPX_REGISTER_COMPONENT(accumulator_type, accumulator);
///////////////////////////////////////////////////////////////////////////////
// Serialization support for accumulator actions.
HPX_REGISTER_ACTION(
accumulator_type::wrapped_type::reset_action,
accumulator_reset_action);
HPX_REGISTER_ACTION(
accumulator_type::wrapped_type::add_action,
accumulator_add_action);
HPX_REGISTER_ACTION(
accumulator_type::wrapped_type::query_action,
accumulator_query_action);
Note
The code above must be placed in the global namespace.
The client class¶
The following code is from accumulator.hpp.
The client class is the primary interface to a component instance. Client classes are used to create components:
// Create a component on this locality.
examples::accumulator c = hpx::new_<examples::accumulator>(hpx::find_here());
and to invoke component actions:
c.add(hpx::launch::apply, 4);
Clients, like servers, need to inherit from a base class, this time,
hpx::components::client_base:
class accumulator
: public hpx::components::client_base<
accumulator, server::accumulator
>
For readability, we typedef the base class like so:
typedef hpx::components::client_base<
accumulator, server::accumulator
> base_type;
Here are examples of how to expose actions through a client class:
There are a few different ways of invoking actions:
Non-blocking: For actions that don’t have return types, or when we do not care about the result of an action, we can invoke the action using fire-and-forget semantics. This means that once we have asked HPX to compute the action, we forget about it completely and continue with our computation. We use
hpx::applyto invoke an action in a non-blocking fashion.
void reset(hpx::launch::apply_policy)
{
HPX_ASSERT(this->get_id());
typedef server::accumulator::reset_action action_type;
hpx::apply<action_type>(this->get_id());
}
Asynchronous: Futures, as demonstrated in Asynchronous execution with hpx::async: Fibonacci, Asynchronous execution with hpx::async and actions: Fibonacci, and the Remote execution with actions: Hello world, enable asynchronous action invocation. Here’s an example from the accumulator client class:
hpx::future<argument_type> query(hpx::launch::async_policy)
{
HPX_ASSERT(this->get_id());
typedef server::accumulator::query_action action_type;
return hpx::async<action_type>(hpx::launch::async, this->get_id());
}
Synchronous: To invoke an action in a fully synchronous manner, we can simply call
hpx::async().get()(i.e., create a future and immediately wait on it to be ready). Here’s an example from the accumulator client class:
void add(argument_type arg)
{
HPX_ASSERT(this->get_id());
typedef server::accumulator::add_action action_type;
action_type()(this->get_id(), arg);
}
Note that this->get_id() references a data member of the
hpx::components::client_base base class which identifies the server
accumulator instance.
hpx::naming::id_type is a type which represents a global identifier
in HPX. This type specifies the target of an action. This is the type that is
returned by hpx::find_here in which case it represents the
locality the code is running on.
Dataflow: Interest calculator¶
HPX provides its users with several different tools to simply express parallel concepts. One of these tools is a local control object (LCO) called dataflow. An LCO is a type of component that can spawn a new thread when triggered. They are also distinguished from other components by a standard interface that allow users to understand and use them easily. A Dataflow, being an LCO, is triggered when the values it depends on become available. For instance, if you have a calculation X that depends on the results of three other calculations, you could set up a dataflow that would begin the calculation X as soon as the other three calculations have returned their values. Dataflows are set up to depend on other dataflows. It is this property that makes dataflow a powerful parallelization tool. If you understand the dependencies of your calculation, you can devise a simple algorithm that sets up a dependency tree to be executed. In this example, we calculate compound interest. To calculate compound interest, one must calculate the interest made in each compound period, and then add that interest back to the principal before calculating the interest made in the next period. A practical person would, of course, use the formula for compound interest:
where \(F\) is the future value, \(P\) is the principal value, \(i\) is the interest rate, and \(n\) is the number of compound periods.
However, for the sake of this example, we have chosen to manually calculate the future value by iterating:
and
Setup¶
The source code for this example can be found here:
interest_calculator.cpp.
To compile this program, go to your HPX build directory (see HPX build system for information on configuring and building HPX) and enter:
make examples.quickstart.interest_calculator
To run the program type:
./bin/interest_calculator --principal 100 --rate 5 --cp 6 --time 36
This should print:
Final amount: 134.01
Amount made: 34.0096
Walkthrough¶
Let us begin with main. Here we can see that we again are using
Boost.Program Options to set our command line variables (see
Asynchronous execution with hpx::async and actions: Fibonacci for more details). These options set the principal,
rate, compound period, and time. It is important to note that the units of time
for cp and time must be the same.
int main(int argc, char ** argv)
{
options_description cmdline("Usage: " HPX_APPLICATION_STRING " [options]");
cmdline.add_options()
("principal", value<double>()->default_value(1000), "The principal [$]")
("rate", value<double>()->default_value(7), "The interest rate [%]")
("cp", value<int>()->default_value(12), "The compound period [months]")
("time", value<int>()->default_value(12*30),
"The time money is invested [months]")
;
hpx::init_params init_args;
init_args.desc_cmdline = cmdline;
return hpx::init(argc, argv, init_args);
}
Next we look at hpx_main.
int hpx_main(variables_map & vm)
{
{
using hpx::dataflow;
using hpx::make_ready_future;
using hpx::shared_future;
using hpx::unwrapping;
hpx::naming::id_type here = hpx::find_here();
double init_principal=vm["principal"].as<double>(); //Initial principal
double init_rate=vm["rate"].as<double>(); //Interest rate
int cp=vm["cp"].as<int>(); //Length of a compound period
int t=vm["time"].as<int>(); //Length of time money is invested
init_rate/=100; //Rate is a % and must be converted
t/=cp; //Determine how many times to iterate interest calculation:
//How many full compound periods can fit in the time invested
// In non-dataflow terms the implemented algorithm would look like:
//
// int t = 5; // number of time periods to use
// double principal = init_principal;
// double rate = init_rate;
//
// for (int i = 0; i < t; ++i)
// {
// double interest = calc(principal, rate);
// principal = add(principal, interest);
// }
//
// Please note the similarity with the code below!
shared_future<double> principal = make_ready_future(init_principal);
shared_future<double> rate = make_ready_future(init_rate);
for (int i = 0; i < t; ++i)
{
shared_future<double> interest = dataflow(unwrapping(calc), principal, rate);
principal = dataflow(unwrapping(add), principal, interest);
}
// wait for the dataflow execution graph to be finished calculating our
// overall interest
double result = principal.get();
std::cout << "Final amount: " << result << std::endl;
std::cout << "Amount made: " << result-init_principal << std::endl;
}
return hpx::finalize();
}
Here we find our command line variables read in, the rate is converted from a
percent to a decimal, the number of calculation iterations is determined, and
then our shared_futures are set up. Notice that we first place our principal and
rate into shares futures by passing the variables init_principal and
init_rate using hpx::make_ready_future.
In this way hpx::shared_future<double> principal
and rate will be initialized to init_principal and init_rate when
hpx::make_ready_future<double> returns a future containing
those initial values. These shared futures then enter the for loop and are
passed to interest. Next principal and interest are passed to the
reassignment of principal using a hpx::dataflow. A dataflow
will first wait for its arguments to be ready before launching any callbacks, so
add in this case will not begin until both principal and interest
are ready. This loop continues for each compound period that must be calculated.
To see how interest and principal are calculated in the loop, let us look
at calc_action and add_action:
// Calculate interest for one period
double calc(double principal, double rate)
{
return principal * rate;
}
///////////////////////////////////////////////////////////////////////////////
// Add the amount made to the principal
double add(double principal, double interest)
{
return principal + interest;
}
After the shared future dependencies have been defined in hpx_main, we see the following statement:
double result = principal.get();
This statement calls hpx::future::get on the shared future
principal which had its value calculated by our for loop. The program will wait
here until the entire dataflow tree has been calculated and the value assigned
to result. The program then prints out the final value of the investment and the
amount of interest made by subtracting the final value of the investment from
the initial value of the investment.
Local to remote: 1D stencil¶
When developers write code they typically begin with a simple serial code and build upon it until all of the required functionality is present. The following set of examples were developed to demonstrate this iterative process of evolving a simple serial program to an efficient, fully-distributed HPX application. For this demonstration, we implemented a 1D heat distribution problem. This calculation simulates the diffusion of heat across a ring from an initialized state to some user-defined point in the future. It does this by breaking each portion of the ring into discrete segments and using the current segment’s temperature and the temperature of the surrounding segments to calculate the temperature of the current segment in the next timestep as shown by Fig. 2 below.
Fig. 2 Heat diffusion example program flow.¶
We parallelize this code over the following eight examples:
The first example is straight serial code. In this code we instantiate a vector
U that contains two vectors of doubles as seen in the structure
stepper.
struct stepper
{
// Our partition type
typedef double partition;
// Our data for one time step
typedef std::vector<partition> space;
// Our operator
static double heat(double left, double middle, double right)
{
return middle + (k*dt/(dx*dx)) * (left - 2*middle + right);
}
// do all the work on 'nx' data points for 'nt' time steps
space do_work(std::size_t nx, std::size_t nt)
{
// U[t][i] is the state of position i at time t.
std::vector<space> U(2);
for (space& s : U)
s.resize(nx);
// Initial conditions: f(0, i) = i
for (std::size_t i = 0; i != nx; ++i)
U[0][i] = double(i);
// Actual time step loop
for (std::size_t t = 0; t != nt; ++t)
{
space const& current = U[t % 2];
space& next = U[(t + 1) % 2];
next[0] = heat(current[nx-1], current[0], current[1]);
for (std::size_t i = 1; i != nx-1; ++i)
next[i] = heat(current[i-1], current[i], current[i+1]);
next[nx-1] = heat(current[nx-2], current[nx-1], current[0]);
}
// Return the solution at time-step 'nt'.
return U[nt % 2];
}
};
Each element in the vector of doubles represents a single grid point. To
calculate the change in heat distribution, the temperature of each grid point,
along with its neighbors, is passed to the function heat. In order to
improve readability, references named current and next are created
which, depending on the time step, point to the first and second vector of
doubles. The first vector of doubles is initialized with a simple heat ramp.
After calling the heat function with the data in the current vector, the
results are placed into the next vector.
In example 2 we employ a technique called futurization. Futurization is a method
by which we can easily transform a code that is serially executed into a code
that creates asynchronous threads. In the simplest case this involves replacing
a variable with a future to a variable, a function with a future to a function,
and adding a .get() at the point where a value is actually needed. The code
below shows how this technique was applied to the struct stepper.
struct stepper
{
// Our partition type
typedef hpx::shared_future<double> partition;
// Our data for one time step
typedef std::vector<partition> space;
// Our operator
static double heat(double left, double middle, double right)
{
return middle + (k*dt/(dx*dx)) * (left - 2*middle + right);
}
// do all the work on 'nx' data points for 'nt' time steps
hpx::future<space> do_work(std::size_t nx, std::size_t nt)
{
using hpx::dataflow;
using hpx::unwrapping;
// U[t][i] is the state of position i at time t.
std::vector<space> U(2);
for (space& s : U)
s.resize(nx);
// Initial conditions: f(0, i) = i
for (std::size_t i = 0; i != nx; ++i)
U[0][i] = hpx::make_ready_future(double(i));
auto Op = unwrapping(&stepper::heat);
// Actual time step loop
for (std::size_t t = 0; t != nt; ++t)
{
space const& current = U[t % 2];
space& next = U[(t + 1) % 2];
// WHEN U[t][i-1], U[t][i], and U[t][i+1] have been computed, THEN we
// can compute U[t+1][i]
for (std::size_t i = 0; i != nx; ++i)
{
next[i] = dataflow(
hpx::launch::async, Op,
current[idx(i, -1, nx)], current[i], current[idx(i, +1, nx)]
);
}
}
// Now the asynchronous computation is running; the above for-loop does not
// wait on anything. There is no implicit waiting at the end of each timestep;
// the computation of each U[t][i] will begin as soon as its dependencies
// are ready and hardware is available.
// Return the solution at time-step 'nt'.
return hpx::when_all(U[nt % 2]);
}
};
In example 2, we redefine our partition type as a shared_future and, in
main, create the object result, which is a future to a vector of
partitions. We use result to represent the last vector in a string of
vectors created for each timestep. In order to move to the next timestep, the
values of a partition and its neighbors must be passed to heat once the
futures that contain them are ready. In HPX, we have an LCO (Local Control
Object) named Dataflow that assists the programmer in expressing this
dependency. Dataflow allows us to pass the results of a set of futures to a
specified function when the futures are ready. Dataflow takes three types of
arguments, one which instructs the dataflow on how to perform the function call
(async or sync), the function to call (in this case Op), and futures to the
arguments that will be passed to the function. When called, dataflow immediately
returns a future to the result of the specified function. This allows users to
string dataflows together and construct an execution tree.
After the values of the futures in dataflow are ready, the values must be pulled
out of the future container to be passed to the function heat. In order to
do this, we use the HPX facility unwrapping, which underneath calls
.get() on each of the futures so that the function heat will be passed
doubles and not futures to doubles.
By setting up the algorithm this way, the program will be able to execute as quickly as the dependencies of each future are met. Unfortunately, this example runs terribly slow. This increase in execution time is caused by the overheads needed to create a future for each data point. Because the work done within each call to heat is very small, the overhead of creating and scheduling each of the three futures is greater than that of the actual useful work! In order to amortize the overheads of our synchronization techniques, we need to be able to control the amount of work that will be done with each future. We call this amount of work per overhead grain size.
In example 3, we return to our serial code to figure out how to control the
grain size of our program. The strategy that we employ is to create “partitions”
of data points. The user can define how many partitions are created and how many
data points are contained in each partition. This is accomplished by creating
the struct partition, which contains a member object data_, a vector of
doubles that holds the data points assigned to a particular instance of
partition.
In example 4, we take advantage of the partition setup by redefining space
to be a vector of shared_futures with each future representing a partition. In
this manner, each future represents several data points. Because the user can
define how many data points are in each partition, and, therefore, how
many data points are represented by one future, a user can control the
grainsize of the simulation. The rest of the code is then futurized in the same
manner as example 2. It should be noted how strikingly similar
example 4 is to example 2.
Example 4 finally shows good results. This code scales equivalently to the OpenMP version. While these results are promising, there are more opportunities to improve the application’s scalability. Currently, this code only runs on one locality, but to get the full benefit of HPX, we need to be able to distribute the work to other machines in a cluster. We begin to add this functionality in example 5.
In order to run on a distributed system, a large amount of boilerplate code must
be added. Fortunately, HPX provides us with the concept of a component,
which saves us from having to write quite as much code. A component is an object
that can be remotely accessed using its global address. Components are made of
two parts: a server and a client class. While the client class is not required,
abstracting the server behind a client allows us to ensure type safety instead
of having to pass around pointers to global objects. Example 5 renames example
4’s struct partition to partition_data and adds serialization support.
Next, we add the server side representation of the data in the structure
partition_server. Partition_server inherits from
hpx::components::component_base, which contains a server-side component
boilerplate. The boilerplate code allows a component’s public members to be
accessible anywhere on the machine via its Global Identifier (GID). To
encapsulate the component, we create a client side helper class. This object
allows us to create new instances of our component and access its members
without having to know its GID. In addition, we are using the client class to
assist us with managing our asynchrony. For example, our client class
partition‘s member function get_data() returns a future to
partition_data get_data(). This struct inherits its boilerplate code from
hpx::components::client_base.
In the structure stepper, we have also had to make some changes to
accommodate a distributed environment. In order to get the data from a
particular neighboring partition, which could be remote, we must retrieve the data from all
of the neighboring partitions. These retrievals are asynchronous and the function
heat_part_data, which, amongst other things, calls heat, should not be
called unless the data from the neighboring partitions have arrived. Therefore,
it should come as no surprise that we synchronize this operation with another
instance of dataflow (found in heat_part). This dataflow receives futures
to the data in the current and surrounding partitions by calling get_data()
on each respective partition. When these futures are ready, dataflow passes them
to the unwrapping function, which extracts the shared_array of doubles and
passes them to the lambda. The lambda calls heat_part_data on the
locality, which the middle partition is on.
Although this example could run distributed, it only runs on one
locality, as it always uses hpx::find_here() as the target for the
functions to run on.
In example 6, we begin to distribute the partition data on different nodes. This
is accomplished in stepper::do_work() by passing the GID of the
locality where we wish to create the partition to the partition
constructor.
for (std::size_t i = 0; i != np; ++i)
U[0][i] = partition(localities[locidx(i, np, nl)], nx, double(i));
We distribute the partitions evenly based on the number of localities used,
which is described in the function locidx. Because some of the data needed
to update the partition in heat_part could now be on a new locality,
we must devise a way of moving data to the locality of the middle
partition. We accomplished this by adding a switch in the function
get_data() that returns the end element of the buffer data_ if it is
from the left partition or the first element of the buffer if the data is from
the right partition. In this way only the necessary elements, not the whole
buffer, are exchanged between nodes. The reader should be reminded that this
exchange of end elements occurs in the function get_data() and, therefore, is
executed asynchronously.
Now that we have the code running in distributed, it is time to make some
optimizations. The function heat_part spends most of its time on two tasks:
retrieving remote data and working on the data in the middle partition. Because
we know that the data for the middle partition is local, we can overlap the work
on the middle partition with that of the possibly remote call of get_data().
This algorithmic change, which was implemented in example 7, can be seen below:
// The partitioned operator, it invokes the heat operator above on all elements
// of a partition.
static partition heat_part(partition const& left,
partition const& middle, partition const& right)
{
using hpx::dataflow;
using hpx::unwrapping;
hpx::shared_future<partition_data> middle_data =
middle.get_data(partition_server::middle_partition);
hpx::future<partition_data> next_middle = middle_data.then(
unwrapping(
[middle](partition_data const& m) -> partition_data
{
HPX_UNUSED(middle);
// All local operations are performed once the middle data of
// the previous time step becomes available.
std::size_t size = m.size();
partition_data next(size);
for (std::size_t i = 1; i != size-1; ++i)
next[i] = heat(m[i-1], m[i], m[i+1]);
return next;
}
)
);
return dataflow(
hpx::launch::async,
unwrapping(
[left, middle, right](partition_data next, partition_data const& l,
partition_data const& m, partition_data const& r) -> partition
{
HPX_UNUSED(left);
HPX_UNUSED(right);
// Calculate the missing boundary elements once the
// corresponding data has become available.
std::size_t size = m.size();
next[0] = heat(l[size-1], m[0], m[1]);
next[size-1] = heat(m[size-2], m[size-1], r[0]);
// The new partition_data will be allocated on the same locality
// as 'middle'.
return partition(middle.get_id(), std::move(next));
}
),
std::move(next_middle),
left.get_data(partition_server::left_partition),
middle_data,
right.get_data(partition_server::right_partition)
);
}
Example 8 completes the futurization process and utilizes the full potential of
HPX by distributing the program flow to multiple localities, usually defined as
nodes in a cluster. It accomplishes this task by running an instance of HPX main
on each locality. In order to coordinate the execution of the program,
the struct stepper is wrapped into a component. In this way, each
locality contains an instance of stepper that executes its own instance
of the function do_work(). This scheme does create an interesting
synchronization problem that must be solved. When the program flow was being
coordinated on the head node, the GID of each component was known. However, when
we distribute the program flow, each partition has no notion of the GID of its
neighbor if the next partition is on another locality. In order to make
the GIDs of neighboring partitions visible to each other, we created two buffers
to store the GIDs of the remote neighboring partitions on the left and right
respectively. These buffers are filled by sending the GID of newly created
edge partitions to the right and left buffers of the neighboring localities.
In order to finish the simulation, the solution vectors named result are then
gathered together on locality 0 and added into a vector of spaces
overall_result using the HPX functions gather_id and gather_here.
Example 8 completes this example series, which takes the serial code of example 1 and incrementally morphs it into a fully distributed parallel code. This evolution was guided by the simple principles of futurization, the knowledge of grainsize, and utilization of components. Applying these techniques easily facilitates the scalable parallelization of most applications.
Manual¶
The manual is your comprehensive guide to HPX. It contains detailed information on how to build and use HPX in different scenarios.
Getting HPX¶
There are HPX packages available for a few Linux distributions. The easiest way to get started with HPX is to use those packages. We keep an up-to-date list with instructions on the HPX Downloads page. If you use one of the available packages you can skip the next section, HPX build system, but we still recommend that you look through it as it contains useful information on how you can customize HPX at compile-time.
If there isn’t a package available for your platform you should either clone our repository:
or download a package with the source files from HPX Downloads.
HPX build system¶
The build system for HPX is based on CMake. CMake is a cross-platform build-generator tool. CMake does not build the project, it generates the files needed by your build tool (GNU make, Visual Studio, etc.) for building HPX.
This section gives an introduction on how to use our build system to build HPX and how to use HPX in your own projects.
CMake basics¶
CMake is a cross-platform build-generator tool. CMake does not build the project, it generates the files needed by your build tool (gnu make, visual studio, etc.) for building HPX.
In general, the HPX CMake scripts try to adhere to the general CMake policies on how to write CMake-based projects.
Basic CMake usage¶
This section explains basic aspects of CMake, specifically options needed for day-to-day usage.
CMake comes with extensive documentation in the form of html files and on the
CMake executable itself. Execute cmake --help for further help options.
CMake needs to know which build tool it will generate files for (GNU make,
Visual Studio, Xcode, etc.). If not specified on the command line, it will try to
guess the build tool based on you environment. Once it has identified the build tool,
CMake uses the corresponding generator to create files for your build tool. You can
explicitly specify the generator with the command line option -G "Name of the
generator". To see the available generators on your platform, execute:
cmake --help
This will list the generator names at the end of the help text. Generator names are case-sensitive. Example:
cmake -G "Visual Studio 16 2019" path/to/hpx
For a given development platform there can be more than one adequate generator.
If you use Visual Studio "NMake Makefiles" is a generator you can use for
building with NMake. By default, CMake chooses the more specific generator
supported by your development environment. If you want an alternative generator,
you must tell this to CMake with the -G option.
Quick start¶
Here, you will use the command-line, non-interactive CMake interface.
Download and install CMake here: CMake Downloads. Version 3.17 is the minimum required version for HPX.
Open a shell. Your development tools must be reachable from this shell through the
PATHenvironment variable.Create a directory for containing the build. Building HPX on the source directory is not supported. cd to this directory:
mkdir mybuilddir cd mybuilddirExecute this command on the shell replacing
path/to/hpxwith the path to the root of your HPX source tree:cmake path/to/hpx
CMake will detect your development environment, perform a series of tests and will generate the files required for building HPX. CMake will use default values for all build parameters. See the CMake variables used to configure HPX section for fine-tuning your build.
This can fail if CMake can’t detect your toolset, or if it thinks that the
environment is not sane enough. In this case make sure that the toolset that you
intend to use is the only one reachable from the shell and that the shell itself
is the correct one for you development environment. CMake will refuse to build
MinGW makefiles if you have a POSIX shell reachable through the PATH
environment variable, for instance. You can force CMake to use various compilers
and tools. Please visit CMake Useful Variables
for a detailed overview of specific CMake variables.
Options and variables¶
Variables customize how the build will be generated. Options are boolean
variables, with possible values ON/OFF. Options and variables are
defined on the CMake command line like this:
cmake -DVARIABLE=value path/to/hpx
You can set a variable after the initial CMake invocation for changing its value. You can also undefine a variable:
cmake -UVARIABLE path/to/hpx
Variables are stored on the CMake cache. This is a file named CMakeCache.txt
on the root of the build directory. Do not hand-edit it.
Variables are listed here appending its type after a colon. You should write the variable and the type on the CMake command line:
cmake -DVARIABLE:TYPE=value path/to/llvm/source
CMake supports the following variable types: BOOL (options), STRING
(arbitrary string), PATH (directory name), FILEPATH (file name).
Prerequisites¶
Supported platforms¶
At this time, HPX supports the following platforms. Other platforms may work, but we do not test HPX with other platforms, so please be warned.
Name |
Minimum Version |
Architectures |
|---|---|---|
Linux |
2.6 |
x86-32, x86-64, k1om |
BlueGeneQ |
V1R2M0 |
PowerPC A2 |
Windows |
Any Windows system |
x86-32, x86-64 |
Mac OSX |
Any OSX system |
x86-64 |
Software and libraries¶
In the simplest case, HPX depends on Boost and Portable Hardware Locality (HWLOC). So, before you read further, please make sure you have a recent version of Boost installed on your target machine. HPX currently requires at least Boost V1.66.0 to work properly. It may build and run with older versions, but we do not test HPX with those versions, so please be warned.
The installation of Boost is described in detail in Boost’s Getting Started document. However, if you’ve never used the Boost libraries (or even if you have), here’s a quick primer: Installing Boost.
It is often possible to download the Boost libraries using the package manager of your distribution. Please refer to the corresponding documentation for your system for more information.
In addition, we require a recent version of hwloc in order to support thread pinning and NUMA awareness. See Installing Hwloc for instructions on building Portable Hardware Locality (HWLOC).
HPX is written in 99.99% Standard C++ (the remaining 0.01% is platform specific assembly code). As such, HPX is compilable with almost any standards compliant C++ compiler. A compiler supporting the C++11 Standard is highly recommended. The code base takes advantage of C++11 language features when available (move semantics, rvalue references, magic statics, etc.). This may speed up the execution of your code significantly. We currently support the following C++ compilers: GCC, MSVC, ICPC and clang. For the status of your favorite compiler with HPX visit HPX Buildbot Website.
Name |
Minimum version |
Notes |
Compilers |
||
7.0 |
||
7.0 |
||
Build System |
||
3.17 |
Cuda support 3.9 |
|
Required Libraries |
||
1.71.0 |
||
1.5 |
||
1.12.0 |
Note
When building Boost using gcc, please note that it is required to specify a
cxxflags=-std=c++14 command line argument to b2 (bjam).
Name |
Minimum version |
Notes |
Compilers |
||
Visual C++ (x64) |
2015 |
|
Build System |
||
3.17 |
||
Required Libraries |
||
1.71.0 |
||
1.5 |
||
1.12.0 |
Note
In most configurations, HPX depends only on header-only Boost. Boost.Filesystem is required if the standard library does not support filesystem. The following are not needed by default, but are required in certain configurations: Boost.Chrono, Boost.DateTime, Boost.Log, Boost.LogSetup, Boost.Regex, and Boost.Thread.
Depending on the options you chose while building and installing HPX, you will find that HPX may depend on several other libraries such as those listed below.
Note
In order to use a high speed parcelport, we currently recommend configuring
HPX to use MPI so that MPI can be used for communication between different
localities. Please set the CMake variable MPI_CXX_COMPILER to your MPI
C++ compiler wrapper if not detected automatically.
Name |
Minimum version |
Notes |
1.7.1 |
Used as a replacement for the system allocator, and for allocation diagnostics. |
|
0.97 |
Dependency of google-perftools on x86-64, used for stack unwinding. |
|
1.8.0 |
Can be used as a highspeed communication library backend for the parcelport. |
Note
When using OpenMPI please note that Ubuntu (notably 18.04 LTS) and older
Debian ship an OpenMPI 2.x built with --enable-heterogeneous which may
cause communication failures at runtime and should not be used.
Name |
Minimum version |
Notes |
Performance Application Programming Interface (PAPI) |
Used for accessing hardware performance data. |
|
2.1.0 |
Used as a replacement for the system allocator. |
|
1.0.0 |
Used as a replacement for the system allocator. |
|
1.6.7 |
Used for data I/O in some example applications. See important note below. |
Name |
Minimum version |
Notes |
1.6.7 |
Used for data I/O in some example applications. See important note below. |
Important
The C++ HDF5 libraries must be compiled with enabled thread safety support. This has to be explicitly specified while configuring the HDF5 libraries as it is not the default. Additionally, you must set the following environment variables before configuring the HDF5 libraries (this part only needs to be done on Linux):
export CFLAGS='-DHDatexit=""'
export CPPFLAGS='-DHDatexit=""'
Documentation¶
To build the HPX documentation, you need recent versions of the following packages:
python3sphinx(Python package)sphinx_rtd_theme(Python package)breathe 4.16.0(Python package)doxygen
If the Python dependencies are not available through your system package
manager, you can install them using the Python package manager pip:
pip install --user sphinx sphinx_rtd_theme breathe
You may need to set the following CMake variables to make sure CMake can find the required dependencies.
Installing Boost¶
Important
When building Boost using gcc, please note that it is required to specify a
cxxflags=-std=c++14 command line argument to b2 (bjam).
Important
On Windows, depending on the installed versions of Visual Studio, you might
also want to pass the correct toolset to the b2 command depending on
which version of the IDE you want to use. In addition, passing
address-model=64 is highly recommended. It might also be necessary to add
command line argument --build-type=complete to the b2 command on the
Windows platform.
The easiest way to create a working Boost installation is to compile Boost from
sources yourself. This is particularly important as many high performance
resources, even if they have Boost installed, usually only provide you with an
older version of Boost. We suggest you download the most recent release of the
Boost libraries from here: Boost Downloads. Unpack the downloaded archive
into a directory of your choosing. We will refer to this directory a $BOOST.
Building and installing the Boost binaries is simple. Regardless of what platform you are on, the basic instructions are as follows (with possible additional platform-dependent command line arguments):
cd $BOOST
bootstrap --prefix=<where to install boost>
./b2 -j<N>
./b2 install
where: <where to install boost> is the directory the built binaries will be
installed to, and <N> is the number of cores to use to build the Boost
binaries.
After the above sequence of commands has been executed (this may take a while!),
you will need to specify the directory where Boost was installed as
BOOST_ROOT (<where to install boost>) while executing CMake for HPX as
explained in detail in the sections How to install HPX on Unix variants and
How to install HPX on Windows.
Installing Hwloc¶
Note
These instructions are for everything except Windows. On Windows there is no
need to build hwloc. Instead, download the latest release, extract the files,
and set HWLOC_ROOT during CMake configuration to the directory in which
you extracted the files.
We suggest you download the most recent release of hwloc from here:
Hwloc Downloads. Unpack the downloaded archive into a directory of your
choosing. We will refer to this directory as $HWLOC.
To build hwloc run:
cd $HWLOC
./configure --prefix=<where to install hwloc>
make -j<N> install
where: <where to install hwloc> is the directory the built binaries will be
installed to, and <N> is the number of cores to use to build hwloc.
After the above sequence of commands has been executed, you will need to specify
the directory where hwloc was installed as HWLOC_ROOT (<where to install
hwloc>) while executing CMake for HPX as explained in detail in the sections
How to install HPX on Unix variants and How to install HPX on Windows.
Please see Hwloc Documentation for more information about hwloc.
Building HPX¶
Basic information¶
Once CMake has been run, the build process can be started. The HPX build process is highly configurable through CMake, and various CMake variables influence the build process. The build process consists of the following parts:
The HPX core libraries (target core): This forms the basic set of HPX libraries. The generated targets are:
hpx: The core HPX library (always enabled).hpx_init: The HPX initialization library that applications need to link against to define the HPX entry points (disabled for static builds).hpx_wrap: The HPX static library used to determine the runtime behavior of HPX code and respective entry points forhpx_main.hiostreams_component: The component used for (distributed) IO (always enabled).component_storage_component: The component needed for migration to persistent storage.unordered_component: The component needed for a distributed (partitioned) hash table.partioned_vector_component: The component needed for a distributed (partitioned) vector.memory_component: A dynamically loaded plugin that exposes memory based performance counters (only available on Linux).io_counter_component: A dynamically loaded plugin that exposes I/O performance counters (only available on Linux).papi_component: A dynamically loaded plugin that exposes PAPI performance counters (enabled withHPX_WITH_PAPI:BOOL, default isOff).
HPX Examples (target
examples): This target is enabled by default and builds all HPX examples (disable by settingHPX_WITH_EXAMPLES:BOOL=Off). HPX examples are part of thealltarget and are included in the installation if enabled.HPX Tests (target
tests): This target builds the HPX test suite and is enabled by default (disable by settingHPX_WITH_TESTS:BOOL=Off). They are not built by thealltarget and have to be built separately.HPX Documentation (target
docs): This target builds the documentation, and is not enabled by default (enable by settingHPX_WITH_DOCUMENTATION:BOOL=On. For more information see Documentation.
For a complete list of available CMake variables that influence the build of HPX, see CMake variables used to configure HPX.
The variables can be used to refine the recipes that can be found at Platform specific build recipes which show some basic steps on how to build HPX for a specific platform.
In order to use HPX, only the core libraries are required (the ones marked as
optional above are truly optional). When building against HPX, the CMake
variable HPX_LIBRARIES will contain hpx and hpx_init (for pkgconfig,
those are added to the Libs sections). In order to use the optional
libraries, you need to specify them as link dependencies in your build (See
Creating HPX projects).
As HPX is a modern C++ library, we require a certain minimum set of features from the C++11 standard. In addition, we make use of certain C++14 features if the used compiler supports them. This means that the HPX build system will try to determine the highest support C++ standard flavor and check for availability of those features. That is, the default will be the highest C++ standard version available. If you want to force HPX to use a specific C++ standard version, you can use the following CMake variables:
HPX_WITH_CXX14: Enables C++14 support (this is the minimum requirement)HPX_WITH_CXX17: Enables C++17 supportHPX_WITH_CXX2A: Enables (experimental) C++20 support
Build types¶
CMake can be configured to generate project files suitable for builds that
have enabled debugging support or for an optimized build (without debugging
support). The CMake variable used to set the build type is
CMAKE_BUILD_TYPE (for more information see the CMake Documentation).
Available build types are:
Debug: Full debug symbols are available as well as additional assertions to help debugging. To enable the debug build type for the HPX API, the C++ Macro
HPX_DEBUGis defined.RelWithDebInfo: Release build with debugging symbols. This is most useful for profiling applications
Release: Release build. This disables assertions and enables default compiler optimizations.
RelMinSize: Release build with optimizations for small binary sizes.
Important
We currently don’t guarantee ABI compatibility between Debug and Release
builds. Please make sure that applications built against HPX use the same
build type as you used to build HPX. For CMake builds, this means that
the CMAKE_BUILD_TYPE variables have to match and for projects not using
CMake, the HPX_DEBUG macro has to be set in debug mode.
Platform specific notes¶
Some platforms require users to have special link and/or compiler flags specified to build HPX. This is handled via CMake’s support for different toolchains (see cmake-toolchains(7) for more information). This is also used for cross compilation.
HPX ships with a set of toolchains that can be used for compilation of HPX itself and applications depending on HPX. Please see CMake toolchains shipped with HPX for more information.
In order to enable full static linking with the libraries, the CMake variable
HPX_WITH_STATIC_LINKING:BOOL has to be set to On.
Debugging applications using core files¶
For HPX to generate useful core files, HPX has to be compiled without signal
and exception handlers
HPX_WITH_DISABLED_SIGNAL_EXCEPTION_HANDLERS:BOOL. If this option is
not specified, the signal handlers change the application state. For example,
after a segmentation fault the stack trace will show the signal handler.
Similarly, unhandled exceptions are also caught by these handlers and the
stack trace will not point to the location where the unhandled exception was
thrown.
In general, core files are a helpful tool to inspect the state of the application at the moment of the crash (post-mortem debugging), without the need of attaching a debugger beforehand. This approach to debugging is especially useful if the error cannot be reliably reproduced, as only a single crashed application run is required to gain potentially helpful information like a stacktrace.
To debug with core files, the operating system first has to be told to actually write them. On most Unix systems this can be done by calling:
ulimit -c unlimited
in the shell. Now the debugger can be started up with:
gdb <application> <core file name>
The debugger should now display the last state of the application. The default
file name for core files is core.
Platform specific build recipes¶
Note
The following build recipes are mostly user-contributed and may be outdated. We always welcome updated and new build recipes.
How to install HPX on Unix variants¶
Create a build directory. HPX requires an out-of-tree build. This means you will be unable to run CMake in the HPX source tree.
cd hpx mkdir my_hpx_build cd my_hpx_build
Invoke CMake from your build directory, pointing the CMake driver to the root of your HPX source tree.
cmake -DBOOST_ROOT=/root/of/boost/installation \ -DHWLOC_ROOT=/root/of/hwloc/installation [other CMake variable definitions] \ /path/to/source/tree
For instance:
cmake -DBOOST_ROOT=~/packages/boost -DHWLOC_ROOT=/packages/hwloc -DCMAKE_INSTALL_PREFIX=~/packages/hpx ~/downloads/hpx_1.5.1
Invoke GNU make. If you are on a machine with multiple cores, add the -jN flag to your make invocation, where N is the number of parallel processes HPX gets compiled with.
gmake -j4
Caution
Compiling and linking HPX needs a considerable amount of memory. It is advisable that at least 2 GB of memory per parallel process is available.
Note
Many Linux distributions use
makeas an alias forgmake.To complete the build and install HPX:
gmake install
Important
These commands will build and install the essential core components of HPX only. In order to build and run the tests, please invoke:
gmake tests && gmake test
and in order to build (and install) all examples invoke:
cmake -DHPX_WITH_EXAMPLES=On . gmake examples gmake install
For more detailed information about using CMake, please refer to its documentation
and also the section Building HPX. Please pay special attention to the
section about HPX_WITH_MALLOC:STRING as this is crucial for getting
decent performance.
How to install HPX on OS X (Mac)¶
This section describes how to build HPX for OS X (Mac).
To build Boost with Clang and make it link to libc++ as standard library, you’ll
need to set up either of the following in your ~/user-config.jam file:
# user-config.jam (put this file into your home directory)
# ...
using clang
:
: "/usr/bin/clang++"
: <cxxflags>"-std=c++11 -fcolor-diagnostics"
<linkflags>"-stdlib=libc++ -L/path/to/libcxx/lib"
;
(Again, remember to replace /path/to with whatever you used earlier.)
Then, you can use one of the following for your build command:
b2 --build-dir=/tmp/build-boost --layout=versioned toolset=clang install -j4
or:
b2 --build-dir=/tmp/build-boost --layout=versioned toolset=clang install -j4
We verified this using Boost V1.53. If you use a different version, just
remember to replace /usr/local/include/boost-1_53 with whatever prefix
you used in your installation.
cd /path/to
git clone https://github.com/STEllAR-GROUP/hpx.git
mkdir build-hpx && cd build-hpx
To build with Clang, execute:
cmake ../hpx \
-DCMAKE_CXX_COMPILER=clang++ \
-DBOOST_ROOT=/path/to/boost \
-DHWLOC_ROOT=/path/to/hwloc \
-DHPX_WITH_GENERIC_CONTEXT_COROUTINES=On
make -j
For more detailed information about using CMake, please refer its documentation and to the section Building HPX.
Alternatively, you can install a recent version of gcc as well as all required libraries via MacPorts:
Install MacPorts
Install CMake, gcc, hwloc:
sudo brew install cmake sudo brew install boost sudo brew install hwloc sudo brew install make
You may also want:
sudo brew install gperftools
If you need to build Boost manually (the Boost package of MacPorts is built with Clang, and unfortunately doesn’t work with a GCC-build version of HPX):
wget https://dl.bintray.com/boostorg/release/1.69.0/source/boost_1_69_0.tar.bz2 tar xjf boost_1_69_0.tar.bz2 pushd boost_1_69_0 export BOOST_ROOT=$HOME/boost_1_69_0 ./bootstrap.sh --prefix=$BOOST_DIR ./b2 -j8 ./b2 -j8 install export DYLD_LIBRARY_PATH=$DYLD_LIBRARY_PATH:$BOOST_ROOT/lib popd
Build HPX:
git clone https://github.com/STEllAR-GROUP/hpx.git mkdir hpx-build pushd hpx-build export HPX_ROOT=$HOME/hpx cmake -DCMAKE_CXX_COMPILER=g++ \ -DCMAKE_CXX_FLAGS="-Wno-unused-local-typedefs" \ -DBOOST_ROOT=$BOOST_ROOT \ -DHWLOC_ROOT=/opt/local \ -DCMAKE_INSTALL_PREFIX=$HOME/hpx \ -DHPX_WITH_GENERIC_CONTEXT_COROUTINES=On \ $(pwd)/../hpx make -j8 make -j8 install export DYLD_LIBRARY_PATH=$DYLD_LIBRARY_PATH:$HPX_ROOT/lib/hpx popd
Note that you need to set
BOOST_ROOT,HPX_ROOTandDYLD_LIBRARY_PATH(for bothBOOST_ROOTandHPX_ROOT) every time you configure, build, or run an HPX application.Note that you need to set
HPX_WITH_GENERIC_CONTEXT_COROUTINES=Onfor MacOS.If you want to use HPX with MPI, you need to enable the MPI parcelport, and also specify the location of the MPI wrapper scripts. This can be done using the following command:
cmake -DHPX_WITH_PARCELPORT_MPI=ON \ -DCMAKE_CXX_COMPILER=g++ \ -DMPI_CXX_COMPILER=openmpic++ \ -DCMAKE_CXX_FLAGS="-Wno-unused-local-typedefs" \ -DBOOST_ROOT=$BOOST_DIR \ -DHWLOC_ROOT=/opt/local \ -DCMAKE_INSTALL_PREFIX=$HOME/hpx $(pwd)/../hpx
How to install HPX on Windows¶
Download the Boost c++ libraries from Boost Downloads
Install the Boost library as explained in the section Installing Boost
Install the hwloc library as explained in the section Installing Hwloc
Download the latest version of CMake binaries, which are located under the platform section of the downloads page at CMake Downloads.
Download the latest version of HPX from the STE||AR website: HPX Downloads.
Create a build folder. HPX requires an out-of-tree-build. This means that you will be unable to run CMake in the HPX source folder.
Open up the CMake GUI. In the input box labelled “Where is the source code:”, enter the full path to the source folder. The source directory is the one where the sources were checked out. CMakeLists.txt files in the source directory as well as the subdirectories describe the build to CMake. In addition to this, there are CMake scripts (usually ending in .cmake) stored in a special CMake directory. CMake does not alter any file in the source directory and doesn’t add new ones either. In the input box labelled “Where to build the binaries:”, enter the full path to the build folder you created before. The build directory is one where all compiler outputs are stored, which includes object files and final executables.
Add CMake variable definitions (if any) by clicking the “Add Entry” button. There are two required variables you need to define:
BOOST_ROOTandHWLOC_ROOTThese (PATH) variables need to be set to point to the root folder of your Boost and hwloc installations. It is recommended to set the variableCMAKE_INSTALL_PREFIXas well. This determines where the HPX libraries will be built and installed. If this (PATH) variable is set, it has to refer to the directory where the built HPX files should be installed to.Press the “Configure” button. A window will pop up asking you which compilers to use. Select the Visual Studio 10 (64Bit) compiler (it usually is the default if available). The Visual Studio 2012 (64Bit) and Visual Studio 2013 (64Bit) compilers are supported as well. Note that while it is possible to build HPX for x86, we don’t recommend doing so as 32 bit runs are severely restricted by a 32 bit Windows system limitation affecting the number of HPX threads you can create.
Press “Configure” again. Repeat this step until the “Generate” button becomes clickable (and until no variable definitions are marked in red anymore).
Press “Generate”.
Open up the build folder, and double-click hpx.sln.
Build the INSTALL target.
For more detailed information about using CMake please refer its documentation and also the section Building HPX.
Download the CMake V3.18.1 installer (or latest version) from here
Download the hwloc V1.11.0 (or the latest version) from here and unpack it.
Download the latest Boost libraries from here and unpack them.
Build the Boost DLLs and LIBs by using these commands from Command Line (or PowerShell). Open CMD/PowerShell inside the Boost dir and type in:
bootstrap.bat
This batch file will set up everything needed to create a successful build. Now execute:
b2.exe link=shared variant=release,debug architecture=x86 address-model=64 threading=multi --build-type=complete install
This command will start a (very long) build of all available Boost libraries. Please, be patient.
Open CMake-GUI.exe and set up your source directory (input field ‘Where is the source code’) to the base directory of the source code you downloaded from HPX’s GitHub pages. Here’s an example of CMake path settings, which point to the
Documents/GitHub/hpxfolder:
Fig. 3 Example CMake path settings.¶
Inside ‘Where is the source-code’ enter the base directory of your HPX source directory (do not enter the “src” sub-directory!). Inside ‘Where to build the binaries’ you should put in the path where all the building processes will happen. This is important because the building machinery will do an “out-of-tree” build. CMake will not touch or change the original source files in any way. Instead, it will generate Visual Studio Solution Files, which will build HPX packages out of the HPX source tree.
Set three new environment variables (in CMake, not in Windows environment):
BOOST_ROOT,HWLOC_ROOT,CMAKE_INSTALL_PREFIX. The meaning of these variables is as follows:BOOST_ROOTthe HPX root directory of the unpacked Boost headers/cpp files.HWLOC_ROOTthe HPX root directory of the unpacked Portable Hardware Locality files.CMAKE_INSTALL_PREFIXthe HPX root directory where the future builds of HPX should be installed.Note
HPX is a very large software collection, so it is not recommended to use the default
C:\Program Files\hpx. Many users may prefer to use simpler paths without whitespace, likeC:\bin\hpxorD:\bin\hpxetc.
To insert new env-vars click on “Add Entry” and then insert the name inside “Name”, select
PATHas Type and put the path-name in the “Path” text field. Repeat this for the first three variables.This is how variable insertion will look:
Fig. 4 Example CMake adding entry.¶
Alternatively, users could provide
BOOST_LIBRARYDIRinstead ofBOOST_ROOT; the difference is thatBOOST_LIBRARYDIRshould point to the subdirectory inside Boost root where all the compiled DLLs/LIBs are. For example,BOOST_LIBRARYDIRmay point to thebin.v2subdirectory under the Boost rootdir. It is important to keep the meanings of these two variables separated from each other:BOOST_DIRpoints to the ROOT folder of the Boost library.BOOST_LIBRARYDIRpoints to the subdir inside the Boost root folder where the compiled binaries are.Click the ‘Configure’ button of CMake-GUI. You will be immediately presented with a small window where you can select the C++ compiler to be used within Visual Studio. This has been tested using the latest v14 (a.k.a C++ 2015) but older versions should be sufficient too. Make sure to select the 64Bit compiler.
After the generate process has finished successfully, click the ‘Generate’ button. Now, CMake will put new VS Solution files into the BUILD folder you selected at the beginning.
Open Visual Studio and load the
HPX.slnfrom your build folder.Go to
CMakePredefinedTargetsand build theINSTALLproject:
Fig. 5 Visual Studio INSTALL target.¶
It will take some time to compile everything, and in the end you should see an output similar to this one:
Fig. 6 Visual Studio build output.¶
How to install HPX on Fedora distributions¶
Important
There are official HPX packages for Fedora. Unless you want to customize your, build you may want to start off with the official packages. Instructions can be found on the HPX Downloads page.
Note
This section of the manual is based off of our collaborator Patrick Diehl’s blog post Installing |hpx| on Fedora 22.
Install all packages for minimal installation:
sudo dnf install gcc-c++ cmake boost-build boost boost-devel hwloc-devel \ hwloc papi-devel gperftools-devel docbook-dtds \ docbook-style-xsl libsodium-devel doxygen boost-doc hdf5-devel \ fop boost-devel boost-openmpi-devel boost-mpich-devel
Get the development branch of HPX:
git clone https://github.com/STEllAR-GROUP/hpx.git
Configure it with CMake:
cd hpx mkdir build cd build cmake -DCMAKE_INSTALL_PREFIX=/opt/hpx .. make -j make install
Note
To build HPX without examples use:
cmake -DCMAKE_INSTALL_PREFIX=/opt/hpx -DHPX_WITH_EXAMPLES=Off ..
Add the library path of HPX to ldconfig:
sudo echo /opt/hpx/lib > /etc/ld.so.conf.d/hpx.conf sudo ldconfig
How to install HPX on Arch distributions¶
Important
There are HPX packages for Arch in the AUR. Unless you want to customize your build, you may want to start off with those. Instructions can be found on the HPX Downloads page.
Install all packages for a minimal installation:
sudo pacman -S gcc clang cmake boost hwloc gperftools
For building the documentation, you will need to further install the following:
sudo pacman -S doxygen python-pip pip install --user sphinx sphinx_rtd_theme breathe
The rest of the installation steps are the same as those for the Fedora or Unix variants.
How to install HPX on Debian-based distributions¶
Install all packages for a minimal installation:
sudo apt install cmake libboost-all-dev hwloc libgoogle-perftools-dev
To build the documentation you will need to further install the following:
sudo apt install doxygen python-pip pip install --user sphinx sphinx_rtd_theme breathe
or the following if you prefer to get Python packages from the Debian repositories:
sudo apt install doxygen python-sphinx python-sphinx-rtd-theme python-breathe
The rest of the installation steps are same as those for the Fedora or Unix variants.
CMake toolchains shipped with HPX¶
In order to compile HPX for various platforms, we provide a variety of toolchain
files that take care of setting up various CMake variables like compilers, etc.
They are located in the cmake/toolchains directory:
To use them, pass the -DCMAKE_TOOLCHAIN_FILE=<toolchain> argument to the
CMake invocation.
ARM-gcc¶
# Copyright (c) 2015 Thomas Heller
#
# SPDX-License-Identifier: BSL-1.0
# Distributed under the Boost Software License, Version 1.0. (See accompanying
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_CROSSCOMPILING ON)
# Set the gcc Compiler
set(CMAKE_CXX_COMPILER arm-linux-gnueabihf-g++-4.8)
set(HPX_WITH_GENERIC_CONTEXT_COROUTINES
ON
CACHE BOOL "enable generic coroutines"
)
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
BGION-gcc¶
# Copyright (c) 2014 John Biddiscombe
#
# SPDX-License-Identifier: BSL-1.0
# Distributed under the Boost Software License, Version 1.0. (See accompanying
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
# This is the default toolchain file to be used with CNK on a BlueGene/Q. It
# sets the appropriate compile flags and compiler such that HPX will compile.
# Note that you still need to provide Boost, hwloc and other utility libraries
# like a custom allocator yourself.
#
# Usage : cmake
# -DCMAKE_TOOLCHAIN_FILE=~/src/hpx/cmake/toolchains/BGION-gcc.cmake ~/src/hpx
#
set(CMAKE_SYSTEM_NAME Linux)
# Set the gcc Compiler
set(CMAKE_CXX_COMPILER g++)
# Add flags we need for BGAS compilation
set(CMAKE_CXX_FLAGS_INIT
"-D__powerpc__ -D__bgion__ -I/gpfs/bbp.cscs.ch/home/biddisco/src/bgas/rdmahelper "
CACHE STRING "Initial compiler flags used to compile for BGAS"
)
# cmake-format: off
# the V1R2M2 includes are necessary for some hardware specific features
# -DHPX_SMALL_STACK_SIZE=0x200000
# -DHPX_MEDIUM_STACK_SIZE=0x200000
# -DHPX_LARGE_STACK_SIZE=0x200000
# -DHPX_HUGE_STACK_SIZE=0x200000
# cmake-format: on
set(CMAKE_EXE_LINKER_FLAGS_INIT
"-L/gpfs/bbp.cscs.ch/apps/bgas/tools/gcc/gcc-4.8.2/install/lib64 -latomic -lrt"
CACHE STRING "BGAS flags"
)
# We do not perform cross compilation here ...
set(CMAKE_CROSSCOMPILING OFF)
# Set our platform name
set(HPX_PLATFORM "native")
# Disable generic coroutines (and use posix version)
set(HPX_WITH_GENERIC_CONTEXT_COROUTINES
OFF
CACHE BOOL "disable generic coroutines"
)
# Always disable the tcp parcelport as it is non-functional on the BGQ.
set(HPX_WITH_PARCELPORT_TCP
ON
CACHE BOOL ""
)
# Always enable the tcp parcelport as it is currently the only way to
# communicate on the BGQ.
set(HPX_WITH_PARCELPORT_MPI
ON
CACHE BOOL ""
)
# We have a bunch of cores on the A2 processor ...
set(HPX_WITH_MAX_CPU_COUNT
"64"
CACHE STRING ""
)
# We have no custom malloc yet
if(NOT DEFINED HPX_WITH_MALLOC)
set(HPX_WITH_MALLOC
"system"
CACHE STRING ""
)
endif()
set(HPX_HIDDEN_VISIBILITY
OFF
CACHE BOOL ""
)
#
# Convenience setup for jb @ bbpbg2.cscs.ch
#
set(BOOST_ROOT "/gpfs/bbp.cscs.ch/home/biddisco/apps/gcc-4.8.2/boost_1_56_0")
set(HWLOC_ROOT "/gpfs/bbp.cscs.ch/home/biddisco/apps/gcc-4.8.2/hwloc-1.8.1")
set(CMAKE_BUILD_TYPE
"Debug"
CACHE STRING "Default build"
)
#
# Testing flags
#
set(BUILD_TESTING
ON
CACHE BOOL "Testing enabled by default"
)
set(HPX_WITH_TESTS
ON
CACHE BOOL "Testing enabled by default"
)
set(HPX_WITH_TESTS_BENCHMARKS
ON
CACHE BOOL "Testing enabled by default"
)
set(HPX_WITH_TESTS_REGRESSIONS
ON
CACHE BOOL "Testing enabled by default"
)
set(HPX_WITH_TESTS_UNIT
ON
CACHE BOOL "Testing enabled by default"
)
set(HPX_WITH_TESTS_EXAMPLES
ON
CACHE BOOL "Testing enabled by default"
)
set(HPX_WITH_TESTS_EXTERNAL_BUILD
OFF
CACHE BOOL "Turn off build of cmake build tests"
)
set(DART_TESTING_TIMEOUT
45
CACHE STRING "Life is too short"
)
# HPX_WITH_STATIC_LINKING
BGQ¶
# Copyright (c) 2014 Thomas Heller
#
# SPDX-License-Identifier: BSL-1.0
# Distributed under the Boost Software License, Version 1.0. (See accompanying
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#
# This is the default toolchain file to be used with CNK on a BlueGene/Q. It sets
# the appropriate compile flags and compiler such that HPX will compile.
# Note that you still need to provide Boost, hwloc and other utility libraries
# like a custom allocator yourself.
#
set(CMAKE_SYSTEM_NAME Linux)
# Set the Intel Compiler
set(CMAKE_CXX_COMPILER bgclang++11)
set(MPI_CXX_COMPILER mpiclang++11)
set(CMAKE_CXX_FLAGS_INIT
""
CACHE STRING ""
)
set(CMAKE_CXX_COMPILE_OBJECT
"<CMAKE_CXX_COMPILER> -fPIC <DEFINES> <FLAGS> -o <OBJECT> -c <SOURCE>"
CACHE STRING ""
)
set(CMAKE_CXX_LINK_EXECUTABLE
"<CMAKE_CXX_COMPILER> -fPIC -dynamic <FLAGS> <CMAKE_CXX_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>"
CACHE STRING ""
)
set(CMAKE_CXX_CREATE_SHARED_LIBRARY
"<CMAKE_CXX_COMPILER> -fPIC -shared <CMAKE_SHARED_LIBRARY_CXX_FLAGS> <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS> <SONAME_FLAG><TARGET_SONAME> -o <TARGET> <OBJECTS> <LINK_LIBRARIES>"
CACHE STRING ""
)
# Disable searches in the default system paths. We are cross compiling after all
# and cmake might pick up wrong libraries that way
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM BOTH)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
# We do a cross compilation here ...
set(CMAKE_CROSSCOMPILING ON)
# Set our platform name
set(HPX_PLATFORM "BlueGeneQ")
# Always disable the tcp parcelport as it is non-functional on the BGQ.
set(HPX_WITH_PARCELPORT_TCP OFF)
# Always enable the mpi parcelport as it is currently the only way to
# communicate on the BGQ.
set(HPX_WITH_PARCELPORT_MPI ON)
# We have a bunch of cores on the BGQ ...
set(HPX_WITH_MAX_CPU_COUNT "64")
# We default to tbbmalloc as our allocator on the MIC
if(NOT DEFINED HPX_WITH_MALLOC)
set(HPX_WITH_MALLOC
"system"
CACHE STRING ""
)
endif()
Cray¶
# Copyright (c) 2014 Thomas Heller
#
# SPDX-License-Identifier: BSL-1.0
# Distributed under the Boost Software License, Version 1.0. (See accompanying
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#
# This is the default toolchain file to be used with Intel Xeon PHIs. It sets
# the appropriate compile flags and compiler such that HPX will compile.
# Note that you still need to provide Boost, hwloc and other utility libraries
# like a custom allocator yourself.
#
# set(CMAKE_SYSTEM_NAME Cray-CNK-Intel)
if(HPX_WITH_STATIC_LINKING)
set_property(GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS FALSE)
else()
endif()
# Set the Cray Compiler Wrapper
set(CMAKE_CXX_COMPILER CC)
set(CMAKE_CXX_FLAGS_INIT
""
CACHE STRING ""
)
set(CMAKE_SHARED_LIBRARY_CXX_FLAGS
"-fPIC -shared"
CACHE STRING ""
)
set(CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS
"-fPIC -shared"
CACHE STRING ""
)
set(CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS
"-fPIC -shared"
CACHE STRING ""
)
set(CMAKE_CXX_COMPILE_OBJECT
"<CMAKE_CXX_COMPILER> -shared -fPIC <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT> -c <SOURCE>"
CACHE STRING ""
)
set(CMAKE_CXX_LINK_EXECUTABLE
"<CMAKE_CXX_COMPILER> -fPIC -dynamic <FLAGS> <CMAKE_CXX_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>"
CACHE STRING ""
)
set(CMAKE_CXX_CREATE_SHARED_LIBRARY
"<CMAKE_CXX_COMPILER> -fPIC -shared <CMAKE_SHARED_LIBRARY_CXX_FLAGS> <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS> <SONAME_FLAG><TARGET_SONAME> -o <TARGET> <OBJECTS> <LINK_LIBRARIES>"
CACHE STRING ""
)
# Disable searches in the default system paths. We are cross compiling after all
# and cmake might pick up wrong libraries that way
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM BOTH)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
set(HPX_WITH_PARCELPORT_TCP
ON
CACHE BOOL ""
)
set(HPX_WITH_PARCELPORT_MPI
ON
CACHE BOOL ""
)
set(HPX_WITH_PARCELPORT_MPI_MULTITHREADED
OFF
CACHE BOOL ""
)
set(HPX_WITH_PARCELPORT_LIBFABRIC
ON
CACHE BOOL ""
)
set(HPX_PARCELPORT_LIBFABRIC_PROVIDER
"gni"
CACHE STRING "See libfabric docs for details, gni,verbs,psm2 etc etc"
)
set(HPX_PARCELPORT_LIBFABRIC_THROTTLE_SENDS
"256"
CACHE STRING "Max number of messages in flight at once"
)
set(HPX_PARCELPORT_LIBFABRIC_WITH_DEV_MODE
OFF
CACHE BOOL "Custom libfabric logging flag"
)
set(HPX_PARCELPORT_LIBFABRIC_WITH_LOGGING
OFF
CACHE BOOL "Libfabric parcelport logging on/off flag"
)
set(HPX_WITH_ZERO_COPY_SERIALIZATION_THRESHOLD
"4096"
CACHE
STRING
"The threshold in bytes to when perform zero copy optimizations (default: 128)"
)
# We do a cross compilation here ...
set(CMAKE_CROSSCOMPILING
ON
CACHE BOOL ""
)
CrayKNL¶
# Copyright (c) 2014 Thomas Heller
#
# SPDX-License-Identifier: BSL-1.0
# Distributed under the Boost Software License, Version 1.0. (See accompanying
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#
# This is the default toolchain file to be used with Intel Xeon PHIs. It sets
# the appropriate compile flags and compiler such that HPX will compile.
# Note that you still need to provide Boost, hwloc and other utility libraries
# like a custom allocator yourself.
#
if(HPX_WITH_STATIC_LINKING)
set_property(GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS FALSE)
else()
endif()
# Set the Cray Compiler Wrapper
set(CMAKE_CXX_COMPILER CC)
set(CMAKE_CXX_FLAGS_INIT
""
CACHE STRING ""
)
set(CMAKE_SHARED_LIBRARY_CXX_FLAGS
"-fPIC -shared"
CACHE STRING ""
)
set(CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS
"-fPIC -shared"
CACHE STRING ""
)
set(CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS
"-fPIC -shared"
CACHE STRING ""
)
set(CMAKE_CXX_COMPILE_OBJECT
"<CMAKE_CXX_COMPILER> -shared -fPIC <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT> -c <SOURCE>"
CACHE STRING ""
)
set(CMAKE_CXX_LINK_EXECUTABLE
"<CMAKE_CXX_COMPILER> -fPIC -dynamic <FLAGS> <CMAKE_CXX_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>"
CACHE STRING ""
)
set(CMAKE_CXX_CREATE_SHARED_LIBRARY
"<CMAKE_CXX_COMPILER> -fPIC -shared <CMAKE_SHARED_LIBRARY_CXX_FLAGS> <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS> <SONAME_FLAG><TARGET_SONAME> -o <TARGET> <OBJECTS> <LINK_LIBRARIES>"
CACHE STRING ""
)
#
# Disable searches in the default system paths. We are cross compiling after all
# and cmake might pick up wrong libraries that way
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM BOTH)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
set(HPX_WITH_PARCELPORT_TCP
ON
CACHE BOOL ""
)
set(HPX_WITH_PARCELPORT_MPI
ON
CACHE BOOL ""
)
set(HPX_WITH_PARCELPORT_MPI_MULTITHREADED
OFF
CACHE BOOL ""
)
set(HPX_WITH_PARCELPORT_LIBFABRIC
ON
CACHE BOOL ""
)
set(HPX_PARCELPORT_LIBFABRIC_PROVIDER
"gni"
CACHE STRING "See libfabric docs for details, gni,verbs,psm2 etc etc"
)
set(HPX_PARCELPORT_LIBFABRIC_THROTTLE_SENDS
"256"
CACHE STRING "Max number of messages in flight at once"
)
set(HPX_PARCELPORT_LIBFABRIC_WITH_DEV_MODE
OFF
CACHE BOOL "Custom libfabric logging flag"
)
set(HPX_PARCELPORT_LIBFABRIC_WITH_LOGGING
OFF
CACHE BOOL "Libfabric parcelport logging on/off flag"
)
set(HPX_WITH_ZERO_COPY_SERIALIZATION_THRESHOLD
"4096"
CACHE
STRING
"The threshold in bytes to when perform zero copy optimizations (default: 128)"
)
# Set the TBBMALLOC_PLATFORM correctly so that find_package(TBBMalloc) sets the
# right hints
set(TBBMALLOC_PLATFORM
"mic-knl"
CACHE STRING ""
)
# We have a bunch of cores on the MIC ... increase the default
set(HPX_WITH_MAX_CPU_COUNT
"512"
CACHE STRING ""
)
# We do a cross compilation here ...
set(CMAKE_CROSSCOMPILING
ON
CACHE BOOL ""
)
# RDTSCP is available on Xeon/Phis
set(HPX_WITH_RDTSCP
ON
CACHE BOOL ""
)
CrayKNLStatic¶
# Copyright (c) 2014-2017 Thomas Heller
# Copyright (c) 2017 Bryce Adelstein Lelbach
#
# SPDX-License-Identifier: BSL-1.0
# Distributed under the Boost Software License, Version 1.0. (See accompanying
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
set(HPX_WITH_STATIC_LINKING
ON
CACHE BOOL ""
)
set(HPX_WITH_STATIC_EXE_LINKING
ON
CACHE BOOL ""
)
set_property(GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS FALSE)
# Set the Cray Compiler Wrapper
set(CMAKE_CXX_COMPILER CC)
set(CMAKE_CXX_FLAGS_INIT
""
CACHE STRING ""
)
set(CMAKE_CXX_COMPILE_OBJECT
"<CMAKE_CXX_COMPILER> -static -fPIC <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT> -c <SOURCE>"
CACHE STRING ""
)
set(CMAKE_CXX_LINK_EXECUTABLE
"<CMAKE_CXX_COMPILER> -fPIC <FLAGS> <CMAKE_CXX_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>"
CACHE STRING ""
)
# Disable searches in the default system paths. We are cross compiling after all
# and cmake might pick up wrong libraries that way
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM BOTH)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
set(HPX_WITH_PARCELPORT_TCP
ON
CACHE BOOL ""
)
set(HPX_WITH_PARCELPORT_MPI
ON
CACHE BOOL ""
)
set(HPX_WITH_PARCELPORT_MPI_MULTITHREADED
ON
CACHE BOOL ""
)
set(HPX_WITH_PARCELPORT_LIBFABRIC
ON
CACHE BOOL ""
)
set(HPX_PARCELPORT_LIBFABRIC_PROVIDER
"gni"
CACHE STRING "See libfabric docs for details, gni,verbs,psm2 etc etc"
)
set(HPX_PARCELPORT_LIBFABRIC_THROTTLE_SENDS
"256"
CACHE STRING "Max number of messages in flight at once"
)
set(HPX_PARCELPORT_LIBFABRIC_WITH_DEV_MODE
OFF
CACHE BOOL "Custom libfabric logging flag"
)
set(HPX_PARCELPORT_LIBFABRIC_WITH_LOGGING
OFF
CACHE BOOL "Libfabric parcelport logging on/off flag"
)
set(HPX_WITH_ZERO_COPY_SERIALIZATION_THRESHOLD
"4096"
CACHE
STRING
"The threshold in bytes to when perform zero copy optimizations (default: 128)"
)
# Set the TBBMALLOC_PLATFORM correctly so that find_package(TBBMalloc) sets the
# right hints
set(TBBMALLOC_PLATFORM
"mic-knl"
CACHE STRING ""
)
# We have a bunch of cores on the MIC ... increase the default
set(HPX_WITH_MAX_CPU_COUNT
"512"
CACHE STRING ""
)
# We do a cross compilation here ...
set(CMAKE_CROSSCOMPILING
ON
CACHE BOOL ""
)
# RDTSCP is available on Xeon/Phis
set(HPX_WITH_RDTSCP
ON
CACHE BOOL ""
)
CrayStatic¶
# Copyright (c) 2014-2017 Thomas Heller
# Copyright (c) 2017 Bryce Adelstein Lelbach
#
# SPDX-License-Identifier: BSL-1.0
# Distributed under the Boost Software License, Version 1.0. (See accompanying
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
set(HPX_WITH_STATIC_LINKING
ON
CACHE BOOL ""
)
set(HPX_WITH_STATIC_EXE_LINKING
ON
CACHE BOOL ""
)
set_property(GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS FALSE)
# Set the Cray Compiler Wrapper
set(CMAKE_CXX_COMPILER CC)
set(CMAKE_CXX_FLAGS_INIT
""
CACHE STRING ""
)
set(CMAKE_CXX_COMPILE_OBJECT
"<CMAKE_CXX_COMPILER> -static -fPIC <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT> -c <SOURCE>"
CACHE STRING ""
)
set(CMAKE_CXX_LINK_EXECUTABLE
"<CMAKE_CXX_COMPILER> -fPIC <FLAGS> <CMAKE_CXX_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>"
CACHE STRING ""
)
# Disable searches in the default system paths. We are cross compiling after all
# and cmake might pick up wrong libraries that way
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM BOTH)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
# We do a cross compilation here ...
set(CMAKE_CROSSCOMPILING
ON
CACHE BOOL ""
)
# RDTSCP is available on Xeon/Phis
set(HPX_WITH_RDTSCP
ON
CACHE BOOL ""
)
set(HPX_WITH_PARCELPORT_TCP
ON
CACHE BOOL ""
)
set(HPX_WITH_PARCELPORT_MPI
ON
CACHE BOOL ""
)
set(HPX_WITH_PARCELPORT_MPI_MULTITHREADED
ON
CACHE BOOL ""
)
set(HPX_WITH_PARCELPORT_LIBFABRIC
ON
CACHE BOOL ""
)
set(HPX_PARCELPORT_LIBFABRIC_PROVIDER
"gni"
CACHE STRING "See libfabric docs for details, gni,verbs,psm2 etc etc"
)
set(HPX_PARCELPORT_LIBFABRIC_THROTTLE_SENDS
"256"
CACHE STRING "Max number of messages in flight at once"
)
set(HPX_PARCELPORT_LIBFABRIC_WITH_DEV_MODE
OFF
CACHE BOOL "Custom libfabric logging flag"
)
set(HPX_PARCELPORT_LIBFABRIC_WITH_LOGGING
OFF
CACHE BOOL "Libfabric parcelport logging on/off flag"
)
set(HPX_WITH_ZERO_COPY_SERIALIZATION_THRESHOLD
"4096"
CACHE
STRING
"The threshold in bytes to when perform zero copy optimizations (default: 128)"
)
XeonPhi¶
# Copyright (c) 2014 Thomas Heller
#
# SPDX-License-Identifier: BSL-1.0
# Distributed under the Boost Software License, Version 1.0. (See accompanying
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#
# This is the default toolchain file to be used with Intel Xeon PHIs. It sets
# the appropriate compile flags and compiler such that HPX will compile.
# Note that you still need to provide Boost, hwloc and other utility libraries
# like a custom allocator yourself.
#
set(CMAKE_SYSTEM_NAME Linux)
# Set the Intel Compiler
set(CMAKE_CXX_COMPILER icpc)
# Add the -mmic compile flag such that everything will be compiled for the
# correct platform
set(CMAKE_CXX_FLAGS_INIT
"-mmic"
CACHE STRING "Initial compiler flags used to compile for the Xeon Phi"
)
# Disable searches in the default system paths. We are cross compiling after all
# and cmake might pick up wrong libraries that way
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM BOTH)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
# We do a cross compilation here ...
set(CMAKE_CROSSCOMPILING ON)
# Set our platform name
set(HPX_PLATFORM "XeonPhi")
set(HPX_WITH_PARCELPORT_MPI
ON
CACHE BOOL "Enable the MPI based parcelport."
)
# We have a bunch of cores on the MIC ... increase the default
set(HPX_WITH_MAX_CPU_COUNT
"256"
CACHE STRING ""
)
# We default to tbbmalloc as our allocator on the MIC
if(NOT DEFINED HPX_WITH_MALLOC)
set(HPX_WITH_MALLOC
"tbbmalloc"
CACHE STRING ""
)
endif()
# Set the TBBMALLOC_PLATFORM correctly so that find_package(TBBMalloc) sets the
# right hints
set(TBBMALLOC_PLATFORM
"mic"
CACHE STRING ""
)
set(HPX_HIDDEN_VISIBILITY
OFF
CACHE BOOL
"Use -fvisibility=hidden for builds on platforms which support it"
)
# RDTSC is available on Xeon/Phis
set(HPX_WITH_RDTSC
ON
CACHE BOOL ""
)
CMake variables used to configure HPX¶
In order to configure HPX, you can set a variety of options to allow CMake to generate your specific makefiles/project files.
Variables that influence how HPX is built¶
The options are split into these categories:
Generic options¶
-
HPX_WITH_ASYNC_CUDA:BOOL¶ ON
-
HPX_WITH_AUTOMATIC_SERIALIZATION_REGISTRATION:BOOL¶ Use automatic serialization registration for actions and functions. This affects compatibility between HPX applications compiled with different compilers (default ON)
-
HPX_WITH_BENCHMARK_SCRIPTS_PATH:PATH¶ Directory to place batch scripts in
-
HPX_WITH_BUILD_BINARY_PACKAGE:BOOL¶ Build HPX on the build infrastructure on any LINUX distribution (default: OFF).
-
HPX_WITH_CHECK_MODULE_DEPENDENCIES:BOOL¶ Verify that no modules are cross-referenced from a different module category (default: OFF)
-
HPX_WITH_COMPILER_WARNINGS:BOOL¶ Enable compiler warnings (default: ON)
-
HPX_WITH_COMPILER_WARNINGS_AS_ERRORS:BOOL¶ Turn compiler warnings into errors (default: OFF)
-
HPX_WITH_COMPRESSION_BZIP2:BOOL¶ Enable bzip2 compression for parcel data (default: OFF).
-
HPX_WITH_COMPRESSION_SNAPPY:BOOL¶ Enable snappy compression for parcel data (default: OFF).
-
HPX_WITH_COMPRESSION_ZLIB:BOOL¶ Enable zlib compression for parcel data (default: OFF).
-
HPX_WITH_CUDA:BOOL¶ Enable HPX_WITH_ASYNC_CUDA (CUDA or HIP futures) and HPX_WITH_CUDA_COMPUTE (CUDA/HIP enabled parallel algorithms) (default: OFF)
-
HPX_WITH_CUDA_CLANG:BOOL¶ Use clang to compile CUDA code (default: OFF)
-
HPX_WITH_CUDA_COMPUTE:BOOL¶ Enable HPX CUDA/HIP compute capability (parallel algorithms) module (default: ON, dependent on HPX_WITH_CUDA or HPX_WITH_HIP, and HPX_WITH_ASYNC_CUDA) - note: enabling this also enables CUDA/HIP futures via HPX_WITH_ASYNC_CUDA
-
HPX_WITH_DATAPAR:BOOL¶ Enable data parallel algorithm support (default: ON)
-
HPX_WITH_DATAPAR_VC:BOOL¶ Enable data parallel algorithm support using the external Vc library (default: OFF)
-
HPX_WITH_DATAPAR_VC_NO_LIBRARY:BOOL¶ Don’t link with the Vc static library (default: OFF)
-
HPX_WITH_DEPRECATION_WARNINGS:BOOL¶ Enable warnings for deprecated facilities. (default: ON)
-
HPX_WITH_DISABLED_SIGNAL_EXCEPTION_HANDLERS:BOOL¶ Disables the mechanism that produces debug output for caught signals and unhandled exceptions (default: OFF)
-
HPX_WITH_DYNAMIC_HPX_MAIN:BOOL¶ Enable dynamic overload of system
main()(Linux and Apple only, default: ON)
-
HPX_WITH_FAULT_TOLERANCE:BOOL¶ Build HPX to tolerate failures of nodes, i.e. ignore errors in active communication channels (default: OFF)
-
HPX_WITH_FULL_RPATH:BOOL¶ Build and link HPX libraries and executables with full RPATHs (default: ON)
-
HPX_WITH_GCC_VERSION_CHECK:BOOL¶ Don’t ignore version reported by gcc (default: ON)
-
HPX_WITH_GENERIC_CONTEXT_COROUTINES:BOOL¶ Use Boost.Context as the underlying coroutines context switch implementation.
-
HPX_WITH_HIDDEN_VISIBILITY:BOOL¶ Use -fvisibility=hidden for builds on platforms which support it (default OFF)
-
HPX_WITH_HIP:BOOL¶ Enable compilation with HIPCC (default: OFF)
-
HPX_WITH_INIT_START_OVERLOADS_COMPATIBILITY:BOOL¶ Enable deprecated init() and start() overloads functions (default: OFF)
-
HPX_WITH_LOGGING:BOOL¶ Build HPX with logging enabled (default: ON).
-
HPX_WITH_MALLOC:STRING¶ Define which allocator should be linked in. Options are: system, tcmalloc, jemalloc, mimalloc, tbbmalloc, and custom (default is: tcmalloc)
-
HPX_WITH_NICE_THREADLEVEL:BOOL¶ Set HPX worker threads to have high NICE level (may impact performance) (default: OFF)
-
HPX_WITH_PARCEL_COALESCING:BOOL¶ Enable the parcel coalescing plugin (default: ON).
-
HPX_WITH_PKGCONFIG:BOOL¶ Enable generation of pkgconfig files (default: ON on Linux without CUDA/HIP, otherwise OFF)
-
HPX_WITH_PRECOMPILED_HEADERS:BOOL¶ Enable precompiled headers for certain build targets (experimental) (default OFF)
-
HPX_WITH_RUN_MAIN_EVERYWHERE:BOOL¶ Run hpx_main by default on all localities (default: OFF).
-
HPX_WITH_STACKOVERFLOW_DETECTION:BOOL¶ Enable stackoverflow detection for HPX threads/coroutines. (default: OFF, debug: ON)
-
HPX_WITH_STATIC_LINKING:BOOL¶ Compile HPX statically linked libraries (Default: OFF)
-
HPX_WITH_UNITY_BUILD:BOOL¶ Enable unity build for certain build targets (default OFF)
-
HPX_WITH_VIM_YCM:BOOL¶ Generate HPX completion file for VIM YouCompleteMe plugin
-
HPX_WITH_ZERO_COPY_SERIALIZATION_THRESHOLD:STRING¶ The threshold in bytes to when perform zero copy optimizations (default: 128)
Build Targets options¶
-
HPX_WITH_ASIO_TAG:STRING¶ Asio repository tag or branch
-
HPX_WITH_COMPILE_ONLY_TESTS:BOOL¶ Create build system support for compile time only HPX tests (default ON)
-
HPX_WITH_DISTRIBUTED_RUNTIME:BOOL¶ Enable the distributed runtime (default: ON). Turning off the distributed runtime completely disallows the creation and use of components and actions. Turning this option off is experimental!
-
HPX_WITH_DOCUMENTATION:BOOL¶ Build the HPX documentation (default OFF).
-
HPX_WITH_DOCUMENTATION_OUTPUT_FORMATS:STRING¶ List of documentation output formats to generate. Valid options are html;singlehtml;latexpdf;man. Multiple values can be separated with semicolons. (default html).
-
HPX_WITH_EXAMPLES:BOOL¶ Build the HPX examples (default ON)
-
HPX_WITH_EXAMPLES_HDF5:BOOL¶ Enable examples requiring HDF5 support (default: OFF).
-
HPX_WITH_EXAMPLES_OPENMP:BOOL¶ Enable examples requiring OpenMP support (default: OFF).
-
HPX_WITH_EXAMPLES_QT4:BOOL¶ Enable examples requiring Qt4 support (default: OFF).
-
HPX_WITH_EXAMPLES_QTHREADS:BOOL¶ Enable examples requiring QThreads support (default: OFF).
-
HPX_WITH_EXAMPLES_TBB:BOOL¶ Enable examples requiring TBB support (default: OFF).
-
HPX_WITH_EXECUTABLE_PREFIX:STRING¶ Executable prefix (default none), ‘hpx_’ useful for system install.
-
HPX_WITH_FAIL_COMPILE_TESTS:BOOL¶ Create build system support for fail compile HPX tests (default ON)
-
HPX_WITH_FETCH_ASIO:BOOL¶ Use FetchContent to fetch Asio. By default an installed Asio will be used. (default: OFF)
-
HPX_WITH_IO_COUNTERS:BOOL¶ Enable IO counters (default: ON)
-
HPX_WITH_TESTS:BOOL¶ Build the HPX tests (default ON)
-
HPX_WITH_TESTS_BENCHMARKS:BOOL¶ Build HPX benchmark tests (default: ON)
-
HPX_WITH_TESTS_EXAMPLES:BOOL¶ Add HPX examples as tests (default: ON)
-
HPX_WITH_TESTS_EXTERNAL_BUILD:BOOL¶ Build external cmake build tests (default: ON)
-
HPX_WITH_TESTS_HEADERS:BOOL¶ Build HPX header tests (default: OFF)
-
HPX_WITH_TESTS_REGRESSIONS:BOOL¶ Build HPX regression tests (default: ON)
-
HPX_WITH_TESTS_UNIT:BOOL¶ Build HPX unit tests (default: ON)
-
HPX_WITH_TOOLS:BOOL¶ Build HPX tools (default: OFF)
Thread Manager options¶
-
HPX_COROUTINES_WITH_SWAP_CONTEXT_EMULATION:BOOL¶ Emulate SwapContext API for coroutines (Windows only, default: OFF)
-
HPX_SCHEDULER_MAX_TERMINATED_THREADS:STRING¶ [Deprecated] Maximum number of terminated threads collected before those are cleaned up (default: 100)
-
HPX_WITH_COROUTINE_COUNTERS:BOOL¶ Enable keeping track of coroutine creation and rebind counts (default: OFF)
-
HPX_WITH_IO_POOL:BOOL¶ Disable internal IO thread pool, do not change if not absolutely necessary (default: ON)
-
HPX_WITH_MAX_CPU_COUNT:STRING¶ HPX applications will not use more that this number of OS-Threads (empty string means dynamic) (default: 64)
-
HPX_WITH_MAX_NUMA_DOMAIN_COUNT:STRING¶ HPX applications will not run on machines with more NUMA domains (default: 8)
-
HPX_WITH_SCHEDULER_LOCAL_STORAGE:BOOL¶ Enable scheduler local storage for all HPX schedulers (default: OFF)
-
HPX_WITH_SPINLOCK_DEADLOCK_DETECTION:BOOL¶ Enable spinlock deadlock detection (default: OFF)
-
HPX_WITH_SPINLOCK_POOL_NUM:STRING¶ Number of elements a spinlock pool manages (default: 128)
-
HPX_WITH_STACKTRACES:BOOL¶ Attach backtraces to HPX exceptions (default: ON)
-
HPX_WITH_STACKTRACES_DEMANGLE_SYMBOLS:BOOL¶ Thread stack back trace symbols will be demangled (default: ON)
-
HPX_WITH_STACKTRACES_STATIC_SYMBOLS:BOOL¶ Thread stack back trace will resolve static symbols (default: OFF)
-
HPX_WITH_THREAD_BACKTRACE_DEPTH:STRING¶ Thread stack back trace depth being captured (default: 20)
-
HPX_WITH_THREAD_BACKTRACE_ON_SUSPENSION:BOOL¶ Enable thread stack back trace being captured on suspension (default: OFF)
-
HPX_WITH_THREAD_CREATION_AND_CLEANUP_RATES:BOOL¶ Enable measuring thread creation and cleanup times (default: OFF)
-
HPX_WITH_THREAD_CUMULATIVE_COUNTS:BOOL¶ Enable keeping track of cumulative thread counts in the schedulers (default: ON)
-
HPX_WITH_THREAD_IDLE_RATES:BOOL¶ Enable measuring the percentage of overhead times spent in the scheduler (default: OFF)
-
HPX_WITH_THREAD_LOCAL_STORAGE:BOOL¶ Enable thread local storage for all HPX threads (default: OFF)
-
HPX_WITH_THREAD_MANAGER_IDLE_BACKOFF:BOOL¶ HPX scheduler threads do exponential backoff on idle queues (default: ON)
-
HPX_WITH_THREAD_QUEUE_WAITTIME:BOOL¶ Enable collecting queue wait times for threads (default: OFF)
-
HPX_WITH_THREAD_STACK_MMAP:BOOL¶ Use mmap for stack allocation on appropriate platforms
-
HPX_WITH_THREAD_STEALING_COUNTS:BOOL¶ Enable keeping track of counts of thread stealing incidents in the schedulers (default: OFF)
-
HPX_WITH_THREAD_TARGET_ADDRESS:BOOL¶ Enable storing target address in thread for NUMA awareness (default: OFF)
-
HPX_WITH_TIMER_POOL:BOOL¶ Disable internal timer thread pool, do not change if not absolutely necessary (default: ON)
AGAS options¶
-
HPX_WITH_AGAS_DUMP_REFCNT_ENTRIES:BOOL¶ Enable dumps of the AGAS refcnt tables to logs (default: OFF)
Parcelport options¶
-
HPX_WITH_NETWORKING:BOOL¶ Enable support for networking and multi-node runs (default: ON)
-
HPX_WITH_PARCELPORT_ACTION_COUNTERS:BOOL¶ Enable performance counters reporting parcelport statistics on a per-action basis.
-
HPX_WITH_PARCELPORT_LIBFABRIC:BOOL¶ Enable the libfabric based parcelport. This is currently an experimental feature
-
HPX_WITH_PARCELPORT_MPI:BOOL¶ Enable the MPI based parcelport.
-
HPX_WITH_PARCELPORT_TCP:BOOL¶ Enable the TCP based parcelport.
-
HPX_WITH_PARCEL_PROFILING:BOOL¶ Enable profiling data for parcels
Profiling options¶
-
HPX_WITH_APEX:BOOL¶ Enable APEX instrumentation support.
-
HPX_WITH_GOOGLE_PERFTOOLS:BOOL¶ Enable Google Perftools instrumentation support.
-
HPX_WITH_ITTNOTIFY:BOOL¶ Enable Amplifier (ITT) instrumentation support.
-
HPX_WITH_PAPI:BOOL¶ Enable the PAPI based performance counter.
Debugging options¶
-
HPX_WITH_ATTACH_DEBUGGER_ON_TEST_FAILURE:BOOL¶ Break the debugger if a test has failed (default: OFF)
-
HPX_WITH_PARALLEL_TESTS_BIND_NONE:BOOL¶ Pass –hpx:bind=none to tests that may run in parallel (cmake -j flag) (default: OFF)
-
HPX_WITH_SANITIZERS:BOOL¶ Configure with sanitizer instrumentation support.
-
HPX_WITH_TESTS_DEBUG_LOG:BOOL¶ Turn on debug logs (–hpx:debug-hpx-log) for tests (default: OFF)
-
HPX_WITH_TESTS_DEBUG_LOG_DESTINATION:STRING¶ Destination for test debug logs (default: cout)
-
HPX_WITH_TESTS_MAX_THREADS_PER_LOCALITY:STRING¶ Maximum number of threads to use for tests (default: 0, use the number of threads specified by the test)
-
HPX_WITH_THREAD_DEBUG_INFO:BOOL¶ Enable thread debugging information (default: OFF, implicitly enabled in debug builds)
-
HPX_WITH_THREAD_DESCRIPTION_FULL:BOOL¶ Use function address for thread description (default: OFF)
-
HPX_WITH_THREAD_GUARD_PAGE:BOOL¶ Enable thread guard page (default: ON)
-
HPX_WITH_VALGRIND:BOOL¶ Enable Valgrind instrumentation support.
-
HPX_WITH_VERIFY_LOCKS:BOOL¶ Enable lock verification code (default: OFF, implicitly enabled in debug builds)
-
HPX_WITH_VERIFY_LOCKS_BACKTRACE:BOOL¶ Enable thread stack back trace being captured on lock registration (to be used in combination with HPX_WITH_VERIFY_LOCKS=ON, default: OFF)
-
HPX_WITH_VERIFY_LOCKS_GLOBALLY:BOOL¶ Enable global lock verification code (default: OFF, implicitly enabled in debug builds)
Modules options¶
HPX_ITERATOR_SUPPORT_WITH_BOOST_ITERATOR_TRAVERSAL_TAG_COMPATIBILITY:BOOLHPX_SERIALIZATION_WITH_ALL_TYPES_ARE_BITWISE_SERIALIZABLE:BOOL
-
HPX_DATASTRUCTURES_WITH_ADAPT_STD_TUPLE:BOOL¶ Enable compatibility of hpx::tuple with std::tuple. (default: ON)
-
HPX_FILESYSTEM_WITH_BOOST_FILESYSTEM_COMPATIBILITY:BOOL¶ Enable Boost.FileSystem compatibility. (default: ON)
-
HPX_ITERATOR_SUPPORT_WITH_BOOST_ITERATOR_TRAVERSAL_TAG_COMPATIBILITY:BOOL¶ Enable Boost.Iterator traversal tag compatibility. (default: OFF)
-
HPX_SERIALIZATION_WITH_ALL_TYPES_ARE_BITWISE_SERIALIZABLE:BOOL¶ Assume all types are bitwise serializable. (default: OFF)
-
HPX_SERIALIZATION_WITH_BOOST_TYPES:BOOL¶ Enable serialization of certain Boost types. (default: ON)
-
HPX_TOPOLOGY_WITH_ADDITIONAL_HWLOC_TESTING:BOOL¶ Enable HWLOC filtering that makes it report no cores, this is purely an
option supporting better testing - do not enable under normal circumstances. (default: OFF)
Additional tools and libraries used by HPX¶
Here is a list of additional libraries and tools that are either optionally supported by the build system or are optionally required for certain examples or tests. These libraries and tools can be detected by the HPX build system.
Each of the tools or libraries listed here will be automatically detected if
they are installed in some standard location. If a tool or library is installed
in a different location, you can specify its base directory by appending
_ROOT to the variable name as listed below. For instance, to configure a
custom directory for BOOST, specify BOOST_ROOT=/custom/boost/root.
-
BOOST_ROOT:PATH¶ Specifies where to look for the Boost installation to be used for compiling HPX. Set this if CMake is not able to locate a suitable version of Boost. The directory specified here can be either the root of an installed Boost distribution or the directory where you unpacked and built Boost without installing it (with staged libraries).
-
HWLOC_ROOT:PATH¶ Specifies where to look for the hwloc library. Set this if CMake is not able to locate a suitable version of hwloc. Hwloc provides platform- independent support for extracting information about the used hardware architecture (number of cores, number of NUMA domains, hyperthreading, etc.). HPX utilizes this information if available.
-
PAPI_ROOT:PATH¶ Specifies where to look for the PAPI library. The PAPI library is needed to compile a special component exposing PAPI hardware events and counters as HPX performance counters. This is not available on the Windows platform.
-
AMPLIFIER_ROOT:PATH¶ Specifies where to look for one of the tools of the Intel Parallel Studio product, either Intel Amplifier or Intel Inspector. This should be set if the CMake variable
HPX_USE_ITT_NOTIFYis set toON. Enabling ITT support in HPX will integrate any application with the mentioned Intel tools, which customizes the generated information for your application and improves the generated diagnostics.
In addition, some of the examples may need the following variables:
-
HDF5_ROOT:PATH¶ Specifies where to look for the Hierarchical Data Format V5 (HDF5) include files and libraries.
Creating HPX projects¶
Using HPX with pkg-config¶
How to build HPX applications with pkg-config¶
After you are done installing HPX, you should be able to build the following
program. It prints Hello World! on the locality you run it on.
// Including 'hpx/hpx_main.hpp' instead of the usual 'hpx/hpx_init.hpp' enables
// to use the plain C-main below as the direct main HPX entry point.
#include <hpx/hpx_main.hpp>
#include <hpx/iostream.hpp>
int main()
{
// Say hello to the world!
hpx::cout << "Hello World!\n" << hpx::flush;
return 0;
}
Copy the text of this program into a file called hello_world.cpp.
Now, in the directory where you put hello_world.cpp, issue the following
commands (where $HPX_LOCATION is the build directory or
CMAKE_INSTALL_PREFIX you used while building HPX):
export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:$HPX_LOCATION/lib/pkgconfig
c++ -o hello_world hello_world.cpp \
`pkg-config --cflags --libs hpx_application`\
-lhpx_iostreams -DHPX_APPLICATION_NAME=hello_world
Important
When using pkg-config with HPX, the pkg-config flags must go after the
-o flag.
Note
HPX libraries have different names in debug and release mode. If you want
to link against a debug HPX library, you need to use the _debug suffix
for the pkg-config name. That means instead of hpx_application or
hpx_component, you will have to use hpx_application_debug or
hpx_component_debug Moreover, all referenced HPX components need to
have an appended d suffix. For example, instead of -lhpx_iostreams you will
need to specify -lhpx_iostreamsd.
Important
If the HPX libraries are in a path that is not found by the dynamic
linker, you will need to add the path $HPX_LOCATION/lib to your linker search
path (for example LD_LIBRARY_PATH on Linux).
To test the program, type:
./hello_world
which should print Hello World! and exit.
How to build HPX components with pkg-config¶
Let’s try a more complex example involving an HPX component. An HPX component is a class that exposes HPX actions. HPX components are compiled into dynamically loaded modules called component libraries. Here’s the source code:
hello_world_component.cpp
#include <hpx/config.hpp>
#if !defined(HPX_COMPUTE_DEVICE_CODE)
#include "hello_world_component.hpp"
#include <hpx/iostream.hpp>
#include <iostream>
namespace examples { namespace server
{
void hello_world::invoke()
{
hpx::cout << "Hello HPX World!" << std::endl;
}
}}
HPX_REGISTER_COMPONENT_MODULE();
typedef hpx::components::component<
examples::server::hello_world
> hello_world_type;
HPX_REGISTER_COMPONENT(hello_world_type, hello_world);
HPX_REGISTER_ACTION(
examples::server::hello_world::invoke_action, hello_world_invoke_action);
#endif
hello_world_component.hpp
#pragma once
#include <hpx/config.hpp>
#if !defined(HPX_COMPUTE_DEVICE_CODE)
#include <hpx/hpx.hpp>
#include <hpx/include/actions.hpp>
#include <hpx/include/lcos.hpp>
#include <hpx/include/components.hpp>
#include <hpx/serialization.hpp>
#include <utility>
namespace examples { namespace server
{
struct HPX_COMPONENT_EXPORT hello_world
: hpx::components::component_base<hello_world>
{
void invoke();
HPX_DEFINE_COMPONENT_ACTION(hello_world, invoke);
};
}}
HPX_REGISTER_ACTION_DECLARATION(
examples::server::hello_world::invoke_action, hello_world_invoke_action);
namespace examples
{
struct hello_world
: hpx::components::client_base<hello_world, server::hello_world>
{
typedef hpx::components::client_base<hello_world, server::hello_world>
base_type;
hello_world(hpx::future<hpx::naming::id_type> && f)
: base_type(std::move(f))
{}
hello_world(hpx::naming::id_type && f)
: base_type(std::move(f))
{}
void invoke()
{
hpx::async<server::hello_world::invoke_action>(this->get_id()).get();
}
};
}
#endif
hello_world_client.cpp
#include <hpx/config.hpp>
#if defined(HPX_COMPUTE_HOST_CODE)
#include <hpx/wrap_main.hpp>
#include "hello_world_component.hpp"
int main()
{
{
// Create a single instance of the component on this locality.
examples::hello_world client =
hpx::new_<examples::hello_world>(hpx::find_here());
// Invoke the component's action, which will print "Hello World!".
client.invoke();
}
return 0;
}
#endif
Copy the three source files above into three files (called
hello_world_component.cpp, hello_world_component.hpp and
hello_world_client.cpp, respectively).
Now, in the directory where you put the files, run the following command to
build the component library. (where $HPX_LOCATION is the build directory or
CMAKE_INSTALL_PREFIX you used while building HPX):
export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:$HPX_LOCATION/lib/pkgconfig
c++ -o libhpx_hello_world.so hello_world_component.cpp \
`pkg-config --cflags --libs hpx_component` \
-lhpx_iostreams -DHPX_COMPONENT_NAME=hpx_hello_world
Now pick a directory in which to install your HPX component libraries. For
this example, we’ll choose a directory named my_hpx_libs:
mkdir ~/my_hpx_libs
mv libhpx_hello_world.so ~/my_hpx_libs
Note
HPX libraries have different names in debug and release mode. If you want
to link against a debug HPX library, you need to use the _debug suffix
for the pkg-config name. That means instead of hpx_application or
hpx_component you will have to use hpx_application_debug or
hpx_component_debug. Moreover, all referenced HPX components need to
have a appended d suffix, e.g. instead of -lhpx_iostreams you will
need to specify -lhpx_iostreamsd.
Important
If the HPX libraries are in a path that is not found by the dynamic linker.
You need to add the path $HPX_LOCATION/lib to your linker search path
(for example LD_LIBRARY_PATH on Linux).
Now, to build the application that uses this component (hello_world_client.cpp),
we do:
export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:$HPX_LOCATION/lib/pkgconfig
c++ -o hello_world_client hello_world_client.cpp \
``pkg-config --cflags --libs hpx_application``\
-L${HOME}/my_hpx_libs -lhpx_hello_world -lhpx_iostreams
Important
When using pkg-config with HPX, the pkg-config flags must go after the
-o flag.
Finally, you’ll need to set your LD_LIBRARY_PATH before you can run the program. To run the program, type:
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$HOME/my_hpx_libs"
./hello_world_client
which should print Hello HPX World! and exit.
Using HPX with CMake-based projects¶
In addition to the pkg-config support discussed on the previous pages, HPX comes with full CMake support. In order to integrate HPX into existing or new CMakeLists.txt, you can leverage the find_package command integrated into CMake. Following, is a Hello World component example using CMake.
Let’s revisit what we have. We have three files that compose our example application:
hello_world_component.hpphello_world_component.cpphello_world_client.hpp
The basic structure to include HPX into your CMakeLists.txt is shown here:
# Require a recent version of cmake
cmake_minimum_required(VERSION 3.17 FATAL_ERROR)
# This project is C++ based.
project(your_app CXX)
# Instruct cmake to find the HPX settings
find_package(HPX)
In order to have CMake find HPX, it needs to be told where to look for the
HPXConfig.cmake file that is generated when HPX is built or installed. It is
used by find_package(HPX) to set up all the necessary macros needed to use
HPX in your project. The ways to achieve this are:
Set the
HPX_DIRCMake variable to point to the directory containing theHPXConfig.cmakescript on the command line when you invoke CMake:cmake -DHPX_DIR=$HPX_LOCATION/lib/cmake/HPX ...
where
$HPX_LOCATIONis the build directory orCMAKE_INSTALL_PREFIXyou used when building/configuring HPX.Set the
CMAKE_PREFIX_PATHvariable to the root directory of your HPX build or install location on the command line when you invoke CMake:cmake -DCMAKE_PREFIX_PATH=$HPX_LOCATION ...
The difference between
CMAKE_PREFIX_PATHandHPX_DIRis that CMake will add common postfixes, such aslib/cmake/<project, to theCMAKE_PREFIX_PATHand search in these locations too. Note that if your project uses HPX as well as other CMake-managed projects, the paths to the locations of these multiple projects may be concatenated in theCMAKE_PREFIX_PATH.The variables above may be set in the CMake GUI or curses ccmake interface instead of the command line.
Additionally, if you wish to require HPX for your project, replace the
find_package(HPX) line with find_package(HPX REQUIRED).
You can check if HPX was successfully found with the HPX_FOUND CMake variable.
Using CMake targets¶
The recommended way of setting up your targets to use HPX is to link to the
HPX::hpx CMake target:
target_link_libraries(hello_world_component PUBLIC HPX::hpx)
This requires that you have already created the target like this:
add_library(hello_world_component SHARED hello_world_component.cpp)
target_include_directories(hello_world_component PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
When you link your library to the HPX::hpx CMake target, you will be able
use HPX functionality in your library. To use main() as the implicit entry
point in your application you must additionally link your application to the
CMake target HPX::wrap_main. This target is automatically linked to
executables if you are using the macros described below
(Using macros to create new targets). See Re-use the main() function as the main HPX entry point for more information on
implicitly using main() as the entry point.
Creating a component requires setting two additional compile definitions:
target_compile_options(hello_world_component
HPX_COMPONENT_NAME=hello_world
HPX_COMPONENT_EXPORTS)
Instead of setting these definitions manually you may link to the
HPX::component target, which sets HPX_COMPONENT_NAME to
hpx_<target_name>, where <target_name> is the target name of your
library. Note that these definitions should be PRIVATE to make sure these
definitions are not propagated transitively to dependent targets.
In addition to making your library a component you can make it a plugin. To do
so link to the HPX::plugin target. Similarly to HPX::component this will
set HPX_PLUGIN_NAME to hpx_<target_name>. This definition should also be
PRIVATE. Unlike regular shared libraries, plugins are loaded at runtime from
certain directories and will not be found without additional configuration.
Plugins should be installed into a directory containing only plugins. For
example, the plugins created by HPX itself are installed into the hpx
subdirectory in the library install directory (typically lib or lib64).
When using the HPX::plugin target you need to install your plugins into an
appropriate directory. You may also want to set the location of your plugin in
the build directory with the *_OUTPUT_DIRECTORY* CMake target properties to
be able to load the plugins in the build directory. Once you’ve set the install
or output directory of your plugin you need to tell your executable where to
find it at runtime. You can do this either by setting the environment variable
HPX_COMPONENT_PATHS or the ini setting hpx.component_paths (see
--hpx:ini) to the directory containing your plugin.
Using macros to create new targets¶
In addition to the targets described above, HPX provides convenience macros to hide optional boilerplate code that may be useful for your project. The link to the targets described above. We recommend that you use the targets directly whenever possible as they tend to compose better with other targets.
The macro for adding an HPX component is add_hpx_component. It can be
used in your CMakeLists.txt file like this:
# build your application using HPX
add_hpx_component(hello_world
SOURCES hello_world_component.cpp
HEADERS hello_world_component.hpp
COMPONENT_DEPENDENCIES iostreams)
Note
add_hpx_component adds a _component suffix to the target name. In the
example above, a hello_world_component target will be created.
The available options to add_hpx_component are:
SOURCES: The source files for that componentHEADERS: The header files for that componentDEPENDENCIES: Other libraries or targets this component depends onCOMPONENT_DEPENDENCIES: The components this component depends onPLUGIN: Treats this component as a plugin-able libraryCOMPILE_FLAGS: Additional compiler flagsLINK_FLAGS: Additional linker flagsFOLDER: Adds the headers and source files to this Source Group folder
EXCLUDE_FROM_ALL: Do not build this component as part of thealltarget
After adding the component, the way you add the executable is as follows:
# build your application using HPX
add_hpx_executable(hello_world
SOURCES hello_world_client.cpp
COMPONENT_DEPENDENCIES hello_world)
Note
add_hpx_executable automatically adds a _component suffix to dependencies
specified in COMPONENT_DEPENDENCIES, meaning you can directly use the name given
when adding a component using add_hpx_component.
When you configure your application, all you need to do is set the HPX_DIR
variable to point to the installation of HPX.
Note
All library targets built with HPX are exported and readily available to be
used as arguments to target_link_libraries
in your targets. The HPX include directories are available with the
HPX_INCLUDE_DIRS CMake variable.
Using the HPX compiler wrapper hpxcxx¶
The hpxcxx compiler wrapper helps to compile a HPX component, application,
or object file, based on the arguments passed to it.
hpxcxx [--exe=<APPLICATION_NAME> | --comp=<COMPONENT_NAME> | -c] FLAGS FILES
The hpxcxx command requires that either an application or a component is
built or -c flag is specified. If the build is against a debug build, the
-g is to be specified while building.
FLAGS¶-l <LIBRARY> | -l<LIBRARY>: Links<LIBRARY>to the build-g: Specifies that the application or component build is against a debug build-rd: Setsrelease-with-debug-infooption-mr: Setsminsize-releaseoption
All other flags (like -o OUTPUT_FILE) are directly passed to the underlying
C++ compiler.
Using macros to set up existing targets to use HPX¶
In addition to the add_hpx_component and add_hpx_executable, you can use
the hpx_setup_target macro to have an already existing target to be used
with the HPX libraries:
hpx_setup_target(target)
Optional parameters are:
EXPORT: Adds it to the CMake export list HPXTargetsINSTALL: Generates an install rule for the targetPLUGIN: Treats this component as a plugin-able libraryTYPE: The type can be: EXECUTABLE, LIBRARY or COMPONENTDEPENDENCIES: Other libraries or targets this component depends onCOMPONENT_DEPENDENCIES: The components this component depends onCOMPILE_FLAGS: Additional compiler flagsLINK_FLAGS: Additional linker flags
If you do not use CMake, you can still build against HPX, but you should refer to the section on How to build HPX components with pkg-config.
Note
Since HPX relies on dynamic libraries, the dynamic linker needs to know
where to look for them. If HPX isn’t installed into a path that is
configured as a linker search path, external projects need to either set
RPATH or adapt LD_LIBRARY_PATH to point to where the HPX libraries
reside. In order to set RPATHs, you can include HPX_SetFullRPATH in
your project after all libraries you want to link against have been added.
Please also consult the CMake documentation here.
Using HPX with Makefile¶
A basic project building with HPX is through creating makefiles. The process
of creating one can get complex depending upon the use of cmake parameter
HPX_WITH_HPX_MAIN (which defaults to ON).
How to build HPX applications with makefile¶
If HPX is installed correctly, you should be able to build and run a simple
Hello World program. It prints Hello World! on the locality you
run it on.
// Including 'hpx/hpx_main.hpp' instead of the usual 'hpx/hpx_init.hpp' enables
// to use the plain C-main below as the direct main HPX entry point.
#include <hpx/hpx_main.hpp>
#include <hpx/iostream.hpp>
int main()
{
// Say hello to the world!
hpx::cout << "Hello World!\n" << hpx::flush;
return 0;
}
Copy the content of this program into a file called hello_world.cpp.
Now, in the directory where you put hello_world.cpp, create a Makefile. Add the following code:
CXX=(CXX) # Add your favourite compiler here or let makefile choose default.
CXXFLAGS=-O3 -std=c++17
BOOST_ROOT=/path/to/boost
HWLOC_ROOT=/path/to/hwloc
TCMALLOC_ROOT=/path/to/tcmalloc
HPX_ROOT=/path/to/hpx
INCLUDE_DIRECTIVES=$(HPX_ROOT)/include $(BOOST_ROOT)/include $(HWLOC_ROOT)/include
LIBRARY_DIRECTIVES=-L$(HPX_ROOT)/lib $(HPX_ROOT)/lib/libhpx_init.a $(HPX_ROOT)/lib/libhpx.so $(BOOST_ROOT)/lib/libboost_atomic-mt.so $(BOOST_ROOT)/lib/libboost_filesystem-mt.so $(BOOST_ROOT)/lib/libboost_program_options-mt.so $(BOOST_ROOT)/lib/libboost_regex-mt.so $(BOOST_ROOT)/lib/libboost_system-mt.so -lpthread $(TCMALLOC_ROOT)/libtcmalloc_minimal.so $(HWLOC_ROOT)/libhwloc.so -ldl -lrt
LINK_FLAGS=$(HPX_ROOT)/lib/libhpx_wrap.a -Wl,-wrap=main # should be left empty for HPX_WITH_HPX_MAIN=OFF
hello_world: hello_world.o
$(CXX) $(CXXFLAGS) -o hello_world hello_world.o $(LIBRARY_DIRECTIVES) $(LINK_FLAGS)
hello_world.o:
$(CXX) $(CXXFLAGS) -c -o hello_world.o hello_world.cpp $(INCLUDE_DIRECTIVES)
Important
LINK_FLAGS should be left empty if HPX_WITH_HPX_MAIN is set to OFF.
Boost in the above example is build with --layout=tagged. Actual Boost
flags may vary on your build of Boost.
To build the program, type:
make
A successful build should result in hello_world binary. To test, type:
./hello_world
How to build HPX components with makefile¶
Let’s try a more complex example involving an HPX component. An HPX component is a class that exposes HPX actions. HPX components are compiled into dynamically-loaded modules called component libraries. Here’s the source code:
hello_world_component.cpp
#include <hpx/config.hpp>
#if !defined(HPX_COMPUTE_DEVICE_CODE)
#include "hello_world_component.hpp"
#include <hpx/iostream.hpp>
#include <iostream>
namespace examples { namespace server
{
void hello_world::invoke()
{
hpx::cout << "Hello HPX World!" << std::endl;
}
}}
HPX_REGISTER_COMPONENT_MODULE();
typedef hpx::components::component<
examples::server::hello_world
> hello_world_type;
HPX_REGISTER_COMPONENT(hello_world_type, hello_world);
HPX_REGISTER_ACTION(
examples::server::hello_world::invoke_action, hello_world_invoke_action);
#endif
hello_world_component.hpp
#pragma once
#include <hpx/config.hpp>
#if !defined(HPX_COMPUTE_DEVICE_CODE)
#include <hpx/hpx.hpp>
#include <hpx/include/actions.hpp>
#include <hpx/include/lcos.hpp>
#include <hpx/include/components.hpp>
#include <hpx/serialization.hpp>
#include <utility>
namespace examples { namespace server
{
struct HPX_COMPONENT_EXPORT hello_world
: hpx::components::component_base<hello_world>
{
void invoke();
HPX_DEFINE_COMPONENT_ACTION(hello_world, invoke);
};
}}
HPX_REGISTER_ACTION_DECLARATION(
examples::server::hello_world::invoke_action, hello_world_invoke_action);
namespace examples
{
struct hello_world
: hpx::components::client_base<hello_world, server::hello_world>
{
typedef hpx::components::client_base<hello_world, server::hello_world>
base_type;
hello_world(hpx::future<hpx::naming::id_type> && f)
: base_type(std::move(f))
{}
hello_world(hpx::naming::id_type && f)
: base_type(std::move(f))
{}
void invoke()
{
hpx::async<server::hello_world::invoke_action>(this->get_id()).get();
}
};
}
#endif
hello_world_client.cpp
#include <hpx/config.hpp>
#if defined(HPX_COMPUTE_HOST_CODE)
#include <hpx/wrap_main.hpp>
#include "hello_world_component.hpp"
int main()
{
{
// Create a single instance of the component on this locality.
examples::hello_world client =
hpx::new_<examples::hello_world>(hpx::find_here());
// Invoke the component's action, which will print "Hello World!".
client.invoke();
}
return 0;
}
#endif
Now, in the directory, create a Makefile. Add the following code:
CXX=(CXX) # Add your favourite compiler here or let makefile choose default.
CXXFLAGS=-O3 -std=c++17
BOOST_ROOT=/path/to/boost
HWLOC_ROOT=/path/to/hwloc
TCMALLOC_ROOT=/path/to/tcmalloc
HPX_ROOT=/path/to/hpx
INCLUDE_DIRECTIVES=$(HPX_ROOT)/include $(BOOST_ROOT)/include $(HWLOC_ROOT)/include
LIBRARY_DIRECTIVES=-L$(HPX_ROOT)/lib $(HPX_ROOT)/lib/libhpx_init.a $(HPX_ROOT)/lib/libhpx.so $(BOOST_ROOT)/lib/libboost_atomic-mt.so $(BOOST_ROOT)/lib/libboost_filesystem-mt.so $(BOOST_ROOT)/lib/libboost_program_options-mt.so $(BOOST_ROOT)/lib/libboost_regex-mt.so $(BOOST_ROOT)/lib/libboost_system-mt.so -lpthread $(TCMALLOC_ROOT)/libtcmalloc_minimal.so $(HWLOC_ROOT)/libhwloc.so -ldl -lrt
LINK_FLAGS=$(HPX_ROOT)/lib/libhpx_wrap.a -Wl,-wrap=main # should be left empty for HPX_WITH_HPX_MAIN=OFF
hello_world_client: libhpx_hello_world hello_world_client.o
$(CXX) $(CXXFLAGS) -o hello_world_client $(LIBRARY_DIRECTIVES) libhpx_hello_world $(LINK_FLAGS)
hello_world_client.o: hello_world_client.cpp
$(CXX) $(CXXFLAGS) -o hello_world_client.o hello_world_client.cpp $(INCLUDE_DIRECTIVES)
libhpx_hello_world: hello_world_component.o
$(CXX) $(CXXFLAGS) -o libhpx_hello_world hello_world_component.o $(LIBRARY_DIRECTIVES)
hello_world_component.o: hello_world_component.cpp
$(CXX) $(CXXFLAGS) -c -o hello_world_component.o hello_world_component.cpp $(INCLUDE_DIRECTIVES)
To build the program, type:
make
A successful build should result in hello_world binary. To test, type:
./hello_world
Note
Due to high variations in CMake flags and library dependencies, it is recommended to build HPX applications and components with pkg-config or CMakeLists.txt. Writing Makefile may result in broken builds if due care is not taken. pkg-config files and CMake systems are configured with CMake build of HPX. Hence, they are stable when used together and provide better support overall.
Starting the HPX runtime¶
In order to write an application which uses services from the HPX runtime system you need to initialize the HPX library by inserting certain calls into the code of your application. Depending on your use case, this can be done in 3 different ways:
Minimally invasive: Re-use the
main()function as the main HPX entry point.Balanced use case: Supply your own main HPX entry point while blocking the main thread.
Most flexibility: Supply your own main HPX entry point while avoiding to block the main thread.
Suspend and resume: As above but suspend and resume the HPX runtime to allow for other runtimes to be used.
Re-use the main() function as the main HPX entry point¶
This method is the least intrusive to your code. It however provides you with the smallest flexibility in terms of initializing the HPX runtime system. The following code snippet shows what a minimal HPX application using this technique looks like:
#include <hpx/hpx_main.hpp>
int main(int argc, char* argv[])
{
return 0;
}
The only change to your code you have to make is to include the file
hpx/hpx_main.hpp. In this case the function main() will be invoked as
the first HPX thread of the application. The runtime system will be
initialized behind the scenes before the function main() is executed and
will automatically stop after main() has returned. For this method to work
you must link your application to the CMake target HPX::wrap_main. This is
done automatically if you are using the provided macros
(Using macros to create new targets) to set up your application, but must be done
explicitly if you are using targets directly (Using CMake targets).
All HPX API functions can be used from within the main() function now.
Note
The function main() does not need to expect receiving argc and
argv as shown above, but could expose the signature int main(). This
is consistent with the usually allowed prototypes for the function main()
in C++ applications.
All command line arguments specific to HPX will still be processed by the
HPX runtime system as usual. However, those command line options will be
removed from the list of values passed to argc/argv of the function
main(). The list of values passed to main() will hold only the
commandline options which are not recognized by the HPX runtime system (see
the section HPX Command Line Options for more details on what options are recognized
by HPX).
Note
In this mode all one-letter-shortcuts are disabled which are normally
available on the HPX command line (such as -t or -l see
HPX Command Line Options). This is done to minimize any possible interaction
between the command line options recognized by the HPX runtime system and
any command line options defined by the application.
The value returned from the function main() as shown above will be returned
to the operating system as usual.
Important
To achieve this seamless integration, the header file hpx/hpx_main.hpp
defines a macro:
#define main hpx_startup::user_main
which could result in unexpected behavior.
Important
To achieve this seamless integration, we use different implementations for
different operating systems. In case of Linux or macOS, the code present in
hpx_wrap.cpp is put into action. We hook into the system function in case
of Linux and provide alternate entry point in case of macOS. For other
operating systems we rely on a macro:
#define main hpx_startup::user_main
provided in the header file hpx/hpx_main.hpp. This implementation can
result in unexpected behavior.
Caution
We make use of an override variable include_libhpx_wrap in the header
file hpx/hpx_main.hpp to swiftly choose the function call stack at
runtime. Therefore, the header file should only be included in the main
executable. Including it in the components will result in multiple definition
of the variable.
Supply your own main HPX entry point while blocking the main thread¶
With this method you need to provide an explicit main thread function named
hpx_main at global scope. This function will be invoked as the main entry
point of your HPX application on the console locality only (this
function will be invoked as the first HPX thread of your application). All
HPX API functions can be used from within this function.
The thread executing the function hpx::init will block waiting for
the runtime system to exit. The value returned from hpx_main will be
returned from hpx::init after the runtime system has stopped.
The function hpx::finalize has to be called on one of the HPX
localities in order to signal that all work has been scheduled and the runtime
system should be stopped after the scheduled work has been executed.
This method of invoking HPX has the advantage of you being able to decide
which version of hpx::init to call. This allows to pass
additional configuration parameters while initializing the HPX runtime system.
#include <hpx/hpx_init.hpp>
int hpx_main(int argc, char* argv[])
{
// Any HPX application logic goes here...
return hpx::finalize();
}
int main(int argc, char* argv[])
{
// Initialize HPX, run hpx_main as the first HPX thread, and
// wait for hpx::finalize being called.
return hpx::init(argc, argv);
}
Note
The function hpx_main does not need to expect receiving argc/argv
as shown above, but could expose one of the following signatures:
int hpx_main();
int hpx_main(int argc, char* argv[]);
int hpx_main(hpx::program_options::variables_map& vm);
This is consistent with (and extends) the usually allowed prototypes for the
function main() in C++ applications.
The header file to include for this method of using HPX is
hpx/hpx_init.hpp.
There are many additional overloads of hpx::init available, such as
for instance to provide your own entry point function instead of hpx_main.
Please refer to the function documentation for more details (see: hpx/hpx_init.hpp).
Supply your own main HPX entry point while avoiding to block the main thread¶
With this method you need to provide an explicit main thread function named
hpx_main at global scope. This function will be invoked as the main entry
point of your HPX application on the console locality only (this
function will be invoked as the first HPX thread of your application). All
HPX API functions can be used from within this function.
The thread executing the function hpx::start will not block
waiting for the runtime system to exit, but will return immediately.
The function hpx::finalize has to be called on one of the HPX
localities in order to signal that all work has been scheduled and the runtime
system should be stopped after the scheduled work has been executed.
This method of invoking HPX is useful for applications where the main thread
is used for special operations, such a GUIs. The function hpx::stop
can be used to wait for the HPX runtime system to exit and should be at least
used as the last function called in main(). The value returned from
hpx_main will be returned from hpx::stop after the runtime
system has stopped.
#include <hpx/hpx_start.hpp>
int hpx_main(int argc, char* argv[])
{
// Any HPX application logic goes here...
return hpx::finalize();
}
int main(int argc, char* argv[])
{
// Initialize HPX, run hpx_main.
hpx::start(argc, argv);
// ...Execute other code here...
// Wait for hpx::finalize being called.
return hpx::stop();
}
Note
The function hpx_main does not need to expect receiving argc/argv
as shown above, but could expose one of the following signatures:
int hpx_main();
int hpx_main(int argc, char* argv[]);
int hpx_main(hpx::program_options::variables_map& vm);
This is consistent with (and extends) the usually allowed prototypes for the
function main() in C++ applications.
The header file to include for this method of using HPX is
hpx/hpx_start.hpp.
There are many additional overloads of hpx::start available, such as
for instance to provide your own entry point function instead of hpx_main.
Please refer to the function documentation for more details (see:
hpx/hpx_start.hpp).
Suspending and resuming the HPX runtime¶
In some applications it is required to combine HPX with other runtimes. To
support this use case HPX provides two functions: hpx::suspend and
hpx::resume. hpx::suspend is a blocking call which will
wait for all scheduled tasks to finish executing and then put the thread pool OS
threads to sleep. hpx::resume simply wakes up the sleeping threads
so that they are ready to accept new work. hpx::suspend and
hpx::resume can be found in the header hpx/hpx_suspend.hpp.
#include <hpx/hpx_start.hpp>
#include <hpx/hpx_suspend.hpp>
int main(int argc, char* argv[])
{
// Initialize HPX, don't run hpx_main
hpx::start(nullptr, argc, argv);
// Schedule a function on the HPX runtime
hpx::apply(&my_function, ...);
// Wait for all tasks to finish, and suspend the HPX runtime
hpx::suspend();
// Execute non-HPX code here
// Resume the HPX runtime
hpx::resume();
// Schedule more work on the HPX runtime
// hpx::finalize has to be called from the HPX runtime before hpx::stop
hpx::apply([]() { hpx::finalize(); });
return hpx::stop();
}
Note
hpx::suspend does not wait for hpx::finalize to be
called. Only call hpx::finalize when you wish to fully stop the
HPX runtime.
Warning
hpx::suspendonly waits for local tasks, i.e. tasks on thecurrent locality, to finish executing. When using
hpx::suspendin a multi-locality scenario the user is responsible for ensuring that any work required from other localities has also finished.
HPX also supports suspending individual thread pools and threads. For details
on how to do that see the documentation for hpx::threads::thread_pool_base.
Automatically suspending worker threads¶
The previous method guarantees that the worker threads are suspended when you ask for it and that they stay suspended. An alternative way to achieve the same effect is to tweak how quickly HPX suspends its worker threads when they run out of work. The following configuration values make sure that HPX idles very quickly:
hpx.max_idle_backoff_time = 1000
hpx.max_idle_loop_count = 0
They can be set on the command line using
--hpx:ini=hpx.max_idle_backoff_time=1000 and
--hpx:ini=hpx.max_idle_loop_count=0. See Launching and configuring HPX applications
for more details on how to set configuration parameters.
After setting idling parameters the previous example could now be written like this instead:
#include <hpx/hpx_start.hpp>
int main(int argc, char* argv[])
{
// Initialize HPX, don't run hpx_main
hpx::start(nullptr, argc, argv);
// Schedule some functions on the HPX runtime
// NOTE: run_as_hpx_thread blocks until completion.
hpx::run_as_hpx_thread(&my_function, ...);
hpx::run_as_hpx_thread(&my_other_function, ...);
// hpx::finalize has to be called from the HPX runtime before hpx::stop
hpx::apply([]() { hpx::finalize(); });
return hpx::stop();
}
In this example each call to hpx::run_as_hpx_thread acts as a
“parallel region”.
Working of hpx_main.hpp¶
In order to initialize HPX from main(), we make use of linker tricks.
It is implemented differently for different Operating Systems. Method of implementation is as follows:
Linux: Using linker
--wrapoption.Mac OSX: Using the linker
-eoption.Windows: Using
#define main hpx_startup::user_main
Linux implementation¶
We make use of the Linux linker ld‘s --wrap option to wrap the
main() function. This way any call to main() are redirected to our own
implementation of main. It is here that we check for the existence of
hpx_main.hpp by making use of a shadow variable include_libhpx_wrap. The
value of this variable determines the function stack at runtime.
The implementation can be found in libhpx_wrap.a.
Important
It is necessary that hpx_main.hpp be not included more than once.
Multiple inclusions can result in multiple definition of
include_libhpx_wrap.
Mac OSX implementation¶
Here we make use of yet another linker option -e to change the entry point
to our custom entry function initialize_main. We initialize the HPX
runtime system from this function and call main from the initialized system. We
determine the function stack at runtime by making use of the shadow variable
include_libhpx_wrap.
The implementation can be found in libhpx_wrap.a.
Important
It is necessary that hpx_main.hpp be not included more than once.
Multiple inclusions can result in multiple definition of
include_libhpx_wrap.
Windows implementation¶
We make use of a macro #define main hpx_startup::user_main to take care of
the initializations.
This implementation could result in unexpected behaviors.
Launching and configuring HPX applications¶
Configuring HPX applications¶
All HPX applications can be configured using special command line options and/or using special configuration files. This section describes the available options, the configuration file format, and the algorithm used to locate possible predefined configuration files. Additionally this section describes the defaults assumed if no external configuration information is supplied.
During startup any HPX application applies a predefined search pattern to locate one or more configuration files. All found files will be read and merged in the sequence they are found into one single internal database holding all configuration properties. This database is used during the execution of the application to configure different aspects of the runtime system.
In addition to the ini files, any application can supply its own configuration
files, which will be merged with the configuration database as well. Moreover,
the user can specify additional configuration parameters on the command line
when executing an application. The HPX runtime system will merge all command
line configuration options (see the description of the --hpx:ini,
--hpx:config, and --hpx:app-config command line options).
The HPX INI File Format¶
All HPX applications can be configured using a special file format which is
similar to the well-known Windows INI file format. This is a structured text format
allowing to group key/value pairs (properties) into sections. The basic element
contained in an ini file is the property. Every property has a name and a
value, delimited by an equals sign '='. The name appears to the left of the
equals sign:
name=value
The value may contain equal signs as only the first '=' character
is interpreted as the delimiter between name and value Whitespace before
the name, after the value and immediately before and after the delimiting equal
sign is ignored. Whitespace inside the value is retained.
Properties may be grouped into arbitrarily named sections. The section name
appears on a line by itself, in square brackets [ and ]. All properties
after the section declaration are associated with that section. There is no
explicit “end of section” delimiter; sections end at the next section
declaration, or the end of the file:
[section]
In HPX sections can be nested. A nested section has a name composed of
all section names it is embedded in. The section names are concatenated using
a dot '.':
[outer_section.inner_section]
Here inner_section is logically nested within outer_section.
It is possible to use the full section name concatenated with the property name to refer to a particular property. For example in:
[a.b.c]
d = e
the property value of d can be referred to as a.b.c.d=e.
In HPX ini files can contain comments. Hash signs '#' at the beginning
of a line indicate a comment. All characters starting with the '#' until the
end of line are ignored.
If a property with the same name is reused inside a section, the second occurrence of this property name will override the first occurrence (discard the first value). Duplicate sections simply merge their properties together, as if they occurred contiguously.
In HPX ini files, a property value ${FOO:default} will use the environmental
variable FOO to extract the actual value if it is set and default otherwise.
No default has to be specified. Therefore ${FOO} refers to the environmental
variable FOO. If FOO is not set or empty the overall expression will evaluate
to an empty string. A property value $[section.key:default] refers to the value
held by the property section.key if it exists and default otherwise. No
default has to be specified. Therefore $[section.key] refers to the property
section.key. If the property section.key is not set or empty, the overall
expression will evaluate to an empty string.
Note
Any property $[section.key:default] is evaluated whenever it is queried
and not when the configuration data is initialized. This allows for lazy
evaluation and relaxes initialization order of different sections. The only
exception are recursive property values, e.g. values referring to the very
key they are associated with. Those property values are evaluated at
initialization time to avoid infinite recursion.
Built-in Default Configuration Settings¶
During startup any HPX application applies a predefined search pattern to locate one or more configuration files. All found files will be read and merged in the sequence they are found into one single internal data structure holding all configuration properties.
As a first step the internal configuration database is filled with a set of default configuration properties. Those settings are described on a section by section basis below.
Note
You can print the default configuration settings used for an executable
by specifying the command line option --hpx:dump-config.
system configuration section¶[system]
pid = <process-id>
prefix = <current prefix path of core HPX library>
executable = <current prefix path of executable>
Property |
Description |
|
This is initialized to store the current OS-process id of the application instance. |
|
This is initialized to the base directory HPX has been loaded from. |
|
This is initialized to the base directory the current executable has been loaded from. |
hpx configuration section¶[hpx]
location = ${HPX_LOCATION:$[system.prefix]}
component_path = $[hpx.location]/lib/hpx:$[system.executable_prefix]/lib/hpx:$[system.executable_prefix]/../lib/hpx
master_ini_path = $[hpx.location]/share/hpx-<version>:$[system.executable_prefix]/share/hpx-<version>:$[system.executable_prefix]/../share/hpx-<version>
ini_path = $[hpx.master_ini_path]/ini
os_threads = 1
localities = 1
program_name =
cmd_line =
lock_detection = ${HPX_LOCK_DETECTION:0}
throw_on_held_lock = ${HPX_THROW_ON_HELD_LOCK:1}
minimal_deadlock_detection = <debug>
spinlock_deadlock_detection = <debug>
spinlock_deadlock_detection_limit = ${HPX_SPINLOCK_DEADLOCK_DETECTION_LIMIT:1000000}
max_background_threads = ${HPX_MAX_BACKGROUND_THREADS:$[hpx.os_threads]}
max_idle_loop_count = ${HPX_MAX_IDLE_LOOP_COUNT:<hpx_idle_loop_count_max>}
max_busy_loop_count = ${HPX_MAX_BUSY_LOOP_COUNT:<hpx_busy_loop_count_max>}
max_idle_backoff_time = ${HPX_MAX_IDLE_BACKOFF_TIME:<hpx_idle_backoff_time_max>}
exception_verbosity = ${HPX_EXCEPTION_VERBOSITY:2}
[hpx.stacks]
small_size = ${HPX_SMALL_STACK_SIZE:<hpx_small_stack_size>}
medium_size = ${HPX_MEDIUM_STACK_SIZE:<hpx_medium_stack_size>}
large_size = ${HPX_LARGE_STACK_SIZE:<hpx_large_stack_size>}
huge_size = ${HPX_HUGE_STACK_SIZE:<hpx_huge_stack_size>}
use_guard_pages = ${HPX_THREAD_GUARD_PAGE:1}
Property |
Description |
|
This is initialized to the id of the locality this application instance is running on. |
|
Duplicates are discarded.
This property can refer to a list of directories separated by |
|
This is initialized to the list of default paths of the main hpx.ini
configuration files. This property can refer to a list of directories
separated by |
|
This is initialized to the default path where HPX will look for more
ini configuration files. This property can refer to a list of directories
separated by |
|
This setting reflects the number of OS-threads used for running HPX-threads. Defaults to number of detected cores (not hyperthreads/PUs). |
|
This setting reflects the number of localities the application is running
on. Defaults to |
|
This setting reflects the program name of the application instance.
Initialized from the command line |
|
This setting reflects the actual command line used to launch this application instance. |
|
This setting verifies that no locks are being held while a HPX thread
is suspended. This setting is applicable only if
|
|
This setting causes an exception if during lock detection at least one
lock is being held while a HPX thread is suspended. This setting is
applicable only if |
|
This setting enables support for minimal deadlock detection for
HPX-threads. By default this is set to |
|
This setting verifies that spinlocks don’t spin longer than specified
using the |
|
This setting specifies the upper limit of allowed number of spins that
spinlocks are allowed to perform. This setting is applicable only if
|
|
This setting defines the number of threads in the scheduler which are used to execute background work. By default this is the same as the number of cores used for the scheduler. |
|
By default this is defined by the preprocessor constant
|
|
This setting defines the maximum value of the busy-loop counter in the
scheduler. By default this is defined by the preprocessor constant
|
|
This setting defines the maximum time (in milliseconds) for the scheduler
to sleep after being idle for |
|
This setting defines the verbosity of exceptions. Valid values are
integers. A setting of |
|
This is initialized to the small stack size to be used by HPX-threads.
Set by default to the value of the compile time preprocessor constant
|
|
This is initialized to the medium stack size to be used by HPX-threads.
Set by default to the value of the compile time preprocessor constant
|
|
This is initialized to the large stack size to be used by HPX-threads.
Set by default to the value of the compile time preprocessor constant
|
|
This is initialized to the huge stack size to be used by HPX-threads.
Set by default to the value of the compile time preprocessor constant
|
|
This entry controls whether the coroutine library will generate stack
guard pages or not. This entry is applicable on Linux only and only if
the |
hpx.threadpools configuration section¶[hpx.threadpools]
io_pool_size = ${HPX_NUM_IO_POOL_SIZE:2}
parcel_pool_size = ${HPX_NUM_PARCEL_POOL_SIZE:2}
timer_pool_size = ${HPX_NUM_TIMER_POOL_SIZE:2}
Property |
Description |
|
The value of this property defines the number of OS-threads created for the internal I/O thread pool. |
|
The value of this property defines the number of OS-threads created for the internal parcel thread pool. |
|
The value of this property defines the number of OS-threads created for the internal timer thread pool. |
hpx.thread_queue configuration section¶Important
These setting control internal values used by the thread scheduling queues in the HPX scheduler. You should not modify these settings except if you know exactly what you are doing]
[hpx.thread_queue]
min_tasks_to_steal_pending = ${HPX_THREAD_QUEUE_MIN_TASKS_TO_STEAL_PENDING:0}
min_tasks_to_steal_staged = ${HPX_THREAD_QUEUE_MIN_TASKS_TO_STEAL_STAGED:0}
min_add_new_count = ${HPX_THREAD_QUEUE_MIN_ADD_NEW_COUNT:10}
max_add_new_count = ${HPX_THREAD_QUEUE_MAX_ADD_NEW_COUNT:10}
max_delete_count = ${HPX_THREAD_QUEUE_MAX_DELETE_COUNT:1000}
Property |
Description |
|
The value of this property defines the number of pending HPX threads which have to be available before neighboring cores are allowed to steal work. The default is to allow stealing always. |
|
The value of this property defines the number of staged HPX tasks have which to be available before neighboring cores are allowed to steal work. The default is to allow stealing always. |
|
The value of this property defines the minimal number tasks to be converted into HPX threads whenever the thread queues for a core have run empty. |
|
The value of this property defines the maximal number tasks to be converted into HPX threads whenever the thread queues for a core have run empty. |
|
The value of this property defines the number of terminated HPX threads to discard during each invocation of the corresponding function. |
hpx.components configuration section¶[hpx.components]
load_external = ${HPX_LOAD_EXTERNAL_COMPONENTS:1}
Property |
Description |
|
This entry defines whether external components will be loaded on this
locality. This entry normally is set to |
Additionally, the section hpx.components will be populated with the
information gathered from all found components. The information loaded for each
of the components will contain at least the following properties:
[hpx.components.<component_instance_name>]
name = <component_name>
path = <full_path_of_the_component_module>
enabled = $[hpx.components.load_external]
Property |
Description |
|
This is the name of a component, usually the same as the second argument
to the macro used while registering the component with
|
|
This is either the full path file name of the component module or the
directory the component module is located in. In this case, the component
module name will be derived from the property
|
|
This setting explicitly enables or disables the component. This is an optional property, HPX assumed that the component is enabled if it is not defined. |
The value for <component_instance_name> is usually the same as for the
corresponding name property. However generally it can be defined to any
arbitrary instance name. It is used to distinguish between different ini
sections, one for each component.
hpx.parcel configuration section¶[hpx.parcel]
address = ${HPX_PARCEL_SERVER_ADDRESS:<hpx_initial_ip_address>}
port = ${HPX_PARCEL_SERVER_PORT:<hpx_initial_ip_port>}
bootstrap = ${HPX_PARCEL_BOOTSTRAP:<hpx_parcel_bootstrap>}
max_connections = ${HPX_PARCEL_MAX_CONNECTIONS:<hpx_parcel_max_connections>}
max_connections_per_locality = ${HPX_PARCEL_MAX_CONNECTIONS_PER_LOCALITY:<hpx_parcel_max_connections_per_locality>}
max_message_size = ${HPX_PARCEL_MAX_MESSAGE_SIZE:<hpx_parcel_max_message_size>}
max_outbound_message_size = ${HPX_PARCEL_MAX_OUTBOUND_MESSAGE_SIZE:<hpx_parcel_max_outbound_message_size>}
array_optimization = ${HPX_PARCEL_ARRAY_OPTIMIZATION:1}
zero_copy_optimization = ${HPX_PARCEL_ZERO_COPY_OPTIMIZATION:$[hpx.parcel.array_optimization]}
async_serialization = ${HPX_PARCEL_ASYNC_SERIALIZATION:1}
message_handlers = ${HPX_PARCEL_MESSAGE_HANDLERS:0}
Property |
Description |
|
This property defines the default IP address to be used for the parcel
layer to listen to. This IP address will be used as long as no other
values are specified (for instance using the |
|
This property defines the default IP port to be used for the parcel layer
to listen to. This IP port will be used as long as no other values are
specified (for instance using the |
|
This property defines which parcelport type should be used during
application bootstrap. The default depends on the compile time
preprocessor constant |
|
This property defines how many network connections between different
localities are overall kept alive by each of locality. The
default depends on the compile time preprocessor constant
|
|
This property defines the maximum number of network connections that one
locality will open to another locality. The default depends
on the compile time preprocessor constant
|
|
This property defines the maximum allowed message size which will be
transferable through the parcel layer. The default depends on the
compile time preprocessor constant |
|
This property defines the maximum allowed outbound coalesced message size
which will be transferable through the parcel layer. The default depends
on the compile time preprocessor constant
|
|
This property defines whether this locality is allowed to utilize
array optimizations during serialization of parcel data. The default is
|
|
This property defines whether this locality is allowed to utilize
zero copy optimizations during serialization of parcel data. The default
is the same value as set for |
|
This property defines whether this locality is allowed to spawn a
new thread for serialization (this is both for encoding and decoding
parcels). The default is |
|
This property defines whether message handlers are loaded. The default is
|
The following settings relate to the TCP/IP parcelport.
[hpx.parcel.tcp]
enable = ${HPX_HAVE_PARCELPORT_TCP:$[hpx.parcel.enabled]}
array_optimization = ${HPX_PARCEL_TCP_ARRAY_OPTIMIZATION:$[hpx.parcel.array_optimization]}
zero_copy_optimization = ${HPX_PARCEL_TCP_ZERO_COPY_OPTIMIZATION:$[hpx.parcel.zero_copy_optimization]}
async_serialization = ${HPX_PARCEL_TCP_ASYNC_SERIALIZATION:$[hpx.parcel.async_serialization]}
parcel_pool_size = ${HPX_PARCEL_TCP_PARCEL_POOL_SIZE:$[hpx.threadpools.parcel_pool_size]}
max_connections = ${HPX_PARCEL_TCP_MAX_CONNECTIONS:$[hpx.parcel.max_connections]}
max_connections_per_locality = ${HPX_PARCEL_TCP_MAX_CONNECTIONS_PER_LOCALITY:$[hpx.parcel.max_connections_per_locality]}
max_message_size = ${HPX_PARCEL_TCP_MAX_MESSAGE_SIZE:$[hpx.parcel.max_message_size]}
max_outbound_message_size = ${HPX_PARCEL_TCP_MAX_OUTBOUND_MESSAGE_SIZE:$[hpx.parcel.max_outbound_message_size]}
Property |
Description |
|
Enable the use of the default TCP parcelport. Note that the initial bootstrap of the overall HPX application will be performed using the default TCP connections. This parcelport is enabled by default. This will be disabled only if MPI is enabled (see below). |
|
This property defines whether this locality is allowed to utilize
array optimizations in the TCP/IP parcelport during serialization of
parcel data. The default is the same value as set for
|
|
This property defines whether this locality is allowed to utilize
zero copy optimizations in the TCP/IP parcelport during serialization of
parcel data. The default is the same value as set for
|
|
This property defines whether this locality is allowed to spawn a
new thread for serialization in the TCP/IP parcelport (this is both for
encoding and decoding parcels). The default is the same value as set for
|
|
The value of this property defines the number of OS-threads created for
the internal parcel thread pool of the TCP parcel port. The default is
taken from |
|
This property defines how many network connections between different
localities are overall kept alive by each of locality. The
default is taken from |
|
This property defines the maximum number of network connections that one
locality will open to another locality. The default is
taken from |
|
This property defines the maximum allowed message size which will be
transferable through the parcel layer. The default is taken from
|
|
This property defines the maximum allowed outbound coalesced message size
which will be transferable through the parcel layer. The default is
taken from |
The following settings relate to the MPI parcelport. These settings take effect
only if the compile time constant HPX_HAVE_PARCELPORT_MPI is set (the
equivalent cmake variable is HPX_WITH_PARCELPORT_MPI and has to be set to
ON.
[hpx.parcel.mpi]
enable = ${HPX_HAVE_PARCELPORT_MPI:$[hpx.parcel.enabled]}
env = ${HPX_HAVE_PARCELPORT_MPI_ENV:MV2_COMM_WORLD_RANK,PMI_RANK,OMPI_COMM_WORLD_SIZE,ALPS_APP_PE}
multithreaded = ${HPX_HAVE_PARCELPORT_MPI_MULTITHREADED:0}
rank = <MPI_rank>
processor_name = <MPI_processor_name>
array_optimization = ${HPX_HAVE_PARCEL_MPI_ARRAY_OPTIMIZATION:$[hpx.parcel.array_optimization]}
zero_copy_optimization = ${HPX_HAVE_PARCEL_MPI_ZERO_COPY_OPTIMIZATION:$[hpx.parcel.zero_copy_optimization]}
use_io_pool = ${HPX_HAVE_PARCEL_MPI_USE_IO_POOL:$1}
async_serialization = ${HPX_HAVE_PARCEL_MPI_ASYNC_SERIALIZATION:$[hpx.parcel.async_serialization]}
parcel_pool_size = ${HPX_HAVE_PARCEL_MPI_PARCEL_POOL_SIZE:$[hpx.threadpools.parcel_pool_size]}
max_connections = ${HPX_HAVE_PARCEL_MPI_MAX_CONNECTIONS:$[hpx.parcel.max_connections]}
max_connections_per_locality = ${HPX_HAVE_PARCEL_MPI_MAX_CONNECTIONS_PER_LOCALITY:$[hpx.parcel.max_connections_per_locality]}
max_message_size = ${HPX_HAVE_PARCEL_MPI_MAX_MESSAGE_SIZE:$[hpx.parcel.max_message_size]}
max_outbound_message_size = ${HPX_HAVE_PARCEL_MPI_MAX_OUTBOUND_MESSAGE_SIZE:$[hpx.parcel.max_outbound_message_size]}
Property |
Description |
|
Enable the use of the MPI parcelport. HPX tries to detect if the application was started within a parallel MPI environment. If the detection was successful, the MPI parcelport is enabled by default. To explicitly disable the MPI parcelport, set to 0. Note that the initial bootstrap of the overall HPX application will be performed using MPI as well. |
|
This property influences which environment variables (comma separated) will be analyzed to find out whether the application was invoked by MPI. |
|
This property is used to determine what threading mode to use when
initializing MPI. If this setting is |
|
This property will be initialized to the MPI rank of the locality. |
|
This property will be initialized to the MPI processor name of the locality. |
|
This property defines whether this locality is allowed to utilize
array optimizations in the MPI parcelport during serialization of
parcel data. The default is the same value as set for
|
|
This property defines whether this locality is allowed to utilize
zero copy optimizations in the MPI parcelport during serialization of
parcel data. The default is the same value as set for
|
|
This property can be set to run the progress thread inside of HPX threads
instead of a separate thread pool. The default is |
|
This property defines whether this locality is allowed to spawn a
new thread for serialization in the MPI parcelport (this is both for
encoding and decoding parcels). The default is the same value as set for
|
|
The value of this property defines the number of OS-threads created for
the internal parcel thread pool of the MPI parcel port. The default is
taken from |
|
This property defines how many network connections between different
localities are overall kept alive by each of locality. The
default is taken from |
|
This property defines the maximum number of network connections that one
locality will open to another locality. The default is
taken from |
|
This property defines the maximum allowed message size which will be
transferable through the parcel layer. The default is taken from
|
|
This property defines the maximum allowed outbound coalesced message size
which will be transferable through the parcel layer. The default is
taken from |
hpx.agas configuration section¶[hpx.agas]
address = ${HPX_AGAS_SERVER_ADDRESS:<hpx_initial_ip_address>}
port = ${HPX_AGAS_SERVER_PORT:<hpx_initial_ip_port>}
service_mode = hosted
dedicated_server = 0
max_pending_refcnt_requests = ${HPX_AGAS_MAX_PENDING_REFCNT_REQUESTS:<hpx_initial_agas_max_pending_refcnt_requests>}
use_caching = ${HPX_AGAS_USE_CACHING:1}
use_range_caching = ${HPX_AGAS_USE_RANGE_CACHING:1}
local_cache_size = ${HPX_AGAS_LOCAL_CACHE_SIZE:<hpx_agas_local_cache_size>}
Property |
Description |
|
This property defines the default IP address to be used for the
AGAS root server. This IP address will be used as long as no
other values are specified (for instance using the |
|
This property defines the default IP port to be used for the AGAS
root server. This IP port will be used as long as no other values are
specified (for instance using the |
|
This property specifies what type of AGAS service is running on
this locality. Currently, two modes exist. The locality
that acts as the AGAS server runs in |
|
This property specifies whether the AGAS server is exclusively
running AGAS services and not hosting any application components.
It is a boolean value. Set to |
|
This property defines the number of reference counting requests
(increments or decrements) to buffer. The default depends on the compile
time preprocessor constant
|
|
This property specifies whether a software address translation cache is
used. It is a boolean value. Defaults to |
|
This property specifies whether range-based caching is used by the
software address translation cache. This property is ignored if
hpx.agas.use_caching is false. It is a boolean value. Defaults to |
|
This property defines the size of the software address translation cache
for AGAS services. This property is ignored
if |
hpx.commandline configuration section¶The following table lists the definition of all pre-defined command line option shortcuts. For more information about commandline options see the section HPX Command Line Options.
[hpx.commandline]
aliasing = ${HPX_COMMANDLINE_ALIASING:1}
allow_unknown = ${HPX_COMMANDLINE_ALLOW_UNKNOWN:0}
[hpx.commandline.aliases]
-a = --hpx:agas
-c = --hpx:console
-h = --hpx:help
-I = --hpx:ini
-l = --hpx:localities
-p = --hpx:app-config
-q = --hpx:queuing
-r = --hpx:run-agas-server
-t = --hpx:threads
-v = --hpx:version
-w = --hpx:worker
-x = --hpx:hpx
-0 = --hpx:node=0
-1 = --hpx:node=1
-2 = --hpx:node=2
-3 = --hpx:node=3
-4 = --hpx:node=4
-5 = --hpx:node=5
-6 = --hpx:node=6
-7 = --hpx:node=7
-8 = --hpx:node=8
-9 = --hpx:node=9
Property |
Description |
|
Enable command line aliases as defined in the section
|
|
Allow for unknown command line options to be passed through to
|
|
On the commandline, |
|
On the commandline, |
|
On the commandline, |
|
On the commandline, |
|
On the commandline, |
|
On the commandline, |
|
On the commandline, |
|
On the commandline, |
|
On the commandline, |
|
On the commandline, |
|
On the commandline, |
|
On the commandline, |
|
On the commandline, |
|
On the commandline, |
|
On the commandline, |
|
On the commandline, |
|
On the commandline, |
|
On the commandline, |
|
On the commandline, |
|
On the commandline, |
|
On the commandline, |
|
On the commandline, |
|
On the commandline, |
|
On the commandline, |
Loading INI files¶
During startup and after the internal database has been initialized as described in the section Built-in Default Configuration Settings, HPX will try to locate and load additional ini files to be used as a source for configuration properties. This allows for a wide spectrum of additional customization possibilities by the user and system administrators. The sequence of locations where HPX will try loading the ini files is well defined and documented in this section. All ini files found are merged into the internal configuration database. The merge operation itself conforms to the rules as described in the section The HPX INI File Format.
Load all component shared libraries found in the directories specified by the property
hpx.component_pathand retrieve their default configuration information (see section Loading components for more details). This property can refer to a list of directories separated by':'(Linux, Android, and MacOS) or using';'(Windows).Load all files named
hpx.iniin the directories referenced by the propertyhpx.master_ini_pathThis property can refer to a list of directories separated by':'(Linux, Android, and MacOS) or using';'(Windows).Load a file named
.hpx.iniin the current working directory, e.g. the directory the application was invoked from.Load a file referenced by the environment variable
HPX_INI. This variable is expected to provide the full path name of the ini configuration file (if any).Load a file named
/etc/hpx.ini. This lookup is done on non-Windows systems only.Load a file named
.hpx.iniin the home directory of the current user, e.g. the directory referenced by the environment variableHOME.Load a file named
.hpx.iniin the directory referenced by the environment variablePWD.Load the file specified on the command line using the option
--hpx:config.Load all properties specified on the command line using the option
--hpx:ini. The properties will be added to the database in the same sequence as they are specified on the command line. The format for those options is for instance--hpx:ini=hpx.default_stack_size=0x4000. In addition to the explicit command line options, this will set the following properties as implied from other settings:hpx.parcel.addressandhpx.parcel.portas set by--hpx:hpxhpx.agas.address,hpx.agas.portandhpx.agas.service_modeas set by--hpx:agashpx.program_nameandhpx.cmd_linewill be derived from the actual command linehpx.os_threadsandhpx.localitiesas set by
hpx.runtime_modewill be derived from any explicit--hpx:console,--hpx:worker, or--hpx:connect, or it will be derived from other settings, such as--hpx:node=0which implies--hpx:console
Load files based on the pattern
*.iniin all directories listed by the propertyhpx.ini_path. All files found during this search will be merged. The propertyhpx.ini_pathcan hold a list of directories separated by':'(on Linux or Mac) or';'(on Windows).Load the file specified on the command line using the option
--hpx:app-config. Note that this file will be merged as the content for a top level section[application].
Note
Any changes made to the configuration database caused by one of the steps
will influence the loading process for all subsequent steps. For instance, if
one of the ini files loaded changes the property hpx.ini_path this will
influence the directories searched in step 9 as described above.
Important
The HPX core library will verify that all configuration settings specified
on the command line (using the --hpx:ini option) will be checked
for validity. That means that the library will accept only known
configuration settings. This is to protect the user from unintentional typos
while specifying those settings. This behavior can be overwritten by
appending a '!' to the configuration key, thus forcing the setting to be
entered into the configuration database, for instance: --hpx:ini=hpx.foo! = 1
If any of the environment variables or files listed above is not found the corresponding loading step will be silently skipped.
Loading components¶
HPX relies on loading application specific components during the runtime of an application. Moreover, HPX comes with a set of preinstalled components supporting basic functionalities useful for almost every application. Any component in HPX is loaded from a shared library, where any of the shared libraries can contain more than one component type. During startup, HPX tries to locate all available components (e.g. their corresponding shared libraries) and creates an internal component registry for later use. This section describes the algorithm used by HPX to locate all relevant shared libraries on a system. As described, this algorithm is customizable by the configuration properties loaded from the ini files (see section Loading INI files).
Loading components is a two stage process. First HPX tries to locate all component shared libraries, loads those, and generates default configuration section in the internal configuration database for each component found. For each found component the following information is generated:
[hpx.components.<component_instance_name>]
name = <name_of_shared_library>
path = $[component_path]
enabled = $[hpx.components.load_external]
default = 1
The values in this section correspond to the expected configuration information for a component as described in the section Built-in Default Configuration Settings.
In order to locate component shared libraries, HPX will try loading all
shared libraries (files with the platform specific extension of a shared
library, Linux: *.so, Windows: *.dll, MacOS: *.dylib found in the
directory referenced by the ini property hpx.component_path).
This first step corresponds to step 1) during the process of filling the internal configuration database with default information as described in section Loading INI files.
After all of the configuration information has been loaded, HPX performs the
second step in terms of loading components. During this step, HPX scans all
existing configuration sections
[hpx.component.<some_component_instance_name>] and instantiates a special
factory object for each of the successfully located and loaded components.
During the application’s life time, these factory objects will be responsible to
create new and discard old instances of the component they are associated with.
This step is performed after step 11) of the process of filling the internal
configuration database with default information as described in section
Loading INI files.
Application specific component example¶
In this section we assume to have a simple application component which exposes
one member function as a component action. The header file app_server.hpp
declares the C++ type to be exposed as a component. This type has a member
function print_greeting() which is exposed as an action
print_greeting_action. We assume the source files for this example are
located in a directory referenced by $APP_ROOT:
// file: $APP_ROOT/app_server.hpp
#include <hpx/hpx.hpp>
#include <hpx/include/iostreams.hpp>
namespace app
{
// Define a simple component exposing one action 'print_greeting'
class HPX_COMPONENT_EXPORT server
: public hpx::components::component_base<server>
{
void print_greeting ()
{
hpx::cout << "Hey, how are you?\n" << hpx::flush;
}
// Component actions need to be declared, this also defines the
// type 'print_greeting_action' representing the action.
HPX_DEFINE_COMPONENT_ACTION(server, print_greeting, print_greeting_action);
};
}
// Declare boilerplate code required for each of the component actions.
HPX_REGISTER_ACTION_DECLARATION(app::server::print_greeting_action);
The corresponding source file contains mainly macro invocations which define boilerplate code needed for HPX to function properly:
// file: $APP_ROOT/app_server.cpp
#include "app_server.hpp"
// Define boilerplate required once per component module.
HPX_REGISTER_COMPONENT_MODULE();
// Define factory object associated with our component of type 'app::server'.
HPX_REGISTER_COMPONENT(app::server, app_server);
// Define boilerplate code required for each of the component actions. Use the
// same argument as used for HPX_REGISTER_ACTION_DECLARATION above.
HPX_REGISTER_ACTION(app::server::print_greeting_action);
The following gives an example of how the component can be used. We create one
instance of the app::server component on the current locality and
invoke the exposed action print_greeting_action using the global id of the
newly created instance. Note, that no special code is required to delete the
component instance after it is not needed anymore. It will be deleted
automatically when its last reference goes out of scope, here at the closing
brace of the block surrounding the code:
// file: $APP_ROOT/use_app_server_example.cpp
#include <hpx/hpx_init.hpp>
#include "app_server.hpp"
int hpx_main()
{
{
// Create an instance of the app_server component on the current locality.
hpx::naming:id_type app_server_instance =
hpx::create_component<app::server>(hpx::find_here());
// Create an instance of the action 'print_greeting_action'.
app::server::print_greeting_action print_greeting;
// Invoke the action 'print_greeting' on the newly created component.
print_greeting(app_server_instance);
}
return hpx::finalize();
}
int main(int argc, char* argv[])
{
return hpx::init(argc, argv);
}
In order to make sure that the application will be able to use the component
app::server, special configuration information must be passed to HPX. The
simples way to allow HPX to ‘find’ the component is to provide special ini
configuration files, which add the necessary information to the internal
configuration database. The component should have a special ini file containing
the information specific to the component app_server.
# file: $APP_ROOT/app_server.ini
[hpx.components.app_server]
name = app_server
path = $APP_LOCATION/
Here $APP_LOCATION is the directory where the (binary) component shared
library is located. HPX will attempt to load the shared library from there.
The section name hpx.components.app_server reflects the instance name of the
component (app_server is an arbitrary, but unique name). The property value
for hpx.components.app_server.name should be the same as used for the second
argument to the macro HPX_REGISTER_COMPONENT above.
Additionally a file .hpx.ini which could be located in the current working
directory (see step 3 as described in the section Loading INI files) can
be used to add to the ini search path for components:
# file: $PWD/.hpx.ini
[hpx]
ini_path = $[hpx.ini_path]:$APP_ROOT/
This assumes that the above ini file specific to the component is located in
the directory $APP_ROOT.
Note
It is possible to reference the defined property from inside its value. HPX
will gracefully use the previous value of hpx.ini_path for the reference
on the right hand side and assign the overall (now expanded) value to the
property.
Logging¶
HPX uses a sophisticated logging framework allowing to follow in detail what operations have been performed inside the HPX library in what sequence. This information proves to be very useful for diagnosing problems or just for improving the understanding what is happening in HPX as a consequence of invoking HPX API functionality.
Default logging¶
Enabling default logging is a simple process. The detailed description in the remainder of this section explains different ways to customize the defaults. Default logging can be enabled by using one of the following:
a command line switch
--hpx:debug-hpx-log, which will enable logging to the console terminalthe command line switch
--hpx:debug-hpx-log=<filename>, which enables logging to a given file<filename>, orsetting an environment variable
HPX_LOGLEVEL=<loglevel>while running the HPX application. In this case<loglevel>should be a number between (or equal to)1and5where1means minimal logging and5causes to log all available messages. When setting the environment variable the logs will be written to a file namedhpx.<PID>.loin the current working directory, where<PID>is the process id of the console instance of the application.
Customizing logging¶
Generally, logging can be customized either using environment variable settings or using by an ini configuration file. Logging is generated in several categories, each of which can be customized independently. All customizable configuration parameters have reasonable defaults, allowing to use logging without any additional configuration effort. The following table lists the available categories.
Category |
Category shortcut |
Information to be generated |
Environment variable |
General |
None |
Logging information generated by different subsystems of HPX, such as thread-manager, parcel layer, LCOs, etc. |
|
|
Logging output generated by the AGAS subsystem |
|
|
Application |
|
Logging generated by applications. |
|
By default, all logging output is redirected to the console instance of an application, where it is collected and written to a file, one file for each logging category.
Each logging category can be customized at two levels, the parameters for each
are stored in the ini configuration sections hpx.logging.CATEGORY and
hpx.logging.console.CATEGORY (where CATEGORY is the category shortcut as
listed in the table above). The former influences logging at the source
locality and the latter modifies the logging behaviour for each of the
categories at the console instance of an application.
Levels¶
All HPX logging output has seven different logging levels. These levels can be set explicitly or through environmental variables in the main HPX ini file as shown below. The logging levels and their associated integral values are shown in the table below, ordered from most verbose to least verbose. By default, all HPX logs are set to 0, e.g. all logging output is disabled by default.
Logging level |
Integral value |
|---|---|
|
|
|
|
|
|
|
|
|
|
No logging |
|
Tip
The easiest way to enable logging output is to set the environment variable
corresponding to the logging category to an integral value as described in
the table above. For instance, setting HPX_LOGLEVEL=5 will enable full
logging output for the general category. Please note that the syntax and
means of setting environment variables varies between operating systems.
Configuration¶
Logs will be saved to destinations as configured by the user. By default,
logging output is saved on the console instance of an application to
hpx.<CATEGORY>.<PID>.lo (where CATEGORY and PID> are placeholders
for the category shortcut and the OS process id). The output for the general
logging category is saved to hpx.<PID>.log. The default settings for the
general logging category are shown here (the syntax is described in the section
The HPX INI File Format):
[hpx.logging]
level = ${HPX_LOGLEVEL:0}
destination = ${HPX_LOGDESTINATION:console}
format = ${HPX_LOGFORMAT:(T%locality%/%hpxthread%.%hpxphase%/%hpxcomponent%) P%parentloc%/%hpxparent%.%hpxparentphase% %time%($hh:$mm.$ss.$mili) [%idx%]|\\n}
The logging level is taken from the environment variable HPX_LOGLEVEL and
defaults to zero, e.g. no logging. The default logging destination is read from
the environment variable HPX_LOGDESTINATION On any of the localities it
defaults to console which redirects all generated logging output to the
console instance of an application. The following table lists the possible
destinations for any logging output. It is possible to specify more than one
destination separated by whitespace.
Logging destination |
Description |
file( |
Direct all output to a file with the given <filename>. |
cout |
Direct all output to the local standard output of the application instance on this locality. |
cerr |
Direct all output to the local standard error output of the application instance on this locality. |
console |
Direct all output to the console instance of the application. The console instance has its logging destinations configured separately. |
android_log |
Direct all output to the (Android) system log (available on Android systems only). |
The logging format is read from the environment variable HPX_LOGFORMAT and
it defaults to a complex format description. This format consists of several
placeholder fields (for instance %locality% which will be replaced by
concrete values when the logging output is generated. All other information is
transferred verbatim to the output. The table below describes the available
field placeholders. The separator character | separates the logging message
prefix formatted as shown and the actual log message which will replace the
separator.
Name |
Description |
The id of the locality on which the logging message was generated. |
|
hpxthread |
The id of the HPX-thread generating this logging output. |
hpxphase |
The phase 1 of the HPX-thread generating this logging output. |
hpxcomponent |
The local virtual address of the component which the current HPX-thread is accessing. |
parentloc |
The id of the locality where the HPX thread was running which initiated the current HPX-thread. The current HPX-thread is generating this logging output. |
hpxparent |
The id of the HPX-thread which initiated the current HPX-thread. The current HPX-thread is generating this logging output. |
hpxparentphase |
The phase of the HPX-thread when it initiated the current HPX-thread. The current HPX-thread is generating this logging output. |
time |
The time stamp for this logging outputline as generated by the source locality. |
idx |
The sequence number of the logging output line as generated on the source locality. |
osthread |
The sequence number of the OS-thread which executes the current HPX-thread. |
Note
Not all of the field placeholder may be expanded for all generated logging
output. If no value is available for a particular field it is replaced with a
sequence of '-' characters.]
Here is an example line from a logging output generated by one of the HPX examples (please note that this is generated on a single line, without line break):
(T00000000/0000000002d46f90.01/00000000009ebc10) P--------/0000000002d46f80.02 17:49.37.320 [000000000000004d]
<info> [RT] successfully created component {0000000100ff0001, 0000000000030002} of type: component_barrier[7(3)]
The default settings for the general logging category on the console is shown here:
[hpx.logging.console]
level = ${HPX_LOGLEVEL:$[hpx.logging.level]}
destination = ${HPX_CONSOLE_LOGDESTINATION:file(hpx.$[system.pid].log)}
format = ${HPX_CONSOLE_LOGFORMAT:|}
These settings define how the logging is customized once the logging output is
received by the console instance of an application. The logging level is read
from the environment variable HPX_LOGLEVEL (as set for the console instance
of the application). The level defaults to the same values as the corresponding
settings in the general logging configuration shown before. The destination on
the console instance is set to be a file which name is generated based from its
OS process id. Setting the environment variable HPX_CONSOLE_LOGDESTINATION
allows customization of the naming scheme for the output file. The logging
format is set to leave the original logging output unchanged, as received from
one of the localities the application runs on.
HPX Command Line Options¶
The predefined command line options for any application using
hpx::init are described in the following subsections.
HPX options (allowed on command line only)¶
-
--hpx:help¶ print out program usage (default: this message), possible values:
full(additionally prints options from components)
-
--hpx:version¶ print out HPX version and copyright information
-
--hpx:info¶ print out HPX configuration information
-
--hpx:options-filearg¶ specify a file containing command line options (alternatively: @filepath)
HPX options (additionally allowed in an options file)¶
-
--hpx:worker¶ run this instance in worker mode
-
--hpx:console¶ run this instance in console mode
-
--hpx:connect¶ run this instance in worker mode, but connecting late
-
--hpx:hpxarg¶ the IP address the HPX parcelport is listening on, expected format:
address:port(default:127.0.0.1:7910)
-
--hpx:agasarg¶ the IP address the AGAS root server is running on, expected format:
address:port(default:127.0.0.1:7910)
-
--hpx:nodefilearg¶ the file name of a node file to use (list of nodes, one node name per line and core)
-
--hpx:nodesarg¶ the (space separated) list of the nodes to use (usually this is extracted from a node file)
-
--hpx:endnodes¶ this can be used to end the list of nodes specified using the option
--hpx:nodes
-
--hpx:ifsuffixarg¶ suffix to append to host names in order to resolve them to the proper network interconnect
-
--hpx:ifprefixarg¶ prefix to prepend to host names in order to resolve them to the proper network interconnect
-
--hpx:iftransformarg¶ sed-style search and replace (
s/search/replace/) used to transform host names to the proper network interconnect
-
--hpx:localitiesarg¶ the number of localities to wait for at application startup (default:
1)
-
--hpx:ignore-batch-env¶ ignore batch environment variables
-
--hpx:expect-connecting-localities¶ this locality expects other localities to dynamically connect (this is implied if the number of initial localities is larger than 1)
-
--hpx:pu-offset¶ the first processing unit this instance of HPX should be run on (default:
0)
-
--hpx:pu-step¶ the step between used processing unit numbers for this instance of HPX (default:
1)
-
--hpx:threadsarg¶ the number of operating system threads to spawn for this HPX locality. Possible values are: numeric values
1,2,3and so on,all(which spawns one thread per processing unit, includes hyperthreads), orcores(which spawns one thread per core) (default:cores).
-
--hpx:coresarg¶ the number of cores to utilize for this HPX locality (default:
all, i.e. the number of cores is based on the number of threads--hpx:threadsassuming--hpx:bind=compact
-
--hpx:affinityarg¶ the affinity domain the OS threads will be confined to, possible values:
pu,core,numa,machine(default:pu)
-
--hpx:bindarg¶ the detailed affinity description for the OS threads, see More details about HPX command line options for a detailed description of possible values. Do not use with
--hpx:pu-step,--hpx:pu-offsetor--hpx:affinityoptions. Implies--hpx:numa-sensitive(--hpx:bind=none) disables defining thread affinities).
-
--hpx:use-process-mask¶ use the process mask to restrict available hardware resources (implies
--hpx:ignore-batch-env)
-
--hpx:print-bind¶ print to the console the bit masks calculated from the arguments specified to all
--hpx:bindoptions.
-
--hpx:queuingarg¶ the queue scheduling policy to use, options are
local,local-priority-fifo,local-priority-lifo,static,static-priority,abp-priority-fifoandabp-priority-lifo(default:local-priority-fifo)
-
--hpx:high-priority-threadsarg¶ the number of operating system threads maintaining a high priority queue (default: number of OS threads), valid for
--hpx:queuing=abp-priority,--hpx:queuing=static-priorityand--hpx:queuing=local-priorityonly
-
--hpx:numa-sensitive¶ makes the scheduler NUMA sensitive
HPX configuration options¶
-
--hpx:app-configarg¶ load the specified application configuration (ini) file
-
--hpx:configarg¶ load the specified hpx configuration (ini) file
-
--hpx:iniarg¶ add a configuration definition to the default runtime configuration
-
--hpx:exit¶ exit after configuring the runtime
HPX debugging options¶
-
--hpx:list-symbolic-names¶ list all registered symbolic names after startup
-
--hpx:list-component-types¶ list all dynamic component types after startup
-
--hpx:dump-config-initial¶ print the initial runtime configuration
-
--hpx:dump-config¶ print the final runtime configuration
-
--hpx:debug-hpx-log[arg]¶ enable all messages on the HPX log channel and send all HPX logs to the target destination (default:
cout)
-
--hpx:debug-agas-log[arg]¶ enable all messages on the AGAS log channel and send all AGAS logs to the target destination (default:
cout)
-
--hpx:debug-parcel-log[arg]¶ enable all messages on the parcel transport log channel and send all parcel transport logs to the target destination (default:
cout)
-
--hpx:debug-timing-log[arg]¶ enable all messages on the timing log channel and send all timing logs to the target destination (default:
cout)
-
--hpx:debug-app-log[arg]¶ enable all messages on the application log channel and send all application logs to the target destination (default:
cout)
-
--hpx:debug-clp¶ debug command line processing
-
--hpx:attach-debuggerarg¶ wait for a debugger to be attached, possible arg values:
startuporexception(default:startup)
Command line argument shortcuts¶
Additionally, the following shortcuts are available from every HPX application.
Shortcut option |
Equivalent long option |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
It is possible to define your own shortcut options. In fact, all of the shortcuts listed above are pre-defined using the technique described here. Also, it is possible to redefine any of the pre-defined shortcuts to expand differently as well.
Shortcut options are obtained from the internal configuration database. They are
stored as key-value properties in a special properties section named
hpx.commandline. You can define your own shortcuts by adding the
corresponding definitions to one of the ini configuration files as described
in the section Configuring HPX applications. For instance, in order to define a command
line shortcut --p which should expand to -hpx:print-counter, the
following configuration information needs to be added to one of the ini
configuration files:
[hpx.commandline.aliases]
--pc = --hpx:print-counter
Note
Any arguments for shortcut options passed on the command line are retained and passed as arguments to the corresponding expanded option. For instance, given the definition above, the command line option:
--pc=/threads{locality#0/total}/count/cumulative
would be expanded to:
--hpx:print-counter=/threads{locality#0/total}/count/cumulative
Important
Any shortcut option should either start with a single '-' or with two
'--' characters. Shortcuts starting with a single '-' are interpreted
as short options (i.e. everything after the first character following the
'-' is treated as the argument). Shortcuts starting with '--' are
interpreted as long options. No other shortcut formats are supported.
Specifying options for single localities only¶
For runs involving more than one locality it is sometimes desirable to
supply specific command line options to single localities only. When the HPX
application is launched using a scheduler (like PBS, for more details see
section How to use HPX applications with PBS), specifying dedicated command line options for single
localities may be desirable. For this reason all of the command line options
which have the general format --hpx:<some_key> can be used in a more general
form: --hpx:<N>:<some_key>, where <N> is the number of the locality
this command line options will be applied to, all other localities will simply
ignore the option. For instance, the following PBS script passes the option
--hpx:pu-offset=4 to the locality '1' only.
#!/bin/bash
#
#PBS -l nodes=2:ppn=4
APP_PATH=~/packages/hpx/bin/hello_world_distributed
APP_OPTIONS=
pbsdsh -u $APP_PATH $APP_OPTIONS --hpx:1:pu-offset=4 --hpx:nodes=`cat $PBS_NODEFILE`
Caution
If the first application specific argument (inside $APP_OPTIONS is a
non-option (i.e. does not start with a - or a --, then it must be
placed before the option --hpx:nodes, which, in this case,
should be the last option on the command line.
Alternatively, use the option --hpx:endnodes to explicitly
mark the end of the list of node names:
pbsdsh -u $APP_PATH --hpx:1:pu-offset=4 --hpx:nodes=`cat $PBS_NODEFILE` --hpx:endnodes $APP_OPTIONS
More details about HPX command line options¶
This section documents the following list of the command line options in more detail:
--hpx:bind¶This command line option allows one to specify the required affinity of the
HPX worker threads to the underlying processing units. As a result the worker
threads will run only on the processing units identified by the corresponding
bind specification. The affinity settings are to be specified using
--hpx:bind=<BINDINGS>, where <BINDINGS> have to be formatted as
described below.
In addition to the syntax described below one can use --hpx:bind=none to disable all binding of any threads to a particular core. This is
mostly supported for debugging purposes.
The specified affinities refer to specific regions within a machine hardware topology. In order to understand the hardware topology of a particular machine it may be useful to run the lstopo tool which is part of Portable Hardware Locality (HWLOC) to see the reported topology tree. Seeing and understanding a topology tree will definitely help in understanding the concepts that are discussed below.
Affinities can be specified using HWLOC (Portable Hardware Locality (HWLOC)) tuples. Tuples of HWLOC
objects and associated indexes can be specified in the form
object:index, object:index-index or object:index,...,index. HWLOC
objects represent types of mapped items in a topology tree. Possible values for
objects are socket, numanode, core and pu (processing unit).
Indexes are non-negative integers that specify a unique physical object in a
topology tree using its logical sequence number.
Chaining multiple tuples together in the more general form
object1:index1[.object2:index2[...]] is permissible. While the first tuple’s
object may appear anywhere in the topology, the Nth tuple’s object must have a
shallower topology depth than the (N+1)th tuple’s object. Put simply: as you
move right in a tuple chain, objects must go deeper in the topology tree.
Indexes specified in chained tuples are relative to the scope of the parent
object. For example, socket:0.core:1 refers to the second core in the first
socket (all indices are zero based).
Multiple affinities can be specified using several --hpx:bind command
line options or by appending several affinities separated by a ';' By
default, if multiple affinities are specified, they are added.
"all" is a special affinity consisting in the entire current topology.
Note
All ‘names’ in an affinity specification, such as thread, socket,
numanode, pu or all can be abbreviated. Thus the affinity
specification threads:0-3=socket:0.core:1.pu:1 is fully equivalent to its
shortened form t:0-3=s:0.c:1.p:1.
Here is a full grammar describing the possible format of mappings:
mappings ::=distribution|mapping(";"mapping)* distribution ::= "compact" | "scatter" | "balanced" | "numa-balanced" mapping ::=thread_spec"="pu_specsthread_spec ::= "thread:"range_specspu_specs ::=pu_spec("."pu_spec)* pu_spec ::=type":"range_specs| "~"pu_specrange_specs ::=range_spec(","range_spec)* range_spec ::= int | int "-" int | "all" type ::= "socket" | "numanode" | "core" | "pu"
The following example assumes a system with at least 4 cores, where each core
has more than 1 processing unit (hardware threads). Running
hello_world_distributed with 4 OS-threads (on 4 processing units), where
each of those threads is bound to the first processing unit of each of the
cores, can be achieved by invoking:
hello_world_distributed -t4 --hpx:bind=thread:0-3=core:0-3.pu:0
Here thread:0-3 specifies the OS threads for which to define affinity
bindings, and core:0-3.pu: defines that for each of the cores (core:0-3)
only their first processing unit pu:0 should be used.
Note
The command line option --hpx:print-bind can be used to print the
bitmasks generated from the affinity mappings as specified with
--hpx:bind. For instance, on a system with hyperthreading enabled
(i.e. 2 processing units per core), the command line:
hello_world_distributed -t4 --hpx:bind=thread:0-3=core:0-3.pu:0 --hpx:print-bind
will cause this output to be printed:
0: PU L#0(P#0), Core L#0, Socket L#0, Node L#0(P#0)
1: PU L#2(P#2), Core L#1, Socket L#0, Node L#0(P#0)
2: PU L#4(P#4), Core L#2, Socket L#0, Node L#0(P#0)
3: PU L#6(P#6), Core L#3, Socket L#0, Node L#0(P#0)
where each bit in the bitmasks corresponds to a processing unit the listed worker thread will be bound to run on.
The difference between the four possible predefined distribution schemes
(compact, scatter, balanced and numa-balanced) is best explained
with an example. Imagine that we have a system with 4 cores and 4 hardware
threads per core on 2 sockets. If we place 8 threads the assignments produced by
the compact, scatter, balanced and numa-balanced types are shown
in the figure below. Notice that compact does not fully utilize all the
cores in the system. For this reason it is recommended that applications are run
using the scatter or balanced/numa-balanced options in most cases.
Fig. 7 Schematic of thread affinity type distributions.¶
In addition to the predefined distributions it is possible to restrict the
resources used by HPX to the process CPU mask. The CPU mask is typically set
by e.g. MPI and batch environments. Using the command line option
--hpx:use-process-mask makes HPX act as if only the processing units
in the CPU mask are available for use by HPX. The number of threads is
automatically determined from the CPU mask. The number of threads can still be
changed manually using this option, but only to a number less than or equal to
the number of processing units in the CPU mask. The option
--hpx:print-bind is useful in conjunction with
--hpx:use-process-mask to make sure threads are placed as expected.
- 1
The phase of a HPX-thread counts how often this thread has been activated.
Writing single-node HPX applications¶
HPX is a C++ Standard Library for Concurrency and Parallelism. This means that it implements all of the corresponding facilities as defined by the C++ Standard. Additionally, HPX implements functionalities proposed as part of the ongoing C++ standardization process. This section focuses on the features available in HPX for parallel and concurrent computation on a single node, although many of the features presented here are also implemented to work in the distributed case.
Using LCOs¶
Lightweight Control Objects (LCOs) provide synchronization for HPX applications. Most of them are familiar from other frameworks, but a few of them work in slightly different ways adapted to HPX. The following synchronization objects are available in HPX:
futurequeueobject_semaphorebarrier
Channels¶
Channels combine communication (the exchange of a value) with synchronization (guaranteeing that two calculations (tasks) are in a known state). A channel can transport any number of values of a given type from a sender to a receiver:
hpx::lcos::local::channel<int> c;
hpx::future<int> f = c.get();
HPX_ASSERT(!f.is_ready());
c.set(42);
HPX_ASSERT(f.is_ready());
hpx::cout << f.get() << hpx::endl;
Channels can be handed to another thread (or in case of channel components, to other localities), thus establishing a communication channel between two independent places in the program:
void do_something(hpx::lcos::local::receive_channel<int> c,
hpx::lcos::local::send_channel<> done)
{
// prints 43
hpx::cout << c.get(hpx::launch::sync) << hpx::endl;
// signal back
done.set();
}
void send_receive_channel()
{
hpx::lcos::local::channel<int> c;
hpx::lcos::local::channel<> done;
hpx::apply(&do_something, c, done);
// send some value
c.set(43);
// wait for thread to be done
done.get().wait();
}
Note how hpx::lcos::local::channel::get without any arguments
returns a future which is ready when a value has been set on the channel. The
launch policy hpx::launch::sync can be used to make
hpx::lcos::local::channel::get block until a value is set and
return the value directly.
A channel component is created on one locality and can be sent to another locality using an action. This example also demonstrates how a channel can be used as a range of values:
// channel components need to be registered for each used type (not needed
// for hpx::lcos::local::channel)
HPX_REGISTER_CHANNEL(double);
void channel_sender(hpx::lcos::channel<double> c)
{
for (double d : c)
hpx::cout << d << std::endl;
}
HPX_PLAIN_ACTION(channel_sender);
void channel()
{
// create the channel on this locality
hpx::lcos::channel<double> c(hpx::find_here());
// pass the channel to a (possibly remote invoked) action
hpx::apply(channel_sender_action(), hpx::find_here(), c);
// send some values to the receiver
std::vector<double> v = {1.2, 3.4, 5.0};
for (double d : v)
c.set(d);
// explicitly close the communication channel (implicit at destruction)
c.close();
}
Composable guards¶
Composable guards operate in a manner similar to locks, but are applied only to asynchronous functions. The guard (or guards) is automatically locked at the beginning of a specified task and automatically unlocked at the end. Because guards are never added to an existing task’s execution context, the calling of guards is freely composable and can never deadlock.
To call an application with a single guard, simply declare the guard and call run_guarded() with a function (task):
hpx::lcos::local::guard gu;
run_guarded(gu,task);
If a single method needs to run with multiple guards, use a guard set:
boost::shared<hpx::lcos::local::guard> gu1(new hpx::lcos::local::guard());
boost::shared<hpx::lcos::local::guard> gu2(new hpx::lcos::local::guard());
gs.add(*gu1);
gs.add(*gu2);
run_guarded(gs,task);
Guards use two atomic operations (which are not called repeatedly) to manage what they do, so overhead should be extremely low. The following guards are available in HPX:
conditional_triggercounting_semaphoredatafloweventmutexoncerecursive_mutexspinlockspinlock_no_backofftrigger
Extended facilities for futures¶
Concurrency is about both decomposing and composing the program from the parts that work well individually and together. It is in the composition of connected and multicore components where today’s C++ libraries are still lacking.
The functionality of std::future offers a partial solution. It allows for
the separation of the initiation of an operation and the act of waiting for its
result; however, the act of waiting is synchronous. In communication-intensive
code this act of waiting can be unpredictable, inefficient and simply
frustrating. The example below illustrates a possible synchronous wait using
futures:
#include <future>
using namespace std;
int main()
{
future<int> f = async([]() { return 123; });
int result = f.get(); // might block
}
For this reason, HPX implements a set of extensions to std::future (as
proposed by __cpp11_n4107__). This proposal introduces the following key
asynchronous operations to hpx::future, hpx::shared_future and
hpx::async, which enhance and enrich these facilities.
Facility |
Description |
|
In asynchronous programming, it is very common for one asynchronous
operation, on completion, to invoke a second operation and pass data to
it. The current C++ standard does not allow one to register a
continuation to a future. With |
unwrapping constructor for |
In some scenarios, you might want to create a future that returns another future, resulting in nested futures. Although it is possible to write code to unwrap the outer future and retrieve the nested future and its result, such code is not easy to write because users must handle exceptions and it may cause a blocking call. Unwrapping can allow users to mitigate this problem by doing an asynchronous call to unwrap the outermost future. |
|
There are often situations where a |
|
Some functions may know the value at the point of construction. In these
cases the value is immediately available, but needs to be returned as a
future. By using |
The standard also omits the ability to compose multiple futures. This is a common pattern that is ubiquitous in other asynchronous frameworks and is absolutely necessary in order to make C++ a powerful asynchronous programming language. Not including these functions is synonymous to Boolean algebra without AND/OR.
In addition to the extensions proposed by N4313, HPX adds functions allowing users to compose several futures in a more flexible way.
Facility |
Description |
Comment |
Asynchronously wait for at least one of multiple future or shared_future objects to finish. |
N4313, |
|
Synchronously wait for at least one of multiple future or shared_future objects to finish. |
HPX only |
|
Asynchronously wait for all future and shared_future objects to finish. |
N4313, |
|
Synchronously wait for all future and shared_future objects to finish. |
HPX only |
|
Asynchronously wait for multiple future and shared_future objects to finish. |
HPX only |
|
Synchronously wait for multiple future and shared_future objects to finish. |
HPX only |
|
Asynchronously wait for multiple future and shared_future objects to finish and call a function for each of the future objects as soon as it becomes ready. |
HPX only |
|
Synchronously wait for multiple future and shared_future objects to finish and call a function for each of the future objects as soon as it becomes ready. |
HPX only |
High level parallel facilities¶
In preparation for the upcoming C++ Standards, there are currently several proposals targeting different facilities supporting parallel programming. HPX implements (and extends) some of those proposals. This is well aligned with our strategy to align the APIs exposed from HPX with current and future C++ Standards.
At this point, HPX implements several of the C++ Standardization working papers, most notably N4409 (Working Draft, Technical Specification for C++ Extensions for Parallelism), N4411 (Task Blocks), and N4406 (Parallel Algorithms Need Executors).
Using parallel algorithms¶
A parallel algorithm is a function template described by this document
which is declared in the (inline) namespace hpx::parallel::v1.
Note
For compilers that do not support inline namespaces, all of the namespace
v1 is imported into the namespace hpx::parallel. The effect is similar
to what inline namespaces would do, namely all names defined in
hpx::parallel::v1 are accessible from the namespace hpx::parallel as
well.
All parallel algorithms are very similar in semantics to their sequential
counterparts (as defined in the namespace std) with an additional formal
template parameter named ExecutionPolicy. The execution policy is generally
passed as the first argument to any of the parallel algorithms and describes the
manner in which the execution of these algorithms may be parallelized and the
manner in which they apply user-provided function objects.
The applications of function objects in parallel algorithms invoked with an
execution policy object of type hpx::execution::sequenced_policy or
hpx::execution::sequenced_task_policy execute in sequential order. For
hpx::execution::sequenced_policy the execution happens in the calling thread.
The applications of function objects in parallel algorithms invoked with an
execution policy object of type hpx::execution::parallel_policy or
hpx::execution::parallel_task_policy are permitted to execute in an unordered
fashion in unspecified threads, and are indeterminately sequenced within each
thread.
Important
It is the caller’s responsibility to ensure correctness, such as making sure that the invocation does not introduce data races or deadlocks.
The applications of function objects in parallel algorithms invoked with an
execution policy of type hpx::execution::parallel_unsequenced_policy is, in HPX,
equivalent to the use of the execution policy hpx::execution::parallel_policy.
Algorithms invoked with an execution policy object of type hpx::parallel::v1::execution_policy
execute internally as if invoked with the contained execution policy object. No
exception is thrown when an hpx::parallel::v1::execution_policy contains an execution policy of
type hpx::execution::sequenced_task_policy or hpx::execution::parallel_task_policy
(which normally turn the algorithm into its asynchronous version). In this case
the execution is semantically equivalent to the case of passing a
hpx::execution::sequenced_policy or hpx::execution::parallel_policy contained in the
hpx::parallel::v1::execution_policy object respectively.
Parallel exceptions¶
During the execution of a standard parallel algorithm, if temporary memory
resources are required by any of the algorithms and no memory is available, the
algorithm throws a std::bad_alloc exception.
During the execution of any of the parallel algorithms, if the application of a function object terminates with an uncaught exception, the behavior of the program is determined by the type of execution policy used to invoke the algorithm:
If the execution policy object is of type
hpx::execution::parallel_unsequenced_policy,hpx::terminateshall be called.If the execution policy object is of type
hpx::execution::sequenced_policy,hpx::execution::sequenced_task_policy,hpx::execution::parallel_policy, orhpx::execution::parallel_task_policy, the execution of the algorithm terminates with anhpx::exception_listexception. All uncaught exceptions thrown during the application of user-provided function objects shall be contained in thehpx::exception_list.
For example, the number of invocations of the user-provided function object in
for_each is unspecified. When hpx::parallel::v1::for_each is executed sequentially, only one
exception will be contained in the hpx::exception_list object.
These guarantees imply that, unless the algorithm has failed to allocate memory
and terminated with std::bad_alloc, all exceptions thrown during the
execution of the algorithm are communicated to the caller. It is unspecified
whether an algorithm implementation will “forge ahead” after encountering and
capturing a user exception.
The algorithm may terminate with the std::bad_alloc exception even if one or
more user-provided function objects have terminated with an exception. For
example, this can happen when an algorithm fails to allocate memory while
creating or adding elements to the hpx::exception_list object.
Parallel algorithms¶
HPX provides implementations of the following parallel algorithms:
Name |
Description |
In header |
Algorithm page at cppreference.com |
Computes the differences between adjacent elements in a range. |
|
||
Checks if a predicate is |
|
||
Checks if a predicate is |
|
||
Returns the number of elements equal to a given value. |
|
||
Returns the number of elements satisfying a specific criteria. |
|
||
Determines if two sets of elements are the same. |
|
||
Finds the first element equal to a given value. |
|
||
Finds the last sequence of elements in a certain range. |
|
||
Searches for any one of a set of elements. |
|
||
Finds the first element satisfying a specific criteria. |
|
||
Finds the first element not satisfying a specific criteria. |
|
||
Applies a function to a range of elements. |
|
||
Applies a function to a number of elements. |
|
||
Checks if a range of values is lexicographically less than another range of values. |
|
||
|
Finds the first position where two ranges differ. |
|
|
Checks if a predicate is |
|
||
Searches for a range of elements. |
|
||
Searches for a number consecutive copies of an element in a range. |
|
Name |
Description |
In header |
Algorithm page at cppreference.com |
Copies a range of elements to a new location. |
|
||
Copies a number of elements to a new location. |
|
||
Copies the elements from a range to a new location for which the given predicate is |
|
||
Moves a range of elements to a new location. |
|
||
Assigns a range of elements a certain value. |
|
||
Assigns a value to a number of elements. |
|
||
Saves the result of a function in a range. |
|
||
Saves the result of N applications of a function. |
|
||
Removes the elements from a range that are equal to the given value. |
|
||
Removes the elements from a range that are equal to the given predicate is |
|
||
Copies the elements from a range to a new location that are not equal to the given value. |
|
||
Copies the elements from a range to a new location for which the given predicate is |
|
||
Replaces all values satisfying specific criteria with another value. |
|
||
Replaces all values satisfying specific criteria with another value. |
|
||
Copies a range, replacing elements satisfying specific criteria with another value. |
|
||
Copies a range, replacing elements satisfying specific criteria with another value. |
|
||
Reverses the order elements in a range. |
|
||
Creates a copy of a range that is reversed. |
|
||
Rotates the order of elements in a range. |
|
||
Copies and rotates a range of elements. |
|
||
Swaps two ranges of elements. |
|
||
Applies a function to a range of elements. |
|
||
Eliminates all but the first element from every consecutive group of equivalent elements from a range. |
|
||
Eliminates all but the first element from every consecutive group of equivalent elements from a range. |
|
Name |
Description |
In header |
Algorithm page at cppreference.com |
Merges two sorted ranges. |
|
||
Merges two ordered ranges in-place. |
|
||
Returns true if one set is a subset of another. |
|
||
Computes the difference between two sets. |
|
||
Computes the intersection of two sets. |
|
||
Computes the symmetric difference between two sets. |
|
||
Computes the union of two sets. |
|
Name |
Description |
In header |
Algorithm page at cppreference.com |
Returns |
|
||
Returns the first element that breaks a max heap. |
|
||
Constructs a max heap in the range [first, last). |
|
Name |
Description |
In header |
Algorithm page at cppreference.com |
Returns the largest element in a range. |
|
||
Returns the smallest element in a range. |
|
||
Returns the smallest and the largest element in a range. |
|
Name |
Description |
In header |
Algorithm page at cppreference.com |
Returns |
|
||
Divides elements into two groups without preserving their relative order. |
|
||
Copies a range dividing the elements into two groups. |
|
||
Divides elements into two groups while preserving their relative order. |
|
Name |
Description |
In header |
Algorithm page at cppreference.com |
Returns |
|
||
Returns the first unsorted element. |
|
||
Sorts the elements in a range. |
|
||
Sorts the elements in a range, maintain sequence of equal elements. |
|
||
Sorts the first elements in a range. |
|
||
Sorts one range of data using keys supplied in another range. |
|
Name |
Description |
In header |
Algorithm page at cppreference.com |
Calculates the difference between each element in an input range and the preceding element. |
|
||
Does an exclusive parallel scan over a range of elements. |
|
||
Sums up a range of elements. |
|
||
Does an inclusive parallel scan over a range of elements. |
|
||
Performs an inclusive scan on consecutive elements with matching keys,
with a reduction to output only the final sum for each key. The key
sequence |
|
||
Sums up a range of elements after applying a function. Also, accumulates the inner products of two input ranges. |
|
||
Does an inclusive parallel scan over a range of elements after applying a function. |
|
||
|
Does an exclusive parallel scan over a range of elements after applying a function. |
|
Name |
Description |
In header |
Algorithm page at cppreference.com |
Destroys a range of objects. |
|
||
Destroys a range of objects. |
|
||
Copies a range of objects to an uninitialized area of memory. |
|
||
Copies a number of objects to an uninitialized area of memory. |
|
||
Copies a range of objects to an uninitialized area of memory. |
|
||
Copies a number of objects to an uninitialized area of memory. |
|
||
Copies an object to an uninitialized area of memory. |
|
||
Copies an object to an uninitialized area of memory. |
|
||
Moves a range of objects to an uninitialized area of memory. |
|
||
Moves a number of objects to an uninitialized area of memory. |
|
||
Constructs objects in an uninitialized area of memory. |
|
||
Constructs objects in an uninitialized area of memory. |
|
Name |
Description |
In header |
Implements loop functionality over a range specified by integral or iterator bounds. |
|
|
Implements loop functionality over a range specified by integral or iterator bounds. |
|
|
Implements loop functionality over a range specified by integral or iterator bounds. |
|
|
Implements loop functionality over a range specified by integral or iterator bounds. |
|
Executor parameters and executor parameter traits¶
HPX introduces the notion of execution parameters and execution parameter traits. At this point, the only parameter that can be customized is the size of the chunks of work executed on a single HPX thread (such as the number of loop iterations combined to run as a single task).
An executor parameter object is responsible for exposing the calculation of the size of the chunks scheduled. It abstracts the (potentially platform-specific) algorithms of determining those chunk sizes.
The way executor parameters are implemented is aligned with the way executors
are implemented. All functionalities of concrete executor parameter types are
exposed and accessible through a corresponding
hpx::parallel::executor_parameter_traits type.
With executor_parameter_traits, clients access all types of executor
parameters uniformly:
std::size_t chunk_size =
executor_parameter_traits<my_parameter_t>::get_chunk_size(my_parameter,
my_executor, [](){ return 0; }, num_tasks);
This call synchronously retrieves the size of a single chunk of loop iterations
(or similar) to combine for execution on a single HPX thread if the overall
number of tasks to schedule is given by num_tasks. The lambda function
exposes a means of test-probing the execution of a single iteration for
performance measurement purposes. The execution parameter type might dynamically
determine the execution time of one or more tasks in order to calculate the
chunk size; see hpx::execution::auto_chunk_size for an example of
this executor parameter type.
Other functions in the interface exist to discover whether an executor parameter
type should be invoked once (i.e., it returns a static chunk size; see
hpx::execution::static_chunk_size) or whether it should be invoked
for each scheduled chunk of work (i.e., it returns a variable chunk size; for an
example, see hpx::execution::guided_chunk_size).
Although this interface appears to require executor parameter type authors to implement all different basic operations, none are required. In practice, all operations have sensible defaults. However, some executor parameter types will naturally specialize all operations for maximum efficiency.
HPX implements the following executor parameter types:
hpx::execution::auto_chunk_size: Loop iterations are divided into pieces and then assigned to threads. The number of loop iterations combined is determined based on measurements of how long the execution of 1% of the overall number of iterations takes. This executor parameter type makes sure that as many loop iterations are combined as necessary to run for the amount of time specified.hpx::execution::static_chunk_size: Loop iterations are divided into pieces of a given size and then assigned to threads. If the size is not specified, the iterations are, if possible, evenly divided contiguously among the threads. This executor parameters type is equivalent to OpenMP’s STATIC scheduling directive.hpx::execution::dynamic_chunk_size: Loop iterations are divided into pieces of a given size and then dynamically scheduled among the cores; when a core finishes one chunk, it is dynamically assigned another. If the size is not specified, the default chunk size is 1. This executor parameter type is equivalent to OpenMP’s DYNAMIC scheduling directive.hpx::execution::guided_chunk_size: Iterations are dynamically assigned to cores in blocks as cores request them until no blocks remain to be assigned. This is similar todynamic_chunk_sizeexcept that the block size decreases each time a number of loop iterations is given to a thread. The size of the initial block is proportional tonumber_of_iterations / number_of_cores. Subsequent blocks are proportional tonumber_of_iterations_remaining / number_of_cores. The optional chunk size parameter defines the minimum block size. The default minimal chunk size is 1. This executor parameter type is equivalent to OpenMP’s GUIDED scheduling directive.
Using task blocks¶
The define_task_block, run and the wait functions implemented based
on N4411 are based on the task_block concept that is a part of the
common subset of the Microsoft Parallel Patterns Library (PPL) and the Intel Threading Building Blocks (TBB) libraries.
These implementations adopt a simpler syntax than exposed by those libraries— one that is influenced by language-based concepts, such as spawn and sync from Cilk++ and async and finish from X10. They improve on existing practice in the following ways:
The exception handling model is simplified and more consistent with normal C++ exceptions.
Most violations of strict fork-join parallelism can be enforced at compile time (with compiler assistance, in some cases).
The syntax allows scheduling approaches other than child stealing.
Consider an example of a parallel traversal of a tree, where a user-provided function compute is applied to each node of the tree, returning the sum of the results:
template <typename Func>
int traverse(node& n, Func && compute)
{
int left = 0, right = 0;
define_task_block(
[&](task_block<>& tr) {
if (n.left)
tr.run([&] { left = traverse(*n.left, compute); });
if (n.right)
tr.run([&] { right = traverse(*n.right, compute); });
});
return compute(n) + left + right;
}
The example above demonstrates the use of two of the functions,
hpx::parallel::define_task_block and the
hpx::parallel::task_block::run member function of a
hpx::parallel::task_block.
The task_block function delineates a region in a program code potentially
containing invocations of threads spawned by the run member function of the
task_block class. The run function spawns an HPX thread, a unit of
work that is allowed to execute in parallel with respect to the caller. Any
parallel tasks spawned by run within the task block are joined back to a
single thread of execution at the end of the define_task_block. run
takes a user-provided function object f and starts it asynchronously—i.e.,
it may return before the execution of f completes. The HPX scheduler may
choose to run f immediately or delay running f until compute resources
become available.
A task_block can be constructed only by define_task_block because it has
no public constructors. Thus, run can be invoked directly or indirectly
only from a user-provided function passed to define_task_block:
void g();
void f(task_block<>& tr)
{
tr.run(g); // OK, invoked from within task_block in h
}
void h()
{
define_task_block(f);
}
int main()
{
task_block<> tr; // Error: no public constructor
tr.run(g); // No way to call run outside of a define_task_block
return 0;
}
Extensions for task blocks¶
HPX implements some extensions for task_block beyond the actual
standards proposal N4411. The main addition is that a task_block
can be invoked with an execution policy as its first argument, very similar to
the parallel algorithms.
An execution policy is an object that expresses the requirements on the
ordering of functions invoked as a consequence of the invocation of a
task block. Enabling passing an execution policy to define_task_block
gives the user control over the amount of parallelism employed by the
created task_block. In the following example the use of an explicit
par execution policy makes the user’s intent explicit:
template <typename Func>
int traverse(node *n, Func&& compute)
{
int left = 0, right = 0;
define_task_block(
execution::par, // execution::parallel_policy
[&](task_block<>& tb) {
if (n->left)
tb.run([&] { left = traverse(n->left, compute); });
if (n->right)
tb.run([&] { right = traverse(n->right, compute); });
});
return compute(n) + left + right;
}
This also causes the hpx::parallel::v2::task_block object to be a
template in our implementation. The template argument is the type of the
execution policy used to create the task block. The template argument defaults
to hpx::execution::parallel_policy.
HPX still supports calling hpx::parallel::v2::define_task_block
without an explicit execution policy. In this case the task block will run using
the hpx::execution::parallel_policy.
HPX also adds the ability to access the execution policy that was used to
create a given task_block.
Often, users want to be able to not only define an execution policy to use by
default for all spawned tasks inside the task block, but also to
customize the execution context for one of the tasks executed by
task_block::run. Adding an optionally passed executor instance to that
function enables this use case:
template <typename Func>
int traverse(node *n, Func&& compute)
{
int left = 0, right = 0;
define_task_block(
execution::par, // execution::parallel_policy
[&](auto& tb) {
if (n->left)
{
// use explicitly specified executor to run this task
tb.run(my_executor(), [&] { left = traverse(n->left, compute); });
}
if (n->right)
{
// use the executor associated with the par execution policy
tb.run([&] { right = traverse(n->right, compute); });
}
});
return compute(n) + left + right;
}
HPX still supports calling hpx::parallel::v2::task_block::run
without an explicit executor object. In this case the task will be run using the
executor associated with the execution policy that was used to call
hpx::parallel::v2::define_task_block.
Writing distributed HPX applications¶
This section focuses on the features of HPX needed to write distributed applications, namely the Active Global Address Space (AGAS), remotely executable functions (i.e. actions), and distributed objects (i.e. components).
Global names¶
HPX implements an Active Global Address Space (AGAS) which is exposing a single uniform address space spanning all localities an application runs on. AGAS is a fundamental component of the ParalleX execution model. Conceptually, there is no rigid demarcation of local or global memory in AGAS; all available memory is a part of the same address space. AGAS enables named objects to be moved (migrated) across localities without having to change the object’s name, i.e., no references to migrated objects have to be ever updated. This feature has significance for dynamic load balancing and in applications where the workflow is highly dynamic, allowing work to be migrated from heavily loaded nodes to less loaded nodes. In addition, immutability of names ensures that AGAS does not have to keep extra indirections (“bread crumbs”) when objects move, hence minimizing complexity of code management for system developers as well as minimizing overheads in maintaining and managing aliases.
The AGAS implementation in HPX does not automatically expose every local address to the global address space. It is the responsibility of the programmer to explicitly define which of the objects have to be globally visible and which of the objects are purely local.
In HPX global addresses (global names) are represented using the
hpx::id_type data type. This data type is conceptually very similar to
void* pointers as it does not expose any type information of the object it
is referring to.
The only predefined global addresses are assigned to all localities. The following HPX API functions allow one to retrieve the global addresses of localities:
hpx::find_here: retrieve the global address of the locality this function is called on.hpx::find_all_localities: retrieve the global addresses of all localities available to this application (including the locality the function is being called on).hpx::find_remote_localities: retrieve the global addresses of all remote localities available to this application (not including the locality the function is being called on)hpx::get_num_localities: retrieve the number of localities available to this application.hpx::find_locality: retrieve the global address of any locality supporting the given component type.hpx::get_colocation_id: retrieve the global address of the locality currently hosting the object with the given global address.
Additionally, the global addresses of localities can be used to create new instances of components using the following HPX API function:
hpx::components::new_: Create a new instance of the givenComponenttype on the specified locality.
Note
HPX does not expose any functionality to delete component instances. All
global addresses (as represented using hpx::id_type) are automatically
garbage collected. When the last (global) reference to a particular component
instance goes out of scope the corresponding component instance is
automatically deleted.
Applying actions¶
Action type definition¶
Actions are special types we use to describe possibly remote operations. For
every global function and every member function which has to be invoked
distantly, a special type must be defined. For any global function the special
macro HPX_PLAIN_ACTION can be used to define the
action type. Here is an example demonstrating this:
namespace app
{
void some_global_function(double d)
{
cout << d;
}
}
// This will define the action type 'some_global_action' which represents
// the function 'app::some_global_function'.
HPX_PLAIN_ACTION(app::some_global_function, some_global_action);
Important
The macro HPX_PLAIN_ACTION has to be placed in
global namespace, even if the wrapped function is located in some other
namespace. The newly defined action type is placed in the global namespace as
well.
If the action type should be defined somewhere not in global namespace, the
action type definition has to be split into two macro invocations
(HPX_DEFINE_PLAIN_ACTION and HPX_REGISTER_ACTION) as shown
in the next example:
namespace app
{
void some_global_function(double d)
{
cout << d;
}
// On conforming compilers the following macro expands to:
//
// typedef hpx::actions::make_action<
// decltype(&some_global_function), &some_global_function
// >::type some_global_action;
//
// This will define the action type 'some_global_action' which represents
// the function 'some_global_function'.
HPX_DEFINE_PLAIN_ACTION(some_global_function, some_global_action);
}
// The following macro expands to a series of definitions of global objects
// which are needed for proper serialization and initialization support
// enabling the remote invocation of the function``some_global_function``
HPX_REGISTER_ACTION(app::some_global_action, app_some_global_action);
The shown code defines an action type some_global_action inside the namespace
app.
Important
If the action type definition is split between two macros as shown above, the
name of the action type to create has to be the same for both macro
invocations (here some_global_action).
Important
The second argument passed to HPX_REGISTER_ACTION (app_some_global_action) has
to comprise a globally unique C++ identifier representing the action. This is
used for serialization purposes.
For member functions of objects which have been registered with AGAS
(e.g. ‘components’) a different registration macro
HPX_DEFINE_COMPONENT_ACTION has to be utilized. Any component needs
to be declared in a header file and have some special support macros defined in
a source file. Here is an example demonstrating this. The first snippet has to
go into the header file:
namespace app
{
struct some_component
: hpx::components::component_base<some_component>
{
int some_member_function(std::string s)
{
return boost::lexical_cast<int>(s);
}
// This will define the action type 'some_member_action' which
// represents the member function 'some_member_function' of the
// object type 'some_component'.
HPX_DEFINE_COMPONENT_ACTION(some_component, some_member_function,
some_member_action);
};
}
// Note: The second argument to the macro below has to be systemwide-unique
// C++ identifiers
HPX_REGISTER_ACTION_DECLARATION(app::some_component::some_member_action, some_component_some_action);
The next snippet belongs into a source file (e.g. the main application source file) in the simplest case:
typedef hpx::components::component<app::some_component> component_type;
typedef app::some_component some_component;
HPX_REGISTER_COMPONENT(component_type, some_component);
// The parameters for this macro have to be the same as used in the corresponding
// HPX_REGISTER_ACTION_DECLARATION() macro invocation above
typedef some_component::some_member_action some_component_some_action;
HPX_REGISTER_ACTION(some_component_some_action);
Granted, these macro invocations are a bit more complex than for simple global functions, however we believe they are still manageable.
The most important macro invocation is the HPX_DEFINE_COMPONENT_ACTION in the header file
as this defines the action type we need to invoke the member function. For a
complete example of a simple component action see [hpx_link
examples/quickstart/component_in_executable.cpp..component_in_executable.cpp]
Action invocation¶
The process of invoking a global function (or a member function of an object) with the help of the associated action is called ‘applying the action’. Actions can have arguments, which will be supplied while the action is applied. At the minimum, one parameter is required to apply any action - the id of the locality the associated function should be invoked on (for global functions), or the id of the component instance (for member functions). Generally, HPX provides several ways to apply an action, all of which are described in the following sections.
Generally, HPX actions are very similar to ‘normal’ C++ functions except that actions can be invoked remotely. Fig. 8 below shows an overview of the main API exposed by HPX. This shows the function invocation syntax as defined by the C++ language (dark gray), the additional invocation syntax as provided through C++ Standard Library features (medium gray), and the extensions added by HPX (light gray) where:
ffunction to invoke,p..: (optional) arguments,R: return type off,action: action type defined by,HPX_DEFINE_PLAIN_ACTIONorHPX_DEFINE_COMPONENT_ACTIONencapsulatingf,a: an instance of the type`action,id: the global address the action is applied to.
Fig. 8 Overview of the main API exposed by HPX.¶
This figure shows that HPX allows the user to apply actions with a syntax
similar to the C++ standard. In fact, all action types have an overloaded
function operator allowing to synchronously apply the action. Further, HPX
implements hpx::async which semantically works similar to the
way std::async works for plain C++ function.
Note
The similarity of applying an action to conventional function invocations
extends even further. HPX implements hpx::bind and hpx::function
two facilities which are semantically equivalent to the std::bind and
std::function types as defined by the C++11 Standard. While
hpx::async extends beyond the conventional semantics by supporting
actions and conventional C++ functions, the HPX facilities hpx::bind
and hpx::function extend beyond the conventional standard facilities too.
The HPX facilities not only support conventional functions, but can be used
for actions as well.
Additionally, HPX exposes hpx::apply and hpx::async_continue both of
which refine and extend the standard C++ facilities.
The different ways to invoke a function in HPX will be explained in more detail in the following sections.
Applying an action asynchronously without any synchronization¶
This method (‘fire and forget’) will make sure the function associated with the action is scheduled to run on the target locality. Applying the action does not wait for the function to start running, instead it is a fully asynchronous operation. The following example shows how to apply the action as defined in the previous section on the local locality (the locality this code runs on):
some_global_action act; // define an instance of some_global_action
hpx::apply(act, hpx::find_here(), 2.0);
(the function hpx::find_here() returns the id of the local locality,
i.e. the locality this code executes on).
Any component member function can be invoked using the same syntactic construct.
Given that id is the global address for a component instance created
earlier, this invocation looks like:
some_component_action act; // define an instance of some_component_action
hpx::apply(act, id, "42");
In this case any value returned from this action (e.g. in this case the integer
42 is ignored. Please look at Action type definition for the code
defining the component action some_component_action used.
Applying an action asynchronously with synchronization¶
This method will make sure the action is scheduled to run on the target
locality. Applying the action itself does not wait for the function to
start running or to complete, instead this is a fully asynchronous operation
similar to using hpx::apply as described above. The difference is that this
method will return an instance of a hpx::future<> encapsulating the result
of the (possibly remote) execution. The future can be used to synchronize with
the asynchronous operation. The following example shows how to apply the action
from above on the local locality:
some_global_action act; // define an instance of some_global_action
hpx::future<void> f = hpx::async(act, hpx::find_here(), 2.0);
//
// ... other code can be executed here
//
f.get(); // this will possibly wait for the asynchronous operation to 'return'
(as before, the function hpx::find_here() returns the id of the local
locality (the locality this code is executed on).
Note
The use of a hpx::future<void> allows the current thread to synchronize
with any remote operation not returning any value.
Note
Any std::future<> returned from std::async() is required to block in
its destructor if the value has not been set for this future yet. This is not
true for hpx::future<> which will never block in its destructor, even if
the value has not been returned to the future yet. We believe that
consistency in the behavior of futures is more important than standards
conformance in this case.
Any component member function can be invoked using the same syntactic construct.
Given that id is the global address for a component instance created
earlier, this invocation looks like:
some_component_action act; // define an instance of some_component_action
hpx::future<int> f = hpx::async(act, id, "42");
//
// ... other code can be executed here
//
cout << f.get(); // this will possibly wait for the asynchronous operation to 'return' 42
Note
The invocation of f.get() will return the result immediately (without
suspending the calling thread) if the result from the asynchronous operation
has already been returned. Otherwise, the invocation of f.get() will
suspend the execution of the calling thread until the asynchronous operation
returns its result.
Applying an action synchronously¶
This method will schedule the function wrapped in the specified action on the target locality. While the invocation appears to be synchronous (as we will see), the calling thread will be suspended while waiting for the function to return. Invoking a plain action (e.g. a global function) synchronously is straightforward:
some_global_action act; // define an instance of some_global_action
act(hpx::find_here(), 2.0);
While this call looks just like a normal synchronous function invocation, the function wrapped by the action will be scheduled to run on a new thread and the calling thread will be suspended. After the new thread has executed the wrapped global function, the waiting thread will resume and return from the synchronous call.
Equivalently, any action wrapping a component member function can be invoked synchronously as follows:
some_component_action act; // define an instance of some_component_action
int result = act(id, "42");
The action invocation will either schedule a new thread locally to execute the
wrapped member function (as before, id is the global address of the
component instance the member function should be invoked on), or it will send a
parcel to the remote locality of the component causing a new thread to
be scheduled there. The calling thread will be suspended until the function
returns its result. This result will be returned from the synchronous action
invocation.
It is very important to understand that this ‘synchronous’ invocation syntax in fact conceals an asynchronous function call. This is beneficial as the calling thread is suspended while waiting for the outcome of a potentially remote operation. The HPX thread scheduler will schedule other work in the meantime, allowing the application to make further progress while the remote result is computed. This helps overlapping computation with communication and hiding communication latencies.
Note
The syntax of applying an action is always the same, regardless whether the target locality is remote to the invocation locality or not. This is a very important feature of HPX as it frees the user from the task of keeping track what actions have to be applied locally and which actions are remote. If the target for applying an action is local, a new thread is automatically created and scheduled. Once this thread is scheduled and run, it will execute the function encapsulated by that action. If the target is remote, HPX will send a parcel to the remote locality which encapsulates the action and its parameters. Once the parcel is received on the remote locality HPX will create and schedule a new thread there. Once this thread runs on the remote locality, it will execute the function encapsulated by the action.
Applying an action with a continuation but without any synchronization¶
This method is very similar to the method described in section Applying an action asynchronously without any synchronization. The
difference is that it allows the user to chain a sequence of asynchronous
operations, while handing the (intermediate) results from one step to the next
step in the chain. Where hpx::apply invokes a single function using ‘fire
and forget’ semantics, hpx::apply_continue asynchronously triggers a chain
of functions without the need for the execution flow ‘to come back’ to the
invocation site. Each of the asynchronous functions can be executed on a
different locality.
Applying an action with a continuation and with synchronization¶
This method is very similar to the method described in section Applying an action asynchronously with synchronization. In
addition to what hpx::async can do, the functions hpx::async_continue
takes an additional function argument. This function will be called as the
continuation of the executed action. It is expected to perform additional
operations and to make sure that a result is returned to the original invocation
site. This method chains operations asynchronously by providing a continuation
operation which is automatically executed once the first action has finished
executing.
As an example we chain two actions, where the result of the first action is forwarded to the second action and the result of the second action is sent back to the original invocation site:
// first action
std::int32_t action1(std::int32_t i)
{
return i+1;
}
HPX_PLAIN_ACTION(action1); // defines action1_type
// second action
std::int32_t action2(std::int32_t i)
{
return i*2;
}
HPX_PLAIN_ACTION(action2); // defines action2_type
// this code invokes 'action1' above and passes along a continuation
// function which will forward the result returned from 'action1' to
// 'action2'.
action1_type act1; // define an instance of 'action1_type'
action2_type act2; // define an instance of 'action2_type'
hpx::future<int> f =
hpx::async_continue(act1, hpx::make_continuation(act2),
hpx::find_here(), 42);
hpx::cout << f.get() << "\n"; // will print: 86 ((42 + 1) * 2)
By default, the continuation is executed on the same locality as
hpx::async_continue is invoked from. If you want to specify the
locality where the continuation should be executed, the code above has
to be written as:
// this code invokes 'action1' above and passes along a continuation
// function which will forward the result returned from 'action1' to
// 'action2'.
action1_type act1; // define an instance of 'action1_type'
action2_type act2; // define an instance of 'action2_type'
hpx::future<int> f =
hpx::async_continue(act1, hpx::make_continuation(act2, hpx::find_here()),
hpx::find_here(), 42);
hpx::cout << f.get() << "\n"; // will print: 86 ((42 + 1) * 2)
Similarly, it is possible to chain more than 2 operations:
action1_type act1; // define an instance of 'action1_type'
action2_type act2; // define an instance of 'action2_type'
hpx::future<int> f =
hpx::async_continue(act1,
hpx::make_continuation(act2, hpx::make_continuation(act1)),
hpx::find_here(), 42);
hpx::cout << f.get() << "\n"; // will print: 87 ((42 + 1) * 2 + 1)
The function hpx::make_continuation creates a special function object
which exposes the following prototype:
struct continuation
{
template <typename Result>
void operator()(hpx::id_type id, Result&& result) const
{
...
}
};
where the parameters passed to the overloaded function operator operator()()
are:
the
idis the global id where the final result of the asynchronous chain of operations should be sent to (in most cases this is the id of thehpx::futurereturned from the initial call tohpx::async_continue. Any custom continuation function should make sure thisidis forwarded to the last operation in the chain.the
resultis the result value of the current operation in the asynchronous execution chain. This value needs to be forwarded to the next operation.
Note
All of those operations are implemented by the predefined continuation
function object which is returned from hpx::make_continuation. Any (custom)
function object used as a continuation should conform to the same interface.
Action error handling¶
Like in any other asynchronous invocation scheme it is important to be able to handle error conditions occurring while the asynchronous (and possibly remote) operation is executed. In HPX all error handling is based on standard C++ exception handling. Any exception thrown during the execution of an asynchronous operation will be transferred back to the original invocation locality, where it is rethrown during synchronization with the calling thread.
Important
Exceptions thrown during asynchronous execution can be transferred back to
the invoking thread only for the synchronous and the asynchronous case with
synchronization. Like with any other unhandled exception, any exception
thrown during the execution of an asynchronous action without
synchronization will result in calling hpx::terminate causing the running
application to exit immediately.
Note
Even if error handling internally relies on exceptions, most of the API functions exposed by HPX can be used without throwing an exception. Please see Working with exceptions for more information.
As an example, we will assume that the following remote function will be executed:
namespace app
{
void some_function_with_error(int arg)
{
if (arg < 0) {
HPX_THROW_EXCEPTION(bad_parameter, "some_function_with_error",
"some really bad error happened");
}
// do something else...
}
}
// This will define the action type 'some_error_action' which represents
// the function 'app::some_function_with_error'.
HPX_PLAIN_ACTION(app::some_function_with_error, some_error_action);
The use of HPX_THROW_EXCEPTION to report the error encapsulates the
creation of a hpx::exception which is initialized with the error
code hpx::bad_parameter. Additionally it carries the passed strings, the
information about the file name, line number, and call stack of the point the
exception was thrown from.
We invoke this action using the synchronous syntax as described before:
// note: wrapped function will throw hpx::exception
some_error_action act; // define an instance of some_error_action
try {
act(hpx::find_here(), -3); // exception will be rethrown from here
}
catch (hpx::exception const& e) {
// prints: 'some really bad error happened: HPX(bad parameter)'
cout << e.what();
}
If this action is invoked asynchronously with synchronization, the exception is
propagated to the waiting thread as well and is re-thrown from the future’s
function get():
// note: wrapped function will throw hpx::exception
some_error_action act; // define an instance of some_error_action
hpx::future<void> f = hpx::async(act, hpx::find_here(), -3);
try {
f.get(); // exception will be rethrown from here
}
catch (hpx::exception const& e) {
// prints: 'some really bad error happened: HPX(bad parameter)'
cout << e.what();
}
For more information about error handling please refer to the section Working with exceptions. There we also explain how to handle error conditions without having to rely on exception.
Writing components¶
A component in HPX is a C++ class which can be created remotely and for which its member functions can be invoked remotely as well. The following sections highlight how components can be defined, created, and used.
Defining components¶
In order for a C++ class type to be managed remotely in HPX, the type must be
derived from the hpx::components::component_base template type. We
call such C++ class types ‘components’.
Note that the component type itself is passed as a template argument to the base class:
// header file some_component.hpp
#include <hpx/include/components.hpp>
namespace app
{
// Define a new component type 'some_component'
struct some_component
: hpx::components::component_base<some_component>
{
// This member function is has to be invoked remotely
int some_member_function(std::string const& s)
{
return boost::lexical_cast<int>(s);
}
// This will define the action type 'some_member_action' which
// represents the member function 'some_member_function' of the
// object type 'some_component'.
HPX_DEFINE_COMPONENT_ACTION(some_component, some_member_function, some_member_action);
};
}
// This will generate the necessary boiler-plate code for the action allowing
// it to be invoked remotely. This declaration macro has to be placed in the
// header file defining the component itself.
//
// Note: The second argument to the macro below has to be systemwide-unique
// C++ identifiers
//
HPX_REGISTER_ACTION_DECLARATION(app::some_component::some_member_action, some_component_some_action);
There is more boiler plate code which has to be placed into a source file in order for the component to be usable. Every component type is required to have macros placed into its source file, one for each component type and one macro for each of the actions defined by the component type.
For instance:
// source file some_component.cpp
#include "some_component.hpp"
// The following code generates all necessary boiler plate to enable the
// remote creation of 'app::some_component' instances with 'hpx::new_<>()'
//
using some_component = app::some_component;
using some_component_type = hpx::components::component<some_component>;
// Please note that the second argument to this macro must be a
// (system-wide) unique C++-style identifier (without any namespaces)
//
HPX_REGISTER_COMPONENT(some_component_type, some_component);
// The parameters for this macro have to be the same as used in the corresponding
// HPX_REGISTER_ACTION_DECLARATION() macro invocation in the corresponding
// header file.
//
// Please note that the second argument to this macro must be a
// (system-wide) unique C++-style identifier (without any namespaces)
//
HPX_REGISTER_ACTION(app::some_component::some_member_action, some_component_some_action);
Defining client side representation classes¶
Often it is very convenient to define a separate type for a component which can be used on the client side (from where the component is instantiated and used). This step might seem as unnecessary duplicating code, however it significantly increases the type safety of the code.
A possible implementation of such a client side representation for the component described in the previous section could look like:
#include <hpx/include/components.hpp>
namespace app
{
// Define a client side representation type for the component type
// 'some_component' defined in the previous section.
//
struct some_component_client
: hpx::components::client_base<some_component_client, some_component>
{
using base_type = hpx::components::client_base<
some_component_client, some_component>;
some_component_client(hpx::future<hpx::id_type> && id)
: base_type(std::move(id))
{}
hpx::future<int> some_member_function(std::string const& s)
{
some_component::some_member_action act;
return hpx::async(act, get_id(), s);
}
};
}
A client side object stores the global id of the component instance it
represents. This global id is accessible by calling the function
client_base<>::get_id(). The special constructor which is provided in the
example allows to create this client side object directly using the API function
hpx::new_.
Creating component instances¶
Instances of defined component types can be created in two different ways. If the component to create has a defined client side representation type, then this can be used, otherwise use the server type.
The following examples assume that some_component_type is the type of the
server side implementation of the component to create. All additional arguments
(see , ... notation below) are passed through to the corresponding
constructor calls of those objects:
// create one instance on the given locality
hpx::id_type here = hpx::find_here();
hpx::future<hpx::id_type> f =
hpx::new_<some_component_type>(here, ...);
// create one instance using the given distribution
// policy (here: hpx::colocating_distribution_policy)
hpx::id_type here = hpx::find_here();
hpx::future<hpx::id_type> f =
hpx::new_<some_component_type>(hpx::colocated(here), ...);
// create multiple instances on the given locality
hpx::id_type here = find_here();
hpx::future<std::vector<hpx::id_type>> f =
hpx::new_<some_component_type[]>(here, num, ...);
// create multiple instances using the given distribution
// policy (here: hpx::binpacking_distribution_policy)
hpx::future<std::vector<hpx::id_type>> f = hpx::new_<some_component_type[]>(
hpx::binpacking(hpx::find_all_localities()), num, ...);
The examples below demonstrate the use of the same API functions for creating
client side representation objects (instead of just plain ids). These examples
assume that client_type is the type of the client side representation of the
component type to create. As above, all additional arguments
(see , ... notation below) are passed through to the corresponding constructor
calls of the server side implementation objects corresponding to the
client_type:
// create one instance on the given locality
hpx::id_type here = hpx::find_here();
client_type c = hpx::new_<client_type>(here, ...);
// create one instance using the given distribution
// policy (here: hpx::colocating_distribution_policy)
hpx::id_type here = hpx::find_here();
client_type c = hpx::new_<client_type>(hpx::colocated(here), ...);
// create multiple instances on the given locality
hpx::id_type here = hpx::find_here();
hpx::future<std::vector<client_type>> f =
hpx::new_<client_type[]>(here, num, ...);
// create multiple instances using the given distribution
// policy (here: hpx::binpacking_distribution_policy)
hpx::future<std::vector<client_type>> f = hpx::new_<client_type[]>(
hpx::binpacking(hpx::find_all_localities()), num, ...);
Using component instances¶
Segmented containers¶
In parallel programming, there is now a plethora of solutions aimed at implementing “partially contiguous” or segmented data structures, whether on shared memory systems or distributed memory systems. HPX implements such structures by drawing inspiration from Standard C++ containers.
Using segmented containers¶
A segmented container is a template class that is described in the namespace
hpx. All segmented containers are very similar semantically to their
sequential counterpart (defined in namespace std but with an additional
template parameter named DistPolicy). The distribution policy is an optional
parameter that is passed last to the segmented container constructor (after the
container size when no default value is given, after the default value if not).
The distribution policy describes the manner in which a container is segmented
and the placement of each segment among the available runtime localities.
However, only a part of the std container member functions were
reimplemented:
(constructor),(destructor),operator=operator[]begin,cbegin,end,cendsize
An example of how to use the partitioned_vector container would be:
#include <hpx/include/partitioned_vector.hpp>
// The following code generates all necessary boiler plate to enable the
// remote creation of 'partitioned_vector' segments
//
HPX_REGISTER_PARTITIONED_VECTOR(double);
// By default, the number of segments is equal to the current number of
// localities
//
hpx::partitioned_vector<double> va(50);
hpx::partitioned_vector<double> vb(50, 0.0);
An example of how to use the partitioned_vector container
with distribution policies would be:
#include <hpx/include/partitioned_vector.hpp>
#include <hpx/runtime_distributed/find_localities.hpp>
// The following code generates all necessary boiler plate to enable the
// remote creation of 'partitioned_vector' segments
//
HPX_REGISTER_PARTITIONED_VECTOR(double);
std::size_t num_segments = 10;
std::vector<hpx::id_type> locs = hpx::find_all_localities()
auto layout =
hpx::container_layout( num_segments, locs );
// The number of segments is 10 and those segments are spread across the
// localities collected in the variable locs in a Round-Robin manner
//
hpx::partitioned_vector<double> va(50, layout);
hpx::partitioned_vector<double> vb(50, 0.0, layout);
By definition, a segmented container must be accessible from any thread although its construction is synchronous only for the thread who has called its constructor. To overcome this problem, it is possible to assign a symbolic name to the segmented container:
#include <hpx/include/partitioned_vector.hpp>
// The following code generates all necessary boiler plate to enable the
// remote creation of 'partitioned_vector' segments
//
HPX_REGISTER_PARTITIONED_VECTOR(double);
hpx::future<void> fserver = hpx::async(
[](){
hpx::partitioned_vector<double> v(50);
// Register the 'partitioned_vector' with the name "some_name"
//
v.register_as("some_name");
/* Do some code */
});
hpx::future<void> fclient =
hpx::async(
[](){
// Naked 'partitioned_vector'
//
hpx::partitioned_vector<double> v;
// Now the variable v points to the same 'partitioned_vector' that has
// been registered with the name "some_name"
//
v.connect_to("some_name");
/* Do some code */
});
HPX provides the following segmented containers:
Name |
Description |
In header |
Class page at cppreference.com |
|
Dynamic segmented contiguous array. |
|
Name |
Description |
In header |
Class page at cppreference.com |
|
Segmented collection of key-value pairs, hashed by keys, keys are unique. |
|
Segmented iterators and segmented iterator traits¶
The basic iterator used in the STL library is only suitable for one-dimensional
structures. The iterators we use in HPX must adapt to the segmented format of
our containers. Our iterators are then able to know when incrementing themselves
if the next element of type T is in the same data segment or in another
segment. In this second case, the iterator will automatically point to the
beginning of the next segment.
Note
Note that the dereference operation operator * does not directly return a
reference of type T& but an intermediate object wrapping this reference.
When this object is used as an l-value, a remote write operation is
performed; When this object is used as an r-value, implicit conversion to
T type will take care of performing remote read operation.
It is sometimes useful not only to iterate element by element, but also segment
by segment, or simply get a local iterator in order to avoid additional
construction costs at each deferencing operations. To mitigate this need, the
hpx::traits::segmented_iterator_traits are used.
With segmented_iterator_traits users can uniformly get the iterators
which specifically iterates over segments (by providing a segmented iterator
as a parameter), or get the local begin/end iterators of the nearest
local segment (by providing a per-segment iterator as a parameter):
#include <hpx/include/partitioned_vector.hpp>
// The following code generates all necessary boiler plate to enable the
// remote creation of 'partitioned_vector' segments
//
HPX_REGISTER_PARTITIONED_VECTOR(double);
using iterator = hpx::partitioned_vector<T>::iterator;
using traits = hpx::traits::segmented_iterator_traits<iterator>;
hpx::partitioned_vector<T> v;
std::size_t count = 0;
auto seg_begin = traits::segment(v.begin());
auto seg_end = traits::segment(v.end());
// Iterate over segments
for (auto seg_it = seg_begin; seg_it != seg_end; ++seg_it)
{
auto loc_begin = traits::begin(seg_it);
auto loc_end = traits::end(seg_it);
// Iterate over elements inside segments
for (auto lit = loc_begin; lit != loc_end; ++lit, ++count)
{
*lit = count;
}
}
Which is equivalent to:
hpx::partitioned_vector<T> v;
std::size_t count = 0;
auto begin = v.begin();
auto end = v.end();
for (auto it = begin; it != end; ++it, ++count)
{
*it = count;
}
Using views¶
The use of multidimensional arrays is quite common in the numerical field
whether to perform dense matrix operations or to process images. It exist many
libraries which implement such object classes overloading their basic operators
(e.g.``+``, -, *, (), etc.). However, such operation becomes more
delicate when the underlying data layout is segmented or when it is mandatory to
use optimized linear algebra subroutines (i.e. BLAS subroutines).
Our solution is thus to relax the level of abstraction by allowing the user to work not directly on n-dimensionnal data, but on “n-dimensionnal collections of 1-D arrays”. The use of well-accepted techniques on contiguous data is thus preserved at the segment level, and the composability of the segments is made possible thanks to multidimensional array-inspired access mode.
Although HPX refutes by design this programming model, the locality plays a dominant role when it comes to implement vectorized code. To maximize local computations and avoid unneeded data transfers, a parallel section (or Single Programming Multiple Data section) is required. Because the use of global variables is prohibited, this parallel section is created via the RAII idiom.
To define a parallel section, simply write an action taking a spmd_block
variable as a first parameter:
#include <hpx/collectives/spmd_block.hpp>
void bulk_function(hpx::lcos::spmd_block block /* , arg0, arg1, ... */)
{
// Parallel section
/* Do some code */
}
HPX_PLAIN_ACTION(bulk_function, bulk_action);
Note
In the following paragraphs, we will use the term “image” several times. An image is defined as a lightweight process whose entry point is a function provided by the user. It’s an “image of the function”.
The spmd_block class contains the following methods:
[def Team information]
get_num_images,this_image,images_per_locality[def Control statements]
sync_all,sync_images
Here is a sample code summarizing the features offered by the spmd_block
class:
#include <hpx/collectives/spmd_block.hpp>
void bulk_function(hpx::lcos::spmd_block block /* , arg0, arg1, ... */)
{
std::size_t num_images = block.get_num_images();
std::size_t this_image = block.this_image();
std::size_t images_per_locality = block.images_per_locality();
/* Do some code */
// Synchronize all images in the team
block.sync_all();
/* Do some code */
// Synchronize image 0 and image 1
block.sync_images(0,1);
/* Do some code */
std::vector<std::size_t> vec_images = {2,3,4};
// Synchronize images 2, 3 and 4
block.sync_images(vec_images);
// Alternative call to synchronize images 2, 3 and 4
block.sync_images(vec_images.begin(), vec_images.end());
/* Do some code */
// Non-blocking version of sync_all()
hpx::future<void> event =
block.sync_all(hpx::launch::async);
// Callback waiting for 'event' to be ready before being scheduled
hpx::future<void> cb =
event.then(
[](hpx::future<void>)
{
/* Do some code */
});
// Finally wait for the execution tree to be finished
cb.get();
}
HPX_PLAIN_ACTION(bulk_test_function, bulk_test_action);
Then, in order to invoke the parallel section, call the function
define_spmd_block specifying an arbitrary symbolic name and indicating the
number of images per locality to create:
void bulk_function(hpx::lcos::spmd_block block, /* , arg0, arg1, ... */)
{
}
HPX_PLAIN_ACTION(bulk_test_function, bulk_test_action);
int main()
{
/* std::size_t arg0, arg1, ...; */
bulk_action act;
std::size_t images_per_locality = 4;
// Instantiate the parallel section
hpx::lcos::define_spmd_block(
"some_name", images_per_locality, std::move(act) /*, arg0, arg1, ... */);
return 0;
}
Note
In principle, the user should never call the spmd_block constructor. The
define_spmd_block function is responsible of instantiating spmd_block
objects and broadcasting them to each created image.
Some classes are defined as “container views” when the purpose is to observe
and/or modify the values of a container using another perspective than the one
that characterizes the container. For example, the values of an std::vector
object can be accessed via the expression [i]. Container views can be used,
for example, when it is desired for those values to be “viewed” as a 2D matrix
that would have been flattened in a std::vector. The values would be
possibly accessible via the expression vv(i,j) which would call internally
the expression v[k].
By default, the partitioned_vector class integrates 1-D views of its segments:
#include <hpx/include/partitioned_vector.hpp>
// The following code generates all necessary boiler plate to enable the
// remote creation of 'partitioned_vector' segments
//
HPX_REGISTER_PARTITIONED_VECTOR(double);
using iterator = hpx::partitioned_vector<double>::iterator;
using traits = hpx::traits::segmented_iterator_traits<iterator>;
hpx::partitioned_vector<double> v;
// Create a 1-D view of the vector of segments
auto vv = traits::segment(v.begin());
// Access segment i
std::vector<double> v = vv[i];
Our views are called “multidimensional” in the sense that they generalize to N
dimensions the purpose of segmented_iterator_traits::segment() in the 1-D
case. Note that in a parallel section, the 2-D expression a(i,j) = b(i,j) is
quite confusing because without convention, each of the images invoked will race
to execute the statement. For this reason, our views are not only
multidimensional but also “spmd-aware”.
Note
SPMD-awareness: The convention is simple. If an assignment statement contains a view subscript as an l-value, it is only and only the image holding the r-value who is evaluating the statement. (In MPI sense, it is called a Put operation).
Here are some examples of using subscripts in the 2-D view case:
#include <hpx/components/containers/partitioned_vector/partitioned_vector_view.hpp>
#include <hpx/include/partitioned_vector.hpp>
// The following code generates all necessary boiler plate to enable the
// remote creation of 'partitioned_vector' segments
//
HPX_REGISTER_PARTITIONED_VECTOR(double);
using Vec = hpx::partitioned_vector<double>;
using View_2D = hpx::partitioned_vector_view<double,2>;
/* Do some code */
Vec v;
// Parallel section (suppose 'block' an spmd_block instance)
{
std::size_t height, width;
// Instantiate the view
View_2D vv(block, v.begin(), v.end(), {height,width});
// The l-value is a view subscript, the image that owns vv(1,0)
// evaluates the assignment.
vv(0,1) = vv(1,0);
// The l-value is a view subscript, the image that owns the r-value
// (result of expression 'std::vector<double>(4,1.0)') evaluates the
// assignment : oops! race between all participating images.
vv(2,3) = std::vector<double>(4,1.0);
}
Here are some examples of using iterators in the 3-D view case:
#include <hpx/components/containers/partitioned_vector/partitioned_vector_view.hpp>
#include <hpx/include/partitioned_vector.hpp>
// The following code generates all necessary boiler plate to enable the
// remote creation of 'partitioned_vector' segments
//
HPX_REGISTER_PARTITIONED_VECTOR(int);
using Vec = hpx::partitioned_vector<int>;
using View_3D = hpx::partitioned_vector_view<int,3>;
/* Do some code */
Vec v1, v2;
// Parallel section (suppose 'block' an spmd_block instance)
{
std::size_t sixe_x, size_y, size_z;
// Instantiate the views
View_3D vv1(block, v1.begin(), v1.end(), {sixe_x,size_y,size_z});
View_3D vv2(block, v2.begin(), v2.end(), {sixe_x,size_y,size_z});
// Save previous segments covered by vv1 into segments covered by vv2
auto vv2_it = vv2.begin();
auto vv1_it = vv1.cbegin();
for(; vv2_it != vv2.end(); vv2_it++, vv1_it++)
{
// It's a Put operation
*vv2_it = *vv1_it;
}
// Ensure that all images have performed their Put operations
block.sync_all();
// Ensure that only one image is putting updated data into the different
// segments covered by vv1
if(block.this_image() == 0)
{
int idx = 0;
// Update all the segments covered by vv1
for(auto i = vv1.begin(); i != vv1.end(); i++)
{
// It's a Put operation
*i = std::vector<float>(elt_size,idx++);
}
}
}
Here is an example that shows how to iterate only over segments owned by the current image:
#include <hpx/components/containers/partitioned_vector/partitioned_vector_view.hpp>
#include <hpx/components/containers/partitioned_vector/partitioned_vector_local_view.hpp>
#include <hpx/include/partitioned_vector.hpp>
// The following code generates all necessary boiler plate to enable the
// remote creation of 'partitioned_vector' segments
//
HPX_REGISTER_PARTITIONED_VECTOR(float);
using Vec = hpx::partitioned_vector<float>;
using View_1D = hpx::partitioned_vector_view<float,1>;
/* Do some code */
Vec v;
// Parallel section (suppose 'block' an spmd_block instance)
{
std::size_t num_segments;
// Instantiate the view
View_1D vv(block, v.begin(), v.end(), {num_segments});
// Instantiate the local view from the view
auto local_vv = hpx::local_view(vv);
for ( auto i = local_vv.begin(); i != local_vv.end(); i++ )
{
std::vector<float> & segment = *i;
/* Do some code */
}
}
It is possible to construct views from other views: we call it sub-views. The constraint nevertheless for the subviews is to retain the dimension and the value type of the input view. Here is an example showing how to create a sub-view:
#include <hpx/components/containers/partitioned_vector/partitioned_vector_view.hpp>
#include <hpx/include/partitioned_vector.hpp>
// The following code generates all necessary boiler plate to enable the
// remote creation of 'partitioned_vector' segments
//
HPX_REGISTER_PARTITIONED_VECTOR(float);
using Vec = hpx::partitioned_vector<float>;
using View_2D = hpx::partitioned_vector_view<float,2>;
/* Do some code */
Vec v;
// Parallel section (suppose 'block' an spmd_block instance)
{
std::size_t N = 20;
std::size_t tilesize = 5;
// Instantiate the view
View_2D vv(block, v.begin(), v.end(), {N,N});
// Instantiate the subview
View_2D svv(
block,&vv(tilesize,0),&vv(2*tilesize-1,tilesize-1),{tilesize,tilesize},{N,N});
if(block.this_image() == 0)
{
// Equivalent to 'vv(tilesize,0) = 2.0f'
svv(0,0) = 2.0f;
// Equivalent to 'vv(2*tilesize-1,tilesize-1) = 3.0f'
svv(tilesize-1,tilesize-1) = 3.0f;
}
}
Note
The last parameter of the subview constructor is the size of the original
view. If one would like to create a subview of the subview and so on, this
parameter should stay unchanged. {N,N} for the above example).
C++ co-arrays¶
Fortran has extended its scalar element indexing approach to reference each segment of a distributed array. In this extension, a segment is attributed a ?co-index? and lives in a specific locality. A co-index provides the application with enough information to retrieve the corresponding data reference. In C++, containers present themselves as a ?smarter? alternative of Fortran arrays but there are still no corresponding standardized features similar to the Fortran co-indexing approach. We present here an implementation of such features in HPX.
As mentioned before, a co-array is a distributed array whose segments are accessible through an array-inspired access mode. We have previously seen that it is possible to reproduce such access mode using the concept of views. Nevertheless, the user must pre-create a segmented container to instantiate this view. We illustrate below how a single constructor call can perform those two operations:
#include <hpx/components/containers/coarray/coarray.hpp>
#include <hpx/collectives/spmd_block.hpp>
// The following code generates all necessary boiler plate to enable the
// co-creation of 'coarray'
//
HPX_REGISTER_COARRAY(double);
// Parallel section (suppose 'block' an spmd_block instance)
{
using hpx::container::placeholders::_;
std::size_t height=32, width=4, segment_size=10;
hpx::coarray<double,3> a(block, "a", {height,width,_}, segment_size);
/* Do some code */
}
Unlike segmented containers, a co-array object can only be instantiated within a parallel section. Here is the description of the parameters to provide to the coarray constructor:
Parameter |
Description |
|
Reference to a |
|
Symbolic name of type |
|
Dimensions of the |
|
Size of a co-indexed element (i.e. size of the object referenced by the
expression |
Note that the “last dimension size” cannot be set by the user. It only accepts
the constexpr variable hpx::container::placeholders::_. This size, which is
considered private, is equal to the number of current images (value returned by
block.get_num_images()).
Note
An important constraint to remember about coarray objects is that all segments sharing the same “last dimension index” are located in the same image.
The member functions owned by the coarray objects are exactly the same as
those of spmd multidimensional views. These are:
* Subscript-based operations
* Iterator-based operations
However, one additional functionality is provided. Knowing that the element
a(i,j,k) is in the memory of the kth image, the use of local subscripts
is possible.
Note
For spmd multidimensional views, subscripts are only global as it still involves potential remote data transfers.
Here is an example of using local subscripts:
#include <hpx/components/containers/coarray/coarray.hpp>
#include <hpx/collectives/spmd_block.hpp>
// The following code generates all necessary boiler plate to enable the
// co-creation of 'coarray'
//
HPX_REGISTER_COARRAY(double);
// Parallel section (suppose 'block' an spmd_block instance)
{
using hpx::container::placeholders::_;
std::size_t height=32, width=4, segment_size=10;
hpx::coarray<double,3> a(block, "a", {height,width,_}, segment_size);
double idx = block.this_image()*height*width;
for (std::size_t j = 0; j<width; j++)
for (std::size_t i = 0; i<height; i++)
{
// Local write operation performed via the use of local subscript
a(i,j,_) = std::vector<double>(elt_size,idx);
idx++;
}
block.sync_all();
}
Note
When the “last dimension index” of a subscript is equal to
hpx::container::placeholders::_, local subscript (and not global
subscript) is used. It is equivalent to a global subscript used with a “last
dimension index” equal to the value returned by block.this_image().
Running on batch systems¶
This section walks you through launching HPX applications on various batch systems.
How to use HPX applications with PBS¶
Most HPX applications are executed on parallel computers. These platforms typically provide integrated job management services that facilitate the allocation of computing resources for each parallel program. HPX includes support for one of the most common job management systems, the Portable Batch System (PBS).
All PBS jobs require a script to specify the resource requirements and other
parameters associated with a parallel job. The PBS script is basically a shell
script with PBS directives placed within commented sections at the beginning of
the file. The remaining (not commented-out) portions of the file executes just
like any other regular shell script. While the description of all available PBS
options is outside the scope of this tutorial (the interested reader may refer
to in-depth documentation for
more information), below is a minimal example to illustrate the approach. The following
test application will use the multithreaded hello_world_distributed
program, explained in the section Remote execution with actions: Hello world.
#!/bin/bash
#
#PBS -l nodes=2:ppn=4
APP_PATH=~/packages/hpx/bin/hello_world_distributed
APP_OPTIONS=
pbsdsh -u $APP_PATH $APP_OPTIONS --hpx:nodes=`cat $PBS_NODEFILE`
Caution
If the first application specific argument (inside $APP_OPTIONS) is a
non-option (i.e., does not start with a - or a --), then the argument has to
be placed before the option --hpx:nodes, which, in this case, should
be the last option on the command line.
Alternatively, use the option --hpx:endnodes to explicitly mark the
end of the list of node names:
pbsdsh -u $APP_PATH --hpx:nodes`cat $PBS_NODEFILE` --hpx:endnodes $APP_OPTIONS
The #PBS -l nodes=2:ppn=4 directive will cause two compute nodes to be
allocated for the application, as specified in the option nodes. Each of the
nodes will dedicate four cores to the program, as per the option ppn, short
for “processors per node” (PBS does not distinguish between processors and
cores). Note that requesting more cores per node than physically available is
pointless and may prevent PBS from accepting the script.
On newer PBS versions the PBS command syntax might be different. For instance, the PBS script above would look like:
#!/bin/bash
#
#PBS -l select=2:ncpus=4
APP_PATH=~/packages/hpx/bin/hello_world_distributed
APP_OPTIONS=
pbsdsh -u $APP_PATH $APP_OPTIONS --hpx:nodes=`cat $PBS_NODEFILE`
APP_PATH and APP_OPTIONS are shell variables that respectively specify
the correct path to the executable (hello_world_distributed in this case)
and the command line options. Since the hello_world_distributed application
doesn’t need any command line options, APP_OPTIONS has been left empty.
Unlike in other execution environments, there is no need to use the
--hpx:threads option to indicate the required number of OS threads per
node; the HPX library will derive this parameter automatically from PBS.
Finally, pbsdsh is a PBS command that starts tasks to the resources allocated to the current job. It is recommended to leave this line as shown and modify only the PBS options and shell variables as needed for a specific application.
Important
A script invoked by pbsdsh starts in a very basic environment: the user’s
$HOME directory is defined and is the current directory, the LANG
variable is set to C and the PATH is set to the basic
/usr/local/bin:/usr/bin:/bin as defined in a system-wide file
pbs_environment. Nothing that would normally be set up by a system shell
profile or user shell profile is defined, unlike the environment for the main
job script.
Another choice is for the pbsdsh command in your main job script to invoke
your program via a shell, like sh or bash, so that it gives an initialized
environment for each instance. Users can create a small script runme.sh, which is used
to invoke the program:
#!/bin/bash
# Small script which invokes the program based on what was passed on its
# command line.
#
# This script is executed by the bash shell which will initialize all
# environment variables as usual.
$@
Now, the script is invoked using the pbsdsh tool:
#!/bin/bash
#
#PBS -l nodes=2:ppn=4
APP_PATH=~/packages/hpx/bin/hello_world_distributed
APP_OPTIONS=
pbsdsh -u runme.sh $APP_PATH $APP_OPTIONS --hpx:nodes=`cat $PBS_NODEFILE`
All that remains now is submitting the job to the queuing system. Assuming that
the contents of the PBS script were saved in the file pbs_hello_world.sh in the
current directory, this is accomplished by typing:
qsub ./pbs_hello_world_pbs.sh
If the job is accepted, qsub will print out the assigned job ID, which may look like:
$ 42.supercomputer.some.university.edu
To check the status of your job, issue the following command:
qstat 42.supercomputer.some.university.edu
and look for a single-letter job status symbol. The common cases include:
Q - signifies that the job is queued and awaiting its turn to be executed.
R - indicates that the job is currently running.
C - means that the job has completed.
The example qstat output below shows a job waiting for execution resources to become available:
Job id Name User Time Use S Queue
------------------------- ---------------- --------------- -------- - -----
42.supercomputer ...ello_world.sh joe_user 0 Q batch
After the job completes, PBS will place two files, pbs_hello_world.sh.o42 and
pbs_hello_world.sh.e42, in the directory where the job was submitted. The
first contains the standard output and the second contains the standard error
from all the nodes on which the application executed. In our example, the error
output file should be empty and the standard output file should contain something
similar to:
hello world from OS-thread 3 on locality 0
hello world from OS-thread 2 on locality 0
hello world from OS-thread 1 on locality 1
hello world from OS-thread 0 on locality 0
hello world from OS-thread 3 on locality 1
hello world from OS-thread 2 on locality 1
hello world from OS-thread 1 on locality 0
hello world from OS-thread 0 on locality 1
Congratulations! You have just run your first distributed HPX application!
How to use HPX applications with SLURM¶
Just like PBS (described in section How to use HPX applications with PBS), SLURM is a job management system which is widely used on large supercomputing systems. Any HPX application can easily be run using SLURM. This section describes how this can be done.
The easiest way to run an HPX application using SLURM is to utilize the command line tool srun, which interacts with the SLURM batch scheduling system:
srun -p <partition> -N <number-of-nodes> hpx-application <application-arguments>
Here, <partition> is one of the node partitions existing on the target
machine (consult the machine’s documentation to get a list of existing
partitions) and <number-of-nodes> is the number of compute nodes that should
be used. By default, the HPX application is started with one locality per
node and uses all available cores on a node. You can change the number of
localities started per node (for example, to account for NUMA effects) by
specifying the -n option of srun. The number of cores per locality
can be set by -c. The <application-arguments> are any application
specific arguments that need to be passed on to the application.
Note
There is no need to use any of the HPX command line options related to the number of localities, number of threads, or related to networking ports. All of this information is automatically extracted from the SLURM environment by the HPX startup code.
Important
The srun documentation explicitly states: “If -c is specified without
-n, as many tasks will be allocated per node as possible while satisfying
the -c restriction. For instance on a cluster with 8 CPUs per node, a job
request for 4 nodes and 3 CPUs per task may be allocated 3 or 6 CPUs per node
(1 or 2 tasks per node) depending upon resource consumption by other jobs.”
For this reason, it’s recommended to always specify -n <number-of-instances>,
even if <number-of-instances> is equal to one (1).
Interactive shells¶
To get an interactive development shell on one of the nodes, users can issue the following command:
srun -p <node-type> -N <number-of-nodes> --pty /bin/bash -l
After the shell has been opened, users can run their HPX application. By default,
it uses all available cores. Note that if you requested one node, you don’t need
to do srun again. However, if you requested more than one node, and want to
run your distributed application, you can use srun again to start up the
distributed HPX application. It will use the resources that have been requested
for the interactive shell.
Scheduling batch jobs¶
The above mentioned method of running HPX applications is fine for development
purposes. The disadvantage that comes with srun is that it only returns once
the application is finished. This might not be appropriate for longer-running
applications (for example, benchmarks or larger scale simulations). In order to
cope with that limitation, users can use the sbatch command.
The sbatch command expects a script that it can run once the requested
resources are available. In order to request resources, users need to add
#SBATCH comments in their script or provide the necessary parameters to
sbatch directly. The parameters are the same as with run. The commands
you need to execute are the same you would need to start your application as if
you were in an interactive shell.
Debugging HPX applications¶
Using a debugger with HPX applications¶
Using a debugger such as gdb with HPX applications is no problem. However,
there are some things to keep in mind to make the experience somewhat more
productive.
Call stacks in HPX can often be quite unwieldy as the library is heavily
templated and the call stacks can be very deep. For this reason it is sometimes
a good idea compile HPX in RelWithDebInfo mode, which applies some
optimizations but keeps debugging symbols. This can often compress call stacks
significantly. On the other hand, stepping through the code can also be more
difficult because of statements being reordered and variables being optimized
away. Also, note that because HPX implements user-space threads and context
switching, call stacks may not always be complete in a debugger.
HPX launches not only worker threads but also a few helper threads. The first thread is the main thread, which typically does no work in an HPX application, except at startup and shutdown. If using the default settings, HPX will spawn six additional threads (used for service thread pools). The first worker thread is usually the eighth thread, and most user codes will be run on these worker threads. The last thread is a helper thread used for HPX shutdown.
Finally, since HPX is a multi-threaded runtime, the following gdb options
can be helpful:
set pagination off
set non-stop on
Non-stop mode allows users to have a single thread stop on a breakpoint without stopping all other threads as well.
Using sanitizers with HPX applications¶
Warning
Not all parts of HPX are sanitizer clean. This means that users may end up with false positives from HPX itself when using sanitizers for their applications.
To use sanitizers with HPX, turn on HPX_WITH_SANITIZERS and turn
off HPX_WITH_STACKOVERFLOW_DETECTION during CMake configuration. It’s
recommended to also build Boost with the same sanitizers that will be
used for HPX. The appropriate sanitizers can then be enabled using CMake by
appending -fsanitize=address -fno-omit-frame-pointer to CMAKE_CXX_FLAGS
and -fsanitize=address to CMAKE_EXE_LINKER_FLAGS. Replace address
with the sanitizer that you want to use.
Optimizing HPX applications¶
Performance counters¶
Performance counters in HPX are used to provide information as to how well the runtime system or an application is performing. The counter data can help determine system bottlenecks, and fine-tune system and application performance. The HPX runtime system, its networking, and other layers provide counter data that an application can consume to provide users with information about how well the application is performing.
Applications can also use counter data to determine how much system resources to consume. For example, an application that transfers data over the network could consume counter data from a network switch to determine how much data to transfer without competing for network bandwidth with other network traffic. The application could use the counter data to adjust its transfer rate as the bandwidth usage from other network traffic increases or decreases.
Performance counters are HPX parallel processes that expose a predefined interface. HPX exposes special API functions that allow one to create, manage, and read the counter data, and release instances of performance counters. Performance Counter instances are accessed by name, and these names have a predefined structure which is described in the section Performance counter names. The advantage of this is that any Performance Counter can be accessed remotely (from a different locality) or locally (from the same locality). Moreover, since all counters expose their data using the same API, any code consuming counter data can be utilized to access arbitrary system information with minimal effort.
Counter data may be accessed in real time. More information about how to consume counter data can be found in the section Consuming performance counter data.
All HPX applications provide command line options related to performance counters, such as the ability to list available counter types, or periodically query specific counters to be printed to the screen or save them in a file. For more information, please refer to the section HPX Command Line Options.
Performance counter names¶
All Performance Counter instances have a name uniquely identifying each instance. This name can be used to access the counter, retrieve all related meta data, and to query the counter data (as described in the section Consuming performance counter data). Counter names are strings with a predefined structure. The general form of a countername is:
/objectname{full_instancename}/countername@parameters
where full_instancename could be either another (full) counter name or a
string formatted as:
parentinstancename#parentindex/instancename#instanceindex
Each separate part of a countername (e.g., objectname, countername
parentinstancename, instancename, and parameters) should start with
a letter ('a'…'z', 'A'…'Z') or an underscore
character ('_'), optionally followed by letters, digits ('0'…'9'), hyphen ('-'), or underscore characters. Whitespace is not allowed
inside a counter name. The characters '/', '{', '}', '#' and
'@' have a special meaning and are used to delimit the different parts of
the counter name.
The parts parentinstanceindex and instanceindex are integers. If an
index is not specified, HPX will assume a default of -1.
Two counter name examples¶
This section gives examples of both simple counter names and aggregate counter names. For more information on simple and aggregate counter names, please see Performance counter instances.
An example of a well-formed (and meaningful) simple counter name would be:
/threads{locality#0/total}/count/cumulative
This counter returns the current cumulative number of executed (retired)
HPX threads for the locality 0. The counter type of this counter
is /threads/count/cumulative and the full instance name is
locality#0/total. This counter type does not require an instanceindex or
parameters to be specified.
In this case, the parentindex (the '0') designates the locality
for which the counter instance is created. The counter will return the number of
HPX threads retired on that particular locality.
Another example for a well formed (aggregate) counter name is:
/statistics{/threads{locality#0/total}/count/cumulative}/average@500
This counter takes the simple counter from the first example, samples its values
every 500 milliseconds, and returns the average of the value samples
whenever it is queried. The counter type of this counter is
/statistics/average and the instance name is the full name of the counter
for which the values have to be averaged. In this case, the parameters (the
'500') specify the sampling interval for the averaging to take place (in
milliseconds).
Performance counter types¶
Every performance counter belongs to a specific performance counter type which
classifies the counters into groups of common semantics. The type of a counter
is identified by the objectname and the countername parts of the name.
/objectname/countername
When an application starts HPX will register all available counter types on each of the localities. These counter types are held in a special performance counter registration database, which can be used to retrieve the meta data related to a counter type and to create counter instances based on a given counter instance name.
Performance counter instances¶
The full_instancename distinguishes different counter instances of the same
counter type. The formatting of the full_instancename depends on the counter
type. There are two types of counters: simple counters, which usually generate
the counter values based on direct measurements, and aggregate counters, which
take another counter and transform its values before generating their own
counter values. An example for a simple counter is given above:
counting retired HPX threads. An aggregate counter is shown as an example
above as well: calculating the average of the underlying
counter values sampled at constant time intervals.
While simple counters use instance names formatted as
parentinstancename#parentindex/instancename#instanceindex, most aggregate
counters have the full counter name of the embedded counter as their instance
name.
Not all simple counter types require specifying all four elements of a full counter
instance name; some of the parts (parentinstancename, parentindex,
instancename, and instanceindex) are optional for specific counters.
Please refer to the documentation of a particular counter for more information
about the formatting requirements for the name of this counter (see
Existing HPX performance counters).
The parameters are used to pass additional information to a counter at
creation time. They are optional, and they fully depend on the concrete counter.
Even if a specific counter type allows additional parameters to be given, those
usually are not required as sensible defaults will be chosen. Please refer to
the documentation of a particular counter for more information about what
parameters are supported, how to specify them, and what default values are
assumed (see also Existing HPX performance counters).
Every locality of an application exposes its own set of performance counter types and performance counter instances. The set of exposed counters is determined dynamically at application start based on the execution environment of the application. For instance, this set is influenced by the current hardware environment for the locality (such as whether the locality has access to accelerators), and the software environment of the application (such as the number of OS threads used to execute HPX threads).
Using wildcards in performance counter names¶
It is possible to use wildcard characters when specifying performance counter names. Performance counter names can contain two types of wildcard characters:
Wildcard characters in the performance counter type
Wildcard characters in the performance counter instance name
A wildcard character has a meaning which is very close to usual file name wildcard matching rules implemented by common shells (like bash).
Wildcard |
Description |
|
This wildcard character matches any number (zero or more) of arbitrary characters. |
|
This wildcard character matches any single arbitrary character. |
|
This wildcard character matches any single character from the list of specified within the square brackets. |
Wildcard |
Description |
|
This wildcard character matches any locality or any thread,
depending on whether it is used for |
Consuming performance counter data¶
You can consume performance data using either the command line interface, the HPX application or the HPX API. The command line interface is easier to use, but it is less flexible and does not allow one to adjust the behaviour of your application at runtime. The command line interface provides a convenience abstraction but simplified abstraction for querying and logging performance counter data for a set of performance counters.
Consuming performance counter data from the command line¶
HPX provides a set of predefined command line options for every application
that uses hpx::init for its initialization. While there are many more
command line options available (see HPX Command Line Options), the set of options related
to performance counters allows one to list existing counters, and query existing
counters once at application termination or repeatedly after a constant time
interval.
The following table summarizes the available command line options:
Command line option |
Description |
|
Prints the specified performance counter either repeatedly and/or at the
times specified by |
|
Prints the specified performance counter either repeatedly and/or at the
times specified by |
|
Prints the performance counter(s) specified with |
|
Prints the performance counter(s) specified with |
|
Lists the names of all registered performance counters. |
|
Lists the description of all registered performance counters. |
|
Prints the performance counter(s) specified with |
|
Prints the performance counter(s) specified with |
|
Prints the performance counter(s) specified with |
|
Resets all performance counter(s) specified with |
|
Appends counter type description to generated output. |
|
Each locality prints only its own local counters. |
While the options --hpx:list-counters and --hpx:list-counter-infos give
a short list of all available counters, the full documentation for those can
be found in the section Existing HPX performance counters.
A simple example¶
All of the commandline options mentioned above can be tested using
the hello_world_distributed example.
Listing all available counters hello_world_distributed --hpx:list-counters
yields:
List of available counter instances (replace * below with the appropriate
sequence number)
-------------------------------------------------------------------------
/agas/count/allocate /agas/count/bind /agas/count/bind_gid
/agas/count/bind_name ... /threads{locality#*/allocator#*}/count/objects
/threads{locality#*/total}/count/stack-recycles
/threads{locality#*/total}/idle-rate
/threads{locality#*/worker-thread#*}/idle-rate
Providing more information about all available counters,
hello_world_distributed --hpx:list-counter-infos yields:
Information about available counter instances (replace * below with the
appropriate sequence number)
------------------------------------------------------------------------------
fullname: /agas/count/allocate helptext: returns the number of invocations of
the AGAS service 'allocate' type: counter_raw version: 1.0.0
------------------------------------------------------------------------------
------------------------------------------------------------------------------
fullname: /agas/count/bind helptext: returns the number of invocations of the
AGAS service 'bind' type: counter_raw version: 1.0.0
------------------------------------------------------------------------------
------------------------------------------------------------------------------
fullname: /agas/count/bind_gid helptext: returns the number of invocations of
the AGAS service 'bind_gid' type: counter_raw version: 1.0.0
------------------------------------------------------------------------------
...
This command will not only list the counter names but also a short description of the data exposed by this counter.
Note
The list of available counters may differ depending on the concrete execution environment (hardware or software) of your application.
Requesting the counter data for one or more performance counters can be achieved
by invoking hello_world_distributed with a list of counter names:
hello_world_distributed \
--hpx:print-counter=/threads{locality#0/total}/count/cumulative \
--hpx:print-counter=/agas{locality#0/total}/count/bind
which yields for instance:
hello world from OS-thread 0 on locality 0
/threads{locality#0/total}/count/cumulative,1,0.212527,[s],33
/agas{locality#0/total}/count/bind,1,0.212790,[s],11
The first line is the normal output generated by hello_world_distributed and
has no relation to the counter data listed. The last two lines contain the
counter data as gathered at application shutdown. These lines have six fields, the
counter name, the sequence number of the counter invocation, the time stamp at
which this information has been sampled, the unit of measure for the time stamp,
the actual counter value and an optional unit of measure for the counter value.
Note
The command line option --hpx:print-counter-types will append a seventh
field to the generated output. This field will hold an abbreviated counter
type.
The actual counter value can be represented by a single number (for counters
returning singular values) or a list of numbers separated by ':' (for
counters returning an array of values, like for instance a histogram).
Note
The name of the performance counter will be enclosed in double quotes '"'
if it contains one or more commas ','.
Requesting to query the counter data once after a constant time interval with this command line:
hello_world_distributed \
--hpx:print-counter=/threads{locality#0/total}/count/cumulative \
--hpx:print-counter=/agas{locality#0/total}/count/bind \
--hpx:print-counter-interval=20
yields for instance (leaving off the actual console output of the
hello_world_distributed example for brevity):
threads{locality#0/total}/count/cumulative,1,0.002409,[s],22
agas{locality#0/total}/count/bind,1,0.002542,[s],9
threads{locality#0/total}/count/cumulative,2,0.023002,[s],41
agas{locality#0/total}/count/bind,2,0.023557,[s],10
threads{locality#0/total}/count/cumulative,3,0.037514,[s],46
agas{locality#0/total}/count/bind,3,0.038679,[s],10
The command --hpx:print-counter-destination=<file> will redirect all counter
data gathered to the specified file name, which avoids cluttering the console
output of your application.
The command line option --hpx:print-counter supports using a limited set of
wildcards for a (very limited) set of use cases. In particular, all occurrences
of #* as in locality#* and in worker-thread#* will be automatically
expanded to the proper set of performance counter names representing the actual
environment for the executed program. For instance, if your program is utilizing
four worker threads for the execution of HPX threads (see command line option
--hpx:threads) the following command line
hello_world_distributed \
--hpx:threads=4 \
--hpx:print-counter=/threads{locality#0/worker-thread#*}/count/cumulative
will print the value of the performance counters monitoring each of the worker threads:
hello world from OS-thread 1 on locality 0
hello world from OS-thread 0 on locality 0
hello world from OS-thread 3 on locality 0
hello world from OS-thread 2 on locality 0
/threads{locality#0/worker-thread#0}/count/cumulative,1,0.0025214,[s],27
/threads{locality#0/worker-thread#1}/count/cumulative,1,0.0025453,[s],33
/threads{locality#0/worker-thread#2}/count/cumulative,1,0.0025683,[s],29
/threads{locality#0/worker-thread#3}/count/cumulative,1,0.0025904,[s],33
The command --hpx:print-counter-format takes values csv and
csv-short to generate CSV formatted counter values with a header.
With format as csv:
hello_world_distributed \
--hpx:threads=2 \
--hpx:print-counter-format csv \
--hpx:print-counter /threads{locality#*/total}/count/cumulative \
--hpx:print-counter /threads{locality#*/total}/count/cumulative-phases
will print the values of performance counters in CSV format with the full countername as a header:
hello world from OS-thread 1 on locality 0
hello world from OS-thread 0 on locality 0
/threads{locality#*/total}/count/cumulative,/threads{locality#*/total}/count/cumulative-phases
39,93
With format csv-short:
hello_world_distributed \
--hpx:threads 2 \
--hpx:print-counter-format csv-short \
--hpx:print-counter cumulative,/threads{locality#*/total}/count/cumulative \
--hpx:print-counter phases,/threads{locality#*/total}/count/cumulative-phases
will print the values of performance counters in CSV format with the short countername as a header:
hello world from OS-thread 1 on locality 0
hello world from OS-thread 0 on locality 0
cumulative,phases
39,93
With format csv and csv-short when used with --hpx:print-counter-interval:
hello_world_distributed \
--hpx:threads 2 \
--hpx:print-counter-format csv-short \
--hpx:print-counter cumulative,/threads{locality#*/total}/count/cumulative \
--hpx:print-counter phases,/threads{locality#*/total}/count/cumulative-phases \
--hpx:print-counter-interval 5
will print the header only once repeating the performance counter value(s) repeatedly:
cum,phases
25,42
hello world from OS-thread 1 on locality 0
hello world from OS-thread 0 on locality 0
44,95
The command --hpx:no-csv-header can be used with
--hpx:print-counter-format to print performance counter values in CSV format
without any header:
hello_world_distributed \
--hpx:threads 2 \
--hpx:print-counter-format csv-short \
--hpx:print-counter cumulative,/threads{locality#*/total}/count/cumulative \
--hpx:print-counter phases,/threads{locality#*/total}/count/cumulative-phases \
--hpx:no-csv-header
will print:
hello world from OS-thread 1 on locality 0
hello world from OS-thread 0 on locality 0
37,91
Consuming performance counter data using the HPX API¶
HPX provides an API that allows users to discover performance counters and to retrieve the current value of any existing performance counter from any application.
Discover existing performance counters¶
Retrieve the current value of any performance counter¶
Performance counters are specialized HPX components. In order to retrieve a counter value, the performance counter needs to be instantiated. HPX exposes a client component object for this purpose:
hpx::performance_counters::performance_counter counter(std::string const& name);
Instantiating an instance of this type will create the performance counter
identified by the given name. Only the first invocation for any given counter
name will create a new instance of that counter. All following invocations for a
given counter name will reference the initially created instance. This ensures
that at any point in time there is never more than one active instance of
any of the existing performance counters.
In order to access the counter value (or to invoke any of the other functionality
related to a performance counter, like start, stop or reset) member
functions of the created client component instance should be called:
// print the current number of threads created on locality 0
hpx::performance_counters::performance_counter count(
"/threads{locality#0/total}/count/cumulative");
hpx::cout << count.get_value<int>().get() << hpx::endl;
For more information about the client component type, see
hpx::performance_counters::performance_counter
Note
In the above example count.get_value() returns a future. In order to print
the result we must append .get() to retrieve the value. You could write the
above example like this for more clarity:
// print the current number of threads created on locality 0
hpx::performance_counters::performance_counter count(
"/threads{locality#0/total}/count/cumulative");
hpx::future<int> result = count.get_value<int>();
hpx::cout << result.get() << hpx::endl;
Providing performance counter data¶
HPX offers several ways by which you may provide your own data as a performance counter. This has the benefit of exposing additional, possibly application-specific information using the existing Performance Counter framework, unifying the process of gathering data about your application.
An application that wants to provide counter data can implement a performance counter to provide the data. When a consumer queries performance data, the HPX runtime system calls the provider to collect the data. The runtime system uses an internal registry to determine which provider to call.
Generally, there are two ways of exposing your own performance counter data: a simple, function-based way and a more complex, but more powerful way of implementing a full performance counter. Both alternatives are described in the following sections.
Exposing performance counter data using a simple function¶
The simplest way to expose arbitrary numeric data is to write a function which will then be called whenever a consumer queries this counter. Currently, this type of performance counter can only be used to expose integer values. The expected signature of this function is:
std::int64_t some_performance_data(bool reset);
The argument bool reset (which is supplied by the runtime system when the
function is invoked) specifies whether the counter value should be reset after
evaluating the current value (if applicable).
For instance, here is such a function returning how often it was invoked:
// The atomic variable 'counter' ensures the thread safety of the counter.
boost::atomic<std::int64_t> counter(0);
std::int64_t some_performance_data(bool reset)
{
std::int64_t result = ++counter;
if (reset)
counter = 0;
return result;
}
This example function exposes a linearly-increasing value as our performance data. The value is incremented on each invocation, i.e., each time a consumer requests the counter data of this performance counter.
The next step in exposing this counter to the runtime system is to register the
function as a new raw counter type using the HPX API function
hpx::performance_counters::install_counter_type. A counter type
represents certain common characteristics of counters, like their counter type
name and any associated description information. The following snippet shows an
example of how to register the function some_performance_data, which is shown
above, for a counter type named "/test/data". This registration has to be
executed before any consumer instantiates, and queries an instance of this
counter type:
#include <hpx/include/performance_counters.hpp>
void register_counter_type()
{
// Call the HPX API function to register the counter type.
hpx::performance_counters::install_counter_type(
"/test/data", // counter type name
&some_performance_data, // function providing counter data
"returns a linearly increasing counter value" // description text (optional)
"" // unit of measure (optional)
);
}
Now it is possible to instantiate a new counter instance based on the naming
scheme "/test{locality#*/total}/data" where * is a zero-based integer
index identifying the locality for which the counter instance should be
accessed. The function
hpx::performance_counters::install_counter_type enables users to
instantiate exactly one counter instance for each locality. Repeated
requests to instantiate such a counter will return the same instance, i.e., the
instance created for the first request.
If this counter needs to be accessed using the standard HPX command line
options, the registration has to be performed during application startup, before
hpx_main is executed. The best way to achieve this is to register an HPX
startup function using the API function
hpx::register_startup_function before calling hpx::init to
initialize the runtime system:
int main(int argc, char* argv[])
{
// By registering the counter type we make it available to any consumer
// who creates and queries an instance of the type "/test/data".
//
// This registration should be performed during startup. The
// function 'register_counter_type' should be executed as an HPX thread right
// before hpx_main is executed.
hpx::register_startup_function(®ister_counter_type);
// Initialize and run HPX.
return hpx::init(argc, argv);
}
Please see the code in simplest_performance_counter.cpp
for a full example demonstrating this functionality.
Implementing a full performance counter¶
Sometimes, the simple way of exposing a single value as a performance counter is not sufficient. For that reason, HPX provides a means of implementing full performance counters which support:
Retrieving the descriptive information about the performance counter
Retrieving the current counter value
Resetting the performance counter (value)
Starting the performance counter
Stopping the performance counter
Setting the (initial) value of the performance counter
Every full performance counter will implement a predefined interface:
// Copyright (c) 2007-2020 Hartmut Kaiser
//
// SPDX-License-Identifier: BSL-1.0
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#pragma once
#include <hpx/config.hpp>
#include <hpx/async_base/launch_policy.hpp>
#include <hpx/components/client_base.hpp>
#include <hpx/functional/bind_front.hpp>
#include <hpx/futures/future.hpp>
#include <hpx/modules/execution.hpp>
#include <hpx/performance_counters/counters_fwd.hpp>
#include <hpx/performance_counters/server/base_performance_counter.hpp>
#include <string>
#include <utility>
#include <vector>
///////////////////////////////////////////////////////////////////////////////
namespace hpx { namespace performance_counters {
///////////////////////////////////////////////////////////////////////////
struct HPX_EXPORT performance_counter
: components::client_base<performance_counter,
server::base_performance_counter>
{
using base_type = components::client_base<performance_counter,
server::base_performance_counter>;
performance_counter() = default;
performance_counter(std::string const& name);
performance_counter(
std::string const& name, hpx::id_type const& locality);
performance_counter(id_type const& id)
: base_type(id)
{
}
performance_counter(future<id_type>&& id)
: base_type(std::move(id))
{
}
performance_counter(hpx::future<performance_counter>&& c)
: base_type(std::move(c))
{
}
///////////////////////////////////////////////////////////////////////
future<counter_info> get_info() const;
counter_info get_info(
launch::sync_policy, error_code& ec = throws) const;
future<counter_value> get_counter_value(bool reset = false);
counter_value get_counter_value(
launch::sync_policy, bool reset = false, error_code& ec = throws);
future<counter_value> get_counter_value() const;
counter_value get_counter_value(
launch::sync_policy, error_code& ec = throws) const;
future<counter_values_array> get_counter_values_array(
bool reset = false);
counter_values_array get_counter_values_array(
launch::sync_policy, bool reset = false, error_code& ec = throws);
future<counter_values_array> get_counter_values_array() const;
counter_values_array get_counter_values_array(
launch::sync_policy, error_code& ec = throws) const;
///////////////////////////////////////////////////////////////////////
future<bool> start();
bool start(launch::sync_policy, error_code& ec = throws);
future<bool> stop();
bool stop(launch::sync_policy, error_code& ec = throws);
future<void> reset();
void reset(launch::sync_policy, error_code& ec = throws);
future<void> reinit(bool reset = true);
void reinit(
launch::sync_policy, bool reset = true, error_code& ec = throws);
///////////////////////////////////////////////////////////////////////
future<std::string> get_name() const;
std::string get_name(
launch::sync_policy, error_code& ec = throws) const;
private:
template <typename T>
static T extract_value(future<counter_value>&& value)
{
return value.get().get_value<T>();
}
public:
template <typename T>
future<T> get_value(bool reset = false)
{
return get_counter_value(reset).then(hpx::launch::sync,
util::bind_front(&performance_counter::extract_value<T>));
}
template <typename T>
T get_value(
launch::sync_policy, bool reset = false, error_code& ec = throws)
{
return get_counter_value(launch::sync, reset).get_value<T>(ec);
}
template <typename T>
future<T> get_value() const
{
return get_counter_value().then(hpx::launch::sync,
util::bind_front(&performance_counter::extract_value<T>));
}
template <typename T>
T get_value(launch::sync_policy, error_code& ec = throws) const
{
return get_counter_value(launch::sync).get_value<T>(ec);
}
};
// Return all counters matching the given name (with optional wild cards).
HPX_EXPORT std::vector<performance_counter> discover_counters(
std::string const& name, error_code& ec = throws);
}} // namespace hpx::performance_counters
In order to implement a full performance counter, you have to create an HPX
component exposing this interface. To simplify this task, HPX provides a
ready-made base class which handles all the boiler plate of creating
a component for you. The remainder of this section will explain the process of creating a full
performance counter based on the Sine example, which you can find in the
directory examples/performance_counters/sine/.
The base class is defined in the header file [hpx_link hpx/performance_counters/base_performance_counter.hpp..hpx/performance_counters/base_performance_counter.hpp] as:
// Copyright (c) 2007-2018 Hartmut Kaiser
//
// SPDX-License-Identifier: BSL-1.0
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#pragma once
#include <hpx/config.hpp>
#include <hpx/actions_base/component_action.hpp>
#include <hpx/components_base/component_type.hpp>
#include <hpx/components_base/server/component_base.hpp>
#include <hpx/performance_counters/counters.hpp>
#include <hpx/performance_counters/server/base_performance_counter.hpp>
///////////////////////////////////////////////////////////////////////////////
//[performance_counter_base_class
namespace hpx { namespace performance_counters {
template <typename Derived>
class base_performance_counter;
}} // namespace hpx::performance_counters
//]
///////////////////////////////////////////////////////////////////////////////
namespace hpx { namespace performance_counters {
template <typename Derived>
class base_performance_counter
: public hpx::performance_counters::server::base_performance_counter
, public hpx::components::component_base<Derived>
{
private:
typedef hpx::components::component_base<Derived> base_type;
public:
typedef Derived type_holder;
typedef hpx::performance_counters::server::base_performance_counter
base_type_holder;
base_performance_counter() {}
base_performance_counter(
hpx::performance_counters::counter_info const& info)
: base_type_holder(info)
{
}
// Disambiguate finalize() which is implemented in both base classes
void finalize()
{
base_type_holder::finalize();
base_type::finalize();
}
};
}} // namespace hpx::performance_counters
The single template parameter is expected to receive the type of the derived class implementing the performance counter. In the Sine example this looks like:
// Copyright (c) 2007-2012 Hartmut Kaiser
//
// SPDX-License-Identifier: BSL-1.0
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#pragma once
#include <hpx/config.hpp>
#if !defined(HPX_COMPUTE_DEVICE_CODE)
#include <hpx/hpx.hpp>
#include <hpx/include/lcos_local.hpp>
#include <hpx/include/performance_counters.hpp>
#include <hpx/include/util.hpp>
#include <cstdint>
namespace performance_counters { namespace sine { namespace server
{
///////////////////////////////////////////////////////////////////////////
//[sine_counter_definition
class sine_counter
: public hpx::performance_counters::base_performance_counter<sine_counter>
//]
{
public:
sine_counter() : current_value_(0), evaluated_at_(0) {}
explicit sine_counter(
hpx::performance_counters::counter_info const& info);
/// This function will be called in order to query the current value of
/// this performance counter
hpx::performance_counters::counter_value get_counter_value(bool reset);
/// The functions below will be called to start and stop collecting
/// counter values from this counter.
bool start();
bool stop();
/// finalize() will be called just before the instance gets destructed
void finalize();
protected:
bool evaluate();
private:
typedef hpx::lcos::local::spinlock mutex_type;
mutable mutex_type mtx_;
double current_value_;
std::uint64_t evaluated_at_;
hpx::util::interval_timer timer_;
};
}}}
#endif
i.e., the type sine_counter is derived from the base class passing the type
as a template argument (please see simplest_performance_counter.cpp
for the full source code of the counter definition). For more information about this
technique (called Curiously Recurring Template Pattern - CRTP), please see for
instance the corresponding Wikipedia article. This base
class itself is derived from the performance_counter interface described
above.
Additionally, a full performance counter implementation not only exposes the actual value but also provides information about:
The point in time a particular value was retrieved.
A (sequential) invocation count.
The actual counter value.
An optional scaling coefficient.
Information about the counter status.
Existing HPX performance counters¶
The HPX runtime system exposes a wide variety of predefined performance counters. These counters expose critical information about different modules of the runtime system. They can help determine system bottlenecks and fine-tune system and application performance.
Counter type |
Counter instance formatting |
Description |
Parameters |
where:
primary namespace services: component namespace services: locality namespace services: symbol namespace services: |
where:
The value for |
None |
Returns the total number of invocations of the specified AGAS service since its creation. |
where:
|
where:
|
None |
Returns the overall total number of invocations of all AGAS services provided by the given AGAS service category since its creation. |
where:
primary namespace services: component namespace services: locality namespace services: symbol namespace services: |
where:
The value for |
None |
Returns the overall execution time of the specified AGAS service since its creation (in nanoseconds). |
where:
|
where:
|
None |
Returns the overall execution time of all AGAS services provided by the given AGAS service category since its creation (in nanoseconds). |
|
where:
|
None |
Returns the number of cache entries resident in the AGAS cache of
the specified locality (see |
where:
|
where:
|
None |
Returns the number of cache events (evictions, hits, inserts, and misses)
in the AGAS cache of the specified locality (see
|
where:
|
where:
|
None |
Returns the number of invocations of the specified cache API function of the AGAS cache. |
where:
|
where:
|
None |
Returns the overall time spent executing of the specified API function of the AGAS cache. |
Counter type |
Counter instance formatting |
Description |
Parameters |
where:
|
where:
|
Returns the overall number of raw (uncompressed) bytes sent or received
(see The performance counters for the connection type Please see CMake variables used to configure HPX for more details. |
None |
where:
|
where:
|
Returns the total time (in nanoseconds) between the start of each
asynchronous transmission operation and the end of the corresponding
operation for the specified The performance counters for the connection type Please see CMake variables used to configure HPX for more details. |
None |
where:
|
where:
|
Returns the overall number of bytes transferred (see The performance counters for the connection type Please see CMake variables used to configure HPX for more details. |
If the configure-time option |
where:
|
where:
|
Returns the overall time spent performing outgoing data serialization for
the specified The performance counters for the connection type Please see CMake variables used to configure HPX for more details. |
If the configure-time option |
|
where:
|
Returns the overall number of routed (outbound) parcels transferred by the given locality. Routed parcels are those which cannot directly be delivered to its destination as the local AGAS is not able to resolve the destination address. In this case a parcel is sent to the AGAS service component which is responsible for creating the destination GID (and is responsible for resolving the destination address). This AGAS service component will deliver the parcel to its final target. |
If the configure-time option |
where:
|
where:
|
Returns the overall number of parcels transferred using the specified
The performance counters for the connection type Please see CMake variables used to configure HPX for more details. |
None |
where:
|
where:
|
Returns the overall number of messages 1 transferred using the
specified The performance counters for the connection type Please see CMake variables used to configure HPX for more details. |
None |
where:
<connection_type` is one of the following: |
where:
|
Returns the overall number cache events (evictions, hits, inserts,
misses, and reclaims) for the connection cache of the given connection
type on the given locality (see The performance counters for the connection type Please see CMake variables used to configure HPX for more details. |
None |
where:
|
where:
|
Returns the current number of parcels stored in the parcel queue (see
|
None |
Counter type |
Counter instance formatting |
Description |
Parameters |
|
where:
|
Returns the overall number of executed (retired) HPX-threads on the
given locality since application start. If the instance name is
|
None |
|
where:
|
Returns the average time spent executing one HPX-thread on the given
locality since application start. If the instance name is |
None |
|
where:
|
Returns the average time spent on overhead while executing one
HPX-thread on the given locality since application start. If
the instance name is |
None |
|
where:
|
Returns the overall number of executed HPX-thread phases (invocations)
on the given locality since application start. If the instance
name is |
None |
|
where:
|
Returns the average time spent executing one HPX-thread phase
(invocation) on the given locality since application start. If
the instance name is |
None |
|
where:
|
Returns the average time spent on overhead executing one HPX-thread
phase (invocation) on the given locality since application start.
If the instance name is |
None |
|
where:
|
Returns the overall time spent running the scheduler on the given
locality since application start. If the instance name is |
None |
|
where:
|
Returns the overall time spent executing all HPX-threads on the given
locality since application start. If the instance name is |
None |
|
where:
|
Returns the overall overhead time incurred executing all HPX-threads on
the given locality since application start. If the instance name
is |
None |
where:
|
where:
The |
Returns the current number of HPX-threads having the given thread state
on the given locality. If the instance name is |
None |
where:
|
where:
The |
Returns the average wait time of HPX-threads (if the thread state is
These counters are available only if the compile time constant
|
None |
|
where:
|
Returns the average idle rate for the given worker thread(s) on the given
locality. The idle rate is defined as the ratio of the time spent
on scheduling and management tasks and the overall time spent executing
work since the application started. This counter is available only if the
configuration time constant |
None |
|
where:
|
Returns the average idle rate for the given worker thread(s) on the given
locality which is caused by creating new threads. The creation idle
rate is defined as the ratio of the time spent on creating new threads and
the overall time spent executing work since the application started. This
counter is available only if the configuration time constants
|
None |
|
where:
|
Returns the average idle rate for the given worker thread(s) on the given
locality which is caused by cleaning up terminated threads. The
cleanup idle rate is defined as the ratio of the time spent on cleaning up
terminated thread objects and the overall time spent executing work since
the application started. This counter is available only if the
configuration time constants |
None |
|
where:
|
Returns the overall length of all queues for the given worker thread(s) on the given locality. |
None |
|
where:
|
Returns the total number of HPX-thread unbind (madvise) operations performed for the referenced locality. Note that this counter is not available on Windows based platforms. |
None |
|
where:
|
Returns the total number of HPX-thread recycling operations performed. |
None |
|
|
Returns the total number of HPX-threads ‘stolen’ from the pending
thread queue by a neighboring thread worker thread (these threads are
executed by a different worker thread than they were initially scheduled
on). This counter is available only if the configuration time constant
|
None |
|
where:
|
Returns the total number of times that the referenced worker-thread on
the referenced locality failed to find pending HPX-threads in
its associated queue. This counter is available only if the configuration
time constant |
None |
|
where:
|
Returns the total number of times that the referenced worker-thread on
the referenced locality looked for pending HPX-threads in its
associated queue. This counter is available only if the configuration
time constant |
None |
|
where:
|
Returns the total number of HPX-threads ‘stolen’ from the staged thread
queue by a neighboring worker thread (these threads are executed by a
different worker thread than they were initially scheduled on). This
counter is available only if the configuration time constant
|
None |
|
where:
|
Returns the total number of HPX-threads ‘stolen’ to the pending thread
queue of the worker thread (these threads are executed by a different
worker thread than they were initially scheduled on). This counter is
available only if the configuration time constant
|
None |
|
where:
|
Returns the total number of HPX-threads ‘stolen’ to the staged thread
queue of a neighboring worker thread (these threads are executed by a
different worker thread than they were initially scheduled on). This
counter is available only if the configuration time constant
|
None |
|
where:
|
Returns the total number of HPX-thread objects created. Note that thread objects are reused to improve system performance, thus this number does not reflect the number of actually executed (retired) HPX-threads. |
None |
|
where:
|
|
Percent |
|
where:
|
Returns the current (instantaneous) idle-loop count for the given HPX- worker thread or the accumulated value for all worker threads. |
None |
|
where:
|
Returns the current (instantaneous) busy-loop count for the given HPX- worker thread or the accumulated value for all worker threads. |
None |
|
where:
|
Returns the overall time spent performing background work on the given
locality since application start. If the instance name is |
None |
|
where:
|
Returns the background overhead on the given locality since application
start. If the instance name is |
None |
|
where:
|
Returns the overall time spent performing background work related to
sending parcels on the given locality since application start. If the
instance name is This counter will currently return meaningful values for the MPI parcelport only. |
None |
|
where:
|
Returns the background overhead related to sending parcels on the given
locality since application start. If the instance name is This counter will currently return meaningful values for the MPI parcelport only. |
None |
|
where:
|
Returns the overall time spent performing background work related to
receiving parcels on the given locality since application start. If the
instance name is This counter will currently return meaningful values for the MPI parcelport only. |
None |
|
where:
|
Returns the background overhead related to receiving parcels on the given
locality since application start. If the instance name is This counter will currently return meaningful values for the MPI parcelport only. |
None |
Counter type |
Counter instance formatting |
Description |
Parameters |
|
where:
|
Returns the overall number of currently active components of the specified type on the given locality. |
The type of the component. This is the string which has been used while
registering the component with HPX, e.g. which has been passed as the
second parameter to the macro |
|
|
Returns the overall (local) invocation count of the specified action type on the given locality. |
The action type. This is the string which has been used while registering
the action with HPX, e.g. which has been passed as the second parameter
to the macro |
|
where:
|
Returns the overall (remote) invocation count of the specified action type on the given locality. |
The action type. This is the string which has been used while registering
the action with HPX, e.g. which has been passed as the second parameter
to the macro |
|
where:
|
Returns the overall time since application start on the given locality in nanoseconds. |
None |
|
where:
|
Returns the amount of virtual memory currently allocated by the referenced locality (in bytes). |
None |
|
where:
|
Returns the amount of resident memory currently allocated by the referenced locality (in bytes). |
None |
|
where:
|
|
None |
|
where:
|
Returns the number of bytes read by the process (aggregate of count arguments passed to read() call or its analogues). This performance counter is available only on systems which expose the related data through the /proc file system. |
None |
|
where:
|
Returns the number of bytes written by the process (aggregate of count arguments passed to write() call or its analogues). This performance counter is available only on systems which expose the related data through the /proc file system. |
None |
|
where:
|
Returns the number of system calls that perform I/O reads. This performance counter is available only on systems which expose the related data through the /proc file system. |
None |
|
where:
|
Returns the number of system calls that perform I/O writes. This performance counter is available only on systems which expose the related data through the /proc file system. |
None |
|
where:
|
Returns the number of bytes retrieved from storage by I/O operations. This performance counter is available only on systems which expose the related data through the /proc file system. |
None |
|
where:
|
Returns the number of bytes retrieved from storage by I/O operations. This performance counter is available only on systems which expose the related data through the /proc file system. |
None |
|
where:
|
Returns the number of bytes accounted by write_bytes_transferred that has not been ultimately stored due to truncation or deletion. This performance counter is available only on systems which expose the related data through the /proc file system. |
None |
Counter type |
Counter instance formatting |
Description |
Parameters |
where:
For a full list of available PAPI events and their (short) description
use the |
where:
|
This counter returns the current count of occurrences of the specified
PAPI event. This counter is available only if the configuration time
constant |
None |
Counter type |
Counter instance formatting |
Description |
Parameters |
|
Any full performance counter name. The referenced performance counter is queried at fixed time intervals as specified by the first parameter. |
Returns the current average (mean) value calculated based on the values queried from the underlying counter (the one specified as the instance name). |
Any parameter will be interpreted as a list of up to two comma separated
(integer) values, where the first is the time interval (in milliseconds)
at which the underlying counter should be queried. If no value is
specified, the counter will assume |
|
Any full performance counter name. The referenced performance counter is queried at fixed time intervals as specified by the first parameter. |
Returns the current rolling average (mean) value calculated based on the values queried from the underlying counter (the one specified as the instance name). |
Any parameter will be interpreted as a list of up to three comma
separated (integer) values, where the first is the time interval (in
milliseconds) at which the underlying counter should be queried. If no
value is specified, the counter will assume |
|
Any full performance counter name. The referenced performance counter is queried at fixed time intervals as specified by the first parameter. |
Returns the current standard deviation (stddev) value calculated based on the values queried from the underlying counter (the one specified as the instance name). |
Any parameter will be interpreted as a list of up to two comma separated
(integer) values, where the first is the time interval (in milliseconds)
at which the underlying counter should be queried. If no value is
specified, the counter will assume |
|
Any full performance counter name. The referenced performance counter is queried at fixed time intervals as specified by the first parameter. |
Returns the current rolling variance (stddev) value calculated based on the values queried from the underlying counter (the one specified as the instance name). |
Any parameter will be interpreted as a list of up to three comma
separated (integer) values, where the first is the time interval (in
milliseconds) at which the underlying counter should be queried. If no
value is specified, the counter will assume |
|
Any full performance counter name. The referenced performance counter is queried at fixed time intervals as specified by the first parameter. |
Returns the current (statistically estimated) median value calculated based on the values queried from the underlying counter (the one specified as the instance name). |
Any parameter will be interpreted as a list of up to two comma separated
(integer) values, where the first is the time interval (in milliseconds)
at which the underlying counter should be queried. If no value is
specified, the counter will assume |
|
Any full performance counter name. The referenced performance counter is queried at fixed time intervals as specified by the first parameter. |
Returns the current maximum value calculated based on the values queried from the underlying counter (the one specified as the instance name). |
Any parameter will be interpreted as a list of up to two comma separated
(integer) values, where the first is the time interval (in milliseconds)
at which the underlying counter should be queried. If no value is
specified, the counter will assume |
|
Any full performance counter name. The referenced performance counter is queried at fixed time intervals as specified by the first parameter. |
Returns the current rolling maximum value calculated based on the values queried from the underlying counter (the one specified as the instance name). |
Any parameter will be interpreted as a list of up to three comma
separated (integer) values, where the first is the time interval (in
milliseconds) at which the underlying counter should be queried. If no
value is specified, the counter will assume |
|
Any full performance counter name. The referenced performance counter is queried at fixed time intervals as specified by the first parameter. |
Returns the current minimum value calculated based on the values queried from the underlying counter (the one specified as the instance name). |
Any parameter will be interpreted as a list of up to two comma separated
(integer) values, where the first is the time interval (in milliseconds)
at which the underlying counter should be queried. If no value is
specified, the counter will assume |
|
Any full performance counter name. The referenced performance counter is queried at fixed time intervals as specified by the first parameter. |
Returns the current rolling minimum value calculated based on the values queried from the underlying counter (the one specified as the instance name). |
Any parameter will be interpreted as a list of up to three comma
separated (integer) values, where the first is the time interval (in
milliseconds) at which the underlying counter should be queried. If no
value is specified, the counter will assume |
Counter type |
Counter instance formatting |
Description |
Parameters |
|
None |
Returns the sum calculated based on the values queried from the underlying counters (the ones specified as the parameters). |
The parameter will be interpreted as a comma separated list of full performance counter names which are queried whenever this counter is accessed. Any wildcards in the counter names will be expanded. |
|
None |
Returns the difference calculated based on the values queried from the underlying counters (the ones specified as the parameters). |
The parameter will be interpreted as a comma separated list of full performance counter names which are queried whenever this counter is accessed. Any wildcards in the counter names will be expanded. |
|
None |
Returns the product calculated based on the values queried from the underlying counters (the ones specified as the parameters). |
The parameter will be interpreted as a comma separated list of full performance counter names which are queried whenever this counter is accessed. Any wildcards in the counter names will be expanded. |
|
None |
Returns the result of division of the values queried from the underlying counters (the ones specified as the parameters). |
The parameter will be interpreted as a comma separated list of full performance counter names which are queried whenever this counter is accessed. Any wildcards in the counter names will be expanded. |
|
None |
Returns the average value of all values queried from the underlying counters (the ones specified as the parameters). |
The parameter will be interpreted as a comma separated list of full performance counter names which are queried whenever this counter is accessed. Any wildcards in the counter names will be expanded. |
|
None |
Returns the standard deviation of all values queried from the underlying counters (the ones specified as the parameters). |
The parameter will be interpreted as a comma separated list of full performance counter names which are queried whenever this counter is accessed. Any wildcards in the counter names will be expanded. |
|
None |
Returns the median value of all values queried from the underlying counters (the ones specified as the parameters). |
The parameter will be interpreted as a comma separated list of full performance counter names which are queried whenever this counter is accessed. Any wildcards in the counter names will be expanded. |
|
None |
Returns the minimum value of all values queried from the underlying counters (the ones specified as the parameters). |
The parameter will be interpreted as a comma separated list of full performance counter names which are queried whenever this counter is accessed. Any wildcards in the counter names will be expanded. |
|
None |
Returns the maximum value of all values queried from the underlying counters (the ones specified as the parameters). |
The parameter will be interpreted as a comma separated list of full performance counter names which are queried whenever this counter is accessed. Any wildcards in the counter names will be expanded. |
|
None |
Returns the count value of all values queried from the underlying counters (the ones specified as the parameters). |
The parameter will be interpreted as a comma separated list of full performance counter names which are queried whenever this counter is accessed. Any wildcards in the counter names will be expanded. |
Note
The /arithmetics counters can consume an arbitrary number of other
counters. For this reason those have to be specified as parameters (a comma
separated list of counters appended after a '@'). For instance:
./bin/hello_world_distributed -t2 \
--hpx:print-counter=/threads{locality#0/worker-thread#*}/count/cumulative \
--hpx:print-counter=/arithmetics/add@/threads{locality#0/worker-thread#*}/count/cumulative
hello world from OS-thread 0 on locality 0
hello world from OS-thread 1 on locality 0
/threads{locality#0/worker-thread#0}/count/cumulative,1,0.515640,[s],25
/threads{locality#0/worker-thread#1}/count/cumulative,1,0.515520,[s],36
/arithmetics/add@/threads{locality#0/worker-thread#*}/count/cumulative,1,0.516445,[s],64
Since all wildcards in the parameters are expanded, this example is fully
equivalent to specifying both counters separately to /arithmetics/add:
./bin/hello_world_distributed -t2 \
--hpx:print-counter=/threads{locality#0/worker-thread#*}/count/cumulative \
--hpx:print-counter=/arithmetics/add@\
/threads{locality#0/worker-thread#0}/count/cumulative,\
/threads{locality#0/worker-thread#1}/count/cumulative
Counter type |
Counter instance formatting |
Description |
Parameters |
|
where:
|
Returns the number of parcels handled by the message handler associated with the action which is given by the counter parameter. |
The action type. This is the string which has been used while registering
the action with HPX, e.g. which has been passed as the second parameter
to the macro |
|
where:
|
Returns the number of messages generated by the message handler associated with the action which is given by the counter parameter. |
The action type. This is the string which has been used while registering
the action with HPX, e.g. which has been passed as the second parameter
to the macro |
|
where:
|
Returns the average number of parcels sent in a message generated by the message handler associated with the action which is given by the counter parameter. |
The action type. This is the string which has been used while registering
the action with HPX, e.g. which has been passed as the second parameter
to the macro |
|
where:
|
Returns the average time between arriving parcels for the action which is given by the counter parameter. |
The action type. This is the string which has been used while registering
the action with HPX, e.g. which has been passed as the second parameter
to the macro |
|
where:
|
Returns a histogram representing the times between arriving parcels for the action which is given by the counter parameter. This counter returns an array of values, where the first three values represent the three parameters used for the histogram followed by one value for each of the histogram buckets. The first unit of measure displayed for this counter For each bucket the counter shows a value between |
The action type and optional histogram parameters. The action type is
the string which has been used while registering the action with HPX,
e.g. which has been passed as the second parameter to the macro
The action type may be followed by a comma separated list of up-to three
numbers: the lower and upper boundaries for the collected histogram, and
the number of buckets for the histogram to generate. By default these
three numbers will be assumed to be |
Note
The performance counters related to parcel coalescing are available only if
the configuration time constant HPX_WITH_PARCEL_COALESCING is set to
ON (default: ON). However, even in this case it will be available
only for actions that are enabled for parcel coalescing (see the
macros HPX_ACTION_USES_MESSAGE_COALESCING and
HPX_ACTION_USES_MESSAGE_COALESCING_NOTHROW).
APEX integration¶
HPX provides integration with APEX, which is a framework for application
profiling using task timers and various performance counters. It can be added as
a git submodule by turning on the option HPX_WITH_APEX:BOOL during
CMake configuration. TAU is an optional dependency when using APEX.
To build HPX with APEX, add HPX_WITH_APEX=ON, and,
optionally, TAU_ROOT=$PATH_TO_TAU to your CMake configuration. In
addition, you can override the tag used for APEX with the
HPX_WITH_APEX_TAG option. Please see the APEX HPX documentation for detailed
instructions on using APEX with HPX.
HPX runtime and resources¶
HPX thread scheduling policies¶
The HPX runtime has five thread scheduling policies: local-priority,
static-priority, local, static and abp-priority. These policies can be specified
from the command line using the command line option --hpx:queuing. In
order to use a particular scheduling policy, the runtime system must be built
with the appropriate scheduler flag turned on (e.g. cmake
-DHPX_THREAD_SCHEDULERS=local, see CMake variables used to configure HPX for more
information).
Priority local scheduling policy (default policy)¶
default or invoke using:
--hpx:queuinglocal-priority-fifo
The priority local scheduling policy maintains one queue per operating system
(OS) thread. The OS thread pulls its work from this queue. By default the number
of high priority queues is equal to the number of OS threads; the number of high
priority queues can be specified on the command line using
--hpx:high-priority-threads. High priority threads are executed by any
of the OS threads before any other work is executed. When a queue is empty work
will be taken from high priority queues first. There is one low priority queue
from which threads will be scheduled only when there is no other work.
For this scheduling policy there is an option to turn on NUMA sensitivity using
the command line option --hpx:numa-sensitive. When NUMA sensitivity is
turned on work stealing is done from queues associated with the same NUMA domain
first, only after that work is stolen from other NUMA domains.
This scheduler is enabled at build time by default and will be available always.
This scheduler can be used with two underlying queuing policies (FIFO:
first-in-first-out, and LIFO: last-in-first-out). The default is FIFO. In order
to use the LIFO policy use the command line option --hpx:queuing=local-priority-lifo.
Static priority scheduling policy¶
invoke using:
--hpx:queuing=static-priority(or-qs)flag to turn on for build:
HPX_THREAD_SCHEDULERS=allorHPX_THREAD_SCHEDULERS=static-priority
The static scheduling policy maintains one queue per OS thread from which each OS thread pulls its tasks (user threads). Threads are distributed in a round robin fashion. There is no thread stealing in this policy.
Local scheduling policy¶
invoke using:
--hpx:queuing=local(or-ql)flag to turn on for build:
HPX_THREAD_SCHEDULERS=allorHPX_THREAD_SCHEDULERS=local
The local scheduling policy maintains one queue per OS thread from which each OS thread pulls its tasks (user threads).
Static scheduling policy¶
invoke using:
--hpx:queuing=staticflag to turn on for build:
HPX_THREAD_SCHEDULERS=allorHPX_THREAD_SCHEDULERS=static
The static scheduling policy maintains one queue per OS thread from which each OS thread pulls its tasks (user threads). Threads are distributed in a round robin fashion. There is no thread stealing in this policy.
Priority ABP scheduling policy¶
invoke using:
--hpx:queuing=abp-priority-fifoflag to turn on for build:
HPX_THREAD_SCHEDULERS=allorHPX_THREAD_SCHEDULERS=abp-priority
Priority ABP policy maintains a double ended lock free queue for each OS thread.
By default the number of high priority queues is equal to the number of OS
threads; the number of high priority queues can be specified on the command line
using --hpx:high-priority-threads. High priority threads are executed
by the first OS threads before any other work is executed. When a queue is empty
work will be taken from high priority queues first. There is one low priority
queue from which threads will be scheduled only when there is no other work. For
this scheduling policy there is an option to turn on NUMA sensitivity using the
command line option --hpx:numa-sensitive. When NUMA sensitivity
is turned on work stealing is done from queues associated with the same NUMA
domain first, only after that work is stolen from other NUMA domains.
This scheduler can be used with two underlying queuing policies (FIFO:
first-in-first-out, and LIFO: last-in-first-out). In order to use the LIFO
policy use the command line option --hpx:queuing=abp-priority-lifo.
The HPX resource partitioner¶
The HPX resource partitioner lets you take the execution resources available
on a system—processing units, cores, and numa domains—and assign them to
thread pools. By default HPX creates a single thread pool name default.
While this is good for most use cases, the resource partitioner lets you create
multiple thread pools with custom resources and options.
Creating custom thread pools is useful for cases where you have tasks which absolutely need to run without interference from other tasks. An example of this is when using MPI for distribution instead of the built-in mechanisms in HPX (useful in legacy applications). In this case one can create a thread pool containing a single thread for MPI communication. MPI tasks will then always run on the same thread, instead of potentially being stuck in a queue behind other threads.
Note that HPX thread pools are completely independent from each other in the sense that task stealing will never happen between different thread pools. However, tasks running on a particular thread pool can schedule tasks on another thread pool.
Note
It is simpler in some situations to schedule important tasks with high priority instead of using a separate thread pool.
Using the resource partitioner¶
The hpx::resource::partitioner is now created during HPX runtime
initialization without explicit action needed from the user. To specify some of
the initialization parameters you can use the hpx::init_params.
#include <hpx/local/init.hpp>
int hpx_main()
{
return hpx::local::finalize();
}
int main(int argc, char** argv)
{
// Setup the init parameters
hpx::local::init_params init_args;
hpx::local::init(hpx_main, argc, argv, init_args);
}
The resource partitioner callback is the interface to add thread pools to the
HPX runtime and to assign resources to the thread pools. In order to create
custom thread pools you can specify the resource partitioner callback
hpx::init_params::rp_callback which will be called once the
resource partitioner will be created , see the example below. You can also
specify other parameters, see hpx::init_params.
To add a thread pool use the
hpx::resource::partitioner::create_thread_pool method. If you
simply want to use the default scheduler and scheduler options it is enough to
call rp.create_thread_pool("my-thread-pool").
Then, to add resources to the thread pool you can use the
hpx::resource::partitioner::add_resource method. The resource
partitioner exposes the hardware topology retrieved using Portable Hardware Locality (HWLOC) and lets you
iterate through the topology to add the wanted processing units to the thread
pool. Below is an example of adding all processing units from the first NUMA
domain to a custom thread pool, unless there is only one NUMA domain in which
case we leave the first processing unit for the default thread pool:
#include <hpx/local/init.hpp>
#include <hpx/modules/resource_partitioner.hpp>
#include <iostream>
int hpx_main()
{
return hpx::local::finalize();
}
void init_resource_partitioner_handler(hpx::resource::partitioner& rp,
hpx::program_options::variables_map const& /*vm*/)
{
rp.create_thread_pool("my-thread-pool");
bool one_numa_domain = rp.numa_domains().size() == 1;
bool skipped_first_pu = false;
hpx::resource::numa_domain const& d = rp.numa_domains()[0];
for (hpx::resource::core const& c : d.cores())
{
for (hpx::resource::pu const& p : c.pus())
{
if (one_numa_domain && !skipped_first_pu)
{
skipped_first_pu = true;
continue;
}
rp.add_resource(p, "my-thread-pool");
}
}
}
int main(int argc, char* argv[])
{
// Set the callback to init the thread_pools
hpx::local::init_params init_args;
init_args.rp_callback = &init_resource_partitioner_handler;
hpx::local::init(hpx_main, argc, argv, init_args);
}
Note
Whatever processing units not assigned to a thread pool by the time
hpx::init is called will be added to the default thread pool. It
is also possible to explicitly add processing units to the default thread
pool, and to create the default thread pool manually (in order to e.g. set
the scheduler type).
Tip
The command line option --hpx:print-bind is useful for checking
that the thread pools have been set up the way you expect.
Difference between the old and new version¶
In the old version, you had to create an instance of the
resource_partitioner with argc and argv.
int main(int argc, char** argv)
{
hpx::resource::partitioner rp(argc, argv);
hpx::init();
}
From HPX 1.5.0 onwards, you just pass argc and argv to hpx::init()
or hpx::start() for the binding options to be parsed by the resource
partitioner.
int main(int argc, char** argv)
{
hpx::init_params init_args;
hpx::init(argc, argv, init_args);
}
In the old version, when creating a custom thread pool, you just called the utilities on the resource partitioner instantiated previously.
int main(int argc, char** argv)
{
hpx::resource::partitioner rp(argc, argv);
rp.create_thread_pool("my-thread-pool");
bool one_numa_domain = rp.numa_domains().size() == 1;
bool skipped_first_pu = false;
hpx::resource::numa_domain const& d = rp.numa_domains()[0];
for (const hpx::resource::core& c : d.cores())
{
for (const hpx::resource::pu& p : c.pus())
{
if (one_numa_domain && !skipped_first_pu)
{
skipped_first_pu = true;
continue;
}
rp.add_resource(p, "my-thread-pool");
}
}
hpx::init();
}
You now specify the resource partitioner callback which will tie the resources to the resource partitioner created during runtime initialization.
void init_resource_partitioner_handler(hpx::resource::partitioner& rp)
{
rp.create_thread_pool("my-thread-pool");
bool one_numa_domain = rp.numa_domains().size() == 1;
bool skipped_first_pu = false;
hpx::resource::numa_domain const& d = rp.numa_domains()[0];
for (const hpx::resource::core& c : d.cores())
{
for (const hpx::resource::pu& p : c.pus())
{
if (one_numa_domain && !skipped_first_pu)
{
skipped_first_pu = true;
continue;
}
rp.add_resource(p, "my-thread-pool");
}
}
}
int main(int argc, char* argv[])
{
hpx::init_params init_args;
init_args.rp_callback = &init_resource_partitioner_handler;
hpx::init(argc, argv, init_args);
}
Advanced usage¶
It is possible to customize the built in schedulers by passing scheduler options
to hpx::resource::partitioner::create_thread_pool. It is also possible
to create and use custom schedulers.
Note
It is not recommended to create your own scheduler. The HPX developers use
this to experiment with new scheduler designs before making them available to
users via the standard mechanisms of choosing a scheduler (command line
options). If you would like to experiment with a custom scheduler the
resource partitioner example shared_priority_queue_scheduler.cpp contains
a fully implemented scheduler with logging etc. to make exploration easier.
To choose a scheduler and custom mode for a thread pool, pass additional options when creating the thread pool like this:
rp.create_thread_pool("my-thread-pool",
hpx::resource::policies::local_priority_lifo,
hpx::policies::scheduler_mode(
hpx::policies::scheduler_mode::default |
hpx::policies::scheduler_mode::enable_elasticity));
The available schedulers are documented here:
hpx::resource::scheduling_policy, and the available scheduler modes
here: hpx::threads::policies::scheduler_mode. Also see the examples
folder for examples of advanced resource partitioner usage:
simple_resource_partitioner.cpp and
oversubscribing_resource_partitioner.cpp.
Miscellaneous¶
Error handling¶
Like in any other asynchronous invocation scheme, it is important to be able to handle error conditions occurring while the asynchronous (and possibly remote) operation is executed. In HPX all error handling is based on standard C++ exception handling. Any exception thrown during the execution of an asynchronous operation will be transferred back to the original invocation locality, where it will be rethrown during synchronization with the calling thread.
The source code for this example can be found here:
error_handling.cpp.
Working with exceptions¶
For the following description assume that the function raise_exception()
is executed by invoking the plain action raise_exception_type.
#include <hpx/iostream.hpp>
#include <hpx/modules/runtime_local.hpp>
//[error_handling_raise_exception
void raise_exception()
The exception is thrown using the macro HPX_THROW_EXCEPTION. The type
of the thrown exception is hpx::exception. This associates
additional diagnostic information with the exception, such as file name and line
number, locality id and thread id, and stack backtrace from the point
where the exception was thrown.
Any exception thrown during the execution of an action is transferred back to
the (asynchronous) invocation site. It will be rethrown in this context when the
calling thread tries to wait for the result of the action by invoking either
future<>::get() or the synchronous action invocation wrapper as shown here:
{
///////////////////////////////////////////////////////////////////////
// Error reporting using exceptions
//[exception_diagnostic_information
hpx::cout << "Error reporting using exceptions\n";
try {
// invoke raise_exception() which throws an exception
raise_exception_action do_it;
do_it(hpx::find_here());
}
catch (hpx::exception const& e) {
// Print just the essential error information.
hpx::cout << "caught exception: " << e.what() << "\n\n";
// Print all of the available diagnostic information as stored with
// the exception.
Note
The exception is transferred back to the invocation site even if it is executed on a different locality.
Additionally, this example demonstrates how an exception thrown by an (possibly
remote) action can be handled. It shows the use of
hpx::diagnostic_information, which retrieves all available diagnostic
information from the exception as a formatted string. This includes, for
instance, the name of the source file and line number, the sequence number of
the OS thread and the HPX thread id, the locality id and the stack
backtrace of the point where the original exception was thrown.
Under certain circumstances it is desirable to output only some of the diagnostics, or to output those using different formatting. For this case, HPX exposes a set of lower-level functions as demonstrated in the following code snippet:
//]
// Detailed error reporting using exceptions
//[exception_diagnostic_elements
hpx::cout << "Detailed error reporting using exceptions\n";
try {
// Invoke raise_exception() which throws an exception.
raise_exception_action do_it;
do_it(hpx::find_here());
}
catch (hpx::exception const& e) {
// Print the elements of the diagnostic information separately.
hpx::cout << "{what}: " << hpx::get_error_what(e) << "\n";
hpx::cout << "{locality-id}: " << hpx::get_error_locality_id(e) << "\n";
hpx::cout << "{hostname}: " << hpx::get_error_host_name(e) << "\n";
hpx::cout << "{pid}: " << hpx::get_error_process_id(e) << "\n";
hpx::cout << "{function}: " << hpx::get_error_function_name(e) << "\n";
hpx::cout << "{file}: " << hpx::get_error_file_name(e) << "\n";
hpx::cout << "{line}: " << hpx::get_error_line_number(e) << "\n";
hpx::cout << "{os-thread}: " << hpx::get_error_os_thread(e) << "\n";
hpx::cout << "{thread-id}: " << std::hex << hpx::get_error_thread_id(e)
<< "\n";
hpx::cout << "{thread-description}: "
<< hpx::get_error_thread_description(e) << "\n";
hpx::cout << "{state}: " << std::hex << hpx::get_error_state(e)
<< "\n";
Working with error codes¶
Most of the API functions exposed by HPX can be invoked in two different
modes. By default those will throw an exception on error as described above.
However, sometimes it is desirable not to throw an exception in case of an error
condition. In this case an object instance of the hpx::error_code
type can be passed as the last argument to the API function. In case of an error,
the error condition will be returned in that hpx::error_code
instance. The following example demonstrates extracting the full diagnostic
information without exception handling:
///////////////////////////////////////////////////////////////////////
// Error reporting using error code
{
//[error_handling_diagnostic_information
hpx::cout << "Error reporting using error code\n";
// Create a new error_code instance.
hpx::error_code ec;
// If an instance of an error_code is passed as the last argument while
// invoking the action, the function will not throw in case of an error
// but store the error information in this error_code instance instead.
raise_exception_action do_it;
do_it(hpx::find_here(), ec);
if (ec) {
// Print just the essential error information.
hpx::cout << "returned error: " << ec.get_message() << "\n";
// Print all of the available diagnostic information as stored with
// the exception.
hpx::cout << "diagnostic information:"
Note
The error information is transferred back to the invocation site even if it is executed on a different locality.
This example show how an error can be handled without having to resolve to
exceptions and that the returned hpx::error_code instance can be
used in a very similar way as the hpx::exception type above. Simply
pass it to the hpx::diagnostic_information, which retrieves all
available diagnostic information from the error code instance as a formatted
string.
As for handling exceptions, when working with error codes, under certain circumstances it is desirable to output only some of the diagnostics, or to output those using different formatting. For this case, HPX exposes a set of lower-level functions usable with error codes as demonstrated in the following code snippet:
// Detailed error reporting using error code
{
//[error_handling_diagnostic_elements
hpx::cout << "Detailed error reporting using error code\n";
// Create a new error_code instance.
hpx::error_code ec;
// If an instance of an error_code is passed as the last argument while
// invoking the action, the function will not throw in case of an error
// but store the error information in this error_code instance instead.
raise_exception_action do_it;
do_it(hpx::find_here(), ec);
if (ec) {
// Print the elements of the diagnostic information separately.
hpx::cout << "{what}: " << hpx::get_error_what(ec) << "\n";
hpx::cout << "{locality-id}: " << hpx::get_error_locality_id(ec) << "\n";
hpx::cout << "{hostname}: " << hpx::get_error_host_name(ec) << "\n";
hpx::cout << "{pid}: " << hpx::get_error_process_id(ec) << "\n";
hpx::cout << "{function}: " << hpx::get_error_function_name(ec)
<< "\n";
hpx::cout << "{file}: " << hpx::get_error_file_name(ec) << "\n";
hpx::cout << "{line}: " << hpx::get_error_line_number(ec) << "\n";
hpx::cout << "{os-thread}: " << hpx::get_error_os_thread(ec) << "\n";
hpx::cout << "{thread-id}: " << std::hex
<< hpx::get_error_thread_id(ec) << "\n";
hpx::cout << "{thread-description}: "
<< hpx::get_error_thread_description(ec) << "\n\n";
hpx::cout << "{state}: " << std::hex << hpx::get_error_state(ec)
<< "\n";
hpx::cout << "{stack-trace}: " << hpx::get_error_backtrace(ec) << "\n";
For more information please refer to the documentation of
hpx::get_error_what, hpx::get_error_locality_id,
hpx::get_error_host_name, hpx::get_error_process_id,
hpx::get_error_function_name, hpx::get_error_file_name,
hpx::get_error_line_number, hpx::get_error_os_thread,
hpx::get_error_thread_id,
hpx::get_error_thread_description,
hpx::get_error_backtrace, hpx::get_error_env, and
hpx::get_error_state.
Lightweight error codes¶
Sometimes it is not desirable to collect all the ambient information about the error at the point where it happened as this might impose too much overhead for simple scenarios. In this case, HPX provides a lightweight error code facility that will hold the error code only. The following snippet demonstrates its use:
// Error reporting using lightweight error code
{
//[lightweight_error_handling_diagnostic_information
hpx::cout << "Error reporting using an lightweight error code\n";
// Create a new error_code instance.
hpx::error_code ec(hpx::lightweight);
// If an instance of an error_code is passed as the last argument while
// invoking the action, the function will not throw in case of an error
// but store the error information in this error_code instance instead.
raise_exception_action do_it;
do_it(hpx::find_here(), ec);
if (ec) {
// Print just the essential error information.
hpx::cout << "returned error: " << ec.get_message() << "\n";
// Print all of the available diagnostic information as stored with
// the exception.
All functions that retrieve other diagnostic elements from the
hpx::error_code will fail if called with a lightweight error_code
instance.
Utilities in HPX¶
In order to ease the burden of programming, HPX provides several utilities to users. The following section documents those facilies.
Checkpoint¶
See checkpoint.
The HPX I/O-streams component¶
The HPX I/O-streams subsystem extends the standard C++ output streams
std::cout and std::cerr to work in the distributed setting of an HPX
application. All of the output streamed to hpx::cout will be dispatched to
std::cout on the console locality. Likewise, all output generated
from hpx::cerr will be dispatched to std::cerr on the console
locality.
Note
All existing standard manipulators can be used in conjunction with
hpx::cout and hpx::cerr Historically, HPX also defines
hpx::endl and hpx::flush but those are just aliases for the
corresponding standard manipulators.
In order to use either hpx::cout or hpx::cerr, application codes need to
#include <hpx/include/iostreams.hpp>. For an example, please see the
following ‘Hello world’ program:
// Copyright (c) 2007-2012 Hartmut Kaiser
//
// SPDX-License-Identifier: BSL-1.0
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
///////////////////////////////////////////////////////////////////////////////
// The purpose of this example is to execute a HPX-thread printing
// "Hello World!" once. That's all.
//[hello_world_1_getting_started
// Including 'hpx/hpx_main.hpp' instead of the usual 'hpx/hpx_init.hpp' enables
// to use the plain C-main below as the direct main HPX entry point.
#include <hpx/hpx_main.hpp>
#include <hpx/iostream.hpp>
int main()
{
// Say hello to the world!
hpx::cout << "Hello World!\n" << hpx::flush;
return 0;
}
//]
Additionally, those applications need to link with the iostreams component. When
using CMake this can be achieved by using the COMPONENT_DEPENDENCIES
parameter; for instance:
include(HPX_AddExecutable)
add_hpx_executable(
hello_world
SOURCES hello_world.cpp
COMPONENT_DEPENDENCIES iostreams
)
Note
The hpx::cout and hpx::cerr streams buffer all output locally until a
std::endl or std::flush is encountered. That means that no output
will appear on the console as long as either of these is explicitly used.
Troubleshooting¶
This section contains commonly encountered problems when compiling or using HPX.
Undefined reference to boost::program_options¶
Boost.ProgramOptions is not ABI compatible between all C++ versions and compilers. Because of this you may see linker errors similar to this:
...: undefined reference to `boost::program_options::operator<<(std::ostream&, boost::program_options::options_description const&)'
if you are not linking to a compatible version of Boost.ProgramOptions. We
recommend that you use hpx::program_options, which is part of HPX, as a
replacement for boost::program_options (see program_options).
Until you have migrated to use hpx::program_options we recommend that you
always build Boost libraries and HPX with the same compiler and C++
standard.
Undefined reference to hpx::cout¶
You may see an linker error message that looks a bit like this:
hello_world.cpp:(.text+0x5aa): undefined reference to `hpx::cout'
hello_world.cpp:(.text+0x5c3): undefined reference to `hpx::iostreams::flush'
This usually happens if you are trying to use HPX iostreams functionality such
as hpx::cout but are not linking against it. The iostreams functionality is
not part of the core HPX library, and must be linked to explicitly. Typically
this can be solved by adding COMPONENT_DEPENDENCIES iostreams to a call to
add_hpx_library/add_hpx_executable/hpx_setup_target if using CMake. See
Creating HPX projects for more details.
Additional material¶
2-day workshop held at CSCS in 2016
Overview¶
HPX is organized into different sub-libraries and those in turn into modules.
The libraries and modules are independent, with clear dependencies and no
cycles. As an end-user, the use of these libraries is completely transparent. If
you use e.g. add_hpx_executable to create a target in your project you will
automatically get all modules as dependencies. See below for a list of the
available libraries and modules. Currently these are nothing more than an
internal grouping and do not affect usage. They cannot be consumed individually
at the moment.
Core modules¶
affinity¶
The affinity module contains helper functionality for mapping worker threads to hardware resources.
See the API reference of the module for more details.
allocator_support¶
This module provides utilities for allocators. It contains
hpx::util::internal_allocator which directly forwards allocation
calls to jemalloc. This utility is is mainly useful on Windows.
See the API reference of the module for more details.
asio¶
The asio module is a thin wrapper around the Boost.ASIO library, providing a few additional helper functions.
See the API reference of the module for more details.
assertion¶
The assertion library implements the macros HPX_ASSERT and
HPX_ASSERT_MSG. Those two macros can be used to implement assertions
which are turned of during a release build.
By default, the location and function where the assert has been called from are
displayed when the assertion fires. This behavior can be modified by using
hpx::assertion::set_assertion_handler. When HPX initializes, it uses
this function to specify a more elaborate assertion handler. If your application
needs to customize this, it needs to do so before calling
hpx::hpx_init, hpx::hpx_main or using the C-main
wrappers.
See the API reference of the module for more details.
cache¶
This module provides two cache data structures:
hpx::util::cache::local_cachehpx::util::cache::lru_cache
See the API reference of the module for more details.
concepts¶
This module provides helpers for emulating concepts. It provides the following macros:
See the API reference of the module for more details.
concurrency¶
This module provides concurrency primitives useful for multi-threaded programming such as:
hpx::util::cache_line_dataandhpx::util::cache_aligned_data: wrappers for aligning and padding data to cache lines.various lockfree queue data structures
See the API reference of the module for more details.
config¶
The config module contains various configuration options, typically hidden behind macros that choose the correct implementation based on the compiler and other available options.
See the API reference of the module for more details.
config_registry¶
The config_registry module is a low level module providing helper functionality
for registering configuration entries to a global registry from other modules.
The hpx::config_registry::add_module_config function is used to add
configuration options, and hpx::config_registry::get_module_configs
can be used to retrieve configuration entries registered so far.
add_module_config_helper can be used to register configuration
entries through static global options.
See the API reference of this module for more details.
coroutines¶
The coroutines module provides coroutine (user-space thread) implementations for different platforms.
See the API reference of the module for more details.
datastructures¶
The datastructures module provides basic data structures (typically provided for compatibility with older C++ standards):
hpx::util::basic_anyhpx::util::optionalhpx::util::tuple
See the API reference of the module for more details.
debugging¶
This module provides helpers for demangling symbol names.
See the API reference of the module for more details.
errors¶
This module provides support for exceptions and error codes:
See the API reference of the module for more details.
execution_base¶
The basic execution module is the main entry point to implement parallel and concurrent operations. It is modeled after P0443 with some additions and implementations for the described concepts. Most notably, it provides an abstraction for execution resources, execution contexts and execution agents in such a way, that it provides customization points that those aforementioned concepts can be replaced and combined with ease.
For that purpose, three virtual base classes are provided to be able to provide implementations with different properties:
resource_base: This is the abstraction for execution resources, that isfor example CPU cores or an accelerator.
context_base: An execution context uses execution resources and is ableto spawn new execution agents, as new threads of executions on the available resources.
agent_base: The execution agent represents the thread of execution, andcan be used to yield, suspend, resume or abort a thread of execution.
filesystem¶
This module provides a compatibility layer for the C++17 filesystem library. If
the filesystem library is available this module will simply forward its contents
into the hpx::filesystem namespace. If the library is not available it will
fall back to Boost.Filesystem instead.
See the API reference of the module for more details.
format¶
The format module exposes the format and format_to
functions for formatting strings.
See the API reference of the module for more details.
functional¶
This module provides function wrappers and helpers for managing functions and their arguments.
hpx::util::functionhpx::util::function_refhpx::util::unique_functionhpx::util::result_of
See the API reference of the module for more details.
hardware¶
The hardware module abstracts away hardware specific details of timestamps and CPU features.
See the API reference of the module for more details.
hashing¶
The hashing module provides two hashing implementations:
See the API reference of the module for more details.
ini¶
TODO: High-level description of the module.
See the API reference of this module for more details.
io_service¶
This module provides an abstraction over Boost.ASIO, combining multiple
asio::io_contexts into a single pool.
hpx::util::io_service_pool provides a simple pool of
asio::io_contexts with an API similar to asio::io_context.
hpx::threads::detail::io_service_thread_pool wraps
hpx::util::io_service_pool into an interface derived from
hpx::threads::detail::thread_pool_base.
See the API reference of this module for more details.
iterator_support¶
This module provides helpers for iterators. It provides
hpx::util::iterator_facade and
hpx::util::iterator_adaptor for creating new iterators, and the
trait hpx::util::is_iterator along with more specific iterator
traits.
See the API reference of the module for more details.
itt_notify¶
This module provides support for profiling with Intel VTune.
See the API reference of this module for more details.
logging¶
This module provides useful macros for logging information.
See the API reference of the module for more details.
memory¶
Part of this module is a forked version of boost::intrusive_ptr from Boost.SmartPtr.
See the API reference of the module for more details.
plugin¶
This module provides base utilities for creating plugins.
See the API reference of the module for more details.
prefix¶
This module provides utilities for handling the prefix of an HPX application, i.e. the paths used for searching components and plugins.
See the API reference of this module for more details.
preprocessor¶
This library contains useful preprocessor macros:
See the API reference of the module for more details.
properties¶
This module implements the prefer customization point for properties in
terms of P2220. This differs from P1393 in that it relies fully on
tag_dispatch overloads and fewer base customization points. Actual properties
are defined in modules. All functionality is experimental and can be accessed
through the hpx::experimental namespace.
See the API reference of this module for more details.
schedulers¶
This module provides schedulers used by thread pools in the thread_pools module. There are currently three main schedulers:
hpx::threads::policies::local_priority_queue_schedulerhpx::threads::policies::static_priority_queue_schedulerhpx::threads::policies::shared_priority_queue_scheduler
Other schedulers are specializations or variations of the above schedulers. See the examples of the resource_partitioner module for examples of specifying a custom scheduler for a thread pool.
See the API reference of this module for more details.
serialization¶
This module provides serialization primitives and support for all built-in types as well as all C++ Standard Library collection and utility types. This list is extended by HPX vocabulary types with proper support for global reference counting. HPX’s mode of serialization is derived from Boost’s serialization model and, as such, is mostly interface compatible with its Boost counterpart.
The purest form of serializing data is to copy the content of the payload bit by bit; however, this method is impractical for generic C++ types, which might be composed of more than just regular built-in types. Instead, HPX’s approach to serialization is derived from the Boost Serialization library, and is geared towards allowing the programmer of a given class explicit control and syntax of what to serialize. It is based on operator overloading of two special archive types that hold a buffer or stream to store the serialized data and is responsible for dispatching the serialization mechanism to the intrusive or non-intrusive version. The serialization process is recursive. Each member that needs to be serialized must be specified explicitly. The advantage of this approach is that the serialization code is written in C++ and leverages all necessary programming techniques. The generic, user-facing interface allows for effective application of the serialization process without obstructing the algorithms that need special code for packing and unpacking. It also allows for optimizations in the implementation of the archives.
See the API reference of the module for more details.
static_reinit¶
This module provides a simple wrapper around static variables that can be reinitialized.
See the API reference of this module for more details.
statistics¶
This module provide some statistics utilities like rolling min/max and histogram.
See the API reference of the module for more details.
string_util¶
This module contains string utilities inspired by the Boost string algorithms library.
See the API reference of this module for more details.
synchronization¶
This module provides synchronization primitives which should be used rather than the C++ standard ones in HPX threads:
hpx::lcos::local::spinlock(std::mutex compatible spinlock)hpx::lcos::local::spinlock_no_backoff(boost::mutex compatible spinlock)hpx::lcos::local::spinlock_pool
See lcos_local, async_combinators, and async for higher level synchronization facilities.
See the API reference of this module for more details.
testing¶
The testing module contains useful macros for testing. The results of tests can
be printed with hpx::util::report_errors. The following macros are
provided:
See the API reference of the module for more details.
thread_pools¶
This module defines the thread pools and utilities used by the HPX runtime.
The only thread pool implementation provided by this module is
hpx::threads::detail::scheduled_thread_pool, which is derived from
hpx::threads::detail::thread_pool_base defined in the
threading_base module.
See the API reference of this module for more details.
thread_support¶
This module provides miscellaneous utilities for threading and concurrency.
See the API reference of the module for more details.
threading_base¶
This module contains the base class definition required for threads. The base
class hpx::threads::thread_data is inherited by two specializations
for stackful and stackless threads:
hpx::threads::thread_data_stackful and
hpx::threads::thread_data_stackless. In addition, the module
defines the base classes for schedulers and thread pools:
hpx::threads::policies::scheduler_base and
hpx::threads::thread_pool_base.
See the API reference of this module for more details.
timing¶
This module provides the timing utilities (clocks and timers).
See the API reference of the module for more details.
topology¶
This module provides the class hpx::threads::topology which
represents the hardware resources available on a node. The class is a light
wrapper around the Portable Hardware Locality (HWLOC) library. The hpx::threads::cpu_mask is
a small companion class that represents a set of resources on a node.
See the API reference of the module for more details.
type_support¶
This module provides helper facilities related to types.
See the API reference of the module for more details.
util¶
The util module provides miscellaneous standalone utilities.
See the API reference of the module for more details.
version¶
This module macros and functions for accessing version information about HPX and its dependencies.
See the API reference of this module for more details.
Parallelism modules¶
algorithms¶
The algorithms module exposes the full set of algorithms defined by the C++ standard. There is also partial support for C++ ranges.
See the API reference of the module for more details.
async_base¶
The async_base module defines the basic functionality for spawning tasks on thread pools. This module does not implement any functionality on its own, but is extended by async_local and modules_async_distributed with implementations for the local and distributed cases.
See the API reference of this module for more details.
async_combinators¶
This module contains combinators for futures. The when_* functions allow you
to turn multiple futures into a single future which is ready when all, any,
some, or each of the given futures are ready. The wait_* combinators are
equivalent to the when_* functions except that they do not return a future.
The split_future combinator takes a single future of a container (e.g.
tuple) and turns it into a container of futures.
See lcos_local, synchronization, and async for other synchronization facilities.
See the API reference of this module for more details.
async_local¶
This module extends async_base to provide local implementations of
hpx::async, hpx::apply, hpx::sync, and
hpx::dataflow.
See the API reference of this module for more details.
execution¶
This library implements executors and execution policies for use with parallel algorithms and other facilities related to managing the execution of tasks.
See the API reference of the module for more details.
executors¶
The executors module exposes executors and execution policies. Most importantly, it exposes the following classes and constants:
hpx::execution::seqhpx::execution::par_unseqhpx::execution::task
See the API reference of this module for more details.
futures¶
This module defines the hpx::lcos::future and
hpx::lcos::shared_future classes corresponding to the C++ standard
library classes std::future and std::shared_future. Note that the
specializations of hpx::lcos::future::then for executors and
execution policies are defined in the execution module.
See the API reference of this module for more details.
lcos_local¶
This module provides the following local LCOs:
hpx::lcos::local::channelhpx::lcos::local::one_element_channelhpx::lcos::local::receive_channelhpx::lcos::local::send_channelhpx::lcos::local::packaged_taskhpx::lcos::local::promisehpx::lcos::local::receive_buffer
See lcos_distributed for distributed LCOs. Basic synchronization primitives for use in HPX threads can be found in synchronization. async_combinators contains useful utility functions for combining futures.
See the API reference of this module for more details.
pack_traversal¶
This module exposes the basic functionality for traversing various packs, both
synchronously and asynchronously: hpx::util::traverse_pack and
hpx::util::traverse_pack_async. It also exposes the higher level
functionality of unwrapping nested futures: hpx::util::unwrap and
its function object form hpx::util::functional::unwrap.
See the API reference of this module for more details.
resiliency¶
In HPX, a program failure is a manifestation of a failing task. This module exposes several APIs that allow users to manage failing tasks in a convenient way by either replaying a failed task or by replicating a specific task.
Task replay is analogous to the Checkpoint/Restart mechanism found in conventional execution models. The key difference being localized fault detection. When the runtime detects an error, it replays the failing task as opposed to completely rolling back the entire program to the previous checkpoint.
Task replication is designed to provide reliability enhancements by replicating a set of tasks and evaluating their results to determine a consensus among them. This technique is most effective in situations where there are few tasks in the critical path of the DAG which leaves the system underutilized or where hardware or software failures may result in an incorrect result instead of an error. However, the drawback of this method is the additional computational cost incurred by repeating a task multiple times.
The following API functions are exposed:
hpx::resiliency::experimental::async_replay: This version of task replay will catch user-defined exceptions and automatically reschedule the task N times before throwing anhpx::resiliency::experimental::abort_replay_exceptionif no task is able to complete execution without an exception.hpx::resiliency::experimental::async_replay_validate: This version of replay adds an argument to async replay which receives a user-provided validation function to test the result of the task against. If the task’s output is validated, the result is returned. If the output fails the check or an exception is thrown, the task is replayed until no errors are encountered or the number of specified retries has been exceeded.hpx::resiliency::experimental::async_replicate: This is the most basic implementation of the task replication. The API returns the first result that runs without detecting any errors.hpx::resiliency::experimental::async_replicate_validate: This API additionally takes a validation function which evaluates the return values produced by the threads. The first task to compute a valid result is returned.hpx::resiliency::experimental::async_replicate_vote: This API adds a vote function to the basic replicate function. Many hardware or software failures are silent errors which do not interrupt program flow. In order to detect errors of this kind, it is necessary to run the task several times and compare the values returned by every version of the task. In order to determine which return value is “correct”, the API allows the user to provide a custom consensus function to properly form a consensus. This voting function then returns the “correct”” answer.hpx::resiliency::experimental::async_replicate_vote_validate: This combines the features of the previously discussed replicate set. Replicate vote validate allows a user to provide a validation function to filter results. Additionally, as described in replicate vote, the user can provide a “voting function” which returns the consensus formed by the voting logic.hpx::resiliency::experimental::dataflow_replay: This version of dataflow replay will catch user-defined exceptions and automatically reschedules the task N times before throwing anhpx::resiliency::experimental::abort_replay_exceptionif no task is able to complete execution without an exception. Any arguments for the executed task that are futures will cause the task invocation to be delayed until all of those futures have become ready.hpx::resiliency::experimental::dataflow_replay_validate: This version of replay adds an argument to dataflow replay which receives a user-provided validation function to test the result of the task against. If the task’s output is validated, the result is returned. If the output fails the check or an exception is thrown, the task is replayed until no errors are encountered or the number of specified retries have been exceeded. Any arguments for the executed task that are futures will cause the task invocation to be delayed until all of those futures have become ready.hpx::resiliency::experimental::dataflow_replicate: This is the most basic implementation of the task replication. The API returns the first result that runs without detecting any errors. Any arguments for the executed task that are futures will cause the task invocation to be delayed until all of those futures have become ready.hpx::resiliency::experimental::dataflow_replicate_validate: This API additionally takes a validation function which evaluates the return values produced by the threads. The first task to compute a valid result is returned. Any arguments for the executed task that are futures will cause the task invocation to be delayed until all of those futures have become ready.hpx::resiliency::experimental::dataflow_replicate_vote: This API adds a vote function to the basic replicate function. Many hardware or software failures are silent errors which do not interrupt program flow. In order to detect errors of this kind, it is necessary to run the task several times and compare the values returned by every version of the task. In order to determine which return value is “correct”, the API allows the user to provide a custom consensus function to properly form a consensus. This voting function then returns the “correct” answer. Any arguments for the executed task that are futures will cause the task invocation to be delayed until all of those futures have become ready.hpx::resiliency::experimental::dataflow_replicate_vote_validate: This combines the features of the previously discussed replicate set. Replicate vote validate allows a user to provide a validation function to filter results. Additionally, as described in replicate vote, the user can provide a “voting function” which returns the consensus formed by the voting logic. Any arguments for the executed task that are futures will cause the task invocation to be delayed until all of those futures have become ready.
See the API reference of the module for more details.
thread_pool_util¶
This module contains helper functions for asynchronously suspending and resuming thread pools and their worker threads.
See the API reference of this module for more details.
threading¶
This module provides the equivalents of std::thread and std::jthread
for lightweight HPX threads:
See the API reference of this module for more details.
timed_execution¶
This module provides extensions to the executor interfaces defined in the execution module that allow timed submission of tasks on thread pools (at or after a specified time).
See the API reference of this module for more details.
Main HPX modules¶
actions¶
TODO: High-level description of the library.
See the API reference of this module for more details.
actions_base¶
TODO: High-level description of the library.
See the API reference of this module for more details.
agas¶
TODO: High-level description of the module.
See the API reference of this module for more details.
agas_base¶
This module holds the implementation of the four AGAS services: primary namespace, locality namespace, component namespace, and symbol namespace.
See the API reference of this module for more details.
async_colocated¶
TODO: High-level description of the module.
See the API reference of this module for more details.
async_cuda¶
This library adds a simple API that enables the user to retrieve a future from a cuda stream. Typically, a user may launch one or more kernels and then get a future from the stream that will become ready when those kernels have completed. The act of getting a future from the cuda_stream_helper object in this library hides the creation of a cuda stream event and the attachment of this event to the promise that is backing the future returned.
The usage is best illustrated by looking at an example
// create a cuda target using device number 0,1,2...
hpx::cuda::experimental::target target(device);
// create a stream helper object
hpx::cuda::experimental::cuda_future_helper helper(device);
// launch a kernel and return a future
auto fn = &cuda_trivial_kernel<double>;
double d = 3.1415;
auto f = helper.async(fn, d);
// attach a continuation to the future
f.then([](hpx::future<void>&& f) {
std::cout << "trivial kernel completed \n";
}).get();
Kernels and CPU work may be freely intermixed/overlapped and synchronized with futures.
It is important to note that multiple kernels may be launched without fetching a future, and multiple futures may be obtained from the helper. Please refer to the unit tests and examples for further examples.
CMake variables¶
HPX_WITH_CUDA - this is a general option that will enable both HPX_WITH_ASYNC_CUDA
and HPX_WITH_CUDA_COMPUTE when turned ON.
HPX_WITH_ASYNC_CUDA=ON enables the building of this module which requires
only the presence of CUDA on the system and only exposes cuda+fuures support
(HPX_WITH_ASYNC_CUDA may be used when HPX_WITH_CUDA_COMPUTE=OFF).
HPX_WITH_CUDA_COMPUTE=ON enables building HPX compute features that allow parallel
algorithms to be passed through to the GPU/CUDA backend.
See the API reference of this module for more details.
async¶
This module contains functionality for asynchronously launching work on remote
localities: hpx::async, hpx::apply. This module extends
the local-only functions in libs_async_local.
See the API reference of this module for more details.
async_mpi¶
The MPI library is intended to simplify the process of integrating MPI based codes with the HPX runtime. Any MPI function that is asynchronous and uses an MPI_Request may be converted into an hpx::future. The syntax is designed to allow a simple replacement of the MPI call with a futurized async version that accepts an executor instead of a communicator, and returns a future instead of assigning a request. Typically, an MPI call of the form
int MPI_Isend(buf, count, datatype, rank, tag, comm, request);
becomes
hpx::future<int> f = hpx::async(executor, MPI_Isend, buf, count, datatype, rank, tag);
When the MPI operation is complete, the future will become ready. This allows communication to integrated cleanly with the rest of HPX, in particular the continuation style of programming may be used to build up more complex code. Consider the following example, that chains user processing, sends and receives using continuations…
// create an executor for MPI dispatch
hpx::mpi::experimental::executor exec(MPI_COMM_WORLD);
// post an asynchronous receive using MPI_Irecv
hpx::future<int> f_recv = hpx::async(
exec, MPI_Irecv, &data, rank, MPI_INT, rank_from, i);
// attach a continuation to run when the recv completes,
f_recv.then([=, &tokens, &counter](auto&&)
{
// call an application specific function
msg_recv(rank, size, rank_to, rank_from, tokens[i], i);
// send a new message
hpx::future<int> f_send = hpx::async(
exec, MPI_Isend, &tokens[i], 1, MPI_INT, rank_to, i);
// when that send completes
f_send.then([=, &tokens, &counter](auto&&)
{
// call an application specific function
msg_send(rank, size, rank_to, rank_from, tokens[i], i);
});
}
The example above makes use of MPI_Isend and MPI_Irecv, but any MPI function
that uses requests may be futurized in this manner.
The following is a (non exhaustive) list of MPI functions that should be supported,
though not all have been tested at the time of writing
(please report any problems to the issue tracker).
int MPI_Isend(...);
int MPI_Ibsend(...);
int MPI_Issend(...);
int MPI_Irsend(...);
int MPI_Irecv(...);
int MPI_Imrecv(...);
int MPI_Ibarrier(...);
int MPI_Ibcast(...);
int MPI_Igather(...);
int MPI_Igatherv(...);
int MPI_Iscatter(...);
int MPI_Iscatterv(...);
int MPI_Iallgather(...);
int MPI_Iallgatherv(...);
int MPI_Ialltoall(...);
int MPI_Ialltoallv(...);
int MPI_Ialltoallw(...);
int MPI_Ireduce(...);
int MPI_Iallreduce(...);
int MPI_Ireduce_scatter(...);
int MPI_Ireduce_scatter_block(...);
int MPI_Iscan(...);
int MPI_Iexscan(...);
int MPI_Ineighbor_allgather(...);
int MPI_Ineighbor_allgatherv(...);
int MPI_Ineighbor_alltoall(...);
int MPI_Ineighbor_alltoallv(...);
int MPI_Ineighbor_alltoallw(...);
Note that the HPX mpi futurization wrapper should work with any asynchronous MPI call, as long as the function signature has the last two arguments MPI_xxx(…, MPI_Comm comm, MPI_Request *request) - internally these two parameters will be substituted by the executor and future data parameters that are supplied by template instantiations inside the hpx::mpi code.
See the API reference of this module for more details.
batch_environments¶
This module allows for the detection of execution as batch jobs, a series of programs executed without user intervention. All data is preselected and will be executed according to preset parameters, such as date or completion of another task. Batch environments are especially useful for executing repetitive tasks.
HPX supports the creation of batch jobs through the Portable Batch System (PBS) and SLURM.
For more information on batch environments, see Running on batch systems and the API reference for the module.
checkpoint¶
A common need of users is to periodically backup an application. This practice
provides resiliency and potential restart points in code. HPX utilizes the
concept of a checkpoint to support this use case.
Found in hpx/util/checkpoint.hpp, checkpoints are defined as objects
that hold a serialized version of an object or set of objects at a particular
moment in time. This representation can be stored in memory for later use or it
can be written to disk for storage and/or recovery at a later point. In order to
create and fill this object with data, users must use a function called
save_checkpoint. In code the function looks like this:
hpx::future<hpx::util::checkpoint> hpx::util::save_checkpoint(a, b, c, ...);
save_checkpoint takes arbitrary data containers, such as int,
double, float, vector, and future, and serializes them into a
newly created checkpoint object. This function returns a future to a
checkpoint containing the data. Here’s an example of a simple use case:
using hpx::util::checkpoint;
using hpx::util::save_checkpoint;
std::vector<int> vec{1,2,3,4,5};
hpx::future<checkpoint> save_checkpoint(vec);
Once the future is ready, the checkpoint object will contain the vector
vec and its five elements.
prepare_checkpoint takes arbitrary data containers (same as for
save_checkpoint), , such as int,
double, float, vector, and future, and calculates the necessary
buffer space for the checkpoint that would be created if save_checkpoint
was called with the same arguments. This function returns a future to a
checkpoint that is appropriately initialized. Here’s an example of a
simple use case:
using hpx::util::checkpoint;
using hpx::util::prepare_checkpoint;
std::vector<int> vec{1,2,3,4,5};
hpx::future<checkpoint> prepare_checkpoint(vec);
Once the future is ready, the checkpoint object will be initialized with an appropriately sized internal buffer.
It is also possible to modify the launch policy used by save_checkpoint.
This is accomplished by passing a launch policy as the first argument. It is
important to note that passing hpx::launch::sync will cause
save_checkpoint to return a checkpoint instead of a future to a
checkpoint. All other policies passed to save_checkpoint will return a
future to a checkpoint.
Sometimes checkpoint s must be declared before they are used.
save_checkpoint allows users to move pre-created checkpoint s into the
function as long as they are the first container passing into the function (In
the case where a launch policy is used, the checkpoint will immediately
follow the launch policy). An example of these features can be found below:
char character = 'd';
int integer = 10;
float flt = 10.01f;
bool boolean = true;
std::string str = "I am a string of characters";
std::vector<char> vec(str.begin(), str.end());
checkpoint archive;
// Test 1
// test basic functionality
hpx::shared_future<checkpoint> f_archive = save_checkpoint(
std::move(archive), character, integer, flt, boolean, str, vec);
Once users can create checkpoints they must now be able to restore the
objects they contain into memory. This is accomplished by the function
restore_checkpoint. This function takes a checkpoint and fills its data
into the containers it is provided. It is important to remember that the
containers must be ordered in the same way they were placed into the
checkpoint. For clarity see the example below:
char character2;
int integer2;
float flt2;
bool boolean2;
std::string str2;
std::vector<char> vec2;
restore_checkpoint(data, character2, integer2, flt2, boolean2, str2, vec2);
The core utility of checkpoint is in its ability to make certain data
persistent. Often, this means that the data needs to be stored in an object,
such as a file, for later use. HPX has two solutions for these issues: stream
operator overloads and access iterators.
HPX contains two stream overloads, operator<< and operator>>, to stream
data out of and into checkpoint. Here is an example of the overloads in
use below:
double a9 = 1.0, b9 = 1.1, c9 = 1.2;
std::ofstream test_file_9("test_file_9.txt");
hpx::future<checkpoint> f_9 = save_checkpoint(a9, b9, c9);
test_file_9 << f_9.get();
test_file_9.close();
double a9_1, b9_1, c9_1;
std::ifstream test_file_9_1("test_file_9.txt");
checkpoint archive9;
test_file_9_1 >> archive9;
restore_checkpoint(archive9, a9_1, b9_1, c9_1);
This is the primary way to move data into and out of a checkpoint. It is
important to note, however, that users should be cautious when using a stream
operator to load data and another function to remove it (or vice versa). Both
operator<< and operator>> rely on a .write() and a .read()
function respectively. In order to know how much data to read from the
std::istream, the operator<< will write the size of the checkpoint
before writing the checkpoint data. Correspondingly, the operator>> will
read the size of the stored data before reading the data into a new instance of
checkpoint. As long as the user employs the operator<< and
operator>> to stream the data, this detail can be ignored.
Important
Be careful when mixing operator<< and operator>> with other
facilities to read and write to a checkpoint. operator<< writes an
extra variable, and operator>> reads this variable back separately. Used
together the user will not encounter any issues and can safely ignore this
detail.
Users may also move the data into and out of a checkpoint using the exposed
.begin() and .end() iterators. An example of this use case is
illustrated below.
std::ofstream test_file_7("checkpoint_test_file.txt");
std::vector<float> vec7{1.02f, 1.03f, 1.04f, 1.05f};
hpx::future<checkpoint> fut_7 = save_checkpoint(vec7);
checkpoint archive7 = fut_7.get();
std::copy(archive7.begin(), // Write data to ofstream
archive7.end(), // ie. the file
std::ostream_iterator<char>(test_file_7));
test_file_7.close();
std::vector<float> vec7_1;
std::vector<char> char_vec;
std::ifstream test_file_7_1("checkpoint_test_file.txt");
if (test_file_7_1)
{
test_file_7_1.seekg(0, test_file_7_1.end);
auto length = test_file_7_1.tellg();
test_file_7_1.seekg(0, test_file_7_1.beg);
char_vec.resize(length);
test_file_7_1.read(char_vec.data(), length);
}
checkpoint archive7_1(std::move(char_vec)); // Write data to checkpoint
restore_checkpoint(archive7_1, vec7_1);
Checkpointing components¶
save_checkpoint and restore_checkpoint are also able to store components
inside checkpoints. This can be done in one of two ways. First a client of
the component can be passed to save_checkpoint. When the user wishes to
resurrect the component she can pass a client instance to
restore_checkpoint.
This technique is demonstrated below:
// Try to checkpoint and restore a component with a client
std::vector<int> vec3{10, 10, 10, 10, 10};
// Create a component instance through client constructor
data_client D(hpx::find_here(), std::move(vec3));
hpx::future<checkpoint> f3 = save_checkpoint(D);
// Create a new client
data_client E;
// Restore server inside client instance
restore_checkpoint(f3.get(), E);
The second way a user can save a component is by passing a shared_ptr to the
component to save_checkpoint. This component can be resurrected by creating
a new instance of the component type and passing a shared_ptr to the new
instance to restore_checkpoint.
This technique is demonstrated below:
// test checkpoint a component using a shared_ptr
std::vector<int> vec{1, 2, 3, 4, 5};
data_client A(hpx::find_here(), std::move(vec));
// Checkpoint Server
hpx::id_type old_id = A.get_id();
hpx::future<std::shared_ptr<data_server>> f_a_ptr =
hpx::get_ptr<data_server>(A.get_id());
std::shared_ptr<data_server> a_ptr = f_a_ptr.get();
hpx::future<checkpoint> f = save_checkpoint(a_ptr);
auto&& data = f.get();
// test prepare_checkpoint API
checkpoint c = prepare_checkpoint(hpx::launch::sync, a_ptr);
HPX_TEST(c.size() == data.size());
// Restore Server
// Create a new server instance
std::shared_ptr<data_server> b_server;
restore_checkpoint(data, b_server);
checkpoint_base¶
The checkpoint_base module contains lower level facilities that wrap simple check-pointing capabilities. This module does not implement special handling for futures or components, but simply serializes all arguments to or from a given container.
This module exposes the hpx::util::save_checkpoint_data,
hpx::util::restore_checkpoint_data, and hpx::util::prepare_checkpoint_data
APIs. These functions encapsulate the basic serialization functionalities
necessary to save/restore a variadic list of arguments to/from a given data
container.
See the API reference of this module for more details.
collectives¶
The collectives module exposes a set of distributed collective operations. Those can be used to exchange data between participating sites in a coordinated way. At this point the module exposes the following collective primitives:
hpx::collectives::all_gather: receives a set of values from all participating sites.hpx::collectives::all_reduce: performs a reduction on data from each participating site to each participating site.hpx::collectives::all_to_all: each participating site provides its element of the data to collect while all participating sites receive the data from every other site.hpx::collectives::broadcast_toandhpx::collectives::broadcast_from: performs a broadcast operation from a root site to all participating sites.- cpp:func:hpx::collectives::exclusive_scan
performs an exclusive scan operation
on a set of values received from all call sites operating on the given base name.
hpx::collectives::gather_hereandhpx::collectives::gather_there: gathers values from all participating sites.- cpp:func:hpx::collectives::inclusive_scan
performs an inclusive scan operation
on a set of values received from all call sites operating on the given base name.
hpx::collectives::reduce_hereandhpx::collectives::reduce_there: performs a reduction on data from each participating site to a root site.hpx::collectives::scatter_toandhpx::collectives::scatter_from: receives an element of a set of values operating on the given base name.hpx::lcos::broadcast: performs a given action on all given global identifiers.hpx::lcos::barrier: distributed barrier.hpx::lcos::fold: performs a fold with a given action on all given global identifiers.hpx::lcos::latch: distributed latch.hpx::lcos::reduce: performs a reduction on data from each given global identifiers.hpx::lcos::spmd_block: performs the same operation on a local image while providing handles to the other images.
See the API reference of the module for more details.
command_line_handling¶
The command_line_handling module defines and handles the command-line options required by the HPX runtime, combining them with configuration options defined by the runtime_configuration module. The actual parsing of command line options is handled by the program_options module.
See the API reference of the module for more details.
command_line_handling_local¶
TODO: High-level description of the module.
See the API reference of this module for more details.
components¶
TODO: High-level description of the module.
See the API reference of this module for more details.
components_base¶
TODO: High-level description of the library.
See the API reference of this module for more details.
compute¶
The compute module provides utilities for handling task and memory affinity on host systems. The compute_cuda for extensions to CUDA programmable GPU devices.
See the API reference of the module for more details.
compute_cuda¶
This module extends the compute module to handle CUDA programmable GPU devices.
See the API reference of the module for more details.
distribution_policies¶
TODO: High-level description of the module.
See the API reference of this module for more details.
executors_distributed¶
This module provides the executor
hpx::parallel::execution::disribution_policy_executor. It allows
one to create work that is implicitly distributed over multiple localities.
See the API reference of this module for more details.
include¶
This module provides no functionality in itself. Instead it provides headers that group together other headers that often appear together.
See the API reference of this module for more details.
include_local¶
This module provides no functionality in itself. Instead it provides headers that group together other headers that often appear together. This module provides local-only headers.
See the API reference of this module for more details.
init_runtime¶
TODO: High-level description of the library.
See the API reference of this module for more details.
init_runtime_local¶
TODO: High-level description of the module.
See the API reference of this module for more details.
lcos_distributed¶
This module contains distributed LCOs. Currently the only LCO provided is :cpp:class::hpx::lcos::channel, a construct for sending values from one locality to another. See libs_lcos_local for local LCOs.
See the API reference of this module for more details.
mpi_base¶
This module provides helper functionality for detecting MPI environments.
See the API reference of this module for more details.
naming¶
TODO: High-level description of the module.
See the API reference of this module for more details.
naming_base¶
This module provides a forward declaration of address_type, component_type and invalid_locality_id.
See the API reference of this module for more details.
performance_counters¶
This module provides the basic functionality required for defining performance counters. See Performance counters for more information about performance counters.
See the API reference of this module for more details.
program_options¶
The module program_options is a direct fork of the Boost.ProgramOptions library
(Boost V1.70.0). For more information about this library please see here.
In order to be included as an HPX module, the Boost.ProgramOptions library has
been moved to the namespace hpx::program_options. We have also replaced all
Boost facilities the library depends on with either the equivalent facilities
from the standard library or from HPX. As a result, the HPX program_options module
is fully interface compatible with Boost.ProgramOptions (sans the hpx
namespace and the #include <hpx/modules/program_options.hpp> changes that need to be
applied to all code relying on this library).
All credit goes to Vladimir Prus, the author of the excellent Boost.ProgramOptions library. All bugs have been introduced by us.
See the API reference of the module for more details.
resiliency_distributed¶
Software resiliency features of HPX were introduced in the resiliency module. This module extends the APIs to run on distributed-memory systems allowing the user to invoke the failing task on other localities at runtime. This is useful in cases where a node is identified to fail more often (e.g., for certain ALU computes) as the task can now be replayed or replicated among different localities. The API exposed allows for an easy integration with the local only resiliency APIs as well.
Distributed software resilience APIs have a similar function signature
and lives under the same namespace of hpx::resiliency::experimental.
The difference arises in the formal parameters where distributed APIs takes
the localities as the first argument, and an action as opposed to a function or
a function object. The localities signify the order in which the API will either
schedule (in case of Task Replay) tasks in a round robin fashion or replicate
the tasks onto the list of localities.
The list of APIs exposed by distributed resiliency modules is the same as those defined in local resiliency module.
See the API reference of this module for more details.
resource_partitioner¶
The resource_partitioner module defines hpx::resource::partitioner,
the class used by the runtime and users to partition available hardware
resources into thread pools. See Using the resource partitioner for more
details on using the resource partitioner in applications.
See the API reference of this module for more details.
runtime_components¶
TODO: High-level description of the module.
See the API reference of this module for more details.
runtime_configuration¶
This module handles the configuration options required by the runtime.
See the API reference of this module for more details.
runtime_distributed¶
TODO: High-level description of the module.
See the API reference of this module for more details.
runtime_local¶
TODO: High-level description of the library.
See the API reference of this module for more details.
segmented_algorithms¶
Segmented algorithms extend the usual parallel algorithms by providing overloads that work with distributed containers, such as partitioned vectors.
See the API reference of the module for more details.
thread_manager¶
This module defines the hpx::threads::threadmanager class. This is
used by the runtime to manage the creation and destruction of thread pools. The
resource_partitioner module handles the partitioning of resources
into thread pools, but not the creation of thread pools.
See the API reference of this module for more details.
API reference¶
HPX follows a versioning scheme with three numbers: major.minor.patch. We
guarantee no breaking changes in the API for patch releases. Minor releases may
remove or break existing APIs, but only after a deprecation period of at least
two minor releases. In rare cases do we outright remove old and unused
functionality without a deprecation period.
We do not provide any ABI compatibility guarantees between any versions, debug and release builds, and builds with different C++ standards.
The public API of HPX is presented below. Clicking on a name brings you to the full documentation for the class or function. Including the header specified in a heading brings in the features listed under that heading.
Note
Names listed here are guaranteed stable with respect to semantic versioning. However, at the moment the list is incomplete and certain unlisted features are intended to be in the public API. While we work on completing the list, if you’re unsure about whether a particular unlisted name is part of the public API you can get into contact with us or open an issue and we’ll clarify the situation.
Public API¶
All names below are also available in the top-level hpx namespace unless
otherwise noted. The names in hpx should be preferred. The names in
sub-namespaces will eventually be removed.
Header hpx/algorithm.hpp¶
This header includes Header hpx/local/algorithm.hpp and contains overloads of the algorithms for segmented iterators.
Header hpx/local/algorithm.hpp¶
Corresponds to the C++ standard library header algorithm. See Using parallel algorithms for more information about the parallel algorithms.
Functions¶
hpx::parallel::v1::mismatchhpx::ranges::fillhpx::ranges::fill_nhpx::ranges::find_ifhpx::ranges::find_if_nothpx::ranges::is_heaphpx::ranges::is_heap_untilhpx::ranges::is_partitionedhpx::ranges::move
Header hpx/any.hpp¶
This header includes Header hpx/local/any.hpp.
Header hpx/local/any.hpp¶
Corresponds to the C++ standard library header any.
hpx::any is compatible with std::any.
Header hpx/assert.hpp¶
Corresponds to the C++ standard library header cassert.
HPX_ASSERT is the HPX equivalent to assert in cassert.
HPX_ASSERT can also be used in CUDA device code.
Macros¶
Header hpx/barrier.hpp¶
This header includes Header hpx/local/barrier.hpp and contains a
distributed barrier implementation. This functionality is also exposed through
the hpx::distributed namespace. The name in hpx::distributed should be
preferred.
Classes¶
Header hpx/local/barrier.hpp¶
Corresponds to the C++ standard library header barrier.
Classes¶
hpx::lcos::local::cpp20_barrier
Header hpx/channel.hpp¶
This header includes Header hpx/local/channel.hpp and contains a
distributed channel implementation. This functionality is also exposed through
the hpx::distributed namespace. The name in hpx::distributed should be
preferred.
Classes¶
hpx::lcos::channel
Header hpx/local/channel.hpp¶
Contains a local channel implementation.
Classes¶
hpx::lcos::local::channel
Header hpx/chrono.hpp¶
This header includes Header hpx/local/chrono.hpp.
Header hpx/local/chrono.hpp¶
Corresponds to the C++ standard library header chrono.
The following replacements and extensions are provided compared to
chrono. The classes below are also available in the
hpx::chrono namespace, not in the top-level hpx namespace.
Header hpx/condition_variable.hpp¶
This header includes Header hpx/local/condition_variable.hpp.
Header hpx/local/condition_variable.hpp¶
Corresponds to the C++ standard library header condition_variable.
Header hpx/exception.hpp¶
This header includes Header hpx/local/exception.hpp.
Header hpx/local/exception.hpp¶
Corresponds to the C++ standard library header exception.
hpx::exception extends std::exception and is the base class for
all exceptions thrown in HPX. HPX_THROW_EXCEPTION can be used to
throw HPX exceptions with file and line information attached to the exception.
Macros¶
Classes¶
Header hpx/execution.hpp¶
This header includes Header hpx/local/execution.hpp.
Header hpx/local/execution.hpp¶
Corresponds to the C++ standard library header execution. See High level parallel facilities, Using parallel algorithms and Executor parameters and executor parameter traits for more information about execution policies and executor parameters.
Note
These names are only available in the hpx::execution namespace, not in
the top-level hpx namespace.
Constants¶
hpx::execution::seqhpx::execution::par_unseqhpx::execution::task
Classes¶
Header hpx/functional.hpp¶
This header includes Header hpx/local/functional.hpp.
Header hpx/local/functional.hpp¶
Corresponds to the C++ standard library header
functional. hpx::util::function is a more
efficient and serializable replacement for std::function.
Constants¶
The following constants are also available in hpx::placeholders, not the
top-level hpx namespace.
hpx::util::placeholders::_1hpx::util::placeholders::_2…
hpx::util::placeholders::_9
Classes¶
hpx::util::functionhpx::util::function_refhpx::util::unique_function
Header hpx/future.hpp¶
This header includes Header hpx/local/future.hpp and contains
overloads of hpx::async, hpx::apply,
hpx::sync, and hpx::dataflow that can be used with
actions. See Action invocation for more information about invoking
actions.
Note
The alias from hpx::promise to hpx::lcos::promise is
deprecated and will be removed in a future release. The alias
hpx::distributed::promise should be used in new applications.
Classes¶
hpx::lcos::promise
Functions¶
Header hpx/local/future.hpp¶
Corresponds to the C++ standard library header future. See Extended facilities for futures for more information about extensions to futures compared to the C++ standard library.
Note
All names except hpx::lcos::local::promise are also available in
the top-level hpx namespace. hpx::promise refers to
hpx::lcos::promise, a distributed variant of
hpx::lcos::local::promise, but will eventually refer to
hpx::lcos::local::promise after a deprecation period.
Classes¶
hpx::lcos::futurehpx::lcos::shared_futurehpx::lcos::local::promise
Functions¶
Examples¶
#include <hpx/assert.hpp>
#include <hpx/future.hpp>
#include <hpx/hpx_main.hpp>
#include <hpx/tuple.hpp>
#include <iostream>
#include <utility>
int main()
{
// Asynchronous execution with futures
hpx::future<void> f1 = hpx::async(hpx::launch::async, []() {});
hpx::shared_future<int> f2 =
hpx::async(hpx::launch::async, []() { return 42; });
hpx::future<int> f3 =
f2.then([](hpx::shared_future<int>&& f) { return f.get() * 3; });
hpx::lcos::local::promise<double> p;
auto f4 = p.get_future();
HPX_ASSERT(!f4.is_ready());
p.set_value(123.45);
HPX_ASSERT(f4.is_ready());
hpx::packaged_task<int()> t([]() { return 43; });
hpx::future<int> f5 = t.get_future();
HPX_ASSERT(!f5.is_ready());
t();
HPX_ASSERT(f5.is_ready());
// Fire-and-forget
hpx::apply([]() {
std::cout << "This will be printed later\n" << std::flush;
});
// Synchronous execution
hpx::sync([]() {
std::cout << "This will be printed immediately\n" << std::flush;
});
// Combinators
hpx::future<double> f6 = hpx::async([]() { return 3.14; });
hpx::future<double> f7 = hpx::async([]() { return 42.0; });
std::cout
<< hpx::when_all(f6, f7)
.then([](hpx::future<
hpx::tuple<hpx::future<double>, hpx::future<double>>>
f) {
hpx::tuple<hpx::future<double>, hpx::future<double>> t =
f.get();
double pi = hpx::get<0>(t).get();
double r = hpx::get<1>(t).get();
return pi * r * r;
})
.get()
<< std::endl;
// Easier continuations with dataflow; it waits for all future or
// shared_future arguments before executing the continuation, and also
// accepts non-future arguments
hpx::future<double> f8 = hpx::async([]() { return 3.14; });
hpx::future<double> f9 = hpx::make_ready_future(42.0);
hpx::shared_future<double> f10 = hpx::async([]() { return 123.45; });
hpx::future<hpx::tuple<double, double>> f11 = hpx::dataflow(
[](hpx::future<double> a, hpx::future<double> b,
hpx::shared_future<double> c, double d) {
return hpx::make_tuple<>(a.get() + b.get(), c.get() / d);
},
f8, f9, f10, -3.9);
// split_future gives a tuple of futures from a future of tuple
hpx::tuple<hpx::future<double>, hpx::future<double>> f12 =
hpx::split_future(std::move(f11));
std::cout << hpx::get<1>(f12).get() << std::endl;
return 0;
}
Header hpx/init.hpp¶
This header contains functionality for starting, stopping, suspending, and resuming the HPX runtime. This is the main way to explicitly start the HPX runtime. See Starting the HPX runtime for more details on starting the HPX runtime.
Classes¶
Header hpx/latch.hpp¶
This header includes Header hpx/local/latch.hpp and contains a
distributed latch implementation. This functionality is also exposed through the
hpx::distributed namespace. The name in hpx::distributed should be
preferred.
Classes¶
Header hpx/mutex.hpp¶
This header includes Header hpx/local/mutex.hpp.
Header hpx/local/mutex.hpp¶
Corresponds to the C++ standard library header mutex.
Classes¶
Functions¶
Header hpx/memory.hpp¶
This header includes Header hpx/local/memory.hpp.
Header hpx/local/memory.hpp¶
Corresponds to the C++ standard library header memory. It contains parallel versions of the copy, fill, move, and construct helper functions in memory. See Using parallel algorithms for more information about the parallel algorithms.
Functions¶
Header hpx/numeric.hpp¶
This header includes Header hpx/local/numeric.hpp.
Header hpx/local/numeric.hpp¶
Corresponds to the C++ standard library header numeric. See Using parallel algorithms for more information about the parallel algorithms.
Functions¶
Header hpx/optional.hpp¶
This header includes Header hpx/local/optional.hpp.
Header hpx/local/optional.hpp¶
Corresponds to the C++ standard library header optional.
hpx::util::optional is compatible with std::optional.
Constants¶
Classes¶
hpx::util::optional
Functions¶
Header hpx/runtime.hpp¶
This header includes Header hpx/local/runtime.hpp and contains functions for accessing distributed runtime information.
Header hpx/local/runtime.hpp¶
This header contains functions for accessing local runtime information.
Header hpx/system_error.hpp¶
This header includes Header hpx/local/system_error.hpp.
Header hpx/local/system_error.hpp¶
Corresponds to the C++ standard library header system_error.
Classes¶
Header hpx/task_block.hpp¶
This header includes Header hpx/local/task_black.hpp.
Header hpx/local/task_black.hpp¶
Corresponds to the task_block feature in N4411. See
Using task blocks for more details on using task blocks.
Classes¶
hpx::parallel::v2::task_block
Header hpx/thread.hpp¶
This header includes Header hpx/local/thread.hpp.
Header hpx/local/thread.hpp¶
Corresponds to the C++ standard library header thread. The functionality in this header is equivalent to the standard library thread functionality, with the exception that the HPX equivalents are implemented on top of lightweight threads and the HPX runtime.
Classes¶
Header hpx/semaphore.hpp¶
This header includes Header hpx/local/semaphore.hpp.
Header hpx/local/semaphore.hpp¶
Corresponds to the C++ standard library header semaphore.
Classes¶
hpx::lcos::local::cpp20_binary_semaphorehpx::lcos::local::cpp20_counting_semaphore
Header hpx/stop_token.hpp¶
This header includes Header hpx/local/stop_token.hpp.
Header hpx/local/stop_token.hpp¶
Corresponds to the C++ standard library header stop_token.
Constants¶
hpx::nostopstate
Classes¶
hpx::stop_callback
Header hpx/tuple.hpp¶
This header includes Header hpx/local/tuple.hpp.
Header hpx/local/tuple.hpp¶
Corresponds to the C++ standard library header tuple.
hpx::tuple can be used in CUDA device code, unlike std::tuple.
Constants¶
Classes¶
hpx::tuplehpx::tuple_element
Functions¶
Header hpx/type_traits.hpp¶
This header includes Header hpx/local/type_traits.hpp.
Header hpx/local/type_traits.hpp¶
Corresponds to the C++ standard library header type_traits.
Classes¶
hpx::is_invocablehpx::is_invocable_r
Header hpx/unwrap.hpp¶
This header includes Header hpx/local/unwrap.hpp.
Header hpx/local/unwrap.hpp¶
Contains utilities for unwrapping futures.
Header hpx/version.hpp¶
This header provides version information about HPX.
Macros¶
HPX_VERSION_MAJORHPX_VERSION_MINORHPX_VERSION_SUBMINORHPX_VERSION_FULLHPX_VERSION_DATEHPX_VERSION_TAGHPX_AGAS_VERSION
Header hpx/wrap_main.hpp¶
This header does not provide any direct functionality but is used for implicitly
using main as the runtime entry point. See Re-use the main() function as the main HPX entry point for more details
on implicitly starting the HPX runtime.
Full API¶
The full API of HPX is presented below. The listings for the public API above refer to the full documentation below.
Note
Most names listed in the full API reference are implementation details or considered unstable. They are listed mostly for completeness. If there is a particular feature you think deserves being in the public API we may consider promoting it. In general we prioritize making sure features corresponding to C++ standard library features are stable and complete.
Main HPX library¶
This lists functionality in the main HPX library that has not been moved to modules yet.
-
namespace
hpx¶
-
namespace
components¶ Functions
-
template<typename
Component>
future<naming::id_type>migrate_from_storage(naming::id_type const &to_resurrect, naming::id_type const &target = naming::invalid_id)¶ Migrate the component with the given id from the specified target storage (resurrect the object)
The function migrate_from_storage<Component> will migrate the component referenced by to_resurrect from the storage facility specified where the object is currently stored on. It returns a future referring to the migrated component instance. The component instance is resurrected on the locality specified by target_locality.
- Return
A future representing the global id of the migrated component instance. This should be the same as to_resurrect.
- Parameters
to_resurrect: [in] The global id of the component to migrate.target: [in] The optional locality to resurrect the object on. By default the object is resurrected on the locality it was located on last.
- Template Parameters
The: only template argument specifies the component type of the component to migrate from the given storage facility.
-
template<typename
Component>
future<naming::id_type>migrate_to_storage(naming::id_type const &to_migrate, naming::id_type const &target_storage)¶ Migrate the component with the given id to the specified target storage
The function migrate_to_storage<Component> will migrate the component referenced by to_migrate to the storage facility specified with target_storage. It returns a future referring to the migrated component instance.
- Return
A future representing the global id of the migrated component instance. This should be the same as migrate_to.
- Parameters
to_migrate: [in] The global id of the component to migrate.target_storage: [in] The id of the storage facility to migrate this object to.
- Template Parameters
The: only template argument specifies the component type of the component to migrate to the given storage facility.
-
template<typename
Derived, typenameStub>
Derivedmigrate_to_storage(client_base<Derived, Stub> const &to_migrate, hpx::components::component_storage const &target_storage)¶ Migrate the given component to the specified target storage
The function migrate_to_storage will migrate the component referenced by to_migrate to the storage facility specified with target_storage. It returns a future referring to the migrated component instance.
- Return
A client side representation of representing of the migrated component instance. This should be the same as migrate_to.
- Parameters
to_migrate: [in] The client side representation of the component to migrate.target_storage: [in] The id of the storage facility to migrate this object to.
-
template<typename
-
file
migrate_from_storage.hpp - #include <hpx/config.hpp>#include <hpx/components_base/traits/is_component.hpp>#include <hpx/futures/future.hpp>#include <hpx/naming_base/id_type.hpp>#include <hpx/components/component_storage/server/migrate_from_storage.hpp>#include <type_traits>
-
file
migrate_to_storage.hpp - #include <hpx/config.hpp>#include <hpx/components/client_base.hpp>#include <hpx/components_base/traits/is_component.hpp>#include <hpx/futures/future.hpp>#include <hpx/naming_base/id_type.hpp>#include <hpx/components/component_storage/component_storage.hpp>#include <hpx/components/component_storage/server/migrate_to_storage.hpp>#include <type_traits>
-
file
set_parcel_write_handler.hpp - #include <hpx/config.hpp>
-
dir
/hpx/source/components/component_storage
-
dir
/hpx/source/components/component_storage/include/hpx/components/component_storage
-
dir
/hpx/source/components/component_storage/include/hpx/components
-
dir
/hpx/source/components
-
dir
/hpx/source/components/component_storage/include/hpx
-
dir
/hpx/source/hpx
-
dir
/hpx/source/components/component_storage/include
-
dir
/hpx/source/hpx/runtime
-
dir
/hpx/source
affinity¶
The contents of this module can be included with the header
hpx/modules/affinity.hpp. These headers may be used by user-code but are not
guaranteed stable (neither header location nor contents). You are using these at
your own risk. If you wish to use non-public functionality from a module we
strongly suggest only including the module header hpx/modules/affinity.hpp, not
the particular header in which the functionality you would like to use is
defined. See Public API for a list of names that are part of the public
HPX API.
-
namespace
hpx -
namespace
threads¶ Functions
-
void
parse_affinity_options(std::string const &spec, std::vector<mask_type> &affinities, std::size_t used_cores, std::size_t max_cores, std::size_t num_threads, std::vector<std::size_t> &num_pus, bool use_process_mask, error_code &ec = throws)¶
-
void
parse_affinity_options(std::string const &spec, std::vector<mask_type> &affinities, error_code &ec = throws)¶
-
void
-
namespace
allocator_support¶
The contents of this module can be included with the header
hpx/modules/allocator_support.hpp. These headers may be used by user-code but are not
guaranteed stable (neither header location nor contents). You are using these at
your own risk. If you wish to use non-public functionality from a module we
strongly suggest only including the module header hpx/modules/allocator_support.hpp, not
the particular header in which the functionality you would like to use is
defined. See Public API for a list of names that are part of the public
HPX API.
Functions
-
void
__aligned_free(void *p)¶
-
namespace
hpx -
namespace
util¶ Functions
-
template<typename
T= int>
structaligned_allocator¶ Public Types
-
typedef T
value_type¶
-
typedef T *
pointer¶
-
typedef T &
reference¶
-
typedef T const &
const_reference¶
Public Functions
-
aligned_allocator()¶
-
template<typename
U>aligned_allocator(aligned_allocator<U> const&)¶
-
const_pointer
address(const_reference x) const¶
-
HPX_NODISCARD pointer hpx::util::aligned_allocator::allocate(size_type n, void const * = nullptr)
Public Members
-
const typedef T* hpx::util::aligned_allocator::const_pointer
-
typedef T
-
template<typename
-
namespace
-
namespace
hpx
-
namespace
hpx -
namespace
util
-
namespace
-
namespace
hpx -
namespace
traits¶ Variables
-
template<typename T>HPX_INLINE_CONSTEXPR_VARIABLE bool hpx::traits::is_allocator_v = is_allocator<T>::value
-
-
namespace
asio¶
The contents of this module can be included with the header
hpx/modules/asio.hpp. These headers may be used by user-code but are not
guaranteed stable (neither header location nor contents). You are using these at
your own risk. If you wish to use non-public functionality from a module we
strongly suggest only including the module header hpx/modules/asio.hpp, not
the particular header in which the functionality you would like to use is
defined. See Public API for a list of names that are part of the public
HPX API.
-
namespace
hpx -
namespace
util Typedefs
-
using
endpoint_iterator_type= asio::ip::tcp::resolver::iterator¶
Functions
-
asio::ip::tcp::endpoint
resolve_hostname(std::string const &hostname, std::uint16_t port, asio::io_context &io_service)¶
-
endpoint_iterator_type
connect_begin(std::string const &address, std::uint16_t port, asio::io_context &io_service)¶
-
template<typename
Locality>
endpoint_iterator_typeconnect_begin(Locality const &loc, asio::io_context &io_service)¶ Returns an iterator which when dereferenced will give an endpoint suitable for a call to connect() related to this locality.
-
endpoint_iterator_type
connect_end()¶
-
endpoint_iterator_type
accept_begin(std::string const &address, std::uint16_t port, asio::io_context &io_service)¶
-
template<typename
Locality>
endpoint_iterator_typeaccept_begin(Locality const &loc, asio::io_context &io_service)¶ Returns an iterator which when dereferenced will give an endpoint suitable for a call to accept() related to this locality.
-
endpoint_iterator_type
accept_end()¶
-
using
-
namespace
-
namespace
hpx -
namespace
util -
struct
map_hostnames¶ Public Types
-
typedef util::function_nonser<std::string(std::string const&)>
transform_function_type¶
Public Functions
-
map_hostnames(bool debug = false)¶
-
void
use_transform(transform_function_type const &f)¶
-
typedef util::function_nonser<std::string(std::string const&)>
-
struct
-
namespace
assertion¶
The contents of this module can be included with the header
hpx/modules/assertion.hpp. These headers may be used by user-code but are not
guaranteed stable (neither header location nor contents). You are using these at
your own risk. If you wish to use non-public functionality from a module we
strongly suggest only including the module header hpx/modules/assertion.hpp, not
the particular header in which the functionality you would like to use is
defined. See Public API for a list of names that are part of the public
HPX API.
Defines
-
HPX_ASSERT_CURRENT_FUNCTION¶
-
namespace
hpx
Defines
-
HPX_ASSERT(expr)¶ This macro asserts that expr evaluates to true.
If
exprevaluates to false, The source location andmsgis being printed along with the expression and additional. Afterwards the program is being aborted. The assertion handler can be customized by calling hpx::assertion::set_assertion_handler().- Parameters
expr: The expression to assert on. This can either be an expression that’s convertible to bool or a callable which returns boolmsg: The optional message that is used to give further information if the assert fails. This should be convertible to a std::string
Asserts are enabled if HPX_DEBUG is set. This is the default for
CMAKE_BUILD_TYPE=Debug
-
HPX_ASSERT_MSG(expr, msg)¶ - See
HPX_ASSERT
-
namespace
hpx -
namespace
assertion Typedefs
-
using
assertion_handler= void (*)(source_location const &loc, const char *expr, std::string const &msg)¶ The signature for an assertion handler.
Functions
-
void
set_assertion_handler(assertion_handler handler)¶ Set the assertion handler to be used within a program. If the handler has been set already once, the call to this function will be ignored.
- Note
This function is not thread safe
-
using
-
namespace
cache¶
The contents of this module can be included with the header
hpx/modules/cache.hpp. These headers may be used by user-code but are not
guaranteed stable (neither header location nor contents). You are using these at
your own risk. If you wish to use non-public functionality from a module we
strongly suggest only including the module header hpx/modules/cache.hpp, not
the particular header in which the functionality you would like to use is
defined. See Public API for a list of names that are part of the public
HPX API.
-
namespace
hpx -
namespace
util -
namespace
cache¶ -
template<typename
Key, typenameEntry, typenameUpdatePolicy= std::less<Entry>, typenameInsertPolicy= policies::always<Entry>, typenameCacheStorage= std::map<Key, Entry>, typenameStatistics= statistics::no_statistics>
classlocal_cache¶ - #include <hpx/cache/local_cache.hpp>
The local_cache implements the basic functionality needed for a local (non-distributed) cache.
- Template Parameters
Key: The type of the keys to use to identify the entries stored in the cacheEntry: The type of the items to be held in the cache, must model the CacheEntry conceptUpdatePolicy: A (optional) type specifying a (binary) function object used to sort the cache entries based on their ‘age’. The ‘oldest’ entries (according to this sorting criteria) will be discarded first if the maximum capacity of the cache is reached. The default is std::less<Entry>. The function object will be invoked using 2 entry instances of the type Entry. This type must model the UpdatePolicy model.InsertPolicy: A (optional) type specifying a (unary) function object used to allow global decisions whether a particular entry should be added to the cache or not. The default is policies::always, imposing no global insert related criteria on the cache. The function object will be invoked using the entry instance to be inserted into the cache. This type must model the InsertPolicy model.CacheStorage: A (optional) container type used to store the cache items. The container must be an associative and STL compatible container.The default is a std::map<Key, Entry>.Statistics: A (optional) type allowing to collect some basic statistics about the operation of the cache instance. The type must conform to the CacheStatistics concept. The default value is the type statistics::no_statistics which does not collect any numbers, but provides empty stubs allowing the code to compile.
Public Types
-
typedef Key
key_type¶
-
typedef Entry
entry_type¶
-
typedef UpdatePolicy
update_policy_type¶
-
typedef InsertPolicy
insert_policy_type¶
-
typedef CacheStorage
storage_type¶
-
typedef Statistics
statistics_type¶
-
typedef entry_type::value_type
value_type¶
-
typedef storage_type::size_type
size_type¶
-
typedef storage_type::value_type
storage_value_type¶
Public Functions
-
local_cache(size_type max_size = 0, update_policy_type const &up = update_policy_type(), insert_policy_type const &ip = insert_policy_type())¶ Construct an instance of a local_cache.
- Parameters
max_size: [in] The maximal size this cache is allowed to reach any time. The default is zero (no size limitation). The unit of this value is usually determined by the unit of the values returned by the entry’s get_size function.up: [in] An instance of the UpdatePolicy to use for this cache. The default is to use a default constructed instance of the type as defined by the UpdatePolicy template parameter.ip: [in] An instance of the InsertPolicy to use for this cache. The default is to use a default constructed instance of the type as defined by the InsertPolicy template parameter.
-
local_cache(local_cache &&other)¶
-
size_type
size() const¶ Return current size of the cache.
- Return
The current size of this cache instance.
-
size_type
capacity() const¶ Access the maximum size the cache is allowed to grow to.
- Note
The unit of this value is usually determined by the unit of the return values of the entry’s function entry::get_size.
- Return
The maximum size this cache instance is currently allowed to reach. If this number is zero the cache has no limitation with regard to a maximum size.
-
bool
reserve(size_type max_size)¶ Change the maximum size this cache can grow to.
- Return
This function returns true if successful. It returns false if the new max_size is smaller than the current limit and the cache could not be shrunk to the new maximum size.
- Parameters
max_size: [in] The new maximum size this cache will be allowed to grow to.
-
bool
holds_key(key_type const &k) const¶ Check whether the cache currently holds an entry identified by the given key.
- Note
This function does not call the entry’s function entry::touch. It just checks if the cache contains an entry corresponding to the given key.
- Return
This function returns true if the cache holds the referenced entry, otherwise it returns false.
- Parameters
k: [in] The key for the entry which should be looked up in the cache.
-
bool
get_entry(key_type const &k, key_type &realkey, entry_type &val)¶ Get a specific entry identified by the given key.
- Note
The function will call the entry’s entry::touch function if the value corresponding to the provided key is found in the cache.
- Return
This function returns true if the cache holds the referenced entry, otherwise it returns false.
- Parameters
k: [in] The key for the entry which should be retrieved from the cache.val: [out] If the entry indexed by the key is found in the cache this value on successful return will be a copy of the corresponding entry.
-
bool
get_entry(key_type const &k, entry_type &val)¶ Get a specific entry identified by the given key.
- Note
The function will call the entry’s entry::touch function if the value corresponding to the provided key is found in the cache.
- Return
This function returns true if the cache holds the referenced entry, otherwise it returns false.
- Parameters
k: [in] The key for the entry which should be retrieved from the cache.val: [out] If the entry indexed by the key is found in the cache this value on successful return will be a copy of the corresponding entry.
-
bool
get_entry(key_type const &k, value_type &val)¶ Get a specific entry identified by the given key.
- Note
The function will call the entry’s entry::touch function if the value corresponding to the provided is found in the cache.
- Return
This function returns true if the cache holds the referenced entry, otherwise it returns false.
- Parameters
k: [in] The key for the entry which should be retrieved from the cacheval: [out] If the entry indexed by the key is found in the cache this value on successful return will be a copy of the corresponding value.
-
bool
insert(key_type const &k, value_type const &val)¶ Insert a new element into this cache.
- Note
This function invokes both, the insert policy as provided to the constructor and the function entry::insert of the newly constructed entry instance. If either of these functions returns false the key/value pair doesn’t get inserted into the cache and the insert function will return false. Other reasons for this function to fail (return false) are a) the key/value pair is already held in the cache or b) inserting the new value into the cache maxed out its capacity and it was not possible to free any of the existing entries.
- Return
This function returns true if the entry has been successfully added to the cache, otherwise it returns false.
- Parameters
k: [in] The key for the entry which should be added to the cache.value: [in] The value which should be added to the cache.
-
bool
insert(key_type const &k, entry_type &e)¶ Insert a new entry into this cache.
- Note
This function invokes both, the insert policy as provided to the constructor and the function entry::insert of the provided entry instance. If either of these functions returns false the key/value pair doesn’t get inserted into the cache and the insert function will return false. Other reasons for this function to fail (return false) are a) the key/value pair is already held in the cache or b) inserting the new value into the cache maxed out its capacity and it was not possible to free any of the existing entries.
- Return
This function returns true if the entry has been successfully added to the cache, otherwise it returns false.
- Parameters
k: [in] The key for the entry which should be added to the cache.value: [in] The entry which should be added to the cache.
-
bool
update(key_type const &k, value_type const &val)¶ Update an existing element in this cache.
- Note
The function will call the entry’s entry::touch function if the indexed value is found in the cache.
- Note
The difference to the other overload of the insert function is that this overload replaces the cached value only, while the other overload replaces the whole cache entry, updating the cache entry properties.
- Return
This function returns true if the entry has been successfully updated, otherwise it returns false. If the entry currently is not held by the cache it is added and the return value reflects the outcome of the corresponding insert operation.
- Parameters
k: [in] The key for the value which should be updated in the cache.value: [in] The value which should be used as a replacement for the existing value in the cache. Any existing cache entry is not changed except for its value.
-
template<typename
F>
boolupdate_if(key_type const &k, value_type const &val, F f)¶ Update an existing element in this cache.
- Note
The function will call the entry’s entry::touch function if the indexed value is found in the cache.
- Note
The difference to the other overload of the insert function is that this overload replaces the cached value only, while the other overload replaces the whole cache entry, updating the cache entry properties.
- Return
This function returns true if the entry has been successfully updated, otherwise it returns false. If the entry currently is not held by the cache it is added and the return value reflects the outcome of the corresponding insert operation.
- Parameters
k: [in] The key for the value which should be updated in the cache.value: [in] The value which should be used as a replacement for the existing value in the cache. Any existing cache entry is not changed except for its value.f: [in] A callable taking two arguments, k and the key found in the cache (in that order). If f returns true, then the update will continue. If f returns false, then the update will not succeed.
-
bool
update(key_type const &k, entry_type &e)¶ Update an existing entry in this cache.
- Note
The function will call the entry’s entry::touch function if the indexed value is found in the cache.
- Note
The difference to the other overload of the insert function is that this overload replaces the whole cache entry, while the other overload retplaces the cached value only, leaving the cache entry properties untouched.
- Return
This function returns true if the entry has been successfully updated, otherwise it returns false. If the entry currently is not held by the cache it is added and the return value reflects the outcome of the corresponding insert operation.
- Parameters
k: [in] The key for the entry which should be updated in the cache.value: [in] The entry which should be used as a replacement for the existing entry in the cache. Any existing entry is first removed and then this entry is added.
-
template<typename
Func>
size_typeerase(Func const &ep = policies::always<storage_value_type>())¶ Remove stored entries from the cache for which the supplied function object returns true.
- Return
This function returns the overall size of the removed entries (which is the sum of the values returned by the entry::get_size functions of the removed entries).
- Parameters
ep: [in] This parameter has to be a (unary) function object. It is invoked for each of the entries currently held in the cache. An entry is considered for removal from the cache whenever the value returned from this invocation is true. Even then the entry might not be removed from the cache as its entry::remove function might return false.
-
size_type
erase()¶ Remove all stored entries from the cache.
- Note
All entries are considered for removal, but in the end an entry might not be removed from the cache as its entry::remove function might return false. This function is very useful for instance in conjunction with an entry’s entry::remove function enforcing additional criteria like entry expiration, etc.
- Return
This function returns the overall size of the removed entries (which is the sum of the values returned by the entry::get_size functions of the removed entries).
-
void
clear()¶ Clear the cache.
Unconditionally removes all stored entries from the cache.
-
statistics_type const &
get_statistics() const¶ Allow to access the embedded statistics instance.
- Return
This function returns a reference to the statistics instance embedded inside this cache
-
statistics_type &
get_statistics()¶
Protected Functions
-
bool
free_space(long num_free)¶
Private Types
-
typedef storage_type::iterator
iterator¶
-
typedef storage_type::const_iterator
const_iterator¶
-
typedef statistics_type::update_on_exit
update_on_exit¶
Private Members
-
storage_type
store_¶
-
adapted_update_policy_type
update_policy_¶
-
insert_policy_type
insert_policy_¶
-
statistics_type
statistics_¶
-
template<typename
-
namespace
-
namespace
-
namespace
hpx -
namespace
util -
namespace
cache -
template<typename
Key, typenameEntry, typenameStatistics= statistics::no_statistics>
classlru_cache¶ - #include <hpx/cache/lru_cache.hpp>
The lru_cache implements the basic functionality needed for a local (non-distributed) LRU cache.
- Template Parameters
Key: The type of the keys to use to identify the entries stored in the cacheEntry: The type of the items to be held in the cache.Statistics: A (optional) type allowing to collect some basic statistics about the operation of the cache instance. The type must conform to the CacheStatistics concept. The default value is the type statistics::no_statistics which does not collect any numbers, but provides empty stubs allowing the code to compile.
Public Types
-
typedef Key
key_type¶
-
typedef Entry
entry_type¶
-
typedef Statistics
statistics_type¶
-
typedef std::pair<key_type, entry_type>
entry_pair¶
-
typedef std::list<entry_pair>
storage_type¶
-
typedef std::map<Key, typename storage_type::iterator>
map_type¶
Public Functions
-
lru_cache(size_type max_size = 0)¶ Construct an instance of a lru_cache.
- Parameters
max_size: [in] The maximal size this cache is allowed to reach any time. The default is zero (no size limitation). The unit of this value is usually determined by the unit of the values returned by the entry’s get_size function.
-
size_type
size() const¶ Return current size of the cache.
- Return
The current size of this cache instance.
-
size_type
capacity() const¶ Access the maximum size the cache is allowed to grow to.
- Note
The unit of this value is usually determined by the unit of the return values of the entry’s function entry::get_size.
- Return
The maximum size this cache instance is currently allowed to reach. If this number is zero the cache has no limitation with regard to a maximum size.
-
void
reserve(size_type max_size)¶ Change the maximum size this cache can grow to.
- Parameters
max_size: [in] The new maximum size this cache will be allowed to grow to.
-
bool
holds_key(key_type const &key)¶ Check whether the cache currently holds an entry identified by the given key.
- Note
This function does not call the entry’s function entry::touch. It just checks if the cache contains an entry corresponding to the given key.
- Return
This function returns true if the cache holds the referenced entry, otherwise it returns false.
- Parameters
k: [in] The key for the entry which should be looked up in the cache.
-
bool
get_entry(key_type const &key, key_type &realkey, entry_type &entry)¶ Get a specific entry identified by the given key.
- Note
The function will “touch” the entry and mark it as recently used if the key was found in the cache.
- Return
This function returns true if the cache holds the referenced entry, otherwise it returns false.
- Parameters
key: [in] The key for the entry which should be retrieved from the cache.entry: [out] If the entry indexed by the key is found in the cache this value on successful return will be a copy of the corresponding entry.
-
bool
get_entry(key_type const &key, entry_type &entry)¶ Get a specific entry identified by the given key.
- Note
The function will “touch” the entry and mark it as recently used if the key was found in the cache.
- Return
This function returns true if the cache holds the referenced entry, otherwise it returns false.
- Parameters
key: [in] The key for the entry which should be retrieved from the cache.entry: [out] If the entry indexed by the key is found in the cache this value on successful return will be a copy of the corresponding entry.
-
bool
insert(key_type const &key, entry_type const &entry)¶ Insert a new entry into this cache.
- Note
This function assumes that the entry is not in the cache already. Inserting an already existing entry is considered undefined behavior
- Parameters
key: [in] The key for the entry which should be added to the cache.entry: [in] The entry which should be added to the cache.
-
void
insert_nonexist(key_type const &key, entry_type const &entry)¶
-
void
update(key_type const &key, entry_type const &entry)¶ Update an existing element in this cache.
- Note
The function will “touch” the entry and mark it as recently used if the key was found in the cache.
- Note
The difference to the other overload of the insert function is that this overload replaces the cached value only, while the other overload replaces the whole cache entry, updating the cache entry properties.
- Parameters
key: [in] The key for the value which should be updated in the cache.entry: [in] The entry which should be used as a replacement for the existing value in the cache. Any existing cache entry is not changed except for its value.
-
template<typename
F>
boolupdate_if(key_type const &key, entry_type const &entry, F &&f)¶ Update an existing element in this cache.
- Note
The function will “touch” the entry and mark it as recently used if the key was found in the cache.
- Note
The difference to the other overload of the insert function is that this overload replaces the cached value only, while the other overload replaces the whole cache entry, updating the cache entry properties.
- Return
This function returns true if the entry has been successfully updated, otherwise it returns false. If the entry currently is not held by the cache it is added and the return value reflects the outcome of the corresponding insert operation.
- Parameters
key: [in] The key for the value which should be updated in the cache.entry: [in] The value which should be used as a replacement for the existing value in the cache. Any existing cache entry is not changed except for its value.f: [in] A callable taking two arguments, k and the key found in the cache (in that order). If f returns true, then the update will continue. If f returns false, then the update will not succeed.
-
template<typename
Func>
size_typeerase(Func const &ep)¶ Remove stored entries from the cache for which the supplied function object returns true.
- Return
This function returns the overall size of the removed entries (which is the sum of the values returned by the entry::get_size functions of the removed entries).
- Parameters
ep: [in] This parameter has to be a (unary) function object. It is invoked for each of the entries currently held in the cache. An entry is considered for removal from the cache whenever the value returned from this invocation is true.
-
size_type
erase()¶ Remove all stored entries from the cache.
- Return
This function returns the overall size of the removed entries (which is the sum of the values returned by the entry::get_size functions of the removed entries).
-
statistics_type const &
get_statistics() const¶ Allow to access the embedded statistics instance.
- Return
This function returns a reference to the statistics instance embedded inside this cache
-
statistics_type &
get_statistics()¶
Private Types
-
typedef statistics_type::update_on_exit
update_on_exit¶
-
template<typename
-
namespace
-
namespace
-
namespace
hpx -
namespace
util -
namespace
cache -
namespace
entries¶ -
class
entry¶ - #include <hpx/cache/entries/entry.hpp>
- Template Parameters
Value: The data type to be stored in a cache. It has to be default constructible, copy constructible and less_than_comparable.Derived: The (optional) type for which this type is used as a base class.
Public Types
-
typedef Value
value_type¶
Public Functions
-
entry()¶ Any cache entry has to be default constructible.
-
entry(value_type const &val)¶ Construct a new instance of a cache entry holding the given value.
-
bool
touch()¶ The function touch is called by a cache holding this instance whenever it has been requested (touched).
- Note
It is possible to change the entry in a way influencing the sort criteria mandated by the UpdatePolicy. In this case the function should return true to indicate this to the cache, forcing to reorder the cache entries.
- Note
This function is part of the CacheEntry concept
- Return
This function should return true if the cache needs to update it’s internal heap. Usually this is needed if the entry has been changed by touch() in a way influencing the sort order as mandated by the cache’s UpdatePolicy
-
bool
insert()¶ The function insert is called by a cache whenever it is about to be inserted into the cache.
- Note
This function is part of the CacheEntry concept
- Return
This function should return true if the entry should be added to the cache, otherwise it should return false.
-
bool
remove()¶ The function remove is called by a cache holding this instance whenever it is about to be removed from the cache.
- Note
This function is part of the CacheEntry concept
- Return
The return value can be used to avoid removing this instance from the cache. If the value is true it is ok to remove the entry, other wise it will stay in the cache.
-
std::size_t
get_size() const¶ Return the ‘size’ of this entry. By default the size of each entry is just one (1), which is sensible if the cache has a limit (capacity) measured in number of entries.
-
value_type &
get()¶ Get a reference to the stored data value.
- Note
This function is part of the CacheEntry concept
-
value_type const &
get() const¶
Private Members
-
value_type
value_¶
Friends
-
bool
operator<(entry const &lhs, entry const &rhs)¶ Forwarding operator< allowing to compare entries instead of the values.
-
class
-
namespace
-
namespace
-
namespace
-
namespace
hpx -
namespace
util -
namespace
cache -
namespace
entries -
template<typename
Value>
classfifo_entry: public hpx::util::cache::entries::entry<Value, fifo_entry<Value>>¶ - #include <hpx/cache/entries/fifo_entry.hpp>
The fifo_entry type can be used to store arbitrary values in a cache. Using this type as the cache’s entry type makes sure that the least recently inserted entries are discarded from the cache first.
- Note
The fifo_entry conforms to the CacheEntry concept.
- Note
This type can be used to model a ‘last in first out’ cache policy if it is used with a std::greater as the caches’ UpdatePolicy (instead of the default std::less).
- Template Parameters
Value: The data type to be stored in a cache. It has to be default constructible, copy constructible and less_than_comparable.
Public Functions
-
fifo_entry()¶ Any cache entry has to be default constructible.
-
fifo_entry(Value const &val)¶ Construct a new instance of a cache entry holding the given value.
-
bool
insert()¶ The function insert is called by a cache whenever it is about to be inserted into the cache.
- Note
This function is part of the CacheEntry concept
- Return
This function should return true if the entry should be added to the cache, otherwise it should return false.
Friends
-
bool
operator<(fifo_entry const &lhs, fifo_entry const &rhs)¶ Compare the ‘age’ of two entries. An entry is ‘older’ than another entry if it has been created earlier (FIFO).
-
template<typename
-
namespace
-
namespace
-
namespace
-
namespace
hpx -
namespace
util -
namespace
cache -
namespace
entries -
template<typename
Value>
classlfu_entry: public hpx::util::cache::entries::entry<Value, lfu_entry<Value>>¶ - #include <hpx/cache/entries/lfu_entry.hpp>
The lfu_entry type can be used to store arbitrary values in a cache. Using this type as the cache’s entry type makes sure that the least frequently used entries are discarded from the cache first.
- Note
The lfu_entry conforms to the CacheEntry concept.
- Note
This type can be used to model a ‘most frequently used’ cache policy if it is used with a std::greater as the caches’ UpdatePolicy (instead of the default std::less).
- Template Parameters
Value: The data type to be stored in a cache. It has to be default constructible, copy constructible and less_than_comparable.
Public Functions
-
lfu_entry()¶ Any cache entry has to be default constructible.
-
lfu_entry(Value const &val)¶ Construct a new instance of a cache entry holding the given value.
-
bool
touch()¶ The function touch is called by a cache holding this instance whenever it has been requested (touched).
In the case of the LFU entry we store the reference count tracking the number of times this entry has been requested. This which will be used to compare the age of an entry during the invocation of the operator<().
- Return
This function should return true if the cache needs to update it’s internal heap. Usually this is needed if the entry has been changed by touch() in a way influencing the sort order as mandated by the cache’s UpdatePolicy
-
unsigned long const &
get_access_count() const¶
Private Members
-
unsigned long
ref_count_¶
Friends
-
bool
operator<(lfu_entry const &lhs, lfu_entry const &rhs)¶ Compare the ‘age’ of two entries. An entry is ‘older’ than another entry if it has been accessed less frequently (LFU).
-
template<typename
-
namespace
-
namespace
-
namespace
-
namespace
hpx -
namespace
util -
namespace
cache -
namespace
entries -
template<typename
Value>
classlru_entry: public hpx::util::cache::entries::entry<Value, lru_entry<Value>>¶ - #include <hpx/cache/entries/lru_entry.hpp>
The lru_entry type can be used to store arbitrary values in a cache. Using this type as the cache’s entry type makes sure that the least recently used entries are discarded from the cache first.
- Note
The lru_entry conforms to the CacheEntry concept.
- Note
This type can be used to model a ‘most recently used’ cache policy if it is used with a std::greater as the caches’ UpdatePolicy (instead of the default std::less).
- Template Parameters
Value: The data type to be stored in a cache. It has to be default constructible, copy constructible and less_than_comparable.
Public Functions
-
lru_entry()¶ Any cache entry has to be default constructible.
-
lru_entry(Value const &val)¶ Construct a new instance of a cache entry holding the given value.
-
bool
touch()¶ The function touch is called by a cache holding this instance whenever it has been requested (touched).
In the case of the LRU entry we store the time of the last access which will be used to compare the age of an entry during the invocation of the operator<().
- Return
This function should return true if the cache needs to update it’s internal heap. Usually this is needed if the entry has been changed by touch() in a way influencing the sort order as mandated by the cache’s UpdatePolicy
Friends
-
bool
operator<(lru_entry const &lhs, lru_entry const &rhs)¶ Compare the ‘age’ of two entries. An entry is ‘older’ than another entry if it has been accessed less recently (LRU).
-
template<typename
-
namespace
-
namespace
-
namespace
-
namespace
hpx -
namespace
util -
namespace
cache -
namespace
entries -
class
size_entry¶ - #include <hpx/cache/entries/size_entry.hpp>
The size_entry type can be used to store values in a cache which have a size associated (such as files, etc.). Using this type as the cache’s entry type makes sure that the entries with the biggest size are discarded from the cache first.
- Note
The size_entry conforms to the CacheEntry concept.
- Note
This type can be used to model a ‘discard smallest first’ cache policy if it is used with a std::greater as the caches’ UpdatePolicy (instead of the default std::less).
- Template Parameters
Value: The data type to be stored in a cache. It has to be default constructible, copy constructible and less_than_comparable.Derived: The (optional) type for which this type is used as a base class.
Public Functions
-
size_entry()¶ Any cache entry has to be default constructible.
Private Types
-
typedef detail::size_derived<Value, Derived>::type
derived_type¶
-
typedef entry<Value, derived_type>
base_type¶
Friends
-
bool
operator<(size_entry const &lhs, size_entry const &rhs)¶ Compare the ‘age’ of two entries. An entry is ‘older’ than another entry if it has a bigger size.
-
class
-
namespace
-
namespace
-
namespace
-
namespace
hpx
-
namespace
hpx -
namespace
util -
namespace
cache -
namespace
statistics¶ -
class
local_full_statistics: public hpx::util::cache::statistics::local_statistics¶ Public Functions
-
std::int64_t
get_get_entry_count(bool reset)¶ The function get_get_entry_count returns the number of invocations of the get_entry() API function of the cache.
-
std::int64_t
get_insert_entry_count(bool reset)¶ The function get_insert_entry_count returns the number of invocations of the insert_entry() API function of the cache.
-
std::int64_t
get_update_entry_count(bool reset)¶ The function get_update_entry_count returns the number of invocations of the update_entry() API function of the cache.
-
std::int64_t
get_erase_entry_count(bool reset)¶ The function get_erase_entry_count returns the number of invocations of the erase() API function of the cache.
-
std::int64_t
get_get_entry_time(bool reset)¶ The function get_get_entry_time returns the overall time spent executing of the get_entry() API function of the cache.
-
std::int64_t
get_insert_entry_time(bool reset)¶ The function get_insert_entry_time returns the overall time spent executing of the insert_entry() API function of the cache.
Private Members
-
api_counter_data
get_entry_¶
-
api_counter_data
insert_entry_¶
-
api_counter_data
update_entry_¶
-
api_counter_data
erase_entry_¶
Friends
-
friend
hpx::util::cache::statistics::update_on_exit
-
struct
update_on_exit¶ - #include <local_full_statistics.hpp>
Helper class to update timings and counts on function exit.
Private Static Functions
-
static api_counter_data &
get_api_counter_data(local_full_statistics &stat, method m)¶
-
static api_counter_data &
-
std::int64_t
-
class
-
namespace
-
namespace
-
namespace
-
namespace
hpx -
namespace
util -
namespace
cache -
namespace
statistics -
class
local_statistics: public hpx::util::cache::statistics::no_statistics¶ Subclassed by hpx::util::cache::statistics::local_full_statistics
Public Functions
-
local_statistics()¶
-
void
got_hit()¶ The function got_hit will be called by a cache instance whenever a entry got touched.
-
void
got_miss()¶ The function got_miss will be called by a cache instance whenever a requested entry has not been found in the cache.
-
void
got_insertion()¶ The function got_insertion will be called by a cache instance whenever a new entry has been inserted.
-
void
got_eviction()¶ The function got_eviction will be called by a cache instance whenever an entry has been removed from the cache because a new inserted entry let the cache grow beyond its capacity.
-
void
clear()¶ Reset all statistics.
-
-
class
-
namespace
-
namespace
-
namespace
-
namespace
hpx -
namespace
util -
namespace
cache -
namespace
statistics Enums
-
class
no_statistics¶ Subclassed by hpx::util::cache::statistics::local_statistics
Public Functions
-
void
got_hit()¶ The function got_hit will be called by a cache instance whenever a entry got touched.
-
void
got_miss()¶ The function got_miss will be called by a cache instance whenever a requested entry has not been found in the cache.
-
void
got_insertion()¶ The function got_insertion will be called by a cache instance whenever a new entry has been inserted.
-
void
got_eviction()¶ The function got_eviction will be called by a cache instance whenever an entry has been removed from the cache because a new inserted entry let the cache grow beyond its capacity.
-
void
clear()¶ Reset all statistics.
-
std::int64_t
get_get_entry_count(bool)¶ The function get_get_entry_count returns the number of invocations of the get_entry() API function of the cache.
-
std::int64_t
get_insert_entry_count(bool)¶ The function get_insert_entry_count returns the number of invocations of the insert_entry() API function of the cache.
-
std::int64_t
get_update_entry_count(bool)¶ The function get_update_entry_count returns the number of invocations of the update_entry() API function of the cache.
-
std::int64_t
get_erase_entry_count(bool)¶ The function get_erase_entry_count returns the number of invocations of the erase() API function of the cache.
-
std::int64_t
get_get_entry_time(bool)¶ The function get_get_entry_time returns the overall time spent executing of the get_entry() API function of the cache.
-
std::int64_t
get_insert_entry_time(bool)¶ The function get_insert_entry_time returns the overall time spent executing of the insert_entry() API function of the cache.
-
struct
update_on_exit¶ - #include <no_statistics.hpp>
Helper class to update timings and counts on function exit.
Public Functions
-
update_on_exit(no_statistics const&, method)¶
-
-
void
-
class
-
namespace
-
namespace
-
namespace
concepts¶
The contents of this module can be included with the header
hpx/modules/concepts.hpp. These headers may be used by user-code but are not
guaranteed stable (neither header location nor contents). You are using these at
your own risk. If you wish to use non-public functionality from a module we
strongly suggest only including the module header hpx/modules/concepts.hpp, not
the particular header in which the functionality you would like to use is
defined. See Public API for a list of names that are part of the public
HPX API.
Defines
-
HPX_HAS_MEMBER_XXX_TRAIT_DEF(MEMBER)¶ This macro creates a boolean unary meta-function which result is true if and only if its parameter type has member function with MEMBER name (no matter static it is or not). The generated trait ends up in a namespace where the macro itself has been placed.
Defines
-
HPX_HAS_XXX_TRAIT_DEF(Name)¶ This macro creates a boolean unary meta-function such that for any type X, has_name<X>::value == true if and only if X is a class type and has a nested type member x::name. The generated trait ends up in a namespace where the macro itself has been placed.
concurrency¶
The contents of this module can be included with the header
hpx/modules/concurrency.hpp. These headers may be used by user-code but are not
guaranteed stable (neither header location nor contents). You are using these at
your own risk. If you wish to use non-public functionality from a module we
strongly suggest only including the module header hpx/modules/concurrency.hpp, not
the particular header in which the functionality you would like to use is
defined. See Public API for a list of names that are part of the public
HPX API.
-
namespace
hpx
-
template<typename
Data>
structcache_aligned_data<Data, std::false_type>¶ Public Functions
-
cache_aligned_data()¶
-
cache_aligned_data(Data &&data)¶
-
cache_aligned_data(Data const &data)¶
Public Members
-
Data
data_¶
-
-
namespace
hpx -
namespace
threads
-
namespace
util -
-
template<typename
Data, typenameNeedsPadding= typename detail::needs_padding<Data>::type>
structcache_aligned_data¶ Public Functions
-
cache_aligned_data()
-
cache_aligned_data(Data &&data)
-
cache_aligned_data(Data const &data)
-
-
template<typename
Data>
structcache_aligned_data<Data, std::false_type> Public Functions
-
cache_aligned_data()
-
cache_aligned_data(Data &&data)
-
cache_aligned_data(Data const &data)
Public Members
-
Data
data_
-
-
template<typename
Data, typenameNeedsPadding= typename detail::needs_padding<Data>::type>
structcache_aligned_data_derived: public Data¶ Public Functions
-
cache_aligned_data_derived()
-
cache_aligned_data_derived(Data &&data)
-
cache_aligned_data_derived(Data const &data)
Public Members
-
template<>
charcacheline_pad[get_cache_line_padding_size(sizeof(Data))]¶
-
-
template<typename
-
namespace
Defines
-
MOODYCAMEL_THREADLOCAL¶
-
MOODYCAMEL_EXCEPTIONS_ENABLED¶
-
MOODYCAMEL_TRY¶
-
MOODYCAMEL_CATCH(...)¶
-
MOODYCAMEL_RETHROW¶
-
MOODYCAMEL_THROW(expr)¶
-
MOODYCAMEL_NOEXCEPT¶
-
MOODYCAMEL_NOEXCEPT_CTOR(type, valueType, expr)¶
-
MOODYCAMEL_NOEXCEPT_ASSIGN(type, valueType, expr)¶
-
MOODYCAMEL_DELETE_FUNCTION¶
-
namespace
hpx -
namespace
concurrency¶ Functions
-
template<typename
T, typenameTraits>
voidswap(typename ConcurrentQueue<T, Traits>::ImplicitProducerKVP &a, typename ConcurrentQueue<T, Traits>::ImplicitProducerKVP &b)¶
-
template<typename
T, typenameTraits>
voidswap(ConcurrentQueue<T, Traits> &a, ConcurrentQueue<T, Traits> &b)¶
-
void
swap(ProducerToken &a, ProducerToken &b)¶
-
void
swap(ConsumerToken &a, ConsumerToken &b)¶
-
template<typename
T, typenameTraits= ConcurrentQueueDefaultTraits>
classConcurrentQueue¶ Public Types
-
typedef ::hpx::concurrency::ProducerToken
producer_token_t¶
-
typedef ::hpx::concurrency::ConsumerToken
consumer_token_t¶
-
typedef Traits::index_t
index_t¶
-
typedef Traits::size_t
size_t¶
Public Functions
-
ConcurrentQueue(size_t capacity = 6 * BLOCK_SIZE)¶
-
~ConcurrentQueue()¶
-
ConcurrentQueue(ConcurrentQueue const&)¶
-
ConcurrentQueue &
operator=(ConcurrentQueue const&)¶
-
ConcurrentQueue(ConcurrentQueue &&other)¶
-
ConcurrentQueue &
operator=(ConcurrentQueue &&other)¶
-
void
swap(ConcurrentQueue &other)¶
-
bool
enqueue(T const &item)¶
-
bool
enqueue(T &&item)¶
-
bool
enqueue(producer_token_t const &token, T const &item)¶
-
bool
enqueue(producer_token_t const &token, T &&item)¶
-
template<typename
It>
boolenqueue_bulk(producer_token_t const &token, It itemFirst, size_t count)¶
-
bool
try_enqueue(T const &item)¶
-
bool
try_enqueue(T &&item)¶
-
bool
try_enqueue(producer_token_t const &token, T const &item)¶
-
bool
try_enqueue(producer_token_t const &token, T &&item)¶
-
template<typename
It>
booltry_enqueue_bulk(producer_token_t const &token, It itemFirst, size_t count)¶
-
template<typename
U>
booltry_dequeue(consumer_token_t &token, U &item)¶
-
template<typename
It>
size_ttry_dequeue_bulk(consumer_token_t &token, It itemFirst, size_t max)¶
-
template<typename
U>
booltry_dequeue_from_producer(producer_token_t const &producer, U &item)¶
-
template<typename
It>
size_ttry_dequeue_bulk_from_producer(producer_token_t const &producer, It itemFirst, size_t max)¶
Public Static Functions
-
static bool
is_lock_free()¶
Public Static Attributes
-
const size_t
EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD= static_cast<size_t>(Traits::EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD)¶
-
const size_t
EXPLICIT_INITIAL_INDEX_SIZE= static_cast<size_t>(Traits::EXPLICIT_INITIAL_INDEX_SIZE)¶
-
const size_t
IMPLICIT_INITIAL_INDEX_SIZE= static_cast<size_t>(Traits::IMPLICIT_INITIAL_INDEX_SIZE)¶
-
const size_t
INITIAL_IMPLICIT_PRODUCER_HASH_SIZE= static_cast<size_t>(Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE)¶
-
const std::uint32_t
EXPLICIT_CONSUMER_CONSUMPTION_QUOTA_BEFORE_ROTATE= static_cast<std::uint32_t>(Traits::EXPLICIT_CONSUMER_CONSUMPTION_QUOTA_BEFORE_ROTATE)¶
-
const size_t hpx::concurrency::ConcurrentQueue::MAX_SUBQUEUE_SIZE = (details::const_numeric_max<size_t>::value - static_cast<size_t>(Traits::MAX_SUBQUEUE_SIZE) < BLOCK_SIZE) ? details::const_numeric_max<size_t>::value : ((static_cast<size_t>(Traits::MAX_SUBQUEUE_SIZE) + (BLOCK_SIZE - 1)) / BLOCK_SIZE * BLOCK_SIZE)
Private Types
Private Functions
-
ConcurrentQueue &
swap_internal(ConcurrentQueue &other)¶
-
template<AllocationMode
canAlloc, typenameU>
boolinner_enqueue(producer_token_t const &token, U &&element)¶
-
template<AllocationMode
canAlloc, typenameU>
boolinner_enqueue(U &&element)¶
-
template<AllocationMode
canAlloc, typenameIt>
boolinner_enqueue_bulk(producer_token_t const &token, It itemFirst, size_t count)¶
-
template<AllocationMode
canAlloc, typenameIt>
boolinner_enqueue_bulk(It itemFirst, size_t count)¶
-
bool
update_current_producer_after_rotation(consumer_token_t &token)¶
-
template<AllocationMode
canAlloc>
Block *requisition_block()¶
-
ProducerBase *
recycle_or_create_producer(bool isExplicit)¶
-
ProducerBase *
recycle_or_create_producer(bool isExplicit, bool &recycled)¶
-
ProducerBase *
add_producer(ProducerBase *producer)¶
-
void
reown_producers()¶
-
void
populate_initial_implicit_producer_hash()¶
-
void
swap_implicit_producer_hashes(ConcurrentQueue &other)¶
-
ImplicitProducer *
get_or_add_implicit_producer()¶
Private Members
-
std::atomic<ProducerBase*>
producerListTail¶
-
std::atomic<ImplicitProducerHash*>
implicitProducerHash¶
-
ImplicitProducerHash
initialImplicitProducerHash¶
-
std::array<ImplicitProducerKVP, INITIAL_IMPLICIT_PRODUCER_HASH_SIZE>
initialImplicitProducerHashEntries¶
Private Static Functions
Friends
-
friend
hpx::concurrency::ProducerToken
-
friend
hpx::concurrency::ConsumerToken
-
friend
hpx::concurrency::ExplicitProducer
-
friend
hpx::concurrency::ImplicitProducer
-
friend
hpx::concurrency::ConcurrentQueueTests
-
struct
Block¶ Public Functions
-
template<>
Block()¶
-
template<InnerQueueContext
context>
boolis_empty() const¶
-
template<InnerQueueContext
context>
boolset_empty(index_t i)¶
-
template<InnerQueueContext
context>
boolset_many_empty(index_t i, size_t count)¶
-
template<InnerQueueContext
context>
voidset_all_empty()¶
-
template<InnerQueueContext
context>
voidreset_empty()¶
-
template<>
T *operator[](index_t idx)¶
-
template<>
T const *operator[](index_t idx) const¶
Public Members
-
template<>
charelements[sizeof(T) *BLOCK_SIZE]¶
-
template<>
details::max_align_tdummy¶
-
template<>
Block *next¶
-
std::atomic<bool> hpx::concurrency::ConcurrentQueue< T, Traits >::Block::emptyFlags[BLOCK_SIZE<=EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD ? BLOCK_SIZE :1]
-
template<>
booldynamicallyAllocated¶
Private Members
-
template<>
union hpx::concurrency::ConcurrentQueue::Block::[anonymous] [anonymous]¶
-
template<>
-
struct
ExplicitProducer: public hpx::concurrency::ConcurrentQueue<T, Traits>::ProducerBase¶ Public Functions
-
template<>
ExplicitProducer(ConcurrentQueue *parent)¶
-
template<>
~ExplicitProducer()¶
-
template<AllocationMode
allocMode, typenameU>
boolenqueue(U &&element)¶
-
template<typename
U>
booldequeue(U &element)¶
-
template<AllocationMode
allocMode, typenameIt>
boolenqueue_bulk(It itemFirst, size_t count)¶
-
template<typename
It>
size_tdequeue_bulk(It &itemFirst, size_t max)¶
Private Functions
-
template<>
boolnew_block_index(size_t numberOfFilledSlotsToExpose)¶
Private Members
-
template<>
size_tpr_blockIndexSlotsUsed¶
-
template<>
size_tpr_blockIndexSize¶
-
template<>
size_tpr_blockIndexFront¶
-
template<>
BlockIndexEntry *pr_blockIndexEntries¶
-
template<>
void *pr_blockIndexRaw¶
-
struct
BlockIndexEntry¶
-
struct
BlockIndexHeader¶
-
template<>
-
template<typename
N>
structFreeList¶ Public Functions
-
template<>
FreeList()¶
-
template<>
voidswap(FreeList &other)¶
-
template<>
FreeList &operator=(FreeList const&)¶
-
template<>
voidadd(N *node)¶
-
template<>
N *try_get()¶
-
template<>
N *head_unsafe() const¶
Private Functions
-
template<>
voidadd_knowing_refcount_is_zero(N *node)¶
-
template<>
-
struct
ImplicitProducer: public hpx::concurrency::ConcurrentQueue<T, Traits>::ProducerBase¶ Public Functions
-
template<>
ImplicitProducer(ConcurrentQueue *parent)¶
-
template<>
~ImplicitProducer()¶
-
template<AllocationMode
allocMode, typenameU>
boolenqueue(U &&element)¶
-
template<typename
U>
booldequeue(U &element)¶
-
template<AllocationMode
allocMode, typenameIt>
boolenqueue_bulk(It itemFirst, size_t count)¶
-
template<typename
It>
size_tdequeue_bulk(It &itemFirst, size_t max)¶
Private Functions
-
template<AllocationMode
allocMode>
boolinsert_block_index_entry(BlockIndexEntry *&idxEntry, index_t blockStartIndex)¶
-
template<>
voidrewind_block_index_tail()¶
-
template<>
BlockIndexEntry *get_block_index_entry_for_index(index_t index) const¶
-
template<>
size_tget_block_index_index_for_index(index_t index, BlockIndexHeader *&localBlockIndex) const¶
-
template<>
boolnew_block_index()¶
Private Members
-
template<>
size_tnextBlockIndexCapacity¶
Private Static Attributes
-
template<>
const index_tINVALID_BLOCK_BASE= 1¶
-
struct
BlockIndexEntry¶
-
struct
BlockIndexHeader¶
-
template<>
-
struct
ImplicitProducerHash¶
-
struct
ImplicitProducerKVP¶ Public Functions
-
template<>
ImplicitProducerKVP()¶
-
template<>
ImplicitProducerKVP(ImplicitProducerKVP &&other)¶
-
template<>
ImplicitProducerKVP &operator=(ImplicitProducerKVP &&other)¶
-
template<>
voidswap(ImplicitProducerKVP &other)¶
-
template<>
-
struct
ProducerBase: public hpx::concurrency::details::ConcurrentQueueProducerTypelessBase¶ Public Functions
-
template<>
ProducerBase(ConcurrentQueue *parent_, bool isExplicit_)¶
-
template<>
virtual~ProducerBase()¶
-
template<typename
U>
booldequeue(U &element)¶
-
template<typename
It>
size_tdequeue_bulk(It &itemFirst, size_t max)¶
-
template<>
ProducerBase *next_prod() const¶
-
template<>
size_tsize_approx() const¶
-
template<>
index_tgetTail() const¶
-
template<>
-
typedef ::hpx::concurrency::ProducerToken
-
struct
ConcurrentQueueDefaultTraits¶ -
Public Static Attributes
-
const size_t
MAX_SUBQUEUE_SIZE= details::const_numeric_max<size_t>::value¶
-
const size_t
-
struct
ConsumerToken¶ Public Functions
-
ConsumerToken(ConsumerToken &&other)¶
-
ConsumerToken &
operator=(ConsumerToken &&other)¶
-
void
swap(ConsumerToken &other)¶
-
ConsumerToken(ConsumerToken const&)¶
-
ConsumerToken &
operator=(ConsumerToken const&)¶
Private Members
-
details::ConcurrentQueueProducerTypelessBase *
currentProducer¶
-
details::ConcurrentQueueProducerTypelessBase *
desiredProducer¶
Friends
-
friend
hpx::concurrency::ConcurrentQueue
-
friend
hpx::concurrency::ConcurrentQueueTests
-
-
struct
ProducerToken¶ Public Functions
-
ProducerToken(ProducerToken &&other)¶
-
ProducerToken &
operator=(ProducerToken &&other)¶
-
void
swap(ProducerToken &other)¶
-
bool
valid() const¶
-
~ProducerToken()¶
-
ProducerToken(ProducerToken const&)¶
-
ProducerToken &
operator=(ProducerToken const&)¶
Protected Attributes
-
details::ConcurrentQueueProducerTypelessBase *
producer¶
Friends
-
friend
hpx::concurrency::ConcurrentQueue
-
friend
hpx::concurrency::ConcurrentQueueTests
-
-
namespace
details¶ -
Functions
-
static thread_id_t
thread_id()¶
-
static bool() hpx::concurrency::details::likely(bool x)
-
static bool() hpx::concurrency::details::unlikely(bool x)
-
static size_t
hash_thread_id(thread_id_t id)¶
-
template<typename
U>
static char *align_for(char *ptr)¶
-
template<bool
use32>
struct_hash_32_or_64¶
-
template<>
struct_hash_32_or_64<1>¶
-
struct
ConcurrentQueueProducerTypelessBase¶ Public Functions
-
ConcurrentQueueProducerTypelessBase()¶
Public Members
-
ProducerToken *
token¶
-
-
template<typename
T>
structconst_numeric_max¶ Public Static Attributes
-
const T hpx::concurrency::details::const_numeric_max::value= std::numeric_limits<T>::is_signed ? (static_cast<T>(1) << (sizeof(T) * CHAR_BIT - 1)) - static_cast<T>(1) : static_cast<T>(-1)
-
-
union
max_align_t¶
-
template<bool
Enable>
structnomove_if¶
-
template<>
structnomove_if<false>¶
-
template<>
structstatic_is_lock_free<bool>¶
-
template<typename
U>
structstatic_is_lock_free<U*>¶ Public Types
-
enum [anonymous]¶
Values:
-
value= ATOMIC_POINTER_LOCK_FREE
-
-
enum [anonymous]¶
-
template<typename
T>
structstatic_is_lock_free_num¶ Public Types
-
enum [anonymous]¶
Values:
-
value= 0
-
-
enum [anonymous]¶
-
template<>
structstatic_is_lock_free_num<int>¶ Public Types
-
enum [anonymous]¶
Values:
-
value= ATOMIC_INT_LOCK_FREE
-
-
enum [anonymous]¶
-
template<>
structstatic_is_lock_free_num<long>¶ Public Types
-
enum [anonymous]¶
Values:
-
value= ATOMIC_LONG_LOCK_FREE
-
-
enum [anonymous]¶
-
template<>
structstatic_is_lock_free_num<long long>¶ Public Types
-
enum [anonymous]¶
Values:
-
value= ATOMIC_LLONG_LOCK_FREE
-
-
enum [anonymous]¶
-
template<>
structstatic_is_lock_free_num<short>¶ Public Types
-
enum [anonymous]¶
Values:
-
value= ATOMIC_SHORT_LOCK_FREE
-
-
enum [anonymous]¶
-
template<>
structstatic_is_lock_free_num<signed char>¶ Public Types
-
enum [anonymous]¶
Values:
-
value= ATOMIC_CHAR_LOCK_FREE
-
-
enum [anonymous]¶
-
template<typename
thread_id_t>
structthread_id_converter¶ -
Public Static Functions
-
static thread_id_hash_t
prehash(thread_id_t const &x)¶
-
static thread_id_hash_t
-
static thread_id_t
-
template<typename
-
namespace
-
namespace
boost¶ -
namespace
lockfree¶ -
-
template<typename
T, typenamefreelist_t= caching_freelist_t, typenameAlloc= std::allocator<T>>
structdeque¶ Public Types
-
template<>
usingnode= deque_node<T>¶
-
template<>
usinganchor= deque_anchor<T>¶
-
template<>
usingnode_allocator= typename std::allocator_traits<Alloc>::template rebind_alloc<node>¶
-
template<>
usingpool= typename std::conditional<std::is_same<freelist_t, caching_freelist_t>::value, caching_freelist<node, node_allocator>, static_freelist<node, node_allocator>>::type¶
Public Functions
-
HPX_NON_COPYABLE(deque)¶
-
~deque()¶
-
bool
empty() const¶
-
bool
is_lock_free() const¶
-
bool
push_left(T const &data)¶
-
bool
push_right(T const &data)¶
-
bool
pop_left(T &r)¶
-
bool
pop_left(T *r)¶
-
bool
pop_right(T &r)¶
-
bool
pop_right(T *r)¶
-
template<>
-
template<typename
T>
structdeque_anchor¶ -
Public Functions
-
deque_anchor()¶
-
deque_anchor(deque_anchor const &p)¶
-
deque_anchor(pair const &p)¶
-
pair
lrs() volatile const¶
-
node *
left() volatile const¶
-
node *
right() volatile const¶
-
tag_t
status() volatile const¶
-
tag_t
tag() volatile const¶
-
bool
cas(deque_anchor &expected, deque_anchor const &desired) volatile¶
-
bool
cas(pair &expected, deque_anchor const &desired) volatile¶
-
bool
cas(deque_anchor &expected, pair const &desired) volatile¶
-
bool
cas(pair &expected, pair const &desired) volatile¶
-
bool
operator==(volatile deque_anchor const &rhs) const¶
-
bool
operator!=(volatile deque_anchor const &rhs) const¶
-
bool
operator==(volatile pair const &rhs) const¶
-
bool
operator!=(volatile pair const &rhs) const¶
-
bool
is_lock_free() const¶
Private Members
-
atomic_pair
pair_¶
-
-
template<typename
T>
structdeque_node¶ Public Types
-
typedef detail::tagged_ptr<deque_node>
pointer¶
Public Functions
-
deque_node()¶
-
deque_node(deque_node const &p)¶
-
deque_node(deque_node *lptr, deque_node *rptr, T const &v, tag_t ltag = 0, tag_t rtag = 0)¶
-
typedef detail::tagged_ptr<deque_node>
-
template<typename
-
namespace
-
namespace
hpx
config¶
The contents of this module can be included with the header
hpx/modules/config.hpp. These headers may be used by user-code but are not
guaranteed stable (neither header location nor contents). You are using these at
your own risk. If you wish to use non-public functionality from a module we
strongly suggest only including the module header hpx/modules/config.hpp, not
the particular header in which the functionality you would like to use is
defined. See Public API for a list of names that are part of the public
HPX API.
Defines
-
HPX_INITIAL_IP_PORT¶ This is the default ip/port number used by the parcel subsystem.
-
HPX_CONNECTING_IP_PORT¶
-
HPX_INITIAL_IP_ADDRESS¶
-
HPX_RUNTIME_INSTANCE_LIMIT¶ This defines the maximum number of possible runtime instances in one executable
-
HPX_PARCEL_BOOTSTRAP¶ This defines the type of the parcelport to be used during application bootstrap. This value can be changed at runtime by the configuration parameter:
hpx.parcel.bootstrap = …
(or by setting the corresponding environment variable HPX_PARCEL_BOOTSTRAP).
-
HPX_PARCEL_MAX_CONNECTIONS¶ This defines the number of outgoing (parcel-) connections kept alive (to all other localities). This value can be changed at runtime by setting the configuration parameter:
hpx.parcel.max_connections = …
(or by setting the corresponding environment variable HPX_PARCEL_MAX_CONNECTIONS).
-
HPX_PARCEL_IPC_DATA_BUFFER_CACHE_SIZE¶ This defines the number of outgoing ipc (parcel-) connections kept alive (to each of the other localities on the same node). This value can be changed at runtime by setting the configuration parameter:
hpx.parcel.ipc.data_buffer_cache_size = …
(or by setting the corresponding environment variable HPX_PARCEL_IPC_DATA_BUFFER_CACHE_SIZE).
-
HPX_PARCEL_MPI_MAX_REQUESTS¶ This defines the number of MPI requests in flight This value can be changed at runtime by setting the configuration parameter:
hpx.parcel.mpi.max_requests = …
(or by setting the corresponding environment variable HPX_PARCEL_MPI_MAX_REQUESTS).
-
HPX_PARCEL_MAX_CONNECTIONS_PER_LOCALITY¶ This defines the number of outgoing (parcel-) connections kept alive (to each of the other localities). This value can be changed at runtime by setting the configuration parameter:
hpx.parcel.max_connections_per_locality = …
(or by setting the corresponding environment variable HPX_PARCEL_MAX_CONNECTIONS_PER_LOCALITY).
-
HPX_PARCEL_MAX_MESSAGE_SIZE¶ This defines the maximally allowed message size for messages transferred between localities. This value can be changed at runtime by setting the configuration parameter:
hpx.parcel.max_message_size = …
(or by setting the corresponding environment variable HPX_PARCEL_MAX_MESSAGE_SIZE).
-
HPX_PARCEL_MAX_OUTBOUND_MESSAGE_SIZE¶ This defines the maximally allowed outbound message size for coalescing messages transferred between localities. This value can be changed at runtime by setting the configuration parameter:
hpx.parcel.max_outbound_message_size = …
(or by setting the corresponding environment variable HPX_PARCEL_MAX_OUTBOUND_MESSAGE_SIZE).
-
HPX_PARCEL_SERIALIZATION_OVERHEAD¶
-
HPX_AGAS_LOCAL_CACHE_SIZE¶ This defines the number of AGAS address translations kept in the local cache. This is just the initial size which may be adjusted depending on the load of the system (not implemented yet), etc. It must be a minimum of 3 for AGAS v3 bootstrapping.
This value can be changes at runtime by setting the configuration parameter:
hpx.agas.local_cache_size = …
(or by setting the corresponding environment variable HPX_AGAS_LOCAL_CACHE_SIZE)
-
HPX_INITIAL_AGAS_MAX_PENDING_REFCNT_REQUESTS¶
-
HPX_GLOBALCREDIT_INITIAL¶ This defines the initial global reference count associated with any created object.
-
HPX_NUM_IO_POOL_SIZE¶ This defines the default number of OS-threads created for the different internal thread pools
-
HPX_NUM_PARCEL_POOL_SIZE¶
-
HPX_NUM_TIMER_POOL_SIZE¶
-
HPX_SPINLOCK_DEADLOCK_DETECTION_LIMIT¶ By default, enable minimal thread deadlock detection in debug builds only.
-
HPX_COROUTINE_NUM_HEAPS¶ This defines the default number of coroutine heaps.
-
HPX_HAVE_THREAD_BACKTRACE_DEPTH¶ By default, enable storing the thread phase in debug builds only.
By default, enable storing the parent thread information in debug builds only. By default, enable storing the thread description in debug builds only. By default, enable storing the target address of the data the thread is accessing in debug builds only. By default we do not maintain stack back-traces on suspension. This is a pure debugging aid to be able to see in the debugger where a suspended thread got stuck. By default we capture only 20 levels of stack back trace on suspension
-
HPX_MAX_NETWORK_RETRIES¶
-
HPX_NETWORK_RETRIES_SLEEP¶
-
HPX_INI_PATH_DELIMITER¶
-
HPX_PATH_DELIMITERS¶
-
HPX_SHARED_LIB_EXTENSION¶
-
HPX_EXECUTABLE_EXTENSION¶
-
HPX_MAKE_DLL_STRING(n)¶
-
HPX_MANGLE_NAME(n)¶
-
HPX_MANGLE_STRING(n)¶
-
HPX_COMPONENT_NAME_DEFAULT¶
-
HPX_COMPONENT_NAME¶
-
HPX_COMPONENT_STRING¶
-
HPX_PLUGIN_COMPONENT_PREFIX¶
-
HPX_PLUGIN_NAME_DEFAULT¶
-
HPX_PLUGIN_NAME¶
-
HPX_PLUGIN_STRING¶
-
HPX_PLUGIN_PLUGIN_PREFIX¶
-
HPX_APPLICATION_STRING¶
-
HPX_IDLE_LOOP_COUNT_MAX¶
-
HPX_BUSY_LOOP_COUNT_MAX¶
-
HPX_THREAD_QUEUE_MAX_THREAD_COUNT¶
-
HPX_THREAD_QUEUE_MIN_TASKS_TO_STEAL_PENDING¶
-
HPX_THREAD_QUEUE_MIN_TASKS_TO_STEAL_STAGED¶
-
HPX_THREAD_QUEUE_MIN_ADD_NEW_COUNT¶
-
HPX_THREAD_QUEUE_MAX_ADD_NEW_COUNT¶
-
HPX_THREAD_QUEUE_MIN_DELETE_COUNT¶
-
HPX_THREAD_QUEUE_MAX_DELETE_COUNT¶
-
HPX_THREAD_QUEUE_MAX_TERMINATED_THREADS¶
-
HPX_IDLE_BACKOFF_TIME_MAX¶
-
HPX_WRAPPER_HEAP_STEP¶
-
HPX_INITIAL_GID_RANGE¶
-
HPX_CONTINUATION_MAX_RECURSION_DEPTH¶
Defines
-
HPX_NOINLINE¶ Function attribute to tell compiler not to inline the function.
-
HPX_NORETURN¶ Function attribute to tell compiler that the function does not return.
-
HPX_DEPRECATED(x)¶ Marks an entity as deprecated. The argument
xspecifies a custom message that is included in the compiler warning. For more details see<>__.
-
HPX_FALLTHROUGH¶ Indicates that the fall through from the previous case label is intentional and should not be diagnosed by a compiler that warns on fallthrough. For more details see
<>__.
-
HPX_NODISCARD¶ If a function declared nodiscard or a function returning an enumeration or class declared nodiscard by value is called from a discarded-value expression other than a cast to void, the compiler is encouraged to issue a warning. For more details see
__.
-
HPX_NO_UNIQUE_ADDRESS¶ Indicates that this data member need not have an address distinct from all other non-static data members of its class. For more details see
__.
Defines
-
HPX_LIKELY(expr)¶ Hint at the compiler that
expris likely to be true.
-
HPX_UNLIKELY(expr)¶ Hint at the compiler that
expris likely to be false.
Defines
-
HPX_COMPILER_FENCE¶ Generates assembly that serves as a fence to the compiler CPU to disable optimization. Usually implemented in the form of a memory barrier.
-
HPX_SMT_PAUSE¶ Generates assembly the executes a “pause” instruction. Useful in spinning loops.
Defines
-
HPX_NATIVE_TLS¶ This macro is replaced with the compiler specific keyword attribute to mark a variable as thread local. For more details see
<__.This macro is deprecated. It is always replaced with the
thread_localkeyword. Prefer usingthread_localdirectly instead.
Defines
-
HPX_GCC_VERSION¶ Returns the GCC version HPX is compiled with. Only set if compiled with GCC.
-
HPX_CLANG_VERSION¶ Returns the Clang version HPX is compiled with. Only set if compiled with Clang.
-
HPX_INTEL_VERSION¶ Returns the Intel Compiler version HPX is compiled with. Only set if compiled with the Intel Compiler.
-
HPX_MSVC¶ This macro is set if the compilation is with MSVC.
-
HPX_MINGW¶ This macro is set if the compilation is with Mingw.
-
HPX_WINDOWS¶ This macro is set if the compilation is for Windows.
-
HPX_NATIVE_MIC¶ This macro is set if the compilation is for Intel Knights Landing.
Defines
-
HPX_CONSTEXPR¶ This macro evaluates to
constexprif the compiler supports it.This macro is deprecated. It is always replaced with the
constexprkeyword. Prefer usingconstexprdirectly instead.
-
HPX_CONSTEXPR_OR_CONST¶ This macro evaluates to
constexprif the compiler supports it,constotherwise.This macro is deprecated. It is always replaced with the
constexprkeyword. Prefer usingconstexprdirectly instead.
-
HPX_INLINE_CONSTEXPR_VARIABLE¶ This macro evaluates to
inline constexprif the compiler supports it,constexprotherwise.
-
HPX_STATIC_CONSTEXPR¶ This macro evaluates to
static constexprif the compiler supports it,static constotherwise.This macro is deprecated. It is always replaced with the
static constexprkeyword. Prefer usingstatic constexprdirectly instead.
Defines
-
HPX_DEBUG¶ Defined if HPX is compiled in debug mode.
-
HPX_BUILD_TYPE¶ Evaluates to
debugif compiled in debug mode,releaseotherwise.
Defines
-
HPX_HAVE_DEPRECATION_WARNINGS_V1_4¶
-
HPX_DEPRECATED_V1_4(x)¶
-
HPX_HAVE_DEPRECATION_WARNINGS_V1_5¶
-
HPX_DEPRECATED_V1_5(x)¶
-
HPX_HAVE_DEPRECATION_WARNINGS_V1_6¶
-
HPX_DEPRECATED_V1_6(x)¶
-
HPX_HAVE_DEPRECATION_WARNINGS_V1_7¶
-
HPX_DEPRECATED_V1_7(x)¶
-
HPX_HAVE_DEPRECATION_WARNINGS_V1_8¶
-
HPX_DEPRECATED_V1_8(x)¶
-
HPX_DEPRECATED_V(major, minor, x)¶
Defines
-
HPX_NON_COPYABLE(cls)¶ Marks a class as non-copyable and non-movable.
Defines
-
HPX_EXPORT¶ Marks a class or function to be exported from HPX or imported if it is consumed.
Defines
-
HPX_FORCEINLINE¶ Marks a function to be forced inline.
Defines
-
HPX_CAPTURE_FORWARD(var)¶ Evaluates to
var = std::forward<decltype(var)>(var)if the compiler supports C++14 Lambdas. Defaults tovar.This macro is deprecated. Prefer using
var = std::forward<decltype((var))>(var)directly instead.
-
HPX_CAPTURE_MOVE(var)¶ Evaluates to
var = std::move(var)if the compiler supports C++14 Lambdas. Defaults tovar.This macro is deprecated. Prefer using
var = std::move(var)directly instead.
Defines
-
HPX_CXX20_CAPTURE_THIS(...)¶
Defines
-
HPX_THREADS_STACK_OVERHEAD¶
-
HPX_SMALL_STACK_SIZE¶
-
HPX_MEDIUM_STACK_SIZE¶
-
HPX_LARGE_STACK_SIZE¶
-
HPX_HUGE_STACK_SIZE¶
Defines
-
HPX_WEAK_SYMBOL¶
config_registry¶
The contents of this module can be included with the header
hpx/modules/config_registry.hpp. These headers may be used by user-code but are not
guaranteed stable (neither header location nor contents). You are using these at
your own risk. If you wish to use non-public functionality from a module we
strongly suggest only including the module header hpx/modules/config_registry.hpp, not
the particular header in which the functionality you would like to use is
defined. See Public API for a list of names that are part of the public
HPX API.
Defines
-
HPX_CONFIG_REGISTRY_EXPORT¶
-
namespace
hpx -
namespace
config_registry¶ Functions
-
HPX_CONFIG_REGISTRY_EXPORT std::vector<module_config> const& hpx::config_registry::get_module_configs()
-
HPX_CONFIG_REGISTRY_EXPORT void hpx::config_registry::add_module_config(module_config const & config)
-
struct
add_module_config_helper¶ Public Functions
-
add_module_config_helper(module_config const &config)¶
-
-
struct
module_config¶
-
-
namespace
coroutines¶
The contents of this module can be included with the header
hpx/modules/coroutines.hpp. These headers may be used by user-code but are not
guaranteed stable (neither header location nor contents). You are using these at
your own risk. If you wish to use non-public functionality from a module we
strongly suggest only including the module header hpx/modules/coroutines.hpp, not
the particular header in which the functionality you would like to use is
defined. See Public API for a list of names that are part of the public
HPX API.
-
namespace
hpx -
namespace
threads -
namespace
coroutines¶ -
class
coroutine¶ Public Types
-
using
impl_type= detail::coroutine_impl¶
-
using
functor_type= util::unique_function_nonser<result_type(arg_type)>¶
Public Functions
-
coroutine(functor_type &&f, thread_id_type id, std::ptrdiff_t stack_size = detail::default_stack_size)¶
-
thread_id_type
get_thread_id() const¶
-
void
rebind(functor_type &&f, thread_id_type id)¶
-
result_type
operator()(arg_type arg = arg_type())¶
-
bool
is_ready() const¶
-
using
-
class
-
namespace
-
namespace
-
namespace
hpx -
namespace
threads -
namespace
coroutines -
class
stackless_coroutine¶ Public Types
-
using
result_type= std::pair<thread_schedule_state, thread_id_type>¶
-
using
arg_type= thread_restart_state¶
-
using
functor_type= util::unique_function_nonser<result_type(arg_type)>¶
Public Functions
-
stackless_coroutine(functor_type &&f, thread_id_type id, std::ptrdiff_t = default_stack_size)¶
-
~stackless_coroutine()¶
-
stackless_coroutine(stackless_coroutine const &src)¶
-
stackless_coroutine &
operator=(stackless_coroutine const &src)¶
-
stackless_coroutine(stackless_coroutine &&src)¶
-
stackless_coroutine &
operator=(stackless_coroutine &&src)¶
-
thread_id_type
get_thread_id() const¶
-
void
rebind(functor_type &&f, thread_id_type id)¶
-
void
reset_tss()¶
-
void
reset()¶
-
stackless_coroutine::result_type
operator()(arg_type arg = arg_type())¶
-
operator bool() const¶
-
bool
is_ready() const¶
Friends
-
friend
hpx::threads::coroutines::reset_on_exit
-
struct
reset_on_exit¶ -
Public Members
-
stackless_coroutine &
this_¶
-
stackless_coroutine &
-
using
-
class
-
namespace
-
namespace
Defines
-
HPX_THREAD_STATE_UNSCOPED_ENUM_DEPRECATION_MSG¶
-
HPX_THREAD_PRIORITY_UNSCOPED_ENUM_DEPRECATION_MSG¶
-
HPX_THREAD_STATE_EX_UNSCOPED_ENUM_DEPRECATION_MSG¶
-
HPX_THREAD_STACKSIZE_UNSCOPED_ENUM_DEPRECATION_MSG¶
-
HPX_THREAD_SCHEDULE_HINT_UNSCOPED_ENUM_DEPRECATION_MSG¶
-
namespace
hpx -
namespace
threads Enums
-
enum
thread_schedule_state¶ The thread_schedule_state enumerator encodes the current state of a thread instance
Values:
-
unknown= 0¶
-
active= 1¶ thread is currently active (running, has resources)
-
pending= 2¶ thread is pending (ready to run, but no hardware resource available)
-
suspended= 3¶ thread has been suspended (waiting for synchronization event, but still known and under control of the thread-manager)
-
depleted= 4¶ thread has been depleted (deeply suspended, it is not known to the thread-manager)
-
terminated= 5¶ thread has been stopped an may be garbage collected
-
staged= 6¶ this is not a real thread state, but allows to reference staged task descriptions, which eventually will be converted into thread objects
-
pending_do_not_schedule= 7¶
-
pending_boost= 8¶
-
-
enum
thread_priority¶ This enumeration lists all possible thread-priorities for HPX threads.
Values:
-
unknown= -1
-
default_= 0¶ Will assign the priority of the task to the default (normal) priority.
-
low= 1¶ Task goes onto a special low priority queue and will not be executed until all high/normal priority tasks are done, even if they are added after the low priority task.
-
normal= 2¶ Task will be executed when it is taken from the normal priority queue, this is usually a first in-first-out ordering of tasks (depending on scheduler choice). This is the default priority.
-
high_recursive= 3¶ The task is a high priority task and any child tasks spawned by this task will be made high priority as well - unless they are specifically flagged as non default priority.
-
boost= 4¶ Same as thread_priority_high except that the thread will fall back to thread_priority_normal if resumed after being suspended.
-
high= 5¶ Task goes onto a special high priority queue and will be executed before normal/low priority tasks are taken (some schedulers modify the behavior slightly and the documentation for those should be consulted).
-
bound= 6¶ Task goes onto a special high priority queue and will never be stolen by another thread after initial assignment. This should be used for thread placement tasks such as OpenMP type for loops.
-
-
enum
thread_restart_state¶ The thread_restart_state enumerator encodes the reason why a thread is being restarted
Values:
-
unknown= 0
-
signaled= 1¶ The thread has been signaled.
-
timeout= 2¶ The thread has been reactivated after a timeout
-
terminate= 3¶ The thread needs to be terminated.
-
abort= 4¶ The thread needs to be aborted.
-
-
enum
thread_stacksize¶ A thread_stacksize references any of the possible stack-sizes for HPX threads.
Values:
-
unknown= -1
-
small_= 1¶ use small stack size (the underscore is to work around small being defined to char on Windows)
-
medium= 2¶ use medium sized stack size
-
large= 3¶ use large stack size
-
huge= 4¶ use very large stack size
-
nostack= 5¶ this thread does not suspend (does not need a stack)
-
current= 6¶ use size of current thread’s stack
-
default_= small_ use default stack size
-
-
enum
thread_schedule_hint_mode¶ The type of hint given when creating new tasks.
Values:
-
none= 0¶ A hint that leaves the choice of scheduling entirely up to the scheduler.
-
thread= 1¶ A hint that tells the scheduler to prefer scheduling a task on the local thread number associated with this hint. Local thread numbers are indexed from zero. It is up to the scheduler to decide how to interpret thread numbers that are larger than the number of threads available to the scheduler. Typically thread numbers will wrap around when too large.
-
numa= 2¶ A hint that tells the scheduler to prefer scheduling a task on the NUMA domain associated with this hint. NUMA domains are indexed from zero. It is up to the scheduler to decide how to interpret NUMA domain indices that are larger than the number of available NUMA domains to the scheduler. Typically indices will wrap around when too large.
-
Functions
-
std::ostream &
operator<<(std::ostream &os, thread_schedule_state const t)¶
-
char const *
get_thread_state_name(thread_schedule_state state)¶ Returns the name of the given state.
Get the readable string representing the name of the given thread_state constant.
- Parameters
state: this represents the thread state.
-
std::ostream &
operator<<(std::ostream &os, thread_priority const t)¶
-
char const *
get_thread_priority_name(thread_priority priority)¶ Return the thread priority name.
Get the readable string representing the name of the given thread_priority constant.
- Parameters
this: represents the thread priority.
-
std::ostream &
operator<<(std::ostream &os, thread_restart_state const t)¶
-
char const *
get_thread_state_ex_name(thread_restart_state state)¶ Get the readable string representing the name of the given thread_restart_state constant.
-
char const *
get_thread_state_name(thread_state state)¶ Get the readable string representing the name of the given thread_state constant.
-
std::ostream &
operator<<(std::ostream &os, thread_stacksize const t)¶
-
char const *
get_stack_size_enum_name(thread_stacksize size)¶ Returns the stack size name.
Get the readable string representing the given stack size constant.
- Parameters
size: this represents the stack size
-
hpx::threads::HPX_DEPRECATED_V(1, 6, HPX_THREAD_SCHEDULE_HINT_UNSCOPED_ENUM_DEPRECATION_MSG) const
Variables
-
constexpr thread_schedule_state
unknown= thread_schedule_state::unknown
-
constexpr thread_schedule_state
active= thread_schedule_state::active
-
constexpr thread_schedule_state
pending= thread_schedule_state::pending
-
constexpr thread_schedule_state
suspended= thread_schedule_state::suspended
-
constexpr thread_schedule_state
depleted= thread_schedule_state::depleted
-
constexpr thread_schedule_state
terminated= thread_schedule_state::terminated
-
constexpr thread_schedule_state
staged= thread_schedule_state::staged
-
constexpr thread_schedule_state
pending_do_not_schedule= thread_schedule_state::pending_do_not_schedule
-
constexpr thread_schedule_state
pending_boost= thread_schedule_state::pending_boost
-
constexpr thread_priority
thread_priority_unknown= thread_priority::unknown¶
-
constexpr thread_priority
thread_priority_default= thread_priority::default_¶
-
constexpr thread_priority
thread_priority_low= thread_priority::low¶
-
constexpr thread_priority
thread_priority_normal= thread_priority::normal¶
-
constexpr thread_priority
thread_priority_high_recursive= thread_priority::high_recursive¶
-
constexpr thread_priority
thread_priority_boost= thread_priority::boost¶
-
constexpr thread_priority
thread_priority_high= thread_priority::high¶
-
constexpr thread_priority
thread_priority_bound= thread_priority::bound¶
-
constexpr thread_priority
thread_priority_critical= thread_priority::critical¶
-
constexpr thread_restart_state
wait_unknown= thread_restart_state::unknown¶
-
constexpr thread_restart_state
wait_signaled= thread_restart_state::signaled¶
-
constexpr thread_restart_state
wait_timeout= thread_restart_state::timeout¶
-
constexpr thread_restart_state
wait_terminate= thread_restart_state::terminate¶
-
constexpr thread_restart_state
wait_abort= thread_restart_state::abort¶
-
constexpr thread_stacksize
thread_stacksize_unknown= thread_stacksize::unknown¶
-
constexpr thread_stacksize
thread_stacksize_small= thread_stacksize::small_¶
-
constexpr thread_stacksize
thread_stacksize_medium= thread_stacksize::medium¶
-
constexpr thread_stacksize
thread_stacksize_large= thread_stacksize::large¶
-
constexpr thread_stacksize
thread_stacksize_huge= thread_stacksize::huge¶
-
constexpr thread_stacksize
thread_stacksize_nostack= thread_stacksize::nostack¶
-
constexpr thread_stacksize
thread_stacksize_current= thread_stacksize::current¶
-
constexpr thread_stacksize
thread_stacksize_default= thread_stacksize::default_¶
-
constexpr thread_stacksize
thread_stacksize_minimal= thread_stacksize::minimal¶
-
constexpr thread_stacksize
thread_stacksize_maximal= thread_stacksize::maximal¶
-
struct
thread_schedule_hint¶ - #include <thread_enums.hpp>
A hint given to a scheduler to guide where a task should be scheduled.
A scheduler is free to ignore the hint, or modify the hint to suit the resources available to the scheduler.
Public Functions
-
constexpr
thread_schedule_hint()¶ Construct a default hint with mode thread_schedule_hint_mode::none.
-
constexpr
thread_schedule_hint(std::int16_t thread_hint)¶ Construct a hint with mode thread_schedule_hint_mode::thread and the given hint as the local thread number.
-
constexpr
thread_schedule_hint(thread_schedule_hint_mode mode, std::int16_t hint)¶ Construct a hint with the given mode and hint. The numerical hint is unused when the mode is thread_schedule_hint_mode::none.
Public Members
-
thread_schedule_hint_mode
mode¶ The mode of the scheduling hint.
-
constexpr
-
enum
-
namespace
-
namespace
hpx -
namespace
threads -
-
struct
thread_id¶ Public Functions
-
constexpr
thread_id()¶
-
constexpr
thread_id(thread_id_repr thrd)¶
-
constexpr
operator bool() const¶
-
constexpr thread_id_repr
get() const¶
-
constexpr void
reset()¶
Private Types
-
using
thread_id_repr= void*¶
Private Members
-
thread_id_repr
thrd_¶
Friends
-
friend constexpr bool
operator==(thread_id const &lhs, thread_id const &rhs)¶
-
friend constexpr bool
operator!=(thread_id const &lhs, thread_id const &rhs)¶
-
friend constexpr bool
operator<(thread_id const &lhs, thread_id const &rhs)¶
-
friend constexpr bool
operator>(thread_id const &lhs, thread_id const &rhs)¶
-
friend constexpr bool
operator<=(thread_id const &lhs, thread_id const &rhs)¶
-
friend constexpr bool
operator>=(thread_id const &lhs, thread_id const &rhs)¶
-
constexpr
-
struct
-
namespace
datastructures¶
The contents of this module can be included with the header
hpx/modules/datastructures.hpp. These headers may be used by user-code but are not
guaranteed stable (neither header location nor contents). You are using these at
your own risk. If you wish to use non-public functionality from a module we
strongly suggest only including the module header hpx/modules/datastructures.hpp, not
the particular header in which the functionality you would like to use is
defined. See Public API for a list of names that are part of the public
HPX API.
-
template<>
classbasic_any<void, void, void, std::true_type>¶ Public Functions
-
constexpr
basic_any()¶
-
template<typename
T, typenameEnable= typename std::enable_if<!std::is_same<basic_any, typename std::decay<T>::type>::value>::type>basic_any(T &&x, typename std::enable_if<std::is_copy_constructible<typename std::decay<T>::type>::value>::type* = nullptr)¶
-
~basic_any()¶
-
basic_any &
operator=(basic_any const &x)¶
-
basic_any &
operator=(basic_any &&rhs)¶
-
template<typename
T, typenameEnable= typename std::enable_if<!std::is_same<basic_any, typename std::decay<T>::type>::value && std::is_copy_constructible<typename std::decay<T>::type>::value>::type>
basic_any &operator=(T &&rhs)¶
-
basic_any &
swap(basic_any &x)¶
-
bool
has_value() const¶
-
void
reset()¶
-
bool
equal_to(basic_any const &rhs) const¶
Private Functions
-
basic_any &
assign(basic_any const &x)¶
-
constexpr
-
template<typename
Char>
classbasic_any<void, void, Char, std::true_type>¶ Public Functions
-
constexpr
basic_any()
-
basic_any(basic_any const &x)
-
basic_any(basic_any &&x)
-
template<typename
T, typenameEnable= typename std::enable_if<!std::is_same<basic_any, typename std::decay<T>::type>::value>::type>basic_any(T &&x, typename std::enable_if<std::is_copy_constructible<typename std::decay<T>::type>::value>::type* = nullptr)
-
~basic_any()
-
basic_any &
operator=(basic_any const &x)
-
basic_any &
operator=(basic_any &&rhs)
-
template<typename
T, typenameEnable= typename std::enable_if<!std::is_same<basic_any, typename std::decay<T>::type>::value && std::is_copy_constructible<typename std::decay<T>::type>::value>::type>
basic_any &operator=(T &&rhs)
-
basic_any &
swap(basic_any &x)
-
std::type_info const &
type() const
-
template<typename
T>
T const &cast() const
-
bool
has_value() const
-
void
reset()
-
bool
equal_to(basic_any const &rhs) const
Private Functions
-
basic_any &
assign(basic_any const &x)
-
constexpr
-
template<>
classbasic_any<void, void, void, std::false_type>¶ Public Functions
-
constexpr
basic_any()
-
basic_any(basic_any &&x)
-
template<typename
T, typenameEnable= typename std::enable_if<!std::is_same<basic_any, typename std::decay<T>::type>::value>::type>basic_any(T &&x, typename std::enable_if<std::is_move_constructible<typename std::decay<T>::type>::value>::type* = nullptr)
-
basic_any(basic_any const &x)
-
basic_any &
operator=(basic_any const &x)
-
~basic_any()
-
basic_any &
operator=(basic_any &&rhs)
-
template<typename
T, typenameEnable= typename std::enable_if<!std::is_same<basic_any, typename std::decay<T>::type>::value && std::is_move_constructible<typename std::decay<T>::type>::value>::type>
basic_any &operator=(T &&rhs)
-
basic_any &
swap(basic_any &x)
-
std::type_info const &
type() const
-
template<typename
T>
T const &cast() const
-
bool
has_value() const
-
void
reset()
-
bool
equal_to(basic_any const &rhs) const
-
constexpr
-
template<typename
Char>
classbasic_any<void, void, Char, std::false_type>¶ Public Functions
-
constexpr
basic_any()
-
basic_any(basic_any &&x)
-
template<typename
T, typenameEnable= typename std::enable_if<!std::is_same<basic_any, typename std::decay<T>::type>::value>::type>basic_any(T &&x, typename std::enable_if<std::is_move_constructible<typename std::decay<T>::type>::value>::type* = nullptr)
-
basic_any(basic_any const &x)
-
basic_any &
operator=(basic_any const &x)
-
~basic_any()
-
basic_any &
operator=(basic_any &&rhs)
-
template<typename
T, typenameEnable= typename std::enable_if<!std::is_same<basic_any, typename std::decay<T>::type>::value && std::is_move_constructible<typename std::decay<T>::type>::value>::type>
basic_any &operator=(T &&rhs)
-
basic_any &
swap(basic_any &x)
-
std::type_info const &
type() const
-
template<typename
T>
T const &cast() const
-
bool
has_value() const
-
void
reset()
-
bool
equal_to(basic_any const &rhs) const
-
constexpr
-
namespace
hpx Typedefs
Functions
-
template<typename
T>
util::basic_any<void, void, void, std::false_type>make_unique_any_nonser(T &&t)¶
-
template<typename
T, typenameIArch, typenameOArch, typenameChar, typenameCopyable>
T *any_cast(util::basic_any<IArch, OArch, Char, Copyable> *operand)¶
-
template<typename
T, typenameIArch, typenameOArch, typenameChar, typenameCopyable>
T const *any_cast(util::basic_any<IArch, OArch, Char, Copyable> const *operand)¶
-
namespace
util Typedefs
Functions
-
template<typename
IArch, typenameOArch, typenameChar, typenameCopyable, typenameEnable= typename std::enable_if<!std::is_void<Char>::value>::type>
std::basic_istream<Char> &operator>>(std::basic_istream<Char> &i, basic_any<IArch, OArch, Char, Copyable> &obj)¶
-
template<typename
IArch, typenameOArch, typenameChar, typenameCopyable, typenameEnable= typename std::enable_if<!std::is_void<Char>::value>::type>
std::basic_ostream<Char> &operator<<(std::basic_ostream<Char> &o, basic_any<IArch, OArch, Char, Copyable> const &obj)¶
-
template<typename
IArch, typenameOArch, typenameChar, typenameCopyable>
voidswap(basic_any<IArch, OArch, Char, Copyable> &lhs, basic_any<IArch, OArch, Char, Copyable> &rhs)¶
-
template<typename T>hpx::util::HPX_DEPRECATED_V(1, 6, "hpx::util::make_any_nonser is deprecated. Please use " "hpx::make_any_nonser instead.")
-
template<typename
T, typenameChar>
basic_any<void, void, Char, std::true_type>make_streamable_any_nonser(T &&t)¶
-
template<typename T>hpx::util::HPX_DEPRECATED_V(1, 6, "hpx::util::make_unique_any_nonser is deprecated. Please use " "hpx::make_unique_any_nonser instead.")
Variables
-
hpx::util::void
-
template<typename
Char>
classbasic_any<void, void, Char, std::false_type> Public Functions
-
constexpr
basic_any()
-
basic_any(basic_any &&x)
-
template<typename
T, typenameEnable= typename std::enable_if<!std::is_same<basic_any, typename std::decay<T>::type>::value>::type>basic_any(T &&x, typename std::enable_if<std::is_move_constructible<typename std::decay<T>::type>::value>::type* = nullptr)
-
basic_any(basic_any const &x)
-
basic_any &
operator=(basic_any const &x)
-
~basic_any()
-
basic_any &
operator=(basic_any &&rhs)
-
template<typename
T, typenameEnable= typename std::enable_if<!std::is_same<basic_any, typename std::decay<T>::type>::value && std::is_move_constructible<typename std::decay<T>::type>::value>::type>
basic_any &operator=(T &&rhs)
-
basic_any &
swap(basic_any &x)
-
std::type_info const &
type() const
-
template<typename
T>
T const &cast() const
-
bool
has_value() const
-
void
reset()
-
bool
equal_to(basic_any const &rhs) const
-
constexpr
-
template<typename
Char>
classbasic_any<void, void, Char, std::true_type> Public Functions
-
constexpr
basic_any()
-
basic_any(basic_any const &x)
-
basic_any(basic_any &&x)
-
template<typename
T, typenameEnable= typename std::enable_if<!std::is_same<basic_any, typename std::decay<T>::type>::value>::type>basic_any(T &&x, typename std::enable_if<std::is_copy_constructible<typename std::decay<T>::type>::value>::type* = nullptr)
-
~basic_any()
-
basic_any &
operator=(basic_any const &x)
-
basic_any &
operator=(basic_any &&rhs)
-
template<typename
T, typenameEnable= typename std::enable_if<!std::is_same<basic_any, typename std::decay<T>::type>::value && std::is_copy_constructible<typename std::decay<T>::type>::value>::type>
basic_any &operator=(T &&rhs)
-
basic_any &
swap(basic_any &x)
-
std::type_info const &
type() const
-
template<typename
T>
T const &cast() const
-
bool
has_value() const
-
void
reset()
-
bool
equal_to(basic_any const &rhs) const
Private Functions
-
basic_any &
assign(basic_any const &x)
-
constexpr
-
template<>
classbasic_any<void, void, void, std::false_type> Public Functions
-
constexpr
basic_any()
-
basic_any(basic_any &&x)
-
template<typename
T, typenameEnable= typename std::enable_if<!std::is_same<basic_any, typename std::decay<T>::type>::value>::type>basic_any(T &&x, typename std::enable_if<std::is_move_constructible<typename std::decay<T>::type>::value>::type* = nullptr)
-
basic_any(basic_any const &x)
-
basic_any &
operator=(basic_any const &x)
-
~basic_any()
-
basic_any &
operator=(basic_any &&rhs)
-
template<typename
T, typenameEnable= typename std::enable_if<!std::is_same<basic_any, typename std::decay<T>::type>::value && std::is_move_constructible<typename std::decay<T>::type>::value>::type>
basic_any &operator=(T &&rhs)
-
basic_any &
swap(basic_any &x)
-
std::type_info const &
type() const
-
template<typename
T>
T const &cast() const
-
bool
has_value() const
-
void
reset()
-
bool
equal_to(basic_any const &rhs) const
-
constexpr
-
template<>
classbasic_any<void, void, void, std::true_type> Public Functions
-
constexpr
basic_any()
-
basic_any(basic_any const &x)
-
basic_any(basic_any &&x)
-
template<typename
T, typenameEnable= typename std::enable_if<!std::is_same<basic_any, typename std::decay<T>::type>::value>::type>basic_any(T &&x, typename std::enable_if<std::is_copy_constructible<typename std::decay<T>::type>::value>::type* = nullptr)
-
~basic_any()
-
basic_any &
operator=(basic_any const &x)
-
basic_any &
operator=(basic_any &&rhs)
-
template<typename
T, typenameEnable= typename std::enable_if<!std::is_same<basic_any, typename std::decay<T>::type>::value && std::is_copy_constructible<typename std::decay<T>::type>::value>::type>
basic_any &operator=(T &&rhs)
-
basic_any &
swap(basic_any &x)
-
std::type_info const &
type() const
-
template<typename
T>
T const &cast() const
-
bool
has_value() const
-
void
reset()
-
bool
equal_to(basic_any const &rhs) const
Private Functions
-
basic_any &
assign(basic_any const &x)
-
constexpr
-
template<typename
-
template<typename
-
template<std::size_t...
Is, typename ...Ts>
structmember_pack<util::index_pack<Is...>, Ts...> : public hpx::util::detail::member_leaf<Is, Ts>¶ Public Functions
-
member_pack()¶
-
-
namespace
hpx -
namespace
serialization¶
-
namespace
-
namespace
hpx -
namespace
util Functions
-
class
bad_optional_access: public logic_error¶
-
struct
nullopt_t¶
-
template<typename
T>
classoptional¶ Public Types
-
template<>
usingvalue_type= T¶
Public Functions
-
constexpr
optional()¶
-
optional(T const &val)¶
-
optional(T &&val)¶
-
~optional()¶
-
optional &
operator=(optional const &other)¶
-
optional &
operator=(optional &&other)¶
-
optional &
operator=(T const &other)¶
-
optional &
operator=(T &&other)¶
-
constexpr T const *
operator->() const¶
-
T *
operator->()¶
-
constexpr T const &
operator*() const¶
-
T &
operator*()¶
-
constexpr
operator bool() const¶
-
constexpr bool
has_value() const¶
-
T &
value()¶
-
T const &
value() const¶
-
void
swap(optional &other)¶
-
void
reset()¶
-
template<>
-
class
-
namespace
Defines
-
HPX_DEFINE_TAG_SPECIFIER(NAME)¶
-
namespace
hpx
-
namespace
hpx -
namespace
util Functions
-
template<typename
Tag1, typenameTag2, typenameT1, typenameT2>
constexpr tagged_pair<Tag1(typename std::decay<T1>::type), Tag2(typename std::decay<T2>::type)>make_tagged_pair(std::pair<T1, T2> &&p)¶
-
template<typename
Tag1, typenameTag2, typenameT1, typenameT2>
constexpr tagged_pair<Tag1(typename std::decay<T1>::type), Tag2(typename std::decay<T2>::type)>make_tagged_pair(std::pair<T1, T2> const &p)¶
-
template<typename
Tag1, typenameTag2, typename ...Ts>
constexpr tagged_pair<Tag1(typename hpx::tuple_element<0, hpx::tuple<Ts...>>::type), Tag2(typename hpx::tuple_element<1, hpx::tuple<Ts...>>::type)>make_tagged_pair(hpx::tuple<Ts...> &&p)¶
-
template<typename
-
namespace
-
namespace
hpx -
namespace
util
-
namespace
-
template<typename
T0, typenameT1>
structtuple_element<0, std::pair<T0, T1>>¶ Public Types
-
template<>
usingtype= T0¶
-
template<>
-
template<typename
T0, typenameT1>
structtuple_element<1, std::pair<T0, T1>>¶ Public Types
-
template<>
usingtype= T1¶
-
template<>
-
template<std::size_t
I, typenameType, std::size_tSize>
structtuple_element<I, std::array<Type, Size>>¶ Public Types
-
template<>
usingtype= Type¶
-
template<>
-
namespace
hpx Functions
-
template<typename ...
Ts>
constexpr tuple<typename util::decay_unwrap<Ts>::type...>make_tuple(Ts&&... vs)¶
-
template<typename ...
Ts, typename ...Us>
constexpr std::enable_if<sizeof...(Ts) == sizeof...(Us), bool>::typeoperator==(tuple<Ts...> const &t, tuple<Us...> const &u)¶
-
template<typename ...
Ts, typename ...Us>
constexpr std::enable_if<sizeof...(Ts) == sizeof...(Us), bool>::typeoperator!=(tuple<Ts...> const &t, tuple<Us...> const &u)¶
-
template<typename ...
Ts, typename ...Us>
constexpr std::enable_if<sizeof...(Ts) == sizeof...(Us), bool>::typeoperator<(tuple<Ts...> const &t, tuple<Us...> const &u)¶
-
template<typename ...
Ts, typename ...Us>
constexpr std::enable_if<sizeof...(Ts) == sizeof...(Us), bool>::typeoperator>(tuple<Ts...> const &t, tuple<Us...> const &u)¶
-
template<typename ...
Ts, typename ...Us>
constexpr std::enable_if<sizeof...(Ts) == sizeof...(Us), bool>::typeoperator<=(tuple<Ts...> const &t, tuple<Us...> const &u)¶
-
template<typename ...
Ts>
classtuple¶ Public Functions
-
template<typename
Dependent= void, typenameEnable= typename std::enable_if<util::all_of<std::is_constructible<Ts>...>::value, Dependent>::type>
constexprtuple()¶
-
constexpr
tuple(Ts const&... vs)¶
-
template<typename
U, typename ...Us, typenameEnable= typename std::enable_if<!std::is_same<tuple, typename std::decay<U>::type>::value || util::pack<Us...>::size != 0>::type, typenameEnableCompatible= typename std::enable_if<hpx::detail::are_tuples_compatible<tuple, tuple<U, Us...>>::value>::type>
constexprtuple(U &&v, Us&&... vs)¶
-
template<typename
UTuple, typenameEnable= typename std::enable_if<!std::is_same<tuple, typename std::decay<UTuple>::type>::value>::type, typenameEnableCompatible= typename std::enable_if<hpx::detail::are_tuples_compatible<tuple, UTuple>::value>::type>
constexprtuple(UTuple &&other)¶
-
tuple &
operator=(tuple const &other)¶
-
tuple &
operator=(tuple &&other)¶
-
void
swap(tuple &other)¶
Private Functions
-
template<std::size_t...
Is, typenameUTuple>
constexprtuple(util::index_pack<Is...>, UTuple &&other)¶
-
template<std::size_t...
Is>
voidassign_(util::index_pack<Is...>, tuple const &other)¶
-
template<std::size_t...
Is>
voidassign_(util::index_pack<Is...>, tuple &&other)¶
-
template<std::size_t...
Is>
voidswap_(util::index_pack<Is...>, tuple &other)¶
Private Members
-
util::member_pack_for<Ts...>
_members¶
-
template<typename
-
template<>
classtuple<>¶
-
template<typename
T0, typenameT1>
structtuple_element<0, std::pair<T0, T1>> Public Types
-
template<>
usingtype= T0
-
template<>
-
template<typename
T0, typenameT1>
structtuple_element<1, std::pair<T0, T1>> Public Types
-
template<>
usingtype= T1
-
template<>
-
template<std::size_t
I, typenameType, std::size_tSize>
structtuple_element<I, std::array<Type, Size>> Public Types
-
template<>
usingtype= Type
-
template<>
-
template<class
T>
structtuple_size¶ Subclassed by hpx::tuple_size< const T >, hpx::tuple_size< const volatile T >, hpx::tuple_size< volatile T >
-
namespace
adl_barrier¶ Functions
-
template<std::size_t
I, typenameTuple, typenameEnable= typename util::always_void<typename hpx::tuple_element<I, Tuple>::type>::type>
constexpr hpx::tuple_element<I, Tuple>::type &get(Tuple &t)¶
-
template<std::size_t
I, typenameTuple, typenameEnable= typename util::always_void<typename hpx::tuple_element<I, Tuple>::type>::type>
constexpr hpx::tuple_element<I, Tuple>::type const &get(Tuple const &t)¶
-
template<std::size_t
I, typenameTuple, typenameEnable= typename util::always_void<typename hpx::tuple_element<I, typename std::decay<Tuple>::type>::type>::type>
constexpr hpx::tuple_element<I, Tuple>::type &&get(Tuple &&t)¶
-
template<std::size_t
I, typenameTuple, typenameEnable= typename util::always_void<typename hpx::tuple_element<I, Tuple>::type>::type>
constexpr hpx::tuple_element<I, Tuple>::type const &&get(Tuple const &&t)¶
-
template<std::size_t
I, typenameTuple, typenameEnable>
constexpr tuple_element<I, Tuple>::type &get(Tuple &t)¶
-
template<std::size_t
I, typenameTuple, typenameEnable>
constexpr tuple_element<I, Tuple>::type const &get(Tuple const &t)¶
-
template<std::size_t
-
namespace
std_adl_barrier¶ Functions
-
template<std::size_t
I, typename ...Ts>
constexpr hpx::tuple_element<I, hpx::tuple<Ts...>>::type &get(hpx::tuple<Ts...> &t)¶
-
template<std::size_t
I, typename ...Ts>
constexpr hpx::tuple_element<I, hpx::tuple<Ts...>>::type const &get(hpx::tuple<Ts...> const &t)¶
-
template<std::size_t
I, typename ...Ts>
constexpr hpx::tuple_element<I, hpx::tuple<Ts...>>::type &&get(hpx::tuple<Ts...> &&t)¶
-
template<std::size_t
I, typename ...Ts>
constexpr hpx::tuple_element<I, hpx::tuple<Ts...>>::type const &&get(hpx::tuple<Ts...> const &&t)¶
-
template<std::size_t
I, typename ...Ts>
constexpr tuple_element<I, tuple<Ts...>>::type &get(tuple<Ts...> &t)¶
-
template<std::size_t
I, typename ...Ts>
constexpr tuple_element<I, tuple<Ts...>>::type const &get(tuple<Ts...> const &t)¶
-
template<std::size_t
-
namespace
util Functions
-
hpx::util::HPX_DEPRECATED_V(1, 6, "hpx::util::ignore is deprecated. Use hpx::ignore instead.")
-
template<typename... Ts>hpx::util::HPX_DEPRECATED_V(1, 6, "hpx::util::make_tuple is deprecated. Use hpx::make_tuple instead.") const&&
-
template<typename... Ts>hpx::util::HPX_DEPRECATED_V(1, 6, "hpx::util::tie is deprecated. Use hpx::tie instead.") const&&
-
template<typename... Ts>hpx::util::HPX_DEPRECATED_V(1, 6, "hpx::util::forward_as_tuple is deprecated. Use hpx::forward_as_tuple " "instead.") const&&
-
template<typename... Ts>hpx::util::HPX_DEPRECATED_V(1, 6, "hpx::util::tuple_cat is deprecated. Use hpx::tuple_cat " "instead.") const&&
-
template<std::size_t I, typename Tuple>hpx::util::HPX_DEPRECATED_V(1, 6, "hpx::util::get is deprecated. Use hpx::get " "instead.") const&&
-
-
template<typename ...
debugging¶
The contents of this module can be included with the header
hpx/modules/debugging.hpp. These headers may be used by user-code but are not
guaranteed stable (neither header location nor contents). You are using these at
your own risk. If you wish to use non-public functionality from a module we
strongly suggest only including the module header hpx/modules/debugging.hpp, not
the particular header in which the functionality you would like to use is
defined. See Public API for a list of names that are part of the public
HPX API.
-
namespace
hpx -
namespace
util Functions
-
void
attach_debugger()¶ Tries to break an attached debugger, if not supported a loop is invoked which gives enough time to attach a debugger manually.
-
void
-
namespace
-
namespace
hpx -
namespace
util
-
namespace
-
namespace
hpx -
namespace
util -
namespace
debug¶ Typedefs
Functions
-
namespace
-
namespace
Variables
-
char **
environ¶
Defines
-
HPX_DP_LAZY(Expr, printer)¶
errors¶
The contents of this module can be included with the header
hpx/modules/errors.hpp. These headers may be used by user-code but are not
guaranteed stable (neither header location nor contents). You are using these at
your own risk. If you wish to use non-public functionality from a module we
strongly suggest only including the module header hpx/modules/errors.hpp, not
the particular header in which the functionality you would like to use is
defined. See Public API for a list of names that are part of the public
HPX API.
-
namespace
hpx Enums
-
enum
error¶ Possible error conditions.
This enumeration lists all possible error conditions which can be reported from any of the API functions.
Values:
-
success= 0¶ The operation was successful.
-
no_success= 1¶ The operation did failed, but not in an unexpected manner.
-
not_implemented= 2¶ The operation is not implemented.
-
out_of_memory= 3¶ The operation caused an out of memory condition.
-
bad_action_code= 4¶
-
bad_component_type= 5¶ The specified component type is not known or otherwise invalid.
-
network_error= 6¶ A generic network error occurred.
-
version_too_new= 7¶ The version of the network representation for this object is too new.
-
version_too_old= 8¶ The version of the network representation for this object is too old.
-
version_unknown= 9¶ The version of the network representation for this object is unknown.
-
unknown_component_address= 10¶
-
duplicate_component_address= 11¶ The given global id has already been registered.
-
invalid_status= 12¶ The operation was executed in an invalid status.
-
bad_parameter= 13¶ One of the supplied parameters is invalid.
-
internal_server_error= 14¶
-
bad_request= 16¶
-
repeated_request= 17¶
-
lock_error= 18¶
-
duplicate_console= 19¶ There is more than one console locality.
-
no_registered_console= 20¶ There is no registered console locality available.
-
startup_timed_out= 21¶
-
uninitialized_value= 22¶
-
bad_response_type= 23¶
-
deadlock= 24¶
-
assertion_failure= 25¶
-
null_thread_id= 26¶ Attempt to invoke a API function from a non-HPX thread.
-
invalid_data= 27¶
-
yield_aborted= 28¶ The yield operation was aborted.
-
dynamic_link_failure= 29¶
-
commandline_option_error= 30¶ One of the options given on the command line is erroneous.
-
serialization_error= 31¶ There was an error during serialization of this object.
-
unhandled_exception= 32¶ An unhandled exception has been caught.
-
kernel_error= 33¶ The OS kernel reported an error.
-
broken_task= 34¶ The task associated with this future object is not available anymore.
-
task_moved= 35¶ The task associated with this future object has been moved.
-
task_already_started= 36¶ The task associated with this future object has already been started.
-
future_already_retrieved= 37¶ The future object has already been retrieved.
-
promise_already_satisfied= 38¶ The value for this future object has already been set.
-
future_does_not_support_cancellation= 39¶ The future object does not support cancellation.
-
future_can_not_be_cancelled= 40¶ The future can’t be canceled at this time.
-
no_state= 41¶ The future object has no valid shared state.
-
broken_promise= 42¶ The promise has been deleted.
-
thread_resource_error= 43¶
-
future_cancelled= 44¶
-
thread_cancelled= 45¶
-
thread_not_interruptable= 46¶
-
duplicate_component_id= 47¶ The component type has already been registered.
-
unknown_error= 48¶ An unknown error occurred.
-
bad_plugin_type= 49¶ The specified plugin type is not known or otherwise invalid.
-
filesystem_error= 50¶ The specified file does not exist or other filesystem related error.
-
bad_function_call= 51¶ equivalent of std::bad_function_call
-
task_canceled_exception= 52¶ parallel::v2::task_canceled_exception
-
task_block_not_active= 53¶ task_region is not active
-
out_of_range= 54¶ Equivalent to std::out_of_range.
-
length_error= 55¶ Equivalent to std::length_error.
-
migration_needs_retry= 56¶ migration failed because of global race, retry
-
-
enum
-
namespace
hpx Unnamed Group
-
error_code
make_error_code(error e, throwmode mode = plain)¶ Returns a new error_code constructed from the given parameters.
-
error_code
make_error_code(error e, char const *func, char const *file, long line, throwmode mode = plain)¶
-
error_code
make_error_code(error e, char const *msg, throwmode mode = plain)¶ Returns error_code(e, msg, mode).
-
error_code
make_error_code(error e, char const *msg, char const *func, char const *file, long line, throwmode mode = plain)¶
-
error_code
make_error_code(error e, std::string const &msg, throwmode mode = plain)¶ Returns error_code(e, msg, mode).
-
error_code
make_error_code(error e, std::string const &msg, char const *func, char const *file, long line, throwmode mode = plain)¶
-
error_code
make_error_code(std::exception_ptr const &e)¶
Functions
-
std::error_category const &
get_hpx_category()¶ Returns generic HPX error category used for new errors.
-
std::error_category const &
get_hpx_rethrow_category()¶ Returns generic HPX error category used for errors re-thrown after the exception has been de-serialized.
-
error_code
make_success_code(throwmode mode = plain)¶ Returns error_code(hpx::success, “success”, mode).
-
class
error_code: public error_code¶ - #include <error_code.hpp>
A hpx::error_code represents an arbitrary error condition.
The class hpx::error_code describes an object used to hold error code values, such as those originating from the operating system or other low-level application program interfaces.
- Note
Class hpx::error_code is an adjunct to error reporting by exception
Public Functions
-
error_code(throwmode mode = plain)¶ Construct an object of type error_code.
- Parameters
mode: The parametermodespecifies whether the constructed hpx::error_code belongs to the error category hpx_category (if mode is plain, this is the default) or to the category hpx_category_rethrow (if mode is rethrow).
- Exceptions
nothing:
-
error_code(error e, throwmode mode = plain)¶ Construct an object of type error_code.
- Parameters
e: The parametereholds the hpx::error code the new exception should encapsulate.mode: The parametermodespecifies whether the constructed hpx::error_code belongs to the error category hpx_category (if mode is plain, this is the default) or to the category hpx_category_rethrow (if mode is rethrow).
- Exceptions
nothing:
-
error_code(error e, char const *func, char const *file, long line, throwmode mode = plain)¶ Construct an object of type error_code.
- Parameters
e: The parametereholds the hpx::error code the new exception should encapsulate.func: The name of the function where the error was raised.file: The file name of the code where the error was raised.line: The line number of the code line where the error was raised.mode: The parametermodespecifies whether the constructed hpx::error_code belongs to the error category hpx_category (if mode is plain, this is the default) or to the category hpx_category_rethrow (if mode is rethrow).
- Exceptions
nothing:
-
error_code(error e, char const *msg, throwmode mode = plain)¶ Construct an object of type error_code.
- Parameters
e: The parametereholds the hpx::error code the new exception should encapsulate.msg: The parametermsgholds the error message the new exception should encapsulate.mode: The parametermodespecifies whether the constructed hpx::error_code belongs to the error category hpx_category (if mode is plain, this is the default) or to the category hpx_category_rethrow (if mode is rethrow).
- Exceptions
std::bad_alloc: (if allocation of a copy of the passed string fails).
-
error_code(error e, char const *msg, char const *func, char const *file, long line, throwmode mode = plain)¶ Construct an object of type error_code.
- Parameters
e: The parametereholds the hpx::error code the new exception should encapsulate.msg: The parametermsgholds the error message the new exception should encapsulate.func: The name of the function where the error was raised.file: The file name of the code where the error was raised.line: The line number of the code line where the error was raised.mode: The parametermodespecifies whether the constructed hpx::error_code belongs to the error category hpx_category (if mode is plain, this is the default) or to the category hpx_category_rethrow (if mode is rethrow).
- Exceptions
std::bad_alloc: (if allocation of a copy of the passed string fails).
-
error_code(error e, std::string const &msg, throwmode mode = plain)¶ Construct an object of type error_code.
- Parameters
e: The parametereholds the hpx::error code the new exception should encapsulate.msg: The parametermsgholds the error message the new exception should encapsulate.mode: The parametermodespecifies whether the constructed hpx::error_code belongs to the error category hpx_category (if mode is plain, this is the default) or to the category hpx_category_rethrow (if mode is rethrow).
- Exceptions
std::bad_alloc: (if allocation of a copy of the passed string fails).
-
error_code(error e, std::string const &msg, char const *func, char const *file, long line, throwmode mode = plain)¶ Construct an object of type error_code.
- Parameters
e: The parametereholds the hpx::error code the new exception should encapsulate.msg: The parametermsgholds the error message the new exception should encapsulate.func: The name of the function where the error was raised.file: The file name of the code where the error was raised.line: The line number of the code line where the error was raised.mode: The parametermodespecifies whether the constructed hpx::error_code belongs to the error category hpx_category (if mode is plain, this is the default) or to the category hpx_category_rethrow (if mode is rethrow).
- Exceptions
std::bad_alloc: (if allocation of a copy of the passed string fails).
-
std::string
get_message() const¶ Return a reference to the error message stored in the hpx::error_code.
- Exceptions
nothing:
-
void
clear()¶ Clear this error_code object. The postconditions of invoking this method are.
value() == hpx::success and category() == hpx::get_hpx_category()
-
error_code(error_code const &rhs)¶ Copy constructor for error_code
- Note
This function maintains the error category of the left hand side if the right hand side is a success code.
-
error_code &
operator=(error_code const &rhs)¶ Assignment operator for error_code
- Note
This function maintains the error category of the left hand side if the right hand side is a success code.
Private Functions
-
error_code
-
namespace
hpx Typedefs
Functions
-
void
set_custom_exception_info_handler(custom_exception_info_handler_type f)¶
-
void
set_pre_exception_handler(pre_exception_handler_type f)¶
-
std::string
get_error_what(exception_info const &xi)¶ Return the error message of the thrown exception.
The function hpx::get_error_what can be used to extract the diagnostic information element representing the error message as stored in the given exception instance.
- Return
The error message stored in the exception If the exception instance does not hold this information, the function will return an empty string.
- See
hpx::diagnostic_information(), hpx::get_error_host_name(), hpx::get_error_process_id(), hpx::get_error_function_name(), hpx::get_error_file_name(), hpx::get_error_line_number(), hpx::get_error_os_thread(), hpx::get_error_thread_id(), hpx::get_error_thread_description(), hpx::get_error() hpx::get_error_backtrace(), hpx::get_error_env(), hpx::get_error_config(), hpx::get_error_state()
- Parameters
xi: The parameterewill be inspected for the requested diagnostic information elements which have been stored at the point where the exception was thrown. This parameter can be one of the following types: hpx::exception_info, hpx::error_code, std::exception, or std::exception_ptr.
- Exceptions
std::bad_alloc: (if one of the required allocations fails)
-
error
get_error(hpx::exception const &e)¶ Return the error code value of the exception thrown.
The function hpx::get_error can be used to extract the diagnostic information element representing the error value code as stored in the given exception instance.
- Return
The error value code of the locality where the exception was thrown. If the exception instance does not hold this information, the function will return hpx::naming::invalid_locality_id.
- See
hpx::diagnostic_information(), hpx::get_error_host_name(), hpx::get_error_process_id(), hpx::get_error_function_name(), hpx::get_error_file_name(), hpx::get_error_line_number(), hpx::get_error_os_thread(), hpx::get_error_thread_id(), hpx::get_error_thread_description(), hpx::get_error_backtrace(), hpx::get_error_env(), hpx::get_error_what(), hpx::get_error_config(), hpx::get_error_state()
- Parameters
e: The parameterewill be inspected for the requested diagnostic information elements which have been stored at the point where the exception was thrown. This parameter can be one of the following types: hpx::exception, hpx::error_code, or std::exception_ptr.
- Exceptions
nothing:
-
error
get_error(hpx::error_code const &e)¶
-
std::string
get_error_function_name(hpx::exception_info const &xi)¶ Return the function name from which the exception was thrown.
The function hpx::get_error_function_name can be used to extract the diagnostic information element representing the name of the function as stored in the given exception instance.
- Return
The name of the function from which the exception was thrown. If the exception instance does not hold this information, the function will return an empty string.
- See
hpx::diagnostic_information(), hpx::get_error_host_name(), hpx::get_error_process_id() hpx::get_error_file_name(), hpx::get_error_line_number(), hpx::get_error_os_thread(), hpx::get_error_thread_id(), hpx::get_error_thread_description(), hpx::get_error(), hpx::get_error_backtrace(), hpx::get_error_env(), hpx::get_error_what(), hpx::get_error_config(), hpx::get_error_state()
- Parameters
xi: The parameterewill be inspected for the requested diagnostic information elements which have been stored at the point where the exception was thrown. This parameter can be one of the following types: hpx::exception_info, hpx::error_code, std::exception, or std::exception_ptr.
- Exceptions
std::bad_alloc: (if one of the required allocations fails)
-
std::string
get_error_file_name(hpx::exception_info const &xi)¶ Return the (source code) file name of the function from which the exception was thrown.
The function hpx::get_error_file_name can be used to extract the diagnostic information element representing the name of the source file as stored in the given exception instance.
- Return
The name of the source file of the function from which the exception was thrown. If the exception instance does not hold this information, the function will return an empty string.
- See
hpx::diagnostic_information(), hpx::get_error_host_name(), hpx::get_error_process_id(), hpx::get_error_function_name(), hpx::get_error_line_number(), hpx::get_error_os_thread(), hpx::get_error_thread_id(), hpx::get_error_thread_description(), hpx::get_error(), hpx::get_error_backtrace(), hpx::get_error_env(), hpx::get_error_what(), hpx::get_error_config(), hpx::get_error_state()
- Parameters
xi: The parameterewill be inspected for the requested diagnostic information elements which have been stored at the point where the exception was thrown. This parameter can be one of the following types: hpx::exception_info, hpx::error_code, std::exception, or std::exception_ptr.
- Exceptions
std::bad_alloc: (if one of the required allocations fails)
-
long
get_error_line_number(hpx::exception_info const &xi)¶ Return the line number in the (source code) file of the function from which the exception was thrown.
The function hpx::get_error_line_number can be used to extract the diagnostic information element representing the line number as stored in the given exception instance.
- Return
The line number of the place where the exception was thrown. If the exception instance does not hold this information, the function will return -1.
- See
hpx::diagnostic_information(), hpx::get_error_host_name(), hpx::get_error_process_id(), hpx::get_error_function_name(), hpx::get_error_file_name() hpx::get_error_os_thread(), hpx::get_error_thread_id(), hpx::get_error_thread_description(), hpx::get_error(), hpx::get_error_backtrace(), hpx::get_error_env(), hpx::get_error_what(), hpx::get_error_config(), hpx::get_error_state()
- Parameters
xi: The parameterewill be inspected for the requested diagnostic information elements which have been stored at the point where the exception was thrown. This parameter can be one of the following types: hpx::exception_info, hpx::error_code, std::exception, or std::exception_ptr.
- Exceptions
nothing:
-
class
exception: public system_error¶ - #include <exception.hpp>
A hpx::exception is the main exception type used by HPX to report errors.
The hpx::exception type is the main exception type used by HPX to report errors. Any exceptions thrown by functions in the HPX library are either of this type or of a type derived from it. This implies that it is always safe to use this type only in catch statements guarding HPX library calls.
Subclassed by hpx::exception_list
Public Functions
-
exception(error e = success)¶ Construct a hpx::exception from a hpx::error.
- Parameters
e: The parametereholds the hpx::error code the new exception should encapsulate.
-
exception(std::system_error const &e)¶ Construct a hpx::exception from a boost::system_error.
-
exception(std::error_code const &e)¶ Construct a hpx::exception from a boost::system::error_code (this is new for Boost V1.69). This constructor is required to compensate for the changes introduced as a resolution to LWG3162 (https://cplusplus.github.io/LWG/issue3162).
-
exception(error e, char const *msg, throwmode mode = plain)¶ Construct a hpx::exception from a hpx::error and an error message.
- Parameters
e: The parametereholds the hpx::error code the new exception should encapsulate.msg: The parametermsgholds the error message the new exception should encapsulate.mode: The parametermodespecifies whether the returned hpx::error_code belongs to the error category hpx_category (if mode is plain, this is the default) or to the category hpx_category_rethrow (if mode is rethrow).
-
exception(error e, std::string const &msg, throwmode mode = plain)¶ Construct a hpx::exception from a hpx::error and an error message.
- Parameters
e: The parametereholds the hpx::error code the new exception should encapsulate.msg: The parametermsgholds the error message the new exception should encapsulate.mode: The parametermodespecifies whether the returned hpx::error_code belongs to the error category hpx_category (if mode is plain, this is the default) or to the category hpx_category_rethrow (if mode is rethrow).
-
~exception()¶ Destruct a hpx::exception
- Exceptions
nothing:
-
error
get_error() const¶ The function get_error() returns the hpx::error code stored in the referenced instance of a hpx::exception. It returns the hpx::error code this exception instance was constructed from.
- Exceptions
nothing:
-
error_code
get_error_code(throwmode mode = plain) const¶ The function get_error_code() returns a hpx::error_code which represents the same error condition as this hpx::exception instance.
- Parameters
mode: The parametermodespecifies whether the returned hpx::error_code belongs to the error category hpx_category (if mode is plain, this is the default) or to the category hpx_category_rethrow (if mode is rethrow).
-
-
struct
thread_interrupted: public exception¶ - #include <exception.hpp>
A hpx::thread_interrupted is the exception type used by HPX to interrupt a running HPX thread.
The hpx::thread_interrupted type is the exception type used by HPX to interrupt a running thread.
A running thread can be interrupted by invoking the interrupt() member function of the corresponding hpx::thread object. When the interrupted thread next executes one of the specified interruption points (or if it is currently blocked whilst executing one) with interruption enabled, then a hpx::thread_interrupted exception will be thrown in the interrupted thread. If not caught, this will cause the execution of the interrupted thread to terminate. As with any other exception, the stack will be unwound, and destructors for objects of automatic storage duration will be executed.
If a thread wishes to avoid being interrupted, it can create an instance of hpx::this_thread::disable_interruption. Objects of this class disable interruption for the thread that created them on construction, and restore the interruption state to whatever it was before on destruction.
void f() { // interruption enabled here { hpx::this_thread::disable_interruption di; // interruption disabled { hpx::this_thread::disable_interruption di2; // interruption still disabled } // di2 destroyed, interruption state restored // interruption still disabled } // di destroyed, interruption state restored // interruption now enabled }
The effects of an instance of hpx::this_thread::disable_interruption can be temporarily reversed by constructing an instance of hpx::this_thread::restore_interruption, passing in the hpx::this_thread::disable_interruption object in question. This will restore the interruption state to what it was when the hpx::this_thread::disable_interruption object was constructed, and then disable interruption again when the hpx::this_thread::restore_interruption object is destroyed.
void g() { // interruption enabled here { hpx::this_thread::disable_interruption di; // interruption disabled { hpx::this_thread::restore_interruption ri(di); // interruption now enabled } // ri destroyed, interruption disable again } // di destroyed, interruption state restored // interruption now enabled }
At any point, the interruption state for the current thread can be queried by calling hpx::this_thread::interruption_enabled().
-
void
-
namespace
hpx Enums
-
enum
throwmode¶ Encode error category for new error_code.
Values:
-
plain= 0¶
-
rethrow= 1¶
-
lightweight= 0x80¶
-
Variables
-
error_code
throws¶ Predefined error_code object used as “throw on error” tag.
The predefined hpx::error_code object hpx::throws is supplied for use as a “throw on error” tag.
Functions that specify an argument in the form ‘error_code& ec=throws’ (with appropriate namespace qualifiers), have the following error handling semantics:
If &ec != &throws and an error occurred: ec.value() returns the implementation specific error number for the particular error that occurred and ec.category() returns the error_category for ec.value().
If &ec != &throws and an error did not occur, ec.clear().
If an error occurs and &ec == &throws, the function throws an exception of type hpx::exception or of a type derived from it. The exception’s get_errorcode() member function returns a reference to an hpx::error_code object with the behavior as specified above.
-
enum
Defines
-
HPX_DEFINE_ERROR_INFO(NAME, TYPE)¶
-
namespace
hpx Functions
-
template<typename E>HPX_NORETURN void hpx::throw_with_info(E && e, exception_info && xi = exception_info ())
-
template<typename E>HPX_NORETURN void hpx::throw_with_info(E && e, exception_info const & xi)
-
template<typename
E>
exception_info *get_exception_info(E &e)¶
-
template<typename
E>
exception_info const *get_exception_info(E const &e)¶
-
template<typename
F>
autoinvoke_with_exception_info(hpx::error_code const &ec, F &&f)¶
-
class
exception_info¶ Subclassed by hpx::detail::exception_with_info_base
Public Functions
-
exception_info()¶
-
exception_info(exception_info const &other)¶
-
exception_info(exception_info &&other)¶
-
exception_info &
operator=(exception_info const &other)¶
-
exception_info &
operator=(exception_info &&other)¶
-
virtual
~exception_info()¶
-
template<typename ...
ErrorInfo>
exception_info &set(ErrorInfo&&... tagged_values)¶
-
-
-
namespace
hpx -
class
exception_list: public hpx::exception¶ - #include <exception_list.hpp>
The class exception_list is a container of exception_ptr objects parallel algorithms may use to communicate uncaught exceptions encountered during parallel execution to the caller of the algorithm
The type exception_list::const_iterator fulfills the requirements of a forward iterator.
Public Types
-
using
iterator= exception_list_type::const_iterator¶ bidirectional iterator
Public Functions
-
std::size_t
size() const¶ The number of exception_ptr objects contained within the exception_list.
- Note
Complexity: Constant time.
-
exception_list_type::const_iterator
begin() const¶ An iterator referring to the first exception_ptr object contained within the exception_list.
-
exception_list_type::const_iterator
end() const¶ An iterator which is the past-the-end value for the exception_list.
-
using
-
class
Defines
-
HPX_THROW_EXCEPTION(errcode, f, ...)¶ Throw a hpx::exception initialized from the given parameters.
The macro HPX_THROW_EXCEPTION can be used to throw a hpx::exception. The purpose of this macro is to prepend the source file name and line number of the position where the exception is thrown to the error message. Moreover, this associates additional diagnostic information with the exception, such as file name and line number, locality id and thread id, and stack backtrace from the point where the exception was thrown.
The parameter
errcodeholds the hpx::error code the new exception should encapsulate. The parameterfis expected to hold the name of the function exception is thrown from and the parametermsgholds the error message the new exception should encapsulate.void raise_exception() { // Throw a hpx::exception initialized from the given parameters. // Additionally associate with this exception some detailed // diagnostic information about the throw-site. HPX_THROW_EXCEPTION(hpx::no_success, "raise_exception", "simulated error"); }
- Example:
-
HPX_THROWS_IF(ec, errcode, f, ...)¶ Either throw a hpx::exception or initialize hpx::error_code from the given parameters.
The macro HPX_THROWS_IF can be used to either throw a hpx::exception or to initialize a hpx::error_code from the given parameters. If &ec == &hpx::throws, the semantics of this macro are equivalent to HPX_THROW_EXCEPTION. If &ec != &hpx::throws, the hpx::error_code instance
ecis initialized instead.The parameter
errcodeholds the hpx::error code from which the new exception should be initialized. The parameterfis expected to hold the name of the function exception is thrown from and the parametermsgholds the error message the new exception should encapsulate.
execution_base¶
The contents of this module can be included with the header
hpx/modules/execution_base.hpp. These headers may be used by user-code but are not
guaranteed stable (neither header location nor contents). You are using these at
your own risk. If you wish to use non-public functionality from a module we
strongly suggest only including the module header hpx/modules/execution_base.hpp, not
the particular header in which the functionality you would like to use is
defined. See Public API for a list of names that are part of the public
HPX API.
-
namespace
hpx -
namespace
execution_base¶ -
struct
agent_base¶ Public Functions
-
virtual
~agent_base()¶
-
virtual context_base const &
context() const = 0¶
-
virtual void
yield(char const *desc) = 0¶
-
virtual void
suspend(char const *desc) = 0¶
-
virtual void
resume(char const *desc) = 0¶
-
virtual void
abort(char const *desc) = 0¶
-
virtual void
sleep_for(hpx::chrono::steady_duration const &sleep_duration, char const *desc) = 0¶
-
virtual void
sleep_until(hpx::chrono::steady_time_point const &sleep_time, char const *desc) = 0¶
-
virtual
-
struct
-
namespace
-
namespace
hpx -
namespace
execution_base -
class
agent_ref¶ Public Functions
-
constexpr
agent_ref()¶
-
constexpr
agent_ref(agent_base *impl)¶
-
constexpr
operator bool() const¶
-
void
reset(agent_base *impl = nullptr)¶
-
void
yield(char const *desc = "hpx::execution_base::agent_ref::yield")¶
-
void
suspend(char const *desc = "hpx::execution_base::agent_ref::suspend")¶
-
void
resume(char const *desc = "hpx::execution_base::agent_ref::resume")¶
-
void
abort(char const *desc = "hpx::execution_base::agent_ref::abort")¶
-
template<typename
Rep, typenamePeriod>
voidsleep_for(std::chrono::duration<Rep, Period> const &sleep_duration, char const *desc = "hpx::execution_base::agent_ref::sleep_for")¶
-
template<typename
Clock, typenameDuration>
voidsleep_until(std::chrono::time_point<Clock, Duration> const &sleep_time, char const *desc = "hpx::execution_base::agent_ref::sleep_until")¶
-
agent_base &
ref()¶
Private Functions
-
void
sleep_for(hpx::chrono::steady_duration const &sleep_duration, char const *desc)¶
-
void
sleep_until(hpx::chrono::steady_time_point const &sleep_time, char const *desc)¶
Private Members
-
agent_base *
impl_¶
-
constexpr
-
class
-
namespace
-
namespace
hpx -
namespace
execution_base -
struct
context_base¶
-
struct
-
namespace
-
namespace
hpx -
namespace
execution¶ -
namespace
experimental¶ Functions
-
template<typename
O>
voidstart(O &&o)¶ start is a customization point object. The expression
hpx::execution::experimental::start(r)is equivalent to:r.start(), if that expression is valid. If the function selected does not signal the receiverr’s done channel, the program is ill-formed (no diagnostic required).Otherwise, `start(r), if that expression is valid, with overload resolution performed in a context that include the declaration
void start();Otherwise, the expression is ill-formed.
The customization is implemented in terms of
hpx::functional::tag_dispatch.
Variables
-
hpx::execution::experimental::start_t
start¶
-
template<typename O>HPX_INLINE_CONSTEXPR_VARIABLE bool hpx::execution::experimental::is_operation_state_v=is_operation_state<O>::value
-
template<typename
O>
structis_operation_state¶ - #include <operation_state.hpp>
An
operation_stateis an object representing the asynchronous operation that has been returned from callinghpx::execution::experimental::connectwith asenderand areceiver. The only operation on anoperation_stateis:hpx::execution::experimental::start
hpx::execution::experimental::startcan be called exactly once. Once it has been invoked, the caller needs to ensure that the receiver’s completion signaling operations strongly happen before the destructor of the state is called. The call tohpx::execution::experimental::startneeds to happen strongly before the completion signaling operations.
-
struct
start_t: public hpx::functional::tag_priority_noexcept<start_t>¶ Friends
-
template<typename
OperationState>
friend constexpr autotag_override_dispatch(start_t, OperationState &o)¶
-
template<typename
-
template<typename
-
namespace
-
namespace
-
namespace
hpx -
namespace
execution -
namespace
experimental Functions
-
template<typename
R, typename ...As>
voidset_value(R &&r, As&&... as)¶ set_value is a customization point object. The expression
hpx::execution::set_value(r, as...)is equivalent to:r.set_value(as...), if that expression is valid. If the function selected does not send the value(s)as...to the Receiverr’s value channel, the program is ill-formed (no diagnostic required).Otherwise, `set_value(r, as…), if that expression is valid, with overload resolution performed in a context that include the declaration
void set_value();Otherwise, the expression is ill-formed.
The customization is implemented in terms of
hpx::functional::tag_dispatch.
-
template<typename
R>
voidset_done(R &&r)¶ set_done is a customization point object. The expression
hpx::execution::set_done(r)is equivalent to:r.set_done(), if that expression is valid. If the function selected does not signal the Receiverr’s done channel, the program is ill-formed (no diagnostic required).Otherwise, `set_done(r), if that expression is valid, with overload resolution performed in a context that include the declaration
void set_done();Otherwise, the expression is ill-formed.
The customization is implemented in terms of
hpx::functional::tag_dispatch.
-
template<typename
R, typenameE>
voidset_error(R &&r, E &&e)¶ set_error is a customization point object. The expression
hpx::execution::set_error(r, e)is equivalent to:r.set_done(e), if that expression is valid. If the function selected does not send the errorethe Receiverr’s error channel, the program is ill-formed (no diagnostic required).Otherwise, `set_error(r, e), if that expression is valid, with overload resolution performed in a context that include the declaration
void set_error();Otherwise, the expression is ill-formed.
The customization is implemented in terms of
hpx::functional::tag_dispatch.
Variables
-
hpx::execution::experimental::set_value_t
set_value¶
-
hpx::execution::experimental::set_error_t
set_error¶
-
hpx::execution::experimental::set_done_t
set_done¶
-
template<typename T, typename E = std::exception_ptr>HPX_INLINE_CONSTEXPR_VARIABLE bool hpx::execution::experimental::is_receiver_v = is_receiver<T, E>::value
-
template<typename T, typename... As>HPX_INLINE_CONSTEXPR_VARIABLE bool hpx::execution::experimental::is_receiver_of_v=is_receiver_of<T, As...>::value
-
template<typename T, typename... As>HPX_INLINE_CONSTEXPR_VARIABLE bool hpx::execution::experimental::is_nothrow_receiver_of_v=is_nothrow_receiver_of<T, As...>::value
-
template<typename
T, typenameE>
structis_receiver¶ - #include <receiver.hpp>
Receiving values from asynchronous computations is handled by the
Receiverconcept. AReceiverneeds to be able to receive an error or be marked as being canceled. As such, the Receiver concept is defined by having the following two customization points defined, which form the completion-signal operations:hpx::execution::experimental::set_donehpx::execution::experimental::set_error
Those two functions denote the completion-signal operations. The Receiver contract is as follows:
None of a Receiver’s completion-signal operation shall be invoked before
hpx::execution::experimental::starthas been called on the operation state object that was returned by connecting a Receiver to a senderhpx::execution::experimental::connect.Once
hpx::execution::starthas been called on the operation state object, exactly one of the Receiver’s completion-signal operation shall complete without an exception before the Receiver is destroyed
Once one of the Receiver’s completion-signal operation has been completed without throwing an exception, the Receiver contract has been satisfied. In other words: The asynchronous operation has been completed.
-
template<typename
T, typename ...As>
structis_receiver_of¶ - #include <receiver.hpp>
The
receiver_ofconcept is a refinement of theReceiverconcept by requiring one additional completion-signal operation:hpx::execution::set_value
This completion-signal operation adds the following to the Receiver’s contract:
If
hpx::execution::set_valueexits with an exception, it is still valid to callhpx::execution::set_errororhpx::execution::set_done
- See
hpx::execution::traits::is_receiver
-
struct
set_done_t: public hpx::functional::tag_priority_noexcept<set_done_t>¶
-
struct
set_error_t: public hpx::functional::tag_priority_noexcept<set_error_t>¶
-
struct
set_value_t: public hpx::functional::tag_priority<set_value_t>¶
-
template<typename
-
namespace
-
namespace
-
namespace
hpx -
namespace
util Functions
-
constexpr bool
unregister_lock(void const*)¶
-
constexpr void
verify_no_locks()¶
-
constexpr void
force_error_on_lock()¶
-
constexpr void
enable_lock_detection()¶
-
constexpr void
disable_lock_detection()¶
-
constexpr void
ignore_lock(void const*)¶
-
constexpr void
reset_ignored(void const*)¶
-
constexpr void
ignore_all_locks()¶
-
constexpr void
reset_ignored_all()¶
-
constexpr bool
-
namespace
-
namespace
hpx
-
namespace
hpx -
namespace
execution -
namespace
experimental Typedefs
Functions
-
template<typename
E, typenameF>
voidexecute(E &&e, F &&f)¶ execute is a customization point object. For some subexpression
eandf, letEbedecltype((e))and letFbedecltype((F)). The expressionexecute(e, f)is ill-formed ifFdoes not modelinvocable, or ifEdoes not model eitherexecutororsender. The result of the expressionhpx::execution::experimental::execute(e, f)is then equivalent to:e.execute(f), if that expression is valid. If the function selected does not execute the function objectfon the executore, the program is ill-formed with no diagnostic required.Otherwise,
execute(e, f), if that expression is valid, with overload resolution performed in a context that includes the declarationvoid execute();and that does not include a declaration ofhpx::execution::experimental::execute. If the function selected by overload resolution does not execute the function objectfon the executore, the program is ill-formed with no diagnostic required.Otherwise, execution::submit(e, as-receiver<remove_cvref_t<F>, E>{forward<F>(f)}) if
F is not an instance of as-invocable<R,E’> for some type R where E and E’ name the same type ignoring cv and reference qualifiers, and
invocable<remove_cvref_t<F>&> && sender_to<E, as-receiver<remove_cvref_t<F>, E>> is true
where as-receiver is some implementation-defined class template equivalent to:
template<class F, class> struct as-receiver { F f_; void set_value() noexcept(is_nothrow_invocable_v<F&>) { invoke(f_); } template<class E> [[noreturn]] void set_error(E&&) noexcept { terminate(); } void set_done() noexcept {} };
The customization is implemented in terms of
hpx::functional::tag_dispatch.
-
template<typename
S, typenameR>
voidconnect(S &&s, R &&r)¶ connect is a customization point object. For some subexpression
sandr, letSbe the type such thatdecltype((s))isSand letRbe the type such thatdecltype((r))isR. The result of the expressionhpx::execution::experimental::connect(s, r)is then equivalent to:s.connect(r), if that expression is valid and returns a type satisfying theoperation_state(- See
hpx::execution::experimental::traits::is_operation_state) and if
Ssatisfies thesenderconcept.
s.connect(r), if that expression is valid and returns a type satisfying theoperation_state(- See
hpx::execution::experimental::traits::is_operation_state) and if
Ssatisfies thesenderconcept. Overload resolution is performed in a context that include the declarationvoid connect();
Otherwise, as-operation{s, r}, if
r is not an instance of as-receiver<F, S’> for some type F where S and S’ name the same type ignoring cv and reference qualifiers, and
receiver_of<R> && executor-of-impl<remove_cvref_t
-
template<typename
S, typenameR>
autosubmit(S &&s, R &&r)¶ The name submit denotes a customization point object.
For some subexpressions s and r, let S be decltype((s)) and let R be decltype((r)). The expression submit(s, r) is ill-formed if sender_to<S, R> is not true. Otherwise, it is expression-equivalent to:
* s.submit(r), if that expression is valid and S models sender. If the function selected does not submit the receiver object r via the sender s, the program is ill-formed with no diagnostic required. * Otherwise, submit(s, r), if that expression is valid and S models sender, with overload resolution performed in a context that includes the declaration void submit(); and that does not include a declaration of execution::submit. If the function selected by overload resolution does not submit the receiver object r via the sender s, the program is ill-formed with no diagnostic required. * Otherwise, start((newsubmit-state<S, R>{s,r})->state_), where submit-state is an implementation-defined class template equivalent to template<class S, class R> struct submit-state { struct submit-receiver { submit-state * p_; template<class...As> requires receiver_of<R, As...> void set_value(As&&... as) && noexcept(is_nothrow_receiver_of_v<R, As...>) { set_value(std::move(p_->r_), (As&&) as...); delete p_; } template<class E> requires receiver<R, E> void set_error(E&& e) && noexcept { set_error(std::move(p_->r_), (E&&) e); delete p_; } void set_done() && noexcept { set_done(std::move(p_->r_)); delete p_; } }; remove_cvref_t<R> r_; connect_result_t<S, submit-receiver> state_; submit-state(S&& s, R&& r) : r_((R&&) r) , state_(connect((S&&) s, submit-receiver{this})) {} };
The customization is implemented in terms of
hpx::functional::tag_dispatch.
Variables
-
template<typename Sender>HPX_INLINE_CONSTEXPR_VARIABLE bool hpx::execution::experimental::is_sender_v = is_sender<Sender>::value
-
hpx::execution::experimental::execute_t
execute¶
-
hpx::execution::experimental::connect_t
connect¶
-
hpx::execution::experimental::submit_t
submit¶
-
template<typename Executor>HPX_INLINE_CONSTEXPR_VARIABLE bool hpx::execution::experimental::is_executor_v=is_executor<Executor>::value
-
template<typename Executor, typename F>HPX_INLINE_CONSTEXPR_VARIABLE bool hpx::execution::experimental::is_executor_of_v=is_executor_of<Executor, F>::value
-
hpx::execution::experimental::schedule_t
schedule¶
-
template<typename Scheduler>HPX_INLINE_CONSTEXPR_VARIABLE bool hpx::execution::experimental::is_scheduler_v=is_scheduler<Scheduler>::value
-
struct
connect_t: public hpx::functional::tag_priority<connect_t>¶
-
struct
execute_t: public hpx::functional::tag_priority<execute_t>¶
-
template<typename
Sender>
structis_sender¶ - #include <sender.hpp>
The name schedule denotes a customization point object. For some subexpression s, let S be decltype((s)). The expression schedule(s) is expression-equivalent to:
* s.schedule(), if that expression is valid and its type models sender. * Otherwise, schedule(s), if that expression is valid and its type models sender with overload resolution performed in a context that includes the declaration void schedule(); and that does not include a declaration of schedule. * Otherwise, as-sender<remove_cvref_t<S>>{s} if S satisfies executor, where as-sender is an implementation-defined class template equivalent to template<class E> struct as-sender { private: E ex_; public: template<template<class...> class Tuple, template<class...> class Variant> using value_types = Variant<Tuple<>>; template<template<class...> class Variant> using error_types = Variant<std::exception_ptr>; static constexpr bool sends_done = true; explicit as-sender(E e) noexcept : ex_((E&&) e) {} template<class R> requires receiver_of<R> connect_result_t<E, R> connect(R&& r) && { return connect((E&&) ex_, (R&&) r); } template<class R> requires receiver_of<R> connect_result_t<const E &, R> connect(R&& r) const & { return connect(ex_, (R&&) r); } }; * Otherwise, schedule(s) is ill-formed.
The customization is implemented in terms of
hpx::functional::tag_dispatch. A sender is a type that is describing an asynchronous operation. The operation itself might not have started yet. In order to get the result of this asynchronous operation, a sender needs to be connected to a receiver with the corresponding value, error and done channels:hpx::execution::experimental::connect
In addition,
hpx::execution::experimental::::sender_traitsneeds to be specialized in some form.A sender’s destructor shall not block pending completion of submitted operations.
-
struct
schedule_t: public hpx::functional::tag_priority<schedule_t>¶
-
template<typename
Sender>
structsender_traits¶ - #include <sender.hpp>
sender_traitsexpose the different value and error types exposed by a sender. This can be either specialized directly for user defined sender types or embedded value_types, error_types and sends_done inside the sender type can be provided.Subclassed by hpx::execution::experimental::sender_traits< Sender & >, hpx::execution::experimental::sender_traits< Sender && >, hpx::execution::experimental::sender_traits< Sender const >, hpx::execution::experimental::sender_traits< Sender volatile >
-
struct
submit_t: public hpx::functional::tag_priority<submit_t>¶ Public Members
-
hpx::execution::experimental::submit_t::state{ start((new detail::submit_state<S, R>{ std::forward<S>(s), std::forward<R>(r)}) ->state)
-
-
template<typename
-
namespace
-
namespace
-
namespace
hpx -
namespace
execution_base -
namespace
this_thread¶ Functions
-
hpx::execution_base::agent_ref
agent()¶
-
void
yield(char const *desc = "hpx::execution_base::this_thread::yield")¶
-
void
suspend(char const *desc = "hpx::execution_base::this_thread::suspend")¶
-
struct
reset_agent¶ Public Functions
-
reset_agent(detail::agent_storage*, agent_base &impl)¶
-
reset_agent(agent_base &impl)¶
-
~reset_agent()¶
-
-
hpx::execution_base::agent_ref
-
namespace
-
namespace
util
-
namespace
-
namespace
hpx -
namespace
traits Typedefs
Variables
-
template<typename T>HPX_INLINE_CONSTEXPR_VARIABLE bool hpx::traits::is_one_way_executor_v=is_one_way_executor<T>::value
-
template<typename T>HPX_INLINE_CONSTEXPR_VARIABLE bool hpx::traits::is_never_blocking_one_way_executor_v=is_never_blocking_one_way_executor<T>::value
-
template<typename T>HPX_INLINE_CONSTEXPR_VARIABLE bool hpx::traits::is_bulk_one_way_executor_v=is_bulk_one_way_executor<T>::value
-
template<typename T>HPX_INLINE_CONSTEXPR_VARIABLE bool hpx::traits::is_two_way_executor_v=is_two_way_executor<T>::value
-
template<typename T>HPX_INLINE_CONSTEXPR_VARIABLE bool hpx::traits::is_bulk_two_way_executor_v=is_bulk_two_way_executor<T>::value
-
template<typename T>HPX_INLINE_CONSTEXPR_VARIABLE bool hpx::traits::is_executor_any_v=is_executor_any<T>::value
-
-
namespace
-
template<typename
Executor>
structextract_executor_parameters<Executor, typename hpx::util::always_void<typename Executor::executor_parameters_type>::type>¶ Public Types
-
template<>
usingtype= typename Executor::executor_parameters_type¶
-
template<>
-
template<typename
Parameters>
structextract_has_variable_chunk_size<Parameters, typename hpx::util::always_void<typename Parameters::has_variable_chunk_size>::type>¶ Public Types
-
template<>
usingtype= typename Parameters::has_variable_chunk_size¶
-
template<>
-
namespace
hpx -
namespace
parallel¶ -
namespace
execution¶ Typedefs
Variables
-
template<typename T>HPX_INLINE_CONSTEXPR_VARIABLE bool hpx::parallel::execution::is_executor_parameters_v=is_executor_parameters<T>::value
-
template<typename
Executor, typenameEnable= void>
structextract_executor_parameters¶ Public Types
-
template<>
usingtype= sequential_executor_parameters¶
-
template<>
-
template<typename
Executor>
structextract_executor_parameters<Executor, typename hpx::util::always_void<typename Executor::executor_parameters_type>::type> Public Types
-
template<>
usingtype= typename Executor::executor_parameters_type
-
template<>
-
template<typename
Parameters, typenameEnable= void>
structextract_has_variable_chunk_size¶
-
template<typename
Parameters>
structextract_has_variable_chunk_size<Parameters, typename hpx::util::always_void<typename Parameters::has_variable_chunk_size>::type> Public Types
-
template<>
usingtype= typename Parameters::has_variable_chunk_size
-
template<>
-
-
namespace
-
namespace
filesystem¶
The contents of this module can be included with the header
hpx/modules/filesystem.hpp. These headers may be used by user-code but are not
guaranteed stable (neither header location nor contents). You are using these at
your own risk. If you wish to use non-public functionality from a module we
strongly suggest only including the module header hpx/modules/filesystem.hpp, not
the particular header in which the functionality you would like to use is
defined. See Public API for a list of names that are part of the public
HPX API.
This file provides a compatibility layer using Boost.Filesystem for the C++17 filesystem library. It is not intended to be a complete compatibility layer. It only contains functions required by the HPX codebase. It also provides some functions only available in Boost.Filesystem when using C++17 filesystem.
-
namespace
hpx -
namespace
filesystem¶
-
namespace
format¶
The contents of this module can be included with the header
hpx/modules/format.hpp. These headers may be used by user-code but are not
guaranteed stable (neither header location nor contents). You are using these at
your own risk. If you wish to use non-public functionality from a module we
strongly suggest only including the module header hpx/modules/format.hpp, not
the particular header in which the functionality you would like to use is
defined. See Public API for a list of names that are part of the public
HPX API.
Defines
-
DECL_TYPE_SPECIFIER(Type, Spec)¶
-
namespace
hpx -
namespace
util
-
namespace
-
namespace
hpx -
namespace
util -
class
bad_lexical_cast: public bad_cast¶
-
class
-
namespace
-
namespace
hpx -
namespace
util
-
namespace
-
namespace
hpx -
namespace
util
-
namespace
functional¶
The contents of this module can be included with the header
hpx/modules/functional.hpp. These headers may be used by user-code but are not
guaranteed stable (neither header location nor contents). You are using these at
your own risk. If you wish to use non-public functionality from a module we
strongly suggest only including the module header hpx/modules/functional.hpp, not
the particular header in which the functionality you would like to use is
defined. See Public API for a list of names that are part of the public
HPX API.
-
namespace
hpx -
namespace
serialization
-
namespace
util Functions
-
namespace
placeholders¶ Variables
-
HPX_INLINE_CONSTEXPR_VARIABLE detail::placeholder<1> hpx::util::placeholders::_1 = {}
-
HPX_INLINE_CONSTEXPR_VARIABLE detail::placeholder<2> hpx::util::placeholders::_2 = {}
-
HPX_INLINE_CONSTEXPR_VARIABLE detail::placeholder<3> hpx::util::placeholders::_3 = {}
-
HPX_INLINE_CONSTEXPR_VARIABLE detail::placeholder<4> hpx::util::placeholders::_4 = {}
-
HPX_INLINE_CONSTEXPR_VARIABLE detail::placeholder<5> hpx::util::placeholders::_5 = {}
-
HPX_INLINE_CONSTEXPR_VARIABLE detail::placeholder<6> hpx::util::placeholders::_6 = {}
-
HPX_INLINE_CONSTEXPR_VARIABLE detail::placeholder<7> hpx::util::placeholders::_7 = {}
-
HPX_INLINE_CONSTEXPR_VARIABLE detail::placeholder<8> hpx::util::placeholders::_8 = {}
-
HPX_INLINE_CONSTEXPR_VARIABLE detail::placeholder<9> hpx::util::placeholders::_9 = {}
-
-
namespace
-
namespace
-
namespace
hpx -
namespace
serialization
-
namespace
util
-
namespace
-
namespace
hpx -
namespace
serialization
-
namespace
util
-
namespace
-
namespace
hpx -
namespace
serialization
-
namespace
util
-
namespace
Defines
-
HPX_UTIL_REGISTER_FUNCTION_DECLARATION(Sig, F, Name)¶
-
HPX_UTIL_REGISTER_FUNCTION(Sig, F, Name)¶
-
namespace
hpx -
namespace
util -
-
template<typename
R, typename ...Ts, boolSerializable>
classfunction<R(Ts...), Serializable> : public detail::basic_function<R(Ts...), true, Serializable>¶ Public Types
-
template<>
usingresult_type= R¶
Public Functions
-
function &
operator=(function const&)¶
-
function &
operator=(function&&)¶
Private Types
-
template<>
usingbase_type= detail::basic_function<R(Ts...), true, Serializable>¶
-
template<>
-
template<typename
-
namespace
-
namespace
hpx -
namespace
util -
template<typename
R, typename ...Ts>
classfunction_ref<R(Ts...)>¶ Public Functions
-
template<typename
F, typenameFD= typename std::decay<F>::type, typenameEnable= typename std::enable_if<!std::is_same<FD, function_ref>::value && is_invocable_r_v<R, F&, Ts...>>::type>function_ref(F &&f)¶
-
function_ref(function_ref const &other)¶
-
template<typename
F, typenameFD= typename std::decay<F>::type, typenameEnable= typename std::enable_if<!std::is_same<FD, function_ref>::value && is_invocable_r_v<R, F&, Ts...>>::type>
function_ref &operator=(F &&f)¶
-
function_ref &
operator=(function_ref const &other)¶
-
template<typename
F, typenameT= typename std::remove_reference<F>::type, typenameEnable= typename std::enable_if<!std::is_pointer<T>::value>::type>
voidassign(F &&f)¶
-
void
swap(function_ref &f)¶
-
R
operator()(Ts... vs) const¶
-
char const *
get_function_annotation() const¶
-
util::itt::string_handle
get_function_annotation_itt() const¶
Private Types
-
template<>
usingVTable= detail::function_ref_vtable<R(Ts...)>¶
Private Static Functions
-
template<typename
T>
static VTable const *get_vtable()¶
-
template<typename
-
template<typename
-
namespace
Defines
-
HPX_INVOKE_R(R, F, ...)¶
-
namespace
hpx -
namespace
util Functions
-
template<typename
F, typename ...Ts>
constexpr util::invoke_result<F, Ts...>::typeinvoke(F &&f, Ts&&... vs)¶ Invokes the given callable object f with the content of the argument pack vs
- Return
The result of the callable object when it’s called with the given argument types.
- Note
This function is similar to
std::invoke(C++17)- Parameters
f: Requires to be a callable object. If f is a member function pointer, the first argument in the pack will be treated as the callee (this object).vs: An arbitrary pack of arguments
- Exceptions
std::exception: like objects thrown by call to object f with the argument types vs.
-
template<typename
-
namespace
-
namespace
hpx -
namespace
util Functions
-
template<typename
F, typenameTuple>
constexpr detail::invoke_fused_result<F, Tuple>::typeinvoke_fused(F &&f, Tuple &&t)¶ Invokes the given callable object f with the content of the sequenced type t (tuples, pairs)
- Return
The result of the callable object when it’s called with the content of the given sequenced type.
- Note
This function is similar to
std::apply(C++17)- Parameters
f: Must be a callable object. If f is a member function pointer, the first argument in the sequenced type will be treated as the callee (this object).t: A type which is content accessible through a call to hpx::util::get.
- Exceptions
std::exception: like objects thrown by call to object f with the arguments contained in the sequenceable type t.
-
template<typename
-
namespace
-
namespace
hpx -
namespace
util
-
namespace
-
namespace
hpx -
namespace
util
-
namespace
-
namespace
hpx -
namespace
serialization
-
namespace
util
-
namespace
-
namespace
hpx -
namespace
util
-
namespace
-
namespace
hpx -
namespace
functional¶ Typedefs
-
template<typename
Tag, typename ...Args>
usingtag_dispatch_result= invoke_result<decltype(tag_dispatch), Tag, Args...>¶ hpx::functional::tag_dispatch_result<Tag, Args...>is the trait returning the result type of the call hpx::functioanl::tag_dispatch. This can be used in a SFINAE context.
-
template<typename
Tag, typename ...Args>
usingtag_dispatch_result_t= typename tag_dispatch_result<Tag, Args...>::type¶ hpx::functional::tag_dispatch_result_t<Tag, Args...>evaluates tohpx::functional::tag_dispatch_result_t<Tag, Args...>::type
Variables
-
constexpr unspecified
tag_dispatch= unspecified¶ The
hpx::functional::tag_dispatchname defines a constexpr object that is invocable with one or more arguments. The first argument is a ‘tag’ (typically a DPO). It is only invocable if an overload of tag_dispatch() that accepts the same arguments could be found via ADL.The evaluation of the expression
hpx::tag_dispatch(tag, args...)is equivalent to evaluating the unqualified call totag_dispatch(decay-copy(tag), std::forward<Args>(args)...).hpx::functional::tag_dispatchis implemented against P1895.Example: Defining a new customization point
foo:namespace mylib { inline constexpr struct foo_fn final : hpx::functional::tag<foo_fn> { } foo{}; }
Defining an object
barwhich customizesfoo:struct bar { int x = 42; friend constexpr int tag_dispatch(mylib::foo_fn, bar const& x) { return b.x; } };
Using the customization point:
static_assert(42 == mylib::foo(bar{}), "The answer is 42");
-
template<typename
Tag, typename ...Args>
constexpr boolis_tag_dispatchable_v= is_tag_dispatchable<Tag, Args...>::value¶ hpx::functional::is_tag_dispatchable_v<Tag, Args...>evaluates tohpx::functional::is_tag_dispatchable<Tag, Args...>::value
-
template<typename
Tag, typename ...Args>
constexpr boolis_nothrow_tag_dispatchable_v= is_nothrow_tag_dispatchable<Tag, Args...>::value¶ hpx::functional::is_tag_dispatchable_v<Tag, Args...>evaluates tohpx::functional::is_tag_dispatchable<Tag, Args...>::value
-
template<typename
Tag, typename ...Args>
structis_nothrow_tag_dispatchable¶ - #include <tag_dispatch.hpp>
hpx::functional::is_nothrow_tag_dispatchable<Tag, Args...>is std::true_type if an overload oftag_dispatch(tag, args...)can be found via ADL and is noexcept.
-
template<typename
Tag, typename ...Args>
structis_tag_dispatchable¶ - #include <tag_dispatch.hpp>
hpx::functional::is_tag_dispatchable<Tag, Args...>is std::true_type if an overload oftag_dispatch(tag, args...)can be found via ADL.
-
template<typename
Tag>
structtag¶ - #include <tag_dispatch.hpp>
hpx::functional::tag<Tag>defines a base class that implements the necessary tag dispatching functionality for a given typeTag
-
template<typename
Tag>
structtag_noexcept¶ - #include <tag_dispatch.hpp>
hpx::functional::tag_noexcept<Tag>defines a base class that implements the necessary tag dispatching functionality for a given typeTagThe implementation has to be noexcept
-
template<typename
-
namespace
-
namespace
hpx -
namespace
functional Typedefs
-
template<typename
Tag, typename ...Args>
usingtag_fallback_dispatch_result= invoke_result<decltype(tag_fallback_dispatch), Tag, Args...>¶ hpx::functional::tag_fallback_dispatch_result<Tag, Args...>is the trait returning the result type of the call hpx::functioanl::tag_fallback_dispatch. This can be used in a SFINAE context.
-
template<typename
Tag, typename ...Args>
usingtag_fallback_dispatch_result_t= typename tag_fallback_dispatch_result<Tag, Args...>::type¶ hpx::functional::tag_fallback_dispatch_result_t<Tag, Args...>evaluates tohpx::functional::tag_fallback_dispatch_result_t<Tag, Args...>::type
Variables
-
constexpr unspecified
tag_fallback_dispatch= unspecified¶ The
hpx::functional::tag_fallback_dispatchname defines a constexpr object that is invocable with one or more arguments. The first argument is a ‘tag’ (typically a DPO). It is only invocable if an overload of tag_fallback_dispatch() that accepts the same arguments could be found via ADL.The evaluation of the expression
hpx::functional::tag_fallback_dispatch(tag, args...)is equivalent to evaluating the unqualified call totag_fallback_dispatch(decay-copy(tag), std::forward<Args>(args)...).hpx::functional::tag_fallback_dispatchis implemented against P1895.Example: Defining a new customization point
foo:namespace mylib { inline constexpr struct foo_fn final : hpx::functional::tag_fallback<foo_fn> { } foo{}; }
Defining an object
barwhich customizesfoo:struct bar { int x = 42; friend constexpr int tag_fallback_dispatch(mylib::foo_fn, bar const& x) { return b.x; } };
Using the customization point:
static_assert(42 == mylib::foo(bar{}), "The answer is 42");
-
template<typename
Tag, typename ...Args>
constexpr boolis_tag_fallback_dispatchable_v= is_tag_fallback_dispatchable<Tag, Args...>::value¶ hpx::functional::is_tag_fallback_dispatchable_v<Tag, Args...>evaluates tohpx::functional::is_tag_fallback_dispatchable<Tag, Args...>::value
-
template<typename
Tag, typename ...Args>
constexpr boolis_nothrow_tag_fallback_dispatchable_v= is_nothrow_tag_fallback_dispatchable<Tag, Args...>::value¶ hpx::functional::is_tag_fallback_dispatchable_v<Tag, Args...>evaluates tohpx::functional::is_tag_fallback_dispatchable<Tag, Args...>::value
-
template<typename
Tag, typename ...Args>
structis_nothrow_tag_fallback_dispatchable¶ - #include <tag_fallback_dispatch.hpp>
hpx::functional::is_nothrow_tag_fallback_dispatchable<Tag, Args...>is std::true_type if an overload oftag_fallback_dispatch(tag, args...)can be found via ADL and is noexcept.
-
template<typename
Tag, typename ...Args>
structis_tag_fallback_dispatchable¶ - #include <tag_fallback_dispatch.hpp>
hpx::functional::is_tag_fallback_dispatchable<Tag, Args...>is std::true_type if an overload oftag_fallback_dispatch(tag, args...)can be found via ADL.
-
template<typename
Tag>
structtag_fallback¶ - #include <tag_fallback_dispatch.hpp>
hpx::functional::tag_fallback<Tag>defines a base class that implements the necessary tag dispatching functionality for a given typeTag
-
template<typename
Tag>
structtag_fallback_noexcept¶ - #include <tag_fallback_dispatch.hpp>
hpx::functional::tag_fallback_noexcept<Tag>defines a base class that implements the necessary tag dispatching functionality for a given typeTagwhere the implementation is required to be noexcept
-
template<typename
-
namespace
-
namespace
hpx -
namespace
functional Typedefs
-
template<typename
Tag, typename ...Args>
usingtag_override_dispatch_result= invoke_result<decltype(tag_override_dispatch), Tag, Args...>¶ hpx::functional::tag_override_dispatch_result<Tag, Args...>is the trait returning the result type of the call hpx::functioanl::tag_override_dispatch. This can be used in a SFINAE context.
-
template<typename
Tag, typename ...Args>
usingtag_override_dispatch_result_t= typename tag_override_dispatch_result<Tag, Args...>::type¶ hpx::functional::tag_override_dispatch_result_t<Tag, Args...>evaluates tohpx::functional::tag_override_dispatch_result_t<Tag, Args...>::type
Variables
-
constexpr unspecified
tag_override_dispatch= unspecified¶ The
hpx::functional::tag_override_dispatchname defines a constexpr object that is invocable with one or more arguments. The first argument is a ‘tag’ (typically a DPO). It is only invocable if an overload of tag_override_dispatch() that accepts the same arguments could be found via ADL.The evaluation of the expression
hpx::functional::tag_override_dispatch(tag, args...)is equivalent to evaluating the unqualified call totag_override_dispatch(decay-copy(tag), std::forward<Args>(args)...).hpx::functional::tag_override_dispatchis implemented against P1895.Example: Defining a new customization point
foo:namespace mylib { inline constexpr struct foo_fn final : hpx::functional::tag_override<foo_fn> { } foo{}; }
Defining an object
barwhich customizesfoo:struct bar { int x = 42; friend constexpr int tag_override_dispatch(mylib::foo_fn, bar const& x) { return b.x; } };
Using the customization point:
static_assert(42 == mylib::foo(bar{}), "The answer is 42");
-
template<typename
Tag, typename ...Args>
constexpr boolis_tag_override_dispatchable_v= is_tag_override_dispatchable<Tag, Args...>::value¶ hpx::functional::is_tag_override_dispatchable_v<Tag, Args...>evaluates tohpx::functional::is_tag_override_dispatchable<Tag, Args...>::value
-
template<typename
Tag, typename ...Args>
constexpr boolis_nothrow_tag_override_dispatchable_v= is_nothrow_tag_override_dispatchable<Tag, Args...>::value¶ hpx::functional::is_tag_override_dispatchable_v<Tag, Args...>evaluates tohpx::functional::is_tag_override_dispatchable<Tag, Args...>::value
-
template<typename
Tag, typename ...Args>
structis_nothrow_tag_override_dispatchable¶ - #include <tag_priority_dispatch.hpp>
hpx::functional::is_nothrow_tag_override_dispatchable<Tag, Args...>is std::true_type if an overload oftag_override_dispatch(tag, args...)can be found via ADL and is noexcept.
-
template<typename
Tag, typename ...Args>
structis_tag_override_dispatchable¶ - #include <tag_priority_dispatch.hpp>
hpx::functional::is_tag_override_dispatchable<Tag, Args...>is std::true_type if an overload oftag_override_dispatch(tag, args...)can be found via ADL.
-
template<typename
Tag>
structtag_override¶ - #include <tag_priority_dispatch.hpp>
hpx::functional::tag_override<Tag>defines a base class that implements the necessary tag dispatching functionality for a given typeTag
-
template<typename
Tag>
structtag_override_noexcept¶ - #include <tag_priority_dispatch.hpp>
hpx::functional::tag_override_noexcept<Tag>defines a base class that implements the necessary tag dispatching functionality for a given typeTagwhere the implementation is required to be noexcept
-
template<typename
-
namespace
Defines
-
HPX_UTIL_REGISTER_UNIQUE_FUNCTION_DECLARATION(Sig, F, Name)¶
-
HPX_UTIL_REGISTER_UNIQUE_FUNCTION(Sig, F, Name)¶
-
namespace
hpx -
namespace
util -
-
template<typename
R, typename ...Ts, boolSerializable>
classunique_function<R(Ts...), Serializable> : public detail::basic_function<R(Ts...), false, Serializable>¶ Public Types
-
typedef R
result_type¶
Public Functions
-
unique_function(unique_function&&)¶
-
unique_function &
operator=(unique_function&&)¶
Private Types
-
template<>
usingbase_type= detail::basic_function<R(Ts...), false, Serializable>¶
-
typedef R
-
template<typename
-
namespace
-
template<typename
R, typenameObj, typename ...Ts>
structget_function_address<R (Obj::*)(Ts...) const>¶
-
namespace
hpx
-
namespace
hpx
-
namespace
hpx -
namespace
traits Variables
-
template<typename T>HPX_INLINE_CONSTEXPR_VARIABLE bool hpx::traits::is_action_v = is_action<T>::value
-
template<typename T>HPX_INLINE_CONSTEXPR_VARIABLE bool hpx::traits::is_bound_action_v=is_bound_action<T>::value
-
-
namespace
-
namespace
hpx
-
namespace
hpx Variables
-
template<typename F, typename... Ts>HPX_INLINE_CONSTEXPR_VARIABLE bool hpx::is_invocable_v=is_invocable<F, Ts...>::value
-
template<typename R, typename F, typename... Ts>HPX_INLINE_CONSTEXPR_VARIABLE bool hpx::is_invocable_r_v=is_invocable_r<R, F, Ts...>::value
-
namespace
traits
-
-
namespace
hpx -
namespace
traits -
template<typename
T>
structis_placeholder¶ - #include <is_placeholder.hpp>
If
Tis a standard, Boost, or HPX placeholder (_1, _2, _3, …) then this template is derived fromstd::integral_constant<int, 1>,std::integral_constant<int, 2>,std::integral_constant<int, 3>, respectively. Otherwise it is derived from ,std::integral_constant<int, 0>.
-
template<typename
-
namespace
hardware¶
The contents of this module can be included with the header
hpx/modules/hardware.hpp. These headers may be used by user-code but are not
guaranteed stable (neither header location nor contents). You are using these at
your own risk. If you wish to use non-public functionality from a module we
strongly suggest only including the module header hpx/modules/hardware.hpp, not
the particular header in which the functionality you would like to use is
defined. See Public API for a list of names that are part of the public
HPX API.
-
namespace
hpx -
namespace
util -
namespace
hardware¶ Functions
-
namespace
-
namespace
-
namespace
hpx
-
namespace
hpx -
namespace
util -
namespace
hardware Functions
-
HPX_DEVICE std::uint64_t hpx::util::hardware::timestamp_cuda()
-
-
namespace
-
namespace
-
namespace
hpx -
namespace
util -
namespace
hardware
-
namespace
-
namespace
hashing¶
The contents of this module can be included with the header
hpx/modules/hashing.hpp. These headers may be used by user-code but are not
guaranteed stable (neither header location nor contents). You are using these at
your own risk. If you wish to use non-public functionality from a module we
strongly suggest only including the module header hpx/modules/hashing.hpp, not
the particular header in which the functionality you would like to use is
defined. See Public API for a list of names that are part of the public
HPX API.
-
namespace
hpx -
namespace
util
-
namespace
-
namespace
hpx -
namespace
util -
class
jenkins_hash¶ - #include <jenkins_hash.hpp>
The jenkins_hash class encapsulates a hash calculation function published by Bob Jenkins here: http://burtleburtle.net/bob/hash
Public Types
Public Functions
-
jenkins_hash()¶ constructors and destructor
-
~jenkins_hash()¶
-
void
swap(jenkins_hash &rhs)¶ support for std::swap
-
-
class
-
namespace
ini¶
The contents of this module can be included with the header
hpx/modules/ini.hpp. These headers may be used by user-code but are not
guaranteed stable (neither header location nor contents). You are using these at
your own risk. If you wish to use non-public functionality from a module we
strongly suggest only including the module header hpx/modules/ini.hpp, not
the particular header in which the functionality you would like to use is
defined. See Public API for a list of names that are part of the public
HPX API.
Defines
-
HPX_SECTION_VERSION¶
-
namespace
hpx -
namespace
util -
class
section¶ Public Types
-
typedef util::function_nonser<void(std::string const&, std::string const&)>
entry_changed_func¶
-
typedef std::pair<std::string, entry_changed_func>
entry_type¶
-
typedef std::map<std::string, entry_type>
entry_map¶
Public Functions
-
section()¶
-
~section()¶
-
void
parse(std::string const &sourcename, std::vector<std::string> const &lines, bool verify_existing = true, bool weed_out_comments = true, bool replace_existing = true)¶
-
void
parse(std::string const &sourcename, std::string const &line, bool verify_existing = true, bool weed_out_comments = true, bool replace_existing = true)¶
-
void
dump(int ind = 0) const¶
-
section_map &
get_sections()¶
-
section_map const &
get_sections() const¶
-
void
add_entry(std::string const &key, entry_type const &val)¶
-
void
add_notification_callback(std::string const &key, entry_changed_func const &callback)¶
Protected Functions
Private Functions
-
void
add_section(std::unique_lock<mutex_type> &l, std::string const &sec_name, section &sec, section *root = nullptr)¶
-
bool
has_section(std::unique_lock<mutex_type> &l, std::string const &sec_name) const¶
-
section *
get_section(std::unique_lock<mutex_type> &l, std::string const &sec_name)¶
-
section const *
get_section(std::unique_lock<mutex_type> &l, std::string const &sec_name) const¶
-
section *
add_section_if_new(std::unique_lock<mutex_type> &l, std::string const &sec_name)¶
-
void
add_entry(std::unique_lock<mutex_type> &l, std::string const &fullkey, std::string const &key, std::string val)¶
-
void
add_entry(std::unique_lock<mutex_type> &l, std::string const &fullkey, std::string const &key, entry_type const &val)¶
-
bool
has_entry(std::unique_lock<mutex_type> &l, std::string const &key) const¶
-
std::string
get_entry(std::unique_lock<mutex_type> &l, std::string const &key) const¶
-
std::string
get_entry(std::unique_lock<mutex_type> &l, std::string const &key, std::string const &dflt) const¶
-
void
add_notification_callback(std::unique_lock<mutex_type> &l, std::string const &key, entry_changed_func const &callback)¶
-
std::string
expand(std::unique_lock<mutex_type> &l, std::string in) const¶
-
void
expand(std::unique_lock<mutex_type> &l, std::string&, std::string::size_type) const¶
-
void
expand_bracket(std::unique_lock<mutex_type> &l, std::string&, std::string::size_type) const¶
-
void
expand_brace(std::unique_lock<mutex_type> &l, std::string&, std::string::size_type) const¶
-
std::string
expand_only(std::unique_lock<mutex_type> &l, std::string in, std::string const &expand_this) const¶
-
void
expand_only(std::unique_lock<mutex_type> &l, std::string&, std::string::size_type, std::string const &expand_this) const¶
Friends
-
friend
hpx::util::hpx::serialization::access
-
typedef util::function_nonser<void(std::string const&, std::string const&)>
-
class
-
namespace
io_service¶
The contents of this module can be included with the header
hpx/modules/io_service.hpp. These headers may be used by user-code but are not
guaranteed stable (neither header location nor contents). You are using these at
your own risk. If you wish to use non-public functionality from a module we
strongly suggest only including the module header hpx/modules/io_service.hpp, not
the particular header in which the functionality you would like to use is
defined. See Public API for a list of names that are part of the public
HPX API.
-
namespace
hpx -
namespace
util -
class
io_service_pool¶ - #include <io_service_pool.hpp>
A pool of io_service objects.
Public Functions
-
HPX_NON_COPYABLE(io_service_pool)¶
-
io_service_pool(std::size_t pool_size = 2, threads::policies::callback_notifier const ¬ifier = threads::policies::callback_notifier(), char const *pool_name = "", char const *name_postfix = "")¶ Construct the io_service pool.
- Parameters
pool_size: [in] The number of threads to run to serve incoming requestsstart_thread: [in]
-
io_service_pool(threads::policies::callback_notifier const ¬ifier, char const *pool_name = "", char const *name_postfix = "")¶ Construct the io_service pool.
- Parameters
start_thread: [in]
-
~io_service_pool()¶
-
bool
run(bool join_threads = true, barrier *startup = nullptr)¶ Run all io_service objects in the pool. If join_threads is true this will also wait for all threads to complete
-
bool
run(std::size_t num_threads, bool join_threads = true, barrier *startup = nullptr)¶ Run all io_service objects in the pool. If join_threads is true this will also wait for all threads to complete
-
void
stop()¶ Stop all io_service objects in the pool.
-
void
join()¶ Join all io_service threads in the pool.
-
void
clear()¶ Clear all internal data structures.
-
void
wait()¶ Wait for all work to be done.
-
bool
stopped()¶
-
asio::io_context &
get_io_service(int index = -1)¶ Get an io_service to use.
-
void
thread_run(std::size_t index, barrier *startup = nullptr)¶ Activate the thread index for this thread pool.
-
char const *
get_name() const¶ Return name of this pool.
Protected Functions
-
void
stop_locked()¶
-
void
join_locked()¶
-
void
clear_locked()¶
-
void
wait_locked()¶
Private Types
-
using
work_type= asio::io_context::work¶
Private Members
-
std::vector<io_service_ptr>
io_services_¶ The pool of io_services.
-
bool
stopped_¶ set to true if stopped
-
threads::policies::callback_notifier const &
notifier_¶ call this for each thread start/stop
-
char const *
pool_name_¶
-
char const *
pool_name_postfix_¶
-
bool
waiting_¶ Set to true if waiting for work to finish.
-
-
class
-
namespace
iterator_support¶
The contents of this module can be included with the header
hpx/modules/iterator_support.hpp. These headers may be used by user-code but are not
guaranteed stable (neither header location nor contents). You are using these at
your own risk. If you wish to use non-public functionality from a module we
strongly suggest only including the module header hpx/modules/iterator_support.hpp, not
the particular header in which the functionality you would like to use is
defined. See Public API for a list of names that are part of the public
HPX API.
Defines
-
HPX_ITERATOR_TRAVERSAL_TAG_NS¶
-
namespace
hpx -
namespace
iterators¶ -
struct
bidirectional_traversal_tag: public hpx::iterators::forward_traversal_tag¶ Subclassed by hpx::iterators::random_access_traversal_tag
-
struct
forward_traversal_tag: public hpx::iterators::single_pass_traversal_tag¶ Subclassed by hpx::iterators::bidirectional_traversal_tag
-
struct
incrementable_traversal_tag: public hpx::iterators::no_traversal_tag¶ Subclassed by hpx::iterators::single_pass_traversal_tag
-
struct
no_traversal_tag¶ Subclassed by hpx::iterators::incrementable_traversal_tag
-
struct
single_pass_traversal_tag: public hpx::iterators::incrementable_traversal_tag¶ Subclassed by hpx::iterators::forward_traversal_tag
-
struct
-
namespace
traits Typedefs
-
template<typename
Traversal>
usingpure_traversal_tag= HPX_ITERATOR_TRAVERSAL_TAG_NS::iterators::pure_traversal_tag<Traversal>¶
-
template<typename
Traversal>
usingpure_traversal_tag_t= typename pure_traversal_tag<Traversal>::type¶
-
template<typename
Iterator>
usingpure_iterator_traversal= HPX_ITERATOR_TRAVERSAL_TAG_NS::iterators::pure_iterator_traversal<Iterator>¶
-
template<typename
Iterator>
usingpure_iterator_traversal_t= typename pure_iterator_traversal<Iterator>::type¶
-
template<typename
Cat>
usingiterator_category_to_traversal= HPX_ITERATOR_TRAVERSAL_TAG_NS::iterators::iterator_category_to_traversal<Cat>¶
-
template<typename
Cat>
usingiterator_category_to_traversal_t= typename iterator_category_to_traversal<Cat>::type¶
-
template<typename
Iterator>
usingiterator_traversal= HPX_ITERATOR_TRAVERSAL_TAG_NS::iterators::iterator_traversal<Iterator>¶
-
template<typename
Iterator>
usingiterator_traversal_t= typename iterator_traversal<Iterator>::type¶
Variables
-
template<typename Traversal>HPX_INLINE_CONSTEXPR_VARIABLE bool hpx::traits::pure_traversal_tag_v= pure_traversal_tag<Traversal>::value
-
template<typename Iterator>HPX_INLINE_CONSTEXPR_VARIABLE bool hpx::traits::pure_iterator_traversal_v= pure_iterator_traversal<Iterator>::value
-
template<typename Cat>HPX_INLINE_CONSTEXPR_VARIABLE bool hpx::traits::iterator_category_to_traversal_v= iterator_category_to_traversal<Cat>::value
-
template<typename Iterator>HPX_INLINE_CONSTEXPR_VARIABLE bool hpx::traits::iterator_traversal_v= iterator_traversal<Iterator>::value
-
template<typename
-
namespace
-
template<typename
Incrementable, typenameCategoryOrTraversal, typenameDifference>
classcounting_iterator<Incrementable, CategoryOrTraversal, Difference, typename std::enable_if<std::is_integral<Incrementable>::value>::type> : public hpx::util::iterator_adaptor<counting_iterator<Incrementable, CategoryOrTraversal, Difference>, Incrementable, Incrementable, traversal, Incrementable const&, difference>¶ Public Functions
-
counting_iterator()¶
-
counting_iterator(counting_iterator const &rhs)¶
-
counting_iterator(Incrementable x)¶
Private Types
-
template<>
usingbase_type= typename detail::counting_iterator_base<Incrementable, CategoryOrTraversal, Difference>::type¶
Private Functions
-
void
increment()¶
-
void
decrement()¶
-
base_type::reference
dereference() const¶
-
template<typename
OtherIncrementable>
base_type::difference_typedistance_to(counting_iterator<OtherIncrementable, CategoryOrTraversal, Difference> const &y) const¶
Friends
-
friend
iterator_core_access
-
-
namespace
hpx -
namespace
util Functions
-
template<typename
Incrementable>
counting_iterator<Incrementable>make_counting_iterator(Incrementable x)¶
-
template<typename
Incrementable, typenameCategoryOrTraversal, typenameDifference, typenameEnable>
classcounting_iterator¶ Public Functions
-
counting_iterator()
-
counting_iterator(counting_iterator const &rhs)
-
counting_iterator(Incrementable x)
Private Types
-
template<>
usingbase_type= typename detail::counting_iterator_base<Incrementable, CategoryOrTraversal, Difference>::type¶
Private Functions
-
base_type::reference
dereference() const
Friends
-
friend
hpx::util::iterator_core_access
-
-
template<typename
Incrementable, typenameCategoryOrTraversal, typenameDifference>
classcounting_iterator<Incrementable, CategoryOrTraversal, Difference, typename std::enable_if<std::is_integral<Incrementable>::value>::type> : public hpx::util::iterator_adaptor<counting_iterator<Incrementable, CategoryOrTraversal, Difference>, Incrementable, Incrementable, traversal, Incrementable const&, difference> Public Functions
-
counting_iterator()
-
counting_iterator(counting_iterator const &rhs)
-
counting_iterator(Incrementable x)
Private Types
-
template<>
usingbase_type= typename detail::counting_iterator_base<Incrementable, CategoryOrTraversal, Difference>::type
Private Functions
-
template<typename
Iterator>
boolequal(Iterator const &rhs) const
-
void
increment()
-
void
decrement()
-
template<typename
Distance>
voidadvance(Distance n)
-
base_type::reference
dereference() const
-
template<typename
OtherIncrementable>
base_type::difference_typedistance_to(counting_iterator<OtherIncrementable, CategoryOrTraversal, Difference> const &y) const
Friends
-
friend
hpx::util::iterator_core_access
-
-
template<typename
-
namespace
-
namespace
hpx -
namespace
util Functions
-
template<typename
Generator>
classgenerator_iterator: public hpx::util::iterator_facade<generator_iterator<Generator>, Generator::result_type, std::forward_iterator_tag, Generator::result_type const&>¶ Public Functions
-
generator_iterator()¶
-
generator_iterator(Generator *g)¶
-
void
increment()¶
-
Generator::result_type const &
dereference() const¶
-
bool
equal(generator_iterator const &y) const¶
Private Types
-
-
template<typename
-
namespace
-
namespace
hpx -
namespace
util -
template<typename
Derived, typenameBase, typenameValue= void, typenameCategory= void, typenameReference= void, typenameDifference= void, typenamePointer= void>
classiterator_adaptor: public hpx::util::iterator_facade<Derived, value_type, iterator_category, reference_type, difference_type, void>¶ Subclassed by hpx::util::counting_iterator< Incrementable, CategoryOrTraversal, Difference, typename std::enable_if< std::is_integral< Incrementable >::value >::type >
Public Types
-
typedef Base
base_type¶
Protected Types
-
typedef hpx::util::detail::iterator_adaptor_base<Derived, Base, Value, Category, Reference, Difference, Pointer>::type
base_adaptor_type¶
-
typedef iterator_adaptor<Derived, Base, Value, Category, Reference, Difference, Pointer>
iterator_adaptor_¶
Private Functions
-
base_adaptor_type::reference
dereference() const¶
-
template<typename
OtherDerived, typenameOtherIterator, typenameV, typenameC, typenameR, typenameD, typenameP>
boolequal(iterator_adaptor<OtherDerived, OtherIterator, V, C, R, D, P> const &x) const¶
-
template<typename
DifferenceType>
voidadvance(DifferenceType n)¶
-
void
increment()¶
-
template<typename
Iterator= Base, typenameEnable= typename std::enable_if<traits::is_bidirectional_iterator<Iterator>::value>::type>
voiddecrement()¶
-
template<typename
OtherDerived, typenameOtherIterator, typenameV, typenameC, typenameR, typenameD, typenameP>
base_adaptor_type::difference_typedistance_to(iterator_adaptor<OtherDerived, OtherIterator, V, C, R, D, P> const &y) const¶
Private Members
-
Base
iterator_¶
Friends
-
friend
hpx::util::hpx::util::iterator_core_access
-
typedef Base
-
template<typename
-
namespace
Defines
-
HPX_UTIL_ITERATOR_FACADE_INTEROP_HEAD(prefix, op, result_type)¶
-
namespace
hpx -
namespace
util Functions
-
template<typename
Derived, typenameT, typenameCategory, typenameReference, typenameDistance, typenamePointer>
util::detail::postfix_increment_result<Derived, typename Derived::value_type, typename Derived::reference>::typeoperator++(iterator_facade<Derived, T, Category, Reference, Distance, Pointer> &i, int)¶
-
hpx::util::HPX_UTIL_ITERATOR_FACADE_INTEROP_HEAD(inline, bool)
-
hpx::util::HPX_UTIL_ITERATOR_FACADE_INTEROP_HEAD(inline, !, bool)
-
hpx::util::HPX_UTIL_ITERATOR_FACADE_INTEROP_HEAD(inline)
-
hpx::util::HPX_UTIL_ITERATOR_FACADE_INTEROP_HEAD(inline, <=, bool)
-
hpx::util::HPX_UTIL_ITERATOR_FACADE_INTEROP_HEAD(inline, >=, bool)
-
hpx::util::HPX_UTIL_ITERATOR_FACADE_INTEROP_HEAD(inline, -, typename std::iterator_traits< Derived2 >::difference_type)
-
class
iterator_core_access¶
-
template<typename
Derived, typenameT, typenameCategory, typenameReference= T&, typenameDistance= std::ptrdiff_t, typenamePointer= void>
structiterator_facade: public hpx::util::detail::iterator_facade_base<Derived, T, Category, T&, std::ptrdiff_t, void>¶ Subclassed by hpx::util::iterator_adaptor< Derived, Base, Value, Category, Reference, Difference, Pointer >
Public Functions
-
iterator_facade()¶
Protected Types
-
typedef iterator_facade<Derived, T, Category, Reference, Distance, Pointer>
iterator_adaptor_¶
Private Types
-
typedef detail::iterator_facade_base<Derived, T, Category, Reference, Distance, Pointer>
base_type¶
-
-
template<typename
-
namespace
-
namespace
hpx -
namespace
util Functions
-
template<typename
Range, typenameIterator= typename traits::range_iterator<Range>::type, typenameSentinel= typename traits::range_iterator<Range>::type>
std::enable_if<traits::is_range<Range>::value, iterator_range<Iterator, Sentinel>>::typemake_iterator_range(Range &r)¶
-
template<typename
-
namespace
-
namespace
hpx -
namespace
util -
namespace
range_adl¶ Functions
-
template<typename
C, typenameIterator= typename detail::iterator<C>::type>
constexpr Iteratorbegin(C &c)¶
-
template<typename
C, typenameIterator= typename detail::iterator<C const>::type>
constexpr Iteratorbegin(C const &c)¶
-
template<typename
C, typenameSentinel= typename detail::sentinel<C>::type>
constexpr Sentinelend(C &c)¶
-
template<typename
C, typenameSentinel= typename detail::sentinel<C const>::type>
constexpr Sentinelend(C const &c)¶
-
template<typename
-
namespace
-
namespace
-
namespace
hpx -
namespace
util Functions
-
template<typename
Transformer, typenameIterator>
transform_iterator<Iterator, Transformer>make_transform_iterator(Iterator const &it, Transformer const &f)¶
-
template<typename
Transformer, typenameIterator>
transform_iterator<Iterator, Transformer>make_transform_iterator(Iterator const &it)¶
-
template<typename
Iterator, typenameTransformer, typenameReference, typenameValue, typenameCategory, typenameDifference>
classtransform_iterator¶ Public Functions
-
transform_iterator()¶
-
transform_iterator(Iterator const &it)¶
-
transform_iterator(Iterator const &it, Transformer const &f)¶
-
template<typename
OtherIterator, typenameOtherTransformer, typenameOtherReference, typenameOtherValue, typenameOtherCategory, typenameOtherDifference>transform_iterator(transform_iterator<OtherIterator, OtherTransformer, OtherReference, OtherValue, OtherCategory, OtherDifference> const &t, typename std::enable_if<std::is_convertible<OtherIterator, Iterator>::value && std::is_convertible<OtherTransformer, Transformer>::value && std::is_convertible<OtherCategory, Category>::value && std::is_convertible<OtherDifference, Difference>::value>::type* = nullptr)¶
-
Transformer const &
transformer() const¶
Private Types
-
typedef detail::transform_iterator_base<Iterator, Transformer, Reference, Value, Category, Difference>::type
base_type¶
Private Members
-
Transformer
transformer_¶
Friends
-
friend
hpx::util::hpx::util::iterator_core_access
-
-
template<typename
-
namespace
-
template<typename ...
Ts>
classzip_iterator<hpx::tuple<Ts...>> : public hpx::util::detail::zip_iterator_base<hpx::tuple<Ts...>, zip_iterator<hpx::tuple<Ts...>>>¶ Public Functions
-
zip_iterator()¶
-
zip_iterator(Ts const&... vs)¶
-
zip_iterator(zip_iterator const &other)¶
-
zip_iterator(zip_iterator &&other)¶
-
zip_iterator &
operator=(zip_iterator const &other)¶
-
zip_iterator &
operator=(zip_iterator &&other)¶
-
-
template<typename
F, typename ...Ts>
structlift_zipped_iterators<F, util::zip_iterator<Ts...>>¶ Public Types
Public Static Functions
-
template<std::size_t...
Is, typename ...Ts_>
static result_typecall(util::index_pack<Is...>, hpx::tuple<Ts_...> const &t)¶
-
template<typename ...
Ts_>
static result_typecall(util::zip_iterator<Ts_...> const &iter)¶
-
template<std::size_t...
-
namespace
hpx -
namespace
traits -
namespace
functional¶ -
template<typename
F, typename ...Ts>
structlift_zipped_iterators<F, util::zip_iterator<Ts...>> Public Types
-
typedef util::zip_iterator<Ts...>::iterator_tuple_type
tuple_type
-
typedef hpx::tuple<typename element_result_of<typename F::template apply<Ts>, Ts>::type...>
result_type
Public Static Functions
-
template<std::size_t...
Is, typename ...Ts_>
static result_typecall(util::index_pack<Is...>, hpx::tuple<Ts_...> const &t)
-
template<typename ...
Ts_>
static result_typecall(util::zip_iterator<Ts_...> const &iter)
-
typedef util::zip_iterator<Ts...>::iterator_tuple_type
-
template<typename
-
namespace
-
namespace
util Functions
-
template<typename ...
Ts>
classzip_iterator: public hpx::util::detail::zip_iterator_base<hpx::tuple<Ts...>, zip_iterator<Ts...>>¶ Public Functions
-
zip_iterator()
-
zip_iterator(Ts const&... vs)
-
zip_iterator(hpx::tuple<Ts...> &&t)
-
zip_iterator(zip_iterator const &other)
-
zip_iterator(zip_iterator &&other)
-
zip_iterator &
operator=(zip_iterator const &other)
-
zip_iterator &
operator=(zip_iterator &&other)
-
-
template<typename ...
Ts>
classzip_iterator<hpx::tuple<Ts...>> : public hpx::util::detail::zip_iterator_base<hpx::tuple<Ts...>, zip_iterator<hpx::tuple<Ts...>>> Public Functions
-
zip_iterator()
-
zip_iterator(Ts const&... vs)
-
zip_iterator(hpx::tuple<Ts...> &&t)
-
zip_iterator(zip_iterator const &other)
-
zip_iterator(zip_iterator &&other)
-
zip_iterator &
operator=(zip_iterator const &other)
-
zip_iterator &
operator=(zip_iterator &&other)
-
-
template<typename ...
-
namespace
-
namespace
hpx -
namespace
traits Typedefs
-
template<typename
Iter>
usingis_bidirectional_iterator_t= typename is_bidirectional_iterator<Iter>::type¶
-
template<typename
Iter>
usingis_random_access_iterator_t= typename is_random_access_iterator<Iter>::type¶
-
template<typename
Iter>
usingis_segmented_local_iterator_t= typename is_segmented_local_iterator<Iter>::type¶
Variables
-
template<typename Iter>HPX_INLINE_CONSTEXPR_VARIABLE bool hpx::traits::is_iterator_v = is_iterator<Iter>::value
-
template<typename Iter>HPX_INLINE_CONSTEXPR_VARIABLE bool hpx::traits::is_output_iterator_v=is_output_iterator<Iter>::value
-
template<typename Iter>HPX_INLINE_CONSTEXPR_VARIABLE bool hpx::traits::is_input_iterator_v=is_input_iterator<Iter>::value
-
template<typename Iter>HPX_INLINE_CONSTEXPR_VARIABLE bool hpx::traits::is_forward_iterator_v=is_forward_iterator<Iter>::value
-
template<typename Iter>HPX_INLINE_CONSTEXPR_VARIABLE bool hpx::traits::is_bidirectional_iterator_v=is_bidirectional_iterator<Iter>::value
-
template<typename Iter>HPX_INLINE_CONSTEXPR_VARIABLE bool hpx::traits::is_random_access_iterator_v=is_random_access_iterator<Iter>::value
-
template<typename Iter>HPX_INLINE_CONSTEXPR_VARIABLE bool hpx::traits::is_segmented_iterator_v=is_segmented_iterator<Iter>::value
-
template<typename Iter>HPX_INLINE_CONSTEXPR_VARIABLE bool hpx::traits::is_segmented_local_iterator_v=is_segmented_local_iterator<Iter>::value
-
template<typename Iter>HPX_INLINE_CONSTEXPR_VARIABLE bool hpx::traits::is_zip_iterator_v=is_zip_iterator<Iter>::value
-
template<typename Iter>HPX_INLINE_CONSTEXPR_VARIABLE bool hpx::traits::is_contiguous_iterator_v=is_contiguous_iterator<Iter>::value
-
template<typename
-
namespace
-
namespace
hpx
-
namespace
hpx -
namespace
traits Variables
-
template<typename Sent, typename Iter>HPX_INLINE_CONSTEXPR_VARIABLE bool hpx::traits::disable_sized_sentinel_for = false
-
-
namespace
Functions
-
template<typename
Iter, typenameValueType, typenameEnable= std::enable_if_t<hpx::traits::is_forward_iterator<Iter>::value>>
booloperator==(Iter it, sentinel<ValueType> s)¶
-
template<typename
Iter, typenameValueType, typenameEnable= std::enable_if_t<hpx::traits::is_forward_iterator<Iter>::value>>
booloperator==(sentinel<ValueType> s, Iter it)¶
-
template<typename
Value>
structiterator¶ Public Types
-
template<>
usingvalue_type= Value¶
-
template<>
usingpointer= Value const*¶
-
template<>
usingreference= Value const&¶
Public Functions
-
iterator(Value initialState)¶
-
virtual Value
operator*() const¶
-
virtual Value
operator->() const¶
-
iterator &
operator++()¶
-
iterator
operator++(int)¶
-
iterator &
operator--()¶
-
iterator
operator--(int)¶
-
virtual Value
operator[](difference_type n) const¶
-
iterator &
operator+=(difference_type n)¶
-
iterator
operator+(difference_type n) const¶
-
iterator &
operator-=(difference_type n)¶
-
iterator
operator-(difference_type n) const¶
-
bool
operator==(const iterator &that) const¶
-
bool
operator!=(const iterator &that) const¶
-
bool
operator<(const iterator &that) const¶
-
bool
operator<=(const iterator &that) const¶
-
bool
operator>(const iterator &that) const¶
-
bool
operator>=(const iterator &that) const¶
Protected Attributes
-
Value
state¶
-
template<>
itt_notify¶
The contents of this module can be included with the header
hpx/modules/itt_notify.hpp. These headers may be used by user-code but are not
guaranteed stable (neither header location nor contents). You are using these at
your own risk. If you wish to use non-public functionality from a module we
strongly suggest only including the module header hpx/modules/itt_notify.hpp, not
the particular header in which the functionality you would like to use is
defined. See Public API for a list of names that are part of the public
HPX API.
Defines
-
HPX_ITT_SYNC_CREATE(obj, type, name)¶
-
HPX_ITT_SYNC_RENAME(obj, name)¶
-
HPX_ITT_SYNC_PREPARE(obj)¶
-
HPX_ITT_SYNC_CANCEL(obj)¶
-
HPX_ITT_SYNC_ACQUIRED(obj)¶
-
HPX_ITT_SYNC_RELEASING(obj)¶
-
HPX_ITT_SYNC_RELEASED(obj)¶
-
HPX_ITT_SYNC_DESTROY(obj)¶
-
HPX_ITT_STACK_CREATE(ctx)¶
-
HPX_ITT_STACK_CALLEE_ENTER(ctx)¶
-
HPX_ITT_STACK_CALLEE_LEAVE(ctx)¶
-
HPX_ITT_STACK_DESTROY(ctx)¶
-
HPX_ITT_FRAME_BEGIN(frame, id)¶
-
HPX_ITT_FRAME_END(frame, id)¶
-
HPX_ITT_MARK_CREATE(mark, name)¶
-
HPX_ITT_MARK_OFF(mark)¶
-
HPX_ITT_MARK(mark, parameter)¶
-
HPX_ITT_THREAD_SET_NAME(name)¶
-
HPX_ITT_THREAD_IGNORE()¶
-
HPX_ITT_TASK_BEGIN(domain, name)¶
-
HPX_ITT_TASK_BEGIN_ID(domain, id, name)¶
-
HPX_ITT_TASK_END(domain)¶
-
HPX_ITT_DOMAIN_CREATE(name)¶
-
HPX_ITT_STRING_HANDLE_CREATE(name)¶
-
HPX_ITT_MAKE_ID(addr, extra)¶
-
HPX_ITT_ID_CREATE(domain, id)¶
-
HPX_ITT_ID_DESTROY(id)¶
-
HPX_ITT_HEAP_FUNCTION_CREATE(name, domain)¶
-
HPX_ITT_HEAP_ALLOCATE_BEGIN(f, size, initialized)¶
-
HPX_ITT_HEAP_ALLOCATE_END(f, addr, size, initialized)¶
-
HPX_ITT_HEAP_FREE_BEGIN(f, addr)¶
-
HPX_ITT_HEAP_FREE_END(f, addr)¶
-
HPX_ITT_HEAP_REALLOCATE_BEGIN(f, addr, new_size, initialized)¶
-
HPX_ITT_HEAP_REALLOCATE_END(f, addr, new_addr, new_size, initialized)¶
-
HPX_ITT_HEAP_INTERNAL_ACCESS_BEGIN()¶
-
HPX_ITT_HEAP_INTERNAL_ACCESS_END()¶
-
HPX_ITT_COUNTER_CREATE(name, domain)¶
-
HPX_ITT_COUNTER_CREATE_TYPED(name, domain, type)¶
-
HPX_ITT_COUNTER_SET_VALUE(id, value_ptr)¶
-
HPX_ITT_COUNTER_DESTROY(id)¶
-
HPX_ITT_METADATA_ADD(domain, id, key, data)¶
Typedefs
-
using
__itt_heap_function= void*¶
Functions
-
constexpr void
itt_sync_create(void*, const char*, const char*)¶
-
constexpr void
itt_sync_rename(void*, const char*)¶
-
constexpr void
itt_sync_prepare(void*)¶
-
constexpr void
itt_sync_acquired(void*)¶
-
constexpr void
itt_sync_cancel(void*)¶
-
constexpr void
itt_sync_releasing(void*)¶
-
constexpr void
itt_sync_released(void*)¶
-
constexpr void
itt_sync_destroy(void*)¶
-
constexpr ___itt_caller *
itt_stack_create()¶
-
constexpr void
itt_stack_enter(___itt_caller*)¶
-
constexpr void
itt_stack_leave(___itt_caller*)¶
-
constexpr void
itt_stack_destroy(___itt_caller*)¶
-
constexpr void
itt_frame_begin(___itt_domain const*, ___itt_id*)¶
-
constexpr void
itt_frame_end(___itt_domain const*, ___itt_id*)¶
-
constexpr int
itt_mark_create(char const*)¶
-
constexpr void
itt_mark_off(int)¶
-
constexpr void
itt_mark(int, char const*)¶
-
constexpr void
itt_thread_set_name(char const*)¶
-
constexpr void
itt_thread_ignore()¶
-
constexpr void
itt_task_begin(___itt_domain const*, ___itt_string_handle*)¶
-
constexpr void
itt_task_begin(___itt_domain const*, ___itt_id*, ___itt_string_handle*)¶
-
constexpr void
itt_task_end(___itt_domain const*)¶
-
constexpr ___itt_domain *
itt_domain_create(char const*)¶
-
constexpr ___itt_string_handle *
itt_string_handle_create(char const*)¶
-
constexpr ___itt_id *
itt_make_id(void*, unsigned long)¶
-
constexpr void
itt_id_create(___itt_domain const*, ___itt_id*)¶
-
constexpr void
itt_id_destroy(___itt_id*)¶
-
constexpr __itt_heap_function
itt_heap_function_create(const char*, const char*)¶
-
constexpr void
itt_heap_allocate_begin(__itt_heap_function, std::size_t, int)¶
-
constexpr void
itt_heap_allocate_end(__itt_heap_function, void**, std::size_t, int)¶
-
constexpr void
itt_heap_free_begin(__itt_heap_function, void*)¶
-
constexpr void
itt_heap_free_end(__itt_heap_function, void*)¶
-
constexpr void
itt_heap_reallocate_begin(__itt_heap_function, void*, std::size_t, int)¶
-
constexpr void
itt_heap_reallocate_end(__itt_heap_function, void*, void**, std::size_t, int)¶
-
constexpr void
itt_heap_internal_access_begin()¶
-
constexpr void
itt_heap_internal_access_end()¶
-
constexpr ___itt_counter *
itt_counter_create(char const*, char const*)¶
-
constexpr ___itt_counter *
itt_counter_create_typed(char const*, char const*, int)¶
-
constexpr void
itt_counter_destroy(___itt_counter*)¶
-
constexpr void
itt_counter_set_value(___itt_counter*, void*)¶
-
constexpr int
itt_event_create(char const*, int)¶
-
constexpr int
itt_event_start(int)¶
-
constexpr int
itt_event_end(int)¶
-
constexpr void
itt_metadata_add(___itt_domain*, ___itt_id*, ___itt_string_handle*, std::uint64_t const&)¶
-
constexpr void
itt_metadata_add(___itt_domain*, ___itt_id*, ___itt_string_handle*, double const&)¶
-
constexpr void
itt_metadata_add(___itt_domain*, ___itt_id*, ___itt_string_handle*, char const*)¶
-
constexpr void
itt_metadata_add(___itt_domain*, ___itt_id*, ___itt_string_handle*, void const*)¶
-
namespace
hpx -
namespace
util -
namespace
itt¶ -
-
struct
caller_context¶
-
struct
counter¶
-
struct
domain¶ Subclassed by hpx::util::itt::thread_domain
-
struct
frame_context¶
-
struct
heap_allocate¶ Public Functions
-
template<typename
T>
constexprheap_allocate(heap_function&, T**, std::size_t, int)¶
-
~heap_allocate()¶
-
template<typename
-
struct
heap_free¶
-
struct
heap_function¶
-
struct
heap_internal_access¶
-
struct
id¶
-
struct
mark_context¶
-
struct
mark_event¶
-
struct
stack_context¶
-
struct
task¶ Public Functions
-
constexpr
task(domain const&, string_handle const&, std::uint64_t)¶
-
constexpr
task(domain const&, string_handle const&)¶
-
~task()¶
-
constexpr
-
struct
undo_frame_context¶
-
struct
undo_mark_context¶
-
struct
-
namespace
-
namespace
logging¶
The contents of this module can be included with the header
hpx/modules/logging.hpp. These headers may be used by user-code but are not
guaranteed stable (neither header location nor contents). You are using these at
your own risk. If you wish to use non-public functionality from a module we
strongly suggest only including the module header hpx/modules/logging.hpp, not
the particular header in which the functionality you would like to use is
defined. See Public API for a list of names that are part of the public
HPX API.
-
namespace
hpx -
namespace
util -
namespace
logging¶ Enums
-
enum
level¶ Handling levels - classes that can hold and/or deal with levels.
filters and level holders
By default we have these levels:
- debug (smallest level), - info, - warning , - error , - fatal (highest level)
Depending on which level is enabled for your application, some messages will reach the log: those messages having at least that level. For instance, if info level is enabled, all logged messages will reach the log. If warning level is enabled, all messages are logged, but the warnings. If debug level is enabled, messages that have levels debug, error, fatal will be logged.
Values:
-
disable_all= static_cast<unsigned int>(-1)¶
-
enable_all= 0¶
-
debug= 1000¶
-
info= 2000¶
-
warning= 3000¶
-
error= 4000¶
-
fatal= 5000¶
-
always= 6000¶
-
enum
-
namespace
-
namespace
Include this file when you’re using the logging lib, but don’t necessarily want to use formatters and destinations. If you want to use formatters and destinations, then you can include this one instead:
#include <hpx/logging/format.hpp>
-
namespace
hpx -
namespace
util -
namespace
logging -
namespace
destination¶ Destination is a manipulator. It contains a place where the message, after being formatted, is to be written to.
Some viable destinations are : the console, a file, a socket, etc.
-
struct
manipulator¶ - #include <manipulator.hpp>
What to use as base class, for your destination classes.
Subclassed by hpx::util::logging::destination::cerr, hpx::util::logging::destination::cout, hpx::util::logging::destination::dbg_window, hpx::util::logging::destination::file, hpx::util::logging::destination::stream
Public Functions
-
virtual void
configure(std::string const&)¶ Override this if you want to allow configuration through scripting.
That is, this allows configuration of your manipulator at run-time.
-
virtual
~manipulator()¶
Protected Functions
-
manipulator()¶
-
virtual void
-
struct
-
namespace
formatter¶ Formatter is a manipulator. It allows you to format the message before writing it to the destination(s)
Examples of formatters are : prepend the time, prepend high-precision time, prepend the index of the message, etc.
-
struct
manipulator¶ - #include <manipulator.hpp>
What to use as base class, for your formatter classes.
Subclassed by hpx::util::logging::formatter::high_precision_time, hpx::util::logging::formatter::idx, hpx::util::logging::formatter::thread_id
Public Functions
-
virtual void
configure(std::string const&)¶ Override this if you want to allow configuration through scripting.
That is, this allows configuration of your manipulator at run-time.
-
virtual
~manipulator()¶
Protected Functions
-
manipulator()¶
-
virtual void
-
struct
-
namespace
-
namespace
-
namespace
-
namespace
hpx -
namespace
util -
namespace
logging -
class
message¶ - #include <message.hpp>
Optimizes the formatting for prepending and/or appending strings to the original message.
It keeps all the modified message in one string. Useful if some formatter needs to access the whole string at once.
reserve() - the size that is reserved for prepending (similar to string::reserve function)
Note : as strings are prepended, reserve() shrinks.
-
class
-
namespace
-
namespace
-
namespace
hpx -
namespace
util -
namespace
logging -
namespace
destination Destination is a manipulator. It contains a place where the message, after being formatted, is to be written to.
Some viable destinations are : the console, a file, a socket, etc.
-
struct
cerr: public hpx::util::logging::destination::manipulator¶ - #include <destinations.hpp>
Writes the string to cerr.
Public Functions
-
~cerr()¶
Protected Functions
-
cerr()¶
-
-
struct
cout: public hpx::util::logging::destination::manipulator¶ - #include <destinations.hpp>
Writes the string to console.
Public Functions
-
~cout()¶
Protected Functions
-
cout()¶
-
-
struct
dbg_window: public hpx::util::logging::destination::manipulator¶ - #include <destinations.hpp>
Writes the string to output debug window.
For non-Windows systems, this is the console.
Public Functions
-
~dbg_window()¶
Public Static Functions
-
static std::unique_ptr<dbg_window>
make()¶
Protected Functions
-
dbg_window()¶
-
-
struct
file: public hpx::util::logging::destination::manipulator¶ - #include <destinations.hpp>
Writes the string to a file.
Public Functions
-
~file()¶
Public Static Functions
-
static std::unique_ptr<file>
make(std::string const &file_name, file_settings set = {})¶ constructs the file destination
- Parameters
file_name: name of the fileset: [optional] file settings - see file_settings class, and dealing_with_flags
Protected Functions
-
file(std::string const &file_name, file_settings set)¶
-
-
struct
stream: public hpx::util::logging::destination::manipulator¶ - #include <destinations.hpp>
writes to stream.
- Note
: The stream must outlive this object! Or, clear() the stream, before the stream is deleted.
-
struct
-
namespace
-
namespace
-
namespace
-
namespace
hpx -
namespace
util -
namespace
logging -
namespace
formatter Formatter is a manipulator. It allows you to format the message before writing it to the destination(s)
Examples of formatters are : prepend the time, prepend high-precision time, prepend the index of the message, etc.
-
struct
high_precision_time: public hpx::util::logging::formatter::manipulator¶ - #include <formatters.hpp>
Prefixes the message with a high-precision time (. You pass the format string at construction.
#include <hpx/logging/format/formatter/high_precision_time.hpp>
Internally, it uses hpx::util::date_time::microsec_time_clock. So, our precision matches this class.
The format can contain escape sequences: $dd - day, 2 digits $MM - month, 2 digits $yy - year, 2 digits $yyyy - year, 4 digits $hh - hour, 2 digits $mm - minute, 2 digits $ss - second, 2 digits $mili - milliseconds $micro - microseconds (if the high precision clock allows; otherwise, it pads zeros) $nano - nanoseconds (if the high precision clock allows; otherwise, it pads zeros)
Example:
high_precision_time("$mm:$ss:$micro");
- Parameters
convert: [optional] In case there needs to be a conversion between std::(w)string and the string that holds your logged message. See convert_format.
Public Functions
-
~high_precision_time()¶
Public Static Functions
-
static std::unique_ptr<high_precision_time>
make(std::string const &format)¶
-
struct
idx: public hpx::util::logging::formatter::manipulator¶ - #include <formatters.hpp>
prefixes each message with an index.
Example:
L_ << "my message"; L_ << "my 2nd message";
This will output something similar to:
[1] my message [2] my 2nd message
Public Functions
-
~idx()¶
Protected Functions
-
idx()¶
-
-
struct
thread_id: public hpx::util::logging::formatter::manipulator¶ - #include <formatters.hpp>
Writes the thread_id to the log.
- Parameters
convert: [optional] In case there needs to be a conversion between std::(w)string and the string that holds your logged message. See convert_format.
Public Functions
-
~thread_id()¶
Protected Functions
-
thread_id()¶
-
struct
-
namespace
-
namespace
-
namespace
-
namespace
hpx -
namespace
util -
namespace
logging -
namespace
writer¶ -
struct
named_write¶ - #include <named_write.hpp>
Composed of a named formatter and a named destinations. Thus, you can specify the formatting and destinations as strings.
#include <hpx/logging/format/named_write.hpp>
Contains a very easy interface for using formatters and destinations:
at construction, specify 2 params: the formatter string and the destinations string
Setting the formatters and destinations to write to is extremely simple:
// Set the formatters (first param) and destinatins (second step) in one step g_l()->writer().write("%time%($hh:$mm.$ss.$mili) [%idx%] |\n", "cout file(out.txt) debug"); // set the formatter(s) g_l()->writer().format("%time%($hh:$mm.$ss.$mili) [%idx%] |\n"); // set the destination(s) g_l()->writer().destination("cout file(out.txt) debug");
Public Functions
-
named_write()¶
-
void
format(std::string const &format_str)¶ sets the format string: what should be before, and what after the original message, separated by “|”
Example:
“[%idx%] |\n” - this writes “[%idx%] ” before the message, and “\n” after the message
If “|” is not present, the whole message is prepended to the message
-
void
destination(std::string const &destination_str)¶ sets the destinations string - where should logged messages be outputted
-
void
write(std::string const &format_str, std::string const &destination_str)¶ Specifies the formats and destinations in one step.
-
template<typename
Formatter>
voidset_formatter(std::string const &name, Formatter fmt)¶ Replaces a formatter from the named formatter.
You can use this, for instance, when you want to share a formatter between multiple named writers.
-
template<typename
Formatter, typename ...Args>
voidset_formatter(std::string const &name, Args&&... args)¶
-
template<typename
Destination>
voidset_destination(std::string const &name, Destination dest)¶ Replaces a destination from the named destination.
You can use this, for instance, when you want to share a destination between multiple named writers.
Private Functions
-
struct
-
namespace
-
namespace
-
namespace
Defines
-
LAGAS_(lvl)¶
-
LPT_(lvl)¶
-
LTIM_(lvl)¶
-
LPROGRESS_¶
-
LHPX_(lvl, cat)¶
-
LAPP_(lvl)¶
-
LDEB_¶
-
LTM_(lvl)¶
-
LRT_(lvl)¶
-
LOSH_(lvl)¶
-
LERR_(lvl)¶
-
LLCO_(lvl)¶
-
LPCS_(lvl)¶
-
LAS_(lvl)¶
-
LBT_(lvl)¶
-
LFATAL_¶
-
LAGAS_CONSOLE_(lvl)¶
-
LPT_CONSOLE_(lvl)¶
-
LTIM_CONSOLE_(lvl)¶
-
LHPX_CONSOLE_(lvl)¶
-
LAPP_CONSOLE_(lvl)¶
-
LDEB_CONSOLE_¶
-
LAGAS_ENABLED(lvl)¶
-
LPT_ENABLED(lvl)¶
-
LTIM_ENABLED(lvl)¶
-
LHPX_ENABLED(lvl)¶
-
LAPP_ENABLED(lvl)¶
-
LDEB_ENABLED¶
Functions
-
template<typename
T>
bootstrap_logging const &operator<<(bootstrap_logging const &l, T&&)¶
Variables
-
constexpr bootstrap_logging
lbt_¶
-
namespace
hpx
memory¶
The contents of this module can be included with the header
hpx/modules/memory.hpp. These headers may be used by user-code but are not
guaranteed stable (neither header location nor contents). You are using these at
your own risk. If you wish to use non-public functionality from a module we
strongly suggest only including the module header hpx/modules/memory.hpp, not
the particular header in which the functionality you would like to use is
defined. See Public API for a list of names that are part of the public
HPX API.
-
namespace
hpx -
namespace
memory¶ Functions
-
template<typename
T, typenameU>
booloperator==(intrusive_ptr<T> const &a, intrusive_ptr<U> const &b)¶
-
template<typename
T>
classintrusive_ptr¶ Public Types
-
template<>
usingelement_type= T¶
Public Functions
-
constexpr
intrusive_ptr()¶
-
intrusive_ptr(T *p, bool add_ref = true)¶
-
template<typename
U, typenameEnable= typename std::enable_if<memory::detail::sp_convertible<U, T>::value>::type>intrusive_ptr(intrusive_ptr<U> const &rhs)¶
-
intrusive_ptr(intrusive_ptr const &rhs)¶
-
~intrusive_ptr()¶
-
constexpr
intrusive_ptr(intrusive_ptr &&rhs)¶
-
intrusive_ptr &
operator=(intrusive_ptr &&rhs)¶
-
template<typename
U, typenameEnable= typename std::enable_if<memory::detail::sp_convertible<U, T>::value>::type>
constexprintrusive_ptr(intrusive_ptr<U> &&rhs)¶
-
intrusive_ptr &
operator=(intrusive_ptr const &rhs)¶
-
intrusive_ptr &
operator=(T *rhs)¶
-
void
reset()¶
-
void
reset(T *rhs)¶
-
void
reset(T *rhs, bool add_ref)¶
-
constexpr T *
get() const¶
-
constexpr T *
detach()¶
-
T &
operator*() const¶
-
T *
operator->() const¶
-
constexpr
operator bool() const¶
-
constexpr void
swap(intrusive_ptr &rhs)¶
Private Types
-
template<>
usingthis_type= intrusive_ptr¶
Private Members
-
T *
px= nullptr¶
Friends
-
friend
hpx::memory::intrusive_ptr
-
template<>
-
template<typename
-
namespace
-
namespace
std
-
namespace
hpx -
namespace
serialization Functions
-
template<typename
T>
voidload(input_archive &ar, hpx::intrusive_ptr<T> &ptr, unsigned)¶
-
template<typename
T>
voidsave(output_archive &ar, hpx::intrusive_ptr<T> const &ptr, unsigned)¶
-
hpx::serialization::HPX_SERIALIZATION_SPLIT_FREE_TEMPLATE((template< typename T >), ( hpx::intrusive_ptr < T >))
-
template<typename
-
namespace
plugin¶
The contents of this module can be included with the header
hpx/modules/plugin.hpp. These headers may be used by user-code but are not
guaranteed stable (neither header location nor contents). You are using these at
your own risk. If you wish to use non-public functionality from a module we
strongly suggest only including the module header hpx/modules/plugin.hpp, not
the particular header in which the functionality you would like to use is
defined. See Public API for a list of names that are part of the public
HPX API.
Defines
-
HPX_PLUGIN_EXPORT_API¶
-
HPX_PLUGIN_API¶
-
HPX_PLUGIN_ARGUMENT_LIMIT¶
-
HPX_PLUGIN_SYMBOLS_PREFIX_DYNAMIC¶
-
HPX_PLUGIN_SYMBOLS_PREFIX¶
-
HPX_PLUGIN_SYMBOLS_PREFIX_DYNAMIC_STR¶
-
HPX_PLUGIN_SYMBOLS_PREFIX_STR¶
-
namespace
hpx -
namespace
util -
namespace
plugin¶ Typedefs
-
namespace
-
namespace
Defines
-
HPX_HAS_DLOPEN¶
Defines
-
HPX_PLUGIN_NAME_2(name1, name2)¶
-
HPX_PLUGIN_NAME_3(name, base, cname)¶
-
HPX_PLUGIN_LIST_NAME_(prefix, name, base)¶
-
HPX_PLUGIN_EXPORTER_NAME_(prefix, name, base, cname)¶
-
HPX_PLUGIN_EXPORTER_INSTANCE_NAME_(prefix, name, base, cname)¶
-
HPX_PLUGIN_FORCE_LOAD_NAME_(prefix, name, base)¶
-
HPX_PLUGIN_LIST_NAME(name, base)¶
-
HPX_PLUGIN_EXPORTER_NAME(name, base, cname)¶
-
HPX_PLUGIN_EXPORTER_INSTANCE_NAME(name, base, cname)¶
-
HPX_PLUGIN_FORCE_LOAD_NAME(name, base)¶
-
HPX_PLUGIN_LIST_NAME_DYNAMIC(name, base)¶
-
HPX_PLUGIN_EXPORTER_NAME_DYNAMIC(name, base, cname)¶
-
HPX_PLUGIN_EXPORTER_INSTANCE_NAME_DYNAMIC(name, base, cname)¶
-
HPX_PLUGIN_FORCE_LOAD_NAME_DYNAMIC(name, base)¶
-
HPX_PLUGIN_EXPORT_(prefix, name, BaseType, ActualType, actualname, classname)¶
-
HPX_PLUGIN_EXPORT(name, BaseType, ActualType, actualname, classname)¶
-
HPX_PLUGIN_EXPORT_DYNAMIC(name, BaseType, ActualType, actualname, classname)¶
-
HPX_PLUGIN_EXPORT_LIST_(prefix, name, classname)¶
-
HPX_PLUGIN_EXPORT_LIST(name, classname)¶
-
HPX_PLUGIN_EXPORT_LIST_DYNAMIC(name, classname)¶
-
namespace
hpx -
namespace
util -
namespace
plugin -
template<class
BasePlugin>
structplugin_factory: public hpx::util::plugin::detail::plugin_factory_item<BasePlugin, detail::plugin_factory_item_base, virtual_constructor<BasePlugin>::type>¶
-
template<class
BasePlugin>
structstatic_plugin_factory: public hpx::util::plugin::detail::static_plugin_factory_item<BasePlugin, detail::static_plugin_factory_item_base, virtual_constructor<BasePlugin>::type>¶ Public Functions
-
static_plugin_factory(get_plugins_list_type const &f)¶
-
-
template<class
-
namespace
-
namespace
-
namespace
hpx
-
namespace
hpx -
namespace
util -
namespace
plugin Typedefs
-
using
exported_plugins_type= std::map<std::string, hpx::any_nonser>¶
-
typedef
exported_plugins_type*(HPX_PLUGIN_API* hpx::util::plugin::get_plugins_list_type) ()
-
typedef
exported_plugins_type* HPX_PLUGIN_API hpx::util::plugin::get_plugins_list_np()
-
using
dll_handle= shared_ptr<get_plugins_list_np>¶
-
template<typename
BasePlugin>
structvirtual_constructor¶
-
using
-
namespace
-
namespace
prefix¶
The contents of this module can be included with the header
hpx/modules/prefix.hpp. These headers may be used by user-code but are not
guaranteed stable (neither header location nor contents). You are using these at
your own risk. If you wish to use non-public functionality from a module we
strongly suggest only including the module header hpx/modules/prefix.hpp, not
the particular header in which the functionality you would like to use is
defined. See Public API for a list of names that are part of the public
HPX API.
-
namespace
hpx -
namespace
util
-
namespace
preprocessor¶
The contents of this module can be included with the header
hpx/modules/preprocessor.hpp. These headers may be used by user-code but are not
guaranteed stable (neither header location nor contents). You are using these at
your own risk. If you wish to use non-public functionality from a module we
strongly suggest only including the module header hpx/modules/preprocessor.hpp, not
the particular header in which the functionality you would like to use is
defined. See Public API for a list of names that are part of the public
HPX API.
Defines
-
HPX_PP_CAT(A, B)¶ Concatenates the tokens
AandBinto a single token. Evaluates toAB- Parameters
A: First tokenB: Second token
Defines
-
HPX_PP_EXPAND(X)¶ The HPX_PP_EXPAND macro performs a double macro-expansion on its argument.
This macro can be used to produce a delayed preprocessor expansion.
- Parameters
X: Token to be expanded twice
Example:
#define MACRO(a, b, c) (a)(b)(c) #define ARGS() (1, 2, 3) HPX_PP_EXPAND(MACRO ARGS()) // expands to (1)(2)(3)
Defines
-
HPX_PP_IDENTITY(...)¶
Defines
-
HPX_PP_NARGS(...)¶ Expands to the number of arguments passed in
Example Usage:
HPX_PP_NARGS(hpx, pp, nargs) HPX_PP_NARGS(hpx, pp) HPX_PP_NARGS(hpx)
- Parameters
...: The variadic number of arguments
Expands to:
3 2 1
Defines
-
HPX_PP_STRINGIZE(X)¶ The HPX_PP_STRINGIZE macro stringizes its argument after it has been expanded.
The passed argument
Xwill expand to"X". Note that the stringizing operator (#) prevents arguments from expanding. This macro circumvents this shortcoming.- Parameters
X: The text to be converted to a string literal
Defines
-
HPX_PP_STRIP_PARENS(X)¶ For any symbol
X, this macro returns the same symbol from which potential outer parens have been removed. If no outer parens are found, this macros evaluates toXitself without error.The original implementation of this macro is from Steven Watanbe as shown in http://boost.2283326.n4.nabble.com/preprocessor-removing-parentheses-td2591973.html#a2591976
HPX_PP_STRIP_PARENS(no_parens) HPX_PP_STRIP_PARENS((with_parens))
- Example Usage:
- Parameters
X: Symbol to strip parens from
This produces the following output
no_parens with_parens
properties¶
The contents of this module can be included with the header
hpx/modules/properties.hpp. These headers may be used by user-code but are not
guaranteed stable (neither header location nor contents). You are using these at
your own risk. If you wish to use non-public functionality from a module we
strongly suggest only including the module header hpx/modules/properties.hpp, not
the particular header in which the functionality you would like to use is
defined. See Public API for a list of names that are part of the public
HPX API.
-
namespace
hpx -
namespace
experimental¶ Variables
-
hpx::experimental::prefer_t
prefer¶
-
struct
prefer_t: public hpx::functional::tag_fallback<prefer_t>¶
-
hpx::experimental::prefer_t
-
namespace
schedulers¶
The contents of this module can be included with the header
hpx/modules/schedulers.hpp. These headers may be used by user-code but are not
guaranteed stable (neither header location nor contents). You are using these at
your own risk. If you wish to use non-public functionality from a module we
strongly suggest only including the module header hpx/modules/schedulers.hpp, not
the particular header in which the functionality you would like to use is
defined. See Public API for a list of names that are part of the public
HPX API.
-
namespace
hpx -
namespace
threads -
namespace
policies¶ Typedefs
-
using
default_local_priority_queue_scheduler_terminated_queue= lockfree_fifo¶
-
template<typename
Mutex= std::mutex, typenamePendingQueuing= lockfree_fifo, typenameStagedQueuing= lockfree_fifo, typenameTerminatedQueuing= default_local_priority_queue_scheduler_terminated_queue>
classlocal_priority_queue_scheduler: public scheduler_base¶ - #include <local_priority_queue_scheduler.hpp>
The local_priority_queue_scheduler maintains exactly one queue of work items (threads) per OS thread, where this OS thread pulls its next work from. Additionally it maintains separate queues: several for high priority threads and one for low priority threads. High priority threads are executed by the first N OS threads before any other work is executed. Low priority threads are executed by the last OS thread whenever no other work is available.
Public Types
-
typedef thread_queue<Mutex, PendingQueuing, StagedQueuing, TerminatedQueuing>
thread_queue_type¶
-
typedef init_parameter
init_parameter_type¶
Public Functions
-
local_priority_queue_scheduler(init_parameter_type const &init, bool deferred_initialization = true)¶
-
~local_priority_queue_scheduler()¶
-
void
abort_all_suspended_threads()¶
-
bool
cleanup_terminated(bool delete_all)¶
-
void
create_thread(thread_init_data &data, thread_id_type *id, error_code &ec)¶
-
bool
get_next_thread(std::size_t num_thread, bool running, threads::thread_data *&thrd, bool enable_stealing)¶ Return the next thread to be executed, return false if none is available
-
void
schedule_thread(threads::thread_data *thrd, threads::thread_schedule_hint schedulehint, bool allow_fallback = false, thread_priority priority = thread_priority::normal)¶ Schedule the passed thread.
-
void
schedule_thread_last(threads::thread_data *thrd, threads::thread_schedule_hint schedulehint, bool allow_fallback = false, thread_priority priority = thread_priority::normal)¶
-
void
destroy_thread(threads::thread_data *thrd)¶ Destroy the passed thread as it has been terminated.
-
std::int64_t
get_thread_count(thread_schedule_state state = thread_schedule_state::unknown, thread_priority priority = thread_priority::default_, std::size_t num_thread = std::size_t(-1), bool = false) const¶
-
bool
enumerate_threads(util::function_nonser<bool(thread_id_type)> const &f, thread_schedule_state state = thread_schedule_state::unknown, ) const¶
-
bool
wait_or_add_new(std::size_t num_thread, bool running, std::int64_t &idle_loop_count, bool enable_stealing, std::size_t &added)¶ This is a function which gets called periodically by the thread manager to allow for maintenance tasks to be executed in the scheduler. Returns true if the OS thread calling this function has to be terminated (i.e. no more work has to be done).
-
void
reset_thread_distribution()¶
Protected Attributes
-
detail::affinity_data const &
affinity_data_¶
-
thread_queue_type
low_priority_queue_¶
-
std::vector<util::cache_line_data<thread_queue_type*>>
queues_¶
-
std::vector<util::cache_line_data<thread_queue_type*>>
high_priority_queues_¶
-
struct
init_parameter¶ Public Functions
-
template<>
init_parameter(std::size_t num_queues, detail::affinity_data const &affinity_data, std::size_t num_high_priority_queues = std::size_t(-1), thread_queue_init_parameters thread_queue_init = {}, char const *description = "local_priority_queue_scheduler")¶
-
template<>
-
typedef thread_queue<Mutex, PendingQueuing, StagedQueuing, TerminatedQueuing>
-
using
-
namespace
-
namespace
-
namespace
hpx -
namespace
threads -
namespace
policies Typedefs
-
using
default_local_queue_scheduler_terminated_queue= lockfree_fifo¶
-
template<typename
Mutex= std::mutex, typenamePendingQueuing= lockfree_fifo, typenameStagedQueuing= lockfree_fifo, typenameTerminatedQueuing= default_local_queue_scheduler_terminated_queue>
classlocal_queue_scheduler: public scheduler_base¶ - #include <local_queue_scheduler.hpp>
The local_queue_scheduler maintains exactly one queue of work items (threads) per OS thread, where this OS thread pulls its next work from.
Public Types
-
typedef thread_queue<Mutex, PendingQueuing, StagedQueuing, TerminatedQueuing>
thread_queue_type¶
-
typedef init_parameter
init_parameter_type¶
Public Functions
-
local_queue_scheduler(init_parameter_type const &init, bool deferred_initialization = true)¶
-
virtual
~local_queue_scheduler()¶
-
void
abort_all_suspended_threads()¶
-
bool
cleanup_terminated(bool delete_all)¶
-
void
create_thread(thread_init_data &data, thread_id_type *id, error_code &ec)¶
-
virtual bool
get_next_thread(std::size_t num_thread, bool running, threads::thread_data *&thrd, bool)¶ Return the next thread to be executed, return false if none is available
-
void
schedule_thread(threads::thread_data *thrd, threads::thread_schedule_hint schedulehint, bool allow_fallback, thread_priority = thread_priority::normal)¶ Schedule the passed thread.
-
void
schedule_thread_last(threads::thread_data *thrd, threads::thread_schedule_hint schedulehint, bool allow_fallback, thread_priority = thread_priority::normal)¶
-
void
destroy_thread(threads::thread_data *thrd)¶ Destroy the passed thread as it has been terminated.
-
std::int64_t
get_thread_count(thread_schedule_state state = thread_schedule_state::unknown, thread_priority priority = thread_priority::default_, std::size_t num_thread = std::size_t(-1), bool = false) const¶
-
bool
enumerate_threads(util::function_nonser<bool(thread_id_type)> const &f, thread_schedule_state state = thread_schedule_state::unknown, ) const¶
-
virtual bool
wait_or_add_new(std::size_t num_thread, bool running, std::int64_t &idle_loop_count, bool, std::size_t &added)¶ This is a function which gets called periodically by the thread manager to allow for maintenance tasks to be executed in the scheduler. Returns true if the OS thread calling this function has to be terminated (i.e. no more work has to be done).
Protected Attributes
-
std::vector<thread_queue_type*>
queues_¶
-
detail::affinity_data const &
affinity_data_¶
-
mask_type
steals_in_numa_domain_¶
-
mask_type
steals_outside_numa_domain_¶
-
struct
init_parameter¶ Public Functions
-
template<>
init_parameter(std::size_t num_queues, detail::affinity_data const &affinity_data, thread_queue_init_parameters thread_queue_init = {}, char const *description = "local_queue_scheduler")¶
-
template<>
-
typedef thread_queue<Mutex, PendingQueuing, StagedQueuing, TerminatedQueuing>
-
using
-
namespace
-
namespace
-
namespace
hpx -
namespace
threads -
namespace
policies -
struct
concurrentqueue_fifo¶
-
struct
lockfree_fifo¶
-
template<typename
T>
structlockfree_fifo_backend¶ Public Types
-
template<>
usingvalue_type= T¶
-
template<>
usingreference= T&¶
-
template<>
usingconst_reference= T const&¶
Public Functions
-
lockfree_fifo_backend(size_type initial_size = 0, size_type = size_type(-1))¶
-
bool
push(const_reference val, bool = false)¶
-
bool
pop(reference val, bool = true)¶
-
bool
empty()¶
Private Members
-
container_type
queue_¶
-
template<>
-
template<typename
T>
structmoodycamel_fifo_backend¶ Public Types
-
template<>
usingcontainer_type= hpx::concurrency::ConcurrentQueue<T>¶
-
template<>
usingvalue_type= T¶
-
template<>
usingreference= T&¶
-
template<>
usingconst_reference= T const&¶
-
template<>
usingrval_reference= T&&¶
Public Functions
-
moodycamel_fifo_backend(size_type initial_size = 0, size_type = size_type(-1))¶
-
bool
push(rval_reference val, bool = false)¶
-
bool
push(const_reference val, bool = false)¶
-
bool
pop(reference val, bool = true)¶
-
bool
empty()¶
Private Members
-
container_type
queue_¶
-
template<>
-
struct
-
namespace
-
namespace
Defines
-
QUEUE_HOLDER_NUMA_DEBUG¶
-
namespace
hpx Functions
-
static hpx::debug::enable_print<QUEUE_HOLDER_NUMA_DEBUG> hpx::nq_deb("QH_NUMA")
-
namespace
threads -
namespace
policies -
template<typename
QueueType>
structqueue_holder_numa¶ Public Types
-
template<>
usingThreadQueue= queue_holder_thread<QueueType>¶
-
template<>
usingmutex_type= typename QueueType::mutex_type¶
Public Functions
-
queue_holder_numa()¶
-
~queue_holder_numa()¶
-
bool
get_next_thread_HP(std::size_t qidx, threads::thread_data *&thrd, bool stealing, bool core_stealing)¶
-
bool
get_next_thread(std::size_t qidx, threads::thread_data *&thrd, bool stealing, bool core_stealing)¶
-
bool
add_new_HP(ThreadQueue *receiver, std::size_t qidx, std::size_t &added, bool stealing, bool allow_stealing)¶
-
bool
add_new(ThreadQueue *receiver, std::size_t qidx, std::size_t &added, bool stealing, bool allow_stealing)¶
-
std::int64_t
get_thread_count(thread_schedule_state state = thread_schedule_state::unknown, thread_priority priority = thread_priority::default_) const¶
-
void
abort_all_suspended_threads()¶
-
bool
enumerate_threads(util::function_nonser<bool(thread_id_type)> const &f, thread_schedule_state state, ) const¶
-
void
debug_info()¶
-
template<>
-
template<typename
-
namespace
-
Defines
-
QUEUE_HOLDER_THREAD_DEBUG¶
-
namespace
hpx Functions
-
static hpx::debug::enable_print<QUEUE_HOLDER_THREAD_DEBUG> hpx::tq_deb("QH_THRD")
-
namespace
threads -
namespace
policies Enums
-
template<typename
QueueType>
structqueue_holder_thread¶ Public Types
-
template<>
usingthread_holder_type= queue_holder_thread<QueueType>¶
-
template<>
usingthread_heap_type= std::list<thread_id_type, util::internal_allocator<thread_id_type>>¶
-
template<>
usingtask_description= thread_init_data¶
-
template<>
usingthread_map_type= std::unordered_set<thread_id_type, std::hash<thread_id_type>, std::equal_to<thread_id_type>, util::internal_allocator<thread_id_type>>¶
-
template<>
usingterminated_items_type= lockfree_fifo::apply<thread_data*>::type¶
Public Functions
-
queue_holder_thread(QueueType *bp_queue, QueueType *hp_queue, QueueType *np_queue, QueueType *lp_queue, std::size_t domain, std::size_t queue, std::size_t thread_num, std::size_t owner, const thread_queue_init_parameters &init)¶
-
~queue_holder_thread()¶
-
bool
owns_bp_queue() const¶
-
bool
owns_hp_queue() const¶
-
bool
owns_np_queue() const¶
-
bool
owns_lp_queue() const¶
-
void
schedule_thread(threads::thread_data *thrd, thread_priority priority, bool other_end = false)¶
-
void
create_thread(thread_init_data &data, thread_id_type *tid, std::size_t thread_num, error_code &ec)¶
-
void
create_thread_object(threads::thread_id_type &tid, threads::thread_init_data &data)¶
-
void
recycle_thread(thread_id_type tid)¶
-
void
add_to_thread_map(threads::thread_id_type tid)¶
-
void
remove_from_thread_map(threads::thread_id_type tid, bool dealloc)¶
-
bool
get_next_thread_HP(threads::thread_data *&thrd, bool stealing, bool check_new)¶
-
bool
get_next_thread(threads::thread_data *&thrd, bool stealing)¶
-
std::size_t
get_thread_count_staged(thread_priority priority) const¶
-
std::size_t
get_thread_count_pending(thread_priority priority) const¶
-
std::size_t
get_thread_count(thread_schedule_state state = thread_schedule_state::unknown, thread_priority priority = thread_priority::default_) const¶
-
void
destroy_thread(threads::thread_data *thrd, std::size_t thread_num, bool xthread)¶ Destroy the passed thread as it has been terminated.
-
void
abort_all_suspended_threads()¶
-
bool
enumerate_threads(util::function_nonser<bool(thread_id_type)> const &f, thread_schedule_state state = thread_schedule_state::unknown, ) const¶
-
void
debug_info()¶
-
void
debug_queues(const char *prefix)¶
Public Members
-
QueueType *const
bp_queue_¶
-
QueueType *const
hp_queue_¶
-
QueueType *const
np_queue_¶
-
QueueType *const
lp_queue_¶
-
util::cache_line_data<mutex_type>
thread_map_mtx_¶
-
thread_heap_type
thread_heap_small_¶
-
thread_heap_type
thread_heap_medium_¶
-
thread_heap_type
thread_heap_large_¶
-
thread_heap_type
thread_heap_huge_¶
-
thread_heap_type
thread_heap_nostack_¶
-
thread_map_type
thread_map_¶
-
util::cache_line_data<std::atomic<std::int32_t>>
thread_map_count_¶
-
terminated_items_type
terminated_items_¶
-
util::cache_line_data<std::atomic<std::int32_t>>
terminated_items_count_¶
-
thread_queue_init_parameters
parameters_¶
Public Static Functions
-
static void
deallocate(threads::thread_data *p)¶
Public Static Attributes
-
util::internal_allocator<threads::thread_data>
thread_alloc_¶
-
template<>
-
template<typename
-
namespace
-
-
namespace
hpx Typedefs
Functions
-
static print_onoff hpx::spq_deb("SPQUEUE")
-
static print_on hpx::spq_arr("SPQUEUE")
-
namespace
threads -
namespace
policies Typedefs
-
struct
core_ratios¶ Public Functions
- #include <shared_priority_queue_scheduler.hpp>
The shared_priority_queue_scheduler maintains a set of high, normal, and low priority queues. For each priority level there is a core/queue ratio which determines how many cores share a single queue. If the high priority core/queue ratio is 4 the first 4 cores will share a single high priority queue, the next 4 will share another one and so on. In addition, the shared_priority_queue_scheduler is NUMA-aware and takes NUMA scheduling hints into account when creating and scheduling work.
Warning: PendingQueuing lifo causes lockup on termination
Public Types
Public Functions
Return the next thread to be executed, return false if none available.
Return the next thread to be executed, return false if none available.
Schedule the passed thread.
Put task on the back of the queue : not yet implemented just put it on the normal queue for now
Public Static Functions
Protected Types
Protected Attributes
-
struct
-
namespace
-