creating workflow for mirror::String compression
All-ASCII String characters are stored in 8-bit blocks
instead of 16-bit. The compression has not taken place, but all
workflow are in the code already (changing kUseStringCompression in
string.h file to TRUE will enable the feature)
Notes: Feature works on interpreter only without optimizing
Test art: m ART_TEST_INTERPRETER=true ART_TEST_OPTIMIZING=false
test-art-host
Also tested with String tests from libcore/:
1. libcore.java.lang.StringTest
2. libcore.java.lang.StringBufferTest
3. libcore.java.lang.StringBuilderTest
4. libcore.java.lang.OldStringTest
5. libcore.java.lang.OldStringBufferTest
Memory improvement is 33% (from 6.03% to 4.03%, total String memory
from all apps per total memory of all apps) measured on Angler
with Hprof tools
Bug: 31040547
Change-Id: I9cc92c265ebf1305fc06b5fc33efd83797660cce
diff --git a/runtime/hprof/hprof.cc b/runtime/hprof/hprof.cc
index 9895395..4005f05 100644
--- a/runtime/hprof/hprof.cc
+++ b/runtime/hprof/hprof.cc
@@ -223,6 +223,12 @@
HandleU1List(values, count);
length_ += count;
}
+ void AddU1AsU2List(const uint8_t* values, size_t count) {
+ HandleU1AsU2List(values, count);
+ // Array of char from compressed String (8-bit) is added as 16-bit blocks
+ int ceil_count_to_even = count + ((count & 1) ? 1 : 0);
+ length_ += ceil_count_to_even * sizeof(uint8_t);
+ }
void AddU2List(const uint16_t* values, size_t count) {
HandleU2List(values, count);
length_ += count * sizeof(uint16_t);
@@ -268,6 +274,9 @@
virtual void HandleU1List(const uint8_t* values ATTRIBUTE_UNUSED,
size_t count ATTRIBUTE_UNUSED) {
}
+ virtual void HandleU1AsU2List(const uint8_t* values ATTRIBUTE_UNUSED,
+ size_t count ATTRIBUTE_UNUSED) {
+ }
virtual void HandleU2List(const uint16_t* values ATTRIBUTE_UNUSED,
size_t count ATTRIBUTE_UNUSED) {
}
@@ -308,6 +317,19 @@
buffer_.insert(buffer_.end(), values, values + count);
}
+ void HandleU1AsU2List(const uint8_t* values, size_t count) OVERRIDE {
+ DCHECK_EQ(length_, buffer_.size());
+ // All 8-bits are grouped in 2 to make 16-bit block like Java Char
+ if (count & 1) {
+ buffer_.push_back(0);
+ }
+ for (size_t i = 0; i < count; ++i) {
+ uint8_t value = *values;
+ buffer_.push_back(value);
+ values++;
+ }
+ }
+
void HandleU2List(const uint16_t* values, size_t count) OVERRIDE {
DCHECK_EQ(length_, buffer_.size());
for (size_t i = 0; i < count; ++i) {
@@ -1354,7 +1376,11 @@
string_value = reinterpret_cast<mirror::Object*>(
reinterpret_cast<uintptr_t>(s) + kObjectAlignment);
} else {
- string_value = reinterpret_cast<mirror::Object*>(s->GetValue());
+ if (s->IsCompressed()) {
+ string_value = reinterpret_cast<mirror::Object*>(s->GetValueCompressed());
+ } else {
+ string_value = reinterpret_cast<mirror::Object*>(s->GetValue());
+ }
}
__ AddObjectId(string_value);
}
@@ -1369,12 +1395,18 @@
CHECK_EQ(obj->IsString(), string_value != nullptr);
if (string_value != nullptr) {
mirror::String* s = obj->AsString();
+ // Compressed string's (8-bit) length is ceil(length/2) in 16-bit blocks
+ int length_in_16_bit = (s->IsCompressed()) ? ((s->GetLength() + 1) / 2) : s->GetLength();
__ AddU1(HPROF_PRIMITIVE_ARRAY_DUMP);
__ AddObjectId(string_value);
__ AddStackTraceSerialNumber(LookupStackTraceSerialNumber(obj));
- __ AddU4(s->GetLength());
+ __ AddU4(length_in_16_bit);
__ AddU1(hprof_basic_char);
- __ AddU2List(s->GetValue(), s->GetLength());
+ if (s->IsCompressed()) {
+ __ AddU1AsU2List(s->GetValueCompressed(), s->GetLength());
+ } else {
+ __ AddU2List(s->GetValue(), s->GetLength());
+ }
}
}