| @@ -1,445 +1,557 @@ |
| -#include "torch_npu/csrc/core/npu/NPUAffinityController.h" | +#include <torch_npu/csrc/core/npu/NPUAffinityController.h> |
| -#include "torch_npu/csrc/core/npu/NPUFunctions.h" | |
| -#include "torch_npu/csrc/core/npu/GetAffinityCPUInfo.h" | |
| -#include "torch_npu/csrc/core/npu/NpuVariables.h" | |
| | |
| #include <pthread.h> | #include <pthread.h> |
| -#include <unistd.h> | |
| -#include <sys/syscall.h> | |
| #include <sys/prctl.h> | #include <sys/prctl.h> |
| +#include <sys/syscall.h> |
| +#include <unistd.h> |
| +#include <mutex> |
| +#include <regex> |
| +#include <set> |
| #include <string> | #include <string> |
| #include <unordered_map> | #include <unordered_map> |
| -#include <mutex> | + |
| +#include <torch_npu/csrc/core/npu/GetAffinityCPUInfo.h> |
| +#include <torch_npu/csrc/core/npu/NPUFunctions.h> |
| +#include <torch_npu/csrc/core/npu/NpuVariables.h> |
| | |
| namespace c10_npu { | namespace c10_npu { |
| | |
| -static thread_local ThreadType local_thread = ThreadType::MAIN_THREAD; | +namespace { |
| | |
| -static pthread_t main_thread; | +thread_local ThreadType local_thread = ThreadType::MAIN_THREAD; |
| -static bool start_main_thread_bind = false; | |
| -static std::mutex core_map_mutex; | |
| -static bool lazy_bind = true; | |
| -static bool force_bind = false; | |
| | |
| +pthread_t main_thread; |
| +bool start_main_thread_bind = false; |
| +std::mutex core_map_mutex; |
| +bool lazy_bind = true; |
| +bool force_bind = false; |
| | |
| -using ThreadCoreMap = std::unordered_map<ThreadType, CoreIdRange>; | +using ThreadCoreMap = std::unordered_map<ThreadType, CoreIdList>; |
| | |
| -static uint32_t cpu_affinity_mode; | +uint32_t cpu_affinity_mode; |
| -static std::vector<CoreIdRange> device_ranges; | +std::vector<CoreIdList> devices_aff_cores; |
| -static std::unordered_map<c10::DeviceIndex, ThreadCoreMap> device_thread_core_maps; | +std::unordered_map<c10::DeviceIndex, ThreadCoreMap> device_thread_core_maps; |
| | |
| -const std::initializer_list<ThreadType> threadTypeList = { | +const std::initializer_list<ThreadType> threadTypeList = |
| - MAIN_THREAD, ACL_THREAD, RELEASE_THREAD, WATCHDOG_THREAD, OTHER_THREAD}; | + {MAIN_THREAD, ACL_THREAD, RELEASE_THREAD, WATCHDOG_THREAD, OTHER_THREAD}; |
| | |
| const std::unordered_map<ThreadType, std::string> threadTypeToNameMap = { | const std::unordered_map<ThreadType, std::string> threadTypeToNameMap = { |
| - {MAIN_THREAD, "main_thread"}, | + {MAIN_THREAD, "main_thread"}, |
| - {ACL_THREAD, "acl_thread"}, | + {ACL_THREAD, "acl_thread"}, |
| - {RELEASE_THREAD, "release_thread"}, | + {RELEASE_THREAD, "release_thread"}, |
| - {WATCHDOG_THREAD, "hccl_watchdog_t"}, | + {WATCHDOG_THREAD, "hccl_watchdog_t"}, |
| - {OTHER_THREAD, "other_thread"}}; | + {OTHER_THREAD, "other_thread"}}; |
| | |
| -CoreIdRange getCPUDefaultRange(c10::DeviceIndex device_id) | +std::string formatCoreRange(const CoreIdList& cores) { |
| -{ | + if (cores.empty()) { |
| - static int core_nums = sysconf(_SC_NPROCESSORS_ONLN); | + return ""; |
| - int device_nums = device_count_ensure_non_zero(); | + } |
| - int block_size = (core_nums > 0 && device_nums > 0) ? core_nums / device_nums : 0; | |
| - return CoreIdRange{static_cast<CoreId>(device_id * block_size), | |
| - static_cast<CoreId>((device_id + 1) * block_size - 1)}; | |
| -} | |
| | |
| -inline bool isAllDigits(const std::string &str) | + std::ostringstream oss; |
| -{ | + auto it = cores.begin(); |
| - if (str.empty()) { | + while (it != cores.end()) { |
| - return false; | + CoreId start = *it; |
| - } | + CoreId end = start; |
| - return std::all_of(str.begin(), str.end(), [](unsigned char c) { | + auto next_it = std::next(it); |
| - return std::isdigit(c); | + while (next_it != cores.end() && *next_it == end + 1) { |
| - }); | + ++end; |
| -} | + ++next_it; |
| - | |
| -void parseCPUAffinityConf(uint32_t &mode, std::vector<CoreIdRange> &ranges) | |
| -{ | |
| - | |
| - int device_nums = device_count_ensure_non_zero(); | |
| - ranges.clear(); | |
| - ranges.resize(device_nums); | |
| - for (int i = 0; i < device_nums; ++i) { | |
| - ranges[i] = getCPUDefaultRange(i); | |
| - } | |
| - mode = 0; | |
| - | |
| - const char *input = c10_npu::option::OptionsManager::GetCpuAffinityConf(); | |
| - if (input == nullptr || strlen(input) == 0) { | |
| - return; | |
| } | } |
| | |
| - std::string inputStr(input); | + if (start == end) { |
| - std::istringstream stream(inputStr); | + oss << start; |
| - std::string option; | |
| - | |
| - std::regex pattern("npu_affine:(\\d)"); | |
| - std::smatch match; | |
| - if (std::regex_search(inputStr, match, pattern)) { | |
| - int isAffinity = std::stoi(match[1].str()); | |
| - if (isAffinity != 0) { | |
| - for (int i = 0; i < device_nums; i++) { | |
| - CoreIdRange getRange = GetAssignAffinityCPU(i); | |
| - if (getRange.start == 0 && getRange.end == 0) { | |
| - break; | |
| - } | |
| - ranges[i] = getRange; | |
| - } | |
| - } | |
| - } | |
| - | |
| - std::regex pattern_for_lazy_bind("lazy_bind:(\\d)"); | |
| - std::smatch match_for_lazy_bind; | |
| - if (std::regex_search(inputStr, match_for_lazy_bind, pattern_for_lazy_bind)) { | |
| - int lazy_bind_val = std::stoi(match_for_lazy_bind[1].str()); | |
| - if (lazy_bind_val == 0) { | |
| - lazy_bind = false; | |
| - } | |
| - } | |
| - | |
| - std::regex pattern_for_force("force:(\\d)"); | |
| - std::smatch match_for_force; | |
| - if (std::regex_search(inputStr, match_for_force, pattern_for_force)) { | |
| - int force_val = std::stoi(match_for_force[1].str()); | |
| - if (force_val != 0 && force_val != 1) { | |
| - ASCEND_LOGE("force value must be 0 or 1, got: %d", force_val); | |
| - } else { | |
| - force_bind = (force_val != 0); | |
| - } | |
| } else { | } else { |
| - std::regex pattern_for_force_check("force:([^,]+)"); | + oss << start << "-" << end; |
| - std::smatch match_for_force_check; | |
| - if (std::regex_search(inputStr, match_for_force_check, pattern_for_force_check)) { | |
| - ASCEND_LOGE("force value must be 0 or 1, got: %s", match_for_force_check[1].str().c_str()); | |
| - } | |
| } | } |
| | |
| - // Handle cases where only `mode` is provided, or `mode:` without value | + it = next_it; |
| - if (isAllDigits(inputStr)) { | + if (it != cores.end()) { |
| - mode = static_cast<uint32_t>(std::stoi(inputStr)); | + oss << ","; |
| - return; | |
| - } | |
| - | |
| - | |
| - while (std::getline(stream, option, ',')) { | |
| - | |
| - size_t colonPos = option.find(':'); | |
| - if (colonPos != std::string::npos) { | |
| - std::string key = option.substr(0, colonPos); | |
| - std::string value = option.substr(colonPos + 1); | |
| - | |
| - | |
| - if (key == "mode") { | |
| - if (isAllDigits(value)) { | |
| - mode = static_cast<uint32_t>(std::stoi(value)); | |
| - } else { | |
| - ASCEND_LOGW("mode is %s, should be all digits", value.c_str()); | |
| - } | |
| - } else if (key.rfind("npu", 0) == 0) { | |
| - | |
| - | |
| - if (isAllDigits(key.substr(3))) { | |
| - int device_id = std::stoi(key.substr(3)); | |
| - if (device_id < device_nums) { | |
| - size_t dashPos = value.find('-'); | |
| - if (dashPos != std::string::npos) { | |
| - std::string startStr = value.substr(0, dashPos); | |
| - std::string endStr = value.substr(dashPos + 1); | |
| - if (isAllDigits(startStr) && isAllDigits(endStr)) { | |
| - CoreId start = static_cast<CoreId>(std::stoi(startStr)); | |
| - CoreId end = static_cast<CoreId>(std::stoi(endStr)); | |
| - ranges[device_id] = {start, end}; | |
| - } else { | |
| - ASCEND_LOGW("core range is %s-%s, should be all digits", startStr.c_str(), endStr.c_str()); | |
| - } | |
| - } else { | |
| - if (isAllDigits(value)) { | |
| - CoreId singleCore = static_cast<CoreId>(std::stoi(value)); | |
| - ranges[device_id] = {singleCore, singleCore}; | |
| - } else { | |
| - ASCEND_LOGW("core range is string : %s, should be all digits", value.c_str()); | |
| - } | |
| - } | |
| - } | |
| - } | |
| - } | |
| - } else if (isAllDigits(option)) { | |
| - | |
| - mode = static_cast<uint32_t>(std::stoi(option)); | |
| - } | |
| } | } |
| + } |
| + return oss.str(); |
| } | } |
| | |
| -void printCoreRanges(const uint32_t mode, const std::vector<CoreIdRange> &ranges) | +CoreIdList getNPUDefaultCores(c10::DeviceIndex device_id) { |
| -{ | + static int core_nums = sysconf(_SC_NPROCESSORS_ONLN); |
| - std::ostringstream oss; | + int device_nums = device_count_ensure_non_zero(); |
| - oss << "Mode: " << mode << ". Core range for each device ID: "; | + int block_size = |
| - | + (core_nums > 0 && device_nums > 0) ? core_nums / device_nums : 0; |
| - for (size_t i = 0; i < ranges.size(); ++i) { | + CoreIdList cores; |
| - oss << "Device " << i << ": [" << ranges[i].start << ", " << ranges[i].end << "]"; | + for (int i = 0; i < block_size; ++i) { |
| - if (i != ranges.size() - 1) { | + cores.insert(static_cast<CoreId>(device_id * block_size + i)); |
| - oss << "; "; | + } |
| - } else { | + return cores; |
| - oss << "."; | |
| - } | |
| - } | |
| - | |
| - ASCEND_LOGD("Read CPU affinity config: %s", oss.str().c_str()); | |
| } | } |
| | |
| -bool getThreadAffinityInfo() | +// Parse npu_affine setting from CPU_AFFINITY_CONF |
| -{ | +void parseNpuAffineMode( |
| - parseCPUAffinityConf(cpu_affinity_mode, device_ranges); | + const std::string& inputStr, |
| - printCoreRanges(cpu_affinity_mode, device_ranges); | + int device_nums, |
| + std::vector<CoreIdList>& devices_aff_cores) { |
| + static const std::regex pattern("npu_affine:(\\d)"); |
| + std::smatch match; |
| + if (std::regex_search(inputStr, match, pattern) && |
| + std::stoi(match[1].str()) != 0) { |
| + ASCEND_LOGD( |
| + "Get npu_affine mode: %s, device_nums: %d, set affinity cores for each device.", |
| + match[1].str().c_str(), |
| + device_nums); |
| + for (int i = 0; i < device_nums; i++) { |
| + CoreIdList cores = GetAffinityCores(i); |
| + if (cores.size() == 0) { |
| + ASCEND_LOGW("Device-%d has no affinity cores.", i); |
| + continue; |
| + } |
| + devices_aff_cores[i] = cores; |
| + ASCEND_LOGD( |
| + "Device-%d affinity cores [%s].", |
| + i, |
| + formatCoreRange(devices_aff_cores[i]).c_str()); |
| + } |
| + } |
| +} |
| | |
| - if (cpu_affinity_mode == 0) { | +// Parse lazy_bind setting from CPU_AFFINITY_CONF |
| - return false; | +void parseLazyBindMode(const std::string& inputStr) { |
| - } | + std::regex pattern_for_lazy_bind("lazy_bind:(\\d)"); |
| + std::smatch match_for_lazy_bind; |
| + if (std::regex_search(inputStr, match_for_lazy_bind, pattern_for_lazy_bind)) { |
| + lazy_bind = std::stoi(match_for_lazy_bind[1].str()) == 0 ? false : true; |
| + } |
| +} |
| | |
| - if (force_bind) { | +// Parse force setting from CPU_AFFINITY_CONF |
| - ASCEND_LOGI("CPU affinity force mode enabled, skipping affinity conflict detection, applying CPU_AFFINITY_CONF binding."); | +void parseForceMode(const std::string& inputStr) { |
| - return true; | + std::regex pattern_for_force("force:(\\d)"); |
| + std::smatch match_for_force; |
| + if (std::regex_search(inputStr, match_for_force, pattern_for_force)) { |
| + int force_val = std::stoi(match_for_force[1].str()); |
| + if (force_val != 0 && force_val != 1) { |
| + ASCEND_LOGE("force value must be 0 or 1, got: %d", force_val); |
| + } else { |
| + force_bind = (force_val != 0); |
| } | } |
| + } else { |
| + std::regex pattern_for_force_check("force:([^,]+)"); |
| + std::smatch match_for_force_check; |
| + if (std::regex_search( |
| + inputStr, match_for_force_check, pattern_for_force_check)) { |
| + ASCEND_LOGE( |
| + "force value must be 0 or 1, got: %s", |
| + match_for_force_check[1].str().c_str()); |
| + } |
| + } |
| +} |
| | |
| - cpu_set_t mask; | +// Parse mode from CPU_AFFINITY_CONF when only digits or mode:xxx is provided |
| - pthread_getaffinity_np(pthread_self(), sizeof(mask), &mask); | +bool parseModeOnly(const std::string& inputStr, uint32_t& mode) { |
| - | + // Handle cases where only `mode` is provided, or `mode:` without value |
| - std::ostringstream affinity_oss; | + if (isAllDigits(inputStr)) { |
| - affinity_oss << "["; | + mode = static_cast<uint32_t>(std::stoi(inputStr)); |
| - int cpu_count = sysconf(_SC_NPROCESSORS_ONLN); | |
| - int range_start = -1; | |
| - bool first_range = true; | |
| - for (int k = 0; k < cpu_count; ++k) { | |
| - if (CPU_ISSET(k, &mask)) { | |
| - if (range_start == -1) { | |
| - range_start = k; | |
| - } | |
| - } else { | |
| - if (range_start != -1) { | |
| - if (!first_range) affinity_oss << ", "; | |
| - if (range_start == k - 1) { | |
| - affinity_oss << range_start; | |
| - } else { | |
| - affinity_oss << range_start << "-" << (k - 1); | |
| - } | |
| - range_start = -1; | |
| - first_range = false; | |
| - } | |
| - } | |
| - } | |
| - if (range_start != -1) { | |
| - if (!first_range) affinity_oss << ", "; | |
| - if (range_start == cpu_count - 1) { | |
| - affinity_oss << range_start; | |
| - } else { | |
| - affinity_oss << range_start << "-" << (cpu_count - 1); | |
| - } | |
| - } | |
| - affinity_oss << "]"; | |
| - ASCEND_LOGI("Current thread CPU affinity mask: %s", affinity_oss.str().c_str()); | |
| - | |
| - for (auto &range : device_ranges) { | |
| - for (unsigned int i = range.start; i <= range.end; i++) { | |
| - if (!CPU_ISSET(i, &mask)) { | |
| - ASCEND_LOGW("Thread affinity conflict detected! Expected core %u (in config range [%u, %u]) is NOT in current thread affinity mask. %s", | |
| - i, range.start, range.end, affinity_oss.str().c_str()); | |
| - ASCEND_LOGW("Thread affinity is already set. Use force:1 to skip this check and force bind."); | |
| - return false; | |
| - } | |
| - } | |
| - } | |
| return true; | return true; |
| -} | + } |
| | |
| -inline bool needToSetThreadAffinity() | + std::istringstream stream(inputStr); |
| -{ | + std::string option; |
| - static bool need_to_set_affinity = getThreadAffinityInfo(); | + while (std::getline(stream, option, ',')) { |
| - return need_to_set_affinity; | + size_t colonPos = option.find(':'); |
| -} | + if (colonPos == std::string::npos && isAllDigits(option)) { |
| - | + mode = static_cast<uint32_t>(std::stoi(option)); |
| -void SetThreadType(ThreadType type) | + return false; |
| -{ | |
| - | |
| - local_thread = type; | |
| - if (type == ThreadType::OTHER_THREAD || type == ThreadType::MAIN_THREAD) { | |
| - return; | |
| } | } |
| - if (prctl(PR_SET_NAME, threadTypeToNameMap.at(type).c_str()) != 0) { | + std::string key = option.substr(0, colonPos); |
| - ASCEND_LOGW("Set thread name to %s failed!", threadTypeToNameMap.at(type).c_str()); | + if (key == "mode") { |
| + std::string value = option.substr(colonPos + 1); |
| + if (isAllDigits(value)) { |
| + mode = static_cast<uint32_t>(std::stoi(value)); |
| + } else { |
| + ASCEND_LOGW("mode is %s, should be all digits", value.c_str()); |
| + } |
| + return false; |
| } | } |
| + } |
| + return false; |
| } | } |
| | |
| -std::string getAffinityMapAsString(c10::DeviceIndex device_id, const ThreadCoreMap &threadCoreMap) | +// Parse device-specific core range from CPU_AFFINITY_CONF (e.g., npu0:0-1) |
| -{ | +void parseDeviceCoreRange( |
| - std::ostringstream oss; | + const std::string& inputStr, |
| - for (auto thread_type : threadTypeList) { | + int device_nums, |
| - oss << threadTypeToNameMap.at(thread_type) << ": [" | + std::vector<CoreIdList>& devices_aff_cores) { |
| - << threadCoreMap.at(thread_type).start << ", " | + std::istringstream stream(inputStr); |
| - << threadCoreMap.at(thread_type).end << "]"; | + std::string option; |
| - if (thread_type != OTHER_THREAD) { | + std::set<int> user_def_devices; |
| - oss << "; "; | + while (std::getline(stream, option, ',')) { |
| - } else { | + size_t colonPos = option.find(':'); |
| - oss << "."; | + if (colonPos == std::string::npos) { |
| + continue; |
| + } |
| + std::string key = option.substr(0, colonPos); |
| + std::string value = option.substr(colonPos + 1); |
| + |
| + std::regex npuPattern("^npu[0-9]{1,2}$"); |
| + if (!std::regex_match(key, npuPattern)) { |
| + ASCEND_LOGW("Invalid device name: %s", key.c_str()); |
| + continue; |
| + } |
| + int device_id = std::stoi(key.substr(3)); |
| + if (device_id >= device_nums || device_id < 0) { |
| + ASCEND_LOGW( |
| + "device_id in CPU_AFFINITY_CONF is %d, should be in range [0, %d)", |
| + device_id, |
| + device_nums); |
| + continue; |
| + } |
| + if (user_def_devices.count(device_id) == 0) { |
| + user_def_devices.insert(device_id); |
| + devices_aff_cores[device_id].clear(); |
| + } |
| + if (isAllDigits(value)) { |
| + CoreId singleCore = static_cast<CoreId>(std::stoi(value)); |
| + devices_aff_cores[device_id].insert(singleCore); |
| + continue; |
| + } |
| + size_t dashPos = value.find('-'); |
| + if (dashPos != std::string::npos) { |
| + std::string startStr = value.substr(0, dashPos); |
| + std::string endStr = value.substr(dashPos + 1); |
| + if (isAllDigits(startStr) && isAllDigits(endStr)) { |
| + CoreId start = static_cast<CoreId>(std::stoi(startStr)); |
| + CoreId end = static_cast<CoreId>(std::stoi(endStr)); |
| + for (CoreId core = start; core <= end; ++core) { |
| + devices_aff_cores[device_id].insert(core); |
| } | } |
| + } else { |
| + ASCEND_LOGW( |
| + "core range is %s-%s, should be all digits", |
| + startStr.c_str(), |
| + endStr.c_str()); |
| + } |
| } | } |
| - return oss.str(); | + } |
| } | } |
| | |
| -ThreadCoreMap getCpuAffinityMap(c10::DeviceIndex device_id, const std::vector<CoreIdRange> &deviceRanges) | +void parseCPUAffinityConf( |
| -{ | + uint32_t& mode, |
| - ThreadCoreMap threadCoreMap; | + std::vector<CoreIdList>& devices_aff_cores) { |
| - CoreIdRange range = deviceRanges[device_id]; | + int device_nums = device_count_ensure_non_zero(); |
| - unsigned int core_nums = range.end - range.start + 1; | + devices_aff_cores.clear(); |
| - if (core_nums < threadTypeList.size()) { | + devices_aff_cores.resize(device_nums); |
| - ASCEND_LOGW("Device %d available core numbers (%d) are insufficient for all %zu thread types and will bind available cores to all threads.", | + ASCEND_LOGD("Get device nums: %d by aclrtGetDeviceCount.", device_nums); |
| - device_id, core_nums, threadTypeList.size()); | + for (int i = 0; i < device_nums; ++i) { |
| - for (auto thread_type : threadTypeList) { | + devices_aff_cores[i] = getNPUDefaultCores(i); |
| - threadCoreMap[thread_type] = range; | + } |
| - } | + mode = 0; |
| - return threadCoreMap; | |
| - } | |
| | |
| - CoreId now = range.start; | + const char* input = c10_npu::option::OptionsManager::GetCpuAffinityConf(); |
| - for (auto thread_type : threadTypeList) { | + if (input == nullptr || strlen(input) == 0) { |
| - if (thread_type != ThreadType::OTHER_THREAD) { | + return; // CPU_AFFINITY_CONF is not set, use default cores |
| - threadCoreMap[thread_type] = CoreIdRange{now, now}; | + } |
| - } else { | + ASCEND_LOGD("Get env var CPU_AFFINITY_CONF: %s", input); |
| - threadCoreMap[ThreadType::OTHER_THREAD] = CoreIdRange{now, range.end}; | |
| - } | |
| - now++; | |
| - } | |
| | |
| - ASCEND_LOGD("Device %d thread affinity map: %s", device_id, getAffinityMapAsString(device_id, threadCoreMap).c_str()); | + const std::string inputStr(input); |
| - return threadCoreMap; | + |
| + |
| + if (parseModeOnly(inputStr, mode)) { |
| + ASCEND_LOGD("Only mode is provided, mode: %d", mode); |
| + return; |
| + } |
| + |
| + parseNpuAffineMode(inputStr, device_nums, devices_aff_cores); |
| + parseLazyBindMode(inputStr); |
| + parseForceMode(inputStr); |
| + |
| + parseDeviceCoreRange(inputStr, device_nums, devices_aff_cores); |
| } | } |
| | |
| -bool setThreadAffinityImpl(pthread_t thread, CoreIdRange core_range) | +void printCoreRanges( |
| -{ | + const uint32_t mode, |
| - cpu_set_t mask; | + const std::vector<CoreIdList>& devices_aff_cores) { |
| - CPU_ZERO(&mask); | + std::ostringstream oss; |
| - for (auto i = core_range.start; i <= core_range.end; i++) { | + oss << "Mode: " << mode << ". Core range for each device ID: "; |
| - CPU_SET(i, &mask); | + |
| + for (size_t i = 0; i < devices_aff_cores.size(); ++i) { |
| + oss << "Device " << i << ": [" << formatCoreRange(devices_aff_cores[i]) |
| + << "]"; |
| + std::string end_str = (i == devices_aff_cores.size() - 1) ? "." : "; "; |
| + oss << end_str; |
| + } |
| + ASCEND_LOGD("Read CPU affinity config: %s", oss.str().c_str()); |
| +} |
| + |
| +std::string formatCPUSetMask(const cpu_set_t& mask) { |
| + CoreIdList cores; |
| + int cpu_count = sysconf(_SC_NPROCESSORS_ONLN); |
| + for (int i = 0; i < cpu_count; ++i) { |
| + if (CPU_ISSET(i, &mask)) { |
| + cores.insert(i); |
| } | } |
| - if (!pthread_setaffinity_np(thread, sizeof(mask), &mask)) { | + } |
| - return true; | + return formatCoreRange(cores); |
| - } else { | +} |
| + |
| +bool checkThreadAffinityConflict( |
| + const std::vector<CoreIdList>& devices_aff_cores) { |
| + cpu_set_t mask; |
| + pthread_getaffinity_np(pthread_self(), sizeof(mask), &mask); |
| + std::string affinity_mask_str = formatCPUSetMask(mask); |
| + ASCEND_LOGI( |
| + "Current thread CPU affinity mask: %s", affinity_mask_str.c_str()); |
| + |
| + for (auto& cores : devices_aff_cores) { |
| + for (auto& core : cores) { |
| + if (!CPU_ISSET(core, &mask)) { |
| + ASCEND_LOGW( |
| + "Thread affinity conflict detected! Expected core %u (in config range [%s]) is NOT in current thread affinity mask. %s", |
| + core, |
| + formatCoreRange(cores).c_str(), |
| + affinity_mask_str.c_str()); |
| + ASCEND_LOGW( |
| + "Thread affinity is already set. Use force:1 to skip this check and force bind."); |
| return false; | return false; |
| + } |
| } | } |
| + } |
| + return true; |
| } | } |
| | |
| -CoreIdRange getCoreRange(c10::DeviceIndex device_id, ThreadType type) | +bool getThreadAffinityInfo() { |
| -{ | + parseCPUAffinityConf(cpu_affinity_mode, devices_aff_cores); |
| - CoreIdRange core_range; | + printCoreRanges(cpu_affinity_mode, devices_aff_cores); |
| - if (cpu_affinity_mode == 0 || cpu_affinity_mode == 1) { | + |
| - core_range = device_ranges[device_id]; | + for (int i = 0; i < devices_aff_cores.size(); ++i) { |
| - } else { | + if (devices_aff_cores[i].size() > 0) { |
| - std::lock_guard<std::mutex> lock(core_map_mutex); | + ASCEND_LOGD( |
| - if (device_thread_core_maps.find(device_id) == device_thread_core_maps.end()) { | + "Device %d get cores %s.", |
| - device_thread_core_maps.emplace(device_id, getCpuAffinityMap(device_id, device_ranges)); | + i, |
| - } | + formatCoreRange(devices_aff_cores[i]).c_str()); |
| - core_range = device_thread_core_maps.at(device_id).at(type); | |
| } | } |
| - return core_range; | + } |
| -} | |
| | |
| -void SetThreadAffinity(c10::DeviceIndex device_id) | + if (cpu_affinity_mode == 0) { |
| -{ | |
| - if (!needToSetThreadAffinity() || local_thread == ThreadType::USER_THREAD) { | |
| - return; | |
| - } | |
| - | |
| - CoreIdRange core_range = getCoreRange(device_id, local_thread); | |
| - if (setThreadAffinityImpl(pthread_self(), core_range)) { | |
| - ASCEND_LOGD("Device %d set %s affinity to %d-%d success.", | |
| - device_id, threadTypeToNameMap.at(local_thread).c_str(), core_range.start, core_range.end); | |
| - } else { | |
| - ASCEND_LOGE("Device %d set %s affinity to %d-%d failed.", | |
| - device_id, threadTypeToNameMap.at(local_thread).c_str(), core_range.start, core_range.end); | |
| - } | |
| -} | |
| - | |
| -void SetThreadAffinity(ThreadType type) | |
| -{ | |
| - if (!needToSetThreadAffinity()) { | |
| - return; | |
| - } | |
| - int device_index; | |
| - NPU_CHECK_ERROR_WITHOUT_UCE(GetDevice(&device_index)); | |
| - c10::DeviceIndex device = static_cast<c10::DeviceIndex>(device_index); | |
| - local_thread = type; | |
| - if (local_thread == ThreadType::MAIN_THREAD) { | |
| - start_main_thread_bind = true; | |
| - } | |
| - SetThreadAffinity(device); | |
| -} | |
| - | |
| -void SetThreadAffinity(int core_start, int core_end) | |
| -{ | |
| - if (!needToSetThreadAffinity()) { | |
| - return; | |
| - } | |
| - | |
| - static int core_nums = sysconf(_SC_NPROCESSORS_ONLN); | |
| - CoreIdRange core_range; | |
| - core_range.start = static_cast<CoreId>(std::min(core_start, core_nums)); | |
| - core_range.end = static_cast<CoreId>(std::min(core_end, core_nums)); | |
| - local_thread = ThreadType::USER_THREAD; | |
| - | |
| - if (setThreadAffinityImpl(pthread_self(), core_range)) { | |
| - ASCEND_LOGD("Set thread affinity to user-defined range %d-%d success.", core_range.start, core_range.end); | |
| - } else { | |
| - ASCEND_LOGE("Set thread affinity to user-defined range %d-%d failed.", core_range.start, core_range.end); | |
| - } | |
| -} | |
| - | |
| -void SetMainThread() | |
| -{ | |
| - main_thread = pthread_self(); | |
| -} | |
| - | |
| -bool NeedMainThreadBind() | |
| -{ | |
| - return start_main_thread_bind && (local_thread == ThreadType::MAIN_THREAD); | |
| -} | |
| - | |
| -bool SetThreadAffinityInInitialize() | |
| -{ | |
| - if (needToSetThreadAffinity() && !lazy_bind) { | |
| - return true; | |
| - } | |
| return false; | return false; |
| + } |
| + |
| + if (force_bind) { |
| + ASCEND_LOGI( |
| + "CPU affinity force mode enabled, skipping affinity conflict detection, applying CPU_AFFINITY_CONF binding."); |
| + return true; |
| + } |
| + |
| + return checkThreadAffinityConflict(devices_aff_cores); |
| } | } |
| | |
| -void StartMainThreadBind(c10::DeviceIndex device_id) | +std::string getAffinityMapAsString( |
| -{ | + c10::DeviceIndex device_id, |
| - if (!needToSetThreadAffinity() || local_thread == ThreadType::USER_THREAD) { | + const ThreadCoreMap& threadCoreMap) { |
| - return; | + std::ostringstream oss; |
| - } | + for (auto thread_type : threadTypeList) { |
| - | + oss << threadTypeToNameMap.at(thread_type) << ": [" |
| - static thread_local bool seted = false; | + << formatCoreRange(threadCoreMap.at(thread_type)) << "]"; |
| - if (!seted) { | + std::string end_str = |
| - seted = true; | + (thread_type == ThreadType::OTHER_THREAD) ? "." : "; "; |
| - if (syscall(SYS_gettid) != getpid()) { | + oss << end_str; |
| - start_main_thread_bind = true; | + } |
| - | + return oss.str(); |
| - SetThreadAffinity(device_id); | |
| - | |
| - CoreIdRange core_range = getCoreRange(device_id, ThreadType::MAIN_THREAD); | |
| - if (setThreadAffinityImpl(main_thread, core_range)) { | |
| - ASCEND_LOGD("Device %d set %s affinity to %d-%d success.", | |
| - device_id, threadTypeToNameMap.at(ThreadType::MAIN_THREAD).c_str(), | |
| - core_range.start, core_range.end); | |
| - } else { | |
| - ASCEND_LOGE("Device %d set %s affinity to %d-%d failed.", | |
| - device_id, threadTypeToNameMap.at(ThreadType::MAIN_THREAD).c_str(), | |
| - core_range.start, core_range.end); | |
| - } | |
| - } | |
| - } | |
| } | } |
| | |
| -} // namespace c10_npu | +ThreadCoreMap getCpuAffinityMap( |
| + c10::DeviceIndex device_id, |
| + const std::vector<CoreIdList>& devices_aff_cores) { |
| + ThreadCoreMap threadCoreMap; |
| + CoreIdList cores = devices_aff_cores[device_id]; |
| + if (cores.size() < threadTypeList.size()) { |
| + ASCEND_LOGW( |
| + "Device %d available core numbers (%zu) are insufficient for all %zu thread types and will bind available cores to all threads.", |
| + device_id, |
| + cores.size(), |
| + threadTypeList.size()); |
| + for (auto thread_type : threadTypeList) { |
| + threadCoreMap[thread_type] = cores; |
| + } |
| + return threadCoreMap; |
| + } |
| + for (auto thread_type : threadTypeList) { |
| + if (thread_type != ThreadType::OTHER_THREAD) { |
| + CoreId first_core = *cores.begin(); |
| + threadCoreMap[thread_type].insert(first_core); |
| + cores.erase(first_core); |
| + } else { |
| + threadCoreMap[ThreadType::OTHER_THREAD] = cores; |
| + } |
| + } |
| + |
| + ASCEND_LOGD( |
| + "Device %d thread affinity map: %s", |
| + device_id, |
| + getAffinityMapAsString(device_id, threadCoreMap).c_str()); |
| + return threadCoreMap; |
| +} |
| + |
| +CoreIdList getCoreList(c10::DeviceIndex device_id, ThreadType type) { |
| + CoreIdList core_list; |
| + if (cpu_affinity_mode == 0 || cpu_affinity_mode == 1) { |
| + core_list = devices_aff_cores[device_id]; |
| + } else { |
| + std::lock_guard<std::mutex> lock(core_map_mutex); |
| + if (device_thread_core_maps.find(device_id) == |
| + device_thread_core_maps.end()) { |
| + device_thread_core_maps.emplace( |
| + device_id, getCpuAffinityMap(device_id, devices_aff_cores)); |
| + } |
| + core_list = device_thread_core_maps.at(device_id).at(type); |
| + } |
| + return core_list; |
| +} |
| + |
| +bool setThreadAffinityImpl(pthread_t thread, CoreIdList core_list) { |
| + cpu_set_t mask; |
| + CPU_ZERO(&mask); |
| + for (auto core : core_list) { |
| + CPU_SET(core, &mask); |
| + } |
| + return pthread_setaffinity_np(thread, sizeof(mask), &mask) == 0; |
| +} |
| + |
| +inline bool needToSetThreadAffinity() { |
| + static bool need_to_set_affinity = getThreadAffinityInfo(); |
| + return need_to_set_affinity; |
| +} |
| + |
| +} |
| + |
| +void SetThreadType(ThreadType type) { |
| + |
| + |
| + local_thread = type; |
| + if (type == ThreadType::OTHER_THREAD || type == ThreadType::MAIN_THREAD) { |
| + return; |
| + } |
| + if (prctl(PR_SET_NAME, threadTypeToNameMap.at(type).c_str()) != 0) { |
| + ASCEND_LOGW( |
| + "Set thread name to %s failed!", threadTypeToNameMap.at(type).c_str()); |
| + } |
| + ASCEND_LOGD( |
| + "Set thread name to %s success.", threadTypeToNameMap.at(type).c_str()); |
| +} |
| + |
| +void SetThreadAffinity(c10::DeviceIndex device_id) { |
| + if (!needToSetThreadAffinity() || local_thread == ThreadType::USER_THREAD) { |
| + return; |
| + } |
| + |
| + CoreIdList core_list = getCoreList(device_id, local_thread); |
| + std::string range_str = formatCoreRange(core_list); |
| + if (setThreadAffinityImpl(pthread_self(), core_list)) { |
| + ASCEND_LOGD( |
| + "Device %d set %s affinity to %s success.", |
| + device_id, |
| + threadTypeToNameMap.at(local_thread).c_str(), |
| + range_str.c_str()); |
| + } else { |
| + ASCEND_LOGE( |
| + "Device %d set %s affinity to %s failed.", |
| + device_id, |
| + threadTypeToNameMap.at(local_thread).c_str(), |
| + range_str.c_str()); |
| + } |
| +} |
| + |
| +void SetThreadAffinity(ThreadType type) { |
| + if (!needToSetThreadAffinity()) { |
| + return; |
| + } |
| + int device_index; |
| + NPU_CHECK_ERROR_WITHOUT_UCE(GetDevice(&device_index)); |
| + c10::DeviceIndex device = static_cast<c10::DeviceIndex>(device_index); |
| + local_thread = type; |
| + if (local_thread == ThreadType::MAIN_THREAD) { |
| + start_main_thread_bind = true; |
| + } |
| + SetThreadAffinity(device); |
| +} |
| + |
| +void SetThreadAffinity(const CoreIdList core_ids) { |
| + if (!needToSetThreadAffinity()) { |
| + return; |
| + } |
| + CoreIdList processed_core_ids = core_ids; |
| + static int core_nums = sysconf(_SC_NPROCESSORS_ONLN); |
| + for (auto it = processed_core_ids.begin(); it != processed_core_ids.end();) { |
| + if (static_cast<int>(*it) >= core_nums) { |
| + ASCEND_LOGW( |
| + "core id %d >= core_nums %d, it will be ignored when setting thread affinity.", |
| + *it, |
| + core_nums); |
| + it = processed_core_ids.erase(it); |
| + } else { |
| + ++it; |
| + } |
| + } |
| + local_thread = ThreadType::USER_THREAD; |
| + if (setThreadAffinityImpl(pthread_self(), processed_core_ids)) { |
| + ASCEND_LOGD( |
| + "Set thread affinity to user-defined range %s success.", |
| + formatCoreRange(processed_core_ids).c_str()); |
| + } else { |
| + ASCEND_LOGE( |
| + "Set thread affinity to user-defined range %s failed.", |
| + formatCoreRange(processed_core_ids).c_str()); |
| + } |
| +} |
| + |
| +void SetThreadAffinity(int core_start, int core_end) { |
| + CoreIdList core_list; |
| + for (int i = core_start; i <= core_end; ++i) { |
| + core_list.insert(static_cast<CoreId>(i)); |
| + } |
| + SetThreadAffinity(core_list); |
| +} |
| + |
| +void SetMainThread() { |
| + main_thread = pthread_self(); |
| +} |
| + |
| +bool NeedMainThreadBind() { |
| + return start_main_thread_bind && (local_thread == ThreadType::MAIN_THREAD); |
| +} |
| + |
| +bool SetThreadAffinityInInitialize() { |
| + if (needToSetThreadAffinity() && !lazy_bind) { |
| + return true; |
| + } |
| + return false; |
| +} |
| + |
| +void StartMainThreadBind(c10::DeviceIndex device_id) { |
| + if (!needToSetThreadAffinity() || local_thread == ThreadType::USER_THREAD) { |
| + return; |
| + } |
| + |
| + static thread_local bool seted = false; |
| + if (seted) { |
| + return; |
| + } |
| + seted = true; |
| + if (syscall(SYS_gettid) != getpid()) { |
| + start_main_thread_bind = true; |
| + SetThreadAffinity(device_id); |
| + CoreIdList core_list = getCoreList(device_id, ThreadType::MAIN_THREAD); |
| + if (setThreadAffinityImpl(main_thread, core_list)) { |
| + ASCEND_LOGD( |
| + "Device %d set %s affinity to %s success.", |
| + device_id, |
| + threadTypeToNameMap.at(ThreadType::MAIN_THREAD).c_str(), |
| + formatCoreRange(core_list).c_str()); |
| + } else { |
| + ASCEND_LOGE( |
| + "Device %d set %s affinity to %s failed.", |
| + device_id, |
| + threadTypeToNameMap.at(ThreadType::MAIN_THREAD).c_str(), |
| + formatCoreRange(core_list).c_str()); |
| + } |
| + } |
| +} |
| + |
| +} |