dart-sdk/runtime/vm/bitmap_test.cc
Vyacheslav Egorov 13d27d669d [vm] Improve Code cluster layout for startup
This change bakes binary search table which maps PC ranges
to corresponding stack maps and Code objects (if still present
in the snapshot) into RO data section of the snapshot - instead
of constructing it at load time.

This allows to considerably reduce amount of work done when
loading Code cluster for programs which have majority of their
Code objects discarded (i.e. in DWARF stack traces mode): as
we no longer write / read any information for discarded Code
objects.

This CL also changes program visitor to deduplicate Code objects
if their instructions are deduplicated in AOT mode. Only a single
Code object can be choose as a representative for the given
PC range so it does not make sense to write multiple Code objects
into the snapshot which refer to the same Instructions.

The overall improvement is hard to quantify but ReadProgramSnapshot
shows the following improvement when starting a large
Flutter application on a slow Android device:

  before  223.55±59.94 (192.02 .. 391.74) ms
  after   178.06±47.03 (151.31 .. 291.34) ms

This CL packs CompressedStackMaps next to the binary search table
itself allowing us to address them via offsets instead of
pointers.

Snapshot sizes are actually affected positively by this change. On
the same large Flutter application I see

  DWARF stack traces on:  -1.34% total SO size
  DWARF stack traces off: -1.63% total SO size

Issue https://github.com/dart-lang/sdk/issues/46116

TEST=ci

Cq-Include-Trybots: luci.dart.try:vm-kernel-precomp-dwarf-linux-product-x64-try,vm-kernel-precomp-linux-debug-simarm64c-try,vm-kernel-precomp-linux-debug-simarm_x64-try,vm-kernel-precomp-linux-debug-x64-try,vm-kernel-precomp-linux-debug-x64c-try,vm-kernel-precomp-linux-product-x64-try,vm-kernel-precomp-linux-release-simarm-try,vm-kernel-precomp-linux-release-simarm64-try,vm-kernel-precomp-linux-release-simarm_x64-try,vm-kernel-precomp-linux-release-x64-try
Change-Id: Ic997045a33daa81ec68df462a0792915885df66b
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/220766
Reviewed-by: Alexander Markov <alexmarkov@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
Commit-Queue: Slava Egorov <vegorov@google.com>
2021-12-16 10:39:49 +00:00

145 lines
4 KiB
C++

// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include "vm/bitmap.h"
#include "platform/assert.h"
#include "vm/code_descriptors.h"
#include "vm/object.h"
#include "vm/unit_test.h"
namespace dart {
// 0x4 is just a placeholder PC offset because no entry of a CSM should
// have a PC offset of 0, otherwise internal assumptions break.
static const uint32_t kTestPcOffset = 0x4;
static const intptr_t kTestSpillSlotBitCount = 0;
static CompressedStackMapsPtr MapsFromBuilder(Zone* zone, BitmapBuilder* bmap) {
CompressedStackMapsBuilder builder(zone);
builder.AddEntry(kTestPcOffset, bmap, kTestSpillSlotBitCount);
return builder.Finalize();
}
ISOLATE_UNIT_TEST_CASE(BitmapBuilder) {
// Test basic bit map builder operations.
BitmapBuilder* builder1 = new BitmapBuilder();
EXPECT_EQ(0, builder1->Length());
bool value = true;
for (int32_t i = 0; i < 128; i++) {
builder1->Set(i, value);
value = !value;
}
EXPECT_EQ(128, builder1->Length());
value = true;
for (int32_t i = 0; i < 128; i++) {
EXPECT_EQ(value, builder1->Get(i));
value = !value;
}
value = true;
for (int32_t i = 0; i < 1024; i++) {
builder1->Set(i, value);
value = !value;
}
EXPECT_EQ(1024, builder1->Length());
value = true;
for (int32_t i = 0; i < 1024; i++) {
EXPECT_EQ(value, builder1->Get(i));
value = !value;
}
// Create a CompressedStackMaps object and verify its contents.
const auto& maps1 = CompressedStackMaps::Handle(
thread->zone(), MapsFromBuilder(thread->zone(), builder1));
auto it1 = maps1.iterator(thread);
EXPECT(it1.MoveNext());
EXPECT_EQ(kTestPcOffset, it1.pc_offset());
EXPECT_EQ(kTestSpillSlotBitCount, it1.SpillSlotBitCount());
EXPECT_EQ(1024, it1.Length());
value = true;
for (int32_t i = 0; i < 1024; i++) {
EXPECT_EQ(value, it1.IsObject(i));
value = !value;
}
EXPECT(!it1.MoveNext());
// Test the SetRange function in the builder.
builder1->SetRange(0, 256, false);
EXPECT_EQ(1024, builder1->Length());
builder1->SetRange(257, 1024, true);
EXPECT_EQ(1025, builder1->Length());
builder1->SetRange(1025, 2048, false);
EXPECT_EQ(2049, builder1->Length());
for (int32_t i = 0; i <= 256; i++) {
EXPECT(!builder1->Get(i));
}
for (int32_t i = 257; i <= 1024; i++) {
EXPECT(builder1->Get(i));
}
for (int32_t i = 1025; i <= 2048; i++) {
EXPECT(!builder1->Get(i));
}
const auto& maps2 = CompressedStackMaps::Handle(
thread->zone(), MapsFromBuilder(thread->zone(), builder1));
auto it2 = maps2.iterator(thread);
EXPECT(it2.MoveNext());
EXPECT_EQ(kTestPcOffset, it2.pc_offset());
EXPECT_EQ(kTestSpillSlotBitCount, it2.SpillSlotBitCount());
EXPECT_EQ(2049, it2.Length());
for (int32_t i = 0; i <= 256; i++) {
EXPECT(!it2.IsObject(i));
}
for (int32_t i = 257; i <= 1024; i++) {
EXPECT(it2.IsObject(i));
}
for (int32_t i = 1025; i <= 2048; i++) {
EXPECT(!it2.IsObject(i));
}
EXPECT(!it2.MoveNext());
// Test using SetLength to shorten the builder, followed by lengthening.
builder1->SetLength(747);
EXPECT_EQ(747, builder1->Length());
for (int32_t i = 257; i < 747; ++i) {
EXPECT(builder1->Get(i));
}
builder1->Set(800, false);
EXPECT_EQ(801, builder1->Length());
for (int32_t i = 257; i < 747; ++i) {
EXPECT(builder1->Get(i));
}
for (int32_t i = 747; i < 801; ++i) {
EXPECT(!builder1->Get(i));
}
builder1->Set(900, true);
EXPECT_EQ(901, builder1->Length());
for (int32_t i = 257; i < 747; ++i) {
EXPECT(builder1->Get(i));
}
for (int32_t i = 747; i < 900; ++i) {
EXPECT(!builder1->Get(i));
}
EXPECT(builder1->Get(900));
}
ISOLATE_UNIT_TEST_CASE(BitmapBuilder_Regress44946) {
BitmapBuilder* builder1 = new BitmapBuilder();
EXPECT_EQ(0, builder1->Length());
builder1->Set(10000, false);
EXPECT_EQ(10001, builder1->Length());
builder1->Set(9999, true);
EXPECT(builder1->Get(9999));
}
} // namespace dart