Skip to content

Commit 3332d18

Browse files
authored
[COMGR] Add VFS support for device library linking (llvm#776)
This commit adds support for linking device library files through the use of a Virtual File System (VFS). Change-Id: I27f1dccfe772ebe9d11f4a570a05d0b9d55a705d
1 parent 7f25952 commit 3332d18

16 files changed

+410
-13
lines changed

amd/comgr/README.md

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

145-
Comgr also supports some environment variables to aid in debugging. These
145+
Comgr supports some environment variables to aid in debugging. These
146146
include:
147147

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

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

amd/comgr/docs/ReleaseNotes.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,17 @@ 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, a user can explicitly dictate if
42+
device libraries should be linked using a Virtual File System (VFS).
3843

3944
Deprecated APIs
4045
---------------

amd/comgr/include/amd_comgr.h.in

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,18 @@ extern "C" {
225225
*/
226226
#define AMD_COMGR_VERSION_2_9
227227

228+
/**
229+
* The function was introduced or changed in version 3.0 of the interface
230+
* and has the symbol version string of ``"@amd_comgr_NAME@_3.0"``.
231+
*/
232+
#define AMD_COMGR_VERSION_3_0
233+
234+
/**
235+
* The function was introduced or changed in version 3.1 of the interface
236+
* and has the symbol version string of ``"@amd_comgr_NAME@_3.1"``.
237+
*/
238+
#define AMD_COMGR_VERSION_3_1
239+
228240
/** @} */
229241

230242
/**
@@ -1420,6 +1432,41 @@ amd_comgr_action_info_get_bundle_entry_id(
14201432
size_t *size,
14211433
char *bundle_entry_id) AMD_COMGR_VERSION_2_8;
14221434

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

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
@@ -532,6 +532,11 @@ SmallString<128> getFilePath(DataObject *Object, StringRef Dir) {
532532
return Path;
533533
}
534534

535+
// TODO: Move inputFromFile and outputToFile within AMDGPUCompiler
536+
//
537+
// Currently, we only invoke these two methods in the context of AMDGPUCompiler.
538+
// Moreover, member functions that deal with file I/O should not worry whether
539+
// the underlying filesystem being used is virtual or real.
535540
amd_comgr_status_t inputFromFile(DataObject *Object, StringRef Path) {
536541
ProfilePoint Point("FileIO");
537542
auto BufOrError = MemoryBuffer::getFile(Path);
@@ -625,7 +630,7 @@ void logArgv(raw_ostream &OS, StringRef ProgramName,
625630

626631
amd_comgr_status_t executeCommand(const Command &Job, raw_ostream &LogS,
627632
DiagnosticOptions &DiagOpts,
628-
llvm::vfs::FileSystem &VFS) {
633+
llvm::vfs::FileSystem &FS) {
629634
TextDiagnosticPrinter DiagClient(LogS, &DiagOpts);
630635
IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs);
631636
DiagnosticsEngine Diags(DiagID, &DiagOpts, &DiagClient, false);
@@ -651,17 +656,19 @@ amd_comgr_status_t executeCommand(const Command &Job, raw_ostream &LogS,
651656

652657
std::unique_ptr<CompilerInstance> Clang(new CompilerInstance());
653658
Clang->setVerboseOutputStream(LogS);
659+
Clang->setFileManager(new FileManager(Clang->getFileSystemOpts(), &FS));
654660
if (!Argv.back()) {
655661
Argv.pop_back();
656662
}
663+
657664
if (!CompilerInvocation::CreateFromArgs(Clang->getInvocation(), Argv,
658665
Diags)) {
659666
return AMD_COMGR_STATUS_ERROR;
660667
}
661668
// Internally this call refers to the invocation created above, so at
662669
// this point the DiagnosticsEngine should accurately reflect all user
663670
// requested configuration from Argv.
664-
Clang->createDiagnostics(VFS, &DiagClient, /* ShouldOwnClient */ false);
671+
Clang->createDiagnostics(FS, &DiagClient, /* ShouldOwnClient */ false);
665672
if (!Clang->hasDiagnostics()) {
666673
return AMD_COMGR_STATUS_ERROR;
667674
}
@@ -734,12 +741,11 @@ AMDGPUCompiler::executeInProcessDriver(ArrayRef<const char *> Args) {
734741
IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs);
735742
DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagClient);
736743

737-
auto VFS = llvm::vfs::getRealFileSystem();
738-
ProcessWarningOptions(Diags, *DiagOpts, *VFS, /*ReportDiags=*/false);
744+
ProcessWarningOptions(Diags, *DiagOpts, *OverlayFS, /*ReportDiags=*/false);
739745

740746
Driver TheDriver((Twine(env::getLLVMPath()) + "/bin/clang").str(),
741747
llvm::sys::getDefaultTargetTriple(), Diags,
742-
"AMDGPU Code Object Manager", VFS);
748+
"AMDGPU Code Object Manager", OverlayFS);
743749
TheDriver.setCheckInputsExist(false);
744750

