1 /* 2 * Copyright (c) 2017, 2021, Oracle 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 it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package jdk.jfr.internal; 27 28 import java.util.List; 29 30 import jdk.internal.vm.annotation.IntrinsicCandidate; 31 import jdk.jfr.Event; 32 import jdk.jfr.internal.handlers.EventHandler; 33 34 /** 35 * Interface against the JVM. 36 * 37 */ 38 public final class JVM { 39 private static final JVM jvm = new JVM(); 40 41 // JVM signals file changes by doing Object#notify on this object 42 static final Object FILE_DELTA_CHANGE = new Object(); 43 44 static final long RESERVED_CLASS_ID_LIMIT = 500; 45 46 private volatile boolean nativeOK; 47 registerNatives()48 private static native void registerNatives(); 49 50 static { registerNatives()51 registerNatives(); 52 for (LogTag tag : LogTag.values()) { subscribeLogLevel(tag, tag.id)53 subscribeLogLevel(tag, tag.id); 54 } Options.ensureInitialized()55 Options.ensureInitialized(); 56 } 57 58 /** 59 * Get the one and only JVM. 60 * 61 * @return the JVM 62 */ getJVM()63 public static JVM getJVM() { 64 return jvm; 65 } 66 JVM()67 private JVM() { 68 } 69 70 /** 71 * Marks current chunk as final 72 * <p> 73 * This allows streaming clients to read the chunk header and 74 * close the stream when no more data will be written into 75 * the current repository. 76 */ markChunkFinal()77 public native void markChunkFinal(); 78 79 /** 80 * Begin recording events 81 * 82 * Requires that JFR has been started with {@link #createNativeJFR()} 83 */ beginRecording()84 public native void beginRecording(); 85 86 /** 87 * Return true if the JVM is recording 88 */ isRecording()89 public native boolean isRecording(); 90 91 /** 92 * End recording events, which includes flushing data in thread buffers 93 * 94 * Requires that JFR has been started with {@link #createNativeJFR()} 95 * 96 */ endRecording()97 public native void endRecording(); 98 99 /** 100 * Return ticks 101 * 102 * @return the time, in ticks 103 * 104 */ 105 @IntrinsicCandidate counterTime()106 public static native long counterTime(); 107 108 /** 109 * Emits native periodic event. 110 * 111 * @param eventTypeId type id 112 * 113 * @param timestamp commit time for event 114 * @param when when it is being done {@link Periodic.When} 115 * 116 * @return true if the event was committed 117 */ emitEvent(long eventTypeId, long timestamp, long when)118 public native boolean emitEvent(long eventTypeId, long timestamp, long when); 119 120 /** 121 * Return a list of all classes deriving from {@link jdk.internal.event.Event} 122 * 123 * @return list of event classes. 124 */ getAllEventClasses()125 public native List<Class<? extends jdk.internal.event.Event>> getAllEventClasses(); 126 127 /** 128 * Return a count of the number of unloaded classes deriving from {@link Event} 129 * 130 * @return number of unloaded event classes. 131 */ getUnloadedEventClassCount()132 public native long getUnloadedEventClassCount(); 133 134 /** 135 * Return a unique identifier for a class. The class is marked as being 136 * "in use" in JFR. 137 * 138 * @param clazz clazz 139 * 140 * @return a unique class identifier 141 */ 142 @IntrinsicCandidate getClassId(Class<?> clazz)143 public static native long getClassId(Class<?> clazz); 144 145 /** 146 * Return process identifier. 147 * 148 * @return process identifier 149 */ getPid()150 public native String getPid(); 151 152 /** 153 * Return unique identifier for stack trace. 154 * 155 * Requires that JFR has been started with {@link #createNativeJFR()} 156 * 157 * @param skipCount number of frames to skip 158 * @return a unique stack trace identifier 159 */ getStackTraceId(int skipCount)160 public native long getStackTraceId(int skipCount); 161 162 /** 163 * Return identifier for thread 164 * 165 * @param t thread 166 * @return a unique thread identifier 167 */ getThreadId(Thread t)168 public native long getThreadId(Thread t); 169 170 /** 171 * Frequency, ticks per second 172 * 173 * @return frequency 174 */ getTicksFrequency()175 public native long getTicksFrequency(); 176 177 /** 178 * Write message to log. Should swallow null or empty message, and be able 179 * to handle any Java character and not crash with very large message 180 * 181 * @param tagSetId the tagset id 182 * @param level on level 183 * @param message log message 184 * 185 */ log(int tagSetId, int level, String message)186 public static native void log(int tagSetId, int level, String message); 187 188 /** 189 * Log an event to jfr+event or jfr+event+system. 190 * <p> 191 * Caller should ensure that message is not null or too large to handle. 192 * 193 * @param level log level 194 * @param lines lines to log 195 * @param system if lines should be written to jfr+event+system 196 */ logEvent(int level, String[] lines, boolean system)197 public static native void logEvent(int level, String[] lines, boolean system); 198 199 /** 200 * Subscribe to LogLevel updates for LogTag 201 * 202 * @param lt the log tag to subscribe 203 * @param tagSetId the tagset id 204 */ subscribeLogLevel(LogTag lt, int tagSetId)205 public static native void subscribeLogLevel(LogTag lt, int tagSetId); 206 207 /** 208 * Call to invoke event tagging and retransformation of the passed classes 209 * 210 * @param classes 211 * 212 * @throws IllegalStateException if wrong JVMTI phase. 213 */ retransformClasses(Class<?>[] classes)214 public native synchronized void retransformClasses(Class<?>[] classes); 215 216 /** 217 * Enable event 218 * 219 * @param eventTypeId event type id 220 * 221 * @param enabled enable event 222 */ setEnabled(long eventTypeId, boolean enabled)223 public native void setEnabled(long eventTypeId, boolean enabled); 224 225 /** 226 * Interval at which the JVM should notify on {@link #FILE_DELTA_CHANGE} 227 * 228 * @param delta number of bytes, reset after file rotation 229 */ setFileNotification(long delta)230 public native void setFileNotification(long delta); 231 232 /** 233 * Set the number of global buffers to use 234 * 235 * @param count 236 * 237 * @throws IllegalArgumentException if count is not within a valid range 238 * @throws IllegalStateException if value can't be changed 239 */ setGlobalBufferCount(long count)240 public native void setGlobalBufferCount(long count) throws IllegalArgumentException, IllegalStateException; 241 242 /** 243 * Set size of a global buffer 244 * 245 * @param size 246 * 247 * @throws IllegalArgumentException if buffer size is not within a valid 248 * range 249 */ setGlobalBufferSize(long size)250 public native void setGlobalBufferSize(long size) throws IllegalArgumentException; 251 252 /** 253 * Set overall memory size 254 * 255 * @param size 256 * 257 * @throws IllegalArgumentException if memory size is not within a valid 258 * range 259 */ setMemorySize(long size)260 public native void setMemorySize(long size) throws IllegalArgumentException; 261 262 /** 263 * Set interval for method samples, in milliseconds. 264 * 265 * Setting interval to 0 turns off the method sampler. 266 * 267 * @param intervalMillis the sampling interval 268 */ setMethodSamplingInterval(long type, long intervalMillis)269 public native void setMethodSamplingInterval(long type, long intervalMillis); 270 271 /** 272 * Sets the file where data should be written. 273 * 274 * Requires that JFR has been started with {@link #createNativeJFR()} 275 * 276 * <pre> 277 * Recording Previous Current Action 278 * ============================================== 279 * true null null Ignore, keep recording in-memory 280 * true null file1 Start disk recording 281 * true file null Copy out metadata to disk and continue in-memory recording 282 * true file1 file2 Copy out metadata and start with new File (file2) 283 * false * null Ignore, but start recording to memory with {@link #beginRecording()} 284 * false * file Ignore, but start recording to disk with {@link #beginRecording()} 285 * 286 * </pre> 287 * 288 * recording can be set to true/false with {@link #beginRecording()} 289 * {@link #endRecording()} 290 * 291 * @param file the file where data should be written, or null if it should 292 * not be copied out (in memory). 293 */ setOutput(String file)294 public native void setOutput(String file); 295 296 /** 297 * Controls if a class deriving from jdk.jfr.Event should 298 * always be instrumented on class load. 299 * 300 * @param force, true to force initialization, false otherwise 301 */ setForceInstrumentation(boolean force)302 public native void setForceInstrumentation(boolean force); 303 304 /** 305 * Turn on/off thread sampling. 306 * 307 * @param sampleThreads true if threads should be sampled, false otherwise. 308 * 309 * @throws IllegalStateException if state can't be changed. 310 */ setSampleThreads(boolean sampleThreads)311 public native void setSampleThreads(boolean sampleThreads) throws IllegalStateException; 312 313 /** 314 * Turn on/off compressed integers. 315 * 316 * @param compressed true if compressed integers should be used, false 317 * otherwise. 318 * 319 * @throws IllegalStateException if state can't be changed. 320 */ setCompressedIntegers(boolean compressed)321 public native void setCompressedIntegers(boolean compressed) throws IllegalStateException; 322 323 /** 324 * Set stack depth. 325 * 326 * @param depth 327 * 328 * @throws IllegalArgumentException if not within a valid range 329 * @throws IllegalStateException if depth can't be changed 330 */ setStackDepth(int depth)331 public native void setStackDepth(int depth) throws IllegalArgumentException, IllegalStateException; 332 333 /** 334 * Turn on stack trace for an event 335 * 336 * @param eventTypeId the event id 337 * 338 * @param enabled if stack traces should be enabled 339 */ setStackTraceEnabled(long eventTypeId, boolean enabled)340 public native void setStackTraceEnabled(long eventTypeId, boolean enabled); 341 342 /** 343 * Set thread buffer size. 344 * 345 * @param size 346 * 347 * @throws IllegalArgumentException if size is not within a valid range 348 * @throws IllegalStateException if size can't be changed 349 */ setThreadBufferSize(long size)350 public native void setThreadBufferSize(long size) throws IllegalArgumentException, IllegalStateException; 351 352 /** 353 * Set threshold for event, 354 * 355 * Long.MAXIMUM_VALUE = no limit 356 * 357 * @param eventTypeId the id of the event type 358 * @param ticks threshold in ticks, 359 * @return true, if it could be set 360 */ setThreshold(long eventTypeId, long ticks)361 public native boolean setThreshold(long eventTypeId, long ticks); 362 363 /** 364 * Store the metadata descriptor that is to be written at the end of a 365 * chunk, data should be written after GMT offset and size of metadata event 366 * should be adjusted 367 * 368 * Requires that JFR has been started with {@link #createNativeJFR()} 369 * 370 * @param bytes binary representation of metadata descriptor 371 */ storeMetadataDescriptor(byte[] bytes)372 public native void storeMetadataDescriptor(byte[] bytes); 373 374 /** 375 * If the JVM supports JVM TI and retransformation has not been disabled this 376 * method will return true. This flag can not change during the lifetime of 377 * the JVM. 378 * 379 * @return if transform is allowed 380 */ getAllowedToDoEventRetransforms()381 public native boolean getAllowedToDoEventRetransforms(); 382 383 /** 384 * Set up native resources, data structures, threads etc. for JFR 385 * 386 * @param simulateFailure simulate a initialization failure and rollback in 387 * native, used for testing purposes 388 * 389 * @throws IllegalStateException if native part of JFR could not be created. 390 * 391 */ createJFR(boolean simulateFailure)392 private native boolean createJFR(boolean simulateFailure) throws IllegalStateException; 393 394 /** 395 * Destroys native part of JFR. If already destroy, call is ignored. 396 * 397 * Requires that JFR has been started with {@link #createNativeJFR()} 398 * 399 * @return if an instance was actually destroyed. 400 * 401 */ destroyJFR()402 private native boolean destroyJFR(); 403 createFailedNativeJFR()404 public boolean createFailedNativeJFR() throws IllegalStateException { 405 return createJFR(true); 406 } 407 createNativeJFR()408 public void createNativeJFR() { 409 nativeOK = createJFR(false); 410 } 411 destroyNativeJFR()412 public boolean destroyNativeJFR() { 413 boolean result = destroyJFR(); 414 nativeOK = !result; 415 return result; 416 } 417 hasNativeJFR()418 public boolean hasNativeJFR() { 419 return nativeOK; 420 } 421 422 /** 423 * Cheap test to check if JFR functionality is available. 424 * 425 * @return 426 */ isAvailable()427 public native boolean isAvailable(); 428 429 /** 430 * To convert ticks to wall clock time. 431 */ getTimeConversionFactor()432 public native double getTimeConversionFactor(); 433 434 /** 435 * Return a unique identifier for a class. Compared to {@link #getClassId(Class)}, 436 * this method does not tag the class as being "in-use". 437 * 438 * @param clazz class 439 * 440 * @return a unique class identifier 441 */ getTypeId(Class<?> clazz)442 public native long getTypeId(Class<?> clazz); 443 444 /** 445 * Fast path fetching the EventWriter using VM intrinsics 446 * 447 * @return thread local EventWriter 448 */ 449 @IntrinsicCandidate getEventWriter()450 public static native Object getEventWriter(); 451 452 /** 453 * Create a new EventWriter 454 * 455 * @return thread local EventWriter 456 */ newEventWriter()457 public static native EventWriter newEventWriter(); 458 459 /** 460 * Flushes the EventWriter for this thread. 461 */ flush(EventWriter writer, int uncommittedSize, int requestedSize)462 public static native boolean flush(EventWriter writer, int uncommittedSize, int requestedSize); 463 464 /** 465 * Flushes all thread buffers to disk and the constant pool data needed to read 466 * them. 467 * <p> 468 * When the method returns, the chunk header should be updated with valid 469 * pointers to the metadata event, last check point event, correct file size and 470 * the generation id. 471 * 472 */ flush()473 public native void flush(); 474 475 /** 476 * Sets the location of the disk repository, to be used at an emergency 477 * dump. 478 * 479 * @param dirText 480 */ setRepositoryLocation(String dirText)481 public native void setRepositoryLocation(String dirText); 482 483 /** 484 * Access to VM termination support. 485 * 486 * @param errorMsg descriptive message to be include in VM termination sequence 487 */ abort(String errorMsg)488 public native void abort(String errorMsg); 489 490 /** 491 * Adds a string to the string constant pool. 492 * 493 * If the same string is added twice, two entries will be created. 494 * 495 * @param id identifier associated with the string, not negative 496 * 497 * @param s string constant to be added, not null 498 * 499 * @return true, if the string was successfully added. 500 */ addStringConstant(long id, String s)501 public static native boolean addStringConstant(long id, String s); 502 uncaughtException(Thread thread, Throwable t)503 public native void uncaughtException(Thread thread, Throwable t); 504 505 /** 506 * Sets cutoff for event. 507 * 508 * Determines how long the event should be allowed to run. 509 * 510 * Long.MAXIMUM_VALUE = no limit 511 * 512 * @param eventTypeId the id of the event type 513 * @param cutoffTicks cutoff in ticks, 514 * @return true, if it could be set 515 */ setCutoff(long eventTypeId, long cutoffTicks)516 public native boolean setCutoff(long eventTypeId, long cutoffTicks); 517 518 /** 519 * Sets the event emission rate in event sample size per time unit. 520 * 521 * Determines how events are throttled. 522 * 523 * @param eventTypeId the id of the event type 524 * @param eventSampleSize event sample size 525 * @param period_ms time period in milliseconds 526 * @return true, if it could be set 527 */ setThrottle(long eventTypeId, long eventSampleSize, long period_ms)528 public native boolean setThrottle(long eventTypeId, long eventSampleSize, long period_ms); 529 530 /** 531 * Emit old object sample events. 532 * 533 * @param cutoff the cutoff in ticks 534 * @param emitAll emit all samples in old object queue 535 * @param skipBFS don't use BFS when searching for path to GC root 536 */ emitOldObjectSamples(long cutoff, boolean emitAll, boolean skipBFS)537 public native void emitOldObjectSamples(long cutoff, boolean emitAll, boolean skipBFS); 538 539 /** 540 * Test if a chunk rotation is warranted. 541 * 542 * @return if it is time to perform a chunk rotation 543 */ shouldRotateDisk()544 public native boolean shouldRotateDisk(); 545 546 /** 547 * Exclude a thread from the jfr system 548 * 549 */ exclude(Thread thread)550 public native void exclude(Thread thread); 551 552 /** 553 * Include a thread back into the jfr system 554 * 555 */ include(Thread thread)556 public native void include(Thread thread); 557 558 /** 559 * Test if a thread ius currently excluded from the jfr system. 560 * 561 * @return is thread currently excluded 562 */ isExcluded(Thread thread)563 public native boolean isExcluded(Thread thread); 564 565 /** 566 * Get the start time in nanos from the header of the current chunk 567 * 568 * @return start time of the recording in nanos, -1 in case of in-memory 569 */ getChunkStartNanos()570 public native long getChunkStartNanos(); 571 572 /** 573 * Stores an EventHandler to the eventHandler field of an event class. 574 * 575 * @param eventClass the class, not {@code null} 576 * 577 * @param handler the handler, may be {@code null} 578 * 579 * @return if the field could be set 580 */ setHandler(Class<? extends jdk.internal.event.Event> eventClass, EventHandler handler)581 public native boolean setHandler(Class<? extends jdk.internal.event.Event> eventClass, EventHandler handler); 582 583 /** 584 * Retrieves the EventHandler for an event class. 585 * 586 * @param eventClass the class, not {@code null} 587 * 588 * @return the handler, may be {@code null} 589 */ getHandler(Class<? extends jdk.internal.event.Event> eventClass)590 public native Object getHandler(Class<? extends jdk.internal.event.Event> eventClass); 591 592 /** 593 * Returns the id for the Java types defined in metadata.xml. 594 * 595 * @param name the name of the type 596 * 597 * @return the id, or a negative value if it does not exists. 598 */ getTypeId(String name)599 public native long getTypeId(String name); 600 } 601