Skip to content
FileIO.hpp 6.43 KiB
Newer Older
#pragma once

#include <cstddef>
#include <fstream>
#include <iomanip>
#include <sstream>
#include <string>

#include "gsl/gsl"

#include "Util.hpp"
#include "state.hpp"

struct FileIO {
	struct Header {
		Size GlobalSize;
		std::size_t HeaderLength;
	};
	static auto ReadHeader(const std::string& path) {
		// read the header into a buf (20 should be sufficient)
		MPI_File fh;
		MPI_File_open(MPI_COMM_SELF, path.c_str(),
		              MPI_MODE_RDONLY | MPI_MODE_UNIQUE_OPEN, MPI_INFO_NULL,
		              &fh);
		constexpr auto HeaderBufSize = 20;
		std::array<char, HeaderBufSize> buf;
		MPI_File_read_all(fh, buf.data(), buf.size(), MPI_CHAR,
		                  MPI_STATUS_IGNORE);
		MPI_File_close(&fh);

		// make stream out of buf
		std::istringstream input;
		input.rdbuf()->pubsetbuf(buf.data(), buf.size());

		// parse the stream
		std::size_t noCols{};
		std::size_t noRows{};
		input >> noCols >> noRows;
		if (noCols < 1 || noRows < 1) {
			std::cerr << "File header corrupt\n";
			MPI_Abort(MPI_COMM_WORLD, EXIT_FAILURE);
		}
		std::string dummy; // skip line break
		std::getline(input, dummy);
		const auto& headerLength = input.tellg();
		return Header{
		    {noCols, noRows},
		    static_cast<std::size_t>(
		        headerLength) // should fit (is max HeaderBuf size)
		};
	// TODO: is not an IO concern
	static auto GetTileSize(Size globalSize, Size gridSize) {
		const auto& tileSizeCols = globalSize.Cols / gridSize.Cols;
		const auto& tileSizeRows = globalSize.Rows / gridSize.Rows;
		return Size{tileSizeCols, tileSizeRows};
	}

	static void StridedRead(std::istream& input, std::size_t inputChunkLength,
	                        std::size_t count, std::size_t inputStride,
	                        gsl::span<State> buf, std::size_t bufStride) {

		std::size_t writeOffset{0};
		for (size_t i{0}; i < count; ++i) {
			input.read(reinterpret_cast<char*>(buf.data()) + writeOffset,
			           inputChunkLength);
			input.seekg(inputStride - inputChunkLength, std::ios::cur);
			writeOffset += bufStride;
		}
	}

	static void ReadTile(const std::string& path, std::size_t headerLength,
	                     Size srcSize, Size gridSize, std::size_t rank,
	                     gsl::span<State> buf) {
		static constexpr auto DebugRank = 4;
		constexpr auto LF = 1; // linefeed chars
		const auto& tileSize = GetTileSize(srcSize, gridSize);
		const auto& tileX = rank % gridSize.Cols;
		const auto& tileY = rank / gridSize.Cols;

Thomas Steinreiter's avatar
Thomas Steinreiter committed
		if (rank == DebugRank) {
			std::cout << "headerLength:" << headerLength << "\n";
			std::cout << "srcSize.Cols:" << srcSize.Cols << "\n";
			std::cout << "srcSize.Rows:" << srcSize.Rows << "\n";
			std::cout << "tileSize.Cols:" << tileSize.Cols << "\n";
			std::cout << "tileSize.Rows:" << tileSize.Rows << "\n";
			std::cout << "tileX:" << tileX << "\n";
			std::cout << "tileY:" << tileY << "\n";
		}

		// create tile type
		MPI_Datatype tileType;
		{
			const std::array<int, 2> sizes{static_cast<int>(srcSize.Rows),
			                               static_cast<int>(srcSize.Cols + LF)};
			const std::array<int, 2> subSizes{static_cast<int>(tileSize.Rows),
			                                  static_cast<int>(tileSize.Cols)};
Thomas Steinreiter's avatar
Thomas Steinreiter committed
			const std::array<int, 2> starts{0, 0};
Thomas Steinreiter's avatar
Thomas Steinreiter committed
			if (rank == DebugRank) {
				std::cout << "tileType\nsizes:";
				for (const auto i : sizes) std::cout << i << ", ";
				std::cout << "\nsubSizes:";
				for (const auto i : subSizes) std::cout << i << ", ";
				std::cout << "\nstarts:";
				for (const auto i : starts) std::cout << i << ", ";
				std::cout << "\n";
			}

			MPI_Type_create_subarray(2,               // ndims
			                         sizes.data(),    // array_of_sizes
			                         subSizes.data(), // array_of_subsizes
			                         starts.data(),   // array_of_starts
			                         MPI_ORDER_C,     // order
			                         MPI_CHAR,        // oldtype
			                         &tileType        // newtype
			                         );
			MPI_Type_commit(&tileType);
		}

		// create buf type
		MPI_Datatype bufType;
		{
			const std::array<int, 2> sizes{static_cast<int>(tileSize.Rows + 2),
			                               static_cast<int>(tileSize.Cols + 2)};
			const std::array<int, 2> subSizes{static_cast<int>(tileSize.Rows),
			                                  static_cast<int>(tileSize.Cols)};
			const std::array<int, 2> starts{1, 1};

Thomas Steinreiter's avatar
Thomas Steinreiter committed
			if (rank == DebugRank) {
				std::cout << "\nbufType\nsizes:";
				for (const auto i : sizes) std::cout << i << ", ";
				std::cout << "\nsubSizes:";
				for (const auto i : subSizes) std::cout << i << ", ";
				std::cout << "\nstarts:";
				for (const auto i : starts) std::cout << i << ", ";
				std::cout << "\n";
			}

			MPI_Type_create_subarray(2,               // ndims
			                         sizes.data(),    // array_of_sizes
			                         subSizes.data(), // array_of_subsizes
			                         starts.data(),   // array_of_starts
			                         MPI_ORDER_C,     // order
			                         MPI_CHAR,        // oldtype
			                         &bufType         // newtype
			                         );
			MPI_Type_commit(&bufType);
		}

		// read
		MPI_File file;
		MPI_File_open(MPI_COMM_WORLD, path.c_str(),
		              MPI_MODE_RDONLY | MPI_MODE_UNIQUE_OPEN, MPI_INFO_NULL,
		              &file);
		const auto displ = headerLength +
		                   (srcSize.Cols + LF) * tileSize.Rows * tileY +
		                   tileSize.Cols * tileX;
Thomas Steinreiter's avatar
Thomas Steinreiter committed
		if (rank == DebugRank) { std::cout << "displ:" << displ << "\n"; }
		MPI_File_set_view(file, displ, MPI_CHAR, tileType, "native",
		                  MPI_INFO_NULL);
		// std::array<char, 84> dbg; dbg.fill((char)0);

		MPI_File_read_all(file, buf.data(), 1, bufType, MPI_STATUS_IGNORE);

Thomas Steinreiter's avatar
Thomas Steinreiter committed
		// if (rank == DebugRank) {
		//	std::cout << "dbg:\n";
		//	std::size_t cnt{};
		//	for (const auto& i : dbg) {
		//		if (cnt++ % (tileSize.Cols + 2) == 0) std::cout << "\n";
		//		std::cout << std::setw(2) <<  i << ", ";
		//	}
		//	std::cout << "\n";
		//}

		// std::ifstream input(path);
		// input.seekg(headerLength);

		//// seek to the begin of the tile
		// const auto& displacement =
		//    (srcSize.Cols + LF) * (tileSize.Rows * tileY) +
		//    (tileSize.Cols * tileX);
		// input.seekg(displacement, std::ios::cur);

		// const auto& tileStride = srcSize.Cols + LF;
		// StridedRead(input, tileSize.Cols, tileSize.Rows, tileStride, buf,
		//            bufStride);
		MPI_Type_free(&tileType);
		MPI_Type_free(&bufType);