blob: b6606d42458e06cbe702a84c031f4956a7c439f7 [file] [edit]
//===- DTLTODistributionDriver.cpp - DTLTO Distribution Driver ---------===//
//
// Part of the LLVM Project, 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
//
//===----------------------------------------------------------------------===//
//
// \file
// This file implements the Integrated Distributed ThinLTO driver that prepares
// the compilation job descriptions and invokes the external distributor.
//
//===----------------------------------------------------------------------===//
#include "llvm/DTLTO/DTLTO.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/JSON.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Process.h"
#include "llvm/Support/TimeProfiler.h"
#include "llvm/Support/raw_ostream.h"
#include <string>
using namespace llvm;
// Generates a JSON file describing the backend compilations, for the
// distributor.
Error lto::DistributionDriver::emitJson() {
using json::Array;
std::error_code EC;
raw_fd_ostream OS(DistributorJsonFile, EC);
if (EC)
return createStringError(EC, "Error while creating Json file");
json::OStream JOS(OS);
JOS.object([&]() {
// Information common to all jobs.
JOS.attributeObject("common", [&]() {
JOS.attribute("linker_output", Params.LinkerOutputFile);
JOS.attributeArray("args", [&]() {
JOS.value(Params.RemoteCompiler);
// Forward any supplied prepend options.
if (!Params.RemoteCompilerPrependArgs.empty())
for (auto &A : Params.RemoteCompilerPrependArgs)
JOS.value(A);
JOS.value("-c");
JOS.value(std::string("--target=") + Params.TargetTriple.str());
for (const auto &A : Params.CodegenOptions)
JOS.value(A);
});
JOS.attribute("inputs", Array(Params.CommonInputs));
});
// Per-compilation-job information.
JOS.attributeArray("jobs", [&]() {
for (const auto &J : Jobs) {
assert(J.Task != 0);
if (J.Cached) {
continue;
}
SmallVector<StringRef, 2> Inputs;
SmallVector<StringRef, 1> Outputs;
JOS.object([&]() {
JOS.attributeArray("args", [&]() {
JOS.value(J.ModuleID);
Inputs.push_back(J.ModuleID);
JOS.value(
std::string("-fthinlto-index=" + J.SummaryIndexPath.str()));
Inputs.push_back(J.SummaryIndexPath);
JOS.value("-o");
JOS.value(J.NativeObjectPath);
Outputs.push_back(J.NativeObjectPath);
});
// Add the bitcode files from which imports will be made. These do
// not explicitly appear on the backend compilation command lines
// but are recorded in the summary index shards.
append_range(Inputs, J.ImportsFilesList);
JOS.attribute("inputs", Array(Inputs));
JOS.attribute("outputs", Array(Outputs));
});
}
});
});
return Error::success();
}
// Saves JSON file on a filesystem.
Error lto::DistributionDriver::saveJson() {
DistributorJsonFile = sys::path::parent_path(Params.LinkerOutputFile);
TimeTraceScope TimeScope("Emit DTLTO JSON");
sys::path::append(DistributorJsonFile,
sys::path::stem(Params.LinkerOutputFile) + "." +
itostr(sys::Process::getProcessId()) +
".dist-file.json");
if (Error E = emitJson())
return make_error<StringError>(
BCError + "failed to generate distributor JSON script: " +
DistributorJsonFile,
errorToErrorCode(std::move(E)));
// Add JSON file to the cleanup files list.
if (!SaveTemps)
AddToCleanup(DistributorJsonFile);
return Error::success();
}
// Invokes the distributor to compile uncached ThinLTO modules remotely.
Error lto::DistributionDriver::operator()() {
if (Error E = saveJson())
return E;
TimeTraceScope TimeScope("Execute DTLTO distributor", Params.DistributorPath);
SmallVector<StringRef, 3> Args = {Params.DistributorPath};
append_range(Args, Params.DistributorArgs);
Args.push_back(DistributorJsonFile);
std::string ErrMsg;
if (sys::ExecuteAndWait(Args[0], Args,
/*Env=*/std::nullopt, /*Redirects=*/{},
/*SecondsToWait=*/0, /*MemoryLimit=*/0, &ErrMsg)) {
return make_error<StringError>(
BCError + "distributor execution failed" +
(!ErrMsg.empty() ? ": " + ErrMsg + Twine(".") : Twine(".")),
inconvertibleErrorCode());
}
return Error::success();
}