[Breaking] Add global versioning. (#4936)

* Use CMake config file for representing version.

* Generate c and Python version file with CMake.

The generated file is written into source tree.  But unless XGBoost upgrades
its version, there will be no actual modification.  This retains compatibility
with Makefiles for R.

* Add XGBoost version the DMatrix binaries.
* Simplify prefetch detection in CMakeLists.txt
This commit is contained in:
Jiaming Yuan
2019-10-22 23:27:26 -04:00
committed by GitHub
parent 7e477a2adb
commit 5620322a48
18 changed files with 301 additions and 56 deletions

View File

@@ -1,25 +1,6 @@
file(GLOB_RECURSE CPU_SOURCES *.cc *.h)
list(REMOVE_ITEM CPU_SOURCES ${PROJECT_SOURCE_DIR}/src/cli_main.cc)
include(CheckCXXSourceCompiles)
check_cxx_source_compiles("
#include <xmmintrin.h>
int main() {
char data = 0;
const char* address = &data;
_mm_prefetch(address, _MM_HINT_NTA);
return 0;
}
" XGBOOST_MM_PREFETCH_PRESENT)
check_cxx_source_compiles("
int main() {
char data = 0;
const char* address = &data;
__builtin_prefetch(address, 0, 0);
return 0;
}
" XGBOOST_BUILTIN_PREFETCH_PRESENT)
#-- Object library
# Object library is necessary for jvm-package, which creates its own shared
# library.
@@ -82,16 +63,6 @@ target_compile_definitions(objxgboost
-DDMLC_LOG_CUSTOMIZE=1 # enable custom logging
$<$<NOT:$<CXX_COMPILER_ID:MSVC>>:_MWAITXINTRIN_H_INCLUDED>
${XGBOOST_DEFINITIONS})
if (XGBOOST_MM_PREFETCH_PRESENT)
target_compile_definitions(objxgboost
PRIVATE
-DXGBOOST_MM_PREFETCH_PRESENT=1)
endif(XGBOOST_MM_PREFETCH_PRESENT)
if (XGBOOST_BUILTIN_PREFETCH_PRESENT)
target_compile_definitions(objxgboost
PRIVATE
-DXGBOOST_BUILTIN_PREFETCH_PRESENT=1)
endif (XGBOOST_BUILTIN_PREFETCH_PRESENT)
if (USE_OPENMP)
find_package(OpenMP REQUIRED)

View File

@@ -149,6 +149,18 @@ struct XGBAPIThreadLocalEntry {
std::vector<GradientPair> tmp_gpair;
};
XGB_DLL void XGBoostVersion(int* major, int* minor, int* patch) {
if (major) {
*major = XGBOOST_VER_MAJOR;
}
if (minor) {
*minor = XGBOOST_VER_MINOR;
}
if (patch) {
*patch = XGBOOST_VER_PATCH;
}
}
// define the threadlocal store.
using XGBAPIThreadLocalStore = dmlc::ThreadLocalStore<XGBAPIThreadLocalEntry>;

90
src/common/version.cc Normal file
View File

@@ -0,0 +1,90 @@
/*!
* Copyright 2019 XGBoost contributors
*/
#include <dmlc/io.h>
#include <string>
#include <tuple>
#include <vector>
#include "xgboost/logging.h"
#include "xgboost/json.h"
#include "version.h"
namespace xgboost {
const Version::TripletT Version::kInvalid {-1, -1, -1};
Version::TripletT Version::Load(Json const& in, bool check) {
if (get<Object const>(in).find("version") == get<Object const>(in).cend()) {
return kInvalid;
}
Integer::Int major {0}, minor {0}, patch {0};
try {
auto const& j_version = get<Array const>(in["version"]);
std::tie(major, minor, patch) = std::make_tuple(
get<Integer const>(j_version.at(0)),
get<Integer const>(j_version.at(1)),
get<Integer const>(j_version.at(2)));
} catch (dmlc::Error const& e) {
LOG(FATAL) << "Invaid version format in loaded JSON object: " << in;
}
return std::make_tuple(major, minor, patch);
}
Version::TripletT Version::Load(dmlc::Stream* fi) {
XGBoostVersionT major{0}, minor{0}, patch{0};
// This is only used in DMatrix serialization, so doesn't break model compability.
std::string msg { "Incorrect version format found in binary file. "
"Binary file from XGBoost < 1.0.0 is no longer supported. "
"Please generate it again." };
std::string verstr { u8"version:" }, read;
read.resize(verstr.size(), 0);
CHECK_EQ(fi->Read(&read[0], verstr.size()), verstr.size()) << msg;
if (verstr != read) {
// read might contain `\0` that terminates the string.
LOG(FATAL) << msg;
}
CHECK_EQ(fi->Read(&major, sizeof(major)), sizeof(major)) << msg;
CHECK_EQ(fi->Read(&minor, sizeof(major)), sizeof(minor)) << msg;
CHECK_EQ(fi->Read(&patch, sizeof(major)), sizeof(patch)) << msg;
return std::make_tuple(major, minor, patch);
}
void Version::Save(Json* out) {
Integer::Int major, minor, patch;
std::tie(major, minor, patch)= Self();
(*out)["version"] = std::vector<Json>{Json(Integer{major}),
Json(Integer{minor}),
Json(Integer{patch})};
}
void Version::Save(dmlc::Stream* fo) {
XGBoostVersionT major, minor, patch;
std::tie(major, minor, patch) = Self();
std::string verstr { u8"version:" };
fo->Write(&verstr[0], verstr.size());
fo->Write(&major, sizeof(major));
fo->Write(&minor, sizeof(minor));
fo->Write(&patch, sizeof(patch));
}
std::string Version::String(TripletT const& version) {
std::stringstream ss;
ss << std::get<0>(version) << "." << get<1>(version) << "." << get<2>(version);
return ss.str();
}
Version::TripletT Version::Self() {
return std::make_tuple(XGBOOST_VER_MAJOR, XGBOOST_VER_MINOR, XGBOOST_VER_PATCH);
}
bool Version::Same(TripletT const& triplet) {
return triplet == Self();
}
} // namespace xgboost

35
src/common/version.h Normal file
View File

@@ -0,0 +1,35 @@
/*!
* Copyright 2019 XGBoost contributors
*/
#ifndef XGBOOST_COMMON_VERSION_H_
#define XGBOOST_COMMON_VERSION_H_
#include <dmlc/io.h>
#include <string>
#include <tuple>
#include "xgboost/base.h"
namespace xgboost {
class Json;
// a static class for handling version info
struct Version {
using TripletT = std::tuple<XGBoostVersionT, XGBoostVersionT, XGBoostVersionT>;
static const TripletT kInvalid;
// Save/Load version info to Json document
static TripletT Load(Json const& in, bool check = false);
static void Save(Json* out);
// Save/Load version info to dmlc::Stream
static Version::TripletT Load(dmlc::Stream* fi);
static void Save(dmlc::Stream* fo);
static std::string String(TripletT const& version);
static TripletT Self();
static bool Same(TripletT const& triplet);
};
} // namespace xgboost
#endif // XGBOOST_COMMON_VERSION_H_

View File

@@ -4,6 +4,7 @@
*/
#include <xgboost/data.h>
#include <xgboost/logging.h>
#include <xgboost/build_config.h>
#include <dmlc/registry.h>
#include <cstring>
@@ -11,6 +12,7 @@
#include "./simple_dmatrix.h"
#include "./simple_csr_source.h"
#include "../common/io.h"
#include "../common/version.h"
#include "../common/group_data.h"
#if DMLC_ENABLE_STD_THREAD
@@ -34,8 +36,7 @@ void MetaInfo::Clear() {
}
void MetaInfo::SaveBinary(dmlc::Stream *fo) const {
int32_t version = kVersion;
fo->Write(&version, sizeof(version));
Version::Save(fo);
fo->Write(&num_row_, sizeof(num_row_));
fo->Write(&num_col_, sizeof(num_col_));
fo->Write(&num_nonzero_, sizeof(num_nonzero_));
@@ -47,19 +48,21 @@ void MetaInfo::SaveBinary(dmlc::Stream *fo) const {
}
void MetaInfo::LoadBinary(dmlc::Stream *fi) {
int version;
CHECK(fi->Read(&version, sizeof(version)) == sizeof(version)) << "MetaInfo: invalid version";
CHECK(version >= 1 && version <= kVersion) << "MetaInfo: unsupported file version";
auto version = Version::Load(fi);
auto major = std::get<0>(version);
// MetaInfo is saved in `SparsePageSource'. So the version in MetaInfo represents the
// version of DMatrix.
CHECK_EQ(major, 1) << "Binary DMatrix generated by XGBoost: "
<< Version::String(version) << " is no longer supported. "
<< "Please process and save your data in current version: "
<< Version::String(Version::Self()) << " again.";
CHECK(fi->Read(&num_row_, sizeof(num_row_)) == sizeof(num_row_)) << "MetaInfo: invalid format";
CHECK(fi->Read(&num_col_, sizeof(num_col_)) == sizeof(num_col_)) << "MetaInfo: invalid format";
CHECK(fi->Read(&num_nonzero_, sizeof(num_nonzero_)) == sizeof(num_nonzero_))
<< "MetaInfo: invalid format";
CHECK(fi->Read(&labels_.HostVector())) << "MetaInfo: invalid format";
CHECK(fi->Read(&group_ptr_)) << "MetaInfo: invalid format";
if (version == kVersionWithQid) {
std::vector<uint64_t> qids;
CHECK(fi->Read(&qids)) << "MetaInfo: invalid format";
}
CHECK(fi->Read(&weights_.HostVector())) << "MetaInfo: invalid format";
CHECK(fi->Read(&root_index_)) << "MetaInfo: invalid format";
CHECK(fi->Read(&base_margin_.HostVector())) << "MetaInfo: invalid format";