CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
209 lines
9.5 KiB
C++
209 lines
9.5 KiB
C++
// MIT License
|
|
//
|
|
// Copyright (c) 2017-2025 Advanced Micro Devices, Inc. All rights reserved.
|
|
//
|
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
// of this software and associated documentation files (the "Software"), to deal
|
|
// in the Software without restriction, including without limitation the rights
|
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
// copies of the Software, and to permit persons to whom the Software is
|
|
// furnished to do so, subject to the following conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be included in all
|
|
// copies or substantial portions of the Software.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
// SOFTWARE.
|
|
|
|
// required test headers
|
|
#include "../common_test_header.hpp"
|
|
|
|
// required rocprim headers
|
|
#include "../../common/utils_device_ptr.hpp"
|
|
#include "../rocprim/test_seed.hpp"
|
|
#include "../rocprim/test_utils.hpp"
|
|
|
|
#include <rocprim/device/device_binary_search.hpp>
|
|
#include <rocprim/device/device_merge_sort.hpp>
|
|
|
|
// required STL headers
|
|
#include <algorithm>
|
|
|
|
template<typename KeyType>
|
|
void generate_needles(const std::vector<KeyType>& input, std::vector<KeyType>& output, const size_t search_needle_size, const std::pair<KeyType, KeyType>& bounds, const seed_type& seed_value)
|
|
{
|
|
// Pick 50% of the needles from the input vector
|
|
std::vector<KeyType> indices = test_utils::get_random_data<KeyType>(search_needle_size / 2, 0, input.size() - 1, seed_value);
|
|
|
|
// Do selection on the in-bounds indices and write the results to the output vector
|
|
std::transform(indices.begin(), indices.end(), output.begin(), [&input](const KeyType& index)
|
|
{
|
|
return input[index];
|
|
});
|
|
|
|
// Generate the other 50% from outside the input vector
|
|
const KeyType max_val = std::get<1>(bounds);
|
|
std::vector<KeyType> out_of_bounds_vals = test_utils::get_random_data<KeyType>(search_needle_size - search_needle_size / 2, max_val, max_val * 2, seed_value);
|
|
|
|
// Append the out-of-bounds values
|
|
for (size_t i = 0; i < out_of_bounds_vals.size(); i++)
|
|
output[indices.size() + i] = out_of_bounds_vals[i];
|
|
|
|
// Mix up the in-bounds and out-of-bounds values to make the test a bit more robust
|
|
std::random_device rd;
|
|
std::default_random_engine gen(rd());
|
|
std::shuffle(output.begin(), output.end(), gen);
|
|
}
|
|
|
|
template<typename KeyType, typename BinaryFunction>
|
|
void computeExpectedSortAndSearchResult(std::vector<KeyType>& sort_input, const std::vector<KeyType>& search_needles, std::vector<KeyType>& expected_search_output, BinaryFunction compare_op)
|
|
{
|
|
// Sort
|
|
std::stable_sort(sort_input.begin(), sort_input.end(), compare_op);
|
|
|
|
// Search
|
|
for (size_t i = 0; i < search_needles.size(); i++)
|
|
expected_search_output[i] = std::binary_search(sort_input.begin(), sort_input.end(), search_needles[i], compare_op);
|
|
}
|
|
|
|
// This test creates a graph that performs a device-wide merge_sort followed by a device-wide binary_search.
|
|
// After the graph is created, it is launched multiple times, each time using different data.
|
|
TEST(TestHipGraphAlgs, SortAndSearch)
|
|
{
|
|
// Test case params
|
|
using key_type = int;
|
|
using compare_fcn_type = typename ::rocprim::less<key_type>;
|
|
compare_fcn_type compare_op;
|
|
const size_t sort_data_size = 4096;
|
|
const size_t search_needle_size = 100;
|
|
const size_t num_trials = 5;
|
|
std::pair<key_type, key_type> bounds = std::make_pair(-10000, 10000); // generated data will fall in this range
|
|
const bool debug_synchronous = false;
|
|
|
|
// Set the device
|
|
int device_id = test_common_utils::obtain_device_from_ctest();
|
|
SCOPED_TRACE(testing::Message() << "with device_id = " << device_id);
|
|
HIP_CHECK(hipSetDevice(device_id));
|
|
|
|
// Generate data on the host
|
|
const seed_type seed_value = seeds[random_seeds_count - 1];
|
|
SCOPED_TRACE(testing::Message() << "with seed = " << seed_value);
|
|
SCOPED_TRACE(testing::Message() << "with sort_data_size = " << sort_data_size);
|
|
SCOPED_TRACE(testing::Message() << "with search_needle_size = " << search_needle_size);
|
|
|
|
// Allocate device buffers and copy data into them
|
|
common::device_ptr<key_type> d_sort_input(sort_data_size);
|
|
common::device_ptr<key_type> d_sort_output(sort_data_size); // also used as search_input
|
|
common::device_ptr<key_type> d_search_output(search_needle_size);
|
|
common::device_ptr<key_type> d_search_needles(search_needle_size);
|
|
|
|
// Default stream does not support hipGraph stream capture, so create a non-blocking one
|
|
hipStream_t stream = 0;
|
|
HIP_CHECK(hipStreamCreateWithFlags(&stream, hipStreamNonBlocking));
|
|
|
|
// Get temporary storage size required for merge_sort.
|
|
// Note: doing this inside a graph doesn't gain us any benefit,
|
|
// since these calls run entirely on the host - however, it is
|
|
// important to validate that they work inside a graph capture block.
|
|
size_t sort_temp_storage_bytes = 0;
|
|
HIP_CHECK(rocprim::merge_sort(nullptr,
|
|
sort_temp_storage_bytes,
|
|
d_sort_input.get(),
|
|
d_sort_output.get(),
|
|
sort_data_size,
|
|
compare_op,
|
|
stream,
|
|
debug_synchronous));
|
|
|
|
// Get size of temporary storage required for binary_search
|
|
size_t search_temp_storage_bytes = 0;
|
|
HIP_CHECK(rocprim::binary_search(nullptr,
|
|
search_temp_storage_bytes,
|
|
d_sort_output.get(),
|
|
d_search_needles.get(),
|
|
d_search_output.get(),
|
|
sort_data_size,
|
|
search_needle_size,
|
|
compare_op,
|
|
stream,
|
|
debug_synchronous));
|
|
|
|
// Allocate the temp storage
|
|
// Note: a single store will be used for both the sort and search algorithms
|
|
size_t temp_storage_bytes = std::max(sort_temp_storage_bytes, search_temp_storage_bytes);
|
|
// temp_storage_size_bytes must be > 0
|
|
ASSERT_GT(temp_storage_bytes, 0);
|
|
|
|
common::device_ptr<void> d_temp_storage(temp_storage_bytes);
|
|
|
|
// Begin graph capture
|
|
test_utils::GraphHelper gHelper;
|
|
gHelper.startStreamCapture(stream);
|
|
|
|
// Launch merge_sort
|
|
HIP_CHECK(rocprim::merge_sort(d_temp_storage.get(),
|
|
sort_temp_storage_bytes,
|
|
d_sort_input.get(),
|
|
d_sort_output.get(),
|
|
sort_data_size,
|
|
compare_op,
|
|
stream,
|
|
false));
|
|
|
|
// Launch binary_search
|
|
HIP_CHECK(rocprim::binary_search<rocprim::default_config>(d_temp_storage.get(),
|
|
search_temp_storage_bytes,
|
|
d_sort_output.get(),
|
|
d_search_needles.get(),
|
|
d_search_output.get(),
|
|
sort_data_size,
|
|
search_needle_size,
|
|
compare_op,
|
|
stream,
|
|
false););
|
|
|
|
// End graph capture, but do not execute the graph yet.
|
|
gHelper.endStreamCapture(stream);
|
|
gHelper.createGraph();
|
|
|
|
std::vector<key_type> sort_input;
|
|
std::vector<key_type> search_needles(search_needle_size);
|
|
std::vector<key_type> expected_search_output(search_needle_size);
|
|
std::vector<key_type> device_output(search_needle_size);
|
|
|
|
// We'll launch the graph multiple times with different data.
|
|
for (size_t i = 0; i < num_trials; i++)
|
|
{
|
|
// Generate the test data
|
|
sort_input = test_utils::get_random_data<key_type>(sort_data_size, std::get<0>(bounds), std::get<1>(bounds), seed_value);
|
|
generate_needles(sort_input, search_needles, search_needle_size, bounds, seed_value);
|
|
|
|
// Compute the expected result on the host
|
|
computeExpectedSortAndSearchResult<key_type, compare_fcn_type>(sort_input, search_needles, expected_search_output, compare_op);
|
|
|
|
// Copy input data to the device
|
|
d_sort_input.store(sort_input);
|
|
d_search_needles.store(search_needles);
|
|
|
|
// Launch the graph
|
|
gHelper.launchGraph(stream, true);
|
|
|
|
// Copy output back to host
|
|
device_output = d_search_output.load();
|
|
|
|
// Validate the results
|
|
ASSERT_NO_FATAL_FAILURE(test_utils::assert_eq(device_output, expected_search_output));
|
|
}
|
|
|
|
// Clean up
|
|
|
|
gHelper.cleanupGraphHelper();
|
|
HIP_CHECK(hipStreamDestroy(stream));
|
|
}
|
|
|
|
|