@@ -272,10 +272,11 @@ PackedData chunked_pack(
272272 cudf::table_view const & table, Buffer& bounce_buf, MemoryReservation& data_res
273273) {
274274 RAPIDSMPF_EXPECTS (
275- bounce_buf.mem_type () == MemoryType:: DEVICE ,
276- " bounce buffer must be in device memory " ,
275+ is_device_accessible ( bounce_buf.mem_type ()) ,
276+ " bounce buffer is not device accessible " ,
277277 std::invalid_argument
278278 );
279+
279280 // all copies will be done on the bounce buffer's stream
280281 auto stream = bounce_buf.stream ();
281282 auto * br = data_res.br ();
@@ -316,4 +317,70 @@ PackedData chunked_pack(
316317 return {packer.build_metadata (), std::move (data_buf)};
317318}
318319
320+ std::unique_ptr<PackedData> pack_to_host (
321+ cudf::table_view const & table,
322+ rmm::cuda_stream_view stream,
323+ MemoryReservation& host_data_res,
324+ float chunked_pack_buffer_size_factor,
325+ std::span<MemoryType const > cpack_buf_mem_types
326+ ) {
327+ RAPIDSMPF_EXPECTS (
328+ is_host_accessible (host_data_res.mem_type ()),
329+ " memory reservation is not host accessible" ,
330+ std::invalid_argument
331+ );
332+
333+ auto * br = host_data_res.br ();
334+
335+ size_t est_table_size = estimated_memory_usage (table, stream);
336+ {
337+ // make a device reservation for packing
338+ auto [pack_res, overbooking] =
339+ br->reserve (MemoryType::DEVICE , est_table_size, true );
340+
341+ if (overbooking == 0 ) {
342+ // if there is enough memory to pack the table, use `cudf::pack`
343+ auto packed_columns = cudf::pack (table, stream, br->device_mr ());
344+ // clear the reservation as we are done with it.
345+ pack_res.clear ();
346+
347+ // note that this is a device buffer, so we need to move it to host memory
348+ auto packed_data = std::make_unique<PackedData>(
349+ std::move (packed_columns.metadata ),
350+ br->move (std::move (packed_columns.gpu_data ), stream)
351+ );
352+
353+ // Handle the case where `cudf::pack` allocates slightly more than
354+ // the input size. This can occur because cudf uses aligned
355+ // allocations, which may exceed the requested size. To
356+ // accommodate this, we allow some wiggle room.
357+ if (packed_data->data ->size > host_data_res.size ()) {
358+ if (packed_data->data ->size
359+ <= host_data_res.size () + total_packing_wiggle_room (table))
360+ {
361+ host_data_res =
362+ br->reserve (
363+ host_data_res.mem_type (), packed_data->data ->size , true
364+ )
365+ .first ;
366+ }
367+ }
368+
369+ // finally copy the packed data device buffer to HOST memory
370+ packed_data->data = br->move (std::move (packed_data->data ), host_data_res);
371+ return packed_data;
372+ }
373+ }
374+
375+ // there is not enough memory to use cudf::pack. Use chunked_pack.
376+ auto chunk_size = std::max (
377+ static_cast <size_t >(est_table_size * chunked_pack_buffer_size_factor),
378+ cudf_chunked_pack_min_buffer_size
379+ );
380+ auto bounce_res = br->reserve_or_fail (chunk_size, cpack_buf_mem_types);
381+ auto bounce_buf = br->allocate (chunk_size, stream, bounce_res);
382+
383+ return std::make_unique<PackedData>(chunked_pack (table, *bounce_buf, host_data_res));
384+ }
385+
319386} // namespace rapidsmpf
0 commit comments