Skip to content

Commit 3ab962c

Browse files
authored
[COMGR] Add VFS support for device library linking (llvm#2472)
1 parent 236ab35 commit 3ab962c

File tree

16 files changed

+417
-14
lines changed

16 files changed

+417
-14
lines changed

amd/comgr/README.md

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ By default, the cache is enabled.
145145
termination. The string format aligns with [Clang's ThinLTO cache pruning policy](https://clang.llvm.org/docs/ThinLTO.html#cache-pruning).
146146
The default policy is set as: "prune_interval=1h:prune_expiration=0h:cache_size=75%:cache_size_bytes=30g:cache_size_files=0".
147147

148-
Comgr also supports some environment variables to aid in debugging. These
148+
Comgr supports some environment variables to aid in debugging. These
149149
include:
150150

151151
* `AMD_COMGR_SAVE_TEMPS`: If this is set, and is not "0", Comgr does not delete
@@ -163,6 +163,20 @@ include:
163163
* `AMD_COMGR_TIME_STATISTICS`: If this is set, and is not "0", logs will
164164
include additional Comgr-specific timing information for compilation actions.
165165

166+
Comgr implements support for an in-memory, virtual filesystem (VFS) for storing
167+
temporaries generated during intermediate compilation steps. This is aimed at
168+
improving performance by reducing on-disk file I/O. Currently, VFS is only supported
169+
for the device library link step, but we aim to progressively add support for
170+
more actions.
171+
172+
By default, VFS is turned on.
173+
174+
* `AMD_COMGR_USE_VFS`: When set to "0", VFS support is turned off.
175+
* Users may use the API `amd_comgr_action_info_set_vfs` to disable VFS for individual actions
176+
without having to modify system-wide environment variables.
177+
* If `AMD_COMGR_SAVE_TEMPS` is set and not "0", VFS support is turned off irrespective
178+
of `AMD_COMGR_USE_VFS` or the use of `amd_comgr_action_info_set_vfs`.
179+
166180
Versioning
167181
----------
168182

amd/comgr/docs/ReleaseNotes.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,18 @@ behaviors:
2929
Extensions (the same license used by LLVM).
3030
- Added Image Support to Comgr's handling of ISA metadata. Support for images
3131
can now be queried with Comgr's metadata APIs.
32+
- Added support for linking device library files through the use of a Virtual
33+
File System (VFS).
3234

3335
Bug Fixes
3436
---------
3537

3638
New APIs
3739
--------
40+
- amd\_comgr\_info\_set\_vfs\_() (v3.1)
41+
- By setting this ActionInfo property, users can explicitly dictate if
42+
device libraries should be linked using the real file system or a
43+
Virtual File System (VFS).
3844

3945
Deprecated APIs
4046
---------------

amd/comgr/include/amd_comgr.h.in

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,18 @@ extern "C" {
234234
*/
235235
#define AMD_COMGR_VERSION_2_9
236236

237+
/**
238+
* The function was introduced or changed in version 3.0 of the interface
239+
* and has the symbol version string of ``"@amd_comgr_NAME@_3.0"``.
240+
*/
241+
#define AMD_COMGR_VERSION_3_0
242+
243+
/**
244+
* The function was introduced or changed in version 3.1 of the interface
245+
* and has the symbol version string of ``"@amd_comgr_NAME@_3.1"``.
246+
*/
247+
#define AMD_COMGR_VERSION_3_1
248+
237249
/** @} */
238250

239251
/**
@@ -1421,6 +1433,41 @@ amd_comgr_action_info_get_bundle_entry_id(
14211433
size_t *size,
14221434
char *bundle_entry_id) AMD_COMGR_VERSION_2_8;
14231435

1436+
/**
1437+
* @brief Set whether the specified action should use an
1438+
* in-memory virtual file system (VFS).
1439+
*
1440+
* @warning Environment variable @p AMD_COMGR_SAVE_TEMPS may override options
1441+
* set by this API and @p AMD_COMGR_USE_VFS. If @p AMD_COMGR_SAVE_TEMPS is set
1442+
* to "1", all actions are performed using the real file system irrespective of
1443+
* the value of @p should_use_vfs @p AMD_COMGR_USE_VFS;
1444+
*
1445+
* @warning Environment variable @p AMD_COMGR_USE_VFS may override options
1446+
* set by this API. If @p AMD_COMGR_USE_VFS is set to "1", all actions
1447+
* are performed using VFS. If @p AMD_COMGR_USE_VFS is set to "0",
1448+
* none of the actions are performed using VFS.
1449+
*
1450+
* If @p AMD_COMGR_USE_VFS is unset, this API can be used to selectively
1451+
* turn VFS usage on/off for specified actions.
1452+
*
1453+
* @param[in] action_info A handle to the action info object to be
1454+
* updated.
1455+
*
1456+
* @param[in] should_use_vfs A boolean that directs the choice to
1457+
* use the VFS.
1458+
*
1459+
* @retval ::AMD_COMGR_STATUS_SUCCESS The function has
1460+
* been executed successfully.
1461+
*
1462+
* @retval ::AMD_COMGR_STATUS_ERROR_INVALID_ARGUMENT @p
1463+
* action_info is an invalid action info object.
1464+
*
1465+
*/
1466+
amd_comgr_status_t AMD_COMGR_API
1467+
amd_comgr_action_info_set_vfs(
1468+
amd_comgr_action_info_t action_info,
1469+
bool should_use_vfs) AMD_COMGR_VERSION_3_1;
1470+
14241471
/**
14251472
* @brief Set the device library linking behavior of an action info object.
14261473
*

amd/comgr/src/amdcomgr.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,3 +48,4 @@ amd_comgr_action_info_set_bundle_entry_ids
4848
amd_comgr_action_info_get_bundle_entry_id_count
4949
amd_comgr_action_info_get_bundle_entry_id
5050
amd_comgr_action_info_set_device_lib_linking
51+
amd_comgr_action_info_set_vfs

amd/comgr/src/comgr-compiler.cpp

Lines changed: 43 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -553,6 +553,11 @@ SmallString<128> getFilePath(DataObject *Object, StringRef Dir) {
553553
return Path;
554554
}
555555

556+
// TODO: Move inputFromFile and outputToFile within AMDGPUCompiler
557+
//
558+
// Currently, we only invoke these two methods in the context of AMDGPUCompiler.
559+
// Moreover, member functions that deal with file I/O should not worry whether
560+
// the underlying filesystem being used is virtual or real.
556561
amd_comgr_status_t inputFromFile(DataObject *Object, StringRef Path) {
557562
ProfilePoint Point("FileIO");
558563
auto BufOrError = MemoryBuffer::getFile(Path);
@@ -646,7 +651,7 @@ void logArgv(raw_ostream &OS, StringRef ProgramName,
646651

647652
amd_comgr_status_t executeCommand(const Command &Job, raw_ostream &LogS,
648653
DiagnosticOptions &DiagOpts,
649-
llvm::vfs::FileSystem &VFS) {
654+
llvm::vfs::FileSystem &FS) {
650655
TextDiagnosticPrinter DiagClient(LogS, &DiagOpts);
651656
IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs);
652657
DiagnosticsEngine Diags(DiagID, &DiagOpts, &DiagClient, false);
@@ -672,17 +677,19 @@ amd_comgr_status_t executeCommand(const Command &Job, raw_ostream &LogS,
672677

673678
std::unique_ptr<CompilerInstance> Clang(new CompilerInstance());
674679
Clang->setVerboseOutputStream(LogS);
680+
Clang->setFileManager(new FileManager(Clang->getFileSystemOpts(), &FS));
675681
if (!Argv.back()) {
676682
Argv.pop_back();
677683
}
684+
678685
if (!CompilerInvocation::CreateFromArgs(Clang->getInvocation(), Argv,
679686
Diags)) {
680687
return AMD_COMGR_STATUS_ERROR;
681688
}
682689
// Internally this call refers to the invocation created above, so at
683690
// this point the DiagnosticsEngine should accurately reflect all user
684691
// requested configuration from Argv.
685-
Clang->createDiagnostics(VFS, &DiagClient, /* ShouldOwnClient */ false);
692+
Clang->createDiagnostics(FS, &DiagClient, /* ShouldOwnClient */ false);
686693
if (!Clang->hasDiagnostics()) {
687694
return AMD_COMGR_STATUS_ERROR;
688695
}
@@ -755,12 +762,11 @@ AMDGPUCompiler::executeInProcessDriver(ArrayRef<const char *> Args) {
755762
IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs);
756763
DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagClient);
757764

758-
auto VFS = llvm::vfs::getRealFileSystem();
759-
ProcessWarningOptions(Diags, *DiagOpts, *VFS, /*ReportDiags=*/false);
765+
ProcessWarningOptions(Diags, *DiagOpts, *OverlayFS, /*ReportDiags=*/false);
760766

761767
Driver TheDriver((Twine(env::getLLVMPath()) + "/bin/clang").str(),
762768
llvm::sys::getDefaultTargetTriple(), Diags,
763-
"AMDGPU Code Object Manager", VFS);
769+
"AMDGPU Code Object Manager", OverlayFS);
764770
TheDriver.setCheckInputsExist(false);
765771

