By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement . We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

I want to use java predict interface(float[][] predicts = booster.predict(testMat);) as online service. But I found it does not support multithreading. Because synchronized used in predict process. Why lock the predict. When I remove key word "synchronized" in function "private synchronized float[][] predict(DMatrix data, boolean outputMargin, int treeLimit, boolean predLeaf, boolean predContribs) throws XGBoostError", the core dump happend. How can i fix this bug. @tqchen @CodingCat @fromradio

@Craigacp @tqchen @phunterlau . i have already fix two unsafe thread call in c++ source code. Because mutithread write share variable at same time.
when i call predict function, the internal function PredLoopSpecalize will be used. there are two part of code which could cause unsafe thread(note that other function maybe have unsafe thread problem, but i just fix my call).

  • thread_temp useing in code as follow is share variable, when multithread write into thread_temp, it cause core dump. i change the thread_temp to local variable.
    inline void PredLoopSpecalize(DMatrix* p_fmat,
    std::vector<bst_float>* out_preds,
    const gbm::GBTreeModel& model, int num_group,
    unsigned tree_begin, unsigned tree_end) {
    const MetaInfo& info = p_fmat->info();
  • const int nthread = omp_get_max_threads();
    InitThreadTemp(nthread, model.param.num_feature);
    std::vector<bst_float>& preds = out_preds;
    CHECK_EQ(model.param.size_leaf_vector, 0)
    << "size_leaf_vector is enforced to 0 so far";
    CHECK_EQ(preds.size(), p_fmat->info().num_row * num_group);
    // start collecting the prediction
    dmlc::DataIter
    iter = p_fmat->RowIterator();
    iter->BeforeFirst();
    int b = 0;
    while (iter->BatchNext()) {
    const RowBatch& batch = iter->Value();
    // parallel over local batch
    const int K = 8;
    const bst_omp_uint nsize = static_cast<bst_omp_uint>(batch.size);
    const bst_omp_uint rest = nsize % K;
    #pragma omp parallel for schedule(static)
    for (bst_omp_uint i = 0; i < nsize - rest; i += K) {
    const int tid = omp_get_thread_num();
    RegTree::FVec& feats = thread_temp [tid];

      int64_t ridx[K];
      RowBatch::Inst inst[K];
      for (int k = 0; k < K; ++k) {
        ridx[k] = static_cast<int64_t>(batch.base_rowid + i + k);
      for (int k = 0; k < K; ++k) {
        inst[k] = batch[i + k];
      for (int k = 0; k < K; ++k) {
        for (int gid = 0; gid < num_group; ++gid) {
          const size_t offset = ridx[k] * num_group + gid;
          preds[offset] += this->PredValue(
              inst[k], model.trees, model.tree_info, gid,
              info.GetRoot(ridx[k]), &feats, tree_begin, tree_end);
    for (bst_omp_uint i = nsize - rest; i < nsize; ++i) {
      RegTree::FVec& feats = **thread_temp**[0];
      const int64_t ridx = static_cast<int64_t>(batch.base_rowid + i);
      const RowBatch::Inst inst = batch[i];
      for (int gid = 0; gid < num_group; ++gid) {
        const size_t offset = ridx * num_group + gid;
        preds[offset] +=
            this->PredValue(inst, model.trees, model.tree_info, gid,
                            info.GetRoot(ridx), &feats, tree_begin, tree_end);
      break;
    
  • variable at_first_ used in BeforeFirst and Next function, it can be changed during multithread call, when its value changed, Next() will return false, then prediction stop, return defaule value.
    void SimpleCSRSource::BeforeFirst() {
    at_first_ = true;

    bool SimpleCSRSource::Next() {
    //LOG(CONSOLE)<<"SimpleCSRSource::Next()"<<"\n";
    if (!at_first_) return false;
    at_first_ = false;
    batch_.size = row_ptr_.size() - 1;
    batch_.base_rowid = 0;
    batch_.ind_ptr = dmlc::BeginPtr(row_ptr_);
    batch_.data_ptr = dmlc::BeginPtr(row_data_);
    return true;

    I face the same problem. hi @superclocks, how do you solve it? I did not get your point.
    just use batch input, or?

    I look at the java source code, it is still synchronized. Should I assume it is not thread-safe in C++ implementation in the latest release(0.72)?
    Thanks,
    James

    private synchronized float[][] predict(DMatrix data, boolean outputMargin, int treeLimit, boolean predLeaf, boolean predContribs) throws XGBoostError.

    @superclocks I follow your blog, but get error:

    在成员函数‘virtual bool xgboost::data::SimpleCSRSource::BatchNext()’中: 
    错误:‘batch_’在此作用域中尚未声明 
    错误:‘row_ptr_’在此作用域中尚未声明 
    错误:‘row_data_’在此作用域中尚未声明
              

    @superclocks After based on tag 0.72 code, the error is:

    src/c_api/c_api.cc: 在成员函数‘void xgboost::Booster::LazyInit()’中:
    src/c_api/c_api.cc:55:27: 错误:‘lock_’在此作用域中尚未声明
           pthread_mutex_lock(&lock_);
    
  •