Program Listing for File io.cpp

Return to documentation for file (umpire/util/io.cpp)

//////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2016-20, Lawrence Livermore National Security, LLC and Umpire
// project contributors. See the COPYRIGHT file for details.
//
// SPDX-License-Identifier: (MIT)
//////////////////////////////////////////////////////////////////////////////

#include "umpire/config.hpp"
#include "umpire/util/io.hpp"
#include "umpire/util/Macros.hpp"
#include "umpire/util/MPI.hpp"
#include "umpire/util/OutputBuffer.hpp"

#include <string>
#include <iostream>
#include <fstream>
#include <ostream>
#include <stdlib.h>   // for getenv()

#if defined(UMPIRE_ENABLE_FILESYSTEM)
#include <filesystem>
#else
#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>
#endif

#if !defined(_MSC_VER)
#include <unistd.h>   // getpid()
#else
#include <process.h>
#define getpid _getpid
#endif

namespace umpire {

std::ostream& log()
{
  static std::ostream out{std::cout.rdbuf()};
  return out;
}

std::ostream& replay()
{
  static std::ostream out{nullptr};
  return out;
}

std::ostream& error()
{
  static std::ostream out{std::cerr.rdbuf()};
  return out;
}

namespace util {

static std::string make_unique_filename(
  const std::string& base_dir,
  const std::string& name,
  const int pid,
  const std::string& extension);

static inline bool file_exists(const std::string& file);

static inline bool directory_exists(const std::string& file);

void initialize_io(const bool enable_log, const bool enable_replay)
{
  static util::OutputBuffer s_log_buffer;
  static util::OutputBuffer s_replay_buffer;
  static util::OutputBuffer s_error_buffer;

  s_log_buffer.setConsoleStream(nullptr);
  s_replay_buffer.setConsoleStream(nullptr);
  s_error_buffer.setConsoleStream(&std::cerr);

  log().rdbuf(&s_log_buffer);
  replay().rdbuf(&s_replay_buffer);
  error().rdbuf(&s_error_buffer);

  std::string root_io_dir{"./"};
  const char* output_dir{std::getenv("UMPIRE_OUTPUT_DIR")};
  if (output_dir) root_io_dir = output_dir;

  std::string file_basename{"umpire"};
  const char* base_name{std::getenv("UMPIRE_OUTPUT_BASENAME")};
  if (base_name) file_basename = base_name;

  const int pid{getpid()};

  const std::string log_filename{
    make_unique_filename(root_io_dir, file_basename, pid, "log")};

  const std::string replay_filename{
    make_unique_filename(root_io_dir, file_basename, pid, "replay")};

  const std::string error_filename{
    make_unique_filename(root_io_dir, file_basename, pid, "error")};

  if (!directory_exists(root_io_dir)) {
    if (MPI::isInitialized()) {
      if (MPI::getRank() == 0) {
#if defined(UMPIRE_ENABLE_FILESYSTEM)
        std::filesystem::path root_io_dir_path{root_io_dir};

        if (!std::filesystem::exists(root_io_dir_path) &&
            (enable_log || enable_replay)) {
          std::filesystem::create_directories(root_io_dir_path);
        }
#else
        struct stat info;
        if ( stat( root_io_dir.c_str(), &info ) )
        {
          if (enable_log || enable_replay) {
            if ( mkdir(root_io_dir.c_str(),
                       S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) ) {
              UMPIRE_ERROR("mkdir(" << root_io_dir << ") failed");
            }
          }
        }
        else if ( !(S_ISDIR(info.st_mode)) )
        {
          UMPIRE_ERROR(root_io_dir << "exists and is not a directory");
        }
#endif
      }
      MPI::sync();
    } else {
      UMPIRE_ERROR("Cannot create output directory before MPI has been initialized. "
                   "Please unset UMPIRE_OUTPUT_DIR in your environment");
    }
  }

  if (enable_log) {
    static std::ofstream s_log_ofstream{log_filename};

    if (s_log_ofstream) {
      s_log_buffer.setFileStream(&s_log_ofstream);
    } else {
      UMPIRE_ERROR("Couldn't open log file:" << log_filename);
    }
  }

  if (enable_replay) {
    static std::ofstream s_replay_ofstream{replay_filename};

    if (s_replay_ofstream) {
      s_replay_buffer.setFileStream(&s_replay_ofstream);
    } else {
      UMPIRE_ERROR("Couldn't open replay file:" << replay_filename);
    }
  }

  MPI::logMpiInfo();
}

void flush_files()
{
  log().flush();
  replay().flush();
  error().flush();
}


static std::string
make_unique_filename(
    const std::string& base_dir,
    const std::string& name,
    const int pid,
    const std::string& extension)
{
  int unique_id{0};
  std::string filename;

  do {
    filename = base_dir + "/" + name +
      "." + std::to_string(pid) +
      "." + std::to_string(unique_id++) +
      "." + extension;
  } while (file_exists(filename));

  return filename;
}

static inline bool file_exists(const std::string& path)
{
  std::ifstream ifile(path.c_str());
  return ifile.good();
}

static inline bool directory_exists(const std::string& path)
{
#if defined(UMPIRE_ENABLE_FILESYSTEM)
  std::filesystem::path fspath_path(path);
  return std::filesystem::exists(fspath_path);
#else
  struct stat info;
  if ( stat( path.c_str(), &info) ) {
    return false;
  } else {
    return S_ISDIR(info.st_mode);
  }
#endif
}

} // end namespace util
} // end namespace umpire