1 /**
2 * Copyright (c) 2023-2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 #include <algorithm>
16 #include "g1_pause_tracker.h"
17 #include "utils/logger.h"
18 #include "utils/type_converter.h"
19 #include "libpandabase/os/time.h"
20
21 namespace ark::mem {
G1PauseTracker(int64_t gcPauseIntervalMs,int64_t maxGcTimeMs)22 G1PauseTracker::G1PauseTracker(int64_t gcPauseIntervalMs, int64_t maxGcTimeMs)
23 : gcPauseIntervalUs_(gcPauseIntervalMs * ark::os::time::MILLIS_TO_MICRO),
24 maxGcTimeUs_(maxGcTimeMs * ark::os::time::MILLIS_TO_MICRO)
25 {
26 }
27
AddPauseInNanos(int64_t startTimeNs,int64_t endTimeNs)28 bool G1PauseTracker::AddPauseInNanos(int64_t startTimeNs, int64_t endTimeNs)
29 {
30 return AddPause(startTimeNs / ark::os::time::MICRO_TO_NANO, endTimeNs / ark::os::time::MICRO_TO_NANO);
31 }
32
AddPause(int64_t startTimeUs,int64_t endTimeUs)33 bool G1PauseTracker::AddPause(int64_t startTimeUs, int64_t endTimeUs)
34 {
35 RemoveOutOfIntervalEntries(endTimeUs);
36 pauses_.push_back(PauseEntry(startTimeUs, endTimeUs));
37 auto gcTime = CalculateIntervalPauseInMicros(endTimeUs);
38 if (gcTime > maxGcTimeUs_) {
39 LOG(DEBUG, GC) << "Target GC pause was exceeded: "
40 << ark::helpers::TimeConverter(gcTime * ark::os::time::MICRO_TO_NANO) << " > "
41 << ark::helpers::TimeConverter(maxGcTimeUs_ * ark::os::time::MICRO_TO_NANO)
42 << " in time interval "
43 << ark::helpers::TimeConverter(gcPauseIntervalUs_ * ark::os::time::MICRO_TO_NANO);
44 return false;
45 }
46 return true;
47 }
48
RemoveOutOfIntervalEntries(int64_t nowUs)49 void G1PauseTracker::RemoveOutOfIntervalEntries(int64_t nowUs)
50 {
51 auto oldestIntervalTime = nowUs - gcPauseIntervalUs_;
52 while (!pauses_.empty()) {
53 auto oldestPause = pauses_.front();
54 if (oldestPause.GetEndTimeInMicros() > oldestIntervalTime) {
55 break;
56 }
57 pauses_.pop_front();
58 }
59 }
60
CalculateIntervalPauseInMicros(int64_t nowUs)61 int64_t G1PauseTracker::CalculateIntervalPauseInMicros(int64_t nowUs)
62 {
63 int64_t gcTime = 0;
64 auto oldestIntervalTime = nowUs - gcPauseIntervalUs_;
65 auto end = pauses_.cend();
66 for (auto it = pauses_.cbegin(); it != end; ++it) {
67 if (it->GetEndTimeInMicros() > oldestIntervalTime) {
68 gcTime += it->DurationInMicros(oldestIntervalTime);
69 }
70 }
71 return gcTime;
72 }
73
MinDelayBeforePauseInMicros(int64_t nowUs,int64_t pauseTimeUs)74 int64_t G1PauseTracker::MinDelayBeforePauseInMicros(int64_t nowUs, int64_t pauseTimeUs)
75 {
76 pauseTimeUs = std::min(pauseTimeUs, maxGcTimeUs_);
77 auto gcBudget = maxGcTimeUs_ - pauseTimeUs;
78 auto newIntervalTime = nowUs + pauseTimeUs;
79 auto oldestIntervalTime = newIntervalTime - gcPauseIntervalUs_;
80
81 auto rend = pauses_.crend();
82 for (auto it = pauses_.crbegin(); it != rend; ++it) {
83 if (it->GetEndTimeInMicros() <= oldestIntervalTime) {
84 break;
85 }
86
87 auto duration = it->DurationInMicros(oldestIntervalTime);
88 if (duration > gcBudget) {
89 auto newOldestIntervalTime = it->GetEndTimeInMicros() - gcBudget;
90 ASSERT(newOldestIntervalTime >= oldestIntervalTime);
91 return newOldestIntervalTime - oldestIntervalTime;
92 }
93
94 gcBudget -= duration;
95 }
96
97 return 0;
98 }
99
MinDelayBeforeMaxPauseInMicros(int64_t nowUs)100 int64_t G1PauseTracker::MinDelayBeforeMaxPauseInMicros(int64_t nowUs)
101 {
102 return MinDelayBeforePauseInMicros(nowUs, maxGcTimeUs_);
103 }
104 } // namespace ark::mem
105