HDF5入门

什么是HDF5

层级数据格式(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/

Introduction to HDF5

官方入门文档 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下使用HDF5-C语言接口编程

在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文件

DMA传输数据写入为h5文件

将之前的应用文件进行了修改,原本是写入为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插件快速发布