Vulkan: Add a perf test for the Pipeline cache.

This micro-benchmark can be used to measure the performance impact
of changing the Pipeline cache. For instance, we can check if changing
the size of the hash key affects performance significantly.

Also updates the build files so angle_perftests can see vulkan.h, and
makes the Vulkan headers an explicit source set.

This test currently shows that a lot of time is spent in PMurmurHash,
with some time also spent in memcmp.

Bug: angleproject:2163
Change-Id: Ie8bb3e31d58590f373d28cbbb59f7e372b80cc29
Reviewed-on: https://chromium-review.googlesource.com/884882
Commit-Queue: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
This commit is contained in:
Jamie Madill 2018-01-29 13:53:43 -05:00 коммит произвёл Commit Bot
Родитель 12c0376106
Коммит 5dd4ad896b
8 изменённых файлов: 175 добавлений и 13 удалений

Просмотреть файл

@ -506,6 +506,7 @@ static_library("libANGLE") {
sources += rebase_path(gles_gypi.libangle_vulkan_xcb_sources, ".", "src")
}
deps += [ "src/vulkan_support:angle_vulkan" ]
public_deps += [ "src/vulkan_support:vulkan_headers" ]
}
if (angle_enable_null) {

Просмотреть файл

@ -793,8 +793,13 @@ vk::Error PipelineCache::getPipeline(VkDevice device,
}
vk::Pipeline newPipeline;
ANGLE_TRY(desc.initializePipeline(device, compatibleRenderPass, pipelineLayout, vertexModule,
fragmentModule, &newPipeline));
// This "if" is left here for the benefit of VulkanPipelineCachePerfTest.
if (device != VK_NULL_HANDLE)
{
ANGLE_TRY(desc.initializePipeline(device, compatibleRenderPass, pipelineLayout,
vertexModule, fragmentModule, &newPipeline));
}
// The Serial will be updated outside of this query.
auto insertedItem =
@ -804,4 +809,15 @@ vk::Error PipelineCache::getPipeline(VkDevice device,
return vk::NoError();
}
void PipelineCache::populate(const vk::PipelineDesc &desc, vk::Pipeline &&pipeline)
{
auto item = mPayload.find(desc);
if (item != mPayload.end())
{
return;
}
mPayload.emplace(desc, vk::PipelineAndSerial(std::move(pipeline), Serial()));
}
} // namespace rx

Просмотреть файл

@ -384,6 +384,7 @@ class PipelineCache final : angle::NonCopyable
void destroy(VkDevice device);
void populate(const vk::PipelineDesc &desc, vk::Pipeline &&pipeline);
vk::Error getPipeline(VkDevice device,
const vk::RenderPass &compatibleRenderPass,
const vk::PipelineLayout &pipelineLayout,

Просмотреть файл

@ -259,6 +259,12 @@ if (is_win || is_linux || is_android || is_mac) {
rebase_path(perftests_gypi.angle_perf_tests_win_sources, ".", "../..")
}
if (angle_enable_vulkan) {
sources += rebase_path(perftests_gypi.angle_perf_tests_vulkan_sources,
".",
"../..")
}
if (build_with_chromium) {
sources += [ "//gpu/angle_perftests_main.cc" ]
} else {

Просмотреть файл

@ -50,7 +50,12 @@
'angle_perf_tests_win_sources':
[
'<(angle_path)/src/tests/perf_tests/IndexDataManagerTest.cpp',
]
],
# Only enabled with angle_enable_vulkan. Not exposed in the gyp.
'angle_perf_tests_vulkan_sources':
[
'<(angle_path)/src/tests/perf_tests/VulkanPipelineCachePerf.cpp',
],
},
# Everything below (except WinRT-related config) must be also maintained for GN.
# If you change anything below, also update angle/src/tests/BUILD.gn.

Просмотреть файл

