| Index: components/sync/protocol/proto_memory_estimations.cc
|
| diff --git a/components/sync/protocol/proto_memory_estimations.cc b/components/sync/protocol/proto_memory_estimations.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..f759f986d8f6482ca5100632aa6674e1ec8c8caa
|
| --- /dev/null
|
| +++ b/components/sync/protocol/proto_memory_estimations.cc
|
| @@ -0,0 +1,126 @@
|
| +// 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 "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);
|
| + }
|
| +
|
| + // Integral types
|
| + template <class P, class F>
|
| + typename std::enable_if<std::is_integral<F>::value>::type
|
| + Visit(const P&, const char* field_name, const F& field) {
|
| + // Integral 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<integral type>
|
| + template <class P, class F>
|
| + typename std::enable_if<std::is_integral<F>::value>::type Visit(
|
| + const P&,
|
| + const char* field_name,
|
| + const google::protobuf::RepeatedField<F>& fields) {
|
| + memory_usage_ += fields.SpaceUsedExcludingSelf();
|
| + // Integral 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(EntitySpecifics)
|
| +INSTANTIATE(AttachmentMetadata)
|
| +INSTANTIATE(DataTypeContext)
|
| +
|
| +} // namespace sync_pb
|
|
|