infer.h 19.6 KB
Newer Older
W
wangguibao 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
// Copyright (c) 2019 PaddlePaddle Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#pragma once
16
#include <pthread.h>
W
wangguibao 已提交
17
#include <sys/stat.h>
W
wangguibao 已提交
18
#include <sys/types.h>
W
wangguibao 已提交
19
#include <unistd.h>
20
#include <numeric>
W
wangguibao 已提交
21
#include <string>
M
MRXLT 已提交
22
#include <utility>
W
wangguibao 已提交
23
#include <vector>
24
#include <functional>
G
guru4elephant 已提交
25
#include "core/predictor/common/inner_common.h"
H
HexToString 已提交
26
#include "core/predictor/framework/bsf.h"
G
guru4elephant 已提交
27 28
#include "core/predictor/framework/factory.h"
#include "core/predictor/framework/infer_data.h"
29
#include "core/predictor/framework/memory.h"
W
wangjiawei04 已提交
30
#include "paddle_inference_api.h"  // NOLINT
W
wangguibao 已提交
31 32 33 34
namespace baidu {
namespace paddle_serving {
namespace predictor {

W
wangguibao 已提交
35 36
using configure::ModelToolkitConf;

Z
zhangjun 已提交
37 38 39 40 41 42 43 44 45 46 47
class AutoLock {
 public:
  explicit AutoLock(pthread_mutex_t& mutex) : _mut(mutex) {
    pthread_mutex_lock(&mutex);
  }
  ~AutoLock() { pthread_mutex_unlock(&_mut); }

 private:
  pthread_mutex_t& _mut;
};

Z
update  
zhangjun 已提交
48
class GlobalCreateMutex {
Z
zhangjun 已提交
49 50 51 52
 public:
  pthread_mutex_t& mutex() { return _mut; }

  static pthread_mutex_t& instance() {
Z
update  
zhangjun 已提交
53
    static GlobalCreateMutex gmutex;
Z
zhangjun 已提交
54 55 56 57
    return gmutex.mutex();
  }

 private:
Z
update  
zhangjun 已提交
58
  GlobalCreateMutex() { pthread_mutex_init(&_mut, NULL); }
Z
zhangjun 已提交
59 60 61
  pthread_mutex_t _mut;
};

W
wangguibao 已提交
62
class InferEngine {
W
wangguibao 已提交
63 64 65 66 67 68 69 70 71 72
 public:
  virtual ~InferEngine() {}

  virtual int proc_initialize(const configure::EngineDesc& conf, bool version) {
    return proc_initialize_impl(conf, version);
  }
  virtual int proc_finalize() { return proc_finalize_impl(); }
  virtual int thrd_initialize() { return thrd_initialize_impl(); }
  virtual int thrd_clear() { return thrd_clear_impl(); }
  virtual int thrd_finalize() { return thrd_finalize_impl(); }
H
HexToString 已提交
73 74 75
  virtual int infer(const void* in, void* out, uint32_t batch_size = -1) {
    return infer_impl(in, out, batch_size);
  }
W
wangguibao 已提交
76 77 78 79 80 81 82 83 84 85 86 87

  virtual int reload() = 0;

  virtual uint64_t version() const = 0;

  // begin: framework inner call
  virtual int proc_initialize_impl(const configure::EngineDesc& conf,
                                   bool version) = 0;
  virtual int thrd_initialize_impl() = 0;
  virtual int thrd_finalize_impl() = 0;
  virtual int thrd_clear_impl() = 0;
  virtual int proc_finalize_impl() = 0;
H
HexToString 已提交
88
  virtual int infer_impl(const void* in,
89 90
                         void* out,
                         uint32_t batch_size = -1) = 0;
91
  virtual int task_infer_impl(const void* in, void* out) = 0;  // NOLINT
H
HexToString 已提交
92

W
wangguibao 已提交
93 94 95 96 97 98
  // end: framework inner call
};

class ReloadableInferEngine : public InferEngine {
 public:
  virtual ~ReloadableInferEngine() {}
W
wangguibao 已提交
99

100 101 102 103 104
  // Reloadable record
  union ReloadableRecord {
    time_t timestamp;
    uint64_t md5sum;
    uint64_t revision;
W
wangguibao 已提交
105
  };
W
wangguibao 已提交
106

Z
update  
zhangjun 已提交
107
  virtual int load(const configure::EngineDesc& conf) = 0;
108
  typedef im::bsf::Task<paddle::PaddleTensor, paddle::PaddleTensor> TaskT;
W
wangguibao 已提交
109

110
  int proc_initialize_impl(const configure::EngineDesc& conf, bool version);
W
wangguibao 已提交
111

112
  int proc_initialize(const configure::EngineDesc& conf, bool version);
H
HexToString 已提交
113

114
  int infer(const void* in, void* out, uint32_t batch_size = -1);
W
wangguibao 已提交
115

116
  int thrd_initialize();
W
wangguibao 已提交
117

118
  int thrd_clear();
W
wangguibao 已提交
119

120
  int proc_finalize();
W
wangguibao 已提交
121

122
  int reload();
W
wangguibao 已提交
123 124 125