@ -0,0 +1,107 @@
//
// Copyright 2018 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// VulkanPipelineCachePerf:
// Performance benchmark for the Vulkan Pipeline cache.
#include "ANGLEPerfTest.h"
#include "libANGLE/renderer/vulkan/vk_cache_utils.h"
#include "random_utils.h"
using namespace rx;
namespace
{
class VulkanPipelineCachePerfTest : public ANGLEPerfTest
{
public:
VulkanPipelineCachePerfTest();
~VulkanPipelineCachePerfTest();
void SetUp() override;
void step() override;
PipelineCache mCache;
angle::RNG mRNG;
std::vector<vk::PipelineDesc> mCacheHits;
std::vector<vk::PipelineDesc> mCacheMisses;
size_t mMissIndex = 0;
private:
void randomizeDesc(vk::PipelineDesc *desc);
};
VulkanPipelineCachePerfTest::VulkanPipelineCachePerfTest()
: ANGLEPerfTest("VulkanPipelineCachePerf", "")
{
}
VulkanPipelineCachePerfTest::~VulkanPipelineCachePerfTest()
{
mCache.destroy(VK_NULL_HANDLE);
}
void VulkanPipelineCachePerfTest::SetUp()
{
// Insert a number of random pipeline states.
for (int pipelineCount = 0; pipelineCount < 100; ++pipelineCount)
{
vk::Pipeline pipeline;
vk::PipelineDesc desc;
randomizeDesc(&desc);
if (pipelineCount < 10)
{
mCacheHits.push_back(desc);
}
mCache.populate(desc, std::move(pipeline));
}
for (int missCount = 0; missCount < 10000; ++missCount)
{
vk::PipelineDesc desc;
randomizeDesc(&desc);
mCacheMisses.push_back(desc);
}
}
void VulkanPipelineCachePerfTest::randomizeDesc(vk::PipelineDesc *desc)
{
std::vector<uint8_t> bytes(sizeof(vk::PipelineDesc));
FillVectorWithRandomUBytes(&mRNG, &bytes);
memcpy(desc, bytes.data(), sizeof(vk::PipelineDesc));
}
void VulkanPipelineCachePerfTest::step()
{
vk::RenderPass rp;
vk::PipelineLayout pl;
vk::ShaderModule sm;
vk::PipelineAndSerial *result = nullptr;
for (int iteration = 0; iteration < 100; ++iteration)
{
for (const auto &hit : mCacheHits)
{
(void)mCache.getPipeline(VK_NULL_HANDLE, rp, pl, sm, sm, hit, &result);
}
}
for (int missCount = 0; missCount < 20 && mMissIndex < mCacheMisses.size();
++missCount, ++mMissIndex)
{
const auto &miss = mCacheMisses[mMissIndex];
(void)mCache.getPipeline(VK_NULL_HANDLE, rp, pl, sm, sm, miss, &result);
}
}
} // anonymous namespace
TEST_F(VulkanPipelineCachePerfTest, Run)
{
run();
}

Просмотреть файл

@ -181,18 +181,33 @@ if (spirv_use_commit_id) {
}
}
config("vulkan_generate_helper_files_config") {
include_dirs = [
vulkan_gen_dir,
"$vulkan_layers_dir/include",
config("vulkan_headers_config") {
include_dirs = [ "$vulkan_layers_dir/include" ]
}
# Vulkan headers only, no compiled sources.
source_set("vulkan_headers") {
sources = [
"$vulkan_layers_dir/include/vulkan/vk_icd.h",
"$vulkan_layers_dir/include/vulkan/vk_layer.h",
"$vulkan_layers_dir/include/vulkan/vk_platform.h",
"$vulkan_layers_dir/include/vulkan/vk_sdk_platform.h",
"$vulkan_layers_dir/include/vulkan/vulkan.h",
"$vulkan_layers_dir/include/vulkan/vulkan.hpp",
]
public_configs = [ ":vulkan_headers_config" ]
}
config("vulkan_generated_files_config") {
include_dirs = [ vulkan_gen_dir ]
}
group("vulkan_generate_helper_files") {
public_deps = [
":spirv_tools_external_revision_generate",
":vulkan_headers",
]
public_configs = [ ":vulkan_generate_helper_files_config" ]
public_configs = [ ":vulkan_generated_files_config" ]
foreach(script_and_dep, helper_script_and_deps) {
target_name = script_and_dep[0]
public_deps += [ ":$target_name" ]
@ -301,6 +316,9 @@ static_library("vulkan_loader") {
deps = [
":vulkan_generate_helper_files",
]
public_deps = [
":vulkan_headers",
]
configs += [ ":vulkan_internal_config" ]
public_configs = [
":vulkan_config",
@ -894,6 +912,9 @@ group("angle_vulkan") {
":glslang",
":vulkan_loader",
]
public_deps = [
":vulkan_headers",
]
data_deps = [
":vulkan_gen_json_files",
]

Просмотреть файл

@ -40,14 +40,19 @@ class ANGLE_EXPORT RNG
std::default_random_engine mGenerator;
};
// Implemented htis way because of cross-module allocation issues.
// Implemented inline to avoid cross-module allocation issues.
inline void FillVectorWithRandomUBytes(RNG *rng, std::vector<uint8_t> *data)
{
for (size_t i = 0; i < data->size(); ++i)
{
(*data)[i] = static_cast<uint8_t>(rng->randomIntBetween(0, 255));
}
}
inline void FillVectorWithRandomUBytes(std::vector<uint8_t> *data)
{
RNG rng;
for (size_t i = 0; i < data->size(); ++i)
{
(*data)[i] = static_cast<uint8_t>(rng.randomIntBetween(0, 255));
}
FillVectorWithRandomUBytes(&rng, data);
}
} // namespace angle