From 9b7fa48c9f74739bddfffa0fa30159755148df0d Mon Sep 17 00:00:00 2001 From: Hyunsu Cho Date: Thu, 8 Jul 2021 01:47:13 -0700 Subject: [PATCH] Remove dmlc::Timer and dmlc::optional --- include/treelite/optional.h | 62 +++++++++++++++++++++++++ src/CMakeLists.txt | 1 + src/compiler/ast/ast.h | 10 ++-- src/compiler/ast/fold_code.cc | 8 ++-- src/compiler/ast_native.cc | 4 +- src/predictor/predictor.cc | 11 +++-- src/predictor/thread_pool/thread_pool.h | 6 +++ 7 files changed, 88 insertions(+), 14 deletions(-) create mode 100644 include/treelite/optional.h diff --git a/include/treelite/optional.h b/include/treelite/optional.h new file mode 100644 index 00000000..9120b80c --- /dev/null +++ b/include/treelite/optional.h @@ -0,0 +1,62 @@ +/*! + * Copyright (c) 2021 by Contributors + * \file optional.h + * \brief Backport of std::optional from C++17 + * \author Hyunsu Cho + */ + +#ifndef TREELITE_OPTIONAL_H_ +#define TREELITE_OPTIONAL_H_ + +namespace treelite { + +template +class optional { // C++17: Switch to std::optional + public: + optional() : empty_{}, has_value_{false} {} + + explicit optional(const T& input_value) : value_{input_value}, has_value_{true} {} + optional(optional&& other) : has_value_{other} { + if (other) { + value_ = *other; + } + } + + ~optional() { + if (has_value_) { + value_.~T(); + } else { + empty_.~empty_byte(); + } + } + + explicit operator bool() const { + return has_value_; + } + T& operator*() { + return value_; + } + const T& operator*() const { + return value_; + } + T* operator->() { + return &value_; + } + optional& operator=(const T& new_value) { + value_ = new_value; + has_value_ = true; + return *this; + } + + private: + struct empty_byte {}; + union { + empty_byte empty_; + T value_; + }; + bool has_value_; +}; + +} // namespace treelite + +#endif // TREELITE_OPTIONAL_H_ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 27f40a52..bbedf7f6 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -113,6 +113,7 @@ target_sources(objtreelite ${PROJECT_SOURCE_DIR}/include/treelite/frontend_impl.h ${PROJECT_SOURCE_DIR}/include/treelite/gtil.h ${PROJECT_SOURCE_DIR}/include/treelite/omp.h + ${PROJECT_SOURCE_DIR}/include/treelite/optional.h ${PROJECT_SOURCE_DIR}/include/treelite/tree.h ${PROJECT_SOURCE_DIR}/include/treelite/tree_impl.h ) diff --git a/src/compiler/ast/ast.h b/src/compiler/ast/ast.h index c37cd513..fbff3758 100644 --- a/src/compiler/ast/ast.h +++ b/src/compiler/ast/ast.h @@ -7,7 +7,7 @@ #ifndef TREELITE_COMPILER_AST_AST_H_ #define TREELITE_COMPILER_AST_AST_H_ -#include +#include #include #include #include @@ -24,8 +24,8 @@ class ASTNode { std::vector children; int node_id; int tree_id; - dmlc::optional data_count; - dmlc::optional sum_hess; + optional data_count; + optional sum_hess; virtual std::string GetDump() const = 0; virtual ~ASTNode() = 0; // force ASTNode to be abstract class protected: @@ -106,12 +106,12 @@ class ConditionNode : public ASTNode { : split_index(split_index), default_left(default_left) {} unsigned split_index; bool default_left; - dmlc::optional gain; + optional gain; std::string GetDump() const override { if (gain) { return fmt::format("ConditionNode {{ split_index: {}, default_left: {}, gain: {} }}", - split_index, default_left, gain.value()); + split_index, default_left, *gain); } else { return fmt::format("ConditionNode {{ split_index: {}, default_left: {} }}", split_index, default_left); diff --git a/src/compiler/ast/fold_code.cc b/src/compiler/ast/fold_code.cc index b9e076f2..447446ef 100644 --- a/src/compiler/ast/fold_code.cc +++ b/src/compiler/ast/fold_code.cc @@ -27,22 +27,22 @@ bool fold_code(ASTNode* node, CodeFoldingContext* context, ASTBuilder* builder) { if (node->node_id == 0) { if (node->data_count) { - context->log_root_data_count = std::log(node->data_count.value()); + context->log_root_data_count = std::log(*node->data_count); } else { context->log_root_data_count = std::numeric_limits::quiet_NaN(); } if (node->sum_hess) { - context->log_root_sum_hess = std::log(node->sum_hess.value()); + context->log_root_sum_hess = std::log(*node->sum_hess); } else { context->log_root_sum_hess = std::numeric_limits::quiet_NaN(); } } if ( (node->data_count && !std::isnan(context->log_root_data_count) - && context->log_root_data_count - std::log(node->data_count.value()) + && context->log_root_data_count - std::log(*node->data_count) >= context->magnitude_req) || (node->sum_hess && !std::isnan(context->log_root_sum_hess) - && context->log_root_sum_hess - std::log(node->sum_hess.value()) + && context->log_root_sum_hess - std::log(*node->sum_hess) >= context->magnitude_req) ) { // fold the subtree whose root is [node] ASTNode* parent_node = node->parent; diff --git a/src/compiler/ast_native.cc b/src/compiler/ast_native.cc index 3323b207..2187b4f5 100644 --- a/src/compiler/ast_native.cc +++ b/src/compiler/ast_native.cc @@ -331,8 +331,8 @@ class ASTNativeCompiler : public Compiler { condition_with_na_check = ExtractCategoricalCondition(t2); } if (node->children[0]->data_count && node->children[1]->data_count) { - const size_t left_freq = node->children[0]->data_count.value(); - const size_t right_freq = node->children[1]->data_count.value(); + const size_t left_freq = *node->children[0]->data_count; + const size_t right_freq = *node->children[1]->data_count; condition_with_na_check = fmt::format(" {keyword}( {condition} ) ", "keyword"_a = ((left_freq > right_freq) ? "LIKELY" : "UNLIKELY"), diff --git a/src/predictor/predictor.cc b/src/predictor/predictor.cc index 9774af7e..099a4047 100644 --- a/src/predictor/predictor.cc +++ b/src/predictor/predictor.cc @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include @@ -19,6 +18,7 @@ #include #include #include +#include #include "thread_pool/thread_pool.h" #ifdef _WIN32 @@ -29,6 +29,11 @@ namespace { +inline double GetTime(void) { + return std::chrono::duration( + std::chrono::high_resolution_clock::now().time_since_epoch()).count(); +} + struct InputToken { const treelite::DMatrix* dmat; // input data bool pred_margin; // whether to store raw margin or transformed scores @@ -411,7 +416,7 @@ class DeallocateOutputVector { size_t Predictor::PredictBatch( const DMatrix* dmat, int verbose, bool pred_margin, PredictorOutputHandle out_result) const { - const double tstart = dmlc::GetTime(); + const double tstart = GetTime(); const size_t num_row = dmat->GetNumRow(); auto* pool = static_cast(thread_pool_handle_); @@ -449,7 +454,7 @@ Predictor::PredictBatch( DispatchWithTypeInfo( leaf_output_type_, num_row, query_size_per_instance, num_class_, out_result); } - const double tend = dmlc::GetTime(); + const double tend = GetTime(); if (verbose > 0) { LOG(INFO) << "Treelite: Finished prediction in " << tend - tstart << " sec"; } diff --git a/src/predictor/thread_pool/thread_pool.h b/src/predictor/thread_pool/thread_pool.h index affb08e6..f0d21b24 100644 --- a/src/predictor/thread_pool/thread_pool.h +++ b/src/predictor/thread_pool/thread_pool.h @@ -16,6 +16,12 @@ #else #include #endif + +#if defined(__APPLE__) && defined(__MACH__) +#include +#include +#include +#endif #include "spsc_queue.h" namespace treelite {