Commit e49ed7ad authored by bratell's avatar bratell Committed by Commit bot

More compact representation of the GL Query cache.

The only thing we need to know per QuerySync block is its
index in the block sequence. Everything else can be
calculated from that if we just store a few numbers in
the Bucket objects.

Total memory reduction is 92%.

This is alt #2 in bug 485536.

BUG=485536

Review URL: https://codereview.chromium.org/1131913004

Cr-Commit-Position: refs/heads/master@{#330334}
parent 0890eeee
...@@ -8,6 +8,8 @@ ...@@ -8,6 +8,8 @@
#include <GLES2/gl2ext.h> #include <GLES2/gl2ext.h>
#include <GLES2/gl2extchromium.h> #include <GLES2/gl2extchromium.h>
#include <limits.h>
#include "base/atomicops.h" #include "base/atomicops.h"
#include "base/numerics/safe_conversions.h" #include "base/numerics/safe_conversions.h"
#include "gpu/command_buffer/client/gles2_cmd_helper.h" #include "gpu/command_buffer/client/gles2_cmd_helper.h"
...@@ -18,6 +20,21 @@ ...@@ -18,6 +20,21 @@
namespace gpu { namespace gpu {
namespace gles2 { namespace gles2 {
QuerySyncManager::Bucket::Bucket(QuerySync* sync_mem,
int32 shm_id,
unsigned int shm_offset)
: syncs(sync_mem),
shm_id(shm_id),
base_shm_offset(shm_offset),
free_queries(kSyncsPerBucket) {
static_assert(kSyncsPerBucket <= USHRT_MAX,
"Can't fit kSyncsPerBucket in unsigned short");
for (size_t ii = 0; ii < kSyncsPerBucket; ++ii)
free_queries[ii] = ii;
}
QuerySyncManager::Bucket::~Bucket() = default;
QuerySyncManager::QuerySyncManager(MappedMemoryManager* manager) QuerySyncManager::QuerySyncManager(MappedMemoryManager* manager)
: mapped_memory_(manager) { : mapped_memory_(manager) {
DCHECK(manager); DCHECK(manager);
...@@ -33,7 +50,14 @@ QuerySyncManager::~QuerySyncManager() { ...@@ -33,7 +50,14 @@ QuerySyncManager::~QuerySyncManager() {
bool QuerySyncManager::Alloc(QuerySyncManager::QueryInfo* info) { bool QuerySyncManager::Alloc(QuerySyncManager::QueryInfo* info) {
DCHECK(info); DCHECK(info);
if (free_queries_.empty()) { Bucket* bucket = nullptr;
for (Bucket* bucket_candidate : buckets_) {
if (!bucket_candidate->free_queries.empty()) {
bucket = bucket_candidate;
break;
}
}
if (!bucket) {
int32 shm_id; int32 shm_id;
unsigned int shm_offset; unsigned int shm_offset;
void* mem = mapped_memory_->Alloc( void* mem = mapped_memory_->Alloc(
...@@ -42,40 +66,31 @@ bool QuerySyncManager::Alloc(QuerySyncManager::QueryInfo* info) { ...@@ -42,40 +66,31 @@ bool QuerySyncManager::Alloc(QuerySyncManager::QueryInfo* info) {
return false; return false;
} }
QuerySync* syncs = static_cast<QuerySync*>(mem); QuerySync* syncs = static_cast<QuerySync*>(mem);
Bucket* bucket = new Bucket(syncs); bucket = new Bucket(syncs, shm_id, shm_offset);
buckets_.push_back(bucket); buckets_.push_back(bucket);
for (size_t ii = 0; ii < kSyncsPerBucket; ++ii) {
free_queries_.push_back(QueryInfo(bucket, shm_id, shm_offset, syncs));
++syncs;
shm_offset += sizeof(*syncs);
}
} }
*info = free_queries_.front();
++(info->bucket->used_query_count); unsigned short index_in_bucket = bucket->free_queries.back();
uint32 shm_offset =
bucket->base_shm_offset + index_in_bucket * sizeof(QuerySync);
QuerySync* sync = bucket->syncs + index_in_bucket;
*info = QueryInfo(bucket, bucket->shm_id, shm_offset, sync);
info->sync->Reset(); info->sync->Reset();
free_queries_.pop_front(); bucket->free_queries.pop_back();
return true; return true;
} }
void QuerySyncManager::Free(const QuerySyncManager::QueryInfo& info) { void QuerySyncManager::Free(const QuerySyncManager::QueryInfo& info) {
DCHECK_GT(info.bucket->used_query_count, 0u); DCHECK(info.bucket->free_queries.size() < kSyncsPerBucket);
--(info.bucket->used_query_count); unsigned short index_in_bucket = info.sync - info.bucket->syncs;
free_queries_.push_back(info); info.bucket->free_queries.push_back(index_in_bucket);
} }
void QuerySyncManager::Shrink() { void QuerySyncManager::Shrink() {
std::deque<QueryInfo> new_queue;
while (!free_queries_.empty()) {
if (free_queries_.front().bucket->used_query_count)
new_queue.push_back(free_queries_.front());
free_queries_.pop_front();
}
free_queries_.swap(new_queue);
std::deque<Bucket*> new_buckets; std::deque<Bucket*> new_buckets;
while (!buckets_.empty()) { while (!buckets_.empty()) {
Bucket* bucket = buckets_.front(); Bucket* bucket = buckets_.front();
if (bucket->used_query_count) { if (bucket->free_queries.size() < kSyncsPerBucket) {
new_buckets.push_back(bucket); new_buckets.push_back(bucket);
} else { } else {
mapped_memory_->Free(bucket->syncs); mapped_memory_->Free(bucket->syncs);
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include <deque> #include <deque>
#include <list> #include <list>
#include <vector>
#include "base/atomicops.h" #include "base/atomicops.h"
#include "base/containers/hash_tables.h" #include "base/containers/hash_tables.h"
...@@ -30,12 +31,12 @@ class GLES2_IMPL_EXPORT QuerySyncManager { ...@@ -30,12 +31,12 @@ class GLES2_IMPL_EXPORT QuerySyncManager {
static const size_t kSyncsPerBucket = 1024; static const size_t kSyncsPerBucket = 1024;
struct Bucket { struct Bucket {
explicit Bucket(QuerySync* sync_mem) Bucket(QuerySync* sync_mem, int32 shm_id, uint32 shm_offset);
: syncs(sync_mem), ~Bucket();
used_query_count(0) {
}
QuerySync* syncs; QuerySync* syncs;
unsigned used_query_count; int32 shm_id;
uint32 base_shm_offset;
std::vector<unsigned short> free_queries;
}; };
struct QueryInfo { struct QueryInfo {
QueryInfo(Bucket* bucket, int32 id, uint32 offset, QuerySync* sync_mem) QueryInfo(Bucket* bucket, int32 id, uint32 offset, QuerySync* sync_mem)
...@@ -68,7 +69,6 @@ class GLES2_IMPL_EXPORT QuerySyncManager { ...@@ -68,7 +69,6 @@ class GLES2_IMPL_EXPORT QuerySyncManager {
private: private:
MappedMemoryManager* mapped_memory_; MappedMemoryManager* mapped_memory_;
std::deque<Bucket*> buckets_; std::deque<Bucket*> buckets_;
std::deque<QueryInfo> free_queries_;
DISALLOW_COPY_AND_ASSIGN(QuerySyncManager); DISALLOW_COPY_AND_ASSIGN(QuerySyncManager);
}; };
......
...@@ -107,6 +107,10 @@ class QueryTrackerTest : public testing::Test { ...@@ -107,6 +107,10 @@ class QueryTrackerTest : public testing::Test {
return query->info_.bucket; return query->info_.bucket;
} }
uint32 GetBucketUsedCount(QuerySyncManager::Bucket* bucket) {
return QuerySyncManager::kSyncsPerBucket - bucket->free_queries.size();
}
uint32 GetFlushGeneration() { return helper_->flush_generation(); } uint32 GetFlushGeneration() { return helper_->flush_generation(); }
scoped_ptr<CommandBuffer> command_buffer_; scoped_ptr<CommandBuffer> command_buffer_;
...@@ -209,7 +213,7 @@ TEST_F(QueryTrackerTest, Remove) { ...@@ -209,7 +213,7 @@ TEST_F(QueryTrackerTest, Remove) {
ASSERT_TRUE(query != NULL); ASSERT_TRUE(query != NULL);
QuerySyncManager::Bucket* bucket = GetBucket(query); QuerySyncManager::Bucket* bucket = GetBucket(query);
EXPECT_EQ(1u, bucket->used_query_count); EXPECT_EQ(1u, GetBucketUsedCount(bucket));
query->MarkAsActive(); query->MarkAsActive();
query->MarkAsPending(kToken); query->MarkAsPending(kToken);
...@@ -219,7 +223,7 @@ TEST_F(QueryTrackerTest, Remove) { ...@@ -219,7 +223,7 @@ TEST_F(QueryTrackerTest, Remove) {
EXPECT_TRUE(query_tracker_->GetQuery(kId1) == NULL); EXPECT_TRUE(query_tracker_->GetQuery(kId1) == NULL);
// Check that memory was not freed. // Check that memory was not freed.
EXPECT_EQ(1u, bucket->used_query_count); EXPECT_EQ(1u, GetBucketUsedCount(bucket));
// Simulate GPU process marking it as available. // Simulate GPU process marking it as available.
QuerySync* sync = GetSync(query); QuerySync* sync = GetSync(query);
...@@ -228,7 +232,7 @@ TEST_F(QueryTrackerTest, Remove) { ...@@ -228,7 +232,7 @@ TEST_F(QueryTrackerTest, Remove) {
// Check FreeCompletedQueries. // Check FreeCompletedQueries.
query_tracker_->FreeCompletedQueries(); query_tracker_->FreeCompletedQueries();
EXPECT_EQ(0u, bucket->used_query_count); EXPECT_EQ(0u, GetBucketUsedCount(bucket));
} }
} // namespace gles2 } // namespace gles2
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment