Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag 'pm-4.12-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm

Pull power management updates from Rafael Wysocki:
"This time the majority of changes go to the cpufreq subsystem (and to
the intel_pstate driver in particular) and there are some updates in
the generic power domains framework, cpuidle, tools and a couple of
other places.

One thing worth mentioning is that the intel_pstate's sysfs interface
has been reworked to be more consistent with the general expectations
of the cpufreq core and less confusing, hopefully for the better.
Also, we have a new cpufreq driver for Tegra186 and new hardware
support in intel_pstata and the Mediatek cpufreq driver.

Apart from that, the AnalyzeSuspend utility for system suspend
profiling gets a companion called AnalyzeBoot for the analogous
profiling of system boot and they both go into one place under
tools/power/pm-graph/.

The rest is mostly fixes, cleanups and code reorganization.

Specifics:

- Rework the intel_pstate driver's sysfs interface to make it more
straightforward and more intuitive (Rafael Wysocki).

- Make intel_pstate support all processors which advertise HWP
(hardware-managed P-states) to the kernel in all operation modes
and make it use the load-based P-state selection algorithm on a
wider range of systems in the active mode (Rafael Wysocki).

- Add cpufreq driver for Tegra186 (Mikko Perttunen).

- Add support for Gemini Lake SoCs to intel_pstate (David Box).

- Add support for MT8176 and MT817x to the Mediatek cpufreq driver
and clean up that driver a bit (Daniel Kurtz).

- Clean up intel_pstate and optimize it slightly (Rafael Wysocki).

- Update the schedutil cpufreq governor, mostly to fix a couple of
issues with it related to specific workloads, and rework its sysfs
tunable and initialization a bit (Rafael Wysocki, Viresh Kumar).

- Fix minor issues in the imx6q, dbx500 and qoriq cpufreq drivers
(Christophe Jaillet, Irina Tirdea, Leonard Crestez, Viresh Kumar,
YuanTian Tang).

- Add file patterns for cpufreq DT bindings to MAINTAINERS (Geert
Uytterhoeven).

- Add support for "always on" power domains to the genpd (generic
power domains) framework and clean up that code somewhat (Ulf
Hansson, Lina Iyer, Viresh Kumar).

- Fix minor issues in the powernv cpuidle driver and clean it up
(Anton Blanchard, Gautham Shenoy).

- Move the AnalyzeSuspend utility under tools/power/pm-graph/ and add
an analogous boot-profiling utility called AnalyzeBoot to it (Todd
Brandt).

- Add rk3328 support to the rockchip-io AVS (Adaptive Voltage
Scaling) driver (David Wu).

- Fix minor issues in the cpuidle core, the intel_pstate_tracer
utility, the devfreq framework and the PM core documentation
(Chanwoo Choi, Doug Smythies, Johan Hovold, Marcin Nowakowski)"

* tag 'pm-4.12-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: (56 commits)
PM / runtime: Document autosuspend-helper side effects
PM / runtime: Fix autosuspend documentation
tools: power: pm-graph: Package makefile and man pages
tools: power: pm-graph: AnalyzeBoot v2.0
tools: power: pm-graph: AnalyzeSuspend v4.6
cpufreq: Add Tegra186 cpufreq driver
cpufreq: imx6q: Fix error handling code
cpufreq: imx6q: Set max suspend_freq to avoid changes during suspend
cpufreq: imx6q: Fix handling EPROBE_DEFER from regulator
cpuidle: powernv: Avoid a branch in the core snooze_loop() loop
cpuidle: powernv: Don't continually set thread priority in snooze_loop()
cpuidle: powernv: Don't bounce between low and very low thread priority
cpuidle: cpuidle-cps: remove unused variable
tools/power/x86/intel_pstate_tracer: Adjust directory ownership
cpufreq: schedutil: Use policy-dependent transition delays
cpufreq: schedutil: Reduce frequencies slower
PM / devfreq: Move struct devfreq_governor to devfreq directory
PM / Domains: Ignore domain-idle-states that are not compatible
cpufreq: intel_pstate: Add support for Gemini Lake
powernv-cpuidle: Validate DT property array size
...

