Sample maven app added to jfr-streaming repo (#8)
* Sample maven app added to jfr-streaming repo * Sample app code modified based on previous discussions and comments on the PR * refactored code to make it more user friendly * Add some javadoc. * typos fixed which resolves the build failure of the sample app Co-authored-by: David Grieve <david.grieve@microsoft.com>
This commit is contained in:
Родитель
07af7e9638
Коммит
684c148b22
|
@ -39,6 +39,7 @@ target/
|
|||
|
||||
# IntelliJ Idea
|
||||
.idea/
|
||||
*.iml
|
||||
|
||||
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||
#wwwroot/
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
*.jfr
|
|
@ -0,0 +1,14 @@
|
|||
# jfr-streaming Samples
|
||||
|
||||
This directory contains sample maven apps that uses `jfr-streaming` API.
|
||||
See the README file in each sample for details.
|
||||
|
||||
|
||||
To build the samples:
|
||||
```shell
|
||||
$ mvn clean compile
|
||||
```
|
||||
To run a sample, provide the Maven `--project` argument, or run from the sample's directory:
|
||||
```shell
|
||||
$ mvn exec:java --projects introductory
|
||||
```
|
|
@ -0,0 +1,18 @@
|
|||
# jfr-streaming introductory sample
|
||||
|
||||
This sample uses jfr-streaming to capture a flight recording file. The sample creates the file `recording.jfr` which
|
||||
can be opened in JDK Mission Control to visualize the stats.
|
||||
|
||||
### Execute
|
||||
|
||||
To build the sample from the 'introductory' directory:
|
||||
```shell
|
||||
$ mvn clean compile
|
||||
```
|
||||
To run the sample:
|
||||
```shell
|
||||
$ mvn exec:java
|
||||
```
|
||||
The sample simulates load by generating numbers of a Fibonacci sequence. The number of
|
||||
values to generate can be specified by passing it as an argument to this command, for
|
||||
example `-Dexec.arguments="1000"`
|
|
@ -0,0 +1,35 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.microsoft.jfr</groupId>
|
||||
<artifactId>jfr-streaming-samples</artifactId>
|
||||
<version>1.0.1-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<artifactId>introductory</artifactId>
|
||||
<version>1.0.1-SNAPSHOT</version>
|
||||
|
||||
<name>introductory</name>
|
||||
<description>A sample for Java Flight Recorder Streaming Library using Fibonacci number generator</description>
|
||||
<url>https://github.com/Microsoft/jfr-streaming.git</url>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>exec-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<mainClass>com.microsoft.jfr.Main</mainClass>
|
||||
<cleanupDaemonThreads>false</cleanupDaemonThreads>
|
||||
<arguments>
|
||||
<argument>100</argument>
|
||||
</arguments>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
|
@ -0,0 +1,65 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.package com.microsoft.jfr;
|
||||
package com.microsoft.jfr;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
/**
|
||||
* This class uses Fibonacci number generation to produce some load on the CPU.
|
||||
*/
|
||||
public class LoadGenerator {
|
||||
|
||||
// The result of the calculations are kept in this cache. This helps drive up
|
||||
// some memory use, especially if the range is significant. Each time
|
||||
// generateLoad() is called, the cache is recreated which may cause some
|
||||
// garbage collection activity (depending on the heap size).
|
||||
private ArrayList<BigInteger> cache;
|
||||
|
||||
// This just keeps track of the index of the last Fibbonacci number in cache.
|
||||
private int lastFibonacciIndex;
|
||||
|
||||
// How many Fibbonacci numbers to calculate. This can be set as an command line argument.
|
||||
private int range = 100;
|
||||
|
||||
/**
|
||||
* In order to keep Main simple, the constructor just takes the array of
|
||||
* arguments passed on the command line.
|
||||
* @param args The command line arguments passed from Main.
|
||||
*/
|
||||
public LoadGenerator (String[] args) {
|
||||
try {
|
||||
range = Integer.parseInt(args[0]);
|
||||
} catch (IndexOutOfBoundsException | NumberFormatException e) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the method that generates the load. It uses fork-join generate load on the system.
|
||||
* Each time this method is called, a new cache for the Fibonacci numbers is created. Calling
|
||||
* this method repeatedly cause garabage collections if the heap is small enough.
|
||||
*/
|
||||
public void generateLoad () {
|
||||
cache = new ArrayList<>(Collections.nCopies(range + 1, BigInteger.ZERO));
|
||||
cache.set(0, BigInteger.ZERO);
|
||||
cache.set(1, BigInteger.ONE);
|
||||
lastFibonacciIndex = 1;
|
||||
|
||||
// Each value in `stream` gets its own thread to run
|
||||
IntStream.range(0, range)
|
||||
.parallel()
|
||||
.forEach(this::nthFibonacci);
|
||||
}
|
||||
|
||||
private BigInteger nthFibonacci (int n) {
|
||||
if (lastFibonacciIndex >= n) return cache.get(n);
|
||||
for(int i = lastFibonacciIndex + 1; i <= n; i++){
|
||||
cache.set(i, cache.get(i - 1).add(cache.get(i - 2)));
|
||||
}
|
||||
lastFibonacciIndex = n;
|
||||
return cache.get(n);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.package com.microsoft.jfr;
|
||||
package com.microsoft.jfr;
|
||||
|
||||
import javax.management.InstanceNotFoundException;
|
||||
import javax.management.MBeanServerConnection;
|
||||
import java.io.IOException;
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
/**
|
||||
* This sample is meant to show the basic usage of the jfr-streaming library. This library provides access
|
||||
* to most of the FlightRecorderMXBean API. There are a few steps to using the library.
|
||||
* <p>
|
||||
* First, an MBeanServerConnection is needed. The MBeanServerConnection can be to a local or
|
||||
* remote MBean server. For simplicity, this sample makes a connection to the MBean server of
|
||||
* the JVM that is running the sample. The library only uses the MBeanServerConnection. Creating,
|
||||
* managing and closing the MBeanServerConnection is the responsibility of the caller.
|
||||
* <p>
|
||||
* Next, a connection to the FlightRecorderMXBean is made using the
|
||||
* {@code com.microsoft.jfr.FlightRecorderConnection#connect(javax.management.MBeanServerConnection)}
|
||||
* method. This call returns a {@code com.microsoft.jfr.FlightRecorderConnection} which can be used
|
||||
* to create Java flight recordings. Only one FlightRecorderConnection is needed for a given
|
||||
* MBeanServerConnection.
|
||||
* <p>
|
||||
* To create a flight recording, call the method
|
||||
* {@code com.microsoft.jfr.FlightRecorderConnection#newRecording(com.microsoft.jfr.RecordingOptions, com.microsoft.jfr.RecordingConfiguration)}.
|
||||
* This method takes two parameters. The first parameter specifies the options that control the
|
||||
* flight recording, such as maximum recording size. The second parameter configures what events are
|
||||
* recorded, typically the 'default' or 'profiling' configurations that are built-in to the JVM.
|
||||
* <p>
|
||||
* The {@code newRecording} method returns a {@code com.microsoft.jfr.Recording} object that is used to
|
||||
* start, stop and stream a recording file. The {@code Recording} can be used repeatedly provided the
|
||||
* {@code Recording} has not been closed.
|
||||
* </p>
|
||||
*/
|
||||
public class Main {
|
||||
|
||||
/**
|
||||
* An integer value can be passed as an argument on the command line. This integer
|
||||
* argument specifies the end of a range of Fibonacci numbers to generate. If no
|
||||
* argument is given, a default value (1000) is used. The larger the number, the more
|
||||
* load will be placed on the system and the more events that will be generated for the
|
||||
* flight recording. But a larger number also means a longer runtime.
|
||||
* @param args
|
||||
*/
|
||||
public static void main( String[] args ) {
|
||||
// This sample uses the local MBean server, but this could also be a remote MBean server.
|
||||
MBeanServerConnection mBeanServer = ManagementFactory.getPlatformMBeanServer();
|
||||
|
||||
try {
|
||||
// In order to upload a JFR file, we need to create a FlightRecorderConnection.
|
||||
// This gives us a connection the the FlightRecorderMXBean on the MBean server.
|
||||
FlightRecorderConnection flightRecorderConnection = FlightRecorderConnection.connect(mBeanServer);
|
||||
|
||||
// To create a recording, we need recording options, and a recording configuration.
|
||||
// This sample uses the 'profile' configuration. Refer to the section on
|
||||
// "Flight Recorder Configurations" in the Flight Recorder API Programmer's Guide
|
||||
// for more information.
|
||||
RecordingOptions recordingOptions = new RecordingOptions.Builder().disk("true").build();
|
||||
RecordingConfiguration recordingConfiguration = RecordingConfiguration.PROFILE_CONFIGURATION;
|
||||
|
||||
// Note that a Recording is AutoCloseable, so we can use it in a try-with-resources block.
|
||||
try (Recording recording = flightRecorderConnection.newRecording(recordingOptions, recordingConfiguration)) {
|
||||
|
||||
// To create a flight recording, the Recording has to be started. Once the
|
||||
// recording is started, flight recording events are collected by the JVM.
|
||||
recording.start();
|
||||
|
||||
// LoadGenerator does some busy work to drive up CPU usage.
|
||||
new LoadGenerator(args).generateLoad();
|
||||
|
||||
// It isn't always necessary to stop the recording. Check the {@code com.microsoft.jfr.Recording} API.
|
||||
recording.stop();
|
||||
|
||||
// The dump method writes the file to the given path on the host where the JVM is running.
|
||||
// The 'getStream' method is most useful for reading a flight recording file from a remote JVM.
|
||||
// This sample saves the flight recording to 'recording.jfr', which can be used in JDK Mission control
|
||||
recording.dump(Paths.get(System.getProperty("user.dir"), "recording.jfr").toString());
|
||||
} catch (IOException ioe) {
|
||||
// IOException can occur when we try to start/stop recording
|
||||
ioe.printStackTrace();
|
||||
}
|
||||
} catch (InstanceNotFoundException | IOException | JfrStreamingException e) {
|
||||
// `InstanceNotFoundException` means that you may need to enable commercial
|
||||
// features by providing `-XX:+UnlockCommercialFeatures` on the command line.
|
||||
// `IOException` means there is a communication problem when talking to the MBean server.
|
||||
// `JfrStreamingException` wraps an exception that may be thrown by the MBean server or from
|
||||
// the FlightRecorderMXBean.
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.microsoft.jfr</groupId>
|
||||
<artifactId>jfr-streaming-samples</artifactId>
|
||||
<version>1.0.1-SNAPSHOT</version>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<name>JFR Streaming library sample apps</name>
|
||||
<description>Sample maven apps to showcase the usage of jfr-streaming library API</description>
|
||||
<url>https://github.com/Microsoft/jfr-streaming</url>
|
||||
<organization>
|
||||
<name>Microsoft Corporation</name>
|
||||
<url>http://microsoft.com</url>
|
||||
</organization>
|
||||
|
||||
<licenses>
|
||||
<license>
|
||||
<name>MIT License</name>
|
||||
<url>http://opensource.org/licenses/MIT</url>
|
||||
<distribution>repo</distribution>
|
||||
</license>
|
||||
</licenses>
|
||||
|
||||
<developers>
|
||||
<developer>
|
||||
<id>microsoft</id>
|
||||
<name>Microsoft Corporation</name>
|
||||
</developer>
|
||||
</developers>
|
||||
|
||||
<modules>
|
||||
<module>introductory</module>
|
||||
</modules>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>11</maven.compiler.source>
|
||||
<maven.compiler.target>11</maven.compiler.target>
|
||||
<maven.compiler.testSource>11</maven.compiler.testSource>
|
||||
<maven.compiler.testTarget>11</maven.compiler.testTarget>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.11</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.microsoft.jfr</groupId>
|
||||
<artifactId>jfr-streaming</artifactId>
|
||||
<version>1.0.1-SNAPSHOT</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<pluginManagement>
|
||||
<plugins>
|
||||
<!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->
|
||||
<plugin>
|
||||
<artifactId>maven-clean-plugin</artifactId>
|
||||
<version>3.1.0</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.8.1</version>
|
||||
<configuration>
|
||||
<source>${maven.compiler.source}</source>
|
||||
<target>${maven.compiler.target}</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>exec-maven-plugin</artifactId>
|
||||
<version>3.0.0</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
</build>
|
||||
</project>
|
|
@ -53,7 +53,7 @@ public class FlightRecorderConnection {
|
|||
* {@code FlightRecorderConnection}, or throws an exception. An {@code IOException}
|
||||
* indicates a problem with the connection to the MBean server. An {@code InstanceNotFoundException}
|
||||
* indicates that the FlightRecorder MBean is not registered on the target JVM. This could happen
|
||||
* if the target JVM does not support Java Flight Recorder, or if expermental features need to be
|
||||
* if the target JVM does not support Java Flight Recorder, or if experimental features need to be
|
||||
* enabled on the target JVM.
|
||||
*
|
||||
* @param mBeanServerConnection The {@code MBeanServerConnection} to the JVM.
|
||||
|
|
Загрузка…
Ссылка в новой задаче