Skip to content

Commit

Permalink
Add gbenchmark for strings find/contains functions (#7392)
Browse files Browse the repository at this point in the history
Reference #5698
This creates a gbenchmark for the `cudf::strings::contains`, `cudf::strings::find`, `cudf::strings::find_multiple`, `cudf::strings::starts_with`, and `cudf::strings::ends_with`. 

This also includes some improvements for `starts_with` and `ends_with` to use `string_view::compare` instead of `string_view::find` since `compare` would be more efficient when checking for a string at a specific position. This improved the performance of these two functions by 2-3x on average.

Authors:
  - David (@davidwendt)

Approvers:
  - Keith Kraus (@kkraus14)
  - Mark Harris (@harrism)
  - Karthikeyan (@karthikeyann)

URL: #7392
  • Loading branch information
davidwendt authored Feb 19, 2021
1 parent 7a6e60e commit 580f9a2
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 11 deletions.
1 change: 1 addition & 0 deletions cpp/benchmarks/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,7 @@ set(STRINGS_BENCH_SRC
"${CMAKE_CURRENT_SOURCE_DIR}/string/case_benchmark.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/string/contains_benchmark.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/string/convert_durations_benchmark.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/string/find_benchmark.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/string/replace_benchmark.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/string/url_decode_benchmark.cpp")

Expand Down
95 changes: 95 additions & 0 deletions cpp/benchmarks/string/find_benchmark.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/*
* Copyright (c) 2021, NVIDIA CORPORATION.
*
* 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.
*/

#include <benchmark/benchmark.h>
#include <benchmarks/common/generate_benchmark_input.hpp>
#include <benchmarks/fixture/benchmark_fixture.hpp>
#include <benchmarks/synchronization/synchronization.hpp>

#include <cudf/scalar/scalar.hpp>
#include <cudf/strings/find.hpp>
#include <cudf/strings/find_multiple.hpp>
#include <cudf/strings/strings_column_view.hpp>
#include <cudf_test/column_wrapper.hpp>

#include <limits>

enum FindAPI { find, find_multi, contains, starts_with, ends_with };

class StringFindScalar : public cudf::benchmark {
};

static void BM_find_scalar(benchmark::State& state, FindAPI find_api)
{
cudf::size_type const n_rows{static_cast<cudf::size_type>(state.range(0))};
cudf::size_type const max_str_length{static_cast<cudf::size_type>(state.range(1))};
data_profile table_profile;
table_profile.set_distribution_params(
cudf::type_id::STRING, distribution_id::NORMAL, 0, max_str_length);
auto const table =
create_random_table({cudf::type_id::STRING}, 1, row_count{n_rows}, table_profile);
cudf::strings_column_view input(table->view().column(0));
cudf::string_scalar target("+");
cudf::test::strings_column_wrapper targets({"+", "-"});

for (auto _ : state) {
cuda_event_timer raii(state, true, 0);
switch (find_api) {
case find: cudf::strings::find(input, target); break;
case find_multi:
cudf::strings::find_multiple(input, cudf::strings_column_view(targets));
break;
case contains: cudf::strings::contains(input, target); break;
case starts_with: cudf::strings::starts_with(input, target); break;
case ends_with: cudf::strings::ends_with(input, target); break;
}
}

state.SetBytesProcessed(state.iterations() * input.chars_size());
}

static void generate_bench_args(benchmark::internal::Benchmark* b)
{
int const min_rows = 1 << 12;
int const max_rows = 1 << 24;
int const row_mult = 8;
int const min_rowlen = 1 << 5;
int const max_rowlen = 1 << 13;
int const len_mult = 4;
for (int row_count = min_rows; row_count <= max_rows; row_count *= row_mult) {
for (int rowlen = min_rowlen; rowlen <= max_rowlen; rowlen *= len_mult) {
// avoid generating combinations that exceed the cudf column limit
size_t total_chars = static_cast<size_t>(row_count) * rowlen;
if (total_chars < std::numeric_limits<cudf::size_type>::max()) {
b->Args({row_count, rowlen});
}
}
}
}

#define STRINGS_BENCHMARK_DEFINE(name) \
BENCHMARK_DEFINE_F(StringFindScalar, name) \
(::benchmark::State & st) { BM_find_scalar(st, name); } \
BENCHMARK_REGISTER_F(StringFindScalar, name) \
->Apply(generate_bench_args) \
->UseManualTime() \
->Unit(benchmark::kMillisecond);

STRINGS_BENCHMARK_DEFINE(find)
STRINGS_BENCHMARK_DEFINE(find_multi)
STRINGS_BENCHMARK_DEFINE(contains)
STRINGS_BENCHMARK_DEFINE(starts_with)
STRINGS_BENCHMARK_DEFINE(ends_with)
24 changes: 13 additions & 11 deletions cpp/src/strings/find.cu
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2019-2020, NVIDIA CORPORATION.
* Copyright (c) 2019-2021, NVIDIA CORPORATION.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -315,7 +315,8 @@ std::unique_ptr<column> starts_with(
rmm::mr::device_memory_resource* mr = rmm::mr::get_current_device_resource())
{
auto pfn = [] __device__(string_view d_string, string_view d_target) {
return d_string.find(d_target) == 0;
return (d_target.size_bytes() <= d_string.size_bytes()) &&
(d_target.compare(d_string.data(), d_target.size_bytes()) == 0);
};
return contains_fn(strings, target, pfn, stream, mr);
}
Expand All @@ -327,7 +328,8 @@ std::unique_ptr<column> starts_with(
rmm::mr::device_memory_resource* mr = rmm::mr::get_current_device_resource())
{
auto pfn = [] __device__(string_view d_string, string_view d_target) {
return d_string.find(d_target) == 0;
return (d_target.size_bytes() <= d_string.size_bytes()) &&
(d_target.compare(d_string.data(), d_target.size_bytes()) == 0);
};
return contains_fn(strings, targets, pfn, stream, mr);
}
Expand All @@ -339,10 +341,10 @@ std::unique_ptr<column> ends_with(
rmm::mr::device_memory_resource* mr = rmm::mr::get_current_device_resource())
{
auto pfn = [] __device__(string_view d_string, string_view d_target) {
auto str_length = d_string.length();
auto tgt_length = d_target.length();
if (str_length < tgt_length) return false;
return d_string.find(d_target, str_length - tgt_length) >= 0;
auto const str_size = d_string.size_bytes();
auto const tgt_size = d_target.size_bytes();
return (tgt_size <= str_size) &&
(d_target.compare(d_string.data() + str_size - tgt_size, tgt_size) == 0);
};

return contains_fn(strings, target, pfn, stream, mr);
Expand All @@ -355,10 +357,10 @@ std::unique_ptr<column> ends_with(
rmm::mr::device_memory_resource* mr = rmm::mr::get_current_device_resource())
{
auto pfn = [] __device__(string_view d_string, string_view d_target) {
auto str_length = d_string.length();
auto tgt_length = d_target.length();
if (str_length < tgt_length) return false;
return d_string.find(d_target, str_length - tgt_length) >= 0;
auto const str_size = d_string.size_bytes();
auto const tgt_size = d_target.size_bytes();
return (tgt_size <= str_size) &&
(d_target.compare(d_string.data() + str_size - tgt_size, tgt_size) == 0);
};

return contains_fn(strings, targets, pfn, stream, mr);
Expand Down

0 comments on commit 580f9a2

Please sign in to comment.