From b10824574cdb21a31b14f9538c64414b62462953 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Sun, 18 Sep 2011 13:30:23 -0700 Subject: [PATCH] DO NOT MERGE: Sample atomic network stats buckets, full poll. When sampling network stats, always use atomic buckets instead of interpolating. Always poll iface and UID together so we distribute into buckets equally. Move stale bucket trimming to just before writing stats. Bug: 5321340 Change-Id: I78a2226778a79c875f3668336e39ea24a7b4d5c4 --- .../java/android/net/NetworkStatsHistory.java | 9 +- .../server/net/NetworkStatsService.java | 168 ++++++++---------- 2 files changed, 79 insertions(+), 98 deletions(-) diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java index d8ac31f277..a5cdf70325 100644 --- a/core/java/android/net/NetworkStatsHistory.java +++ b/core/java/android/net/NetworkStatsHistory.java @@ -441,10 +441,10 @@ public class NetworkStatsHistory implements Parcelable { final long curStart = bucketStart[i]; final long curEnd = curStart + bucketDuration; - // bucket is older than record; we're finished - if (curEnd < start) break; - // bucket is newer than record; keep looking - if (curStart > end) continue; + // bucket is older than request; we're finished + if (curEnd <= start) break; + // bucket is newer than request; keep looking + if (curStart >= end) continue; // include full value for active buckets, otherwise only fractional final boolean activeBucket = curStart < now && curEnd > now; @@ -466,7 +466,6 @@ public class NetworkStatsHistory implements Parcelable { if (txPackets != null) entry.txPackets += txPackets[i] * overlap / bucketDuration; if (operations != null) entry.operations += operations[i] * overlap / bucketDuration; } - return entry; } diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index bb5f015de6..947cf9c2d8 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -36,7 +36,6 @@ import static android.net.NetworkTemplate.buildTemplateMobileAll; import static android.net.NetworkTemplate.buildTemplateWifi; import static android.net.TrafficStats.UID_REMOVED; import static android.net.TrafficStats.UID_TETHERING; -import static android.provider.Settings.Secure.NETSTATS_FORCE_COMPLETE_POLL; import static android.provider.Settings.Secure.NETSTATS_NETWORK_BUCKET_DURATION; import static android.provider.Settings.Secure.NETSTATS_NETWORK_MAX_HISTORY; import static android.provider.Settings.Secure.NETSTATS_PERSIST_THRESHOLD; @@ -136,15 +135,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private static final int MSG_PERFORM_POLL = 0x1; /** Flags to control detail level of poll event. */ - private static final int FLAG_POLL_NETWORK = 0x1; - private static final int FLAG_POLL_UID = 0x2; - private static final int FLAG_POLL_TETHER = 0x3; private static final int FLAG_PERSIST_NETWORK = 0x10; private static final int FLAG_PERSIST_UID = 0x20; - private static final int FLAG_FORCE_PERSIST = 0x100; - - private static final int FLAG_POLL_ALL = FLAG_POLL_NETWORK | FLAG_POLL_UID | FLAG_POLL_TETHER; private static final int FLAG_PERSIST_ALL = FLAG_PERSIST_NETWORK | FLAG_PERSIST_UID; + private static final int FLAG_PERSIST_FORCE = 0x100; private final Context mContext; private final INetworkManagementService mNetworkManager; @@ -182,7 +176,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { public long getUidMaxHistory(); public long getTagMaxHistory(); public long getTimeCacheMaxAge(); - public boolean getForceCompletePoll(); } private final Object mStatsLock = new Object(); @@ -529,7 +522,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public void forceUpdate() { mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG); - performPoll(FLAG_POLL_ALL | FLAG_PERSIST_ALL); + performPoll(FLAG_PERSIST_ALL); } /** @@ -561,7 +554,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { public void onReceive(Context context, Intent intent) { // on background handler thread, and verified CONNECTIVITY_INTERNAL // permission above. - performPoll(FLAG_POLL_TETHER); + performPoll(FLAG_PERSIST_NETWORK); } }; @@ -570,7 +563,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { public void onReceive(Context context, Intent intent) { // on background handler thread, and verified UPDATE_DEVICE_STATS // permission above. - performPoll(FLAG_POLL_ALL | FLAG_PERSIST_ALL); + performPoll(FLAG_PERSIST_ALL); // verify that we're watching global alert registerGlobalAlert(); @@ -617,7 +610,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { if (LIMIT_GLOBAL_ALERT.equals(limitName)) { // kick off background poll to collect network stats; UID stats // are handled during normal polling interval. - final int flags = FLAG_POLL_NETWORK | FLAG_PERSIST_NETWORK; + final int flags = FLAG_PERSIST_NETWORK; mHandler.obtainMessage(MSG_PERFORM_POLL, flags, 0).sendToTarget(); // re-arm global alert for next update @@ -639,10 +632,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // isn't perfect, since the kernel may already be counting traffic from // the updated network. - // poll both network and UID stats, but only persist network stats, - // since this codepath should stay fast. UID stats will be persisted - // during next alarm poll event. - performPollLocked(FLAG_POLL_ALL | FLAG_PERSIST_NETWORK); + // poll, but only persist network stats to keep codepath fast. UID stats + // will be persisted during next alarm poll event. + performPollLocked(FLAG_PERSIST_NETWORK); final NetworkState[] states; try { @@ -706,21 +698,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { if (LOGV) Slog.v(TAG, "performPollLocked(flags=0x" + Integer.toHexString(flags) + ")"); final long startRealtime = SystemClock.elapsedRealtime(); - boolean pollNetwork = (flags & FLAG_POLL_NETWORK) != 0; - boolean pollUid = (flags & FLAG_POLL_UID) != 0; - boolean pollTether = (flags & FLAG_POLL_TETHER) != 0; - - // when complete poll requested, any partial poll enables everything - final boolean forceCompletePoll = mSettings.getForceCompletePoll(); - if (forceCompletePoll && (pollNetwork || pollUid || pollTether)) { - pollNetwork = true; - pollUid = true; - pollTether = true; - } - final boolean persistNetwork = (flags & FLAG_PERSIST_NETWORK) != 0; final boolean persistUid = (flags & FLAG_PERSIST_UID) != 0; - final boolean forcePersist = (flags & FLAG_FORCE_PERSIST) != 0; + final boolean persistForce = (flags & FLAG_PERSIST_FORCE) != 0; // try refreshing time source when stale if (mTime.getCacheAge() > mSettings.getTimeCacheMaxAge()) { @@ -733,41 +713,36 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final long threshold = mSettings.getPersistThreshold(); try { - if (pollNetwork) { - final NetworkStats networkSnapshot = mNetworkManager.getNetworkStatsSummary(); - performNetworkPollLocked(networkSnapshot, currentTime); + // record network stats + final NetworkStats networkSnapshot = mNetworkManager.getNetworkStatsSummary(); + performNetworkPollLocked(networkSnapshot, currentTime); - // persist when enough network data has occurred - final NetworkStats persistNetworkDelta = computeStatsDelta( - mLastPersistNetworkSnapshot, networkSnapshot, true); - final boolean pastThreshold = persistNetworkDelta.getTotalBytes() > threshold; - if (forcePersist || (persistNetwork && pastThreshold)) { - writeNetworkStatsLocked(); - mLastPersistNetworkSnapshot = networkSnapshot; - } + // persist when enough network data has occurred + final NetworkStats persistNetworkDelta = computeStatsDelta( + mLastPersistNetworkSnapshot, networkSnapshot, true); + final boolean networkPastThreshold = persistNetworkDelta.getTotalBytes() > threshold; + if (persistForce || (persistNetwork && networkPastThreshold)) { + writeNetworkStatsLocked(); + mLastPersistNetworkSnapshot = networkSnapshot; } - if (pollTether) { - final String[] ifacePairs = mConnManager.getTetheredIfacePairs(); - final NetworkStats tetherSnapshot = mNetworkManager.getNetworkStatsTethering( - ifacePairs); - performTetherPollLocked(tetherSnapshot, currentTime); + // record tethering stats; persisted during normal UID cycle below + final String[] ifacePairs = mConnManager.getTetheredIfacePairs(); + final NetworkStats tetherSnapshot = mNetworkManager.getNetworkStatsTethering( + ifacePairs); + performTetherPollLocked(tetherSnapshot, currentTime); - // persisted during normal UID cycle below - } + // record uid stats + final NetworkStats uidSnapshot = mNetworkManager.getNetworkStatsUidDetail(UID_ALL); + performUidPollLocked(uidSnapshot, currentTime); - if (pollUid) { - final NetworkStats uidSnapshot = mNetworkManager.getNetworkStatsUidDetail(UID_ALL); - performUidPollLocked(uidSnapshot, currentTime); - - // persist when enough network data has occurred - final NetworkStats persistUidDelta = computeStatsDelta( - mLastPersistUidSnapshot, uidSnapshot, true); - final boolean pastThreshold = persistUidDelta.getTotalBytes() > threshold; - if (forcePersist || (persistUid && pastThreshold)) { - writeUidStatsLocked(); - mLastPersistUidSnapshot = uidSnapshot; - } + // persist when enough network data has occurred + final NetworkStats persistUidDelta = computeStatsDelta( + mLastPersistUidSnapshot, uidSnapshot, true); + final boolean uidPastThreshold = persistUidDelta.getTotalBytes() > threshold; + if (persistForce || (persistUid && uidPastThreshold)) { + writeUidStatsLocked(); + mLastPersistUidSnapshot = uidSnapshot; } } catch (IllegalStateException e) { Log.wtf(TAG, "problem reading network stats", e); @@ -781,9 +756,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } // sample stats after each full poll - if (pollNetwork && pollUid) { - performSample(); - } + performSample(); // finally, dispatch updated event to any listeners final Intent updatedIntent = new Intent(ACTION_NETWORK_STATS_UPDATED); @@ -813,12 +786,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { history.recordData(timeStart, currentTime, entry); } - // trim any history beyond max - final long maxHistory = mSettings.getNetworkMaxHistory(); - for (NetworkStatsHistory history : mNetworkStats.values()) { - history.removeBucketsBefore(currentTime - maxHistory); - } - mLastPollNetworkSnapshot = networkSnapshot; if (LOGD && unknownIface.size() > 0) { @@ -862,20 +829,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { history.recordData(timeStart, currentTime, entry); } - // trim any history beyond max - final long maxUidHistory = mSettings.getUidMaxHistory(); - final long maxTagHistory = mSettings.getTagMaxHistory(); - for (UidStatsKey key : mUidStats.keySet()) { - final NetworkStatsHistory history = mUidStats.get(key); - - // detailed tags are trimmed sooner than summary in TAG_NONE - if (key.tag == TAG_NONE) { - history.removeBucketsBefore(currentTime - maxUidHistory); - } else { - history.removeBucketsBefore(currentTime - maxTagHistory); - } - } - mLastPollUidSnapshot = uidSnapshot; mLastPollOperationsSnapshot = mOperations; mOperations = new NetworkStats(0L, 10); @@ -917,9 +870,13 @@ public class NetworkStatsService extends INetworkStatsService.Stub { * Sample recent statistics summary into {@link EventLog}. */ private void performSample() { - // take sample as total over last 4 hours - final long end = mTime.hasCache() ? mTime.currentTimeMillis() : System.currentTimeMillis(); - final long start = end - (4 * HOUR_IN_MILLIS); + final long largestBucketSize = Math.max( + mSettings.getNetworkBucketDuration(), mSettings.getUidBucketDuration()); + + // take sample as atomic buckets + final long now = mTime.hasCache() ? mTime.currentTimeMillis() : System.currentTimeMillis(); + final long end = now - (now % largestBucketSize) + largestBucketSize; + final long start = end - largestBucketSize; NetworkTemplate template = null; NetworkStats.Entry ifaceTotal = null; @@ -929,15 +886,17 @@ public class NetworkStatsService extends INetworkStatsService.Stub { template = buildTemplateMobileAll(getActiveSubscriberId(mContext)); ifaceTotal = getSummaryForNetwork(template, start, end).getTotal(ifaceTotal); uidTotal = getSummaryForAllUid(template, start, end, false).getTotal(uidTotal); - EventLogTags.writeNetstatsMobileSample( - ifaceTotal.rxBytes, ifaceTotal.txBytes, uidTotal.rxBytes, uidTotal.txBytes); + EventLogTags.writeNetstatsMobileSample(ifaceTotal.rxBytes, ifaceTotal.rxPackets, + ifaceTotal.txBytes, ifaceTotal.txPackets, uidTotal.rxBytes, uidTotal.rxPackets, + uidTotal.txBytes, uidTotal.rxPackets); // collect wifi sample template = buildTemplateWifi(); ifaceTotal = getSummaryForNetwork(template, start, end).getTotal(ifaceTotal); uidTotal = getSummaryForAllUid(template, start, end, false).getTotal(uidTotal); - EventLogTags.writeNetstatsWifiSample( - ifaceTotal.rxBytes, ifaceTotal.txBytes, uidTotal.rxBytes, uidTotal.txBytes); + EventLogTags.writeNetstatsWifiSample(ifaceTotal.rxBytes, ifaceTotal.rxPackets, + ifaceTotal.txBytes, ifaceTotal.txPackets, uidTotal.rxBytes, uidTotal.rxPackets, + uidTotal.txBytes, uidTotal.rxPackets); } /** @@ -1137,6 +1096,15 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // TODO: consider duplicating stats and releasing lock while writing + // trim any history beyond max + if (mTime.hasCache()) { + final long currentTime = mTime.currentTimeMillis(); + final long maxHistory = mSettings.getNetworkMaxHistory(); + for (NetworkStatsHistory history : mNetworkStats.values()) { + history.removeBucketsBefore(currentTime - maxHistory); + } + } + FileOutputStream fos = null; try { fos = mNetworkFile.startWrite(); @@ -1172,6 +1140,23 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // TODO: consider duplicating stats and releasing lock while writing + // trim any history beyond max + if (mTime.hasCache()) { + final long currentTime = mTime.currentTimeMillis(); + final long maxUidHistory = mSettings.getUidMaxHistory(); + final long maxTagHistory = mSettings.getTagMaxHistory(); + for (UidStatsKey key : mUidStats.keySet()) { + final NetworkStatsHistory history = mUidStats.get(key); + + // detailed tags are trimmed sooner than summary in TAG_NONE + if (key.tag == TAG_NONE) { + history.removeBucketsBefore(currentTime - maxUidHistory); + } else { + history.removeBucketsBefore(currentTime - maxTagHistory); + } + } + } + // build UidStatsKey lists grouped by ident final HashMap> keysByIdent = Maps.newHashMap(); for (UidStatsKey key : mUidStats.keySet()) { @@ -1236,7 +1221,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } if (argSet.contains("poll")) { - performPollLocked(FLAG_POLL_ALL | FLAG_PERSIST_ALL | FLAG_FORCE_PERSIST); + performPollLocked(FLAG_PERSIST_ALL | FLAG_PERSIST_FORCE); pw.println("Forced poll"); return; } @@ -1464,8 +1449,5 @@ public class NetworkStatsService extends INetworkStatsService.Stub { public long getTimeCacheMaxAge() { return DAY_IN_MILLIS; } - public boolean getForceCompletePoll() { - return getSecureBoolean(NETSTATS_FORCE_COMPLETE_POLL, false); - } } }