blob: bb4a0e96683099180a27ab92c8620ba6e8d058ed [file] [log] [blame]
// Copyright (c) 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Keep this file in sync with the .proto files in this directory.
#include "components/sync/protocol/proto_memory_estimations.h"
#include <string>
#include "base/trace_event/memory_usage_estimator.h"
#include "components/sync/protocol/proto_visitors.h"
namespace {
// This class is a VisitProtoFields()-compatible visitor that estimates
// proto's memory usage:
//
// MemoryUsageVisitor visitor;
// VisitProtoFields(visitor, proto);
// size_t memory_usage = visitor.memory_usage();
//
class MemoryUsageVisitor {
public:
MemoryUsageVisitor() : memory_usage_(0) {}
size_t memory_usage() const { return memory_usage_; }
template <class P>
void VisitBytes(const P& parent_proto,
const char* field_name,
const std::string& field) {
// Delegate to Visit(..., const std::string&) below.
Visit(parent_proto, field_name, field);
}
template <class P, class E>
void VisitEnum(const P&, const char* field_name, E field) {}
// Types derived from MessageLite (i.e. protos)
template <class P, class F>
typename std::enable_if<
std::is_base_of<google::protobuf::MessageLite, F>::value>::type
Visit(const P&, const char* field_name, const F& field) {
using base::trace_event::EstimateMemoryUsage;
// All object fields are dynamically allocated.
memory_usage_ += sizeof(F) + EstimateMemoryUsage(field);
}
// Arithmetic types
template <class P, class F>
typename std::enable_if<std::is_arithmetic<F>::value>::type
Visit(const P&, const char* field_name, const F& field) {
// Arithmetic fields (integers, floats & bool) don't allocate.
}
// std::string
template <class P>
void Visit(const P&, const char* field_name, const std::string& field) {
using base::trace_event::EstimateMemoryUsage;
// All strings are of type ArenaStringPtr, which essentially
// is std::string*.
memory_usage_ += sizeof(std::string) + EstimateMemoryUsage(field);
}
// RepeatedPtrField
template <class P, class F>
void Visit(const P&,
const char* field_name,
const google::protobuf::RepeatedPtrField<F>& fields) {
using base::trace_event::EstimateMemoryUsage;
// Can't use RepeatedPtrField::SpaceUsedExcludingSelf() because it will
// end up calling undefined TypeHandler::SpaceUsed() method.
memory_usage_ += fields.Capacity() ? sizeof(void*) : 0; // header
memory_usage_ += fields.Capacity() * sizeof(void*);
for (const auto& field : fields) {
memory_usage_ += sizeof(F) + EstimateMemoryUsage(field);
}
}
// RepeatedField<arithmetic type>
template <class P, class F>
typename std::enable_if<std::is_arithmetic<F>::value>::type Visit(
const P&,
const char* field_name,
const google::protobuf::RepeatedField<F>& fields) {
memory_usage_ += fields.SpaceUsedExcludingSelf();
// Arithmetic fields (integers, floats & bool) don't allocate, so no point
// in iterating over |fields|.
}
// RepeatedField<std::string>
template <class P>
void Visit(const P&,
const char* field_name,
const google::protobuf::RepeatedField<std::string>& fields) {
using base::trace_event::EstimateMemoryUsage;
memory_usage_ += fields.SpaceUsedExcludingSelf();
for (const auto& field : fields) {
memory_usage_ += EstimateMemoryUsage(field);
}
}
private:
size_t memory_usage_;
};
} // namespace
namespace sync_pb {
template <class P>
size_t EstimateMemoryUsage(const P& proto) {
MemoryUsageVisitor visitor;
syncer::VisitProtoFields(visitor, proto);
return visitor.memory_usage();
}
// Explicit instantiations
#define INSTANTIATE(Proto) \
template size_t EstimateMemoryUsage<Proto>(const Proto&);
INSTANTIATE(DataTypeContext)
INSTANTIATE(DataTypeProgressMarker)
INSTANTIATE(EntityMetadata)
INSTANTIATE(EntitySpecifics)
INSTANTIATE(ModelTypeState)
INSTANTIATE(PersistedEntityData)
INSTANTIATE(UniquePosition)
} // namespace sync_pb