745751
// Log arguments used to build compilation
@@ -761,7 +767,7 @@ AMDGPUCompiler::executeInProcessDriver(ArrayRef<const char *> Args) {
761767

762768
auto Cache = CommandCache::get(LogS);
763769
for (auto &Job : C->getJobs()) {
764-
ClangCommand C(Job, *DiagOpts, *VFS, executeCommand);
770+
ClangCommand C(Job, *DiagOpts, *OverlayFS, executeCommand);
765771
if (Cache) {
766772
if (auto Status = Cache->execute(C, LogS)) {
767773
return Status;
@@ -1075,8 +1081,18 @@ amd_comgr_status_t AMDGPUCompiler::addDeviceLibraries() {
10751081
for (auto DeviceLib : getDeviceLibraries()) {
10761082
llvm::SmallString<128> DeviceLibPath = DeviceLibsDir;
10771083
path::append(DeviceLibPath, std::get<0>(DeviceLib));
1078-
if (auto Status = outputToFile(std::get<1>(DeviceLib), DeviceLibPath)) {
1079-
return Status;
1084+
// TODO: We should abstract the logic of deciding whether to use the VFS
1085+
// or the real file system within inputFromFile and outputToFile.
1086+
if (UseVFS) {
1087+
if (!InMemoryFS->addFile(
1088+
DeviceLibPath, /* ModificationTime */ 0,
1089+
llvm::MemoryBuffer::getMemBuffer(std::get<1>(DeviceLib)))) {
1090+
return AMD_COMGR_STATUS_ERROR;
1091+
}
1092+
} else {
1093+
if (auto Status = outputToFile(std::get<1>(DeviceLib), DeviceLibPath)) {
1094+
return Status;
1095+
}
10801096
}
10811097
}
10821098
}
@@ -2074,6 +2090,25 @@ AMDGPUCompiler::AMDGPUCompiler(DataAction *ActionInfo, DataSet *InSet,
20742090
: ActionInfo(ActionInfo), InSet(InSet), OutSetT(DataSet::convert(OutSet)),
20752091
LogS(LogS) {
20762092
initializeCommandLineArgs(Args);
2093+
2094+
// Initialize OverlayFS with the real file system which helps redirect
2095+
// non-VFS reads and writes.
2096+
OverlayFS = new vfs::OverlayFileSystem(vfs::getRealFileSystem());
2097+
2098+
std::optional<bool> VFSStatus = env::shouldUseVFS();
2099+
if ((VFSStatus.has_value() && *VFSStatus) ||
2100+
(!VFSStatus.has_value() && ActionInfo->ShouldUseVFS)) {
2101+
if (env::shouldEmitVerboseLogs()) {
2102+
LogS << " File System: VFS\n";
2103+
}
2104+
UseVFS = true;
2105+
InMemoryFS = new vfs::InMemoryFileSystem;
2106+
OverlayFS->pushOverlay(InMemoryFS);
2107+
} else {
2108+
if (env::shouldEmitVerboseLogs()) {
2109+
LogS << " File System: Real\n";
2110+
}
2111+
}
20772112
}
20782113

20792114
AMDGPUCompiler::~AMDGPUCompiler() {

amd/comgr/src/comgr-compiler.h

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

1212
#include "comgr.h"
1313
#include "clang/Driver/Driver.h"
14+
#include "llvm/Support/VirtualFileSystem.h"
1415

1516
namespace COMGR {
1617

@@ -36,6 +37,10 @@ class AMDGPUCompiler {
3637
llvm::StringSaver Saver = Allocator;
3738
/// Whether we need to disable Clang's device-lib linking.
3839
bool NoGpuLib = true;
40+
bool UseVFS = false;
41+
42+
llvm::IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> OverlayFS;
43+
llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFS;
3944

4045
amd_comgr_status_t createTmpDirs();
4146
amd_comgr_status_t removeTmpDirs();

amd/comgr/src/comgr-env.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,21 @@ bool shouldSaveLLVMTemps() {
3131
return SaveTemps && StringRef(SaveTemps) != "0";
3232
}
3333

34+
std::optional<bool> shouldUseVFS() {
35+
if (shouldSaveTemps())
36+
return false;
37+
38+
static char *UseVFS = getenv("AMD_COMGR_USE_VFS");
39+
if (UseVFS) {
40+
if (StringRef(UseVFS) == "0")
41+
return false;
42+
else if (StringRef(UseVFS) == "1")
43+
return true;
44+
}
45+
46+
return std::nullopt;
47+
}
48+
3449
std::optional<StringRef> getRedirectLogs() {
3550
static char *RedirectLogs = getenv("AMD_COMGR_REDIRECT_LOGS");
3651
if (!RedirectLogs || StringRef(RedirectLogs) == "0") {

amd/comgr/src/comgr-env.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ namespace env {
1717
/// Return whether the environment requests temps be saved.
1818
bool shouldSaveTemps();
1919
bool shouldSaveLLVMTemps();
20+
std::optional<bool> shouldUseVFS();
2021

2122
/// If the environment requests logs be redirected, return the string identifier
2223
/// 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
@@ -1169,6 +1169,22 @@ amd_comgr_status_t AMD_COMGR_API
11691169
return ActionP->setBundleEntryIDs(ArrayRef<const char *>(EntryIDs, Count));
11701170
}
11711171

1172+
amd_comgr_status_t AMD_COMGR_API
1173+
// NOLINTNEXTLINE(readability-identifier-naming)
1174+
amd_comgr_action_info_set_vfs
1175+
//
1176+
(amd_comgr_action_info_t ActionInfo, bool ShouldUseVFS) {
1177+
DataAction *ActionP = DataAction::convert(ActionInfo);
1178+
1179+
if (!ActionP) {
1180+
return AMD_COMGR_STATUS_ERROR_INVALID_ARGUMENT;
1181+
}
1182+
1183+
ActionP->ShouldUseVFS = ShouldUseVFS;
1184+
1185+
return AMD_COMGR_STATUS_SUCCESS;
1186+
}
1187+
11721188
amd_comgr_status_t AMD_COMGR_API
11731189
// NOLINTNEXTLINE(readability-identifier-naming)
11741190
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
@@ -204,6 +204,7 @@ struct DataAction {
204204
amd_comgr_language_t Language;
205205
bool Logging;
206206
bool ShouldLinkDeviceLibs = false;
207+
bool ShouldUseVFS = false;
207208

208209
std::vector<std::string> BundleEntryIDs;
209210

0 commit comments

Comments
 (0)