Add logic for calculating offsets during writing
Delete all the offset related layout logic, move the logic to
writing. Layout is now controlled by changing the order of the data
vectors.
Calculate all offsets during writing instead of reading. This allows
more flexible layout optimizations without needing to be as careful
about offsets in other sections changing.
Maintained logic for using existing offsets in the case where
changing the layout is not required.
Areas to improve:
How to size the memmap, do we want 2 passes? Currently the algorithm
reserves 10% extra space in case required. This is sufficient for top
1000 apps in the play store. Will consider a two pass approach later.
Bug: 63756964
Bug: 68948395
Bug: 68867570
Bug: 68864106
Bug: 68864168
Test: test/testrunner/testrunner.py --host -j40
Test: test-art-host-gtest
Test: Dexlayout speed profile top 1000 apps
Change-Id: I7dee869da3a010559547f8cfdf93e9aa4c3f47ff
diff --git a/runtime/dex_file_layout.h b/runtime/dex_file_layout.h
index 40cc912..4c960c3 100644
--- a/runtime/dex_file_layout.h
+++ b/runtime/dex_file_layout.h
@@ -17,22 +17,25 @@
#ifndef ART_RUNTIME_DEX_FILE_LAYOUT_H_
#define ART_RUNTIME_DEX_FILE_LAYOUT_H_
+#include <algorithm>
#include <cstdint>
#include <iosfwd>
+#include "base/logging.h"
+
namespace art {
class DexFile;
enum class LayoutType : uint8_t {
+ // Layout of things that are hot (commonly accessed), these should be pinned or madvised will
+ // need.
+ kLayoutTypeHot,
// Layout of things that are randomly used. These should be advised to random access.
// Without layout, this is the default mode when loading a dex file.
kLayoutTypeSometimesUsed,
// Layout of things that are only used during startup, these can be madvised after launch.
kLayoutTypeStartupOnly,
- // Layout of things that are hot (commonly accessed), these should be pinned or madvised will
- // need.
- kLayoutTypeHot,
// Layout of things that are needed probably only once (class initializers). These can be
// madvised during trim events.
kLayoutTypeUsedOnce,
@@ -44,6 +47,11 @@
};
std::ostream& operator<<(std::ostream& os, const LayoutType& collector_type);
+// Return the "best" layout option if the same item has multiple different layouts.
+static inline LayoutType MergeLayoutType(LayoutType a, LayoutType b) {
+ return std::min(a, b);
+}
+
enum class MadviseState : uint8_t {
// Madvise based on a file that was just loaded.
kMadviseStateAtLoad,
@@ -55,15 +63,35 @@
std::ostream& operator<<(std::ostream& os, const MadviseState& collector_type);
// A dex layout section such as code items or strings. Each section is composed of subsections
-// that are layed out ajacently to each other such as (hot, unused, startup, etc...).
+// that are laid out adjacently to each other such as (hot, unused, startup, etc...).
class DexLayoutSection {
public:
// A subsection is a a continuous range of dex file that is all part of the same layout hint.
class Subsection {
public:
// Use uint32_t to handle 32/64 bit cross compilation.
- uint32_t offset_ = 0u;
- uint32_t size_ = 0u;
+ uint32_t start_offset_ = 0u;
+ uint32_t end_offset_ = 0u;
+
+ bool Contains(uint32_t offset) const {
+ return start_offset_ <= offset && offset < end_offset_;
+ }
+
+ bool Size() const {
+ DCHECK_LE(start_offset_, end_offset_);
+ return end_offset_ - start_offset_;
+ }
+
+ void CombineSection(uint32_t start_offset, uint32_t end_offset) {
+ DCHECK_LT(start_offset, end_offset);
+ if (start_offset_ == end_offset_) {
+ start_offset_ = start_offset;
+ end_offset_ = end_offset;
+ } else {
+ start_offset_ = std::min(start_offset_, start_offset);
+ end_offset_ = std::max(end_offset_, end_offset);
+ }
+ }
void Madvise(const DexFile* dex_file, int advice) const;
};