@@ -582,11 +582,13 @@ __device__ static cudf::timestamp_us convert_timestamp_between_timezones(
582582 cudf::timestamp_us ts,
583583 orc_base_offset_info writer_2015_year_base_offset,
584584 tz_side_info const & writer,
585- tz_side_info const & reader)
585+ tz_side_info const & reader,
586+ bool writer_reader_rules_differ)
586587{
587588 int64_t const decoded_us = static_cast <int64_t >(
588589 cuda::std::chrono::duration_cast<cudf::duration_us>(ts.time_since_epoch ()).count ());
589590 int64_t const adjusted_us = apply_orc_base_offset (decoded_us, writer_2015_year_base_offset);
591+ if (!writer_reader_rules_differ) { return cudf::timestamp_us{cudf::duration_us{adjusted_us}}; }
590592
591593 // Floor-divide to get epoch millis (handles negative timestamps correctly)
592594 int64_t const epoch_millis =
@@ -665,29 +667,32 @@ CUDF_KERNEL void __launch_bounds__(CONVERT_TZ_BLOCK_SIZE)
665667 cudf::size_type input_offset,
666668 orc_base_offset_info writer_2015_year_base_offset,
667669 orc_tz_side_kernel_args writer_args,
668- orc_tz_side_kernel_args reader_args)
670+ orc_tz_side_kernel_args reader_args,
671+ bool writer_reader_rules_differ)
669672{
670673 // Shared memory layout: writer transitions, writer offsets, reader transitions, reader offsets
671674 extern __shared__ char smem[];
672675
673- char * ptr = smem;
674- int64_t const *wt_begin, *wt_end, *rt_begin, *rt_end;
675- int32_t const *wo_begin, *ro_begin;
676- stage_side_transitions (writer_args.trans ,
677- writer_args.offsets ,
678- writer_args.trans_count ,
679- ptr,
680- wt_begin,
681- wt_end,
682- wo_begin);
683- stage_side_transitions (reader_args.trans ,
684- reader_args.offsets ,
685- reader_args.trans_count ,
686- ptr,
687- rt_begin,
688- rt_end,
689- ro_begin);
690- __syncthreads ();
676+ char * ptr = smem;
677+ int64_t const *wt_begin = nullptr , *wt_end = nullptr , *rt_begin = nullptr , *rt_end = nullptr ;
678+ int32_t const *wo_begin = nullptr , *ro_begin = nullptr ;
679+ if (writer_reader_rules_differ) {
680+ stage_side_transitions (writer_args.trans ,
681+ writer_args.offsets ,
682+ writer_args.trans_count ,
683+ ptr,
684+ wt_begin,
685+ wt_end,
686+ wo_begin);
687+ stage_side_transitions (reader_args.trans ,
688+ reader_args.offsets ,
689+ reader_args.trans_count ,
690+ ptr,
691+ rt_begin,
692+ rt_end,
693+ ro_begin);
694+ __syncthreads ();
695+ }
691696
692697 cudf::size_type idx = blockIdx .x * blockDim .x + threadIdx .x ;
693698 if (idx < num_rows) {
@@ -706,8 +711,8 @@ CUDF_KERNEL void __launch_bounds__(CONVERT_TZ_BLOCK_SIZE)
706711 reader_args.raw_offset ,
707712 reader_args.dst ,
708713 reader_args.is_fixed };
709- output[idx] =
710- convert_timestamp_between_timezones ( input[idx], writer_2015_year_base_offset, writer, reader);
714+ output[idx] = convert_timestamp_between_timezones (
715+ input[idx], writer_2015_year_base_offset, writer, reader, writer_reader_rules_differ );
711716 }
712717}
713718
@@ -716,7 +721,8 @@ std::unique_ptr<column> convert_timezones(cudf::column_view const& input,
716721 spark_rapids_jni::orc_tz_side writer,
717722 spark_rapids_jni::orc_tz_side reader,
718723 rmm::cuda_stream_view stream,
719- rmm::device_async_resource_ref mr)
724+ rmm::device_async_resource_ref mr,
725+ bool writer_reader_rules_differ)
720726{
721727 SRJ_FUNC_RANGE ();
722728
@@ -747,13 +753,15 @@ std::unique_ptr<column> convert_timezones(cudf::column_view const& input,
747753 int32_t reader_trans_count = reader.tz_info_table ? reader.tz_info_table ->column (0 ).size () : 0 ;
748754
749755 size_t smem_bytes = 0 ;
750- if (writer_trans_count > 0 && writer_trans_count <= MAX_SMEM_TRANSITIONS ) {
751- smem_bytes += writer_trans_count * (sizeof (int64_t ) + sizeof (int32_t ));
752- }
753- if (reader_trans_count > 0 && reader_trans_count <= MAX_SMEM_TRANSITIONS ) {
754- // Alignment padding between writer offsets (int32_t) and reader transitions (int64_t)
755- smem_bytes = align_up (smem_bytes, alignof (int64_t ));
756- smem_bytes += reader_trans_count * (sizeof (int64_t ) + sizeof (int32_t ));
756+ if (writer_reader_rules_differ) {
757+ if (writer_trans_count > 0 && writer_trans_count <= MAX_SMEM_TRANSITIONS ) {
758+ smem_bytes += writer_trans_count * (sizeof (int64_t ) + sizeof (int32_t ));
759+ }
760+ if (reader_trans_count > 0 && reader_trans_count <= MAX_SMEM_TRANSITIONS ) {
761+ // Alignment padding between writer offsets (int32_t) and reader transitions (int64_t)
762+ smem_bytes = align_up (smem_bytes, alignof (int64_t ));
763+ smem_bytes += reader_trans_count * (sizeof (int64_t ) + sizeof (int32_t ));
764+ }
757765 }
758766
759767 int32_t num_blocks = cudf::util::div_rounding_up_safe (input.size (), CONVERT_TZ_BLOCK_SIZE );
@@ -789,12 +797,124 @@ std::unique_ptr<column> convert_timezones(cudf::column_view const& input,
789797 input.offset (),
790798 writer_2015_year_base_offset,
791799 writer_args,
792- reader_args);
800+ reader_args,
801+ writer_reader_rules_differ);
793802 CUDF_CHECK_CUDA (stream.value ());
794803
795804 return results;
796805}
797806
807+ __device__ static int64_t wrapping_subtract (int64_t lhs, int64_t rhs)
808+ {
809+ return static_cast <int64_t >(static_cast <uint64_t >(lhs) - static_cast <uint64_t >(rhs));
810+ }
811+
812+ template <typename T>
813+ __device__ static T convert_orc_from_utc_value (T value, tz_side_info const & reader);
814+
815+ template <>
816+ __device__ cudf::timestamp_us convert_orc_from_utc_value (cudf::timestamp_us value,
817+ tz_side_info const & reader)
818+ {
819+ auto const value_us = value.time_since_epoch ().count ();
820+ auto offset_ms = reader.raw_offset ;
821+ if (!reader.is_fixed ) {
822+ auto const value_ms = spark_rapids_jni::integer_utils::floor_div (value_us, MICROS_PER_MILLI );
823+ auto const offset_lookup_ms = wrapping_subtract (value_ms, reader.raw_offset );
824+ offset_ms = get_transition_index (offset_lookup_ms, reader);
825+ }
826+ auto const result_us =
827+ wrapping_subtract (value_us, static_cast <int64_t >(offset_ms) * MICROS_PER_MILLI );
828+ return cudf::timestamp_us{cudf::duration_us{result_us}};
829+ }
830+
831+ template <typename T>
832+ CUDF_KERNEL void __launch_bounds__ (CONVERT_TZ_BLOCK_SIZE )
833+ convert_orc_from_utc_kernel(T const * __restrict__ input,
834+ cudf::bitmask_type const * __restrict__ null_mask,
835+ T* __restrict__ output,
836+ cudf::size_type num_rows,
837+ cudf::size_type input_offset,
838+ orc_tz_side_kernel_args reader_args)
839+ {
840+ extern __shared__ char smem[];
841+ char * ptr = smem;
842+ int64_t const *rt_begin = nullptr , *rt_end = nullptr ;
843+ int32_t const * ro_begin = nullptr ;
844+ if (!reader_args.is_fixed ) {
845+ stage_side_transitions (reader_args.trans ,
846+ reader_args.offsets ,
847+ reader_args.trans_count ,
848+ ptr,
849+ rt_begin,
850+ rt_end,
851+ ro_begin);
852+ __syncthreads ();
853+ }
854+
855+ cudf::size_type idx = blockIdx .x * blockDim .x + threadIdx .x ;
856+ if (idx < num_rows) {
857+ if (null_mask && !cudf::bit_is_set (null_mask, idx + input_offset)) { return ; }
858+ tz_side_info const reader{rt_begin,
859+ rt_end,
860+ ro_begin,
861+ reader_args.initial_offset ,
862+ reader_args.raw_offset ,
863+ reader_args.dst ,
864+ reader_args.is_fixed };
865+ output[idx] = convert_orc_from_utc_value (input[idx], reader);
866+ }
867+ }
868+
869+ template <typename T>
870+ std::unique_ptr<column> convert_orc_from_utc_typed (cudf::column_view const & input,
871+ spark_rapids_jni::orc_tz_side reader,
872+ rmm::cuda_stream_view stream,
873+ rmm::device_async_resource_ref mr)
874+ {
875+ auto results = cudf::make_fixed_width_column (input.type (),
876+ input.size (),
877+ cudf::copy_bitmask (input, stream, mr),
878+ input.null_count (),
879+ stream,
880+ mr);
881+ if (input.size () == 0 ) { return results; }
882+
883+ int64_t const * reader_trans_ptr =
884+ reader.tz_info_table ? reader.tz_info_table ->column (0 ).begin <int64_t >() : nullptr ;
885+ int32_t const * reader_offsets_ptr =
886+ reader.tz_info_table ? reader.tz_info_table ->column (1 ).begin <int32_t >() : nullptr ;
887+ int32_t reader_trans_count = reader.tz_info_table ? reader.tz_info_table ->column (0 ).size () : 0 ;
888+ auto const is_reader_fixed = reader_trans_count == 0 && !reader.dst .has_dst ;
889+ size_t smem_bytes = 0 ;
890+ if (reader_trans_count > 0 && reader_trans_count <= MAX_SMEM_TRANSITIONS ) {
891+ smem_bytes = reader_trans_count * (sizeof (int64_t ) + sizeof (int32_t ));
892+ }
893+
894+ auto const reader_args = orc_tz_side_kernel_args{reader_trans_ptr,
895+ reader_offsets_ptr,
896+ reader_trans_count,
897+ reader.initial_offset ,
898+ reader.raw_offset ,
899+ reader.dst ,
900+ is_reader_fixed};
901+ int32_t num_blocks = cudf::util::div_rounding_up_safe (input.size (), CONVERT_TZ_BLOCK_SIZE );
902+ auto const launch_config = cuda::make_config (cuda::grid_dims (num_blocks),
903+ cuda::block_dims<CONVERT_TZ_BLOCK_SIZE >(),
904+ cuda::dynamic_shared_memory<char []>(smem_bytes));
905+ cuda::launch (stream.value (),
906+ launch_config,
907+ convert_orc_from_utc_kernel<T>,
908+ input.begin <T>(),
909+ input.null_mask (),
910+ results->mutable_view ().begin <T>(),
911+ input.size (),
912+ input.offset (),
913+ reader_args);
914+ CUDF_CHECK_CUDA (stream.value ());
915+ return results;
916+ }
917+
798918// =================== ORC timezones end ===================
799919
800920} // namespace
@@ -875,9 +995,22 @@ std::unique_ptr<cudf::column> convert_orc_writer_reader_timezones(
875995 orc_tz_side writer,
876996 orc_tz_side reader,
877997 rmm::cuda_stream_view stream,
878- rmm::device_async_resource_ref mr)
998+ rmm::device_async_resource_ref mr,
999+ bool writer_reader_rules_differ)
1000+ {
1001+ return convert_timezones (
1002+ input, writer_2015_year_base_offset_us, writer, reader, stream, mr, writer_reader_rules_differ);
1003+ }
1004+
1005+ std::unique_ptr<cudf::column> convert_orc_from_utc (cudf::column_view const & input,
1006+ orc_tz_side reader,
1007+ rmm::cuda_stream_view stream,
1008+ rmm::device_async_resource_ref mr)
8791009{
880- return convert_timezones (input, writer_2015_year_base_offset_us, writer, reader, stream, mr);
1010+ validate_timezone_table (reader.tz_info_table );
1011+ CUDF_EXPECTS (input.type ().id () == cudf::type_id::TIMESTAMP_MICROSECONDS ,
1012+ " ORC convertFromUtc input must be TIMESTAMP_MICROSECONDS" );
1013+ return convert_orc_from_utc_typed<cudf::timestamp_us>(input, reader, stream, mr);
8811014}
8821015
8831016std::unique_ptr<cudf::column> convert_orc_writer_reader_timezones (
0 commit comments