namespace __sanitizer {
+// Used externally
+SleepInterval last_sleep_int = {common_flags()->bgthread_min_sleep_ms, true};
+
bool ReportFile::SupportsColors() {
SpinMutexLock l(mu);
ReopenIfNecessary();
SoftRssLimitExceededCallback = Callback;
}
+static int MinNonZeroTimeout(void)
+{
+ int T = Max(common_flags()->heap_profile_full_out_time,
+ common_flags()->heap_profile_short_out_time);
+ int t = Min(common_flags()->heap_profile_full_out_time,
+ common_flags()->heap_profile_short_out_time);
+ return t > 0 ? t : T;
+}
+
+static int Mid(uptr a, uptr b)
+{
+ int m = Min(a, b);
+ int M = Max(a, b);
+ return m + (M - m + 1) / 2;
+}
+
+// Calculate new BackgroundThread sleep duration based on previous
+// sleep intervals.
+//
+// This algorithm remembers the last several sleeps (namely 2), their
+// durations and whether or not they were followed by some interesting
+// events (i.e. delivery of memory usage statistics). Based on that criteria,
+// it considers every interval to be either interesting or uninteresting.
+// If the last sleeping interval was interesting, then we probably need to
+// sleep less, and vice versa. How much less (or more) is determined by
+// "reference points":
+//
+// * if last and last but one intervals have different
+// interesting/uninteresting attributes, then change is considered to be
+// smooth, and duration of last but one interval will serve as a reference
+// point:
+// 0 low_ref new duration, ms
+// -|------|-------------|-----------|------------|-------------|-------->
+// low_thrhold last_but_one last high_thrhold
+// (uninteresting) (interesting)
+//
+// * if 2 last intervals are both interesting (both uninteresting), then
+// change is considered to be rapid, and low/high threshold will serve
+// as a reference point:
+// 0 new high_ref duration, ms
+// -|------|-------------|---------------|---------|---------|----------->
+// low_thrhold last_but_one last high_thrhold
+// (uninteresting) (uninteresting)
+//
+// High/low thresholds, in turn, are determined by both
+// bgthread_min/max_sleep_ms values and profiler timeouts (if the user wants
+// us to gather statistics every Tms, there's no sense in sleeping longer
+// than Tms).
+//
+// The algorithm also tries not to change interval duration too rapidly,
+// thus multiplying/dividing it by factor of 2 together with calculating
+// Mid() value with high/low reference points and choosing more "smooth"
+// option.
+static int CalcNewSleepInterval(void)
+{
+ static SleepInterval last_but_one_sleep_int =
+ {common_flags()->bgthread_min_sleep_ms, true};
+
+ static const int wanted_timeout = MinNonZeroTimeout();
+ static const int high_threshold = wanted_timeout > 0 ?
+ Min(common_flags()->bgthread_max_sleep_ms,
+ wanted_timeout) :
+ common_flags()->bgthread_max_sleep_ms;
+ static const int low_threshold = wanted_timeout > 0 ?
+ Min(common_flags()->bgthread_min_sleep_ms,
+ wanted_timeout) :
+ common_flags()->bgthread_min_sleep_ms;
+
+ static int last_eventful_dur = high_threshold;
+ static int last_eventless_dur = low_threshold;
+
+ int new_sleep_dur;
+
+ if (!last_sleep_int.ends_with_event) {
+ // Increase sleep interval length
+ last_eventless_dur = last_sleep_int.duration_ms;
+ if (last_eventful_dur <= last_sleep_int.duration_ms) {
+ last_eventful_dur = high_threshold;
+ }
+
+ int high_ref;
+ if (!last_but_one_sleep_int.ends_with_event ||
+ last_but_one_sleep_int.duration_ms <= last_sleep_int.duration_ms) {
+ high_ref = high_threshold;
+ } else {
+ high_ref = last_but_one_sleep_int.duration_ms;
+ }
+
+ new_sleep_dur = Min(Min(last_sleep_int.duration_ms * 2,
+ Mid(last_sleep_int.duration_ms, high_ref)),
+ last_eventful_dur);
+ } else {
+ // Decrease sleep interval length
+ last_eventful_dur = last_sleep_int.duration_ms;
+ if (last_eventless_dur >= last_sleep_int.duration_ms) {
+ last_eventless_dur = low_threshold;
+ }
+
+ int low_ref;
+ if (last_but_one_sleep_int.ends_with_event ||
+ last_but_one_sleep_int.duration_ms >= last_sleep_int.duration_ms) {
+ low_ref = low_threshold;
+ } else {
+ low_ref = last_but_one_sleep_int.duration_ms;
+ }
+
+ new_sleep_dur = Max(Max(last_sleep_int.duration_ms / 2,
+ Mid(last_sleep_int.duration_ms, low_ref)),
+ last_eventless_dur);
+ }
+
+ last_but_one_sleep_int = last_sleep_int;
+ last_sleep_int = {new_sleep_dur, false};
+
+ return new_sleep_dur;
+}
+
#if SANITIZER_LINUX && !SANITIZER_GO
void BackgroundThread(void *arg) {
uptr hard_rss_limit_mb = common_flags()->hard_rss_limit_mb;
bool reached_soft_rss_limit = false;
while (true) {
- SleepForMillis(100);
+ SleepForMillis(CalcNewSleepInterval());
uptr current_rss_mb = GetRSS() >> 20;
if (Verbosity()) {
// If RSS has grown 10% since last time, print some information.