766772
// Log arguments used to build compilation
@@ -782,7 +788,7 @@ AMDGPUCompiler::executeInProcessDriver(ArrayRef<const char *> Args) {
782788

783789
auto Cache = CommandCache::get(LogS);
784790
for (auto &Job : C->getJobs()) {
785-
ClangCommand C(Job, *DiagOpts, *VFS, executeCommand);
791+
ClangCommand C(Job, *DiagOpts, *OverlayFS, executeCommand);
786792
if (Cache) {
787793
if (auto Status = Cache->execute(C, LogS)) {
788794
return Status;
@@ -1089,8 +1095,18 @@ amd_comgr_status_t AMDGPUCompiler::addDeviceLibraries() {
10891095
for (auto DeviceLib : getDeviceLibraries()) {
10901096
llvm::SmallString<128> DeviceLibPath = DeviceLibsDir;
10911097
path::append(DeviceLibPath, std::get<0>(DeviceLib));
1092-
if (auto Status = outputToFile(std::get<1>(DeviceLib), DeviceLibPath)) {
1093-
return Status;
1098+
// TODO: We should abstract the logic of deciding whether to use the VFS
1099+
// or the real file system within inputFromFile and outputToFile.
1100+
if (UseVFS) {
1101+
if (!InMemoryFS->addFile(
1102+
DeviceLibPath, /* ModificationTime */ 0,
1103+
llvm::MemoryBuffer::getMemBuffer(std::get<1>(DeviceLib)))) {
1104+
return AMD_COMGR_STATUS_ERROR;
1105+
}
1106+
} else {
1107+
if (auto Status = outputToFile(std::get<1>(DeviceLib), DeviceLibPath)) {
1108+
return Status;
1109+
}
10941110
}
10951111
}
10961112
}
@@ -1944,6 +1960,25 @@ AMDGPUCompiler::AMDGPUCompiler(DataAction *ActionInfo, DataSet *InSet,
19441960
: ActionInfo(ActionInfo), InSet(InSet), OutSetT(DataSet::convert(OutSet)),
19451961
LogS(LogS) {
19461962
initializeCommandLineArgs(Args);
1963+
1964+
// Initialize OverlayFS with the real file system which helps redirect
1965+
// non-VFS reads and writes.
1966+
OverlayFS = new vfs::OverlayFileSystem(vfs::getRealFileSystem());
1967+
1968+
std::optional<bool> VFSStatus = env::shouldUseVFS();
1969+
if ((VFSStatus.has_value() && *VFSStatus) ||
1970+
(!VFSStatus.has_value() && ActionInfo->ShouldUseVFS)) {
1971+
if (env::shouldEmitVerboseLogs()) {
1972+
LogS << " File System: VFS\n";
1973+
}
1974+
UseVFS = true;
1975+
InMemoryFS = new vfs::InMemoryFileSystem;
1976+
OverlayFS->pushOverlay(InMemoryFS);
1977+
} else {
1978+
if (env::shouldEmitVerboseLogs()) {
1979+
LogS << " File System: Real\n";
1980+
}
1981+
}
19471982
}
19481983

19491984
AMDGPUCompiler::~AMDGPUCompiler() {

amd/comgr/src/comgr-compiler.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141

4242
#include "comgr.h"
4343
#include "clang/Driver/Driver.h"
44+
#include "llvm/Support/VirtualFileSystem.h"
4445

4546
namespace COMGR {
4647

@@ -72,6 +73,10 @@ class AMDGPUCompiler {
7273
llvm::StringSaver Saver = Allocator;
7374
/// Whether we need to disable Clang's device-lib linking.
7475
bool NoGpuLib = true;
76+
bool UseVFS = false;
77+
78+
llvm::IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> OverlayFS;
79+
llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFS;
7580

7681
amd_comgr_status_t createTmpDirs();
7782
amd_comgr_status_t removeTmpDirs();

amd/comgr/src/comgr-env.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,26 @@ bool shouldSaveTemps() {
4747
return SaveTemps && StringRef(SaveTemps) != "0";
4848
}
4949

50+
bool shouldSaveLLVMTemps() {
51+
static char *SaveTemps = getenv("AMD_COMGR_SAVE_LLVM_TEMPS");
52+
return SaveTemps && StringRef(SaveTemps) != "0";
53+
}
54+
55+
std::optional<bool> shouldUseVFS() {
56+
if (shouldSaveTemps())
57+
return false;
58+
59+
static char *UseVFS = getenv("AMD_COMGR_USE_VFS");
60+
if (UseVFS) {
61+
if (StringRef(UseVFS) == "0")
62+
return false;
63+
else if (StringRef(UseVFS) == "1")
64+
return true;
65+
}
66+
67+
return std::nullopt;
68+
}
69+
5070
std::optional<StringRef> getRedirectLogs() {
5171
static char *RedirectLogs = getenv("AMD_COMGR_REDIRECT_LOGS");
5272
if (!RedirectLogs || StringRef(RedirectLogs) == "0") {

amd/comgr/src/comgr-env.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ namespace env {
4343

4444
/// Return whether the environment requests temps be saved.
4545
bool shouldSaveTemps();
46+
bool shouldSaveLLVMTemps();
47+
std::optional<bool> shouldUseVFS();
4648

4749
/// If the environment requests logs be redirected, return the string identifier
4850
/// of where to redirect. Otherwise return @p None.

amd/comgr/src/comgr.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1186,6 +1186,22 @@ amd_comgr_status_t AMD_COMGR_API
11861186
return ActionP->setBundleEntryIDs(ArrayRef<const char *>(EntryIDs, Count));
11871187
}
11881188

1189+
amd_comgr_status_t AMD_COMGR_API
1190+
// NOLINTNEXTLINE(readability-identifier-naming)
1191+
amd_comgr_action_info_set_vfs
1192+
//
1193+
(amd_comgr_action_info_t ActionInfo, bool ShouldUseVFS) {
1194+
DataAction *ActionP = DataAction::convert(ActionInfo);
1195+
1196+
if (!ActionP) {
1197+
return AMD_COMGR_STATUS_ERROR_INVALID_ARGUMENT;
1198+
}
1199+
1200+
ActionP->ShouldUseVFS = ShouldUseVFS;
1201+
1202+
return AMD_COMGR_STATUS_SUCCESS;
1203+
}
1204+
11891205
amd_comgr_status_t AMD_COMGR_API
11901206
// NOLINTNEXTLINE(readability-identifier-naming)
11911207
amd_comgr_action_info_set_device_lib_linking

amd/comgr/src/comgr.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,7 @@ struct DataAction {
230230
amd_comgr_language_t Language;
231231
bool Logging;
232232
bool ShouldLinkDeviceLibs = false;
233+
bool ShouldUseVFS = true;
233234

234235
std::vector<std::string> BundleEntryIDs;
235236

0 commit comments

Comments
 (0)