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 or find out the associated umpire::Platform, which can help you decide where to operate on this 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;

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

    std::cout << "The size of the allocation is << "
              << 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-20, 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_DEVICE)
    ,
    "DEVICE"
#endif
#if defined(UMPIRE_ENABLE_UM)
    ,
    "UM"
#endif
#if defined(UMPIRE_ENABLE_PINNED)
    ,
    "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;

    // _sphinx_tag_tut_getallocator_start
    auto found_allocator = rm.getAllocator(data);
    // _sphinx_tag_tut_getallocator_end

    // _sphinx_tag_tut_getinfo_start
    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;
    // _sphinx_tag_tut_getinfo_end

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

    allocator.deallocate(data);
  }

  return 0;
}