dawn-cmake/src/block_allocator_test.cc
Ben Clayton ba1a8f8d05 optimization: BlockAllocator: Actually allocate in blocks
Instead of hitting the heap for each and every call to Create()

Significantly improves performance for heavy loads. Slight performance
loss for lighter loads.

A: base.bench
B: new.bench

Test name                             | Δ (A → B)    | % (A → B)
--------------------------------------+--------------+-----------
GenerateSPIRV/"simple_fragment.wgsl"  | 27.021µs     | +6.4%
GenerateMSL/"simple_compute.wgsl"     | 35.592µs     | +6.1%
GenerateMSL/"simple_vertex.wgsl"      | 37.64µs      | +5.5%
GenerateHLSL/"simple_fragment.wgsl"   | 42.145µs     | +5.2%
GenerateGLSL/"simple_fragment.wgsl"   | 31.506µs     | +4.9%
GenerateHLSL/"simple_vertex.wgsl"     | 38.843µs     | +4.7%
GenerateMSL/"simple_fragment.wgsl"    | 29.977µs     | +4.5%
GenerateSPIRV/"simple_vertex.wgsl"    | 19.882µs     | +4.2%
GenerateGLSL/"simple_vertex.wgsl"     | 24.702µs     | +3.7%
GenerateSPIRV/"simple_compute.wgsl"   | 17.652µs     | +3.2%
GenerateHLSL/"simple_compute.wgsl"    | 26.826µs     | +2.7%
GenerateGLSL/"simple_compute.wgsl"    | 11.952µs     | +1.8%
ParseWGSL/"particles.wgsl"            | -104.83µs    | -4.2%
GenerateMSL/"particles.wgsl"          | -1.079243ms  | -9.4%
GenerateSPIRV/"particles.wgsl"        | -1.012483ms  | -9.4%
GenerateGLSL/"particles.wgsl"         | -3.522106ms  | -9.5%
GenerateHLSL/"particles.wgsl"         | -1.849666ms  | -10.6%

Issue: tint:1383
Change-Id: Ib691328538c597c06a75dfba392c99d2afbd5442
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/76961
Reviewed-by: Antonio Maiorano <amaiorano@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
2022-01-22 20:32:38 +00:00

148 lines
3.4 KiB
C++

// Copyright 2021 The Tint Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "src/block_allocator.h"
#include "gtest/gtest.h"
namespace tint {
namespace {
struct LifetimeCounter {
explicit LifetimeCounter(size_t* count) : count_(count) { (*count)++; }
~LifetimeCounter() { (*count_)--; }
size_t* const count_;
};
using BlockAllocatorTest = testing::Test;
TEST_F(BlockAllocatorTest, Empty) {
using Allocator = BlockAllocator<int>;
Allocator allocator;
for (int* i : allocator.Objects()) {
(void)i;
if ((true)) { // Workaround for "error: loop will run at most once"
FAIL() << "BlockAllocator should be empty";
}
}
for (const int* i : static_cast<const Allocator&>(allocator).Objects()) {
(void)i;
if ((true)) { // Workaround for "error: loop will run at most once"
FAIL() << "BlockAllocator should be empty";
}
}
}
TEST_F(BlockAllocatorTest, ObjectLifetime) {
using Allocator = BlockAllocator<LifetimeCounter>;
size_t count = 0;
{
Allocator allocator;
EXPECT_EQ(count, 0u);
allocator.Create(&count);
EXPECT_EQ(count, 1u);
allocator.Create(&count);
EXPECT_EQ(count, 2u);
allocator.Create(&count);
EXPECT_EQ(count, 3u);
}
EXPECT_EQ(count, 0u);
}
TEST_F(BlockAllocatorTest, MoveConstruct) {
using Allocator = BlockAllocator<LifetimeCounter>;
for (size_t n :
{0, 1, 10, 16, 20, 32, 50, 64, 100, 256, 300, 512, 500, 512}) {
size_t count = 0;
{
Allocator allocator_a;
for (size_t i = 0; i < n; i++) {
allocator_a.Create(&count);
}
EXPECT_EQ(count, n);
Allocator allocator_b{std::move(allocator_a)};
EXPECT_EQ(count, n);
}
EXPECT_EQ(count, 0u);
}
}
TEST_F(BlockAllocatorTest, MoveAssign) {
using Allocator = BlockAllocator<LifetimeCounter>;
for (size_t n :
{0, 1, 10, 16, 20, 32, 50, 64, 100, 256, 300, 512, 500, 512}) {
size_t count_a = 0;
size_t count_b = 0;
{
Allocator allocator_a;
for (size_t i = 0; i < n; i++) {
allocator_a.Create(&count_a);
}
EXPECT_EQ(count_a, n);
Allocator allocator_b;
for (size_t i = 0; i < n; i++) {
allocator_b.Create(&count_b);
}
EXPECT_EQ(count_b, n);
allocator_b = std::move(allocator_a);
EXPECT_EQ(count_a, n);
EXPECT_EQ(count_b, 0u);
}
EXPECT_EQ(count_a, 0u);
EXPECT_EQ(count_b, 0u);
}
}
TEST_F(BlockAllocatorTest, ObjectOrder) {
using Allocator = BlockAllocator<int>;
Allocator allocator;
constexpr int N = 10000;
for (int i = 0; i < N; i++) {
allocator.Create(i);
}
{
int i = 0;
for (int* p : allocator.Objects()) {
EXPECT_EQ(*p, i);
i++;
}
EXPECT_EQ(i, N);
}
{
int i = 0;
for (const int* p : static_cast<const Allocator&>(allocator).Objects()) {
EXPECT_EQ(*p, i);
i++;
}
EXPECT_EQ(i, N);
}
}
} // namespace
} // namespace tint