/* * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ #ifndef HERMES_PUBLIC_GCCONFIG_H #define HERMES_PUBLIC_GCCONFIG_H #include "hermes/Public/CtorConfig.h" #include "hermes/Public/GCTripwireContext.h" #include #include #include #include #include #include #include #include #include namespace hermes { namespace vm { /// A type big enough to accomodate the entire allocated address space. /// Individual allocations are always 'uint32_t', but on a 64-bit machine we /// might want to accommodate a larger total heap (or not, in which case we keep /// it 32-bit). using gcheapsize_t = uint32_t; /// Represents a value before and after an event. /// NOTE: Not a std::pair because using the names are more readable than first /// and second. struct BeforeAndAfter { uint64_t before; uint64_t after; }; struct GCAnalyticsEvent { /// The same value as \p Name from GCConfig. Stored here for simplicity of /// the API since this is passed in callbacks that might not be able to store /// the name. For a given Runtime, this will be the same value every time. std::string runtimeDescription; /// The kind of GC this was. For a given Runtime, this will be the same value /// every time. std::string gcKind; /// The type of collection that ran, typically differentiating a "young" /// generation GC and an "old" generation GC. When other values say they're /// "scoped to the collectionType", it means that for a generation GC /// they're only reporting the numbers for that generation. std::string collectionType; /// The cause of this GC. Can be an arbitrary string describing the cause. /// Typically "natural" is used to mean that the GC decided it was time, and /// other causes mean it was forced by some other condition. std::string cause; /// The wall time a collection took from start to end. std::chrono::milliseconds duration; /// The CPU time a collection took from start to end. This time measure will /// exclude time waiting on disk, mutexes, or time spent not scheduled to run. std::chrono::milliseconds cpuDuration; /// The number of bytes allocated in the heap before and after the collection. /// measurement does not include fragmentation, and is the same as the sum of /// all sizes in calls to \p GC::makeA into that generation (including any /// rounding up the GC does). /// The value is scoped to the \p collectionType. BeforeAndAfter allocated; /// The number of bytes in use by the heap before and after the collection. /// This measurement can include fragmentation if the \p gcKind has that /// concept. /// The value is scoped to the \p collectionType. BeforeAndAfter size; /// The number of bytes external to the JS heap before and after the /// collection. /// The value is scoped to the \p collectionType. BeforeAndAfter external; /// The ratio of cells that survived the collection to all cells before /// the collection. Note that this is in term of sizes of cells, not the /// numbers of cells. Excludes any cells not in direct use by the JS program, /// such as FillerCell or FreelistCell. /// The value is scoped to the \p collectionType. double survivalRatio; /// A list of metadata tags to annotate this event with. std::vector tags; }; /// Parameters to control a tripwire function called when the live set size /// surpasses a given threshold after collections. Check documentation in /// README.md #define GC_TRIPWIRE_FIELDS(F) \ /* If the heap size is above this threshold after a collection, the tripwire \ * is triggered. */ \ F(constexpr, gcheapsize_t, Limit, std::numeric_limits::max()) \ \ /* The callback to call when the tripwire is considered triggered. */ \ F(HERMES_NON_CONSTEXPR, \ std::function, \ Callback, \ nullptr) \ /* GC_TRIPWIRE_FIELDS END */ _HERMES_CTORCONFIG_STRUCT(GCTripwireConfig, GC_TRIPWIRE_FIELDS, {}); #undef HEAP_TRIPWIRE_FIELDS #define GC_HANDLESAN_FIELDS(F) \ /* The probability with which the GC should keep moving the heap */ \ /* to detect stale GC handles. */ \ F(constexpr, double, SanitizeRate, 0.0) \ /* Random seed to use for basis of decisions whether or not to */ \ /* sanitize. A negative value will mean a seed will be chosen at */ \ /* random. */ \ F(constexpr, int64_t, RandomSeed, -1) \ /* GC_HANDLESAN_FIELDS END */ _HERMES_CTORCONFIG_STRUCT(GCSanitizeConfig, GC_HANDLESAN_FIELDS, {}); #undef GC_HANDLESAN_FIELDS /// How aggressively to return unused memory to the OS. enum ReleaseUnused { kReleaseUnusedNone = 0, /// Don't try to release unused memory. kReleaseUnusedOld, /// Only old gen, on full collections. kReleaseUnusedYoungOnFull, /// Also young gen, but only on full collections. kReleaseUnusedYoungAlways /// Also young gen, also on young gen collections. }; enum class GCEventKind { CollectionStart, CollectionEnd, }; /// Parameters for GC Initialisation. Check documentation in README.md /// constexpr indicates that the default value is constexpr. #define GC_FIELDS(F) \ /* Minimum heap size hint. */ \ F(constexpr, gcheapsize_t, MinHeapSize, 0) \ \ /* Initial heap size hint. */ \ F(constexpr, gcheapsize_t, InitHeapSize, 32 << 20) \ \ /* Maximum heap size hint. */ \ F(constexpr, gcheapsize_t, MaxHeapSize, 3u << 30) \ \ /* Sizing heuristic: fraction of heap to be occupied by live data. */ \ F(constexpr, double, OccupancyTarget, 0.5) \ \ /* Number of consecutive full collections considered to be an OOM. */ \ F(constexpr, \ unsigned, \ EffectiveOOMThreshold, \ std::numeric_limits::max()) \ \ /* Sanitizer configuration for the GC. */ \ F(constexpr, GCSanitizeConfig, SanitizeConfig) \ \ /* Whether to Keep track of GC Statistics. */ \ F(constexpr, bool, ShouldRecordStats, false) \ \ /* How aggressively to return unused memory to the OS. */ \ F(constexpr, ReleaseUnused, ShouldReleaseUnused, kReleaseUnusedOld) \ \ /* Name for this heap in logs. */ \ F(HERMES_NON_CONSTEXPR, std::string, Name, "") \ \ /* Configuration for the Heap Tripwire. */ \ F(HERMES_NON_CONSTEXPR, GCTripwireConfig, TripwireConfig) \ \ /* Whether to (initially) allocate from the young gen (true) or the */ \ /* old gen (false). */ \ F(constexpr, bool, AllocInYoung, true) \ \ /* Whether to fill the YG with invalid data after each collection. */ \ F(constexpr, bool, OverwriteDeadYGObjects, false) \ \ /* Whether to revert, if necessary, to young-gen allocation at TTI. */ \ F(constexpr, bool, RevertToYGAtTTI, false) \ \ /* Whether to use mprotect on GC metadata between GCs. */ \ F(constexpr, bool, ProtectMetadata, false) \ \ /* Callout for an analytics event. */ \ F(HERMES_NON_CONSTEXPR, \ std::function, \ AnalyticsCallback, \ nullptr) \ \ /* Called at GC events (see GCEventKind enum for the list). The */ \ /* second argument contains human-readable details about the event. */ \ /* NOTE: The function MUST NOT invoke any methods on the Runtime. */ \ F(HERMES_NON_CONSTEXPR, \ std::function, \ Callback, \ nullptr) \ /* GC_FIELDS END */ _HERMES_CTORCONFIG_STRUCT(GCConfig, GC_FIELDS, { if (builder.hasMinHeapSize()) { if (builder.hasInitHeapSize()) { // If both are specified, normalize the initial size up to the minimum, // if necessary. InitHeapSize_ = std::max(MinHeapSize_, InitHeapSize_); } else { // If the minimum is set explicitly, but the initial heap size is not, // use the minimum as the initial size. InitHeapSize_ = MinHeapSize_; } } assert(InitHeapSize_ >= MinHeapSize_); // Make sure the max is at least the Init. MaxHeapSize_ = std::max(InitHeapSize_, MaxHeapSize_); }); #undef GC_FIELDS } // namespace vm } // namespace hermes #endif // HERMES_PUBLIC_GCCONFIG_H