Files
TheRock/rocm-libraries/projects/rocprim/test/hipgraph/test_hipgraph_algs.cpp
T
derek.holloway 7502bf64a4
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
Flatten subprojects into a single base monorepo
2026-09-02 16:34:47 -07:00

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));
}