diff --git a/Cargo.toml b/Cargo.toml index 7ac479caf3a1..03cd380f7505 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -353,22 +353,24 @@ result_large_err = "allow" debug = 1 lto = "thin" overflow-checks = false -incremental = false -opt-level = "s" +opt-level = "s" ## defaults to be 3 +incremental = true -# codegen-units = 1 # Reduce number of codegen units to increase optimizations. +[profile.ci] +inherits = "release" +overflow-checks = true +incremental = false +debug-assertions = true # [profile.release.package] -# arrow2 = { codegen-units = 4 } -# common-functions = { codegen-units = 16 } # databend-query = { codegen-units = 4 } # databend-binaries = { codegen-units = 4 } [profile.dev] split-debuginfo = "unpacked" -overflow-checks = false -# wait until https://github.com/rust-lang/rust/issues/100142 fixed -incremental = false +overflow-checks = true +# Report to https://github.com/rust-lang/rust/issues/100142 if incremental works well +incremental = true [profile.dev.package] addr2line = { opt-level = 3 } diff --git a/src/common/arrow/src/arrow/buffer/iterator.rs b/src/common/arrow/src/arrow/buffer/iterator.rs index cf908272015f..f858a8f8b86d 100644 --- a/src/common/arrow/src/arrow/buffer/iterator.rs +++ b/src/common/arrow/src/arrow/buffer/iterator.rs @@ -19,20 +19,20 @@ use crate::arrow::trusted_len::TrustedLen; /// This crates' equivalent of [`std::vec::IntoIter`] for [`Buffer`]. #[derive(Debug, Clone)] pub struct IntoIter { - values: Buffer, - index: usize, - end: usize, + buffer: Buffer, + current: *const T, + end: *const T, } impl IntoIter { - /// Creates a new [`Buffer`] #[inline] - pub fn new(values: Buffer) -> Self { - let end = values.len(); + pub fn new(buffer: Buffer) -> Self { + let ptr = buffer.as_ptr(); + let len = buffer.len(); Self { - values, - index: 0, - end, + current: ptr, + end: unsafe { ptr.add(len) }, + buffer, } } } @@ -42,40 +42,30 @@ impl Iterator for IntoIter { #[inline] fn next(&mut self) -> Option { - if self.index == self.end { - return None; + if self.current == self.end { + None + } else { + let value = unsafe { *self.current }; + self.current = unsafe { self.current.add(1) }; + Some(value) } - let old = self.index; - self.index += 1; - Some(*unsafe { self.values.get_unchecked(old) }) } #[inline] fn size_hint(&self) -> (usize, Option) { - (self.end - self.index, Some(self.end - self.index)) - } - - #[inline] - fn nth(&mut self, n: usize) -> Option { - let new_index = self.index + n; - if new_index > self.end { - self.index = self.end; - None - } else { - self.index = new_index; - self.next() - } + let len = unsafe { self.end.offset_from(self.current) } as usize; + (len, Some(len)) } } impl DoubleEndedIterator for IntoIter { #[inline] fn next_back(&mut self) -> Option { - if self.index == self.end { + if self.current == self.end { None } else { - self.end -= 1; - Some(*unsafe { self.values.get_unchecked(self.end) }) + self.end = unsafe { self.end.sub(1) }; + Some(unsafe { *self.end }) } } } diff --git a/src/query/expression/benches/bench.rs b/src/query/expression/benches/bench.rs new file mode 100644 index 000000000000..8ff91219fa5c --- /dev/null +++ b/src/query/expression/benches/bench.rs @@ -0,0 +1,239 @@ +// Copyright 2021 Datafuse Labs +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#[macro_use] +extern crate criterion; + +use criterion::Criterion; +use databend_common_column::buffer::Buffer; +use databend_common_expression::arrow::deserialize_column; +use databend_common_expression::arrow::serialize_column; +use databend_common_expression::types::BinaryType; +use databend_common_expression::types::StringType; +use databend_common_expression::Column; +use databend_common_expression::DataBlock; +use databend_common_expression::FromData; +use rand::rngs::StdRng; +use rand::Rng; +use rand::SeedableRng; + +fn bench(c: &mut Criterion) { + let mut group = c.benchmark_group("bench_kernels"); + + let mut rng = StdRng::seed_from_u64(0); + // concats + { + for length in [12, 20, 500] { + let (s, b) = generate_random_string_data(&mut rng, length); + let bin_col = (0..5).map(|_| BinaryType::from_data(b.clone())); + let str_col = (0..5).map(|_| StringType::from_data(s.clone())); + + group.bench_function(format!("concat_string_offset/{length}"), |b| { + b.iter(|| Column::concat_columns(bin_col.clone()).unwrap()) + }); + + group.bench_function(format!("concat_string_view/{length}"), |b| { + b.iter(|| Column::concat_columns(str_col.clone()).unwrap()) + }); + } + } + + // take compact + { + for length in [12, 20, 500] { + let (s, b) = generate_random_string_data(&mut rng, length); + let block_bin = DataBlock::new_from_columns(vec![BinaryType::from_data(b.clone())]); + let block_view = DataBlock::new_from_columns(vec![StringType::from_data(s.clone())]); + + let indices: Vec<(u32, u32)> = (0..s.len()) + .filter(|x| x % 10 == 0) + .map(|x| (x as u32, 1000)) + .collect(); + let num_rows = indices.len() * 1000; + + group.bench_function(format!("take_compact_string_offset/{length}"), |b| { + b.iter(|| { + block_bin + .take_compacted_indices(&indices, num_rows) + .unwrap() + }) + }); + + group.bench_function(format!("take_compact_string_view/{length}"), |b| { + b.iter(|| { + block_view + .take_compacted_indices(&indices, num_rows) + .unwrap() + }) + }); + } + } + + // IPC + // bench_kernels/serialize_string_offset/12 + // time: [183.25 µs 183.49 µs 183.93 µs] + // Found 7 outliers among 100 measurements (7.00%) + // 3 (3.00%) high mild + // 4 (4.00%) high severe + // bench_kernels/serialize_string_view/12 + // time: [415.25 µs 415.36 µs 415.47 µs] + // Found 6 outliers among 100 measurements (6.00%) + // 3 (3.00%) high mild + // 3 (3.00%) high severe + // bench_kernels/serialize_string_offset/20 + // time: [195.09 µs 195.15 µs 195.23 µs] + // Found 6 outliers among 100 measurements (6.00%) + // 6 (6.00%) high mild + // bench_kernels/serialize_string_view/20 + // time: [464.96 µs 465.08 µs 465.21 µs] + // Found 4 outliers among 100 measurements (4.00%) + // 4 (4.00%) high mild + // bench_kernels/serialize_string_offset/500 + // time: [3.3092 ms 3.3139 ms 3.3194 ms] + // Found 2 outliers among 100 measurements (2.00%) + // 1 (1.00%) high mild + // 1 (1.00%) high severe + // bench_kernels/serialize_string_view/500 + // time: [3.9254 ms 3.9303 ms 3.9366 ms] + // Found 9 outliers among 100 measurements (9.00%) + // 4 (4.00%) high mild + // 5 (5.00%) high severe + + { + for length in [12, 20, 500] { + let (s, b) = generate_random_string_data(&mut rng, length); + let b_c = BinaryType::from_data(b.clone()); + let s_c = StringType::from_data(s.clone()); + + group.bench_function(format!("serialize_string_offset/{length}"), |b| { + b.iter(|| { + let bs = serialize_column(&b_c); + deserialize_column(&bs).unwrap(); + }) + }); + + group.bench_function(format!("serialize_string_view/{length}"), |b| { + b.iter(|| { + let bs = serialize_column(&s_c); + deserialize_column(&bs).unwrap(); + }) + }); + } + } + + for length in [10240, 102400] { + let (left, right) = generate_random_int_data(&mut rng, length); + + group.bench_function(format!("function_iterator_iterator_v1/{length}"), |b| { + b.iter(|| { + let left = left.clone(); + let right = right.clone(); + + let _c = left + .into_iter() + .zip(right.into_iter()) + .map(|(a, b)| a + b) + .collect::>(); + }) + }); + + group.bench_function(format!("function_iterator_iterator_v2/{length}"), |b| { + b.iter(|| { + let _c = left + .iter() + .cloned() + .zip(right.iter().cloned()) + .map(|(a, b)| a + b) + .collect::>(); + }) + }); + + group.bench_function( + format!("function_buffer_index_unchecked_iterator/{length}"), + |b| { + b.iter(|| { + let _c = (0..length) + .map(|i| unsafe { left.get_unchecked(i) + right.get_unchecked(i) }) + .collect::>(); + }) + }, + ); + + group.bench_function( + format!("function_slice_index_unchecked_iterator/{length}"), + |b| { + b.iter(|| { + let left = left.as_slice(); + let right = right.as_slice(); + + let _c = (0..length) + .map(|i| unsafe { left.get_unchecked(i) + right.get_unchecked(i) }) + .collect::>(); + }) + }, + ); + + let left_vec: Vec<_> = left.iter().cloned().collect(); + let right_vec: Vec<_> = right.iter().cloned().collect(); + + group.bench_function( + format!("function_vec_index_unchecked_iterator/{length}"), + |b| { + b.iter(|| { + let _c = (0..length) + .map(|i| unsafe { left_vec.get_unchecked(i) + right_vec.get_unchecked(i) }) + .collect::>(); + }) + }, + ); + + group.bench_function(format!("function_buffer_index_iterator/{length}"), |b| { + b.iter(|| { + let _c = (0..length) + .map(|i| left[i] + right[i]) + .collect::>(); + }) + }); + } +} + +criterion_group!(benches, bench); +criterion_main!(benches); + +fn generate_random_string_data(rng: &mut StdRng, length: usize) -> (Vec, Vec>) { + let iter_str: Vec<_> = (0..10000) + .map(|_| { + let random_string: String = (0..length) + .map(|_| { + // Generate a random character (ASCII printable characters) + rng.gen_range(32..=126) as u8 as char + }) + .collect(); + random_string + }) + .collect(); + + let iter_binary: Vec<_> = iter_str + .iter() + .map(|x| x.clone().as_bytes().to_vec()) + .collect(); + + (iter_str, iter_binary) +} + +fn generate_random_int_data(rng: &mut StdRng, length: usize) -> (Buffer, Buffer) { + let s: Buffer = (0..length).map(|_| rng.gen_range(-1000..1000)).collect(); + let b: Buffer = (0..length).map(|_| rng.gen_range(-1000..1000)).collect(); + (s, b) +} diff --git a/src/query/expression/src/filter/like.rs b/src/query/expression/src/filter/like.rs index 7e162cb997c3..d3b9c511a942 100644 --- a/src/query/expression/src/filter/like.rs +++ b/src/query/expression/src/filter/like.rs @@ -271,13 +271,13 @@ fn find(mut haystack: &[u8], needle: &[u8]) -> Option { return None; } // Inspired by fast_strstr (https://github.com/RaphaelJ/fast_strstr). - let mut checksum = 0; + let mut checksum: i64 = 0; for i in 0..needle_len { // # Safety // `needle_len` <= haystack_len unsafe { - checksum += haystack.get_unchecked(i); - checksum -= needle.get_unchecked(i); + checksum += *haystack.get_unchecked(i) as i64; + checksum -= *needle.get_unchecked(i) as i64; } } let mut idx = 0; @@ -298,8 +298,8 @@ fn find(mut haystack: &[u8], needle: &[u8]) -> Option { // # Safety // `idx` < `haystack_len` and `idx` + `needle_len` < `haystack_len`. unsafe { - checksum -= haystack.get_unchecked(idx); - checksum += haystack.get_unchecked(idx + needle_len); + checksum -= *haystack.get_unchecked(idx) as i64; + checksum += *haystack.get_unchecked(idx + needle_len) as i64; } idx += 1; } diff --git a/src/query/expression/src/utils/block_debug.rs b/src/query/expression/src/utils/block_debug.rs index 05f877215ea5..d6ffa2191cdc 100644 --- a/src/query/expression/src/utils/block_debug.rs +++ b/src/query/expression/src/utils/block_debug.rs @@ -186,7 +186,7 @@ fn create_box_table( let row_count: usize = results.iter().map(|block| block.num_rows()).sum(); let mut rows_to_render = row_count.min(max_rows); - if row_count <= max_rows + 3 { + if row_count <= max_rows.saturating_add(3) { // hiding rows adds 3 extra rows // so hiding rows makes no sense if we are only slightly over the limit // if we are 1 row over the limit hiding rows will actually increase the number of lines we display! @@ -228,7 +228,7 @@ fn create_box_table( // "..." take up three lengths if max_width > 0 { (widths, column_map) = - compute_render_widths(schema, max_width, max_col_width + 3, &res_vec); + compute_render_widths(schema, max_width, max_col_width.saturating_add(3), &res_vec); } let mut header = Vec::with_capacity(schema.fields().len()); @@ -355,7 +355,7 @@ fn compute_render_widths( for field in schema.fields() { // head_name = field_name + "\n" + field_data_type let col_length = field.name().len().max(field.data_type().to_string().len()); - widths.push(col_length + 3); + widths.push(col_length.saturating_add(3)); } for values in results { diff --git a/src/query/service/src/sessions/session_ctx.rs b/src/query/service/src/sessions/session_ctx.rs index 0a0e03b6d4fc..f79f5c5c076e 100644 --- a/src/query/service/src/sessions/session_ctx.rs +++ b/src/query/service/src/sessions/session_ctx.rs @@ -297,7 +297,7 @@ impl SessionContext { index }; - if idx < 0 || idx > (query_ids_len - 1) as i32 { + if query_ids_len < 1 || idx < 0 || idx > (query_ids_len - 1) as i32 { return "".to_string(); } diff --git a/src/query/service/src/sessions/session_mgr_status.rs b/src/query/service/src/sessions/session_mgr_status.rs index 69e43bea1afa..2db67041972a 100644 --- a/src/query/service/src/sessions/session_mgr_status.rs +++ b/src/query/service/src/sessions/session_mgr_status.rs @@ -31,7 +31,7 @@ impl SessionManagerStatus { } pub(crate) fn query_finish(&mut self, now: SystemTime) { - self.running_queries_count -= 1; + self.running_queries_count = self.running_queries_count.saturating_sub(1); if self.running_queries_count == 0 { self.last_query_finished_at = Some(now) } diff --git a/tests/suites/1_stateful/02_query/02_0000_kill_query.py b/tests/suites/1_stateful/02_query/02_0000_kill_query.py index f3dc069f6223..d538411d4662 100755 --- a/tests/suites/1_stateful/02_query/02_0000_kill_query.py +++ b/tests/suites/1_stateful/02_query/02_0000_kill_query.py @@ -37,7 +37,7 @@ res = mycursor.fetchone() kill_query = "kill query " + str(res[0]) + ";" mycursor.execute(kill_query) - time.sleep(0.5) + time.sleep(10) mycursor.execute( "SELECT * FROM system.processes WHERE extra_info LIKE '%SELECT max(number)%' AND extra_info NOT LIKE '%system.processes%';" )