Skip to content

Commit 666d47b

Browse files
Arlie-Cappscyrush
andauthored
Example using Conduit allocators (#1419)
* First step: change function pointers to std::function. * Correct errors and include <functional> * Changing srandom() and random() to srand() and rand(). The former functions are not available on Windows while the latter are, since they're in the standard. * Init on first use * Another try to fix static init * Made memcpy and memset handlers members of AllocManager: centralized leakage. * Adjusted type names * Update src/libs/conduit/conduit_utils.hpp Co-authored-by: Cyrus Harrison <cyrush@llnl.gov> * More consistent ordering of functions. Noted change in CHANGELOG. * First draft of example of using with Umpire allocators * Correct the project name * Added an adapter class with start of code to exercise it. --------- Co-authored-by: Cyrus Harrison <cyrush@llnl.gov>
1 parent 94d50f7 commit 666d47b

2 files changed

Lines changed: 232 additions & 0 deletions

File tree

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
# Copyright (c) Lawrence Livermore National Security, LLC and other Conduit
2+
# Project developers. See top-level LICENSE AND COPYRIGHT files for dates and
3+
# other details. No copyright assignment is required to contribute to Conduit.
4+
###############################################################################
5+
#
6+
# Example that shows how to use an installed instance of Conduit in another
7+
# CMake-based build system.
8+
#
9+
# To build:
10+
# mkdir build
11+
# cd build
12+
# cmake -DCONDUIT_DIR={conduit install path} ../
13+
# make
14+
# ./conduit_example
15+
#
16+
#
17+
# If run in sub directory of a conduit install,
18+
# CONDUIT_DIR will default to ../../..
19+
#
20+
# mkdir build
21+
# cd build
22+
# cmake ..
23+
# make
24+
# ./conduit_example
25+
#
26+
###############################################################################
27+
28+
cmake_minimum_required(VERSION 3.0)
29+
30+
project(using_with_cmake_umpire)
31+
32+
33+
################################################################
34+
# Option 1: import conduit using an explicit path (recommended)
35+
################################################################
36+
37+
#
38+
# Provide default CONDUIT_DIR that works in a conduit install
39+
#
40+
if(NOT CONDUIT_DIR)
41+
set(CONDUIT_DIR "../../..")
42+
endif()
43+
44+
#
45+
# Check for valid conduit install
46+
#
47+
48+
# if given relative path, resolve
49+
get_filename_component(CONDUIT_DIR ${CONDUIT_DIR} ABSOLUTE)
50+
# check for expected cmake exported target files
51+
if(NOT EXISTS ${CONDUIT_DIR}/lib/cmake/conduit/ConduitConfig.cmake)
52+
message(FATAL_ERROR "Could not find Conduit CMake include file (${CONDUIT_DIR}/lib/cmake/conduit/ConduitConfig.cmake)")
53+
endif()
54+
55+
#
56+
# Use CMake's find_package to import conduit's targets
57+
# using explicit path
58+
#
59+
find_package(Conduit REQUIRED
60+
NO_DEFAULT_PATH
61+
PATHS ${CONDUIT_DIR}/lib/cmake/conduit)
62+
63+
64+
#
65+
# Use CMake's find_package to import umpire's targets
66+
# using explicit path
67+
#
68+
find_package(Umpire REQUIRED
69+
NO_DEFAULT_PATH
70+
PATHS ${UMPIRE_DIR}/lib/cmake/umpire)
71+
72+
73+
74+
75+
#######################################################
76+
# create our example
77+
#######################################################
78+
add_executable(conduit_umpire_example conduit_umpire_example.cpp)
79+
80+
# link to conduit targets
81+
target_link_libraries(conduit_umpire_example conduit::conduit umpire)
82+
83+
# if you are using conduit's python CAPI capsule interface
84+
# target_link_libraries(conduit_example conduit::conduit_python)
85+
86+
87+
# if you are using conduit's mpi features
88+
# if(NOT MPI_FOUND)
89+
# find_package(MPI COMPONENTS C)
90+
# endif()
91+
# target_link_libraries(conduit_example conduit::conduit_mpi)
92+
93+
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
// Copyright (c) Lawrence Livermore National Security, LLC and other Conduit
2+
// Project developers. See top-level LICENSE AND COPYRIGHT files for dates and
3+
// other details. No copyright assignment is required to contribute to Conduit.
4+
5+
//-----------------------------------------------------------------------------
6+
///
7+
/// file: conduit_umpire_example.cpp
8+
///
9+
//-----------------------------------------------------------------------------
10+
11+
#include <iostream>
12+
13+
#include "conduit.hpp"
14+
#include "conduit_relay.hpp"
15+
#include "conduit_blueprint.hpp"
16+
17+
#include "umpire/ResourceManager.hpp"
18+
#include "umpire/Allocator.hpp"
19+
#include "umpire/strategy/AlignedAllocator.hpp"
20+
#include "umpire/strategy/DynamicPoolList.hpp"
21+
#include "umpire/strategy/QuickPool.hpp"
22+
#include "umpire/strategy/ThreadSafeAllocator.hpp"
23+
24+
25+
class UmpireConduitAllocatorAdapter
26+
{
27+
public:
28+
static void memcpy(void* dst, const void* src, size_t size)
29+
{
30+
// Evil doings to match the Umpire API:
31+
void* unconst_src = const_cast<void*>(src);
32+
umpire::ResourceManager::getInstance().copy(dst, unconst_src, size);
33+
}
34+
35+
static void memset(void* dst, int val, size_t size)
36+
{
37+
umpire::ResourceManager::getInstance().memset(dst, val, size);
38+
}
39+
40+
conduit::index_t registerUmpireConduitAllocator(int umpireId)
41+
{
42+
conduit::index_t retval;
43+
if (m_allocators.count(umpireId) > 0)
44+
{
45+
retval = m_allocators[umpireId];
46+
}
47+
else
48+
{
49+
conduit::utils::handle_alloc_type the_allocator =
50+
[umpireId](size_t items, size_t size)
51+
{
52+
return allocate_pointer(umpireId, items, size);
53+
};
54+
conduit::utils::handle_free_type the_deallocator =
55+
[](void* ptr) { free_pointer(ptr); };
56+
retval = conduit::utils::register_allocator(the_allocator, the_deallocator);
57+
m_allocators[umpireId] = retval;
58+
}
59+
60+
return retval;
61+
}
62+
63+
private:
64+
std::map<int, conduit::index_t> m_allocators;
65+
66+
static void* allocate_pointer(int umpireId, size_t items, size_t item_size)
67+
{
68+
// Assume that the requested allocator exists
69+
auto allocator = umpire::ResourceManager::getInstance().getAllocator(umpireId);
70+
size_t bytes = items * item_size;
71+
return allocator.allocate(bytes);
72+
// May need to zero out the new allocation before returning the pointer.
73+
}
74+
75+
static void free_pointer(void * ptr)
76+
{
77+
umpire::ResourceManager::getInstance().deallocate(ptr);
78+
}
79+
};
80+
81+
int main(int argc, char **argv)
82+
{
83+
// Hello from Conduit
84+
conduit::Node about;
85+
conduit::about(about["conduit"]);
86+
conduit::relay::about(about["conduit/relay"]);
87+
conduit::relay::io::about(about["conduit/relay/io"]);
88+
conduit::blueprint::about(about["conduit/blueprint"]);
89+
90+
std::cout << about.to_yaml() << std::endl;
91+
92+
// Hello from Umpire
93+
auto& rm = umpire::ResourceManager::getInstance();
94+
umpire::Allocator alloc = rm.getAllocator("HOST");
95+
96+
std::cout << "Got allocator: " << alloc.getName() << std::endl;
97+
98+
std::cout << "Available allocators: ";
99+
for (auto s : rm.getAllocatorNames()){
100+
std::cout << s << " ";
101+
}
102+
std::cout << std::endl;
103+
104+
// Now show how to use Conduit allocators with the adapter class.
105+
// Here are some new Allocators, copied from Umpire test pool_allocator_stress.cpp.
106+
const bool run_quick{ true };
107+
const bool run_list{ true };
108+
const std::size_t one_megabyte{ 1024 * 1024 };
109+
const std::size_t one_gigabyte{ one_megabyte * 1024 };
110+
const std::size_t allocation_alignment{ 64 };
111+
const std::size_t initial_pool_size{ 12ull * one_gigabyte };
112+
const std::size_t subsequent_pool_increments{ 1024 };
113+
auto quick_allocation_pool = rm.makeAllocator<umpire::strategy::QuickPool>(
114+
"HOST_quick_pool", rm.getAllocator("HOST"), initial_pool_size, subsequent_pool_increments);
115+
auto quick_aligned_allocator = rm.makeAllocator<umpire::strategy::AlignedAllocator>(
116+
"HOST_quick_aligned", quick_allocation_pool, allocation_alignment);
117+
auto quick_alloc =
118+
rm.makeAllocator<umpire::strategy::ThreadSafeAllocator>("HOST_quick_safe_pool", quick_aligned_allocator);
119+
120+
// Conduit Nodes can use these allocators:
121+
conduit::utils::set_memcpy_handler(UmpireConduitAllocatorAdapter::memcpy);
122+
conduit::utils::set_memset_handler(UmpireConduitAllocatorAdapter::memset);
123+
UmpireConduitAllocatorAdapter ucaa;
124+
conduit::index_t qap_id = ucaa.registerUmpireConduitAllocator(quick_allocation_pool.getId());
125+
conduit::index_t qaa_id = ucaa.registerUmpireConduitAllocator(quick_aligned_allocator.getId());
126+
conduit::index_t qa_id = ucaa.registerUmpireConduitAllocator(quick_alloc.getId());
127+
128+
conduit::Node theroot; // This has the default Conduit allocator.
129+
conduit::Node& first = theroot["first"];
130+
first.set_allocator(qap_id); // Now all Node children of first will use the quick_allocation_pool.
131+
conduit::Node& second = theroot["second"];
132+
second.set_allocator(qaa_id);
133+
conduit::Node& third = theroot["third"];
134+
third.set_allocator(qa_id);
135+
136+
return 0;
137+
}
138+
139+

0 commit comments

Comments
 (0)