2323#include " absl/base/internal/cycleclock.h"
2424#include " absl/base/nullability.h"
2525#include " absl/base/optimization.h"
26- #include " absl/time/time.h"
2726#include " tcmalloc/huge_cache.h"
28- #include " tcmalloc/huge_page_subrelease.h"
2927#include " tcmalloc/huge_pages.h"
30- #include " tcmalloc/internal/clock.h"
3128#include " tcmalloc/internal/config.h"
3229#include " tcmalloc/internal/linked_list.h"
3330#include " tcmalloc/internal/logging.h"
@@ -152,17 +149,8 @@ class HugeRegion : public TList<HugeRegion>::Elem {
152149template <typename Region>
153150class HugeRegionSet {
154151 public:
155- // For testing with mock clock.
156- HugeRegionSet (HugeRegionUsageOption use_huge_region_more_often, Clock clock)
157- : n_(0 ),
158- use_huge_region_more_often_ (use_huge_region_more_often),
159- regionstats_tracker_(clock, absl::Minutes(10 ), absl::Minutes(5 )) {}
160-
161152 explicit HugeRegionSet (HugeRegionUsageOption use_huge_region_more_often)
162- : HugeRegionSet(
163- use_huge_region_more_often,
164- Clock{.now = absl::base_internal::CycleClock::Now,
165- .freq = absl::base_internal::CycleClock::Frequency}) {}
153+ : n_(0 ), use_huge_region_more_often_(use_huge_region_more_often) {}
166154
167155 // If available, return a range of n free pages, setting *from_released =
168156 // true iff the returned range is currently unbacked.
@@ -176,19 +164,6 @@ class HugeRegionSet {
176164 // Add region to the set.
177165 void Contribute (Region* region);
178166
179- // Tries to release up to <desired> number of pages from fully-free but backed
180- // hugepages in HugeRegions. <intervals> defines the skip-subrelease
181- // intervals, but unlike HugePageFiller skip-subrelease, it only releases free
182- // hugepages.
183- // Releases all free and backed hugepages to system when <hit_limit> is set to
184- // true. Else, it uses intervals to determine recent demand as seen by
185- // HugeRegions to compute realized fragmentation. It may only release as much
186- // memory in free pages as determined by the realized fragmentation.
187- // Returns the number of pages actually released.
188- Length ReleasePagesByPeakDemand (Length desired,
189- SkipSubreleaseIntervals intervals,
190- bool hit_limit);
191-
192167 // Release hugepages that are unused but backed.
193168 // Releases up to <release_fraction> times number of free-but-backed hugepages
194169 // from each huge region. Note that this clamps release_fraction between 0 and
@@ -259,59 +234,10 @@ class HugeRegionSet {
259234 list_.append (r);
260235 }
261236
262- using StatsTrackerType = SubreleaseStatsTracker<600 >;
263- StatsTrackerType::SubreleaseStats GetSubreleaseStats () const {
264- StatsTrackerType::SubreleaseStats stats;
265- for (Region* region : list_) {
266- stats.num_pages += region->used_pages ();
267- stats.free_pages += region->free_pages ();
268- stats.unmapped_pages += region->unmapped_pages ();
269- stats.huge_pages [StatsTrackerType::kRegular ] += region->size ();
270- }
271- stats.num_pages_subreleased = subrelease_stats_.num_pages_subreleased ;
272- return stats;
273- }
274-
275- Length used_pages () const {
276- Length used;
277- for (Region* region : list_) {
278- used += region->used_pages ();
279- }
280- return used;
281- }
282-
283- Length free_pages () const {
284- Length free;
285- for (Region* region : list_) {
286- free += region->free_pages ();
287- }
288- return free;
289- }
290-
291- HugeLength size () const {
292- HugeLength size;
293- for (Region* region : list_) {
294- size += region->size ();
295- }
296- return size;
297- }
298-
299237 size_t n_;
300238 HugeRegionUsageOption use_huge_region_more_often_;
301239 // Sorted by longest_free increasing.
302240 TList<Region> list_;
303-
304- // Computes the recent demand to compute the number of pages that may be
305- // released. <desired> determines an upper-bound on the number of pages to
306- // release.
307- // Returns number of pages that may be released based on recent demand.
308- Length GetDesiredReleasablePages (Length desired,
309- SkipSubreleaseIntervals intervals);
310-
311- // Functionality related to tracking demand.
312- void UpdateStatsTracker ();
313- StatsTrackerType regionstats_tracker_;
314- SubreleaseStats subrelease_stats_;
315241};
316242
317243// REQUIRES: r.len() == size(); r unbacked.
@@ -558,78 +484,6 @@ inline HugeLength HugeRegion::UnbackHugepages(
558484 return released;
559485}
560486
561- template <typename Region>
562- inline Length HugeRegionSet<Region>::GetDesiredReleasablePages(
563- Length desired, SkipSubreleaseIntervals intervals) {
564- if (!intervals.SkipSubreleaseEnabled ()) {
565- return desired;
566- }
567- UpdateStatsTracker ();
568-
569- Length required_pages;
570- // There are two ways to calculate the demand requirement. We give priority to
571- // using the peak if peak_interval is set.
572- if (intervals.IsPeakIntervalSet ()) {
573- required_pages =
574- regionstats_tracker_.GetRecentPeak (intervals.peak_interval );
575- } else {
576- required_pages = regionstats_tracker_.GetRecentDemand (
577- intervals.short_interval , intervals.long_interval );
578- }
579-
580- Length current_pages = used_pages () + free_pages ();
581-
582- if (required_pages != Length (0 )) {
583- Length new_desired;
584- if (required_pages < current_pages) {
585- new_desired = current_pages - required_pages;
586- }
587-
588- // Because we currently release pages from fully backed and free hugepages,
589- // make sure that the realized fragmentation in HugeRegion is at least equal
590- // to kPagesPerHugePage. Otherwise, return zero to make sure we do not
591- // release any pages.
592- if (new_desired < kPagesPerHugePage ) {
593- new_desired = Length (0 );
594- }
595-
596- if (new_desired >= desired) {
597- return desired;
598- }
599-
600- // Compute the number of releasable pages from HugeRegion. We do not
601- // subrelease pages yet. Instead, we only release hugepages that are fully
602- // free but backed. Note: the remaining target should always be smaller or
603- // equal to the number of free pages according to the mechanism (recent peak
604- // is always larger or equal to current used_pages), however, we still
605- // calculate allowed release using the minimum of the two to avoid relying
606- // on that assumption.
607- Length free_backed_pages = free_backed ().in_pages ();
608- Length releasable_pages = std::min (free_backed_pages, new_desired);
609-
610- // Reports the amount of memory that we didn't release due to this
611- // mechanism, but never more than skipped free pages. In other words,
612- // skipped_pages is zero if all free pages are allowed to be released by
613- // this mechanism. Note, only free pages in the smaller of the two
614- // (current_pages and required_pages) are skipped, the rest are allowed to
615- // be subreleased.
616- Length skipped_pages = std::min ((free_backed_pages - releasable_pages),
617- (desired - new_desired));
618-
619- regionstats_tracker_.ReportSkippedSubreleasePages (
620- skipped_pages, std::min (current_pages, required_pages));
621- return new_desired;
622- }
623-
624- return desired;
625- }
626-
627- template <typename Region>
628- inline void HugeRegionSet<Region>::UpdateStatsTracker() {
629- regionstats_tracker_.Report (GetSubreleaseStats ());
630- subrelease_stats_.reset ();
631- }
632-
633487// If available, return a range of n free pages, setting *from_released =
634488// true iff the returned range is currently unbacked.
635489// Returns false if no range available.
@@ -639,7 +493,6 @@ inline bool HugeRegionSet<Region>::MaybeGet(Length n, PageId* page,
639493 for (Region* region : list_) {
640494 if (region->MaybeGet (n, page, from_released)) {
641495 Fix (region);
642- UpdateStatsTracker ();
643496 return true ;
644497 }
645498 }
@@ -657,7 +510,6 @@ inline bool HugeRegionSet<Region>::MaybePut(Range r) {
657510 if (region->contains (r.p )) {
658511 region->Put (r, release);
659512 Fix (region);
660- UpdateStatsTracker ();
661513 return true ;
662514 }
663515 }
@@ -670,49 +522,6 @@ template <typename Region>
670522inline void HugeRegionSet<Region>::Contribute(Region* region) {
671523 n_++;
672524 AddToList (region);
673- UpdateStatsTracker ();
674- }
675-
676- template <typename Region>
677- inline Length HugeRegionSet<Region>::ReleasePagesByPeakDemand(
678- Length desired, SkipSubreleaseIntervals intervals, bool hit_limit) {
679- // Because we are releasing fully-freed hugepages, in cases when malloc
680- // release rate is set to zero, we would still want to release some pages,
681- // provided it is allowed by the demand-based release strategy. We try to
682- // release up to 10% of the free and backed hugepages.
683- if (!hit_limit && desired == Length (0 )) {
684- size_t new_desired =
685- kFractionToReleaseFromRegion * free_backed ().in_pages ().raw_num ();
686- desired = Length (new_desired);
687- }
688-
689- // Only reduce desired if skip subrelease is on.
690- //
691- // Additionally, if we hit the limit, we should not be applying skip
692- // subrelease. OOM may be imminent.
693- if (intervals.SkipSubreleaseEnabled () && !hit_limit) {
694- desired = GetDesiredReleasablePages (desired, intervals);
695- }
696-
697- subrelease_stats_.set_limit_hit (hit_limit);
698-
699- Length released;
700- if (desired != Length (0 )) {
701- for (Region* region : list_) {
702- released += region->Release (desired - released).in_pages ();
703- if (released >= desired) break ;
704- }
705- }
706-
707- subrelease_stats_.num_pages_subreleased += released;
708-
709- // Keep separate stats if the on going release is triggered by reaching
710- // tcmalloc limit.
711- if (subrelease_stats_.limit_hit ()) {
712- subrelease_stats_.total_pages_subreleased_due_to_limit += released;
713- }
714-
715- return released;
716525}
717526
718527template <typename Region>
@@ -758,17 +567,6 @@ inline void HugeRegionSet<Region>::Print(Printer& out) const {
758567 in_pages > Length (0 ) ? static_cast <double >(total_free.raw_num ()) /
759568 static_cast <double >(in_pages.raw_num ())
760569 : 0.0 );
761-
762- // Subrelease telemetry.
763- out.printf (
764- " HugeRegion: Since startup, %zu pages subreleased, %zu hugepages "
765- " broken, (%zu pages, %zu hugepages due to reaching tcmalloc limit)\n " ,
766- subrelease_stats_.total_pages_subreleased .raw_num (),
767- subrelease_stats_.total_hugepages_broken .raw_num (),
768- subrelease_stats_.total_pages_subreleased_due_to_limit .raw_num (),
769- subrelease_stats_.total_hugepages_broken_due_to_limit .raw_num ());
770-
771- regionstats_tracker_.Print (out, " HugeRegion" );
772570}
773571
774572template <typename Region>
@@ -779,17 +577,6 @@ inline void HugeRegionSet<Region>::PrintInPbtxt(PbtxtRegion& hpaa) const {
779577 auto detail = hpaa.CreateSubRegion (" huge_region_details" );
780578 region->PrintInPbtxt (detail);
781579 }
782-
783- hpaa.PrintI64 (" region_num_pages_subreleased" ,
784- subrelease_stats_.total_pages_subreleased .raw_num ());
785- hpaa.PrintI64 (
786- " region_num_pages_subreleased_due_to_limit" ,
787- subrelease_stats_.total_pages_subreleased_due_to_limit .raw_num ());
788-
789- regionstats_tracker_.PrintSubreleaseStatsInPbtxt (hpaa,
790- " region_skipped_subrelease" );
791- regionstats_tracker_.PrintTimeseriesStatsInPbtxt (hpaa,
792- " region_stats_timeseries" );
793580}
794581
795582template <typename Region>
0 commit comments