From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 1CB5BA0C4B; Thu, 11 Nov 2021 02:35:33 +0100 (CET) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id D746E41169; Thu, 11 Nov 2021 02:35:02 +0100 (CET) Received: from linux.microsoft.com (linux.microsoft.com [13.77.154.182]) by mails.dpdk.org (Postfix) with ESMTP id 4805F410F7 for ; Thu, 11 Nov 2021 02:34:54 +0100 (CET) Received: by linux.microsoft.com (Postfix, from userid 1059) id CA9BB20C3583; Wed, 10 Nov 2021 17:34:52 -0800 (PST) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com CA9BB20C3583 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1636594492; bh=XNcxcpW82wsjqfdq11hwRNHJEgairwx+bA4euoiEK+4=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=UUdzpFoNO8bKvIGh7TmV5LBW6L7PMKQNTJFiG0Zc3T5F7QcLomjLzUtKq/9ieccnF 9U4JIkWPJVbdERBi6ZXzraUqBMzTny7Aul1E5XID7B+vHjqNgv1F1Pv6KBIA06I3s8 m3BH6vMu7A674lr5Ch2RLvzmBAi3vIWbt/O978RI= From: Narcisa Ana Maria Vasile To: dev@dpdk.org, thomas@monjalon.net, dmitry.kozliuk@gmail.com, khot@microsoft.com, navasile@microsoft.com, dmitrym@microsoft.com, roretzla@microsoft.com, talshn@nvidia.com, ocardona@microsoft.com Cc: bruce.richardson@intel.com, david.marchand@redhat.com, pallavi.kadam@intel.com Subject: [PATCH v18 5/8] eal: implement thread priority management functions Date: Wed, 10 Nov 2021 17:33:42 -0800 Message-Id: <1636594425-9692-6-git-send-email-navasile@linux.microsoft.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1636594425-9692-1-git-send-email-navasile@linux.microsoft.com> References: <1636513302-7359-1-git-send-email-navasile@linux.microsoft.com> <1636594425-9692-1-git-send-email-navasile@linux.microsoft.com> X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org From: Narcisa Vasile Add functions for setting and getting the priority of a thread. Priorities on multiple platforms are similarly determined by a priority value and a priority class/policy. Currently in DPDK most threads operate at the OS-default priority level but there are cases when increasing the priority is useful. For example, high performance applications may require elevated priority levels. For these reasons, EAL will expose two priority levels which are named suggestively "normal" and "realtime_critical" and are computed as follows: On Linux, the following mapping is created: RTE_THREAD_PRIORITY_NORMAL corresponds to * policy SCHED_OTHER * priority value: (sched_get_priority_min(SCHED_OTHER) + sched_get_priority_max(SCHED_OTHER))/2; RTE_THREAD_PRIORITY_REALTIME_CRITICAL corresponds to * policy SCHED_RR * priority value: sched_get_priority_max(SCHED_RR); On Windows, the following mapping is created: RTE_THREAD_PRIORITY_NORMAL corresponds to * class NORMAL_PRIORITY_CLASS * priority THREAD_PRIORITY_NORMAL RTE_THREAD_PRIORITY_REALTIME_CRITICAL corresponds to * class REALTIME_PRIORITY_CLASS * priority THREAD_PRIORITY_TIME_CRITICAL Note that on Linux the resulting priority value will be 0, in accordance to the docs that mention the value should be 0 for SCHED_OTHER policy. Signed-off-by: Narcisa Vasile --- lib/eal/common/rte_thread.c | 103 ++++++++++++++++++++++++++++ lib/eal/include/rte_thread.h | 34 ++++++++++ lib/eal/version.map | 2 + lib/eal/windows/rte_thread.c | 127 +++++++++++++++++++++++++++++++++++ 4 files changed, 266 insertions(+) diff --git a/lib/eal/common/rte_thread.c b/lib/eal/common/rte_thread.c index 73b7b3141c..fc5d7c5b1a 100644 --- a/lib/eal/common/rte_thread.c +++ b/lib/eal/common/rte_thread.c @@ -50,6 +50,109 @@ rte_thread_get_affinity_by_id(rte_thread_t thread_id, sizeof(*cpuset), cpuset); } +static int +thread_map_priority_to_os_value(enum rte_thread_priority eal_pri, + int *os_pri, int *pol) +{ + /* Clear the output parameters */ + *os_pri = sched_get_priority_min(SCHED_OTHER) - 1; + *pol = -1; + + switch (eal_pri) { + case RTE_THREAD_PRIORITY_NORMAL: + *pol = SCHED_OTHER; + + /* + * Choose the middle of the range to represent + * the priority 'normal'. + * On Linux, this should be 0, since both + * sched_get_priority_min/_max return 0 for SCHED_OTHER. + */ + *os_pri = (sched_get_priority_min(SCHED_OTHER) + + sched_get_priority_max(SCHED_OTHER))/2; + break; + case RTE_THREAD_PRIORITY_REALTIME_CRITICAL: + *pol = SCHED_RR; + *os_pri = sched_get_priority_max(SCHED_RR); + break; + default: + RTE_LOG(DEBUG, EAL, "The requested priority value is invalid.\n"); + return EINVAL; + } + return 0; +} + +static int +thread_map_os_priority_to_eal_priority(int policy, int os_pri, + enum rte_thread_priority *eal_pri) +{ + switch (policy) { + case SCHED_OTHER: + if (os_pri == (sched_get_priority_min(SCHED_OTHER) + + sched_get_priority_max(SCHED_OTHER))/2) { + *eal_pri = RTE_THREAD_PRIORITY_NORMAL; + return 0; + } + break; + case SCHED_RR: + if (os_pri == sched_get_priority_max(SCHED_RR)) { + *eal_pri = RTE_THREAD_PRIORITY_REALTIME_CRITICAL; + return 0; + } + break; + default: + RTE_LOG(DEBUG, EAL, "The OS priority value does not map to an EAL-defined priority.\n"); + return EINVAL; + } + + return 0; +} + +int +rte_thread_get_priority(rte_thread_t thread_id, + enum rte_thread_priority *priority) +{ + int ret; + int policy; + struct sched_param param; + + ret = pthread_getschedparam((pthread_t)thread_id.opaque_id, &policy, + ¶m); + if (ret != 0) { + RTE_LOG(DEBUG, EAL, "pthread_getschedparam failed\n"); + goto cleanup; + } + + return thread_map_os_priority_to_eal_priority(policy, + param.sched_priority, priority); + +cleanup: + return ret; +} + +int +rte_thread_set_priority(rte_thread_t thread_id, + enum rte_thread_priority priority) +{ + int ret; + int policy; + struct sched_param param; + +/* Realtime priority can cause crashes on non-Windows platforms. */ +#ifndef RTE_EXEC_ENV_WINDOWS + if (priority == RTE_THREAD_PRIORITY_REALTIME_CRITICAL) + return ENOTSUP; +#endif + + ret = thread_map_priority_to_os_value(priority, ¶m.sched_priority, + &policy); + if (ret != 0) + return ret; + + return pthread_setschedparam((pthread_t)thread_id.opaque_id, + policy, ¶m); +} + int rte_thread_attr_init(rte_thread_attr_t *attr) { diff --git a/lib/eal/include/rte_thread.h b/lib/eal/include/rte_thread.h index 5b100cafda..7077c9ce46 100644 --- a/lib/eal/include/rte_thread.h +++ b/lib/eal/include/rte_thread.h @@ -213,6 +213,40 @@ void rte_thread_get_affinity(rte_cpuset_t *cpusetp); #endif /* RTE_HAS_CPUSET */ +/** + * Get the priority of a thread. + * + * @param thread_id + * Id of the thread for which to get priority. + * + * @param priority + * Location to store the retrieved priority. + * + * @return + * On success, return 0. + * On failure, return a positive errno-style error number. + */ +__rte_experimental +int rte_thread_get_priority(rte_thread_t thread_id, + enum rte_thread_priority *priority); + +/** + * Set the priority of a thread. + * + * @param thread_id + * Id of the thread for which to set priority. + * + * @param priority + * Priority value to be set. + * + * @return + * On success, return 0. + * On failure, return a positive errno-style error number. + */ +__rte_experimental +int rte_thread_set_priority(rte_thread_t thread_id, + enum rte_thread_priority priority); + /** * Create a TLS data key visible to all threads in the process. * the created key is later used to get/set a value. diff --git a/lib/eal/version.map b/lib/eal/version.map index 193a79a4d2..5bc5a6cf76 100644 --- a/lib/eal/version.map +++ b/lib/eal/version.map @@ -429,6 +429,8 @@ EXPERIMENTAL { rte_thread_attr_set_priority; rte_thread_get_affinity_by_id; rte_thread_set_affinity_by_id; + rte_thread_get_priority; + rte_thread_set_priority; }; INTERNAL { diff --git a/lib/eal/windows/rte_thread.c b/lib/eal/windows/rte_thread.c index 0127119f49..5c02a6eaff 100644 --- a/lib/eal/windows/rte_thread.c +++ b/lib/eal/windows/rte_thread.c @@ -200,6 +200,133 @@ rte_thread_get_affinity_by_id(rte_thread_t thread_id, return ret; } +static int +thread_map_priority_to_os_value(enum rte_thread_priority eal_pri, + int *os_pri, int *pri_class) +{ + /* Clear the output parameters */ + *os_pri = -1; + *pri_class = -1; + + switch (eal_pri) { + case RTE_THREAD_PRIORITY_NORMAL: + *pri_class = NORMAL_PRIORITY_CLASS; + *os_pri = THREAD_PRIORITY_NORMAL; + break; + case RTE_THREAD_PRIORITY_REALTIME_CRITICAL: + *pri_class = REALTIME_PRIORITY_CLASS; + *os_pri = THREAD_PRIORITY_TIME_CRITICAL; + break; + default: + RTE_LOG(DEBUG, EAL, "The requested priority value is invalid.\n"); + return EINVAL; + } + + return 0; +} + +static int +thread_map_os_priority_to_eal_value(int os_pri, int pri_class, + enum rte_thread_priority *eal_pri) +{ + switch (pri_class) { + case NORMAL_PRIORITY_CLASS: + if (os_pri == THREAD_PRIORITY_NORMAL) { + *eal_pri = RTE_THREAD_PRIORITY_NORMAL; + return 0; + } + break; + case REALTIME_PRIORITY_CLASS: + if (os_pri == THREAD_PRIORITY_TIME_CRITICAL) { + *eal_pri = RTE_THREAD_PRIORITY_REALTIME_CRITICAL; + return 0; + } + break; + default: + RTE_LOG(DEBUG, EAL, "The OS priority value does not map to an EAL-defined priority.\n"); + return EINVAL; + } + return 0; +} + +int +rte_thread_get_priority(rte_thread_t thread_id, + enum rte_thread_priority *priority) +{ + HANDLE thread_handle = NULL; + DWORD pri_class; + int os_pri; + int ret; + + pri_class = GetPriorityClass(GetCurrentProcess()); + if (pri_class == 0) { + ret = thread_log_last_error("GetPriorityClass()"); + goto cleanup; + } + + thread_handle = OpenThread(THREAD_SET_INFORMATION | + THREAD_QUERY_INFORMATION, FALSE, thread_id.opaque_id); + if (thread_handle == NULL) { + ret = thread_log_last_error("OpenThread()"); + goto cleanup; + } + + os_pri = GetThreadPriority(thread_handle); + if (os_pri == THREAD_PRIORITY_ERROR_RETURN) { + ret = thread_log_last_error("GetThreadPriority()"); + goto cleanup; + } + + ret = thread_map_os_priority_to_eal_value(os_pri, pri_class, priority); + if (ret != 0) + goto cleanup; + +cleanup: + if (thread_handle != NULL) + CloseHandle(thread_handle); + + return ret; +} + +int +rte_thread_set_priority(rte_thread_t thread_id, + enum rte_thread_priority priority) +{ + HANDLE thread_handle; + int priority_class; + int os_priority; + int ret = 0; + + thread_handle = OpenThread(THREAD_SET_INFORMATION | + THREAD_QUERY_INFORMATION, FALSE, + thread_id.opaque_id); + if (thread_handle == NULL) { + ret = thread_log_last_error("OpenThread()"); + goto cleanup; + } + + ret = thread_map_priority_to_os_value(priority, &os_priority, + &priority_class); + if (ret != 0) + goto cleanup; + + if (!SetPriorityClass(GetCurrentProcess(), priority_class)) { + ret = thread_log_last_error("SetPriorityClass()"); + goto cleanup; + } + + if (!SetThreadPriority(thread_handle, os_priority)) { + ret = thread_log_last_error("SetThreadPriority()"); + goto cleanup; + } + +cleanup: + if (thread_handle != NULL) + CloseHandle(thread_handle); + + return ret; +} + int rte_thread_attr_init(rte_thread_attr_t *attr) { -- 2.31.0.vfs.0.1