Skip to content

Commit 90b1418

Browse files
committed
more "homogeneous" speed for different CXX standards.
1 parent 5173f39 commit 90b1418

File tree

5 files changed

+61
-12
lines changed

5 files changed

+61
-12
lines changed

inst/include/cpp4r/R.hpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
// clang-format on
3434

3535
#include <type_traits>
36+
#include "cpp4r/cpp_version.hpp" // for CPP4R optimization macros
3637

3738
#if defined(R_VERSION) && R_VERSION >= R_Version(4, 4, 0)
3839
// Use R's new macro
@@ -119,14 +120,14 @@ template <typename T>
119120
inline T na();
120121

121122
template <typename T>
122-
inline typename std::enable_if<!std::is_same<typename std::decay<T>::type, double>::value,
123+
CPP4R_HOT inline typename std::enable_if<!std::is_same<typename std::decay<T>::type, double>::value,
123124
bool>::type
124125
is_na(const T& value) {
125126
return value == na<T>();
126127
}
127128

128129
template <typename T>
129-
inline typename std::enable_if<std::is_same<typename std::decay<T>::type, double>::value,
130+
CPP4R_HOT inline typename std::enable_if<std::is_same<typename std::decay<T>::type, double>::value,
130131
bool>::type
131132
is_na(const T& value) {
132133
return ISNA(value);

inst/include/cpp4r/cpp_version.hpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,4 +112,39 @@
112112
#else
113113
#define CPP4R_LIKELY(x) (x)
114114
#define CPP4R_UNLIKELY(x) (x)
115+
#endif
116+
117+
// CPP4R_RESTRICT: pointer aliasing hints for better optimization
118+
#if defined(__GNUC__) || defined(__clang__)
119+
#define CPP4R_RESTRICT __restrict__
120+
#elif defined(_MSC_VER)
121+
#define CPP4R_RESTRICT __restrict
122+
#else
123+
#define CPP4R_RESTRICT
124+
#endif
125+
126+
// CPP4R_ALWAYS_INLINE: force inlining of hot path functions
127+
// CPP4R_NOINLINE: prevent inlining of cold path functions
128+
#if CPP4R_HAS_CXX17 && (defined(__GNUC__) || defined(__clang__))
129+
#define CPP4R_ALWAYS_INLINE [[gnu::always_inline]] inline
130+
#define CPP4R_NOINLINE [[gnu::noinline]]
131+
#elif defined(__GNUC__) || defined(__clang__)
132+
#define CPP4R_ALWAYS_INLINE __attribute__((always_inline)) inline
133+
#define CPP4R_NOINLINE __attribute__((noinline))
134+
#elif defined(_MSC_VER)
135+
#define CPP4R_ALWAYS_INLINE __forceinline
136+
#define CPP4R_NOINLINE __declspec(noinline)
137+
#else
138+
#define CPP4R_ALWAYS_INLINE inline
139+
#define CPP4R_NOINLINE
140+
#endif
141+
142+
// CPP4R_HOT: mark frequently executed functions for better optimization
143+
// CPP4R_COLD: mark rarely executed functions (errors, initialization)
144+
#if defined(__GNUC__) || defined(__clang__)
145+
#define CPP4R_HOT __attribute__((hot))
146+
#define CPP4R_COLD __attribute__((cold))
147+
#else
148+
#define CPP4R_HOT
149+
#define CPP4R_COLD
115150
#endif

inst/include/cpp4r/matrix.hpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,9 @@ class matrix : public matrix_slices<S> {
101101
}
102102
bool operator!=(const slice& rhs) const noexcept { return !operator==(rhs); }
103103

104-
T operator[](int pos) const { return parent_.vector_[offset_ + stride() * pos]; }
104+
CPP4R_ALWAYS_INLINE T operator[](int pos) const {
105+
return parent_.vector_[offset_ + stride() * pos];
106+
}
105107

106108
// iterates elements of a slice
107109
class iterator {
@@ -239,7 +241,9 @@ class matrix : public matrix_slices<S> {
239241

240242
r_vector<r_string> names() const { return r_vector<r_string>(vector_.names()); }
241243

242-
T operator()(int row, int col) const { return vector_[row + (col * nrow())]; }
244+
CPP4R_ALWAYS_INLINE T operator()(int row, int col) const {
245+
return vector_[row + (col * nrow())];
246+
}
243247

244248
slice operator[](int index) const { return {*this, index}; }
245249

inst/include/cpp4r/r_vector_impl.hpp

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#pragma once
22

33
#include "cpp4r/r_vector_fwd.hpp"
4+
#include "cpp4r/cpp_version.hpp" // for CPP4R optimization macros
45

56
namespace cpp4r {
67

@@ -252,18 +253,18 @@ inline r_vector<r_string> r_vector<T>::names() const {
252253
}
253254

254255
template <typename T>
255-
inline T r_vector<T>::get_oob() {
256+
CPP4R_COLD inline T r_vector<T>::get_oob() {
256257
throw std::out_of_range("r_vector");
257258
}
258259

259260
template <typename T>
260261
inline SEXP r_vector<T>::valid_type(SEXP x) {
261262
const SEXPTYPE type = get_sexptype();
262263

263-
if (x == nullptr) {
264+
if (CPP4R_UNLIKELY(x == nullptr)) {
264265
throw type_error(type, NILSXP);
265266
}
266-
if (detail::r_typeof(x) != type) {
267+
if (CPP4R_UNLIKELY(detail::r_typeof(x) != type)) {
267268
throw type_error(type, detail::r_typeof(x));
268269
}
269270

@@ -316,9 +317,9 @@ r_vector<T>::const_iterator::const_iterator(const r_vector* data, R_xlen_t pos)
316317
}
317318

318319
template <typename T>
319-
inline typename r_vector<T>::const_iterator& r_vector<T>::const_iterator::operator++() {
320+
CPP4R_ALWAYS_INLINE typename r_vector<T>::const_iterator& r_vector<T>::const_iterator::operator++() {
320321
++pos_;
321-
if (use_buf(data_->is_altrep()) && pos_ >= block_start_ + length_) {
322+
if (CPP4R_UNLIKELY(use_buf(data_->is_altrep()) && pos_ >= block_start_ + length_)) {
322323
fill_buf(pos_);
323324
}
324325
return *this;
@@ -396,12 +397,12 @@ inline typename r_vector<T>::const_iterator r_vector<T>::find(
396397
}
397398

398399
template <typename T>
399-
inline T r_vector<T>::const_iterator::operator*() const {
400-
if (use_buf(data_->is_altrep())) {
400+
CPP4R_ALWAYS_INLINE T r_vector<T>::const_iterator::operator*() const {
401+
if (CPP4R_UNLIKELY(use_buf(data_->is_altrep()))) {
401402
// Use pre-loaded buffer for compatible ALTREP types
402403
return static_cast<T>(buf_[pos_ - block_start_]);
403404
} else {
404-
// Otherwise pass through to normal retrieval method
405+
// Otherwise pass through to normal retrieval method (common case)
405406
return data_->operator[](pos_);
406407
}
407408
}

scripts/combine-benchmarks.R

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,14 @@ res <- res %>%
171171
rel_cpp4r_Rcpp = signif(rel_time_cpp4r / rel_time_Rcpp, 3)
172172
)
173173

174+
# add rel time for cpp4r within the same test group
175+
res <- res %>%
176+
group_by(test) %>%
177+
mutate(
178+
rel_cpp4r_within_test = signif(rel_time_cpp4r / min(rel_time_cpp4r, na.rm = TRUE), 3)
179+
) %>%
180+
ungroup()
181+
174182
res <- res %>%
175183
mutate(
176184
avg_time_cpp11 = paste(avg_time_cpp11, paste0("(", rel_time_cpp11, ")")),

0 commit comments

Comments
 (0)