1//===- DTLTODistributionDriver.cpp - DTLTO Distribution Driver ---------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// \file
10// This file implements the Integrated Distributed ThinLTO driver that prepares
11// the compilation job descriptions and invokes the external distributor.
12//
13//===----------------------------------------------------------------------===//
14
15#include "llvm/DTLTO/DTLTO.h"
16
17#include "llvm/ADT/STLExtras.h"
18#include "llvm/ADT/StringExtras.h"
19#include "llvm/ADT/StringRef.h"
20#include "llvm/Support/JSON.h"
21#include "llvm/Support/Path.h"
22#include "llvm/Support/Process.h"
23#include "llvm/Support/TimeProfiler.h"
24#include "llvm/Support/raw_ostream.h"
25
26#include <string>
27
28using namespace llvm;
29
30// Generates a JSON file describing the backend compilations, for the
31// distributor.
32Error lto::DistributionDriver::emitJson() {
33 using json::Array;
34 std::error_code EC;
35 raw_fd_ostream OS(DistributorJsonFile, EC);
36 if (EC)
37 return createStringError(EC, S: "Error while creating Json file");
38
39 json::OStream JOS(OS);
40 JOS.object(Contents: [&]() {
41 // Information common to all jobs.
42 JOS.attributeObject(Key: "common", Contents: [&]() {
43 JOS.attribute(Key: "linker_output", Contents: Params.LinkerOutputFile);
44
45 JOS.attributeArray(Key: "args", Contents: [&]() {
46 JOS.value(V: Params.RemoteCompiler);
47
48 // Forward any supplied prepend options.
49 if (!Params.RemoteCompilerPrependArgs.empty())
50 for (auto &A : Params.RemoteCompilerPrependArgs)
51 JOS.value(V: A);
52
53 JOS.value(V: "-c");
54
55 JOS.value(V: std::string("--target=") + Params.TargetTriple.str());
56
57 for (const auto &A : Params.CodegenOptions)
58 JOS.value(V: A);
59 });
60
61 JOS.attribute(Key: "inputs", Contents: Array(Params.CommonInputs));
62 });
63
64 // Per-compilation-job information.
65 JOS.attributeArray(Key: "jobs", Contents: [&]() {
66 for (const auto &J : Jobs) {
67 assert(J.Task != 0);
68 if (J.Cached) {
69 continue;
70 }
71
72 SmallVector<StringRef, 2> Inputs;
73 SmallVector<StringRef, 1> Outputs;
74
75 JOS.object(Contents: [&]() {
76 JOS.attributeArray(Key: "args", Contents: [&]() {
77 JOS.value(V: J.ModuleID);
78 Inputs.push_back(Elt: J.ModuleID);
79
80 JOS.value(
81 V: std::string("-fthinlto-index=" + J.SummaryIndexPath.str()));
82 Inputs.push_back(Elt: J.SummaryIndexPath);
83
84 JOS.value(V: "-o");
85 JOS.value(V: J.NativeObjectPath);
86 Outputs.push_back(Elt: J.NativeObjectPath);
87 });
88
89 // Add the bitcode files from which imports will be made. These do
90 // not explicitly appear on the backend compilation command lines
91 // but are recorded in the summary index shards.
92 append_range(C&: Inputs, R: J.ImportsFilesList);
93 JOS.attribute(Key: "inputs", Contents: Array(Inputs));
94
95 JOS.attribute(Key: "outputs", Contents: Array(Outputs));
96 });
97 }
98 });
99 });
100
101 return Error::success();
102}
103
104// Saves JSON file on a filesystem.
105Error lto::DistributionDriver::saveJson() {
106 DistributorJsonFile = sys::path::parent_path(path: Params.LinkerOutputFile);
107 TimeTraceScope TimeScope("Emit DTLTO JSON");
108 sys::path::append(path&: DistributorJsonFile,
109 a: sys::path::stem(path: Params.LinkerOutputFile) + "." +
110 itostr(X: sys::Process::getProcessId()) +
111 ".dist-file.json");
112 if (Error E = emitJson())
113 return make_error<StringError>(
114 Args: BCError + "failed to generate distributor JSON script: " +
115 DistributorJsonFile,
116 Args: errorToErrorCode(Err: std::move(E)));
117
118 // Add JSON file to the cleanup files list.
119 if (!SaveTemps)
120 AddToCleanup(DistributorJsonFile);
121 return Error::success();
122}
123
124// Invokes the distributor to compile uncached ThinLTO modules remotely.
125Error lto::DistributionDriver::operator()() {
126 if (Error E = saveJson())
127 return E;
128
129 TimeTraceScope TimeScope("Execute DTLTO distributor", Params.DistributorPath);
130 SmallVector<StringRef, 3> Args = {Params.DistributorPath};
131 append_range(C&: Args, R&: Params.DistributorArgs);
132 Args.push_back(Elt: DistributorJsonFile);
133 std::string ErrMsg;
134 if (sys::ExecuteAndWait(Program: Args[0], Args,
135 /*Env=*/std::nullopt, /*Redirects=*/{},
136 /*SecondsToWait=*/0, /*MemoryLimit=*/0, ErrMsg: &ErrMsg)) {
137 return make_error<StringError>(
138 Args: BCError + "distributor execution failed" +
139 (!ErrMsg.empty() ? ": " + ErrMsg + Twine(".") : Twine(".")),
140 Args: inconvertibleErrorCode());
141 }
142 return Error::success();
143}
144