
/*

   This program illustrates the performance problem with
   using a 1D memory dataspace with a 4D dataset.  If you
   use a 4D memory dataspace with the 4D dataset, the
   performance is much better.

   This is a known issue with HDF5.

*/

#include "hdf5.h"
#include <sys/time.h>

#define difference(a, b, result)\
        do {                            \
        (result).tv_sec = (a).tv_sec - (b).tv_sec; \
        (result).tv_usec = (a).tv_usec - (b).tv_usec;  \
        if ((result).tv_usec < 0) {  \
                --(result).tv_sec;   \
                (result).tv_usec += 1000000; \
                } \
        } while (0)

#define     NbrSamples  5000        
#define     NbrSegments  100        
#define     NbrBufs  10         
#define     NbrWrites  10      

float DataBuffer[NbrSamples*NbrSegments];

int main()
{
     int mdc_nelmts;
     size_t rdcc_nelmts;
     size_t rdcc_nbytes;
     double rdcc_w0;
     hsize_t ChunkDims[4];
     struct timeval start, finish;
     struct timeval diff;
     double total;
     hid_t file_idChunked, fapl_idChunked, fcpl_idChunked;
     herr_t status;
     hsize_t DataDims[4];
     hsize_t UBsize = 512;
     const char *filenameChunked = "h5p.h5";
     hid_t DataPlistChunked, FileDSpace; 
     hid_t DSetChunked, BufferDSpace;

/* This line will also have to be changed to see the
   difference in performance for a 1D memory dataspace:
     hsize_t BufferDim[1];
*/
     hsize_t BufferDim[4];

     hsize_t  offset_file[4];
     hsize_t  count_file[4];
     int i;


     /*chunk dimensions */
     ChunkDims[0]=1;
     ChunkDims[1]=1;
     ChunkDims[2]=NbrSegments;
     ChunkDims[3]=NbrSamples;

     for (i = 0; i < (NbrSamples*NbrSegments); i++)
        DataBuffer[i] = 1.25 + i;

     gettimeofday(&start, NULL);

     fcpl_idChunked = H5Pcreate(H5P_FILE_CREATE);
     status = H5Pset_userblock(fcpl_idChunked, UBsize);

     /* create/modify file access property list */
     fapl_idChunked = H5Pcreate(H5P_FILE_ACCESS);
 

     status = H5Pget_cache (fapl_idChunked, &mdc_nelmts, &rdcc_nelmts, 
                            &rdcc_nbytes, &rdcc_w0);

     rdcc_nbytes = ChunkDims[2]*ChunkDims[3]*2*sizeof(float);
     
     status = H5Pset_cache (fapl_idChunked, mdc_nelmts, rdcc_nelmts, 
                            rdcc_nbytes, rdcc_w0);

     file_idChunked = H5Fcreate (filenameChunked, H5F_ACC_TRUNC, 
                                 fcpl_idChunked, fapl_idChunked);

/* Use Default set_cache value
     file_idChunked = H5Fcreate (filenameChunked, H5F_ACC_TRUNC, 
                                 fcpl_idChunked, H5P_DEFAULT);
*/

     /*create Dataset */
     DataDims[0]=NbrWrites;
     DataDims[1]=NbrBufs;
     DataDims[2]=NbrSegments;
     DataDims[3]=NbrSamples;

     DataPlistChunked  = H5Pcreate(H5P_DATASET_CREATE);
     status = H5Pset_chunk (DataPlistChunked, 4, ChunkDims);

     FileDSpace = H5Screate_simple(4, DataDims, NULL);

     DSetChunked = H5Dcreate (file_idChunked, "/Data", H5T_NATIVE_FLOAT, 
                              FileDSpace, DataPlistChunked);

     for (int w = 0; w < NbrWrites; w++)
     {
        for (int b = 0; b < NbrBufs; b++)
        {

/* This causes a performance problem!  This is here in case you would 
   like to see the difference in performance when you use a 1D memory 
   dataspace rather than a 4D dataspace 
            BufferDim[0]=NbrSegments*NbrSamples;
            BufferDSpace = H5Screate_simple(1, BufferDim, NULL);
*/

            BufferDim[0]=1;
            BufferDim[1]=1;
            BufferDim[2]=NbrSegments;
            BufferDim[3] = NbrSamples;
            BufferDSpace = H5Screate_simple(4, BufferDim, NULL);

            offset_file[0] = w;
            offset_file[1] = b;
            offset_file[2] = 0;
            offset_file[3] = 0;

            count_file[0] = 1;
            count_file[1] = 1;
            count_file[2] = NbrSegments;
            count_file[3] = NbrSamples;

            status = H5Sselect_hyperslab (FileDSpace, H5S_SELECT_SET, 
                           offset_file, NULL, count_file, NULL);

            status= H5Dwrite (DSetChunked, H5T_NATIVE_FLOAT, BufferDSpace, 
                          FileDSpace, H5P_DEFAULT, DataBuffer);
            status = H5Sclose(BufferDSpace);
         }
     }

     status = H5Dclose(DSetChunked);
     status = H5Sclose(FileDSpace);
     status = H5Pclose(DataPlistChunked);
     status = H5Fclose(file_idChunked);

     gettimeofday(&finish, NULL);
     difference(finish, start, diff);
     total = ((double)diff.tv_sec+(double)diff.tv_usec/(double)1000000.0);
     printf (" %lf       \n", total);
}
