Path: blob/main/contrib/llvm-project/llvm/lib/ProfileData/PGOCtxProfReader.cpp
35233 views
//===- PGOCtxProfReader.cpp - Contextual Instrumentation profile reader ---===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// Read a contextual profile into a datastructure suitable for maintenance9// throughout IPO10//11//===----------------------------------------------------------------------===//1213#include "llvm/ProfileData/PGOCtxProfReader.h"14#include "llvm/Bitstream/BitCodeEnums.h"15#include "llvm/Bitstream/BitstreamReader.h"16#include "llvm/ProfileData/InstrProf.h"17#include "llvm/ProfileData/PGOCtxProfWriter.h"18#include "llvm/Support/Errc.h"19#include "llvm/Support/Error.h"2021using namespace llvm;2223// FIXME(#92054) - these Error handling macros are (re-)invented in a few24// places.25#define EXPECT_OR_RET(LHS, RHS) \26auto LHS = RHS; \27if (!LHS) \28return LHS.takeError();2930#define RET_ON_ERR(EXPR) \31if (auto Err = (EXPR)) \32return Err;3334Expected<PGOContextualProfile &>35PGOContextualProfile::getOrEmplace(uint32_t Index, GlobalValue::GUID G,36SmallVectorImpl<uint64_t> &&Counters) {37auto [Iter, Inserted] = Callsites[Index].insert(38{G, PGOContextualProfile(G, std::move(Counters))});39if (!Inserted)40return make_error<InstrProfError>(instrprof_error::invalid_prof,41"Duplicate GUID for same callsite.");42return Iter->second;43}4445void PGOContextualProfile::getContainedGuids(46DenseSet<GlobalValue::GUID> &Guids) const {47Guids.insert(GUID);48for (const auto &[_, Callsite] : Callsites)49for (const auto &[_, Callee] : Callsite)50Callee.getContainedGuids(Guids);51}5253Expected<BitstreamEntry> PGOCtxProfileReader::advance() {54return Cursor.advance(BitstreamCursor::AF_DontAutoprocessAbbrevs);55}5657Error PGOCtxProfileReader::wrongValue(const Twine &Msg) {58return make_error<InstrProfError>(instrprof_error::invalid_prof, Msg);59}6061Error PGOCtxProfileReader::unsupported(const Twine &Msg) {62return make_error<InstrProfError>(instrprof_error::unsupported_version, Msg);63}6465bool PGOCtxProfileReader::canReadContext() {66auto Blk = advance();67if (!Blk) {68consumeError(Blk.takeError());69return false;70}71return Blk->Kind == BitstreamEntry::SubBlock &&72Blk->ID == PGOCtxProfileBlockIDs::ContextNodeBlockID;73}7475Expected<std::pair<std::optional<uint32_t>, PGOContextualProfile>>76PGOCtxProfileReader::readContext(bool ExpectIndex) {77RET_ON_ERR(Cursor.EnterSubBlock(PGOCtxProfileBlockIDs::ContextNodeBlockID));7879std::optional<ctx_profile::GUID> Guid;80std::optional<SmallVector<uint64_t, 16>> Counters;81std::optional<uint32_t> CallsiteIndex;8283SmallVector<uint64_t, 1> RecordValues;8485// We don't prescribe the order in which the records come in, and we are ok86// if other unsupported records appear. We seek in the current subblock until87// we get all we know.88auto GotAllWeNeed = [&]() {89return Guid.has_value() && Counters.has_value() &&90(!ExpectIndex || CallsiteIndex.has_value());91};92while (!GotAllWeNeed()) {93RecordValues.clear();94EXPECT_OR_RET(Entry, advance());95if (Entry->Kind != BitstreamEntry::Record)96return wrongValue(97"Expected records before encountering more subcontexts");98EXPECT_OR_RET(ReadRecord,99Cursor.readRecord(bitc::UNABBREV_RECORD, RecordValues));100switch (*ReadRecord) {101case PGOCtxProfileRecords::Guid:102if (RecordValues.size() != 1)103return wrongValue("The GUID record should have exactly one value");104Guid = RecordValues[0];105break;106case PGOCtxProfileRecords::Counters:107Counters = std::move(RecordValues);108if (Counters->empty())109return wrongValue("Empty counters. At least the entry counter (one "110"value) was expected");111break;112case PGOCtxProfileRecords::CalleeIndex:113if (!ExpectIndex)114return wrongValue("The root context should not have a callee index");115if (RecordValues.size() != 1)116return wrongValue("The callee index should have exactly one value");117CallsiteIndex = RecordValues[0];118break;119default:120// OK if we see records we do not understand, like records (profile121// components) introduced later.122break;123}124}125126PGOContextualProfile Ret(*Guid, std::move(*Counters));127128while (canReadContext()) {129EXPECT_OR_RET(SC, readContext(true));130auto &Targets = Ret.callsites()[*SC->first];131auto [_, Inserted] =132Targets.insert({SC->second.guid(), std::move(SC->second)});133if (!Inserted)134return wrongValue(135"Unexpected duplicate target (callee) at the same callsite.");136}137return std::make_pair(CallsiteIndex, std::move(Ret));138}139140Error PGOCtxProfileReader::readMetadata() {141EXPECT_OR_RET(Blk, advance());142if (Blk->Kind != BitstreamEntry::SubBlock)143return unsupported("Expected Version record");144RET_ON_ERR(145Cursor.EnterSubBlock(PGOCtxProfileBlockIDs::ProfileMetadataBlockID));146EXPECT_OR_RET(MData, advance());147if (MData->Kind != BitstreamEntry::Record)148return unsupported("Expected Version record");149150SmallVector<uint64_t, 1> Ver;151EXPECT_OR_RET(Code, Cursor.readRecord(bitc::UNABBREV_RECORD, Ver));152if (*Code != PGOCtxProfileRecords::Version)153return unsupported("Expected Version record");154if (Ver.size() != 1 || Ver[0] > PGOCtxProfileWriter::CurrentVersion)155return unsupported("Version " + Twine(*Code) +156" is higher than supported version " +157Twine(PGOCtxProfileWriter::CurrentVersion));158return Error::success();159}160161Expected<std::map<GlobalValue::GUID, PGOContextualProfile>>162PGOCtxProfileReader::loadContexts() {163std::map<GlobalValue::GUID, PGOContextualProfile> Ret;164RET_ON_ERR(readMetadata());165while (canReadContext()) {166EXPECT_OR_RET(E, readContext(false));167auto Key = E->second.guid();168if (!Ret.insert({Key, std::move(E->second)}).second)169return wrongValue("Duplicate roots");170}171return std::move(Ret);172}173174175