+2778 -1157
+3 -1
Documentation/devicetree/bindings/power/power_domain.txt
··· 31 31 32 32 - domain-idle-states : A phandle of an idle-state that shall be soaked into a 33 33 generic domain power state. The idle state definitions are 34 - compatible with domain-idle-state specified in [1]. 34 + compatible with domain-idle-state specified in [1]. phandles 35 + that are not compatible with domain-idle-state will be 36 + ignored. 35 37 The domain-idle-state property reflects the idle state of this PM domain and 36 38 not the idle states of the devices or sub-domains in the PM domain. Devices 37 39 and sub-domains have their own idle-states independent of the parent
+1
Documentation/devicetree/bindings/power/rockchip-io-domain.txt
··· 33 33 - compatible: should be one of: 34 34 - "rockchip,rk3188-io-voltage-domain" for rk3188 35 35 - "rockchip,rk3288-io-voltage-domain" for rk3288 36 + - "rockchip,rk3328-io-voltage-domain" for rk3328 36 37 - "rockchip,rk3368-io-voltage-domain" for rk3368 37 38 - "rockchip,rk3368-pmu-io-voltage-domain" for rk3368 pmu-domains 38 39 - "rockchip,rk3399-io-voltage-domain" for rk3399
+13 -6
Documentation/power/runtime_pm.txt
··· 478 478 - set the power.last_busy field to the current time 479 479 480 480 void pm_runtime_use_autosuspend(struct device *dev); 481 - - set the power.use_autosuspend flag, enabling autosuspend delays 481 + - set the power.use_autosuspend flag, enabling autosuspend delays; call 482 + pm_runtime_get_sync if the flag was previously cleared and 483 + power.autosuspend_delay is negative 482 484 483 485 void pm_runtime_dont_use_autosuspend(struct device *dev); 484 - - clear the power.use_autosuspend flag, disabling autosuspend delays 486 + - clear the power.use_autosuspend flag, disabling autosuspend delays; 487 + decrement the device's usage counter if the flag was previously set and 488 + power.autosuspend_delay is negative; call pm_runtime_idle 485 489 486 490 void pm_runtime_set_autosuspend_delay(struct device *dev, int delay); 487 491 - set the power.autosuspend_delay value to 'delay' (expressed in 488 492 milliseconds); if 'delay' is negative then runtime suspends are 489 - prevented 493 + prevented; if power.use_autosuspend is set, pm_runtime_get_sync may be 494 + called or the device's usage counter may be decremented and 495 + pm_runtime_idle called depending on if power.autosuspend_delay is 496 + changed to or from a negative value; if power.use_autosuspend is clear, 497 + pm_runtime_idle is called 490 498 491 499 unsigned long pm_runtime_autosuspend_expiration(struct device *dev); 492 500 - calculate the time when the current autosuspend delay period will expire, ··· 844 836 Instead of: pm_runtime_put_sync use: pm_runtime_put_sync_autosuspend. 845 837 846 838 Drivers may also continue to use the non-autosuspend helper functions; they 847 - will behave normally, not taking the autosuspend delay into account. 848 - Similarly, if the power.use_autosuspend field isn't set then the autosuspend 849 - helper functions will behave just like the non-autosuspend counterparts. 839 + will behave normally, which means sometimes taking the autosuspend delay into 840 + account (see pm_runtime_idle). 850 841 851 842 Under some circumstances a driver or subsystem may want to prevent a device 852 843 from autosuspending immediately, even though the usage counter is zero and the
+1
MAINTAINERS
··· 3471 3471 T: git git://git.linaro.org/people/vireshk/linux.git (For ARM Updates) 3472 3472 B: https://bugzilla.kernel.org 3473 3473 F: Documentation/cpu-freq/ 3474 + F: Documentation/devicetree/bindings/cpufreq/ 3474 3475 F: drivers/cpufreq/ 3475 3476 F: include/linux/cpufreq.h 3476 3477 F: tools/testing/selftests/cpufreq/
-5
arch/arm/boot/dts/ste-dbx5x0.dtsi
··· 1189 1189 status = "disabled"; 1190 1190 }; 1191 1191 1192 - cpufreq-cooling { 1193 - compatible = "stericsson,db8500-cpufreq-cooling"; 1194 - status = "disabled"; 1195 - }; 1196 - 1197 1192 mcde@a0350000 { 1198 1193 compatible = "stericsson,mcde"; 1199 1194 reg = <0xa0350000 0x1000>, /* MCDE */
+42 -26
drivers/base/power/domain.c
··· 121 121 #define genpd_lock_interruptible(p) p->lock_ops->lock_interruptible(p) 122 122 #define genpd_unlock(p) p->lock_ops->unlock(p) 123 123 124 + #define genpd_status_on(genpd) (genpd->status == GPD_STATE_ACTIVE) 124 125 #define genpd_is_irq_safe(genpd) (genpd->flags & GENPD_FLAG_IRQ_SAFE) 126 + #define genpd_is_always_on(genpd) (genpd->flags & GENPD_FLAG_ALWAYS_ON) 125 127 126 128 static inline bool irq_safe_dev_in_no_sleep_domain(struct device *dev, 127 129 struct generic_pm_domain *genpd) ··· 132 130 133 131 ret = pm_runtime_is_irq_safe(dev) && !genpd_is_irq_safe(genpd); 134 132 135 - /* Warn once if IRQ safe dev in no sleep domain */ 136 - if (ret) 133 + /* 134 + * Warn once if an IRQ safe device is attached to a no sleep domain, as 135 + * to indicate a suboptimal configuration for PM. For an always on 136 + * domain this isn't case, thus don't warn. 137 + */ 138 + if (ret && !genpd_is_always_on(genpd)) 137 139 dev_warn_once(dev, "PM domain %s will not be powered off\n", 138 140 genpd->name); 139 141 ··· 302 296 * (1) The domain is already in the "power off" state. 303 297 * (2) System suspend is in progress. 304 298 */ 305 - if (genpd->status == GPD_STATE_POWER_OFF 306 - || genpd->prepared_count > 0) 299 + if (!genpd_status_on(genpd) || genpd->prepared_count > 0) 307 300 return 0; 308 301 309 - if (atomic_read(&genpd->sd_count) > 0) 302 + /* 303 + * Abort power off for the PM domain in the following situations: 304 + * (1) The domain is configured as always on. 305 + * (2) When the domain has a subdomain being powered on. 306 + */ 307 + if (genpd_is_always_on(genpd) || atomic_read(&genpd->sd_count) > 0) 310 308 return -EBUSY; 311 309 312 310 list_for_each_entry(pdd, &genpd->dev_list, list_node) { ··· 383 373 struct gpd_link *link; 384 374 int ret = 0; 385 375 386 - if (genpd->status == GPD_STATE_ACTIVE) 376 + if (genpd_status_on(genpd)) 387 377 return 0; 388 378 389 379 /* ··· 762 752 { 763 753 struct gpd_link *link; 764 754 765 - if (genpd->status == GPD_STATE_POWER_OFF) 755 + if (!genpd_status_on(genpd) || genpd_is_always_on(genpd)) 766 756 return; 767 757 768 758 if (genpd->suspended_count != genpd->device_count ··· 771 761 772 762 /* Choose the deepest state when suspending */ 773 763 genpd->state_idx = genpd->state_count - 1; 774 - _genpd_power_off(genpd, false); 764 + if (_genpd_power_off(genpd, false)) 765 + return; 775 766 776 767 genpd->status = GPD_STATE_POWER_OFF; 777 768 ··· 804 793 { 805 794 struct gpd_link *link; 806 795 807 - if (genpd->status == GPD_STATE_ACTIVE) 796 + if (genpd_status_on(genpd)) 808 797 return; 809 798 810 799 list_for_each_entry(link, &genpd->slave_links, slave_node) { ··· 1340 1329 genpd_lock(subdomain); 1341 1330 genpd_lock_nested(genpd, SINGLE_DEPTH_NESTING); 1342 1331 1343 - if (genpd->status == GPD_STATE_POWER_OFF 1344 - && subdomain->status != GPD_STATE_POWER_OFF) { 1332 + if (!genpd_status_on(genpd) && genpd_status_on(subdomain)) { 1345 1333 ret = -EINVAL; 1346 1334 goto out; 1347 1335 } ··· 1356 1346 list_add_tail(&link->master_node, &genpd->master_links); 1357 1347 link->slave = subdomain; 1358 1348 list_add_tail(&link->slave_node, &subdomain->slave_links); 1359 - if (subdomain->status != GPD_STATE_POWER_OFF) 1349 + if (genpd_status_on(subdomain)) 1360 1350 genpd_sd_counter_inc(genpd); 1361 1351 1362 1352 out: ··· 1416 1406 list_del(&link->master_node); 1417 1407 list_del(&link->slave_node); 1418 1408 kfree(link); 1419 - if (subdomain->status != GPD_STATE_POWER_OFF) 1409 + if (genpd_status_on(subdomain)) 1420 1410 genpd_sd_counter_dec(genpd); 1421 1411 1422 1412 ret = 0; ··· 1501 1491 genpd->dev_ops.stop = pm_clk_suspend; 1502 1492 genpd->dev_ops.start = pm_clk_resume; 1503 1493 } 1494 + 1495 + /* Always-on domains must be powered on at initialization. */ 1496 + if (genpd_is_always_on(genpd) && !genpd_status_on(genpd)) 1497 + return -EINVAL; 1504 1498 1505 1499 /* Use only one "off" state if there were no states declared */ 1506 1500 if (genpd->state_count == 0) { ··· 1714 1700 1715 1701 mutex_lock(&gpd_list_lock); 1716 1702 1717 - if (pm_genpd_present(genpd)) 1703 + if (pm_genpd_present(genpd)) { 1718 1704 ret = genpd_add_provider(np, genpd_xlate_simple, genpd); 1719 - 1720 - if (!ret) { 1721 - genpd->provider = &np->fwnode; 1722 - genpd->has_provider = true; 1705 + if (!ret) { 1706 + genpd->provider = &np->fwnode; 1707 + genpd->has_provider = true; 1708 + } 1723 1709 } 1724 1710 1725 1711 mutex_unlock(&gpd_list_lock); ··· 2093 2079 int err; 2094 2080 u32 residency; 2095 2081 u32 entry_latency, exit_latency; 2096 - const struct of_device_id *match_id; 2097 - 2098 - match_id = of_match_node(idle_state_match, state_node); 2099 - if (!match_id) 2100 - return -EINVAL; 2101 2082 2102 2083 err = of_property_read_u32(state_node, "entry-latency-us", 2103 2084 &entry_latency); ··· 2141 2132 int err, ret; 2142 2133 int count; 2143 2134 struct of_phandle_iterator it; 2135 + const struct of_device_id *match_id; 2144 2136 2145 2137 count = of_count_phandle_with_args(dn, "domain-idle-states", NULL); 2146 2138 if (count <= 0) ··· 2154 2144 /* Loop over the phandles until all the requested entry is found */ 2155 2145 of_for_each_phandle(&it, err, dn, "domain-idle-states", NULL, 0) { 2156 2146 np = it.node; 2147 + match_id = of_match_node(idle_state_match, np); 2148 + if (!match_id) 2149 + continue; 2157 2150 ret = genpd_parse_state(&st[i++], np); 2158 2151 if (ret) { 2159 2152 pr_err ··· 2168 2155 } 2169 2156 } 2170 2157 2171 - *n = count; 2172 - *states = st; 2158 + *n = i; 2159 + if (!i) 2160 + kfree(st); 2161 + else 2162 + *states = st; 2173 2163 2174 2164 return 0; 2175 2165 } ··· 2237 2221 2238 2222 if (WARN_ON(genpd->status >= ARRAY_SIZE(status_lookup))) 2239 2223 goto exit; 2240 - if (genpd->status == GPD_STATE_POWER_OFF) 2224 + if (!genpd_status_on(genpd)) 2241 2225 snprintf(state, sizeof(state), "%s-%u", 2242 2226 status_lookup[genpd->status], genpd->state_idx); 2243 2227 else
+6
drivers/cpufreq/Kconfig.arm
··· 247 247 help 248 248 This adds the CPUFreq driver support for Tegra124 SOCs. 249 249 250 + config ARM_TEGRA186_CPUFREQ 251 + tristate "Tegra186 CPUFreq support" 252 + depends on ARCH_TEGRA && TEGRA_BPMP 253 + help 254 + This adds the CPUFreq driver support for Tegra186 SOCs. 255 + 250 256 config ARM_TI_CPUFREQ 251 257 bool "Texas Instruments CPUFreq support" 252 258 depends on ARCH_OMAP2PLUS
+1
drivers/cpufreq/Makefile
··· 77 77 obj-$(CONFIG_ARM_STI_CPUFREQ) += sti-cpufreq.o 78 78 obj-$(CONFIG_ARM_TEGRA20_CPUFREQ) += tegra20-cpufreq.o 79 79 obj-$(CONFIG_ARM_TEGRA124_CPUFREQ) += tegra124-cpufreq.o 80 + obj-$(CONFIG_ARM_TEGRA186_CPUFREQ) += tegra186-cpufreq.o 80 81 obj-$(CONFIG_ARM_TI_CPUFREQ) += ti-cpufreq.o 81 82 obj-$(CONFIG_ARM_VEXPRESS_SPC_CPUFREQ) += vexpress-spc-cpufreq.o 82 83 obj-$(CONFIG_ACPI_CPPC_CPUFREQ) += cppc_cpufreq.o
+20
drivers/cpufreq/dbx500-cpufreq.c
··· 11 11 #include <linux/module.h> 12 12 #include <linux/kernel.h> 13 13 #include <linux/cpufreq.h> 14 + #include <linux/cpu_cooling.h> 14 15 #include <linux/delay.h> 15 16 #include <linux/slab.h> 16 17 #include <linux/platform_device.h> ··· 19 18 20 19 static struct cpufreq_frequency_table *freq_table; 21 20 static struct clk *armss_clk; 21 + static struct thermal_cooling_device *cdev; 22 22 23 23 static int dbx500_cpufreq_target(struct cpufreq_policy *policy, 24 24 unsigned int index) ··· 34 32 return cpufreq_generic_init(policy, freq_table, 20 * 1000); 35 33 } 36 34 35 + static int dbx500_cpufreq_exit(struct cpufreq_policy *policy) 36 + { 37 + if (!IS_ERR(cdev)) 38 + cpufreq_cooling_unregister(cdev); 39 + return 0; 40 + } 41 + 42 + static void dbx500_cpufreq_ready(struct cpufreq_policy *policy) 43 + { 44 + cdev = cpufreq_cooling_register(policy->cpus); 45 + if (IS_ERR(cdev)) 46 + pr_err("Failed to register cooling device %ld\n", PTR_ERR(cdev)); 47 + else 48 + pr_info("Cooling device registered: %s\n", cdev->type); 49 + } 50 + 37 51 static struct cpufreq_driver dbx500_cpufreq_driver = { 38 52 .flags = CPUFREQ_STICKY | CPUFREQ_CONST_LOOPS | 39 53 CPUFREQ_NEED_INITIAL_FREQ_CHECK, ··· 57 39 .target_index = dbx500_cpufreq_target, 58 40 .get = cpufreq_generic_get, 59 41 .init = dbx500_cpufreq_init, 42 + .exit = dbx500_cpufreq_exit, 43 + .ready = dbx500_cpufreq_ready, 60 44 .name = "DBX500", 61 45 .attr = cpufreq_generic_attr, 62 46 };
+15 -2
drivers/cpufreq/imx6q-cpufreq.c
··· 161 161 162 162 static int imx6q_cpufreq_init(struct cpufreq_policy *policy) 163 163 { 164 + int ret; 165 + 164 166 policy->clk = arm_clk; 165 - return cpufreq_generic_init(policy, freq_table, transition_latency); 167 + ret = cpufreq_generic_init(policy, freq_table, transition_latency); 168 + policy->suspend_freq = policy->max; 169 + 170 + return ret; 166 171 } 167 172 168 173 static struct cpufreq_driver imx6q_cpufreq_driver = { ··· 178 173 .init = imx6q_cpufreq_init, 179 174 .name = "imx6q-cpufreq", 180 175 .attr = cpufreq_generic_attr, 176 + .suspend = cpufreq_generic_suspend, 181 177 }; 182 178 183 179 static int imx6q_cpufreq_probe(struct platform_device *pdev) ··· 228 222 arm_reg = regulator_get(cpu_dev, "arm"); 229 223 pu_reg = regulator_get_optional(cpu_dev, "pu"); 230 224 soc_reg = regulator_get(cpu_dev, "soc"); 225 + if (PTR_ERR(arm_reg) == -EPROBE_DEFER || 226 + PTR_ERR(soc_reg) == -EPROBE_DEFER || 227 + PTR_ERR(pu_reg) == -EPROBE_DEFER) { 228 + ret = -EPROBE_DEFER; 229 + dev_dbg(cpu_dev, "regulators not ready, defer\n"); 230 + goto put_reg; 231 + } 231 232 if (IS_ERR(arm_reg) || IS_ERR(soc_reg)) { 232 233 dev_err(cpu_dev, "failed to get regulators\n"); 233 234 ret = -ENOENT; ··· 268 255 ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table); 269 256 if (ret) { 270 257 dev_err(cpu_dev, "failed to init cpufreq table: %d\n", ret); 271 - goto put_reg; 258 + goto out_free_opp; 272 259 } 273 260 274 261 /* Make imx6_soc_volt array's size same as arm opp number */
+414 -504
drivers/cpufreq/intel_pstate.c
··· 37 37 #include <asm/cpufeature.h> 38 38 #include <asm/intel-family.h> 39 39 40 + #define INTEL_PSTATE_DEFAULT_SAMPLING_INTERVAL (10 * NSEC_PER_MSEC) 41 + #define INTEL_PSTATE_HWP_SAMPLING_INTERVAL (50 * NSEC_PER_MSEC) 42 + 40 43 #define INTEL_CPUFREQ_TRANSITION_LATENCY 20000 44 + #define INTEL_CPUFREQ_TRANSITION_DELAY 500 41 45 42 46 #ifdef CONFIG_ACPI 43 47 #include <acpi/processor.h> ··· 76 72 if (x & mask) 77 73 ret += 1; 78 74 return ret; 75 + } 76 + 77 + static inline int32_t percent_fp(int percent) 78 + { 79 + return div_fp(percent, 100); 79 80 } 80 81 81 82 static inline u64 mul_ext_fp(u64 x, u64 y) ··· 195 186 }; 196 187 197 188 /** 198 - * struct perf_limits - Store user and policy limits 199 - * @no_turbo: User requested turbo state from intel_pstate sysfs 200 - * @turbo_disabled: Platform turbo status either from msr 201 - * MSR_IA32_MISC_ENABLE or when maximum available pstate 202 - * matches the maximum turbo pstate 203 - * @max_perf_pct: Effective maximum performance limit in percentage, this 204 - * is minimum of either limits enforced by cpufreq policy 205 - * or limits from user set limits via intel_pstate sysfs 206 - * @min_perf_pct: Effective minimum performance limit in percentage, this 207 - * is maximum of either limits enforced by cpufreq policy 208 - * or limits from user set limits via intel_pstate sysfs 209 - * @max_perf: This is a scaled value between 0 to 255 for max_perf_pct 210 - * This value is used to limit max pstate 211 - * @min_perf: This is a scaled value between 0 to 255 for min_perf_pct 212 - * This value is used to limit min pstate 213 - * @max_policy_pct: The maximum performance in percentage enforced by 214 - * cpufreq setpolicy interface 215 - * @max_sysfs_pct: The maximum performance in percentage enforced by 216 - * intel pstate sysfs interface, unused when per cpu 217 - * controls are enforced 218 - * @min_policy_pct: The minimum performance in percentage enforced by 219 - * cpufreq setpolicy interface 220 - * @min_sysfs_pct: The minimum performance in percentage enforced by 221 - * intel pstate sysfs interface, unused when per cpu 222 - * controls are enforced 223 - * 224 - * Storage for user and policy defined limits. 189 + * struct global_params - Global parameters, mostly tunable via sysfs. 190 + * @no_turbo: Whether or not to use turbo P-states. 191 + * @turbo_disabled: Whethet or not turbo P-states are available at all, 192 + * based on the MSR_IA32_MISC_ENABLE value and whether or 193 + * not the maximum reported turbo P-state is different from 194 + * the maximum reported non-turbo one. 195 + * @min_perf_pct: Minimum capacity limit in percent of the maximum turbo 196 + * P-state capacity. 197 + * @max_perf_pct: Maximum capacity limit in percent of the maximum turbo 198 + * P-state capacity. 225 199 */ 226 - struct perf_limits { 227 - int no_turbo; 228 - int turbo_disabled; 200 + struct global_params { 201 + bool no_turbo; 202 + bool turbo_disabled; 229 203 int max_perf_pct; 230 204 int min_perf_pct; 231 - int32_t max_perf; 232 - int32_t min_perf; 233 - int max_policy_pct; 234 - int max_sysfs_pct; 235 - int min_policy_pct; 236 - int min_sysfs_pct; 237 205 }; 238 206 239 207 /** ··· 231 245 * @prev_cummulative_iowait: IO Wait time difference from last and 232 246 * current sample 233 247 * @sample: Storage for storing last Sample data 234 - * @perf_limits: Pointer to perf_limit unique to this CPU 235 - * Not all field in the structure are applicable 236 - * when per cpu controls are enforced 248 + * @min_perf: Minimum capacity limit as a fraction of the maximum 249 + * turbo P-state capacity. 250 + * @max_perf: Maximum capacity limit as a fraction of the maximum 251 + * turbo P-state capacity. 237 252 * @acpi_perf_data: Stores ACPI perf information read from _PSS 238 253 * @valid_pss_table: Set to true for valid ACPI _PSS entries found 239 254 * @epp_powersave: Last saved HWP energy performance preference ··· 266 279 u64 prev_tsc; 267 280 u64 prev_cummulative_iowait; 268 281 struct sample sample; 269 - struct perf_limits *perf_limits; 282 + int32_t min_perf; 283 + int32_t max_perf; 270 284 #ifdef CONFIG_ACPI 271 285 struct acpi_processor_performance acpi_perf_data; 272 286 bool valid_pss_table; ··· 312 324 * @get_scaling: Callback to get frequency scaling factor 313 325 * @get_val: Callback to convert P state to actual MSR write value 314 326 * @get_vid: Callback to get VID data for Atom platforms 315 - * @get_target_pstate: Callback to a function to calculate next P state to use 327 + * @update_util: Active mode utilization update callback. 316 328 * 317 329 * Core and Atom CPU models have different way to get P State limits. This 318 330 * structure is used to store those callbacks. ··· 325 337 int (*get_scaling)(void); 326 338 u64 (*get_val)(struct cpudata*, int pstate); 327 339 void (*get_vid)(struct cpudata *); 328 - int32_t (*get_target_pstate)(struct cpudata *); 340 + void (*update_util)(struct update_util_data *data, u64 time, 341 + unsigned int flags); 329 342 }; 330 343 331 - /** 332 - * struct cpu_defaults- Per CPU model default config data 333 - * @pid_policy: PID config data 334 - * @funcs: Callback function data 335 - */ 336 - struct cpu_defaults { 337 - struct pstate_adjust_policy pid_policy; 338 - struct pstate_funcs funcs; 339 - }; 340 - 341 - static inline int32_t get_target_pstate_use_performance(struct cpudata *cpu); 342 - static inline int32_t get_target_pstate_use_cpu_load(struct cpudata *cpu); 343 - 344 - static struct pstate_adjust_policy pid_params __read_mostly; 345 344 static struct pstate_funcs pstate_funcs __read_mostly; 345 + static struct pstate_adjust_policy pid_params __read_mostly = { 346 + .sample_rate_ms = 10, 347 + .sample_rate_ns = 10 * NSEC_PER_MSEC, 348 + .deadband = 0, 349 + .setpoint = 97, 350 + .p_gain_pct = 20, 351 + .d_gain_pct = 0, 352 + .i_gain_pct = 0, 353 + }; 354 + 346 355 static int hwp_active __read_mostly; 347 356 static bool per_cpu_limits __read_mostly; 348 357 349 - static bool driver_registered __read_mostly; 358 + static struct cpufreq_driver *intel_pstate_driver __read_mostly; 350 359 351 360 #ifdef CONFIG_ACPI 352 361 static bool acpi_ppc; 353 362 #endif 354 363 355 - static struct perf_limits global; 356 - 357 - static void intel_pstate_init_limits(struct perf_limits *limits) 358 - { 359 - memset(limits, 0, sizeof(*limits)); 360 - limits->max_perf_pct = 100; 361 - limits->max_perf = int_ext_tofp(1); 362 - limits->max_policy_pct = 100; 363 - limits->max_sysfs_pct = 100; 364 - } 364 + static struct global_params global; 365 365 366 366 static DEFINE_MUTEX(intel_pstate_driver_lock); 367 367 static DEFINE_MUTEX(intel_pstate_limits_lock); ··· 506 530 } 507 531 #endif 508 532 509 - static inline void pid_reset(struct _pid *pid, int setpoint, int busy, 510 - int deadband, int integral) { 511 - pid->setpoint = int_tofp(setpoint); 512 - pid->deadband = int_tofp(deadband); 513 - pid->integral = int_tofp(integral); 514 - pid->last_err = int_tofp(setpoint) - int_tofp(busy); 515 - } 516 - 517 - static inline void pid_p_gain_set(struct _pid *pid, int percent) 518 - { 519 - pid->p_gain = div_fp(percent, 100); 520 - } 521 - 522 - static inline void pid_i_gain_set(struct _pid *pid, int percent) 523 - { 524 - pid->i_gain = div_fp(percent, 100); 525 - } 526 - 527 - static inline void pid_d_gain_set(struct _pid *pid, int percent) 528 - { 529 - pid->d_gain = div_fp(percent, 100); 530 - } 531 - 532 533 static signed int pid_calc(struct _pid *pid, int32_t busy) 533 534 { 534 535 signed int result; ··· 543 590 return (signed int)fp_toint(result); 544 591 } 545 592 546 - static inline void intel_pstate_busy_pid_reset(struct cpudata *cpu) 593 + static inline void intel_pstate_pid_reset(struct cpudata *cpu) 547 594 { 548 - pid_p_gain_set(&cpu->pid, pid_params.p_gain_pct); 549 - pid_d_gain_set(&cpu->pid, pid_params.d_gain_pct); 550 - pid_i_gain_set(&cpu->pid, pid_params.i_gain_pct); 595 + struct _pid *pid = &cpu->pid; 551 596 552 - pid_reset(&cpu->pid, pid_params.setpoint, 100, pid_params.deadband, 0); 553 - } 554 - 555 - static inline void intel_pstate_reset_all_pid(void) 556 - { 557 - unsigned int cpu; 558 - 559 - for_each_online_cpu(cpu) { 560 - if (all_cpu_data[cpu]) 561 - intel_pstate_busy_pid_reset(all_cpu_data[cpu]); 562 - } 597 + pid->p_gain = percent_fp(pid_params.p_gain_pct); 598 + pid->d_gain = percent_fp(pid_params.d_gain_pct); 599 + pid->i_gain = percent_fp(pid_params.i_gain_pct); 600 + pid->setpoint = int_tofp(pid_params.setpoint); 601 + pid->last_err = pid->setpoint - int_tofp(100); 602 + pid->deadband = int_tofp(pid_params.deadband); 603 + pid->integral = 0; 563 604 } 564 605 565 606 static inline void update_turbo_state(void) ··· 566 619 global.turbo_disabled = 567 620 (misc_en & MSR_IA32_MISC_ENABLE_TURBO_DISABLE || 568 621 cpu->pstate.max_pstate == cpu->pstate.turbo_pstate); 622 + } 623 + 624 + static int min_perf_pct_min(void) 625 + { 626 + struct cpudata *cpu = all_cpu_data[0]; 627 + 628 + return DIV_ROUND_UP(cpu->pstate.min_pstate * 100, 629 + cpu->pstate.turbo_pstate); 569 630 } 570 631 571 632 static s16 intel_pstate_get_epb(struct cpudata *cpu_data) ··· 793 838 NULL, 794 839 }; 795 840 796 - static void intel_pstate_hwp_set(struct cpufreq_policy *policy) 841 + static void intel_pstate_hwp_set(unsigned int cpu) 797 842 { 798 - int min, hw_min, max, hw_max, cpu; 799 - struct perf_limits *perf_limits = &global; 843 + struct cpudata *cpu_data = all_cpu_data[cpu]; 844 + int min, hw_min, max, hw_max; 800 845 u64 value, cap; 846 + s16 epp; 801 847 802 - for_each_cpu(cpu, policy->cpus) { 803 - struct cpudata *cpu_data = all_cpu_data[cpu]; 804 - s16 epp; 848 + rdmsrl_on_cpu(cpu, MSR_HWP_CAPABILITIES, &cap); 849 + hw_min = HWP_LOWEST_PERF(cap); 850 + if (global.no_turbo) 851 + hw_max = HWP_GUARANTEED_PERF(cap); 852 + else 853 + hw_max = HWP_HIGHEST_PERF(cap); 805 854 806 - if (per_cpu_limits) 807 - perf_limits = all_cpu_data[cpu]->perf_limits; 855 + max = fp_ext_toint(hw_max * cpu_data->max_perf); 856 + if (cpu_data->policy == CPUFREQ_POLICY_PERFORMANCE) 857 + min = max; 858 + else 859 + min = fp_ext_toint(hw_max * cpu_data->min_perf); 808 860 809 - rdmsrl_on_cpu(cpu, MSR_HWP_CAPABILITIES, &cap); 810 - hw_min = HWP_LOWEST_PERF(cap); 811 - if (global.no_turbo) 812 - hw_max = HWP_GUARANTEED_PERF(cap); 813 - else 814 - hw_max = HWP_HIGHEST_PERF(cap); 861 + rdmsrl_on_cpu(cpu, MSR_HWP_REQUEST, &value); 815 862 816 - max = fp_ext_toint(hw_max * perf_limits->max_perf); 817 - if (cpu_data->policy == CPUFREQ_POLICY_PERFORMANCE) 818 - min = max; 819 - else 820 - min = fp_ext_toint(hw_max * perf_limits->min_perf); 863 + value &= ~HWP_MIN_PERF(~0L); 864 + value |= HWP_MIN_PERF(min); 821 865 822 - rdmsrl_on_cpu(cpu, MSR_HWP_REQUEST, &value); 866 + value &= ~HWP_MAX_PERF(~0L); 867 + value |= HWP_MAX_PERF(max); 823 868 824 - value &= ~HWP_MIN_PERF(~0L); 825 - value |= HWP_MIN_PERF(min); 869 + if (cpu_data->epp_policy == cpu_data->policy) 870 + goto skip_epp; 826 871 827 - value &= ~HWP_MAX_PERF(~0L); 828 - value |= HWP_MAX_PERF(max); 872 + cpu_data->epp_policy = cpu_data->policy; 829 873 830 - if (cpu_data->epp_policy == cpu_data->policy) 874 + if (cpu_data->epp_saved >= 0) { 875 + epp = cpu_data->epp_saved; 876 + cpu_data->epp_saved = -EINVAL; 877 + goto update_epp; 878 + } 879 + 880 + if (cpu_data->policy == CPUFREQ_POLICY_PERFORMANCE) { 881 + epp = intel_pstate_get_epp(cpu_data, value); 882 + cpu_data->epp_powersave = epp; 883 + /* If EPP read was failed, then don't try to write */ 884 + if (epp < 0) 831 885 goto skip_epp; 832 886 833 - cpu_data->epp_policy = cpu_data->policy; 887 + epp = 0; 888 + } else { 889 + /* skip setting EPP, when saved value is invalid */ 890 + if (cpu_data->epp_powersave < 0) 891 + goto skip_epp; 834 892 835 - if (cpu_data->epp_saved >= 0) { 836 - epp = cpu_data->epp_saved; 837 - cpu_data->epp_saved = -EINVAL; 838 - goto update_epp; 839 - } 893 + /* 894 + * No need to restore EPP when it is not zero. This 895 + * means: 896 + * - Policy is not changed 897 + * - user has manually changed 898 + * - Error reading EPB 899 + */ 900 + epp = intel_pstate_get_epp(cpu_data, value); 901 + if (epp) 902 + goto skip_epp; 840 903 841 - if (cpu_data->policy == CPUFREQ_POLICY_PERFORMANCE) { 842 - epp = intel_pstate_get_epp(cpu_data, value); 843 - cpu_data->epp_powersave = epp; 844 - /* If EPP read was failed, then don't try to write */ 845 - if (epp < 0) 846 - goto skip_epp; 847 - 848 - 849 - epp = 0; 850 - } else { 851 - /* skip setting EPP, when saved value is invalid */ 852 - if (cpu_data->epp_powersave < 0) 853 - goto skip_epp; 854 - 855 - /* 856 - * No need to restore EPP when it is not zero. This 857 - * means: 858 - * - Policy is not changed 859 - * - user has manually changed 860 - * - Error reading EPB 861 - */ 862 - epp = intel_pstate_get_epp(cpu_data, value); 863 - if (epp) 864 - goto skip_epp; 865 - 866 - epp = cpu_data->epp_powersave; 867 - } 868 - update_epp: 869 - if (static_cpu_has(X86_FEATURE_HWP_EPP)) { 870 - value &= ~GENMASK_ULL(31, 24); 871 - value |= (u64)epp << 24; 872 - } else { 873 - intel_pstate_set_epb(cpu, epp); 874 - } 875 - skip_epp: 876 - wrmsrl_on_cpu(cpu, MSR_HWP_REQUEST, value); 904 + epp = cpu_data->epp_powersave; 877 905 } 878 - } 879 - 880 - static int intel_pstate_hwp_set_policy(struct cpufreq_policy *policy) 881 - { 882 - if (hwp_active) 883 - intel_pstate_hwp_set(policy); 884 - 885 - return 0; 906 + update_epp: 907 + if (static_cpu_has(X86_FEATURE_HWP_EPP)) { 908 + value &= ~GENMASK_ULL(31, 24); 909 + value |= (u64)epp << 24; 910 + } else { 911 + intel_pstate_set_epb(cpu, epp); 912 + } 913 + skip_epp: 914 + wrmsrl_on_cpu(cpu, MSR_HWP_REQUEST, value); 886 915 } 887 916 888 917 static int intel_pstate_hwp_save_state(struct cpufreq_policy *policy) ··· 883 944 884 945 static int intel_pstate_resume(struct cpufreq_policy *policy) 885 946 { 886 - int ret; 887 - 888 947 if (!hwp_active) 889 948 return 0; 890 949 891 950 mutex_lock(&intel_pstate_limits_lock); 892 951 893 952 all_cpu_data[policy->cpu]->epp_policy = 0; 894 - 895 - ret = intel_pstate_hwp_set_policy(policy); 953 + intel_pstate_hwp_set(policy->cpu); 896 954 897 955 mutex_unlock(&intel_pstate_limits_lock); 898 956 899 - return ret; 957 + return 0; 900 958 } 901 959 902 960 static void intel_pstate_update_policies(void) ··· 907 971 /************************** debugfs begin ************************/ 908 972 static int pid_param_set(void *data, u64 val) 909 973 { 974 + unsigned int cpu; 975 + 910 976 *(u32 *)data = val; 911 977 pid_params.sample_rate_ns = pid_params.sample_rate_ms * NSEC_PER_MSEC; 912 - intel_pstate_reset_all_pid(); 978 + for_each_possible_cpu(cpu) 979 + if (all_cpu_data[cpu]) 980 + intel_pstate_pid_reset(all_cpu_data[cpu]); 981 + 913 982 return 0; 914 983 } 915 984 ··· 1025 1084 1026 1085 mutex_lock(&intel_pstate_driver_lock); 1027 1086 1028 - if (!driver_registered) { 1087 + if (!intel_pstate_driver) { 1029 1088 mutex_unlock(&intel_pstate_driver_lock); 1030 1089 return -EAGAIN; 1031 1090 } ··· 1050 1109 1051 1110 mutex_lock(&intel_pstate_driver_lock); 1052 1111 1053 - if (!driver_registered) { 1112 + if (!intel_pstate_driver) { 1054 1113 mutex_unlock(&intel_pstate_driver_lock); 1055 1114 return -EAGAIN; 1056 1115 } ··· 1070 1129 1071 1130 mutex_lock(&intel_pstate_driver_lock); 1072 1131 1073 - if (!driver_registered) { 1132 + if (!intel_pstate_driver) { 1074 1133 mutex_unlock(&intel_pstate_driver_lock); 1075 1134 return -EAGAIN; 1076 1135 } ··· 1098 1157 1099 1158 mutex_lock(&intel_pstate_driver_lock); 1100 1159 1101 - if (!driver_registered) { 1160 + if (!intel_pstate_driver) { 1102 1161 mutex_unlock(&intel_pstate_driver_lock); 1103 1162 return -EAGAIN; 1104 1163 } ··· 1114 1173 } 1115 1174 1116 1175 global.no_turbo = clamp_t(int, input, 0, 1); 1176 + 1177 + if (global.no_turbo) { 1178 + struct cpudata *cpu = all_cpu_data[0]; 1179 + int pct = cpu->pstate.max_pstate * 100 / cpu->pstate.turbo_pstate; 1180 + 1181 + /* Squash the global minimum into the permitted range. */ 1182 + if (global.min_perf_pct > pct) 1183 + global.min_perf_pct = pct; 1184 + } 1117 1185 1118 1186 mutex_unlock(&intel_pstate_limits_lock); 1119 1187 ··· 1145 1195 1146 1196 mutex_lock(&intel_pstate_driver_lock); 1147 1197 1148 - if (!driver_registered) { 1198 + if (!intel_pstate_driver) { 1149 1199 mutex_unlock(&intel_pstate_driver_lock); 1150 1200 return -EAGAIN; 1151 1201 } 1152 1202 1153 1203 mutex_lock(&intel_pstate_limits_lock); 1154 1204 1155 - global.max_sysfs_pct = clamp_t(int, input, 0 , 100); 1156 - global.max_perf_pct = min(global.max_policy_pct, global.max_sysfs_pct); 1157 - global.max_perf_pct = max(global.min_policy_pct, global.max_perf_pct); 1158 - global.max_perf_pct = max(global.min_perf_pct, global.max_perf_pct); 1159 - global.max_perf = percent_ext_fp(global.max_perf_pct); 1205 + global.max_perf_pct = clamp_t(int, input, global.min_perf_pct, 100); 1160 1206 1161 1207 mutex_unlock(&intel_pstate_limits_lock); 1162 1208 ··· 1175 1229 1176 1230 mutex_lock(&intel_pstate_driver_lock); 1177 1231 1178 - if (!driver_registered) { 1232 + if (!intel_pstate_driver) { 1179 1233 mutex_unlock(&intel_pstate_driver_lock); 1180 1234 return -EAGAIN; 1181 1235 } 1182 1236 1183 1237 mutex_lock(&intel_pstate_limits_lock); 1184 1238 1185 - global.min_sysfs_pct = clamp_t(int, input, 0 , 100); 1186 - global.min_perf_pct = max(global.min_policy_pct, global.min_sysfs_pct); 1187 - global.min_perf_pct = min(global.max_policy_pct, global.min_perf_pct); 1188 - global.min_perf_pct = min(global.max_perf_pct, global.min_perf_pct); 1189 - global.min_perf = percent_ext_fp(global.min_perf_pct); 1239 + global.min_perf_pct = clamp_t(int, input, 1240 + min_perf_pct_min(), global.max_perf_pct); 1190 1241 1191 1242 mutex_unlock(&intel_pstate_limits_lock); 1192 1243 ··· 1497 1554 return ret; 1498 1555 } 1499 1556 1500 - static struct cpu_defaults core_params = { 1501 - .pid_policy = { 1502 - .sample_rate_ms = 10, 1503 - .deadband = 0, 1504 - .setpoint = 97, 1505 - .p_gain_pct = 20, 1506 - .d_gain_pct = 0, 1507 - .i_gain_pct = 0, 1508 - }, 1509 - .funcs = { 1510 - .get_max = core_get_max_pstate, 1511 - .get_max_physical = core_get_max_pstate_physical, 1512 - .get_min = core_get_min_pstate, 1513 - .get_turbo = core_get_turbo_pstate, 1514 - .get_scaling = core_get_scaling, 1515 - .get_val = core_get_val, 1516 - .get_target_pstate = get_target_pstate_use_performance, 1517 - }, 1518 - }; 1519 - 1520 - static const struct cpu_defaults silvermont_params = { 1521 - .pid_policy = { 1522 - .sample_rate_ms = 10, 1523 - .deadband = 0, 1524 - .setpoint = 60, 1525 - .p_gain_pct = 14, 1526 - .d_gain_pct = 0, 1527 - .i_gain_pct = 4, 1528 - }, 1529 - .funcs = { 1530 - .get_max = atom_get_max_pstate, 1531 - .get_max_physical = atom_get_max_pstate, 1532 - .get_min = atom_get_min_pstate, 1533 - .get_turbo = atom_get_turbo_pstate, 1534 - .get_val = atom_get_val, 1535 - .get_scaling = silvermont_get_scaling, 1536 - .get_vid = atom_get_vid, 1537 - .get_target_pstate = get_target_pstate_use_cpu_load, 1538 - }, 1539 - }; 1540 - 1541 - static const struct cpu_defaults airmont_params = { 1542 - .pid_policy = { 1543 - .sample_rate_ms = 10, 1544 - .deadband = 0, 1545 - .setpoint = 60, 1546 - .p_gain_pct = 14, 1547 - .d_gain_pct = 0, 1548 - .i_gain_pct = 4, 1549 - }, 1550 - .funcs = { 1551 - .get_max = atom_get_max_pstate, 1552 - .get_max_physical = atom_get_max_pstate, 1553 - .get_min = atom_get_min_pstate, 1554 - .get_turbo = atom_get_turbo_pstate, 1555 - .get_val = atom_get_val, 1556 - .get_scaling = airmont_get_scaling, 1557 - .get_vid = atom_get_vid, 1558 - .get_target_pstate = get_target_pstate_use_cpu_load, 1559 - }, 1560 - }; 1561 - 1562 - static const struct cpu_defaults knl_params = { 1563 - .pid_policy = { 1564 - .sample_rate_ms = 10, 1565 - .deadband = 0, 1566 - .setpoint = 97, 1567 - .p_gain_pct = 20, 1568 - .d_gain_pct = 0, 1569 - .i_gain_pct = 0, 1570 - }, 1571 - .funcs = { 1572 - .get_max = core_get_max_pstate, 1573 - .get_max_physical = core_get_max_pstate_physical, 1574 - .get_min = core_get_min_pstate, 1575 - .get_turbo = knl_get_turbo_pstate, 1576 - .get_scaling = core_get_scaling, 1577 - .get_val = core_get_val, 1578 - .get_target_pstate = get_target_pstate_use_performance, 1579 - }, 1580 - }; 1581 - 1582 - static const struct cpu_defaults bxt_params = { 1583 - .pid_policy = { 1584 - .sample_rate_ms = 10, 1585 - .deadband = 0, 1586 - .setpoint = 60, 1587 - .p_gain_pct = 14, 1588 - .d_gain_pct = 0, 1589 - .i_gain_pct = 4, 1590 - }, 1591 - .funcs = { 1592 - .get_max = core_get_max_pstate, 1593 - .get_max_physical = core_get_max_pstate_physical, 1594 - .get_min = core_get_min_pstate, 1595 - .get_turbo = core_get_turbo_pstate, 1596 - .get_scaling = core_get_scaling, 1597 - .get_val = core_get_val, 1598 - .get_target_pstate = get_target_pstate_use_cpu_load, 1599 - }, 1600 - }; 1601 - 1602 - static void intel_pstate_get_min_max(struct cpudata *cpu, int *min, int *max) 1557 + static int intel_pstate_get_base_pstate(struct cpudata *cpu) 1603 1558 { 1604 - int max_perf = cpu->pstate.turbo_pstate; 1605 - int max_perf_adj; 1606 - int min_perf; 1607 - struct perf_limits *perf_limits = &global; 1608 - 1609 - if (global.no_turbo || global.turbo_disabled) 1610 - max_perf = cpu->pstate.max_pstate; 1611 - 1612 - if (per_cpu_limits) 1613 - perf_limits = cpu->perf_limits; 1614 - 1615 - /* 1616 - * performance can be limited by user through sysfs, by cpufreq 1617 - * policy, or by cpu specific default values determined through 1618 - * experimentation. 1619 - */ 1620 - max_perf_adj = fp_ext_toint(max_perf * perf_limits->max_perf); 1621 - *max = clamp_t(int, max_perf_adj, 1622 - cpu->pstate.min_pstate, cpu->pstate.turbo_pstate); 1623 - 1624 - min_perf = fp_ext_toint(max_perf * perf_limits->min_perf); 1625 - *min = clamp_t(int, min_perf, cpu->pstate.min_pstate, max_perf); 1559 + return global.no_turbo || global.turbo_disabled ? 1560 + cpu->pstate.max_pstate : cpu->pstate.turbo_pstate; 1626 1561 } 1627 1562 1628 1563 static void intel_pstate_set_pstate(struct cpudata *cpu, int pstate) ··· 1523 1702 1524 1703 static void intel_pstate_max_within_limits(struct cpudata *cpu) 1525 1704 { 1526 - int min_pstate, max_pstate; 1705 + int pstate; 1527 1706 1528 1707 update_turbo_state(); 1529 - intel_pstate_get_min_max(cpu, &min_pstate, &max_pstate); 1530 - intel_pstate_set_pstate(cpu, max_pstate); 1708 + pstate = intel_pstate_get_base_pstate(cpu); 1709 + pstate = max(cpu->pstate.min_pstate, 1710 + fp_ext_toint(pstate * cpu->max_perf)); 1711 + intel_pstate_set_pstate(cpu, pstate); 1531 1712 } 1532 1713 1533 1714 static void intel_pstate_get_cpu_pstates(struct cpudata *cpu) ··· 1590 1767 * that sample.time will always be reset before setting the utilization 1591 1768 * update hook and make the caller skip the sample then. 1592 1769 */ 1593 - return !!cpu->last_sample_time; 1770 + if (cpu->last_sample_time) { 1771 + intel_pstate_calc_avg_perf(cpu); 1772 + return true; 1773 + } 1774 + return false; 1594 1775 } 1595 1776 1596 1777 static inline int32_t get_avg_frequency(struct cpudata *cpu) ··· 1614 1787 struct sample *sample = &cpu->sample; 1615 1788 int32_t busy_frac, boost; 1616 1789 int target, avg_pstate; 1790 + 1791 + if (cpu->policy == CPUFREQ_POLICY_PERFORMANCE) 1792 + return cpu->pstate.turbo_pstate; 1617 1793 1618 1794 busy_frac = div_fp(sample->mperf, sample->tsc); 1619 1795 ··· 1654 1824 int32_t perf_scaled, max_pstate, current_pstate, sample_ratio; 1655 1825 u64 duration_ns; 1656 1826 1827 + if (cpu->policy == CPUFREQ_POLICY_PERFORMANCE) 1828 + return cpu->pstate.turbo_pstate; 1829 + 1657 1830 /* 1658 1831 * perf_scaled is the ratio of the average P-state during the last 1659 1832 * sampling period to the P-state requested last time (in percent). ··· 1691 1858 1692 1859 static int intel_pstate_prepare_request(struct cpudata *cpu, int pstate) 1693 1860 { 1694 - int max_perf, min_perf; 1861 + int max_pstate = intel_pstate_get_base_pstate(cpu); 1862 + int min_pstate; 1695 1863 1696 - intel_pstate_get_min_max(cpu, &min_perf, &max_perf); 1697 - pstate = clamp_t(int, pstate, min_perf, max_perf); 1698 - return pstate; 1864 + min_pstate = max(cpu->pstate.min_pstate, 1865 + fp_ext_toint(max_pstate * cpu->min_perf)); 1866 + max_pstate = max(min_pstate, fp_ext_toint(max_pstate * cpu->max_perf)); 1867 + return clamp_t(int, pstate, min_pstate, max_pstate); 1699 1868 } 1700 1869 1701 1870 static void intel_pstate_update_pstate(struct cpudata *cpu, int pstate) ··· 1709 1874 wrmsrl(MSR_IA32_PERF_CTL, pstate_funcs.get_val(cpu, pstate)); 1710 1875 } 1711 1876 1712 - static inline void intel_pstate_adjust_busy_pstate(struct cpudata *cpu) 1877 + static void intel_pstate_adjust_pstate(struct cpudata *cpu, int target_pstate) 1713 1878 { 1714 - int from, target_pstate; 1879 + int from = cpu->pstate.current_pstate; 1715 1880 struct sample *sample; 1716 - 1717 - from = cpu->pstate.current_pstate; 1718 - 1719 - target_pstate = cpu->policy == CPUFREQ_POLICY_PERFORMANCE ? 1720 - cpu->pstate.turbo_pstate : pstate_funcs.get_target_pstate(cpu); 1721 1881 1722 1882 update_turbo_state(); 1723 1883 ··· 1732 1902 fp_toint(cpu->iowait_boost * 100)); 1733 1903 } 1734 1904 1905 + static void intel_pstate_update_util_hwp(struct update_util_data *data, 1906 + u64 time, unsigned int flags) 1907 + { 1908 + struct cpudata *cpu = container_of(data, struct cpudata, update_util); 1909 + u64 delta_ns = time - cpu->sample.time; 1910 + 1911 + if ((s64)delta_ns >= INTEL_PSTATE_HWP_SAMPLING_INTERVAL) 1912 + intel_pstate_sample(cpu, time); 1913 + } 1914 + 1915 + static void intel_pstate_update_util_pid(struct update_util_data *data, 1916 + u64 time, unsigned int flags) 1917 + { 1918 + struct cpudata *cpu = container_of(data, struct cpudata, update_util); 1919 + u64 delta_ns = time - cpu->sample.time; 1920 + 1921 + if ((s64)delta_ns < pid_params.sample_rate_ns) 1922 + return; 1923 + 1924 + if (intel_pstate_sample(cpu, time)) { 1925 + int target_pstate; 1926 + 1927 + target_pstate = get_target_pstate_use_performance(cpu); 1928 + intel_pstate_adjust_pstate(cpu, target_pstate); 1929 + } 1930 + } 1931 + 1735 1932 static void intel_pstate_update_util(struct update_util_data *data, u64 time, 1736 1933 unsigned int flags) 1737 1934 { 1738 1935 struct cpudata *cpu = container_of(data, struct cpudata, update_util); 1739 1936 u64 delta_ns; 1740 1937 1741 - if (pstate_funcs.get_target_pstate == get_target_pstate_use_cpu_load) { 1742 - if (flags & SCHED_CPUFREQ_IOWAIT) { 1743 - cpu->iowait_boost = int_tofp(1); 1744 - } else if (cpu->iowait_boost) { 1745 - /* Clear iowait_boost if the CPU may have been idle. */ 1746 - delta_ns = time - cpu->last_update; 1747 - if (delta_ns > TICK_NSEC) 1748 - cpu->iowait_boost = 0; 1749 - } 1750 - cpu->last_update = time; 1938 + if (flags & SCHED_CPUFREQ_IOWAIT) { 1939 + cpu->iowait_boost = int_tofp(1); 1940 + } else if (cpu->iowait_boost) { 1941 + /* Clear iowait_boost if the CPU may have been idle. */ 1942 + delta_ns = time - cpu->last_update; 1943 + if (delta_ns > TICK_NSEC) 1944 + cpu->iowait_boost = 0; 1751 1945 } 1752 - 1946 + cpu->last_update = time; 1753 1947 delta_ns = time - cpu->sample.time; 1754 - if ((s64)delta_ns >= pid_params.sample_rate_ns) { 1755 - bool sample_taken = intel_pstate_sample(cpu, time); 1948 + if ((s64)delta_ns < INTEL_PSTATE_DEFAULT_SAMPLING_INTERVAL) 1949 + return; 1756 1950 1757 - if (sample_taken) { 1758 - intel_pstate_calc_avg_perf(cpu); 1759 - if (!hwp_active) 1760 - intel_pstate_adjust_busy_pstate(cpu); 1761 - } 1951 + if (intel_pstate_sample(cpu, time)) { 1952 + int target_pstate; 1953 + 1954 + target_pstate = get_target_pstate_use_cpu_load(cpu); 1955 + intel_pstate_adjust_pstate(cpu, target_pstate); 1762 1956 } 1763 1957 } 1958 + 1959 + static struct pstate_funcs core_funcs = { 1960 + .get_max = core_get_max_pstate, 1961 + .get_max_physical = core_get_max_pstate_physical, 1962 + .get_min = core_get_min_pstate, 1963 + .get_turbo = core_get_turbo_pstate, 1964 + .get_scaling = core_get_scaling, 1965 + .get_val = core_get_val, 1966 + .update_util = intel_pstate_update_util_pid, 1967 + }; 1968 + 1969 + static const struct pstate_funcs silvermont_funcs = { 1970 + .get_max = atom_get_max_pstate, 1971 + .get_max_physical = atom_get_max_pstate, 1972 + .get_min = atom_get_min_pstate, 1973 + .get_turbo = atom_get_turbo_pstate, 1974 + .get_val = atom_get_val, 1975 + .get_scaling = silvermont_get_scaling, 1976 + .get_vid = atom_get_vid, 1977 + .update_util = intel_pstate_update_util, 1978 + }; 1979 + 1980 + static const struct pstate_funcs airmont_funcs = { 1981 + .get_max = atom_get_max_pstate, 1982 + .get_max_physical = atom_get_max_pstate, 1983 + .get_min = atom_get_min_pstate, 1984 + .get_turbo = atom_get_turbo_pstate, 1985 + .get_val = atom_get_val, 1986 + .get_scaling = airmont_get_scaling, 1987 + .get_vid = atom_get_vid, 1988 + .update_util = intel_pstate_update_util, 1989 + }; 1990 + 1991 + static const struct pstate_funcs knl_funcs = { 1992 + .get_max = core_get_max_pstate, 1993 + .get_max_physical = core_get_max_pstate_physical, 1994 + .get_min = core_get_min_pstate, 1995 + .get_turbo = knl_get_turbo_pstate, 1996 + .get_scaling = core_get_scaling, 1997 + .get_val = core_get_val, 1998 + .update_util = intel_pstate_update_util_pid, 1999 + }; 2000 + 2001 + static const struct pstate_funcs bxt_funcs = { 2002 + .get_max = core_get_max_pstate, 2003 + .get_max_physical = core_get_max_pstate_physical, 2004 + .get_min = core_get_min_pstate, 2005 + .get_turbo = core_get_turbo_pstate, 2006 + .get_scaling = core_get_scaling, 2007 + .get_val = core_get_val, 2008 + .update_util = intel_pstate_update_util, 2009 + }; 1764 2010 1765 2011 #define ICPU(model, policy) \ 1766 2012 { X86_VENDOR_INTEL, 6, model, X86_FEATURE_APERFMPERF,\ 1767 2013 (unsigned long)&policy } 1768 2014 1769 2015 static const struct x86_cpu_id intel_pstate_cpu_ids[] = { 1770 - ICPU(INTEL_FAM6_SANDYBRIDGE, core_params), 1771 - ICPU(INTEL_FAM6_SANDYBRIDGE_X, core_params), 1772 - ICPU(INTEL_FAM6_ATOM_SILVERMONT1, silvermont_params), 1773 - ICPU(INTEL_FAM6_IVYBRIDGE, core_params), 1774 - ICPU(INTEL_FAM6_HASWELL_CORE, core_params), 1775 - ICPU(INTEL_FAM6_BROADWELL_CORE, core_params), 1776 - ICPU(INTEL_FAM6_IVYBRIDGE_X, core_params), 1777 - ICPU(INTEL_FAM6_HASWELL_X, core_params), 1778 - ICPU(INTEL_FAM6_HASWELL_ULT, core_params), 1779 - ICPU(INTEL_FAM6_HASWELL_GT3E, core_params), 1780 - ICPU(INTEL_FAM6_BROADWELL_GT3E, core_params), 1781 - ICPU(INTEL_FAM6_ATOM_AIRMONT, airmont_params), 1782 - ICPU(INTEL_FAM6_SKYLAKE_MOBILE, core_params), 1783 - ICPU(INTEL_FAM6_BROADWELL_X, core_params), 1784 - ICPU(INTEL_FAM6_SKYLAKE_DESKTOP, core_params), 1785 - ICPU(INTEL_FAM6_BROADWELL_XEON_D, core_params), 1786 - ICPU(INTEL_FAM6_XEON_PHI_KNL, knl_params), 1787 - ICPU(INTEL_FAM6_XEON_PHI_KNM, knl_params), 1788 - ICPU(INTEL_FAM6_ATOM_GOLDMONT, bxt_params), 2016 + ICPU(INTEL_FAM6_SANDYBRIDGE, core_funcs), 2017 + ICPU(INTEL_FAM6_SANDYBRIDGE_X, core_funcs), 2018 + ICPU(INTEL_FAM6_ATOM_SILVERMONT1, silvermont_funcs), 2019 + ICPU(INTEL_FAM6_IVYBRIDGE, core_funcs), 2020 + ICPU(INTEL_FAM6_HASWELL_CORE, core_funcs), 2021 + ICPU(INTEL_FAM6_BROADWELL_CORE, core_funcs), 2022 + ICPU(INTEL_FAM6_IVYBRIDGE_X, core_funcs), 2023 + ICPU(INTEL_FAM6_HASWELL_X, core_funcs), 2024 + ICPU(INTEL_FAM6_HASWELL_ULT, core_funcs), 2025 + ICPU(INTEL_FAM6_HASWELL_GT3E, core_funcs), 2026 + ICPU(INTEL_FAM6_BROADWELL_GT3E, core_funcs), 2027 + ICPU(INTEL_FAM6_ATOM_AIRMONT, airmont_funcs), 2028 + ICPU(INTEL_FAM6_SKYLAKE_MOBILE, core_funcs), 2029 + ICPU(INTEL_FAM6_BROADWELL_X, core_funcs), 2030 + ICPU(INTEL_FAM6_SKYLAKE_DESKTOP, core_funcs), 2031 + ICPU(INTEL_FAM6_BROADWELL_XEON_D, core_funcs), 2032 + ICPU(INTEL_FAM6_XEON_PHI_KNL, knl_funcs), 2033 + ICPU(INTEL_FAM6_XEON_PHI_KNM, knl_funcs), 2034 + ICPU(INTEL_FAM6_ATOM_GOLDMONT, bxt_funcs), 2035 + ICPU(INTEL_FAM6_ATOM_GEMINI_LAKE, bxt_funcs), 1789 2036 {} 1790 2037 }; 1791 2038 MODULE_DEVICE_TABLE(x86cpu, intel_pstate_cpu_ids); 1792 2039 1793 2040 static const struct x86_cpu_id intel_pstate_cpu_oob_ids[] __initconst = { 1794 - ICPU(INTEL_FAM6_BROADWELL_XEON_D, core_params), 1795 - ICPU(INTEL_FAM6_BROADWELL_X, core_params), 1796 - ICPU(INTEL_FAM6_SKYLAKE_X, core_params), 2041 + ICPU(INTEL_FAM6_BROADWELL_XEON_D, core_funcs), 2042 + ICPU(INTEL_FAM6_BROADWELL_X, core_funcs), 2043 + ICPU(INTEL_FAM6_SKYLAKE_X, core_funcs), 1797 2044 {} 1798 2045 }; 1799 2046 1800 2047 static const struct x86_cpu_id intel_pstate_cpu_ee_disable_ids[] = { 1801 - ICPU(INTEL_FAM6_KABYLAKE_DESKTOP, core_params), 2048 + ICPU(INTEL_FAM6_KABYLAKE_DESKTOP, core_funcs), 1802 2049 {} 1803 2050 }; 2051 + 2052 + static bool pid_in_use(void); 1804 2053 1805 2054 static int intel_pstate_init_cpu(unsigned int cpunum) 1806 2055 { ··· 1888 1979 cpu = all_cpu_data[cpunum]; 1889 1980 1890 1981 if (!cpu) { 1891 - unsigned int size = sizeof(struct cpudata); 1892 - 1893 - if (per_cpu_limits) 1894 - size += sizeof(struct perf_limits); 1895 - 1896 - cpu = kzalloc(size, GFP_KERNEL); 1982 + cpu = kzalloc(sizeof(*cpu), GFP_KERNEL); 1897 1983 if (!cpu) 1898 1984 return -ENOMEM; 1899 1985 1900 1986 all_cpu_data[cpunum] = cpu; 1901 - if (per_cpu_limits) 1902 - cpu->perf_limits = (struct perf_limits *)(cpu + 1); 1903 1987 1904 1988 cpu->epp_default = -EINVAL; 1905 1989 cpu->epp_powersave = -EINVAL; ··· 1911 2009 intel_pstate_disable_ee(cpunum); 1912 2010 1913 2011 intel_pstate_hwp_enable(cpu); 1914 - pid_params.sample_rate_ms = 50; 1915 - pid_params.sample_rate_ns = 50 * NSEC_PER_MSEC; 2012 + } else if (pid_in_use()) { 2013 + intel_pstate_pid_reset(cpu); 1916 2014 } 1917 2015 1918 2016 intel_pstate_get_cpu_pstates(cpu); 1919 - 1920 - intel_pstate_busy_pid_reset(cpu); 1921 2017 1922 2018 pr_debug("controlling: cpu %d\n", cpunum); 1923 2019 ··· 1939 2039 /* Prevent intel_pstate_update_util() from using stale data. */ 1940 2040 cpu->sample.time = 0; 1941 2041 cpufreq_add_update_util_hook(cpu_num, &cpu->update_util, 1942 - intel_pstate_update_util); 2042 + pstate_funcs.update_util); 1943 2043 cpu->update_util_set = true; 1944 2044 } 1945 2045 ··· 1955 2055 synchronize_sched(); 1956 2056 } 1957 2057 1958 - static void intel_pstate_update_perf_limits(struct cpufreq_policy *policy, 1959 - struct perf_limits *limits) 2058 + static int intel_pstate_get_max_freq(struct cpudata *cpu) 1960 2059 { 2060 + return global.turbo_disabled || global.no_turbo ? 2061 + cpu->pstate.max_freq : cpu->pstate.turbo_freq; 2062 + } 2063 + 2064 + static void intel_pstate_update_perf_limits(struct cpufreq_policy *policy, 2065 + struct cpudata *cpu) 2066 + { 2067 + int max_freq = intel_pstate_get_max_freq(cpu); 1961 2068 int32_t max_policy_perf, min_policy_perf; 1962 2069 1963 - max_policy_perf = div_ext_fp(policy->max, policy->cpuinfo.max_freq); 2070 + max_policy_perf = div_ext_fp(policy->max, max_freq); 1964 2071 max_policy_perf = clamp_t(int32_t, max_policy_perf, 0, int_ext_tofp(1)); 1965 2072 if (policy->max == policy->min) { 1966 2073 min_policy_perf = max_policy_perf; 1967 2074 } else { 1968 - min_policy_perf = div_ext_fp(policy->min, 1969 - policy->cpuinfo.max_freq); 2075 + min_policy_perf = div_ext_fp(policy->min, max_freq); 1970 2076 min_policy_perf = clamp_t(int32_t, min_policy_perf, 1971 2077 0, max_policy_perf); 1972 2078 } 1973 2079 1974 2080 /* Normalize user input to [min_perf, max_perf] */ 1975 - limits->min_perf = max(min_policy_perf, 1976 - percent_ext_fp(limits->min_sysfs_pct)); 1977 - limits->min_perf = min(limits->min_perf, max_policy_perf); 1978 - limits->max_perf = min(max_policy_perf, 1979 - percent_ext_fp(limits->max_sysfs_pct)); 1980 - limits->max_perf = max(min_policy_perf, limits->max_perf); 2081 + if (per_cpu_limits) { 2082 + cpu->min_perf = min_policy_perf; 2083 + cpu->max_perf = max_policy_perf; 2084 + } else { 2085 + int32_t global_min, global_max; 1981 2086 1982 - /* Make sure min_perf <= max_perf */ 1983 - limits->min_perf = min(limits->min_perf, limits->max_perf); 2087 + /* Global limits are in percent of the maximum turbo P-state. */ 2088 + global_max = percent_ext_fp(global.max_perf_pct); 2089 + global_min = percent_ext_fp(global.min_perf_pct); 2090 + if (max_freq != cpu->pstate.turbo_freq) { 2091 + int32_t turbo_factor; 1984 2092 1985 - limits->max_perf = round_up(limits->max_perf, EXT_FRAC_BITS); 1986 - limits->min_perf = round_up(limits->min_perf, EXT_FRAC_BITS); 1987 - limits->max_perf_pct = fp_ext_toint(limits->max_perf * 100); 1988 - limits->min_perf_pct = fp_ext_toint(limits->min_perf * 100); 2093 + turbo_factor = div_ext_fp(cpu->pstate.turbo_pstate, 2094 + cpu->pstate.max_pstate); 2095 + global_min = mul_ext_fp(global_min, turbo_factor); 2096 + global_max = mul_ext_fp(global_max, turbo_factor); 2097 + } 2098 + global_min = clamp_t(int32_t, global_min, 0, global_max); 2099 + 2100 + cpu->min_perf = max(min_policy_perf, global_min); 2101 + cpu->min_perf = min(cpu->min_perf, max_policy_perf); 2102 + cpu->max_perf = min(max_policy_perf, global_max); 2103 + cpu->max_perf = max(min_policy_perf, cpu->max_perf); 2104 + 2105 + /* Make sure min_perf <= max_perf */ 2106 + cpu->min_perf = min(cpu->min_perf, cpu->max_perf); 2107 + } 2108 + 2109 + cpu->max_perf = round_up(cpu->max_perf, EXT_FRAC_BITS); 2110 + cpu->min_perf = round_up(cpu->min_perf, EXT_FRAC_BITS); 1989 2111 1990 2112 pr_debug("cpu:%d max_perf_pct:%d min_perf_pct:%d\n", policy->cpu, 1991 - limits->max_perf_pct, limits->min_perf_pct); 2113 + fp_ext_toint(cpu->max_perf * 100), 2114 + fp_ext_toint(cpu->min_perf * 100)); 1992 2115 } 1993 2116 1994 2117 static int intel_pstate_set_policy(struct cpufreq_policy *policy) 1995 2118 { 1996 2119 struct cpudata *cpu; 1997 - struct perf_limits *perf_limits = &global; 1998 2120 1999 2121 if (!policy->cpuinfo.max_freq) 2000 2122 return -ENODEV; ··· 2027 2105 cpu = all_cpu_data[policy->cpu]; 2028 2106 cpu->policy = policy->policy; 2029 2107 2030 - if (cpu->pstate.max_pstate_physical > cpu->pstate.max_pstate && 2031 - policy->max < policy->cpuinfo.max_freq && 2032 - policy->max > cpu->pstate.max_pstate * cpu->pstate.scaling) { 2033 - pr_debug("policy->max > max non turbo frequency\n"); 2034 - policy->max = policy->cpuinfo.max_freq; 2035 - } 2036 - 2037 - if (per_cpu_limits) 2038 - perf_limits = cpu->perf_limits; 2039 - 2040 2108 mutex_lock(&intel_pstate_limits_lock); 2041 2109 2042 - intel_pstate_update_perf_limits(policy, perf_limits); 2110 + intel_pstate_update_perf_limits(policy, cpu); 2043 2111 2044 2112 if (cpu->policy == CPUFREQ_POLICY_PERFORMANCE) { 2045 2113 /* ··· 2042 2130 2043 2131 intel_pstate_set_update_util_hook(policy->cpu); 2044 2132 2045 - intel_pstate_hwp_set_policy(policy); 2133 + if (hwp_active) 2134 + intel_pstate_hwp_set(policy->cpu); 2046 2135 2047 2136 mutex_unlock(&intel_pstate_limits_lock); 2048 2137 2049 2138 return 0; 2139 + } 2140 + 2141 + static void intel_pstate_adjust_policy_max(struct cpufreq_policy *policy, 2142 + struct cpudata *cpu) 2143 + { 2144 + if (cpu->pstate.max_pstate_physical > cpu->pstate.max_pstate && 2145 + policy->max < policy->cpuinfo.max_freq && 2146 + policy->max > cpu->pstate.max_freq) { 2147 + pr_debug("policy->max > max non turbo frequency\n"); 2148 + policy->max = policy->cpuinfo.max_freq; 2149 + } 2050 2150 } 2051 2151 2052 2152 static int intel_pstate_verify_policy(struct cpufreq_policy *policy) ··· 2066 2142 struct cpudata *cpu = all_cpu_data[policy->cpu]; 2067 2143 2068 2144 update_turbo_state(); 2069 - policy->cpuinfo.max_freq = global.turbo_disabled || global.no_turbo ? 2070 - cpu->pstate.max_freq : 2071 - cpu->pstate.turbo_freq; 2072 - 2073 - cpufreq_verify_within_cpu_limits(policy); 2145 + cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq, 2146 + intel_pstate_get_max_freq(cpu)); 2074 2147 2075 2148 if (policy->policy != CPUFREQ_POLICY_POWERSAVE && 2076 2149 policy->policy != CPUFREQ_POLICY_PERFORMANCE) 2077 2150 return -EINVAL; 2078 2151 2079 - /* When per-CPU limits are used, sysfs limits are not used */ 2080 - if (!per_cpu_limits) { 2081 - unsigned int max_freq, min_freq; 2082 - 2083 - max_freq = policy->cpuinfo.max_freq * 2084 - global.max_sysfs_pct / 100; 2085 - min_freq = policy->cpuinfo.max_freq * 2086 - global.min_sysfs_pct / 100; 2087 - cpufreq_verify_within_limits(policy, min_freq, max_freq); 2088 - } 2152 + intel_pstate_adjust_policy_max(policy, cpu); 2089 2153 2090 2154 return 0; 2091 2155 } ··· 2114 2202 2115 2203 cpu = all_cpu_data[policy->cpu]; 2116 2204 2117 - if (per_cpu_limits) 2118 - intel_pstate_init_limits(cpu->perf_limits); 2205 + cpu->max_perf = int_ext_tofp(1); 2206 + cpu->min_perf = 0; 2119 2207 2120 2208 policy->min = cpu->pstate.min_pstate * cpu->pstate.scaling; 2121 2209 policy->max = cpu->pstate.turbo_pstate * cpu->pstate.scaling; ··· 2169 2257 struct cpudata *cpu = all_cpu_data[policy->cpu]; 2170 2258 2171 2259 update_turbo_state(); 2172 - policy->cpuinfo.max_freq = global.no_turbo || global.turbo_disabled ? 2173 - cpu->pstate.max_freq : cpu->pstate.turbo_freq; 2260 + cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq, 2261 + intel_pstate_get_max_freq(cpu)); 2174 2262 2175 - cpufreq_verify_within_cpu_limits(policy); 2263 + intel_pstate_adjust_policy_max(policy, cpu); 2264 + 2265 + intel_pstate_update_perf_limits(policy, cpu); 2176 2266 2177 2267 return 0; 2178 2268 } ··· 2238 2324 return ret; 2239 2325 2240 2326 policy->cpuinfo.transition_latency = INTEL_CPUFREQ_TRANSITION_LATENCY; 2327 + policy->transition_delay_us = INTEL_CPUFREQ_TRANSITION_DELAY; 2241 2328 /* This reflects the intel_pstate_get_cpu_pstates() setting. */ 2242 2329 policy->cur = policy->cpuinfo.min_freq; 2243 2330 ··· 2256 2341 .name = "intel_cpufreq", 2257 2342 }; 2258 2343 2259 - static struct cpufreq_driver *intel_pstate_driver = &intel_pstate; 2344 + static struct cpufreq_driver *default_driver = &intel_pstate; 2345 + 2346 + static bool pid_in_use(void) 2347 + { 2348 + return intel_pstate_driver == &intel_pstate && 2349 + pstate_funcs.update_util == intel_pstate_update_util_pid; 2350 + } 2260 2351 2261 2352 static void intel_pstate_driver_cleanup(void) 2262 2353 { ··· 2279 2358 } 2280 2359 } 2281 2360 put_online_cpus(); 2361 + intel_pstate_driver = NULL; 2282 2362 } 2283 2363 2284 - static int intel_pstate_register_driver(void) 2364 + static int intel_pstate_register_driver(struct cpufreq_driver *driver) 2285 2365 { 2286 2366 int ret; 2287 2367 2288 - intel_pstate_init_limits(&global); 2368 + memset(&global, 0, sizeof(global)); 2369 + global.max_perf_pct = 100; 2289 2370 2371 + intel_pstate_driver = driver; 2290 2372 ret = cpufreq_register_driver(intel_pstate_driver); 2291 2373 if (ret) { 2292 2374 intel_pstate_driver_cleanup(); 2293 2375 return ret; 2294 2376 } 2295 2377 2296 - mutex_lock(&intel_pstate_limits_lock); 2297 - driver_registered = true; 2298 - mutex_unlock(&intel_pstate_limits_lock); 2378 + global.min_perf_pct = min_perf_pct_min(); 2299 2379 2300 - if (intel_pstate_driver == &intel_pstate && !hwp_active && 2301 - pstate_funcs.get_target_pstate != get_target_pstate_use_cpu_load) 2380 + if (pid_in_use()) 2302 2381 intel_pstate_debug_expose_params(); 2303 2382 2304 2383 return 0; ··· 2309 2388 if (hwp_active) 2310 2389 return -EBUSY; 2311 2390 2312 - if (intel_pstate_driver == &intel_pstate && !hwp_active && 2313 - pstate_funcs.get_target_pstate != get_target_pstate_use_cpu_load) 2391 + if (pid_in_use()) 2314 2392 intel_pstate_debug_hide_params(); 2315 - 2316 - mutex_lock(&intel_pstate_limits_lock); 2317 - driver_registered = false; 2318 - mutex_unlock(&intel_pstate_limits_lock); 2319 2393 2320 2394 cpufreq_unregister_driver(intel_pstate_driver); 2321 2395 intel_pstate_driver_cleanup(); ··· 2320 2404 2321 2405 static ssize_t intel_pstate_show_status(char *buf) 2322 2406 { 2323 - if (!driver_registered) 2407 + if (!intel_pstate_driver) 2324 2408 return sprintf(buf, "off\n"); 2325 2409 2326 2410 return sprintf(buf, "%s\n", intel_pstate_driver == &intel_pstate ? ··· 2332 2416 int ret; 2333 2417 2334 2418 if (size == 3 && !strncmp(buf, "off", size)) 2335 - return driver_registered ? 2419 + return intel_pstate_driver ? 2336 2420 intel_pstate_unregister_driver() : -EINVAL; 2337 2421 2338 2422 if (size == 6 && !strncmp(buf, "active", size)) { 2339 - if (driver_registered) { 2423 + if (intel_pstate_driver) { 2340 2424 if (intel_pstate_driver == &intel_pstate) 2341 2425 return 0; 2342 2426 ··· 2345 2429 return ret; 2346 2430 } 2347 2431 2348 - intel_pstate_driver = &intel_pstate; 2349 - return intel_pstate_register_driver(); 2432 + return intel_pstate_register_driver(&intel_pstate); 2350 2433 } 2351 2434 2352 2435 if (size == 7 && !strncmp(buf, "passive", size)) { 2353 - if (driver_registered) { 2354 - if (intel_pstate_driver != &intel_pstate) 2436 + if (intel_pstate_driver) { 2437 + if (intel_pstate_driver == &intel_cpufreq) 2355 2438 return 0; 2356 2439 2357 2440 ret = intel_pstate_unregister_driver(); ··· 2358 2443 return ret; 2359 2444 } 2360 2445 2361 - intel_pstate_driver = &intel_cpufreq; 2362 - return intel_pstate_register_driver(); 2446 + return intel_pstate_register_driver(&intel_cpufreq); 2363 2447 } 2364 2448 2365 2449 return -EINVAL; ··· 2379 2465 return 0; 2380 2466 } 2381 2467 2382 - static void __init copy_pid_params(struct pstate_adjust_policy *policy) 2383 - { 2384 - pid_params.sample_rate_ms = policy->sample_rate_ms; 2385 - pid_params.sample_rate_ns = pid_params.sample_rate_ms * NSEC_PER_MSEC; 2386 - pid_params.p_gain_pct = policy->p_gain_pct; 2387 - pid_params.i_gain_pct = policy->i_gain_pct; 2388 - pid_params.d_gain_pct = policy->d_gain_pct; 2389 - pid_params.deadband = policy->deadband; 2390 - pid_params.setpoint = policy->setpoint; 2391 - } 2392 - 2393 2468 #ifdef CONFIG_ACPI 2394 2469 static void intel_pstate_use_acpi_profile(void) 2395 2470 { 2396 - if (acpi_gbl_FADT.preferred_profile == PM_MOBILE) 2397 - pstate_funcs.get_target_pstate = 2398 - get_target_pstate_use_cpu_load; 2471 + switch (acpi_gbl_FADT.preferred_profile) { 2472 + case PM_MOBILE: 2473 + case PM_TABLET: 2474 + case PM_APPLIANCE_PC: 2475 + case PM_DESKTOP: 2476 + case PM_WORKSTATION: 2477 + pstate_funcs.update_util = intel_pstate_update_util; 2478 + } 2399 2479 } 2400 2480 #else 2401 2481 static void intel_pstate_use_acpi_profile(void) ··· 2406 2498 pstate_funcs.get_scaling = funcs->get_scaling; 2407 2499 pstate_funcs.get_val = funcs->get_val; 2408 2500 pstate_funcs.get_vid = funcs->get_vid; 2409 - pstate_funcs.get_target_pstate = funcs->get_target_pstate; 2501 + pstate_funcs.update_util = funcs->update_util; 2410 2502 2411 2503 intel_pstate_use_acpi_profile(); 2412 2504 } ··· 2545 2637 2546 2638 static int __init intel_pstate_init(void) 2547 2639 { 2548 - const struct x86_cpu_id *id; 2549 - struct cpu_defaults *cpu_def; 2550 - int rc = 0; 2640 + int rc; 2551 2641 2552 2642 if (no_load) 2553 2643 return -ENODEV; 2554 2644 2555 - if (x86_match_cpu(hwp_support_ids) && !no_hwp) { 2556 - copy_cpu_funcs(&core_params.funcs); 2557 - hwp_active++; 2558 - intel_pstate.attr = hwp_cpufreq_attrs; 2559 - goto hwp_cpu_matched; 2645 + if (x86_match_cpu(hwp_support_ids)) { 2646 + copy_cpu_funcs(&core_funcs); 2647 + if (no_hwp) { 2648 + pstate_funcs.update_util = intel_pstate_update_util; 2649 + } else { 2650 + hwp_active++; 2651 + intel_pstate.attr = hwp_cpufreq_attrs; 2652 + pstate_funcs.update_util = intel_pstate_update_util_hwp; 2653 + goto hwp_cpu_matched; 2654 + } 2655 + } else { 2656 + const struct x86_cpu_id *id; 2657 + 2658 + id = x86_match_cpu(intel_pstate_cpu_ids); 2659 + if (!id) 2660 + return -ENODEV; 2661 + 2662 + copy_cpu_funcs((struct pstate_funcs *)id->driver_data); 2560 2663 } 2561 - 2562 - id = x86_match_cpu(intel_pstate_cpu_ids); 2563 - if (!id) 2564 - return -ENODEV; 2565 - 2566 - cpu_def = (struct cpu_defaults *)id->driver_data; 2567 - 2568 - copy_pid_params(&cpu_def->pid_policy); 2569 - copy_cpu_funcs(&cpu_def->funcs); 2570 2664 2571 2665 if (intel_pstate_msrs_not_valid()) 2572 2666 return -ENODEV; ··· 2595 2685 intel_pstate_sysfs_expose_params(); 2596 2686 2597 2687 mutex_lock(&intel_pstate_driver_lock); 2598 - rc = intel_pstate_register_driver(); 2688 + rc = intel_pstate_register_driver(default_driver); 2599 2689 mutex_unlock(&intel_pstate_driver_lock); 2600 2690 if (rc) 2601 2691 return rc; ··· 2616 2706 no_load = 1; 2617 2707 } else if (!strcmp(str, "passive")) { 2618 2708 pr_info("Passive mode enabled\n"); 2619 - intel_pstate_driver = &intel_cpufreq; 2709 + default_driver = &intel_cpufreq; 2620 2710 no_hwp = 1; 2621 2711 } 2622 2712 if (!strcmp(str, "no_hwp")) {
+21 -2
drivers/cpufreq/mt8173-cpufreq.c
··· 573 573 .probe = mt8173_cpufreq_probe, 574 574 }; 575 575 576 - static int mt8173_cpufreq_driver_init(void) 576 + /* List of machines supported by this driver */ 577 + static const struct of_device_id mt8173_cpufreq_machines[] __initconst = { 578 + { .compatible = "mediatek,mt817x", }, 579 + { .compatible = "mediatek,mt8173", }, 580 + { .compatible = "mediatek,mt8176", }, 581 + 582 + { } 583 + }; 584 + 585 + static int __init mt8173_cpufreq_driver_init(void) 577 586 { 587 + struct device_node *np; 588 + const struct of_device_id *match; 578 589 struct platform_device *pdev; 579 590 int err; 580 591 581 - if (!of_machine_is_compatible("mediatek,mt8173")) 592 + np = of_find_node_by_path("/"); 593 + if (!np) 582 594 return -ENODEV; 595 + 596 + match = of_match_node(mt8173_cpufreq_machines, np); 597 + of_node_put(np); 598 + if (!match) { 599 + pr_warn("Machine is not compatible with mt8173-cpufreq\n"); 600 + return -ENODEV; 601 + } 583 602 584 603 err = platform_driver_register(&mt8173_cpufreq_platdrv); 585 604 if (err)
+17 -7
drivers/cpufreq/qoriq-cpufreq.c
··· 52 52 { 53 53 struct device_node *soc; 54 54 u32 sysfreq; 55 + struct clk *pltclk; 56 + int ret; 55 57 58 + /* get platform freq by searching bus-frequency property */ 56 59 soc = of_find_node_by_type(NULL, "soc"); 57 - if (!soc) 58 - return 0; 60 + if (soc) { 61 + ret = of_property_read_u32(soc, "bus-frequency", &sysfreq); 62 + of_node_put(soc); 63 + if (!ret) 64 + return sysfreq; 65 + } 59 66 60 - if (of_property_read_u32(soc, "bus-frequency", &sysfreq)) 61 - sysfreq = 0; 67 + /* get platform freq by its clock name */ 68 + pltclk = clk_get(NULL, "cg-pll0-div1"); 69 + if (IS_ERR(pltclk)) { 70 + pr_err("%s: can't get bus frequency %ld\n", 71 + __func__, PTR_ERR(pltclk)); 72 + return PTR_ERR(pltclk); 73 + } 62 74 63 - of_node_put(soc); 64 - 65 - return sysfreq; 75 + return clk_get_rate(pltclk); 66 76 } 67 77 68 78 static struct clk *cpu_to_clk(int cpu)
+275
drivers/cpufreq/tegra186-cpufreq.c
··· 1 + /* 2 + * Copyright (c) 2017, NVIDIA CORPORATION. All rights reserved 3 + * 4 + * This program is free software; you can redistribute it and/or modify it 5 + * under the terms and conditions of the GNU General Public License, 6 + * version 2, as published by the Free Software Foundation. 7 + * 8 + * This program is distributed in the hope it will be useful, but WITHOUT 9 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 11 + * more details. 12 + */ 13 + 14 + #include <linux/cpufreq.h> 15 + #include <linux/dma-mapping.h> 16 + #include <linux/module.h> 17 + #include <linux/of.h> 18 + #include <linux/platform_device.h> 19 + 20 + #include <soc/tegra/bpmp.h> 21 + #include <soc/tegra/bpmp-abi.h> 22 + 23 + #define EDVD_CORE_VOLT_FREQ(core) (0x20 + (core) * 0x4) 24 + #define EDVD_CORE_VOLT_FREQ_F_SHIFT 0 25 + #define EDVD_CORE_VOLT_FREQ_V_SHIFT 16 26 + 27 + struct tegra186_cpufreq_cluster_info { 28 + unsigned long offset; 29 + int cpus[4]; 30 + unsigned int bpmp_cluster_id; 31 + }; 32 + 33 + #define NO_CPU -1 34 + static const struct tegra186_cpufreq_cluster_info tegra186_clusters[] = { 35 + /* Denver cluster */ 36 + { 37 + .offset = SZ_64K * 7, 38 + .cpus = { 1, 2, NO_CPU, NO_CPU }, 39 + .bpmp_cluster_id = 0, 40 + }, 41 + /* A57 cluster */ 42 + { 43 + .offset = SZ_64K * 6, 44 + .cpus = { 0, 3, 4, 5 }, 45 + .bpmp_cluster_id = 1, 46 + }, 47 + }; 48 + 49 + struct tegra186_cpufreq_cluster { 50 + const struct tegra186_cpufreq_cluster_info *info; 51 + struct cpufreq_frequency_table *table; 52 + }; 53 + 54 + struct tegra186_cpufreq_data { 55 + void __iomem *regs; 56 + 57 + size_t num_clusters; 58 + struct tegra186_cpufreq_cluster *clusters; 59 + }; 60 + 61 + static int tegra186_cpufreq_init(struct cpufreq_policy *policy) 62 + { 63 + struct tegra186_cpufreq_data *data = cpufreq_get_driver_data(); 64 + unsigned int i; 65 + 66 + for (i = 0; i < data->num_clusters; i++) { 67 + struct tegra186_cpufreq_cluster *cluster = &data->clusters[i]; 68 + const struct tegra186_cpufreq_cluster_info *info = 69 + cluster->info; 70 + int core; 71 + 72 + for (core = 0; core < ARRAY_SIZE(info->cpus); core++) { 73 + if (info->cpus[core] == policy->cpu) 74 + break; 75 + } 76 + if (core == ARRAY_SIZE(info->cpus)) 77 + continue; 78 + 79 + policy->driver_data = 80 + data->regs + info->offset + EDVD_CORE_VOLT_FREQ(core); 81 + cpufreq_table_validate_and_show(policy, cluster->table); 82 + } 83 + 84 + policy->cpuinfo.transition_latency = 300 * 1000; 85 + 86 + return 0; 87 + } 88 + 89 + static int tegra186_cpufreq_set_target(struct cpufreq_policy *policy, 90 + unsigned int index) 91 + { 92 + struct cpufreq_frequency_table *tbl = policy->freq_table + index; 93 + void __iomem *edvd_reg = policy->driver_data; 94 + u32 edvd_val = tbl->driver_data; 95 + 96 + writel(edvd_val, edvd_reg); 97 + 98 + return 0; 99 + } 100 + 101 + static struct cpufreq_driver tegra186_cpufreq_driver = { 102 + .name = "tegra186", 103 + .flags = CPUFREQ_STICKY | CPUFREQ_HAVE_GOVERNOR_PER_POLICY, 104 + .verify = cpufreq_generic_frequency_table_verify, 105 + .target_index = tegra186_cpufreq_set_target, 106 + .init = tegra186_cpufreq_init, 107 + .attr = cpufreq_generic_attr, 108 + }; 109 + 110 + static struct cpufreq_frequency_table *init_vhint_table( 111 + struct platform_device *pdev, struct tegra_bpmp *bpmp, 112 + unsigned int cluster_id) 113 + { 114 + struct cpufreq_frequency_table *table; 115 + struct mrq_cpu_vhint_request req; 116 + struct tegra_bpmp_message msg; 117 + struct cpu_vhint_data *data; 118 + int err, i, j, num_rates = 0; 119 + dma_addr_t phys; 120 + void *virt; 121 + 122 + virt = dma_alloc_coherent(bpmp->dev, sizeof(*data), &phys, 123 + GFP_KERNEL | GFP_DMA32); 124 + if (!virt) 125 + return ERR_PTR(-ENOMEM); 126 + 127 + data = (struct cpu_vhint_data *)virt; 128 + 129 + memset(&req, 0, sizeof(req)); 130 + req.addr = phys; 131 + req.cluster_id = cluster_id; 132 + 133 + memset(&msg, 0, sizeof(msg)); 134 + msg.mrq = MRQ_CPU_VHINT; 135 + msg.tx.data = &req; 136 + msg.tx.size = sizeof(req); 137 + 138 + err = tegra_bpmp_transfer(bpmp, &msg); 139 + if (err) { 140 + table = ERR_PTR(err); 141 + goto free; 142 + } 143 + 144 + for (i = data->vfloor; i <= data->vceil; i++) { 145 + u16 ndiv = data->ndiv[i]; 146 + 147 + if (ndiv < data->ndiv_min || ndiv > data->ndiv_max) 148 + continue; 149 + 150 + /* Only store lowest voltage index for each rate */ 151 + if (i > 0 && ndiv == data->ndiv[i - 1]) 152 + continue; 153 + 154 + num_rates++; 155 + } 156 + 157 + table = devm_kcalloc(&pdev->dev, num_rates + 1, sizeof(*table), 158 + GFP_KERNEL); 159 + if (!table) { 160 + table = ERR_PTR(-ENOMEM); 161 + goto free; 162 + } 163 + 164 + for (i = data->vfloor, j = 0; i <= data->vceil; i++) { 165 + struct cpufreq_frequency_table *point; 166 + u16 ndiv = data->ndiv[i]; 167 + u32 edvd_val = 0; 168 + 169 + if (ndiv < data->ndiv_min || ndiv > data->ndiv_max) 170 + continue; 171 + 172 + /* Only store lowest voltage index for each rate */ 173 + if (i > 0 && ndiv == data->ndiv[i - 1]) 174 + continue; 175 + 176 + edvd_val |= i << EDVD_CORE_VOLT_FREQ_V_SHIFT; 177 + edvd_val |= ndiv << EDVD_CORE_VOLT_FREQ_F_SHIFT; 178 + 179 + point = &table[j++]; 180 + point->driver_data = edvd_val; 181 + point->frequency = data->ref_clk_hz * ndiv / data->pdiv / 182 + data->mdiv / 1000; 183 + } 184 + 185 + table[j].frequency = CPUFREQ_TABLE_END; 186 + 187 + free: 188 + dma_free_coherent(bpmp->dev, sizeof(*data), virt, phys); 189 + 190 + return table; 191 + } 192 + 193 + static int tegra186_cpufreq_probe(struct platform_device *pdev) 194 + { 195 + struct tegra186_cpufreq_data *data; 196 + struct tegra_bpmp *bpmp; 197 + struct resource *res; 198 + unsigned int i = 0, err; 199 + 200 + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); 201 + if (!data) 202 + return -ENOMEM; 203 + 204 + data->clusters = devm_kcalloc(&pdev->dev, ARRAY_SIZE(tegra186_clusters), 205 + sizeof(*data->clusters), GFP_KERNEL); 206 + if (!data->clusters) 207 + return -ENOMEM; 208 + 209 + data->num_clusters = ARRAY_SIZE(tegra186_clusters); 210 + 211 + bpmp = tegra_bpmp_get(&pdev->dev); 212 + if (IS_ERR(bpmp)) 213 + return PTR_ERR(bpmp); 214 + 215 + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 216 + data->regs = devm_ioremap_resource(&pdev->dev, res); 217 + if (IS_ERR(data->regs)) { 218 + err = PTR_ERR(data->regs); 219 + goto put_bpmp; 220 + } 221 + 222 + for (i = 0; i < data->num_clusters; i++) { 223 + struct tegra186_cpufreq_cluster *cluster = &data->clusters[i]; 224 + 225 + cluster->info = &tegra186_clusters[i]; 226 + cluster->table = init_vhint_table( 227 + pdev, bpmp, cluster->info->bpmp_cluster_id); 228 + if (IS_ERR(cluster->table)) { 229 + err = PTR_ERR(cluster->table); 230 + goto put_bpmp; 231 + } 232 + } 233 + 234 + tegra_bpmp_put(bpmp); 235 + 236 + tegra186_cpufreq_driver.driver_data = data; 237 + 238 + err = cpufreq_register_driver(&tegra186_cpufreq_driver); 239 + if (err) 240 + return err; 241 + 242 + return 0; 243 + 244 + put_bpmp: 245 + tegra_bpmp_put(bpmp); 246 + 247 + return err; 248 + } 249 + 250 + static int tegra186_cpufreq_remove(struct platform_device *pdev) 251 + { 252 + cpufreq_unregister_driver(&tegra186_cpufreq_driver); 253 + 254 + return 0; 255 + } 256 + 257 + static const struct of_device_id tegra186_cpufreq_of_match[] = { 258 + { .compatible = "nvidia,tegra186-ccplex-cluster", }, 259 + { } 260 + }; 261 + MODULE_DEVICE_TABLE(of, tegra186_cpufreq_of_match); 262 + 263 + static struct platform_driver tegra186_cpufreq_platform_driver = { 264 + .driver = { 265 + .name = "tegra186-cpufreq", 266 + .of_match_table = tegra186_cpufreq_of_match, 267 + }, 268 + .probe = tegra186_cpufreq_probe, 269 + .remove = tegra186_cpufreq_remove, 270 + }; 271 + module_platform_driver(tegra186_cpufreq_platform_driver); 272 + 273 + MODULE_AUTHOR("Mikko Perttunen <mperttunen@nvidia.com>"); 274 + MODULE_DESCRIPTION("NVIDIA Tegra186 cpufreq driver"); 275 + MODULE_LICENSE("GPL v2");
+1 -2
drivers/cpuidle/cpuidle-cps.c
··· 118 118 119 119 static int __init cps_cpuidle_init(void) 120 120 { 121 - int err, cpu, core, i; 121 + int err, cpu, i; 122 122 struct cpuidle_device *device; 123 123 124 124 /* Detect supported states */ ··· 160 160 } 161 161 162 162 for_each_possible_cpu(cpu) { 163 - core = cpu_data[cpu].core; 164 163 device = &per_cpu(cpuidle_dev, cpu); 165 164 device->cpu = cpu; 166 165 #ifdef CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED
+63 -6
drivers/cpuidle/cpuidle-powernv.c
··· 56 56 57 57 snooze_exit_time = get_tb() + snooze_timeout; 58 58 ppc64_runlatch_off(); 59 + HMT_very_low(); 59 60 while (!need_resched()) { 60 - HMT_low(); 61 - HMT_very_low(); 62 - if (snooze_timeout_en && get_tb() > snooze_exit_time) 61 + if (likely(snooze_timeout_en) && get_tb() > snooze_exit_time) 63 62 break; 64 63 } 65 64 ··· 214 215 stop_psscr_table[index].mask = psscr_mask; 215 216 } 216 217 218 + /* 219 + * Returns 0 if prop1_len == prop2_len. Else returns -1 220 + */ 221 + static inline int validate_dt_prop_sizes(const char *prop1, int prop1_len, 222 + const char *prop2, int prop2_len) 223 + { 224 + if (prop1_len == prop2_len) 225 + return 0; 226 + 227 + pr_warn("cpuidle-powernv: array sizes don't match for %s and %s\n", 228 + prop1, prop2); 229 + return -1; 230 + } 231 + 217 232 static int powernv_add_idle_states(void) 218 233 { 219 234 struct device_node *power_mgt; 220 235 int nr_idle_states = 1; /* Snooze */ 221 - int dt_idle_states; 236 + int dt_idle_states, count; 222 237 u32 latency_ns[CPUIDLE_STATE_MAX]; 223 238 u32 residency_ns[CPUIDLE_STATE_MAX]; 224 239 u32 flags[CPUIDLE_STATE_MAX]; ··· 256 243 pr_warn("cpuidle-powernv: no idle states found in the DT\n"); 257 244 goto out; 258 245 } 246 + 247 + count = of_property_count_u32_elems(power_mgt, 248 + "ibm,cpu-idle-state-latencies-ns"); 249 + 250 + if (validate_dt_prop_sizes("ibm,cpu-idle-state-flags", dt_idle_states, 251 + "ibm,cpu-idle-state-latencies-ns", 252 + count) != 0) 253 + goto out; 254 + 255 + count = of_property_count_strings(power_mgt, 256 + "ibm,cpu-idle-state-names"); 257 + if (validate_dt_prop_sizes("ibm,cpu-idle-state-flags", dt_idle_states, 258 + "ibm,cpu-idle-state-names", 259 + count) != 0) 260 + goto out; 259 261 260 262 /* 261 263 * Since snooze is used as first idle state, max idle states allowed is ··· 306 278 has_stop_states = (flags[0] & 307 279 (OPAL_PM_STOP_INST_FAST | OPAL_PM_STOP_INST_DEEP)); 308 280 if (has_stop_states) { 281 + count = of_property_count_u64_elems(power_mgt, 282 + "ibm,cpu-idle-state-psscr"); 283 + if (validate_dt_prop_sizes("ibm,cpu-idle-state-flags", 284 + dt_idle_states, 285 + "ibm,cpu-idle-state-psscr", 286 + count) != 0) 287 + goto out; 288 + 289 + count = of_property_count_u64_elems(power_mgt, 290 + "ibm,cpu-idle-state-psscr-mask"); 291 + if (validate_dt_prop_sizes("ibm,cpu-idle-state-flags", 292 + dt_idle_states, 293 + "ibm,cpu-idle-state-psscr-mask", 294 + count) != 0) 295 + goto out; 296 + 309 297 if (of_property_read_u64_array(power_mgt, 310 298 "ibm,cpu-idle-state-psscr", psscr_val, dt_idle_states)) { 311 299 pr_warn("cpuidle-powernv: missing ibm,cpu-idle-state-psscr in DT\n"); ··· 336 292 } 337 293 } 338 294 339 - rc = of_property_read_u32_array(power_mgt, 340 - "ibm,cpu-idle-state-residency-ns", residency_ns, dt_idle_states); 295 + count = of_property_count_u32_elems(power_mgt, 296 + "ibm,cpu-idle-state-residency-ns"); 297 + 298 + if (count < 0) { 299 + rc = count; 300 + } else if (validate_dt_prop_sizes("ibm,cpu-idle-state-flags", 301 + dt_idle_states, 302 + "ibm,cpu-idle-state-residency-ns", 303 + count) != 0) { 304 + goto out; 305 + } else { 306 + rc = of_property_read_u32_array(power_mgt, 307 + "ibm,cpu-idle-state-residency-ns", 308 + residency_ns, dt_idle_states); 309 + } 341 310 342 311 for (i = 0; i < dt_idle_states; i++) { 343 312 unsigned int exit_latency, target_residency;
+29
drivers/devfreq/governor.h
··· 25 25 #define DEVFREQ_GOV_SUSPEND 0x4 26 26 #define DEVFREQ_GOV_RESUME 0x5 27 27 28 + /** 29 + * struct devfreq_governor - Devfreq policy governor 30 + * @node: list node - contains registered devfreq governors 31 + * @name: Governor's name 32 + * @immutable: Immutable flag for governor. If the value is 1, 33 + * this govenror is never changeable to other governor. 34 + * @get_target_freq: Returns desired operating frequency for the device. 35 + * Basically, get_target_freq will run 36 + * devfreq_dev_profile.get_dev_status() to get the 37 + * status of the device (load = busy_time / total_time). 38 + * If no_central_polling is set, this callback is called 39 + * only with update_devfreq() notified by OPP. 40 + * @event_handler: Callback for devfreq core framework to notify events 41 + * to governors. Events include per device governor 42 + * init and exit, opp changes out of devfreq, suspend 43 + * and resume of per device devfreq during device idle. 44 + * 45 + * Note that the callbacks are called with devfreq->lock locked by devfreq. 46 + */ 47 + struct devfreq_governor { 48 + struct list_head node; 49 + 50 + const char name[DEVFREQ_NAME_LEN]; 51 + const unsigned int immutable; 52 + int (*get_target_freq)(struct devfreq *this, unsigned long *freq); 53 + int (*event_handler)(struct devfreq *devfreq, 54 + unsigned int event, void *data); 55 + }; 56 + 28 57 /* Caution: devfreq->lock must be locked before calling update_devfreq */ 29 58 extern int update_devfreq(struct devfreq *devfreq); 30 59
+41
drivers/power/avs/rockchip-io-domain.c
··· 43 43 #define RK3288_SOC_CON2_FLASH0 BIT(7) 44 44 #define RK3288_SOC_FLASH_SUPPLY_NUM 2 45 45 46 + #define RK3328_SOC_CON4 0x410 47 + #define RK3328_SOC_CON4_VCCIO2 BIT(7) 48 + #define RK3328_SOC_VCCIO2_SUPPLY_NUM 1 49 + 46 50 #define RK3368_SOC_CON15 0x43c 47 51 #define RK3368_SOC_CON15_FLASH0 BIT(14) 48 52 #define RK3368_SOC_FLASH_SUPPLY_NUM 2 ··· 170 166 dev_warn(iod->dev, "couldn't update flash0 ctrl\n"); 171 167 } 172 168 169 + static void rk3328_iodomain_init(struct rockchip_iodomain *iod) 170 + { 171 + int ret; 172 + u32 val; 173 + 174 + /* if no vccio2 supply we should leave things alone */ 175 + if (!iod->supplies[RK3328_SOC_VCCIO2_SUPPLY_NUM].reg) 176 + return; 177 + 178 + /* 179 + * set vccio2 iodomain to also use this framework 180 + * instead of a special gpio. 181 + */ 182 + val = RK3328_SOC_CON4_VCCIO2 | (RK3328_SOC_CON4_VCCIO2 << 16); 183 + ret = regmap_write(iod->grf, RK3328_SOC_CON4, val); 184 + if (ret < 0) 185 + dev_warn(iod->dev, "couldn't update vccio2 vsel ctrl\n"); 186 + } 187 + 173 188 static void rk3368_iodomain_init(struct rockchip_iodomain *iod) 174 189 { 175 190 int ret; ··· 270 247 .init = rk3288_iodomain_init, 271 248 }; 272 249 250 + static const struct rockchip_iodomain_soc_data soc_data_rk3328 = { 251 + .grf_offset = 0x410, 252 + .supply_names = { 253 + "vccio1", 254 + "vccio2", 255 + "vccio3", 256 + "vccio4", 257 + "vccio5", 258 + "vccio6", 259 + "pmuio", 260 + }, 261 + .init = rk3328_iodomain_init, 262 + }; 263 + 273 264 static const struct rockchip_iodomain_soc_data soc_data_rk3368 = { 274 265 .grf_offset = 0x900, 275 266 .supply_names = { ··· 347 310 { 348 311 .compatible = "rockchip,rk3288-io-voltage-domain", 349 312 .data = (void *)&soc_data_rk3288 313 + }, 314 + { 315 + .compatible = "rockchip,rk3328-io-voltage-domain", 316 + .data = (void *)&soc_data_rk3328 350 317 }, 351 318 { 352 319 .compatible = "rockchip,rk3368-io-voltage-domain",
-12
drivers/thermal/Kconfig
··· 291 291 Enable this option if you want to have support for thermal management 292 292 controller present in Armada 370 and Armada XP SoC. 293 293 294 - config DB8500_CPUFREQ_COOLING 295 - tristate "DB8500 cpufreq cooling" 296 - depends on ARCH_U8500 || COMPILE_TEST 297 - depends on HAS_IOMEM 298 - depends on CPU_THERMAL 299 - default y 300 - help 301 - Adds DB8500 cpufreq cooling devices, and these cooling devices can be 302 - bound to thermal zone trip points. When a trip point reached, the 303 - bound cpufreq cooling device turns active to set CPU frequency low to 304 - cool down the CPU. 305 - 306 294 config INTEL_POWERCLAMP 307 295 tristate "Intel PowerClamp idle injection driver" 308 296 depends on THERMAL
-1
drivers/thermal/Makefile
··· 41 41 obj-$(CONFIG_IMX_THERMAL) += imx_thermal.o 42 42 obj-$(CONFIG_MAX77620_THERMAL) += max77620_thermal.o 43 43 obj-$(CONFIG_QORIQ_THERMAL) += qoriq_thermal.o 44 - obj-$(CONFIG_DB8500_CPUFREQ_COOLING) += db8500_cpufreq_cooling.o 45 44 obj-$(CONFIG_INTEL_POWERCLAMP) += intel_powerclamp.o 46 45 obj-$(CONFIG_X86_PKG_TEMP_THERMAL) += x86_pkg_temp_thermal.o 47 46 obj-$(CONFIG_INTEL_SOC_DTS_IOSF_CORE) += intel_soc_dts_iosf.o
-105
drivers/thermal/db8500_cpufreq_cooling.c
··· 1 - /* 2 - * db8500_cpufreq_cooling.c - DB8500 cpufreq works as cooling device. 3 - * 4 - * Copyright (C) 2012 ST-Ericsson 5 - * Copyright (C) 2012 Linaro Ltd. 6 - * 7 - * Author: Hongbo Zhang <hongbo.zhang@linaro.com> 8 - * 9 - * This program is free software; you can redistribute it and/or modify 10 - * it under the terms of the GNU General Public License as published by 11 - * the Free Software Foundation; either version 2 of the License, or 12 - * (at your option) any later version. 13 - * 14 - * This program is distributed in the hope that it will be useful, 15 - * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 - * GNU General Public License for more details. 18 - */ 19 - 20 - #include <linux/cpu_cooling.h> 21 - #include <linux/err.h> 22 - #include <linux/module.h> 23 - #include <linux/of.h> 24 - #include <linux/platform_device.h> 25 - #include <linux/slab.h> 26 - 27 - static int db8500_cpufreq_cooling_probe(struct platform_device *pdev) 28 - { 29 - struct thermal_cooling_device *cdev; 30 - 31 - cdev = cpufreq_cooling_register(cpu_present_mask); 32 - if (IS_ERR(cdev)) { 33 - int ret = PTR_ERR(cdev); 34 - 35 - if (ret != -EPROBE_DEFER) 36 - dev_err(&pdev->dev, 37 - "Failed to register cooling device %d\n", 38 - ret); 39 - 40 - return ret; 41 - } 42 - 43 - platform_set_drvdata(pdev, cdev); 44 - 45 - dev_info(&pdev->dev, "Cooling device registered: %s\n", cdev->type); 46 - 47 - return 0; 48 - } 49 - 50 - static int db8500_cpufreq_cooling_remove(struct platform_device *pdev) 51 - { 52 - struct thermal_cooling_device *cdev = platform_get_drvdata(pdev); 53 - 54 - cpufreq_cooling_unregister(cdev); 55 - 56 - return 0; 57 - } 58 - 59 - static int db8500_cpufreq_cooling_suspend(struct platform_device *pdev, 60 - pm_message_t state) 61 - { 62 - return -ENOSYS; 63 - } 64 - 65 - static int db8500_cpufreq_cooling_resume(struct platform_device *pdev) 66 - { 67 - return -ENOSYS; 68 - } 69 - 70 - #ifdef CONFIG_OF 71 - static const struct of_device_id db8500_cpufreq_cooling_match[] = { 72 - { .compatible = "stericsson,db8500-cpufreq-cooling" }, 73 - {}, 74 - }; 75 - MODULE_DEVICE_TABLE(of, db8500_cpufreq_cooling_match); 76 - #endif 77 - 78 - static struct platform_driver db8500_cpufreq_cooling_driver = { 79 - .driver = { 80 - .name = "db8500-cpufreq-cooling", 81 - .of_match_table = of_match_ptr(db8500_cpufreq_cooling_match), 82 - }, 83 - .probe = db8500_cpufreq_cooling_probe, 84 - .suspend = db8500_cpufreq_cooling_suspend, 85 - .resume = db8500_cpufreq_cooling_resume, 86 - .remove = db8500_cpufreq_cooling_remove, 87 - }; 88 - 89 - static int __init db8500_cpufreq_cooling_init(void) 90 - { 91 - return platform_driver_register(&db8500_cpufreq_cooling_driver); 92 - } 93 - 94 - static void __exit db8500_cpufreq_cooling_exit(void) 95 - { 96 - platform_driver_unregister(&db8500_cpufreq_cooling_driver); 97 - } 98 - 99 - /* Should be later than db8500_cpufreq_register */ 100 - late_initcall(db8500_cpufreq_cooling_init); 101 - module_exit(db8500_cpufreq_cooling_exit); 102 - 103 - MODULE_AUTHOR("Hongbo Zhang <hongbo.zhang@stericsson.com>"); 104 - MODULE_DESCRIPTION("DB8500 cpufreq cooling driver"); 105 - MODULE_LICENSE("GPL");
+7
include/linux/cpufreq.h
··· 120 120 bool fast_switch_possible; 121 121 bool fast_switch_enabled; 122 122 123 + /* 124 + * Preferred average time interval between consecutive invocations of 125 + * the driver to set the frequency for this policy. To be set by the 126 + * scaling driver (0, which is the default, means no preference). 127 + */ 128 + unsigned int transition_delay_us; 129 + 123 130 /* Cached frequency lookup from cpufreq_driver_resolve_freq. */ 124 131 unsigned int cached_target_freq; 125 132 int cached_resolved_idx;
+1 -29
include/linux/devfreq.h
··· 27 27 #define DEVFREQ_POSTCHANGE (1) 28 28 29 29 struct devfreq; 30 + struct devfreq_governor; 30 31 31 32 /** 32 33 * struct devfreq_dev_status - Data given from devfreq user device to ··· 99 98 100 99 unsigned long *freq_table; 101 100 unsigned int max_state; 102 - }; 103 - 104 - /** 105 - * struct devfreq_governor - Devfreq policy governor 106 - * @node: list node - contains registered devfreq governors 107 - * @name: Governor's name 108 - * @immutable: Immutable flag for governor. If the value is 1, 109 - * this govenror is never changeable to other governor. 110 - * @get_target_freq: Returns desired operating frequency for the device. 111 - * Basically, get_target_freq will run 112 - * devfreq_dev_profile.get_dev_status() to get the 113 - * status of the device (load = busy_time / total_time). 114 - * If no_central_polling is set, this callback is called 115 - * only with update_devfreq() notified by OPP. 116 - * @event_handler: Callback for devfreq core framework to notify events 117 - * to governors. Events include per device governor 118 - * init and exit, opp changes out of devfreq, suspend 119 - * and resume of per device devfreq during device idle. 120 - * 121 - * Note that the callbacks are called with devfreq->lock locked by devfreq. 122 - */ 123 - struct devfreq_governor { 124 - struct list_head node; 125 - 126 - const char name[DEVFREQ_NAME_LEN]; 127 - const unsigned int immutable; 128 - int (*get_target_freq)(struct devfreq *this, unsigned long *freq); 129 - int (*event_handler)(struct devfreq *devfreq, 130 - unsigned int event, void *data); 131 101 }; 132 102 133 103 /**
+1
include/linux/pm_domain.h
··· 20 20 /* Defines used for the flags field in the struct generic_pm_domain */ 21 21 #define GENPD_FLAG_PM_CLK (1U << 0) /* PM domain uses PM clk */ 22 22 #define GENPD_FLAG_IRQ_SAFE (1U << 1) /* PM domain operates in atomic */ 23 + #define GENPD_FLAG_ALWAYS_ON (1U << 2) /* PM domain is always powered on */ 23 24 24 25 enum gpd_status { 25 26 GPD_STATE_ACTIVE = 0, /* PM domain is active */
+1
include/linux/tick.h
··· 117 117 extern void tick_nohz_idle_exit(void); 118 118 extern void tick_nohz_irq_exit(void); 119 119 extern ktime_t tick_nohz_get_sleep_length(void); 120 + extern unsigned long tick_nohz_get_idle_calls(void); 120 121 extern u64 get_cpu_idle_time_us(int cpu, u64 *last_update_time); 121 122 extern u64 get_cpu_iowait_time_us(int cpu, u64 *last_update_time); 122 123 #else /* !CONFIG_NO_HZ_COMMON */
+54 -28
kernel/sched/cpufreq_schedutil.c
··· 61 61 unsigned long util; 62 62 unsigned long max; 63 63 unsigned int flags; 64 + 65 + /* The field below is for single-CPU policies only. */ 66 + #ifdef CONFIG_NO_HZ_COMMON 67 + unsigned long saved_idle_calls; 68 + #endif 64 69 }; 65 70 66 71 static DEFINE_PER_CPU(struct sugov_cpu, sugov_cpu); ··· 98 93 { 99 94 struct cpufreq_policy *policy = sg_policy->policy; 100 95 96 + if (sg_policy->next_freq == next_freq) 97 + return; 98 + 99 + if (sg_policy->next_freq > next_freq) 100 + next_freq = (sg_policy->next_freq + next_freq) >> 1; 101 + 102 + sg_policy->next_freq = next_freq; 101 103 sg_policy->last_freq_update_time = time; 102 104 103 105 if (policy->fast_switch_enabled) { 104 - if (sg_policy->next_freq == next_freq) { 105 - trace_cpu_frequency(policy->cur, smp_processor_id()); 106 - return; 107 - } 108 - sg_policy->next_freq = next_freq; 109 106 next_freq = cpufreq_driver_fast_switch(policy, next_freq); 110 107 if (next_freq == CPUFREQ_ENTRY_INVALID) 111 108 return; 112 109 113 110 policy->cur = next_freq; 114 111 trace_cpu_frequency(next_freq, smp_processor_id()); 115 - } else if (sg_policy->next_freq != next_freq) { 116 - sg_policy->next_freq = next_freq; 112 + } else { 117 113 sg_policy->work_in_progress = true; 118 114 irq_work_queue(&sg_policy->irq_work); 119 115 } ··· 198 192 sg_cpu->iowait_boost >>= 1; 199 193 } 200 194 195 + #ifdef CONFIG_NO_HZ_COMMON 196 + static bool sugov_cpu_is_busy(struct sugov_cpu *sg_cpu) 197 + { 198 + unsigned long idle_calls = tick_nohz_get_idle_calls(); 199 + bool ret = idle_calls == sg_cpu->saved_idle_calls; 200 + 201 + sg_cpu->saved_idle_calls = idle_calls; 202 + return ret; 203 + } 204 + #else 205 + static inline bool sugov_cpu_is_busy(struct sugov_cpu *sg_cpu) { return false; } 206 + #endif /* CONFIG_NO_HZ_COMMON */ 207 + 201 208 static void sugov_update_single(struct update_util_data *hook, u64 time, 202 209 unsigned int flags) 203 210 { ··· 219 200 struct cpufreq_policy *policy = sg_policy->policy; 220 201 unsigned long util, max; 221 202 unsigned int next_f; 203 + bool busy; 222 204 223 205 sugov_set_iowait_boost(sg_cpu, time, flags); 224 206 sg_cpu->last_update = time; ··· 227 207 if (!sugov_should_update_freq(sg_policy, time)) 228 208 return; 229 209 210 + busy = sugov_cpu_is_busy(sg_cpu); 211 + 230 212 if (flags & SCHED_CPUFREQ_RT_DL) { 231 213 next_f = policy->cpuinfo.max_freq; 232 214 } else { 233 215 sugov_get_util(&util, &max); 234 216 sugov_iowait_boost(sg_cpu, &util, &max); 235 217 next_f = get_next_freq(sg_policy, util, max); 218 + /* 219 + * Do not reduce the frequency if the CPU has not been idle 220 + * recently, as the reduction is likely to be premature then. 221 + */ 222 + if (busy && next_f < sg_policy->next_freq) 223 + next_f = sg_policy->next_freq; 236 224 } 237 225 sugov_update_commit(sg_policy, time, next_f); 238 226 } 239 227 240 - static unsigned int sugov_next_freq_shared(struct sugov_cpu *sg_cpu, 241 - unsigned long util, unsigned long max, 242 - unsigned int flags) 228 + static unsigned int sugov_next_freq_shared(struct sugov_cpu *sg_cpu) 243 229 { 244 230 struct sugov_policy *sg_policy = sg_cpu->sg_policy; 245 231 struct cpufreq_policy *policy = sg_policy->policy; 246 - unsigned int max_f = policy->cpuinfo.max_freq; 247 232 u64 last_freq_update_time = sg_policy->last_freq_update_time; 233 + unsigned long util = 0, max = 1; 248 234 unsigned int j; 249 235 250 - if (flags & SCHED_CPUFREQ_RT_DL) 251 - return max_f; 252 - 253 - sugov_iowait_boost(sg_cpu, &util, &max); 254 - 255 236 for_each_cpu(j, policy->cpus) { 256 - struct sugov_cpu *j_sg_cpu; 237 + struct sugov_cpu *j_sg_cpu = &per_cpu(sugov_cpu, j); 257 238 unsigned long j_util, j_max; 258 239 s64 delta_ns; 259 240 260 - if (j == smp_processor_id()) 261 - continue; 262 - 263 - j_sg_cpu = &per_cpu(sugov_cpu, j); 264 241 /* 265 242 * If the CPU utilization was last updated before the previous 266 243 * frequency update and the time elapsed between the last update ··· 271 254 continue; 272 255 } 273 256 if (j_sg_cpu->flags & SCHED_CPUFREQ_RT_DL) 274 - return max_f; 257 + return policy->cpuinfo.max_freq; 275 258 276 259 j_util = j_sg_cpu->util; 277 260 j_max = j_sg_cpu->max; ··· 306 289 sg_cpu->last_update = time; 307 290 308 291 if (sugov_should_update_freq(sg_policy, time)) { 309 - next_f = sugov_next_freq_shared(sg_cpu, util, max, flags); 292 + if (flags & SCHED_CPUFREQ_RT_DL) 293 + next_f = sg_policy->policy->cpuinfo.max_freq; 294 + else 295 + next_f = sugov_next_freq_shared(sg_cpu); 296 + 310 297 sugov_update_commit(sg_policy, time, next_f); 311 298 } 312 299 ··· 494 473 { 495 474 struct sugov_policy *sg_policy; 496 475 struct sugov_tunables *tunables; 497 - unsigned int lat; 498 476 int ret = 0; 499 477 500 478 /* State should be equivalent to EXIT */ ··· 532 512 goto stop_kthread; 533 513 } 534 514 535 - tunables->rate_limit_us = LATENCY_MULTIPLIER; 536 - lat = policy->cpuinfo.transition_latency / NSEC_PER_USEC; 537 - if (lat) 538 - tunables->rate_limit_us *= lat; 515 + if (policy->transition_delay_us) { 516 + tunables->rate_limit_us = policy->transition_delay_us; 517 + } else { 518 + unsigned int lat; 519 + 520 + tunables->rate_limit_us = LATENCY_MULTIPLIER; 521 + lat = policy->cpuinfo.transition_latency / NSEC_PER_USEC; 522 + if (lat) 523 + tunables->rate_limit_us *= lat; 524 + } 539 525 540 526 policy->governor_data = sg_policy; 541 527 sg_policy->tunables = tunables;
+12
kernel/time/tick-sched.c
··· 993 993 return ts->sleep_length; 994 994 } 995 995 996 + /** 997 + * tick_nohz_get_idle_calls - return the current idle calls counter value 998 + * 999 + * Called from the schedutil frequency scaling governor in scheduler context. 1000 + */ 1001 + unsigned long tick_nohz_get_idle_calls(void) 1002 + { 1003 + struct tick_sched *ts = this_cpu_ptr(&tick_cpu_sched); 1004 + 1005 + return ts->idle_calls; 1006 + } 1007 + 996 1008 static void tick_nohz_account_idle_ticks(struct tick_sched *ts) 997 1009 { 998 1010 #ifndef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
+495 -421
scripts/analyze_suspend.py tools/power/pm-graph/analyze_suspend.py
··· 12 12 # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 13 13 # more details. 14 14 # 15 - # You should have received a copy of the GNU General Public License along with 16 - # this program; if not, write to the Free Software Foundation, Inc., 17 - # 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. 18 - # 19 15 # Authors: 20 16 # Todd Brandt <todd.e.brandt@linux.intel.com> 21 17 # ··· 19 23 # Home Page 20 24 # https://01.org/suspendresume 21 25 # Source repo 22 - # https://github.com/01org/suspendresume 26 + # https://github.com/01org/pm-graph 23 27 # 24 28 # Description: 25 29 # This tool is designed to assist kernel and OS developers in optimizing ··· 67 71 # A global, single-instance container used to 68 72 # store system values and test parameters 69 73 class SystemValues: 74 + title = 'SleepGraph' 75 + version = '4.6' 70 76 ansi = False 71 - version = '4.5' 72 77 verbose = False 73 78 addlogs = False 74 79 mindevlen = 0.0 75 80 mincglen = 0.0 76 81 cgphase = '' 77 82 cgtest = -1 83 + max_graph_depth = 0 78 84 callloopmaxgap = 0.0001 79 85 callloopmaxlen = 0.005 80 86 srgap = 0 ··· 104 106 ftracefile = '' 105 107 htmlfile = '' 106 108 embedded = False 107 - rtcwake = False 108 - rtcwaketime = 10 109 + rtcwake = True 110 + rtcwaketime = 15 109 111 rtcpath = '' 110 112 devicefilter = [] 111 113 stamp = 0 ··· 233 235 self.rtcpath = rtc 234 236 if (hasattr(sys.stdout, 'isatty') and sys.stdout.isatty()): 235 237 self.ansi = True 238 + def rootUser(self, fatal=False): 239 + if 'USER' in os.environ and os.environ['USER'] == 'root': 240 + return True 241 + if fatal: 242 + doError('This command must be run as root') 243 + return False 236 244 def setPrecision(self, num): 237 245 if num < 0 or num > 6: 238 246 return ··· 568 564 self.fsetVal('global', 'trace_clock') 569 565 # set trace buffer to a huge value 570 566 self.fsetVal('nop', 'current_tracer') 571 - self.fsetVal('100000', 'buffer_size_kb') 567 + self.fsetVal('131073', 'buffer_size_kb') 572 568 # go no further if this is just a status check 573 569 if testing: 574 570 return ··· 587 583 self.fsetVal('nofuncgraph-overhead', 'trace_options') 588 584 self.fsetVal('context-info', 'trace_options') 589 585 self.fsetVal('graph-time', 'trace_options') 590 - self.fsetVal('0', 'max_graph_depth') 586 + self.fsetVal('%d' % self.max_graph_depth, 'max_graph_depth') 591 587 cf = ['dpm_run_callback'] 592 588 if(self.usetraceeventsonly): 593 589 cf += ['dpm_prepare', 'dpm_complete'] ··· 643 639 return '\x1B[%d;40m%s\x1B[m' % (color, str) 644 640 645 641 sysvals = SystemValues() 642 + suspendmodename = { 643 + 'freeze': 'Freeze (S0)', 644 + 'standby': 'Standby (S1)', 645 + 'mem': 'Suspend (S3)', 646 + 'disk': 'Hibernate (S4)' 647 + } 646 648 647 649 # Class: DevProps 648 650 # Description: ··· 1023 1013 tmp = dict() 1024 1014 for devname in list: 1025 1015 dev = list[devname] 1016 + if dev['length'] == 0: 1017 + continue 1026 1018 tmp[dev['start']] = devname 1027 1019 for t in sorted(tmp): 1028 1020 slist.append(tmp[t]) ··· 1489 1477 # Each instance is tied to a single device in a single phase, and is 1490 1478 # comprised of an ordered list of FTraceLine objects 1491 1479 class FTraceCallGraph: 1480 + id = '' 1492 1481 start = -1.0 1493 1482 end = -1.0 1494 1483 list = [] 1495 1484 invalid = False 1496 1485 depth = 0 1497 1486 pid = 0 1487 + name = '' 1498 1488 def __init__(self, pid): 1499 1489 self.start = -1.0 1500 1490 self.end = -1.0 ··· 1645 1631 return True 1646 1632 return False 1647 1633 def postProcess(self, debug=False): 1634 + if len(self.list) > 0: 1635 + self.name = self.list[0].name 1648 1636 stack = dict() 1649 1637 cnt = 0 1638 + last = 0 1650 1639 for l in self.list: 1640 + # ftrace bug: reported duration is not reliable 1641 + # check each leaf and clip it at max possible length 1642 + if(last and last.freturn and last.fcall): 1643 + if last.length > l.time - last.time: 1644 + last.length = l.time - last.time 1651 1645 if(l.fcall and not l.freturn): 1652 1646 stack[l.depth] = l 1653 1647 cnt += 1 ··· 1665 1643 print 'Post Process Error: Depth missing' 1666 1644 l.debugPrint() 1667 1645 return False 1668 - # transfer total time from return line to call line 1669 - stack[l.depth].length = l.length 1646 + # calculate call length from call/return lines 1647 + stack[l.depth].length = l.time - stack[l.depth].time 1670 1648 stack.pop(l.depth) 1671 1649 l.length = 0 1672 1650 cnt -= 1 1651 + last = l 1673 1652 if(cnt == 0): 1674 1653 # trace caught the whole call tree 1675 1654 return True ··· 1687 1664 'dpm_prepare': 'suspend_prepare', 1688 1665 'dpm_complete': 'resume_complete' 1689 1666 } 1690 - if(self.list[0].name in borderphase): 1691 - p = borderphase[self.list[0].name] 1667 + if(self.name in borderphase): 1668 + p = borderphase[self.name] 1692 1669 list = data.dmesg[p]['list'] 1693 1670 for devname in list: 1694 1671 dev = list[devname] ··· 1713 1690 break 1714 1691 return found 1715 1692 def newActionFromFunction(self, data): 1716 - name = self.list[0].name 1693 + name = self.name 1717 1694 if name in ['dpm_run_callback', 'dpm_prepare', 'dpm_complete']: 1718 1695 return 1719 1696 fs = self.start ··· 1733 1710 phase, myname = out 1734 1711 data.dmesg[phase]['list'][myname]['ftrace'] = self 1735 1712 def debugPrint(self): 1736 - print('[%f - %f] %s (%d)') % (self.start, self.end, self.list[0].name, self.pid) 1713 + print('[%f - %f] %s (%d)') % (self.start, self.end, self.name, self.pid) 1737 1714 for l in self.list: 1738 1715 if(l.freturn and l.fcall): 1739 1716 print('%f (%02d): %s(); (%.3f us)' % (l.time, \ ··· 1761 1738 # A container for a device timeline which calculates 1762 1739 # all the html properties to display it correctly 1763 1740 class Timeline: 1764 - html = {} 1741 + html = '' 1765 1742 height = 0 # total timeline height 1766 1743 scaleH = 20 # timescale (top) row height 1767 1744 rowH = 30 # device row height ··· 1769 1746 rows = 0 # total timeline rows 1770 1747 rowlines = dict() 1771 1748 rowheight = dict() 1749 + html_tblock = '<div id="block{0}" class="tblock" style="left:{1}%;width:{2}%;"><div class="tback" style="height:{3}px"></div>\n' 1750 + html_device = '<div id="{0}" title="{1}" class="thread{7}" style="left:{2}%;top:{3}px;height:{4}px;width:{5}%;{8}">{6}</div>\n' 1751 + html_phase = '<div class="phase" style="left:{0}%;width:{1}%;top:{2}px;height:{3}px;background:{4}">{5}</div>\n' 1752 + html_phaselet = '<div id="{0}" class="phaselet" style="left:{1}%;width:{2}%;background:{3}"></div>\n' 1772 1753 def __init__(self, rowheight, scaleheight): 1773 1754 self.rowH = rowheight 1774 1755 self.scaleH = scaleheight 1775 - self.html = { 1776 - 'header': '', 1777 - 'timeline': '', 1778 - 'legend': '', 1779 - } 1756 + self.html = '' 1757 + def createHeader(self, sv, suppress=''): 1758 + if(not sv.stamp['time']): 1759 + return 1760 + self.html += '<div class="version"><a href="https://01.org/suspendresume">%s v%s</a></div>' \ 1761 + % (sv.title, sv.version) 1762 + if sv.logmsg and 'log' not in suppress: 1763 + self.html += '<button id="showtest" class="logbtn">log</button>' 1764 + if sv.addlogs and 'dmesg' not in suppress: 1765 + self.html += '<button id="showdmesg" class="logbtn">dmesg</button>' 1766 + if sv.addlogs and sv.ftracefile and 'ftrace' not in suppress: 1767 + self.html += '<button id="showftrace" class="logbtn">ftrace</button>' 1768 + headline_stamp = '<div class="stamp">{0} {1} {2} {3}</div>\n' 1769 + self.html += headline_stamp.format(sv.stamp['host'], sv.stamp['kernel'], 1770 + sv.stamp['mode'], sv.stamp['time']) 1780 1771 # Function: getDeviceRows 1781 1772 # Description: 1782 1773 # determine how may rows the device funcs will take ··· 1917 1880 break 1918 1881 top += self.rowheight[test][phase][i] 1919 1882 return top 1920 - # Function: calcTotalRows 1921 - # Description: 1922 - # Calculate the heights and offsets for the header and rows 1923 1883 def calcTotalRows(self): 1884 + # Calculate the heights and offsets for the header and rows 1924 1885 maxrows = 0 1925 1886 standardphases = [] 1926 1887 for t in self.rowlines: ··· 1936 1901 for t, p in standardphases: 1937 1902 for i in sorted(self.rowheight[t][p]): 1938 1903 self.rowheight[t][p][i] = self.bodyH/len(self.rowlines[t][p]) 1904 + def createZoomBox(self, mode='command', testcount=1): 1905 + # Create bounding box, add buttons 1906 + html_zoombox = '<center><button id="zoomin">ZOOM IN +</button><button id="zoomout">ZOOM OUT -</button><button id="zoomdef">ZOOM 1:1</button></center>\n' 1907 + html_timeline = '<div id="dmesgzoombox" class="zoombox">\n<div id="{0}" class="timeline" style="height:{1}px">\n' 1908 + html_devlist1 = '<button id="devlist1" class="devlist" style="float:left;">Device Detail{0}</button>' 1909 + html_devlist2 = '<button id="devlist2" class="devlist" style="float:right;">Device Detail2</button>\n' 1910 + if mode != 'command': 1911 + if testcount > 1: 1912 + self.html += html_devlist2 1913 + self.html += html_devlist1.format('1') 1914 + else: 1915 + self.html += html_devlist1.format('') 1916 + self.html += html_zoombox 1917 + self.html += html_timeline.format('dmesg', self.height) 1939 1918 # Function: createTimeScale 1940 1919 # Description: 1941 1920 # Create the timescale for a timeline block ··· 1962 1913 # The html code needed to display the time scale 1963 1914 def createTimeScale(self, m0, mMax, tTotal, mode): 1964 1915 timescale = '<div class="t" style="right:{0}%">{1}</div>\n' 1965 - rline = '<div class="t" style="left:0;border-left:1px solid black;border-right:0;">Resume</div>\n' 1916 + rline = '<div class="t" style="left:0;border-left:1px solid black;border-right:0;">{0}</div>\n' 1966 1917 output = '<div class="timescale">\n' 1967 1918 # set scale for timeline 1968 1919 mTotal = mMax - m0 ··· 1975 1926 divEdge = (mTotal - tS*(divTotal-1))*100/mTotal 1976 1927 for i in range(divTotal): 1977 1928 htmlline = '' 1978 - if(mode == 'resume'): 1929 + if(mode == 'suspend'): 1930 + pos = '%0.3f' % (100 - ((float(i)*tS*100)/mTotal) - divEdge) 1931 + val = '%0.fms' % (float(i-divTotal+1)*tS*1000) 1932 + if(i == divTotal - 1): 1933 + val = mode 1934 + htmlline = timescale.format(pos, val) 1935 + else: 1979 1936 pos = '%0.3f' % (100 - ((float(i)*tS*100)/mTotal)) 1980 1937 val = '%0.fms' % (float(i)*tS*1000) 1981 1938 htmlline = timescale.format(pos, val) 1982 1939 if(i == 0): 1983 - htmlline = rline 1984 - else: 1985 - pos = '%0.3f' % (100 - ((float(i)*tS*100)/mTotal) - divEdge) 1986 - val = '%0.fms' % (float(i-divTotal+1)*tS*1000) 1987 - if(i == divTotal - 1): 1988 - val = 'Suspend' 1989 - htmlline = timescale.format(pos, val) 1940 + htmlline = rline.format(mode) 1990 1941 output += htmlline 1991 - output += '</div>\n' 1992 - return output 1942 + self.html += output+'</div>\n' 1993 1943 1994 1944 # Class: TestProps 1995 1945 # Description: ··· 2057 2009 val['kern'] = kern 2058 2010 if ujiff > 0 or kjiff > 0: 2059 2011 running[pid] = ujiff + kjiff 2060 - result = process.wait() 2012 + process.wait() 2061 2013 out = '' 2062 2014 for pid in running: 2063 2015 jiffies = running[pid] ··· 2118 2070 data.stamp['mode'] = sysvals.suspendmode 2119 2071 if not sysvals.stamp: 2120 2072 sysvals.stamp = data.stamp 2121 - 2122 - # Function: diffStamp 2123 - # Description: 2124 - # compare the host, kernel, and mode fields in 3 stamps 2125 - # Arguments: 2126 - # stamp1: string array with mode, kernel, and host 2127 - # stamp2: string array with mode, kernel, and host 2128 - # Return: 2129 - # True if stamps differ, False if they're the same 2130 - def diffStamp(stamp1, stamp2): 2131 - if 'host' in stamp1 and 'host' in stamp2: 2132 - if stamp1['host'] != stamp2['host']: 2133 - return True 2134 - if 'kernel' in stamp1 and 'kernel' in stamp2: 2135 - if stamp1['kernel'] != stamp2['kernel']: 2136 - return True 2137 - if 'mode' in stamp1 and 'mode' in stamp2: 2138 - if stamp1['mode'] != stamp2['mode']: 2139 - return True 2140 - return False 2141 2073 2142 2074 # Function: doesTraceLogHaveTraceEvents 2143 2075 # Description: ··· 2750 2722 # create blocks for orphan cg data 2751 2723 for sortkey in sorted(sortlist): 2752 2724 cg = sortlist[sortkey] 2753 - name = cg.list[0].name 2725 + name = cg.name 2754 2726 if sysvals.isCallgraphFunc(name): 2755 2727 vprint('Callgraph found for task %d: %.3fms, %s' % (cg.pid, (cg.end - cg.start)*1000, name)) 2756 2728 cg.newActionFromFunction(data) ··· 3128 3100 data.fixupInitcallsThatDidntReturn() 3129 3101 return True 3130 3102 3103 + def callgraphHTML(sv, hf, num, cg, title, color, devid): 3104 + html_func_top = '<article id="{0}" class="atop" style="background:{1}">\n<input type="checkbox" class="pf" id="f{2}" checked/><label for="f{2}">{3} {4}</label>\n' 3105 + html_func_start = '<article>\n<input type="checkbox" class="pf" id="f{0}" checked/><label for="f{0}">{1} {2}</label>\n' 3106 + html_func_end = '</article>\n' 3107 + html_func_leaf = '<article>{0} {1}</article>\n' 3108 + 3109 + cgid = devid 3110 + if cg.id: 3111 + cgid += cg.id 3112 + cglen = (cg.end - cg.start) * 1000 3113 + if cglen < sv.mincglen: 3114 + return num 3115 + 3116 + fmt = '<r>(%.3f ms @ '+sv.timeformat+' to '+sv.timeformat+')</r>' 3117 + flen = fmt % (cglen, cg.start, cg.end) 3118 + hf.write(html_func_top.format(cgid, color, num, title, flen)) 3119 + num += 1 3120 + for line in cg.list: 3121 + if(line.length < 0.000000001): 3122 + flen = '' 3123 + else: 3124 + fmt = '<n>(%.3f ms @ '+sv.timeformat+')</n>' 3125 + flen = fmt % (line.length*1000, line.time) 3126 + if(line.freturn and line.fcall): 3127 + hf.write(html_func_leaf.format(line.name, flen)) 3128 + elif(line.freturn): 3129 + hf.write(html_func_end) 3130 + else: 3131 + hf.write(html_func_start.format(num, line.name, flen)) 3132 + num += 1 3133 + hf.write(html_func_end) 3134 + return num 3135 + 3136 + def addCallgraphs(sv, hf, data): 3137 + hf.write('<section id="callgraphs" class="callgraph">\n') 3138 + # write out the ftrace data converted to html 3139 + num = 0 3140 + for p in data.phases: 3141 + if sv.cgphase and p != sv.cgphase: 3142 + continue 3143 + list = data.dmesg[p]['list'] 3144 + for devname in data.sortedDevices(p): 3145 + dev = list[devname] 3146 + color = 'white' 3147 + if 'color' in data.dmesg[p]: 3148 + color = data.dmesg[p]['color'] 3149 + if 'color' in dev: 3150 + color = dev['color'] 3151 + name = devname 3152 + if(devname in sv.devprops): 3153 + name = sv.devprops[devname].altName(devname) 3154 + if sv.suspendmode in suspendmodename: 3155 + name += ' '+p 3156 + if('ftrace' in dev): 3157 + cg = dev['ftrace'] 3158 + num = callgraphHTML(sv, hf, num, cg, 3159 + name, color, dev['id']) 3160 + if('ftraces' in dev): 3161 + for cg in dev['ftraces']: 3162 + num = callgraphHTML(sv, hf, num, cg, 3163 + name+' &rarr; '+cg.name, color, dev['id']) 3164 + 3165 + hf.write('\n\n </section>\n') 3166 + 3131 3167 # Function: createHTMLSummarySimple 3132 3168 # Description: 3133 3169 # Create summary html file for a series of tests 3134 3170 # Arguments: 3135 3171 # testruns: array of Data objects from parseTraceLog 3136 - def createHTMLSummarySimple(testruns, htmlfile): 3137 - # print out the basic summary of all the tests 3138 - hf = open(htmlfile, 'w') 3139 - 3172 + def createHTMLSummarySimple(testruns, htmlfile, folder): 3140 3173 # write the html header first (html head, css code, up to body start) 3141 3174 html = '<!DOCTYPE html>\n<html>\n<head>\n\ 3142 3175 <meta http-equiv="content-type" content="text/html; charset=UTF-8">\n\ 3143 - <title>AnalyzeSuspend Summary</title>\n\ 3176 + <title>SleepGraph Summary</title>\n\ 3144 3177 <style type=\'text/css\'>\n\ 3145 - body {overflow-y: scroll;}\n\ 3146 - .stamp {width: 100%;text-align:center;background-color:#495E09;line-height:30px;color:white;font: 25px Arial;}\n\ 3178 + .stamp {width: 100%;text-align:center;background:#888;line-height:30px;color:white;font: 25px Arial;}\n\ 3147 3179 table {width:100%;border-collapse: collapse;}\n\ 3148 - .summary {font: 22px Arial;border:1px solid;}\n\ 3149 - th {border: 1px solid black;background-color:#A7C942;color:white;}\n\ 3150 - td {text-align: center;}\n\ 3151 - tr.alt td {background-color:#EAF2D3;}\n\ 3152 - tr.avg td {background-color:#BDE34C;}\n\ 3153 - a:link {color: #90B521;}\n\ 3154 - a:visited {color: #495E09;}\n\ 3155 - a:hover {color: #B1DF28;}\n\ 3156 - a:active {color: #FFFFFF;}\n\ 3180 + .summary {border:1px solid;}\n\ 3181 + th {border: 1px solid black;background:#222;color:white;}\n\ 3182 + td {font: 16px "Times New Roman";text-align: center;}\n\ 3183 + tr.alt td {background:#ddd;}\n\ 3184 + tr.avg td {background:#aaa;}\n\ 3157 3185 </style>\n</head>\n<body>\n' 3158 3186 3159 3187 # group test header 3160 - count = len(testruns) 3161 - headline_stamp = '<div class="stamp">{0} {1} {2} {3} ({4} tests)</div>\n' 3162 - html += headline_stamp.format(sysvals.stamp['host'], 3163 - sysvals.stamp['kernel'], sysvals.stamp['mode'], 3164 - sysvals.stamp['time'], count) 3165 - 3166 - # check to see if all the tests have the same value 3167 - stampcolumns = False 3168 - for data in testruns: 3169 - if diffStamp(sysvals.stamp, data.stamp): 3170 - stampcolumns = True 3171 - break 3172 - 3188 + html += '<div class="stamp">%s (%d tests)</div>\n' % (folder, len(testruns)) 3173 3189 th = '\t<th>{0}</th>\n' 3174 3190 td = '\t<td>{0}</td>\n' 3175 - tdlink = '\t<td><a href="{0}">Click Here</a></td>\n' 3191 + tdlink = '\t<td><a href="{0}">html</a></td>\n' 3176 3192 3177 3193 # table header 3178 - html += '<table class="summary">\n<tr>\n' 3179 - html += th.format("Test #") 3180 - if stampcolumns: 3181 - html += th.format("Hostname") 3182 - html += th.format("Kernel Version") 3183 - html += th.format("Suspend Mode") 3184 - html += th.format("Test Time") 3185 - html += th.format("Suspend Time") 3186 - html += th.format("Resume Time") 3187 - html += th.format("Detail") 3188 - html += '</tr>\n' 3194 + html += '<table class="summary">\n<tr>\n' + th.format('#') +\ 3195 + th.format('Mode') + th.format('Host') + th.format('Kernel') +\ 3196 + th.format('Test Time') + th.format('Suspend') + th.format('Resume') +\ 3197 + th.format('Detail') + '</tr>\n' 3189 3198 3190 3199 # test data, 1 row per test 3191 - sTimeAvg = 0.0 3192 - rTimeAvg = 0.0 3193 - num = 1 3194 - for data in testruns: 3195 - # data.end is the end of post_resume 3196 - resumeEnd = data.dmesg['resume_complete']['end'] 3200 + avg = '<tr class="avg"><td></td><td></td><td></td><td></td>'+\ 3201 + '<td>Average of {0} {1} tests</td><td>{2}</td><td>{3}</td><td></td></tr>\n' 3202 + sTimeAvg = rTimeAvg = 0.0 3203 + mode = '' 3204 + num = 0 3205 + for data in sorted(testruns, key=lambda v:(v['mode'], v['host'], v['kernel'])): 3206 + if mode != data['mode']: 3207 + # test average line 3208 + if(num > 0): 3209 + sTimeAvg /= (num - 1) 3210 + rTimeAvg /= (num - 1) 3211 + html += avg.format('%d' % (num - 1), mode, 3212 + '%3.3f ms' % sTimeAvg, '%3.3f ms' % rTimeAvg) 3213 + sTimeAvg = rTimeAvg = 0.0 3214 + mode = data['mode'] 3215 + num = 1 3216 + # alternate row color 3197 3217 if num % 2 == 1: 3198 3218 html += '<tr class="alt">\n' 3199 3219 else: 3200 3220 html += '<tr>\n' 3201 - 3202 - # test num 3203 - html += td.format("test %d" % num) 3221 + html += td.format("%d" % num) 3204 3222 num += 1 3205 - if stampcolumns: 3206 - # host name 3223 + # basic info 3224 + for item in ['mode', 'host', 'kernel', 'time']: 3207 3225 val = "unknown" 3208 - if('host' in data.stamp): 3209 - val = data.stamp['host'] 3226 + if(item in data): 3227 + val = data[item] 3210 3228 html += td.format(val) 3211 - # host kernel 3212 - val = "unknown" 3213 - if('kernel' in data.stamp): 3214 - val = data.stamp['kernel'] 3215 - html += td.format(val) 3216 - # suspend mode 3217 - val = "unknown" 3218 - if('mode' in data.stamp): 3219 - val = data.stamp['mode'] 3220 - html += td.format(val) 3221 - # test time 3222 - val = "unknown" 3223 - if('time' in data.stamp): 3224 - val = data.stamp['time'] 3225 - html += td.format(val) 3226 3229 # suspend time 3227 - sTime = (data.tSuspended - data.start)*1000 3230 + sTime = float(data['suspend']) 3228 3231 sTimeAvg += sTime 3229 - html += td.format("%3.3f ms" % sTime) 3232 + html += td.format('%.3f ms' % sTime) 3230 3233 # resume time 3231 - rTime = (resumeEnd - data.tResumed)*1000 3234 + rTime = float(data['resume']) 3232 3235 rTimeAvg += rTime 3233 - html += td.format("%3.3f ms" % rTime) 3236 + html += td.format('%.3f ms' % rTime) 3234 3237 # link to the output html 3235 - html += tdlink.format(data.outfile) 3236 - 3237 - html += '</tr>\n' 3238 - 3239 - # last line: test average 3240 - if(count > 0): 3241 - sTimeAvg /= count 3242 - rTimeAvg /= count 3243 - html += '<tr class="avg">\n' 3244 - html += td.format('Average') # name 3245 - if stampcolumns: 3246 - html += td.format('') # host 3247 - html += td.format('') # kernel 3248 - html += td.format('') # mode 3249 - html += td.format('') # time 3250 - html += td.format("%3.3f ms" % sTimeAvg) # suspend time 3251 - html += td.format("%3.3f ms" % rTimeAvg) # resume time 3252 - html += td.format('') # output link 3253 - html += '</tr>\n' 3238 + html += tdlink.format(data['url']) + '</tr>\n' 3239 + # last test average line 3240 + if(num > 0): 3241 + sTimeAvg /= (num - 1) 3242 + rTimeAvg /= (num - 1) 3243 + html += avg.format('%d' % (num - 1), mode, 3244 + '%3.3f ms' % sTimeAvg, '%3.3f ms' % rTimeAvg) 3254 3245 3255 3246 # flush the data to file 3256 - hf.write(html+'</table>\n') 3257 - hf.write('</body>\n</html>\n') 3247 + hf = open(htmlfile, 'w') 3248 + hf.write(html+'</table>\n</body>\n</html>\n') 3258 3249 hf.close() 3259 - 3260 - def htmlTitle(): 3261 - modename = { 3262 - 'freeze': 'Freeze (S0)', 3263 - 'standby': 'Standby (S1)', 3264 - 'mem': 'Suspend (S3)', 3265 - 'disk': 'Hibernate (S4)' 3266 - } 3267 - kernel = sysvals.stamp['kernel'] 3268 - host = sysvals.hostname[0].upper()+sysvals.hostname[1:] 3269 - mode = sysvals.suspendmode 3270 - if sysvals.suspendmode in modename: 3271 - mode = modename[sysvals.suspendmode] 3272 - return host+' '+mode+' '+kernel 3273 3250 3274 3251 def ordinal(value): 3275 3252 suffix = 'th' ··· 3305 3272 kerror = True 3306 3273 data.normalizeTime(testruns[-1].tSuspended) 3307 3274 3308 - x2changes = ['', 'absolute'] 3309 - if len(testruns) > 1: 3310 - x2changes = ['1', 'relative'] 3311 3275 # html function templates 3312 - headline_version = '<div class="version"><a href="https://01.org/suspendresume">AnalyzeSuspend v%s</a></div>' % sysvals.version 3313 - headline_stamp = '<div class="stamp">{0} {1} {2} {3}</div>\n' 3314 - html_devlist1 = '<button id="devlist1" class="devlist" style="float:left;">Device Detail%s</button>' % x2changes[0] 3315 - html_zoombox = '<center><button id="zoomin">ZOOM IN +</button><button id="zoomout">ZOOM OUT -</button><button id="zoomdef">ZOOM 1:1</button></center>\n' 3316 - html_devlist2 = '<button id="devlist2" class="devlist" style="float:right;">Device Detail2</button>\n' 3317 - html_timeline = '<div id="dmesgzoombox" class="zoombox">\n<div id="{0}" class="timeline" style="height:{1}px">\n' 3318 - html_tblock = '<div id="block{0}" class="tblock" style="left:{1}%;width:{2}%;"><div class="tback" style="height:{3}px"></div>\n' 3319 - html_device = '<div id="{0}" title="{1}" class="thread{7}" style="left:{2}%;top:{3}px;height:{4}px;width:{5}%;{8}">{6}</div>\n' 3320 3276 html_error = '<div id="{1}" title="kernel error/warning" class="err" style="right:{0}%">ERROR&rarr;</div>\n' 3321 3277 html_traceevent = '<div title="{0}" class="traceevent{6}" style="left:{1}%;top:{2}px;height:{3}px;width:{4}%;line-height:{3}px;{7}">{5}</div>\n' 3322 3278 html_cpuexec = '<div class="jiffie" style="left:{0}%;top:{1}px;height:{2}px;width:{3}%;background:{4};"></div>\n' 3323 - html_phase = '<div class="phase" style="left:{0}%;width:{1}%;top:{2}px;height:{3}px;background-color:{4}">{5}</div>\n' 3324 - html_phaselet = '<div id="{0}" class="phaselet" style="left:{1}%;width:{2}%;background:{3}"></div>\n' 3325 - html_legend = '<div id="p{3}" class="square" style="left:{0}%;background-color:{1}">&nbsp;{2}</div>\n' 3279 + html_legend = '<div id="p{3}" class="square" style="left:{0}%;background:{1}">&nbsp;{2}</div>\n' 3326 3280 html_timetotal = '<table class="time1">\n<tr>'\ 3327 3281 '<td class="green" title="{3}">{2} Suspend Time: <b>{0} ms</b></td>'\ 3328 3282 '<td class="yellow" title="{4}">{2} Resume Time: <b>{1} ms</b></td>'\ ··· 3331 3311 '</tr>\n</table>\n' 3332 3312 3333 3313 # html format variables 3334 - hoverZ = 'z-index:8;' 3335 - if sysvals.usedevsrc: 3336 - hoverZ = '' 3337 3314 scaleH = 20 3338 - scaleTH = 20 3339 3315 if kerror: 3340 3316 scaleH = 40 3341 - scaleTH = 60 3342 3317 3343 3318 # device timeline 3344 3319 vprint('Creating Device Timeline...') 3345 3320 3346 3321 devtl = Timeline(30, scaleH) 3322 + 3323 + # write the test title and general info header 3324 + devtl.createHeader(sysvals) 3347 3325 3348 3326 # Generate the header for this timeline 3349 3327 for data in testruns: ··· 3364 3346 if(len(testruns) > 1): 3365 3347 testdesc = ordinal(data.testnumber+1)+' '+testdesc 3366 3348 thtml = html_timetotal3.format(run_time, testdesc) 3367 - devtl.html['header'] += thtml 3349 + devtl.html += thtml 3368 3350 elif data.fwValid: 3369 3351 suspend_time = '%.0f'%(sktime + (data.fwSuspend/1000000.0)) 3370 3352 resume_time = '%.0f'%(rktime + (data.fwResume/1000000.0)) ··· 3381 3363 else: 3382 3364 thtml = html_timetotal2.format(suspend_time, low_time, \ 3383 3365 resume_time, testdesc1, stitle, rtitle) 3384 - devtl.html['header'] += thtml 3366 + devtl.html += thtml 3385 3367 sftime = '%.3f'%(data.fwSuspend / 1000000.0) 3386 3368 rftime = '%.3f'%(data.fwResume / 1000000.0) 3387 - devtl.html['header'] += html_timegroups.format('%.3f'%sktime, \ 3369 + devtl.html += html_timegroups.format('%.3f'%sktime, \ 3388 3370 sftime, rftime, '%.3f'%rktime, testdesc2, sysvals.suspendmode) 3389 3371 else: 3390 3372 suspend_time = '%.3f' % sktime ··· 3400 3382 else: 3401 3383 thtml = html_timetotal2.format(suspend_time, low_time, \ 3402 3384 resume_time, testdesc, stitle, rtitle) 3403 - devtl.html['header'] += thtml 3385 + devtl.html += thtml 3404 3386 3405 3387 # time scale for potentially multiple datasets 3406 3388 t0 = testruns[0].start ··· 3447 3429 devtl.getPhaseRows(threadlist, devtl.rows) 3448 3430 devtl.calcTotalRows() 3449 3431 3450 - # create bounding box, add buttons 3451 - if sysvals.suspendmode != 'command': 3452 - devtl.html['timeline'] += html_devlist1 3453 - if len(testruns) > 1: 3454 - devtl.html['timeline'] += html_devlist2 3455 - devtl.html['timeline'] += html_zoombox 3456 - devtl.html['timeline'] += html_timeline.format('dmesg', devtl.height) 3457 - 3458 3432 # draw the full timeline 3433 + devtl.createZoomBox(sysvals.suspendmode, len(testruns)) 3459 3434 phases = {'suspend':[],'resume':[]} 3460 3435 for phase in data.dmesg: 3461 3436 if 'resume' in phase: ··· 3463 3452 # draw suspend and resume blocks separately 3464 3453 bname = '%s%d' % (dir[0], data.testnumber) 3465 3454 if dir == 'suspend': 3466 - m0 = testruns[data.testnumber].start 3467 - mMax = testruns[data.testnumber].tSuspended 3468 - mTotal = mMax - m0 3455 + m0 = data.start 3456 + mMax = data.tSuspended 3469 3457 left = '%f' % (((m0-t0)*100.0)/tTotal) 3470 3458 else: 3471 - m0 = testruns[data.testnumber].tSuspended 3472 - mMax = testruns[data.testnumber].end 3459 + m0 = data.tSuspended 3460 + mMax = data.end 3473 3461 # in an x2 run, remove any gap between blocks 3474 3462 if len(testruns) > 1 and data.testnumber == 0: 3475 3463 mMax = testruns[1].start 3476 - mTotal = mMax - m0 3477 3464 left = '%f' % ((((m0-t0)*100.0)+sysvals.srgap/2)/tTotal) 3465 + mTotal = mMax - m0 3478 3466 # if a timeline block is 0 length, skip altogether 3479 3467 if mTotal == 0: 3480 3468 continue 3481 3469 width = '%f' % (((mTotal*100.0)-sysvals.srgap/2)/tTotal) 3482 - devtl.html['timeline'] += html_tblock.format(bname, left, width, devtl.scaleH) 3470 + devtl.html += devtl.html_tblock.format(bname, left, width, devtl.scaleH) 3483 3471 for b in sorted(phases[dir]): 3484 3472 # draw the phase color background 3485 3473 phase = data.dmesg[b] 3486 3474 length = phase['end']-phase['start'] 3487 3475 left = '%f' % (((phase['start']-m0)*100.0)/mTotal) 3488 3476 width = '%f' % ((length*100.0)/mTotal) 3489 - devtl.html['timeline'] += html_phase.format(left, width, \ 3477 + devtl.html += devtl.html_phase.format(left, width, \ 3490 3478 '%.3f'%devtl.scaleH, '%.3f'%devtl.bodyH, \ 3491 3479 data.dmesg[b]['color'], '') 3492 3480 for e in data.errorinfo[dir]: 3493 3481 # draw red lines for any kernel errors found 3494 3482 t, err = e 3495 3483 right = '%f' % (((mMax-t)*100.0)/mTotal) 3496 - devtl.html['timeline'] += html_error.format(right, err) 3484 + devtl.html += html_error.format(right, err) 3497 3485 for b in sorted(phases[dir]): 3498 3486 # draw the devices for this phase 3499 3487 phaselist = data.dmesg[b]['list'] ··· 3506 3496 if 'htmlclass' in dev: 3507 3497 xtraclass = dev['htmlclass'] 3508 3498 if 'color' in dev: 3509 - xtrastyle = 'background-color:%s;' % dev['color'] 3499 + xtrastyle = 'background:%s;' % dev['color'] 3510 3500 if(d in sysvals.devprops): 3511 3501 name = sysvals.devprops[d].altName(d) 3512 3502 xtraclass = sysvals.devprops[d].xtraClass() ··· 3531 3521 title += 'post_resume_process' 3532 3522 else: 3533 3523 title += b 3534 - devtl.html['timeline'] += html_device.format(dev['id'], \ 3524 + devtl.html += devtl.html_device.format(dev['id'], \ 3535 3525 title, left, top, '%.3f'%rowheight, width, \ 3536 3526 d+drv, xtraclass, xtrastyle) 3537 3527 if('cpuexec' in dev): ··· 3545 3535 left = '%f' % (((start-m0)*100)/mTotal) 3546 3536 width = '%f' % ((end-start)*100/mTotal) 3547 3537 color = 'rgba(255, 0, 0, %f)' % j 3548 - devtl.html['timeline'] += \ 3538 + devtl.html += \ 3549 3539 html_cpuexec.format(left, top, height, width, color) 3550 3540 if('src' not in dev): 3551 3541 continue ··· 3558 3548 xtrastyle = '' 3559 3549 if e.color: 3560 3550 xtrastyle = 'background:%s;' % e.color 3561 - devtl.html['timeline'] += \ 3551 + devtl.html += \ 3562 3552 html_traceevent.format(e.title(), \ 3563 3553 left, top, height, width, e.text(), '', xtrastyle) 3564 3554 # draw the time scale, try to make the number of labels readable 3565 - devtl.html['timeline'] += devtl.createTimeScale(m0, mMax, tTotal, dir) 3566 - devtl.html['timeline'] += '</div>\n' 3555 + devtl.createTimeScale(m0, mMax, tTotal, dir) 3556 + devtl.html += '</div>\n' 3567 3557 3568 3558 # timeline is finished 3569 - devtl.html['timeline'] += '</div>\n</div>\n' 3559 + devtl.html += '</div>\n</div>\n' 3570 3560 3571 3561 # draw a legend which describes the phases by color 3572 3562 if sysvals.suspendmode != 'command': 3573 3563 data = testruns[-1] 3574 - devtl.html['legend'] = '<div class="legend">\n' 3564 + devtl.html += '<div class="legend">\n' 3575 3565 pdelta = 100.0/len(data.phases) 3576 3566 pmargin = pdelta / 4.0 3577 3567 for phase in data.phases: ··· 3581 3571 id += tmp[1][0] 3582 3572 order = '%.2f' % ((data.dmesg[phase]['order'] * pdelta) + pmargin) 3583 3573 name = string.replace(phase, '_', ' &nbsp;') 3584 - devtl.html['legend'] += html_legend.format(order, \ 3574 + devtl.html += html_legend.format(order, \ 3585 3575 data.dmesg[phase]['color'], name, id) 3586 - devtl.html['legend'] += '</div>\n' 3576 + devtl.html += '</div>\n' 3587 3577 3588 3578 hf = open(sysvals.htmlfile, 'w') 3589 - 3590 - if not sysvals.cgexp: 3591 - cgchk = 'checked' 3592 - cgnchk = 'not(:checked)' 3593 - else: 3594 - cgchk = 'not(:checked)' 3595 - cgnchk = 'checked' 3596 - 3597 - # write the html header first (html head, css code, up to body start) 3598 - html_header = '<!DOCTYPE html>\n<html>\n<head>\n\ 3599 - <meta http-equiv="content-type" content="text/html; charset=UTF-8">\n\ 3600 - <title>'+htmlTitle()+'</title>\n\ 3601 - <style type=\'text/css\'>\n\ 3602 - body {overflow-y:scroll;}\n\ 3603 - .stamp {width:100%;text-align:center;background-color:gray;line-height:30px;color:white;font:25px Arial;}\n\ 3604 - .callgraph {margin-top:30px;box-shadow:5px 5px 20px black;}\n\ 3605 - .callgraph article * {padding-left:28px;}\n\ 3606 - h1 {color:black;font:bold 30px Times;}\n\ 3607 - t0 {color:black;font:bold 30px Times;}\n\ 3608 - t1 {color:black;font:30px Times;}\n\ 3609 - t2 {color:black;font:25px Times;}\n\ 3610 - t3 {color:black;font:20px Times;white-space:nowrap;}\n\ 3611 - t4 {color:black;font:bold 30px Times;line-height:60px;white-space:nowrap;}\n\ 3612 - cS {font:bold 13px Times;}\n\ 3613 - table {width:100%;}\n\ 3614 - .gray {background-color:rgba(80,80,80,0.1);}\n\ 3615 - .green {background-color:rgba(204,255,204,0.4);}\n\ 3616 - .purple {background-color:rgba(128,0,128,0.2);}\n\ 3617 - .yellow {background-color:rgba(255,255,204,0.4);}\n\ 3618 - .time1 {font:22px Arial;border:1px solid;}\n\ 3619 - .time2 {font:15px Arial;border-bottom:1px solid;border-left:1px solid;border-right:1px solid;}\n\ 3620 - td {text-align:center;}\n\ 3621 - r {color:#500000;font:15px Tahoma;}\n\ 3622 - n {color:#505050;font:15px Tahoma;}\n\ 3623 - .tdhl {color:red;}\n\ 3624 - .hide {display:none;}\n\ 3625 - .pf {display:none;}\n\ 3626 - .pf:'+cgchk+' + label {background:url(\'data:image/svg+xml;utf,<?xml version="1.0" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" height="18" width="18" version="1.1"><circle cx="9" cy="9" r="8" stroke="black" stroke-width="1" fill="white"/><rect x="4" y="8" width="10" height="2" style="fill:black;stroke-width:0"/><rect x="8" y="4" width="2" height="10" style="fill:black;stroke-width:0"/></svg>\') no-repeat left center;}\n\ 3627 - .pf:'+cgnchk+' ~ label {background:url(\'data:image/svg+xml;utf,<?xml version="1.0" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" height="18" width="18" version="1.1"><circle cx="9" cy="9" r="8" stroke="black" stroke-width="1" fill="white"/><rect x="4" y="8" width="10" height="2" style="fill:black;stroke-width:0"/></svg>\') no-repeat left center;}\n\ 3628 - .pf:'+cgchk+' ~ *:not(:nth-child(2)) {display:none;}\n\ 3629 - .zoombox {position:relative;width:100%;overflow-x:scroll;-webkit-user-select:none;-moz-user-select:none;user-select:none;}\n\ 3630 - .timeline {position:relative;font-size:14px;cursor:pointer;width:100%; overflow:hidden;background:linear-gradient(#cccccc, white);}\n\ 3631 - .thread {position:absolute;height:0%;overflow:hidden;z-index:7;line-height:30px;font-size:14px;border:1px solid;text-align:center;white-space:nowrap;}\n\ 3632 - .thread.ps {border-radius:3px;background:linear-gradient(to top, #ccc, #eee);}\n\ 3633 - .thread:hover {background-color:white;border:1px solid red;'+hoverZ+'}\n\ 3634 - .thread.sec,.thread.sec:hover {background-color:black;border:0;color:white;line-height:15px;font-size:10px;}\n\ 3635 - .hover {background-color:white;border:1px solid red;'+hoverZ+'}\n\ 3636 - .hover.sync {background-color:white;}\n\ 3637 - .hover.bg,.hover.kth,.hover.sync,.hover.ps {background-color:white;}\n\ 3638 - .jiffie {position:absolute;pointer-events: none;z-index:8;}\n\ 3639 - .traceevent {position:absolute;font-size:10px;z-index:7;overflow:hidden;color:black;text-align:center;white-space:nowrap;border-radius:5px;border:1px solid black;background:linear-gradient(to bottom right,#CCC,#969696);}\n\ 3640 - .traceevent:hover {color:white;font-weight:bold;border:1px solid white;}\n\ 3641 - .phase {position:absolute;overflow:hidden;border:0px;text-align:center;}\n\ 3642 - .phaselet {position:absolute;overflow:hidden;border:0px;text-align:center;height:100px;font-size:24px;}\n\ 3643 - .t {position:absolute;line-height:'+('%d'%scaleTH)+'px;pointer-events:none;top:0;height:100%;border-right:1px solid black;z-index:6;}\n\ 3644 - .err {position:absolute;top:0%;height:100%;border-right:3px solid red;color:red;font:bold 14px Times;line-height:18px;}\n\ 3645 - .legend {position:relative; width:100%; height:40px; text-align:center;margin-bottom:20px}\n\ 3646 - .legend .square {position:absolute;cursor:pointer;top:10px; width:0px;height:20px;border:1px solid;padding-left:20px;}\n\ 3647 - button {height:40px;width:200px;margin-bottom:20px;margin-top:20px;font-size:24px;}\n\ 3648 - .logbtn {position:relative;float:right;height:25px;width:50px;margin-top:3px;margin-bottom:0;font-size:10px;text-align:center;}\n\ 3649 - .devlist {position:'+x2changes[1]+';width:190px;}\n\ 3650 - a:link {color:white;text-decoration:none;}\n\ 3651 - a:visited {color:white;}\n\ 3652 - a:hover {color:white;}\n\ 3653 - a:active {color:white;}\n\ 3654 - .version {position:relative;float:left;color:white;font-size:10px;line-height:30px;margin-left:10px;}\n\ 3655 - #devicedetail {height:100px;box-shadow:5px 5px 20px black;}\n\ 3656 - .tblock {position:absolute;height:100%;background-color:#ddd;}\n\ 3657 - .tback {position:absolute;width:100%;background:linear-gradient(#ccc, #ddd);}\n\ 3658 - .bg {z-index:1;}\n\ 3659 - </style>\n</head>\n<body>\n' 3660 3579 3661 3580 # no header or css if its embedded 3662 3581 if(sysvals.embedded): ··· 3593 3654 (data.tSuspended-data.start, data.end-data.tSuspended, data.tLow, data.fwValid, \ 3594 3655 data.fwSuspend/1000000, data.fwResume/1000000)) 3595 3656 else: 3596 - hf.write(html_header) 3597 - 3598 - # write the test title and general info header 3599 - if(sysvals.stamp['time'] != ""): 3600 - hf.write(headline_version) 3601 - if sysvals.logmsg: 3602 - hf.write('<button id="showtest" class="logbtn">log</button>') 3603 - if sysvals.addlogs and sysvals.dmesgfile: 3604 - hf.write('<button id="showdmesg" class="logbtn">dmesg</button>') 3605 - if sysvals.addlogs and sysvals.ftracefile: 3606 - hf.write('<button id="showftrace" class="logbtn">ftrace</button>') 3607 - hf.write(headline_stamp.format(sysvals.stamp['host'], 3608 - sysvals.stamp['kernel'], sysvals.stamp['mode'], \ 3609 - sysvals.stamp['time'])) 3657 + addCSS(hf, sysvals, len(testruns), kerror) 3610 3658 3611 3659 # write the device timeline 3612 - hf.write(devtl.html['header']) 3613 - hf.write(devtl.html['timeline']) 3614 - hf.write(devtl.html['legend']) 3660 + hf.write(devtl.html) 3615 3661 hf.write('<div id="devicedetailtitle"></div>\n') 3616 3662 hf.write('<div id="devicedetail" style="display:none;">\n') 3617 3663 # draw the colored boxes for the device detail section 3618 3664 for data in testruns: 3619 3665 hf.write('<div id="devicedetail%d">\n' % data.testnumber) 3620 3666 pscolor = 'linear-gradient(to top left, #ccc, #eee)' 3621 - hf.write(html_phaselet.format('pre_suspend_process', \ 3667 + hf.write(devtl.html_phaselet.format('pre_suspend_process', \ 3622 3668 '0', '0', pscolor)) 3623 3669 for b in data.phases: 3624 3670 phase = data.dmesg[b] 3625 3671 length = phase['end']-phase['start'] 3626 3672 left = '%.3f' % (((phase['start']-t0)*100.0)/tTotal) 3627 3673 width = '%.3f' % ((length*100.0)/tTotal) 3628 - hf.write(html_phaselet.format(b, left, width, \ 3674 + hf.write(devtl.html_phaselet.format(b, left, width, \ 3629 3675 data.dmesg[b]['color'])) 3630 - hf.write(html_phaselet.format('post_resume_process', \ 3676 + hf.write(devtl.html_phaselet.format('post_resume_process', \ 3631 3677 '0', '0', pscolor)) 3632 3678 if sysvals.suspendmode == 'command': 3633 - hf.write(html_phaselet.format('cmdexec', '0', '0', pscolor)) 3679 + hf.write(devtl.html_phaselet.format('cmdexec', '0', '0', pscolor)) 3634 3680 hf.write('</div>\n') 3635 3681 hf.write('</div>\n') 3636 3682 ··· 3625 3701 else: 3626 3702 data = testruns[-1] 3627 3703 if(sysvals.usecallgraph and not sysvals.embedded): 3628 - hf.write('<section id="callgraphs" class="callgraph">\n') 3629 - # write out the ftrace data converted to html 3630 - html_func_top = '<article id="{0}" class="atop" style="background-color:{1}">\n<input type="checkbox" class="pf" id="f{2}" checked/><label for="f{2}">{3} {4}</label>\n' 3631 - html_func_start = '<article>\n<input type="checkbox" class="pf" id="f{0}" checked/><label for="f{0}">{1} {2}</label>\n' 3632 - html_func_end = '</article>\n' 3633 - html_func_leaf = '<article>{0} {1}</article>\n' 3634 - num = 0 3635 - for p in data.phases: 3636 - if sysvals.cgphase and p != sysvals.cgphase: 3637 - continue 3638 - list = data.dmesg[p]['list'] 3639 - for devname in data.sortedDevices(p): 3640 - if('ftrace' not in list[devname]): 3641 - continue 3642 - devid = list[devname]['id'] 3643 - cg = list[devname]['ftrace'] 3644 - clen = (cg.end - cg.start) * 1000 3645 - if clen < sysvals.mincglen: 3646 - continue 3647 - fmt = '<r>(%.3f ms @ '+sysvals.timeformat+' to '+sysvals.timeformat+')</r>' 3648 - flen = fmt % (clen, cg.start, cg.end) 3649 - name = devname 3650 - if(devname in sysvals.devprops): 3651 - name = sysvals.devprops[devname].altName(devname) 3652 - if sysvals.suspendmode == 'command': 3653 - ftitle = name 3654 - else: 3655 - ftitle = name+' '+p 3656 - hf.write(html_func_top.format(devid, data.dmesg[p]['color'], \ 3657 - num, ftitle, flen)) 3658 - num += 1 3659 - for line in cg.list: 3660 - if(line.length < 0.000000001): 3661 - flen = '' 3662 - else: 3663 - fmt = '<n>(%.3f ms @ '+sysvals.timeformat+')</n>' 3664 - flen = fmt % (line.length*1000, line.time) 3665 - if(line.freturn and line.fcall): 3666 - hf.write(html_func_leaf.format(line.name, flen)) 3667 - elif(line.freturn): 3668 - hf.write(html_func_end) 3669 - else: 3670 - hf.write(html_func_start.format(num, line.name, flen)) 3671 - num += 1 3672 - hf.write(html_func_end) 3673 - hf.write('\n\n </section>\n') 3704 + addCallgraphs(sysvals, hf, data) 3674 3705 3675 3706 # add the test log as a hidden div 3676 3707 if sysvals.logmsg: ··· 3667 3788 hf.close() 3668 3789 return True 3669 3790 3791 + def addCSS(hf, sv, testcount=1, kerror=False, extra=''): 3792 + kernel = sv.stamp['kernel'] 3793 + host = sv.hostname[0].upper()+sv.hostname[1:] 3794 + mode = sv.suspendmode 3795 + if sv.suspendmode in suspendmodename: 3796 + mode = suspendmodename[sv.suspendmode] 3797 + title = host+' '+mode+' '+kernel 3798 + 3799 + # various format changes by flags 3800 + cgchk = 'checked' 3801 + cgnchk = 'not(:checked)' 3802 + if sv.cgexp: 3803 + cgchk = 'not(:checked)' 3804 + cgnchk = 'checked' 3805 + 3806 + hoverZ = 'z-index:8;' 3807 + if sv.usedevsrc: 3808 + hoverZ = '' 3809 + 3810 + devlistpos = 'absolute' 3811 + if testcount > 1: 3812 + devlistpos = 'relative' 3813 + 3814 + scaleTH = 20 3815 + if kerror: 3816 + scaleTH = 60 3817 + 3818 + # write the html header first (html head, css code, up to body start) 3819 + html_header = '<!DOCTYPE html>\n<html>\n<head>\n\ 3820 + <meta http-equiv="content-type" content="text/html; charset=UTF-8">\n\ 3821 + <title>'+title+'</title>\n\ 3822 + <style type=\'text/css\'>\n\ 3823 + body {overflow-y:scroll;}\n\ 3824 + .stamp {width:100%;text-align:center;background:gray;line-height:30px;color:white;font:25px Arial;}\n\ 3825 + .callgraph {margin-top:30px;box-shadow:5px 5px 20px black;}\n\ 3826 + .callgraph article * {padding-left:28px;}\n\ 3827 + h1 {color:black;font:bold 30px Times;}\n\ 3828 + t0 {color:black;font:bold 30px Times;}\n\ 3829 + t1 {color:black;font:30px Times;}\n\ 3830 + t2 {color:black;font:25px Times;}\n\ 3831 + t3 {color:black;font:20px Times;white-space:nowrap;}\n\ 3832 + t4 {color:black;font:bold 30px Times;line-height:60px;white-space:nowrap;}\n\ 3833 + cS {font:bold 13px Times;}\n\ 3834 + table {width:100%;}\n\ 3835 + .gray {background:rgba(80,80,80,0.1);}\n\ 3836 + .green {background:rgba(204,255,204,0.4);}\n\ 3837 + .purple {background:rgba(128,0,128,0.2);}\n\ 3838 + .yellow {background:rgba(255,255,204,0.4);}\n\ 3839 + .blue {background:rgba(169,208,245,0.4);}\n\ 3840 + .time1 {font:22px Arial;border:1px solid;}\n\ 3841 + .time2 {font:15px Arial;border-bottom:1px solid;border-left:1px solid;border-right:1px solid;}\n\ 3842 + td {text-align:center;}\n\ 3843 + r {color:#500000;font:15px Tahoma;}\n\ 3844 + n {color:#505050;font:15px Tahoma;}\n\ 3845 + .tdhl {color:red;}\n\ 3846 + .hide {display:none;}\n\ 3847 + .pf {display:none;}\n\ 3848 + .pf:'+cgchk+' + label {background:url(\'data:image/svg+xml;utf,<?xml version="1.0" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" height="18" width="18" version="1.1"><circle cx="9" cy="9" r="8" stroke="black" stroke-width="1" fill="white"/><rect x="4" y="8" width="10" height="2" style="fill:black;stroke-width:0"/><rect x="8" y="4" width="2" height="10" style="fill:black;stroke-width:0"/></svg>\') no-repeat left center;}\n\ 3849 + .pf:'+cgnchk+' ~ label {background:url(\'data:image/svg+xml;utf,<?xml version="1.0" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" height="18" width="18" version="1.1"><circle cx="9" cy="9" r="8" stroke="black" stroke-width="1" fill="white"/><rect x="4" y="8" width="10" height="2" style="fill:black;stroke-width:0"/></svg>\') no-repeat left center;}\n\ 3850 + .pf:'+cgchk+' ~ *:not(:nth-child(2)) {display:none;}\n\ 3851 + .zoombox {position:relative;width:100%;overflow-x:scroll;-webkit-user-select:none;-moz-user-select:none;user-select:none;}\n\ 3852 + .timeline {position:relative;font-size:14px;cursor:pointer;width:100%; overflow:hidden;background:linear-gradient(#cccccc, white);}\n\ 3853 + .thread {position:absolute;height:0%;overflow:hidden;z-index:7;line-height:30px;font-size:14px;border:1px solid;text-align:center;white-space:nowrap;}\n\ 3854 + .thread.ps {border-radius:3px;background:linear-gradient(to top, #ccc, #eee);}\n\ 3855 + .thread:hover {background:white;border:1px solid red;'+hoverZ+'}\n\ 3856 + .thread.sec,.thread.sec:hover {background:black;border:0;color:white;line-height:15px;font-size:10px;}\n\ 3857 + .hover {background:white;border:1px solid red;'+hoverZ+'}\n\ 3858 + .hover.sync {background:white;}\n\ 3859 + .hover.bg,.hover.kth,.hover.sync,.hover.ps {background:white;}\n\ 3860 + .jiffie {position:absolute;pointer-events: none;z-index:8;}\n\ 3861 + .traceevent {position:absolute;font-size:10px;z-index:7;overflow:hidden;color:black;text-align:center;white-space:nowrap;border-radius:5px;border:1px solid black;background:linear-gradient(to bottom right,#CCC,#969696);}\n\ 3862 + .traceevent:hover {color:white;font-weight:bold;border:1px solid white;}\n\ 3863 + .phase {position:absolute;overflow:hidden;border:0px;text-align:center;}\n\ 3864 + .phaselet {float:left;overflow:hidden;border:0px;text-align:center;min-height:100px;font-size:24px;}\n\ 3865 + .t {position:absolute;line-height:'+('%d'%scaleTH)+'px;pointer-events:none;top:0;height:100%;border-right:1px solid black;z-index:6;}\n\ 3866 + .err {position:absolute;top:0%;height:100%;border-right:3px solid red;color:red;font:bold 14px Times;line-height:18px;}\n\ 3867 + .legend {position:relative; width:100%; height:40px; text-align:center;margin-bottom:20px}\n\ 3868 + .legend .square {position:absolute;cursor:pointer;top:10px; width:0px;height:20px;border:1px solid;padding-left:20px;}\n\ 3869 + button {height:40px;width:200px;margin-bottom:20px;margin-top:20px;font-size:24px;}\n\ 3870 + .logbtn {position:relative;float:right;height:25px;width:50px;margin-top:3px;margin-bottom:0;font-size:10px;text-align:center;}\n\ 3871 + .devlist {position:'+devlistpos+';width:190px;}\n\ 3872 + a:link {color:white;text-decoration:none;}\n\ 3873 + a:visited {color:white;}\n\ 3874 + a:hover {color:white;}\n\ 3875 + a:active {color:white;}\n\ 3876 + .version {position:relative;float:left;color:white;font-size:10px;line-height:30px;margin-left:10px;}\n\ 3877 + #devicedetail {min-height:100px;box-shadow:5px 5px 20px black;}\n\ 3878 + .tblock {position:absolute;height:100%;background:#ddd;}\n\ 3879 + .tback {position:absolute;width:100%;background:linear-gradient(#ccc, #ddd);}\n\ 3880 + .bg {z-index:1;}\n\ 3881 + '+extra+'\ 3882 + </style>\n</head>\n<body>\n' 3883 + hf.write(html_header) 3884 + 3670 3885 # Function: addScriptCode 3671 3886 # Description: 3672 3887 # Adds the javascript code to the output html ··· 3782 3809 ' var resolution = -1;\n'\ 3783 3810 ' var dragval = [0, 0];\n'\ 3784 3811 ' function redrawTimescale(t0, tMax, tS) {\n'\ 3785 - ' var rline = \'<div class="t" style="left:0;border-left:1px solid black;border-right:0;"><cS>&larr;R</cS></div>\';\n'\ 3812 + ' var rline = \'<div class="t" style="left:0;border-left:1px solid black;border-right:0;">\';\n'\ 3786 3813 ' var tTotal = tMax - t0;\n'\ 3787 3814 ' var list = document.getElementsByClassName("tblock");\n'\ 3788 3815 ' for (var i = 0; i < list.length; i++) {\n'\ ··· 3797 3824 ' var pos = 0.0, val = 0.0;\n'\ 3798 3825 ' for (var j = 0; j < divTotal; j++) {\n'\ 3799 3826 ' var htmlline = "";\n'\ 3800 - ' if(list[i].id[5] == "r") {\n'\ 3801 - ' pos = 100 - (((j)*tS*100)/mTotal);\n'\ 3802 - ' val = (j)*tS;\n'\ 3803 - ' htmlline = \'<div class="t" style="right:\'+pos+\'%">\'+val+\'ms</div>\';\n'\ 3804 - ' if(j == 0)\n'\ 3805 - ' htmlline = rline;\n'\ 3806 - ' } else {\n'\ 3827 + ' var mode = list[i].id[5];\n'\ 3828 + ' if(mode == "s") {\n'\ 3807 3829 ' pos = 100 - (((j)*tS*100)/mTotal) - divEdge;\n'\ 3808 3830 ' val = (j-divTotal+1)*tS;\n'\ 3809 3831 ' if(j == divTotal - 1)\n'\ 3810 3832 ' htmlline = \'<div class="t" style="right:\'+pos+\'%"><cS>S&rarr;</cS></div>\';\n'\ 3811 3833 ' else\n'\ 3812 3834 ' htmlline = \'<div class="t" style="right:\'+pos+\'%">\'+val+\'ms</div>\';\n'\ 3835 + ' } else {\n'\ 3836 + ' pos = 100 - (((j)*tS*100)/mTotal);\n'\ 3837 + ' val = (j)*tS;\n'\ 3838 + ' htmlline = \'<div class="t" style="right:\'+pos+\'%">\'+val+\'ms</div>\';\n'\ 3839 + ' if(j == 0)\n'\ 3840 + ' if(mode == "r")\n'\ 3841 + ' htmlline = rline+"<cS>&larr;R</cS></div>";\n'\ 3842 + ' else\n'\ 3843 + ' htmlline = rline+"<cS>0ms</div>";\n'\ 3813 3844 ' }\n'\ 3814 3845 ' html += htmlline;\n'\ 3815 3846 ' }\n'\ ··· 3979 4002 ' }\n'\ 3980 4003 ' }\n'\ 3981 4004 ' }\n'\ 4005 + ' if(typeof devstats !== \'undefined\')\n'\ 4006 + ' callDetail(this.id, this.title);\n'\ 3982 4007 ' var cglist = document.getElementById("callgraphs");\n'\ 3983 4008 ' if(!cglist) return;\n'\ 3984 4009 ' var cg = cglist.getElementsByClassName("atop");\n'\ 3985 4010 ' if(cg.length < 10) return;\n'\ 3986 4011 ' for (var i = 0; i < cg.length; i++) {\n'\ 3987 - ' if(idlist.indexOf(cg[i].id) >= 0) {\n'\ 4012 + ' cgid = cg[i].id.split("x")[0]\n'\ 4013 + ' if(idlist.indexOf(cgid) >= 0) {\n'\ 4014 + ' cg[i].style.display = "block";\n'\ 4015 + ' } else {\n'\ 4016 + ' cg[i].style.display = "none";\n'\ 4017 + ' }\n'\ 4018 + ' }\n'\ 4019 + ' }\n'\ 4020 + ' function callDetail(devid, devtitle) {\n'\ 4021 + ' if(!(devid in devstats) || devstats[devid].length < 1)\n'\ 4022 + ' return;\n'\ 4023 + ' var list = devstats[devid];\n'\ 4024 + ' var tmp = devtitle.split(" ");\n'\ 4025 + ' var name = tmp[0], phase = tmp[tmp.length-1];\n'\ 4026 + ' var dd = document.getElementById(phase);\n'\ 4027 + ' var total = parseFloat(tmp[1].slice(1));\n'\ 4028 + ' var mlist = [];\n'\ 4029 + ' var maxlen = 0;\n'\ 4030 + ' var info = []\n'\ 4031 + ' for(var i in list) {\n'\ 4032 + ' if(list[i][0] == "@") {\n'\ 4033 + ' info = list[i].split("|");\n'\ 4034 + ' continue;\n'\ 4035 + ' }\n'\ 4036 + ' var tmp = list[i].split("|");\n'\ 4037 + ' var t = parseFloat(tmp[0]), f = tmp[1], c = parseInt(tmp[2]);\n'\ 4038 + ' var p = (t*100.0/total).toFixed(2);\n'\ 4039 + ' mlist[mlist.length] = [f, c, t.toFixed(2), p+"%"];\n'\ 4040 + ' if(f.length > maxlen)\n'\ 4041 + ' maxlen = f.length;\n'\ 4042 + ' }\n'\ 4043 + ' var pad = 5;\n'\ 4044 + ' if(mlist.length == 0) pad = 30;\n'\ 4045 + ' var html = \'<div style="padding-top:\'+pad+\'px"><t3> <b>\'+name+\':</b>\';\n'\ 4046 + ' if(info.length > 2)\n'\ 4047 + ' html += " start=<b>"+info[1]+"</b>, end=<b>"+info[2]+"</b>";\n'\ 4048 + ' if(info.length > 3)\n'\ 4049 + ' html += ", length<i>(w/o overhead)</i>=<b>"+info[3]+" ms</b>";\n'\ 4050 + ' if(info.length > 4)\n'\ 4051 + ' html += ", return=<b>"+info[4]+"</b>";\n'\ 4052 + ' html += "</t3></div>";\n'\ 4053 + ' if(mlist.length > 0) {\n'\ 4054 + ' html += \'<table class=fstat style="padding-top:\'+(maxlen*5)+\'px;"><tr><th>Function</th>\';\n'\ 4055 + ' for(var i in mlist)\n'\ 4056 + ' html += "<td class=vt>"+mlist[i][0]+"</td>";\n'\ 4057 + ' html += "</tr><tr><th>Calls</th>";\n'\ 4058 + ' for(var i in mlist)\n'\ 4059 + ' html += "<td>"+mlist[i][1]+"</td>";\n'\ 4060 + ' html += "</tr><tr><th>Time(ms)</th>";\n'\ 4061 + ' for(var i in mlist)\n'\ 4062 + ' html += "<td>"+mlist[i][2]+"</td>";\n'\ 4063 + ' html += "</tr><tr><th>Percent</th>";\n'\ 4064 + ' for(var i in mlist)\n'\ 4065 + ' html += "<td>"+mlist[i][3]+"</td>";\n'\ 4066 + ' html += "</tr></table>";\n'\ 4067 + ' }\n'\ 4068 + ' dd.innerHTML = html;\n'\ 4069 + ' var height = (maxlen*5)+100;\n'\ 4070 + ' dd.style.height = height+"px";\n'\ 4071 + ' document.getElementById("devicedetail").style.height = height+"px";\n'\ 4072 + ' }\n'\ 4073 + ' function callSelect() {\n'\ 4074 + ' var cglist = document.getElementById("callgraphs");\n'\ 4075 + ' if(!cglist) return;\n'\ 4076 + ' var cg = cglist.getElementsByClassName("atop");\n'\ 4077 + ' for (var i = 0; i < cg.length; i++) {\n'\ 4078 + ' if(this.id == cg[i].id) {\n'\ 3988 4079 ' cg[i].style.display = "block";\n'\ 3989 4080 ' } else {\n'\ 3990 4081 ' cg[i].style.display = "none";\n'\ ··· 4138 4093 ' dev[i].onmouseover = deviceHover;\n'\ 4139 4094 ' dev[i].onmouseout = deviceUnhover;\n'\ 4140 4095 ' }\n'\ 4096 + ' var dev = dmesg.getElementsByClassName("srccall");\n'\ 4097 + ' for (var i = 0; i < dev.length; i++)\n'\ 4098 + ' dev[i].onclick = callSelect;\n'\ 4141 4099 ' zoomTimeline();\n'\ 4142 4100 ' });\n'\ 4143 4101 '</script>\n' ··· 4723 4675 if(os.access(sysvals.powerfile, os.W_OK)): 4724 4676 return True 4725 4677 if fatal: 4726 - doError('This command must be run as root') 4678 + doError('This command requires sysfs mount and root access') 4727 4679 return False 4728 4680 4729 4681 # Function: getArgInt ··· 4815 4767 cmd = 'chown -R {0}:{0} {1} > /dev/null 2>&1' 4816 4768 call(cmd.format(os.environ['SUDO_USER'], sysvals.testdir), shell=True) 4817 4769 4770 + def find_in_html(html, strs, div=False): 4771 + for str in strs: 4772 + l = len(str) 4773 + i = html.find(str) 4774 + if i >= 0: 4775 + break 4776 + if i < 0: 4777 + return '' 4778 + if not div: 4779 + return re.search(r'[-+]?\d*\.\d+|\d+', html[i+l:i+l+50]).group() 4780 + n = html[i+l:].find('</div>') 4781 + if n < 0: 4782 + return '' 4783 + return html[i+l:i+l+n] 4784 + 4818 4785 # Function: runSummary 4819 4786 # Description: 4820 4787 # create a summary of tests in a sub-directory 4821 - def runSummary(subdir, output): 4822 - # get a list of ftrace output files 4823 - files = [] 4788 + def runSummary(subdir, local=True): 4789 + inpath = os.path.abspath(subdir) 4790 + outpath = inpath 4791 + if local: 4792 + outpath = os.path.abspath('.') 4793 + print('Generating a summary of folder "%s"' % inpath) 4794 + testruns = [] 4824 4795 for dirname, dirnames, filenames in os.walk(subdir): 4825 4796 for filename in filenames: 4826 - if(re.match('.*_ftrace.txt', filename)): 4827 - files.append("%s/%s" % (dirname, filename)) 4828 - 4829 - # process the files in order and get an array of data objects 4830 - testruns = [] 4831 - for file in sorted(files): 4832 - if output: 4833 - print("Test found in %s" % os.path.dirname(file)) 4834 - sysvals.ftracefile = file 4835 - sysvals.dmesgfile = file.replace('_ftrace.txt', '_dmesg.txt') 4836 - doesTraceLogHaveTraceEvents() 4837 - sysvals.usecallgraph = False 4838 - if not sysvals.usetraceeventsonly: 4839 - if(not os.path.exists(sysvals.dmesgfile)): 4840 - print("Skipping %s: not a valid test input" % file) 4797 + if(not re.match('.*.html', filename)): 4841 4798 continue 4842 - else: 4843 - if output: 4844 - f = os.path.basename(sysvals.ftracefile) 4845 - d = os.path.basename(sysvals.dmesgfile) 4846 - print("\tInput files: %s and %s" % (f, d)) 4847 - testdata = loadKernelLog() 4848 - data = testdata[0] 4849 - parseKernelLog(data) 4850 - testdata = [data] 4851 - appendIncompleteTraceLog(testdata) 4852 - else: 4853 - if output: 4854 - print("\tInput file: %s" % os.path.basename(sysvals.ftracefile)) 4855 - testdata = parseTraceLog() 4856 - data = testdata[0] 4857 - data.normalizeTime(data.tSuspended) 4858 - link = file.replace(subdir+'/', '').replace('_ftrace.txt', '.html') 4859 - data.outfile = link 4860 - testruns.append(data) 4861 - 4862 - createHTMLSummarySimple(testruns, subdir+'/summary.html') 4799 + file = os.path.join(dirname, filename) 4800 + html = open(file, 'r').read(10000) 4801 + suspend = find_in_html(html, 4802 + ['Kernel Suspend: ', 'Kernel Suspend Time: ']) 4803 + resume = find_in_html(html, 4804 + ['Kernel Resume: ', 'Kernel Resume Time: ']) 4805 + line = find_in_html(html, ['<div class="stamp">'], True) 4806 + stmp = line.split() 4807 + if not suspend or not resume or len(stmp) < 4: 4808 + continue 4809 + data = { 4810 + 'host': stmp[0], 4811 + 'kernel': stmp[1], 4812 + 'mode': stmp[2], 4813 + 'time': string.join(stmp[3:], ' '), 4814 + 'suspend': suspend, 4815 + 'resume': resume, 4816 + 'url': os.path.relpath(file, outpath), 4817 + } 4818 + if len(stmp) == 7: 4819 + data['kernel'] = 'unknown' 4820 + data['mode'] = stmp[1] 4821 + data['time'] = string.join(stmp[2:], ' ') 4822 + testruns.append(data) 4823 + outfile = os.path.join(outpath, 'summary.html') 4824 + print('Summary file: %s' % outfile) 4825 + createHTMLSummarySimple(testruns, outfile, inpath) 4863 4826 4864 4827 # Function: checkArgBool 4865 4828 # Description: ··· 4928 4869 sysvals.predelay = getArgInt('-predelay', value, 0, 60000, False) 4929 4870 elif(opt.lower() == 'postdelay'): 4930 4871 sysvals.postdelay = getArgInt('-postdelay', value, 0, 60000, False) 4872 + elif(opt.lower() == 'maxdepth'): 4873 + sysvals.max_graph_depth = getArgInt('-maxdepth', value, 0, 1000, False) 4931 4874 elif(opt.lower() == 'rtcwake'): 4932 - sysvals.rtcwake = True 4933 - sysvals.rtcwaketime = getArgInt('-rtcwake', value, 0, 3600, False) 4875 + if value.lower() == 'off': 4876 + sysvals.rtcwake = False 4877 + else: 4878 + sysvals.rtcwake = True 4879 + sysvals.rtcwaketime = getArgInt('-rtcwake', value, 0, 3600, False) 4934 4880 elif(opt.lower() == 'timeprec'): 4935 4881 sysvals.setPrecision(getArgInt('-timeprec', value, 0, 6, False)) 4936 4882 elif(opt.lower() == 'mindev'): ··· 5033 4969 modes = getModes() 5034 4970 5035 4971 print('') 5036 - print('AnalyzeSuspend v%s' % sysvals.version) 5037 - print('Usage: sudo analyze_suspend.py <options>') 4972 + print('%s v%s' % (sysvals.title, sysvals.version)) 4973 + print('Usage: sudo sleepgraph <options> <commands>') 5038 4974 print('') 5039 4975 print('Description:') 5040 4976 print(' This tool is designed to assist kernel and OS developers in optimizing') ··· 5045 4981 print(' a detailed view of which devices/subsystems are taking the most') 5046 4982 print(' time in suspend/resume.') 5047 4983 print('') 4984 + print(' If no specific command is given, the default behavior is to initiate') 4985 + print(' a suspend/resume and capture the dmesg/ftrace output as an html timeline.') 4986 + print('') 5048 4987 print(' Generates output files in subdirectory: suspend-mmddyy-HHMMSS') 5049 4988 print(' HTML output: <hostname>_<mode>.html') 5050 4989 print(' raw dmesg output: <hostname>_<mode>_dmesg.txt') 5051 4990 print(' raw ftrace output: <hostname>_<mode>_ftrace.txt') 5052 4991 print('') 5053 4992 print('Options:') 5054 - print(' [general]') 5055 4993 print(' -h Print this help text') 5056 4994 print(' -v Print the current tool version') 5057 4995 print(' -config fn Pull arguments and config options from file fn') 5058 4996 print(' -verbose Print extra information during execution and analysis') 5059 - print(' -status Test to see if the system is enabled to run this tool') 5060 - print(' -modes List available suspend modes') 5061 4997 print(' -m mode Mode to initiate for suspend %s (default: %s)') % (modes, sysvals.suspendmode) 5062 4998 print(' -o subdir Override the output subdirectory') 5063 - print(' -rtcwake t Use rtcwake to autoresume after <t> seconds (default: disabled)') 4999 + print(' -rtcwake t Wakeup t seconds after suspend, set t to "off" to disable (default: 15)') 5064 5000 print(' -addlogs Add the dmesg and ftrace logs to the html output') 5065 5001 print(' -srgap Add a visible gap in the timeline between sus/res (default: disabled)') 5066 5002 print(' [advanced]') ··· 5076 5012 print(' be created in a new subdirectory with a summary page.') 5077 5013 print(' [debug]') 5078 5014 print(' -f Use ftrace to create device callgraphs (default: disabled)') 5015 + print(' -maxdepth N limit the callgraph data to N call levels (default: 0=all)') 5079 5016 print(' -expandcg pre-expand the callgraph data in the html output (default: disabled)') 5080 - print(' -flist Print the list of functions currently being captured in ftrace') 5081 - print(' -flistall Print all functions capable of being captured in ftrace') 5082 5017 print(' -fadd file Add functions to be graphed in the timeline from a list in a text file') 5083 5018 print(' -filter "d1,d2,..." Filter out all but this comma-delimited list of device names') 5084 5019 print(' -mincg ms Discard all callgraphs shorter than ms milliseconds (e.g. 0.001 for us)') 5085 5020 print(' -cgphase P Only show callgraph data for phase P (e.g. suspend_late)') 5086 5021 print(' -cgtest N Only show callgraph data for test N (e.g. 0 or 1 in an x2 run)') 5087 5022 print(' -timeprec N Number of significant digits in timestamps (0:S, [3:ms], 6:us)') 5088 - print(' [utilities]') 5023 + print(' [commands]') 5024 + print(' -ftrace ftracefile Create HTML output using ftrace input (used with -dmesg)') 5025 + print(' -dmesg dmesgfile Create HTML output using dmesg (used with -ftrace)') 5026 + print(' -summary directory Create a summary of all test in this dir') 5027 + print(' -modes List available suspend modes') 5028 + print(' -status Test to see if the system is enabled to run this tool') 5089 5029 print(' -fpdt Print out the contents of the ACPI Firmware Performance Data Table') 5090 5030 print(' -usbtopo Print out the current USB topology with power info') 5091 5031 print(' -usbauto Enable autosuspend for all connected USB devices') 5092 - print(' [re-analyze data from previous runs]') 5093 - print(' -ftrace ftracefile Create HTML output using ftrace input') 5094 - print(' -dmesg dmesgfile Create HTML output using dmesg (not needed for kernel >= 3.15)') 5095 - print(' -summary directory Create a summary of all test in this dir') 5032 + print(' -flist Print the list of functions currently being captured in ftrace') 5033 + print(' -flistall Print all functions capable of being captured in ftrace') 5096 5034 print('') 5097 5035 return True 5098 5036 ··· 5142 5076 sysvals.useprocmon = True 5143 5077 elif(arg == '-dev'): 5144 5078 sysvals.usedevsrc = True 5079 + elif(arg == '-maxdepth'): 5080 + sysvals.max_graph_depth = getArgInt('-maxdepth', args, 0, 1000) 5145 5081 elif(arg == '-rtcwake'): 5146 - sysvals.rtcwake = True 5147 - sysvals.rtcwaketime = getArgInt('-rtcwake', args, 0, 3600) 5082 + try: 5083 + val = args.next() 5084 + except: 5085 + doError('No rtcwake time supplied', True) 5086 + if val.lower() == 'off': 5087 + sysvals.rtcwake = False 5088 + else: 5089 + sysvals.rtcwake = True 5090 + sysvals.rtcwaketime = getArgInt('-rtcwake', val, 0, 3600, False) 5148 5091 elif(arg == '-timeprec'): 5149 5092 sysvals.setPrecision(getArgInt('-timeprec', args, 0, 6)) 5150 5093 elif(arg == '-mindev'): ··· 5276 5201 elif(cmd == 'usbauto'): 5277 5202 setUSBDevicesAuto() 5278 5203 elif(cmd == 'summary'): 5279 - print("Generating a summary of folder \"%s\"" % cmdarg) 5280 5204 runSummary(cmdarg, True) 5281 5205 sys.exit() 5282 5206
+28
tools/power/pm-graph/Makefile
··· 1 + PREFIX ?= /usr 2 + DESTDIR ?= 3 + 4 + all: 5 + @echo "Nothing to build" 6 + 7 + install : 8 + install -d $(DESTDIR)$(PREFIX)/lib/pm-graph 9 + install analyze_suspend.py $(DESTDIR)$(PREFIX)/lib/pm-graph 10 + install analyze_boot.py $(DESTDIR)$(PREFIX)/lib/pm-graph 11 + 12 + ln -s $(DESTDIR)$(PREFIX)/lib/pm-graph/analyze_boot.py $(DESTDIR)$(PREFIX)/bin/bootgraph 13 + ln -s $(DESTDIR)$(PREFIX)/lib/pm-graph/analyze_suspend.py $(DESTDIR)$(PREFIX)/bin/sleepgraph 14 + 15 + install -d $(DESTDIR)$(PREFIX)/share/man/man8 16 + install bootgraph.8 $(DESTDIR)$(PREFIX)/share/man/man8 17 + install sleepgraph.8 $(DESTDIR)$(PREFIX)/share/man/man8 18 + 19 + uninstall : 20 + rm $(DESTDIR)$(PREFIX)/share/man/man8/bootgraph.8 21 + rm $(DESTDIR)$(PREFIX)/share/man/man8/sleepgraph.8 22 + 23 + rm $(DESTDIR)$(PREFIX)/bin/bootgraph 24 + rm $(DESTDIR)$(PREFIX)/bin/sleepgraph 25 + 26 + rm $(DESTDIR)$(PREFIX)/lib/pm-graph/analyze_boot.py 27 + rm $(DESTDIR)$(PREFIX)/lib/pm-graph/analyze_suspend.py 28 + rmdir $(DESTDIR)$(PREFIX)/lib/pm-graph
+824
tools/power/pm-graph/analyze_boot.py
··· 1 + #!/usr/bin/python 2 + # 3 + # Tool for analyzing boot timing 4 + # Copyright (c) 2013, Intel Corporation. 5 + # 6 + # This program is free software; you can redistribute it and/or modify it 7 + # under the terms and conditions of the GNU General Public License, 8 + # version 2, as published by the Free Software Foundation. 9 + # 10 + # This program is distributed in the hope it will be useful, but WITHOUT 11 + # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 + # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 13 + # more details. 14 + # 15 + # Authors: 16 + # Todd Brandt <todd.e.brandt@linux.intel.com> 17 + # 18 + # Description: 19 + # This tool is designed to assist kernel and OS developers in optimizing 20 + # their linux stack's boot time. It creates an html representation of 21 + # the kernel boot timeline up to the start of the init process. 22 + # 23 + 24 + # ----------------- LIBRARIES -------------------- 25 + 26 + import sys 27 + import time 28 + import os 29 + import string 30 + import re 31 + import platform 32 + import shutil 33 + from datetime import datetime, timedelta 34 + from subprocess import call, Popen, PIPE 35 + import analyze_suspend as aslib 36 + 37 + # ----------------- CLASSES -------------------- 38 + 39 + # Class: SystemValues 40 + # Description: 41 + # A global, single-instance container used to 42 + # store system values and test parameters 43 + class SystemValues(aslib.SystemValues): 44 + title = 'BootGraph' 45 + version = 2.0 46 + hostname = 'localhost' 47 + testtime = '' 48 + kernel = '' 49 + dmesgfile = '' 50 + ftracefile = '' 51 + htmlfile = 'bootgraph.html' 52 + outfile = '' 53 + phoronix = False 54 + addlogs = False 55 + useftrace = False 56 + usedevsrc = True 57 + suspendmode = 'boot' 58 + max_graph_depth = 2 59 + graph_filter = 'do_one_initcall' 60 + reboot = False 61 + manual = False 62 + iscronjob = False 63 + timeformat = '%.6f' 64 + def __init__(self): 65 + if('LOG_FILE' in os.environ and 'TEST_RESULTS_IDENTIFIER' in os.environ): 66 + self.phoronix = True 67 + self.addlogs = True 68 + self.outfile = os.environ['LOG_FILE'] 69 + self.htmlfile = os.environ['LOG_FILE'] 70 + self.hostname = platform.node() 71 + self.testtime = datetime.now().strftime('%Y-%m-%d_%H:%M:%S') 72 + if os.path.exists('/proc/version'): 73 + fp = open('/proc/version', 'r') 74 + val = fp.read().strip() 75 + fp.close() 76 + self.kernel = self.kernelVersion(val) 77 + else: 78 + self.kernel = 'unknown' 79 + def kernelVersion(self, msg): 80 + return msg.split()[2] 81 + def kernelParams(self): 82 + cmdline = 'initcall_debug log_buf_len=32M' 83 + if self.useftrace: 84 + cmdline += ' trace_buf_size=128M trace_clock=global '\ 85 + 'trace_options=nooverwrite,funcgraph-abstime,funcgraph-cpu,'\ 86 + 'funcgraph-duration,funcgraph-proc,funcgraph-tail,'\ 87 + 'nofuncgraph-overhead,context-info,graph-time '\ 88 + 'ftrace=function_graph '\ 89 + 'ftrace_graph_max_depth=%d '\ 90 + 'ftrace_graph_filter=%s' % \ 91 + (self.max_graph_depth, self.graph_filter) 92 + return cmdline 93 + def setGraphFilter(self, val): 94 + fp = open(self.tpath+'available_filter_functions') 95 + master = fp.read().split('\n') 96 + fp.close() 97 + for i in val.split(','): 98 + func = i.strip() 99 + if func not in master: 100 + doError('function "%s" not available for ftrace' % func) 101 + self.graph_filter = val 102 + def cronjobCmdString(self): 103 + cmdline = '%s -cronjob' % os.path.abspath(sys.argv[0]) 104 + args = iter(sys.argv[1:]) 105 + for arg in args: 106 + if arg in ['-h', '-v', '-cronjob', '-reboot']: 107 + continue 108 + elif arg in ['-o', '-dmesg', '-ftrace', '-filter']: 109 + args.next() 110 + continue 111 + cmdline += ' '+arg 112 + if self.graph_filter != 'do_one_initcall': 113 + cmdline += ' -filter "%s"' % self.graph_filter 114 + cmdline += ' -o "%s"' % os.path.abspath(self.htmlfile) 115 + return cmdline 116 + def manualRebootRequired(self): 117 + cmdline = self.kernelParams() 118 + print 'To generate a new timeline manually, follow these steps:\n' 119 + print '1. Add the CMDLINE string to your kernel command line.' 120 + print '2. Reboot the system.' 121 + print '3. After reboot, re-run this tool with the same arguments but no command (w/o -reboot or -manual).\n' 122 + print 'CMDLINE="%s"' % cmdline 123 + sys.exit() 124 + 125 + sysvals = SystemValues() 126 + 127 + # Class: Data 128 + # Description: 129 + # The primary container for test data. 130 + class Data(aslib.Data): 131 + dmesg = {} # root data structure 132 + start = 0.0 # test start 133 + end = 0.0 # test end 134 + dmesgtext = [] # dmesg text file in memory 135 + testnumber = 0 136 + idstr = '' 137 + html_device_id = 0 138 + valid = False 139 + initstart = 0.0 140 + boottime = '' 141 + phases = ['boot'] 142 + do_one_initcall = False 143 + def __init__(self, num): 144 + self.testnumber = num 145 + self.idstr = 'a' 146 + self.dmesgtext = [] 147 + self.dmesg = { 148 + 'boot': {'list': dict(), 'start': -1.0, 'end': -1.0, 'row': 0, 'color': '#dddddd'} 149 + } 150 + def deviceTopology(self): 151 + return '' 152 + def newAction(self, phase, name, start, end, ret, ulen): 153 + # new device callback for a specific phase 154 + self.html_device_id += 1 155 + devid = '%s%d' % (self.idstr, self.html_device_id) 156 + list = self.dmesg[phase]['list'] 157 + length = -1.0 158 + if(start >= 0 and end >= 0): 159 + length = end - start 160 + i = 2 161 + origname = name 162 + while(name in list): 163 + name = '%s[%d]' % (origname, i) 164 + i += 1 165 + list[name] = {'name': name, 'start': start, 'end': end, 166 + 'pid': 0, 'length': length, 'row': 0, 'id': devid, 167 + 'ret': ret, 'ulen': ulen } 168 + return name 169 + def deviceMatch(self, cg): 170 + if cg.end - cg.start == 0: 171 + return True 172 + list = self.dmesg['boot']['list'] 173 + for devname in list: 174 + dev = list[devname] 175 + if cg.name == 'do_one_initcall': 176 + if(cg.start <= dev['start'] and cg.end >= dev['end'] and dev['length'] > 0): 177 + dev['ftrace'] = cg 178 + self.do_one_initcall = True 179 + return True 180 + else: 181 + if(cg.start > dev['start'] and cg.end < dev['end']): 182 + if 'ftraces' not in dev: 183 + dev['ftraces'] = [] 184 + dev['ftraces'].append(cg) 185 + return True 186 + return False 187 + 188 + # ----------------- FUNCTIONS -------------------- 189 + 190 + # Function: loadKernelLog 191 + # Description: 192 + # Load a raw kernel log from dmesg 193 + def loadKernelLog(): 194 + data = Data(0) 195 + data.dmesg['boot']['start'] = data.start = ktime = 0.0 196 + sysvals.stamp = { 197 + 'time': datetime.now().strftime('%B %d %Y, %I:%M:%S %p'), 198 + 'host': sysvals.hostname, 199 + 'mode': 'boot', 'kernel': ''} 200 + 201 + devtemp = dict() 202 + if(sysvals.dmesgfile): 203 + lf = open(sysvals.dmesgfile, 'r') 204 + else: 205 + lf = Popen('dmesg', stdout=PIPE).stdout 206 + for line in lf: 207 + line = line.replace('\r\n', '') 208 + idx = line.find('[') 209 + if idx > 1: 210 + line = line[idx:] 211 + m = re.match('[ \t]*(\[ *)(?P<ktime>[0-9\.]*)(\]) (?P<msg>.*)', line) 212 + if(not m): 213 + continue 214 + ktime = float(m.group('ktime')) 215 + if(ktime > 120): 216 + break 217 + msg = m.group('msg') 218 + data.end = data.initstart = ktime 219 + data.dmesgtext.append(line) 220 + if(ktime == 0.0 and re.match('^Linux version .*', msg)): 221 + if(not sysvals.stamp['kernel']): 222 + sysvals.stamp['kernel'] = sysvals.kernelVersion(msg) 223 + continue 224 + m = re.match('.* setting system clock to (?P<t>.*) UTC.*', msg) 225 + if(m): 226 + bt = datetime.strptime(m.group('t'), '%Y-%m-%d %H:%M:%S') 227 + bt = bt - timedelta(seconds=int(ktime)) 228 + data.boottime = bt.strftime('%Y-%m-%d_%H:%M:%S') 229 + sysvals.stamp['time'] = bt.strftime('%B %d %Y, %I:%M:%S %p') 230 + continue 231 + m = re.match('^calling *(?P<f>.*)\+.*', msg) 232 + if(m): 233 + devtemp[m.group('f')] = ktime 234 + continue 235 + m = re.match('^initcall *(?P<f>.*)\+.* returned (?P<r>.*) after (?P<t>.*) usecs', msg) 236 + if(m): 237 + data.valid = True 238 + f, r, t = m.group('f', 'r', 't') 239 + if(f in devtemp): 240 + data.newAction('boot', f, devtemp[f], ktime, int(r), int(t)) 241 + data.end = ktime 242 + del devtemp[f] 243 + continue 244 + if(re.match('^Freeing unused kernel memory.*', msg)): 245 + break 246 + 247 + data.dmesg['boot']['end'] = data.end 248 + lf.close() 249 + return data 250 + 251 + # Function: loadTraceLog 252 + # Description: 253 + # Check if trace is available and copy to a temp file 254 + def loadTraceLog(data): 255 + # load the data to a temp file if none given 256 + if not sysvals.ftracefile: 257 + lib = aslib.sysvals 258 + aslib.rootCheck(True) 259 + if not lib.verifyFtrace(): 260 + doError('ftrace not available') 261 + if lib.fgetVal('current_tracer').strip() != 'function_graph': 262 + doError('ftrace not configured for a boot callgraph') 263 + sysvals.ftracefile = '/tmp/boot_ftrace.%s.txt' % os.getpid() 264 + call('cat '+lib.tpath+'trace > '+sysvals.ftracefile, shell=True) 265 + if not sysvals.ftracefile: 266 + doError('No trace data available') 267 + 268 + # parse the trace log 269 + ftemp = dict() 270 + tp = aslib.TestProps() 271 + tp.setTracerType('function_graph') 272 + tf = open(sysvals.ftracefile, 'r') 273 + for line in tf: 274 + if line[0] == '#': 275 + continue 276 + m = re.match(tp.ftrace_line_fmt, line.strip()) 277 + if(not m): 278 + continue 279 + m_time, m_proc, m_pid, m_msg, m_dur = \ 280 + m.group('time', 'proc', 'pid', 'msg', 'dur') 281 + if float(m_time) > data.end: 282 + break 283 + if(m_time and m_pid and m_msg): 284 + t = aslib.FTraceLine(m_time, m_msg, m_dur) 285 + pid = int(m_pid) 286 + else: 287 + continue 288 + if t.fevent or t.fkprobe: 289 + continue 290 + key = (m_proc, pid) 291 + if(key not in ftemp): 292 + ftemp[key] = [] 293 + ftemp[key].append(aslib.FTraceCallGraph(pid)) 294 + cg = ftemp[key][-1] 295 + if(cg.addLine(t)): 296 + ftemp[key].append(aslib.FTraceCallGraph(pid)) 297 + tf.close() 298 + 299 + # add the callgraph data to the device hierarchy 300 + for key in ftemp: 301 + proc, pid = key 302 + for cg in ftemp[key]: 303 + if len(cg.list) < 1 or cg.invalid: 304 + continue 305 + if(not cg.postProcess()): 306 + print('Sanity check failed for %s-%d' % (proc, pid)) 307 + continue 308 + # match cg data to devices 309 + if not data.deviceMatch(cg): 310 + print ' BAD: %s %s-%d [%f - %f]' % (cg.name, proc, pid, cg.start, cg.end) 311 + 312 + # Function: colorForName 313 + # Description: 314 + # Generate a repeatable color from a list for a given name 315 + def colorForName(name): 316 + list = [ 317 + ('c1', '#ec9999'), 318 + ('c2', '#ffc1a6'), 319 + ('c3', '#fff0a6'), 320 + ('c4', '#adf199'), 321 + ('c5', '#9fadea'), 322 + ('c6', '#a699c1'), 323 + ('c7', '#ad99b4'), 324 + ('c8', '#eaffea'), 325 + ('c9', '#dcecfb'), 326 + ('c10', '#ffffea') 327 + ] 328 + i = 0 329 + total = 0 330 + count = len(list) 331 + while i < len(name): 332 + total += ord(name[i]) 333 + i += 1 334 + return list[total % count] 335 + 336 + def cgOverview(cg, minlen): 337 + stats = dict() 338 + large = [] 339 + for l in cg.list: 340 + if l.fcall and l.depth == 1: 341 + if l.length >= minlen: 342 + large.append(l) 343 + if l.name not in stats: 344 + stats[l.name] = [0, 0.0] 345 + stats[l.name][0] += (l.length * 1000.0) 346 + stats[l.name][1] += 1 347 + return (large, stats) 348 + 349 + # Function: createBootGraph 350 + # Description: 351 + # Create the output html file from the resident test data 352 + # Arguments: 353 + # testruns: array of Data objects from parseKernelLog or parseTraceLog 354 + # Output: 355 + # True if the html file was created, false if it failed 356 + def createBootGraph(data, embedded): 357 + # html function templates 358 + html_srccall = '<div id={6} title="{5}" class="srccall" style="left:{1}%;top:{2}px;height:{3}px;width:{4}%;line-height:{3}px;">{0}</div>\n' 359 + html_timetotal = '<table class="time1">\n<tr>'\ 360 + '<td class="blue">Time from Kernel Boot to start of User Mode: <b>{0} ms</b></td>'\ 361 + '</tr>\n</table>\n' 362 + 363 + # device timeline 364 + devtl = aslib.Timeline(100, 20) 365 + 366 + # write the test title and general info header 367 + devtl.createHeader(sysvals, 'noftrace') 368 + 369 + # Generate the header for this timeline 370 + t0 = data.start 371 + tMax = data.end 372 + tTotal = tMax - t0 373 + if(tTotal == 0): 374 + print('ERROR: No timeline data') 375 + return False 376 + boot_time = '%.0f'%(tTotal*1000) 377 + devtl.html += html_timetotal.format(boot_time) 378 + 379 + # determine the maximum number of rows we need to draw 380 + phase = 'boot' 381 + list = data.dmesg[phase]['list'] 382 + devlist = [] 383 + for devname in list: 384 + d = aslib.DevItem(0, phase, list[devname]) 385 + devlist.append(d) 386 + devtl.getPhaseRows(devlist) 387 + devtl.calcTotalRows() 388 + 389 + # draw the timeline background 390 + devtl.createZoomBox() 391 + boot = data.dmesg[phase] 392 + length = boot['end']-boot['start'] 393 + left = '%.3f' % (((boot['start']-t0)*100.0)/tTotal) 394 + width = '%.3f' % ((length*100.0)/tTotal) 395 + devtl.html += devtl.html_tblock.format(phase, left, width, devtl.scaleH) 396 + devtl.html += devtl.html_phase.format('0', '100', \ 397 + '%.3f'%devtl.scaleH, '%.3f'%devtl.bodyH, \ 398 + 'white', '') 399 + 400 + # draw the device timeline 401 + num = 0 402 + devstats = dict() 403 + for devname in sorted(list): 404 + cls, color = colorForName(devname) 405 + dev = list[devname] 406 + info = '@|%.3f|%.3f|%.3f|%d' % (dev['start']*1000.0, dev['end']*1000.0, 407 + dev['ulen']/1000.0, dev['ret']) 408 + devstats[dev['id']] = {'info':info} 409 + dev['color'] = color 410 + height = devtl.phaseRowHeight(0, phase, dev['row']) 411 + top = '%.6f' % ((dev['row']*height) + devtl.scaleH) 412 + left = '%.6f' % (((dev['start']-t0)*100)/tTotal) 413 + width = '%.6f' % (((dev['end']-dev['start'])*100)/tTotal) 414 + length = ' (%0.3f ms) ' % ((dev['end']-dev['start'])*1000) 415 + devtl.html += devtl.html_device.format(dev['id'], 416 + devname+length+'kernel_mode', left, top, '%.3f'%height, 417 + width, devname, ' '+cls, '') 418 + rowtop = devtl.phaseRowTop(0, phase, dev['row']) 419 + height = '%.6f' % (devtl.rowH / 2) 420 + top = '%.6f' % (rowtop + devtl.scaleH + (devtl.rowH / 2)) 421 + if data.do_one_initcall: 422 + if('ftrace' not in dev): 423 + continue 424 + cg = dev['ftrace'] 425 + large, stats = cgOverview(cg, 0.001) 426 + devstats[dev['id']]['fstat'] = stats 427 + for l in large: 428 + left = '%f' % (((l.time-t0)*100)/tTotal) 429 + width = '%f' % (l.length*100/tTotal) 430 + title = '%s (%0.3fms)' % (l.name, l.length * 1000.0) 431 + devtl.html += html_srccall.format(l.name, left, 432 + top, height, width, title, 'x%d'%num) 433 + num += 1 434 + continue 435 + if('ftraces' not in dev): 436 + continue 437 + for cg in dev['ftraces']: 438 + left = '%f' % (((cg.start-t0)*100)/tTotal) 439 + width = '%f' % ((cg.end-cg.start)*100/tTotal) 440 + cglen = (cg.end - cg.start) * 1000.0 441 + title = '%s (%0.3fms)' % (cg.name, cglen) 442 + cg.id = 'x%d' % num 443 + devtl.html += html_srccall.format(cg.name, left, 444 + top, height, width, title, dev['id']+cg.id) 445 + num += 1 446 + 447 + # draw the time scale, try to make the number of labels readable 448 + devtl.createTimeScale(t0, tMax, tTotal, phase) 449 + devtl.html += '</div>\n' 450 + 451 + # timeline is finished 452 + devtl.html += '</div>\n</div>\n' 453 + 454 + if(sysvals.outfile == sysvals.htmlfile): 455 + hf = open(sysvals.htmlfile, 'a') 456 + else: 457 + hf = open(sysvals.htmlfile, 'w') 458 + 459 + # add the css if this is not an embedded run 460 + extra = '\ 461 + .c1 {background:rgba(209,0,0,0.4);}\n\ 462 + .c2 {background:rgba(255,102,34,0.4);}\n\ 463 + .c3 {background:rgba(255,218,33,0.4);}\n\ 464 + .c4 {background:rgba(51,221,0,0.4);}\n\ 465 + .c5 {background:rgba(17,51,204,0.4);}\n\ 466 + .c6 {background:rgba(34,0,102,0.4);}\n\ 467 + .c7 {background:rgba(51,0,68,0.4);}\n\ 468 + .c8 {background:rgba(204,255,204,0.4);}\n\ 469 + .c9 {background:rgba(169,208,245,0.4);}\n\ 470 + .c10 {background:rgba(255,255,204,0.4);}\n\ 471 + .vt {transform:rotate(-60deg);transform-origin:0 0;}\n\ 472 + table.fstat {table-layout:fixed;padding:150px 15px 0 0;font-size:10px;column-width:30px;}\n\ 473 + .fstat th {width:55px;}\n\ 474 + .fstat td {text-align:left;width:35px;}\n\ 475 + .srccall {position:absolute;font-size:10px;z-index:7;overflow:hidden;color:black;text-align:center;white-space:nowrap;border-radius:5px;border:1px solid black;background:linear-gradient(to bottom right,#CCC,#969696);}\n\ 476 + .srccall:hover {color:white;font-weight:bold;border:1px solid white;}\n' 477 + if(not embedded): 478 + aslib.addCSS(hf, sysvals, 1, False, extra) 479 + 480 + # write the device timeline 481 + hf.write(devtl.html) 482 + 483 + # add boot specific html 484 + statinfo = 'var devstats = {\n' 485 + for n in sorted(devstats): 486 + statinfo += '\t"%s": [\n\t\t"%s",\n' % (n, devstats[n]['info']) 487 + if 'fstat' in devstats[n]: 488 + funcs = devstats[n]['fstat'] 489 + for f in sorted(funcs, key=funcs.get, reverse=True): 490 + if funcs[f][0] < 0.01 and len(funcs) > 10: 491 + break 492 + statinfo += '\t\t"%f|%s|%d",\n' % (funcs[f][0], f, funcs[f][1]) 493 + statinfo += '\t],\n' 494 + statinfo += '};\n' 495 + html = \ 496 + '<div id="devicedetailtitle"></div>\n'\ 497 + '<div id="devicedetail" style="display:none;">\n'\ 498 + '<div id="devicedetail0">\n'\ 499 + '<div id="kernel_mode" class="phaselet" style="left:0%;width:100%;background:#DDDDDD"></div>\n'\ 500 + '</div>\n</div>\n'\ 501 + '<script type="text/javascript">\n'+statinfo+\ 502 + '</script>\n' 503 + hf.write(html) 504 + 505 + # add the callgraph html 506 + if(sysvals.usecallgraph): 507 + aslib.addCallgraphs(sysvals, hf, data) 508 + 509 + # add the dmesg log as a hidden div 510 + if sysvals.addlogs: 511 + hf.write('<div id="dmesglog" style="display:none;">\n') 512 + for line in data.dmesgtext: 513 + line = line.replace('<', '&lt').replace('>', '&gt') 514 + hf.write(line) 515 + hf.write('</div>\n') 516 + 517 + if(not embedded): 518 + # write the footer and close 519 + aslib.addScriptCode(hf, [data]) 520 + hf.write('</body>\n</html>\n') 521 + else: 522 + # embedded out will be loaded in a page, skip the js 523 + hf.write('<div id=bounds style=display:none>%f,%f</div>' % \ 524 + (data.start*1000, data.initstart*1000)) 525 + hf.close() 526 + return True 527 + 528 + # Function: updateCron 529 + # Description: 530 + # (restore=False) Set the tool to run automatically on reboot 531 + # (restore=True) Restore the original crontab 532 + def updateCron(restore=False): 533 + if not restore: 534 + sysvals.rootUser(True) 535 + crondir = '/var/spool/cron/crontabs/' 536 + cronfile = crondir+'root' 537 + backfile = crondir+'root-analyze_boot-backup' 538 + if not os.path.exists(crondir): 539 + doError('%s not found' % crondir) 540 + out = Popen(['which', 'crontab'], stdout=PIPE).stdout.read() 541 + if not out: 542 + doError('crontab not found') 543 + # on restore: move the backup cron back into place 544 + if restore: 545 + if os.path.exists(backfile): 546 + shutil.move(backfile, cronfile) 547 + return 548 + # backup current cron and install new one with reboot 549 + if os.path.exists(cronfile): 550 + shutil.move(cronfile, backfile) 551 + else: 552 + fp = open(backfile, 'w') 553 + fp.close() 554 + res = -1 555 + try: 556 + fp = open(backfile, 'r') 557 + op = open(cronfile, 'w') 558 + for line in fp: 559 + if '@reboot' not in line: 560 + op.write(line) 561 + continue 562 + fp.close() 563 + op.write('@reboot python %s\n' % sysvals.cronjobCmdString()) 564 + op.close() 565 + res = call('crontab %s' % cronfile, shell=True) 566 + except Exception, e: 567 + print 'Exception: %s' % str(e) 568 + shutil.move(backfile, cronfile) 569 + res = -1 570 + if res != 0: 571 + doError('crontab failed') 572 + 573 + # Function: updateGrub 574 + # Description: 575 + # update grub.cfg for all kernels with our parameters 576 + def updateGrub(restore=False): 577 + # call update-grub on restore 578 + if restore: 579 + try: 580 + call(['update-grub'], stderr=PIPE, stdout=PIPE, 581 + env={'PATH': '.:/sbin:/usr/sbin:/usr/bin:/sbin:/bin'}) 582 + except Exception, e: 583 + print 'Exception: %s\n' % str(e) 584 + return 585 + # verify we can do this 586 + sysvals.rootUser(True) 587 + grubfile = '/etc/default/grub' 588 + if not os.path.exists(grubfile): 589 + print 'ERROR: Unable to set the kernel parameters via grub.\n' 590 + sysvals.manualRebootRequired() 591 + out = Popen(['which', 'update-grub'], stdout=PIPE).stdout.read() 592 + if not out: 593 + print 'ERROR: Unable to set the kernel parameters via grub.\n' 594 + sysvals.manualRebootRequired() 595 + 596 + # extract the option and create a grub config without it 597 + tgtopt = 'GRUB_CMDLINE_LINUX_DEFAULT' 598 + cmdline = '' 599 + tempfile = '/etc/default/grub.analyze_boot' 600 + shutil.move(grubfile, tempfile) 601 + res = -1 602 + try: 603 + fp = open(tempfile, 'r') 604 + op = open(grubfile, 'w') 605 + cont = False 606 + for line in fp: 607 + line = line.strip() 608 + if len(line) == 0 or line[0] == '#': 609 + continue 610 + opt = line.split('=')[0].strip() 611 + if opt == tgtopt: 612 + cmdline = line.split('=', 1)[1].strip('\\') 613 + if line[-1] == '\\': 614 + cont = True 615 + elif cont: 616 + cmdline += line.strip('\\') 617 + if line[-1] != '\\': 618 + cont = False 619 + else: 620 + op.write('%s\n' % line) 621 + fp.close() 622 + # if the target option value is in quotes, strip them 623 + sp = '"' 624 + val = cmdline.strip() 625 + if val[0] == '\'' or val[0] == '"': 626 + sp = val[0] 627 + val = val.strip(sp) 628 + cmdline = val 629 + # append our cmd line options 630 + if len(cmdline) > 0: 631 + cmdline += ' ' 632 + cmdline += sysvals.kernelParams() 633 + # write out the updated target option 634 + op.write('\n%s=%s%s%s\n' % (tgtopt, sp, cmdline, sp)) 635 + op.close() 636 + res = call('update-grub') 637 + os.remove(grubfile) 638 + except Exception, e: 639 + print 'Exception: %s' % str(e) 640 + res = -1 641 + # cleanup 642 + shutil.move(tempfile, grubfile) 643 + if res != 0: 644 + doError('update-grub failed') 645 + 646 + # Function: doError 647 + # Description: 648 + # generic error function for catastrphic failures 649 + # Arguments: 650 + # msg: the error message to print 651 + # help: True if printHelp should be called after, False otherwise 652 + def doError(msg, help=False): 653 + if help == True: 654 + printHelp() 655 + print 'ERROR: %s\n' % msg 656 + sys.exit() 657 + 658 + # Function: printHelp 659 + # Description: 660 + # print out the help text 661 + def printHelp(): 662 + print('') 663 + print('%s v%.1f' % (sysvals.title, sysvals.version)) 664 + print('Usage: bootgraph <options> <command>') 665 + print('') 666 + print('Description:') 667 + print(' This tool reads in a dmesg log of linux kernel boot and') 668 + print(' creates an html representation of the boot timeline up to') 669 + print(' the start of the init process.') 670 + print('') 671 + print(' If no specific command is given the tool reads the current dmesg') 672 + print(' and/or ftrace log and outputs bootgraph.html') 673 + print('') 674 + print('Options:') 675 + print(' -h Print this help text') 676 + print(' -v Print the current tool version') 677 + print(' -addlogs Add the dmesg log to the html output') 678 + print(' -o file Html timeline name (default: bootgraph.html)') 679 + print(' [advanced]') 680 + print(' -f Use ftrace to add function detail (default: disabled)') 681 + print(' -callgraph Add callgraph detail, can be very large (default: disabled)') 682 + print(' -maxdepth N limit the callgraph data to N call levels (default: 2)') 683 + print(' -mincg ms Discard all callgraphs shorter than ms milliseconds (e.g. 0.001 for us)') 684 + print(' -timeprec N Number of significant digits in timestamps (0:S, 3:ms, [6:us])') 685 + print(' -expandcg pre-expand the callgraph data in the html output (default: disabled)') 686 + print(' -filter list Limit ftrace to comma-delimited list of functions (default: do_one_initcall)') 687 + print(' [commands]') 688 + print(' -reboot Reboot the machine automatically and generate a new timeline') 689 + print(' -manual Show the requirements to generate a new timeline manually') 690 + print(' -dmesg file Load a stored dmesg file (used with -ftrace)') 691 + print(' -ftrace file Load a stored ftrace file (used with -dmesg)') 692 + print(' -flistall Print all functions capable of being captured in ftrace') 693 + print('') 694 + return True 695 + 696 + # ----------------- MAIN -------------------- 697 + # exec start (skipped if script is loaded as library) 698 + if __name__ == '__main__': 699 + # loop through the command line arguments 700 + cmd = '' 701 + simplecmds = ['-updategrub', '-flistall'] 702 + args = iter(sys.argv[1:]) 703 + for arg in args: 704 + if(arg == '-h'): 705 + printHelp() 706 + sys.exit() 707 + elif(arg == '-v'): 708 + print("Version %.1f" % sysvals.version) 709 + sys.exit() 710 + elif(arg in simplecmds): 711 + cmd = arg[1:] 712 + elif(arg == '-f'): 713 + sysvals.useftrace = True 714 + elif(arg == '-callgraph'): 715 + sysvals.useftrace = True 716 + sysvals.usecallgraph = True 717 + elif(arg == '-mincg'): 718 + sysvals.mincglen = aslib.getArgFloat('-mincg', args, 0.0, 10000.0) 719 + elif(arg == '-timeprec'): 720 + sysvals.setPrecision(aslib.getArgInt('-timeprec', args, 0, 6)) 721 + elif(arg == '-maxdepth'): 722 + sysvals.max_graph_depth = aslib.getArgInt('-maxdepth', args, 0, 1000) 723 + elif(arg == '-filter'): 724 + try: 725 + val = args.next() 726 + except: 727 + doError('No filter functions supplied', True) 728 + aslib.rootCheck(True) 729 + sysvals.setGraphFilter(val) 730 + elif(arg == '-ftrace'): 731 + try: 732 + val = args.next() 733 + except: 734 + doError('No ftrace file supplied', True) 735 + if(os.path.exists(val) == False): 736 + doError('%s does not exist' % val) 737 + sysvals.ftracefile = val 738 + elif(arg == '-addlogs'): 739 + sysvals.addlogs = True 740 + elif(arg == '-expandcg'): 741 + sysvals.cgexp = True 742 + elif(arg == '-dmesg'): 743 + try: 744 + val = args.next() 745 + except: 746 + doError('No dmesg file supplied', True) 747 + if(os.path.exists(val) == False): 748 + doError('%s does not exist' % val) 749 + if(sysvals.htmlfile == val or sysvals.outfile == val): 750 + doError('Output filename collision') 751 + sysvals.dmesgfile = val 752 + elif(arg == '-o'): 753 + try: 754 + val = args.next() 755 + except: 756 + doError('No HTML filename supplied', True) 757 + if(sysvals.dmesgfile == val or sysvals.ftracefile == val): 758 + doError('Output filename collision') 759 + sysvals.htmlfile = val 760 + elif(arg == '-reboot'): 761 + if sysvals.iscronjob: 762 + doError('-reboot and -cronjob are incompatible') 763 + sysvals.reboot = True 764 + elif(arg == '-manual'): 765 + sysvals.reboot = True 766 + sysvals.manual = True 767 + # remaining options are only for cron job use 768 + elif(arg == '-cronjob'): 769 + sysvals.iscronjob = True 770 + if sysvals.reboot: 771 + doError('-reboot and -cronjob are incompatible') 772 + else: 773 + doError('Invalid argument: '+arg, True) 774 + 775 + if cmd != '': 776 + if cmd == 'updategrub': 777 + updateGrub() 778 + elif cmd == 'flistall': 779 + sysvals.getFtraceFilterFunctions(False) 780 + sys.exit() 781 + 782 + # update grub, setup a cronjob, and reboot 783 + if sysvals.reboot: 784 + if not sysvals.manual: 785 + updateGrub() 786 + updateCron() 787 + call('reboot') 788 + else: 789 + sysvals.manualRebootRequired() 790 + sys.exit() 791 + 792 + # disable the cronjob 793 + if sysvals.iscronjob: 794 + updateCron(True) 795 + updateGrub(True) 796 + 797 + data = loadKernelLog() 798 + if sysvals.useftrace: 799 + loadTraceLog(data) 800 + if sysvals.iscronjob: 801 + try: 802 + sysvals.fsetVal('0', 'tracing_on') 803 + except: 804 + pass 805 + 806 + if(sysvals.outfile and sysvals.phoronix): 807 + fp = open(sysvals.outfile, 'w') 808 + fp.write('pass %s initstart %.3f end %.3f boot %s\n' % 809 + (data.valid, data.initstart*1000, data.end*1000, data.boottime)) 810 + fp.close() 811 + if(not data.valid): 812 + if sysvals.dmesgfile: 813 + doError('No initcall data found in %s' % sysvals.dmesgfile) 814 + else: 815 + doError('No initcall data found, is initcall_debug enabled?') 816 + 817 + print(' Host: %s' % sysvals.hostname) 818 + print(' Test time: %s' % sysvals.testtime) 819 + print(' Boot time: %s' % data.boottime) 820 + print('Kernel Version: %s' % sysvals.kernel) 821 + print(' Kernel start: %.3f' % (data.start * 1000)) 822 + print(' init start: %.3f' % (data.initstart * 1000)) 823 + 824 + createBootGraph(data, sysvals.phoronix)
+132
tools/power/pm-graph/bootgraph.8
··· 1 + .TH BOOTGRAPH 8 2 + .SH NAME 3 + bootgraph \- Kernel boot timing analysis 4 + .SH SYNOPSIS 5 + .ft B 6 + .B bootgraph 7 + .RB [ OPTIONS ] 8 + .RB [ COMMAND ] 9 + .SH DESCRIPTION 10 + \fBbootgraph \fP reads the dmesg log from kernel boot and 11 + creates an html representation of the initcall timeline up to the start 12 + of the init process. 13 + .PP 14 + If no specific command is given, the tool reads the current dmesg log and 15 + outputs bootgraph.html. 16 + .PP 17 + The tool can also augment the timeline with ftrace data on custom target 18 + functions as well as full trace callgraphs. 19 + .SH OPTIONS 20 + .TP 21 + \fB-h\fR 22 + Print this help text 23 + .TP 24 + \fB-v\fR 25 + Print the current tool version 26 + .TP 27 + \fB-addlogs\fR 28 + Add the dmesg log to the html output. It will be viewable by 29 + clicking a button in the timeline. 30 + .TP 31 + \fB-o \fIfile\fR 32 + Override the HTML output filename (default: bootgraph.html) 33 + .SS "Ftrace Debug" 34 + .TP 35 + \fB-f\fR 36 + Use ftrace to add function detail (default: disabled) 37 + .TP 38 + \fB-callgraph\fR 39 + Use ftrace to create initcall callgraphs (default: disabled). If -filter 40 + is not used there will be one callgraph per initcall. This can produce 41 + very large outputs, i.e. 10MB - 100MB. 42 + .TP 43 + \fB-maxdepth \fIlevel\fR 44 + limit the callgraph trace depth to \fIlevel\fR (default: 2). This is 45 + the best way to limit the output size when using -callgraph. 46 + .TP 47 + \fB-mincg \fIt\fR 48 + Discard all callgraphs shorter than \fIt\fR milliseconds (default: 0=all). 49 + This reduces the html file size as there can be many tiny callgraphs 50 + which are barely visible in the timeline. 51 + The value is a float: e.g. 0.001 represents 1 us. 52 + .TP 53 + \fB-timeprec \fIn\fR 54 + Number of significant digits in timestamps (0:S, 3:ms, [6:us]) 55 + .TP 56 + \fB-expandcg\fR 57 + pre-expand the callgraph data in the html output (default: disabled) 58 + .TP 59 + \fB-filter \fI"func1,func2,..."\fR 60 + Instead of tracing each initcall, trace a custom list of functions (default: do_one_initcall) 61 + 62 + .SH COMMANDS 63 + .TP 64 + \fB-reboot\fR 65 + Reboot the machine and generate a new timeline automatically. Works in 4 steps. 66 + 1. updates grub with the required kernel parameters 67 + 2. installs a cron job which re-runs the tool after reboot 68 + 3. reboots the system 69 + 4. after startup, extracts the data and generates the timeline 70 + .TP 71 + \fB-manual\fR 72 + Show the requirements to generate a new timeline manually. Requires 3 steps. 73 + 1. append the string to the kernel command line via your native boot manager. 74 + 2. reboot the system 75 + 3. after startup, re-run the tool with the same arguments and no command 76 + .TP 77 + \fB-dmesg \fIfile\fR 78 + Create HTML output from an existing dmesg file. 79 + .TP 80 + \fB-ftrace \fIfile\fR 81 + Create HTML output from an existing ftrace file (used with -dmesg). 82 + .TP 83 + \fB-flistall\fR 84 + Print all ftrace functions capable of being captured. These are all the 85 + possible values you can add to trace via the -filter argument. 86 + 87 + .SH EXAMPLES 88 + Create a timeline using the current dmesg log. 89 + .IP 90 + \f(CW$ bootgraph\fR 91 + .PP 92 + Create a timeline using the current dmesg and ftrace log. 93 + .IP 94 + \f(CW$ bootgraph -callgraph\fR 95 + .PP 96 + Create a timeline using the current dmesg, add the log to the html and change the name. 97 + .IP 98 + \f(CW$ bootgraph -addlogs -o myboot.html\fR 99 + .PP 100 + Capture a new boot timeline by automatically rebooting the machine. 101 + .IP 102 + \f(CW$ sudo bootgraph -reboot -addlogs -o latestboot.html\fR 103 + .PP 104 + Capture a new boot timeline with function trace data. 105 + .IP 106 + \f(CW$ sudo bootgraph -reboot -f\fR 107 + .PP 108 + Capture a new boot timeline with trace & callgraph data. Skip callgraphs smaller than 5ms. 109 + .IP 110 + \f(CW$ sudo bootgraph -reboot -callgraph -mincg 5\fR 111 + .PP 112 + Capture a new boot timeline with callgraph data over custom functions. 113 + .IP 114 + \f(CW$ sudo bootgraph -reboot -callgraph -filter "acpi_ps_parse_aml,msleep"\fR 115 + .PP 116 + Capture a brand new boot timeline with manual reboot. 117 + .IP 118 + \f(CW$ sudo bootgraph -callgraph -manual\fR 119 + .IP 120 + \f(CW$ vi /etc/default/grub # add the CMDLINE string to your kernel params\fR 121 + .IP 122 + \f(CW$ sudo reboot # reboot the machine\fR 123 + .IP 124 + \f(CW$ sudo bootgraph -callgraph # re-run the tool after restart\fR 125 + .PP 126 + 127 + .SH "SEE ALSO" 128 + dmesg(1), update-grub(8), crontab(1), reboot(8) 129 + .PP 130 + .SH AUTHOR 131 + .nf 132 + Written by Todd Brandt <todd.e.brandt@linux.intel.com>
+243
tools/power/pm-graph/sleepgraph.8
··· 1 + .TH SLEEPGRAPH 8 2 + .SH NAME 3 + sleepgraph \- Suspend/Resume timing analysis 4 + .SH SYNOPSIS 5 + .ft B 6 + .B sleepgraph 7 + .RB [ OPTIONS ] 8 + .RB [ COMMAND ] 9 + .SH DESCRIPTION 10 + \fBsleepgraph \fP is designed to assist kernel and OS developers 11 + in optimizing their linux stack's suspend/resume time. Using a kernel 12 + image built with a few extra options enabled, the tool will execute a 13 + suspend and capture dmesg and ftrace data until resume is complete. 14 + This data is transformed into a device timeline and an optional 15 + callgraph to give a detailed view of which devices/subsystems are 16 + taking the most time in suspend/resume. 17 + .PP 18 + If no specific command is given, the default behavior is to initiate 19 + a suspend/resume. 20 + .PP 21 + Generates output files in subdirectory: suspend-yymmdd-HHMMSS 22 + html timeline : <hostname>_<mode>.html 23 + raw dmesg file : <hostname>_<mode>_dmesg.txt 24 + raw ftrace file : <hostname>_<mode>_ftrace.txt 25 + .SH OPTIONS 26 + .TP 27 + \fB-h\fR 28 + Print the help text. 29 + .TP 30 + \fB-v\fR 31 + Print the current tool version. 32 + .TP 33 + \fB-verbose\fR 34 + Print extra information during execution and analysis. 35 + .TP 36 + \fB-config \fIfile\fR 37 + Pull arguments and config options from a file. 38 + .TP 39 + \fB-m \fImode\fR 40 + Mode to initiate for suspend e.g. standby, freeze, mem (default: mem). 41 + .TP 42 + \fB-o \fIsubdir\fR 43 + Override the output subdirectory. Use {date}, {time}, {hostname} for current values. 44 + .sp 45 + e.g. suspend-{hostname}-{date}-{time} 46 + .TP 47 + \fB-rtcwake \fIt\fR | off 48 + Use rtcwake to autoresume after \fIt\fR seconds (default: 15). Set t to "off" to 49 + disable rtcwake and require a user keypress to resume. 50 + .TP 51 + \fB-addlogs\fR 52 + Add the dmesg and ftrace logs to the html output. They will be viewable by 53 + clicking buttons in the timeline. 54 + 55 + .SS "Advanced" 56 + .TP 57 + \fB-cmd \fIstr\fR 58 + Run the timeline over a custom suspend command, e.g. pm-suspend. By default 59 + the tool forces suspend via /sys/power/state so this allows testing over 60 + an OS's official suspend method. The output file will change to 61 + hostname_command.html and will autodetect which suspend mode was triggered. 62 + .TP 63 + \fB-filter \fI"d1,d2,..."\fR 64 + Filter out all but these device callbacks. These strings can be device names 65 + or module names. e.g. 0000:00:02.0, ata5, i915, usb, etc. 66 + .TP 67 + \fB-mindev \fIt\fR 68 + Discard all device callbacks shorter than \fIt\fR milliseconds (default: 0.0). 69 + This reduces the html file size as there can be many tiny callbacks which are barely 70 + visible. The value is a float: e.g. 0.001 represents 1 us. 71 + .TP 72 + \fB-proc\fR 73 + Add usermode process info into the timeline (default: disabled). 74 + .TP 75 + \fB-dev\fR 76 + Add kernel source calls and threads to the timeline (default: disabled). 77 + .TP 78 + \fB-x2\fR 79 + Run two suspend/resumes back to back (default: disabled). 80 + .TP 81 + \fB-x2delay \fIt\fR 82 + Include \fIt\fR ms delay between multiple test runs (default: 0 ms). 83 + .TP 84 + \fB-predelay \fIt\fR 85 + Include \fIt\fR ms delay before 1st suspend (default: 0 ms). 86 + .TP 87 + \fB-postdelay \fIt\fR 88 + Include \fIt\fR ms delay after last resume (default: 0 ms). 89 + .TP 90 + \fB-multi \fIn d\fR 91 + Execute \fIn\fR consecutive tests at \fId\fR seconds intervals. The outputs will 92 + be created in a new subdirectory with a summary page: suspend-xN-{date}-{time}. 93 + 94 + .SS "Ftrace Debug" 95 + .TP 96 + \fB-f\fR 97 + Use ftrace to create device callgraphs (default: disabled). This can produce 98 + very large outputs, i.e. 10MB - 100MB. 99 + .TP 100 + \fB-maxdepth \fIlevel\fR 101 + limit the callgraph trace depth to \fIlevel\fR (default: 0=all). This is 102 + the best way to limit the output size when using callgraphs via -f. 103 + .TP 104 + \fB-expandcg\fR 105 + pre-expand the callgraph data in the html output (default: disabled) 106 + .TP 107 + \fB-fadd \fIfile\fR 108 + Add functions to be graphed in the timeline from a list in a text file 109 + .TP 110 + \fB-mincg \fIt\fR 111 + Discard all callgraphs shorter than \fIt\fR milliseconds (default: 0.0). 112 + This reduces the html file size as there can be many tiny callgraphs 113 + which are barely visible in the timeline. 114 + The value is a float: e.g. 0.001 represents 1 us. 115 + .TP 116 + \fB-cgphase \fIp\fR 117 + Only show callgraph data for phase \fIp\fR (e.g. suspend_late). 118 + .TP 119 + \fB-cgtest \fIn\fR 120 + In an x2 run, only show callgraph data for test \fIn\fR (e.g. 0 or 1). 121 + .TP 122 + \fB-timeprec \fIn\fR 123 + Number of significant digits in timestamps (0:S, [3:ms], 6:us). 124 + 125 + .SH COMMANDS 126 + .TP 127 + \fB-ftrace \fIfile\fR 128 + Create HTML output from an existing ftrace file. 129 + .TP 130 + \fB-dmesg \fIfile\fR 131 + Create HTML output from an existing dmesg file. 132 + .TP 133 + \fB-summary \fIindir\fR 134 + Create a summary page of all tests in \fIindir\fR. Creates summary.html 135 + in the current folder. The output page is a table of tests with 136 + suspend and resume values sorted by suspend mode, host, and kernel. 137 + Includes test averages by mode and links to the test html files. 138 + .TP 139 + \fB-modes\fR 140 + List available suspend modes. 141 + .TP 142 + \fB-status\fR 143 + Test to see if the system is able to run this tool. Use this along 144 + with any options you intend to use to see if they will work. 145 + .TP 146 + \fB-fpdt\fR 147 + Print out the contents of the ACPI Firmware Performance Data Table. 148 + .TP 149 + \fB-usbtopo\fR 150 + Print out the current USB topology with power info. 151 + .TP 152 + \fB-usbauto\fR 153 + Enable autosuspend for all connected USB devices. 154 + .TP 155 + \fB-flist\fR 156 + Print the list of ftrace functions currently being captured. Functions 157 + that are not available as symbols in the current kernel are shown in red. 158 + By default, the tool traces a list of important suspend/resume functions 159 + in order to better fill out the timeline. If the user has added their own 160 + with -fadd they will also be checked. 161 + .TP 162 + \fB-flistall\fR 163 + Print all ftrace functions capable of being captured. These are all the 164 + possible values you can add to trace via the -fadd argument. 165 + 166 + .SH EXAMPLES 167 + .SS "Simple Commands" 168 + Check which suspend modes are currently supported. 169 + .IP 170 + \f(CW$ sleepgraph -modes\fR 171 + .PP 172 + Read the Firmware Performance Data Table (FPDT) 173 + .IP 174 + \f(CW$ sudo sleepgraph -fpdt\fR 175 + .PP 176 + Print out the current USB power topology 177 + .IP 178 + \f(CW$ sleepgraph -usbtopo 179 + .PP 180 + Verify that you can run a command with a set of arguments 181 + .IP 182 + \f(CW$ sudo sleepgraph -f -rtcwake 30 -status 183 + .PP 184 + Generate a summary of all timelines in a particular folder. 185 + .IP 186 + \f(CW$ sleepgraph -summary ~/workspace/myresults/\fR 187 + .PP 188 + Re-generate the html output from a previous run's dmesg and ftrace log. 189 + .IP 190 + \f(CW$ sleepgraph -dmesg myhost_mem_dmesg.txt -ftrace myhost_mem_ftrace.txt\fR 191 + .PP 192 + 193 + .SS "Capturing Simple Timelines" 194 + Execute a mem suspend with a 15 second wakeup. Include the logs in the html. 195 + .IP 196 + \f(CW$ sudo sleepgraph -rtcwake 15 -addlogs\fR 197 + .PP 198 + Execute a standby with a 15 second wakeup. Change the output folder name. 199 + .IP 200 + \f(CW$ sudo sleepgraph -m standby -rtcwake 15 -o "standby-{hostname}-{date}-{time}"\fR 201 + .PP 202 + Execute a freeze with no wakeup (require keypress). Change output folder name. 203 + .IP 204 + \f(CW$ sudo sleepgraph -m freeze -rtcwake off -o "freeze-{hostname}-{date}-{time}"\fR 205 + .PP 206 + 207 + .SS "Capturing Advanced Timelines" 208 + Execute a suspend & include dev mode source calls, limit callbacks to 5ms or larger. 209 + .IP 210 + \f(CW$ sudo sleepgraph -m mem -rtcwake 15 -dev -mindev 5\fR 211 + .PP 212 + Run two suspends back to back, include a 500ms delay before, after, and in between runs. 213 + .IP 214 + \f(CW$ sudo sleepgraph -m mem -rtcwake 15 -x2 -predelay 500 -x2delay 500 -postdelay 500\fR 215 + .PP 216 + Do a batch run of 10 freezes with 30 seconds delay between runs. 217 + .IP 218 + \f(CW$ sudo sleepgraph -m freeze -rtcwake 15 -multi 10 30\fR 219 + .PP 220 + Execute a suspend using a custom command. 221 + .IP 222 + \f(CW$ sudo sleepgraph -cmd "echo mem > /sys/power/state" -rtcwake 15\fR 223 + .PP 224 + 225 + 226 + .SS "Capturing Timelines with Callgraph Data" 227 + Add device callgraphs. Limit the trace depth and only show callgraphs 10ms or larger. 228 + .IP 229 + \f(CW$ sudo sleepgraph -m mem -rtcwake 15 -f -maxdepth 5 -mincg 10\fR 230 + .PP 231 + Capture a full callgraph across all suspend, then filter the html by a single phase. 232 + .IP 233 + \f(CW$ sudo sleepgraph -m mem -rtcwake 15 -f\fR 234 + .IP 235 + \f(CW$ sleepgraph -dmesg host_mem_dmesg.txt -ftrace host_mem_ftrace.txt -f -cgphase resume 236 + .PP 237 + 238 + .SH "SEE ALSO" 239 + dmesg(1) 240 + .PP 241 + .SH AUTHOR 242 + .nf 243 + Written by Todd Brandt <todd.e.brandt@linux.intel.com>
+17
tools/power/x86/intel_pstate_tracer/intel_pstate_tracer.py
··· 353 353 os.system('grep -m 1 common_cpu cpu.csv > cpu{:0>3}.csv'.format(index)) 354 354 os.system('grep CPU_{:0>3} cpu.csv >> cpu{:0>3}.csv'.format(index, index)) 355 355 356 + def fix_ownership(path): 357 + """Change the owner of the file to SUDO_UID, if required""" 358 + 359 + uid = os.environ.get('SUDO_UID') 360 + gid = os.environ.get('SUDO_GID') 361 + if uid is not None: 362 + os.chown(path, int(uid), int(gid)) 363 + 356 364 def cleanup_data_files(): 357 365 """ clean up existing data files """ 358 366 ··· 526 518 527 519 if not os.path.exists('results'): 528 520 os.mkdir('results') 521 + # The regular user needs to own the directory, not root. 522 + fix_ownership('results') 529 523 530 524 os.chdir('results') 531 525 if os.path.exists(testname): 532 526 print('The test name directory already exists. Please provide a unique test name. Test re-run not supported, yet.') 533 527 sys.exit() 534 528 os.mkdir(testname) 529 + # The regular user needs to own the directory, not root. 530 + fix_ownership(testname) 535 531 os.chdir(testname) 536 532 537 533 # Temporary (or perhaps not) ··· 577 565 plot_scaled_cpu() 578 566 plot_boost_cpu() 579 567 plot_ghz_cpu() 568 + 569 + # It is preferrable, but not necessary, that the regular user owns the files, not root. 570 + for root, dirs, files in os.walk('.'): 571 + for f in files: 572 + fix_ownership(f) 580 573 581 574 os.chdir('../../')