From ea993cf59373b89a42a87c2a799abd81f70a655e Mon Sep 17 00:00:00 2001 From: david-cortes Date: Wed, 22 Nov 2023 20:11:58 +0100 Subject: [PATCH 1/4] switch non-beneficial parallels to simds --- R-package/src/lightgbm_R.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/R-package/src/lightgbm_R.cpp b/R-package/src/lightgbm_R.cpp index 21ba801a3a60..2067c6fa09c1 100644 --- a/R-package/src/lightgbm_R.cpp +++ b/R-package/src/lightgbm_R.cpp @@ -226,7 +226,7 @@ SEXP LGBM_DatasetGetSubset_R(SEXP handle, int32_t len = static_cast(Rf_asInteger(len_used_row_indices)); std::vector idxvec(len); // convert from one-based to zero-based index -#pragma omp parallel for num_threads(OMP_NUM_THREADS()) schedule(static, 512) if (len >= 1024) +#pragma omp simd for (int32_t i = 0; i < len; ++i) { idxvec[i] = static_cast(INTEGER(used_row_indices)[i] - 1); } @@ -339,7 +339,7 @@ SEXP LGBM_DatasetSetField_R(SEXP handle, const char* name = CHAR(PROTECT(Rf_asChar(field_name))); if (!strcmp("group", name) || !strcmp("query", name)) { std::vector vec(len); -#pragma omp parallel for num_threads(OMP_NUM_THREADS()) schedule(static, 512) if (len >= 1024) +#pragma omp simd for (int i = 0; i < len; ++i) { vec[i] = static_cast(INTEGER(field_data)[i]); } @@ -348,7 +348,7 @@ SEXP LGBM_DatasetSetField_R(SEXP handle, CHECK_CALL(LGBM_DatasetSetField(R_ExternalPtrAddr(handle), name, REAL(field_data), len, C_API_DTYPE_FLOAT64)); } else { std::vector vec(len); -#pragma omp parallel for num_threads(OMP_NUM_THREADS()) schedule(static, 512) if (len >= 1024) +#pragma omp simd for (int i = 0; i < len; ++i) { vec[i] = static_cast(REAL(field_data)[i]); } @@ -372,19 +372,19 @@ SEXP LGBM_DatasetGetField_R(SEXP handle, if (!strcmp("group", name) || !strcmp("query", name)) { auto p_data = reinterpret_cast(res); // convert from boundaries to size -#pragma omp parallel for num_threads(OMP_NUM_THREADS()) schedule(static, 512) if (out_len >= 1024) +#pragma omp simd for (int i = 0; i < out_len - 1; ++i) { INTEGER(field_data)[i] = p_data[i + 1] - p_data[i]; } } else if (!strcmp("init_score", name)) { auto p_data = reinterpret_cast(res); -#pragma omp parallel for num_threads(OMP_NUM_THREADS()) schedule(static, 512) if (out_len >= 1024) +#pragma omp simd for (int i = 0; i < out_len; ++i) { REAL(field_data)[i] = p_data[i]; } } else { auto p_data = reinterpret_cast(res); -#pragma omp parallel for num_threads(OMP_NUM_THREADS()) schedule(static, 512) if (out_len >= 1024) +#pragma omp simd for (int i = 0; i < out_len; ++i) { REAL(field_data)[i] = p_data[i]; } @@ -611,7 +611,7 @@ SEXP LGBM_BoosterUpdateOneIterCustom_R(SEXP handle, int is_finished = 0; int int_len = Rf_asInteger(len); std::vector tgrad(int_len), thess(int_len); -#pragma omp parallel for num_threads(OMP_NUM_THREADS()) schedule(static, 512) if (int_len >= 1024) +#pragma omp simd for (int j = 0; j < int_len; ++j) { tgrad[j] = static_cast(REAL(grad)[j]); thess[j] = static_cast(REAL(hess)[j]); From 0b227e46e15995144c4b4111aeb60cb941506106 Mon Sep 17 00:00:00 2001 From: david-cortes Date: Thu, 28 Dec 2023 15:16:09 +0100 Subject: [PATCH 2/4] remove unused simds, disable 'omp simd' for msvc --- R-package/src/lightgbm_R.cpp | 37 ++++++++++++++---------------------- 1 file changed, 14 insertions(+), 23 deletions(-) diff --git a/R-package/src/lightgbm_R.cpp b/R-package/src/lightgbm_R.cpp index 2067c6fa09c1..dfb2295e579a 100644 --- a/R-package/src/lightgbm_R.cpp +++ b/R-package/src/lightgbm_R.cpp @@ -226,9 +226,12 @@ SEXP LGBM_DatasetGetSubset_R(SEXP handle, int32_t len = static_cast(Rf_asInteger(len_used_row_indices)); std::vector idxvec(len); // convert from one-based to zero-based index + int *used_row_indices_ = INTEGER(used_row_indices); +#ifndef _MSC_VER #pragma omp simd +#endif for (int32_t i = 0; i < len; ++i) { - idxvec[i] = static_cast(INTEGER(used_row_indices)[i] - 1); + idxvec[i] = static_cast(used_row_indices_[i] - 1); } const char* parameters_ptr = CHAR(PROTECT(Rf_asChar(parameters))); DatasetHandle res = nullptr; @@ -339,19 +342,13 @@ SEXP LGBM_DatasetSetField_R(SEXP handle, const char* name = CHAR(PROTECT(Rf_asChar(field_name))); if (!strcmp("group", name) || !strcmp("query", name)) { std::vector vec(len); -#pragma omp simd - for (int i = 0; i < len; ++i) { - vec[i] = static_cast(INTEGER(field_data)[i]); - } + std::copy(INTEGER(field_data), INTEGER(field_data) + len, vec.begin()); CHECK_CALL(LGBM_DatasetSetField(R_ExternalPtrAddr(handle), name, vec.data(), len, C_API_DTYPE_INT32)); } else if (!strcmp("init_score", name)) { CHECK_CALL(LGBM_DatasetSetField(R_ExternalPtrAddr(handle), name, REAL(field_data), len, C_API_DTYPE_FLOAT64)); } else { std::vector vec(len); -#pragma omp simd - for (int i = 0; i < len; ++i) { - vec[i] = static_cast(REAL(field_data)[i]); - } + std::copy(REAL(field_data), REAL(field_data) _ len, vec.begin()); CHECK_CALL(LGBM_DatasetSetField(R_ExternalPtrAddr(handle), name, vec.data(), len, C_API_DTYPE_FLOAT32)); } UNPROTECT(1); @@ -372,22 +369,19 @@ SEXP LGBM_DatasetGetField_R(SEXP handle, if (!strcmp("group", name) || !strcmp("query", name)) { auto p_data = reinterpret_cast(res); // convert from boundaries to size + int *field_data_ = INTEGER(field_data); +#ifndef _MSC_VER #pragma omp simd +#endif for (int i = 0; i < out_len - 1; ++i) { - INTEGER(field_data)[i] = p_data[i + 1] - p_data[i]; + field_data_[i] = p_data[i + 1] - p_data[i]; } } else if (!strcmp("init_score", name)) { auto p_data = reinterpret_cast(res); -#pragma omp simd - for (int i = 0; i < out_len; ++i) { - REAL(field_data)[i] = p_data[i]; - } + std:::copy(p_data, p_data + out_len, REAL(field_data)); } else { auto p_data = reinterpret_cast(res); -#pragma omp simd - for (int i = 0; i < out_len; ++i) { - REAL(field_data)[i] = p_data[i]; - } + std::copy(p_data, p_data + out_len, REAL(field_data)); } UNPROTECT(1); return R_NilValue; @@ -611,11 +605,8 @@ SEXP LGBM_BoosterUpdateOneIterCustom_R(SEXP handle, int is_finished = 0; int int_len = Rf_asInteger(len); std::vector tgrad(int_len), thess(int_len); -#pragma omp simd - for (int j = 0; j < int_len; ++j) { - tgrad[j] = static_cast(REAL(grad)[j]); - thess[j] = static_cast(REAL(hess)[j]); - } + std::copy(REAL(grad), REAL(grad) + int_len, tgrad.begin()); + std::copy(REAL(hess), REAL(hess) + int_len, thess.begin()); CHECK_CALL(LGBM_BoosterUpdateOneIterCustom(R_ExternalPtrAddr(handle), tgrad.data(), thess.data(), &is_finished)); return R_NilValue; R_API_END(); From b5e7c09c36e70f9b0bf35b2f589dc1193e376c05 Mon Sep 17 00:00:00 2001 From: david-cortes Date: Thu, 28 Dec 2023 15:25:21 +0100 Subject: [PATCH 3/4] typos --- R-package/src/lightgbm_R.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/R-package/src/lightgbm_R.cpp b/R-package/src/lightgbm_R.cpp index 9a73de8eb24c..e5c5d3c90e15 100644 --- a/R-package/src/lightgbm_R.cpp +++ b/R-package/src/lightgbm_R.cpp @@ -348,7 +348,7 @@ SEXP LGBM_DatasetSetField_R(SEXP handle, CHECK_CALL(LGBM_DatasetSetField(R_ExternalPtrAddr(handle), name, REAL(field_data), len, C_API_DTYPE_FLOAT64)); } else { std::vector vec(len); - std::copy(REAL(field_data), REAL(field_data) _ len, vec.begin()); + std::copy(REAL(field_data), REAL(field_data) + len, vec.begin()); CHECK_CALL(LGBM_DatasetSetField(R_ExternalPtrAddr(handle), name, vec.data(), len, C_API_DTYPE_FLOAT32)); } UNPROTECT(1); @@ -378,7 +378,7 @@ SEXP LGBM_DatasetGetField_R(SEXP handle, } } else if (!strcmp("init_score", name)) { auto p_data = reinterpret_cast(res); - std:::copy(p_data, p_data + out_len, REAL(field_data)); + std::copy(p_data, p_data + out_len, REAL(field_data)); } else { auto p_data = reinterpret_cast(res); std::copy(p_data, p_data + out_len, REAL(field_data)); From 7fcbd9cd5daab70fb91b657edaa779e2cb1d6fc1 Mon Sep 17 00:00:00 2001 From: david-cortes Date: Thu, 28 Dec 2023 15:38:53 +0100 Subject: [PATCH 4/4] prefer unique_ptr over vec --- R-package/src/lightgbm_R.cpp | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/R-package/src/lightgbm_R.cpp b/R-package/src/lightgbm_R.cpp index e5c5d3c90e15..a76a56c06b24 100644 --- a/R-package/src/lightgbm_R.cpp +++ b/R-package/src/lightgbm_R.cpp @@ -224,7 +224,7 @@ SEXP LGBM_DatasetGetSubset_R(SEXP handle, _AssertDatasetHandleNotNull(handle); SEXP ret = PROTECT(R_MakeExternalPtr(nullptr, R_NilValue, R_NilValue)); int32_t len = static_cast(Rf_asInteger(len_used_row_indices)); - std::vector idxvec(len); + std::unique_ptr idxvec(new int32_t[len]); // convert from one-based to zero-based index const int *used_row_indices_ = INTEGER(used_row_indices); #ifndef _MSC_VER @@ -236,7 +236,7 @@ SEXP LGBM_DatasetGetSubset_R(SEXP handle, const char* parameters_ptr = CHAR(PROTECT(Rf_asChar(parameters))); DatasetHandle res = nullptr; CHECK_CALL(LGBM_DatasetGetSubset(R_ExternalPtrAddr(handle), - idxvec.data(), len, parameters_ptr, + idxvec.get(), len, parameters_ptr, &res)); R_SetExternalPtrAddr(ret, res); R_RegisterCFinalizerEx(ret, _DatasetFinalizer, TRUE); @@ -250,13 +250,13 @@ SEXP LGBM_DatasetSetFeatureNames_R(SEXP handle, R_API_BEGIN(); _AssertDatasetHandleNotNull(handle); auto vec_names = Split(CHAR(PROTECT(Rf_asChar(feature_names))), '\t'); - std::vector vec_sptr; int len = static_cast(vec_names.size()); + std::unique_ptr vec_sptr(new const char*[len]); for (int i = 0; i < len; ++i) { - vec_sptr.push_back(vec_names[i].c_str()); + vec_sptr[i] = vec_names[i].c_str(); } CHECK_CALL(LGBM_DatasetSetFeatureNames(R_ExternalPtrAddr(handle), - vec_sptr.data(), len)); + vec_sptr.get(), len)); UNPROTECT(1); return R_NilValue; R_API_END(); @@ -341,15 +341,13 @@ SEXP LGBM_DatasetSetField_R(SEXP handle, int len = Rf_asInteger(num_element); const char* name = CHAR(PROTECT(Rf_asChar(field_name))); if (!strcmp("group", name) || !strcmp("query", name)) { - std::vector vec(len); - std::copy(INTEGER(field_data), INTEGER(field_data) + len, vec.begin()); - CHECK_CALL(LGBM_DatasetSetField(R_ExternalPtrAddr(handle), name, vec.data(), len, C_API_DTYPE_INT32)); + CHECK_CALL(LGBM_DatasetSetField(R_ExternalPtrAddr(handle), name, INTEGER(field_data), len, C_API_DTYPE_INT32)); } else if (!strcmp("init_score", name)) { CHECK_CALL(LGBM_DatasetSetField(R_ExternalPtrAddr(handle), name, REAL(field_data), len, C_API_DTYPE_FLOAT64)); } else { - std::vector vec(len); - std::copy(REAL(field_data), REAL(field_data) + len, vec.begin()); - CHECK_CALL(LGBM_DatasetSetField(R_ExternalPtrAddr(handle), name, vec.data(), len, C_API_DTYPE_FLOAT32)); + std::unique_ptr vec(new float[len]); + std::copy(REAL(field_data), REAL(field_data) + len, vec.get()); + CHECK_CALL(LGBM_DatasetSetField(R_ExternalPtrAddr(handle), name, vec.get(), len, C_API_DTYPE_FLOAT32)); } UNPROTECT(1); return R_NilValue; @@ -604,10 +602,10 @@ SEXP LGBM_BoosterUpdateOneIterCustom_R(SEXP handle, _AssertBoosterHandleNotNull(handle); int is_finished = 0; int int_len = Rf_asInteger(len); - std::vector tgrad(int_len), thess(int_len); - std::copy(REAL(grad), REAL(grad) + int_len, tgrad.begin()); - std::copy(REAL(hess), REAL(hess) + int_len, thess.begin()); - CHECK_CALL(LGBM_BoosterUpdateOneIterCustom(R_ExternalPtrAddr(handle), tgrad.data(), thess.data(), &is_finished)); + std::unique_ptr tgrad(new float[int_len]), thess(new float[int_len]); + std::copy(REAL(grad), REAL(grad) + int_len, tgrad.get()); + std::copy(REAL(hess), REAL(hess) + int_len, thess.get()); + CHECK_CALL(LGBM_BoosterUpdateOneIterCustom(R_ExternalPtrAddr(handle), tgrad.get(), thess.get(), &is_finished)); return R_NilValue; R_API_END(); }