Skip to content

Commit

Permalink
add tests for ghist building
Browse files Browse the repository at this point in the history
  • Loading branch information
Dmitry Razdoburdin committed Mar 15, 2024
1 parent 04a7205 commit 3ffa8dc
Show file tree
Hide file tree
Showing 3 changed files with 167 additions and 4 deletions.
1 change: 1 addition & 0 deletions plugin/sycl/common/hist_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "row_set.h"

#include "../../src/common/hist_util.h"
#include "../data/gradient_index.h"

#include <CL/sycl.hpp>

Expand Down
9 changes: 5 additions & 4 deletions tests/cpp/plugin/sycl_helpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,23 @@
namespace xgboost::sycl {
template<typename T, typename Container>
void VerifySyclVector(const USMVector<T, MemoryType::shared>& sycl_vector,
const Container& host_vector) {
const Container& host_vector, T eps = T()) {
ASSERT_EQ(sycl_vector.Size(), host_vector.size());

size_t size = sycl_vector.Size();
for (size_t i = 0; i < size; ++i) {
ASSERT_EQ(sycl_vector[i], host_vector[i]);
EXPECT_NEAR(sycl_vector[i], host_vector[i], eps);
}
}

template<typename T, typename Container>
void VerifySyclVector(const std::vector<T>& sycl_vector, const Container& host_vector) {
void VerifySyclVector(const std::vector<T>& sycl_vector,
const Container& host_vector, T eps = T()) {
ASSERT_EQ(sycl_vector.size(), host_vector.size());

size_t size = sycl_vector.size();
for (size_t i = 0; i < size; ++i) {
ASSERT_EQ(sycl_vector[i], host_vector[i]);
EXPECT_NEAR(sycl_vector[i], host_vector[i], eps);
}
}

Expand Down
161 changes: 161 additions & 0 deletions tests/cpp/plugin/test_sycl_ghist_builder.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
/**
* Copyright 2020-2024 by XGBoost contributors
*/
#include <gtest/gtest.h>

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wtautological-constant-compare"
#pragma GCC diagnostic ignored "-W#pragma-messages"
#include "../../../src/data/gradient_index.h" // for GHistIndexMatrix
#pragma GCC diagnostic pop

#include "../../../plugin/sycl/common/hist_util.h"
#include "../../../plugin/sycl/device_manager.h"
#include "sycl_helpers.h"
#include "../helpers.h"

namespace xgboost::sycl::common {

template <typename GradientSumT>
void GHistBuilderTest(int n_bins, float sparsity) {
const size_t num_rows = 8;
const size_t num_columns = 1;

Context ctx;
ctx.UpdateAllowUnknown(Args{{"device", "sycl"}});

DeviceManager device_manager;
auto qu = device_manager.GetQueue(ctx.Device());

auto p_fmat = RandomDataGenerator{num_rows, num_columns, sparsity}.GenerateDMatrix();
sycl::DeviceMatrix dmat;
dmat.Init(qu, p_fmat.get());

GHistIndexMatrix gmat_sycl;
gmat_sycl.Init(qu, &ctx, dmat, n_bins);

xgboost::GHistIndexMatrix gmat{&ctx, p_fmat.get(), n_bins, 0.3, false};

RowSetCollection row_set_collection;
auto& row_indices = row_set_collection.Data();
row_indices.Resize(&qu, num_rows);
size_t* p_row_indices = row_indices.Data();

qu.submit([&](::sycl::handler& cgh) {
cgh.parallel_for<>(::sycl::range<1>(num_rows),
[p_row_indices](::sycl::item<1> pid) {
const size_t idx = pid.get_id(0);
p_row_indices[idx] = idx;
});
}).wait_and_throw();
row_set_collection.Init();

auto builder = GHistBuilder<GradientSumT>(qu, n_bins);

std::vector<GradientPair> gpair = {
{0.1f, 0.2f}, {0.3f, 0.4f}, {0.5f, 0.6f}, {0.7f, 0.8f},
{0.9f, 0.1f}, {0.2f, 0.3f}, {0.4f, 0.5f}, {0.6f, 0.7f}};
CHECK_EQ(gpair.size(), num_rows);
USMVector<GradientPair, MemoryType::on_device> gpair_device(&qu, gpair);

std::vector<GradientSumT> hist_host(2*n_bins);
GHistRow<GradientSumT, MemoryType::on_device> hist(&qu, 2 * n_bins);
InitHist(qu, &hist, hist.Size());

const size_t nblocks = 2;
GHistRow<GradientSumT, MemoryType::on_device> hist_buffer(&qu, 2 * nblocks * n_bins);
InitHist(qu, &hist_buffer, hist_buffer.Size());

::sycl::event event;
event = builder.BuildHist(gpair_device, row_set_collection[0], gmat_sycl, &hist, true, &hist_buffer, event);
qu.memcpy(hist_host.data(), hist.Data(),
2 * n_bins * sizeof(GradientSumT), event);
qu.wait_and_throw();

// Build hist on host to compare
std::vector<GradientSumT> hist_desired(2*n_bins);
for (size_t rid = 0; rid < num_rows; ++rid) {
const size_t ibegin = gmat.row_ptr[rid];
const size_t iend = gmat.row_ptr[rid + 1];
for (size_t i = ibegin; i < iend; ++i) {
const size_t bin_idx = gmat.index[i];
hist_desired[2*bin_idx] += gpair[rid].GetGrad();
hist_desired[2*bin_idx+1] += gpair[rid].GetHess();
}
}

const GradientSumT eps = 1e-6;
VerifySyclVector(hist_host, hist_desired, eps);
}

template <typename GradientSumT>
void GHistSubtractionTest() {
const size_t n_bins = 4;
using GHistType = GHistRow<GradientSumT, MemoryType::on_device>;

Context ctx;
ctx.UpdateAllowUnknown(Args{{"device", "sycl"}});

DeviceManager device_manager;
auto qu = device_manager.GetQueue(ctx.Device());

std::vector<GradientSumT> hist1_host = {0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8};
GHistType hist1(&qu, 2 * n_bins);
InitHist(qu, &hist1, hist1.Size());
qu.memcpy(hist1.Data(), hist1_host.data(),
2 * n_bins * sizeof(GradientSumT));
qu.wait();

std::vector<GradientSumT> hist2_host = {0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1};
GHistType hist2(&qu, 2 * n_bins);
InitHist(qu, &hist2, hist2.Size());
qu.memcpy(hist2.Data(), hist2_host.data(),
2 * n_bins * sizeof(GradientSumT));
qu.wait();

std::vector<GradientSumT> hist3_host(2 * n_bins);
GHistType hist3(&qu, 2 * n_bins);
auto event = SubtractionHist(qu, &hist3, hist1, hist2, 2 * n_bins, ::sycl::event());
qu.memcpy(hist3_host.data(), hist3.Data(),
2 * n_bins * sizeof(GradientSumT), event);
qu.wait();

std::vector<GradientSumT> hist3_desired(2 * n_bins);
for (size_t idx = 0; idx < 2 * n_bins; ++idx) {
hist3_desired[idx] = hist1_host[idx] - hist2_host[idx];
}

const GradientSumT eps = 1e-6;
VerifySyclVector(hist3_host, hist3_desired, eps);
}

TEST(SyclGHistBuilder, ByBlockDenseCase) {
// 2-bins. In this case block builder is used
GHistBuilderTest<float>(2, 0.0);
GHistBuilderTest<double>(2, 0.0);
}

TEST(SyclGHistBuilder, ByBlockSparseCase) {
// 2-bins. In this case block builder is used
GHistBuilderTest<float>(2, 0.3);
GHistBuilderTest<double>(2, 0.3);
}

TEST(SyclGHistBuilder, ByAtomicDenseCase) {
// 16-bins. In this case block builder is used
GHistBuilderTest<float>(16, 0.0);
GHistBuilderTest<double>(16, 0.0);
}

TEST(SyclGHistBuilder, ByAtomicSparseCase) {
// 16-bins. In this case block builder is used
GHistBuilderTest<float>(16, 0.3);
GHistBuilderTest<double>(16, 0.3);
}

TEST(SyclGHistBuilder, Subtraction) {
GHistSubtractionTest<float>();
GHistSubtractionTest<double>();
}

} // namespace xgboost::sycl::common

0 comments on commit 3ffa8dc

Please sign in to comment.