nvinferserver的插件和底层库在DS6.3上开源了。这样nvinferserver和nvinfer推理就都开源了,有什么问题,可以直接调代码。
NvDsInferTensorMeta{
/** Array of pointers to the output host buffers for the batch / frame / object. */
void **out_buf_ptrs_host;
/** Array of pointers to the output device buffers for the batch / frame / object. */
void **out_buf_ptrs_dev;
/** GPU device ID on which the device buffers have been allocated. */
}
问题1, out_buf_ptrs_host和out_buf_ptrs_dev在nvinfer和nvinferserver中有什么区别呢?
可以从插件层往底层查这个问题,在nvinfer中,赋值的地方是:
attach_tensor_output_meta{
meta->out_buf_ptrs_host = new void *[meta->num_output_layers];
meta->out_buf_ptrs_dev = new void *[meta->num_output_layers];
。。。。。。
meta->out_buf_ptrs_dev[i] =
(uint8_t *) batch_output->outputDeviceBuffers[i] +
info.inferDims.numElements * get_element_size (info.dataType) * j;
meta->out_buf_ptrs_host[i] =
(uint8_t *) batch_output->hostBuffers[info.bindingIndex] +
info.inferDims.numElements * get_element_size (info.dataType) * j;
。。。。。。
}
那就得去底层找outputDeviceBuffers和hostBuffers。
在InferPostprocessor::postProcessHost中,可以看到outputDeviceBuffers指向GPU的buffer。
batchOutput.outputDeviceBuffers[i] =
batch.m_DeviceBuffers[m_OutputLayerInfo[i].bindingIndex];
在InferPostprocessor::postProcessHost中,可以看到hostBuffers指向m_HostBuffers,那m_HostBuffers从哪里来?
batchOutput.hostBuffers[i] =
batch.m_HostBuffers[i] ? batch.m_HostBuffers[i]->ptr() : nullptr;
在InferPostprocessor::copyBuffersToHostMemory中,因为needOutputCopyB4Processing一直是true,所以必然进入如下判断,从m_DeviceBuffers中拷贝数据到m_HostBuffers。
if (!info.isInput && needOutputCopyB4Processing())
{
cudaMemcpyAsync(batch.m_HostBuffers[info.bindingIndex]->ptr(),
batch.m_DeviceBuffers[info.bindingIndex],
}
在nvinferserver中,逻辑是不一样的,在插件的attachTensorOutputMeta中,out_buf_ptrs_dev赋的空,只有out_buf_ptrs_host可用。
{
void *bufPtr = buf->getBufPtr(batchIdx);
meta->out_buf_ptrs_host[i] = bufPtr;
meta->out_buf_ptrs_dev[i] = nullptr;
}
以为nvinferserver的CAPI为例,nvinferserver在做推理的时候,需要指定输出的回调函数,也就是TrtISBackend::allocateResponseBuf,在nvdsinferserver_common.proto中,可以找到输出buffer的支持的类型, triton默认输出gpubuffer类型。
/** Tensor memory type
*/
enum MemoryType {
MEMORY_TYPE_DEFAULT = 0;
MEMORY_TYPE_CPU = 1;
MEMORY_TYPE_GPU = 2;
}
在memTypeFromDsProto中,会将配置转为内部类型。
memTypeFromDsProto(ic::MemoryType t)
{
static const std::unordered_map
{ic::MEMORY_TYPE_DEFAULT, InferMemType::kNone},
{ic::MEMORY_TYPE_CPU, InferMemType::kCpuCuda},
{ic::MEMORY_TYPE_GPU, InferMemType::kGpuCuda},
};
}
nvinerserver会强行想triton的返回值转成hostcpu类型,在InferCudaContext::acquireTensorHostBuf中创建hostbuffer, 在Postprocessor::postCudaImpl中,通过 cudaMemcpyAsync(outBufPtr, inBufPtr把gpubuffer拷贝到cpubuffer。
因为out_buf_ptrs_host指向的是hostcpu类型的buffer。