1+ /*
2+ * Copyright (c) 2023, 2023, Oracle and/or its affiliates. All rights reserved.
3+ * Copyright (c) 2023, 2023, Red Hat Inc. All rights reserved.
4+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5+ *
6+ * This code is free software; you can redistribute it and/or modify it
7+ * under the terms of the GNU General Public License version 2 only, as
8+ * published by the Free Software Foundation. Oracle designates this
9+ * particular file as subject to the "Classpath" exception as provided
10+ * by Oracle in the LICENSE file that accompanied this code.
11+ *
12+ * This code is distributed in the hope that it will be useful, but WITHOUT
13+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15+ * version 2 for more details (a copy is included in the LICENSE file that
16+ * accompanied this code).
17+ *
18+ * You should have received a copy of the GNU General Public License version
19+ * 2 along with this work; if not, write to the Free Software Foundation,
20+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
21+ *
22+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
23+ * or visit www.oracle.com if you need additional information or have any
24+ * questions.
25+ */
26+
127package com .oracle .svm .core .jfr ;
228
329import com .oracle .svm .core .jdk .UninterruptibleUtils ;
@@ -18,23 +44,22 @@ public class JfrThrottler {
1844 private static final long SECOND_IN_NS = 1000000000 ;
1945 private static final long SECOND_IN_MS = 1000 ;
2046 private static final long MINUTE_IN_NS = SECOND_IN_NS * 60 ;
21- // private static final long MINUTE_IN_MS = SECOND_IN_MS *60;
22- // private static final long HOUR_IN_MS = MINUTE_IN_MS * 60;
23- // private static final long HOUR_IN_NS = MINUTE_IN_NS * 60;
24- // private static final long DAY_IN_MS = HOUR_IN_MS * 24;
25- // private static final long DAY_IN_NS = HOUR_IN_NS * 24;
26- // private static final long TEN_PER_S_IN_MINUTES = 600;
27- // private static final long TEN_PER_S_IN_HOURS = 36000;
28- // private static final long TEN_PER_S_IN_DAYS = 864000;
29- // Copied from hotspot
47+ // private static final long MINUTE_IN_MS = SECOND_IN_MS *60;
48+ // private static final long HOUR_IN_MS = MINUTE_IN_MS * 60;
49+ // private static final long HOUR_IN_NS = MINUTE_IN_NS * 60;
50+ // private static final long DAY_IN_MS = HOUR_IN_MS * 24;
51+ // private static final long DAY_IN_NS = HOUR_IN_NS * 24;
52+ // private static final long TEN_PER_S_IN_MINUTES = 600;
53+ // private static final long TEN_PER_S_IN_HOURS = 36000;
54+ // private static final long TEN_PER_S_IN_DAYS = 864000;
55+ // Copied from hotspot
3056 private static final int WINDOW_DIVISOR = 5 ;
3157 private static final int EVENT_THROTTLER_OFF = -2 ;
3258
3359 // Can't use reentrant lock because it allocates
34- // private final UninterruptibleUtils.AtomicPointer<IsolateThread> lock;
60+ // private final UninterruptibleUtils.AtomicPointer<IsolateThread> lock;
3561 private final VMMutex mutex ;
3662
37-
3863 public UninterruptibleUtils .AtomicBoolean disabled ; // Already volatile
3964 private JfrThrottlerWindow window0 ;
4065 private JfrThrottlerWindow window1 ;
@@ -52,8 +77,8 @@ public JfrThrottler(VMMutex mutex) {
5277 accumulatedDebtCarryCount = 0 ;
5378 reconfigure = false ;
5479 disabled = new UninterruptibleUtils .AtomicBoolean (true );
55- // lock = new UninterruptibleUtils.AtomicPointer<>(); // I assume this is initially
56- // WordFactorynullPointer()
80+ // lock = new UninterruptibleUtils.AtomicPointer<>(); // I assume this is initially
81+ // WordFactorynullPointer()
5782 window0 = new JfrThrottlerWindow ();
5883 window1 = new JfrThrottlerWindow ();
5984 activeWindow = window0 ; // same as hotspot. Unguarded is ok because all throttler instances
@@ -62,40 +87,39 @@ public JfrThrottler(VMMutex mutex) {
6287 }
6388
6489 /**
65- * Convert rate to samples/second if possible.
66- * Want to avoid long period with large windows with a large number of samples per window
67- * in favor of many smaller windows.
68- * This is in the critical section because setting the sample size and period must be done together atomically.
90+ * Convert rate to samples/second if possible. Want to avoid long period with large windows with
91+ * a large number of samples per window in favor of many smaller windows. This is in the
92+ * critical section because setting the sample size and period must be done together atomically.
6993 * Otherwise, we risk a window's params being set with only one of the two updated.
7094 */
71- // private void normalize1(long eventSampleSize, long periodMs){
72- // VMError.guarantee(mutex.isOwner(), "Throttler lock must be acquired in critical section.");
73- // // Do we want more than 10samples/s ? If so convert to samples/s
74- // if (periodMs <= SECOND_IN_MS){
75- // //nothing
76- // } else if (periodMs <= MINUTE_IN_MS) {
77- // if (eventSampleSize >= TEN_PER_S_IN_MINUTES) {
78- // eventSampleSize /= 60;
79- // periodMs /= 60;
80- // }
81- // } else if (periodMs <= HOUR_IN_MS) {
82- // if (eventSampleSize >=TEN_PER_S_IN_HOURS) {
83- // eventSampleSize /= 3600;
84- // periodMs /= 3600;
85- // }
86- // } else if (periodMs <= DAY_IN_MS) {
87- // if (eventSampleSize >=TEN_PER_S_IN_DAYS) {
88- // eventSampleSize /= 86400;
89- // periodMs /= 86400;
90- // }
91- // }
92- // this.eventSampleSize = eventSampleSize;
93- // this.periodNs = periodMs * 1000000;
94- // }
95- private void normalize (long samplesPerPeriod , double periodMs ){
95+ // private void normalize1(long eventSampleSize, long periodMs){
96+ // VMError.guarantee(mutex.isOwner(), "Throttler lock must be acquired in critical section.");
97+ // // Do we want more than 10samples/s ? If so convert to samples/s
98+ // if (periodMs <= SECOND_IN_MS){
99+ // //nothing
100+ // } else if (periodMs <= MINUTE_IN_MS) {
101+ // if (eventSampleSize >= TEN_PER_S_IN_MINUTES) {
102+ // eventSampleSize /= 60;
103+ // periodMs /= 60;
104+ // }
105+ // } else if (periodMs <= HOUR_IN_MS) {
106+ // if (eventSampleSize >=TEN_PER_S_IN_HOURS) {
107+ // eventSampleSize /= 3600;
108+ // periodMs /= 3600;
109+ // }
110+ // } else if (periodMs <= DAY_IN_MS) {
111+ // if (eventSampleSize >=TEN_PER_S_IN_DAYS) {
112+ // eventSampleSize /= 86400;
113+ // periodMs /= 86400;
114+ // }
115+ // }
116+ // this.eventSampleSize = eventSampleSize;
117+ // this.periodNs = periodMs * 1000000;
118+ // }
119+ private void normalize (long samplesPerPeriod , double periodMs ) {
96120 VMError .guarantee (mutex .isOwner (), "Throttler lock must be acquired in critical section." );
97121 // Do we want more than 10samples/s ? If so convert to samples/s
98- double periodsPerSecond = 1000.0 / periodMs ;
122+ double periodsPerSecond = 1000.0 / periodMs ;
99123 double samplesPerSecond = samplesPerPeriod * periodsPerSecond ;
100124 if (samplesPerSecond >= 10 && periodMs > SECOND_IN_MS ) {
101125 this .periodNs = SECOND_IN_NS ;
@@ -187,7 +211,7 @@ private long computeAccumulatedDebtCarryLimit(long windowDurationNs) {
187211 if (periodNs == 0 || windowDurationNs >= SECOND_IN_NS ) {
188212 return 1 ;
189213 }
190- return SECOND_IN_NS / windowDurationNs ;
214+ return SECOND_IN_NS / windowDurationNs ;
191215 }
192216
193217 private long amortizeDebt (JfrThrottlerWindow lastWindow ) {
@@ -206,33 +230,34 @@ private long amortizeDebt(JfrThrottlerWindow lastWindow) {
206230 /**
207231 * Handles the case where the sampling rate is very low.
208232 */
209- // private void setSamplePointsAndWindowDuration1(){
210- // VMError.guarantee(mutex.isOwner(), "Throttler lock must be acquired in critical section.");
211- // VMError.guarantee(reconfigure, "Should only modify sample size and window duration during reconfigure.");
212- // JfrThrottlerWindow next = getNextWindow();
213- // long samplesPerWindow = eventSampleSize / WINDOW_DIVISOR;
214- // long windowDurationNs = periodNs / WINDOW_DIVISOR;
215- // if (eventSampleSize < 10
216- // || periodNs >= MINUTE_IN_NS && eventSampleSize < TEN_PER_S_IN_MINUTES
217- // || periodNs >= HOUR_IN_NS && eventSampleSize < TEN_PER_S_IN_HOURS
218- // || periodNs >= DAY_IN_NS && eventSampleSize < TEN_PER_S_IN_DAYS){
219- // samplesPerWindow = eventSampleSize;
220- // windowDurationNs = periodNs;
221- // }
222- // activeWindow.samplesPerWindow = samplesPerWindow;
223- // activeWindow.windowDurationNs = windowDurationNs;
224- // next.samplesPerWindow = samplesPerWindow;
225- // next.windowDurationNs = windowDurationNs;
226- // }
227- private void setSamplePointsAndWindowDuration (){
233+ // private void setSamplePointsAndWindowDuration1(){
234+ // VMError.guarantee(mutex.isOwner(), "Throttler lock must be acquired in critical section.");
235+ // VMError.guarantee(reconfigure, "Should only modify sample size and window duration during
236+ // reconfigure.");
237+ // JfrThrottlerWindow next = getNextWindow();
238+ // long samplesPerWindow = eventSampleSize / WINDOW_DIVISOR;
239+ // long windowDurationNs = periodNs / WINDOW_DIVISOR;
240+ // if (eventSampleSize < 10
241+ // || periodNs >= MINUTE_IN_NS && eventSampleSize < TEN_PER_S_IN_MINUTES
242+ // || periodNs >= HOUR_IN_NS && eventSampleSize < TEN_PER_S_IN_HOURS
243+ // || periodNs >= DAY_IN_NS && eventSampleSize < TEN_PER_S_IN_DAYS){
244+ // samplesPerWindow = eventSampleSize;
245+ // windowDurationNs = periodNs;
246+ // }
247+ // activeWindow.samplesPerWindow = samplesPerWindow;
248+ // activeWindow.windowDurationNs = windowDurationNs;
249+ // next.samplesPerWindow = samplesPerWindow;
250+ // next.windowDurationNs = windowDurationNs;
251+ // }
252+ private void setSamplePointsAndWindowDuration () {
228253 VMError .guarantee (mutex .isOwner (), "Throttler lock must be acquired in critical section." );
229254 VMError .guarantee (reconfigure , "Should only modify sample size and window duration during reconfigure." );
230255 JfrThrottlerWindow next = getNextWindow ();
231256 long samplesPerWindow = eventSampleSize / WINDOW_DIVISOR ;
232257 long windowDurationNs = periodNs / WINDOW_DIVISOR ;
233258 // If period isn't 1s, then we're effectively taking under 10 samples/s
234259 // because the values have already undergone normalization.
235- if (eventSampleSize < 10 || periodNs > SECOND_IN_NS ){
260+ if (eventSampleSize < 10 || periodNs > SECOND_IN_NS ) {
236261 samplesPerWindow = eventSampleSize ;
237262 windowDurationNs = periodNs ;
238263 }
@@ -276,38 +301,39 @@ private double projectPopulationSize(long lastWindowMeasuredPop) {
276301 return avgPopulationSize ;
277302 }
278303
279- private static double exponentiallyWeightedMovingAverage (double Y , double alpha , double S ) {
280- return alpha * Y + (1 - alpha ) * S ;
304+ private static double exponentiallyWeightedMovingAverage (double currentMeasurement , double alpha , double prevEwma ) {
305+ return alpha * currentMeasurement + (1 - alpha ) * prevEwma ;
281306 }
282307
283- // /** Basic spin lock */
284- // private void lock() {
285- // while (!tryLock()) {
286- // PauseNode.pause();
287- // }
288- // }
308+ // /** Basic spin lock */
309+ // private void lock() {
310+ // while (!tryLock()) {
311+ // PauseNode.pause();
312+ // }
313+ // }
289314//
290- // private boolean tryLock() {
291- // return lock.compareAndSet(WordFactory.nullPointer(), CurrentIsolate.getCurrentThread());
292- // }
315+ // private boolean tryLock() {
316+ // return lock.compareAndSet(WordFactory.nullPointer(), CurrentIsolate.getCurrentThread());
317+ // }
293318//
294- // private void unlock() {
295- //// VMError.guarantee(lock.get().equal(CurrentIsolate.getCurrentThread()), "Throttler lock must be acquired in critical section.");
296- // lock.set(WordFactory.nullPointer());
297- // }
319+ // private void unlock() {
320+ //// VMError.guarantee(lock.get().equal(CurrentIsolate.getCurrentThread()), "Throttler lock must be
321+ // acquired in critical section.");
322+ // lock.set(WordFactory.nullPointer());
323+ // }
298324
299325 /** Visible for testing. */
300326 public void beginTest (long eventSampleSize , long periodMs ) {
301327 window0 .isTest = true ;
302328 window1 .isTest = true ;
303- window0 .testCurrentNanos = 0 ;
304- window1 .testCurrentNanos = 0 ;
329+ window0 .currentTestNanos = 0 ;
330+ window1 .currentTestNanos = 0 ;
305331 setThrottle (eventSampleSize , periodMs );
306332 }
307333
308334 /** Visible for testing. */
309335 public double getActiveWindowProjectedPopulationSize () {
310- return activeWindow . projectedPopSize ;
336+ return avgPopulationSize ;
311337 }
312338
313339 /** Visible for testing. */
@@ -325,24 +351,27 @@ public double getWindowLookback() {
325351 }
326352
327353 /** Visible for testing. */
328- public boolean IsActiveWindowExpired () {
354+ public boolean isActiveWindowExpired () {
329355 return activeWindow .isExpired ();
330356 }
357+
331358 /** Visible for testing. */
332359 public long getPeriodNs () {
333360 return periodNs ;
334361 }
362+
335363 /** Visible for testing. */
336364 public long getEventSampleSize () {
337365 return eventSampleSize ;
338366 }
367+
339368 /** Visible for testing. */
340369 public void expireActiveWindow () {
341- if (eventSampleSize < 10 || periodNs > SECOND_IN_NS ){
342- window0 .testCurrentNanos += periodNs ;
343- window1 .testCurrentNanos += periodNs ;
370+ if (eventSampleSize < 10 || periodNs > SECOND_IN_NS ) {
371+ window0 .currentTestNanos += periodNs ;
372+ window1 .currentTestNanos += periodNs ;
344373 }
345- window0 .testCurrentNanos += periodNs / WINDOW_DIVISOR ;
346- window1 .testCurrentNanos += periodNs / WINDOW_DIVISOR ;
374+ window0 .currentTestNanos += periodNs / WINDOW_DIVISOR ;
375+ window1 .currentTestNanos += periodNs / WINDOW_DIVISOR ;
347376 }
348377}
0 commit comments