Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Clean up string casts and improve performance #2284

Merged
merged 1 commit into from Aug 3, 2022

Conversation

alamb
Copy link
Contributor

@alamb alamb commented Aug 2, 2022

Draft until #2283 is merged

Which issue does this PR close?

Closes #2285

Rationale for this change

Here are some cleanups I suggested to @stuartcarnie of while reviewing #2251
-- #2251 (comment). Turns out not only did I give a bad suggestion (馃う ), he was following the existing pattern in this file.

Since I was already working on this, I figured I would finish up the change so that new kernels don't get the same copy/paste code.

I think this both makes the code easier to read (it is less verbose) and it should improve performance by removing bounds checks (and unnecessary String construction and allocation)

What changes are included in this PR?

  1. Use Iterators rather than value() and is_null and remove several to_string() calls
  2. Move duplicated constants into temporal_conversion.rs

Are there any user-facing changes?

No (maybe faster cast kernels)

@github-actions github-actions bot added the arrow Changes to the arrow crate label Aug 2, 2022
@@ -1247,19 +1251,6 @@ const fn time_unit_multiple(unit: &TimeUnit) -> i64 {
}
}

/// Number of seconds in a day
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these were already defined in temporal_conversion.rs so use those definitions instead of duplicating them)

@@ -1463,35 +1454,28 @@ where
<T as ArrowPrimitiveType>::Native: lexical_core::FromLexical,
{
if cast_options.safe {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I basically applied the same transformation to all the kernels I modified -- I changed the safe path to use iter().map(|v| v.and_then) and I changed the not safe path to use iter().map(|v| v.map().transpose)

if from.is_null(i) {
Ok(None)
} else {
let string = from.value(i);
Copy link
Contributor Author

@alamb alamb Aug 2, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know why this code was creating an owned String for each element, so I removed it. The same pattern was repeated in all the other kernels I modified in this PR

@alamb alamb changed the title [Minor] Clean up string casts Clean up string casts and improve performance Aug 2, 2022
@alamb alamb marked this pull request as ready for review August 2, 2022 17:18
} else {
let string = string_array
.value(i);
chrono::Duration::days(3);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this seems to be an unused random chrono::Duration::days(3); construction 馃し

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gosh, I thought that was removed from my branch, but there were multiple instances. Sorry about that!

Copy link
Contributor

@stuartcarnie stuartcarnie left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are nice, concise improvements to the previous implementation and will provide good examples for future developers.

+ time.nanosecond() as i64 / NANOS_PER_MICRO)
.map_err(|_| {
ArrowError::CastError(
format!("Cannot cast string '{}' to value of arrow::datatypes::types::Time64MicrosecondType type", v),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Personally I think Time64MicrosecondType is enough. But just nitpicking.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree -- they are heinous -- here is a proposal to fix them: #2295

@HaoYang670
Copy link
Contributor

As the title says, there should be performance improvement. However, I don't see it when doing benchmarks on my laptop:
Tested on Intel Ubuntu

cargo bench --bench cast_kernels -- --baseline master
...
cast utf8 to date32 512 time:   [22.682 us 22.698 us 22.716 us]                                     
                        change: [-0.3103% -0.2050% -0.1135%] (p = 0.00 < 0.05)
                        Change within noise threshold.
Found 12 outliers among 100 measurements (12.00%)
  4 (4.00%) high mild
  8 (8.00%) high severe

cast utf8 to date64 512 time:   [39.237 us 39.258 us 39.285 us]                                     
                        change: [+2.0238% +2.2611% +2.4840%] (p = 0.00 < 0.05)
                        Performance has regressed.
Found 13 outliers among 100 measurements (13.00%)
  1 (1.00%) low mild
  3 (3.00%) high mild
  9 (9.00%) high severe
...

Copy link
Contributor

@tustvold tustvold left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's worth noting this will in most cases boil down to the same thing, unfortunately ArrayIter has the same naive null mask handling, but once we fix that this code will benefit 馃憤

The code is also more concise and easier to read so

@tustvold tustvold merged commit ec83638 into apache:master Aug 3, 2022
@ursabot
Copy link

ursabot commented Aug 3, 2022

Benchmark runs are scheduled for baseline = 1f9973c and contender = ec83638. ec83638 is a master commit associated with this PR. Results will be available as each benchmark for each run completes.
Conbench compare runs links:
[Skipped 鈿狅笍 Benchmarking of arrow-rs-commits is not supported on ec2-t3-xlarge-us-east-2] ec2-t3-xlarge-us-east-2
[Skipped 鈿狅笍 Benchmarking of arrow-rs-commits is not supported on test-mac-arm] test-mac-arm
[Skipped 鈿狅笍 Benchmarking of arrow-rs-commits is not supported on ursa-i9-9960x] ursa-i9-9960x
[Skipped 鈿狅笍 Benchmarking of arrow-rs-commits is not supported on ursa-thinkcentre-m75q] ursa-thinkcentre-m75q
Buildkite builds:
Supported benchmarks:
ec2-t3-xlarge-us-east-2: Supported benchmark langs: Python, R. Runs only benchmarks with cloud = True
test-mac-arm: Supported benchmark langs: C++, Python, R
ursa-i9-9960x: Supported benchmark langs: Python, R, JavaScript
ursa-thinkcentre-m75q: Supported benchmark langs: C++, Java

@alamb alamb deleted the alamb/cleaner_cast branch August 3, 2022 10:27
@alamb
Copy link
Contributor Author

alamb commented Aug 3, 2022

As the title says, there should be performance improvement. However, I don't see it when doing benchmarks on my laptop:

Thanks for checking @HaoYang670

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
arrow Changes to the arrow crate
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Improve readability and maybe performance of string --> numeric/time/date/timetamp cast kernels
6 participants