Merge "Fix issue #28602068: Add count to job scheduler stats" into nyc-dev

am: d90be6cccc

* commit 'd90be6cccca683e34566f5550ebb34f1c8e75b69':
  Fix issue #28602068: Add count to job scheduler stats

Change-Id: I60628c4c2150b51b34ad192bbca29bfd420e4b2f
This commit is contained in:
Dianne Hackborn
2016-05-05 22:02:18 +00:00
committed by android-build-merger
2 changed files with 157 additions and 57 deletions

View File

@@ -0,0 +1,82 @@
/*
* Copyright (C) 2016 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.internal.util;
/**
* Helper class for implementing a ring buffer. This supplies the indices, you supply
* the array(s).
*/
public class RingBufferIndices {
private final int mCapacity;
// The first valid element and the next open slot.
private int mStart;
private int mSize;
/**
* Create ring buffer of the given capacity.
*/
public RingBufferIndices(int capacity) {
mCapacity = capacity;
}
/**
* Add a new item to the ring buffer. If the ring buffer is full, this
* replaces the oldest item.
* @return Returns the index at which the new item appears, for placing in your array.
*/
public int add() {
if (mSize < mCapacity) {
final int pos = mSize;
mSize++;
return pos;
}
int pos = mStart;
mStart++;
if (mStart == mCapacity) {
mStart = 0;
}
return pos;
}
/**
* Clear the ring buffer.
*/
public void clear() {
mStart = 0;
mSize = 0;
}
/**
* Return the current size of the ring buffer.
*/
public int size() {
return mSize;
}
/**
* Convert a position in the ring buffer that is [0..size()] to an offset
* in the array(s) containing the ring buffer items.
*/
public int indexOf(int pos) {
int index = mStart + pos;
if (index >= mCapacity) {
index -= mCapacity;
}
return index;
}
}

View File

