Skip to content

Commit

Permalink
Merge branches 'pm-cpuidle' and 'pm-tools'
Browse files Browse the repository at this point in the history
* pm-cpuidle:
  cpuidle: poll_state: Avoid invoking local_clock() too often
  PM: cpuidle/suspend: Add s2idle usage and time state attributes
  cpuidle: Enable coupled cpuidle support on Exynos3250 platform
  cpuidle: poll_state: Add time limit to poll_idle()
  ARM: cpuidle: Drop memory allocation error message from arm_idle_init_cpu()

* pm-tools:
  pm-graph: AnalyzeSuspend v5.0
  pm-graph: AnalyzeBoot v2.2
  pm-graph: config files and installer
  • Loading branch information
rafaeljw committed Apr 2, 2018
3 parents a9f36db + 4dc2375 + 700abc9 commit 103cf0e
Show file tree
Hide file tree
Showing 25 changed files with 2,685 additions and 706 deletions.
25 changes: 25 additions & 0 deletions Documentation/ABI/testing/sysfs-devices-system-cpu
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,31 @@ Description:
time (in microseconds) this cpu should spend in this idle state
to make the transition worth the effort.

What: /sys/devices/system/cpu/cpuX/cpuidle/stateN/s2idle/
Date: March 2018
KernelVersion: v4.17
Contact: Linux power management list <linux-pm@vger.kernel.org>
Description:
Idle state usage statistics related to suspend-to-idle.

This attribute group is only present for states that can be
used in suspend-to-idle with suspended timekeeping.

What: /sys/devices/system/cpu/cpuX/cpuidle/stateN/s2idle/time
Date: March 2018
KernelVersion: v4.17
Contact: Linux power management list <linux-pm@vger.kernel.org>
Description:
Total time spent by the CPU in suspend-to-idle (with scheduler
tick suspended) after requesting this state.

What: /sys/devices/system/cpu/cpuX/cpuidle/stateN/s2idle/usage
Date: March 2018
KernelVersion: v4.17
Contact: Linux power management list <linux-pm@vger.kernel.org>
Description:
Total number of times this state has been requested by the CPU
while entering suspend-to-idle.

What: /sys/devices/system/cpu/cpu#/cpufreq/*
Date: pre-git history
Expand Down
1 change: 0 additions & 1 deletion drivers/cpuidle/cpuidle-arm.c
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,6 @@ static int __init arm_idle_init_cpu(int cpu)

dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (!dev) {
pr_err("Failed to allocate cpuidle device\n");
ret = -ENOMEM;
goto out_unregister_drv;
}
Expand Down
3 changes: 2 additions & 1 deletion drivers/cpuidle/cpuidle-exynos.c
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,8 @@ static int exynos_cpuidle_probe(struct platform_device *pdev)
int ret;

