diff options
author | Joe Onorato <joeo@google.com> | 2018-11-16 17:41:09 -0800 |
---|---|---|
committer | Joe Onorato <joeo@google.com> | 2018-11-29 10:48:26 -0800 |
commit | 795bfbaabfac07be7063b12789a5286ac1ebf579 (patch) | |
tree | 7ac092bdba8e9914b7f9b1d76756266ad44a3360 /tools/powermodel/src | |
parent | 68cf7a9e196d1702082a61f02ae259a59c0fe800 (diff) |
Power model calculation based on batterystats data.
Similar to the ActivityReport, the PowerReport contains the power
usage for a device. To do the calculations, each of the
ComponentActivity objects are called, giving them the whole activity
info (in case they need to apportion blame) and the PowerProfile.
From that, they compute the per-component power usage, which is
then summed up into the AppPower and PowerReport objects.
Test: atest frameworks/base/tools/powermodel --host
Change-Id: Ibc9ada6f7f4a667152fc4af388f04766125ca74c
Diffstat (limited to 'tools/powermodel/src')
10 files changed, 376 insertions, 3 deletions
diff --git a/tools/powermodel/src/com/android/powermodel/AppPower.java b/tools/powermodel/src/com/android/powermodel/AppPower.java new file mode 100644 index 000000000000..283982b8eda6 --- /dev/null +++ b/tools/powermodel/src/com/android/powermodel/AppPower.java @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.powermodel; + +import java.util.HashMap; +import java.util.Set; + +import com.google.common.collect.ImmutableMap; + +public class AppPower extends AppInfo { + private ImmutableMap<Component, ComponentPower> mComponents; + + private double mAppPowerMah; + + + private AppPower() { + } + + /** + * Returns the {@link ComponentPower} for the {@link Component} provided, + * or null if this AppPower does not have that component. + * @more + * If the component was in the power profile for this device, there + * will be a component for it, even if there was no power used + * by that component. In that case, the + * {@link ComponentPower.getUsage() ComponentPower.getUsage()} + * method will return 0. + */ + public ComponentPower getComponentPower(Component component) { + return mComponents.get(component); + } + + public Set<Component> getComponents() { + return mComponents.keySet(); + } + + /** + * Return the total power used by this app. + */ + public double getAppPowerMah() { + return mAppPowerMah; + } + + /** + * Builder class for {@link AppPower} + */ + public static class Builder extends AppInfo.Builder<AppPower> { + private HashMap<Component, ComponentPower> mComponents = new HashMap(); + + public Builder() { + } + + public AppPower build() { + final AppPower result = new AppPower(); + init(result); + result.mComponents = ImmutableMap.copyOf(mComponents); + + // Add up the components + double appPowerMah = 0; + for (final ComponentPower componentPower: mComponents.values()) { + appPowerMah += componentPower.powerMah; + } + result.mAppPowerMah = appPowerMah; + + return result; + } + + public void addComponentPower(Component component, ComponentPower componentPower) { + mComponents.put(component, componentPower); + } + } +} diff --git a/tools/powermodel/src/com/android/powermodel/ComponentActivity.java b/tools/powermodel/src/com/android/powermodel/ComponentActivity.java index e619a96687ab..c1e2662b7b5f 100644 --- a/tools/powermodel/src/com/android/powermodel/ComponentActivity.java +++ b/tools/powermodel/src/com/android/powermodel/ComponentActivity.java @@ -23,8 +23,20 @@ package com.android.powermodel; public class ComponentActivity { public AttributionKey attribution; - public ComponentActivity(AttributionKey attribution) { + protected ComponentActivity(AttributionKey attribution) { this.attribution = attribution; } + + // TODO: Can we refactor what goes into the activities so this function + // doesn't need the global state? + /** + * Apply the power profile for this component. Subclasses should implement this + * to do the per-component calculatinos. The default implementation returns null. + * If this method returns null, then there will be no power associated for this + * component, which, for example is true with some of the GLOBAL activities. + */ + public ComponentPower applyProfile(ActivityReport activityReport, PowerProfile profile) { + return null; + } } diff --git a/tools/powermodel/src/com/android/powermodel/ComponentPower.java b/tools/powermodel/src/com/android/powermodel/ComponentPower.java new file mode 100644 index 000000000000..b22ff8731d6f --- /dev/null +++ b/tools/powermodel/src/com/android/powermodel/ComponentPower.java @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.powermodel; + +/** + * The hardware component that uses power on a device. + * <p> + * This base class contains the total power used by each Component in an app. + * Subclasses may add more detail, which is a drill-down, but is not to be + * <i>added</i> to {@link #powerMah}. + */ +public abstract class ComponentPower<ACTIVITY extends ComponentActivity> { + /** + * The app associated with this ComponentPower. + */ + public AttributionKey attribution; + + /** + * The app activity that resulted in the power usage for this component. + */ + public ACTIVITY activity; + + /** + * The total power used by this component in this app. + */ + public double powerMah; +} diff --git a/tools/powermodel/src/com/android/powermodel/PowerReport.java b/tools/powermodel/src/com/android/powermodel/PowerReport.java new file mode 100644 index 000000000000..76ba67235b0a --- /dev/null +++ b/tools/powermodel/src/com/android/powermodel/PowerReport.java @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.powermodel; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +import com.google.common.collect.ImmutableMap; + +/** + * PowerReport contains the summary of all power used on a device + * as reported by batterystats or statsd, based on the power profile. + */ +public class PowerReport { + private AppList<AppPower> mApps; + private double mTotalPowerMah; + + private PowerReport() { + } + + /** + * The total power used by this device for this PowerReport. + */ + public double getTotalPowerMah() { + return mTotalPowerMah; + } + + public List<AppPower> getAllApps() { + return mApps.getAllApps(); + } + + public List<AppPower> getRegularApps() { + return mApps.getRegularApps(); + } + + public List<AppPower> findApp(String pkg) { + return mApps.findApp(pkg); + } + + public AppPower findApp(SpecialApp specialApp) { + return mApps.findApp(specialApp); + } + + public static PowerReport createReport(PowerProfile profile, ActivityReport activityReport) { + final PowerReport.Builder powerReport = new PowerReport.Builder(); + for (final AppActivity appActivity: activityReport.getAllApps()) { + final AppPower.Builder appPower = new AppPower.Builder(); + appPower.setAttribution(appActivity.getAttribution()); + + for (final ImmutableMap.Entry<Component,ComponentActivity> entry: + appActivity.getComponentActivities().entrySet()) { + final ComponentPower componentPower = entry.getValue() + .applyProfile(activityReport, profile); + if (componentPower != null) { + appPower.addComponentPower(entry.getKey(), componentPower); + } + } + + powerReport.add(appPower); + } + return powerReport.build(); + } + + private static class Builder { + private AppList.Builder mApps = new AppList.Builder(); + + public Builder() { + } + + public PowerReport build() { + final PowerReport report = new PowerReport(); + + report.mApps = mApps.build(); + + for (AppPower app: report.mApps.getAllApps()) { + report.mTotalPowerMah += app.getAppPowerMah(); + } + + return report; + } + + public void add(AppPower.Builder app) { + mApps.put(app.getAttribution(), app); + } + } +} diff --git a/tools/powermodel/src/com/android/powermodel/component/ModemAppActivity.java b/tools/powermodel/src/com/android/powermodel/component/ModemAppActivity.java index 53aa3c00aa40..cb70051f1ae6 100644 --- a/tools/powermodel/src/com/android/powermodel/component/ModemAppActivity.java +++ b/tools/powermodel/src/com/android/powermodel/component/ModemAppActivity.java @@ -21,6 +21,7 @@ import com.android.powermodel.AttributionKey; import com.android.powermodel.Component; import com.android.powermodel.ComponentActivity; import com.android.powermodel.PowerProfile; +import com.android.powermodel.util.Conversion; /** * Encapsulates the work done by the celluar modem on behalf of an app. @@ -42,5 +43,43 @@ public class ModemAppActivity extends ComponentActivity { * The number of packets sent by the app. */ public long txPacketCount; + + @Override + public ModemAppPower applyProfile(ActivityReport activityReport, PowerProfile profile) { + // Profile + final ModemProfile modemProfile = (ModemProfile)profile.getComponent(Component.MODEM); + if (modemProfile == null) { + // TODO: This is kind of a big problem... Should this throw instead? + return null; + } + + // Activity + final ModemGlobalActivity global + = (ModemGlobalActivity)activityReport.findGlobalComponent(Component.MODEM); + if (global == null) { + return null; + } + + final double averageModemPowerMa = getAverageModemPowerMa(modemProfile); + final long totalPacketCount = global.rxPacketCount + global.txPacketCount; + final long appPacketCount = this.rxPacketCount + this.txPacketCount; + + final ModemAppPower result = new ModemAppPower(); + result.attribution = this.attribution; + result.activity = this; + result.powerMah = Conversion.msToHr( + (totalPacketCount > 0 ? (appPacketCount / (double)totalPacketCount) : 0) + * global.totalActiveTimeMs + * averageModemPowerMa); + return result; + } + + static final double getAverageModemPowerMa(ModemProfile profile) { + double sumMa = profile.getRxMa(); + for (float powerAtTxLevelMa: profile.getTxMa()) { + sumMa += powerAtTxLevelMa; + } + return sumMa / (profile.getTxMa().length + 1); + } } diff --git a/tools/powermodel/src/com/android/powermodel/component/ModemAppPower.java b/tools/powermodel/src/com/android/powermodel/component/ModemAppPower.java new file mode 100644 index 000000000000..f5531272d0b9 --- /dev/null +++ b/tools/powermodel/src/com/android/powermodel/component/ModemAppPower.java @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.powermodel.component; + +import com.android.powermodel.Component; +import com.android.powermodel.ComponentPower; + +public class ModemAppPower extends ComponentPower<ModemAppActivity> { +} + diff --git a/tools/powermodel/src/com/android/powermodel/component/ModemGlobalActivity.java b/tools/powermodel/src/com/android/powermodel/component/ModemGlobalActivity.java index b9b39672f014..a53b53eede2b 100644 --- a/tools/powermodel/src/com/android/powermodel/component/ModemGlobalActivity.java +++ b/tools/powermodel/src/com/android/powermodel/component/ModemGlobalActivity.java @@ -19,6 +19,8 @@ package com.android.powermodel.component; import com.android.powermodel.ActivityReport; import com.android.powermodel.AttributionKey; import com.android.powermodel.ComponentActivity; +import com.android.powermodel.ComponentPower; +import com.android.powermodel.PowerProfile; /** * Encapsulates total work done by the modem for the device. diff --git a/tools/powermodel/src/com/android/powermodel/component/ModemRemainderActivity.java b/tools/powermodel/src/com/android/powermodel/component/ModemRemainderActivity.java index 5694de301d2d..0e268c21d01d 100644 --- a/tools/powermodel/src/com/android/powermodel/component/ModemRemainderActivity.java +++ b/tools/powermodel/src/com/android/powermodel/component/ModemRemainderActivity.java @@ -20,13 +20,13 @@ import com.android.powermodel.ActivityReport; import com.android.powermodel.AttributionKey; import com.android.powermodel.Component; import com.android.powermodel.ComponentActivity; +import com.android.powermodel.PowerProfile; +import com.android.powermodel.util.Conversion; /** * Encapsulates the work done by the remaining */ public class ModemRemainderActivity extends ComponentActivity { - private static final double MS_PER_HR = 3600000.0; - /** * Construct a new ModemRemainderActivity. */ @@ -49,5 +49,39 @@ public class ModemRemainderActivity extends ComponentActivity { * than an app transmitting and receiving data. */ public long activeTimeMs; + + @Override + public ModemRemainderPower applyProfile(ActivityReport activityReport, PowerProfile profile) { + // Profile + final ModemProfile modemProfile = (ModemProfile)profile.getComponent(Component.MODEM); + if (modemProfile == null) { + return null; + } + + // Activity + final ModemRemainderPower result = new ModemRemainderPower(); + result.attribution = this.attribution; + result.activity = this; + + // strengthMah + // TODO: If the array lengths don't match... then? + result.strengthMah = new double[this.strengthTimeMs.length]; + for (int i=0; i<this.strengthTimeMs.length; i++) { + result.strengthMah[i] = Conversion.msToHr( + this.strengthTimeMs[i] * modemProfile.getTxMa()[i]); + result.powerMah += result.strengthMah[i]; + } + + // scanningMah + result.scanningMah = Conversion.msToHr(this.scanningTimeMs * modemProfile.getScanningMa()); + result.powerMah += result.scanningMah; + + // activeMah + result.activeMah = Conversion.msToHr( + this.activeTimeMs * ModemAppActivity.getAverageModemPowerMa(modemProfile)); + result.powerMah += result.activeMah; + + return result; + } } diff --git a/tools/powermodel/src/com/android/powermodel/component/ModemRemainderPower.java b/tools/powermodel/src/com/android/powermodel/component/ModemRemainderPower.java new file mode 100644 index 000000000000..7f38cd342e2f --- /dev/null +++ b/tools/powermodel/src/com/android/powermodel/component/ModemRemainderPower.java @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.powermodel.component; + +import com.android.powermodel.Component; +import com.android.powermodel.ComponentPower; + +public class ModemRemainderPower extends ComponentPower<ModemRemainderActivity> { + + public double[] strengthMah; + + public double scanningMah; + + public double activeMah; +} + diff --git a/tools/powermodel/src/com/android/powermodel/util/Conversion.java b/tools/powermodel/src/com/android/powermodel/util/Conversion.java index 9a79a2d48a59..e556c251a1c9 100644 --- a/tools/powermodel/src/com/android/powermodel/util/Conversion.java +++ b/tools/powermodel/src/com/android/powermodel/util/Conversion.java @@ -35,6 +35,10 @@ public class Conversion { return result; } + public static double msToHr(double ms) { + return ms / 3600.0 / 1000.0; + } + /** * No public constructor. */ |