@@ -23,6 +23,7 @@ import android.text.format.DateFormat;
import android.util.ArrayMap; import android.util.ArrayMap;
import android.util.SparseArray; import android.util.SparseArray;
import android.util.TimeUtils; import android.util.TimeUtils;
import com.android.internal.util.RingBufferIndices;
import com.android.server.job.controllers.JobStatus; import com.android.server.job.controllers.JobStatus;
import java.io.PrintWriter; import java.io.PrintWriter;
@@ -33,26 +34,24 @@ public final class JobPackageTracker {
// Number of historical data sets we keep. // Number of historical data sets we keep.
static final int NUM_HISTORY = 5; static final int NUM_HISTORY = 5;
private static final int EVENT_BUFFER_SIZE = 50; private static final int EVENT_BUFFER_SIZE = 100;
public static final int EVENT_NULL = 0; public static final int EVENT_NULL = 0;
public static final int EVENT_START_JOB = 1; public static final int EVENT_START_JOB = 1;
public static final int EVENT_STOP_JOB = 2; public static final int EVENT_STOP_JOB = 2;
private int[] mEventCmds = new int[EVENT_BUFFER_SIZE]; private final RingBufferIndices mEventIndices = new RingBufferIndices(EVENT_BUFFER_SIZE);
private long[] mEventTimes = new long[EVENT_BUFFER_SIZE]; private final int[] mEventCmds = new int[EVENT_BUFFER_SIZE];
private int[] mEventUids = new int[EVENT_BUFFER_SIZE]; private final long[] mEventTimes = new long[EVENT_BUFFER_SIZE];
private String[] mEventTags = new String[EVENT_BUFFER_SIZE]; private final int[] mEventUids = new int[EVENT_BUFFER_SIZE];
private final String[] mEventTags = new String[EVENT_BUFFER_SIZE];
public void addEvent(int cmd, int uid, String tag) { public void addEvent(int cmd, int uid, String tag) {
System.arraycopy(mEventCmds, 0, mEventCmds, 1, EVENT_BUFFER_SIZE - 1); int index = mEventIndices.add();
System.arraycopy(mEventTimes, 0, mEventTimes, 1, EVENT_BUFFER_SIZE - 1); mEventCmds[index] = cmd;
System.arraycopy(mEventUids, 0, mEventUids, 1, EVENT_BUFFER_SIZE - 1); mEventTimes[index] = SystemClock.elapsedRealtime();
System.arraycopy(mEventTags, 0, mEventTags, 1, EVENT_BUFFER_SIZE - 1); mEventUids[index] = uid;
mEventCmds[0] = cmd; mEventTags[index] = tag;
mEventTimes[0] = SystemClock.elapsedRealtime();
mEventUids[0] = uid;
mEventTags[0] = tag;
} }
DataSet mCurDataSet = new DataSet(); DataSet mCurDataSet = new DataSet();
@@ -61,20 +60,23 @@ public final class JobPackageTracker {
final static class PackageEntry { final static class PackageEntry {
long pastActiveTime; long pastActiveTime;
long activeStartTime; long activeStartTime;
int activeNesting;
int activeCount; int activeCount;
boolean hadActive; boolean hadActive;
long pastActiveTopTime; long pastActiveTopTime;
long activeTopStartTime; long activeTopStartTime;
int activeTopNesting;
int activeTopCount; int activeTopCount;
boolean hadActiveTop; boolean hadActiveTop;
long pastPendingTime; long pastPendingTime;
long pendingStartTime; long pendingStartTime;
int pendingNesting;
int pendingCount; int pendingCount;
boolean hadPending; boolean hadPending;
public long getActiveTime(long now) { public long getActiveTime(long now) {
long time = pastActiveTime; long time = pastActiveTime;
if (activeCount > 0) { if (activeNesting > 0) {
time += now - activeStartTime; time += now - activeStartTime;
} }
return time; return time;
@@ -82,7 +84,7 @@ public final class JobPackageTracker {
public long getActiveTopTime(long now) { public long getActiveTopTime(long now) {
long time = pastActiveTopTime; long time = pastActiveTopTime;
if (activeTopCount > 0) { if (activeTopNesting > 0) {
time += now - activeTopStartTime; time += now - activeTopStartTime;
} }
return time; return time;
@@ -90,7 +92,7 @@ public final class JobPackageTracker {
public long getPendingTime(long now) { public long getPendingTime(long now) {
long time = pastPendingTime; long time = pastPendingTime;
if (pendingCount > 0) { if (pendingNesting > 0) {
time += now - pendingStartTime; time += now - pendingStartTime;
} }
return time; return time;
@@ -147,50 +149,53 @@ public final class JobPackageTracker {
void incPending(int uid, String pkg, long now) { void incPending(int uid, String pkg, long now) {
PackageEntry pe = getOrCreateEntry(uid, pkg); PackageEntry pe = getOrCreateEntry(uid, pkg);
if (pe.pendingCount == 0) { if (pe.pendingNesting == 0) {
pe.pendingStartTime = now; pe.pendingStartTime = now;
pe.pendingCount++;
} }
pe.pendingCount++; pe.pendingNesting++;
} }
void decPending(int uid, String pkg, long now) { void decPending(int uid, String pkg, long now) {
PackageEntry pe = getOrCreateEntry(uid, pkg); PackageEntry pe = getOrCreateEntry(uid, pkg);
if (pe.pendingCount == 1) { if (pe.pendingNesting == 1) {
pe.pastPendingTime += now - pe.pendingStartTime; pe.pastPendingTime += now - pe.pendingStartTime;
} }
pe.pendingCount--; pe.pendingNesting--;
} }
void incActive(int uid, String pkg, long now) { void incActive(int uid, String pkg, long now) {
PackageEntry pe = getOrCreateEntry(uid, pkg); PackageEntry pe = getOrCreateEntry(uid, pkg);
if (pe.activeCount == 0) { if (pe.activeNesting == 0) {
pe.activeStartTime = now; pe.activeStartTime = now;
pe.activeCount++;
} }
pe.activeCount++; pe.activeNesting++;
} }
void decActive(int uid, String pkg, long now) { void decActive(int uid, String pkg, long now) {
PackageEntry pe = getOrCreateEntry(uid, pkg); PackageEntry pe = getOrCreateEntry(uid, pkg);
if (pe.activeCount == 1) { if (pe.activeNesting == 1) {
pe.pastActiveTime += now - pe.activeStartTime; pe.pastActiveTime += now - pe.activeStartTime;
} }
pe.activeCount--; pe.activeNesting--;
} }
void incActiveTop(int uid, String pkg, long now) { void incActiveTop(int uid, String pkg, long now) {
PackageEntry pe = getOrCreateEntry(uid, pkg); PackageEntry pe = getOrCreateEntry(uid, pkg);
if (pe.activeTopCount == 0) { if (pe.activeTopNesting == 0) {
pe.activeTopStartTime = now; pe.activeTopStartTime = now;
pe.activeTopCount++;
} }
pe.activeTopCount++; pe.activeTopNesting++;
} }
void decActiveTop(int uid, String pkg, long now) { void decActiveTop(int uid, String pkg, long now) {
PackageEntry pe = getOrCreateEntry(uid, pkg); PackageEntry pe = getOrCreateEntry(uid, pkg);
if (pe.activeTopCount == 1) { if (pe.activeTopNesting == 1) {
pe.pastActiveTopTime += now - pe.activeTopStartTime; pe.pastActiveTopTime += now - pe.activeTopStartTime;
} }
pe.activeTopCount--; pe.activeTopNesting--;
} }
void finish(DataSet next, long now) { void finish(DataSet next, long now) {
@@ -198,27 +203,27 @@ public final class JobPackageTracker {
ArrayMap<String, PackageEntry> uidMap = mEntries.valueAt(i); ArrayMap<String, PackageEntry> uidMap = mEntries.valueAt(i);
for (int j = uidMap.size() - 1; j >= 0; j--) { for (int j = uidMap.size() - 1; j >= 0; j--) {
PackageEntry pe = uidMap.valueAt(j); PackageEntry pe = uidMap.valueAt(j);
if (pe.activeCount > 0 || pe.activeTopCount > 0 || pe.pendingCount > 0) { if (pe.activeNesting > 0 || pe.activeTopNesting > 0 || pe.pendingNesting > 0) {
// Propagate existing activity in to next data set. // Propagate existing activity in to next data set.
PackageEntry nextPe = next.getOrCreateEntry(mEntries.keyAt(i), uidMap.keyAt(j)); PackageEntry nextPe = next.getOrCreateEntry(mEntries.keyAt(i), uidMap.keyAt(j));
nextPe.activeStartTime = now; nextPe.activeStartTime = now;
nextPe.activeCount = pe.activeCount; nextPe.activeNesting = pe.activeNesting;
nextPe.activeTopStartTime = now; nextPe.activeTopStartTime = now;
nextPe.activeTopCount = pe.activeTopCount; nextPe.activeTopNesting = pe.activeTopNesting;
nextPe.pendingStartTime = now; nextPe.pendingStartTime = now;
nextPe.pendingCount = pe.pendingCount; nextPe.pendingNesting = pe.pendingNesting;
// Finish it off. // Finish it off.
if (pe.activeCount > 0) { if (pe.activeNesting > 0) {
pe.pastActiveTime += now - pe.activeStartTime; pe.pastActiveTime += now - pe.activeStartTime;
pe.activeCount = 0; pe.activeNesting = 0;
} }
if (pe.activeTopCount > 0) { if (pe.activeTopNesting > 0) {
pe.pastActiveTopTime += now - pe.activeTopStartTime; pe.pastActiveTopTime += now - pe.activeTopStartTime;
pe.activeTopCount = 0; pe.activeTopNesting = 0;
} }
if (pe.pendingCount > 0) { if (pe.pendingNesting > 0) {
pe.pastPendingTime += now - pe.pendingStartTime; pe.pastPendingTime += now - pe.pendingStartTime;
pe.pendingCount = 0; pe.pendingNesting = 0;
} }
} }
} }
@@ -233,17 +238,20 @@ public final class JobPackageTracker {
PackageEntry pe = uidMap.valueAt(j); PackageEntry pe = uidMap.valueAt(j);
PackageEntry outPe = out.getOrCreateEntry(mEntries.keyAt(i), uidMap.keyAt(j)); PackageEntry outPe = out.getOrCreateEntry(mEntries.keyAt(i), uidMap.keyAt(j));
outPe.pastActiveTime += pe.pastActiveTime; outPe.pastActiveTime += pe.pastActiveTime;
outPe.activeCount += pe.activeCount;
outPe.pastActiveTopTime += pe.pastActiveTopTime; outPe.pastActiveTopTime += pe.pastActiveTopTime;
outPe.activeTopCount += pe.activeTopCount;
outPe.pastPendingTime += pe.pastPendingTime; outPe.pastPendingTime += pe.pastPendingTime;
if (pe.activeCount > 0) { outPe.pendingCount += pe.pendingCount;
if (pe.activeNesting > 0) {
outPe.pastActiveTime += now - pe.activeStartTime; outPe.pastActiveTime += now - pe.activeStartTime;
outPe.hadActive = true; outPe.hadActive = true;
} }
if (pe.activeTopCount > 0) { if (pe.activeTopNesting > 0) {
outPe.pastActiveTopTime += now - pe.activeTopStartTime; outPe.pastActiveTopTime += now - pe.activeTopStartTime;
outPe.hadActiveTop = true; outPe.hadActiveTop = true;
} }
if (pe.pendingCount > 0) { if (pe.pendingNesting > 0) {
outPe.pastPendingTime += now - pe.pendingStartTime; outPe.pastPendingTime += now - pe.pendingStartTime;
outPe.hadPending = true; outPe.hadPending = true;
} }
@@ -251,13 +259,20 @@ public final class JobPackageTracker {
} }
} }
void printDuration(PrintWriter pw, long period, long duration, String suffix) { void printDuration(PrintWriter pw, long period, long duration, int count, String suffix) {
float fraction = duration / (float) period; float fraction = duration / (float) period;
int percent = (int) ((fraction * 100) + .5f); int percent = (int) ((fraction * 100) + .5f);
if (percent > 0) { if (percent > 0) {
pw.print(" "); pw.print(" ");
pw.print(percent); pw.print(percent);
pw.print("% "); pw.print("% ");
pw.print(count);
pw.print("x ");
pw.print(suffix);
} else if (count > 0) {
pw.print(" ");
pw.print(count);
pw.print("x ");
pw.print(suffix); pw.print(suffix);
} }
} }
@@ -286,16 +301,17 @@ public final class JobPackageTracker {
UserHandle.formatUid(pw, uid); UserHandle.formatUid(pw, uid);
pw.print(" / "); pw.print(uidMap.keyAt(j)); pw.print(" / "); pw.print(uidMap.keyAt(j));
pw.print(":"); pw.print(":");
printDuration(pw, period, pe.getPendingTime(now), "pending"); printDuration(pw, period, pe.getPendingTime(now), pe.pendingCount, "pending");
printDuration(pw, period, pe.getActiveTime(now), "active"); printDuration(pw, period, pe.getActiveTime(now), pe.activeCount, "active");
printDuration(pw, period, pe.getActiveTopTime(now), "active-top"); printDuration(pw, period, pe.getActiveTopTime(now), pe.activeTopCount,
if (pe.pendingCount > 0 || pe.hadPending) { "active-top");
if (pe.pendingNesting > 0 || pe.hadPending) {
pw.print(" (pending)"); pw.print(" (pending)");
} }
if (pe.activeCount > 0 || pe.hadActive) { if (pe.activeNesting > 0 || pe.hadActive) {
pw.print(" (active)"); pw.print(" (active)");
} }
if (pe.activeTopCount > 0 || pe.hadActiveTop) { if (pe.activeTopNesting > 0 || pe.hadActiveTop) {
pw.print(" (active-top)"); pw.print(" (active-top)");
} }
pw.println(); pw.println();
@@ -389,34 +405,36 @@ public final class JobPackageTracker {
} }
public boolean dumpHistory(PrintWriter pw, String prefix, int filterUid) { public boolean dumpHistory(PrintWriter pw, String prefix, int filterUid) {
if (mEventCmds[0] == EVENT_NULL) { final int size = mEventIndices.size();
if (size <= 0) {
return false; return false;
} }
pw.println(" Job history:"); pw.println(" Job history:");
long now = SystemClock.elapsedRealtime(); final long now = SystemClock.elapsedRealtime();
for (int i=EVENT_BUFFER_SIZE-1; i>=0; i--) { for (int i=0; i<size; i++) {
int uid = mEventUids[i]; final int index = mEventIndices.indexOf(i);
final int uid = mEventUids[index];
if (filterUid != -1 && filterUid != UserHandle.getAppId(filterUid)) { if (filterUid != -1 && filterUid != UserHandle.getAppId(filterUid)) {
continue; continue;
} }
int cmd = mEventCmds[i]; final int cmd = mEventCmds[index];
if (cmd == EVENT_NULL) { if (cmd == EVENT_NULL) {
continue; continue;
} }
String label; final String label;
switch (mEventCmds[i]) { switch (mEventCmds[index]) {
case EVENT_START_JOB: label = "START"; break; case EVENT_START_JOB: label = "START"; break;
case EVENT_STOP_JOB: label = " STOP"; break; case EVENT_STOP_JOB: label = " STOP"; break;
default: label = " ??"; break; default: label = " ??"; break;
} }
pw.print(prefix); pw.print(prefix);
TimeUtils.formatDuration(mEventTimes[i]-now, pw, TimeUtils.HUNDRED_DAY_FIELD_LEN); TimeUtils.formatDuration(mEventTimes[index]-now, pw, TimeUtils.HUNDRED_DAY_FIELD_LEN);
pw.print(" "); pw.print(" ");
pw.print(label); pw.print(label);
pw.print(": "); pw.print(": ");
UserHandle.formatUid(pw, uid); UserHandle.formatUid(pw, uid);
pw.print(" "); pw.print(" ");
pw.println(mEventTags[i]); pw.println(mEventTags[index]);
} }
return true; return true;
} }