Path: blob/master/test/hotspot/jtreg/serviceability/jvmti/HeapMonitor/libHeapMonitorTest.cpp
41153 views
/*1* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.2* Copyright (c) 2018, Google and/or its affiliates. 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*/2324#include <assert.h>25#include <stdio.h>26#include <stdlib.h>27#include <string.h>28#include "jvmti.h"2930extern "C" {3132#define TRUE 133#define FALSE 034#define PRINT_OUT 03536static jvmtiEnv *jvmti = NULL;37static jvmtiEnv *second_jvmti = NULL;3839typedef struct _ObjectTrace{40jweak object;41jlong size;42jvmtiFrameInfo* frames;43size_t frame_count;44jthread thread;45} ObjectTrace;4647typedef struct _EventStorage {48int live_object_additions;49int live_object_size;50int live_object_count;51ObjectTrace** live_objects;5253int garbage_history_size;54int garbage_history_index;55ObjectTrace** garbage_collected_objects;5657// Two separate monitors to separate storage data race and the compaction field58// data race.59jrawMonitorID storage_monitor;6061int compaction_required;62jrawMonitorID compaction_monitor;63} EventStorage;6465typedef struct _ExpectedContentFrame {66const char *name;67const char *signature;68const char *file_name;69int line_number;70} ExpectedContentFrame;7172static73void event_storage_lock(EventStorage* storage) {74jvmti->RawMonitorEnter(storage->storage_monitor);75}7677static78void event_storage_unlock(EventStorage* storage) {79jvmti->RawMonitorExit(storage->storage_monitor);80}8182static83void event_storage_lock_compaction(EventStorage* storage) {84jvmti->RawMonitorEnter(storage->compaction_monitor);85}8687static88void event_storage_unlock_compaction(EventStorage* storage) {89jvmti->RawMonitorExit(storage->compaction_monitor);90}9192// Given a method and a location, this method gets the line number.93static94jint get_line_number(jmethodID method, jlocation location) {95// Read the line number table.96jvmtiLineNumberEntry *table_ptr = 0;97jint line_number_table_entries;98int l;99jlocation last_location;100int jvmti_error = jvmti->GetLineNumberTable(method,101&line_number_table_entries,102&table_ptr);103104if (JVMTI_ERROR_NONE != jvmti_error) {105return -1;106}107if (line_number_table_entries <= 0) {108return -1;109}110if (line_number_table_entries == 1) {111return table_ptr[0].line_number;112}113114// Go through all the line numbers...115last_location = table_ptr[0].start_location;116for (l = 1; l < line_number_table_entries; l++) {117// ... and if you see one that is in the right place for your118// location, you've found the line number!119if ((location < table_ptr[l].start_location) &&120(location >= last_location)) {121return table_ptr[l - 1].line_number;122}123last_location = table_ptr[l].start_location;124}125126if (location >= last_location) {127return table_ptr[line_number_table_entries - 1].line_number;128} else {129return -1;130}131}132133static void print_out_frames(JNIEnv* env, ObjectTrace* trace) {134jvmtiFrameInfo* frames = trace->frames;135size_t i;136for (i = 0; i < trace->frame_count; i++) {137// Get basic information out of the trace.138jlocation bci = frames[i].location;139jmethodID methodid = frames[i].method;140char *name = NULL, *signature = NULL, *file_name = NULL;141jclass declaring_class;142int line_number;143jvmtiError err;144145if (bci < 0) {146fprintf(stderr, "\tNative frame\n");147continue;148}149150// Transform into usable information.151line_number = get_line_number(methodid, bci);152if (JVMTI_ERROR_NONE != jvmti->GetMethodName(methodid, &name, &signature, 0)) {153fprintf(stderr, "\tUnknown method name\n");154continue;155}156157if (JVMTI_ERROR_NONE != jvmti->GetMethodDeclaringClass(methodid, &declaring_class)) {158fprintf(stderr, "\tUnknown class\n");159continue;160}161162err = jvmti->GetSourceFileName(declaring_class, &file_name);163if (err != JVMTI_ERROR_NONE) {164fprintf(stderr, "\tUnknown file\n");165continue;166}167168// Compare now, none should be NULL.169if (name == NULL) {170fprintf(stderr, "\tUnknown name\n");171continue;172}173174if (file_name == NULL) {175fprintf(stderr, "\tUnknown file\n");176continue;177}178179if (signature == NULL) {180fprintf(stderr, "\tUnknown signature\n");181continue;182}183184fprintf(stderr, "\t%s%s (%s: %d)\n", name, signature, file_name, line_number);185}186}187188static jboolean check_sample_content(JNIEnv* env,189ObjectTrace* trace,190ExpectedContentFrame *expected,191size_t expected_count,192jboolean check_lines,193int print_out_comparisons) {194jvmtiFrameInfo* frames;195size_t i;196197if (expected_count > trace->frame_count) {198return FALSE;199}200201frames = trace->frames;202for (i = 0; i < expected_count; i++) {203// Get basic information out of the trace.204jlocation bci = frames[i].location;205jmethodID methodid = frames[i].method;206char *name = NULL, *signature = NULL, *file_name = NULL;207jclass declaring_class;208int line_number;209jboolean differ;210jvmtiError err;211212if (bci < 0 && expected[i].line_number != -1) {213return FALSE;214}215216// Transform into usable information.217line_number = get_line_number(methodid, bci);218jvmti->GetMethodName(methodid, &name, &signature, 0);219220if (JVMTI_ERROR_NONE != jvmti->GetMethodDeclaringClass(methodid, &declaring_class)) {221return FALSE;222}223224err = jvmti->GetSourceFileName(declaring_class, &file_name);225if (err != JVMTI_ERROR_NONE) {226return FALSE;227}228229// Compare now, none should be NULL.230if (name == NULL) {231return FALSE;232}233234if (file_name == NULL) {235return FALSE;236}237238if (signature == NULL) {239return FALSE;240}241242differ = (strcmp(name, expected[i].name) ||243strcmp(signature, expected[i].signature) ||244strcmp(file_name, expected[i].file_name) ||245(check_lines && line_number != expected[i].line_number));246247if (print_out_comparisons) {248fprintf(stderr, "\tComparing: (check_lines: %d)\n", check_lines);249fprintf(stderr, "\t\tNames: %s and %s\n", name, expected[i].name);250fprintf(stderr, "\t\tSignatures: %s and %s\n", signature, expected[i].signature);251fprintf(stderr, "\t\tFile name: %s and %s\n", file_name, expected[i].file_name);252fprintf(stderr, "\t\tLines: %d and %d\n", line_number, expected[i].line_number);253fprintf(stderr, "\t\tResult is %d\n", differ);254}255256if (differ) {257return FALSE;258}259}260261return TRUE;262}263264// Static native API for various tests.265static int fill_native_frames(JNIEnv* env, jobjectArray frames,266ExpectedContentFrame* native_frames, size_t size) {267size_t i;268for (i = 0; i < size; i++) {269jclass frame_class = NULL;270jfieldID line_number_field_id = 0;271int line_number = 0;272jfieldID string_id = 0;273jstring string_object = NULL;274const char* method = NULL;275const char* file_name = NULL;276const char* signature = NULL;277278jobject obj = env->GetObjectArrayElement(frames, (jsize) i);279280if (env->ExceptionOccurred()) {281fprintf(stderr, "fill_native_frames: Exception in jni GetObjectArrayElement\n");282return -1;283}284285frame_class = env->GetObjectClass(obj);286287if (env->ExceptionOccurred()) {288fprintf(stderr, "fill_native_frames: Exception in jni GetObjectClass\n");289return -1;290}291292line_number_field_id = env->GetFieldID(frame_class, "lineNumber", "I");293294if (env->ExceptionOccurred()) {295fprintf(stderr, "fill_native_frames: Exception in jni GetFieldID\n");296return -1;297}298299line_number = env->GetIntField(obj, line_number_field_id);300301if (env->ExceptionOccurred()) {302fprintf(stderr, "fill_native_frames: Exception in jni GetIntField\n");303return -1;304}305306string_id = env->GetFieldID(frame_class, "method", "Ljava/lang/String;");307308if (env->ExceptionOccurred()) {309fprintf(stderr, "fill_native_frames: Exception in jni GetFieldID\n");310return -1;311}312313string_object = (jstring) env->GetObjectField(obj, string_id);314315if (env->ExceptionOccurred()) {316fprintf(stderr, "fill_native_frames: Exception in jni GetObjectField\n");317return -1;318}319320method = env->GetStringUTFChars(string_object, 0);321322if (env->ExceptionOccurred()) {323fprintf(stderr, "Exception in jni GetStringUTFChars\n");324return -1;325}326327string_id = env->GetFieldID(frame_class, "fileName", "Ljava/lang/String;");328329if (env->ExceptionOccurred()) {330fprintf(stderr, "Exception in jni GetFieldID\n");331return -1;332}333334string_object = (jstring) (env->GetObjectField(obj, string_id));335336if (env->ExceptionOccurred()) {337fprintf(stderr, "fill_native_frames: Exception in second jni GetObjectField\n");338return -1;339}340341file_name = env->GetStringUTFChars(string_object, 0);342343if (env->ExceptionOccurred()) {344fprintf(stderr, "fill_native_frames: Exception in jni GetStringUTFChars\n");345return -1;346}347348string_id = env->GetFieldID(frame_class, "signature", "Ljava/lang/String;");349350if (env->ExceptionOccurred()) {351fprintf(stderr, "fill_native_frames: Exception in second jni GetFieldID\n");352return -1;353}354355string_object = (jstring) (env->GetObjectField(obj, string_id));356357if (env->ExceptionOccurred()) {358fprintf(stderr, "fill_native_frames: Exception in third jni GetObjectField\n");359return -1;360}361362signature = env->GetStringUTFChars(string_object, 0);363364if (env->ExceptionOccurred()) {365fprintf(stderr, "fill_native_frames: Exception in jni GetStringUTFChars\n");366return -1;367}368369native_frames[i].name = method;370native_frames[i].file_name = file_name;371native_frames[i].signature = signature;372native_frames[i].line_number = line_number;373}374375return 0;376}377378// Internal storage system implementation.379static EventStorage global_event_storage;380static EventStorage second_global_event_storage;381382static void event_storage_set_compaction_required(EventStorage* storage) {383event_storage_lock_compaction(storage);384storage->compaction_required = 1;385event_storage_unlock_compaction(storage);386}387388static int event_storage_get_compaction_required(EventStorage* storage) {389int result;390event_storage_lock_compaction(storage);391result = storage->compaction_required;392event_storage_unlock_compaction(storage);393return result;394}395396static void event_storage_set_garbage_history(EventStorage* storage, int value) {397size_t size;398event_storage_lock(storage);399global_event_storage.garbage_history_size = value;400free(global_event_storage.garbage_collected_objects);401size = sizeof(*global_event_storage.garbage_collected_objects) * value;402global_event_storage.garbage_collected_objects = reinterpret_cast<ObjectTrace**>(malloc(size));403memset(global_event_storage.garbage_collected_objects, 0, size);404event_storage_unlock(storage);405}406407// No mutex here, it is handled by the caller.408static void event_storage_add_garbage_collected_object(EventStorage* storage,409ObjectTrace* object) {410int idx = storage->garbage_history_index;411ObjectTrace* old_object = storage->garbage_collected_objects[idx];412if (old_object != NULL) {413free(old_object->frames);414free(storage->garbage_collected_objects[idx]);415}416417storage->garbage_collected_objects[idx] = object;418storage->garbage_history_index = (idx + 1) % storage->garbage_history_size;419}420421static int event_storage_get_count(EventStorage* storage) {422int result;423event_storage_lock(storage);424result = storage->live_object_count;425event_storage_unlock(storage);426return result;427}428429static double event_storage_get_average_size(EventStorage* storage) {430double accumulation = 0;431int max_size;432int i;433434event_storage_lock(storage);435max_size = storage->live_object_count;436437for (i = 0; i < max_size; i++) {438accumulation += storage->live_objects[i]->size;439}440441event_storage_unlock(storage);442return accumulation / max_size;443}444445static jboolean event_storage_contains(JNIEnv* env,446EventStorage* storage,447ExpectedContentFrame* frames,448size_t size,449jboolean check_lines) {450int i;451event_storage_lock(storage);452fprintf(stderr, "Checking storage count %d\n", storage->live_object_count);453for (i = 0; i < storage->live_object_count; i++) {454ObjectTrace* trace = storage->live_objects[i];455456if (check_sample_content(env, trace, frames, size, check_lines, PRINT_OUT)) {457event_storage_unlock(storage);458return TRUE;459}460}461event_storage_unlock(storage);462return FALSE;463}464465static jlong event_storage_get_size(JNIEnv* env,466EventStorage* storage,467ExpectedContentFrame* frames,468size_t size,469jboolean check_lines) {470int i;471event_storage_lock(storage);472fprintf(stderr, "Getting element from storage count, size %d\n", storage->live_object_count);473for (i = 0; i < storage->live_object_count; i++) {474ObjectTrace* trace = storage->live_objects[i];475476if (check_sample_content(env, trace, frames, size, check_lines, PRINT_OUT)) {477jlong result = trace->size;478event_storage_unlock(storage);479return result;480}481}482event_storage_unlock(storage);483return 0;484}485486static jboolean event_storage_garbage_contains(JNIEnv* env,487EventStorage* storage,488ExpectedContentFrame* frames,489size_t size,490jboolean check_lines) {491int i;492event_storage_lock(storage);493fprintf(stderr, "Checking garbage storage count %d\n",494storage->garbage_history_size);495for (i = 0; i < storage->garbage_history_size; i++) {496ObjectTrace* trace = storage->garbage_collected_objects[i];497498if (trace == NULL) {499continue;500}501502if (check_sample_content(env, trace, frames, size, check_lines, PRINT_OUT)) {503event_storage_unlock(storage);504return TRUE;505}506}507event_storage_unlock(storage);508return FALSE;509}510511// No mutex here, handled by the caller.512static void event_storage_augment_storage(EventStorage* storage) {513int new_max = (storage->live_object_size * 2) + 1;514ObjectTrace** new_objects = reinterpret_cast<ObjectTrace**>(malloc(new_max * sizeof(*new_objects)));515516int current_count = storage->live_object_count;517memcpy(new_objects, storage->live_objects, current_count * sizeof(*new_objects));518free(storage->live_objects);519storage->live_objects = new_objects;520storage->live_object_size = new_max;521}522523static void event_storage_add(EventStorage* storage,524JNIEnv* jni,525jthread thread,526jobject object,527jclass klass,528jlong size) {529jvmtiFrameInfo frames[64];530jint count;531jvmtiError err;532533err = jvmti->GetStackTrace(thread, 0, 64, frames, &count);534if (err == JVMTI_ERROR_NONE && count >= 1) {535ObjectTrace* live_object;536jvmtiFrameInfo* allocated_frames = (jvmtiFrameInfo*) malloc(count * sizeof(*allocated_frames));537memcpy(allocated_frames, frames, count * sizeof(*allocated_frames));538539live_object = (ObjectTrace*) malloc(sizeof(*live_object));540live_object->frames = allocated_frames;541live_object->frame_count = count;542live_object->size = size;543live_object->thread = thread;544live_object->object = jni->NewWeakGlobalRef(object);545546if (jni->ExceptionOccurred()) {547jni->FatalError("Error in event_storage_add: Exception in jni NewWeakGlobalRef");548}549550// Only now lock and get things done quickly.551event_storage_lock(storage);552553storage->live_object_additions++;554555if (storage->live_object_count >= storage->live_object_size) {556event_storage_augment_storage(storage);557}558assert(storage->live_object_count < storage->live_object_size);559560if (PRINT_OUT) {561fprintf(stderr, "Adding trace for thread %p, frame_count %d, storage %p\n",562thread, count, storage);563print_out_frames(jni, live_object);564}565storage->live_objects[storage->live_object_count] = live_object;566storage->live_object_count++;567568event_storage_unlock(storage);569}570}571572static void event_storage_compact(EventStorage* storage, JNIEnv* jni) {573int max, i, dest;574ObjectTrace** live_objects;575576event_storage_lock_compaction(storage);577storage->compaction_required = 0;578event_storage_unlock_compaction(storage);579580event_storage_lock(storage);581582max = storage->live_object_count;583live_objects = storage->live_objects;584585for (i = 0, dest = 0; i < max; i++) {586ObjectTrace* live_object = live_objects[i];587jweak object = live_object->object;588589if (!jni->IsSameObject(object, NULL)) {590if (dest != i) {591live_objects[dest] = live_object;592dest++;593}594} else {595jni->DeleteWeakGlobalRef(object);596live_object->object = NULL;597598event_storage_add_garbage_collected_object(storage, live_object);599}600}601602storage->live_object_count = dest;603event_storage_unlock(storage);604}605606static void event_storage_free_objects(ObjectTrace** array, int max) {607int i;608for (i = 0; i < max; i++) {609free(array[i]), array[i] = NULL;610}611}612613static void event_storage_reset(EventStorage* storage) {614event_storage_lock(storage);615616// Reset everything except the mutex and the garbage collection.617event_storage_free_objects(storage->live_objects,618storage->live_object_count);619storage->live_object_additions = 0;620storage->live_object_size = 0;621storage->live_object_count = 0;622free(storage->live_objects), storage->live_objects = NULL;623624event_storage_free_objects(storage->garbage_collected_objects,625storage->garbage_history_size);626627storage->compaction_required = 0;628storage->garbage_history_index = 0;629630event_storage_unlock(storage);631}632633static int event_storage_number_additions(EventStorage* storage) {634int result;635event_storage_lock(storage);636result = storage->live_object_additions;637event_storage_unlock(storage);638return result;639}640641// Start of the JVMTI agent code.642static const char *EXC_CNAME = "java/lang/Exception";643644static int check_error(jvmtiError err, const char *s) {645if (err != JVMTI_ERROR_NONE) {646printf(" ## %s error: %d\n", s, err);647return 1;648}649return 0;650}651652static int check_capability_error(jvmtiError err, const char *s) {653if (err != JVMTI_ERROR_NONE) {654if (err == JVMTI_ERROR_MUST_POSSESS_CAPABILITY) {655return 0;656}657fprintf(stderr, " ## %s error: %d\n", s, err);658}659return 1;660}661662static jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved);663664JNIEXPORT665jint JNICALL Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) {666return Agent_Initialize(jvm, options, reserved);667}668669JNIEXPORT670jint JNICALL Agent_OnAttach(JavaVM *jvm, char *options, void *reserved) {671return Agent_Initialize(jvm, options, reserved);672}673674JNIEXPORT675jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) {676return JNI_VERSION_1_8;677}678679#define MAX_THREADS 500680681typedef struct ThreadStats {682int thread_count;683int counts[MAX_THREADS];684char* threads[MAX_THREADS];685} ThreadStats;686687static ThreadStats thread_stats;688689JNIEXPORT jboolean JNICALL690Java_MyPackage_HeapMonitorThreadDisabledTest_checkThreadSamplesOnlyFrom(691JNIEnv* env, jclass cls, jthread thread) {692jvmtiThreadInfo info;693jvmtiError err;694char* expected_name;695int found_thread = FALSE;696697err = jvmti->GetThreadInfo(thread, &info);698expected_name = info.name;699700if (err != JVMTI_ERROR_NONE) {701fprintf(stderr, "Failed to get thread information\n");702return FALSE;703}704705if (thread_stats.thread_count != 1) {706fprintf(stderr, "Wrong thread number: %d (expected 1)\n",707thread_stats.thread_count);708return FALSE;709}710711if (strcmp(expected_name, thread_stats.threads[0]) != 0) {712fprintf(stderr, "Unexpected thread name: '%s' (expected '%s')\n",713thread_stats.threads[0], expected_name);714return FALSE;715}716717return TRUE;718}719720static void add_thread_count(jthread thread) {721int i;722jvmtiThreadInfo info;723jvmtiError err;724725err = jvmti->GetThreadInfo(thread, &info);726if (err != JVMTI_ERROR_NONE) {727fprintf(stderr, "Thread info for %p failed, ignoring thread count\n",728thread);729return;730}731732event_storage_lock(&global_event_storage);733for (i = 0; i < thread_stats.thread_count; i++) {734if (!strcmp(thread_stats.threads[i], info.name)) {735thread_stats.counts[i]++;736event_storage_unlock(&global_event_storage);737return;738}739}740741thread_stats.threads[thread_stats.thread_count] = info.name;742thread_stats.counts[thread_stats.thread_count]++;743thread_stats.thread_count++;744event_storage_unlock(&global_event_storage);745}746747JNIEXPORT void JNICALL748Java_MyPackage_HeapMonitorThreadDisabledTest_enableSamplingEvents(749JNIEnv* env, jclass cls, jthread thread) {750fprintf(stderr, "Enabling for %p\n", thread);751check_error(jvmti->SetEventNotificationMode(752JVMTI_ENABLE, JVMTI_EVENT_SAMPLED_OBJECT_ALLOC, thread),753"Set event notifications for a single thread");754}755756static void print_thread_stats() {757int i;758event_storage_lock(&global_event_storage);759fprintf(stderr, "Thread count:\n");760for (i = 0; i < thread_stats.thread_count; i++) {761fprintf(stderr, "\t%s: %d\n", thread_stats.threads[i], thread_stats.counts[i]);762}763event_storage_unlock(&global_event_storage);764}765766JNIEXPORT767void JNICALL SampledObjectAlloc(jvmtiEnv *jvmti_env,768JNIEnv* jni_env,769jthread thread,770jobject object,771jclass object_klass,772jlong size) {773add_thread_count(thread);774775if (event_storage_get_compaction_required(&global_event_storage)) {776event_storage_compact(&global_event_storage, jni_env);777}778779event_storage_add(&global_event_storage, jni_env, thread, object,780object_klass, size);781}782783JNIEXPORT784void JNICALL VMObjectAlloc(jvmtiEnv *jvmti_env,785JNIEnv* jni_env,786jthread thread,787jobject object,788jclass object_klass,789jlong size) {790event_storage_add(&second_global_event_storage, jni_env, thread, object,791object_klass, size);792}793794JNIEXPORT795void JNICALL GarbageCollectionFinish(jvmtiEnv *jvmti_env) {796event_storage_set_compaction_required(&global_event_storage);797}798799static int enable_notifications() {800if (check_error(jvmti->SetEventNotificationMode(801JVMTI_ENABLE, JVMTI_EVENT_GARBAGE_COLLECTION_FINISH, NULL),802"Set event notifications")) {803return 1;804}805806return check_error(jvmti->SetEventNotificationMode(807JVMTI_ENABLE, JVMTI_EVENT_SAMPLED_OBJECT_ALLOC, NULL),808"Set event notifications");809}810811static812jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) {813jint res;814jvmtiEventCallbacks callbacks;815jvmtiCapabilities caps;816817res = jvm->GetEnv((void **) &jvmti, JVMTI_VERSION);818if (res != JNI_OK || jvmti == NULL) {819fprintf(stderr, "Error: wrong result of a valid call to GetEnv!\n");820return JNI_ERR;821}822823// Get second jvmti environment.824res = jvm->GetEnv((void **) &second_jvmti, JVMTI_VERSION);825if (res != JNI_OK || second_jvmti == NULL) {826fprintf(stderr, "Error: wrong result of a valid second call to GetEnv!\n");827return JNI_ERR;828}829830if (PRINT_OUT) {831fprintf(stderr, "Storage is at %p, secondary is at %p\n",832&global_event_storage, &second_global_event_storage);833}834835jvmti->CreateRawMonitor("storage_monitor",836&global_event_storage.storage_monitor);837jvmti->CreateRawMonitor("second_storage_monitor",838&second_global_event_storage.storage_monitor);839840jvmti->CreateRawMonitor("compaction_monitor",841&global_event_storage.compaction_monitor);842jvmti->CreateRawMonitor("second_compaction_monitor",843&second_global_event_storage.compaction_monitor);844845event_storage_set_garbage_history(&global_event_storage, 200);846event_storage_set_garbage_history(&second_global_event_storage, 200);847848memset(&callbacks, 0, sizeof(callbacks));849callbacks.SampledObjectAlloc = &SampledObjectAlloc;850callbacks.VMObjectAlloc = &VMObjectAlloc;851callbacks.GarbageCollectionFinish = &GarbageCollectionFinish;852853memset(&caps, 0, sizeof(caps));854// Get line numbers, sample events, filename, and gc events for the tests.855caps.can_get_line_numbers = 1;856caps.can_get_source_file_name = 1;857caps.can_generate_garbage_collection_events = 1;858caps.can_generate_sampled_object_alloc_events = 1;859caps.can_generate_vm_object_alloc_events = 1;860if (check_error(jvmti->AddCapabilities(&caps), "Add capabilities")) {861return JNI_ERR;862}863864if (check_error(jvmti->SetEventCallbacks(&callbacks,865sizeof(jvmtiEventCallbacks)),866" Set Event Callbacks")) {867return JNI_ERR;868}869return JNI_OK;870}871872JNIEXPORT void JNICALL873Java_MyPackage_HeapMonitor_setSamplingInterval(JNIEnv* env, jclass cls, jint value) {874jvmti->SetHeapSamplingInterval(value);875}876877JNIEXPORT jboolean JNICALL878Java_MyPackage_HeapMonitor_eventStorageIsEmpty(JNIEnv* env, jclass cls) {879return event_storage_get_count(&global_event_storage) == 0;880}881882JNIEXPORT jint JNICALL883Java_MyPackage_HeapMonitor_getEventStorageElementCount(JNIEnv* env, jclass cls) {884return event_storage_get_count(&global_event_storage);885}886887JNIEXPORT void JNICALL888Java_MyPackage_HeapMonitor_enableSamplingEvents(JNIEnv* env, jclass cls) {889enable_notifications();890}891892JNIEXPORT void JNICALL893Java_MyPackage_HeapMonitor_disableSamplingEvents(JNIEnv* env, jclass cls) {894check_error(jvmti->SetEventNotificationMode(895JVMTI_DISABLE, JVMTI_EVENT_SAMPLED_OBJECT_ALLOC, NULL),896"Set event notifications");897898check_error(jvmti->SetEventNotificationMode(899JVMTI_DISABLE, JVMTI_EVENT_GARBAGE_COLLECTION_FINISH, NULL),900"Garbage Collection Finish");901}902903static ExpectedContentFrame *get_native_frames(JNIEnv* env, jclass cls,904jobjectArray frames) {905ExpectedContentFrame *native_frames;906jsize size = env->GetArrayLength(frames);907908if (env->ExceptionOccurred()) {909env->FatalError("get_native_frames failed with the GetArrayLength call");910}911912native_frames = reinterpret_cast<ExpectedContentFrame*> (malloc(size * sizeof(*native_frames)));913914if (native_frames == NULL) {915env->FatalError("Error in get_native_frames: malloc returned NULL\n");916}917918if (fill_native_frames(env, frames, native_frames, size) != 0) {919env->FatalError("Error in get_native_frames: fill_native_frames returned failed status\n");920}921922return native_frames;923}924925JNIEXPORT jboolean JNICALL926Java_MyPackage_HeapMonitor_obtainedEvents(JNIEnv* env, jclass cls,927jobjectArray frames,928jboolean check_lines) {929jboolean result;930jsize size = env->GetArrayLength(frames);931ExpectedContentFrame *native_frames = get_native_frames(env, cls, frames);932933result = event_storage_contains(env, &global_event_storage, native_frames,934size, check_lines);935936free(native_frames), native_frames = NULL;937return result;938}939940JNIEXPORT jboolean JNICALL941Java_MyPackage_HeapMonitor_garbageContains(JNIEnv* env, jclass cls,942jobjectArray frames,943jboolean check_lines) {944jboolean result;945jsize size = env->GetArrayLength(frames);946ExpectedContentFrame *native_frames = get_native_frames(env, cls, frames);947948result = event_storage_garbage_contains(env, &global_event_storage,949native_frames, size, check_lines);950951free(native_frames), native_frames = NULL;952return result;953}954955JNIEXPORT jlong JNICALL956Java_MyPackage_HeapMonitor_getSize(JNIEnv* env, jclass cls,957jobjectArray frames,958jboolean check_lines) {959jlong result = 0;960jsize size = env->GetArrayLength(frames);961ExpectedContentFrame *native_frames = get_native_frames(env, cls, frames);962963result = event_storage_get_size(env, &global_event_storage,964native_frames, size, check_lines);965966free(native_frames), native_frames = NULL;967return result;968}969970JNIEXPORT void JNICALL971Java_MyPackage_HeapMonitor_forceGarbageCollection(JNIEnv* env, jclass cls) {972check_error(jvmti->ForceGarbageCollection(),973"Forced Garbage Collection");974}975976JNIEXPORT void JNICALL977Java_MyPackage_HeapMonitor_resetEventStorage(JNIEnv* env, jclass cls) {978event_storage_reset(&global_event_storage);979event_storage_reset(&second_global_event_storage);980}981982JNIEXPORT jboolean JNICALL983Java_MyPackage_HeapMonitorNoCapabilityTest_allSamplingMethodsFail(JNIEnv *env,984jclass cls) {985jvmtiCapabilities caps;986memset(&caps, 0, sizeof(caps));987caps.can_generate_sampled_object_alloc_events = 1;988if (check_error(jvmti->RelinquishCapabilities(&caps),989"Add capabilities\n")){990return FALSE;991}992993if (check_capability_error(jvmti->SetHeapSamplingInterval(1<<19),994"Set Heap Sampling Interval")) {995return FALSE;996}997return TRUE;998}9991000JNIEXPORT jboolean JNICALL1001Java_MyPackage_HeapMonitorIllegalArgumentTest_testIllegalArgument(JNIEnv *env,1002jclass cls) {1003if (check_error(jvmti->SetHeapSamplingInterval(0),1004"Sampling interval 0 failed\n")){1005return FALSE;1006}10071008if (check_error(jvmti->SetHeapSamplingInterval(1024),1009"Sampling interval 1024 failed\n")){1010return FALSE;1011}10121013if (!check_error(jvmti->SetHeapSamplingInterval(-1),1014"Sampling interval -1 passed\n")){1015return FALSE;1016}10171018if (!check_error(jvmti->SetHeapSamplingInterval(-1024),1019"Sampling interval -1024 passed\n")){1020return FALSE;1021}10221023return TRUE;1024}10251026JNIEXPORT jdouble JNICALL1027Java_MyPackage_HeapMonitor_getAverageSize(JNIEnv *env, jclass cls) {1028return event_storage_get_average_size(&global_event_storage);1029}10301031typedef struct sThreadsFound {1032jthread* threads;1033int num_threads;1034} ThreadsFound;10351036JNIEXPORT jboolean JNICALL1037Java_MyPackage_HeapMonitorThreadTest_checkSamples(JNIEnv* env, jclass cls,1038jint num_threads) {1039print_thread_stats();1040// Ensure we got stacks from at least num_threads.1041return thread_stats.thread_count >= num_threads;1042}10431044JNIEXPORT1045void JNICALL SampledObjectAlloc2(jvmtiEnv *jvmti_env,1046JNIEnv* jni_env,1047jthread thread,1048jobject object,1049jclass object_klass,1050jlong size) {1051// Nop for now, two agents are not yet implemented.1052assert(0);1053}10541055JNIEXPORT jboolean JNICALL1056Java_MyPackage_HeapMonitorTwoAgentsTest_enablingSamplingInSecondaryAgent(1057JNIEnv* env, jclass cls) {1058// Currently this method should be failing directly at the AddCapability step1059// but the implementation is correct for when multi-agent support is enabled.1060jvmtiCapabilities caps;1061jvmtiEventCallbacks callbacks;10621063memset(&caps, 0, sizeof(caps));1064caps.can_generate_sampled_object_alloc_events = 1;1065if (check_error(second_jvmti->AddCapabilities(&caps),1066"Set the capability for second agent")) {1067return FALSE;1068}10691070memset(&callbacks, 0, sizeof(callbacks));1071callbacks.SampledObjectAlloc = &SampledObjectAlloc2;10721073if (check_error(second_jvmti->SetEventCallbacks(&callbacks,1074sizeof(jvmtiEventCallbacks)),1075" Set Event Callbacks for second agent")) {1076return FALSE;1077}10781079return TRUE;1080}10811082JNIEXPORT void JNICALL1083Java_MyPackage_HeapMonitor_enableVMEvents(JNIEnv* env, jclass cls) {1084check_error(jvmti->SetEventNotificationMode(1085JVMTI_ENABLE, JVMTI_EVENT_VM_OBJECT_ALLOC, NULL),1086"Set vm event notifications");1087}10881089JNIEXPORT jint JNICALL1090Java_MyPackage_HeapMonitorVMEventsTest_vmEvents(JNIEnv* env, jclass cls) {1091return event_storage_number_additions(&second_global_event_storage);1092}10931094JNIEXPORT jint JNICALL1095Java_MyPackage_HeapMonitor_sampledEvents(JNIEnv* env, jclass cls) {1096return event_storage_number_additions(&global_event_storage);1097}10981099static jobject allocate_object(JNIEnv* env) {1100// Construct an Object.1101jclass cls = env->FindClass("java/lang/Object");1102jmethodID constructor;1103jobject result;11041105if (env->ExceptionOccurred() || cls == NULL) {1106env->FatalError("Error in jni FindClass: Cannot find Object class\n");1107}11081109constructor = env->GetMethodID(cls, "<init>", "()V");1110if (env->ExceptionOccurred() || constructor == NULL) {1111env->FatalError("Error in jni GetMethodID: Cannot find Object class constructor\n");1112}11131114// Call back constructor to allocate a new instance, with an int argument1115result = env->NewObject(cls, constructor);11161117if (env->ExceptionOccurred() || result == NULL) {1118env->FatalError("Error in jni NewObject: Cannot allocate an object\n");1119}1120return result;1121}11221123// Ensure we got a callback for the test.1124static int did_recursive_callback_test;11251126JNIEXPORT1127void JNICALL RecursiveSampledObjectAlloc(jvmtiEnv *jvmti_env,1128JNIEnv* jni_env,1129jthread thread,1130jobject object,1131jclass object_klass,1132jlong size) {1133// Basically ensure that if we were to allocate objects, we would not have an1134// infinite recursion here.1135int i;1136for (i = 0; i < 1000; i++) {1137if (allocate_object(jni_env) == NULL) {1138jni_env->FatalError("allocate_object returned NULL\n");1139}1140}11411142did_recursive_callback_test = 1;1143}11441145JNIEXPORT jboolean JNICALL1146Java_MyPackage_HeapMonitorRecursiveTest_didCallback(JNIEnv* env, jclass cls) {1147return did_recursive_callback_test != 0;1148}11491150JNIEXPORT void JNICALL1151Java_MyPackage_HeapMonitorRecursiveTest_setCallbackToCallAllocateSomeMore(JNIEnv* env, jclass cls) {1152jvmtiEventCallbacks callbacks;11531154memset(&callbacks, 0, sizeof(callbacks));1155callbacks.SampledObjectAlloc = &RecursiveSampledObjectAlloc;11561157if (check_error(jvmti->SetEventCallbacks(&callbacks,1158sizeof(jvmtiEventCallbacks)),1159"Set Event Callbacks")) {1160env->FatalError("Cannot reset the callback.");1161}1162}11631164}116511661167