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