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:
debjitMS 2021-04-13 06:10:59 -07:00 коммит произвёл GitHub
Родитель 07af7e9638
Коммит 684c148b22
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
9 изменённых файлов: 313 добавлений и 1 удалений

1
.gitignore поставляемый
Просмотреть файл

@ -39,6 +39,7 @@ target/
# IntelliJ Idea
.idea/
*.iml
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/

1
samples/.gitignore поставляемый Normal file
Просмотреть файл

@ -0,0 +1 @@
*.jfr

14
samples/README.md Normal file
Просмотреть файл

@ -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();
}
}
}

85
samples/pom.xml Normal file
Просмотреть файл

@ -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.