  uint64_t version() const { return _version; }
  uint32_t thread_num() const { return _infer_thread_num; }
W
wangguibao 已提交
126

W
wangguibao 已提交
127
 private:
128
  int parse_version_info(const configure::EngineDesc& config, bool version);
W
wangguibao 已提交
129

130
  bool check_need_reload();
W
wangguibao 已提交
131

132
  bool check_timestamp_ne();
W
wangguibao 已提交
133

134
  bool check_timestamp_gt();
W
wangguibao 已提交
135 136 137 138 139 140

  bool check_md5sum() { return false; }

  bool check_revision() { return false; }

 protected:
141 142 143 144
  // Model directory
  std::string _model_dir;

  // The description of inference engine
Z
update  
zhangjun 已提交
145
  configure::EngineDesc _conf;
W
wangguibao 已提交
146 147

 private:
148
  // Tag file of reloadable model
W
wangguibao 已提交
149
  std::string _reload_tag_file;
150 151 152 153 154 155 156 157

  // Type of reload, e.g. timestamp_ne, timestamp_gt, md5sum, reversion
  std::string _reload_type;

  // Record the last loading infermation
  ReloadableRecord _last_record;

  // Number of inference threads
W
wangguibao 已提交
158
  uint32_t _infer_thread_num;
159 160

  // Size of inference batch
W
wangguibao 已提交
161
  uint32_t _infer_batch_size;
162 163

  // Need to align batch_size in inferring
W
wangguibao 已提交
164
  bool _infer_batch_align;
165 166

  // model version
W
wangguibao 已提交
167 168
  uint64_t _version;
};
W
wangguibao 已提交
169

170
// Lock free switching two models
W
wangguibao 已提交
171 172 173 174 175 176 177 178 179 180 181 182
template <typename EngineCore>
struct ModelData {
  ModelData() : current_idx(1) {
    cores[0] = NULL;
    cores[1] = NULL;
  }

  ~ModelData() {
    delete cores[0];
    delete cores[1];
  }

183 184
  void* get() { return cores[current_idx]->get(); }

W
wangguibao 已提交
185 186 187 188 189 190 191 192 193 194 195 196
  EngineCore* cores[2];
  uint32_t current_idx;
};

template <typename EngineCore>
class DBReloadableInferEngine : public ReloadableInferEngine {
 public:
  virtual ~DBReloadableInferEngine() {}

