blob: 409e5667b6f165d704125f6050b5f1a8d1147bf7 [file] [log] [blame] [edit]
//===--- Level Zero Target RTL Implementation -----------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// Level Zero RTL Options support.
//
//===----------------------------------------------------------------------===//
#include "omptarget.h"
#include "L0Defs.h"
#include "L0Options.h"
#include "L0Trace.h"
namespace llvm::omp::target::plugin {
/// Read environment variables.
void L0OptionsTy::processEnvironmentVars() {
// Compilation options for IGC.
UserCompilationOptions +=
std::string(" ") +
StringEnvar("LIBOMPTARGET_LEVEL_ZERO_COMPILATION_OPTIONS", "").get();
// Memory pool syntax:
// LIBOMPTARGET_LEVEL_ZERO_MEMORY_POOL=<Option>
// <Option> := 0 | <PoolInfoList>
// <PoolInfoList> := <PoolInfo>[,<PoolInfoList>]
// <PoolInfo> := <MemType>[,<AllocMax>[,<Capacity>[,<PoolSize>]]]
// <MemType> := all | device | host | shared
// <AllocMax> := non-negative integer or empty, max allocation size in
// MB (default: 1).
// <Capacity> := positive integer or empty, number of allocations from
// a single block (default: 4).
// <PoolSize> := positive integer or empty, max pool size in MB
// (default: 256).
const StringEnvar MemoryPoolVar("LIBOMPTARGET_LEVEL_ZERO_MEMORY_POOL", "");
if (MemoryPoolVar.isPresent()) {
if (MemoryPoolVar.get() == "0") {
Flags.UseMemoryPool = 0;
MemPoolConfig.fill({false, 0, 0, 0});
} else {
std::istringstream Str(MemoryPoolVar.get());
int32_t MemType = -1;
int32_t Offset = 0;
int32_t Valid = 1;
constexpr std::array<int32_t, 3> DefaultValue{1, 4, 256};
constexpr int32_t AllMemType =
std::numeric_limits<decltype(AllMemType)>::max();
std::array<int32_t, 3> AllInfo{1, 4, 256};
std::array<std::array<int32_t, 3>, 3> PoolInfo;
PoolInfo.fill({-1, 0, 0});
for (std::string Token; std::getline(Str, Token, ',') && Valid > 0;) {
if (Token == "device") {
MemType = TARGET_ALLOC_DEVICE;
PoolInfo[TARGET_ALLOC_DEVICE] = DefaultValue;
Offset = 0;
} else if (Token == "host") {
MemType = TARGET_ALLOC_HOST;
PoolInfo[TARGET_ALLOC_HOST] = DefaultValue;
Offset = 0;
} else if (Token == "shared") {
MemType = TARGET_ALLOC_SHARED;
PoolInfo[TARGET_ALLOC_SHARED] = DefaultValue;
Offset = 0;
} else if (Token == "all") {
MemType = AllMemType;
Offset = 0;
Valid = 2;
} else if (Offset < 3 && MemType >= 0) {
int32_t Num = std::atoi(Token.c_str());
bool ValidNum = (Num >= 0 && Offset == 0) || (Num > 0 && Offset > 0);
if (ValidNum && MemType == AllMemType)
AllInfo[Offset++] = Num;
else if (ValidNum)
PoolInfo[MemType][Offset++] = Num;
else if (Token.size() == 0)
Offset++;
else
Valid = 0;
} else {
Valid = 0;
}
}
if (Valid > 0) {
if (Valid == 2) {
// "all" is specified -- ignore other inputs.
if (AllInfo[0] > 0) {
MemPoolConfig[TARGET_ALLOC_DEVICE] = {true, AllInfo[0], AllInfo[1],
AllInfo[2]};
MemPoolConfig[TARGET_ALLOC_HOST] = {true, AllInfo[0], AllInfo[1],
AllInfo[2]};
MemPoolConfig[TARGET_ALLOC_SHARED] = {true, AllInfo[0], AllInfo[1],
AllInfo[2]};
} else {
MemPoolConfig.fill({false, 0, 0, 0});
}
} else {
for (size_t Pool = 0; Pool < PoolInfo.size(); ++Pool) {
switch (PoolInfo[Pool][0]) {
case -1:
// No value was specified, keep the default.
break;
case 0:
// Pool was disabled.
MemPoolConfig[Pool] = {false, 0, 0, 0};
break;
default:
// Use the user specified values.
MemPoolConfig[Pool] = {true, PoolInfo[Pool][0], PoolInfo[Pool][1],
PoolInfo[Pool][2]};
break;
}
}
}
} else {
DP("Ignoring incorrect memory pool configuration "
"LIBOMPTARGET_LEVEL_ZERO_MEMORY_POOL=%s\n",
MemoryPoolVar.get().c_str());
DP("LIBOMPTARGET_LEVEL_ZERO_MEMORY_POOL=<Option>\n");
DP(" <Option> := 0 | <PoolInfoList>\n");
DP(" <PoolInfoList> := <PoolInfo>[,<PoolInfoList>]\n");
DP(" <PoolInfo> := "
"<MemType>[,<AllocMax>[,<Capacity>[,<PoolSize>]]]\n");
DP(" <MemType> := all | device | host | shared\n");
DP(" <AllocMax> := non-negative integer or empty, "
"max allocation size in MB (default: 1)\n");
DP(" <Capacity> := positive integer or empty, "
"number of allocations from a single block (default: 4)\n");
DP(" <PoolSize> := positive integer or empty, "
"max pool size in MB (default: 256)\n");
}
}
}
if (StringEnvar("INTEL_ENABLE_OFFLOAD_ANNOTATIONS").isPresent()) {
// To match SYCL RT behavior, we just need to check whether
// INTEL_ENABLE_OFFLOAD_ANNOTATIONS is set. The actual value
// does not matter.
CommonSpecConstants.addConstant<char>(0xFF747469, 1);
}
// LIBOMPTARGET_LEVEL_ZERO_STAGING_BUFFER_SIZE=<SizeInKB>.
const Envar<size_t> StagingBufferSizeVar(
"LIBOMPTARGET_LEVEL_ZERO_STAGING_BUFFER_SIZE");
if (StagingBufferSizeVar.isPresent()) {
size_t SizeInKB = StagingBufferSizeVar;
if (SizeInKB > (16 << 10)) {
SizeInKB = (16 << 10);
DP("Staging buffer size is capped at %zu KB\n", SizeInKB);
}
StagingBufferSize = SizeInKB << 10;
}
// LIBOMPTARGET_LEVEL_ZERO_COMMAND_MODE=<Fmt>.
// <Fmt> := sync | async | async_ordered
// sync: perform synchronization after each command.
// async: perform synchronization when it is required.
// async_ordered: same as "async", but command is ordered.
// This option is ignored unless IMM is fully enabled on compute and copy.
// On Intel PVC GPU, when used with immediate command lists over Level Zero
// backend, a target region may involve multiple command submissions to the
// L0 copy queue and compute queue. L0 events are used for each submission
// (data transfer of a single item or kernel execution). When "async" is
// specified, a) each data transfer to device is submitted with an event.
// b) The kernel is submitted next with a dependence on all the previous
// data transfer events. The kernel also has an event associated with it.
// c) The data transfer from device will be submitted with a dependence on
// the kernel event. d) Finally wait on the host for all the events
// associated with the data transfer from device.
// The env-var also affects any "target update" constructs as well.
// The env-var only affects the L0 copy/ compute commands issued from a
// single target construct execution, not across multiple invocations.
const StringEnvar CommandModeVar("LIBOMPTARGET_LEVEL_ZERO_COMMAND_MODE");
if (CommandModeVar.isPresent()) {
if (match(CommandModeVar, "sync"))
CommandMode = CommandModeTy::Sync;
else if (match(CommandModeVar, "async"))
CommandMode = CommandModeTy::Async;
else if (match(CommandModeVar, "async_ordered"))
CommandMode = CommandModeTy::AsyncOrdered;
else
MESSAGE("Warning: Ignoring invalid value for "
"LIBOMPTARGET_LEVEL_ZERO_COMMAND_MODE=%s\n",
CommandModeVar.get().c_str());
}
// Detect if we need to enable compatibility with Level Zero debug mode.
ZeDebugEnabled = BoolEnvar("ZET_ENABLE_PROGRAM_DEBUGGING", false);
}
} // namespace llvm::omp::target::plugin