am 5ea916b1: Merge change 26050 into eclair

Merge commit '5ea916b17cf0071f4d49936a370f4b873e4eb3e3' into eclair-plus-aosp

* commit '5ea916b17cf0071f4d49936a370f4b873e4eb3e3':
  Track CPU speed stepping to get more accurate CPU cost per app.
This commit is contained in:
Amith Yamasani
2009-09-20 17:08:53 -07:00
committed by Android Git Automerger
8 changed files with 196 additions and 19 deletions

View File

@@ -314,6 +314,15 @@ public abstract class BatteryStats implements Parcelable {
* @return foreground cpu time in microseconds * @return foreground cpu time in microseconds
*/ */
public abstract long getForegroundTime(int which); public abstract long getForegroundTime(int which);
/**
* Returns the approximate cpu time spent in microseconds, at a certain CPU speed.
* @param speedStep the index of the CPU speed. This is not the actual speed of the
* CPU.
* @param which one of STATS_TOTAL, STATS_LAST, STATS_CURRENT or STATS_UNPLUGGED
* @see BatteryStats#getCpuSpeedSteps()
*/
public abstract long getTimeAtCpuSpeedStep(int speedStep, int which);
} }
/** /**
@@ -573,6 +582,9 @@ public abstract class BatteryStats implements Parcelable {
public abstract Map<String, ? extends Timer> getKernelWakelockStats(); public abstract Map<String, ? extends Timer> getKernelWakelockStats();
/** Returns the number of different speeds that the CPU can run at */
public abstract int getCpuSpeedSteps();
private final static void formatTimeRaw(StringBuilder out, long seconds) { private final static void formatTimeRaw(StringBuilder out, long seconds) {
long days = seconds / (60 * 60 * 24); long days = seconds / (60 * 60 * 24);
if (days != 0) { if (days != 0) {

View File

@@ -121,6 +121,9 @@ public class VolumePreference extends SeekBarPreference implements
if (mSeekBarVolumizer != null) { if (mSeekBarVolumizer != null) {
Dialog dialog = getDialog(); Dialog dialog = getDialog();
if (dialog != null && dialog.isShowing()) { if (dialog != null && dialog.isShowing()) {
View view = dialog.getWindow().getDecorView()
.findViewById(com.android.internal.R.id.seekbar);
if (view != null) view.setOnKeyListener(null);
// Stopped while dialog was showing, revert changes // Stopped while dialog was showing, revert changes
mSeekBarVolumizer.revertVolume(); mSeekBarVolumizer.revertVolume();
} }

View File

@@ -56,7 +56,9 @@ public final class BatteryStatsImpl extends BatteryStats {
private static final int MAGIC = 0xBA757475; // 'BATSTATS' private static final int MAGIC = 0xBA757475; // 'BATSTATS'
// Current on-disk Parcel version // Current on-disk Parcel version
private static final int VERSION = 39; private static final int VERSION = 40;
private static int sNumSpeedSteps;
private final File mFile; private final File mFile;
private final File mBackupFile; private final File mBackupFile;
@@ -213,7 +215,7 @@ public final class BatteryStatsImpl extends BatteryStats {
/** /**
* State for keeping track of counting information. * State for keeping track of counting information.
*/ */
public static final class Counter extends BatteryStats.Counter implements Unpluggable { public static class Counter extends BatteryStats.Counter implements Unpluggable {
int mCount; int mCount;
int mLoadedCount; int mLoadedCount;
int mLastCount; int mLastCount;
@@ -302,7 +304,22 @@ public final class BatteryStatsImpl extends BatteryStats {
mUnpluggedCount = mPluggedCount = mCount; mUnpluggedCount = mPluggedCount = mCount;
} }
} }
public static class SamplingCounter extends Counter {
SamplingCounter(ArrayList<Unpluggable> unpluggables, Parcel in) {
super(unpluggables, in);
}
SamplingCounter(ArrayList<Unpluggable> unpluggables) {
super(unpluggables);
}
public void addCountLocked(long count) {
mCount += count;
}
}
/** /**
* State for keeping track of timing information. * State for keeping track of timing information.
*/ */
@@ -1940,10 +1957,16 @@ public final class BatteryStatsImpl extends BatteryStats {
*/ */
long mUnpluggedForegroundTime; long mUnpluggedForegroundTime;
SamplingCounter[] mSpeedBins;
Proc() { Proc() {
mUnpluggables.add(this); mUnpluggables.add(this);
mSpeedBins = new SamplingCounter[getCpuSpeedSteps()];
for (int i = 0; i < mSpeedBins.length; i++) {
mSpeedBins[i] = new SamplingCounter(mUnpluggables);
}
} }
public void unplug(long batteryUptime, long batteryRealtime) { public void unplug(long batteryUptime, long batteryRealtime) {
mUnpluggedUserTime = mUserTime; mUnpluggedUserTime = mUserTime;
mUnpluggedSystemTime = mSystemTime; mUnpluggedSystemTime = mSystemTime;
@@ -1974,6 +1997,11 @@ public final class BatteryStatsImpl extends BatteryStats {
out.writeLong(mUnpluggedSystemTime); out.writeLong(mUnpluggedSystemTime);
out.writeLong(mUnpluggedForegroundTime); out.writeLong(mUnpluggedForegroundTime);
out.writeInt(mUnpluggedStarts); out.writeInt(mUnpluggedStarts);
out.writeInt(mSpeedBins.length);
for (int i = 0; i < mSpeedBins.length; i++) {
mSpeedBins[i].writeToParcel(out);
}
} }
void readFromParcelLocked(Parcel in) { void readFromParcelLocked(Parcel in) {
@@ -1993,6 +2021,12 @@ public final class BatteryStatsImpl extends BatteryStats {
mUnpluggedSystemTime = in.readLong(); mUnpluggedSystemTime = in.readLong();
mUnpluggedForegroundTime = in.readLong(); mUnpluggedForegroundTime = in.readLong();
mUnpluggedStarts = in.readInt(); mUnpluggedStarts = in.readInt();
int bins = in.readInt();
mSpeedBins = new SamplingCounter[bins];
for (int i = 0; i < bins; i++) {
mSpeedBins[i] = new SamplingCounter(mUnpluggables, in);
}
} }
public BatteryStatsImpl getBatteryStats() { public BatteryStatsImpl getBatteryStats() {
@@ -2075,6 +2109,22 @@ public final class BatteryStatsImpl extends BatteryStats {
} }
return val; return val;
} }
/* Called by ActivityManagerService when CPU times are updated. */
public void addSpeedStepTimes(long[] values) {
for (int i = 0; i < mSpeedBins.length && i < values.length; i++) {
mSpeedBins[i].addCountLocked(values[i]);
}
}
@Override
public long getTimeAtCpuSpeedStep(int speedStep, int which) {
if (speedStep < mSpeedBins.length) {
return mSpeedBins[speedStep].getCountLocked(which);
} else {
return 0;
}
}
} }
/** /**
@@ -2625,6 +2675,10 @@ public final class BatteryStatsImpl extends BatteryStats {
readFromParcel(p); readFromParcel(p);
} }
public void setNumSpeedSteps(int steps) {
if (sNumSpeedSteps == 0) sNumSpeedSteps = steps;
}
@Override @Override
public int getStartCount() { public int getStartCount() {
return mStartCount; return mStartCount;
@@ -2853,6 +2907,11 @@ public final class BatteryStatsImpl extends BatteryStats {
return mDischargeCurrentLevel; return mDischargeCurrentLevel;
} }
@Override
public int getCpuSpeedSteps() {
return sNumSpeedSteps;
}
/** /**
* Retrieve the statistics object for a particular uid, creating if needed. * Retrieve the statistics object for a particular uid, creating if needed.
*/ */
@@ -3063,7 +3122,9 @@ public final class BatteryStatsImpl extends BatteryStats {
getKernelWakelockTimerLocked(kwltName).readSummaryFromParcelLocked(in); getKernelWakelockTimerLocked(kwltName).readSummaryFromParcelLocked(in);
} }
} }
sNumSpeedSteps = in.readInt();
final int NU = in.readInt(); final int NU = in.readInt();
for (int iu = 0; iu < NU; iu++) { for (int iu = 0; iu < NU; iu++) {
int uid = in.readInt(); int uid = in.readInt();
@@ -3206,6 +3267,7 @@ public final class BatteryStatsImpl extends BatteryStats {
} }
} }
out.writeInt(sNumSpeedSteps);
final int NU = mUidStats.size(); final int NU = mUidStats.size();
out.writeInt(NU); out.writeInt(NU);
for (int iu = 0; iu < NU; iu++) { for (int iu = 0; iu < NU; iu++) {
@@ -3404,6 +3466,8 @@ public final class BatteryStatsImpl extends BatteryStats {
mFullTimers.clear(); mFullTimers.clear();
mWindowTimers.clear(); mWindowTimers.clear();
sNumSpeedSteps = in.readInt();
int numUids = in.readInt(); int numUids = in.readInt();
mUidStats.clear(); mUidStats.clear();
for (int i = 0; i < numUids; i++) { for (int i = 0; i < numUids; i++) {
@@ -3484,7 +3548,9 @@ public final class BatteryStatsImpl extends BatteryStats {
out.writeInt(0); out.writeInt(0);
} }
} }
out.writeInt(sNumSpeedSteps);
int size = mUidStats.size(); int size = mUidStats.size();
out.writeInt(size); out.writeInt(size);
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {

View File

@@ -47,14 +47,9 @@ public class PowerProfile {
public static final String POWER_CPU_IDLE = "cpu.idle"; public static final String POWER_CPU_IDLE = "cpu.idle";
/** /**
* Power consumption when CPU is running at normal speed. * Power consumption when CPU is in power collapse mode.
*/ */
public static final String POWER_CPU_NORMAL = "cpu.normal"; public static final String POWER_CPU_ACTIVE = "cpu.active";
/**
* Power consumption when CPU is running at full speed.
*/
public static final String POWER_CPU_FULL = "cpu.full";
/** /**
* Power consumption when WiFi driver is scanning for networks. * Power consumption when WiFi driver is scanning for networks.
@@ -124,6 +119,8 @@ public class PowerProfile {
*/ */
public static final String POWER_VIDEO = "dsp.video"; public static final String POWER_VIDEO = "dsp.video";
public static final String POWER_CPU_SPEEDS = "cpu.speeds";
static final HashMap<String, Object> sPowerMap = new HashMap<String, Object>(); static final HashMap<String, Object> sPowerMap = new HashMap<String, Object>();
private static final String TAG_DEVICE = "device"; private static final String TAG_DEVICE = "device";
@@ -214,10 +211,10 @@ public class PowerProfile {
} }
/** /**
* Returns the average current in mA consumed by the subsystem for the given level. * Returns the average current in mA consumed by the subsystem for the given level.
* @param type the subsystem type * @param type the subsystem type
* @param level the level of power at which the subsystem is running. For instance, the * @param level the level of power at which the subsystem is running. For instance, the
* signal strength of the cell network between 0 and 4 (if there are 4 bars max.). * signal strength of the cell network between 0 and 4 (if there are 4 bars max.)
* If there is no data for multiple levels, the level is ignored. * If there is no data for multiple levels, the level is ignored.
* @return the average current in milliAmps. * @return the average current in milliAmps.
*/ */
@@ -240,4 +237,12 @@ public class PowerProfile {
return 0; return 0;
} }
} }
public int getNumSpeedSteps() {
Object value = sPowerMap.get(POWER_CPU_SPEEDS);
if (value != null && value instanceof Double[]) {
return ((Double[])value).length;
}
return 1; // Only one speed
}
} }

View File

@@ -26,15 +26,24 @@
<item name="wifi.on">0.1</item> <item name="wifi.on">0.1</item>
<item name="wifi.active">0.1</item> <item name="wifi.active">0.1</item>
<item name="wifi.scan">0.1</item> <item name="wifi.scan">0.1</item>
<item name="cpu.idle">0.1</item>
<item name="cpu.normal">0.2</item>
<item name="cpu.full">1</item>
<item name="dsp.audio">0.1</item> <item name="dsp.audio">0.1</item>
<item name="dsp.video">0.1</item> <item name="dsp.video">0.1</item>
<item name="radio.active">1</item> <item name="radio.active">1</item>
<item name="gps.on">1</item> <item name="gps.on">1</item>
<!-- Current consumed by the radio at different signal strengths, when paging -->
<array name="radio.on"> <!-- Strength 0 to BINS-1 --> <array name="radio.on"> <!-- Strength 0 to BINS-1 -->
<value>1</value> <value>1</value>
<value>0.1</value> <value>0.1</value>
</array> </array>
<!-- Different CPU speeds as reported in
/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state -->
<array name="cpu.speeds">
<value>400000</value> <!-- 400 MHz CPU speed -->
</array>
<!-- Power consumption when CPU is idle -->
<item name="cpu.idle">0.1</item>
<!-- Power consumption at different speeds -->
<array name="cpu.active">
<value>0.2</value>
</array>
</device> </device>

View File

@@ -30,6 +30,7 @@ import java.io.StringWriter;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
import java.util.StringTokenizer;
public class ProcessStats { public class ProcessStats {
private static final String TAG = "ProcessStats"; private static final String TAG = "ProcessStats";
@@ -138,7 +139,22 @@ public class ProcessStats {
private boolean mFirst = true; private boolean mFirst = true;
private byte[] mBuffer = new byte[256]; private byte[] mBuffer = new byte[256];
/**
* The time in microseconds that the CPU has been running at each speed.
*/
private long[] mCpuSpeedTimes;
/**
* The relative time in microseconds that the CPU has been running at each speed.
*/
private long[] mRelCpuSpeedTimes;
/**
* The different speeds that the CPU can be running at.
*/
private long[] mCpuSpeeds;
public static class Stats { public static class Stats {
public final int pid; public final int pid;
final String statFile; final String statFile;
@@ -460,6 +476,67 @@ public class ProcessStats {
return 0; return 0;
} }
/**
* Returns the times spent at each CPU speed, since the last call to this method. If this
* is the first time, it will return 1 for each value.
* @return relative times spent at different speed steps.
*/
public long[] getLastCpuSpeedTimes() {
if (mCpuSpeedTimes == null) {
mCpuSpeedTimes = getCpuSpeedTimes(null);
mRelCpuSpeedTimes = new long[mCpuSpeedTimes.length];
for (int i = 0; i < mCpuSpeedTimes.length; i++) {
mRelCpuSpeedTimes[i] = 1; // Initialize
}
} else {
getCpuSpeedTimes(mRelCpuSpeedTimes);
for (int i = 0; i < mCpuSpeedTimes.length; i++) {
long temp = mRelCpuSpeedTimes[i];
mRelCpuSpeedTimes[i] -= mCpuSpeedTimes[i];
mCpuSpeedTimes[i] = temp;
}
}
return mRelCpuSpeedTimes;
}
private long[] getCpuSpeedTimes(long[] out) {
long[] tempTimes = out;
long[] tempSpeeds = mCpuSpeeds;
final int MAX_SPEEDS = 20;
if (out == null) {
tempTimes = new long[MAX_SPEEDS]; // Hopefully no more than that
tempSpeeds = new long[MAX_SPEEDS];
}
int speed = 0;
String file = readFile("/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state", '\0');
StringTokenizer st = new StringTokenizer(file, "\n ");
while (st.hasMoreElements()) {
String token = st.nextToken();
try {
long val = Long.parseLong(token);
tempSpeeds[speed] = val;
token = st.nextToken();
val = Long.parseLong(token);
tempTimes[speed] = val;
speed++;
if (speed == MAX_SPEEDS) break; // No more
if (localLOGV && out == null) {
Log.v(TAG, "First time : Speed/Time = " + tempSpeeds[speed - 1]
+ "\t" + tempTimes[speed - 1]);
}
} catch (NumberFormatException nfe) {
Log.i(TAG, "Unable to parse time_in_state");
}
}
if (out == null) {
out = new long[speed];
mCpuSpeeds = new long[speed];
System.arraycopy(tempSpeeds, 0, mCpuSpeeds, 0, speed);
System.arraycopy(tempTimes, 0, out, 0, speed);
}
return out;
}
final public int getLastUserTime() { final public int getLastUserTime() {
return mRelUserTime; return mRelUserTime;
} }

View File

@@ -1572,6 +1572,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
} }
} }
long[] cpuSpeedTimes = mProcessStats.getLastCpuSpeedTimes();
final BatteryStatsImpl bstats = mBatteryStatsService.getActiveStatistics(); final BatteryStatsImpl bstats = mBatteryStatsService.getActiveStatistics();
synchronized(bstats) { synchronized(bstats) {
synchronized(mPidsSelfLocked) { synchronized(mPidsSelfLocked) {
@@ -1585,11 +1586,13 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if (pr != null) { if (pr != null) {
BatteryStatsImpl.Uid.Proc ps = pr.batteryStats; BatteryStatsImpl.Uid.Proc ps = pr.batteryStats;
ps.addCpuTimeLocked(st.rel_utime, st.rel_stime); ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
ps.addSpeedStepTimes(cpuSpeedTimes);
} else { } else {
BatteryStatsImpl.Uid.Proc ps = BatteryStatsImpl.Uid.Proc ps =
bstats.getProcessStatsLocked(st.name, st.pid); bstats.getProcessStatsLocked(st.name, st.pid);
if (ps != null) { if (ps != null) {
ps.addCpuTimeLocked(st.rel_utime, st.rel_stime); ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
ps.addSpeedStepTimes(cpuSpeedTimes);
} }
} }
} }

View File

@@ -28,6 +28,7 @@ import android.util.Log;
import com.android.internal.app.IBatteryStats; import com.android.internal.app.IBatteryStats;
import com.android.internal.os.BatteryStatsImpl; import com.android.internal.os.BatteryStatsImpl;
import com.android.internal.os.PowerProfile;
import java.io.FileDescriptor; import java.io.FileDescriptor;
import java.io.PrintWriter; import java.io.PrintWriter;
@@ -49,6 +50,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub {
public void publish(Context context) { public void publish(Context context) {
mContext = context; mContext = context;
ServiceManager.addService("batteryinfo", asBinder()); ServiceManager.addService("batteryinfo", asBinder());
mStats.setNumSpeedSteps(new PowerProfile(mContext).getNumSpeedSteps());
} }
public void shutdown() { public void shutdown() {