  int proc_initialize(const configure::EngineDesc& conf, bool version) {
    THREAD_KEY_CREATE(&_skey, NULL);
    THREAD_MUTEX_INIT(&_mutex, NULL);
197
    gpu_index = 0;
W
wangguibao 已提交
198 199 200
    return ReloadableInferEngine::proc_initialize(conf, version);
  }

201 202 203 204 205
  // 进程初始化会调用load,但由于未执行线程初始化,所以_reload_vec为空,不再继续执行。
  // 热加载的话会调用load,由于线程已经初始化,_reload_vec不为空,所以继续执行load_data操作加载数据。
  // 线程初始化会执行load_data操作加载数据,然后将engine加入_reload_vec中。
  // 每个模型只有一个CloneDBReloadableInferEngine对象。
  // 但一个CloneDBReloadableInferEngine对象,可以包含N个EngineCore。
Z
update  
zhangjun 已提交
206
  virtual int load(const configure::EngineDesc& conf) {
W
wangguibao 已提交
207 208
    if (_reload_vec.empty()) {
      return 0;
W
wangguibao 已提交
209
    }
210
    gpu_index = 0;
W
wangguibao 已提交
211
    for (uint32_t ti = 0; ti < _reload_vec.size(); ++ti) {
Z
update  
zhangjun 已提交
212
      if (load_data(_reload_vec[ti], conf) != 0) {
W
wangguibao 已提交
213 214 215 216 217
        LOG(ERROR) << "Failed reload engine model: " << ti;
        return -1;
      }
    }

Z
update  
zhangjun 已提交
218
    LOG(WARNING) << "Succ load engine, path: " << conf.model_dir();
W
wangguibao 已提交
219 220
    return 0;
  }
W
wangguibao 已提交
221

222 223
  virtual int load_data(ModelData<EngineCore>* md,
                        const configure::EngineDesc& conf) {
W
wangguibao 已提交
224 225 226
    uint32_t next_idx = (md->current_idx + 1) % 2;
    if (md->cores[next_idx]) {
      delete md->cores[next_idx];
W
wangguibao 已提交
227 228
    }

W
wangguibao 已提交
229
    md->cores[next_idx] = new (std::nothrow) EngineCore;
230

H
HexToString 已提交
231
    // params.dump();
232 233 234 235 236 237 238 239
    size_t gpu_ids_num = conf.gpu_ids_size();
    im::bsf::AutoMutex lock(_mutex);
    int gpu_id = -1;
    if (gpu_ids_num > 0) {
      gpu_id = conf.gpu_ids(gpu_index % gpu_ids_num);
    }
    if (!md->cores[next_idx] ||
        md->cores[next_idx]->create(conf, gpu_id) != 0) {
Z
update  
zhangjun 已提交
240
      LOG(ERROR) << "Failed create model, path: " << conf.model_dir();
W
wangguibao 已提交
241
      return -1;
W
wangguibao 已提交
242
    }
243
    gpu_index++;
W
wangguibao 已提交
244 245 246
    md->current_idx = next_idx;
    return 0;
  }
W
wangguibao 已提交
247

W
wangguibao 已提交
248 249
  virtual int thrd_initialize_impl() {
    ModelData<EngineCore>* md = new (std::nothrow) ModelData<EngineCore>;
Z
update  
zhangjun 已提交
250
    if (!md || load_data(md, _conf) != 0) {
251
      LOG(ERROR) << "Failed create thread data from " << _conf.model_dir();
W
wangguibao 已提交
252
      return -1;
W
wangguibao 已提交
253 254
    }

W
wangguibao 已提交
255
    THREAD_SETSPECIFIC(_skey, md);
H
HexToString 已提交
256
    im::bsf::AutoMutex lock(_mutex);
W
wangguibao 已提交
257 258 259 260 261
    _reload_vec.push_back(md);
    return 0;
  }

  int thrd_clear_impl() {
262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278
    // for bsf-Task-threads
    // actually, there are 2 kinds of multi-thread.
    // 1. brpc thread 2. bsf Task thread
    // each request is in 1-single brpc thread.
    // IF (bsf Task thread is not used)
    // every single brpc thread thread corresponds to all the EngineCores.
    // each request runs all models in 1-single thread brpc thread.

    // IF (bsf Task thread is used)
    // there will be a ThreadPool called bsf TaskExecutor.
    // in TaskExecutor, 1 bsf thread corresponds to 1 EngineCore.
    // brpc thread only put the data into the task_queue(which is in
    // TaskExecutor)
    // EngineCore->infer() is running in bsf Task thread.

    // MempoolWrapper::instance() is actually a Thread-Local Mempool.
    // so it belongs to a single Thread.
W
wangguibao 已提交
279 280 281 282
    return 0;
  }

