Skip to content

Commit 46b007a

Browse files
Dmitry Razdoburdinrazdoburdin
authored andcommitted
allow build with cmake; fix test; fix bug with mingw
1 parent d3772fb commit 46b007a

File tree

7 files changed

+149
-163
lines changed

7 files changed

+149
-163
lines changed

CMakeLists.txt

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -170,10 +170,6 @@ if (USE_CUDA)
170170
find_package(CUDAToolkit REQUIRED)
171171
endif (USE_CUDA)
172172

173-
if (PLUGIN_UPDATER_ONEAPI)
174-
target_compile_definitions(xgboost PRIVATE -DXGBOOST_USE_ONEAPI=1)
175-
endif (PLUGIN_UPDATER_ONEAPI)
176-
177173
if (FORCE_COLORED_OUTPUT AND (CMAKE_GENERATOR STREQUAL "Ninja") AND
178174
((CMAKE_CXX_COMPILER_ID STREQUAL "GNU") OR
179175
(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")))
@@ -268,6 +264,15 @@ if (PLUGIN_RMM)
268264
get_target_property(rmm_link_libs rmm::rmm INTERFACE_LINK_LIBRARIES)
269265
endif (PLUGIN_RMM)
270266

267+
if (PLUGIN_UPDATER_ONEAPI)
268+
set(CMAKE_CXX_LINK_EXECUTABLE
269+
"icpx <FLAGS> <CMAKE_CXX_LINK_FLAGS> -qopenmp <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>")
270+
set(CMAKE_CXX_CREATE_SHARED_LIBRARY
271+
"icpx <CMAKE_SHARED_LIBRARY_CXX_FLAGS> -qopenmp <LANGUAGE_COMPILE_FLAGS> \
272+
<CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS> <SONAME_FLAG>,<TARGET_SONAME> \
273+
-o <TARGET> <OBJECTS> <LINK_LIBRARIES>")
274+
endif (PLUGIN_UPDATER_ONEAPI)
275+
271276
#-- library
272277
if (BUILD_STATIC_LIB)
273278
add_library(xgboost STATIC)

plugin/CMakeLists.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ if (PLUGIN_DENSE_PARSER)
33
endif (PLUGIN_DENSE_PARSER)
44

55
if (PLUGIN_UPDATER_ONEAPI)
6+
set(CMAKE_CXX_COMPILER "icpx")
67
add_library(oneapi_plugin OBJECT
78
${xgboost_SOURCE_DIR}/plugin/updater_oneapi/hist_util_oneapi.cc
89
${xgboost_SOURCE_DIR}/plugin/updater_oneapi/regression_obj_oneapi.cc
@@ -24,7 +25,8 @@ if (PLUGIN_UPDATER_ONEAPI)
2425
POSITION_INDEPENDENT_CODE ON)
2526
if (USE_OPENMP)
2627
find_package(OpenMP REQUIRED)
27-
target_link_libraries(oneapi_plugin PUBLIC OpenMP::OpenMP_CXX)
28+
set_target_properties(oneapi_plugin PROPERTIES
29+
COMPILE_FLAGS "-fsycl -qopenmp")
2830
endif (USE_OPENMP)
2931
# Get compilation and link flags of oneapi_plugin and propagate to objxgboost
3032
target_link_libraries(objxgboost PUBLIC oneapi_plugin)

plugin/updater_oneapi/device_manager_oneapi.cc

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@
99
namespace xgboost {
1010

1111
sycl::device DeviceManagerOneAPI::GetDevice(const DeviceOrd& device_spec) const {
12+
if (!device_spec.IsSycl()) {
13+
LOG(WARNING) << "Sycl kernel is executed with non-sycl context. "
14+
<< "Default sycl device_selector will be used.";
15+
}
16+
1217
bool not_use_default_selector = (device_spec.ordinal != kDefaultOrdinal) ||
1318
(rabit::IsDistributed());
1419
if (not_use_default_selector) {
@@ -28,22 +33,27 @@ sycl::device DeviceManagerOneAPI::GetDevice(const DeviceOrd& device_spec) const
2833
return gpu_devices[device_idx];
2934
}
3035
} else {
31-
if (device_spec.IsSyclDefault()) {
32-
return sycl::device(sycl::default_selector_v);
33-
} else if(device_spec.IsSyclCPU()) {
34-
return sycl::device(sycl::cpu_selector_v);
35-
} else {
36-
return sycl::device(sycl::gpu_selector_v);
37-
}
36+
if(device_spec.IsSyclCPU()) {
37+
return sycl::device(sycl::cpu_selector_v);
38+
} else if(device_spec.IsSyclGPU()) {
39+
return sycl::device(sycl::gpu_selector_v);
40+
} else {
41+
return sycl::device(sycl::default_selector_v);
42+
}
3843
}
3944
}
4045

4146
sycl::queue DeviceManagerOneAPI::GetQueue(const DeviceOrd& device_spec) const {
47+
if (!device_spec.IsSycl()) {
48+
LOG(WARNING) << "Sycl kernel is executed with non-sycl context. "
49+
<< "Default sycl device_selector will be used.";
50+
}
51+
4252
QueueRegister_t& queue_register = GetQueueRegister();
4353
if (queue_register.count(device_spec.Name()) > 0) {
4454
return queue_register.at(device_spec.Name());
4555
}
46-
56+
4757
bool not_use_default_selector = (device_spec.ordinal != kDefaultOrdinal) ||
4858
(rabit::IsDistributed());
4959
std::lock_guard<std::mutex> guard(queue_registering_mutex);
@@ -64,12 +74,12 @@ sycl::queue DeviceManagerOneAPI::GetQueue(const DeviceOrd& device_spec) const {
6474
queue_register[device_spec.Name()] = sycl::queue(gpu_devices[device_idx]);
6575
}
6676
} else {
67-
if (device_spec.IsSyclDefault()) {
68-
queue_register[device_spec.Name()] = sycl::queue(sycl::default_selector_v);
69-
} else if (device_spec.IsSyclCPU()) {
77+
if (device_spec.IsSyclCPU()) {
7078
queue_register[device_spec.Name()] = sycl::queue(sycl::cpu_selector_v);
7179
} else if (device_spec.IsSyclGPU()) {
7280
queue_register[device_spec.Name()] = sycl::queue(sycl::gpu_selector_v);
81+
} else {
82+
queue_register[device_spec.Name()] = sycl::queue(sycl::default_selector_v);
7383
}
7484
}
7585
return queue_register.at(device_spec.Name());

plugin/updater_oneapi/predictor_oneapi.cc

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,7 @@ namespace predictor {
2828
DMLC_REGISTRY_FILE_TAG(predictor_oneapi);
2929

3030
class PredictorOneAPI : public Predictor {
31-
public:
32-
explicit PredictorOneAPI(Context const* context) :
33-
Predictor::Predictor{context} {}
34-
35-
void Configure(const std::vector<std::pair<std::string, std::string>>& args) override {
31+
void SetupBackend() {
3632
const DeviceOrd device_spec = ctx_->Device();
3733

3834
bool is_cpu;
@@ -42,14 +38,22 @@ class PredictorOneAPI : public Predictor {
4238
} else {
4339
is_cpu = true;
4440
}
45-
4641
LOG(INFO) << "device = " << device_spec.Name() << ", is_cpu = " << int(is_cpu);
47-
4842
if (is_cpu) {
4943
predictor_backend_.reset(Predictor::Create("cpu_predictor", ctx_));
5044
} else{
5145
predictor_backend_.reset(Predictor::Create("oneapi_predictor_backend", ctx_));
5246
}
47+
}
48+
49+
public:
50+
explicit PredictorOneAPI(Context const* context) :
51+
Predictor::Predictor{context} {
52+
SetupBackend();
53+
}
54+
55+
void Configure(const std::vector<std::pair<std::string, std::string>>& args) override {
56+
SetupBackend();
5357
predictor_backend_->Configure(args);
5458
}
5559

src/context.cc

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,12 +120,23 @@ DeviceOrd CUDAOrdinal(DeviceOrd device, bool) {
120120
#endif // defined(__MINGW32__)
121121

122122
// handle alias
123+
#if defined(__MINGW32__)
124+
// mingw hangs on regex using rtools 430. Basic checks only.
125+
bool is_sycl = (substr == "syc");
126+
#else
127+
bool is_sycl = std::regex_match(input, std::regex("sycl(:cpu|:gpu)?(:-1|:[0-9]+)?"));
128+
#endif // defined(__MINGW32__)
129+
123130
std::string s_device = input;
124-
if (!std::regex_match(s_device, std::regex("sycl(:cpu|:gpu)?(:-1|:[0-9]+)?")))
131+
if (!is_sycl) {
125132
s_device = std::regex_replace(s_device, std::regex{"gpu"}, DeviceSym::CUDA());
126133

127134
auto split_it = std::find(s_device.cbegin(), s_device.cend(), ':');
128-
if (std::regex_match(s_device, std::regex("sycl:(cpu|gpu)?"))) split_it = s_device.cend();
135+
// For these cases we need to move iterator to the end, not to look for a ordinal.
136+
if ((s_device == "sycl:cpu") ||
137+
(s_device == "sycl:gpu")) {
138+
split_it = s_device.cend();
139+
}
129140

130141
// For s_device like "sycl:gpu:1"
131142
if (split_it != s_device.cend()) {

tests/cpp/plugin/test_predictor_oneapi.cc

Lines changed: 45 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -5,56 +5,57 @@
55
#include <xgboost/predictor.h>
66

77
#include "../../../src/data/adapter.h"
8+
#include "../../../src/data/proxy_dmatrix.h"
89
#include "../../../src/gbm/gbtree_model.h"
910
#include "../filesystem.h" // dmlc::TemporaryDirectory
1011
#include "../helpers.h"
1112
#include "../predictor/test_predictor.h"
1213

1314
namespace xgboost {
14-
TEST(Plugin, OneAPIPredictorBasic) {
15-
auto lparam = MakeCUDACtx(0);
15+
namespace {
16+
void TestBasic(DMatrix* dmat) {
17+
Context ctx;
18+
ctx.UpdateAllowUnknown(Args{{"device", "sycl"}});
1619
std::unique_ptr<Predictor> oneapi_predictor =
17-
std::unique_ptr<Predictor>(Predictor::Create("oneapi_predictor", &lparam));
20+
std::unique_ptr<Predictor>(Predictor::Create("oneapi_predictor", &ctx));
1821

19-
int kRows = 5;
20-
int kCols = 5;
22+
size_t const kRows = dmat->Info().num_row_;
23+
size_t const kCols = dmat->Info().num_col_;
2124

22-
LearnerModelParam param;
23-
param.num_feature = kCols;
24-
param.base_score = 0.0;
25-
param.num_output_group = 1;
26-
27-
gbm::GBTreeModel model = CreateTestModel(&param);
28-
29-
auto dmat = RandomDataGenerator(kRows, kCols, 0).GenerateDMatrix();
25+
LearnerModelParam param(MakeMP(kCols, .0, 1));
26+
gbm::GBTreeModel model = CreateTestModel(&param, &ctx);
3027

3128
// Test predict batch
3229
PredictionCacheEntry out_predictions;
33-
oneapi_predictor->PredictBatch(dmat.get(), &out_predictions, model, 0);
34-
ASSERT_EQ(model.trees.size(), out_predictions.version);
30+
oneapi_predictor->InitOutPredictions(dmat->Info(), &out_predictions.predictions, model);
31+
oneapi_predictor->PredictBatch(dmat, &out_predictions, model, 0);
32+
3533
std::vector<float>& out_predictions_h = out_predictions.predictions.HostVector();
3634
for (size_t i = 0; i < out_predictions.predictions.Size(); i++) {
3735
ASSERT_EQ(out_predictions_h[i], 1.5);
3836
}
3937

4038
// Test predict instance
4139
auto const &batch = *dmat->GetBatches<xgboost::SparsePage>().begin();
40+
auto page = batch.GetView();
4241
for (size_t i = 0; i < batch.Size(); i++) {
4342
std::vector<float> instance_out_predictions;
44-
oneapi_predictor->PredictInstance(batch[i], &instance_out_predictions, model);
43+
oneapi_predictor->PredictInstance(page[i], &instance_out_predictions, model);
4544
ASSERT_EQ(instance_out_predictions[0], 1.5);
4645
}
4746

4847
// Test predict leaf
49-
std::vector<float> leaf_out_predictions;
50-
oneapi_predictor->PredictLeaf(dmat.get(), &leaf_out_predictions, model);
51-
for (auto v : leaf_out_predictions) {
48+
HostDeviceVector<float> leaf_out_predictions;
49+
oneapi_predictor->PredictLeaf(dmat, &leaf_out_predictions, model);
50+
auto const& h_leaf_out_predictions = leaf_out_predictions.ConstHostVector();
51+
for (auto v : h_leaf_out_predictions) {
5252
ASSERT_EQ(v, 0);
5353
}
5454

5555
// Test predict contribution
56-
std::vector<float> out_contribution;
57-
oneapi_predictor->PredictContribution(dmat.get(), &out_contribution, model);
56+
HostDeviceVector<float> out_contribution_hdv;
57+
auto& out_contribution = out_contribution_hdv.HostVector();
58+
oneapi_predictor->PredictContribution(dmat, &out_contribution_hdv, model);
5859
ASSERT_EQ(out_contribution.size(), kRows * (kCols + 1));
5960
for (size_t i = 0; i < out_contribution.size(); ++i) {
6061
auto const& contri = out_contribution[i];
@@ -65,8 +66,9 @@ TEST(Plugin, OneAPIPredictorBasic) {
6566
ASSERT_EQ(contri, 0);
6667
}
6768
}
69+
6870
// Test predict contribution (approximate method)
69-
oneapi_predictor->PredictContribution(dmat.get(), &out_contribution, model, 0, nullptr, true);
71+
oneapi_predictor->PredictContribution(dmat, &out_contribution_hdv, model, 0, nullptr, true);
7072
for (size_t i = 0; i < out_contribution.size(); ++i) {
7173
auto const& contri = out_contribution[i];
7274
// shift 1 for bias, as test tree is a decision dump, only global bias is filled with LeafValue().
@@ -77,92 +79,38 @@ TEST(Plugin, OneAPIPredictorBasic) {
7779
}
7880
}
7981
}
82+
} // anonymous namespace
8083

81-
TEST(Plugin, OneAPIPredictorExternalMemory) {
82-
dmlc::TemporaryDirectory tmpdir;
83-
std::string filename = tmpdir.path + "/big.libsvm";
84-
std::unique_ptr<DMatrix> dmat = CreateSparsePageDMatrix(12, 64, filename);
85-
auto lparam = MakeCUDACtx(0);
86-
87-
std::unique_ptr<Predictor> oneapi_predictor =
88-
std::unique_ptr<Predictor>(Predictor::Create("oneapi_predictor", &lparam));
89-
90-
LearnerModelParam param;
91-
param.base_score = 0;
92-
param.num_feature = dmat->Info().num_col_;
93-
param.num_output_group = 1;
94-
95-
gbm::GBTreeModel model = CreateTestModel(&param);
96-
97-
// Test predict batch
98-
PredictionCacheEntry out_predictions;
99-
oneapi_predictor->PredictBatch(dmat.get(), &out_predictions, model, 0);
100-
std::vector<float> &out_predictions_h = out_predictions.predictions.HostVector();
101-
ASSERT_EQ(out_predictions.predictions.Size(), dmat->Info().num_row_);
102-
for (const auto& v : out_predictions_h) {
103-
ASSERT_EQ(v, 1.5);
104-
}
105-
106-
// Test predict leaf
107-
std::vector<float> leaf_out_predictions;
108-
oneapi_predictor->PredictLeaf(dmat.get(), &leaf_out_predictions, model);
109-
ASSERT_EQ(leaf_out_predictions.size(), dmat->Info().num_row_);
110-
for (const auto& v : leaf_out_predictions) {
111-
ASSERT_EQ(v, 0);
112-
}
113-
114-
// Test predict contribution
115-
std::vector<float> out_contribution;
116-
oneapi_predictor->PredictContribution(dmat.get(), &out_contribution, model);
117-
ASSERT_EQ(out_contribution.size(), dmat->Info().num_row_ * (dmat->Info().num_col_ + 1));
118-
for (size_t i = 0; i < out_contribution.size(); ++i) {
119-
auto const& contri = out_contribution[i];
120-
// shift 1 for bias, as test tree is a decision dump, only global bias is filled with LeafValue().
121-
if ((i + 1) % (dmat->Info().num_col_ + 1) == 0) {
122-
ASSERT_EQ(out_contribution.back(), 1.5f);
123-
} else {
124-
ASSERT_EQ(contri, 0);
125-
}
126-
}
84+
TEST(SyclPredictor, Basic) {
85+
size_t constexpr kRows = 5;
86+
size_t constexpr kCols = 5;
87+
auto dmat = RandomDataGenerator(kRows, kCols, 0).GenerateDMatrix();
88+
TestBasic(dmat.get());
89+
}
12790

128-
// Test predict contribution (approximate method)
129-
std::vector<float> out_contribution_approximate;
130-
oneapi_predictor->PredictContribution(dmat.get(), &out_contribution_approximate, model, 0, nullptr, true);
131-
ASSERT_EQ(out_contribution_approximate.size(),
132-
dmat->Info().num_row_ * (dmat->Info().num_col_ + 1));
133-
for (size_t i = 0; i < out_contribution.size(); ++i) {
134-
auto const& contri = out_contribution[i];
135-
// shift 1 for bias, as test tree is a decision dump, only global bias is filled with LeafValue().
136-
if ((i + 1) % (dmat->Info().num_col_ + 1) == 0) {
137-
ASSERT_EQ(out_contribution.back(), 1.5f);
138-
} else {
139-
ASSERT_EQ(contri, 0);
140-
}
141-
}
91+
TEST(SyclPredictor, ExternalMemory) {
92+
size_t constexpr kPageSize = 64, kEntriesPerCol = 3;
93+
size_t constexpr kEntries = kPageSize * kEntriesPerCol * 2;
94+
std::unique_ptr<DMatrix> dmat = CreateSparsePageDMatrix(kEntries);
95+
TestBasic(dmat.get());
14296
}
14397

144-
TEST(Plugin, OneAPIPredictorInplacePredict) {
98+
TEST(SyclPredictor, InplacePredict) {
14599
bst_row_t constexpr kRows{128};
146100
bst_feature_t constexpr kCols{64};
147101
auto gen = RandomDataGenerator{kRows, kCols, 0.5}.Device(-1);
148102
{
149103
HostDeviceVector<float> data;
150104
gen.GenerateDense(&data);
151105
ASSERT_EQ(data.Size(), kRows * kCols);
152-
std::shared_ptr<data::DenseAdapter> x{
153-
new data::DenseAdapter(data.HostPointer(), kRows, kCols)};
154-
TestInplacePrediction(x, "oneapi_predictor", kRows, kCols, -1);
155-
}
156-
157-
{
158-
HostDeviceVector<float> data;
159-
HostDeviceVector<bst_row_t> rptrs;
160-
HostDeviceVector<bst_feature_t> columns;
161-
gen.GenerateCSR(&data, &rptrs, &columns);
162-
std::shared_ptr<data::CSRAdapter> x{new data::CSRAdapter(
163-
rptrs.HostPointer(), columns.HostPointer(), data.HostPointer(), kRows,
164-
data.Size(), kCols)};
165-
TestInplacePrediction(x, "oneapi_predictor", kRows, kCols, -1);
106+
Context ctx;
107+
ctx.UpdateAllowUnknown(Args{{"device", "sycl"}});
108+
std::shared_ptr<data::DMatrixProxy> x{new data::DMatrixProxy{}};
109+
auto array_interface = GetArrayInterface(&data, kRows, kCols);
110+
std::string arr_str;
111+
Json::Dump(array_interface, &arr_str);
112+
x->SetArrayData(arr_str.data());
113+
TestInplacePrediction(&ctx, x, kRows, kCols);
166114
}
167115
}
168116
} // namespace xgboost

0 commit comments

Comments
 (0)