1 /*
2  * Copyright (C) 2010 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef A_TRAFFIC_RECORDER_H_
18 
19 #define A_TRAFFIC_RECORDER_H_
20 
21 #include <android-base/logging.h>
22 #include <utils/RefBase.h>
23 
24 namespace android {
25 
26 // Circular array to save recent amount of bytes
27 template <class Time, class Bytes>
28 class TrafficRecorder : public RefBase {
29 private:
30     constexpr static size_t kMinNumEntries = 4;
31     constexpr static size_t kMaxNumEntries = 1024;
32 
33     size_t mSize;
34     size_t mSizeMask;
35     Time *mTimeArray = NULL;
36     Bytes *mBytesArray = NULL;
37     size_t mHeadIdx;
38     size_t mTailIdx;
39 
40     int mLastReadIdx;
41 
42     const Time mRecordLimit;
43     Time mClock;
44     Time mLastTimeOfPrint;
45     Bytes mAccuBytes;
46 
47 public:
48     TrafficRecorder(size_t size, Time accuTimeLimit);
49     virtual ~TrafficRecorder();
50 
51     void init();
52     void updateClock(Time now);
53     Bytes readBytesForTotal();
54     Bytes readBytesForLastPeriod(Time period);
55     void writeBytes(Bytes bytes);
56     void printAccuBitsForLastPeriod(Time period, Time unit);
57 };
58 
59 template <class Time, class Bytes>
TrafficRecorder(size_t size,Time recordLimit)60 TrafficRecorder<Time, Bytes>::TrafficRecorder(size_t size, Time recordLimit)
61     : mRecordLimit(recordLimit) {
62     if (size > kMaxNumEntries) {
63         LOG(VERBOSE) << "Limiting TrafficRecorder size to " << kMaxNumEntries;
64         size = kMaxNumEntries;
65     } else if (size < kMinNumEntries) {
66         LOG(VERBOSE) << "Limiting TrafficRecorder size to " << kMaxNumEntries;
67         size = kMinNumEntries;
68     }
69 
70     size_t exp = ((sizeof(size_t) == 8) ?
71                   64 - __builtin_clzl(size - 1) :
72                   32 - __builtin_clz(size - 1));
73     mSize = (1ul << exp);         // size = 2^exp
74     mSizeMask = mSize - 1;
75 
76     LOG(VERBOSE) << "TrafficRecorder Init size " << mSize;
77     mTimeArray = new Time[mSize];
78     mBytesArray = new Bytes[mSize];
79 
80     init();
81 }
82 
83 template <class Time, class Bytes>
~TrafficRecorder()84 TrafficRecorder<Time, Bytes>::~TrafficRecorder() {
85     delete[] mTimeArray;
86     delete[] mBytesArray;
87 }
88 
89 template <class Time, class Bytes>
init()90 void TrafficRecorder<Time, Bytes>::init() {
91     mHeadIdx = 0;
92     mTailIdx = mSizeMask;
93     for (int i = 0 ; i < mSize ; i++) {
94         mTimeArray[i] = 0;
95         mBytesArray[i] = 0;
96     }
97     mClock = 0;
98     mLastReadIdx = 0;
99     mLastTimeOfPrint = 0;
100     mAccuBytes = 0;
101 }
102 
103 template <class Time, class Bytes>
updateClock(Time now)104 void TrafficRecorder<Time, Bytes>::updateClock(Time now) {
105     mClock = now;
106 }
107 
108 template <class Time, class Bytes>
readBytesForTotal()109 Bytes TrafficRecorder<Time, Bytes>::readBytesForTotal() {
110     return mAccuBytes;
111 }
112 
113 template <class Time, class Bytes>
readBytesForLastPeriod(Time period)114 Bytes TrafficRecorder<Time, Bytes>::readBytesForLastPeriod(Time period) {
115     // Not enough data
116     if (period > mClock)
117         return 0;
118 
119     Bytes bytes = 0;
120     int i = mHeadIdx;
121     while (i != mTailIdx) {
122         LOG(VERBOSE) << "READ " << i << " time " << mTimeArray[i]
123                 << " \t EndOfPeriod " << mClock - period
124                 << "\t\t Bytes:" << mBytesArray[i] << "\t\t Accu: " << bytes;
125         if (mTimeArray[i] < mClock - period) {
126             break;
127         }
128         bytes += mBytesArray[i];
129         i = (i - 1) & mSizeMask;
130     }
131     mLastReadIdx = (i + 1) & mSizeMask;
132 
133     return bytes;
134 }
135 
136 template <class Time, class Bytes>
writeBytes(Bytes bytes)137 void TrafficRecorder<Time, Bytes>::writeBytes(Bytes bytes) {
138     int writeIdx;
139     if (mClock == mTimeArray[mHeadIdx]) {
140         writeIdx = mHeadIdx;
141         mBytesArray[writeIdx] += bytes;
142     } else {
143         writeIdx = (mHeadIdx + 1) & mSizeMask;
144         mTimeArray[writeIdx] = mClock;
145         mBytesArray[writeIdx] = bytes;
146     }
147 
148     LOG(VERBOSE) << "WRITE " << writeIdx << " time " << mClock;
149     if (writeIdx == mTailIdx) {
150         mTailIdx = (mTailIdx + 1) & mSizeMask;
151     }
152 
153     mHeadIdx = writeIdx;
154     mAccuBytes += bytes;
155 }
156 
157 template <class Time, class Bytes>
printAccuBitsForLastPeriod(Time period,Time unit)158 void TrafficRecorder<Time, Bytes>::printAccuBitsForLastPeriod(Time period, Time unit) {
159     Time timeSinceLastPrint = mClock - mLastTimeOfPrint;
160     if (timeSinceLastPrint < period)
161         return;
162 
163     Bytes sum = readBytesForLastPeriod(period);
164     Time readPeriod = mClock - mTimeArray[mLastReadIdx];
165 
166     float numOfUnit = (float)(readPeriod) / (unit + FLT_MIN);
167     ALOGD("Actual Tx period %.3f unit \t %.0f bytes (%.0f Kbits)/Unit",
168           numOfUnit, sum / numOfUnit, sum * 8.f / numOfUnit / 1000.f);
169     mLastTimeOfPrint = mClock;
170 
171     if (mClock - mTimeArray[mTailIdx] < mRecordLimit) {
172         // Size is not enough to record bytes for mRecordLimit period
173         ALOGW("Traffic recorder size is not enough. mRecordLimit %d", mRecordLimit);
174     }
175 }
176 
177 }  // namespace android
178 
179 #endif  // A_TRAFFIC_RECORDER_H_
180