* Copyright (c) 2025 Huawei Technologies Co., Ltd.
* This program is free software, you can redistribute it and/or modify it under the terms and conditions of
* CANN Open Software License Agreement Version 2.0 (the "License").
* Please refer to the License for details. You may not use this file except in compliance with the License.
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
* See LICENSE in the root of the software repository for the full text of the License.
*/
* \file sk_options_manager.cpp
* \brief Implementation of SuperKernelOptionsManager and option value classes
*/
#include <cctype>
#include <array>
#include <vector>
#include <cstdlib>
#include <limits>
#include <string>
#include <unordered_set>
#include "sk_options_manager.h"
#include "sk_common.h"
#include "sk_log.h"
#include <nlohmann/json.hpp>
namespace {
constexpr size_t kMaxExtendOptionLength = 1024;
using DefaultOptionFactory = std::unique_ptr<OptOptionBase> (*)();
struct DefaultOptionFactoryEntry {
aclskOptionType optType;
DefaultOptionFactory factory;
};
const std::array<DefaultOptionFactoryEntry, static_cast<size_t>(aclskOptionType::SK_OPTION_MAX)>
DEFAULT_OPTION_FACTORIES = {{
{aclskOptionType::PRELOAD_CODE, []() -> std::unique_ptr<OptOptionBase> {
return std::make_unique<NumberOptOption>("preload_code", aclskOptionType::PRELOAD_CODE, 1, 0, 2);
}},
{aclskOptionType::SPLIT_MODE, []() -> std::unique_ptr<OptOptionBase> {
return std::make_unique<NumberOptOption>("split_mode", aclskOptionType::SPLIT_MODE, 4, 1, 4);
}},
{aclskOptionType::STREAM_FUSION, []() -> std::unique_ptr<OptOptionBase> {
return std::make_unique<NumberOptOption>("stream_fusion", aclskOptionType::STREAM_FUSION, 1, 0, 1);
}},
{aclskOptionType::DCCI_DISABLE_ON_KERNEL, []() -> std::unique_ptr<OptOptionBase> {
return std::make_unique<StringListOptOption>(
"dcci_disable_on_kernel", aclskOptionType::DCCI_DISABLE_ON_KERNEL);
}},
{aclskOptionType::DEBUG_SYNC_ALL, []() -> std::unique_ptr<OptOptionBase> {
return std::make_unique<NumberOptOption>("debug_sync_all", aclskOptionType::DEBUG_SYNC_ALL, 0, 0, 1);
}},
{aclskOptionType::KERNEL_MAP, []() -> std::unique_ptr<OptOptionBase> {
return std::make_unique<OptOptionBase>("kernel_map", aclskOptionType::KERNEL_MAP);
}},
{aclskOptionType::CONSTANT_CODEGEN, []() -> std::unique_ptr<OptOptionBase> {
return std::make_unique<NumberOptOption>(
"constant_codegen", aclskOptionType::CONSTANT_CODEGEN, 0, 0, 1);
}},
{aclskOptionType::AUTO_OP_PARALLEL, []() -> std::unique_ptr<OptOptionBase> {
return std::make_unique<NumberOptOption>(
"auto_op_parallel", aclskOptionType::AUTO_OP_PARALLEL, 0, 0, 1);
}},
{aclskOptionType::DCCI_BEFORE_KERNEL_START, []() -> std::unique_ptr<OptOptionBase> {
return std::make_unique<StringListOptOption>(
"dcci_before_kernel_start", aclskOptionType::DCCI_BEFORE_KERNEL_START);
}},
{aclskOptionType::DEBUG_OP_EXEC_TRACE, []() -> std::unique_ptr<OptOptionBase> {
return std::make_unique<NumberOptOption>(
"debug_op_exec_trace", aclskOptionType::DEBUG_OP_EXEC_TRACE, 0, 0, 1);
}},
{aclskOptionType::DEBUG_CROSS_CORE_SYNC_CHECK, []() -> std::unique_ptr<OptOptionBase> {
return std::make_unique<NumberOptOption>(
"debug_cross_core_sync_check", aclskOptionType::DEBUG_CROSS_CORE_SYNC_CHECK, 0, 0, 1);
}},
{aclskOptionType::OPT_EXTEND_OPTION, []() -> std::unique_ptr<OptOptionBase> {
return std::make_unique<MapOptOption>("opt_extend_option", aclskOptionType::OPT_EXTEND_OPTION);
}},
{aclskOptionType::DEBUG_EXTEND_OPTION, []() -> std::unique_ptr<OptOptionBase> {
return std::make_unique<MapOptOption>("debug_extend_option", aclskOptionType::DEBUG_EXTEND_OPTION);
}},
{aclskOptionType::DCCI_AFTER_KERNEL_END, []() -> std::unique_ptr<OptOptionBase> {
return std::make_unique<StringListOptOption>(
"dcci_after_kernel_end", aclskOptionType::DCCI_AFTER_KERNEL_END);
}},
{aclskOptionType::AGGRESSIVE_OPT_STRATEGIES, []() -> std::unique_ptr<OptOptionBase> {
return std::make_unique<AggressiveOptStrategiesOption>(
"aggressive_opt_strategies", aclskOptionType::AGGRESSIVE_OPT_STRATEGIES);
}},
{aclskOptionType::UBUF_LOCK_IGNORE_KERNEL, []() -> std::unique_ptr<OptOptionBase> {
return std::make_unique<StringListOptOption>(
"ubuf_lock_ignore_kernel", aclskOptionType::UBUF_LOCK_IGNORE_KERNEL);
}},
{aclskOptionType::EARLY_START, []() -> std::unique_ptr<OptOptionBase> {
return std::make_unique<NumberOptOption>(
"early_start", aclskOptionType::EARLY_START,
aclskEarlyStartValue::ACLSK_EARLY_START_DISABLED,
aclskEarlyStartValue::ACLSK_EARLY_START_DISABLED,
aclskEarlyStartValue::ACLSK_EARLY_START_ENABLED);
}},
{aclskOptionType::DEBUG_PER_OP_MAX_CORE_NUM, []() -> std::unique_ptr<OptOptionBase> {
return std::make_unique<NumberOptOption>(
"debug_per_op_max_core_num", aclskOptionType::DEBUG_PER_OP_MAX_CORE_NUM, 0, 0, 1);
}},
}};
const DefaultOptionFactoryEntry* FindDefaultOptionFactory(aclskOptionType optType)
{
for (const auto& entry : DEFAULT_OPTION_FACTORIES) {
if (entry.optType == optType) {
return &entry;
}
}
return nullptr;
}
using DefaultInnerOptionFactory = std::unique_ptr<OptOptionBase> (*)();
struct DefaultInnerOptionFactoryEntry {
SkInnerOptionType optType;
DefaultInnerOptionFactory factory;
};
const std::array<DefaultInnerOptionFactoryEntry, static_cast<size_t>(SkInnerOptionType::SK_INNER_OPTION_MAX)>
DEFAULT_INNER_OPTION_FACTORIES = {{
{SkInnerOptionType::ENABLE_MIX_KERNEL_SPLIT, []() -> std::unique_ptr<OptOptionBase> {
return std::make_unique<NumberOptOption>("enable_mix_kernel_split",
aclskOptionType::SK_OPTION_MAX, 0, 0, 1);
}},
{SkInnerOptionType::ENABLE_SIMT_OP_CHECK, []() -> std::unique_ptr<OptOptionBase> {
return std::make_unique<NumberOptOption>("enable_simt_op_check",
aclskOptionType::SK_OPTION_MAX, 0, 0, 1);
}},
}};
const DefaultInnerOptionFactoryEntry* FindDefaultInnerOptionFactory(SkInnerOptionType optType)
{
for (const auto& entry : DEFAULT_INNER_OPTION_FACTORIES) {
if (entry.optType == optType) {
return &entry;
}
}
return nullptr;
}
uint32_t GetValidatedUintValue(const std::string& optionName, uint32_t value, uint32_t defaultValue,
uint32_t minValue, uint32_t maxValue)
{
if (value < minValue || value > maxValue) {
SK_LOGW("OptionName: %s, set value is invalid, value is %u, valid range is [%u, %u],"
" the process will use default value: %u",
optionName.c_str(), value, minValue, maxValue, defaultValue);
return defaultValue;
}
SK_LOGI("OptionName: %s, set value: %u", optionName.c_str(), value);
return value;
}
std::string TrimString(const std::string& input)
{
size_t start = 0;
while (start < input.size() && std::isspace(static_cast<unsigned char>(input[start])) != 0) {
++start;
}
size_t end = input.size();
while (end > start && std::isspace(static_cast<unsigned char>(input[end - 1])) != 0) {
--end;
}
return input.substr(start, end - start);
}
std::vector<std::string> SplitString(const std::string& input, char delimiter)
{
std::vector<std::string> tokens;
size_t start = 0;
while (start <= input.size()) {
size_t end = input.find(delimiter, start);
if (end == std::string::npos) {
tokens.push_back(input.substr(start));
break;
}
tokens.push_back(input.substr(start, end - start));
start = end + 1;
}
return tokens;
}
bool IsValidExtendOptionToken(const std::string& token, bool allowSlash)
{
if (token.empty()) {
return false;
}
for (char ch : token) {
const unsigned char uchar = static_cast<unsigned char>(ch);
if (std::isalnum(uchar) != 0 || ch == '_' || ch == '-' || ch == '.') {
continue;
}
if (allowSlash && ch == '/') {
continue;
}
return false;
}
return true;
}
bool ParseAndValidateExtendOptionValue(const char* rawValue, const std::string& optionName,
std::unordered_map<std::string, std::vector<std::string>>& parsedValue)
{
if (rawValue == nullptr) {
SK_LOGW("OptionName:%s, raw extend value is nullptr", optionName.c_str());
return false;
}
const std::string input(rawValue);
if (input.size() > kMaxExtendOptionLength) {
SK_LOGW("OptionName:%s, raw extend value is too long: %zu", optionName.c_str(), input.size());
return false;
}
const std::string trimmedInput = TrimString(input);
if (trimmedInput.empty()) {
SK_LOGW("OptionName:%s, raw extend value is empty after trim", optionName.c_str());
return false;
}
std::unordered_map<std::string, std::vector<std::string>> tmpResult;
const std::vector<std::string> pairs = SplitString(trimmedInput, ':');
for (const std::string& rawPair : pairs) {
const std::string pair = TrimString(rawPair);
if (pair.empty()) {
SK_LOGW("OptionName:%s, extend pair is empty", optionName.c_str());
return false;
}
const size_t eqPos = pair.find('=');
if (eqPos == std::string::npos || eqPos == 0 || eqPos == pair.size() - 1 ||
pair.find('=', eqPos + 1) != std::string::npos) {
SK_LOGW("OptionName:%s, extend pair format is invalid: %s", optionName.c_str(), pair.c_str());
return false;
}
const std::string key = TrimString(pair.substr(0, eqPos));
if (!IsValidExtendOptionToken(key, false)) {
SK_LOGW("OptionName:%s, extend key is invalid: %s", optionName.c_str(), key.c_str());
return false;
}
if (tmpResult.find(key) != tmpResult.end()) {
SK_LOGW("OptionName:%s, extend key is duplicated: %s", optionName.c_str(), key.c_str());
return false;
}
const std::vector<std::string> rawValues = SplitString(pair.substr(eqPos + 1), ',');
std::vector<std::string> valueList;
valueList.reserve(rawValues.size());
for (const std::string& rawSubValue : rawValues) {
const std::string value = TrimString(rawSubValue);
if (!IsValidExtendOptionToken(value, true)) {
SK_LOGW("OptionName:%s, extend value is invalid: %s", optionName.c_str(), value.c_str());
return false;
}
valueList.push_back(value);
}
tmpResult.emplace(key, std::move(valueList));
}
parsedValue = std::move(tmpResult);
return true;
}
}
void NumberOptOption::SetValue(const uint32_t value) {
if (value < optValueMin || value > optValueMax) {
SK_LOGW("OptionName: %s, set value is invalid, value is %u, valid range is [%u, %u],"
" the process will use default value: %u",
optionName.c_str(), value, optValueMin, optValueMax, optValue);
return;
}
SK_LOGI("OptionName: %s, set value: %u", optionName.c_str(), value);
optValue = value;
}
uint32_t NumberOptOption::GetIntValue() const {
return optValue;
}
void StringOptOption::SetValue(const std::string& value) {
if (value.empty()) {
SK_LOGW("OptionName: %s, set value is invalid, value is empty", optionName.c_str());
return;
}
SK_LOGI("OptionName: %s, set value: %s", optionName.c_str(), value.c_str());
optValue = value;
}
std::string StringOptOption::GetStringValue() const {
return optValue;
}
void StringListOptOption::SetValue(const std::vector<std::string>& value) {
if (value.empty()) {
SK_LOGW("OptionName: %s, set value is invalid, value is empty", optionName.c_str());
return;
}
for (size_t i = 0; i < value.size(); i++) {
SK_LOGI("OptionName:%s, value[%zu]: %s", optionName.c_str(), i, value[i].c_str());
}
optValue = value;
}
std::vector<std::string> StringListOptOption::GetStringListValue() const {
return optValue;
}
void MapOptOption::SetValue(const std::unordered_map<std::string, std::vector<std::string>>& value) {
if (value.empty()) {
SK_LOGW("OptionName:%s, set value is invalid, value is empty", optionName.c_str());
return;
}
for (const auto& pair : value) {
const std::string& key = pair.first;
const std::vector<std::string>& valList = pair.second;
SK_LOGI("OptionName:%s, key: %s, values:", optionName.c_str(), key.c_str());
for (const auto& val : valList) {
SK_LOGI(" %s", val.c_str());
}
}
optValue = value;
}
std::unordered_map<std::string, std::vector<std::string>> MapOptOption::GetMapValue() const {
return optValue;
}
void SuperKernelOptionsManager::AddOption(std::unique_ptr<OptOptionBase> option) {
if (option == nullptr) {
SK_LOGI("option is nullptr");
return;
}
auto iter = optionMap.find(option->GetType());
if (iter != optionMap.end()) {
SK_LOGW("OptionName:%s, already exists", option->GetName().c_str());
return;
}
optionMap[option->GetType()] = std::move(option);
}
OptOptionBase* SuperKernelOptionsManager::GetOption(aclskOptionType optType) {
auto iter = optionMap.find(optType);
if (iter == optionMap.end()) {
return nullptr;
}
return iter->second.get();
}
const OptOptionBase* SuperKernelOptionsManager::GetOption(aclskOptionType optType) const {
auto iter = optionMap.find(optType);
if (iter == optionMap.end()) {
return nullptr;
}
return iter->second.get();
}
OptOptionBase* SuperKernelOptionsManager::GetOption(SkInnerOptionType optType) {
auto iter = innerOptionMap.find(optType);
if (iter == innerOptionMap.end()) {
return nullptr;
}
return iter->second.get();
}
const OptOptionBase* SuperKernelOptionsManager::GetOption(SkInnerOptionType optType) const {
auto iter = innerOptionMap.find(optType);
if (iter == innerOptionMap.end()) {
return nullptr;
}
return iter->second.get();
}
bool SuperKernelOptionsManager::MatchKernelNameInList(
const std::vector<std::string>& kernelList, const std::string& kernelName) const {
for (size_t i = 0; i < kernelList.size(); i++) {
if (MatchRegex(kernelList[i], kernelName)) {
SK_LOGI("kernel: %s matches pattern: %s", kernelName.c_str(), kernelList[i].c_str());
return true;
}
}
return false;
}
bool SuperKernelOptionsManager::JudgeUbufLockIgnoreKernel(const std::vector<std::string>& ignoredKernels,
const std::string& opName) const {
for (const auto& ignoredKernel : ignoredKernels) {
if (MatchRegex(ignoredKernel, opName)) {
SK_LOGI("op: %s match ubuf lock ignore kernel option: %s, op will ignore mix kernel split",
opName.c_str(), ignoredKernel.c_str());
return true;
}
}
return false;
}
static bool IsValidRegexPattern(const std::string& pattern) {
if (pattern.empty()) {
return false;
}
for (char ch : pattern) {
const unsigned char uchar = static_cast<unsigned char>(ch);
if (std::isalnum(uchar) != 0 || ch == '_' || ch == '-' || ch == '.' || ch == '*') {
continue;
}
return false;
}
return true;
}
bool SuperKernelOptionsManager::MatchRegex(const std::string& pattern, const std::string& opName) {
const std::string trimmedPattern = TrimString(pattern);
if (trimmedPattern.empty()) {
SK_LOGE("pattern is empty after trim");
return false;
}
if (!IsValidRegexPattern(trimmedPattern)) {
SK_LOGE("pattern contains invalid characters, only alphanumeric, '_', '-', '.', '*' are allowed: %s",
trimmedPattern.c_str());
return false;
}
if (trimmedPattern[0] == '*') {
SK_LOGE("invalid pattern starts with '*': %s", trimmedPattern.c_str());
return false;
}
size_t m = opName.size();
size_t n = trimmedPattern.size();
auto matches = [&](size_t i, size_t j) {
if (i == 0 || j == 0) {
return false;
}
if (trimmedPattern[j - 1] == '.') {
return true;
}
return opName[i - 1] == trimmedPattern[j - 1];
};
std::vector<std::vector<size_t>> matchFlag(m + 1, std::vector<size_t>(n + 1));
matchFlag[0][0] = true;
for (size_t i = 0; i <= m; ++i) {
for (size_t j = 1; j <= n; ++j) {
if (trimmedPattern[j - 1] == '*') {
if (j >= 2) {
matchFlag[i][j] |= matchFlag[i][j - 2];
if (matches(i, j - 1)) {
matchFlag[i][j] |= matchFlag[i - 1][j];
}
}
}
else {
if (matches(i, j)) {
matchFlag[i][j] |= matchFlag[i - 1][j - 1];
}
}
}
}
return matchFlag[m][n];
}
bool SuperKernelOptionsManager::EnableDebug() const {
auto iterSyncAll = optionMap.find(aclskOptionType::DEBUG_SYNC_ALL);
const bool enableSyncAll =
(iterSyncAll != optionMap.end() && iterSyncAll->second != nullptr && iterSyncAll->second->GetIntValue() == 1);
if (enableSyncAll) {
SK_LOGI("debug mode enabled");
return true;
}
return false;
}
void SuperKernelOptionsManager::RegisterDefaultSkOptions()
{
for (int32_t i = 0; i < static_cast<int32_t>(aclskOptionType::SK_OPTION_MAX); ++i) {
auto type = static_cast<aclskOptionType>(i);
if (optionMap.find(type) != optionMap.end()) {
continue;
}
const auto* entry = FindDefaultOptionFactory(type);
if (entry == nullptr) {
continue;
}
optionMap[type] = entry->factory();
}
}
void SuperKernelOptionsManager::RegisterDefaultInnerOptions()
{
for (int32_t i = 0; i < static_cast<int32_t>(SkInnerOptionType::SK_INNER_OPTION_MAX); ++i) {
auto type = static_cast<SkInnerOptionType>(i);
if (innerOptionMap.find(type) != innerOptionMap.end()) {
continue;
}
const auto* entry = FindDefaultInnerOptionFactory(type);
if (entry == nullptr) {
continue;
}
innerOptionMap[type] = entry->factory();
}
}
void SuperKernelOptionsManager::ApplySoCSpecificOptions()
{
std::string socName = GetSocName();
bool isDav3510 = GetCurrentSkKernelArch() == SkKernelArch::DAV_3510;
if (isDav3510) {
auto* mixSplitOpt = GetOption(SkInnerOptionType::ENABLE_MIX_KERNEL_SPLIT);
if (mixSplitOpt != nullptr) {
mixSplitOpt->SetValue(1);
}
auto* simtCheckOpt = GetOption(SkInnerOptionType::ENABLE_SIMT_OP_CHECK);
if (simtCheckOpt != nullptr) {
simtCheckOpt->SetValue(1);
}
}
SK_LOGI("ApplySoCSpecificOptions: socName=%s, "
"enableMixKernelSplit=%u, enableSimtOpCheck=%u",
socName.c_str(),
GetOption(SkInnerOptionType::ENABLE_MIX_KERNEL_SPLIT) != nullptr ?
GetOption(SkInnerOptionType::ENABLE_MIX_KERNEL_SPLIT)->GetIntValue() : 0,
GetOption(SkInnerOptionType::ENABLE_SIMT_OP_CHECK) != nullptr ?
GetOption(SkInnerOptionType::ENABLE_SIMT_OP_CHECK)->GetIntValue() : 0);
}
void SuperKernelOptionsManager::RegisterDefaultOptions()
{
RegisterDefaultSkOptions();
RegisterDefaultInnerOptions();
ApplySoCSpecificOptions();
}
void SuperKernelOptionsManager::SetOptOptionValue(const aclskOption* option) {
if (option == nullptr) {
SK_LOGW("sub aclskOption is nullptr");
return;
}
auto type = option->optionType;
auto iter = optionMap.find(type);
if (iter == optionMap.end()) {
const auto* entry = FindDefaultOptionFactory(type);
if (entry != nullptr) {
optionMap[type] = entry->factory();
iter = optionMap.find(type);
}
}
if (iter == optionMap.end()) {
SK_LOGI("Optiontype: %d is not support now", static_cast<int>(type));
return;
}
auto* subOption = iter->second.get();
switch (type) {
case aclskOptionType::PRELOAD_CODE:
subOption->SetValue(option->preload.preloadMode);
break;
case aclskOptionType::SPLIT_MODE:
subOption->SetValue(option->splitMode.splitCnt);
break;
case aclskOptionType::DCCI_DISABLE_ON_KERNEL:
{
std::vector<std::string> vecValue;
const size_t kernelCnt = static_cast<size_t>(option->disableKernelDcci.kernelCnt);
if (kernelCnt > 0 && option->disableKernelDcci.kernelNames == nullptr) {
SK_LOGW("OptionName:%s, kernelNames is nullptr while kernelCnt is %zu",
subOption->GetName().c_str(), kernelCnt);
break;
}
vecValue.reserve(kernelCnt);
for (size_t i = 0; i < kernelCnt; i++) {
if (option->disableKernelDcci.kernelNames[i] == nullptr) {
SK_LOGW("OptionName:%s, kernelNames[%zu] is nullptr, skip",
subOption->GetName().c_str(), i);
continue;
}
vecValue.push_back(std::string(option->disableKernelDcci.kernelNames[i]));
}
subOption->SetValue(vecValue);
break;
}
case aclskOptionType::DCCI_BEFORE_KERNEL_START:
{
std::vector<std::string> vecValue;
const size_t kernelCnt = static_cast<size_t>(option->dcciBeforeKernelStart.kernelCnt);
if (kernelCnt > 0 && option->dcciBeforeKernelStart.kernelNames == nullptr) {
SK_LOGW("OptionName:%s, kernelNames is nullptr while kernelCnt is %zu",
subOption->GetName().c_str(), kernelCnt);
break;
}
vecValue.reserve(kernelCnt);
for (size_t i = 0; i < kernelCnt; i++) {
if (option->dcciBeforeKernelStart.kernelNames[i] == nullptr) {
SK_LOGW("OptionName:%s, kernelNames[%zu] is nullptr, skip",
subOption->GetName().c_str(), i);
continue;
}
vecValue.push_back(std::string(option->dcciBeforeKernelStart.kernelNames[i]));
}
subOption->SetValue(vecValue);
break;
}
case aclskOptionType::DCCI_AFTER_KERNEL_END:
{
std::vector<std::string> vecValue;
const size_t kernelCnt = static_cast<size_t>(option->dcciAfterKernelEnd.kernelCnt);
if (kernelCnt > 0 && option->dcciAfterKernelEnd.kernelNames == nullptr) {
SK_LOGW("OptionName:%s, kernelNames is nullptr while kernelCnt is %zu",
subOption->GetName().c_str(), kernelCnt);
break;
}
vecValue.reserve(kernelCnt);
for (size_t i = 0; i < kernelCnt; i++) {
if (option->dcciAfterKernelEnd.kernelNames[i] == nullptr) {
SK_LOGW("OptionName:%s, kernelNames[%zu] is nullptr, skip",
subOption->GetName().c_str(), i);
continue;
}
vecValue.push_back(std::string(option->dcciAfterKernelEnd.kernelNames[i]));
}
subOption->SetValue(vecValue);
break;
}
case aclskOptionType::AGGRESSIVE_OPT_STRATEGIES:
{
auto* aggressiveOpt = static_cast<AggressiveOptStrategiesOption*>(subOption);
auto aggressiveOpts = option->aggressiveOpts;
aggressiveOpts.eventBreakerBypass = GetValidatedUintValue(
"event_breaker_bypass",
option->aggressiveOpts.eventBreakerBypass,
0,
0,
std::numeric_limits<decltype(option->aggressiveOpts.eventBreakerBypass)>::max());
aggressiveOpts.valueBreakerBypass = GetValidatedUintValue(
"value_breaker_bypass",
option->aggressiveOpts.valueBreakerBypass,
ACLSK_VALUE_BREAKER_BYPASS_NONE,
ACLSK_VALUE_BREAKER_BYPASS_NONE,
std::numeric_limits<decltype(option->aggressiveOpts.valueBreakerBypass)>::max());
aggressiveOpts.taskBreakerBypass = GetValidatedUintValue(
"task_breaker_bypass", option->aggressiveOpts.taskBreakerBypass, 0, 0, 1);
SK_LOGI("Aggressive opt strategies set: eventBreakerBypass=%u, valueBreakerBypass=%u, "
"taskBreakerBypass=%u",
aggressiveOpts.eventBreakerBypass, aggressiveOpts.valueBreakerBypass,
aggressiveOpts.taskBreakerBypass);
aggressiveOpt->SetValue(aggressiveOpts);
break;
}
case aclskOptionType::UBUF_LOCK_IGNORE_KERNEL:
{
std::vector<std::string> vecValue;
const size_t kernelCnt = static_cast<size_t>(
option->ubufLockIgnoreKernel.ubufLockIgnoreKernelCnt);
if (kernelCnt > 0 && option->ubufLockIgnoreKernel.ubufLockIgnoreKernel == nullptr) {
SK_LOGW("OptionName:%s, ubufLockIgnoreKernel is nullptr while kernelCnt is %zu",
subOption->GetName().c_str(), kernelCnt);
break;
}
vecValue.reserve(kernelCnt);
for (size_t i = 0; i < kernelCnt; i++) {
if (option->ubufLockIgnoreKernel.ubufLockIgnoreKernel[i] == nullptr) {
SK_LOGW("OptionName:%s, ubufLockIgnoreKernel[%zu] is nullptr, skip",
subOption->GetName().c_str(), i);
continue;
}
vecValue.push_back(std::string(option->ubufLockIgnoreKernel.ubufLockIgnoreKernel[i]));
}
subOption->SetValue(vecValue);
break;
}
case aclskOptionType::DEBUG_SYNC_ALL:
subOption->SetValue(option->debugSync.debugSyncAll);
break;
case aclskOptionType::OPT_EXTEND_OPTION:
{
std::unordered_map<std::string, std::vector<std::string>> parsedValue;
if (ParseAndValidateExtendOptionValue(
option->optExtend.value, subOption->GetName(), parsedValue)) {
subOption->SetValue(parsedValue);
}
break;
}
case aclskOptionType::DEBUG_EXTEND_OPTION:
{
std::unordered_map<std::string, std::vector<std::string>> parsedValue;
if (ParseAndValidateExtendOptionValue(
option->debugExtend.value, subOption->GetName(), parsedValue)) {
subOption->SetValue(parsedValue);
}
break;
}
case aclskOptionType::STREAM_FUSION:
subOption->SetValue(option->streamFusion.streamFusion);
break;
case aclskOptionType::CONSTANT_CODEGEN:
subOption->SetValue(option->constantCodegen.enableConstant);
SK_LOGI("Constant codegen option set: enable=%u", option->constantCodegen.enableConstant);
break;
case aclskOptionType::AUTO_OP_PARALLEL:
subOption->SetValue(option->autoOpParallel.enableAutoOpParallel);
SK_LOGI("Auto op parallel option set: enable=%u", option->autoOpParallel.enableAutoOpParallel);
break;
case aclskOptionType::DEBUG_CROSS_CORE_SYNC_CHECK:
subOption->SetValue(option->debugCrossCoreSyncCheck.enableCrossCoreSyncCheck);
SK_LOGI("Debug cross-core sync check option set: enable=%u",
option->debugCrossCoreSyncCheck.enableCrossCoreSyncCheck);
break;
case aclskOptionType::DEBUG_OP_EXEC_TRACE:
subOption->SetValue(option->debugOpExecTrace.enableOpExecTrace);
SK_LOGI("Debug op exec trace option set: enable=%u",
option->debugOpExecTrace.enableOpExecTrace);
break;
case aclskOptionType::EARLY_START:
subOption->SetValue(option->earlyStart.enableEarlyStart);
SK_LOGI("Early start option set: enable=%u", option->earlyStart.enableEarlyStart);
break;
case aclskOptionType::DEBUG_PER_OP_MAX_CORE_NUM:
subOption->SetValue(option->debugPerOpMaxCoreNum.enableDebugPerOpMaxCoreNum);
SK_LOGI("Debug per op max core num option set: enable=%u",
option->debugPerOpMaxCoreNum.enableDebugPerOpMaxCoreNum);
if (option->debugPerOpMaxCoreNum.enableDebugPerOpMaxCoreNum == 1) {
auto crossCoreSyncOpt = GetOption(aclskOptionType::DEBUG_CROSS_CORE_SYNC_CHECK);
if (crossCoreSyncOpt == nullptr || crossCoreSyncOpt->GetIntValue() != 1) {
aclskOption crossCoreSyncOption;
crossCoreSyncOption.optionType = aclskOptionType::DEBUG_CROSS_CORE_SYNC_CHECK;
crossCoreSyncOption.debugCrossCoreSyncCheck.enableCrossCoreSyncCheck = 1;
SetOptOptionValue(&crossCoreSyncOption);
SK_LOGI("[DEBUG_PER_OP_MAX_CORE_NUM] auto-enabled DEBUG_CROSS_CORE_SYNC_CHECK");
}
}
break;
default:
SK_LOGI("Optiontype: %d is not support now", static_cast<int>(type));
break;
}
}
void SuperKernelOptionsManager::ParseOptions(const aclskOptions* options) {
RegisterDefaultOptions();
if (options == nullptr) {
SK_LOGI("aclskOption is nullptr");
return;
}
SK_LOGI("Options nums: %d", static_cast<int>(options->numOptions));
if (options->numOptions > 0 && options->options == nullptr) {
SK_LOGW("aclskOptions options is nullptr while numOptions is %zu", options->numOptions);
return;
}
std::unordered_set<aclskOptionType> parsedTypes;
for (size_t i = 0; i < static_cast<size_t>(options->numOptions); i++) {
const aclskOptionType optionType = options->options[i].optionType;
if (parsedTypes.find(optionType) != parsedTypes.end()) {
const auto iter = optionMap.find(optionType);
const char* optionName = (iter != optionMap.end() && iter->second != nullptr) ?
iter->second->GetName().c_str() : "unsupported";
SK_LOGW("OptionName %s already parsed", optionName);
continue;
}
parsedTypes.insert(optionType);
SetOptOptionValue(&options->options[i]);
}
}
nlohmann::ordered_json SuperKernelOptionsManager::ToJson() const
{
nlohmann::ordered_json optionsJson = nlohmann::ordered_json::object();
for (int32_t i = 0; i < static_cast<int32_t>(aclskOptionType::SK_OPTION_MAX); ++i) {
auto type = static_cast<aclskOptionType>(i);
const auto iter = optionMap.find(type);
if (iter == optionMap.end()) {
continue;
}
const OptOptionBase* opt = iter->second.get();
if (opt == nullptr) {
continue;
}
nlohmann::ordered_json optJson;
optJson["name"] = opt->GetName();
optJson["type"] = static_cast<int>(type);
switch (type) {
case aclskOptionType::PRELOAD_CODE:
case aclskOptionType::SPLIT_MODE:
case aclskOptionType::DEBUG_SYNC_ALL:
case aclskOptionType::STREAM_FUSION:
case aclskOptionType::CONSTANT_CODEGEN:
case aclskOptionType::AUTO_OP_PARALLEL:
case aclskOptionType::DEBUG_CROSS_CORE_SYNC_CHECK:
case aclskOptionType::DEBUG_OP_EXEC_TRACE:
case aclskOptionType::EARLY_START:
case aclskOptionType::DEBUG_PER_OP_MAX_CORE_NUM:
optJson["value"] = opt->GetIntValue();
break;
case aclskOptionType::DCCI_DISABLE_ON_KERNEL:
case aclskOptionType::DCCI_BEFORE_KERNEL_START:
case aclskOptionType::DCCI_AFTER_KERNEL_END:
case aclskOptionType::UBUF_LOCK_IGNORE_KERNEL:
optJson["value"] = opt->GetStringListValue();
break;
case aclskOptionType::OPT_EXTEND_OPTION:
case aclskOptionType::DEBUG_EXTEND_OPTION:
optJson["value"] = opt->GetMapValue();
break;
case aclskOptionType::AGGRESSIVE_OPT_STRATEGIES:
{
const auto* aggressiveOpt = static_cast<const AggressiveOptStrategiesOption*>(opt);
const auto& value = aggressiveOpt->GetValue();
optJson["value"] = {
{"eventBreakerBypass", value.eventBreakerBypass},
{"valueBreakerBypass", value.valueBreakerBypass},
{"taskBreakerBypass", value.taskBreakerBypass}
};
break;
}
default:
optJson["value"] = nullptr;
break;
}
optionsJson[opt->GetName()] = optJson;
}
nlohmann::ordered_json innerOptionsJson = nlohmann::ordered_json::object();
for (int32_t i = 0; i < static_cast<int32_t>(SkInnerOptionType::SK_INNER_OPTION_MAX); ++i) {
auto type = static_cast<SkInnerOptionType>(i);
const auto iter = innerOptionMap.find(type);
if (iter == innerOptionMap.end() || iter->second == nullptr) {
continue;
}
const OptOptionBase* opt = iter->second.get();
nlohmann::ordered_json optJson;
optJson["name"] = opt->GetName();
optJson["type"] = static_cast<int>(type);
switch (type) {
case SkInnerOptionType::ENABLE_MIX_KERNEL_SPLIT:
case SkInnerOptionType::ENABLE_SIMT_OP_CHECK:
optJson["value"] = opt->GetIntValue();
break;
default:
optJson["value"] = nullptr;
break;
}
innerOptionsJson[opt->GetName()] = optJson;
}
optionsJson["inner_options"] = innerOptionsJson;
return optionsJson;
}