From patchwork Wed Oct 22 13:57:52 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Lezcano X-Patchwork-Id: 39306 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-la0-f70.google.com (mail-la0-f70.google.com [209.85.215.70]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id 6CD70202DB for ; Wed, 22 Oct 2014 13:58:18 +0000 (UTC) Received: by mail-la0-f70.google.com with SMTP id ge10sf2090808lab.1 for ; Wed, 22 Oct 2014 06:58:17 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:delivered-to:from:to:cc:subject :date:message-id:in-reply-to:references:x-original-sender :x-original-authentication-results:precedence:mailing-list:list-id :list-post:list-help:list-archive:list-unsubscribe; bh=5thravVTNlkCHLocRIS6T0HlS23KuIe4F0WRB9vnD8c=; b=dvWl9YhntBqcSsSJYu4LSS4umBxZbc7Vpvzo1tuhiRaWJ1+B63fyspFUe5pmL7mqG0 SeKwHVmiarJtbNj9KBXs/N+Ab4Lz4frEIm7kdCMlDzNagORPTVZ2AR1NGbhfd20VuXYN XTjW4jaxFBOvxX50l3zlklMxJJGH9lauIt2FNDE0KmCZCXq6bbLEgttuV7rueXr4MZn4 IPU3JErxrh8VMe/xsVLaUMySdsLe+aLcGYs4bPIvPgrhfBLXdPyY3doYy9cN6hY3WepU CCYm+35bmBikArKAwsSnWaU/YhTuYvtxHD8s3h09TaG0tip3vkSRhmlZVdZjjsKTjqqz Pmrg== X-Gm-Message-State: ALoCoQnlkZJ8GCI6y7qOv66OHpyHSxs63bE0EXvLX5jQxzVF3haJwhhTYR9HKeFlWtCACIG/AIs5 X-Received: by 10.152.21.170 with SMTP id w10mr530071lae.6.1413986297244; Wed, 22 Oct 2014 06:58:17 -0700 (PDT) MIME-Version: 1.0 X-BeenThere: patchwork-forward@linaro.org Received: by 10.152.205.108 with SMTP id lf12ls171513lac.48.gmail; Wed, 22 Oct 2014 06:58:17 -0700 (PDT) X-Received: by 10.152.45.2 with SMTP id i2mr11064546lam.7.1413986296824; Wed, 22 Oct 2014 06:58:16 -0700 (PDT) Received: from mail-la0-f48.google.com (mail-la0-f48.google.com. [209.85.215.48]) by mx.google.com with ESMTPS id xv1si23398787lbb.119.2014.10.22.06.58.16 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Wed, 22 Oct 2014 06:58:16 -0700 (PDT) Received-SPF: pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 209.85.215.48 as permitted sender) client-ip=209.85.215.48; Received: by mail-la0-f48.google.com with SMTP id gi9so2920082lab.21 for ; Wed, 22 Oct 2014 06:58:16 -0700 (PDT) X-Received: by 10.112.97.135 with SMTP id ea7mr42171828lbb.46.1413986296717; Wed, 22 Oct 2014 06:58:16 -0700 (PDT) X-Forwarded-To: patchwork-forward@linaro.org X-Forwarded-For: patch@linaro.org patchwork-forward@linaro.org Delivered-To: patches@linaro.org Received: by 10.112.84.229 with SMTP id c5csp76319lbz; Wed, 22 Oct 2014 06:58:16 -0700 (PDT) X-Received: by 10.180.11.227 with SMTP id t3mr5812395wib.45.1413986295239; Wed, 22 Oct 2014 06:58:15 -0700 (PDT) Received: from mail-wi0-f174.google.com (mail-wi0-f174.google.com. [209.85.212.174]) by mx.google.com with ESMTPS id u2si1871929wiy.51.2014.10.22.06.58.15 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Wed, 22 Oct 2014 06:58:15 -0700 (PDT) Received-SPF: pass (google.com: domain of daniel.lezcano@linaro.org designates 209.85.212.174 as permitted sender) client-ip=209.85.212.174; Received: by mail-wi0-f174.google.com with SMTP id r20so1462475wiv.7 for ; Wed, 22 Oct 2014 06:58:14 -0700 (PDT) X-Received: by 10.194.110.167 with SMTP id ib7mr28204345wjb.95.1413986294910; Wed, 22 Oct 2014 06:58:14 -0700 (PDT) Received: from localhost.localdomain (AToulouse-656-1-959-39.w90-50.abo.wanadoo.fr. [90.50.216.39]) by mx.google.com with ESMTPSA id f7sm2030217wiz.13.2014.10.22.06.58.13 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 22 Oct 2014 06:58:14 -0700 (PDT) From: Daniel Lezcano To: linux-pm@vger.kernel.org, linux-kernel@vger.kernel.org Cc: axboe@kernel.dk, rafael.j.wysocki@intel.com, mingo@kernel.org, peterz@infradead.org, preeti@linux.vnet.ibm.com, Morten.Rasmussen@arm.com, mturquette@linaro.org, tuukka.tikkanen@linaro.org, nicolas.pitre@linaro.org, patches@linaro.org Subject: [RFD PATCH 09/10] cpuidle: sysfs: Add per cpu idle state prediction statistics Date: Wed, 22 Oct 2014 15:57:52 +0200 Message-Id: <1413986273-28522-10-git-send-email-daniel.lezcano@linaro.org> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1413986273-28522-1-git-send-email-daniel.lezcano@linaro.org> References: <1413986273-28522-1-git-send-email-daniel.lezcano@linaro.org> X-Removed-Original-Auth: Dkim didn't pass. X-Original-Sender: daniel.lezcano@linaro.org X-Original-Authentication-Results: mx.google.com; spf=pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 209.85.215.48 as permitted sender) smtp.mail=patch+caf_=patchwork-forward=linaro.org@linaro.org Precedence: list Mailing-list: list patchwork-forward@linaro.org; contact patchwork-forward+owners@linaro.org List-ID: X-Google-Group-Id: 836684582541 List-Post: , List-Help: , List-Archive: List-Unsubscribe: , Signed-off-by: Daniel Lezcano --- drivers/cpuidle/cpuidle.c | 8 +++ drivers/cpuidle/sysfs.c | 156 ++++++++++++++++++++++++++++++++++++++++++++++ include/linux/cpuidle.h | 7 ++- 3 files changed, 170 insertions(+), 1 deletion(-) diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index bf42e17..66231a40 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c @@ -139,6 +139,14 @@ int cpuidle_enter_state(struct cpuidle_device *dev, struct cpuidle_driver *drv, */ dev->states_usage[entered_state].time += dev->last_residency; dev->states_usage[entered_state].usage++; + if (diff < dev->last_residency) + atomic_inc(&dev->over_estimate); + else if (entered_state < (drv->state_count - 1) && + dev->last_residency < + drv->states[entered_state + 1].target_residency) + atomic_inc(&dev->under_estimate); + else + atomic_inc(&dev->right_estimate); } else { dev->last_residency = 0; } diff --git a/drivers/cpuidle/sysfs.c b/drivers/cpuidle/sysfs.c index 97c5903..f446bd0 100644 --- a/drivers/cpuidle/sysfs.c +++ b/drivers/cpuidle/sysfs.c @@ -439,6 +439,154 @@ static void cpuidle_remove_state_sysfs(struct cpuidle_device *device) cpuidle_free_state_kobj(device, i); } +#define kobj_to_stats_kobj(k) container_of(k, struct cpuidle_stats_kobj, kobj) +#define attr_to_stats_attr(a) container_of(a, struct cpuidle_stats_attr, attr) + +#define define_show_stats_function(_name) \ + static ssize_t show_stats_##_name(struct cpuidle_device *dev, \ + char *buf) \ + { \ + return sprintf(buf, "%d\n", atomic_read(&dev->_name)); \ + } + +#define define_store_stats_function(_name) \ + static ssize_t store_stats_##_name(struct cpuidle_device *dev, \ + const char *buf, size_t size) \ + { \ + unsigned long long value; \ + int err; \ + if (!capable(CAP_SYS_ADMIN)) \ + return -EPERM; \ + err = kstrtoull(buf, 0, &value); \ + if (err) \ + return err; \ + \ + atomic_set(&dev->_name, value); \ + return size; \ + } + +#define define_one_stats_rw(_name, show, store) \ + static struct cpuidle_stats_attr attr_stats_##_name = \ + __ATTR(_name, 0644, show, store) + +struct cpuidle_stats_kobj { + struct cpuidle_device *dev; + struct completion kobj_unregister; + struct kobject kobj; +}; + +struct cpuidle_stats_attr { + struct attribute attr; + ssize_t (*show)(struct cpuidle_device *, char *); + ssize_t (*store)(struct cpuidle_device *, const char *, size_t); +}; + +static void cpuidle_stats_sysfs_release(struct kobject *kobj) +{ + struct cpuidle_stats_kobj *stats_kobj = kobj_to_stats_kobj(kobj); + complete(&stats_kobj->kobj_unregister); +} + +static ssize_t cpuidle_stats_show(struct kobject *kobj, struct attribute *attr, + char *buf) +{ + int ret = -EIO; + struct cpuidle_stats_kobj *stats_kobj = kobj_to_stats_kobj(kobj); + struct cpuidle_stats_attr *dattr = attr_to_stats_attr(attr); + + if (dattr->show) + ret = dattr->show(stats_kobj->dev, buf); + + return ret; +} + +static ssize_t cpuidle_stats_store(struct kobject *kobj, + struct attribute *attr, + const char *buf, size_t size) +{ + int ret = -EIO; + struct cpuidle_stats_kobj *stats_kobj = kobj_to_stats_kobj(kobj); + struct cpuidle_stats_attr *dattr = attr_to_stats_attr(attr); + + if (dattr->store) + ret = dattr->store(stats_kobj->dev, buf, size); + + return ret; +} + +define_show_stats_function(right_estimate); +define_store_stats_function(right_estimate); + +define_show_stats_function(under_estimate); +define_store_stats_function(under_estimate); + +define_show_stats_function(over_estimate); +define_store_stats_function(over_estimate); + +define_one_stats_rw(right_estimate, + show_stats_right_estimate, + store_stats_right_estimate); + +define_one_stats_rw(under_estimate, + show_stats_under_estimate, + store_stats_under_estimate); + +define_one_stats_rw(over_estimate, + show_stats_over_estimate, + store_stats_over_estimate); + +static const struct sysfs_ops cpuidle_stats_sysfs_ops = { + .show = cpuidle_stats_show, + .store = cpuidle_stats_store, +}; + +static struct attribute *cpuidle_stats_default_attrs[] = { + &attr_stats_right_estimate.attr, + &attr_stats_under_estimate.attr, + &attr_stats_over_estimate.attr, + NULL +}; + +static struct kobj_type ktype_stats_cpuidle = { + .sysfs_ops = &cpuidle_stats_sysfs_ops, + .default_attrs = cpuidle_stats_default_attrs, + .release = cpuidle_stats_sysfs_release, +}; + +static int cpuidle_add_stats_sysfs(struct cpuidle_device *dev) +{ + struct cpuidle_stats_kobj *kstats; + struct cpuidle_device_kobj *kdev = dev->kobj_dev; + int ret; + + kstats = kzalloc(sizeof(*kstats), GFP_KERNEL); + if (!kstats) + return -ENOMEM; + + kstats->dev = dev; + init_completion(&kstats->kobj_unregister); + + ret = kobject_init_and_add(&kstats->kobj, &ktype_stats_cpuidle, + &kdev->kobj, "stats"); + if (ret) { + kfree(kstats); + return ret; + } + + kobject_uevent(&kstats->kobj, KOBJ_ADD); + dev->kobj_stats = kstats; + + return ret; +} + +static void cpuidle_remove_stats_sysfs(struct cpuidle_device *dev) +{ + struct cpuidle_stats_kobj *kstats = dev->kobj_stats; + kobject_put(&kstats->kobj); + wait_for_completion(&kstats->kobj_unregister); + kfree(kstats); +} + #ifdef CONFIG_CPU_IDLE_MULTIPLE_DRIVERS #define kobj_to_driver_kobj(k) container_of(k, struct cpuidle_driver_kobj, kobj) #define attr_to_driver_attr(a) container_of(a, struct cpuidle_driver_attr, attr) @@ -589,6 +737,13 @@ int cpuidle_add_device_sysfs(struct cpuidle_device *device) ret = cpuidle_add_driver_sysfs(device); if (ret) cpuidle_remove_state_sysfs(device); + + ret = cpuidle_add_stats_sysfs(device); + if (ret) { + cpuidle_remove_driver_sysfs(device); + cpuidle_remove_state_sysfs(device); + } + return ret; } @@ -598,6 +753,7 @@ int cpuidle_add_device_sysfs(struct cpuidle_device *device) */ void cpuidle_remove_device_sysfs(struct cpuidle_device *device) { + cpuidle_remove_stats_sysfs(device); cpuidle_remove_driver_sysfs(device); cpuidle_remove_state_sysfs(device); } diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h index e99823f..c3b9bdd 100644 --- a/include/linux/cpuidle.h +++ b/include/linux/cpuidle.h @@ -44,7 +44,6 @@ struct cpuidle_state { int power_usage; /* in mW */ unsigned int target_residency; /* in US */ bool disabled; /* disabled on all CPUs */ - int (*enter) (struct cpuidle_device *dev, struct cpuidle_driver *drv, int index); @@ -62,6 +61,7 @@ struct cpuidle_state { struct cpuidle_device_kobj; struct cpuidle_state_kobj; struct cpuidle_driver_kobj; +struct cpuidle_stats_kobj; struct cpuidle_device { unsigned int registered:1; @@ -74,8 +74,13 @@ struct cpuidle_device { struct cpuidle_state_kobj *kobjs[CPUIDLE_STATE_MAX]; struct cpuidle_driver_kobj *kobj_driver; struct cpuidle_device_kobj *kobj_dev; + struct cpuidle_stats_kobj *kobj_stats; struct list_head device_list; + atomic_t right_estimate; + atomic_t under_estimate; + atomic_t over_estimate; + #ifdef CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED int safe_state_index; cpumask_t coupled_cpus;