Introspection

When writing code to run on computers with a complex memory hierarchy, one of the most difficult things can be keeping track of where each pointer has been allocated. Umpire’s instrospection capability keeps track of this information, as well as other useful bits and pieces you might want to know.

The umpire::ResourceManager can be used to find the allocator associated with an address:

    auto found_allocator = rm.getAllocator(data);

Once you have this, it’s easy to query things like the name of the Allocator:

      << found_allocator.getName()

You can also find out the associated umpire::Platform, which can help you decide where to operate on this data:

      << static_cast<int>(found_allocator.getPlatform()) << std::endl;

You can also find out how big the allocation is, in case you forgot:

      << found_allocator.getSize(data) << std::endl;

Remember that these functions will work on any allocation made using an Allocator or umpire::TypedAllocator.

//////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2016-19, Lawrence Livermore National Security, LLC and Umpire
// project contributors. See the COPYRIGHT file for details.
//
// SPDX-License-Identifier: (MIT)
//////////////////////////////////////////////////////////////////////////////
#include "umpire/Allocator.hpp"
#include "umpire/ResourceManager.hpp"

int main(int, char**) {
  constexpr std::size_t SIZE = 1024;

  auto& rm = umpire::ResourceManager::getInstance();

  const std::string destinations[] = {
    "HOST"
#if defined(UMPIRE_ENABLE_CUDA)
      , "DEVICE"
      , "UM"
      , "PINNED"
#endif
#if defined(UMPIRE_ENABLE_HIP)
      , "DEVICE"
      , "PINNED"
#endif
  };

  for (auto& destination : destinations) {
    auto allocator = rm.getAllocator(destination);
    double* data = static_cast<double*>(
        allocator.allocate(SIZE*sizeof(double)));

    std::cout << "Allocated " << (SIZE*sizeof(double)) << " bytes using the "
      << allocator.getName() << " allocator." << std::endl;

    auto found_allocator = rm.getAllocator(data);

    std::cout << "According to the ResourceManager, the Allocator used is "
      << found_allocator.getName()
      << ", which has the Platform "
      << static_cast<int>(found_allocator.getPlatform()) << std::endl;

    std::cout << "The size of the allocation is << "
      << found_allocator.getSize(data) << std::endl;

    allocator.deallocate(data);
  }

  return 0;
}