mirror of
https://github.com/openjdk/jdk.git
synced 2026-05-14 15:39:45 +00:00
8358619: Fix interval recomputation in CPU Time Profiler
Reviewed-by: jbachorik, mgronlun
This commit is contained in:
parent
9697e5bf74
commit
c70258ca1c
@ -170,9 +170,15 @@ NO_TRANSITION(jboolean, jfr_set_throttle(JNIEnv* env, jclass jvm, jlong event_ty
|
||||
return JNI_TRUE;
|
||||
NO_TRANSITION_END
|
||||
|
||||
JVM_ENTRY_NO_ENV(void, jfr_set_cpu_throttle(JNIEnv* env, jclass jvm, jdouble rate, jboolean auto_adapt))
|
||||
JVM_ENTRY_NO_ENV(void, jfr_set_cpu_rate(JNIEnv* env, jclass jvm, jdouble rate))
|
||||
JfrEventSetting::set_enabled(JfrCPUTimeSampleEvent, rate > 0);
|
||||
JfrCPUTimeThreadSampling::set_rate(rate, auto_adapt == JNI_TRUE);
|
||||
JfrCPUTimeThreadSampling::set_rate(rate);
|
||||
JVM_END
|
||||
|
||||
JVM_ENTRY_NO_ENV(void, jfr_set_cpu_period(JNIEnv* env, jclass jvm, jlong period_nanos))
|
||||
assert(period_nanos >= 0, "invariant");
|
||||
JfrEventSetting::set_enabled(JfrCPUTimeSampleEvent, period_nanos > 0);
|
||||
JfrCPUTimeThreadSampling::set_period(period_nanos);
|
||||
JVM_END
|
||||
|
||||
NO_TRANSITION(void, jfr_set_miscellaneous(JNIEnv* env, jclass jvm, jlong event_type_id, jlong value))
|
||||
|
||||
@ -129,7 +129,9 @@ jlong JNICALL jfr_get_unloaded_event_classes_count(JNIEnv* env, jclass jvm);
|
||||
|
||||
jboolean JNICALL jfr_set_throttle(JNIEnv* env, jclass jvm, jlong event_type_id, jlong event_sample_size, jlong period_ms);
|
||||
|
||||
void JNICALL jfr_set_cpu_throttle(JNIEnv* env, jclass jvm, jdouble rate, jboolean auto_adapt);
|
||||
void JNICALL jfr_set_cpu_rate(JNIEnv* env, jclass jvm, jdouble rate);
|
||||
|
||||
void JNICALL jfr_set_cpu_period(JNIEnv* env, jclass jvm, jlong period_nanos);
|
||||
|
||||
void JNICALL jfr_set_miscellaneous(JNIEnv* env, jclass jvm, jlong id, jlong value);
|
||||
|
||||
|
||||
@ -83,7 +83,8 @@ JfrJniMethodRegistration::JfrJniMethodRegistration(JNIEnv* env) {
|
||||
(char*)"getUnloadedEventClassCount", (char*)"()J", (void*)jfr_get_unloaded_event_classes_count,
|
||||
(char*)"setMiscellaneous", (char*)"(JJ)V", (void*)jfr_set_miscellaneous,
|
||||
(char*)"setThrottle", (char*)"(JJJ)Z", (void*)jfr_set_throttle,
|
||||
(char*)"setCPUThrottle", (char*)"(DZ)V", (void*)jfr_set_cpu_throttle,
|
||||
(char*)"setCPURate", (char*)"(D)V", (void*)jfr_set_cpu_rate,
|
||||
(char*)"setCPUPeriod", (char*)"(J)V", (void*)jfr_set_cpu_period,
|
||||
(char*)"emitOldObjectSamples", (char*)"(JZZ)V", (void*)jfr_emit_old_object_samples,
|
||||
(char*)"shouldRotateDisk", (char*)"()Z", (void*)jfr_should_rotate_disk,
|
||||
(char*)"exclude", (char*)"(Ljava/lang/Thread;)V", (void*)jfr_exclude_thread,
|
||||
|
||||
@ -45,7 +45,7 @@
|
||||
|
||||
#include "signals_posix.hpp"
|
||||
|
||||
static const int64_t AUTOADAPT_INTERVAL_MS = 100;
|
||||
static const int64_t RECOMPUTE_INTERVAL_MS = 100;
|
||||
|
||||
static bool is_excluded(JavaThread* jt) {
|
||||
return jt->is_hidden_from_external_view() ||
|
||||
@ -163,20 +163,42 @@ void JfrCPUTimeTraceQueue::clear() {
|
||||
Atomic::release_store(&_head, (u4)0);
|
||||
}
|
||||
|
||||
static int64_t compute_sampling_period(double rate) {
|
||||
if (rate == 0) {
|
||||
return 0;
|
||||
// A throttle is either a rate or a fixed period
|
||||
class JfrCPUSamplerThrottle {
|
||||
|
||||
union {
|
||||
double _rate;
|
||||
u8 _period_nanos;
|
||||
};
|
||||
bool _is_rate;
|
||||
|
||||
public:
|
||||
|
||||
JfrCPUSamplerThrottle(double rate) : _rate(rate), _is_rate(true) {
|
||||
assert(rate >= 0, "invariant");
|
||||
}
|
||||
return os::active_processor_count() * 1000000000.0 / rate;
|
||||
}
|
||||
|
||||
JfrCPUSamplerThrottle(u8 period_nanos) : _period_nanos(period_nanos), _is_rate(false) {}
|
||||
|
||||
bool enabled() const { return _is_rate ? _rate > 0 : _period_nanos > 0; }
|
||||
|
||||
int64_t compute_sampling_period() const {
|
||||
if (_is_rate) {
|
||||
if (_rate == 0) {
|
||||
return 0;
|
||||
}
|
||||
return os::active_processor_count() * 1000000000.0 / _rate;
|
||||
}
|
||||
return _period_nanos;
|
||||
}
|
||||
};
|
||||
|
||||
class JfrCPUSamplerThread : public NonJavaThread {
|
||||
friend class JfrCPUTimeThreadSampling;
|
||||
private:
|
||||
Semaphore _sample;
|
||||
NonJavaThread* _sampler_thread;
|
||||
double _rate;
|
||||
bool _auto_adapt;
|
||||
JfrCPUSamplerThrottle _throttle;
|
||||
volatile int64_t _current_sampling_period_ns;
|
||||
volatile bool _disenrolled;
|
||||
// top bit is used to indicate that no signal handler should proceed
|
||||
@ -187,7 +209,7 @@ class JfrCPUSamplerThread : public NonJavaThread {
|
||||
|
||||
static const u4 STOP_SIGNAL_BIT = 0x80000000;
|
||||
|
||||
JfrCPUSamplerThread(double rate, bool auto_adapt);
|
||||
JfrCPUSamplerThread(JfrCPUSamplerThrottle& throttle);
|
||||
|
||||
void start_thread();
|
||||
|
||||
@ -195,9 +217,9 @@ class JfrCPUSamplerThread : public NonJavaThread {
|
||||
void disenroll();
|
||||
void update_all_thread_timers();
|
||||
|
||||
void auto_adapt_period_if_needed();
|
||||
void recompute_period_if_needed();
|
||||
|
||||
void set_rate(double rate, bool auto_adapt);
|
||||
void set_throttle(JfrCPUSamplerThrottle& throttle);
|
||||
int64_t get_sampling_period() const { return Atomic::load(&_current_sampling_period_ns); };
|
||||
|
||||
void sample_thread(JfrSampleRequest& request, void* ucontext, JavaThread* jt, JfrThreadLocal* tl, JfrTicks& now);
|
||||
@ -231,18 +253,16 @@ public:
|
||||
void trigger_async_processing_of_cpu_time_jfr_requests();
|
||||
};
|
||||
|
||||
JfrCPUSamplerThread::JfrCPUSamplerThread(double rate, bool auto_adapt) :
|
||||
JfrCPUSamplerThread::JfrCPUSamplerThread(JfrCPUSamplerThrottle& throttle) :
|
||||
_sample(),
|
||||
_sampler_thread(nullptr),
|
||||
_rate(rate),
|
||||
_auto_adapt(auto_adapt),
|
||||
_current_sampling_period_ns(compute_sampling_period(rate)),
|
||||
_throttle(throttle),
|
||||
_current_sampling_period_ns(throttle.compute_sampling_period()),
|
||||
_disenrolled(true),
|
||||
_active_signal_handlers(STOP_SIGNAL_BIT),
|
||||
_is_async_processing_of_cpu_time_jfr_requests_triggered(false),
|
||||
_warned_about_timer_creation_failure(false),
|
||||
_signal_handler_installed(false) {
|
||||
assert(rate >= 0, "invariant");
|
||||
}
|
||||
|
||||
void JfrCPUSamplerThread::trigger_async_processing_of_cpu_time_jfr_requests() {
|
||||
@ -321,7 +341,7 @@ void JfrCPUSamplerThread::disenroll() {
|
||||
void JfrCPUSamplerThread::run() {
|
||||
assert(_sampler_thread == nullptr, "invariant");
|
||||
_sampler_thread = this;
|
||||
int64_t last_auto_adapt_check = os::javaTimeNanos();
|
||||
int64_t last_recompute_check = os::javaTimeNanos();
|
||||
while (true) {
|
||||
if (!_sample.trywait()) {
|
||||
// disenrolled
|
||||
@ -329,9 +349,9 @@ void JfrCPUSamplerThread::run() {
|
||||
}
|
||||
_sample.signal();
|
||||
|
||||
if (os::javaTimeNanos() - last_auto_adapt_check > AUTOADAPT_INTERVAL_MS * 1000000) {
|
||||
auto_adapt_period_if_needed();
|
||||
last_auto_adapt_check = os::javaTimeNanos();
|
||||
if (os::javaTimeNanos() - last_recompute_check > RECOMPUTE_INTERVAL_MS * 1000000) {
|
||||
recompute_period_if_needed();
|
||||
last_recompute_check = os::javaTimeNanos();
|
||||
}
|
||||
|
||||
if (Atomic::cmpxchg(&_is_async_processing_of_cpu_time_jfr_requests_triggered, true, false)) {
|
||||
@ -442,42 +462,50 @@ JfrCPUTimeThreadSampling::~JfrCPUTimeThreadSampling() {
|
||||
}
|
||||
}
|
||||
|
||||
void JfrCPUTimeThreadSampling::create_sampler(double rate, bool auto_adapt) {
|
||||
void JfrCPUTimeThreadSampling::create_sampler(JfrCPUSamplerThrottle& throttle) {
|
||||
assert(_sampler == nullptr, "invariant");
|
||||
_sampler = new JfrCPUSamplerThread(rate, auto_adapt);
|
||||
_sampler = new JfrCPUSamplerThread(throttle);
|
||||
_sampler->start_thread();
|
||||
_sampler->enroll();
|
||||
}
|
||||
|
||||
void JfrCPUTimeThreadSampling::update_run_state(double rate, bool auto_adapt) {
|
||||
if (rate != 0) {
|
||||
void JfrCPUTimeThreadSampling::update_run_state(JfrCPUSamplerThrottle& throttle) {
|
||||
if (throttle.enabled()) {
|
||||
if (_sampler == nullptr) {
|
||||
create_sampler(rate, auto_adapt);
|
||||
create_sampler(throttle);
|
||||
} else {
|
||||
_sampler->set_rate(rate, auto_adapt);
|
||||
_sampler->set_throttle(throttle);
|
||||
_sampler->enroll();
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (_sampler != nullptr) {
|
||||
_sampler->set_rate(rate /* 0 */, auto_adapt);
|
||||
_sampler->set_throttle(throttle);
|
||||
_sampler->disenroll();
|
||||
}
|
||||
}
|
||||
|
||||
void JfrCPUTimeThreadSampling::set_rate(double rate, bool auto_adapt) {
|
||||
assert(rate >= 0, "invariant");
|
||||
void JfrCPUTimeThreadSampling::set_rate(double rate) {
|
||||
if (_instance == nullptr) {
|
||||
return;
|
||||
}
|
||||
instance().set_rate_value(rate, auto_adapt);
|
||||
JfrCPUSamplerThrottle throttle(rate);
|
||||
instance().set_throttle_value(throttle);
|
||||
}
|
||||
|
||||
void JfrCPUTimeThreadSampling::set_rate_value(double rate, bool auto_adapt) {
|
||||
if (_sampler != nullptr) {
|
||||
_sampler->set_rate(rate, auto_adapt);
|
||||
void JfrCPUTimeThreadSampling::set_period(u8 nanos) {
|
||||
if (_instance == nullptr) {
|
||||
return;
|
||||
}
|
||||
update_run_state(rate, auto_adapt);
|
||||
JfrCPUSamplerThrottle throttle(nanos);
|
||||
instance().set_throttle_value(throttle);
|
||||
}
|
||||
|
||||
void JfrCPUTimeThreadSampling::set_throttle_value(JfrCPUSamplerThrottle& throttle) {
|
||||
if (_sampler != nullptr) {
|
||||
_sampler->set_throttle(throttle);
|
||||
}
|
||||
update_run_state(throttle);
|
||||
}
|
||||
|
||||
void JfrCPUTimeThreadSampling::on_javathread_create(JavaThread *thread) {
|
||||
@ -704,24 +732,21 @@ void JfrCPUSamplerThread::stop_timer() {
|
||||
VMThread::execute(&op);
|
||||
}
|
||||
|
||||
void JfrCPUSamplerThread::auto_adapt_period_if_needed() {
|
||||
void JfrCPUSamplerThread::recompute_period_if_needed() {
|
||||
int64_t current_period = get_sampling_period();
|
||||
if (_auto_adapt || current_period == -1) {
|
||||
int64_t period = compute_sampling_period(_rate);
|
||||
if (period != current_period) {
|
||||
Atomic::store(&_current_sampling_period_ns, period);
|
||||
update_all_thread_timers();
|
||||
}
|
||||
int64_t period = _throttle.compute_sampling_period();
|
||||
if (period != current_period) {
|
||||
Atomic::store(&_current_sampling_period_ns, period);
|
||||
update_all_thread_timers();
|
||||
}
|
||||
}
|
||||
|
||||
void JfrCPUSamplerThread::set_rate(double rate, bool auto_adapt) {
|
||||
_rate = rate;
|
||||
_auto_adapt = auto_adapt;
|
||||
if (_rate > 0 && Atomic::load_acquire(&_disenrolled) == false) {
|
||||
auto_adapt_period_if_needed();
|
||||
void JfrCPUSamplerThread::set_throttle(JfrCPUSamplerThrottle& throttle) {
|
||||
_throttle = throttle;
|
||||
if (_throttle.enabled() && Atomic::load_acquire(&_disenrolled) == false) {
|
||||
recompute_period_if_needed();
|
||||
} else {
|
||||
Atomic::store(&_current_sampling_period_ns, compute_sampling_period(rate));
|
||||
Atomic::store(&_current_sampling_period_ns, _throttle.compute_sampling_period());
|
||||
}
|
||||
}
|
||||
|
||||
@ -765,12 +790,18 @@ void JfrCPUTimeThreadSampling::destroy() {
|
||||
_instance = nullptr;
|
||||
}
|
||||
|
||||
void JfrCPUTimeThreadSampling::set_rate(double rate, bool auto_adapt) {
|
||||
void JfrCPUTimeThreadSampling::set_rate(double rate) {
|
||||
if (rate != 0) {
|
||||
warn();
|
||||
}
|
||||
}
|
||||
|
||||
void JfrCPUTimeThreadSampling::set_period(u8 period_nanos) {
|
||||
if (period_nanos != 0) {
|
||||
warn();
|
||||
}
|
||||
}
|
||||
|
||||
void JfrCPUTimeThreadSampling::on_javathread_create(JavaThread* thread) {
|
||||
}
|
||||
|
||||
|
||||
@ -95,14 +95,16 @@ public:
|
||||
|
||||
class JfrCPUSamplerThread;
|
||||
|
||||
class JfrCPUSamplerThrottle;
|
||||
|
||||
class JfrCPUTimeThreadSampling : public JfrCHeapObj {
|
||||
friend class JfrRecorder;
|
||||
private:
|
||||
|
||||
JfrCPUSamplerThread* _sampler;
|
||||
|
||||
void create_sampler(double rate, bool auto_adapt);
|
||||
void set_rate_value(double rate, bool auto_adapt);
|
||||
void create_sampler(JfrCPUSamplerThrottle& throttle);
|
||||
void set_throttle_value(JfrCPUSamplerThrottle& throttle);
|
||||
|
||||
JfrCPUTimeThreadSampling();
|
||||
~JfrCPUTimeThreadSampling();
|
||||
@ -111,10 +113,13 @@ class JfrCPUTimeThreadSampling : public JfrCHeapObj {
|
||||
static JfrCPUTimeThreadSampling* create();
|
||||
static void destroy();
|
||||
|
||||
void update_run_state(double rate, bool auto_adapt);
|
||||
void update_run_state(JfrCPUSamplerThrottle& throttle);
|
||||
|
||||
static void set_rate(JfrCPUSamplerThrottle& throttle);
|
||||
|
||||
public:
|
||||
static void set_rate(double rate, bool auto_adapt);
|
||||
static void set_rate(double rate);
|
||||
static void set_period(u8 nanos);
|
||||
|
||||
static void on_javathread_create(JavaThread* thread);
|
||||
static void on_javathread_terminate(JavaThread* thread);
|
||||
@ -140,7 +145,8 @@ private:
|
||||
static void destroy();
|
||||
|
||||
public:
|
||||
static void set_rate(double rate, bool auto_adapt);
|
||||
static void set_rate(double rate);
|
||||
static void set_period(u8 nanos);
|
||||
|
||||
static void on_javathread_create(JavaThread* thread);
|
||||
static void on_javathread_terminate(JavaThread* thread);
|
||||
|
||||
@ -273,12 +273,24 @@ public final class JVM {
|
||||
/**
|
||||
* Set the maximum event emission rate for the CPU time sampler
|
||||
*
|
||||
* Use {@link #setCPUPeriod(long)} if you want a fixed sampling period instead.
|
||||
*
|
||||
* Setting rate to 0 turns off the CPU time sampler.
|
||||
*
|
||||
* @param rate the new rate in events per second
|
||||
* @param autoAdapt true if the rate should be adapted automatically
|
||||
*/
|
||||
public static native void setCPUThrottle(double rate, boolean autoAdapt);
|
||||
public static native void setCPURate(double rate);
|
||||
|
||||
/**
|
||||
* Set the fixed CPU time sampler period.
|
||||
*
|
||||
* Use {@link #setCPURate(double)} if you want a fixed rate with an auto-adjusted period instead.
|
||||
*
|
||||
* Setting period to 0 turns off the CPU time sampler.
|
||||
*
|
||||
* @param periodNanos the new fixed period in nanoseconds
|
||||
*/
|
||||
public static native void setCPUPeriod(long periodNanos);
|
||||
|
||||
/**
|
||||
* Sets the file where data should be written.
|
||||
|
||||
@ -204,7 +204,11 @@ public final class PlatformEventType extends Type {
|
||||
if (isCPUTimeMethodSampling) {
|
||||
this.cpuRate = rate;
|
||||
if (isEnabled()) {
|
||||
JVM.setCPUThrottle(rate.rate(), rate.autoAdapt());
|
||||
if (rate.isRate()) {
|
||||
JVM.setCPURate(rate.rate());
|
||||
} else {
|
||||
JVM.setCPUPeriod(rate.periodNanos());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -270,8 +274,12 @@ public final class PlatformEventType extends Type {
|
||||
long p = enabled ? period : 0;
|
||||
JVM.setMethodSamplingPeriod(getId(), p);
|
||||
} else if (isCPUTimeMethodSampling) {
|
||||
TimespanRate r = enabled ? cpuRate : new TimespanRate(0, false);
|
||||
JVM.setCPUThrottle(r.rate(), r.autoAdapt());
|
||||
TimespanRate r = enabled ? cpuRate : TimespanRate.OFF;
|
||||
if (r.isRate()) {
|
||||
JVM.setCPURate(r.rate());
|
||||
} else {
|
||||
JVM.setCPUPeriod(r.periodNanos());
|
||||
}
|
||||
} else {
|
||||
JVM.setEnabled(getId(), enabled);
|
||||
}
|
||||
|
||||
@ -58,18 +58,18 @@ public final class CPUThrottleSetting extends SettingControl {
|
||||
|
||||
@Override
|
||||
public String combine(Set<String> values) {
|
||||
TimespanRate max = null;
|
||||
TimespanRate highestRate = null;
|
||||
for (String value : values) {
|
||||
TimespanRate rate = TimespanRate.of(value);
|
||||
if (rate != null) {
|
||||
if (max == null || rate.isHigher(max)) {
|
||||
max = rate;
|
||||
if (highestRate == null) {
|
||||
highestRate = rate;
|
||||
} else {
|
||||
highestRate = TimespanRate.selectHigherResolution(highestRate, rate);
|
||||
}
|
||||
max = new TimespanRate(max.rate(), max.autoAdapt() || rate.autoAdapt());
|
||||
}
|
||||
}
|
||||
// "off" is not supported
|
||||
return Objects.requireNonNullElse(max.toString(), DEFAULT_VALUE);
|
||||
return Objects.requireNonNullElse(highestRate.toString(), DEFAULT_VALUE);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -30,11 +30,22 @@ import jdk.jfr.internal.settings.CPUThrottleSetting;
|
||||
/**
|
||||
* A rate or fixed period, see {@link jdk.jfr.internal.Rate}
|
||||
*/
|
||||
public record TimespanRate(double rate, boolean autoAdapt) {
|
||||
public record TimespanRate(double rate, long periodNanos, boolean isRate) {
|
||||
|
||||
public static final TimespanRate OFF = new TimespanRate(0, 0, false);
|
||||
|
||||
/**
|
||||
* Parses the rate string. Supports
|
||||
*
|
||||
* <ul>
|
||||
* <li>off</li>
|
||||
* <li>time value like "1ms"</li>
|
||||
* <li>rate value like "10/s"</li>
|
||||
* </ul>
|
||||
*/
|
||||
public static TimespanRate of(String text) {
|
||||
if (text.equals("off")) {
|
||||
text = CPUThrottleSetting.DEFAULT_VALUE;
|
||||
return OFF;
|
||||
}
|
||||
boolean isPeriod = !text.contains("/");
|
||||
if (isPeriod) {
|
||||
@ -43,26 +54,62 @@ public record TimespanRate(double rate, boolean autoAdapt) {
|
||||
return null;
|
||||
}
|
||||
if (period == 0) {
|
||||
return new TimespanRate(0, false);
|
||||
return OFF;
|
||||
}
|
||||
return new TimespanRate(Runtime.getRuntime().availableProcessors() / (period / 1_000_000_000.0), false);
|
||||
return new TimespanRate(0, period, false);
|
||||
}
|
||||
Rate r = Rate.of(text);
|
||||
if (r == null) {
|
||||
return null;
|
||||
}
|
||||
return new TimespanRate(r.perSecond(), true);
|
||||
return new TimespanRate(r.perSecond(), 0, true);
|
||||
}
|
||||
|
||||
public boolean isHigher(TimespanRate that) {
|
||||
return rate() > that.rate();
|
||||
public static TimespanRate selectHigherResolution(TimespanRate a, TimespanRate b) {
|
||||
if (a.isRate && b.isRate) {
|
||||
return a.rate() > b.rate() ? a : b;
|
||||
}
|
||||
if (!a.isRate && !b.isRate) {
|
||||
return a.periodNanos() < b.periodNanos() ? a : b;
|
||||
}
|
||||
if (a.isRate) {
|
||||
double bRate = Runtime.getRuntime().availableProcessors() * (1_000_000_000.0 / b.periodNanos());
|
||||
return new TimespanRate(Math.max(a.rate(), bRate), 0, true);
|
||||
}
|
||||
double aRate = Runtime.getRuntime().availableProcessors() * (1_000_000_000.0 / a.periodNanos());
|
||||
return new TimespanRate(Math.max(aRate, b.rate()), 0, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (autoAdapt) {
|
||||
return String.format("%d/ns", (long)(rate * 1_000_000_000L));
|
||||
if (isRate) {
|
||||
return toRateString();
|
||||
}
|
||||
return String.format("%dns", (long)(Runtime.getRuntime().availableProcessors() / rate * 1_000_000_000L));
|
||||
return toPeriodString();
|
||||
}
|
||||
|
||||
private String toRateString() {
|
||||
// idea: try to use the smallest unit possible where the rate is still an integer
|
||||
// start with seconds, then try minutes, hours, etc.
|
||||
assert isRate;
|
||||
if (rate == 0) {
|
||||
return "0/s";
|
||||
}
|
||||
for (TimespanUnit unit : TimespanUnit.values()) {
|
||||
double value = rate / unit.nanos * 1_000_000_000.0;
|
||||
if (value % 1 == 0) {
|
||||
return String.format("%d/%s", (long)value, unit.text);
|
||||
}
|
||||
}
|
||||
// fallback to days if no smaller unit is found
|
||||
return String.format("%d/%s", (long)(rate / TimespanUnit.DAYS.nanos * 1_000_000_000.0), TimespanUnit.DAYS.text);
|
||||
}
|
||||
|
||||
private String toPeriodString() {
|
||||
assert !isRate;
|
||||
if (periodNanos == 0) {
|
||||
return "0ms";
|
||||
}
|
||||
return String.format("%dns", periodNanos);
|
||||
}
|
||||
}
|
||||
|
||||
@ -38,23 +38,21 @@ import jdk.test.lib.jfr.RecurseThread;
|
||||
*/
|
||||
public class TestCPUTimeAndExecutionSample {
|
||||
|
||||
static String sampleEvent = EventNames.CPUTimeSample;
|
||||
|
||||
// The period is set to 1100 ms to provoke the 1000 ms
|
||||
// threshold in the JVM for os::naked_short_sleep().
|
||||
public static void main(String[] args) throws Exception {
|
||||
run(EventNames.ExecutionSample);
|
||||
run(EventNames.CPUTimeSample);
|
||||
run(EventNames.ExecutionSample);
|
||||
run(EventNames.CPUTimeSample);
|
||||
run(EventNames.CPUTimeSample, "throttle", "1000/s");
|
||||
run(EventNames.ExecutionSample, "period", "1100ms");
|
||||
run(EventNames.CPUTimeSample, "throttle", "1100ms");
|
||||
run(EventNames.ExecutionSample, "period", "1000ms");
|
||||
}
|
||||
|
||||
private static void run(String eventType) {
|
||||
private static void run(String eventType, String attribute, String value) {
|
||||
RecurseThread t = new RecurseThread(50);
|
||||
t.setDaemon(true);
|
||||
try (RecordingStream rs = new RecordingStream()) {
|
||||
rs.enable(sampleEvent).with("throttle", "1000/s");
|
||||
rs.onEvent(sampleEvent, e -> {
|
||||
rs.enable(eventType).with(attribute, value);
|
||||
rs.onEvent(eventType, e -> {
|
||||
t.quit();
|
||||
rs.close();
|
||||
});
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user