  int thrd_finalize_impl() { return 0; }
W
wangguibao 已提交
283

W
wangguibao 已提交
284 285 286 287 288
  int proc_finalize_impl() {
    THREAD_KEY_DELETE(_skey);
    THREAD_MUTEX_DESTROY(&_mutex);
    return 0;
  }
W
wangguibao 已提交
289

W
wangguibao 已提交
290 291 292 293 294 295
  EngineCore* get_core() {
    ModelData<EngineCore>* md =
        (ModelData<EngineCore>*)THREAD_GETSPECIFIC(_skey);
    if (!md) {
      LOG(ERROR) << "Failed get thread specific data";
      return NULL;
W
wangguibao 已提交
296
    }
W
wangguibao 已提交
297 298
    return md->cores[md->current_idx];
  }
W
wangguibao 已提交
299

W
wangguibao 已提交
300 301 302 303
 protected:
  THREAD_KEY_T _skey;
  THREAD_MUTEX_T _mutex;
  std::vector<ModelData<EngineCore>*> _reload_vec;
304
  int gpu_index = 0;
W
wangguibao 已提交
305
};
W
wangguibao 已提交
306

W
wangguibao 已提交
307 308 309 310 311 312 313
// 多个EngineCore共用同一份模型数据
template <typename EngineCore>
class CloneDBReloadableInferEngine
    : public DBReloadableInferEngine<EngineCore> {
 public:
  virtual ~CloneDBReloadableInferEngine() {}

314 315 316 317 318
  // 进程初始化会调用load,但由于未执行线程初始化,所以_reload_vec为空,不再继续执行。
  // 热加载的话会调用load,由于线程已经初始化,_reload_vec不为空,所以继续执行load_data操作加载数据。
  // 线程初始化会执行load_data操作加载数据,然后将engine加入_reload_vec中。
  // 每个模型只有一个CloneDBReloadableInferEngine对象。
  // 但一个CloneDBReloadableInferEngine对象,可以包含N个EngineCore。
W
wangguibao 已提交
319

320 321 322 323 324
  virtual int load_data(ModelData<EngineCore>* md,
                        const configure::EngineDesc& conf) {
    uint32_t next_idx = (md->current_idx + 1) % 2;
    if (md->cores[next_idx]) {
      delete md->cores[next_idx];
W
wangguibao 已提交
325
    }
326
    md->cores[next_idx] = new (std::nothrow) EngineCore;
W
wangguibao 已提交
327

328 329 330 331 332 333 334
    // params.dump();
    size_t gpu_ids_num = conf.gpu_ids_size();
    im::bsf::AutoMutex lock(DBReloadableInferEngine<EngineCore>::_mutex);
    int gpu_id = -1;
    if (gpu_ids_num > 0) {
      gpu_id = conf.gpu_ids(DBReloadableInferEngine<EngineCore>::gpu_index %
                            gpu_ids_num);
W
wangguibao 已提交
335
    }
336 337 338 339 340 341 342 343 344 345
    // gpu_index will be set to be 0, when load() or proc_initial() is called.
    // gpu_index < gpu_ids_num, means there are still not create on some GPU
    // card.
    // so we need to create the predictor.
    // gpu_index >= gpu_ids_num, means each GPU card has already create one.
    // so we need to clone the predictor.
    if (DBReloadableInferEngine<EngineCore>::gpu_index < gpu_ids_num) {
      if (!md->cores[next_idx] ||
          md->cores[next_idx]->create(conf, gpu_id) != 0) {
        LOG(ERROR) << "Failed create model, path: " << conf.model_dir();
W
wangguibao 已提交
346 347
        return -1;
      }
348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367
      DBReloadableInferEngine<EngineCore>::gpu_index++;
      md->current_idx = next_idx;
      if (_cloneTemplate.size() <
          DBReloadableInferEngine<EngineCore>::gpu_index) {
        _cloneTemplate.push_back(md);
      } else {
        _cloneTemplate[DBReloadableInferEngine<EngineCore>::gpu_index - 1] = md;
      }
    } else {
      // when gpu_id = -1, means we use cpu, but the index should be 0.
      if (gpu_id == -1) gpu_id = 0;
      if (!md->cores[next_idx] ||
          md->cores[next_idx]->clone(_cloneTemplate[gpu_id]->get()) != 0) {
        LOG(ERROR) << "Failed clone model from core";
        return -1;
      }
      DBReloadableInferEngine<EngineCore>::gpu_index++;
      md->current_idx = next_idx;
      LOG(WARNING) << "core clone model succ, cur_idx[" << md->current_idx
                   << "].";
W
wangguibao 已提交
368 369
    }

W
wangguibao 已提交
370 371
    return 0;
  }
W
wangguibao 已提交
372

W
wangguibao 已提交
373
 protected:
374 375 376
  // 模板EngineCore,如果已创建,则多个线程级EngineCore共用该对象的模型数据
  std::vector<ModelData<EngineCore>*>
      _cloneTemplate;
W
wangguibao 已提交
377 378
};

H
HexToString 已提交
379
template <typename EngineCore>
M
bug fix  
MRXLT 已提交
380
#ifdef WITH_TRT
H
HexToString 已提交
381
class FluidInferEngine : public DBReloadableInferEngine<EngineCore> {
M
bug fix  
MRXLT 已提交
382
#else
H
HexToString 已提交
383
class FluidInferEngine : public CloneDBReloadableInferEngine<EngineCore> {
M
bug fix  
MRXLT 已提交
384 385
#endif
 public:  // NOLINT
W
wangguibao 已提交
386 387
  FluidInferEngine() {}
  ~FluidInferEngine() {}
H
HexToString 已提交
388
  typedef std::vector<paddle::PaddleTensor> TensorVector;
H
HexToString 已提交
389
  int infer_impl(const void* in, void* out, uint32_t batch_size = -1) {
H
HexToString 已提交
390 391 392
    // First of all, get the real core acording to the
    // Template parameter <EngineCore>.
    EngineCore* core = DBReloadableInferEngine<EngineCore>::get_core();
W
wangguibao 已提交
393 394 395
    if (!core || !core->get()) {
      LOG(ERROR) << "Failed get fluid core in infer_impl()";
      return -1;
W
wangguibao 已提交
396
    }
H
HexToString 已提交
397 398 399 400 401 402
    // We use the for loop to process the input data.
    // Inside each for loop, use the in[i]->name as inputName and call
    // 'core->GetInputHandle(inputName)' to get the pointer of InputData.
    // Set the lod and shape information of InputData first.
    // Then copy data from cpu to the core.
    const TensorVector* tensorVector_in_pointer =
403 404
        reinterpret_cast<const TensorVector*>(in);
    for (int i = 0; i < tensorVector_in_pointer->size(); ++i) {
H
HexToString 已提交
405
      auto lod_tensor_in =
406
          core->GetInputHandle((*tensorVector_in_pointer)[i].name);
H
HexToString 已提交
407 408 409
      lod_tensor_in->SetLoD((*tensorVector_in_pointer)[i].lod);
      lod_tensor_in->Reshape((*tensorVector_in_pointer)[i].shape);
      void* origin_data = (*tensorVector_in_pointer)[i].data.data();
H
HexToString 已提交
410 411 412 413
      // Because the core needs to determine the size of memory space
      // according to the data type passed in.
      // The pointer type of data must be one of
      // float *,int64_t*,int32_t* instead void*.
H
HexToString 已提交
414
      if ((*tensorVector_in_pointer)[i].dtype == paddle::PaddleDType::FLOAT32) {
H
HexToString 已提交
415
        float* data = static_cast<float*>(origin_data);
H
HexToString 已提交
416
        lod_tensor_in->CopyFromCpu(data);
H
HexToString 已提交
417
      } else if ((*tensorVector_in_pointer)[i].dtype ==
418
                 paddle::PaddleDType::INT64) {
H
HexToString 已提交
419
        int64_t* data = static_cast<int64_t*>(origin_data);
H
HexToString 已提交
420
        lod_tensor_in->CopyFromCpu(data);
H
HexToString 已提交
421
      } else if ((*tensorVector_in_pointer)[i].dtype ==
422
                 paddle::PaddleDType::INT32) {
H
HexToString 已提交
423
        int32_t* data = static_cast<int32_t*>(origin_data);
H
HexToString 已提交
424
        lod_tensor_in->CopyFromCpu(data);
H
HexToString 已提交
425
      }
W
wangjiawei04 已提交
426
    }
H
HexToString 已提交
427 428
    // After the input data is passed in,
    // call 'core->Run()' perform the prediction process.
W
wangjiawei04 已提交
429
    if (!core->Run()) {
430 431
      LOG(ERROR) << "Failed run fluid family core";
      return -1;
W
wangjiawei04 已提交
432
    }
H
HexToString 已提交
433 434 435 436
    // In order to get the results,
    // first, call the 'core->GetOutputNames()' to get the name of output
    // (which is a dict like {OutputName:pointer of OutputValue}).
    // Then, use for-loop to get OutputValue by calling 'core->GetOutputHandle'.
H
HexToString 已提交
437
    std::vector<std::string> outnames = core->GetOutputNames();
H
HexToString 已提交
438
    std::vector<int> output_shape;
H
HexToString 已提交
439 440
    int out_num = 0;
    int dataType = 0;
H
HexToString 已提交
441 442 443
    void* databuf_data = NULL;
    char* databuf_char = NULL;
    size_t databuf_size = 0;
H
HexToString 已提交
444
    TensorVector* tensorVector_out_pointer =
445
        reinterpret_cast<TensorVector*>(out);
H
HexToString 已提交
446
    if (!tensorVector_out_pointer) {
H
HexToString 已提交
447
      LOG(ERROR) << "tensorVector_out_pointer is nullptr,error";
W
wangguibao 已提交
448 449
      return -1;
    }
H
HexToString 已提交
450 451 452 453
    // Get the type and shape information of OutputData first.
    // then copy data to cpu from the core.
    // The pointer type of data_out must be one of
    // float *,int64_t*,int32_t* instead void*.
454
    for (int i = 0; i < outnames.size(); ++i) {
H
HexToString 已提交
455
      auto lod_tensor_out = core->GetOutputHandle(outnames[i]);
H
HexToString 已提交
456
      output_shape = lod_tensor_out->shape();
H
HexToString 已提交
457 458
      out_num = std::accumulate(
          output_shape.begin(), output_shape.end(), 1, std::multiplies<int>());
H
HexToString 已提交
459
      dataType = lod_tensor_out->type();
H
HexToString 已提交
460
      if (dataType == paddle::PaddleDType::FLOAT32) {
461
        databuf_size = out_num * sizeof(float);
H
HexToString 已提交
462
        databuf_data = MempoolWrapper::instance().malloc(databuf_size);
H
HexToString 已提交
463
        if (!databuf_data) {
464 465
          LOG(ERROR) << "Malloc failed, size: " << databuf_size;
          return -1;
H
HexToString 已提交
466 467
        }
        float* data_out = reinterpret_cast<float*>(databuf_data);
H
HexToString 已提交
468
        lod_tensor_out->CopyToCpu(data_out);
H
HexToString 已提交
469
        databuf_char = reinterpret_cast<char*>(data_out);
H
HexToString 已提交
470
      } else if (dataType == paddle::PaddleDType::INT64) {
471
        databuf_size = out_num * sizeof(int64_t);
H
HexToString 已提交
472
        databuf_data = MempoolWrapper::instance().malloc(databuf_size);
H
HexToString 已提交
473
        if (!databuf_data) {
474 475
          LOG(ERROR) << "Malloc failed, size: " << databuf_size;
          return -1;
H
HexToString 已提交
476
        }
H
HexToString 已提交
477
        int64_t* data_out = reinterpret_cast<int64_t*>(databuf_data);
H
HexToString 已提交
478
        lod_tensor_out->CopyToCpu(data_out);
H
HexToString 已提交
479
        databuf_char = reinterpret_cast<char*>(data_out);
H
HexToString 已提交
480
      } else if (dataType == paddle::PaddleDType::INT32) {
481
        databuf_size = out_num * sizeof(int32_t);
H
HexToString 已提交
482
        databuf_data = MempoolWrapper::instance().malloc(databuf_size);
H
HexToString 已提交
483
        if (!databuf_data) {
484 485
          LOG(ERROR) << "Malloc failed, size: " << databuf_size;
          return -1;
H
HexToString 已提交
486 487 488 489
        }
        int32_t* data_out = reinterpret_cast<int32_t*>(databuf_data);
        lod_tensor_out->CopyToCpu(data_out);
        databuf_char = reinterpret_cast<char*>(data_out);
H
HexToString 已提交
490
      }
H
HexToString 已提交
491 492 493 494 495
      // Because task scheduling requires OPs to use 'Channel'
      // (which is a data structure) to transfer data between OPs.
      // We need to copy the processed data to the 'Channel' for the next OP.
      // In this function, it means we should copy the 'databuf_char' to
      // 'void* out'.(which is also called ‘tensorVector_out_pointer’)
H
HexToString 已提交
496 497 498 499 500
      paddle::PaddleTensor tensor_out;
      tensor_out.name = outnames[i];
      tensor_out.dtype = paddle::PaddleDType(dataType);
      tensor_out.shape.assign(output_shape.begin(), output_shape.end());
      std::vector<std::vector<size_t>> out_lod = lod_tensor_out->lod();
501
      for (int li = 0; li < out_lod.size(); ++li) {
H
HexToString 已提交
502 503 504 505
        std::vector<size_t> lod_element;
        lod_element.assign(out_lod[li].begin(), out_lod[li].end());
        tensor_out.lod.push_back(lod_element);
      }
H
HexToString 已提交
506
      paddle::PaddleBuf paddleBuf(databuf_char, databuf_size);
H
HexToString 已提交
507 508
      tensor_out.data = paddleBuf;
      tensorVector_out_pointer->push_back(tensor_out);
H
HexToString 已提交
509
    }
W
wangguibao 已提交
510 511
    return 0;
  }
H
HexToString 已提交
512

513 514
  int task_infer_impl(const void* in, void* out) {  // NOLINT
    return infer_impl(in, out);
H
HexToString 已提交
515
  }
W
wangguibao 已提交
516 517
};

W
wangguibao 已提交
518 519 520 521 522 523 524
typedef FactoryPool<InferEngine> StaticInferFactory;

class VersionedInferEngine : public InferEngine {
 public:
  VersionedInferEngine() { _versions.clear(); }
  ~VersionedInferEngine() {}

525
  int proc_initialize(const configure::EngineDesc& conf);
W
wangguibao 已提交
526

527
  int proc_initialize(const configure::EngineDesc& conf, bool version);
W
wangguibao 已提交
528

529
  int proc_finalize();
W
wangguibao 已提交
530

531
  int thrd_initialize();
W
wangguibao 已提交
532

533
  int thrd_clear();
W
wangguibao 已提交
534

535
  int thrd_finalize();
W
wangguibao 已提交
536

537
  int reload();
W
wangguibao 已提交
538

539
  uint64_t version() const;
W
wangguibao 已提交
540 541

