Path: blob/master/test/hotspot/gtest/jfr/test_adaptiveSampler.cpp
41144 views
/*1* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.2* Copyright (c) 2020, Datadog, Inc. All rights reserved.3* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.4*5* This code is free software; you can redistribute it and/or modify it6* under the terms of the GNU General Public License version 2 only, as7* published by the Free Software Foundation.8*9* This code is distributed in the hope that it will be useful, but WITHOUT10* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or11* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License12* version 2 for more details (a copy is included in the LICENSE file that13* accompanied this code).14*15* You should have received a copy of the GNU General Public License version16* 2 along with this work; if not, write to the Free Software Foundation,17* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.18*19* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA20* or visit www.oracle.com if you need additional information or have any21* questions.22*23*/2425#include "precompiled.hpp"2627// This test performs mocking of certain JVM functionality. This works by28// including the source file under test inside an anonymous namespace (which29// prevents linking conflicts) with the mocked symbols redefined.3031// The include list should mirror the one found in the included source file -32// with the ones that should pick up the mocks removed. Those should be included33// later after the mocks have been defined.3435#include <cmath>3637#include "jfr/utilities/jfrAllocation.hpp"38#include "jfr/utilities/jfrRandom.inline.hpp"39#include "jfr/utilities/jfrSpinlockHelper.hpp"40#include "jfr/utilities/jfrTime.hpp"41#include "jfr/utilities/jfrTimeConverter.hpp"42#include "jfr/utilities/jfrTryLock.hpp"43#include "logging/log.hpp"44#include "runtime/atomic.hpp"45#include "utilities/globalDefinitions.hpp"4647#include "unittest.hpp"4849// #undef SHARE_JFR_SUPPORT_JFRADAPTIVESAMPLER_HPP5051namespace {52class MockJfrTimeConverter : public ::JfrTimeConverter {53public:54static double nano_to_counter_multiplier(bool is_os_time = false) {55return 1.0;56}57static jlong counter_to_nanos(jlong c, bool is_os_time = false) {58return c;59}60static jlong counter_to_millis(jlong c, bool is_os_time = false) {61return c * NANOS_PER_MILLISEC;62}63static jlong nanos_to_countertime(jlong c, bool as_os_time = false) {64return c;65}66};6768class MockJfrTickValue {69private:70jlong _ticks;71public:72MockJfrTickValue(jlong ticks) : _ticks(ticks) {};73jlong value() {74return _ticks;75}76};77class MockJfrTicks {78public:79static jlong tick;80static MockJfrTickValue now() {81return MockJfrTickValue(tick);82}83};8485jlong MockJfrTicks::tick = 0;8687// Reincluding source files in the anonymous namespace unfortunately seems to88// behave strangely with precompiled headers (only when using gcc though)89#ifndef DONT_USE_PRECOMPILED_HEADER90#define DONT_USE_PRECOMPILED_HEADER91#endif9293#define JfrTicks MockJfrTicks94#define JfrTimeConverter MockJfrTimeConverter9596#include "jfr/support/jfrAdaptiveSampler.hpp"97#include "jfr/support/jfrAdaptiveSampler.cpp"9899#undef JfrTimeConverter100#undef JfrTicks101} // anonymous namespace102103class JfrGTestAdaptiveSampling : public ::testing::Test {104protected:105const int max_population_per_window = 2000;106const int min_population_per_window = 2;107const int window_count = 10000;108const clock_t window_duration_ms = 100;109const size_t expected_sample_points_per_window = 50;110const size_t expected_sample_points = expected_sample_points_per_window * (size_t)window_count;111const size_t window_lookback_count = 50; // 50 windows == 5 seconds (for a window duration of 100 ms)112const double max_sample_bias = 0.11;113114void SetUp() {115// Ensure that tests are separated in time by spreading them by 24hrs apart116MockJfrTicks::tick += (24 * 60 * 60) * NANOSECS_PER_SEC;117}118119void TearDown() {120// nothing121}122123void assertDistributionProperties(int distr_slots, jlong* population, jlong* sample, size_t population_size, size_t sample_size, const char* msg) {124size_t population_sum = 0;125size_t sample_sum = 0;126for (int i = 0; i < distr_slots; i++) {127population_sum += i * population[i];128sample_sum += i * sample[i];129}130131double population_mean = population_sum / (double)population_size;132double sample_mean = sample_sum / (double)sample_size;133134double population_variance = 0;135double sample_variance = 0;136for (int i = 0; i < distr_slots; i++) {137double population_diff = i - population_mean;138population_variance = population[i] * population_diff * population_diff;139140double sample_diff = i - sample_mean;141sample_variance = sample[i] * sample_diff * sample_diff;142}143population_variance = population_variance / (population_size - 1);144sample_variance = sample_variance / (sample_size - 1);145double population_stdev = sqrt(population_variance);146double sample_stdev = sqrt(sample_variance);147148// make sure the standard deviation is ok149EXPECT_NEAR(population_stdev, sample_stdev, 0.5) << msg;150// make sure that the subsampled set mean is within 2-sigma of the original set mean151EXPECT_NEAR(population_mean, sample_mean, population_stdev) << msg;152// make sure that the original set mean is within 2-sigma of the subsampled set mean153EXPECT_NEAR(sample_mean, population_mean, sample_stdev) << msg;154}155156typedef size_t(JfrGTestAdaptiveSampling::* incoming)() const;157void test(incoming inc, size_t events_per_window, double expectation, const char* description);158159public:160size_t incoming_uniform() const {161return os::random() % max_population_per_window + min_population_per_window;162}163164size_t incoming_bursty_10_percent() const {165bool is_burst = (os::random() % 100) < 10; // 10% burst chance166return is_burst ? max_population_per_window : min_population_per_window;167}168169size_t incoming_bursty_90_percent() const {170bool is_burst = (os::random() % 100) < 90; // 90% burst chance171return is_burst ? max_population_per_window : min_population_per_window;172}173174size_t incoming_low_rate() const {175return min_population_per_window;176}177178size_t incoming_high_rate() const {179return max_population_per_window;180}181182size_t incoming_burst_eval(size_t& count, size_t mod_value) const {183return count++ % 10 == mod_value ? max_population_per_window : 0;184}185186size_t incoming_early_burst() const {187static size_t count = 1;188return incoming_burst_eval(count, 1);189}190191size_t incoming_mid_burst() const {192static size_t count = 1;193return incoming_burst_eval(count, 5);194}195196size_t incoming_late_burst() const {197static size_t count = 1;198return incoming_burst_eval(count, 0);199}200};201202void JfrGTestAdaptiveSampling::test(JfrGTestAdaptiveSampling::incoming inc, size_t sample_points_per_window, double error_factor, const char* const description) {203assert(description != NULL, "invariant");204char output[1024] = "Adaptive sampling: ";205strcat(output, description);206fprintf(stdout, "=== %s\n", output);207jlong population[100] = { 0 };208jlong sample[100] = { 0 };209::JfrGTestFixedRateSampler sampler = ::JfrGTestFixedRateSampler(expected_sample_points_per_window, window_duration_ms, window_lookback_count);210EXPECT_TRUE(sampler.initialize());211212size_t population_size = 0;213size_t sample_size = 0;214for (int t = 0; t < window_count; t++) {215const size_t incoming_events = (this->*inc)();216for (size_t i = 0; i < incoming_events; i++) {217++population_size;218size_t index = os::random() % 100;219population[index] += 1;220if (sampler.sample()) {221++sample_size;222sample[index] += 1;223}224}225MockJfrTicks::tick += window_duration_ms * NANOSECS_PER_MILLISEC + 1;226sampler.sample(); // window rotation227}228229const size_t target_sample_size = sample_points_per_window * window_count;230EXPECT_NEAR(target_sample_size, sample_size, expected_sample_points * error_factor) << output;231strcat(output, ", hit distribution");232assertDistributionProperties(100, population, sample, population_size, sample_size, output);233}234235TEST_VM_F(JfrGTestAdaptiveSampling, DISABLED_uniform_rate) {236test(&JfrGTestAdaptiveSampling::incoming_uniform, expected_sample_points_per_window, 0.05, "random uniform, all samples");237}238239TEST_VM_F(JfrGTestAdaptiveSampling, DISABLED_low_rate) {240test(&JfrGTestAdaptiveSampling::incoming_low_rate, min_population_per_window, 0.05, "low rate");241}242243TEST_VM_F(JfrGTestAdaptiveSampling, DISABLED_high_rate) {244test(&JfrGTestAdaptiveSampling::incoming_high_rate, expected_sample_points_per_window, 0.02, "high rate");245}246247// We can think of the windows as splitting up a time period, for example a second (window_duration_ms = 100)248// The burst tests for early, mid and late apply a burst rate at a selected window, with other windows having no incoming input.249//250// - early during the first window of a new time period251// - mid during the middle window of a new time period252// - late during the last window of a new time period253//254// The tests verify the total sample size correspond to the selected bursts:255//256// - early start of a second -> each second will have sampled the window set point for a single window only since no debt has accumulated into the new time period.257// - mid middle of the second -> each second will have sampled the window set point + accumulated debt for the first 4 windows.258// - late end of the second -> each second will have sampled the window set point + accumulated debt for the first 9 windows (i.e. it will have sampled all)259//260261TEST_VM_F(JfrGTestAdaptiveSampling, DISABLED_early_burst) {262test(&JfrGTestAdaptiveSampling::incoming_early_burst, expected_sample_points_per_window, 0.9, "early burst");263}264265TEST_VM_F(JfrGTestAdaptiveSampling, DISABLED_mid_burst) {266test(&JfrGTestAdaptiveSampling::incoming_mid_burst, expected_sample_points_per_window, 0.5, "mid burst");267}268269TEST_VM_F(JfrGTestAdaptiveSampling, DISABLED_late_burst) {270test(&JfrGTestAdaptiveSampling::incoming_late_burst, expected_sample_points_per_window, 0.0, "late burst");271}272273// These are randomized burst tests274TEST_VM_F(JfrGTestAdaptiveSampling, DISABLED_bursty_rate_10_percent) {275test(&JfrGTestAdaptiveSampling::incoming_bursty_10_percent, expected_sample_points_per_window, 0.96, "bursty 10%");276}277278TEST_VM_F(JfrGTestAdaptiveSampling, DISABLED_bursty_rate_90_percent) {279test(&JfrGTestAdaptiveSampling::incoming_bursty_10_percent, expected_sample_points_per_window, 0.96, "bursty 90%");280}281282283