Fix incorrect interpolation of active bucket for partial requests.

Just because the bucket is active (ie. overlaps with 'now') doesn't
mean the request necessarily covers the entire bucket.

For example a bucketDuration=5 with a bucket from curStart=1 to
curEnd=6 with now=4 and requests:
- from start=0 to end=3 --> overlap=[1,3] --> bucketSpan=2
- from start=2 to end=3 --> overlap=[2,3] --> bucketSpan=1
- from start=2 to end=5 --> overlap=[2,4] --> bucketSpan=2
- from start=2 to end=7 --> overlap=[2,4] --> bucketSpan=2
and the previously correctly handled cases:
- from start=0 to end=5 --> overlap=[1,4] --> bucketSpan=3
- from start=0 to end=7 --> overlap=[1,4] --> bucketSpan=3

We fix this by bounding the end of buckets to now, this means
that bucketDuration is no longer a constant, but it simplifies
all the rest of the logic.

Test: builds, atest
Bug: 143338233
Signed-off-by: Maciej Żenczykowski <maze@google.com>
Change-Id: I642b57f7b8486071ad7808fd9b901859923b6d25
This commit is contained in:
Maciej Żenczykowski
2020-01-27 17:36:56 -08:00
parent 79e97166a8
commit 2b92fa5323

View File

@@ -548,32 +548,32 @@ public class NetworkStatsHistory implements Parcelable {
final int startIndex = getIndexAfter(end); final int startIndex = getIndexAfter(end);
for (int i = startIndex; i >= 0; i--) { for (int i = startIndex; i >= 0; i--) {
final long curStart = bucketStart[i]; final long curStart = bucketStart[i];
final long curEnd = curStart + bucketDuration; long curEnd = curStart + bucketDuration;
// bucket is older than request; we're finished // bucket is older than request; we're finished
if (curEnd <= start) break; if (curEnd <= start) break;
// bucket is newer than request; keep looking // bucket is newer than request; keep looking
if (curStart >= end) continue; if (curStart >= end) continue;
// include full value for active buckets, otherwise only fractional // the active bucket is shorter then a normal completed bucket
final boolean activeBucket = curStart < now && curEnd > now; if (curEnd > now) curEnd = now;
final long overlap; // usually this is simply bucketDuration
if (activeBucket) { final long bucketSpan = curEnd - curStart;
overlap = bucketDuration; // prevent division by zero
} else { if (bucketSpan <= 0) continue;
final long overlapEnd = curEnd < end ? curEnd : end;
final long overlapStart = curStart > start ? curStart : start; final long overlapEnd = curEnd < end ? curEnd : end;
overlap = overlapEnd - overlapStart; final long overlapStart = curStart > start ? curStart : start;
} final long overlap = overlapEnd - overlapStart;
if (overlap <= 0) continue; if (overlap <= 0) continue;
// integer math each time is faster than floating point // integer math each time is faster than floating point
if (activeTime != null) entry.activeTime += activeTime[i] * overlap / bucketDuration; if (activeTime != null) entry.activeTime += activeTime[i] * overlap / bucketSpan;
if (rxBytes != null) entry.rxBytes += rxBytes[i] * overlap / bucketDuration; if (rxBytes != null) entry.rxBytes += rxBytes[i] * overlap / bucketSpan;
if (rxPackets != null) entry.rxPackets += rxPackets[i] * overlap / bucketDuration; if (rxPackets != null) entry.rxPackets += rxPackets[i] * overlap / bucketSpan;
if (txBytes != null) entry.txBytes += txBytes[i] * overlap / bucketDuration; if (txBytes != null) entry.txBytes += txBytes[i] * overlap / bucketSpan;
if (txPackets != null) entry.txPackets += txPackets[i] * overlap / bucketDuration; if (txPackets != null) entry.txPackets += txPackets[i] * overlap / bucketSpan;
if (operations != null) entry.operations += operations[i] * overlap / bucketDuration; if (operations != null) entry.operations += operations[i] * overlap / bucketSpan;
} }
return entry; return entry;
} }