* Copyright (c) Huawei Technologies Co., Ltd. 2026-2026. All rights reserved.
* ubs-engine is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* 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 FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
#include "ubse_mem_scheduler_request.h"
#include "ubse_logger.h"
#include "ubse_math_util.h"
#include "ubse_mem_scheduler_node_manager.h"
namespace ubse::mem::scheduler {
UBSE_DEFINE_THIS_MODULE("ubse_mem_scheduler");
SchedulerRequest SchedulerRequest::BuildFromFdBorrow(const adapter_plugins::mmi::UbseMemFdBorrowReq& req)
{
SchedulerRequest schedulerReq;
schedulerReq.name_ = req.name;
schedulerReq.requestNodeId_ = req.requestNodeId;
schedulerReq.importNodeId_ = req.importNodeId;
schedulerReq.requestSize_ = req.size;
schedulerReq.filterNames_ = {
"ConfigConsistencyFilter", "RoleConflictFilter", "LenderRoleFilter", "GroupFilter",
"ProviderFilter", "NodeStateFilter", "RadiusBorrowFilter", "RadiusLenderFilter",
"LendCountFilter", "TopoReachabilityFilter", "MaxLentSizeFilter", "FreeMemoryFilter"};
if (!req.candidateNodeList.empty()) {
schedulerReq.provideNodes_ = req.candidateNodeList;
schedulerReq.filterNames_.emplace_back("RequestedProvidersFilter");
}
if (!req.lenderLocs.empty()) {
std::vector<adapter_plugins::mmi::UbseMemLenderInfo> lenderInfos;
for (size_t i = 0; i < req.lenderLocs.size(); ++i) {
adapter_plugins::mmi::UbseMemLenderInfo info{};
info.nodeId = req.lenderLocs[i].nodeId;
info.numaId = req.lenderLocs[i].numaId;
if (i >= req.lenderSizes.size()) {
UBSE_LOG_WARN << "lenderSizes.size()=" << req.lenderSizes.size()
<< " < lenderLocs.size()=" << req.lenderLocs.size() << ", lender[" << i
<< "] has no size, defaulting to 0";
}
info.lender_size = (i < req.lenderSizes.size()) ? req.lenderSizes[i] : 0;
lenderInfos.push_back(info);
}
schedulerReq.params_["lenderInfos"] = lenderInfos;
schedulerReq.filterNames_.emplace_back("SpecifiedLenderFilter");
}
schedulerReq.requestMode_ = RequestMode::BORROW;
return schedulerReq;
}
SchedulerRequest SchedulerRequest::BuildFromNumaBorrow(const adapter_plugins::mmi::UbseMemNumaBorrowReq& req)
{
SchedulerRequest schedulerReq;
schedulerReq.name_ = req.name;
schedulerReq.importNodeId_ = req.importNodeId;
schedulerReq.requestNodeId_ = req.requestNodeId;
schedulerReq.requestSize_ = req.size;
size_t highWatermark = req.highWatermark;
if (highWatermark > MAX_PERCENT) {
UBSE_LOG_WARN << "highWatermark=" << highWatermark << " exceeds MAX_PERCENT, capping to " << MAX_PERCENT;
highWatermark = MAX_PERCENT;
}
schedulerReq.params_["highWatermark"] = highWatermark;
schedulerReq.filterNames_ = {
"ConfigConsistencyFilter", "RoleConflictFilter", "LenderRoleFilter", "GroupFilter",
"ProviderFilter", "NodeStateFilter", "RadiusBorrowFilter", "RadiusLenderFilter",
"LendCountFilter", "TopoReachabilityFilter", "MaxLentSizeFilter", "FreeMemoryFilter"};
if (req.linkInfo.lenderSocketId != -1) {
schedulerReq.params_["linkInfo"] = req.linkInfo;
schedulerReq.filterNames_.emplace_back("SpecifiedLinkFilter");
} else if (!req.lenderLocs.empty()) {
std::vector<adapter_plugins::mmi::UbseMemLenderInfo> lenderInfos;
for (size_t i = 0; i < req.lenderLocs.size(); ++i) {
adapter_plugins::mmi::UbseMemLenderInfo info{};
info.nodeId = req.lenderLocs[i].nodeId;
info.numaId = req.lenderLocs[i].numaId;
if (i >= req.lenderSizes.size()) {
UBSE_LOG_WARN << "lenderSizes.size()=" << req.lenderSizes.size()
<< " < lenderLocs.size()=" << req.lenderLocs.size() << ", lender[" << i
<< "] has no size, defaulting to 0";
}
info.lender_size = (i < req.lenderSizes.size()) ? req.lenderSizes[i] : 0;
lenderInfos.push_back(info);
}
schedulerReq.params_["lenderInfos"] = lenderInfos;
schedulerReq.filterNames_.emplace_back("SpecifiedLenderFilter");
}
if (!req.candidateNodeList.empty()) {
schedulerReq.provideNodes_ = req.candidateNodeList;
schedulerReq.filterNames_.emplace_back("RequestedProvidersFilter");
}
if (req.srcSocket != -1) {
schedulerReq.filterNames_.emplace_back("SocketAffinityFilter");
schedulerReq.params_["affinitySocketId"] = req.srcSocket;
}
schedulerReq.requestMode_ = RequestMode::BORROW;
return schedulerReq;
}
SchedulerRequest SchedulerRequest::BuildFromAddrBorrow(const adapter_plugins::mmi::UbseMemAddrBorrowReq& req)
{
SchedulerRequest schedulerReq;
schedulerReq.name_ = req.name;
schedulerReq.requestNodeId_ = req.requestNodeId;
schedulerReq.importNodeId_ = req.importNodeId;
schedulerReq.requestSize_ = 0;
for (const auto& addr : req.exportAddrList) {
if (!ubse::utils::SafeAdd(schedulerReq.requestSize_, addr.size, schedulerReq.requestSize_)) {
UBSE_LOG_ERROR << "requestSize overflow when summing exportAddrList";
schedulerReq.requestSize_ = UINT64_MAX / 2;
break;
}
}
schedulerReq.filterNames_ = {"LenderRoleFilter", "NodeStateFilter", "RoleConflictFilter"};
if (req.dstSocket != -1 && req.dstNuma != -1 && !req.exportAddrList.empty()) {
std::vector<adapter_plugins::mmi::UbseMemLenderInfo> lenderInfos;
adapter_plugins::mmi::UbseMemLenderInfo info{};
info.nodeId = req.exportNodeId;
info.socketId = static_cast<uint32_t>(req.dstSocket);
info.numaId = static_cast<uint32_t>(req.dstNuma);
lenderInfos.push_back(info);
schedulerReq.params_["lenderInfos"] = lenderInfos;
schedulerReq.filterNames_.emplace_back("SpecifiedLenderFilter");
}
schedulerReq.requestMode_ = RequestMode::BORROW;
schedulerReq.params_["isAddr"] = true;
return schedulerReq;
}
SchedulerRequest SchedulerRequest::BuildFromShareBorrow(const adapter_plugins::mmi::UbseMemShareBorrowReq& req)
{
SchedulerRequest schedulerReq;
schedulerReq.name_ = req.name;
schedulerReq.requestNodeId_ = req.requestNodeId;
schedulerReq.requestSize_ = req.size;
schedulerReq.provideNodes_ = req.providerList;
schedulerReq.params_["shmRegion"] = req.shmRegion;
if (req.withAffinity.enableCreateWithAffinity) {
schedulerReq.params_["affinitySocketId"] = static_cast<int>(req.withAffinity.affinitySocketId);
}
schedulerReq.filterNames_ = {"ConfigConsistencyFilter", "LenderRoleFilter", "ProviderFilter",
"NodeStateFilter", "RegionFilter", "LendCountFilter",
"TopoReachabilityFilter", "MaxLentSizeFilter", "FreeMemoryFilter"};
if (!req.providerList.empty()) {
schedulerReq.filterNames_.emplace_back("RequestedProvidersFilter");
}
if (req.withAffinity.enableCreateWithAffinity) {
schedulerReq.filterNames_.emplace_back("SocketAffinityFilter");
}
if (req.lenderInfo.lender_size != 0) {
std::vector<adapter_plugins::mmi::UbseMemLenderInfo> lenderInfos;
lenderInfos.push_back(req.lenderInfo);
schedulerReq.params_["lenderInfos"] = lenderInfos;
schedulerReq.filterNames_.emplace_back("SpecifiedLenderFilter");
}
schedulerReq.requestMode_ = RequestMode::SHARE;
return schedulerReq;
}
SchedulerRequest SchedulerRequest::SetupFromNodeConf(SchedulerRequest&& req, SchedulerNodeManager* info)
{
if (req.requestMode_ == RequestMode::SHARE) {
req.scoreNames_ = {"LatencyScore", "RegionBalanceScore", "BalanceScore", "ShareReliabilityScore",
"DivideNumaScore"};
req.weights_ = ScoreWeights::ForShare();
return std::move(req);
}
auto mode = info->GetSchedulerMode();
switch (mode) {
case SchedulerMode::FreePriority:
req.scoreNames_ = {"LatencyScore", "RegionBalanceScore", "BalanceScore", "BorrowReliabilityScore",
"DivideNumaScore"};
req.weights_ = ScoreWeights::ForBorrow();
break;
case SchedulerMode::ReliabilityPriority:
req.scoreNames_ = {"LatencyScore", "RegionBalanceScore", "BalanceScore", "ReliabilityBalanceScore",
"DivideNumaScore"};
req.weights_ = ScoreWeights::ForLenderBalance();
req.params_["lenderBalance"] = true;
break;
case SchedulerMode::PerformancePriority:
req.scoreNames_ = {"LatencyScore", "RegionBalanceScore", "BalanceScore", "BorrowBandwidthScore",
"DivideNumaScore"};
req.weights_ = ScoreWeights::ForPerformancePriority();
req.params_["schedulerMode"] = std::string("performance-priority");
break;
default:
break;
}
return std::move(req);
}
}