Skip to content

Commit 0a6dc40

Browse files
A uint64 array wrapper for optimized allocation and copying
Bug: 315052795 Bug: 357697495 Test: atest libbattery_test; atest FrameworksCoreTests Flag: EXEMPT bugfix Change-Id: I3c09c438131b3f67ef04436667e589d1d86aff71
1 parent fc8ace0 commit 0a6dc40

5 files changed

Lines changed: 231 additions & 100 deletions

File tree

libs/battery/LongArrayMultiStateCounter.cpp

Lines changed: 110 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -21,58 +21,134 @@
2121
namespace android {
2222
namespace battery {
2323

24-
template <>
25-
bool LongArrayMultiStateCounter::delta(const std::vector<uint64_t>& previousValue,
26-
const std::vector<uint64_t>& newValue,
27-
std::vector<uint64_t>* outValue) const {
28-
size_t size = previousValue.size();
29-
if (newValue.size() != size) {
30-
ALOGE("Incorrect array size: %d, should be %d", (int)newValue.size(), (int)size);
31-
return false;
24+
Uint64ArrayRW::Uint64ArrayRW(const Uint64Array &copy) : Uint64Array(copy.size()) {
25+
if (mSize != 0 && copy.data() != nullptr) {
26+
mData = new uint64_t[mSize];
27+
memcpy(mData, copy.data(), mSize * sizeof(uint64_t));
28+
} else {
29+
mData = nullptr;
3230
}
31+
}
3332

34-
bool is_delta_valid = true;
35-
for (int i = size - 1; i >= 0; i--) {
36-
if (newValue[i] >= previousValue[i]) {
37-
(*outValue)[i] = newValue[i] - previousValue[i];
33+
uint64_t *Uint64ArrayRW::dataRW() {
34+
if (mData == nullptr) {
35+
mData = new uint64_t[mSize];
36+
memset(mData, 0, mSize * sizeof(uint64_t));
37+
}
38+
return mData;
39+
}
40+
41+
Uint64ArrayRW &Uint64ArrayRW::operator=(const Uint64Array &t) {
42+
if (t.size() != mSize) {
43+
delete[] mData;
44+
mSize = t.size();
45+
mData = nullptr;
46+
}
47+
if (mSize != 0) {
48+
if (t.data() != nullptr) {
49+
mData = new uint64_t[mSize];
50+
memcpy(mData, t.data(), mSize * sizeof(uint64_t));
3851
} else {
39-
(*outValue)[i] = 0;
40-
is_delta_valid = false;
52+
mData = nullptr;
4153
}
4254
}
43-
return is_delta_valid;
55+
return *this;
56+
}
57+
58+
std::ostream &operator<<(std::ostream &os, const Uint64Array &v) {
59+
os << "{";
60+
const uint64_t *data = v.data();
61+
if (data != nullptr) {
62+
bool first = true;
63+
for (size_t i = 0; i < v.size(); i++) {
64+
if (!first) {
65+
os << ", ";
66+
}
67+
os << data[i];
68+
first = false;
69+
}
70+
}
71+
os << "}";
72+
return os;
73+
}
74+
75+
// Convenience constructor for tests
76+
Uint64ArrayRW::Uint64ArrayRW(std::initializer_list<uint64_t> init) : Uint64Array(init.size()) {
77+
mData = new uint64_t[mSize];
78+
memcpy(mData, init.begin(), mSize * sizeof(uint64_t));
79+
}
80+
81+
// Used in tests only.
82+
bool Uint64Array::operator==(const Uint64Array &other) const {
83+
if (size() != other.size()) {
84+
return false;
85+
}
86+
const uint64_t* thisData = data();
87+
const uint64_t* thatData = other.data();
88+
for (size_t i = 0; i < mSize; i++) {
89+
const uint64_t v1 = thisData != nullptr ? thisData[i] : 0;
90+
const uint64_t v2 = thatData != nullptr ? thatData[i] : 0;
91+
if (v1 != v2) {
92+
return false;
93+
}
94+
}
95+
return true;
4496
}
4597

4698
template <>
47-
void LongArrayMultiStateCounter::add(std::vector<uint64_t>* value1,
48-
const std::vector<uint64_t>& value2, const uint64_t numerator,
49-
const uint64_t denominator) const {
99+
void LongArrayMultiStateCounter::add(Uint64ArrayRW *value1, const Uint64Array &value2,
100+
const uint64_t numerator, const uint64_t denominator) const {
101+
const uint64_t* data2 = value2.data();
102+
if (data2 == nullptr) {
103+
return;
104+
}
105+
106+
uint64_t* data1 = value1->dataRW();
107+
size_t size = value2.size();
50108
if (numerator != denominator) {
51-
for (int i = value2.size() - 1; i >= 0; i--) {
109+
for (size_t i = 0; i < size; i++) {
52110
// The caller ensures that denominator != 0
53-
(*value1)[i] += value2[i] * numerator / denominator;
111+
data1[i] += data2[i] * numerator / denominator;
54112
}
55113
} else {
56-
for (int i = value2.size() - 1; i >= 0; i--) {
57-
(*value1)[i] += value2[i];
114+
for (size_t i = 0; i < size; i++) {
115+
data1[i] += data2[i];
58116
}
59117
}
60118
}
61119

62-
template <>
63-
std::string LongArrayMultiStateCounter::valueToString(const std::vector<uint64_t>& v) const {
64-
std::stringstream s;
65-
s << "{";
66-
bool first = true;
67-
for (uint64_t n : v) {
68-
if (!first) {
69-
s << ", ";
120+
template<>
121+
bool LongArrayMultiStateCounter::delta(const Uint64ArrayRW &previousValue,
122+
const Uint64Array &newValue, Uint64ArrayRW *outValue) const {
123+
size_t size = previousValue.size();
124+
if (newValue.size() != size) {
125+
ALOGE("Incorrect array size: %d, should be %d", (int) newValue.size(), (int) size);
126+
return false;
127+
}
128+
if (outValue->size() != size) {
129+
ALOGE("Incorrect outValue size: %d, should be %d", (int) outValue->size(), (int) size);
130+
return false;
131+
}
132+
133+
bool is_delta_valid = true;
134+
const uint64_t *prevData = previousValue.data();
135+
const uint64_t *newData = newValue.data();
136+
uint64_t *outData = outValue->dataRW();
137+
for (size_t i = 0; i < size; i++) {
138+
if (prevData == nullptr) {
139+
if (newData == nullptr) {
140+
outData[i] = 0;
141+
} else {
142+
outData[i] = newData[i];
143+
}
144+
} else if (newData == nullptr || newData[i] < prevData[i]) {
145+
outData[i] = 0;
146+
is_delta_valid = false;
147+
} else {
148+
outData[i] = newData[i] - prevData[i];
70149
}
71-
s << n;
72-
first = false;
73150
}
74-
s << "}";
75-
return s.str();
151+
return is_delta_valid;
76152
}
77153

78154
} // namespace battery

libs/battery/LongArrayMultiStateCounter.h

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,66 @@
2323
namespace android {
2424
namespace battery {
2525

26-
typedef MultiStateCounter<std::vector<uint64_t>> LongArrayMultiStateCounter;
26+
/**
27+
* Wrapper for an array of uint64's.
28+
*/
29+
class Uint64Array {
30+
protected:
31+
size_t mSize;
32+
33+
public:
34+
Uint64Array() : Uint64Array(0) {}
35+
36+
Uint64Array(size_t size) : mSize(size) {}
37+
38+
virtual ~Uint64Array() {}
39+
40+
size_t size() const { return mSize; }
41+
42+
/**
43+
* Returns the wrapped array.
44+
*
45+
* Nullable! Null should be interpreted the same as an array of zeros
46+
*/
47+
virtual const uint64_t *data() const { return nullptr; }
48+
49+
friend std::ostream &operator<<(std::ostream &os, const Uint64Array &v);
50+
51+
// Test API
52+
bool operator==(const Uint64Array &other) const;
53+
};
54+
55+
/**
56+
* Mutable version of Uint64Array.
57+
*/
58+
class Uint64ArrayRW: public Uint64Array {
59+
uint64_t* mData;
60+
61+
public:
62+
Uint64ArrayRW() : Uint64ArrayRW(0) {}
63+
64+
Uint64ArrayRW(size_t size) : Uint64Array(size), mData(nullptr) {}
65+
66+
Uint64ArrayRW(const Uint64Array &copy);
67+
68+
// Need an explicit copy constructor. In the initialization context C++ does not understand that
69+
// a Uint64ArrayRW is a Uint64Array.
70+
Uint64ArrayRW(const Uint64ArrayRW &copy) : Uint64ArrayRW((const Uint64Array &) copy) {}
71+
72+
// Test API
73+
Uint64ArrayRW(std::initializer_list<uint64_t> init);
74+
75+
~Uint64ArrayRW() override { delete[] mData; }
76+
77+
const uint64_t *data() const override { return mData; }
78+
79+
// NonNull. Will initialize the wrapped array if it is null.
80+
uint64_t *dataRW();
81+
82+
Uint64ArrayRW &operator=(const Uint64Array &t);
83+
};
84+
85+
typedef MultiStateCounter<Uint64ArrayRW, Uint64Array> LongArrayMultiStateCounter;
2786

2887
} // namespace battery
2988
} // namespace android

libs/battery/LongArrayMultiStateCounterTest.cpp

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -24,42 +24,42 @@ namespace battery {
2424
class LongArrayMultiStateCounterTest : public testing::Test {};
2525

2626
TEST_F(LongArrayMultiStateCounterTest, stateChange) {
27-
LongArrayMultiStateCounter testCounter(2, std::vector<uint64_t>(4));
28-
testCounter.updateValue(std::vector<uint64_t>({0, 0, 0, 0}), 1000);
27+
LongArrayMultiStateCounter testCounter(2, Uint64Array(4));
28+
testCounter.updateValue(Uint64ArrayRW({0, 0, 0, 0}), 1000);
2929
testCounter.setState(0, 1000);
3030
testCounter.setState(1, 2000);
31-
testCounter.updateValue(std::vector<uint64_t>({100, 200, 300, 400}), 3000);
31+
testCounter.updateValue(Uint64ArrayRW({100, 200, 300, 400}), 3000);
3232

3333
// Time was split in half between the two states, so the counts will be split 50:50 too
34-
EXPECT_EQ(std::vector<uint64_t>({50, 100, 150, 200}), testCounter.getCount(0));
35-
EXPECT_EQ(std::vector<uint64_t>({50, 100, 150, 200}), testCounter.getCount(1));
34+
EXPECT_EQ(Uint64ArrayRW({50, 100, 150, 200}), testCounter.getCount(0));
35+
EXPECT_EQ(Uint64ArrayRW({50, 100, 150, 200}), testCounter.getCount(1));
3636
}
3737

3838
TEST_F(LongArrayMultiStateCounterTest, accumulation) {
39-
LongArrayMultiStateCounter testCounter(2, std::vector<uint64_t>(4));
40-
testCounter.updateValue(std::vector<uint64_t>({0, 0, 0, 0}), 1000);
39+
LongArrayMultiStateCounter testCounter(2, Uint64Array(4));
40+
testCounter.updateValue(Uint64ArrayRW({0, 0, 0, 0}), 1000);
4141
testCounter.setState(0, 1000);
4242
testCounter.setState(1, 2000);
43-
testCounter.updateValue(std::vector<uint64_t>({100, 200, 300, 400}), 3000);
43+
testCounter.updateValue(Uint64ArrayRW({100, 200, 300, 400}), 3000);
4444
testCounter.setState(0, 4000);
45-
testCounter.updateValue(std::vector<uint64_t>({200, 300, 400, 500}), 8000);
45+
testCounter.updateValue(Uint64ArrayRW({200, 300, 400, 500}), 8000);
4646

4747
// The first delta is split 50:50:
4848
// 0: {50, 100, 150, 200}
4949
// 1: {50, 100, 150, 200}
5050
// The second delta is split 4:1
5151
// 0: {80, 80, 80, 80}
5252
// 1: {20, 20, 20, 20}
53-
EXPECT_EQ(std::vector<uint64_t>({130, 180, 230, 280}), testCounter.getCount(0));
54-
EXPECT_EQ(std::vector<uint64_t>({70, 120, 170, 220}), testCounter.getCount(1));
53+
EXPECT_EQ(Uint64ArrayRW({130, 180, 230, 280}), testCounter.getCount(0));
54+
EXPECT_EQ(Uint64ArrayRW({70, 120, 170, 220}), testCounter.getCount(1));
5555
}
5656

5757
TEST_F(LongArrayMultiStateCounterTest, toString) {
58-
LongArrayMultiStateCounter testCounter(2, std::vector<uint64_t>(4));
59-
testCounter.updateValue(std::vector<uint64_t>({0, 0, 0, 0}), 1000);
58+
LongArrayMultiStateCounter testCounter(2, Uint64Array(4));
59+
testCounter.updateValue(Uint64ArrayRW({0, 0, 0, 0}), 1000);
6060
testCounter.setState(0, 1000);
6161
testCounter.setState(1, 2000);
62-
testCounter.updateValue(std::vector<uint64_t>({100, 200, 300, 400}), 3000);
62+
testCounter.updateValue(Uint64ArrayRW({100, 200, 300, 400}), 3000);
6363

6464
EXPECT_STREQ("[0: {50, 100, 150, 200}, 1: {50, 100, 150, 200}] updated: 3000 currentState: 1",
6565
testCounter.toString().c_str());

0 commit comments

Comments
 (0)