if (IS_ENABLED(CONFIG_SMP) &&
of_machine_is_compatible("samsung,exynos4210")) {
(of_machine_is_compatible("samsung,exynos4210") ||
of_machine_is_compatible("samsung,exynos3250"))) {
exynos_cpuidle_pdata = pdev->dev.platform_data;

ret = cpuidle_register(&exynos_coupled_idle_driver,
Expand Down
9 changes: 9 additions & 0 deletions drivers/cpuidle/cpuidle.c
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,10 @@ int cpuidle_find_deepest_state(struct cpuidle_driver *drv,
static void enter_s2idle_proper(struct cpuidle_driver *drv,
struct cpuidle_device *dev, int index)
{
ktime_t time_start, time_end;

time_start = ns_to_ktime(local_clock());

/*
* trace_suspend_resume() called by tick_freeze() for the last CPU
* executing it contains RCU usage regarded as invalid in the idle
Expand All @@ -152,6 +156,11 @@ static void enter_s2idle_proper(struct cpuidle_driver *drv,
*/
RCU_NONIDLE(tick_unfreeze());
start_critical_timings();

time_end = ns_to_ktime(local_clock());

dev->states_usage[index].s2idle_time += ktime_us_delta(time_end, time_start);
dev->states_usage[index].s2idle_usage++;
}

/**
Expand Down
17 changes: 16 additions & 1 deletion drivers/cpuidle/poll_state.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,30 @@

#include <linux/cpuidle.h>
#include <linux/sched.h>
#include <linux/sched/clock.h>
#include <linux/sched/idle.h>

#define POLL_IDLE_TIME_LIMIT (TICK_NSEC / 16)
#define POLL_IDLE_RELAX_COUNT 200

static int __cpuidle poll_idle(struct cpuidle_device *dev,
struct cpuidle_driver *drv, int index)
{
u64 time_start = local_clock();

local_irq_enable();
if (!current_set_polling_and_test()) {
while (!need_resched())
unsigned int loop_count = 0;

while (!need_resched()) {
cpu_relax();
if (loop_count++ < POLL_IDLE_RELAX_COUNT)
continue;

loop_count = 0;
if (local_clock() - time_start > POLL_IDLE_TIME_LIMIT)
break;
}
}
current_clr_polling();

Expand Down
54 changes: 54 additions & 0 deletions drivers/cpuidle/sysfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,58 @@ struct cpuidle_state_kobj {
struct kobject kobj;
};

#ifdef CONFIG_SUSPEND
#define define_show_state_s2idle_ull_function(_name) \
static ssize_t show_state_s2idle_##_name(struct cpuidle_state *state, \
struct cpuidle_state_usage *state_usage, \
char *buf) \
{ \
return sprintf(buf, "%llu\n", state_usage->s2idle_##_name);\
}

define_show_state_s2idle_ull_function(usage);
define_show_state_s2idle_ull_function(time);

#define define_one_state_s2idle_ro(_name, show) \
static struct cpuidle_state_attr attr_s2idle_##_name = \
__ATTR(_name, 0444, show, NULL)

define_one_state_s2idle_ro(usage, show_state_s2idle_usage);
define_one_state_s2idle_ro(time, show_state_s2idle_time);

static struct attribute *cpuidle_state_s2idle_attrs[] = {
&attr_s2idle_usage.attr,
&attr_s2idle_time.attr,
NULL
};

static const struct attribute_group cpuidle_state_s2idle_group = {
.name = "s2idle",
.attrs = cpuidle_state_s2idle_attrs,
};

static void cpuidle_add_s2idle_attr_group(struct cpuidle_state_kobj *kobj)
{
int ret;

if (!kobj->state->enter_s2idle)
return;

ret = sysfs_create_group(&kobj->kobj, &cpuidle_state_s2idle_group);
if (ret)
pr_debug("%s: sysfs attribute group not created\n", __func__);
}

static void cpuidle_remove_s2idle_attr_group(struct cpuidle_state_kobj *kobj)
{
if (kobj->state->enter_s2idle)
sysfs_remove_group(&kobj->kobj, &cpuidle_state_s2idle_group);
}
#else
static inline void cpuidle_add_s2idle_attr_group(struct cpuidle_state_kobj *kobj) { }
static inline void cpuidle_remove_s2idle_attr_group(struct cpuidle_state_kobj *kobj) { }
#endif /* CONFIG_SUSPEND */

#define kobj_to_state_obj(k) container_of(k, struct cpuidle_state_kobj, kobj)
#define kobj_to_state(k) (kobj_to_state_obj(k)->state)
#define kobj_to_state_usage(k) (kobj_to_state_obj(k)->state_usage)
Expand Down Expand Up @@ -383,6 +435,7 @@ static struct kobj_type ktype_state_cpuidle = {

static inline void cpuidle_free_state_kobj(struct cpuidle_device *device, int i)
{
cpuidle_remove_s2idle_attr_group(device->kobjs[i]);
kobject_put(&device->kobjs[i]->kobj);
wait_for_completion(&device->kobjs[i]->kobj_unregister);
kfree(device->kobjs[i]);
Expand Down Expand Up @@ -417,6 +470,7 @@ static int cpuidle_add_state_sysfs(struct cpuidle_device *device)
kfree(kobj);
goto error_state;
}
cpuidle_add_s2idle_attr_group(kobj);
kobject_uevent(&kobj->kobj, KOBJ_ADD);
device->kobjs[i] = kobj;
}
Expand Down
4 changes: 4 additions & 0 deletions include/linux/cpuidle.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ struct cpuidle_state_usage {
unsigned long long disable;
unsigned long long usage;
unsigned long long time; /* in US */
#ifdef CONFIG_SUSPEND
unsigned long long s2idle_usage;
unsigned long long s2idle_time; /* in US */
#endif
};

struct cpuidle_state {
Expand Down
29 changes: 22 additions & 7 deletions tools/power/pm-graph/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,24 @@ all:

install : uninstall
install -d $(DESTDIR)$(PREFIX)/lib/pm-graph
install analyze_suspend.py $(DESTDIR)$(PREFIX)/lib/pm-graph
install analyze_boot.py $(DESTDIR)$(PREFIX)/lib/pm-graph
install sleepgraph.py $(DESTDIR)$(PREFIX)/lib/pm-graph
install bootgraph.py $(DESTDIR)$(PREFIX)/lib/pm-graph
install -d $(DESTDIR)$(PREFIX)/lib/pm-graph/config
install -m 644 config/cgskip.txt $(DESTDIR)$(PREFIX)/lib/pm-graph/config
install -m 644 config/freeze-callgraph.cfg $(DESTDIR)$(PREFIX)/lib/pm-graph/config
install -m 644 config/freeze.cfg $(DESTDIR)$(PREFIX)/lib/pm-graph/config
install -m 644 config/freeze-dev.cfg $(DESTDIR)$(PREFIX)/lib/pm-graph/config
install -m 644 config/standby-callgraph.cfg $(DESTDIR)$(PREFIX)/lib/pm-graph/config
install -m 644 config/standby.cfg $(DESTDIR)$(PREFIX)/lib/pm-graph/config
install -m 644 config/standby-dev.cfg $(DESTDIR)$(PREFIX)/lib/pm-graph/config
install -m 644 config/suspend-callgraph.cfg $(DESTDIR)$(PREFIX)/lib/pm-graph/config
install -m 644 config/suspend.cfg $(DESTDIR)$(PREFIX)/lib/pm-graph/config
install -m 644 config/suspend-dev.cfg $(DESTDIR)$(PREFIX)/lib/pm-graph/config
install -m 644 config/suspend-x2-proc.cfg $(DESTDIR)$(PREFIX)/lib/pm-graph/config

ln -s $(DESTDIR)$(PREFIX)/lib/pm-graph/analyze_boot.py $(DESTDIR)$(PREFIX)/bin/bootgraph
ln -s $(DESTDIR)$(PREFIX)/lib/pm-graph/analyze_suspend.py $(DESTDIR)$(PREFIX)/bin/sleepgraph
install -d $(DESTDIR)$(PREFIX)/bin
ln -s $(DESTDIR)$(PREFIX)/lib/pm-graph/bootgraph.py $(DESTDIR)$(PREFIX)/bin/bootgraph
ln -s $(DESTDIR)$(PREFIX)/lib/pm-graph/sleepgraph.py $(DESTDIR)$(PREFIX)/bin/sleepgraph

install -d $(DESTDIR)$(PREFIX)/share/man/man8
install bootgraph.8 $(DESTDIR)$(PREFIX)/share/man/man8
Expand All @@ -24,9 +37,11 @@ uninstall :
rm -f $(DESTDIR)$(PREFIX)/bin/bootgraph
rm -f $(DESTDIR)$(PREFIX)/bin/sleepgraph

rm -f $(DESTDIR)$(PREFIX)/lib/pm-graph/analyze_boot.py
rm -f $(DESTDIR)$(PREFIX)/lib/pm-graph/analyze_suspend.py
rm -f $(DESTDIR)$(PREFIX)/lib/pm-graph/*.pyc
rm -f $(DESTDIR)$(PREFIX)/lib/pm-graph/config/*
if [ -d $(DESTDIR)$(PREFIX)/lib/pm-graph/config ] ; then \
rmdir $(DESTDIR)$(PREFIX)/lib/pm-graph/config; \
fi;
rm -f $(DESTDIR)$(PREFIX)/lib/pm-graph/*
if [ -d $(DESTDIR)$(PREFIX)/lib/pm-graph ] ; then \
rmdir $(DESTDIR)$(PREFIX)/lib/pm-graph; \
fi;
18 changes: 14 additions & 4 deletions tools/power/pm-graph/bootgraph.8
Original file line number Diff line number Diff line change
Expand Up @@ -37,21 +37,24 @@ Print the current tool version
Add the dmesg log to the html output. It will be viewable by
clicking a button in the timeline.
.TP
\fB-result \fIfile\fR
Export a results table to a text file for parsing.
.TP
\fB-o \fIname\fR
Overrides the output subdirectory name when running a new test.
Use {date}, {time}, {hostname} for current values.
.sp
e.g. boot-{hostname}-{date}-{time}
.SS "advanced"
.TP
\fB-f\fR
Use ftrace to add function detail (default: disabled)
.TP
\fB-callgraph\fR
\fB-f or -callgraph\fR
Use ftrace to create initcall callgraphs (default: disabled). If -func
is not used there will be one callgraph per initcall. This can produce
very large outputs, i.e. 10MB - 100MB.
.TP
\fB-fstat\fR
Use ftrace to add function detail (default: disabled)
.TP
\fB-maxdepth \fIlevel\fR
limit the callgraph trace depth to \fIlevel\fR (default: 2). This is
the best way to limit the output size when using -callgraph.
Expand All @@ -67,6 +70,13 @@ Reduce callgraph output in the timeline by limiting it to a list of calls. The
argument can be a single function name or a comma delimited list.
(default: none)
.TP
\fB-cgskip \fIfile\fR
Reduce callgraph output in the timeline by skipping over uninteresting
functions in the trace, e.g. printk or console_unlock. The functions listed
in this file will show up as empty leaves in the callgraph with only the start/end
times displayed.
(default: none)
.TP
\fB-timeprec \fIn\fR
Number of significant digits in timestamps (0:S, 3:ms, [6:us])
.TP
Expand Down
Loading

0 comments on commit 103cf0e

Please sign in to comment.