Skip to content

Commit

Permalink
Move collective file reading to a common header
Browse files Browse the repository at this point in the history
  • Loading branch information
franzpoeschel committed Oct 22, 2021
1 parent 2810f34 commit b0a2054
Show file tree
Hide file tree
Showing 4 changed files with 153 additions and 96 deletions.
86 changes: 86 additions & 0 deletions include/picongpu/plugins/common/MPIHelpers.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/* Copyright 2021 Franz Poeschel
*
* This file is part of PIConGPU.
*
* PIConGPU is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PIConGPU is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with PIConGPU.
* If not, see <http://www.gnu.org/licenses/>.
*/

#include "picongpu/plugins/common/MPIHelpers.hpp"

#include <pmacc/communication/manager_common.hpp>

#include <algorithm>
#include <fstream>
#include <numeric>
#include <sstream>
#include <vector>


namespace picongpu
{
/**
* @brief Read a file in MPI-collective manner.
*
* The file is read on rank 0 and its contents subsequently distributed
* to all other ranks.
*
* @param path Path for the file to read.
* @param comm MPI communicator.
* @return std::string Full file content.
*/
std::string collective_file_read(std::string const& path, MPI_Comm comm)
{
int rank, size;
MPI_CHECK(MPI_Comm_rank(comm, &rank));
MPI_CHECK(MPI_Comm_size(comm, &size));

std::string res;
size_t stringLength = 0;
if(rank == 0)
{
std::fstream handle;
handle.open(path, std::ios_base::in);
std::stringstream stream;
stream << handle.rdbuf();
res = stream.str();
if(!handle.good())
{
throw std::runtime_error("Failed reading JSON config from file " + path + ".");
}
stringLength = res.size() + 1;
}
MPI_Datatype datatype = MPI_Types<size_t>{}.value;
int err = MPI_Bcast(&stringLength, 1, datatype, 0, comm);
if(err != MPI_SUCCESS)
{
throw std::runtime_error("[collective_file_read] MPI_Bcast stringLength failure.");
}
std::vector<char> recvbuf(stringLength, 0);
if(rank == 0)
{
std::copy_n(res.c_str(), stringLength, recvbuf.data());
}
err = MPI_Bcast(recvbuf.data(), stringLength, MPI_CHAR, 0, comm);
if(err != MPI_SUCCESS)
{
throw std::runtime_error("[collective_file_read] MPI_Bcast file content failure.");
}
if(rank != 0)
{
res = recvbuf.data();
}
return res;
}
} // namespace picongpu
66 changes: 66 additions & 0 deletions include/picongpu/plugins/common/MPIHelpers.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/* Copyright 2021 Franz Poeschel
*
* This file is part of PIConGPU.
*
* PIConGPU is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PIConGPU is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with PIConGPU.
* If not, see <http://www.gnu.org/licenses/>.
*/

#pragma once

#include <vector>

#include <mpi.h>

namespace picongpu
{
/**
* @brief Helper class to help figure out a platform-independent
* MPI_Datatype for size_t.
*/
template<typename>
struct MPI_Types;

template<>
struct MPI_Types<unsigned long>
{
// can't make this constexpr due to MPI
// so, make this non-static for simplicity
MPI_Datatype value = MPI_UNSIGNED_LONG;
};

template<>
struct MPI_Types<unsigned long long>
{
MPI_Datatype value = MPI_UNSIGNED_LONG_LONG;
};

template<>
struct MPI_Types<unsigned>
{
MPI_Datatype value = MPI_UNSIGNED;
};

/**
* @brief Read a file in MPI-collective manner.
*
* The file is read on rank 0 and its contents subsequently distributed
* to all other ranks.
*
* @param path Path for the file to read.
* @param comm MPI communicator.
* @return std::string Full file content.
*/
std::string collective_file_read(std::string const& path, MPI_Comm comm);
} // namespace picongpu
56 changes: 0 additions & 56 deletions include/picongpu/plugins/openPMD/Json.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,6 @@

# include <algorithm> // std::copy_n, std::find
# include <cctype> // std::isspace
# include <fstream>
# include <sstream>

/*
* Note:
Expand Down Expand Up @@ -225,60 +223,6 @@ namespace
}
}

/**
* @brief Read a file in MPI-collective manner.
*
* The file is read on rank 0 and its contents subsequently distributed
* to all other ranks.
*
* @param path Path for the file to read.
* @param comm MPI communicator.
* @return std::string Full file content.
*/
std::string collective_file_read(std::string const& path, MPI_Comm comm)
{
int rank, size;
MPI_Comm_rank(comm, &rank);
MPI_Comm_size(comm, &size);

std::string res;
size_t stringLength = 0;
if(rank == 0)
{
std::fstream handle;
handle.open(path, std::ios_base::in);
std::stringstream stream;
stream << handle.rdbuf();
res = stream.str();
if(!handle.good())
{
throw std::runtime_error("Failed reading JSON config from file " + path + ".");
}
stringLength = res.size() + 1;
}
MPI_Datatype datatype = MPI_Types<size_t>{}.value;
int err = MPI_Bcast(&stringLength, 1, datatype, 0, comm);
if(err)
{
throw std::runtime_error("[collective_file_read] MPI_Bcast stringLength failure.");
}
std::vector<char> recvbuf(stringLength, 0);
if(rank == 0)
{
std::copy_n(res.c_str(), stringLength, recvbuf.data());
}
err = MPI_Bcast(recvbuf.data(), stringLength, MPI_CHAR, 0, comm);
if(err)
{
throw std::runtime_error("[collective_file_read] MPI_Bcast file content failure.");
}
if(rank != 0)
{
res = recvbuf.data();
}
return res;
}

KindOfConfig readPattern(
std::vector<picongpu::json::Pattern>& patterns,
nlohmann::json& defaultConfig,
Expand Down
41 changes: 1 addition & 40 deletions include/picongpu/plugins/openPMD/Json_private.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,13 @@

#pragma once

#include "picongpu/plugins/common/MPIHelpers.hpp"
#include "picongpu/plugins/openPMD/Json.hpp"

#include <regex>
#include <string>
#include <vector>

#include <mpi.h>
#include <nlohmann/json.hpp>

/*
Expand Down Expand Up @@ -208,45 +208,6 @@ namespace
*/
std::string extractFilename(std::string const& unparsed);

/**
* @brief Helper class to help figure out a platform-independent
* MPI_Datatype for size_t.
*/
template<typename>
struct MPI_Types;

template<>
struct MPI_Types<unsigned long>
{
// can't make this constexpr due to MPI
// so, make this non-static for simplicity
MPI_Datatype value = MPI_UNSIGNED_LONG;
};

template<>
struct MPI_Types<unsigned long long>
{
MPI_Datatype value = MPI_UNSIGNED_LONG_LONG;
};

template<>
struct MPI_Types<unsigned>
{
MPI_Datatype value = MPI_UNSIGNED;
};

/**
* @brief Read a file in MPI-collective manner.
*
* The file is read on rank 0 and its contents subsequently distributed
* to all other ranks.
*
* @param path Path for the file to read.
* @param comm MPI communicator.
* @return std::string Full file content.
*/
std::string collective_file_read(std::string const& path, MPI_Comm comm);

enum class KindOfConfig : char
{
Pattern,
Expand Down

0 comments on commit b0a2054

Please sign in to comment.