225 lines
		
	
	
		
			7.8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			225 lines
		
	
	
		
			7.8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /**
 | |
|  * \file    utils.hpp
 | |
|  * \brief   Utilities header
 | |
|  *
 | |
|  * \author
 | |
|  *    Christos Choutouridis AEM:8997
 | |
|  *    <cchoutou@ece.auth.gr>
 | |
|  */
 | |
| #ifndef UTILS_HPP_
 | |
| #define UTILS_HPP_
 | |
| 
 | |
| #include <iostream>
 | |
| #include <chrono>
 | |
| #include <unistd.h>
 | |
| #include <hdf5.h>
 | |
| 
 | |
| #include "matrix.hpp"
 | |
| #include "config.h"
 | |
| 
 | |
| /*!
 | |
|  * A Logger for entire program.
 | |
|  */
 | |
| struct Log {
 | |
|    struct Endl {} endl;    //!< a tag object to to use it as a new line request.
 | |
| 
 | |
|    //! We provide logging via << operator
 | |
|    template<typename T>
 | |
|    Log& operator<< (T&& t) {
 | |
|       if (session.verbose) {
 | |
|          if (line_) {
 | |
|             std::cout << "[Log]: " << t;
 | |
|             line_ = false;
 | |
|          }
 | |
|          else
 | |
|             std::cout << t;
 | |
|       }
 | |
|       return *this;
 | |
|    }
 | |
|    // overload for special end line handling
 | |
|    Log& operator<< (Endl e) { (void)e;
 | |
|       if (session.verbose) {
 | |
|          std::cout << '\n';
 | |
|          line_ = true;
 | |
|       }
 | |
|       return *this;
 | |
|    }
 | |
| private:
 | |
|    bool line_ {true};
 | |
| };
 | |
| 
 | |
| extern Log logger;
 | |
| 
 | |
| /*!
 | |
|  * A small timing utility based on chrono.
 | |
|  */
 | |
| struct Timing{
 | |
|    using Tpoint = std::chrono::steady_clock::time_point;
 | |
|    using microseconds = std::chrono::microseconds;
 | |
|    using milliseconds = std::chrono::milliseconds;
 | |
|    using seconds = std::chrono::seconds;
 | |
| 
 | |
|    //! tool to mark the starting point
 | |
|    Tpoint start () noexcept { return start_ = std::chrono::steady_clock::now(); }
 | |
|    //! tool to mark the ending point
 | |
|    Tpoint stop ()  noexcept { return stop_ = std::chrono::steady_clock::now(); }
 | |
| 
 | |
|    auto dt () noexcept {
 | |
|       return std::chrono::duration_cast<std::chrono::microseconds>(stop_ - start_).count();
 | |
|    }
 | |
|    //! tool to print the time interval
 | |
|    void print_dt (const char* what) noexcept {
 | |
|       if (session.timing) {
 | |
|          auto t = stop_ - start_;
 | |
|          if       (std::chrono::duration_cast<microseconds>(t).count() < 10000)
 | |
|             std::cout << "[Timing]: " << what << ": " << std::to_string(std::chrono::duration_cast<microseconds>(t).count()) << " [usec]\n";
 | |
|          else if (std::chrono::duration_cast<milliseconds>(t).count() < 10000)
 | |
|             std::cout << "[Timing]: " << what << ": " << std::to_string(std::chrono::duration_cast<milliseconds>(t).count()) << " [msec]\n";
 | |
|          else
 | |
|             std::cout << "[Timing]: " << what << ": " << std::to_string(std::chrono::duration_cast<seconds>(t).count()) << " [sec]\n";
 | |
|       }
 | |
|    }
 | |
| private:
 | |
|    Tpoint start_;
 | |
|    Tpoint stop_;
 | |
| };
 | |
| 
 | |
| 
 | |
| 
 | |
