diff options
author | Jeff Sharkey <jsharkey@android.com> | 2011-06-11 22:16:55 -0700 |
---|---|---|
committer | Jeff Sharkey <jsharkey@android.com> | 2011-06-11 22:17:17 -0700 |
commit | 4a97122ebf4d92a3f94402041729d77905e6c0c0 (patch) | |
tree | 2dce98de643ebbfe98c06c70b54d743362a900d2 | |
parent | 39ebc2195ed16b9e955dd57f5c95212bb7b934b6 (diff) | |
download | frameworks_base-4a97122ebf4d92a3f94402041729d77905e6c0c0.zip frameworks_base-4a97122ebf4d92a3f94402041729d77905e6c0c0.tar.gz frameworks_base-4a97122ebf4d92a3f94402041729d77905e6c0c0.tar.bz2 |
Growable NetworkStats object instead of builder.
NetworkStats now grows in place with arraycopy() instead of callers
needing to know record count a priori. Better growth calculation for
both NetworkStats and NetworkStatsHistory; 50% each time. Better
estimates of buckets needed in calling services.
Change-Id: I3adbffa0b7407612cc6349d9135a8b4eb63cd440
8 files changed, 130 insertions, 101 deletions
diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index 6354e9a..60f740e 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -23,6 +23,7 @@ import android.util.SparseBooleanArray; import java.io.CharArrayWriter; import java.io.PrintWriter; +import java.util.Arrays; import java.util.HashSet; /** @@ -48,74 +49,60 @@ public class NetworkStats implements Parcelable { * generated. */ public final long elapsedRealtime; - public final String[] iface; - public final int[] uid; - public final long[] rx; - public final long[] tx; + public int size; + public String[] iface; + public int[] uid; + public long[] rx; + public long[] tx; // TODO: add fg/bg stats once reported by kernel - private NetworkStats(long elapsedRealtime, String[] iface, int[] uid, long[] rx, long[] tx) { + public NetworkStats(long elapsedRealtime, int initialSize) { this.elapsedRealtime = elapsedRealtime; - this.iface = iface; - this.uid = uid; - this.rx = rx; - this.tx = tx; + this.size = 0; + this.iface = new String[initialSize]; + this.uid = new int[initialSize]; + this.rx = new long[initialSize]; + this.tx = new long[initialSize]; } public NetworkStats(Parcel parcel) { elapsedRealtime = parcel.readLong(); + size = parcel.readInt(); iface = parcel.createStringArray(); uid = parcel.createIntArray(); rx = parcel.createLongArray(); tx = parcel.createLongArray(); } - public static class Builder { - private long mElapsedRealtime; - private final String[] mIface; - private final int[] mUid; - private final long[] mRx; - private final long[] mTx; - - private int mIndex = 0; - - public Builder(long elapsedRealtime, int size) { - mElapsedRealtime = elapsedRealtime; - mIface = new String[size]; - mUid = new int[size]; - mRx = new long[size]; - mTx = new long[size]; + public NetworkStats addEntry(String iface, int uid, long rx, long tx) { + if (size >= this.iface.length) { + final int newLength = Math.max(this.iface.length, 10) * 3 / 2; + this.iface = Arrays.copyOf(this.iface, newLength); + this.uid = Arrays.copyOf(this.uid, newLength); + this.rx = Arrays.copyOf(this.rx, newLength); + this.tx = Arrays.copyOf(this.tx, newLength); } - public Builder addEntry(String iface, int uid, long rx, long tx) { - mIface[mIndex] = iface; - mUid[mIndex] = uid; - mRx[mIndex] = rx; - mTx[mIndex] = tx; - mIndex++; - return this; - } + this.iface[size] = iface; + this.uid[size] = uid; + this.rx[size] = rx; + this.tx[size] = tx; + size++; - public NetworkStats build() { - if (mIndex != mIface.length) { - throw new IllegalArgumentException("unexpected number of entries"); - } - return new NetworkStats(mElapsedRealtime, mIface, mUid, mRx, mTx); - } + return this; } + @Deprecated public int length() { - // length is identical for all fields - return iface.length; + return size; } /** * Find first stats index that matches the requested parameters. */ public int findIndex(String iface, int uid) { - final int length = length(); - for (int i = 0; i < length; i++) { + for (int i = 0; i < size; i++) { if (equal(iface, this.iface[i]) && uid == this.uid[i]) { return i; } @@ -195,9 +182,8 @@ public class NetworkStats implements Parcelable { } // result will have our rows, and elapsed time between snapshots - final int length = length(); - final NetworkStats.Builder result = new NetworkStats.Builder(deltaRealtime, length); - for (int i = 0; i < length; i++) { + final NetworkStats result = new NetworkStats(deltaRealtime, size); + for (int i = 0; i < size; i++) { final String iface = this.iface[i]; final int uid = this.uid[i]; @@ -221,7 +207,7 @@ public class NetworkStats implements Parcelable { } } - return result.build(); + return result; } private static boolean equal(Object a, Object b) { @@ -255,6 +241,7 @@ public class NetworkStats implements Parcelable { /** {@inheritDoc} */ public void writeToParcel(Parcel dest, int flags) { dest.writeLong(elapsedRealtime); + dest.writeInt(size); dest.writeStringArray(iface); dest.writeIntArray(uid); dest.writeLongArray(rx); diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java index a697e96..5fa8e21 100644 --- a/core/java/android/net/NetworkStatsHistory.java +++ b/core/java/android/net/NetworkStatsHistory.java @@ -53,11 +53,15 @@ public class NetworkStatsHistory implements Parcelable { public long[] tx; public NetworkStatsHistory(long bucketDuration) { + this(bucketDuration, 10); + } + + public NetworkStatsHistory(long bucketDuration, int initialSize) { this.bucketDuration = bucketDuration; - bucketStart = new long[0]; - rx = new long[0]; - tx = new long[0]; - bucketCount = bucketStart.length; + bucketStart = new long[initialSize]; + rx = new long[initialSize]; + tx = new long[initialSize]; + bucketCount = 0; } public NetworkStatsHistory(Parcel in) { @@ -168,8 +172,8 @@ public class NetworkStatsHistory implements Parcelable { */ private void insertBucket(int index, long start) { // create more buckets when needed - if (bucketCount + 1 > bucketStart.length) { - final int newLength = bucketStart.length + 10; + if (bucketCount >= bucketStart.length) { + final int newLength = Math.max(bucketStart.length, 10) * 3 / 2; bucketStart = Arrays.copyOf(bucketStart, newLength); rx = Arrays.copyOf(rx, newLength); tx = Arrays.copyOf(tx, newLength); diff --git a/core/tests/coretests/src/android/net/NetworkStatsTest.java b/core/tests/coretests/src/android/net/NetworkStatsTest.java index 8a3e871..5250a7c 100644 --- a/core/tests/coretests/src/android/net/NetworkStatsTest.java +++ b/core/tests/coretests/src/android/net/NetworkStatsTest.java @@ -16,7 +16,6 @@ package android.net; -import android.os.SystemClock; import android.test.suitebuilder.annotation.SmallTest; import junit.framework.TestCase; @@ -25,12 +24,14 @@ import junit.framework.TestCase; public class NetworkStatsTest extends TestCase { private static final String TEST_IFACE = "test0"; + private static final int TEST_UID = 1001; + private static final long TEST_START = 1194220800000L; public void testFindIndex() throws Exception { - final NetworkStats stats = new NetworkStats.Builder(SystemClock.elapsedRealtime(), 3) + final NetworkStats stats = new NetworkStats(TEST_START, 3) .addEntry(TEST_IFACE, 100, 1024, 0) .addEntry(TEST_IFACE, 101, 0, 1024) - .addEntry(TEST_IFACE, 102, 1024, 1024).build(); + .addEntry(TEST_IFACE, 102, 1024, 1024); assertEquals(2, stats.findIndex(TEST_IFACE, 102)); assertEquals(2, stats.findIndex(TEST_IFACE, 102)); @@ -38,14 +39,40 @@ public class NetworkStatsTest extends TestCase { assertEquals(-1, stats.findIndex(TEST_IFACE, 6)); } + public void testAddEntryGrow() throws Exception { + final NetworkStats stats = new NetworkStats(TEST_START, 2); + + assertEquals(0, stats.size); + assertEquals(2, stats.iface.length); + + stats.addEntry(TEST_IFACE, TEST_UID, 1L, 2L); + stats.addEntry(TEST_IFACE, TEST_UID, 2L, 2L); + + assertEquals(2, stats.size); + assertEquals(2, stats.iface.length); + + stats.addEntry(TEST_IFACE, TEST_UID, 3L, 4L); + stats.addEntry(TEST_IFACE, TEST_UID, 4L, 4L); + stats.addEntry(TEST_IFACE, TEST_UID, 5L, 5L); + + assertEquals(5, stats.size); + assertTrue(stats.iface.length >= 5); + + assertEquals(1L, stats.rx[0]); + assertEquals(2L, stats.rx[1]); + assertEquals(3L, stats.rx[2]); + assertEquals(4L, stats.rx[3]); + assertEquals(5L, stats.rx[4]); + } + public void testSubtractIdenticalData() throws Exception { - final NetworkStats before = new NetworkStats.Builder(SystemClock.elapsedRealtime(), 2) + final NetworkStats before = new NetworkStats(TEST_START, 2) .addEntry(TEST_IFACE, 100, 1024, 0) - .addEntry(TEST_IFACE, 101, 0, 1024).build(); + .addEntry(TEST_IFACE, 101, 0, 1024); - final NetworkStats after = new NetworkStats.Builder(SystemClock.elapsedRealtime(), 2) + final NetworkStats after = new NetworkStats(TEST_START, 2) .addEntry(TEST_IFACE, 100, 1024, 0) - .addEntry(TEST_IFACE, 101, 0, 1024).build(); + .addEntry(TEST_IFACE, 101, 0, 1024); final NetworkStats result = after.subtract(before); @@ -57,13 +84,13 @@ public class NetworkStatsTest extends TestCase { } public void testSubtractIdenticalRows() throws Exception { - final NetworkStats before = new NetworkStats.Builder(SystemClock.elapsedRealtime(), 2) + final NetworkStats before = new NetworkStats(TEST_START, 2) .addEntry(TEST_IFACE, 100, 1024, 0) - .addEntry(TEST_IFACE, 101, 0, 1024).build(); + .addEntry(TEST_IFACE, 101, 0, 1024); - final NetworkStats after = new NetworkStats.Builder(SystemClock.elapsedRealtime(), 2) + final NetworkStats after = new NetworkStats(TEST_START, 2) .addEntry(TEST_IFACE, 100, 1025, 2) - .addEntry(TEST_IFACE, 101, 3, 1028).build(); + .addEntry(TEST_IFACE, 101, 3, 1028); final NetworkStats result = after.subtract(before); @@ -75,14 +102,14 @@ public class NetworkStatsTest extends TestCase { } public void testSubtractNewRows() throws Exception { - final NetworkStats before = new NetworkStats.Builder(SystemClock.elapsedRealtime(), 2) + final NetworkStats before = new NetworkStats(TEST_START, 2) .addEntry(TEST_IFACE, 100, 1024, 0) - .addEntry(TEST_IFACE, 101, 0, 1024).build(); + .addEntry(TEST_IFACE, 101, 0, 1024); - final NetworkStats after = new NetworkStats.Builder(SystemClock.elapsedRealtime(), 3) + final NetworkStats after = new NetworkStats(TEST_START, 3) .addEntry(TEST_IFACE, 100, 1024, 0) .addEntry(TEST_IFACE, 101, 0, 1024) - .addEntry(TEST_IFACE, 102, 1024, 1024).build(); + .addEntry(TEST_IFACE, 102, 1024, 1024); final NetworkStats result = after.subtract(before); diff --git a/services/java/com/android/server/NetworkManagementService.java b/services/java/com/android/server/NetworkManagementService.java index 8f179f5..2190b30 100644 --- a/services/java/com/android/server/NetworkManagementService.java +++ b/services/java/com/android/server/NetworkManagementService.java @@ -882,8 +882,7 @@ class NetworkManagementService extends INetworkManagementService.Stub { android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService"); final String[] ifaces = listInterfaces(); - final NetworkStats.Builder stats = new NetworkStats.Builder( - SystemClock.elapsedRealtime(), ifaces.length); + final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), ifaces.length); for (String iface : ifaces) { final long rx = getInterfaceCounter(iface, true); @@ -891,7 +890,7 @@ class NetworkManagementService extends INetworkManagementService.Stub { stats.addEntry(iface, NetworkStats.UID_ALL, rx, tx); } - return stats.build(); + return stats; } @Override @@ -900,7 +899,7 @@ class NetworkManagementService extends INetworkManagementService.Stub { android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService"); final String[] knownUids = PATH_PROC_UID_STAT.list(); - final NetworkStats.Builder stats = new NetworkStats.Builder( + final NetworkStats stats = new NetworkStats( SystemClock.elapsedRealtime(), knownUids.length); for (String uid : knownUids) { @@ -908,7 +907,7 @@ class NetworkManagementService extends INetworkManagementService.Stub { collectNetworkStatsDetail(stats, uidInt); } - return stats.build(); + return stats; } @Override @@ -918,13 +917,12 @@ class NetworkManagementService extends INetworkManagementService.Stub { android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService"); } - final NetworkStats.Builder stats = new NetworkStats.Builder( - SystemClock.elapsedRealtime(), 1); + final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 1); collectNetworkStatsDetail(stats, uid); - return stats.build(); + return stats; } - private void collectNetworkStatsDetail(NetworkStats.Builder stats, int uid) { + private void collectNetworkStatsDetail(NetworkStats stats, int uid) { // TODO: kernel module will provide interface-level stats in future // TODO: migrate these stats to come across netd in bulk, instead of all // these individual file reads. diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index f5d01d6..de69849 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -255,7 +255,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // combine all interfaces that match template final String subscriberId = getActiveSubscriberId(); final NetworkStatsHistory combined = new NetworkStatsHistory( - mSettings.getNetworkBucketDuration()); + mSettings.getNetworkBucketDuration(), estimateNetworkBuckets()); for (InterfaceIdentity ident : mNetworkStats.keySet()) { final NetworkStatsHistory history = mNetworkStats.get(ident); if (ident.matchesTemplate(networkTemplate, subscriberId)) { @@ -297,9 +297,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } - final NetworkStats.Builder stats = new NetworkStats.Builder(end - start, 1); + final NetworkStats stats = new NetworkStats(end - start, 1); stats.addEntry(IFACE_ALL, UID_ALL, tx, tx); - return stats.build(); + return stats; } } @@ -313,7 +313,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { ensureUidStatsLoadedLocked(); final int size = mUidStats.size(); - final NetworkStats.Builder stats = new NetworkStats.Builder(end - start, size); + final NetworkStats stats = new NetworkStats(end - start, size); long[] total = new long[2]; for (int i = 0; i < size; i++) { @@ -322,7 +322,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { total = history.getTotalData(start, end, total); stats.addEntry(IFACE_ALL, uid, total[0], total[1]); } - return stats.build(); + return stats; } } @@ -510,9 +510,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // update when no existing, or when bucket duration changed NetworkStatsHistory updated = null; if (existing == null) { - updated = new NetworkStatsHistory(bucketDuration); + updated = new NetworkStatsHistory(bucketDuration, 10); } else if (existing.bucketDuration != bucketDuration) { - updated = new NetworkStatsHistory(bucketDuration); + updated = new NetworkStatsHistory( + bucketDuration, estimateResizeBuckets(existing, bucketDuration)); updated.recordEntireHistory(existing); } @@ -531,9 +532,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // update when no existing, or when bucket duration changed NetworkStatsHistory updated = null; if (existing == null) { - updated = new NetworkStatsHistory(bucketDuration); + updated = new NetworkStatsHistory(bucketDuration, 10); } else if (existing.bucketDuration != bucketDuration) { - updated = new NetworkStatsHistory(bucketDuration); + updated = new NetworkStatsHistory( + bucketDuration, estimateResizeBuckets(existing, bucketDuration)); updated.recordEntireHistory(existing); } @@ -809,6 +811,18 @@ public class NetworkStatsService extends INetworkStatsService.Stub { return telephony.getSubscriberId(); } + private int estimateNetworkBuckets() { + return (int) (mSettings.getNetworkMaxHistory() / mSettings.getNetworkBucketDuration()); + } + + private int estimateUidBuckets() { + return (int) (mSettings.getUidMaxHistory() / mSettings.getUidBucketDuration()); + } + + private static int estimateResizeBuckets(NetworkStatsHistory existing, long newBucketDuration) { + return (int) (existing.bucketCount * existing.bucketDuration / newBucketDuration); + } + /** * Default external settings that read from {@link Settings.Secure}. */ diff --git a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java index 1eeb56b..f831ca3 100644 --- a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java @@ -357,8 +357,8 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase { expectTime(TIME_MAR_10 + elapsedRealtime); // pretend that 512 bytes total have happened - stats = new NetworkStats.Builder(elapsedRealtime, 1).addEntry( - TEST_IFACE, UID_ALL, 256L, 256L).build(); + stats = new NetworkStats(elapsedRealtime, 1) + .addEntry(TEST_IFACE, UID_ALL, 256L, 256L); expect(mStatsService.getSummaryForNetwork(TIME_FEB_15, TIME_MAR_10, TEMPLATE_WIFI, null)) .andReturn(stats).atLeastOnce(); diff --git a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java index d6e4b8b..2457ff3 100644 --- a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java @@ -145,8 +145,8 @@ public class NetworkStatsServiceTest extends AndroidTestCase { elapsedRealtime += HOUR_IN_MILLIS; expectTime(TEST_START + elapsedRealtime); expectDefaultSettings(); - expectNetworkStatsSummary(new NetworkStats.Builder(elapsedRealtime, 1) - .addEntry(TEST_IFACE, UID_ALL, 1024L, 2048L).build()); + expectNetworkStatsSummary(new NetworkStats(elapsedRealtime, 1) + .addEntry(TEST_IFACE, UID_ALL, 1024L, 2048L)); expectNetworkStatsDetail(buildEmptyStats(elapsedRealtime)); replay(); @@ -161,8 +161,8 @@ public class NetworkStatsServiceTest extends AndroidTestCase { elapsedRealtime += DAY_IN_MILLIS; expectTime(TEST_START + elapsedRealtime); expectDefaultSettings(); - expectNetworkStatsSummary(new NetworkStats.Builder(elapsedRealtime, 1) - .addEntry(TEST_IFACE, UID_ALL, 4096L, 8192L).build()); + expectNetworkStatsSummary(new NetworkStats(elapsedRealtime, 1) + .addEntry(TEST_IFACE, UID_ALL, 4096L, 8192L)); expectNetworkStatsDetail(buildEmptyStats(elapsedRealtime)); replay(); @@ -196,12 +196,12 @@ public class NetworkStatsServiceTest extends AndroidTestCase { elapsedRealtime += HOUR_IN_MILLIS; expectTime(TEST_START + elapsedRealtime); expectDefaultSettings(); - expectNetworkStatsSummary(new NetworkStats.Builder(elapsedRealtime, 1) - .addEntry(TEST_IFACE, UID_ALL, 1024L, 2048L).build()); + expectNetworkStatsSummary(new NetworkStats(elapsedRealtime, 1) + .addEntry(TEST_IFACE, UID_ALL, 1024L, 2048L)); // TODO: switch these stats to specific iface - expectNetworkStatsDetail(new NetworkStats.Builder(elapsedRealtime, 2) + expectNetworkStatsDetail(new NetworkStats(elapsedRealtime, 2) .addEntry(IFACE_ALL, TEST_UID_1, 512L, 256L) - .addEntry(IFACE_ALL, TEST_UID_2, 128L, 128L).build()); + .addEntry(IFACE_ALL, TEST_UID_2, 128L, 128L)); replay(); mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL)); @@ -262,8 +262,8 @@ public class NetworkStatsServiceTest extends AndroidTestCase { elapsedRealtime += 2 * HOUR_IN_MILLIS; expectTime(TEST_START + elapsedRealtime); expectSettings(0L, HOUR_IN_MILLIS, WEEK_IN_MILLIS); - expectNetworkStatsSummary(new NetworkStats.Builder(elapsedRealtime, 1) - .addEntry(TEST_IFACE, UID_ALL, 512L, 512L).build()); + expectNetworkStatsSummary(new NetworkStats(elapsedRealtime, 1) + .addEntry(TEST_IFACE, UID_ALL, 512L, 512L)); expectNetworkStatsDetail(buildEmptyStats(elapsedRealtime)); replay(); @@ -378,7 +378,7 @@ public class NetworkStatsServiceTest extends AndroidTestCase { } private static NetworkStats buildEmptyStats(long elapsedRealtime) { - return new NetworkStats.Builder(elapsedRealtime, 0).build(); + return new NetworkStats(elapsedRealtime, 0); } private void replay() { diff --git a/services/tests/servicestests/src/com/android/server/ThrottleServiceTest.java b/services/tests/servicestests/src/com/android/server/ThrottleServiceTest.java index d1ee4f6..30afdd8 100644 --- a/services/tests/servicestests/src/com/android/server/ThrottleServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/ThrottleServiceTest.java @@ -288,11 +288,10 @@ public class ThrottleServiceTest extends AndroidTestCase { */ public void expectGetInterfaceCounter(long rx, long tx) throws Exception { // TODO: provide elapsedRealtime mock to match TimeAuthority - final NetworkStats.Builder stats = new NetworkStats.Builder( - SystemClock.elapsedRealtime(), 1); + final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 1); stats.addEntry(TEST_IFACE, NetworkStats.UID_ALL, rx, tx); - expect(mMockNMService.getNetworkStatsSummary()).andReturn(stats.build()).atLeastOnce(); + expect(mMockNMService.getNetworkStatsSummary()).andReturn(stats).atLeastOnce(); } /** |