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 @@
#include <GLES2/gl2ext.h>
#include <GLES2/gl2extchromium.h>
#include <limits.h>
#include "base/atomicops.h"
#include "base/numerics/safe_conversions.h"
#include "gpu/command_buffer/client/gles2_cmd_helper.h"
......@@ -18,6 +20,21 @@
namespace gpu {
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)
: mapped_memory_(manager) {
DCHECK(manager);
......@@ -33,7 +50,14 @@ QuerySyncManager::~QuerySyncManager() {
bool QuerySyncManager::Alloc(QuerySyncManager::QueryInfo* 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;
unsigned int shm_offset;
void* mem = mapped_memory_->Alloc(
......@@ -42,40 +66,31 @@ bool QuerySyncManager::Alloc(QuerySyncManager::QueryInfo* info) {
return false;
}
QuerySync* syncs = static_cast<QuerySync*>(mem);
Bucket* bucket = new Bucket(syncs);
bucket = new Bucket(syncs, shm_id, shm_offset);
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();
free_queries_.pop_front();
bucket->free_queries.pop_back();
return true;
}
void QuerySyncManager::Free(const QuerySyncManager::QueryInfo& info) {
DCHECK_GT(info.bucket->used_query_count, 0u);
--(info.bucket->used_query_count);
free_queries_.push_back(info);
DCHECK(info.bucket->free_queries.size() < kSyncsPerBucket);
unsigned short index_in_bucket = info.sync - info.bucket->syncs;
info.bucket->free_queries.push_back(index_in_bucket);
}
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;
while (!buckets_.empty()) {
Bucket* bucket = buckets_.front();
if (bucket->used_query_count) {
if (bucket->free_queries.size() < kSyncsPerBucket) {
new_buckets.push_back(bucket);
} else {
mapped_memory_->Free(bucket->syncs);
......
......@@ -9,6 +9,7 @@
#include <deque>
#include <list>
#include <vector>
#include "base/atomicops.h"
#include "base/containers/hash_tables.h"
......@@ -30,12 +31,12 @@ class GLES2_IMPL_EXPORT QuerySyncManager {
static const size_t kSyncsPerBucket = 1024;
struct Bucket {
explicit Bucket(QuerySync* sync_mem)
: syncs(sync_mem),
used_query_count(0) {
}
Bucket(QuerySync* sync_mem, int32 shm_id, uint32 shm_offset);
~Bucket();
QuerySync* syncs;
unsigned used_query_count;
int32 shm_id;
uint32 base_shm_offset;
std::vector<unsigned short> free_queries;
};
struct QueryInfo {
QueryInfo(Bucket* bucket, int32 id, uint32 offset, QuerySync* sync_mem)
......@@ -68,7 +69,6 @@ class GLES2_IMPL_EXPORT QuerySyncManager {
private:
MappedMemoryManager* mapped_memory_;
std::deque<Bucket*> buckets_;
std::deque<QueryInfo> free_queries_;
DISALLOW_COPY_AND_ASSIGN(QuerySyncManager);
};
......
......@@ -107,6 +107,10 @@ class QueryTrackerTest : public testing::Test {
return query->info_.bucket;
}
uint32 GetBucketUsedCount(QuerySyncManager::Bucket* bucket) {
return QuerySyncManager::kSyncsPerBucket - bucket->free_queries.size();
}
uint32 GetFlushGeneration() { return helper_->flush_generation(); }
scoped_ptr<CommandBuffer> command_buffer_;
......@@ -209,7 +213,7 @@ TEST_F(QueryTrackerTest, Remove) {
ASSERT_TRUE(query != NULL);
QuerySyncManager::Bucket* bucket = GetBucket(query);
EXPECT_EQ(1u, bucket->used_query_count);
EXPECT_EQ(1u, GetBucketUsedCount(bucket));
query->MarkAsActive();
query->MarkAsPending(kToken);
......@@ -219,7 +223,7 @@ TEST_F(QueryTrackerTest, Remove) {
EXPECT_TRUE(query_tracker_->GetQuery(kId1) == NULL);
// 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.
QuerySync* sync = GetSync(query);
......@@ -228,7 +232,7 @@ TEST_F(QueryTrackerTest, Remove) {
// Check FreeCompletedQueries.
query_tracker_->FreeCompletedQueries();
EXPECT_EQ(0u, bucket->used_query_count);
EXPECT_EQ(0u, GetBucketUsedCount(bucket));
}
} // 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