Skip to content

Commit c5587e7

Browse files
author
Salinas, David
authored
Cache commits rebased for promotion mainline (llvm#907)
2 parents 8aa7f7d + b7ab5d6 commit c5587e7

30 files changed

+1616
-62
lines changed

amd/comgr/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,9 @@ option(COMGR_BUILD_SHARED_LIBS "Build the shared library"
7171
${build_shared_libs_default})
7272

7373
set(SOURCES
74+
src/comgr-cache.cpp
75+
src/comgr-cache-command.cpp
76+
src/comgr-cache-bundler-command.cpp
7477
src/comgr-compiler.cpp
7578
src/comgr.cpp
7679
src/comgr-device-libs.cpp
@@ -81,6 +84,7 @@ set(SOURCES
8184
src/comgr-metadata.cpp
8285
src/comgr-objdump.cpp
8386
src/comgr-signal.cpp
87+
src/comgr-spirv-command.cpp
8488
src/comgr-symbol.cpp
8589
src/comgr-symbolizer.cpp
8690
src/time-stat/time-stat.cpp)

amd/comgr/README.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,26 @@ These include:
125125
certain runtime headers. If this is not set, it has a default value of
126126
"${ROCM_PATH}/llvm".
127127

128+
Comgr utilizes a cache to preserve the results of compilations between executions.
129+
The cache's status (enabled/disabled), storage location for its results,
130+
and eviction policy can be manipulated through specific environment variables.
131+
If an issue arises during cache initialization, the execution will proceed with
132+
the cache turned off.
133+
134+
By default, the cache is turned off, set the environment variable
135+
`AMD_COMGR_CACHE=1` to enable it. This may change in a future release.
136+
137+
* `AMD_COMGR_CACHE`: When unset or set to 0, the cache is turned off.
138+
* `AMD_COMGR_CACHE_DIR`: When set to "", the cache is turned off. If assigned a
139+
value, that value is used as the path for cache storage. By default, it is
140+
directed to "$XDG_CACHE_HOME/comgr_cache" (which defaults to
141+
"$USER/.cache/comgr_cache" on Linux, and "%LOCALAPPDATA%\cache\comgr_cache"
142+
on Microsoft Windows).
143+
* `AMD_COMGR_CACHE_POLICY`: If assigned a value, the string is interpreted and
144+
applied to the cache pruning policy. The cache is pruned only upon program
145+
termination. The string format aligns with [Clang's ThinLTO cache pruning policy](https://clang.llvm.org/docs/ThinLTO.html#cache-pruning).
146+
The default policy is set as: "prune_interval=1h:prune_expiration=0h:cache_size=75%:cache_size_bytes=30g:cache_size_files=0".
147+
128148
Comgr also supports some environment variables to aid in debugging. These
129149
include:
130150

amd/comgr/cmake/DeviceLibs.cmake

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ foreach(AMDGCN_LIB_TARGET ${AMD_DEVICE_LIBS_TARGETS})
5959
add_dependencies(amd_comgr ${AMDGCN_LIB_TARGET}_header)
6060

6161
list(APPEND TARGETS_INCLUDES "#include \"${header}\"")
62+
list(APPEND TARGETS_HEADERS "${INC_DIR}/${header}")
6263
endforeach()
6364

6465
list(JOIN TARGETS_INCLUDES "\n" TARGETS_INCLUDES)
@@ -110,4 +111,17 @@ list(APPEND TARGETS_DEFS "#undef AMD_DEVICE_LIBS_FUNCTION")
110111
list(JOIN TARGETS_DEFS "\n" TARGETS_DEFS)
111112
file(GENERATE OUTPUT ${GEN_LIBRARY_DEFS_INC_FILE} CONTENT "${TARGETS_DEFS}")
112113

114+
# compute the sha256 of the device libraries to detect changes and pass them to comgr (used by the cache)
115+
find_package(Python3 REQUIRED Interpreter)
116+
set(DEVICE_LIBS_ID_SCRIPT "${CMAKE_CURRENT_SOURCE_DIR}/cmake/device-libs-id.py")
117+
set(DEVICE_LIBS_ID_HEADER ${INC_DIR}/libraries_sha.inc)
118+
add_custom_command(OUTPUT ${DEVICE_LIBS_ID_HEADER}
119+
COMMAND ${Python3_EXECUTABLE} ${DEVICE_LIBS_ID_SCRIPT} --varname DEVICE_LIBS_ID --output ${DEVICE_LIBS_ID_HEADER} ${TARGETS_HEADERS}
120+
DEPENDS ${DEVICE_LIBS_ID_SCRIPT} ${TARGETS_HEADERS}
121+
COMMENT "Generating ${INC_DIR}/libraries_sha.inc"
122+
)
123+
set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES ${INC_DIR}/libraries_sha.inc)
124+
add_custom_target(libraries_sha_header DEPENDS ${INC_DIR}/libraries_sha.inc)
125+
add_dependencies(amd_comgr libraries_sha_header)
126+
113127
include_directories(${INC_DIR})

amd/comgr/cmake/device-libs-id.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
from argparse import ArgumentParser
2+
from hashlib import sha256
3+
from functools import reduce
4+
5+
if __name__ == "__main__":
6+
parser = ArgumentParser(description='Generate id by computing a hash of the generated headers')
7+
parser.add_argument("headers", nargs='+', help='List of headers to generate id from')
8+
parser.add_argument("--varname", help='Name of the variable to generate', required=True)
9+
parser.add_argument("--output", help='Name of the header to generate', required=True)
10+
11+
args = parser.parse_args()
12+
args.headers.sort()
13+
14+
hash = sha256()
15+
for x in args.headers:
16+
hash.update(open(x, 'rb').read())
17+
digest_uchar = hash.digest()
18+
digest_char = [e if e < 128 else e-256 for e in digest_uchar]
19+
digest_elts = ", ".join(map(str, digest_char))
20+
print(f"static const char {args.varname}[] = {{{digest_elts}, 0}};", file=open(args.output, 'w'))

amd/comgr/cmake/opencl_pch.cmake

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,3 +50,7 @@ endfunction()
5050

5151
generate_pch(1.2)
5252
generate_pch(2.0)
53+
54+
# hash the opencl header and pass the result to comgr compilation
55+
file(SHA256 ${OPENCL_C_H} OPENCL_C_SHA)
56+
list(APPEND AMD_COMGR_PRIVATE_COMPILE_DEFINITIONS "OPENCL_C_SHA=${OPENCL_C_SHA}")
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::V3HeaderSize;
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

0 commit comments

Comments
 (0)