From patchwork Mon Feb 22 22:46:39 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: gary.robertson@linaro.org X-Patchwork-Id: 62642 Delivered-To: patch@linaro.org Received: by 10.112.43.199 with SMTP id y7csp1515227lbl; Mon, 22 Feb 2016 14:48:48 -0800 (PST) X-Received: by 10.55.53.208 with SMTP id c199mr38301547qka.109.1456181328301; Mon, 22 Feb 2016 14:48:48 -0800 (PST) Return-Path: Received: from lists.linaro.org (lists.linaro.org. [54.225.227.206]) by mx.google.com with ESMTP id v63si31557093qhc.0.2016.02.22.14.48.48; Mon, 22 Feb 2016 14:48:48 -0800 (PST) Received-SPF: pass (google.com: domain of lng-odp-bounces@lists.linaro.org designates 54.225.227.206 as permitted sender) client-ip=54.225.227.206; Authentication-Results: mx.google.com; spf=pass (google.com: domain of lng-odp-bounces@lists.linaro.org designates 54.225.227.206 as permitted sender) smtp.mailfrom=lng-odp-bounces@lists.linaro.org Received: by lists.linaro.org (Postfix, from userid 109) id E405A6175C; Mon, 22 Feb 2016 22:48:47 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on ip-10-142-244-252 X-Spam-Level: X-Spam-Status: No, score=-2.6 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_LOW, RCVD_IN_MSPIKE_H2, URIBL_BLOCKED autolearn=disabled version=3.4.0 Received: from [127.0.0.1] (localhost [127.0.0.1]) by lists.linaro.org (Postfix) with ESMTP id 50C5D618C2; Mon, 22 Feb 2016 22:48:03 +0000 (UTC) X-Original-To: lng-odp@lists.linaro.org Delivered-To: lng-odp@lists.linaro.org Received: by lists.linaro.org (Postfix, from userid 109) id 1458361752; Mon, 22 Feb 2016 22:47:50 +0000 (UTC) Received: from mail-ob0-f171.google.com (mail-ob0-f171.google.com [209.85.214.171]) by lists.linaro.org (Postfix) with ESMTPS id BDB1D618C2 for ; Mon, 22 Feb 2016 22:47:16 +0000 (UTC) Received: by mail-ob0-f171.google.com with SMTP id ts10so64657571obc.1 for ; Mon, 22 Feb 2016 14:47:16 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=ITc+Uf6S7sVY66OcHMeKKwAlO7HN6cT49xEnMMf/JWU=; b=KNCnCOFlW2+p+Wb3uefK8aVbA+Ph7soH3tHjlFTQ51R6V9FhMPMCpFMwEhQ1mOxs1v omhCntkc56xG5MvnGB2RrcJJL6gJujKaPtyqBJqtXDZxO8gE2edwKM4OHYgEyFPCGdj1 tcA+Dx7ODQVux1J8SE8jF3PXoAucLN9LeGz0GYRpS7uv03Xt+0N8DGK7FUFMYE8DCCxt 2206Mwfx6eBD0LFp/S24F9liBBuqucBOsT0wUjPQQR8rzbPuwOViOF5/wS5GrHLw4mg5 j8Hl+8vhTplJJg/osF5eopUgUlAwO+Jn7W8vLxXH7R//Pz495HJ87Zh3CpE3AtqYs1BB OO9A== X-Gm-Message-State: AG10YORbU+FsEnxBH6f1TOpHHd09E7yG0xk6dXX7RFLGKsF3gpN4lQkTLntnbr4MNEQpxT4x0X8= X-Received: by 10.60.57.193 with SMTP id k1mr24690008oeq.66.1456181236292; Mon, 22 Feb 2016 14:47:16 -0800 (PST) Received: from honkintosh.cybertech.lan (65-120-133-114.dia.static.qwest.net. [65.120.133.114]) by smtp.googlemail.com with ESMTPSA id tu11sm18045413oec.13.2016.02.22.14.47.13 (version=TLSv1/SSLv3 cipher=OTHER); Mon, 22 Feb 2016 14:47:15 -0800 (PST) From: "Gary S. Robertson" To: mike.holmes@linaro.org, bill.fischofer@linaro.org, maxim.uvarov@linaro.org, anders.roxell@linaro.org, petri.savolainen@linaro.org Date: Mon, 22 Feb 2016 16:46:39 -0600 Message-Id: <1456181199-29634-3-git-send-email-gary.robertson@linaro.org> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1456181199-29634-1-git-send-email-gary.robertson@linaro.org> References: <1456181199-29634-1-git-send-email-gary.robertson@linaro.org> X-Topics: patch Cc: lng-odp@lists.linaro.org Subject: [lng-odp] [PATCH V3 2/2] linux-generic: Make cpu detection work with NO_HZ_FULL X-BeenThere: lng-odp@lists.linaro.org X-Mailman-Version: 2.1.16 Precedence: list List-Id: "The OpenDataPlane \(ODP\) List" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: lng-odp-bounces@lists.linaro.org Sender: "lng-odp" sched_getaffinity() and pthread_getaffinity_np() do not return an accurate mask of all CPUs in the machine when the kernel is compiled with NO_HZ_FULL support. See Linaro BUG 2027 for details. https://bugs.linaro.org/show_bug.cgi?id=2027 This code replaces the 'getaffinity' based CPU discovery logic -and- removes any exclusivity between default control and worker cpumasks, based on an assumption that external cpumask specifications will segregate CPUs if needed. The results of these changes which address BUG 2027 are: (1) all CPUs known to the kernel at boot time are considered for use by ODP regardless of the default CPU affinity masks set by the kernel scheduler, (2) the default control and worker cpumasks both contain all CPUs Also - this code: (a) adds control worker cpumasks to the linux-generic global data (b) adds logic to odp_init_global() to initialize these masks, -and- (c) reduces odp_cpumask_default_control() and odp_cpumask_default_worker() to use the content of these new cpumasks without modification. These changes provide prerequisite infrastructure for pending changes which will allow ODP to accept cpumasks passed in from external entities such as a provisioning service. Signed-off-by: Gary S. Robertson --- platform/linux-generic/include/odp_internal.h | 6 ++ platform/linux-generic/odp_cpumask_task.c | 45 +++++++------- platform/linux-generic/odp_init.c | 90 ++++++++++++++++++++++++++- platform/linux-generic/odp_system_info.c | 14 ++--- 4 files changed, 119 insertions(+), 36 deletions(-) diff --git a/platform/linux-generic/include/odp_internal.h b/platform/linux-generic/include/odp_internal.h index e75154a..32e2b46 100644 --- a/platform/linux-generic/include/odp_internal.h +++ b/platform/linux-generic/include/odp_internal.h @@ -19,6 +19,7 @@ extern "C" { #endif #include +#include #include #include @@ -40,6 +41,8 @@ struct odp_global_data_s { odp_log_func_t log_fn; odp_abort_func_t abort_fn; odp_system_info_t system_info; + odp_cpumask_t control_cpus; + odp_cpumask_t worker_cpus; }; enum init_stage { @@ -60,6 +63,9 @@ enum init_stage { extern struct odp_global_data_s odp_global_data; +/* Number of logical CPUs detected at boot time */ +extern int num_cpus_installed; + int _odp_term_global(enum init_stage stage); int _odp_term_local(enum init_stage stage); diff --git a/platform/linux-generic/odp_cpumask_task.c b/platform/linux-generic/odp_cpumask_task.c index c5093e0..36a158b 100644 --- a/platform/linux-generic/odp_cpumask_task.c +++ b/platform/linux-generic/odp_cpumask_task.c @@ -12,55 +12,52 @@ #include #include +/* + * The following functions assume that odp_init_global() or some external + * logic has previously initialized the globally accessible cpumasks + * for ODP control and worker CPU selections. + */ int odp_cpumask_default_worker(odp_cpumask_t *mask, int num) { - int ret, cpu, i; - cpu_set_t cpuset; - - ret = pthread_getaffinity_np(pthread_self(), - sizeof(cpu_set_t), &cpuset); - if (ret != 0) - ODP_ABORT("failed to read CPU affinity value\n"); - - odp_cpumask_zero(mask); + odp_cpumask_t overlap; + int cpu, i; /* * If no user supplied number or it's too large, then attempt * to use all CPUs */ - if (0 == num || CPU_SETSIZE < num) - num = CPU_COUNT(&cpuset); + cpu = odp_cpumask_count(&odp_global_data.worker_cpus); + if (0 == num || cpu < num) + num = cpu; /* build the mask, allocating down from highest numbered CPU */ + odp_cpumask_zero(mask); for (cpu = 0, i = CPU_SETSIZE - 1; i >= 0 && cpu < num; --i) { - if (CPU_ISSET(i, &cpuset)) { + if (odp_cpumask_isset(&odp_global_data.worker_cpus, i)) { odp_cpumask_set(mask, i); cpu++; } } - if (odp_cpumask_isset(mask, 0)) - ODP_DBG("\n\tCPU0 will be used for both control and worker threads,\n" - "\tthis will likely have a performance impact on the worker thread.\n"); + odp_cpumask_and(&overlap, mask, &odp_global_data.control_cpus); + if (odp_cpumask_count(&overlap)) + ODP_DBG("\n\tWorker and Control CPU selections overlap...\n" + "\tthis will likely have a performance impact on the worker threads.\n"); return cpu; } int odp_cpumask_default_control(odp_cpumask_t *mask, int num ODP_UNUSED) { - odp_cpumask_zero(mask); - /* By default all control threads on CPU 0 */ - odp_cpumask_set(mask, 0); - return 1; + odp_cpumask_copy(mask, &odp_global_data.control_cpus); + + return odp_cpumask_count(mask); } int odp_cpumask_all_available(odp_cpumask_t *mask) { - odp_cpumask_t mask_work, mask_ctrl; - - odp_cpumask_default_worker(&mask_work, 0); - odp_cpumask_default_control(&mask_ctrl, 0); - odp_cpumask_or(mask, &mask_work, &mask_ctrl); + odp_cpumask_or(mask, &odp_global_data.worker_cpus, + &odp_global_data.control_cpus); return odp_cpumask_count(mask); } diff --git a/platform/linux-generic/odp_init.c b/platform/linux-generic/odp_init.c index 3a990d2..335c3d3 100644 --- a/platform/linux-generic/odp_init.c +++ b/platform/linux-generic/odp_init.c @@ -4,13 +4,94 @@ * SPDX-License-Identifier: BSD-3-Clause */ -#include -#include +#include + +#include +#include +#include +#include +#include + +#include #include #include +#include +#include struct odp_global_data_s odp_global_data; +/* + * This function obtains system information specifying which cpus are + * available at boot time. These data are then used to produce cpumasks of + * configured CPUs without concern over isolation support. + */ +static int get_installed_cpus(void) +{ + char *numptr; + char *endptr; + long int cpu_idnum; + DIR *d; + struct dirent *dir; + + /* Clear the global cpumasks for control and worker CPUs */ + odp_cpumask_zero(&odp_global_data.control_cpus); + odp_cpumask_zero(&odp_global_data.worker_cpus); + + /* + * Scan the /sysfs pseudo-filesystem for CPU info directories. + * There should be one subdirectory for each installed logical CPU + */ + d = opendir("/sys/devices/system/cpu"); + if (d) { + while ((dir = readdir(d)) != NULL) { + cpu_idnum = CPU_SETSIZE; + + /* + * If the current directory entry doesn't represent + * a CPU info subdirectory then skip to the next entry. + */ + if (dir->d_type == DT_DIR) { + if (!strncmp(dir->d_name, "cpu", 3)) { + /* + * Directory name starts with "cpu"... + * Try to extract a CPU ID number + * from the remainder of the dirname. + */ + errno = 0; + numptr = dir->d_name; + numptr += 3; + cpu_idnum = strtol(numptr, &endptr, + 10); + if (errno || (endptr == numptr)) + continue; + } else { + continue; + } + } else { + continue; + } + /* + * If we get here the current directory entry specifies + * a CPU info subdir for the CPU indexed by cpu_idnum. + */ + + /* Track number of logical CPUs discovered */ + if (num_cpus_installed < (int)(cpu_idnum + 1)) + num_cpus_installed = (int)(cpu_idnum + 1); + + /* Add the CPU to our default cpumasks */ + odp_cpumask_set(&odp_global_data.control_cpus, + (int)cpu_idnum); + odp_cpumask_set(&odp_global_data.worker_cpus, + (int)cpu_idnum); + } + closedir(d); + return 0; + } else { + return -1; + } +} + int odp_init_global(const odp_init_t *params, const odp_platform_init_t *platform_params ODP_UNUSED) { @@ -25,6 +106,11 @@ int odp_init_global(const odp_init_t *params, odp_global_data.abort_fn = params->abort_fn; } + if (get_installed_cpus()) { + ODP_ERR("ODP cpumask init failed.\n"); + goto init_failed; + } + if (odp_time_init_global()) { ODP_ERR("ODP time init failed.\n"); goto init_failed; diff --git a/platform/linux-generic/odp_system_info.c b/platform/linux-generic/odp_system_info.c index 42aef8a..313badb 100644 --- a/platform/linux-generic/odp_system_info.c +++ b/platform/linux-generic/odp_system_info.c @@ -30,21 +30,15 @@ #define HUGE_PAGE_DIR "/sys/kernel/mm/hugepages" +/* Number of logical CPUs detected at boot time */ +int num_cpus_installed; /* - * Report the number of CPUs in the affinity mask of the main thread + * Report the number of logical CPUs detected at boot time */ static int sysconf_cpu_count(void) { - cpu_set_t cpuset; - int ret; - - ret = pthread_getaffinity_np(pthread_self(), - sizeof(cpuset), &cpuset); - if (ret != 0) - return 0; - - return CPU_COUNT(&cpuset); + return num_cpus_installed; } #if defined __x86_64__ || defined __i386__ || defined __OCTEON__ || \