diff --git a/CHANGELOG.md b/CHANGELOG.md index bf2a9834e..79c12b451 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,11 @@ and this project aspires to adhere to [Semantic Versioning](https://semver.org/s ## Unreleased +### Added + +#### General +- Added support to register custom memory allocators and a custom data movement handler. This allows conduit to move trees of data between heterogenous memory spaces (e.g. CPU and GPU memory). See conduit_utils.hpp for API details. + ### Changed #### Relay diff --git a/src/libs/conduit/conduit_data_array.cpp b/src/libs/conduit/conduit_data_array.cpp index 64c9b7e9d..7f32dcde0 100644 --- a/src/libs/conduit/conduit_data_array.cpp +++ b/src/libs/conduit/conduit_data_array.cpp @@ -1625,16 +1625,14 @@ void DataArray::compact_elements_to(uint8 *data) const { // copy all elements - index_t num_ele = m_dtype.number_of_elements(); - index_t ele_bytes = DataType::default_bytes(m_dtype.id()); - uint8 *data_ptr = data; - for(index_t i=0;iset(schema); - walk_schema(this,m_schema,m_data); + walk_schema(this,m_schema,m_data,m_allocator_id); /// /// TODO: Design Issue @@ -420,7 +420,8 @@ Node::mmap(const std::string &stream_path, m_mmaped = false; m_schema->set(schema); - walk_schema(this,m_schema,m_data); + + walk_schema(this,m_schema,m_data, m_allocator_id); /// /// TODO: Design Issue @@ -466,6 +467,7 @@ Node::set_node(const Node &node) Schema *curr_schema = &this->m_schema->add_child(*itr); size_t idx = (size_t) this->m_schema->child_index(*itr); Node *curr_node = new Node(); + curr_node->set_allocator(m_allocator_id); curr_node->set_schema_ptr(curr_schema); curr_node->set_parent(this); curr_node->set(*node.m_children[idx]); @@ -481,6 +483,7 @@ Node::set_node(const Node &node) this->m_schema->append(); Schema *curr_schema = this->m_schema->child_ptr(i); Node *curr_node = new Node(); + curr_node->set_allocator(m_allocator_id); curr_node->set_schema_ptr(curr_schema); curr_node->set_parent(this); curr_node->set(*node.m_children[i]); @@ -529,9 +532,9 @@ Node::set_schema(const Schema &schema) // for this case, we need the total bytes spanned by the schema size_t nbytes =(size_t) m_schema->spanned_bytes(); allocate(nbytes); - memset(m_data,0,nbytes); + utils::conduit_memset(m_data,0,nbytes); // call walk w/ internal data pointer - walk_schema(this,m_schema,m_data); + walk_schema(this,m_schema,m_data,m_allocator_id); } //---------------------------------------------------------------------------// @@ -552,8 +555,8 @@ Node::set_data_using_schema(const Schema &schema, // for this case, we need the total bytes spanned by the schema size_t nbytes = (size_t)m_schema->spanned_bytes(); allocate(nbytes); - memcpy(m_data, data, nbytes); - walk_schema(this,m_schema,m_data); + utils::conduit_memcpy(m_data, data, nbytes); + walk_schema(this,m_schema,m_data,m_allocator_id); } //---------------------------------------------------------------------------// @@ -572,8 +575,10 @@ Node::set_data_using_dtype(const DataType &dtype, release(); m_schema->set(dtype); allocate(m_schema->spanned_bytes()); - memcpy(m_data, data, (size_t) m_schema->spanned_bytes()); - walk_schema(this,m_schema,m_data); + utils::conduit_memcpy(m_data, + data, + (size_t) m_schema->spanned_bytes()); + walk_schema(this,m_schema,m_data,m_allocator_id); } //---------------------------------------------------------------------------// @@ -596,8 +601,9 @@ void Node::set_int8(int8 data) { init(DataType::int8()); - // TODO IMP: use element_ptr() ? - *(int8*)((char*)m_data + schema().element_index(0)) = data; + utils::conduit_memcpy(element_ptr(0), + &data, + sizeof(int8)); } //---------------------------------------------------------------------------// @@ -612,7 +618,9 @@ void Node::set_int16(int16 data) { init(DataType::int16()); - *(int16*)((char*)m_data + schema().element_index(0)) = data; + utils::conduit_memcpy(element_ptr(0), + &data, + sizeof(int16)); } //---------------------------------------------------------------------------// @@ -627,7 +635,9 @@ void Node::set_int32(int32 data) { init(DataType::int32()); - *(int32*)((char*)m_data + schema().element_index(0)) = data; + utils::conduit_memcpy(element_ptr(0), + &data, + sizeof(int32)); } //---------------------------------------------------------------------------// @@ -642,7 +652,9 @@ void Node::set_int64(int64 data) { init(DataType::int64()); - *(int64*)((char*)m_data + schema().element_index(0)) = data; + utils::conduit_memcpy(element_ptr(0), + &data, + sizeof(int64)); } //---------------------------------------------------------------------------// @@ -661,7 +673,9 @@ void Node::set_uint8(uint8 data) { init(DataType::uint8()); - *(uint8*)((char*)m_data + schema().element_index(0)) = data; + utils::conduit_memcpy(element_ptr(0), + &data, + sizeof(uint8)); } //---------------------------------------------------------------------------// @@ -676,7 +690,9 @@ void Node::set_uint16(uint16 data) { init(DataType::uint16()); - *(uint16*)((char*)m_data + schema().element_index(0)) = data; + utils::conduit_memcpy(element_ptr(0), + &data, + sizeof(uint16)); } //---------------------------------------------------------------------------// @@ -691,7 +707,9 @@ void Node::set_uint32(uint32 data) { init(DataType::uint32()); - *(uint32*)((char*)m_data + schema().element_index(0)) = data; + utils::conduit_memcpy(element_ptr(0), + &data, + sizeof(uint32)); } //---------------------------------------------------------------------------// @@ -706,7 +724,9 @@ void Node::set_uint64(uint64 data) { init(DataType::uint64()); - *(uint64*)((char*)m_data + schema().element_index(0)) = data; + utils::conduit_memcpy(element_ptr(0), + &data, + sizeof(uint64)); } //---------------------------------------------------------------------------// @@ -725,7 +745,9 @@ void Node::set_float32(float32 data) { init(DataType::float32()); - *(float32*)((char*)m_data + schema().element_index(0)) = data; + utils::conduit_memcpy(element_ptr(0), + &data, + sizeof(float32)); } //---------------------------------------------------------------------------// @@ -740,7 +762,9 @@ void Node::set_float64(float64 data) { init(DataType::float64()); - *(float64*)((char*)m_data + schema().element_index(0)) = data; + utils::conduit_memcpy(element_ptr(0), + &data, + sizeof(float64)); } //---------------------------------------------------------------------------// @@ -896,7 +920,14 @@ void Node::set_int8_array(const int8_array &data) { init(DataType::int8(data.number_of_elements())); - data.compact_elements_to((uint8*)m_data); + const DataType dest_dtype = dtype(); + const DataType src_dtype = data.dtype(); + utils::conduit_memcpy_strided_elements(element_ptr(0), // dest + (size_t)dest_dtype.number_of_elements(), // num eles to copy + (size_t)dest_dtype.element_bytes(), // bytes per element + (size_t)dest_dtype.stride(), // dest stride per ele + data.element_ptr(0), // src + (size_t)src_dtype.stride()); // src stride per ele } //---------------------------------------------------------------------------// @@ -911,7 +942,14 @@ void Node::set_int16_array(const int16_array &data) { init(DataType::int16(data.number_of_elements())); - data.compact_elements_to((uint8*)m_data); + const DataType dest_dtype = dtype(); + const DataType src_dtype = data.dtype(); + utils::conduit_memcpy_strided_elements(element_ptr(0), // dest + (size_t)dest_dtype.number_of_elements(), // num eles to copy + (size_t)dest_dtype.element_bytes(), // bytes per element + (size_t)dest_dtype.stride(), // dest stride per ele + data.element_ptr(0), // src + (size_t)src_dtype.stride()); // src stride per ele } //---------------------------------------------------------------------------// @@ -926,7 +964,14 @@ void Node::set_int32_array(const int32_array &data) { init(DataType::int32(data.number_of_elements())); - data.compact_elements_to((uint8*)m_data); + const DataType dest_dtype = dtype(); + const DataType src_dtype = data.dtype(); + utils::conduit_memcpy_strided_elements(element_ptr(0), // dest + (size_t)dest_dtype.number_of_elements(), // num eles to copy + (size_t)dest_dtype.element_bytes(), // bytes per element + (size_t)dest_dtype.stride(), // dest stride per ele + data.element_ptr(0), // src + (size_t)src_dtype.stride()); // src stride per ele } //---------------------------------------------------------------------------// @@ -941,7 +986,14 @@ void Node::set_int64_array(const int64_array &data) { init(DataType::int64(data.number_of_elements())); - data.compact_elements_to((uint8*)m_data); + const DataType dest_dtype = dtype(); + const DataType src_dtype = data.dtype(); + utils::conduit_memcpy_strided_elements(element_ptr(0), // dest + (size_t)dest_dtype.number_of_elements(), // num eles to copy + (size_t)dest_dtype.element_bytes(), // bytes per element + (size_t)dest_dtype.stride(), // dest stride per ele + data.element_ptr(0), // src + (size_t)src_dtype.stride()); // src stride per ele } //---------------------------------------------------------------------------// @@ -960,7 +1012,14 @@ void Node::set_uint8_array(const uint8_array &data) { init(DataType::uint8(data.number_of_elements())); - data.compact_elements_to((uint8*)m_data); + const DataType dest_dtype = dtype(); + const DataType src_dtype = data.dtype(); + utils::conduit_memcpy_strided_elements(element_ptr(0), // dest + (size_t)dest_dtype.number_of_elements(), // num eles to copy + (size_t)dest_dtype.element_bytes(), // bytes per element + (size_t)dest_dtype.stride(), // dest stride per ele + data.element_ptr(0), // src + (size_t)src_dtype.stride()); // src stride per ele } //---------------------------------------------------------------------------// @@ -975,7 +1034,14 @@ void Node::set_uint16_array(const uint16_array &data) { init(DataType::uint16(data.number_of_elements())); - data.compact_elements_to((uint8*)m_data); + const DataType dest_dtype = dtype(); + const DataType src_dtype = data.dtype(); + utils::conduit_memcpy_strided_elements(element_ptr(0), // dest + (size_t)dest_dtype.number_of_elements(), // num eles to copy + (size_t)dest_dtype.element_bytes(), // bytes per element + (size_t)dest_dtype.stride(), // dest stride per ele + data.element_ptr(0), // src + (size_t)src_dtype.stride()); // src stride per ele } //---------------------------------------------------------------------------// @@ -990,7 +1056,14 @@ void Node::set_uint32_array(const uint32_array &data) { init(DataType::uint32(data.number_of_elements())); - data.compact_elements_to((uint8*)m_data); + const DataType dest_dtype = dtype(); + const DataType src_dtype = data.dtype(); + utils::conduit_memcpy_strided_elements(element_ptr(0), // dest + (size_t)dest_dtype.number_of_elements(), // num eles to copy + (size_t)dest_dtype.element_bytes(), // bytes per element + (size_t)dest_dtype.stride(), // dest stride per ele + data.element_ptr(0), // src + (size_t)src_dtype.stride()); // src stride per ele } //---------------------------------------------------------------------------// @@ -1005,7 +1078,14 @@ void Node::set_uint64_array(const uint64_array &data) { init(DataType::uint64(data.number_of_elements())); - data.compact_elements_to((uint8*)m_data); + const DataType dest_dtype = dtype(); + const DataType src_dtype = data.dtype(); + utils::conduit_memcpy_strided_elements(element_ptr(0), // dest + (size_t)dest_dtype.number_of_elements(), // num eles to copy + (size_t)dest_dtype.element_bytes(), // bytes per element + (size_t)dest_dtype.stride(), // dest stride per ele + data.element_ptr(0), // src + (size_t)src_dtype.stride()); // src stride per ele } //---------------------------------------------------------------------------// void @@ -1018,13 +1098,19 @@ Node::set(const uint64_array &data) //----------------------------------------------------------------------------- // floating point array types via conduit::DataArray //----------------------------------------------------------------------------- - //---------------------------------------------------------------------------// void Node::set_float32_array(const float32_array &data) { init(DataType::float32(data.number_of_elements())); - data.compact_elements_to((uint8*)m_data); + const DataType dest_dtype = dtype(); + const DataType src_dtype = data.dtype(); + utils::conduit_memcpy_strided_elements(element_ptr(0), // dest + (size_t)dest_dtype.number_of_elements(), // num eles to copy + (size_t)dest_dtype.element_bytes(), // bytes per element + (size_t)dest_dtype.stride(), // dest stride per ele + data.element_ptr(0), // src + (size_t)src_dtype.stride()); // src stride per ele } //---------------------------------------------------------------------------// @@ -1039,7 +1125,14 @@ void Node::set_float64_array(const float64_array &data) { init(DataType::float64(data.number_of_elements())); - data.compact_elements_to((uint8*)m_data); + const DataType dest_dtype = dtype(); + const DataType src_dtype = data.dtype(); + utils::conduit_memcpy_strided_elements(element_ptr(0), // dest + (size_t)dest_dtype.number_of_elements(), // num eles to copy + (size_t)dest_dtype.element_bytes(), // bytes per element + (size_t)dest_dtype.stride(), // dest stride per ele + data.element_ptr(0), // src + (size_t)src_dtype.stride()); // src stride per ele } //---------------------------------------------------------------------------// @@ -1058,7 +1151,14 @@ void Node::set(const char_array &data) { init(DataType::c_char(data.number_of_elements())); - data.compact_elements_to((uint8*)m_data); + const DataType dest_dtype = dtype(); + const DataType src_dtype = data.dtype(); + utils::conduit_memcpy_strided_elements(element_ptr(0), // dest + (size_t)dest_dtype.number_of_elements(), // num eles to copy + (size_t)dest_dtype.element_bytes(), // bytes per element + (size_t)dest_dtype.stride(), // dest stride per ele + data.element_ptr(0), // src + (size_t)src_dtype.stride()); // src stride per ele } @@ -1071,7 +1171,14 @@ void Node::set(const signed_char_array &data) { init(DataType::c_signed_char(data.number_of_elements())); - data.compact_elements_to((uint8*)m_data); + const DataType dest_dtype = dtype(); + const DataType src_dtype = data.dtype(); + utils::conduit_memcpy_strided_elements(element_ptr(0), // dest + (size_t)dest_dtype.number_of_elements(), // num eles to copy + (size_t)dest_dtype.element_bytes(), // bytes per element + (size_t)dest_dtype.stride(), // dest stride per ele + data.element_ptr(0), // src + (size_t)src_dtype.stride()); // src stride per ele } @@ -1080,7 +1187,14 @@ void Node::set(const unsigned_char_array &data) { init(DataType::c_unsigned_char(data.number_of_elements())); - data.compact_elements_to((uint8*)m_data); + const DataType dest_dtype = dtype(); + const DataType src_dtype = data.dtype(); + utils::conduit_memcpy_strided_elements(element_ptr(0), // dest + (size_t)dest_dtype.number_of_elements(), // num eles to copy + (size_t)dest_dtype.element_bytes(), // bytes per element + (size_t)dest_dtype.stride(), // dest stride per ele + data.element_ptr(0), // src + (size_t)src_dtype.stride()); // src stride per ele } //----------------------------------------------------------------------------- #endif // end use char check @@ -1093,7 +1207,14 @@ void Node::set(const short_array &data) { init(DataType::c_short(data.number_of_elements())); - data.compact_elements_to((uint8*)m_data); + const DataType dest_dtype = dtype(); + const DataType src_dtype = data.dtype(); + utils::conduit_memcpy_strided_elements(element_ptr(0), // dest + (size_t)dest_dtype.number_of_elements(), // num eles to copy + (size_t)dest_dtype.element_bytes(), // bytes per element + (size_t)dest_dtype.stride(), // dest stride per ele + data.element_ptr(0), // src + (size_t)src_dtype.stride()); // src stride per ele } //----------------------------------------------------------------------------- @@ -1101,7 +1222,14 @@ void Node::set(const unsigned_short_array&data) { init(DataType::c_unsigned_short(data.number_of_elements())); - data.compact_elements_to((uint8*)m_data); + const DataType dest_dtype = dtype(); + const DataType src_dtype = data.dtype(); + utils::conduit_memcpy_strided_elements(element_ptr(0), // dest + (size_t)dest_dtype.number_of_elements(), // num eles to copy + (size_t)dest_dtype.element_bytes(), // bytes per element + (size_t)dest_dtype.stride(), // dest stride per ele + data.element_ptr(0), // src + (size_t)src_dtype.stride()); // src stride per ele } //----------------------------------------------------------------------------- #endif // end use short check @@ -1114,7 +1242,14 @@ void Node::set(const int_array &data) { init(DataType::c_int(data.number_of_elements())); - data.compact_elements_to((uint8*)m_data); + const DataType dest_dtype = dtype(); + const DataType src_dtype = data.dtype(); + utils::conduit_memcpy_strided_elements(element_ptr(0), // dest + (size_t)dest_dtype.number_of_elements(), // num eles to copy + (size_t)dest_dtype.element_bytes(), // bytes per element + (size_t)dest_dtype.stride(), // dest stride per ele + data.element_ptr(0), // src + (size_t)src_dtype.stride()); // src stride per ele } //----------------------------------------------------------------------------- @@ -1122,7 +1257,14 @@ void Node::set(const unsigned_int_array &data) { init(DataType::c_unsigned_int(data.number_of_elements())); - data.compact_elements_to((uint8*)m_data); + const DataType dest_dtype = dtype(); + const DataType src_dtype = data.dtype(); + utils::conduit_memcpy_strided_elements(element_ptr(0), // dest + (size_t)dest_dtype.number_of_elements(), // num eles to copy + (size_t)dest_dtype.element_bytes(), // bytes per element + (size_t)dest_dtype.stride(), // dest stride per ele + data.element_ptr(0), // src + (size_t)src_dtype.stride()); // src stride per ele } //----------------------------------------------------------------------------- #endif // end use int check @@ -1135,7 +1277,14 @@ void Node::set(const long_array &data) { init(DataType::c_long(data.number_of_elements())); - data.compact_elements_to((uint8*)m_data); + const DataType dest_dtype = dtype(); + const DataType src_dtype = data.dtype(); + utils::conduit_memcpy_strided_elements(element_ptr(0), // dest + (size_t)dest_dtype.number_of_elements(), // num eles to copy + (size_t)dest_dtype.element_bytes(), // bytes per element + (size_t)dest_dtype.stride(), // dest stride per ele + data.element_ptr(0), // src + (size_t)src_dtype.stride()); // src stride per ele } //----------------------------------------------------------------------------- @@ -1143,7 +1292,14 @@ void Node::set(const unsigned_long_array &data) { init(DataType::c_unsigned_long(data.number_of_elements())); - data.compact_elements_to((uint8*)m_data); + const DataType dest_dtype = dtype(); + const DataType src_dtype = data.dtype(); + utils::conduit_memcpy_strided_elements(element_ptr(0), // dest + (size_t)dest_dtype.number_of_elements(), // num eles to copy + (size_t)dest_dtype.element_bytes(), // bytes per element + (size_t)dest_dtype.stride(), // dest stride per ele + data.element_ptr(0), // src + (size_t)src_dtype.stride()); // src stride per ele } //----------------------------------------------------------------------------- #endif // end use long check @@ -1156,7 +1312,14 @@ void Node::set(const long_long_array &data) { init(DataType::c_long_long(data.number_of_elements())); - data.compact_elements_to((uint8*)m_data); + const DataType dest_dtype = dtype(); + const DataType src_dtype = data.dtype(); + utils::conduit_memcpy_strided_elements(element_ptr(0), // dest + (size_t)dest_dtype.number_of_elements(), // num eles to copy + (size_t)dest_dtype.element_bytes(), // bytes per element + (size_t)dest_dtype.stride(), // dest stride per ele + data.element_ptr(0), // src + (size_t)src_dtype.stride()); // src stride per ele } //----------------------------------------------------------------------------- @@ -1164,7 +1327,14 @@ void Node::set(const unsigned_long_long_array &data) { init(DataType::c_unsigned_long_long(data.number_of_elements())); - data.compact_elements_to((uint8*)m_data); + const DataType dest_dtype = dtype(); + const DataType src_dtype = data.dtype(); + utils::conduit_memcpy_strided_elements(element_ptr(0), // dest + (size_t)dest_dtype.number_of_elements(), // num eles to copy + (size_t)dest_dtype.element_bytes(), // bytes per element + (size_t)dest_dtype.stride(), // dest stride per ele + data.element_ptr(0), // src + (size_t)src_dtype.stride()); // src stride per ele } //----------------------------------------------------------------------------- #endif // end use long long check @@ -1177,7 +1347,14 @@ void Node::set(const float_array &data) { init(DataType::c_float(data.number_of_elements())); - data.compact_elements_to((uint8*)m_data); + const DataType dest_dtype = dtype(); + const DataType src_dtype = data.dtype(); + utils::conduit_memcpy_strided_elements(element_ptr(0), // dest + (size_t)dest_dtype.number_of_elements(), // num eles to copy + (size_t)dest_dtype.element_bytes(), // bytes per element + (size_t)dest_dtype.stride(), // dest stride per ele + data.element_ptr(0), // src + (size_t)src_dtype.stride()); // src stride per ele } //----------------------------------------------------------------------------- #endif // end use float check @@ -1190,7 +1367,14 @@ void Node::set(const double_array &data) { init(DataType::c_double(data.number_of_elements())); - data.compact_elements_to((uint8*)m_data); + const DataType dest_dtype = dtype(); + const DataType src_dtype = data.dtype(); + utils::conduit_memcpy_strided_elements(element_ptr(0), // dest + (size_t)dest_dtype.number_of_elements(), // num eles to copy + (size_t)dest_dtype.element_bytes(), // bytes per element + (size_t)dest_dtype.stride(), // dest stride per ele + data.element_ptr(0), // src + (size_t)src_dtype.stride()); // src stride per ele } //----------------------------------------------------------------------------- #endif // end use double check @@ -1224,15 +1408,21 @@ Node::set_string(const std::string &data) // so we need to follow a 'compact_elements_to' style // of copying the data - index_t ele_bytes = dtype().element_bytes(); + size_t ele_bytes = (size_t) dtype().element_bytes(); + size_t stride = (size_t) dtype().stride(); const char *data_ptr = data.c_str(); - for(index_t i=0; i< (index_t) str_size_with_term; i++) - { - memcpy(element_ptr(i), - data_ptr, - (size_t)ele_bytes); - data_ptr+=ele_bytes; - } + + // Note: + // conduit_memcpy_strided_elements will use a single + // conduit_memcpy for cases where src and dest are compactly strided. + // + // element_ptr(0) gets us to start of dest + utils::conduit_memcpy_strided_elements(element_ptr(0), // dest ptr + str_size_with_term, // num ele + ele_bytes, // bytes per ele + stride, // dest stride + data_ptr, // src + ele_bytes); // stride } //---------------------------------------------------------------------------// @@ -1260,16 +1450,21 @@ Node::set_char8_str(const char *data) // so we need to follow a 'compact_elements_to' style // of copying the data - const char *data_ptr = data; + size_t ele_bytes = (size_t) dtype().element_bytes(); + size_t stride = (size_t) dtype().stride(); + + // Note: + // conduit_memcpy_strided_elements will use a single + // conduit_memcpy for cases where src and dest are compactly strided. + // + // element_ptr(0) gets us to start of dest + utils::conduit_memcpy_strided_elements(element_ptr(0), // dest ptr + str_size_with_term, // num ele + ele_bytes, // bytes per ele + stride, // dest stride + data, // src ptr + ele_bytes); // src stride - index_t ele_bytes = dtype().element_bytes(); - for(index_t i=0; i< (index_t)str_size_with_term; i++) - { - memcpy(element_ptr(i), - data_ptr, - (size_t)ele_bytes); - data_ptr+=ele_bytes; - } } @@ -1286,7 +1481,9 @@ void Node::set_int8_vector(const std::vector &data) { init(DataType::int8(data.size())); - memcpy(m_data,&data[0],sizeof(int8)*data.size()); + utils::conduit_memcpy(element_ptr(0), + &data[0], + sizeof(int8)*data.size()); } //---------------------------------------------------------------------------// @@ -1301,7 +1498,9 @@ void Node::set_int16_vector(const std::vector &data) { init(DataType::int16(data.size())); - memcpy(m_data,&data[0],sizeof(int16)*data.size()); + utils::conduit_memcpy(element_ptr(0), + &data[0], + sizeof(int16)*data.size()); } //---------------------------------------------------------------------------// @@ -1316,7 +1515,9 @@ void Node::set_int32_vector(const std::vector &data) { init(DataType::int32(data.size())); - memcpy(m_data,&data[0],sizeof(int32)*data.size()); + utils::conduit_memcpy(element_ptr(0), + &data[0], + sizeof(int32)*data.size()); } //---------------------------------------------------------------------------// @@ -1331,7 +1532,9 @@ void Node::set_int64_vector(const std::vector &data) { init(DataType::int64(data.size())); - memcpy(m_data,&data[0],sizeof(int64)*data.size()); + utils::conduit_memcpy(element_ptr(0), + &data[0], + sizeof(int64)*data.size()); } //---------------------------------------------------------------------------// @@ -1350,7 +1553,9 @@ void Node::set_uint8_vector(const std::vector &data) { init(DataType::uint8(data.size())); - memcpy(m_data,&data[0],sizeof(uint8)*data.size()); + utils::conduit_memcpy(element_ptr(0), + &data[0], + sizeof(uint8)*data.size()); } //---------------------------------------------------------------------------// @@ -1365,7 +1570,9 @@ void Node::set_uint16_vector(const std::vector &data) { init(DataType::uint16(data.size())); - memcpy(m_data,&data[0],sizeof(uint16)*data.size()); + utils::conduit_memcpy(element_ptr(0), + &data[0], + sizeof(uint16)*data.size()); } //---------------------------------------------------------------------------// @@ -1380,7 +1587,9 @@ void Node::set_uint32_vector(const std::vector &data) { init(DataType::uint32(data.size())); - memcpy(m_data,&data[0],sizeof(uint32)*data.size()); + utils::conduit_memcpy(element_ptr(0), + &data[0], + sizeof(uint32)*data.size()); } //---------------------------------------------------------------------------// @@ -1395,7 +1604,9 @@ void Node::set_uint64_vector(const std::vector &data) { init(DataType::uint64(data.size())); - memcpy(m_data,&data[0],sizeof(uint64)*data.size()); + utils::conduit_memcpy(element_ptr(0), + &data[0], + sizeof(uint64)*data.size()); } //---------------------------------------------------------------------------// @@ -1414,7 +1625,9 @@ void Node::set_float32_vector(const std::vector &data) { init(DataType::float32(data.size())); - memcpy(m_data,&data[0],sizeof(float32)*data.size()); + utils::conduit_memcpy(element_ptr(0), + &data[0], + sizeof(float32)*data.size()); } //---------------------------------------------------------------------------// @@ -1430,7 +1643,9 @@ void Node::set_float64_vector(const std::vector &data) { init(DataType::float64(data.size())); - memcpy(m_data,&data[0],sizeof(float64)*data.size()); + utils::conduit_memcpy(element_ptr(0), + &data[0], + sizeof(float64)*data.size()); } //---------------------------------------------------------------------------// @@ -1450,7 +1665,9 @@ void Node::set(const std::vector &data) { init(DataType::c_char(data.size())); - memcpy(m_data,&data[0],sizeof(char)*data.size()); + utils::conduit_memcpy(element_ptr(0), + &data[0], + sizeof(char)*data.size()); } //----------------------------------------------------------------------------- @@ -1460,7 +1677,9 @@ void Node::set(const std::vector &data) { init(DataType::c_char(data.size())); - memcpy(m_data,&data[0],sizeof(signed char)*data.size()); + utils::conduit_memcpy(element_ptr(0), + &data[0], + sizeof(signed char)*data.size()); } //----------------------------------------------------------------------------- @@ -1468,7 +1687,9 @@ void Node::set(const std::vector &data) { init(DataType::c_unsigned_char(data.size())); - memcpy(m_data,&data[0],sizeof(unsigned char)*data.size()); + utils::conduit_memcpy(element_ptr(0), + &data[0], + sizeof(unsigned char)*data.size()); } //----------------------------------------------------------------------------- #endif // end use char check @@ -1481,7 +1702,9 @@ void Node::set(const std::vector &data) { init(DataType::c_short(data.size())); - memcpy(m_data,&data[0],sizeof(short)*data.size()); + utils::conduit_memcpy(element_ptr(0), + &data[0], + sizeof(short)*data.size()); } //----------------------------------------------------------------------------- @@ -1489,7 +1712,9 @@ void Node::set(const std::vector &data) { init(DataType::c_unsigned_short(data.size())); - memcpy(m_data,&data[0],sizeof(unsigned short)*data.size()); + utils::conduit_memcpy(element_ptr(0), + &data[0], + sizeof(unsigned short)*data.size()); } //----------------------------------------------------------------------------- #endif // end use short check @@ -1502,7 +1727,9 @@ void Node::set(const std::vector &data) { init(DataType::c_int(data.size())); - memcpy(m_data,&data[0],sizeof(int)*data.size()); + utils::conduit_memcpy(element_ptr(0), + &data[0], + sizeof(int)*data.size()); } //----------------------------------------------------------------------------- @@ -1510,7 +1737,9 @@ void Node::set(const std::vector &data) { init(DataType::c_unsigned_int(data.size())); - memcpy(m_data,&data[0],sizeof(unsigned int)*data.size()); + utils::conduit_memcpy(element_ptr(0), + &data[0], + sizeof(unsigned int)*data.size()); } //----------------------------------------------------------------------------- #endif // end use int check @@ -1523,7 +1752,9 @@ void Node::set(const std::vector &data) { init(DataType::c_long(data.size())); - memcpy(m_data,&data[0],sizeof(long)*data.size()); + utils::conduit_memcpy(element_ptr(0), + &data[0], + sizeof(long)*data.size()); } //----------------------------------------------------------------------------- @@ -1531,7 +1762,9 @@ void Node::set(const std::vector &data) { init(DataType::c_unsigned_long(data.size())); - memcpy(m_data,&data[0],sizeof(unsigned long)*data.size()); + utils::conduit_memcpy(element_ptr(0), + &data[0], + sizeof(unsigned long)*data.size()); } //----------------------------------------------------------------------------- #endif // end use long check @@ -1544,7 +1777,9 @@ void Node::set(const std::vector &data) { init(DataType::c_long_long(data.size())); - memcpy(m_data,&data[0],sizeof(long long)*data.size()); + utils::conduit_memcpy(element_ptr(0), + &data[0], + sizeof(long long)*data.size()); } //----------------------------------------------------------------------------- @@ -1552,7 +1787,9 @@ void Node::set(const std::vector &data) { init(DataType::c_unsigned_long_long(data.size())); - memcpy(m_data,&data[0],sizeof(unsigned long long)*data.size()); + utils::conduit_memcpy(element_ptr(0), + &data[0], + sizeof(unsigned long long)*data.size()); } //----------------------------------------------------------------------------- #endif // end use long long check @@ -1565,7 +1802,9 @@ void Node::set(const std::vector &data) { init(DataType::c_float(data.size())); - memcpy(m_data,&data[0],sizeof(float)*data.size()); + utils::conduit_memcpy(element_ptr(0), + &data[0], + sizeof(float)*data.size()); } //----------------------------------------------------------------------------- #endif // end use float check @@ -1578,7 +1817,9 @@ void Node::set(const std::vector &data) { init(DataType::c_double(data.size())); - memcpy(m_data,&data[0],sizeof(double)*data.size()); + utils::conduit_memcpy(element_ptr(0), + &data[0], + sizeof(double)*data.size()); } //----------------------------------------------------------------------------- #endif // end use double check @@ -1616,12 +1857,9 @@ void Node::set_int8_initializer_list(const std::initializer_list &data) { init(DataType::int8(data.size())); - int8 *data_ptr = (int8*)m_data; - for (auto val : data) - { - *data_ptr = val; - data_ptr++; - } + utils::conduit_memcpy(element_ptr(0), + (void*)data.begin(), + sizeof(int8) * data.size()); } //----------------------------------------------------------------------------- @@ -1638,12 +1876,9 @@ void Node::set_int16_initializer_list(const std::initializer_list &data) { init(DataType::int16(data.size())); - int16 *data_ptr = (int16*)m_data; - for (auto val : data) - { - *data_ptr = val; - data_ptr++; - } + utils::conduit_memcpy(element_ptr(0), + (void*)data.begin(), + sizeof(int16) * data.size()); } //----------------------------------------------------------------------------- @@ -1660,12 +1895,9 @@ void Node::set_int32_initializer_list(const std::initializer_list &data) { init(DataType::int32(data.size())); - int32 *data_ptr = (int32*)m_data; - for (auto val : data) - { - *data_ptr = val; - data_ptr++; - } + utils::conduit_memcpy(element_ptr(0), + (void*)data.begin(), + sizeof(int32) * data.size()); } //----------------------------------------------------------------------------- @@ -1683,12 +1915,9 @@ void Node::set_int64_initializer_list(const std::initializer_list &data) { init(DataType::int64(data.size())); - int64 *data_ptr = (int64*)m_data; - for (auto val : data) - { - *data_ptr = val; - data_ptr++; - } + utils::conduit_memcpy(element_ptr(0), + (void*)data.begin(), + sizeof(int64) * data.size()); } //----------------------------------------------------------------------------- @@ -1710,12 +1939,9 @@ void Node::set_uint8_initializer_list(const std::initializer_list &data) { init(DataType::uint8(data.size())); - uint8 *data_ptr = (uint8*)m_data; - for (auto val : data) - { - *data_ptr = val; - data_ptr++; - } + utils::conduit_memcpy(element_ptr(0), + (void*)data.begin(), + sizeof(uint8) * data.size()); } //----------------------------------------------------------------------------- @@ -1732,12 +1958,9 @@ void Node::set_uint16_initializer_list(const std::initializer_list &data) { init(DataType::uint16(data.size())); - uint16 *data_ptr = (uint16*)m_data; - for (auto val : data) - { - *data_ptr = val; - data_ptr++; - } + utils::conduit_memcpy(element_ptr(0), + (void*)data.begin(), + sizeof(uint16) * data.size()); } //----------------------------------------------------------------------------- @@ -1754,12 +1977,9 @@ void Node::set_uint32_initializer_list(const std::initializer_list &data) { init(DataType::uint32(data.size())); - uint32 *data_ptr = (uint32*)m_data; - for (auto val : data) - { - *data_ptr = val; - data_ptr++; - } + utils::conduit_memcpy(element_ptr(0), + (void*)data.begin(), + sizeof(uint32) * data.size()); } //----------------------------------------------------------------------------- @@ -1776,12 +1996,9 @@ void Node::set_uint64_initializer_list(const std::initializer_list &data) { init(DataType::uint64(data.size())); - uint64 *data_ptr = (uint64*)m_data; - for (auto val : data) - { - *data_ptr = val; - data_ptr++; - } + utils::conduit_memcpy(element_ptr(0), + (void*)data.begin(), + sizeof(uint64) * data.size()); } //----------------------------------------------------------------------------- @@ -1803,12 +2020,9 @@ void Node::set_float32_initializer_list(const std::initializer_list &data) { init(DataType::float32(data.size())); - float32 *data_ptr = (float32*)m_data; - for (auto val : data) - { - *data_ptr = val; - data_ptr++; - } + utils::conduit_memcpy(element_ptr(0), + (void*)data.begin(), + sizeof(float32) * data.size()); } //----------------------------------------------------------------------------- @@ -1825,12 +2039,9 @@ void Node::set_float64_initializer_list(const std::initializer_list &data) { init(DataType::float64(data.size())); - float64 *data_ptr = (float64*)m_data; - for (auto val : data) - { - *data_ptr = val; - data_ptr++; - } + utils::conduit_memcpy(element_ptr(0), + (void*)data.begin(), + sizeof(float64) * data.size()); } //----------------------------------------------------------------------------- @@ -1849,12 +2060,9 @@ void Node::set(const std::initializer_list &data) { init(DataType::c_char(data.size())); - char *data_ptr = (char*)m_data; - for (auto val : data) - { - *data_ptr = val; - data_ptr++; - } + utils::conduit_memcpy(element_ptr(0), + (void*)data.begin(), + sizeof(char) * data.size()); } //----------------------------------------------------------------------------- @@ -1864,13 +2072,9 @@ void Node::set(const std::initializer_list &data) { init(DataType::c_char(data.size())); - signed char *data_ptr = (signed char*)m_data; - for (auto val : data) - { - *data_ptr = val; - data_ptr++; - } - + utils::conduit_memcpy(element_ptr(0), + (void*)data.begin(), + sizeof(signed char) * data.size()); } //----------------------------------------------------------------------------- @@ -1878,13 +2082,9 @@ void Node::set(const std::initializer_list &data) { init(DataType::c_unsigned_char(data.size())); - unsigned char *data_ptr = (unsigned char*)m_data; - for (auto val : data) - { - *data_ptr = val; - data_ptr++; - } - + utils::conduit_memcpy(element_ptr(0), + (void*)data.begin(), + sizeof(unsigned char) * data.size()); } //----------------------------------------------------------------------------- @@ -1898,12 +2098,9 @@ void Node::set(const std::initializer_list &data) { init(DataType::c_short(data.size())); - short *data_ptr = (short*)m_data; - for (auto val : data) - { - *data_ptr = val; - data_ptr++; - } + utils::conduit_memcpy(element_ptr(0), + (void*)data.begin(), + sizeof(short) * data.size()); } //----------------------------------------------------------------------------- @@ -1911,12 +2108,9 @@ void Node::set(const std::initializer_list &data) { init(DataType::c_unsigned_short(data.size())); - unsigned short *data_ptr = (unsigned short*)m_data; - for (auto val : data) - { - *data_ptr = val; - data_ptr++; - } + utils::conduit_memcpy(element_ptr(0), + (void*)data.begin(), + sizeof(unsigned short) * data.size()); } //----------------------------------------------------------------------------- @@ -1930,12 +2124,9 @@ void Node::set(const std::initializer_list &data) { init(DataType::c_int(data.size())); - int *data_ptr = (int*)m_data; - for (auto val : data) - { - *data_ptr = val; - data_ptr++; - } + utils::conduit_memcpy(element_ptr(0), + (void*)data.begin(), + sizeof(int) * data.size()); } //----------------------------------------------------------------------------- @@ -1943,12 +2134,9 @@ void Node::set(const std::initializer_list &data) { init(DataType::c_unsigned_int(data.size())); - unsigned int *data_ptr = (unsigned int*)m_data; - for (auto val : data) - { - *data_ptr = val; - data_ptr++; - } + utils::conduit_memcpy(element_ptr(0), + (void*)data.begin(), + sizeof(unsigned int) * data.size()); } //----------------------------------------------------------------------------- @@ -1962,12 +2150,9 @@ void Node::set(const std::initializer_list &data) { init(DataType::c_long(data.size())); - long *data_ptr = (long*)m_data; - for (auto val : data) - { - *data_ptr = val; - data_ptr++; - } + utils::conduit_memcpy(element_ptr(0), + (void*)data.begin(), + sizeof(long) * data.size()); } //----------------------------------------------------------------------------- @@ -1975,12 +2160,9 @@ void Node::set(const std::initializer_list &data) { init(DataType::c_unsigned_long(data.size())); - unsigned long *data_ptr = (unsigned long*)m_data; - for (auto val : data) - { - *data_ptr = val; - data_ptr++; - } + utils::conduit_memcpy(element_ptr(0), + (void*)data.begin(), + sizeof(unsigned long) * data.size()); } //----------------------------------------------------------------------------- @@ -1994,12 +2176,9 @@ void Node::set(const std::initializer_list &data) { init(DataType::c_long_long(data.size())); - long long *data_ptr = (long long*)m_data; - for (auto val : data) - { - *data_ptr = val; - data_ptr++; - } + utils::conduit_memcpy(element_ptr(0), + (void*)data.begin(), + sizeof(long long) * data.size()); } //----------------------------------------------------------------------------- @@ -2007,12 +2186,9 @@ void Node::set(const std::initializer_list &data) { init(DataType::c_unsigned_long_long(data.size())); - unsigned long long *data_ptr = (unsigned long long*)m_data; - for (auto val : data) - { - *data_ptr = val; - data_ptr++; - } + utils::conduit_memcpy(element_ptr(0), + (void*)data.begin(), + sizeof(unsigned long long) * data.size()); } //----------------------------------------------------------------------------- @@ -2026,12 +2202,9 @@ void Node::set(const std::initializer_list &data) { init(DataType::c_float(data.size())); - float *data_ptr = (float*)m_data; - for (auto val : data) - { - *data_ptr = val; - data_ptr++; - } + utils::conduit_memcpy(element_ptr(0), + (void*)data.begin(), + sizeof(float) * data.size()); } //----------------------------------------------------------------------------- #endif // end use float check @@ -2044,12 +2217,9 @@ void Node::set(const std::initializer_list &data) { init(DataType::c_double(data.size())); - double *data_ptr = (double*)m_data; - for (auto val : data) - { - *data_ptr = val; - data_ptr++; - } + utils::conduit_memcpy(element_ptr(0), + (void*)data.begin(), + sizeof(double) * data.size()); } //----------------------------------------------------------------------------- #endif // end use double check @@ -4385,7 +4555,7 @@ Node::set_external_data_using_schema(const Schema &schema, { reset(); m_schema->set(schema); - walk_schema(this,m_schema,data); + walk_schema(this,m_schema,data,m_allocator_id); } //---------------------------------------------------------------------------// @@ -8329,7 +8499,7 @@ Node::compact_to(Node &n_dest) const uint8 *n_dest_data = (uint8*)n_dest.m_data; compact_to(n_dest_data,0); // need node structure - walk_schema(&n_dest,n_dest.m_schema,n_dest_data); + walk_schema(&n_dest,n_dest.m_schema,n_dest_data,m_allocator_id); } //----------------------------------------------------------------------------- @@ -8394,14 +8564,19 @@ Node::update(const Node &n_src) (this->dtype().number_of_elements() >= n_src.dtype().number_of_elements())) { - for(index_t idx = 0; - idx < n_src.dtype().number_of_elements(); - idx++) - { - memcpy(element_ptr(idx), - n_src.element_ptr(idx), - (size_t)this->dtype().element_bytes()); - } + size_t ele_bytes = (size_t) dtype().element_bytes(); + size_t stride = (size_t) dtype().stride(); + size_t num_ele = (size_t) n_src.dtype().number_of_elements(); + size_t src_stride = (size_t) n_src.dtype().stride(); + // + // Note: conduit_memcpy_strided_elements will use a single + // memcpy when src and dest are compactly strided + utils::conduit_memcpy_strided_elements(element_ptr(0), // dest ptr + num_ele, // num ele + ele_bytes, // dest bytes per ele + stride, // dest stride + n_src.element_ptr(0), // src ptr + src_stride); // src stride } else // not compatible { @@ -8458,14 +8633,19 @@ Node::update_compatible(const Node &n_src) (this->dtype().number_of_elements() >= n_src.dtype().number_of_elements())) { - for(index_t idx = 0; - idx < n_src.dtype().number_of_elements(); - idx++) - { - memcpy(element_ptr(idx), - n_src.element_ptr(idx), - (size_t)this->dtype().element_bytes()); - } + size_t ele_bytes = (size_t) dtype().element_bytes(); + size_t stride = (size_t) dtype().stride(); + size_t num_ele = (size_t) n_src.dtype().number_of_elements(); + size_t src_stride = (size_t) n_src.dtype().stride(); + // + // Note: conduit_memcpy_strided_elements will use a single + // memcpy when src and dest are compactly strided + utils::conduit_memcpy_strided_elements(element_ptr(0), // dest ptr + num_ele, // num ele + ele_bytes, // dest bytes per ele + stride, // dest stride + n_src.element_ptr(0), // src ptr + src_stride); // src stride } } } @@ -12802,8 +12982,11 @@ Node::to_base64_json(std::ostream &os, std::ios_base::fmtflags prev_stream_flags(os.flags()); os.precision(15); + // // we need compact data - // TODO check if already compact + contig + // + // TODO check to support fast path if already + // compact + contig and host accessible? Node n; compact_to(n); @@ -12813,9 +12996,11 @@ Node::to_base64_json(std::ostream &os, Node bb64_data; bb64_data.set(DataType::char8_str(enc_buff_size)); + // since we use compact_to(n) above, the data will always compact + // and on the host, so we can use it directly in utils::base64_encode const char *src_ptr = (const char*)n.data_ptr(); char *dest_ptr = (char*)bb64_data.data_ptr(); - memset(dest_ptr,0,(size_t)enc_buff_size); + utils::conduit_memset(dest_ptr,0,(size_t)enc_buff_size); utils::base64_encode(src_ptr,nbytes,dest_ptr); @@ -13267,6 +13452,7 @@ Node::add_child(const std::string &name) Schema &child_schema = m_schema->add_child(name); Schema *child_ptr = &child_schema; Node *child_node = new Node(); + child_node->set_allocator(m_allocator_id); child_node->set_schema_ptr(child_ptr); child_node->m_parent = this; m_children.push_back(child_node); @@ -13453,8 +13639,11 @@ Node::fetch(const std::string &path) { Schema *schema_ptr = m_schema->fetch_ptr(p_curr); Node *curr_node = new Node(); + curr_node->set_allocator(m_allocator_id); curr_node->set_schema_ptr(schema_ptr); curr_node->m_parent = this; + // current allocator is inherited + curr_node->set_allocator(m_allocator_id); m_children.push_back(curr_node); idx = m_children.size() - 1; } @@ -13627,6 +13816,7 @@ Node::append() Schema *schema_ptr = m_schema->child_ptr(idx); Node *res_node = new Node(); + res_node->set_allocator(m_allocator_id); res_node->set_schema_ptr(schema_ptr); res_node->m_parent=this; m_children.push_back(res_node); @@ -15653,6 +15843,47 @@ Node::as_long_double_array() const // //----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// +// -- begin definition of Node allocator selection methods -- +// +//----------------------------------------------------------------------------- +void +Node::set_allocator(index_t allocator_id) +{ + if(allocator_id != m_allocator_id) + { + reset(); + // TODO: add check for allocator exists + m_allocator_id = allocator_id; + } +} + +//----------------------------------------------------------------------------- +void +Node::reset_allocator() +{ + if(m_allocator_id != 0) + { + reset(); + m_allocator_id = 0; + } +} + +//----------------------------------------------------------------------------- +index_t +Node::allocator() +{ + return m_allocator_id; +} + +//----------------------------------------------------------------------------- +// +// -- end definition of Node allocator selection methods -- +// +//----------------------------------------------------------------------------- + //----------------------------------------------------------------------------- // // -- begin definition of Interface Warts -- @@ -15683,7 +15914,6 @@ Node::set_data_ptr(void *data) m_data = data; } - //----------------------------------------------------------------------------- // // -- end definition of Interface Warts -- @@ -15924,7 +16154,8 @@ Node::allocate(const DataType &dtype) void Node::allocate(index_t dsize) { - m_data = calloc((size_t)dsize,(size_t)1); + m_data = utils::conduit_allocate((size_t)dsize, (size_t)1, m_allocator_id); + // calloc((size_t)dsize,(size_t)1); m_data_size = dsize; m_alloced = true; m_mmaped = false; @@ -15965,7 +16196,7 @@ Node::release() if(dtype().id() != DataType::EMPTY_ID) { // clean up our storage - free(m_data); + utils::conduit_free(m_data, m_allocator_id); m_data = NULL; m_data_size = 0; m_alloced = false; @@ -16030,6 +16261,7 @@ Node::init_defaults() m_owns_schema = true; m_parent = NULL; + m_allocator_id = 0; } //----------------------------------------------------------------------------- @@ -16094,9 +16326,10 @@ Node::identify_protocol(const std::string &path, //---------------------------------------------------------------------------// void -Node::walk_schema(Node *node, - Schema *schema, - void *data) +Node::walk_schema(Node *node, + Schema *schema, + void *data, + index_t allocator_id) { // we can have an object, list, or leaf node->set_data_ptr(data); @@ -16108,9 +16341,10 @@ Node::walk_schema(Node *node, std::string curr_name = schema->object_order()[i]; Schema *curr_schema = &schema->add_child(curr_name); Node *curr_node = new Node(); + curr_node->set_allocator(allocator_id); curr_node->set_schema_ptr(curr_schema); curr_node->set_parent(node); - walk_schema(curr_node,curr_schema,data); + walk_schema(curr_node,curr_schema,data,allocator_id); node->append_node_ptr(curr_node); } } @@ -16121,9 +16355,10 @@ Node::walk_schema(Node *node, { Schema *curr_schema = schema->child_ptr(i); Node *curr_node = new Node(); + curr_node->set_allocator(allocator_id); curr_node->set_schema_ptr(curr_schema); curr_node->set_parent(node); - walk_schema(curr_node,curr_schema,data); + walk_schema(curr_node,curr_schema,data,allocator_id); node->append_node_ptr(curr_node); } } @@ -16149,6 +16384,7 @@ Node::mirror_node(Node *node, Schema *curr_schema = &schema->add_child(curr_name); Node *curr_node = new Node(); const Node *curr_src = src->child_ptr(i); + curr_node->set_allocator(node->allocator()); curr_node->set_schema_ptr(curr_schema); curr_node->set_parent(node); mirror_node(curr_node,curr_schema,curr_src); @@ -16163,6 +16399,7 @@ Node::mirror_node(Node *node, Schema *curr_schema = schema->child_ptr(i); Node *curr_node = new Node(); const Node *curr_src = src->child_ptr(i); + curr_node->set_allocator(node->allocator()); curr_node->set_schema_ptr(curr_schema); curr_node->set_parent(node); mirror_node(curr_node,curr_schema,curr_src); @@ -16212,21 +16449,28 @@ Node::compact_elements_to(uint8 *data) const dtype_id == DataType::LIST_ID || dtype_id == DataType::EMPTY_ID) { - // TODO: error + // TODO: error ? + // NOTE: WE RELY ON THIS NOT BEING AN ERROR + // FIND OUT WHY! (https://github.com/LLNL/conduit/issues/780) + // CONDUIT_ERROR("Node::compact_elements_to cannot compact " + // " Object, List, or Empty Node to array."); } else { - // copy all elements - index_t num_ele = dtype().number_of_elements(); - index_t ele_bytes = DataType::default_bytes(dtype_id); - uint8 *data_ptr = data; - for(index_t i=0;i #include #include +#include // define proper path sep @@ -75,6 +76,242 @@ namespace conduit namespace utils { +//----------------------------------------------------------------------------- +void * +default_alloc_handler(size_t items, size_t item_size) +{ + return calloc(items, item_size); +} + +//----------------------------------------------------------------------------- +void +default_free_handler(void *data_ptr) +{ + free(data_ptr); +} + +//----------------------------------------------------------------------------- +void +default_memset_handler(void * ptr, int value, size_t num ) +{ + memset(ptr,value,num); +} + +//----------------------------------------------------------------------------- +void +default_memcpy_handler(void * destination, const void * source, size_t num) +{ + memcpy(destination,source,num); +} + + +//----------------------------------------------------------------------------- +// Private namespace member that holds our memcpy callback. +void (*conduit_handle_memcpy)(void * destination, + const void * source, + size_t num) = default_memcpy_handler; + +//----------------------------------------------------------------------------- +// Private namespace member that holds our memset callback. +void (*conduit_handle_memset)(void * ptr, + int value, + size_t num ) = default_memset_handler; + +//----------------------------------------------------------------------------- +void +set_memcpy_handler(void(*conduit_hnd_copy)(void*, + const void *, + size_t)) +{ + conduit_handle_memcpy = conduit_hnd_copy; +} + +//----------------------------------------------------------------------------- +void +set_memset_handler(void(*conduit_hnd_memset)(void*, + int, + size_t)) +{ + conduit_handle_memset = conduit_hnd_memset; +} + +namespace detail +{ + // + // AllocManager: A singleton that holds our alloc and free function maps + // + // + // NOTE: THE SINGLETON INSTNACE IS INTENTIONALLY LEAKED! + // + // These maps are used by Node instances to alloc and free + // memory, they need to exist as long as any Node object exists! + // + // We are doing static init correctly here, so we + // avoid the C++ static obj init fiasco: + // https://isocpp.org/wiki/faq/ctors#static-init-order + // + // However, we still can't apply fine grained control + // to when these objects are cleaned up. This means + // if you use a statically initialized Node object + // you could get a crash on exit + // (unless we leak the singleton) + // + // One strategy to avoid this is to move everything + // into the same compilation unit. We tried this + // but we still hit an on exit cleanup where + // the alloc maps were destructed, but a static Node + // object still needed to cleanup. + // + // If leaking this singleton offends your sensibilities, + // I am sorry. Ideally, these would be cleaned up on + // exit absolutely last - meaning you could never use + // those few precious bytes for anything else. + // + class AllocManager { + + public: + static AllocManager& instance() + { + // + // NOTE: THIS IS INTENTIONALLY LEAKED + // See note above. + // + static AllocManager *inst = new AllocManager(); + return *inst; + } + + // reg interface + index_t register_allocator(void*(*conduit_hnd_allocate) (size_t, size_t), + void(*conduit_hnd_free)(void *)) + { + m_allocator_map[m_allocator_id] = conduit_hnd_allocate; + m_free_map[m_allocator_id] = conduit_hnd_free; + return m_allocator_id++; + } + + // alloc interface + void *allocate(size_t n_items, + size_t item_size, + index_t allocator_id) + { + return m_allocator_map[allocator_id](n_items, item_size); + } + + // free interface + void free(void *ptr, + index_t allocator_id) + { + m_free_map[allocator_id](ptr); + } + + private: + // constructor + AllocManager() + : m_allocator_map(), + m_free_map() + { + // register default handlers + m_allocator_map[0] = &default_alloc_handler; + m_free_map[0] = &default_free_handler; + + m_allocator_id = 1; + + } + + // destructor + ~AllocManager() + { + + } + + // vars + index_t m_allocator_id; + std::map m_allocator_map; + std::map m_free_map; + + }; +} + +//----------------------------------------------------------------------------- +index_t +register_allocator(void*(*conduit_hnd_allocate) (size_t, size_t), + void(*conduit_hnd_free)(void *)) +{ + return detail::AllocManager::instance().register_allocator(conduit_hnd_allocate, + conduit_hnd_free); +} + + +//----------------------------------------------------------------------------- +void * +conduit_allocate(size_t n_items, + size_t item_size, + index_t allocator_id) +{ + return detail::AllocManager::instance().allocate(n_items, + item_size, + allocator_id); +} + +//----------------------------------------------------------------------------- +void +conduit_free(void *ptr, + index_t allocator_id) +{ + detail::AllocManager::instance().free(ptr,allocator_id); +} + +//----------------------------------------------------------------------------- +void +conduit_memcpy(void *destination, + const void *source, + size_t num) +{ + conduit_handle_memcpy(destination,source,num); +} + + +//----------------------------------------------------------------------------- +void conduit_memset(void *ptr, + int value, + size_t num) +{ + conduit_handle_memset(ptr,value,num); +} +//----------------------------------------------------------------------------- +void +conduit_memcpy_strided_elements(void *dest, + size_t num_elements, + size_t ele_bytes, + size_t dest_stride, + const void *src, + size_t src_stride) +{ + // source and dest are compact + if( dest_stride == ele_bytes && src_stride == ele_bytes) + { + utils::conduit_memcpy(dest, + src, + ele_bytes * num_elements); + } + else // the source or dest are strided in a non compact way + { + char *src_data_ptr = (char*) src; + char *dest_data_ptr = (char*) dest; + for(size_t i=0; i< num_elements; i++) + { + // copy next strided element + utils::conduit_memcpy(dest_data_ptr, + src_data_ptr, + ele_bytes); + // move by src stride + src_data_ptr += src_stride; + // move by dest stride + dest_data_ptr += dest_stride; + } + } +} + //----------------------------------------------------------------------------- // default info message handler callback, simply prints to std::cout. void diff --git a/src/libs/conduit/conduit_utils.hpp b/src/libs/conduit/conduit_utils.hpp index a31d00d4d..8a0e5ce8c 100644 --- a/src/libs/conduit/conduit_utils.hpp +++ b/src/libs/conduit/conduit_utils.hpp @@ -263,6 +263,76 @@ namespace utils conduit_error_handler CONDUIT_API error_handler(); + +//----------------------------------------------------------------------------- +/// Primary interface used by the conduit API to move memory. +//----------------------------------------------------------------------------- + + // conduit uses a single pair of memset and memcpy functions to + // manage data movement. + + // this strategy allows downstream users to support complex cases + // like moving between memory spaces not accessible on the host. + // + // These methods aren't bound to allocators b/c allocators + // won't be tied into all of the places where source and dest pointers + // need to be located. + // + void CONDUIT_API set_memcpy_handler(void(*conduit_hnd_copy)(void*, + const void *, + size_t)); + void CONDUIT_API set_memset_handler(void(*conduit_hnd_memset)(void*, + int, + size_t)); + + void CONDUIT_API default_memset_handler(void *ptr, + int value, + size_t num); + + void CONDUIT_API default_memcpy_handler(void *destination, + const void *source, + size_t num); + + // general memcpy interface used by conduit + void CONDUIT_API conduit_memcpy(void *destination, + const void *source, + size_t num); + + void CONDUIT_API conduit_memcpy_strided_elements(void *dest, + size_t num_elements, + size_t ele_bytes, + size_t dest_stride, + const void *src, + size_t src_stride); + + // general memset interface used by conduit + // NOTE (cyrush): The default memset returns the orig pointer, but + // other allocators like cuda do not. + // TODO: GIVEN THIS DO WE NEED TO PASS AN ALLOC_ID? + void CONDUIT_API conduit_memset(void * ptr, + int value, + size_t num); + +//----------------------------------------------------------------------------- +/// Primary interface used by the conduit API to allocate memory. +//----------------------------------------------------------------------------- + + // register a custom allocator + index_t CONDUIT_API register_allocator(void*(*conduit_hnd_allocate) (size_t, size_t), + void(*conduit_hnd_free)(void *)); + + // generic allocate interface + // allocator_id 0 is the default + void CONDUIT_API * conduit_allocate(size_t num_items, + size_t item_size, + index_t allocator_id = 0); + + // generic free interface + void CONDUIT_API conduit_free(void *data_ptr, + index_t allocator_id = 0); + + + //----------------------------------------------------------------------------- /// Helpers for common string splitting operations. //----------------------------------------------------------------------------- @@ -388,7 +458,7 @@ namespace utils //----------------------------------------------------------------------------- /// fmt style string formatting helpers -//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- std::string CONDUIT_API format(const std::string &s, const conduit::Node &args); diff --git a/src/tests/conduit/CMakeLists.txt b/src/tests/conduit/CMakeLists.txt index a52ec7b11..7192dec07 100644 --- a/src/tests/conduit/CMakeLists.txt +++ b/src/tests/conduit/CMakeLists.txt @@ -16,6 +16,7 @@ set(BASIC_TESTS t_conduit_smoke t_conduit_node t_conduit_node_parent t_conduit_node_compare + t_conduit_node_static_init t_conduit_serialize t_conduit_array t_conduit_list_of @@ -39,7 +40,7 @@ set(BASIC_TESTS t_conduit_smoke t_conduit_schema t_conduit_error t_conduit_log - t_conduit_utils + t_conduit_mem_allocator t_conduit_intro_cpp_example) diff --git a/src/tests/conduit/t_conduit_array.cpp b/src/tests/conduit/t_conduit_array.cpp index 23233bedf..44cbcd911 100644 --- a/src/tests/conduit/t_conduit_array.cpp +++ b/src/tests/conduit/t_conduit_array.cpp @@ -60,7 +60,7 @@ TEST(conduit_array, basic_construction) da_3[0] = -16; std::cout << da_3.to_string() << std::endl; - + // test other variants of to_string and to stream, etc da_3.to_string_stream(std::cout); da_3.to_json_stream(std::cout); @@ -90,7 +90,7 @@ TEST(conduit_array, array_stride_int8) std::cout << (int64) data[i] << " "; } std::cout << std::endl; - + DataType arr_t(DataType::INT8_ID, 10, 0, @@ -115,7 +115,7 @@ TEST(conduit_array, array_stride_int8) arr[1] = 100; EXPECT_EQ(data[2],100); - + std::cout << "Full Data" << std::endl; for(int i=0;i<20;i++) @@ -130,18 +130,18 @@ TEST(conduit_array, array_stride_int8) true); /// true for external int8_array arr_2 = n2.as_int8_array(); - + for(int i=0;i<10;i++) { // note: the cast is for proper printing to std::out std::cout << "value[" << i << "] = " << ((int64)arr_2[i] ) << std::endl; } std::cout << std::endl; - + EXPECT_EQ(arr_2[0],0); - EXPECT_EQ(arr_2[9],-9); + EXPECT_EQ(arr_2[9],-9); -} +} //----------------------------------------------------------------------------- TEST(conduit_array, array_stride_int8_external) @@ -164,7 +164,7 @@ TEST(conduit_array, array_stride_int8_external) std::cout << (int64) data[i] << " "; } std::cout << std::endl; - + Node n; n["value"].set_external(data); @@ -208,7 +208,7 @@ TEST(conduit_array, set_using_ptrs) Node n; - + // int8_array n["vint8"].set(DataType::int8(10)); n["vint8"].as_int8_array().set(&v_int8[0],10); @@ -334,7 +334,7 @@ TEST(conduit_array, set_using_data_array) Node n; - + // int8_array n["vint8"].set(DataType::int8(10)); n["vint8"].as_int8_array().set(va_int8); @@ -448,7 +448,7 @@ TEST(conduit_array, set_using_std_vectors) Node n; - + // int8_array n["vint8"].set(DataType::int8(10)); n["vint8"].as_int8_array().set(v_int8); @@ -702,7 +702,33 @@ TEST(conduit_array, fill) } +//----------------------------------------------------------------------------- +TEST(conduit_array, compact_to_bytes) +{ + std::vector vals(8,0); + + vals[0] = 3; + vals[2] = 7; + vals[4] = 9; + vals[6] = 11; + + // stride every 16 bytes (2 int64s) + int64_array varray(&vals[0], + DataType::int64(4,0,16)); + + std::cout << varray.to_string() << std::endl; + + uint8 buff[64*4]; + + varray.compact_elements_to(buff); + + int64 *vals_cpt = (int64*)buff; + EXPECT_EQ(vals_cpt[0],3); + EXPECT_EQ(vals_cpt[1],7); + EXPECT_EQ(vals_cpt[2],9); + EXPECT_EQ(vals_cpt[3],11); +} //----------------------------------------------------------------------------- #ifdef CONDUIT_USE_CXX11 @@ -718,7 +744,7 @@ TEST(conduit_array, summary_stats) int64_array va_int64(&v_int64[0],DataType::int64(3)); uint64_array va_uint64(&v_uint64[0],DataType::uint64(3)); float64_array va_float64(&v_float64[0],DataType::float64(3)); - + va_int64.set({-1,0,1}); va_uint64.set({1,2,3}); va_float64.set({-1.0,0.0,1.0}); @@ -739,6 +765,8 @@ TEST(conduit_array, summary_stats) EXPECT_EQ(va_float64.sum(),0.0); } + + //----------------------------------------------------------------------------- TEST(conduit_array, summary_print) { @@ -884,7 +912,7 @@ TEST(conduit_array, cxx_11_init_lists) EXPECT_EQ(va_int8[1],2); EXPECT_EQ(va_int8[2],3); va_int8.print(); - + va_int8 = {1ul,2ul,3ul}; va_int8.print(); EXPECT_EQ(va_int8[0],1); @@ -1148,7 +1176,7 @@ TEST(conduit_array, cxx_11_init_lists) va_uint8 = {1.0,2.0,3.0}; va_uint8.print(); } - + // uint 16 { va_uint16.set({1,2,3}); @@ -1373,7 +1401,7 @@ TEST(conduit_array, cxx_11_init_lists) va_float32 = {1.0,2.0,3.0}; va_float32.print(); } - + // float 64 { va_float64.set({-1,-2,-3}); @@ -1424,3 +1452,6 @@ TEST(conduit_array, cxx_11_init_lists) + + + diff --git a/src/tests/conduit/t_conduit_mem_allocator.cpp b/src/tests/conduit/t_conduit_mem_allocator.cpp new file mode 100644 index 000000000..b45221eba --- /dev/null +++ b/src/tests/conduit/t_conduit_mem_allocator.cpp @@ -0,0 +1,253 @@ +// Copyright (c) Lawrence Livermore National Security, LLC and other Conduit +// Project developers. See top-level LICENSE AND COPYRIGHT files for dates and +// other details. No copyright assignment is required to contribute to Conduit. + +//----------------------------------------------------------------------------- +/// +/// file: conduit_smoke.cpp +/// +//----------------------------------------------------------------------------- + +#include "conduit.hpp" + +#include +#include "gtest/gtest.h" + + +struct TestAllocator +{ + static size_t m_total_bytes_alloced; + static size_t m_alloc_count; + static size_t m_free_count; + static size_t m_memcpy_count; + static size_t m_memset_count; + + static void * banana_alloc(size_t items, size_t item_size) + { + std::cout<<"Bananas allocate\n"; + m_total_bytes_alloced += items * item_size; + m_alloc_count++; + return calloc(items, item_size); + } + + static void free_bananas(void *data_ptr) + { + std::cout<<"free bananas\n"; + m_free_count++; + free(data_ptr); + } + + static void banana_memset(void * ptr, int value, size_t num ) + { + m_memset_count++; + std::cout<<"set bananas\n"; + memset(ptr,value,num); + } + + static void banana_copy(void * destination, const void * source, size_t num) + { + m_memcpy_count++; + std::cout<<"copy bananas\n"; + memcpy(destination,source,num); + } + + static void all_about_bananas() + { + std::cout << "[total_bytes_alloced: " << m_total_bytes_alloced << + " alloc_count: " << m_alloc_count << + " free_count: " << m_free_count << + " memcpy_count: " << m_memcpy_count << + " memset_count: " << m_memset_count << std::endl; + } +}; + + +size_t TestAllocator::m_total_bytes_alloced = 0; +size_t TestAllocator::m_alloc_count = 0; +size_t TestAllocator::m_free_count = 0; +size_t TestAllocator::m_memcpy_count = 0; +size_t TestAllocator::m_memset_count = 0; + +//----------------------------------------------------------------------------- +TEST(conduit_memory_allocator, test_custom_allocator) +{ + conduit::Node node_info; + conduit::Node other_info; + + conduit::utils::set_memcpy_handler(TestAllocator::banana_copy); + conduit::utils::set_memset_handler(TestAllocator::banana_memset); + + int allocator_id + = conduit::utils::register_allocator(TestAllocator::banana_alloc, + TestAllocator::free_bananas); + + EXPECT_EQ(TestAllocator::m_memset_count,0); + + conduit::Node node; + node.set_allocator(allocator_id); + // this should allocate 10 * 8 bytes + node["array"].set(conduit::DataType::float64(10)); + + TestAllocator::all_about_bananas(); + EXPECT_EQ(TestAllocator::m_total_bytes_alloced,80); + EXPECT_EQ(TestAllocator::m_alloc_count,1); + EXPECT_EQ(TestAllocator::m_free_count,0); + + // this should allocate 4 bytes + node["int"].set_int32(1); + + TestAllocator::all_about_bananas(); + EXPECT_EQ(TestAllocator::m_total_bytes_alloced,84); + EXPECT_EQ(TestAllocator::m_alloc_count,2); + EXPECT_EQ(TestAllocator::m_free_count,0); + + // ---------------------------------------------- + conduit::Node other; + other["path"].set_float32(1.0); + + // this should allocate 4 bytes + node.update(other); + + EXPECT_EQ(TestAllocator::m_total_bytes_alloced,88); + EXPECT_EQ(TestAllocator::m_alloc_count,3); + EXPECT_EQ(TestAllocator::m_free_count,0); + + node.info(node_info); + other.info(other_info); + + // this should free everything, free count == 3 + node.reset(); + TestAllocator::all_about_bananas(); + EXPECT_EQ(TestAllocator::m_alloc_count,3); + EXPECT_EQ(TestAllocator::m_free_count,3); + + std::cout << "Main Node Info" << std::endl; + node_info.print(); + // all pointers should be use alloc_id = 1 + conduit::NodeConstIterator ptr_itr = node_info["mem_spaces"].children(); + while(ptr_itr.has_next()) + { + const conduit::Node &p_n = ptr_itr.next(); + EXPECT_EQ(p_n["allocator_id"].to_int64(),1); + } + + std::cout << "Other Node Info" << std::endl; + other_info.print(); + + // all pointers should be use alloc_id = 0 + ptr_itr = other_info["mem_spaces"].children(); + while(ptr_itr.has_next()) + { + const conduit::Node &p_n = ptr_itr.next(); + EXPECT_EQ(p_n["allocator_id"].to_int64(),0); + } +} + + +struct StrangeAllocator +{ + static void * strange_alloc(size_t items, size_t item_size) + { + std::cout<<"Strange allocate\n"; + return calloc(items, item_size); + } + + static void strange_free(void *data_ptr) + { + std::cout<<"strange free \n"; + free(data_ptr); + } + + static void strange_memset(void * ptr, int value, size_t num ) + { + // init with -1 bytes + std::cout<<"strange set\n"; + memset(ptr,-1,num); + } + + static void strange_copy(void * destination, const void * source, size_t num) + { + std::cout<<"strange copy\n"; + conduit::uint8 *des_ptr = (conduit::uint8*)destination; + for(int i=0;i txt_cases; txt_cases.push_back(n.to_string()); // yaml txt_cases.push_back(n.to_string_default()); // yaml - n.to_string_stream(oss); + n.to_string_stream(oss); txt_cases.push_back(oss.str()); // yaml txt_cases.push_back(n.to_string("yaml")); oss.str(""); - n.to_string_stream(oss,"json"); + n.to_string_stream(oss,"json"); txt_cases.push_back(oss.str()); // json txt_cases.push_back(n.to_string("json")); diff --git a/src/tests/conduit/t_conduit_node_set.cpp b/src/tests/conduit/t_conduit_node_set.cpp index 395794c2e..8b71c6695 100644 --- a/src/tests/conduit/t_conduit_node_set.cpp +++ b/src/tests/conduit/t_conduit_node_set.cpp @@ -6905,6 +6905,7 @@ TEST(conduit_node, node_set_non_compact_dtype) } + //----------------------------------------------------------------------------- #ifdef CONDUIT_USE_CXX11 //----------------------------------------------------------------------------- @@ -7017,4 +7018,34 @@ TEST(conduit_array, cxx_11_init_lists) #endif // end CONDUIT_USE_CXX11 //----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +TEST(conduit_node, node_set_with_offset) +{ + Node n; + + conduit::float64 vals[6] = { 1.0, 2.0, + 1.0, 2.0, + 1.0, 2.0,}; + + n["v1"].set(vals, + 3, + 0, + 2 * sizeof(conduit::float64)); + n["v2"].set(vals, + 3, + sizeof(conduit::float64), + 2 * sizeof(conduit::float64)); + n.print(); + + float64_array av1 = n["v1"].value(); + float64_array av2 = n["v2"].value(); + + EXPECT_EQ(av1[0],1.0); + EXPECT_EQ(av1[1],1.0); + EXPECT_EQ(av1[2],1.0); + EXPECT_EQ(av2[0],2.0); + EXPECT_EQ(av2[1],2.0); + EXPECT_EQ(av2[2],2.0); + +} diff --git a/src/tests/conduit/t_conduit_node_static_init.cpp b/src/tests/conduit/t_conduit_node_static_init.cpp new file mode 100644 index 000000000..075a325cc --- /dev/null +++ b/src/tests/conduit/t_conduit_node_static_init.cpp @@ -0,0 +1,42 @@ +// Copyright (c) Lawrence Livermore National Security, LLC and other Conduit +// Project developers. See top-level LICENSE AND COPYRIGHT files for dates and +// other details. No copyright assignment is required to contribute to Conduit. + +//----------------------------------------------------------------------------- +/// +/// file: conduit_smoke.cpp +/// +//----------------------------------------------------------------------------- + +#include "conduit.hpp" + +#include +#include "gtest/gtest.h" + +// +// This test is here to trigger +// https://isocpp.org/wiki/faq/ctors#static-init-order +// *If* it is present related to a conduit Node. +// +// Even with this test the crash may not always happen, +// but with several CI checks we increase our confidence +// that we are clear of static init problems +// + + +std::string use_with_static_init() +{ + conduit::Node n; + n["value"] = 42; + return n.to_yaml(); +} + +const std::string STATIC_INIT_RES = use_with_static_init(); + +//----------------------------------------------------------------------------- +TEST(conduit_smoke, test_static_init) +{ + conduit::Node n; + n["value"] = 42; + EXPECT_EQ(n.to_yaml(),STATIC_INIT_RES); +}