%PDF- %PDF-
| Direktori : /home/vacivi36/vittasync.vacivitta.com.br/vittasync/node/deps/v8/src/snapshot/ |
| Current File : /home/vacivi36/vittasync.vacivitta.com.br/vittasync/node/deps/v8/src/snapshot/sort-builtins.h |
// Copyright 2023 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_SNAPSHOT_SORT_BUILTINS_H_
#define V8_SNAPSHOT_SORT_BUILTINS_H_
#include <unordered_map>
#include <vector>
#include "src/builtins/builtins.h"
#include "src/diagnostics/basic-block-profiler.h"
// The inputs were the builtin size, call graph and basic block execution count.
// There are 3 steps in this sorting algorithm:
// 1. Initializing cluster and sorting:
// A cluster represents a group of functions. At the beginning, each
// function was in an individual cluster, and we sort these clusters
// by their density (which means how much probabilities this function was
// invoked).
//
// 2. Merge the best predecessor:
// After step 1, we will get lots of clusters which may contain only
// one function. According to this order, we iterate each function
// and merge cluster with some conditions, like:
// 1) The most incoming probability.
// 2) Incoming probability must be bigger than a threshold, like 0.1
// 3) Merged cluster size couldn't be bigger than a threshold, like 1 mb.
// 4) Predecessor cluster density couldn't be bigger N times than the new
// merged cluster, N is 8 now.
//
// 3. Sorting clusters:
// After step 2, we obtain lots of clusters which comprise several functions.
// We will finally sort these clusters by their density.
namespace v8 {
namespace internal {
class Cluster;
struct CallProbability {
CallProbability(int32_t incoming = 0, int32_t outgoing = 0)
: incoming_(incoming), outgoing_(outgoing) {}
// There are a caller and a callee, we assume caller was invoked
// "caller-count" times, it calls callee "call-count" times, the callee was
// invoked "callee-count" times. imcoming_ means the possibity the callee
// calls from caller, it was calculted by call-count / callee-count. If
// callee-count is 0 (may not be compiled by TurboFan or normalized as 0 due
// to too small), we set imcoming_ as -1.
int32_t incoming_;
// outgoing_ means the possibity the caller
// calls to callee, it was calculted by call-count / caller-count. If
// caller-count is 0 (may not be compiled by TurboFan or normalized as 0 due
// to too small), we set outgoing_ as -1. We didn't use outgoing_ as condition
// for reordering builtins yet, but we could try to do some experiments with
// it later for obtaining a better order of builtins.
int32_t outgoing_;
};
// The key is the callee builtin, the value is call probabilities in percent
// (mostly range in 0 ~ 100, except one call happend in a loop block which was
// executed more times than block 0 of this builtin).
using CallProbabilities = std::unordered_map<Builtin, CallProbability>;
// The key is the caller builtin.
using CallGraph = std::unordered_map<Builtin, CallProbabilities>;
// The key is the builtin id, the value is density of builtin (range in 0 ~
// 10000).
using BuiltinDensityMap = std::unordered_map<Builtin, uint32_t>;
// The index is the builtin id, the value is size of builtin (in bytes).
using BuiltinSize = std::vector<uint32_t>;
// The key is the builtin id, the value is the cluster which it was comprised.
using BuiltinClusterMap = std::unordered_map<Builtin, Cluster*>;
class BuiltinsSorter {
const int32_t kMinEdgeProbabilityThreshold = 10;
const uint32_t kMaxClusterSize = 1 * MB;
const uint32_t kMaxDensityDecreaseThreshold = 8;
const std::string kBuiltinCallBlockDensityMarker = "block_count";
const std::string kBuiltinDensityMarker = "builtin_count";
// Pair of denstity of builtin and builtin id.
struct BuiltinDensitySlot {
BuiltinDensitySlot(uint32_t density, Builtin builtin)
: density_(density), builtin_(builtin) {}
uint32_t density_;
Builtin builtin_;
};
public:
BuiltinsSorter();
~BuiltinsSorter();
std::vector<Builtin> SortBuiltins(const char* profiling_file,
const std::vector<uint32_t>& builtin_size);
private:
void InitializeCallGraph(const char* profiling_file,
const std::vector<uint32_t>& size);
void InitializeClusters();
void MergeBestPredecessors();
void SortClusters();
Builtin FindBestPredecessorOf(Builtin callee);
void ProcessBlockCountLineInfo(
std::istringstream& line_stream,
std::unordered_map<std::string, Builtin>& name2id);
void ProcessBuiltinDensityLineInfo(
std::istringstream& line_stream,
std::unordered_map<std::string, Builtin>& name2id);
std::vector<Cluster*> clusters_;
std::vector<BuiltinDensitySlot> builtin_density_order_;
CallGraph call_graph_;
BuiltinDensityMap builtin_density_map_;
BuiltinSize builtin_size_;
BuiltinClusterMap builtin_cluster_map_;
friend class Cluster;
};
class Cluster {
public:
Cluster(uint32_t density, uint32_t size, Builtin target,
BuiltinsSorter* sorter);
void Merge(Cluster* other);
uint64_t time_approximation();
private:
// Max initialized density was normalized as 10000.
uint32_t density_;
// Size of the cluster in bytes.
uint32_t size_;
std::vector<Builtin> targets_;
BuiltinsSorter* sorter_;
friend class BuiltinsSorter;
};
} // namespace internal
} // namespace v8
#endif // V8_SNAPSHOT_SORT_BUILTINS_H_