blob: 7862809c416e5a92a6c273e2ac15935c7c0a74bf [file] [log] [blame]
/*
* 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 SRC_TRACE_PROCESSOR_STACK_PROFILE_TRACKER_H_
#define SRC_TRACE_PROCESSOR_STACK_PROFILE_TRACKER_H_
#include <deque>
#include <unordered_map>
#include "perfetto/ext/base/optional.h"
#include "protos/perfetto/trace/profiling/profile_common.pbzero.h"
#include "protos/perfetto/trace/profiling/profile_packet.pbzero.h"
#include "src/trace_processor/trace_storage.h"
namespace std {
template <>
struct hash<std::pair<uint32_t, int64_t>> {
using argument_type = std::pair<uint32_t, int64_t>;
using result_type = size_t;
result_type operator()(const argument_type& p) const {
return std::hash<uint32_t>{}(p.first) ^ std::hash<int64_t>{}(p.second);
}
};
template <>
struct hash<std::vector<uint64_t>> {
using argument_type = std::vector<uint64_t>;
using result_type = size_t;
result_type operator()(const argument_type& p) const {
size_t h = 0u;
for (auto v : p)
h = h ^ std::hash<uint64_t>{}(v);
return h;
}
};
} // namespace std
namespace perfetto {
namespace trace_processor {
class TraceProcessorContext;
// TODO(lalitm): Overhaul this class to make row vs id consistent and use
// base::Optional instead of int64_t.
class StackProfileTracker {
public:
using SourceStringId = uint64_t;
enum class InternedStringType {
kMappingPath,
kBuildId,
kFunctionName,
};
struct SourceMapping {
SourceStringId build_id = 0;
uint64_t exact_offset = 0;
uint64_t start_offset = 0;
uint64_t start = 0;
uint64_t end = 0;
uint64_t load_bias = 0;
std::vector<SourceStringId> name_ids;
};
using SourceMappingId = uint64_t;
struct SourceFrame {
SourceStringId name_id = 0;
SourceMappingId mapping_id = 0;
uint64_t rel_pc = 0;
};
using SourceFrameId = uint64_t;
using SourceCallstack = std::vector<SourceFrameId>;
using SourceCallstackId = uint64_t;
struct SourceAllocation {
uint64_t pid = 0;
// This is int64_t, because we get this from the TraceSorter which also
// converts this for us.
int64_t timestamp = 0;
SourceCallstackId callstack_id = 0;
uint64_t self_allocated = 0;
uint64_t self_freed = 0;
uint64_t alloc_count = 0;
uint64_t free_count = 0;
};
class InternLookup {
public:
virtual ~InternLookup();
virtual base::Optional<base::StringView> GetString(
SourceStringId,
InternedStringType) const = 0;
virtual base::Optional<SourceMapping> GetMapping(SourceMappingId) const = 0;
virtual base::Optional<SourceFrame> GetFrame(SourceFrameId) const = 0;
virtual base::Optional<SourceCallstack> GetCallstack(
SourceCallstackId) const = 0;
};
explicit StackProfileTracker(TraceProcessorContext* context);
~StackProfileTracker();
void AddString(SourceStringId, base::StringView);
base::Optional<int64_t> AddMapping(
SourceMappingId,
const SourceMapping&,
const InternLookup* intern_lookup = nullptr);
base::Optional<int64_t> AddFrame(SourceFrameId,
const SourceFrame&,
const InternLookup* intern_lookup = nullptr);
base::Optional<int64_t> AddCallstack(
SourceCallstackId,
const SourceCallstack&,
const InternLookup* intern_lookup = nullptr);
int64_t GetDatabaseFrameIdForTesting(SourceFrameId);
// Gets the row number of string / mapping / frame / callstack previously
// added through AddString / AddMapping/ AddFrame / AddCallstack.
//
// If it is not found, look up the string / mapping / frame / callstack in
// the global InternedData state, and if found, add to the database, if not
// already added before.
//
// This is to support both ProfilePackets that contain the interned data
// (for Android Q) and where the interned data is kept globally in
// InternedData (for versions newer than Q).
base::Optional<StringId> FindAndInternString(
SourceStringId,
const InternLookup* intern_lookup,
InternedStringType type);
base::Optional<std::string> FindString(SourceStringId,
const InternLookup* intern_lookup,
InternedStringType type);
base::Optional<int64_t> FindMapping(SourceMappingId,
const InternLookup* intern_lookup);
base::Optional<int64_t> FindFrame(SourceFrameId,
const InternLookup* intern_lookup);
base::Optional<int64_t> FindCallstack(SourceCallstackId,
const InternLookup* intern_lookup);
// Clear indices when they're no longer needed.
void ClearIndices();
private:
StringId GetEmptyStringId();
std::unordered_map<SourceStringId, std::string> string_map_;
std::unordered_map<SourceMappingId, int64_t> mappings_;
std::unordered_map<SourceFrameId, int64_t> frames_;
std::unordered_map<SourceCallstackId, int64_t> callstacks_;
// TODO(oysteine): Share these indices between the StackProfileTrackers,
// since they're not sequence-specific.
std::unordered_map<tables::StackProfileMappingTable::Row, int64_t>
mapping_idx_;
std::unordered_map<tables::StackProfileFrameTable::Row, int64_t> frame_idx_;
std::unordered_map<tables::StackProfileCallsiteTable::Row, int64_t>
callsite_idx_;
TraceProcessorContext* const context_;
StringId empty_;
};
} // namespace trace_processor
} // namespace perfetto
#endif // SRC_TRACE_PROCESSOR_STACK_PROFILE_TRACKER_H_