| // Copyright 2023 The IREE Authors |
| // |
| // Licensed under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| |
| #include "iree_pjrt/common/debugging.h" |
| |
| #include <filesystem> |
| #include <fstream> |
| #include <iostream> |
| #include <vector> |
| |
| namespace iree::pjrt { |
| |
| //===----------------------------------------------------------------------===// |
| // Logger |
| //===----------------------------------------------------------------------===// |
| |
| void Logger::debug(std::string_view message) { |
| std::cerr << "[IREE-PJRT] DEBUG: " << message << std::endl; |
| } |
| |
| void Logger::error(std::string_view message) { |
| std::cerr << "[IREE-PJRT] ERROR: " << message << std::endl; |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // ArtifactDumper |
| //===----------------------------------------------------------------------===// |
| |
| ArtifactDumper::~ArtifactDumper() = default; |
| |
| std::unique_ptr<ArtifactDumper::Transaction> |
| ArtifactDumper::CreateTransaction() { |
| return nullptr; |
| } |
| |
| std::string ArtifactDumper::DebugString() { return std::string("disabled"); } |
| |
| //===----------------------------------------------------------------------===// |
| // FilesArtifactDumper |
| //===----------------------------------------------------------------------===// |
| |
| class FilesArtifactDumper::FilesTransaction final |
| : public ArtifactDumper::Transaction { |
| public: |
| FilesTransaction(Logger& logger, std::filesystem::path base_path, |
| int64_t transaction_id, bool retain_all) |
| : logger_(logger), |
| base_path_(std::move(base_path)), |
| transaction_id_(transaction_id), |
| retain_all_(retain_all) {} |
| ~FilesTransaction() { Retain(); } |
| |
| std::optional<std::string> AllocateArtifactPath(std::string_view label, |
| std::string_view extension, |
| int index) override { |
| std::string basename = std::to_string(transaction_id_); |
| basename.append("-"); |
| basename.append(label); |
| if (index >= 0) { |
| basename.append(std::to_string(index)); |
| } |
| basename.append("."); |
| basename.append(extension); |
| |
| auto file_path = base_path_ / basename; |
| written_paths_.push_back(file_path); |
| |
| return file_path; |
| } |
| |
| void WriteArtifact(std::string_view label, std::string_view extension, |
| int index, std::string_view contents) override { |
| // Note that the API declares this as optional, but our implementation |
| // always returns a path. |
| auto file_path = AllocateArtifactPath(label, extension, index); |
| |
| std::ofstream fout; |
| fout.open(*file_path, std::ofstream::out | std::ofstream::trunc | |
| std::ofstream::binary); |
| fout.write(contents.data(), contents.size()); |
| fout.close(); |
| |
| if (!fout.good()) { |
| std::string message("I/O error dumping artifact: "); |
| message.append(*file_path); |
| logger_.error(message); |
| } |
| } |
| |
| void Retain() override { |
| if (written_paths_.empty()) return; |
| |
| std::string message; |
| message.append("Retained artifacts in: "); |
| message.append(base_path_); |
| for (auto& p : written_paths_) { |
| message.append("\n "); |
| message.append(p.filename()); |
| } |
| logger_.debug(message); |
| |
| written_paths_.clear(); |
| } |
| |
| void Cancel() override { |
| if (retain_all_) { |
| Retain(); |
| return; |
| } |
| |
| for (auto& p : written_paths_) { |
| std::error_code ec; |
| std::filesystem::remove(p, ec); |
| if (ec) { |
| // Only carp as a debug message since there are legitimate reasons |
| // this can happen depending on what is going on at the system level. |
| std::string message("Error removing artifact: "); |
| message.append(p); |
| logger_.debug(message); |
| } |
| } |
| |
| written_paths_.clear(); |
| } |
| |
| private: |
| Logger& logger_; |
| std::vector<std::filesystem::path> written_paths_; |
| std::filesystem::path base_path_; |
| int64_t transaction_id_; |
| bool retain_all_; |
| }; |
| |
| FilesArtifactDumper::FilesArtifactDumper(Logger& logger, |
| PathCallback path_callback, |
| bool retain_all) |
| : logger_(logger), |
| path_callback_(std::move(path_callback)), |
| retain_all_(retain_all) { |
| enabled_ = true; |
| } |
| |
| FilesArtifactDumper::~FilesArtifactDumper() = default; |
| |
| std::unique_ptr<ArtifactDumper::Transaction> |
| FilesArtifactDumper::CreateTransaction() { |
| auto maybe_path = path_callback_(); |
| if (!maybe_path) { |
| return nullptr; |
| } |
| |
| std::filesystem::path path(*maybe_path); |
| std::error_code ec; |
| std::filesystem::create_directories(path, ec); |
| if (ec) { |
| std::string message("Error creating artifact directory '"); |
| message.append(path); |
| message.append("' (artifact dumping disabled): "); |
| message.append(ec.message()); |
| logger_.error(message); |
| return nullptr; |
| } |
| |
| return std::make_unique<FilesTransaction>( |
| logger_, path, next_transaction_id_.fetch_add(1), retain_all_); |
| } |
| |
| std::string FilesArtifactDumper::DebugString() { |
| return std::string("dump to files"); |
| } |
| |
| } // namespace iree::pjrt |