  // inference interface
542
  InferEngine* default_engine() const;
W
wangguibao 已提交
543

544
  int infer(const void* in, void* out, uint32_t batch_size);
W
wangguibao 已提交
545 546

  template <typename T>
547
  T* get_core();
W
wangguibao 已提交
548 549

  // versioned inference interface
550
  int infer(const void* in, void* out, uint32_t batch_size, uint64_t version);
W
wangguibao 已提交
551 552

  template <typename T>
553
  T* get_core(uint64_t version);
W
wangguibao 已提交
554

555
  int proc_initialize_impl(const configure::EngineDesc& conf, bool);
W
wangguibao 已提交
556

557 558 559 560 561 562 563 564 565 566
  int thrd_initialize_impl();

  int thrd_finalize_impl();

  int thrd_clear_impl();

  int proc_finalize_impl();

  int infer_impl(const void* in, void* out, uint32_t batch_size = -1);

567
  int task_infer_impl(const void* in, void* out);
W
wangguibao 已提交
568 569 570

 private:
  boost::unordered_map<uint64_t, InferEngine*> _versions;
W
wangguibao 已提交
571 572
};

W
wangguibao 已提交
573 574 575 576 577 578 579
class InferManager {
 public:
  static InferManager& instance() {
    static InferManager ins;
    return ins;
  }

580
  int proc_initialize(const char* path, const char* file);
W
wangguibao 已提交
581

582
  int thrd_initialize();
W
wangguibao 已提交
583

584
  int thrd_clear();
W
wangguibao 已提交
585

586
  int reload();
W
wangguibao 已提交
587

588
  int thrd_finalize();
W
wangguibao 已提交
589

590
  int proc_finalize();
W
wangguibao 已提交
591 592

  // Inference interface
H
HexToString 已提交
593 594 595
  int infer(const char* model_name,
            const void* in,
            void* out,
596
            uint32_t batch_size = -1);
W
wangguibao 已提交
597 598

  template <typename T>
599
  T* get_core(const char* model_name);
W
wangguibao 已提交
600 601

  // Versioned inference interface
H
HexToString 已提交
602
  int infer(const char* model_name,
H
HexToString 已提交
603 604 605
            const void* in,
            void* out,
            uint32_t batch_size,
606
            uint64_t version);
W
wangguibao 已提交
607 608

  template <typename T>
609
  T* get_core(const char* model_name, uint64_t version);
W
wangguibao 已提交
610

611
  int query_version(const std::string& model, uint64_t& version);
W
wangguibao 已提交
612 613 614 615

 private:
  boost::unordered_map<std::string, VersionedInferEngine*> _map;
};
W
wangguibao 已提交
616

W
wangguibao 已提交
617 618 619
}  // namespace predictor
}  // namespace paddle_serving
}  // namespace baidu