You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@datafusion.apache.org by gi...@apache.org on 2026/07/22 16:33:20 UTC

(datafusion) branch gh-readonly-queue/main/pr-23762-f33dcec6dfd0b900ddf89b75b46e547f7923c0e7 created (now e271f65c9f)

This is an automated email from the ASF dual-hosted git repository.

github-merge-queue[bot] pushed a change to branch gh-readonly-queue/main/pr-23762-f33dcec6dfd0b900ddf89b75b46e547f7923c0e7
in repository https://gitbox.apache.org/repos/asf/datafusion.git


      at e271f65c9f perf: optimize left_right in datafusion-functions (#23762)

This branch includes the following new commits:

     new e271f65c9f perf: optimize left_right in datafusion-functions (#23762)

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@datafusion.apache.org
For additional commands, e-mail: commits-help@datafusion.apache.org


(datafusion) 01/01: perf: optimize left_right in datafusion-functions (#23762)

Posted by gi...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

github-merge-queue[bot] pushed a commit to branch gh-readonly-queue/main/pr-23762-f33dcec6dfd0b900ddf89b75b46e547f7923c0e7
in repository https://gitbox.apache.org/repos/asf/datafusion.git

commit e271f65c9f8188cb6b1876da099646f396e34e00
Author: Andy Grove <ag...@apache.org>
AuthorDate: Wed Jul 22 10:32:56 2026 -0600

    perf: optimize left_right in datafusion-functions (#23762)
    
    ## Which issue does this PR close?
    
    N/A
    
    ## Rationale for this change
    
    Optimize existing expression.
    
    ## What changes are included in this PR?
    
    Added an ASCII fast path to left_right_byte_length so left/right compute
    the n-th codepoint byte offset via O(1) arithmetic instead of a per-row
    char_indices() UTF-8 scan.
    
    ## Are these changes tested?
    
    Existing tests.
    
    Benchmark (criterion):
    
    - string_view short_result: 4.848% faster (base 56784ns -> cand 54031ns)
    - string long_result: 38.098% faster (base 141926ns -> cand 87855ns)
    - string_view long_result: 44.817% faster (base 94346ns -> cand 52063ns)
    - string short_result: 13.184% faster (base 88532ns -> cand 76860ns)
    - string_view short_result: 15.165% faster (base 57136ns -> cand
    48472ns)
    - string long_result: 39.278% faster (base 140969ns -> cand 85600ns)
    - string_view long_result: 40.29% faster (base 81808ns -> cand 48847ns)
    - string short_result: 14.369% faster (base 86809ns -> cand 74336ns)
    
    Full criterion output:
    
    ```text
    left/string short_result
                            time:   [73.406 µs 73.726 µs 74.067 µs]
                            change: [−15.026% −14.369% −13.742%] (p = 0.00 < 0.05)
                            Performance has improved.
    Found 1 outliers among 100 measurements (1.00%)
      1 (1.00%) low mild
    left/string long_result time:   [85.227 µs 85.519 µs 85.827 µs]
                            change: [−39.588% −39.278% −38.969%] (p = 0.00 < 0.05)
                            Performance has improved.
    Found 3 outliers among 100 measurements (3.00%)
      1 (1.00%) low mild
      2 (2.00%) high mild
    left/string_view short_result
                            time:   [48.206 µs 48.411 µs 48.613 µs]
                            change: [−17.549% −15.165% −13.033%] (p = 0.00 < 0.05)
                            Performance has improved.
    left/string_view long_result
                            time:   [48.383 µs 48.691 µs 49.038 µs]
                            change: [−40.884% −40.290% −39.714%] (p = 0.00 < 0.05)
                            Performance has improved.
    
    right/string short_result
                            time:   [76.804 µs 76.986 µs 77.159 µs]
                            change: [−13.955% −13.184% −12.465%] (p = 0.00 < 0.05)
                            Performance has improved.
    Found 6 outliers among 100 measurements (6.00%)
      3 (3.00%) low severe
      3 (3.00%) low mild
    right/string long_result
                            time:   [88.219 µs 88.597 µs 88.938 µs]
                            change: [−38.351% −38.098% −37.853%] (p = 0.00 < 0.05)
                            Performance has improved.
    right/string_view short_result
                            time:   [53.380 µs 53.545 µs 53.728 µs]
                            change: [−5.5061% −4.8482% −4.1872%] (p = 0.00 < 0.05)
                            Performance has improved.
    Found 3 outliers among 100 measurements (3.00%)
      3 (3.00%) high mild
    right/string_view long_result
                            time:   [52.049 µs 52.332 µs 52.633 µs]
                            change: [−45.883% −44.817% −43.850%] (p = 0.00 < 0.05)
                            Performance has improved.
    Found 6 outliers among 100 measurements (6.00%)
      6 (6.00%) high mild
    ```
    
    
    ## Are there any user-facing changes?
    
    No
    
    <!--
    If there are user-facing changes then we may require documentation to be
    updated before approving the PR.
    -->
    
    <!--
    If there are any breaking changes to public APIs, please add the `api
    change` label.
    -->
---
 datafusion/functions/src/unicode/common.rs | 16 +++++++++++-----
 1 file changed, 11 insertions(+), 5 deletions(-)

diff --git a/datafusion/functions/src/unicode/common.rs b/datafusion/functions/src/unicode/common.rs
index 9f91e4f1b0..5dc8f334da 100644
--- a/datafusion/functions/src/unicode/common.rs
+++ b/datafusion/functions/src/unicode/common.rs
@@ -125,16 +125,22 @@ pub(crate) enum StringCharLen {
 /// Calculate the byte length of the substring of `n` chars from string `string`
 #[inline]
 fn left_right_byte_length(string: &str, n: i64) -> usize {
+    let abs = n.unsigned_abs().min(usize::MAX as u64) as usize;
+    // For ASCII input every character is exactly one byte, so the byte offset of
+    // the n-th codepoint is just the (clamped) character count. This avoids the
+    // per-character `char_indices()` scan of the general path.
     match n.cmp(&0) {
+        Ordering::Equal => 0,
+        // `abs` chars trimmed from the end: keep the leading `len - abs`.
+        Ordering::Less if string.is_ascii() => string.len().saturating_sub(abs),
         Ordering::Less => string
             .char_indices()
-            .nth_back((n.unsigned_abs().min(usize::MAX as u64) - 1) as usize)
+            .nth_back(abs - 1)
             .map(|(index, _)| index)
             .unwrap_or(0),
-        Ordering::Equal => 0,
-        Ordering::Greater => {
-            byte_offset_of_char(string, n.unsigned_abs().min(usize::MAX as u64) as usize)
-        }
+        // First `abs` chars, but never past the end of the string.
+        Ordering::Greater if string.is_ascii() => abs.min(string.len()),
+        Ordering::Greater => byte_offset_of_char(string, abs),
     }
 }
 


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@datafusion.apache.org
For additional commands, e-mail: commits-help@datafusion.apache.org