chromium/third_party/perfetto/include/perfetto/tracing/track_event_interned_data_index.h

/*
 * Copyright (C) 2019 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef INCLUDE_PERFETTO_TRACING_TRACK_EVENT_INTERNED_DATA_INDEX_H_
#define INCLUDE_PERFETTO_TRACING_TRACK_EVENT_INTERNED_DATA_INDEX_H_

#include "perfetto/tracing/internal/track_event_internal.h"

#include "perfetto/base/compiler.h"
#include "perfetto/tracing/event_context.h"

#include <map>
#include <type_traits>
#include <unordered_map>

// This file has templates for defining your own interned data types to be used
// with track event. Interned data can be useful for avoiding repeating the same
// constant data (e.g., strings) throughout the trace.
//
// =============
// Example usage
// =============
//
// First define an interning index for your type. It should map to a specific
// field of interned_data.proto and define how the interned data is written into
// that message.
//
//   struct MyInternedData
//       : public perfetto::TrackEventInternedDataIndex<
//           MyInternedData,
//           perfetto::protos::pbzero::InternedData::kMyInternedDataFieldNumber,
//           const char*> {
//     static void Add(perfetto::protos::pbzero::InternedData* interned_data,
//                      size_t iid,
//                      const char* value) {
//       auto my_data = interned_data->add_my_interned_data();
//       my_data->set_iid(iid);
//       my_data->set_value(value);
//     }
//   };
//
// Next, use your interned data in a trace point as shown below. The interned
// string will only be emitted the first time the trace point is hit.
//
//   TRACE_EVENT_BEGIN(
//      "category", "Event", [&](perfetto::EventContext ctx) {
//        auto my_message = ctx.event()->set_my_message();
//        size_t iid = MyInternedData::Get(&ctx, "Some data");
//        my_message->set_iid(iid);
//      });
//

namespace perfetto {

// By default, the interning index stores a full copy of the interned data. This
// ensures the same data is always mapped to the same interning id, and there is
// no danger of collisions. This comes at the cost of memory usage, however, so
// consider using HashedInternedDataTraits if that may be an issue.
//
// This type of index also performs hashing on the stored data for lookups; for
// types where this isn't necessary (e.g., raw const char*), use
// SmallInternedDataTraits.
struct BigInternedDataTraits {};

// This type of interning index keeps full copies of interned data without
// hashing the values. This is a good fit for small types that can be directly
// used as index keys.
struct SmallInternedDataTraits {};

// This type of interning index only stores the hash of the interned values
// instead of the values themselves. This is more efficient in terms of memory
// usage, but assumes that there are no hash collisions. If a hash collision
// occurs, two or more values will be mapped to the same interning id.
//
// Note that the given type must have a specialization for std::hash.
struct HashedInternedDataTraits {};

// A templated base class for an interned data type which corresponds to a field
// in interned_data.proto.
//
// |InternedDataType| must be the type of the subclass.
// |FieldNumber| is the corresponding protobuf field in InternedData.
// |ValueType| is the type which is stored in the index. It must be copyable.
// |Traits| can be used to customize the storage and lookup mechanism.
//
// The subclass should define a static method with the following signature for
// committing interned data together with the interning id |iid| into the trace:
//
//   static void Add(perfetto::protos::pbzero::InternedData*,
//                   size_t iid,
//                   const ValueType& value);
//
template <typename InternedDataType,
          size_t FieldNumber,
          typename ValueType,
          // Avoid unnecessary hashing for pointers by default.
          typename Traits =
              typename std::conditional<(std::is_pointer<ValueType>::value),
                                        SmallInternedDataTraits,
                                        BigInternedDataTraits>::type>
class TrackEventInternedDataIndex
    : public internal::BaseTrackEventInternedDataIndex {};

}  // namespace perfetto

#endif  // INCLUDE_PERFETTO_TRACING_TRACK_EVENT_INTERNED_DATA_INDEX_H_