• NDArrayPool源代码解析以及测试程序


     NDArrayPool源代码:

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #include
    9. #include
    10. #include
    11. #include
    12. #include "asynNDArrayDriver.h"
    13. #include "NDArray.h"
    14. // 在认为一个NDArray对象太大前,它必须比所需的尺寸大多少。
    15. #define THRESHOLD_SIZE_RATIO 1.5
    16. static const char *driverName = "NDArrayPool";
    17. /*
    18. * eraseNDAttributes是一个控制每次用NDArrayPool->alloc()分配一个新数组时是否调用NDArray::clearAttributes()的全局标记。
    19. * 默认值是0,表示clearAttributes()不被调用。这种模式是高效的,因为它节省了大量的分配/接触分配,并且当一旦
    20. * 为一个驱动设置了这些属性并且不变化时,这是可以的。如果驱动属性被删除,如果这个标记为0,分配的数组将仍然有这些旧的属性,
    21. * 设置这个标记在每次分配一个的NDArray时强制删除属性。
    22. */
    23. volatile int eraseNDAttributes=0;
    24. // 导出这个变量到EPICS IOC
    25. extern "C" {epicsExportAddress(int, eraseNDAttributes);}
    26. /** NDArrayPool构造器
    27. * [in] pDriver: 指向创建这个对象的asynNDArrayDriver的指针.
    28. * [in] maxMemory : 允许这个池使用的最大内存字节量,所有NDArray对象求和,0=无限
    29. */
    30. NDArrayPool::NDArrayPool(class asynNDArrayDriver *pDriver, size_t maxMemory)
    31. : numBuffers_(0), maxMemory_(maxMemory), memorySize_(0), pDriver_(pDriver)
    32. // 初始化时,NDArray对象数目为0,使用内存字节数为0,可用内存最大字节数为传入的maxMemory
    33. {
    34. listLock_ = epicsMutexCreate(); // 创建互斥量
    35. }
    36. /** 创建新的NDArray对象。
    37. * 这个方法应该被管理派生自NDArray类的对象的池对象重写。
    38. */
    39. NDArray* NDArrayPool::createArray()
    40. {
    41. return new NDArray;
    42. }
    43. /*
    44. * 管理派生自NDArray类的对象的池类的hook。
    45. * 在新的数组已经被分配后,这个hook被调用。
    46. * [in] pArray: 指向分配的NDArray对象的指针
    47. */
    48. void NDArrayPool::onAllocateArray(NDArray *pArray)
    49. {
    50. }
    51. /** 管理派生自NDArray类的对象的池类的hook。
    52. * 在这个数组已经被保留后,这个hook被调用。
    53. * [in] pArray : 指向被保留的NDArray对象的指针
    54. */
    55. void NDArrayPool::onReserveArray(NDArray *pArray)
    56. {
    57. }
    58. /** 管理派生自NDArray类的对象的池类的hook。
    59. * 在这个数组已经被释放后,这个hook被调用。
    60. * [in] pArray:指向被释放的NDArray对象的指针
    61. */
    62. void NDArrayPool::onReleaseArray(NDArray *pArray)
    63. {
    64. }
    65. /** 分配一个新的NDArray对象,需要前3个参数.
    66. * [in] ndims:这个NDArray中维度数目.
    67. * [in] dims :维度的数组,其尺寸必须至少为ndims.
    68. * [in] dataType : NDArray的数据类型.
    69. * [in] dataSize :为数组数据分配的字节数目 ; 如果0,则alloc将从ndims,
    70. * 如果0,则alloc()将从ndims,dims和dataType计算除所需的尺寸。
    71. * [in] pData : 指向一个数据缓存的指针;如果NULL,则alloc将分配一个新的数组缓存;如果非0,则认为它指向一个有效缓存。
    72. * 如果pData不是NULL,则dataSize必须包含已有数组中实际的字节数目,并且这个数组必须足够大来保存这些数组数据。
    73. * alloc()搜索它的空闲列表来查找一个空闲的NDArray缓存。如果不能找到一个空闲的,则它将分配一个新数组
    74. * 并且添加它到这个空闲列表。如果分配这个NDArray所需的内存将使得为这个池分配的累积内存超过maxMemory,
    75. * 则将返回一个错误。alloc()设置返回的NDArray的引用计数为1.
    76. */
    77. NDArray* NDArrayPool::alloc(int ndims, size_t *dims, NDDataType_t dataType, size_t dataSize, void *pData)
    78. {
    79. NDArray *pArray=NULL;
    80. NDArrayInfo_t arrayInfo;
    81. const char* functionName = "NDArrayPool::alloc:";
    82. epicsMutexLock(listLock_);
    83. // 计算所需的NDArray尺寸
    84. NDArray::computeArrayInfo(ndims, dims, dataType, &arrayInfo); // 根据ndims,dims和dataType获取每个总字节数
    85. if (dataSize == 0) {
    86. dataSize = arrayInfo.totalBytes;
    87. }
    88. std::multiset::iterator pListElement; // freeListElement对象迭代器
    89. // 传入的数组数据未空,从空闲列表中获取一个
    90. if (!pData) {
    91. // 尝试寻找空闲列表中足够大的数组
    92. freeListElement testElement(NULL, dataSize);
    93. pListElement = freeList_.lower_bound(testElement); // dataSize为下限的迭代器,调用一次返回一个freeListElement对象
    94. } else {// 传入的数组数据不为空,则从空闲列表中获取第一个最小的freeListElement对象
    95. // dataSize没关系, pData将被替代.
    96. pListElement = freeList_.begin();
    97. }
    98. if (pListElement == freeList_.end()) {
    99. /* 我们未找到一个足够大的空闲列表,分配一个新数组 */
    100. numBuffers_++; //NDArray对象数目加1
    101. pArray = this->createArray();
    102. } else {
    103. pArray = pListElement->pArray_; //到一个足够大的空闲列表,取出这个NDArray对象
    104. if (pData || (pListElement->dataSize_ > (dataSize * THRESHOLD_SIZE_RATIO))) {
    105. // 我们找到了一个数组,但它太大。设置这个尺寸为0,因而在下面分配它
    106. memorySize_ -= pArray->dataSize;
    107. free(pArray->pData);
    108. pArray->pData = NULL;
    109. }
    110. freeList_.erase(pListElement); //空闲列表从删除这个freeListElement对象
    111. }
    112. /* 初始化字段:设置这个分配这个NDArray对象的NDArrayPool,引用次数,分配这个NDArray的驱动,数组数据类型,数组数据维度数目 */
    113. pArray->pNDArrayPool = this;
    114. pArray->referenceCount = 1;
    115. pArray->pDriver = pDriver_;
    116. pArray->dataType = dataType;
    117. pArray->ndims = ndims;
    118. // 维度数组置0
    119. memset(pArray->dims, 0, sizeof(pArray->dims));
    120. for (int i=0; i
    121. pArray->dims[i].size = dims[i];
    122. pArray->dims[i].offset = 0;
    123. pArray->dims[i].binning = 1;
    124. pArray->dims[i].reverse = 0;
    125. }
    126. /* 如果置位了全局标记,删除这些属性 */
    127. if (eraseNDAttributes) pArray->pAttributeList->clear();
    128. /* 清除codec */
    129. pArray->codec.clear();
    130. /* 到此,pArray存在,但pArray->pData可能是NULL */
    131. /* 如果调用者传递一个有效缓存,使用那个缓存 */
    132. if (pData) {
    133. pArray->pData = pData;
    134. pArray->dataSize = dataSize;
    135. memorySize_ += dataSize;
    136. } else if (pArray->pData == NULL) {
    137. if ((maxMemory_ > 0) && ((memorySize_ + dataSize) > maxMemory_)) {
    138. /*
    139. * 我们没有分配这个数组的足够内存,看我们是否能通过删除数组获取内存
    140. * 首先删除最大的数组,及从freeList_末尾开始。
    141. */
    142. NDArray *freeArray;
    143. std::multiset::iterator it;
    144. // 已用内存+dataSiz大于可用最大内存量,需要释放数组
    145. while (!freeList_.empty() && ((memorySize_ + dataSize) > maxMemory_)) {
    146. it = freeList_.end(); // 获取末尾的freeListElement对象
    147. it--;
    148. freeArray = it->pArray_;
    149. // 从空闲列表中删除获取的freeListElement对象
    150. freeList_.erase(it);
    151. // 内存使用量减少获取的freeListElement对象的dataSize
    152. memorySize_ -= freeArray->dataSize;
    153. // NDArray对象数目减少1
    154. numBuffers_--;
    155. // 释放获取的freeListElement对象
    156. delete freeArray;
    157. }
    158. }
    159. // 如果最大可用内存量有限制并且已用内存量+dataSize大于最大可用内存量
    160. if ((maxMemory_ > 0) && ((memorySize_ + dataSize) > maxMemory_)) {
    161. asynPrint(pDriver_->pasynUserSelf, ASYN_TRACE_ERROR,
    162. "%s: error: reached limit of %ld memory (%d buffers)\n",
    163. functionName, (long)maxMemory_, numBuffers_);
    164. } else {
    165. pArray->pData = malloc(dataSize); // 分配数组数据区
    166. if (pArray->pData) {//分配成功,设置NDArray的dataSize和
    167. pArray->dataSize = dataSize;
    168. pArray->compressedSize = dataSize;
    169. memorySize_ += dataSize; // 内存使用量增加dataSize
    170. }
    171. }
    172. }
    173. // 如果我们没有一个有效内存缓存,设置pArray为NULL来表示错误
    174. if (pArray && (pArray->pData == NULL)) {
    175. delete pArray;
    176. numBuffers_--;
    177. pArray = NULL;
    178. }
    179. // 调用分配hook(用于管理派生自NDArray类的对象的池)
    180. onAllocateArray(pArray);
    181. epicsMutexUnlock(listLock_);
    182. return (pArray);
    183. }
    184. /** 这个方法复制一个NDArray对象。
    185. * [in] pIn :要被复制的输入数组.
    186. * [in] pOut:将被复制到的输出数组;可以是NULL或者一个指向一个已有NDArray的指针。
    187. * [in] copyData:如果这个标记为true,则包括数组数据的所有东西都被复制。如果0, 复制除了数据外(包括属性)的所有东西。
    188. * [in] copyDimensions :如果这个标记为true, 则即使pOut不为NULL,也复制这些维度;默认为true
    189. * [in] copyDataType:如果这个标记为true, 即使pOut不为NULL,也复制dataType, 默认为true
    190. * 返回:返回一个指向输出数组的指针
    191. *
    192. * 如果pOut为NULL,首先分配它。如果输出数组对象已经存在(pOut!=NULL),则必须已经分配足够空间给它来保存数据。
    193. */
    194. NDArray* NDArrayPool::copy(NDArray *pIn, NDArray *pOut, bool copyData, bool copyDimensions, bool copyDataType)
    195. {
    196. //const char *functionName = "copy";
    197. size_t dimSizeOut[ND_ARRAY_MAX_DIMS];
    198. int i;
    199. size_t numCopy;
    200. NDArrayInfo arrayInfo;
    201. /* 如果输出数组不存在,则创建它 */
    202. if (!pOut) {
    203. for (i=0; indims; i++) dimSizeOut[i] = pIn->dims[i].size; // 从输入数组的每个维度获取输出数组每个维度尺寸
    204. pOut = this->alloc(pIn->ndims, dimSizeOut, pIn->dataType, 0, NULL); // 数据类型使用输入数组的数据类型,dataSize取0,则alloc自行计算
    205. if(NULL==pOut) return NULL;
    206. }
    207. // 复制uniqueId, timeStamp,epicsTS
    208. pOut->uniqueId = pIn->uniqueId;
    209. pOut->timeStamp = pIn->timeStamp;
    210. pOut->epicsTS = pIn->epicsTS;
    211. // 如果copyDimensions为true,则复制维度数目以及每个维度上的尺寸
    212. if (copyDimensions) {
    213. pOut->ndims = pIn->ndims;
    214. memcpy(pOut->dims, pIn->dims, sizeof(pIn->dims));
    215. }
    216. // 如果copyDataType为true,则复制数据类型
    217. if (copyDataType) {
    218. pOut->dataType = pIn->dataType;
    219. }
    220. // 复制编码算法名
    221. pOut->codec.name = pIn->codec.name;
    222. // 复制压缩后的尺寸
    223. pOut->compressedSize = pIn->compressedSize;
    224. // 如果copyData为true,
    225. if (copyData) { //
    226. pIn->getInfo(&arrayInfo);
    227. numCopy = pIn->codec.empty() ? arrayInfo.totalBytes : pIn->compressedSize; // codec.empty()为true,表示没有使用压缩算法
    228. if (pOut->dataSize < numCopy) numCopy = pOut->dataSize; //需要复制的数据量取数组数据尺寸和输入数组尺寸中的小者
    229. memcpy(pOut->pData, pIn->pData, numCopy); // 将输入数组中数据区中数据复制到输出数组中数据区
    230. }
    231. pOut->pAttributeList->clear(); // 清除输出数组中属性列表中所有属性
    232. pIn->pAttributeList->copy(pOut->pAttributeList); // 将输入数组中属性列表中所有属性复制到输出数组的属性列表中
    233. return(pOut);
    234. }
    235. /** 这个方法增加这个NDArray对象的引用次数。
    236. * [in] pArray :对这个数组增加引用计数.
    237. * 当一个NDArray被放到一个队列为了之后处理,插件必须调用reserve()。
    238. */
    239. int NDArrayPool::reserve(NDArray *pArray)
    240. {
    241. const char *functionName = "reserve";
    242. /* Make sure we own this array 确认我们拥有这个数组 */
    243. if (pArray->pNDArrayPool != this) {// 这个NDArray对象不是这个NDArrayPool对象分配的
    244. asynPrint(pDriver_->pasynUserSelf, ASYN_TRACE_ERROR,
    245. "%s::%s: ERROR, not owner! owner=%p, should be this=%p\n",
    246. driverName, functionName, pArray->pNDArrayPool, this);
    247. return(ND_ERROR);
    248. }
    249. //asynPrint(pDriver_->pasynUserSelf, ASYN_TRACE_FLOW,
    250. // "NDArrayPool::reserve pArray=%p, count=%d\n", pArray, pArray->referenceCount);
    251. epicsMutexLock(listLock_);
    252. // 如果引用次数少于1,则出问题了,这个NDArray已经被释放了
    253. if (pArray->referenceCount < 1) {
    254. cantProceed("%s:reserve ERROR, reference count = %d, should be >= 1, pArray=%p\n",
    255. driverName, pArray->referenceCount, pArray);
    256. }
    257. pArray->referenceCount++; // 传入NDArray对象的引用次数加1
    258. // 调用保留hook(用于管理派生自NDArray类的对象的池)
    259. onReserveArray(pArray);
    260. epicsMutexUnlock(listLock_);
    261. return ND_SUCCESS;
    262. }
    263. /** 这个方法减小对NDArray对象的引用次数。
    264. * [in] pArray :对这个数组减少引用次数
    265. * 当引用次数到达0,NDArray被放回空闲列表。
    266. * 当一个NDArray被从队列移除并且对其处理结束时,插件必须调用release()。
    267. * 在调用所有插件后,驱动必须调用release()。
    268. */
    269. int NDArrayPool::release(NDArray *pArray)
    270. {
    271. const char *functionName = "release";
    272. /* 确认我们拥有这个数组 */
    273. if (pArray->pNDArrayPool != this) {
    274. asynPrint(pDriver_->pasynUserSelf, ASYN_TRACE_ERROR,
    275. "%s::%s: ERROR, not owner! owner=%p, should be this=%p\n",
    276. driverName, functionName, pArray->pNDArrayPool, this);
    277. return(ND_ERROR);
    278. }
    279. //asynPrint(pDriver_->pasynUserSelf, ASYN_TRACE_FLOW,
    280. // "NDArrayPool::release pArray=%p, count=%d\n", pArray, pArray->referenceCount);
    281. epicsMutexLock(listLock_);
    282. pArray->referenceCount--;// 引用次数减少1
    283. if (pArray->referenceCount == 0) {// 引用次数为0
    284. /* The last user has released this image, add it back to the free list 最后的用户释放这个图像,添加它到空闲列表*/
    285. freeListElement listElement(pArray, pArray->dataSize);
    286. freeList_.insert(listElement);
    287. }
    288. if (pArray->referenceCount < 0) {
    289. cantProceed("%s:release ERROR, reference count < 0 pArray=%p\n",
    290. driverName, pArray);
    291. }
    292. // 调用释放释放hook(用于管理派生自NDArray类的池)
    293. onReleaseArray(pArray);
    294. epicsMutexUnlock(listLock_);
    295. return ND_SUCCESS;
    296. }
    297. // 输入数组数据类型和输出数组数据类型之间的转换
    298. template <typename dataTypeIn, typename dataTypeOut> void convertType(NDArray *pIn, NDArray *pOut)
    299. {
    300. size_t i;
    301. dataTypeIn *pDataIn = (dataTypeIn *)pIn->pData; // 输入数组的数据区
    302. dataTypeOut *pDataOut = (dataTypeOut *)pOut->pData; // 输出数组的数据区
    303. NDArrayInfo_t arrayInfo;
    304. pOut->getInfo(&arrayInfo);
    305. for (i=0; i
    306. *pDataOut++ = (dataTypeOut)(*pDataIn++); // 将输入数组中数据类型转成输出数据中数据类型
    307. }
    308. }
    309. //把输入数组数据类型转成输出数组数据类型
    310. template <typename dataTypeOut> int convertTypeSwitch (NDArray *pIn, NDArray *pOut)
    311. {
    312. int status = ND_SUCCESS;
    313. switch(pIn->dataType) {
    314. case NDInt8:
    315. convertType (pIn, pOut);
    316. break;
    317. case NDUInt8:
    318. convertType (pIn, pOut);
    319. break;
    320. case NDInt16:
    321. convertType (pIn, pOut);
    322. break;
    323. case NDUInt16:
    324. convertType (pIn, pOut);
    325. break;
    326. case NDInt32:
    327. convertType (pIn, pOut);
    328. break;
    329. case NDUInt32:
    330. convertType (pIn, pOut);
    331. break;
    332. case NDInt64:
    333. convertType (pIn, pOut);
    334. break;
    335. case NDUInt64:
    336. convertType (pIn, pOut);
    337. break;
    338. case NDFloat32:
    339. convertType (pIn, pOut);
    340. break;
    341. case NDFloat64:
    342. convertType (pIn, pOut);
    343. break;
    344. default:
    345. status = ND_ERROR;
    346. break;
    347. }
    348. return(status);
    349. }
    350. /*
    351. 1、当输入和输出数组都是一维数组时,dim = 0
    352. 1 2 3 4 5 6 => 1 2 3
    353. */
    354. template <typename dataTypeIn, typename dataTypeOut> void convertDim(NDArray *pIn, NDArray *pOut,
    355. void *pDataIn, void *pDataOut, int dim)
    356. {
    357. dataTypeOut *pDOut = (dataTypeOut *)pDataOut; // 输出数组数据区
    358. dataTypeIn *pDIn = (dataTypeIn *)pDataIn; // 输入数组数据区
    359. /*
    360. size_t size;
    361. size_t offset;
    362. int binning;
    363. int reverse;
    364. */
    365. NDDimension_t *pOutDims = pOut->dims; // 输出数组的维度数组
    366. NDDimension_t *pInDims = pIn->dims; //输入数组的维度数组
    367. size_t inStep, outStep, inOffset;
    368. int inDir;
    369. int i, bin;
    370. size_t inc, in, out;
    371. inStep = 1;
    372. outStep = 1;
    373. inDir = 1;
    374. inOffset = pOutDims[dim].offset;
    375. for (i=0; i// 以dim为1为例子,inStep是输入数组元素数目,outStep是输出数组元素数目
    376. inStep *= pInDims[i].size;
    377. outStep *= pOutDims[i].size;
    378. }
    379. if (pOutDims[dim].reverse) {// 如果输出数组是反向的,输入数组中要取的最后一个元素的偏移
    380. inOffset += pOutDims[dim].size * pOutDims[dim].binning - 1;
    381. inDir = -1; // 表示输入数组反向取
    382. }
    383. inc = inDir * inStep; // 步长
    384. pDIn += inOffset*inStep; // 输入数组数据区取值起始位置
    385. for (in=0, out=0; out// 逐个从输入数组中按顺序取数值进行转换放入输出数组数据区
    386. for (bin=0; bin
    387. if (dim > 0) {
    388. convertDim (pIn, pOut, pDIn, pDOut, dim-1);
    389. } else {
    390. *pDOut += (dataTypeOut)*pDIn;
    391. }
    392. pDIn += inc;
    393. }
    394. pDOut += outStep;
    395. }
    396. }
    397. //
    398. template <typename dataTypeOut> int convertDimensionSwitch(NDArray *pIn, NDArray *pOut,
    399. void *pDataIn, void *pDataOut, int dim)
    400. {
    401. int status = ND_SUCCESS;
    402. switch(pIn->dataType) {
    403. case NDInt8:
    404. convertDim (pIn, pOut, pDataIn, pDataOut, dim);
    405. break;
    406. case NDUInt8:
    407. convertDim (pIn, pOut, pDataIn, pDataOut, dim);
    408. break;
    409. case NDInt16:
    410. convertDim (pIn, pOut, pDataIn, pDataOut, dim);
    411. break;
    412. case NDUInt16:
    413. convertDim (pIn, pOut, pDataIn, pDataOut, dim);
    414. break;
    415. case NDInt32:
    416. convertDim (pIn, pOut, pDataIn, pDataOut, dim);
    417. break;
    418. case NDUInt32:
    419. convertDim (pIn, pOut, pDataIn, pDataOut, dim);
    420. break;
    421. case NDInt64:
    422. convertDim (pIn, pOut, pDataIn, pDataOut, dim);
    423. break;
    424. case NDUInt64:
    425. convertDim (pIn, pOut, pDataIn, pDataOut, dim);
    426. break;
    427. case NDFloat32:
    428. convertDim (pIn, pOut, pDataIn, pDataOut, dim);
    429. break;
    430. case NDFloat64:
    431. convertDim (pIn, pOut, pDataIn, pDataOut, dim);
    432. break;
    433. default:
    434. status = ND_ERROR;
    435. break;
    436. }
    437. return(status);
    438. }
    439. static int convertDimension(NDArray *pIn,
    440. NDArray *pOut,
    441. void *pDataIn,
    442. void *pDataOut,
    443. int dim)
    444. {
    445. int status = ND_SUCCESS;
    446. /* 这个例程被传递:
    447. * 一个指向输入数据起始位置的指针:
    448. * 一个指向输出数据起始位置的指针
    449. * 一个维度的数组
    450. * 维度索引
    451. */
    452. switch(pOut->dataType) {
    453. case NDInt8:
    454. convertDimensionSwitch (pIn, pOut, pDataIn, pDataOut, dim);
    455. break;
    456. case NDUInt8:
    457. convertDimensionSwitch (pIn, pOut, pDataIn, pDataOut, dim);
    458. break;
    459. case NDInt16:
    460. convertDimensionSwitch (pIn, pOut, pDataIn, pDataOut, dim);
    461. break;
    462. case NDUInt16:
    463. convertDimensionSwitch (pIn, pOut, pDataIn, pDataOut, dim);
    464. break;
    465. case NDInt32:
    466. convertDimensionSwitch (pIn, pOut, pDataIn, pDataOut, dim);
    467. break;
    468. case NDUInt32:
    469. convertDimensionSwitch (pIn, pOut, pDataIn, pDataOut, dim);
    470. break;
    471. case NDInt64:
    472. convertDimensionSwitch (pIn, pOut, pDataIn, pDataOut, dim);
    473. break;
    474. case NDUInt64:
    475. convertDimensionSwitch (pIn, pOut, pDataIn, pDataOut, dim);
    476. break;
    477. case NDFloat32:
    478. convertDimensionSwitch (pIn, pOut, pDataIn, pDataOut, dim);
    479. break;
    480. case NDFloat64:
    481. convertDimensionSwitch (pIn, pOut, pDataIn, pDataOut, dim);
    482. break;
    483. default:
    484. status = ND_ERROR;
    485. break;
    486. }
    487. return(status);
    488. }
    489. /** 从一个输入NDArray创建一个新的输出NDArray,执行转换操作。
    490. * 这个函数形式用于仅更改数据类型,不是维度,维度被保留。
    491. * [in] pIn :输入数组,转换的来源.
    492. * [out] ppOut : 输出数组,转换结果。
    493. * [in] dataTypeOut :输出数组的数据类型
    494. */
    495. int NDArrayPool::convert(NDArray *pIn,
    496. NDArray **ppOut,
    497. NDDataType_t dataTypeOut)
    498. {
    499. NDDimension_t dims[ND_ARRAY_MAX_DIMS];
    500. int i;
    501. // 输出数组的维度与输入数组的维度一样
    502. for (i=0; indims; i++) {
    503. dims[i].size = pIn->dims[i].size;
    504. dims[i].offset = 0;
    505. dims[i].binning = 1;
    506. dims[i].reverse = 0;
    507. }
    508. return this->convert(pIn, ppOut, dataTypeOut, dims);
    509. }
    510. /** 从一个输入NDArray创建一个新的输出NDArray,执行转换操作。
    511. * 如果dataTypeout不同于pIn->dataType,转换可以更改数据类型。
    512. * 它也可以更改维度,outDims其每个维度可以有与输入数组维度(pIn->dims)不同的size,binning,offset和reverse的值。
    513. *
    514. * [in] pIn :这个输入数组,转换的来源.
    515. * [out]ppOut:输出数组,转换的结果
    516. * [in] dataTypeOut:输出数组的数据类型
    517. * [in] dimsOut :输出数组的维度.
    518. */
    519. int NDArrayPool::convert(NDArray *pIn,
    520. NDArray **ppOut,
    521. NDDataType_t dataTypeOut,
    522. NDDimension_t *dimsOut)
    523. {
    524. int dimsUnchanged;
    525. size_t dimSizeOut[ND_ARRAY_MAX_DIMS];
    526. NDDimension_t dimsOutCopy[ND_ARRAY_MAX_DIMS];
    527. int i;
    528. NDArray *pOut;
    529. NDArrayInfo_t arrayInfo;
    530. NDAttribute *pAttribute;
    531. int colorMode, colorModeMono = NDColorModeMono;
    532. const char *functionName = "convert";
    533. /* 初始化出错 */
    534. *ppOut = NULL;
    535. /* 不能转换被压缩的数据 */
    536. if (!pIn->codec.empty()) {
    537. fprintf(stderr, "%s:%s: can't convert compressed data [%s]\n",
    538. driverName, functionName, pIn->codec.name.c_str());
    539. return ND_ERROR;
    540. }
    541. /* 因为我们需要修改它,但我们不要影响调用者,复制输入维度数组 */
    542. memcpy(dimsOutCopy, dimsOut, pIn->ndims*sizeof(NDDimension_t)); // 维度数由输入数组的维度数决定
    543. /* 计算输出数组的维度 */
    544. dimsUnchanged = 1;
    545. for (i=0; indims; i++) {
    546. dimsOutCopy[i].size = dimsOutCopy[i].size/dimsOutCopy[i].binning; // 输出数组每个维度的尺寸
    547. if (dimsOutCopy[i].size <= 0) {
    548. asynPrint(pDriver_->pasynUserSelf, ASYN_TRACE_ERROR,
    549. "%s:%s: ERROR, invalid output dimension, size=%d, binning=%d\n",
    550. driverName, functionName, (int)dimsOut[i].size, dimsOut[i].binning);
    551. return(ND_ERROR);
    552. }
    553. dimSizeOut[i] = dimsOutCopy[i].size; // 存储输出数组每一维度的尺寸的数组
    554. if ((pIn->dims[i].size != dimsOutCopy[i].size) || // 只要满足输出数组每个维度上尺寸与输入输入对那个维度不同
    555. (dimsOutCopy[i].offset != 0) || // 或者输出数组每个维度上有偏移量或者有binning或者反向了,则输出维度就发生了变化
    556. (dimsOutCopy[i].binning != 1) ||
    557. (dimsOutCopy[i].reverse != 0)) dimsUnchanged = 0;
    558. }
    559. /* 我们知道了输出数组的数据类型和维度,分配它 */
    560. pOut = alloc(pIn->ndims, dimSizeOut, dataTypeOut, 0, NULL);
    561. *ppOut = pOut;
    562. if (!pOut) {
    563. asynPrint(pDriver_->pasynUserSelf, ASYN_TRACE_ERROR,
    564. "%s:%s: ERROR, cannot allocate output array\n",
    565. driverName, functionName);
    566. return(ND_ERROR);
    567. }
    568. /*从输入NDArray对象复制字段到输出NDArray对象 */
    569. pOut->timeStamp = pIn->timeStamp;
    570. pOut->epicsTS = pIn->epicsTS;
    571. pOut->uniqueId = pIn->uniqueId;
    572. /* 用传递给这个函数的那些维度结构体替换输出NDArray中的dims中存储的维度结构体 */
    573. memcpy(pOut->dims, dimsOutCopy, pIn->ndims*sizeof(NDDimension_t));
    574. pIn->pAttributeList->copy(pOut->pAttributeList);
    575. pOut->getInfo(&arrayInfo);
    576. if (dimsUnchanged) {
    577. if (pIn->dataType == pOut->dataType) {
    578. /*
    579. * 维度相同并且数据类型相同,则仅复制输入图像到输出图像。
    580. */
    581. memcpy(pOut->pData, pIn->pData, arrayInfo.totalBytes);
    582. return ND_SUCCESS;
    583. } else {
    584. /* 我们需要转换数据类型 */
    585. switch(pOut->dataType) {// 根据输出NDArray中数据类型,将输入NDArray中数据转成输出NDArray中数据类型
    586. case NDInt8:
    587. convertTypeSwitch (pIn, pOut);
    588. break;
    589. case NDUInt8:
    590. convertTypeSwitch (pIn, pOut);
    591. break;
    592. case NDInt16:
    593. convertTypeSwitch (pIn, pOut);
    594. break;
    595. case NDUInt16:
    596. convertTypeSwitch (pIn, pOut);
    597. break;
    598. case NDInt32:
    599. convertTypeSwitch (pIn, pOut);
    600. break;
    601. case NDUInt32:
    602. convertTypeSwitch (pIn, pOut);
    603. break;
    604. case NDInt64:
    605. convertTypeSwitch (pIn, pOut);
    606. break;
    607. case NDUInt64:
    608. convertTypeSwitch (pIn, pOut);
    609. break;
    610. case NDFloat32:
    611. convertTypeSwitch (pIn, pOut);
    612. break;
    613. case NDFloat64:
    614. convertTypeSwitch (pIn, pOut);
    615. break;
    616. default:
    617. //status = ND_ERROR;
    618. break;
    619. }
    620. }
    621. } else {
    622. /* 对整个输出NDArray的数据清零 */
    623. memset(pOut->pData, 0, arrayInfo.totalBytes);
    624. convertDimension(pIn, pOut, pIn->pData, pOut->pData, pIn->ndims-1);
    625. }
    626. /* 设置输出数组中的字段 */
    627. for (i=0; indims; i++) {
    628. pOut->dims[i].offset = pIn->dims[i].offset + dimsOutCopy[i].offset;
    629. pOut->dims[i].binning = pIn->dims[i].binning * dimsOutCopy[i].binning;
    630. if (pIn->dims[i].reverse) pOut->dims[i].reverse = !pOut->dims[i].reverse;
    631. }
    632. /*
    633. * 如果帧是RGBx帧,并且我们折叠那个维度,则更改颜色模式
    634. */
    635. pAttribute = pOut->pAttributeList->find("ColorMode");
    636. if (pAttribute && pAttribute->getValue(NDAttrInt32, &colorMode)) {
    637. if ((colorMode == NDColorModeRGB1) && (pOut->dims[0].size != 3))
    638. pAttribute->setValue(&colorModeMono);
    639. else if ((colorMode == NDColorModeRGB2) && (pOut->dims[1].size != 3))
    640. pAttribute->setValue(&colorModeMono);
    641. else if ((colorMode == NDColorModeRGB3) && (pOut->dims[2].size != 3))
    642. pAttribute->setValue(&colorModeMono);
    643. }
    644. return ND_SUCCESS;
    645. }
    646. /** 返回这个对象当分配的缓存数目 */
    647. int NDArrayPool::getNumBuffers()
    648. {
    649. return numBuffers_;
    650. }
    651. /** 0=unlimited 返回允许这个对象分配的最大内存字节 */
    652. size_t NDArrayPool::getMaxMemory()
    653. {
    654. return maxMemory_;
    655. }
    656. /** 返回这个对象当前已经分配的内存字节数 */
    657. size_t NDArrayPool::getMemorySize()
    658. {
    659. return memorySize_;
    660. }
    661. /** 返回空闲列表中NDArray对象的数目 */
    662. int NDArrayPool::getNumFree()
    663. {
    664. epicsMutexLock(listLock_);
    665. int size = (int)freeList_.size();
    666. epicsMutexUnlock(listLock_);
    667. return size;
    668. }
    669. /** 删除空闲列表中所有NDArrays */
    670. void NDArrayPool::emptyFreeList()
    671. {
    672. NDArray *freeArray;
    673. std::multiset::iterator it; // 获取freeListElement对象的迭代器
    674. epicsMutexLock(listLock_);
    675. while (!freeList_.empty()) {
    676. it = freeList_.begin(); // 获取第一个freeListElement对象
    677. freeArray = it->pArray_; // 获取NDArray对象
    678. freeList_.erase(it); // 从空闲列表中删除
    679. memorySize_ -= freeArray->dataSize;
    680. numBuffers_--;
    681. delete freeArray;
    682. }
    683. epicsMutexUnlock(listLock_);
    684. }
    685. /** 报告NDArrayPool空闲列表尺寸和其它性质。
    686. * [in] fp : 报告输出的文件指针
    687. * [in] details : 所要报告的详细程度,当前什么也没做.
    688. */
    689. int NDArrayPool::report(FILE *fp, int details)
    690. {
    691. fprintf(fp, "\n");
    692. fprintf(fp, "NDArrayPool:\n");
    693. fprintf(fp, " numBuffers=%d, numFree=%d\n",
    694. numBuffers_, this->getNumFree()); // 缓存数量,还可分配的内存
    695. fprintf(fp, " memorySize=%ld, maxMemory=%ld\n",
    696. (long)memorySize_, (long)maxMemory_); //已用内存数,最大内存分配数量
    697. if (details > 5) { // 每个NDArray的信息:NDArray序号,NDArray数据区的尺寸,以及NDArray的地址
    698. int i;
    699. std::multiset::iterator it;
    700. NDArray *freeArray;
    701. fprintf(fp, " freeList: (index, dataSize, pArray)\n");
    702. epicsMutexLock(listLock_);
    703. for (it=freeList_.begin(),i=0; it!=freeList_.end(); ++it,i++) {
    704. fprintf(fp, " %d %d %p\n", i, (int)it->dataSize_, it->pArray_);
    705. }
    706. // 每个NDArray的详细信息: NDArray对象的地址 DArray对象的维度数目
    707. // NDArray对象每个维度的元素数目 数据类型,数据尺寸,数据地址 唯一id,时间戳 引用计数 属性数目 每个属性信息
    708. if (details > 10) {
    709. for (it=freeList_.begin(); it!=freeList_.end(); ++it) {
    710. freeArray = it->pArray_;
    711. fprintf(fp, " Array %d\n", i);
    712. freeArray->report(fp, details);
    713. }
    714. }
    715. epicsMutexUnlock(listLock_);
    716. }
    717. return ND_SUCCESS;
    718. }

    NDArrayPool类中方法的测试:

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #include
    9. #include
    10. #include
    11. #include
    12. #include "asynNDArrayDriver.h"
    13. #include "NDArray.h"
    14. int main()
    15. {
    16. // NDArrayPool::NDArrayPool(class asynNDArrayDriver *pDriver, size_t maxMemory)
    17. printf("***********Test NDArrayPool construct:*********************\n");
    18. NDArrayPool * pPool = new NDArrayPool(NULL, 10000);
    19. printf("NDArrayPool information:\n");
    20. pPool->report(stdout, 11);
    21. printf("*************************************************************\n");
    22. printf("**********************Test NDArrayPool::alloc:***************\n");
    23. size_t dims[2] = {2,3};
    24. int ndims = 2;
    25. NDArray * pArray = pPool->alloc(ndims, dims, NDInt32, 0, NULL);
    26. printf("NDArray Information:\n");
    27. pArray->report(stdout, 11);
    28. printf("NDArrayPool information:\n");
    29. pPool->report(stdout , 11);
    30. printf("*************************************************************\n");
    31. printf("********************Test NDArrayPool::copy:*****************\n");
    32. NDArrayInfo_t info;
    33. pArray->getInfo(&info);
    34. size_t i;
    35. size_t j;
    36. printf("Set Value for pArray:\n");
    37. epicsInt32* pArr = (epicsInt32 *)pArray->pData;
    38. for (i = 0; i < info.nElements; i++){
    39. pArr[i] = i;
    40. }
    41. printf("copy a new NDArray from pArray:\n");
    42. NDArray * pArrayout = pPool->copy(pArray, NULL, true, true, true);
    43. pArrayout->getInfo(&info);
    44. pArr = (epicsInt32 *)pArrayout->pData;
    45. printf("xDim = %d, yDim = %d, xSize = %lu, ySize = %lu\n", info.xDim, info.yDim, info.xSize, info.ySize);
    46. printf("output the values from the new NDArray:\n");
    47. for (i = 0; i < info.ySize; i++){
    48. for (j = 0; j < info.xSize; j++){
    49. printf("%d\t", pArr[i * info.xSize + j]);
    50. }
    51. printf("\n");
    52. }
    53. printf("\n");
    54. printf("New created pArrayout information:\n");
    55. pArrayout->report(stdout, 11);
    56. printf("NDArrayPool information:\n");
    57. pPool->report(stdout ,11);
    58. printf("*************************************************************\n");
    59. printf("**********************Test NDArrayPool::reserve**************\n");
    60. pPool->reserve(pArray);
    61. printf("NDArray Information:\n");
    62. pArray->report(stdout, 11);
    63. printf("*************************************************************\n");
    64. printf("**********************Test NDArrayPool:release**************\n");
    65. printf("New created pArrayout information:\n");
    66. pPool->release(pArrayout);
    67. pPool->report(stdout ,11);
    68. printf("*************************************************************\n");
    69. printf("Use NDArrayPool::alloc to allocate a new NDArray:*************\n");
    70. dims[0] = 3;
    71. dims[1] = 2;
    72. printf("NDArrayPool Information:\n");
    73. NDArray * pArrayOut = pPool->alloc(ndims, dims, NDFloat64, 0, NULL);
    74. pArrayOut->report(stdout, 11);
    75. printf("*************************************************************\n");
    76. printf("**********************Use NArrayPool::convert***************\n");
    77. NDArray * pnewNDArray = NULL;
    78. //int NDArrayPool::convert(NDArray *pIn, NDArray **ppOut, NDDataType_t dataTypeOut, NDDimension_t *dimsOut)
    79. pPool->convert(pArray, &pnewNDArray, NDFloat64, pArrayOut->dims);
    80. pnewNDArray->report(stdout, 11);
    81. epicsFloat64 * pf64 = (epicsFloat64 *)pnewNDArray->pData;
    82. pnewNDArray->getInfo(&info);
    83. printf("xDim = %d, yDim = %d, xSize = %lu, ySize = %lu\n", info.xDim, info.yDim, info.xSize, info.ySize);
    84. for (i = 0; i < info.ySize; i++){
    85. for (j = 0; j < info.xSize; j++){
    86. printf("%f\t", pf64[j + info.xSize * i]);
    87. }
    88. printf("\n");
    89. }
    90. printf("*************************************************************\n");
    91. pPool->report(stdout, 11);
    92. return 0;
    93. }

    测试结果如下:

    1. orangepi@orangepi5:~/C_program/host_program/hostApp$ O.linux-aarch64/testNDArrayPool
    2. ***********Test NDArrayPool construct:*********************
    3. NDArrayPool information:
    4. NDArrayPool:
    5. numBuffers=0, numFree=0
    6. memorySize=0, maxMemory=10000
    7. freeList: (index, dataSize, pArray)
    8. *************************************************************
    9. **********************Test NDArrayPool::alloc:***************
    10. NDArray Information:
    11. NDArray Array address=0x558d2d9090:
    12. ndims=2 dims=[2 3 ]
    13. dataType=4, dataSize=24, pData=0x558d2d92d0
    14. uniqueId=0, timeStamp=0.000000, epicsTS.secPastEpoch=0, epicsTS.nsec=0
    15. referenceCount=1
    16. number of attributes=0
    17. NDAttributeList: address=0x558d2d9230:
    18. number of attributes=0
    19. NDArrayPool information:
    20. NDArrayPool:
    21. numBuffers=1, numFree=0
    22. memorySize=24, maxMemory=10000
    23. freeList: (index, dataSize, pArray)
    24. *************************************************************
    25. ********************Test NDArrayPool::copy:*****************
    26. Set Value for pArray:
    27. copy a new NDArray from pArray:
    28. xDim = 0, yDim = 1, xSize = 2, ySize = 3
    29. output the values from the new NDArray:
    30. 0 1
    31. 2 3
    32. 4 5
    33. New created pArrayout information:
    34. NDArray Array address=0x558d2d9310:
    35. ndims=2 dims=[2 3 ]
    36. dataType=4, dataSize=24, pData=0x558d2d92f0
    37. uniqueId=0, timeStamp=0.000000, epicsTS.secPastEpoch=0, epicsTS.nsec=0
    38. referenceCount=1
    39. number of attributes=0
    40. NDAttributeList: address=0x558d2d94b0:
    41. number of attributes=0
    42. NDArrayPool information:
    43. NDArrayPool:
    44. numBuffers=2, numFree=0
    45. memorySize=48, maxMemory=10000
    46. freeList: (index, dataSize, pArray)
    47. *************************************************************
    48. **********************Test NDArrayPool::reserve**************
    49. NDArray Information:
    50. NDArray Array address=0x558d2d9090:
    51. ndims=2 dims=[2 3 ]
    52. dataType=4, dataSize=24, pData=0x558d2d92d0
    53. uniqueId=0, timeStamp=0.000000, epicsTS.secPastEpoch=0, epicsTS.nsec=0
    54. referenceCount=2
    55. number of attributes=0
    56. NDAttributeList: address=0x558d2d9230:
    57. number of attributes=0
    58. *************************************************************
    59. **********************Test NDArrayPool:release**************
    60. New created pArrayout information:
    61. NDArrayPool:
    62. numBuffers=2, numFree=1
    63. memorySize=48, maxMemory=10000
    64. freeList: (index, dataSize, pArray)
    65. 0 24 0x558d2d9310
    66. Array 1
    67. NDArray Array address=0x558d2d9310:
    68. ndims=2 dims=[2 3 ]
    69. dataType=4, dataSize=24, pData=0x558d2d92f0
    70. uniqueId=0, timeStamp=0.000000, epicsTS.secPastEpoch=0, epicsTS.nsec=0
    71. referenceCount=0
    72. number of attributes=0
    73. NDAttributeList: address=0x558d2d94b0:
    74. number of attributes=0
    75. *************************************************************
    76. Use NDArrayPool::alloc to allocate a new NDArray:*************
    77. NDArrayPool Information:
    78. NDArray Array address=0x558d2d95b0:
    79. ndims=2 dims=[3 2 ]
    80. dataType=9, dataSize=48, pData=0x558d2d97f0
    81. uniqueId=0, timeStamp=0.000000, epicsTS.secPastEpoch=0, epicsTS.nsec=0
    82. referenceCount=1
    83. number of attributes=0
    84. NDAttributeList: address=0x558d2d9750:
    85. number of attributes=0
    86. *************************************************************
    87. **********************Use NArrayPool::convert***************
    88. NDArray Array address=0x558d2d9830:
    89. ndims=2 dims=[3 2 ]
    90. dataType=9, dataSize=48, pData=0x558d2d9a70
    91. uniqueId=0, timeStamp=0.000000, epicsTS.secPastEpoch=0, epicsTS.nsec=0
    92. referenceCount=1
    93. number of attributes=0
    94. NDAttributeList: address=0x558d2d99d0:
    95. number of attributes=0
    96. xDim = 0, yDim = 1, xSize = 3, ySize = 2
    97. 0.000000 1.000000 2.000000
    98. 2.000000 3.000000 4.000000
    99. *************************************************************
    100. NDArrayPool:
    101. numBuffers=4, numFree=1
    102. memorySize=144, maxMemory=10000
    103. freeList: (index, dataSize, pArray)
    104. 0 24 0x558d2d9310
    105. Array 1
    106. NDArray Array address=0x558d2d9310:
    107. ndims=2 dims=[2 3 ]
    108. dataType=4, dataSize=24, pData=0x558d2d92f0
    109. uniqueId=0, timeStamp=0.000000, epicsTS.secPastEpoch=0, epicsTS.nsec=0
    110. referenceCount=0
    111. number of attributes=0
    112. NDAttributeList: address=0x558d2d94b0:
    113. number of attributes=0

  • 相关阅读:
    LabVIEW如何修复或重置NI MAX数据库文件
    Job 和 DaemonSet
    web安全渗透
    Facebook的创新实验室:人工智能与新技术探索
    热门项目!知识付费小程序源码系统 带完整的安装代码包以及安装部署教程
    Java架构师设计思想
    【Python】Python环境安装与简单代码运行
    在kubernetes中部署kubersphere
    【Unity3D】拖尾TrailRenderer
    高级Shopify主题开发教程
  • 原文地址:https://blog.csdn.net/yuyuyuliang00/article/details/133692126