层级数据格式(Hierarchical Data Format:HDF)是设计用来存储和组织大量数据的一组文件格式(HDF4,HDF5)。它最初开发于美国国家超级计算应用中心,现在由非营利社团HDF Group支持,其任务是确保HDF5技术的持续开发和存储在HDF中数据的持续可访问性。
hdf5 github https://github.com/HDFGroup/hdf5
hdf5 下载页 https://support.hdfgroup.org/ftp/HDF5/releases/
官方入门文档 https://docs.hdfgroup.org/hdf5/v1_14/_intro_h_d_f5.html
官方文档部分中文翻译 https://zhuanlan.zhihu.com/p/656178708
HDF5由以下几个部分组成:
(1)一个可以存储HDF5数据的文件格式。
(2)一个可以在应用中组织和访问HDF5数据的数据模型。
(3)一些相关软件(库、编程接口和工具)。
在linux命令行中执行下面两个命令
sudo apt install hdf5-helpers
sudo apt-get install libhdf5-serial-dev
然后就可以使用h5cc
命令了,用法类似于gcc
现有一个示例C语言文件 h5_write.c
,功能为创建一个名为"SDS.h5"的HDF5文件,在其中创建一个名为"IntArray"的数据集,并写入一个5x6的二维整型数组
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Copyright by The HDF Group. *
* All rights reserved. *
* *
* This file is part of HDF5. The full HDF5 copyright notice, including *
* terms governing use, modification, and redistribution, is contained in *
* the COPYING file, which can be found at the root of the source code *
* distribution tree, or in https://www.hdfgroup.org/licenses. *
* If you do not have access to either file, you may request a copy from *
* help@hdfgroup.org. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*
* This example writes data to the HDF5 file.
* Data conversion is performed during write operation.
*/
#include "hdf5.h"
#define H5FILE_NAME "SDS.h5"
#define DATASETNAME "IntArray"
#define NX 5 /* dataset dimensions */
#define NY 6
#define RANK 2
int
main(void)
{
hid_t file, dataset; /* file and dataset handles */
hid_t datatype, dataspace; /* handles */
hsize_t dimsf[2]; /* dataset dimensions */
herr_t status;
int data[NX][NY]; /* data to write */
int i, j;
/*
* Data and output buffer initialization.
*/
for (j = 0; j < NX; j++)
for (i = 0; i < NY; i++)
data[j][i] = i + j;
/*
* 0 1 2 3 4 5
* 1 2 3 4 5 6
* 2 3 4 5 6 7
* 3 4 5 6 7 8
* 4 5 6 7 8 9
*/
/*
* Create a new file using H5F_ACC_TRUNC access,
* default file creation properties, and default file
* access properties.
*/
file = H5Fcreate(H5FILE_NAME, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);
/*
* Describe the size of the array and create the data space for fixed
* size dataset.
*/
dimsf[0] = NX;
dimsf[1] = NY;
dataspace = H5Screate_simple(RANK, dimsf, NULL);
/*
* Define datatype for the data in the file.
* We will store little endian INT numbers.
*/
datatype = H5Tcopy(H5T_NATIVE_INT);
status = H5Tset_order(datatype, H5T_ORDER_LE);
/*
* Create a new dataset within the file using defined dataspace and
* datatype and default dataset creation properties.
*/
dataset = H5Dcreate2(file, DATASETNAME, datatype, dataspace, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
/*
* Write the data to the dataset using default transfer properties.
*/
status = H5Dwrite(dataset, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, data);
/*
* Close/release resources.
*/
H5Sclose(dataspace);
H5Tclose(datatype);
H5Dclose(dataset);
H5Fclose(file);
return 0;
}
然后就可以编译这个C语言源代码
h5cc h5_write.c -o h5_write
将会在当前目录下生成一个名为h5_write
的可执行文件,执行h5_write
又会生成一个名为"SDS.h5"的HDF5文件
将之前的应用文件进行了修改,原本是写入为txt文件,现在修改为写入成h5文件
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <fcntl.h>
#include <string.h>
#include <sys/ioctl.h>
#include <time.h>
#include <sys/time.h>
#include "hdf5.h" // 添加HDF5头文件
#define ADC_IOCTL_MAGIC 'M'
#define CMD_GET_DMADATA _IO(ADC_IOCTL_MAGIC, 0)
#define CMD_SET_START _IO(ADC_IOCTL_MAGIC, 1)
#define ADC_SIZE (8*1024 * 1024)
#define DATASETNAME "DMAData"
#define H5FILE_NAME "/nvme/DMAData.h5" // 指定HDF5文件的完整路径
double calculate_elapsed_time(struct timeval start, struct timeval end) {
return (end.tv_sec - start.tv_sec) + (end.tv_usec - start.tv_usec) / 1000000.0;
}
int main()
{
printf("init\n");
int fd; // 文件描述符
int ret = 0; // 返回值
uint16_t* data = (uint16_t*) malloc(ADC_SIZE); // 更改为uint16_t*
int start = 1; // 控制 DMA 数据传输的标志
struct timeval start_time, end_time;
double total_time = 0;
size_t total_data_written = 0;
// 打开 DMA 设备文件
fd = open("/dev/adcdma_0", O_RDWR);
if (fd < 0)
{
printf("Can't open file adcdma_0\n");
return -1;
}
printf("open file adcdma_0\n");
// 启动 DMA 数据传输
ioctl(fd, CMD_SET_START, &start);
gettimeofday(&start_time, NULL); // 开始时间
// 创建 HDF5 文件
hid_t file = H5Fcreate(H5FILE_NAME, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);
if (file < 0)
{
printf("Failed to create HDF5 file.\n");
return -1;
}
while (1)
{
// 从 DMA 设备中读取数据
ret = ioctl(fd, CMD_GET_DMADATA, data);
if (ret < 0)
{
perror("Get data error\n");
break;
}
// 将数据写入 HDF5 文件
{
hid_t dataset; // 数据集句柄
hid_t dataspace; // 数据空间句柄
hsize_t dims[1] = {ADC_SIZE / sizeof(uint16_t)}; // 数据集尺寸
// 创建数据空间
dataspace = H5Screate_simple(1, dims, NULL);
// 如果数据集不存在,则创建新的数据集
if (H5Lexists(file, DATASETNAME, H5P_DEFAULT) <= 0)
{
dataset = H5Dcreate2(file, DATASETNAME, H5T_NATIVE_UINT16, dataspace, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
}
else
{
// 如果数据集已存在,则打开它
dataset = H5Dopen2(file, DATASETNAME, H5P_DEFAULT);
}
// 写入数据
herr_t status = H5Dwrite(dataset, H5T_NATIVE_UINT16, H5S_ALL, H5S_ALL, H5P_DEFAULT, data);
// 关闭资源
H5Sclose(dataspace);
H5Dclose(dataset);
}
total_data_written += ADC_SIZE;
gettimeofday(&end_time, NULL); // 当前时间
total_time = calculate_elapsed_time(start_time, end_time);
printf("Write speed: %.2f MB/s\n", total_data_written / (1024.0 * 1024.0) / total_time);
}
// 停止 DMA 数据传输
start = 0;
ioctl(fd, CMD_SET_START, &start);
// 关闭 HDF5 文件
H5Fclose(file);
// 关闭 DMA 设备文件
close(fd);
free(data); // 释放分配的内存
return ret;
}
dma传输写入h5文件速度测试得120MB/s
dma传输写入txt文件速度为90MB/s
(不使用dma传输)直接向txt文件写数据速度则可达300MB/s
可以提速的方向:DMA传输过程,硬盘写入过程
本文章使用limfx的vscode插件快速发布