Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit dbce3560 authored by Yurii Zubrytskyi's avatar Yurii Zubrytskyi
Browse files

[res] Reuse memory in RebuildFilterList()

Original code deleted all allocated arrays to new' them back
right away. Now, with new methods in ByteBucketArray the code
only clears the vectors without releasing the capacity, and then
proceeds to free the vectors that ended up not being used.

This speeds up theme changes (accents / dark theme etc) by
about 20%

+ small other improvements in ByteBucketArray

Bug: 237583012
Test: build + UTs + boot
Change-Id: I158af793e5476b4f3215dbe602daa872136d633f
parent 591895bd
Loading
Loading
Loading
Loading
+6 −5
Original line number Diff line number Diff line
@@ -1356,21 +1356,22 @@ base::expected<uint32_t, NullOrIOError> AssetManager2::GetResourceId(

void AssetManager2::RebuildFilterList() {
  for (PackageGroup& group : package_groups_) {
    for (ConfiguredPackage& impl : group.packages_) {
      impl.filtered_configs_.clear();

    for (ConfiguredPackage& package : group.packages_) {
      package.filtered_configs_.forEachItem([](auto, auto& fcg) { fcg.type_entries.clear(); });
      // Create the filters here.
      impl.loaded_package_->ForEachTypeSpec([&](const TypeSpec& type_spec, uint8_t type_id) {
      package.loaded_package_->ForEachTypeSpec([&](const TypeSpec& type_spec, uint8_t type_id) {
        FilteredConfigGroup* group = nullptr;
        for (const auto& type_entry : type_spec.type_entries) {
          if (type_entry.config.match(configuration_)) {
            if (!group) {
              group = &impl.filtered_configs_.editItemAt(type_id - 1);
              group = &package.filtered_configs_.editItemAt(type_id - 1);
            }
            group->type_entries.push_back(&type_entry);
          }
        }
      });
      package.filtered_configs_.trimBuckets(
          [](const auto& fcg) { return fcg.type_entries.empty(); });
    }
  }
}
+40 −10
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
#ifndef __BYTE_BUCKET_ARRAY_H
#define __BYTE_BUCKET_ARRAY_H

#include <algorithm>
#include <cstdint>
#include <cstring>

@@ -36,15 +37,11 @@ class ByteBucketArray {
  }

  ~ByteBucketArray() {
    clear();
    deleteBuckets();
  }

  void clear() {
    for (size_t i = 0; i < kNumBuckets; i++) {
      if (buckets_[i] != NULL) {
        delete[] buckets_[i];
      }
    }
    deleteBuckets();
    memset(buckets_, 0, sizeof(buckets_));
  }

@@ -59,7 +56,7 @@ class ByteBucketArray {

    uint8_t bucket_index = static_cast<uint8_t>(index) >> 4;
    T* bucket = buckets_[bucket_index];
    if (bucket == NULL) {
    if (bucket == nullptr) {
      return default_;
    }
    return bucket[0x0f & static_cast<uint8_t>(index)];
@@ -70,9 +67,9 @@ class ByteBucketArray {
                          << ") with size=" << size();

    uint8_t bucket_index = static_cast<uint8_t>(index) >> 4;
    T* bucket = buckets_[bucket_index];
    if (bucket == NULL) {
      bucket = buckets_[bucket_index] = new T[kBucketSize]();
    T*& bucket = buckets_[bucket_index];
    if (bucket == nullptr) {
      bucket = new T[kBucketSize]();
    }
    return bucket[0x0f & static_cast<uint8_t>(index)];
  }
@@ -86,9 +83,42 @@ class ByteBucketArray {
    return true;
  }

  template <class Func>
  void forEachItem(Func f) {
    for (size_t i = 0; i < kNumBuckets; i++) {
      const auto bucket = buckets_[i];
      if (bucket != nullptr) {
        for (size_t j = 0; j < kBucketSize; j++) {
          f((i << 4) | j, bucket[j]);
        }
      }
    }
  }

  template <class Func>
  void trimBuckets(Func isEmptyFunc) {
    for (size_t i = 0; i < kNumBuckets; i++) {
      const auto bucket = buckets_[i];
      if (bucket != nullptr) {
        if (std::all_of(bucket, bucket + kBucketSize, isEmptyFunc)) {
          delete[] bucket;
          buckets_[i] = nullptr;
        }
      }
    }
  }

 private:
  enum { kNumBuckets = 16, kBucketSize = 16 };

  void deleteBuckets() {
    for (size_t i = 0; i < kNumBuckets; i++) {
      if (buckets_[i] != nullptr) {
        delete[] buckets_[i];
      }
    }
  }

  T* buckets_[kNumBuckets];
  static inline const T default_ = {};
};
+53 −0
Original line number Diff line number Diff line
@@ -52,4 +52,57 @@ TEST(ByteBucketArrayTest, TestSparseInsertion) {
  }
}

TEST(ByteBucketArrayTest, TestForEach) {
  ByteBucketArray<int> bba;
  ASSERT_TRUE(bba.set(0, 1));
  ASSERT_TRUE(bba.set(10, 2));
  ASSERT_TRUE(bba.set(26, 3));
  ASSERT_TRUE(bba.set(129, 4));
  ASSERT_TRUE(bba.set(234, 5));

  int count = 0;
  bba.forEachItem([&count](auto i, auto val) {
    ++count;
    switch (i) {
      case 0:
        EXPECT_EQ(1, val);
        break;
      case 10:
        EXPECT_EQ(2, val);
        break;
      case 26:
        EXPECT_EQ(3, val);
        break;
      case 129:
        EXPECT_EQ(4, val);
        break;
      case 234:
        EXPECT_EQ(5, val);
        break;
      default:
        EXPECT_EQ(0, val);
        break;
    }
  });
  ASSERT_EQ(4 * 16, count);
}

TEST(ByteBucketArrayTest, TestTrimBuckets) {
  ByteBucketArray<int> bba;
  ASSERT_TRUE(bba.set(0, 1));
  ASSERT_TRUE(bba.set(255, 2));
  {
    bba.trimBuckets([](auto val) { return val < 2; });
    int count = 0;
    bba.forEachItem([&count](auto, auto) { ++count; });
    ASSERT_EQ(1 * 16, count);
  }
  {
    bba.trimBuckets([](auto val) { return val < 3; });
    int count = 0;
    bba.forEachItem([&count](auto, auto) { ++count; });
    ASSERT_EQ(0, count);
  }
}

}  // namespace android