Skip to content

Commit 9d8e2dc

Browse files
authored
Additional cache fixes for 6.4 (llvm#838)
2 parents fedd7b7 + 83daddd commit 9d8e2dc

10 files changed

+557
-115
lines changed

amd/comgr/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ option(COMGR_BUILD_SHARED_LIBS "Build the shared library"
7373
set(SOURCES
7474
src/comgr-cache.cpp
7575
src/comgr-cache-command.cpp
76+
src/comgr-cache-bundler-command.cpp
7677
src/comgr-compiler.cpp
7778
src/comgr.cpp
7879
src/comgr-device-libs.cpp
@@ -83,6 +84,7 @@ set(SOURCES
8384
src/comgr-metadata.cpp
8485
src/comgr-objdump.cpp
8586
src/comgr-signal.cpp
87+
src/comgr-spirv-command.cpp
8688
src/comgr-symbol.cpp
8789
src/comgr-symbolizer.cpp
8890
src/time-stat/time-stat.cpp)
Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
/*******************************************************************************
2+
*
3+
* University of Illinois/NCSA
4+
* Open Source License
5+
*
6+
* Copyright (c) 2003-2017 University of Illinois at Urbana-Champaign.
7+
* Modifications (c) 2018 Advanced Micro Devices, Inc.
8+
* All rights reserved.
9+
*
10+
* Permission is hereby granted, free of charge, to any person obtaining a copy
11+
* of this software and associated documentation files (the "Software"), to deal
12+
* with the Software without restriction, including without limitation the
13+
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
14+
* sell copies of the Software, and to permit persons to whom the Software is
15+
* furnished to do so, subject to the following conditions:
16+
*
17+
* * Redistributions of source code must retain the above copyright notice,
18+
* this list of conditions and the following disclaimers.
19+
*
20+
* * Redistributions in binary form must reproduce the above copyright
21+
* notice, this list of conditions and the following disclaimers in the
22+
* documentation and/or other materials provided with the distribution.
23+
*
24+
* * Neither the names of the LLVM Team, University of Illinois at
25+
* Urbana-Champaign, nor the names of its contributors may be used to
26+
* endorse or promote products derived from this Software without specific
27+
* prior written permission.
28+
*
29+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
30+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
31+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
32+
* CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
33+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
34+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH
35+
* THE SOFTWARE.
36+
*
37+
******************************************************************************/
38+
39+
#include <comgr-cache-bundler-command.h>
40+
41+
#include <clang/Driver/OffloadBundler.h>
42+
#include <llvm/BinaryFormat/Magic.h>
43+
44+
namespace COMGR {
45+
using namespace llvm;
46+
using namespace clang;
47+
48+
using SizeFieldType = uint32_t;
49+
50+
bool UnbundleCommand::canCache() const {
51+
// The header format for AR files is not the same as object files
52+
if (Kind == AMD_COMGR_DATA_KIND_AR_BUNDLE)
53+
return false;
54+
55+
StringRef InputFilename = Config.InputFileNames.front();
56+
file_magic Magic;
57+
if (identify_magic(InputFilename, Magic))
58+
return false;
59+
60+
// Check the input file magic. Handle only compressed bundles
61+
// It's not worth to cache other types of bundles
62+
return Magic == file_magic::offload_bundle_compressed;
63+
}
64+
65+
Error UnbundleCommand::writeExecuteOutput(StringRef CachedBuffer) {
66+
for (StringRef OutputFilename : Config.OutputFileNames) {
67+
SizeFieldType OutputFileSize;
68+
if (CachedBuffer.size() < sizeof(OutputFileSize))
69+
return createStringError(std::errc::invalid_argument,
70+
"Not enough bytes to read output file size");
71+
memcpy(&OutputFileSize, CachedBuffer.data(), sizeof(OutputFileSize));
72+
CachedBuffer = CachedBuffer.drop_front(sizeof(OutputFileSize));
73+
74+
if (CachedBuffer.size() < OutputFileSize)
75+
return createStringError(std::errc::invalid_argument,
76+
"Not enough bytes to read output file contents");
77+
78+
StringRef OutputFileContents = CachedBuffer.substr(0, OutputFileSize);
79+
CachedBuffer = CachedBuffer.drop_front(OutputFileSize);
80+
81+
if (Error Err = CachedCommandAdaptor::writeUniqueExecuteOutput(
82+
OutputFilename, OutputFileContents))
83+
return Err;
84+
}
85+
86+
if (!CachedBuffer.empty())
87+
return createStringError(std::errc::invalid_argument,
88+
"Bytes in cache entry not used for the output");
89+
return Error::success();
90+
}
91+
92+
Expected<StringRef> UnbundleCommand::readExecuteOutput() {
93+
size_t OutputSize = 0;
94+
for (StringRef OutputFilename : Config.OutputFileNames) {
95+
auto MaybeOneOutput =
96+
CachedCommandAdaptor::readUniqueExecuteOutput(OutputFilename);
97+
if (!MaybeOneOutput)
98+
return MaybeOneOutput.takeError();
99+
100+
const MemoryBuffer &OneOutputBuffer = **MaybeOneOutput;
101+
SizeFieldType OneOutputFileSize = OneOutputBuffer.getBufferSize();
102+
103+
OutputBuffer.resize_for_overwrite(OutputSize + sizeof(OneOutputFileSize) +
104+
OneOutputFileSize);
105+
106+
memcpy(OutputBuffer.data() + OutputSize, &OneOutputFileSize,
107+
sizeof(OneOutputFileSize));
108+
OutputSize += sizeof(OneOutputFileSize);
109+
memcpy(OutputBuffer.data() + OutputSize, OneOutputBuffer.getBufferStart(),
110+
OneOutputFileSize);
111+
OutputSize += OneOutputFileSize;
112+
}
113+
return OutputBuffer;
114+
}
115+
116+
amd_comgr_status_t UnbundleCommand::execute(raw_ostream &LogS) {
117+
assert(Config.InputFileNames.size() == 1);
118+
119+
OffloadBundler Bundler(Config);
120+
121+
switch (Kind) {
122+
case AMD_COMGR_DATA_KIND_BC_BUNDLE:
123+
case AMD_COMGR_DATA_KIND_OBJ_BUNDLE: {
124+
if (Error Err = Bundler.UnbundleFiles()) {
125+
logAllUnhandledErrors(std::move(Err), LogS, "Unbundle Error: ");
126+
return AMD_COMGR_STATUS_ERROR;
127+
}
128+
break;
129+
}
130+
case AMD_COMGR_DATA_KIND_AR_BUNDLE: {
131+
if (Error Err = Bundler.UnbundleArchive()) {
132+
logAllUnhandledErrors(std::move(Err), LogS, "Unbundle Archives Error: ");
133+
return AMD_COMGR_STATUS_ERROR;
134+
}
135+
break;
136+
}
137+
default:
138+
llvm_unreachable("invalid bundle type");
139+
}
140+
141+
return AMD_COMGR_STATUS_SUCCESS;
142+
}
143+
144+
CachedCommandAdaptor::ActionClass UnbundleCommand::getClass() const {
145+
return clang::driver::Action::OffloadUnbundlingJobClass;
146+
}
147+
148+
void UnbundleCommand::addOptionsIdentifier(HashAlgorithm &H) const {
149+
H.update(Config.TargetNames.size());
150+
for (StringRef Target : Config.TargetNames) {
151+
CachedCommandAdaptor::addString(H, Target);
152+
}
153+
}
154+
155+
Error UnbundleCommand::addInputIdentifier(HashAlgorithm &H) const {
156+
StringRef InputFilename = Config.InputFileNames.front();
157+
158+
constexpr size_t LargestHeaderSize = CompressedOffloadBundle::V2HeaderSize;
159+
160+
ErrorOr<std::unique_ptr<MemoryBuffer>> MaybeInputBuffer =
161+
MemoryBuffer::getFileSlice(InputFilename, LargestHeaderSize, 0);
162+
if (!MaybeInputBuffer) {
163+
std::error_code EC = MaybeInputBuffer.getError();
164+
return createStringError(EC, Twine("Failed to open ") + InputFilename +
165+
" : " + EC.message() + "\n");
166+
}
167+
168+
MemoryBuffer &InputBuffer = **MaybeInputBuffer;
169+
170+
uint8_t Header[LargestHeaderSize];
171+
memset(Header, 0, sizeof(Header));
172+
memcpy(Header, InputBuffer.getBufferStart(),
173+
std::min(LargestHeaderSize, InputBuffer.getBufferSize()));
174+
175+
// only hash the input file, not the whole header. Colissions are unlikely
176+
// since the header includes a hash (weak) of the contents
177+
H.update(Header);
178+
return Error::success();
179+
}
180+
181+
} // namespace COMGR
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/*******************************************************************************
2+
*
3+
* University of Illinois/NCSA
4+
* Open Source License
5+
*
6+
* Copyright (c) 2018 Advanced Micro Devices, Inc. All Rights Reserved.
7+
*
8+
* Permission is hereby granted, free of charge, to any person obtaining a copy
9+
* of this software and associated documentation files (the "Software"), to deal
10+
* with the Software without restriction, including without limitation the
11+
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
12+
* sell copies of the Software, and to permit persons to whom the Software is
13+
* furnished to do so, subject to the following conditions:
14+
*
15+
* * Redistributions of source code must retain the above copyright notice,
16+
* this list of conditions and the following disclaimers.
17+
*
18+
* * Redistributions in binary form must reproduce the above copyright
19+
* notice, this list of conditions and the following disclaimers in the
20+
* documentation and/or other materials provided with the distribution.
21+
*
22+
* * Neither the names of Advanced Micro Devices, Inc. nor the names of its
23+
* contributors may be used to endorse or promote products derived from
24+
* this Software without specific prior written permission.
25+
*
26+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
27+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
28+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
29+
* CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
30+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
31+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH
32+
* THE SOFTWARE.
33+
*
34+
******************************************************************************/
35+
36+
#ifndef COMGR_CACHE_BUNDLER_COMMAND_H
37+
#define COMGR_CACHE_BUNDLER_COMMAND_H
38+
39+
#include <comgr-cache-command.h>
40+
41+
namespace clang {
42+
class OffloadBundlerConfig;
43+
} // namespace clang
44+
45+
namespace COMGR {
46+
class UnbundleCommand final : public CachedCommandAdaptor {
47+
private:
48+
amd_comgr_data_kind_t Kind;
49+
const clang::OffloadBundlerConfig &Config;
50+
51+
// To avoid copies, store the output of execute, such that readExecuteOutput
52+
// can return a reference.
53+
llvm::SmallString<64> OutputBuffer;
54+
55+
public:
56+
UnbundleCommand(amd_comgr_data_kind_t Kind,
57+
const clang::OffloadBundlerConfig &Config)
58+
: Kind(Kind), Config(Config) {}
59+
60+
bool canCache() const override;
61+
llvm::Error writeExecuteOutput(llvm::StringRef CachedBuffer) override;
62+
llvm::Expected<llvm::StringRef> readExecuteOutput() override;
63+
amd_comgr_status_t execute(llvm::raw_ostream &LogS) override;
64+
65+
~UnbundleCommand() override = default;
66+
67+
protected:
68+
ActionClass getClass() const override;
69+
void addOptionsIdentifier(HashAlgorithm &) const override;
70+
llvm::Error addInputIdentifier(HashAlgorithm &) const override;
71+
};
72+
} // namespace COMGR
73+
74+
#endif

amd/comgr/src/comgr-cache-command.cpp

Lines changed: 51 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -68,14 +68,6 @@ bool hasDebugOrProfileInfo(ArrayRef<const char *> Args) {
6868
return false;
6969
}
7070

71-
void addString(CachedCommandAdaptor::HashAlgorithm &H, StringRef S) {
72-
// hash size + contents to avoid collisions
73-
// for example, we have to ensure that the result of hashing "AA" "BB" is
74-
// different from "A" "ABB"
75-
H.update(S.size());
76-
H.update(S);
77-
}
78-
7971
Error addFile(CachedCommandAdaptor::HashAlgorithm &H, StringRef Path) {
8072
auto BufOrError = MemoryBuffer::getFile(Path);
8173
if (std::error_code EC = BufOrError.getError()) {
@@ -151,6 +143,15 @@ void CachedCommandAdaptor::addFileContents(
151143
}
152144
}
153145

146+
void CachedCommandAdaptor::addString(CachedCommandAdaptor::HashAlgorithm &H,
147+
StringRef S) {
148+
// hash size + contents to avoid collisions
149+
// for example, we have to ensure that the result of hashing "AA" "BB" is
150+
// different from "A" "ABB"
151+
H.update(S.size());
152+
H.update(S);
153+
}
154+
154155
Expected<CachedCommandAdaptor::Identifier>
155156
CachedCommandAdaptor::getIdentifier() const {
156157
CachedCommandAdaptor::HashAlgorithm H;
@@ -170,6 +171,41 @@ CachedCommandAdaptor::getIdentifier() const {
170171
return Id;
171172
}
172173

174+
llvm::Error
175+
CachedCommandAdaptor::writeUniqueExecuteOutput(StringRef OutputFilename,
176+
StringRef CachedBuffer) {
177+
std::error_code EC;
178+
raw_fd_ostream Out(OutputFilename, EC);
179+
if (EC) {
180+
Error E = createStringError(EC, Twine("Failed to open ") + OutputFilename +
181+
" : " + EC.message() + "\n");
182+
return E;
183+
}
184+
185+
Out.write(CachedBuffer.data(), CachedBuffer.size());
186+
Out.close();
187+
if (Out.has_error()) {
188+
Error E = createStringError(EC, Twine("Failed to write ") + OutputFilename +
189+
" : " + EC.message() + "\n");
190+
return E;
191+
}
192+
193+
return Error::success();
194+
}
195+
196+
Expected<std::unique_ptr<MemoryBuffer>>
197+
CachedCommandAdaptor::readUniqueExecuteOutput(StringRef OutputFilename) {
198+
ErrorOr<std::unique_ptr<MemoryBuffer>> MBOrErr =
199+
MemoryBuffer::getFile(OutputFilename);
200+
if (!MBOrErr) {
201+
std::error_code EC = MBOrErr.getError();
202+
return createStringError(EC, Twine("Failed to open ") + OutputFilename +
203+
" : " + EC.message() + "\n");
204+
}
205+
206+
return std::move(*MBOrErr);
207+
}
208+
173209
CachedCommand::CachedCommand(driver::Command &Command,
174210
DiagnosticOptions &DiagOpts,
175211
ExecuteFnTy &&ExecuteImpl)
@@ -249,35 +285,16 @@ bool CachedCommand::canCache() const {
249285

250286
Error CachedCommand::writeExecuteOutput(StringRef CachedBuffer) {
251287
StringRef OutputFilename = Command.getOutputFilenames().front();
252-
std::error_code EC;
253-
raw_fd_ostream Out(OutputFilename, EC);
254-
if (EC) {
255-
Error E = createStringError(EC, Twine("Failed to open ") + OutputFilename +
256-
" : " + EC.message() + "\n");
257-
return E;
258-
}
259-
260-
Out.write(CachedBuffer.data(), CachedBuffer.size());
261-
Out.close();
262-
if (Out.has_error()) {
263-
Error E = createStringError(EC, Twine("Failed to write ") + OutputFilename +
264-
" : " + EC.message() + "\n");
265-
return E;
266-
}
267-
268-
return Error::success();
288+
return CachedCommandAdaptor::writeUniqueExecuteOutput(OutputFilename,
289+
CachedBuffer);
269290
}
270291

271292
Expected<StringRef> CachedCommand::readExecuteOutput() {
272-
StringRef OutputFilename = Command.getOutputFilenames().front();
273-
ErrorOr<std::unique_ptr<MemoryBuffer>> MBOrErr =
274-
MemoryBuffer::getFile(OutputFilename);
275-
if (!MBOrErr) {
276-
std::error_code EC = MBOrErr.getError();
277-
return createStringError(EC, Twine("Failed to open ") + OutputFilename +
278-
" : " + EC.message() + "\n");
279-
}
280-
Output = std::move(*MBOrErr);
293+
auto MaybeBuffer = CachedCommandAdaptor::readUniqueExecuteOutput(
294+
Command.getOutputFilenames().front());
295+
if (!MaybeBuffer)
296+
return MaybeBuffer.takeError();
297+
Output = std::move(*MaybeBuffer);
281298
return Output->getBuffer();
282299
}
283300

0 commit comments

Comments
 (0)