| struct Mtx {
 | |
| 
 | |
|    template<typename MatrixType, HDF5_type Type>
 | |
|    static void load(const std::string& filename, const std::string& dataset, MatrixType& matrix) {
 | |
| 
 | |
|       hid_t file_id{}, dataset_id{}, dataspace_id{};
 | |
|       herr_t read_st;
 | |
|       do {
 | |
|          // Open file
 | |
|          logger << "Load HDF5 file: " << filename << " Dataset: " << dataset << "...";
 | |
|          if ((file_id = H5Fopen(filename.c_str(), H5F_ACC_RDONLY, H5P_DEFAULT)) < 0)
 | |
|             break;
 | |
| 
 | |
|          // Open dataset
 | |
|          if ((dataset_id = H5Dopen2(file_id, dataset.c_str(), H5P_DEFAULT)) < 0)
 | |
|             break;
 | |
| 
 | |
|          // Get dataspace and allocate memory for read buffer
 | |
|          if ((dataspace_id = H5Dget_space(dataset_id)) < 0)
 | |
|             break;
 | |
|          hsize_t dims[2];
 | |
|          H5Sget_simple_extent_dims(dataspace_id, dims, NULL);
 | |
|          matrix.resize(dims[0], dims[1]);
 | |
| 
 | |
|          // Read the dataset
 | |
|          // ToDo: Come up with a better way to do this
 | |
|          if constexpr (Type == HDF5_type::DOUBLE) {
 | |
|             if ((read_st = H5Dread(dataset_id, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, H5P_DEFAULT, matrix.data())) < 0)
 | |
|                break;
 | |
|          }
 | |
|          else if (Type == HDF5_type::FLOAT) {
 | |
|             if ((read_st = H5Dread(dataset_id, H5T_NATIVE_FLOAT, H5S_ALL, H5S_ALL, H5P_DEFAULT, matrix.data())) < 0)
 | |
|                break;
 | |
|          }
 | |
|          else if (Type == HDF5_type::UINT) {
 | |
|             if ((read_st = H5Dread(dataset_id, H5T_NATIVE_UINT, H5S_ALL, H5S_ALL, H5P_DEFAULT, matrix.data())) < 0)
 | |
|                break;
 | |
|          }
 | |
|          else if (Type == HDF5_type::INT) {
 | |
|             if ((read_st = H5Dread(dataset_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, matrix.data())) < 0)
 | |
|                break;
 | |
|          }
 | |
|          // Done
 | |
|          H5Dclose(dataset_id);
 | |
|          H5Sclose(dataspace_id);
 | |
|          H5Fclose(file_id);
 | |
|          logger << " Done" << logger.endl;
 | |
|          return;
 | |
|       } while (0);
 | |
| 
 | |
|       // Error: close everything (if possible) and return false
 | |
|       H5Dclose(dataset_id);
 | |
|       H5Sclose(dataspace_id);
 | |
|       H5Fclose(file_id);
 | |
|       throw std::runtime_error("Cannot store to " + filename + " dataset:" + dataset + '\n');
 | |
|    }
 | |
| 
 | |
| 
 | |
|    template<typename MatrixType, HDF5_type Type>
 | |
|    static void store(const std::string& filename, const std::string& dataset, MatrixType& matrix) {
 | |
| 
 | |
|       hid_t file_id{}, dataset_id{}, dataspace_id{};
 | |
|       herr_t write_st;
 | |
|       do {
 | |
|          // Try to open the file in read-write mode
 | |
|          logger << "Store HDF5 file: " << filename << " Dataset: " << dataset << "...";
 | |
|          if (access(session.outMtxFile.c_str(), F_OK) == 0){
 | |
|             if ((file_id = H5Fopen(filename.c_str(), H5F_ACC_RDWR, H5P_DEFAULT)) < 0)
 | |
|                break;
 | |
|          }
 | |
|          else {
 | |
|             if ((file_id = H5Fcreate(filename.c_str(), H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)) < 0)
 | |
|                break;
 | |
|          }
 | |
| 
 | |
|          // Create the dataspace for the dataset
 | |
|          hsize_t dims[] = { matrix.rows(), matrix.columns() };
 | |
|          if ((dataspace_id = H5Screate_simple(2, dims, NULL)) < 0)
 | |
|             break;
 | |
| 
 | |
|          // ToDo: Come up with a better way to do this
 | |
|          if constexpr (Type == HDF5_type::DOUBLE) {
 | |
|             // Create the dataset with default properties
 | |
|             if ((dataset_id = H5Dcreate2(
 | |
|                   file_id, dataset.c_str(), H5T_NATIVE_DOUBLE, dataspace_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0)
 | |
|                break;
 | |
|             // Write the data to the dataset
 | |
|             if ((write_st = H5Dwrite(dataset_id, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, H5P_DEFAULT, matrix.data())) <0 )
 | |
|                break;
 | |
|          }
 | |
|          else if (Type == HDF5_type::FLOAT) {
 | |
|             // Create the dataset with default properties
 | |
|             if ((dataset_id = H5Dcreate2(
 | |
|                   file_id, dataset.c_str(), H5T_NATIVE_FLOAT, dataspace_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0)
 | |
|                break;
 | |
|             // Write the data to the dataset
 | |
|             if ((write_st = H5Dwrite(dataset_id, H5T_NATIVE_FLOAT, H5S_ALL, H5S_ALL, H5P_DEFAULT, matrix.data())) <0 )
 | |
|                break;
 | |
|          }
 | |
|          else if (Type == HDF5_type::UINT) {
 | |
|             // Create the dataset with default properties
 | |
|             if ((dataset_id = H5Dcreate2(
 | |
|                   file_id, dataset.c_str(), H5T_NATIVE_UINT, dataspace_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0)
 | |
|                break;
 | |
|             // Write the data to the dataset
 | |
|             if ((write_st = H5Dwrite(dataset_id, H5T_NATIVE_UINT, H5S_ALL, H5S_ALL, H5P_DEFAULT, matrix.data())) <0 )
 | |
|                break;
 | |
|          }
 | |
|          else if (Type == HDF5_type::INT) {
 | |
|             // Create the dataset with default properties
 | |
|             if ((dataset_id = H5Dcreate2(
 | |
|                   file_id, dataset.c_str(), H5T_NATIVE_INT, dataspace_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0)
 | |
|                break;
 | |
|             // Write the data to the dataset
 | |
|             if ((write_st = H5Dwrite(dataset_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, matrix.data())) <0 )
 | |
|                break;
 | |
|          }
 | |
|          // Close the dataset, dataspace, and file
 | |
|          H5Dclose(dataset_id);
 | |
|          H5Sclose(dataspace_id);
 | |
|          H5Fclose(file_id);
 | |
|          logger << " Done" << logger.endl;
 | |
|          return;
 | |
|       } while (0);
 | |
| 
 | |
|       // Error: close everything (if possible) and return false
 | |
|       H5Dclose(dataset_id);
 | |
|       H5Sclose(dataspace_id);
 | |
|       H5Fclose(file_id);
 | |
|       throw std::runtime_error("Cannot store " + filename + " with dataset:" + dataset +'\n');
 | |
|    }
 | |
| };
 | |
| 
 | |
| 
 | |
| 
 | |
| #endif /* UTILS_HPP_ */
 |