Allocator Accessibility¶
The Umpire library provides a variety of umpire::resource::MemoryResource
s
which can be used to create umpire::Allocator
s depending on what’s available on
your system. The resources are explained more on the Resources page.
Additionally, the platforms that Umpire supports is defined by the CAMP library. This means that there is also a selection of platforms for which an allocator can be associated with as well. For example, an Allocator created with the pinned memory resource can be used with the host, cuda, hip, or sycl platforms.
Because of these options, it can be difficult to trace
not only which memory resource an allocator has been created with but also
which allocators can be accessed by which platforms. Umpire has the memory resource
trait, resource_type
, to provide the ability to query which memory resource is
associated with a particular allocator (See example here).
Additionally, Umpire has a function, is_accessible(Platform p, Allocator a)
, that determines
if a particular allocator is accessible by a particular platform
(See example here). The allocator_accessibility.cpp
test checks what platforms are available and confirms that all memory resources which should be accessible
to that platform can actually be accessed and used.
For example, if a umpire::Allocator
, alloc
,
is created with the host memory resource and we want to know if it should be
accessible from the omp_target
CAMP platform, then we can use the is_accessible(Platform::omp_target, alloc)
function and find that it should be accessible. The allocator_access.cpp
file demonstrates this
functionality for the host platform specifically.
Allocator Inaccessibility Configuration¶
On a different note, for those allocators that are deemed inaccessible, it may be useful to
double check or confirm that the allocator can in fact NOT access memory on that given platform.
In this case, the cmake flag, UMPIRE_ENABLE_INACCESSIBILITY_TESTS
, will need to be turned on.
Build and Run Configuration¶
To build and run these files, either use uberenv or the appropriate cmake flags for the
desired platform and then run ctest -T test -R allocator_accessibility_tests --output-on-failure
for the test code and ./bin/alloc_access
for the example code.
Note
The Developer’s Guide shows how to configure Umpire with uberenv to build with different CAMP platforms.
Below, the allocator_access.cpp
code is shown to demonstrate how this functionality can be
used during development.
//////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2016-21, Lawrence Livermore National Security, LLC and Umpire
// project contributors. See the COPYRIGHT file for details.
//
// SPDX-License-Identifier: (MIT)
//////////////////////////////////////////////////////////////////////////////
#include <iostream>
#include <string>
#include "umpire/Allocator.hpp"
#include "umpire/ResourceManager.hpp"
#include "umpire/Umpire.hpp"
bool is_accessible_from_host(umpire::Allocator a)
{
if (umpire::is_accessible(umpire::Platform::host, a)) {
std::cout << "The allocator, " << a.getName() << ", is accessible." << std::endl;
return true;
} else {
std::cout << "The allocator, " << a.getName() << ", is _not_ accessible." << std::endl << std::endl;
return false;
}
}
/////////////////////////////////////////////////////////////////////////////////////////
// Depending on how Umpire has been set up, several different allocators could be accessible
// from the host CAMP platform. This example will create a list of all currently available
// allocators and then determine whether each can be accessed from the host platform.
//(To test other platforms, see allocator accessibility test.)
////////////////////////////////////////////////////////////////////////////////////////
int main()
{
auto& rm = umpire::ResourceManager::getInstance();
std::vector<std::string> allNames = rm.getResourceNames();
std::vector<umpire::Allocator> alloc;
///////////////////////////////////////////////////
// Create an allocator for each available type
//////////////////////////////////////////////////
std::cout << "Available allocators: ";
for (auto a : allNames) {
if (a.find("::") == std::string::npos) {
alloc.push_back(rm.getAllocator(a));
std::cout << a << " ";
}
}
std::cout << std::endl;
///////////////////////////////////////////////////
// Test accessibility
///////////////////////////////////////////////////
std::cout << "Testing the available allocators for accessibility from the CAMP host platform:" << std::endl;
const int size = 100;
for (auto a : alloc) {
if (is_accessible_from_host(a)) {
int* data = static_cast<int*>(a.allocate(size * sizeof(int)));
for (int i = 0; i < size; i++) {
data[i] = i * i;
}
UMPIRE_ASSERT(data[size - 1] == (size - 1) * (size - 1) && "Inequality found in array that should be accessible");
}
}
return 0;
}