NDArrayPool源代码:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "asynNDArrayDriver.h"
#include "NDArray.h"
// 在认为一个NDArray对象太大前,它必须比所需的尺寸大多少。
#define THRESHOLD_SIZE_RATIO 1.5
static const char *driverName = "NDArrayPool";
/*
* eraseNDAttributes是一个控制每次用NDArrayPool->alloc()分配一个新数组时是否调用NDArray::clearAttributes()的全局标记。
* 默认值是0,表示clearAttributes()不被调用。这种模式是高效的,因为它节省了大量的分配/接触分配,并且当一旦
* 为一个驱动设置了这些属性并且不变化时,这是可以的。如果驱动属性被删除,如果这个标记为0,分配的数组将仍然有这些旧的属性,
* 设置这个标记在每次分配一个的NDArray时强制删除属性。
*/
volatile int eraseNDAttributes=0;
// 导出这个变量到EPICS IOC
extern "C" {epicsExportAddress(int, eraseNDAttributes);}
/** NDArrayPool构造器
* [in] pDriver: 指向创建这个对象的asynNDArrayDriver的指针.
* [in] maxMemory : 允许这个池使用的最大内存字节量,所有NDArray对象求和,0=无限
*/
NDArrayPool::NDArrayPool(class asynNDArrayDriver *pDriver, size_t maxMemory)
: numBuffers_(0), maxMemory_(maxMemory), memorySize_(0), pDriver_(pDriver)
// 初始化时,NDArray对象数目为0,使用内存字节数为0,可用内存最大字节数为传入的maxMemory
{
listLock_ = epicsMutexCreate(); // 创建互斥量
}
/** 创建新的NDArray对象。
* 这个方法应该被管理派生自NDArray类的对象的池对象重写。
*/
NDArray* NDArrayPool::createArray()
{
return new NDArray;
}
/*
* 管理派生自NDArray类的对象的池类的hook。
* 在新的数组已经被分配后,这个hook被调用。
* [in] pArray: 指向分配的NDArray对象的指针
*/
void NDArrayPool::onAllocateArray(NDArray *pArray)
{
}
/** 管理派生自NDArray类的对象的池类的hook。
* 在这个数组已经被保留后,这个hook被调用。
* [in] pArray : 指向被保留的NDArray对象的指针
*/
void NDArrayPool::onReserveArray(NDArray *pArray)
{
}
/** 管理派生自NDArray类的对象的池类的hook。
* 在这个数组已经被释放后,这个hook被调用。
* [in] pArray:指向被释放的NDArray对象的指针
*/
void NDArrayPool::onReleaseArray(NDArray *pArray)
{
}
/** 分配一个新的NDArray对象,需要前3个参数.
* [in] ndims:这个NDArray中维度数目.
* [in] dims :维度的数组,其尺寸必须至少为ndims.
* [in] dataType : NDArray的数据类型.
* [in] dataSize :为数组数据分配的字节数目 ; 如果0,则alloc将从ndims,
* 如果0,则alloc()将从ndims,dims和dataType计算除所需的尺寸。
* [in] pData : 指向一个数据缓存的指针;如果NULL,则alloc将分配一个新的数组缓存;如果非0,则认为它指向一个有效缓存。
* 如果pData不是NULL,则dataSize必须包含已有数组中实际的字节数目,并且这个数组必须足够大来保存这些数组数据。
* alloc()搜索它的空闲列表来查找一个空闲的NDArray缓存。如果不能找到一个空闲的,则它将分配一个新数组
* 并且添加它到这个空闲列表。如果分配这个NDArray所需的内存将使得为这个池分配的累积内存超过maxMemory,
* 则将返回一个错误。alloc()设置返回的NDArray的引用计数为1.
*/
NDArray* NDArrayPool::alloc(int ndims, size_t *dims, NDDataType_t dataType, size_t dataSize, void *pData)
{
NDArray *pArray=NULL;
NDArrayInfo_t arrayInfo;
const char* functionName = "NDArrayPool::alloc:";
epicsMutexLock(listLock_);
// 计算所需的NDArray尺寸
NDArray::computeArrayInfo(ndims, dims, dataType, &arrayInfo); // 根据ndims,dims和dataType获取每个总字节数
if (dataSize == 0) {
dataSize = arrayInfo.totalBytes;
}
std::multiset::iterator pListElement; // freeListElement对象迭代器
// 传入的数组数据未空,从空闲列表中获取一个
if (!pData) {
// 尝试寻找空闲列表中足够大的数组
freeListElement testElement(NULL, dataSize);
pListElement = freeList_.lower_bound(testElement); // dataSize为下限的迭代器,调用一次返回一个freeListElement对象
} else {// 传入的数组数据不为空,则从空闲列表中获取第一个最小的freeListElement对象
// dataSize没关系, pData将被替代.
pListElement = freeList_.begin();
}
if (pListElement == freeList_.end()) {
/* 我们未找到一个足够大的空闲列表,分配一个新数组 */
numBuffers_++; //NDArray对象数目加1
pArray = this->createArray();
} else {
pArray = pListElement->pArray_; //到一个足够大的空闲列表,取出这个NDArray对象
if (pData || (pListElement->dataSize_ > (dataSize * THRESHOLD_SIZE_RATIO))) {
// 我们找到了一个数组,但它太大。设置这个尺寸为0,因而在下面分配它
memorySize_ -= pArray->dataSize;
free(pArray->pData);
pArray->pData = NULL;
}
freeList_.erase(pListElement); //空闲列表从删除这个freeListElement对象
}
/* 初始化字段:设置这个分配这个NDArray对象的NDArrayPool,引用次数,分配这个NDArray的驱动,数组数据类型,数组数据维度数目 */
pArray->pNDArrayPool = this;
pArray->referenceCount = 1;
pArray->pDriver = pDriver_;
pArray->dataType = dataType;
pArray->ndims = ndims;
// 维度数组置0
memset(pArray->dims, 0, sizeof(pArray->dims));
for (int i=0; idims[i].size = dims[i];
pArray->dims[i].offset = 0;
pArray->dims[i].binning = 1;
pArray->dims[i].reverse = 0;
}
/* 如果置位了全局标记,删除这些属性 */
if (eraseNDAttributes) pArray->pAttributeList->clear();
/* 清除codec */
pArray->codec.clear();
/* 到此,pArray存在,但pArray->pData可能是NULL */
/* 如果调用者传递一个有效缓存,使用那个缓存 */
if (pData) {
pArray->pData = pData;
pArray->dataSize = dataSize;
memorySize_ += dataSize;
} else if (pArray->pData == NULL) {
if ((maxMemory_ > 0) && ((memorySize_ + dataSize) > maxMemory_)) {
/*
* 我们没有分配这个数组的足够内存,看我们是否能通过删除数组获取内存
* 首先删除最大的数组,及从freeList_末尾开始。
*/
NDArray *freeArray;
std::multiset::iterator it;
// 已用内存+dataSiz大于可用最大内存量,需要释放数组
while (!freeList_.empty() && ((memorySize_ + dataSize) > maxMemory_)) {
it = freeList_.end(); // 获取末尾的freeListElement对象
it--;
freeArray = it->pArray_;
// 从空闲列表中删除获取的freeListElement对象
freeList_.erase(it);
// 内存使用量减少获取的freeListElement对象的dataSize
memorySize_ -= freeArray->dataSize;
// NDArray对象数目减少1
numBuffers_--;
// 释放获取的freeListElement对象
delete freeArray;
}
}
// 如果最大可用内存量有限制并且已用内存量+dataSize大于最大可用内存量
if ((maxMemory_ > 0) && ((memorySize_ + dataSize) > maxMemory_)) {
asynPrint(pDriver_->pasynUserSelf, ASYN_TRACE_ERROR,
"%s: error: reached limit of %ld memory (%d buffers)\n",
functionName, (long)maxMemory_, numBuffers_);
} else {
pArray->pData = malloc(dataSize); // 分配数组数据区
if (pArray->pData) {//分配成功,设置NDArray的dataSize和
pArray->dataSize = dataSize;
pArray->compressedSize = dataSize;
memorySize_ += dataSize; // 内存使用量增加dataSize
}
}
}
// 如果我们没有一个有效内存缓存,设置pArray为NULL来表示错误
if (pArray && (pArray->pData == NULL)) {
delete pArray;
numBuffers_--;
pArray = NULL;
}
// 调用分配hook(用于管理派生自NDArray类的对象的池)
onAllocateArray(pArray);
epicsMutexUnlock(listLock_);
return (pArray);
}
/** 这个方法复制一个NDArray对象。
* [in] pIn :要被复制的输入数组.
* [in] pOut:将被复制到的输出数组;可以是NULL或者一个指向一个已有NDArray的指针。
* [in] copyData:如果这个标记为true,则包括数组数据的所有东西都被复制。如果0, 复制除了数据外(包括属性)的所有东西。
* [in] copyDimensions :如果这个标记为true, 则即使pOut不为NULL,也复制这些维度;默认为true
* [in] copyDataType:如果这个标记为true, 即使pOut不为NULL,也复制dataType, 默认为true
* 返回:返回一个指向输出数组的指针
*
* 如果pOut为NULL,首先分配它。如果输出数组对象已经存在(pOut!=NULL),则必须已经分配足够空间给它来保存数据。
*/
NDArray* NDArrayPool::copy(NDArray *pIn, NDArray *pOut, bool copyData, bool copyDimensions, bool copyDataType)
{
//const char *functionName = "copy";
size_t dimSizeOut[ND_ARRAY_MAX_DIMS];
int i;
size_t numCopy;
NDArrayInfo arrayInfo;
/* 如果输出数组不存在,则创建它 */
if (!pOut) {
for (i=0; indims; i++) dimSizeOut[i] = pIn->dims[i].size; // 从输入数组的每个维度获取输出数组每个维度尺寸
pOut = this->alloc(pIn->ndims, dimSizeOut, pIn->dataType, 0, NULL); // 数据类型使用输入数组的数据类型,dataSize取0,则alloc自行计算
if(NULL==pOut) return NULL;
}
// 复制uniqueId, timeStamp,epicsTS
pOut->uniqueId = pIn->uniqueId;
pOut->timeStamp = pIn->timeStamp;
pOut->epicsTS = pIn->epicsTS;
// 如果copyDimensions为true,则复制维度数目以及每个维度上的尺寸
if (copyDimensions) {
pOut->ndims = pIn->ndims;
memcpy(pOut->dims, pIn->dims, sizeof(pIn->dims));
}
// 如果copyDataType为true,则复制数据类型
if (copyDataType) {
pOut->dataType = pIn->dataType;
}
// 复制编码算法名
pOut->codec.name = pIn->codec.name;
// 复制压缩后的尺寸
pOut->compressedSize = pIn->compressedSize;
// 如果copyData为true,
if (copyData) { //
pIn->getInfo(&arrayInfo);
numCopy = pIn->codec.empty() ? arrayInfo.totalBytes : pIn->compressedSize; // codec.empty()为true,表示没有使用压缩算法
if (pOut->dataSize < numCopy) numCopy = pOut->dataSize; //需要复制的数据量取数组数据尺寸和输入数组尺寸中的小者
memcpy(pOut->pData, pIn->pData, numCopy); // 将输入数组中数据区中数据复制到输出数组中数据区
}
pOut->pAttributeList->clear(); // 清除输出数组中属性列表中所有属性
pIn->pAttributeList->copy(pOut->pAttributeList); // 将输入数组中属性列表中所有属性复制到输出数组的属性列表中
return(pOut);
}
/** 这个方法增加这个NDArray对象的引用次数。
* [in] pArray :对这个数组增加引用计数.
* 当一个NDArray被放到一个队列为了之后处理,插件必须调用reserve()。
*/
int NDArrayPool::reserve(NDArray *pArray)
{
const char *functionName = "reserve";
/* Make sure we own this array 确认我们拥有这个数组 */
if (pArray->pNDArrayPool != this) {// 这个NDArray对象不是这个NDArrayPool对象分配的
asynPrint(pDriver_->pasynUserSelf, ASYN_TRACE_ERROR,
"%s::%s: ERROR, not owner! owner=%p, should be this=%p\n",
driverName, functionName, pArray->pNDArrayPool, this);
return(ND_ERROR);
}
//asynPrint(pDriver_->pasynUserSelf, ASYN_TRACE_FLOW,
// "NDArrayPool::reserve pArray=%p, count=%d\n", pArray, pArray->referenceCount);
epicsMutexLock(listLock_);
// 如果引用次数少于1,则出问题了,这个NDArray已经被释放了
if (pArray->referenceCount < 1) {
cantProceed("%s:reserve ERROR, reference count = %d, should be >= 1, pArray=%p\n",
driverName, pArray->referenceCount, pArray);
}
pArray->referenceCount++; // 传入NDArray对象的引用次数加1
// 调用保留hook(用于管理派生自NDArray类的对象的池)
onReserveArray(pArray);
epicsMutexUnlock(listLock_);
return ND_SUCCESS;
}
/** 这个方法减小对NDArray对象的引用次数。
* [in] pArray :对这个数组减少引用次数
* 当引用次数到达0,NDArray被放回空闲列表。
* 当一个NDArray被从队列移除并且对其处理结束时,插件必须调用release()。
* 在调用所有插件后,驱动必须调用release()。
*/
int NDArrayPool::release(NDArray *pArray)
{
const char *functionName = "release";
/* 确认我们拥有这个数组 */
if (pArray->pNDArrayPool != this) {
asynPrint(pDriver_->pasynUserSelf, ASYN_TRACE_ERROR,
"%s::%s: ERROR, not owner! owner=%p, should be this=%p\n",
driverName, functionName, pArray->pNDArrayPool, this);
return(ND_ERROR);
}
//asynPrint(pDriver_->pasynUserSelf, ASYN_TRACE_FLOW,
// "NDArrayPool::release pArray=%p, count=%d\n", pArray, pArray->referenceCount);
epicsMutexLock(listLock_);
pArray->referenceCount--;// 引用次数减少1
if (pArray->referenceCount == 0) {// 引用次数为0
/* The last user has released this image, add it back to the free list 最后的用户释放这个图像,添加它到空闲列表*/
freeListElement listElement(pArray, pArray->dataSize);
freeList_.insert(listElement);
}
if (pArray->referenceCount < 0) {
cantProceed("%s:release ERROR, reference count < 0 pArray=%p\n",
driverName, pArray);
}
// 调用释放释放hook(用于管理派生自NDArray类的池)
onReleaseArray(pArray);
epicsMutexUnlock(listLock_);
return ND_SUCCESS;
}
// 输入数组数据类型和输出数组数据类型之间的转换
template void convertType(NDArray *pIn, NDArray *pOut)
{
size_t i;
dataTypeIn *pDataIn = (dataTypeIn *)pIn->pData; // 输入数组的数据区
dataTypeOut *pDataOut = (dataTypeOut *)pOut->pData; // 输出数组的数据区
NDArrayInfo_t arrayInfo;
pOut->getInfo(&arrayInfo);
for (i=0; i int convertTypeSwitch (NDArray *pIn, NDArray *pOut)
{
int status = ND_SUCCESS;
switch(pIn->dataType) {
case NDInt8:
convertType (pIn, pOut);
break;
case NDUInt8:
convertType (pIn, pOut);
break;
case NDInt16:
convertType (pIn, pOut);
break;
case NDUInt16:
convertType (pIn, pOut);
break;
case NDInt32:
convertType (pIn, pOut);
break;
case NDUInt32:
convertType (pIn, pOut);
break;
case NDInt64:
convertType (pIn, pOut);
break;
case NDUInt64:
convertType (pIn, pOut);
break;
case NDFloat32:
convertType (pIn, pOut);
break;
case NDFloat64:
convertType (pIn, pOut);
break;
default:
status = ND_ERROR;
break;
}
return(status);
}
/*
1、当输入和输出数组都是一维数组时,dim = 0
1 2 3 4 5 6 => 1 2 3
*/
template void convertDim(NDArray *pIn, NDArray *pOut,
void *pDataIn, void *pDataOut, int dim)
{
dataTypeOut *pDOut = (dataTypeOut *)pDataOut; // 输出数组数据区
dataTypeIn *pDIn = (dataTypeIn *)pDataIn; // 输入数组数据区
/*
size_t size;
size_t offset;
int binning;
int reverse;
*/
NDDimension_t *pOutDims = pOut->dims; // 输出数组的维度数组
NDDimension_t *pInDims = pIn->dims; //输入数组的维度数组
size_t inStep, outStep, inOffset;
int inDir;
int i, bin;
size_t inc, in, out;
inStep = 1;
outStep = 1;
inDir = 1;
inOffset = pOutDims[dim].offset;
for (i=0; i 0) {
convertDim (pIn, pOut, pDIn, pDOut, dim-1);
} else {
*pDOut += (dataTypeOut)*pDIn;
}
pDIn += inc;
}
pDOut += outStep;
}
}
//
template int convertDimensionSwitch(NDArray *pIn, NDArray *pOut,
void *pDataIn, void *pDataOut, int dim)
{
int status = ND_SUCCESS;
switch(pIn->dataType) {
case NDInt8:
convertDim (pIn, pOut, pDataIn, pDataOut, dim);
break;
case NDUInt8:
convertDim (pIn, pOut, pDataIn, pDataOut, dim);
break;
case NDInt16:
convertDim (pIn, pOut, pDataIn, pDataOut, dim);
break;
case NDUInt16:
convertDim (pIn, pOut, pDataIn, pDataOut, dim);
break;
case NDInt32:
convertDim (pIn, pOut, pDataIn, pDataOut, dim);
break;
case NDUInt32:
convertDim (pIn, pOut, pDataIn, pDataOut, dim);
break;
case NDInt64:
convertDim (pIn, pOut, pDataIn, pDataOut, dim);
break;
case NDUInt64:
convertDim (pIn, pOut, pDataIn, pDataOut, dim);
break;
case NDFloat32:
convertDim (pIn, pOut, pDataIn, pDataOut, dim);
break;
case NDFloat64:
convertDim (pIn, pOut, pDataIn, pDataOut, dim);
break;
default:
status = ND_ERROR;
break;
}
return(status);
}
static int convertDimension(NDArray *pIn,
NDArray *pOut,
void *pDataIn,
void *pDataOut,
int dim)
{
int status = ND_SUCCESS;
/* 这个例程被传递:
* 一个指向输入数据起始位置的指针:
* 一个指向输出数据起始位置的指针
* 一个维度的数组
* 维度索引
*/
switch(pOut->dataType) {
case NDInt8:
convertDimensionSwitch (pIn, pOut, pDataIn, pDataOut, dim);
break;
case NDUInt8:
convertDimensionSwitch (pIn, pOut, pDataIn, pDataOut, dim);
break;
case NDInt16:
convertDimensionSwitch (pIn, pOut, pDataIn, pDataOut, dim);
break;
case NDUInt16:
convertDimensionSwitch (pIn, pOut, pDataIn, pDataOut, dim);
break;
case NDInt32:
convertDimensionSwitch (pIn, pOut, pDataIn, pDataOut, dim);
break;
case NDUInt32:
convertDimensionSwitch (pIn, pOut, pDataIn, pDataOut, dim);
break;
case NDInt64:
convertDimensionSwitch (pIn, pOut, pDataIn, pDataOut, dim);
break;
case NDUInt64:
convertDimensionSwitch (pIn, pOut, pDataIn, pDataOut, dim);
break;
case NDFloat32:
convertDimensionSwitch (pIn, pOut, pDataIn, pDataOut, dim);
break;
case NDFloat64:
convertDimensionSwitch (pIn, pOut, pDataIn, pDataOut, dim);
break;
default:
status = ND_ERROR;
break;
}
return(status);
}
/** 从一个输入NDArray创建一个新的输出NDArray,执行转换操作。
* 这个函数形式用于仅更改数据类型,不是维度,维度被保留。
* [in] pIn :输入数组,转换的来源.
* [out] ppOut : 输出数组,转换结果。
* [in] dataTypeOut :输出数组的数据类型
*/
int NDArrayPool::convert(NDArray *pIn,
NDArray **ppOut,
NDDataType_t dataTypeOut)
{
NDDimension_t dims[ND_ARRAY_MAX_DIMS];
int i;
// 输出数组的维度与输入数组的维度一样
for (i=0; indims; i++) {
dims[i].size = pIn->dims[i].size;
dims[i].offset = 0;
dims[i].binning = 1;
dims[i].reverse = 0;
}
return this->convert(pIn, ppOut, dataTypeOut, dims);
}
/** 从一个输入NDArray创建一个新的输出NDArray,执行转换操作。
* 如果dataTypeout不同于pIn->dataType,转换可以更改数据类型。
* 它也可以更改维度,outDims其每个维度可以有与输入数组维度(pIn->dims)不同的size,binning,offset和reverse的值。
*
* [in] pIn :这个输入数组,转换的来源.
* [out]ppOut:输出数组,转换的结果
* [in] dataTypeOut:输出数组的数据类型
* [in] dimsOut :输出数组的维度.
*/
int NDArrayPool::convert(NDArray *pIn,
NDArray **ppOut,
NDDataType_t dataTypeOut,
NDDimension_t *dimsOut)
{
int dimsUnchanged;
size_t dimSizeOut[ND_ARRAY_MAX_DIMS];
NDDimension_t dimsOutCopy[ND_ARRAY_MAX_DIMS];
int i;
NDArray *pOut;
NDArrayInfo_t arrayInfo;
NDAttribute *pAttribute;
int colorMode, colorModeMono = NDColorModeMono;
const char *functionName = "convert";
/* 初始化出错 */
*ppOut = NULL;
/* 不能转换被压缩的数据 */
if (!pIn->codec.empty()) {
fprintf(stderr, "%s:%s: can't convert compressed data [%s]\n",
driverName, functionName, pIn->codec.name.c_str());
return ND_ERROR;
}
/* 因为我们需要修改它,但我们不要影响调用者,复制输入维度数组 */
memcpy(dimsOutCopy, dimsOut, pIn->ndims*sizeof(NDDimension_t)); // 维度数由输入数组的维度数决定
/* 计算输出数组的维度 */
dimsUnchanged = 1;
for (i=0; indims; i++) {
dimsOutCopy[i].size = dimsOutCopy[i].size/dimsOutCopy[i].binning; // 输出数组每个维度的尺寸
if (dimsOutCopy[i].size <= 0) {
asynPrint(pDriver_->pasynUserSelf, ASYN_TRACE_ERROR,
"%s:%s: ERROR, invalid output dimension, size=%d, binning=%d\n",
driverName, functionName, (int)dimsOut[i].size, dimsOut[i].binning);
return(ND_ERROR);
}
dimSizeOut[i] = dimsOutCopy[i].size; // 存储输出数组每一维度的尺寸的数组
if ((pIn->dims[i].size != dimsOutCopy[i].size) || // 只要满足输出数组每个维度上尺寸与输入输入对那个维度不同
(dimsOutCopy[i].offset != 0) || // 或者输出数组每个维度上有偏移量或者有binning或者反向了,则输出维度就发生了变化
(dimsOutCopy[i].binning != 1) ||
(dimsOutCopy[i].reverse != 0)) dimsUnchanged = 0;
}
/* 我们知道了输出数组的数据类型和维度,分配它 */
pOut = alloc(pIn->ndims, dimSizeOut, dataTypeOut, 0, NULL);
*ppOut = pOut;
if (!pOut) {
asynPrint(pDriver_->pasynUserSelf, ASYN_TRACE_ERROR,
"%s:%s: ERROR, cannot allocate output array\n",
driverName, functionName);
return(ND_ERROR);
}
/*从输入NDArray对象复制字段到输出NDArray对象 */
pOut->timeStamp = pIn->timeStamp;
pOut->epicsTS = pIn->epicsTS;
pOut->uniqueId = pIn->uniqueId;
/* 用传递给这个函数的那些维度结构体替换输出NDArray中的dims中存储的维度结构体 */
memcpy(pOut->dims, dimsOutCopy, pIn->ndims*sizeof(NDDimension_t));
pIn->pAttributeList->copy(pOut->pAttributeList);
pOut->getInfo(&arrayInfo);
if (dimsUnchanged) {
if (pIn->dataType == pOut->dataType) {
/*
* 维度相同并且数据类型相同,则仅复制输入图像到输出图像。
*/
memcpy(pOut->pData, pIn->pData, arrayInfo.totalBytes);
return ND_SUCCESS;
} else {
/* 我们需要转换数据类型 */
switch(pOut->dataType) {// 根据输出NDArray中数据类型,将输入NDArray中数据转成输出NDArray中数据类型
case NDInt8:
convertTypeSwitch (pIn, pOut);
break;
case NDUInt8:
convertTypeSwitch (pIn, pOut);
break;
case NDInt16:
convertTypeSwitch (pIn, pOut);
break;
case NDUInt16:
convertTypeSwitch (pIn, pOut);
break;
case NDInt32:
convertTypeSwitch (pIn, pOut);
break;
case NDUInt32:
convertTypeSwitch (pIn, pOut);
break;
case NDInt64:
convertTypeSwitch (pIn, pOut);
break;
case NDUInt64:
convertTypeSwitch (pIn, pOut);
break;
case NDFloat32:
convertTypeSwitch (pIn, pOut);
break;
case NDFloat64:
convertTypeSwitch (pIn, pOut);
break;
default:
//status = ND_ERROR;
break;
}
}
} else {
/* 对整个输出NDArray的数据清零 */
memset(pOut->pData, 0, arrayInfo.totalBytes);
convertDimension(pIn, pOut, pIn->pData, pOut->pData, pIn->ndims-1);
}
/* 设置输出数组中的字段 */
for (i=0; indims; i++) {
pOut->dims[i].offset = pIn->dims[i].offset + dimsOutCopy[i].offset;
pOut->dims[i].binning = pIn->dims[i].binning * dimsOutCopy[i].binning;
if (pIn->dims[i].reverse) pOut->dims[i].reverse = !pOut->dims[i].reverse;
}
/*
* 如果帧是RGBx帧,并且我们折叠那个维度,则更改颜色模式
*/
pAttribute = pOut->pAttributeList->find("ColorMode");
if (pAttribute && pAttribute->getValue(NDAttrInt32, &colorMode)) {
if ((colorMode == NDColorModeRGB1) && (pOut->dims[0].size != 3))
pAttribute->setValue(&colorModeMono);
else if ((colorMode == NDColorModeRGB2) && (pOut->dims[1].size != 3))
pAttribute->setValue(&colorModeMono);
else if ((colorMode == NDColorModeRGB3) && (pOut->dims[2].size != 3))
pAttribute->setValue(&colorModeMono);
}
return ND_SUCCESS;
}
/** 返回这个对象当分配的缓存数目 */
int NDArrayPool::getNumBuffers()
{
return numBuffers_;
}
/** 0=unlimited 返回允许这个对象分配的最大内存字节 */
size_t NDArrayPool::getMaxMemory()
{
return maxMemory_;
}
/** 返回这个对象当前已经分配的内存字节数 */
size_t NDArrayPool::getMemorySize()
{
return memorySize_;
}
/** 返回空闲列表中NDArray对象的数目 */
int NDArrayPool::getNumFree()
{
epicsMutexLock(listLock_);
int size = (int)freeList_.size();
epicsMutexUnlock(listLock_);
return size;
}
/** 删除空闲列表中所有NDArrays */
void NDArrayPool::emptyFreeList()
{
NDArray *freeArray;
std::multiset::iterator it; // 获取freeListElement对象的迭代器
epicsMutexLock(listLock_);
while (!freeList_.empty()) {
it = freeList_.begin(); // 获取第一个freeListElement对象
freeArray = it->pArray_; // 获取NDArray对象
freeList_.erase(it); // 从空闲列表中删除
memorySize_ -= freeArray->dataSize;
numBuffers_--;
delete freeArray;
}
epicsMutexUnlock(listLock_);
}
/** 报告NDArrayPool空闲列表尺寸和其它性质。
* [in] fp : 报告输出的文件指针
* [in] details : 所要报告的详细程度,当前什么也没做.
*/
int NDArrayPool::report(FILE *fp, int details)
{
fprintf(fp, "\n");
fprintf(fp, "NDArrayPool:\n");
fprintf(fp, " numBuffers=%d, numFree=%d\n",
numBuffers_, this->getNumFree()); // 缓存数量,还可分配的内存
fprintf(fp, " memorySize=%ld, maxMemory=%ld\n",
(long)memorySize_, (long)maxMemory_); //已用内存数,最大内存分配数量
if (details > 5) { // 每个NDArray的信息:NDArray序号,NDArray数据区的尺寸,以及NDArray的地址
int i;
std::multiset::iterator it;
NDArray *freeArray;
fprintf(fp, " freeList: (index, dataSize, pArray)\n");
epicsMutexLock(listLock_);
for (it=freeList_.begin(),i=0; it!=freeList_.end(); ++it,i++) {
fprintf(fp, " %d %d %p\n", i, (int)it->dataSize_, it->pArray_);
}
// 每个NDArray的详细信息: NDArray对象的地址 DArray对象的维度数目
// NDArray对象每个维度的元素数目 数据类型,数据尺寸,数据地址 唯一id,时间戳 引用计数 属性数目 每个属性信息
if (details > 10) {
for (it=freeList_.begin(); it!=freeList_.end(); ++it) {
freeArray = it->pArray_;
fprintf(fp, " Array %d\n", i);
freeArray->report(fp, details);
}
}
epicsMutexUnlock(listLock_);
}
return ND_SUCCESS;
}
NDArrayPool类中方法的测试:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "asynNDArrayDriver.h"
#include "NDArray.h"
int main()
{
// NDArrayPool::NDArrayPool(class asynNDArrayDriver *pDriver, size_t maxMemory)
printf("***********Test NDArrayPool construct:*********************\n");
NDArrayPool * pPool = new NDArrayPool(NULL, 10000);
printf("NDArrayPool information:\n");
pPool->report(stdout, 11);
printf("*************************************************************\n");
printf("**********************Test NDArrayPool::alloc:***************\n");
size_t dims[2] = {2,3};
int ndims = 2;
NDArray * pArray = pPool->alloc(ndims, dims, NDInt32, 0, NULL);
printf("NDArray Information:\n");
pArray->report(stdout, 11);
printf("NDArrayPool information:\n");
pPool->report(stdout , 11);
printf("*************************************************************\n");
printf("********************Test NDArrayPool::copy:*****************\n");
NDArrayInfo_t info;
pArray->getInfo(&info);
size_t i;
size_t j;
printf("Set Value for pArray:\n");
epicsInt32* pArr = (epicsInt32 *)pArray->pData;
for (i = 0; i < info.nElements; i++){
pArr[i] = i;
}
printf("copy a new NDArray from pArray:\n");
NDArray * pArrayout = pPool->copy(pArray, NULL, true, true, true);
pArrayout->getInfo(&info);
pArr = (epicsInt32 *)pArrayout->pData;
printf("xDim = %d, yDim = %d, xSize = %lu, ySize = %lu\n", info.xDim, info.yDim, info.xSize, info.ySize);
printf("output the values from the new NDArray:\n");
for (i = 0; i < info.ySize; i++){
for (j = 0; j < info.xSize; j++){
printf("%d\t", pArr[i * info.xSize + j]);
}
printf("\n");
}
printf("\n");
printf("New created pArrayout information:\n");
pArrayout->report(stdout, 11);
printf("NDArrayPool information:\n");
pPool->report(stdout ,11);
printf("*************************************************************\n");
printf("**********************Test NDArrayPool::reserve**************\n");
pPool->reserve(pArray);
printf("NDArray Information:\n");
pArray->report(stdout, 11);
printf("*************************************************************\n");
printf("**********************Test NDArrayPool:release**************\n");
printf("New created pArrayout information:\n");
pPool->release(pArrayout);
pPool->report(stdout ,11);
printf("*************************************************************\n");
printf("Use NDArrayPool::alloc to allocate a new NDArray:*************\n");
dims[0] = 3;
dims[1] = 2;
printf("NDArrayPool Information:\n");
NDArray * pArrayOut = pPool->alloc(ndims, dims, NDFloat64, 0, NULL);
pArrayOut->report(stdout, 11);
printf("*************************************************************\n");
printf("**********************Use NArrayPool::convert***************\n");
NDArray * pnewNDArray = NULL;
//int NDArrayPool::convert(NDArray *pIn, NDArray **ppOut, NDDataType_t dataTypeOut, NDDimension_t *dimsOut)
pPool->convert(pArray, &pnewNDArray, NDFloat64, pArrayOut->dims);
pnewNDArray->report(stdout, 11);
epicsFloat64 * pf64 = (epicsFloat64 *)pnewNDArray->pData;
pnewNDArray->getInfo(&info);
printf("xDim = %d, yDim = %d, xSize = %lu, ySize = %lu\n", info.xDim, info.yDim, info.xSize, info.ySize);
for (i = 0; i < info.ySize; i++){
for (j = 0; j < info.xSize; j++){
printf("%f\t", pf64[j + info.xSize * i]);
}
printf("\n");
}
printf("*************************************************************\n");
pPool->report(stdout, 11);
return 0;
}
测试结果如下:
orangepi@orangepi5:~/C_program/host_program/hostApp$ O.linux-aarch64/testNDArrayPool
***********Test NDArrayPool construct:*********************
NDArrayPool information:
NDArrayPool:
numBuffers=0, numFree=0
memorySize=0, maxMemory=10000
freeList: (index, dataSize, pArray)
*************************************************************
**********************Test NDArrayPool::alloc:***************
NDArray Information:
NDArray Array address=0x558d2d9090:
ndims=2 dims=[2 3 ]
dataType=4, dataSize=24, pData=0x558d2d92d0
uniqueId=0, timeStamp=0.000000, epicsTS.secPastEpoch=0, epicsTS.nsec=0
referenceCount=1
number of attributes=0
NDAttributeList: address=0x558d2d9230:
number of attributes=0
NDArrayPool information:
NDArrayPool:
numBuffers=1, numFree=0
memorySize=24, maxMemory=10000
freeList: (index, dataSize, pArray)
*************************************************************
********************Test NDArrayPool::copy:*****************
Set Value for pArray:
copy a new NDArray from pArray:
xDim = 0, yDim = 1, xSize = 2, ySize = 3
output the values from the new NDArray:
0 1
2 3
4 5
New created pArrayout information:
NDArray Array address=0x558d2d9310:
ndims=2 dims=[2 3 ]
dataType=4, dataSize=24, pData=0x558d2d92f0
uniqueId=0, timeStamp=0.000000, epicsTS.secPastEpoch=0, epicsTS.nsec=0
referenceCount=1
number of attributes=0
NDAttributeList: address=0x558d2d94b0:
number of attributes=0
NDArrayPool information:
NDArrayPool:
numBuffers=2, numFree=0
memorySize=48, maxMemory=10000
freeList: (index, dataSize, pArray)
*************************************************************
**********************Test NDArrayPool::reserve**************
NDArray Information:
NDArray Array address=0x558d2d9090:
ndims=2 dims=[2 3 ]
dataType=4, dataSize=24, pData=0x558d2d92d0
uniqueId=0, timeStamp=0.000000, epicsTS.secPastEpoch=0, epicsTS.nsec=0
referenceCount=2
number of attributes=0
NDAttributeList: address=0x558d2d9230:
number of attributes=0
*************************************************************
**********************Test NDArrayPool:release**************
New created pArrayout information:
NDArrayPool:
numBuffers=2, numFree=1
memorySize=48, maxMemory=10000
freeList: (index, dataSize, pArray)
0 24 0x558d2d9310
Array 1
NDArray Array address=0x558d2d9310:
ndims=2 dims=[2 3 ]
dataType=4, dataSize=24, pData=0x558d2d92f0
uniqueId=0, timeStamp=0.000000, epicsTS.secPastEpoch=0, epicsTS.nsec=0
referenceCount=0
number of attributes=0
NDAttributeList: address=0x558d2d94b0:
number of attributes=0
*************************************************************
Use NDArrayPool::alloc to allocate a new NDArray:*************
NDArrayPool Information:
NDArray Array address=0x558d2d95b0:
ndims=2 dims=[3 2 ]
dataType=9, dataSize=48, pData=0x558d2d97f0
uniqueId=0, timeStamp=0.000000, epicsTS.secPastEpoch=0, epicsTS.nsec=0
referenceCount=1
number of attributes=0
NDAttributeList: address=0x558d2d9750:
number of attributes=0
*************************************************************
**********************Use NArrayPool::convert***************
NDArray Array address=0x558d2d9830:
ndims=2 dims=[3 2 ]
dataType=9, dataSize=48, pData=0x558d2d9a70
uniqueId=0, timeStamp=0.000000, epicsTS.secPastEpoch=0, epicsTS.nsec=0
referenceCount=1
number of attributes=0
NDAttributeList: address=0x558d2d99d0:
number of attributes=0
xDim = 0, yDim = 1, xSize = 3, ySize = 2
0.000000 1.000000 2.000000
2.000000 3.000000 4.000000
*************************************************************
NDArrayPool:
numBuffers=4, numFree=1
memorySize=144, maxMemory=10000
freeList: (index, dataSize, pArray)
0 24 0x558d2d9310
Array 1
NDArray Array address=0x558d2d9310:
ndims=2 dims=[2 3 ]
dataType=4, dataSize=24, pData=0x558d2d92f0
uniqueId=0, timeStamp=0.000000, epicsTS.secPastEpoch=0, epicsTS.nsec=0
referenceCount=0
number of attributes=0
NDAttributeList: address=0x558d2d94b0:
number of attributes=0