Skip to content

Commit f622f7b

Browse files
authored
Merge branch 'main' into codex/11361-json-duplicate-policy
2 parents 711e569 + 781d7d4 commit f622f7b

10 files changed

Lines changed: 549 additions & 47 deletions

File tree

ci/Jenkinsfile.premerge

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,7 @@ git --no-pager diff --name-only HEAD \$BASE -- ${PREMERGE_DOCKERFILE} || true"""
315315
void runPremergeBuild() {
316316
common.prepareArtNetrc(this)
317317
withEnv([
318-
"ARROW_THRIFT_MIRROR_URL=https://${env.ARTIFACTORY_NAME}/artifactory/apache-remote",
318+
"ARROW_THRIFT_MIRROR_URL=https://${env.ARTIFACTORY_NAME}/artifactory/sw-spark-maven/apache-remote",
319319
"CMAKE_NETRC=OPTIONAL",
320320
]) {
321321
sh 'source build/env.sh && ${sclCMD} "ci/premerge-build.sh"'

src/main/cpp/src/GpuTimeZoneDBJni.cpp

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,8 @@ JNIEXPORT jlong JNICALL Java_com_nvidia_spark_rapids_jni_GpuTimeZoneDB_convertOr
140140
jlong reader_tz_info_table,
141141
jint reader_tz_initial_offset,
142142
jint reader_tz_raw_offset,
143-
jintArray reader_dst_rule)
143+
jintArray reader_dst_rule,
144+
jboolean writer_reader_rules_differ)
144145
{
145146
JNI_NULL_CHECK(env, input_handle, "input column is null", 0);
146147

@@ -160,7 +161,38 @@ JNIEXPORT jlong JNICALL Java_com_nvidia_spark_rapids_jni_GpuTimeZoneDB_convertOr
160161
auto const reader = spark_rapids_jni::orc_tz_side{
161162
reader_tz_info_tab, reader_tz_initial_offset, reader_tz_raw_offset, reader_dst};
162163
return cudf::jni::release_as_jlong(spark_rapids_jni::convert_orc_writer_reader_timezones(
163-
*input, static_cast<int64_t>(writer_tz_offset_at_orc_2015_base_us), writer, reader));
164+
*input,
165+
static_cast<int64_t>(writer_tz_offset_at_orc_2015_base_us),
166+
writer,
167+
reader,
168+
cudf::get_default_stream(),
169+
cudf::get_current_device_resource_ref(),
170+
writer_reader_rules_differ));
171+
}
172+
JNI_CATCH(env, 0);
173+
}
174+
175+
JNIEXPORT jlong JNICALL Java_com_nvidia_spark_rapids_jni_GpuTimeZoneDB_convertOrcFromUtcWithRules(
176+
JNIEnv* env,
177+
jclass,
178+
jlong input_handle,
179+
jlong reader_tz_info_table,
180+
jint reader_tz_initial_offset,
181+
jint reader_tz_raw_offset,
182+
jintArray reader_dst_rule)
183+
{
184+
JNI_NULL_CHECK(env, input_handle, "input column is null", 0);
185+
186+
JNI_TRY
187+
{
188+
cudf::jni::auto_set_device(env);
189+
auto const input = reinterpret_cast<cudf::column_view const*>(input_handle);
190+
auto const reader_tz_info_tab = reinterpret_cast<cudf::table_view const*>(reader_tz_info_table);
191+
auto const reader_dst = parse_dst_rule(env, reader_dst_rule);
192+
cudf::jni::check_java_exception(env);
193+
auto const reader = spark_rapids_jni::orc_tz_side{
194+
reader_tz_info_tab, reader_tz_initial_offset, reader_tz_raw_offset, reader_dst};
195+
return cudf::jni::release_as_jlong(spark_rapids_jni::convert_orc_from_utc(*input, reader));
164196
}
165197
JNI_CATCH(env, 0);
166198
}

src/main/cpp/src/timezones.cu

Lines changed: 166 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -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

8831016
std::unique_ptr<cudf::column> convert_orc_writer_reader_timezones(

src/main/cpp/src/timezones.hpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,8 @@ struct orc_tz_side {
158158
* the same frame as Apache ORC. Pass 0 for no adjustment.
159159
* @param writer writer timezone transition data, offsets, and DST rule.
160160
* @param reader reader timezone transition data, offsets, and DST rule.
161+
* @param writer_reader_rules_differ whether Apache ORC would call
162+
* SerializationUtils.convertBetweenTimezones for this timezone pair.
161163
* @param stream CUDA stream.
162164
* @param mr Device memory resource.
163165
* @return timestamps rebased between writer and reader timezones.
@@ -168,6 +170,23 @@ struct orc_tz_side {
168170
orc_tz_side writer,
169171
orc_tz_side reader,
170172
rmm::cuda_stream_view stream = cudf::get_default_stream(),
173+
rmm::device_async_resource_ref mr = cudf::get_current_device_resource_ref(),
174+
bool writer_reader_rules_differ = true);
175+
176+
/**
177+
* @brief Apply Apache ORC SerializationUtils.convertFromUtc semantics.
178+
*
179+
* @param input TIMESTAMP_MICROSECONDS input column.
180+
* @param reader reader timezone transition data, offsets, and DST rule.
181+
* @param stream CUDA stream.
182+
* @param mr Device memory resource.
183+
* @return converted column with the same type as input.
184+
* @throws cudf::logic_error If input is not TIMESTAMP_MICROSECONDS.
185+
*/
186+
[[nodiscard]] std::unique_ptr<cudf::column> convert_orc_from_utc(
187+
cudf::column_view const& input,
188+
orc_tz_side reader,
189+
rmm::cuda_stream_view stream = cudf::get_default_stream(),
171190
rmm::device_async_resource_ref mr = cudf::get_current_device_resource_ref());
172191

173192
/**

0 commit comments

Comments
 (0)