├── .editorconfig ├── .github ├── dependabot.yml └── workflows │ └── maven.yml ├── .gitignore ├── .idea ├── compiler.xml ├── copyright │ ├── Apache_Copyright_Notice.xml │ └── profiles_settings.xml ├── encodings.xml ├── libraries │ ├── Maven__commons_cli_commons_cli_1_4.xml │ ├── Maven__commons_lang_commons_lang_2_6.xml │ ├── Maven__jline_jline_2_14_5.xml │ ├── Maven__junit_junit_4_12.xml │ ├── Maven__org_apache_commons_commons_lang3_3_8_1.xml │ ├── Maven__org_cyclopsgroup_jmxterm_1_0_0.xml │ └── Maven__org_hamcrest_hamcrest_core_1_3.xml ├── misc.xml ├── modules.xml └── vcs.xml ├── .travis.yml ├── CONTRIBUTING.md ├── LICENSE.txt ├── README.md ├── docs ├── COMMAND_LINE_INTERFACE.md ├── CONFIGURATION.md ├── JMX_INTERFACE.md ├── LOGGING.md ├── SCREENSHOTS.md └── _config.yml ├── images ├── top4j-blocked-threads-screenshot.png ├── top4j-icon-panther-style.png ├── top4j-thread-stack-trace-screenshot.png ├── top4j-top-threads-I-option-screenshot.png ├── top4j-top-threads-screenshot.png └── top4j-top-threads-t-option-screenshot.png ├── pom.xml ├── top4j-cli ├── .gitignore ├── .idea │ ├── .name │ ├── compiler.xml │ ├── copyright │ │ └── profiles_settings.xml │ ├── encodings.xml │ ├── libraries │ │ ├── Maven__avalon_framework_avalon_framework_4_1_3.xml │ │ ├── Maven__classworlds_classworlds_1_1.xml │ │ ├── Maven__classworlds_classworlds_boot_1_0.xml │ │ ├── Maven__commons_beanutils_commons_beanutils_1_7_0.xml │ │ ├── Maven__commons_cli_commons_cli_1_1.xml │ │ ├── Maven__commons_collections_commons_collections_3_2.xml │ │ ├── Maven__commons_io_commons_io_1_3_2.xml │ │ ├── Maven__commons_lang_commons_lang_2_6.xml │ │ ├── Maven__commons_logging_commons_logging_1_1.xml │ │ ├── Maven__io_top4j_top4j_javaagent_0_0_1_SNAPSHOT.xml │ │ ├── Maven__javax_servlet_servlet_api_2_3.xml │ │ ├── Maven__jline_jline_2_12.xml │ │ ├── Maven__junit_junit_3_8_1.xml │ │ ├── Maven__log4j_log4j_1_2_12.xml │ │ ├── Maven__logkit_logkit_1_0_1.xml │ │ ├── Maven__org_cyclopsgroup_jcli_1_0_alpha_3.xml │ │ └── Maven__org_cyclopsgroup_jmxterm_1_0_alpha_4.xml │ ├── misc.xml │ ├── modules.xml │ └── vcs.xml ├── pom.xml ├── src │ └── main │ │ ├── java │ │ └── io │ │ │ └── top4j │ │ │ ├── cli │ │ │ ├── ConsoleController.java │ │ │ ├── ConsoleControllerTask.java │ │ │ ├── DisplayConfig.java │ │ │ ├── Top4J.java │ │ │ ├── UserInput.java │ │ │ └── exception │ │ │ │ └── ScreenUpdateException.java │ │ │ └── vm │ │ │ ├── Jdk9JavaProcess.java │ │ │ └── Jdk9JavaProcessManager.java │ │ └── scripts │ │ └── top4j └── top4j-cli.iml ├── top4j-javaagent ├── .gitignore ├── .idea │ ├── .name │ ├── compiler.xml │ ├── copyright │ │ └── profiles_settings.xml │ ├── encodings.xml │ ├── libraries │ │ ├── Maven__junit_junit_4_12.xml │ │ └── Maven__org_hamcrest_hamcrest_core_1_3.xml │ ├── misc.xml │ ├── modules.xml │ └── vcs.xml ├── pom.xml ├── sonar-project.properties ├── src │ ├── main │ │ ├── java │ │ │ └── io │ │ │ │ └── top4j │ │ │ │ └── javaagent │ │ │ │ ├── config │ │ │ │ ├── Configurator.java │ │ │ │ └── Constants.java │ │ │ │ ├── controller │ │ │ │ ├── Agent.java │ │ │ │ ├── Collector.java │ │ │ │ ├── Controller.java │ │ │ │ └── LoggerThread.java │ │ │ │ ├── exception │ │ │ │ ├── MBeanAccessException.java │ │ │ │ ├── MBeanDiscoveryException.java │ │ │ │ ├── MBeanInitException.java │ │ │ │ └── MBeanRuntimeException.java │ │ │ │ ├── listener │ │ │ │ └── CollectionListener.java │ │ │ │ ├── mbeans │ │ │ │ ├── StatsMXBean.java │ │ │ │ ├── agent │ │ │ │ │ ├── AgentMXBean.java │ │ │ │ │ ├── AgentStats.java │ │ │ │ │ └── AgentStatsMXBean.java │ │ │ │ ├── jvm │ │ │ │ │ ├── JVMStats.java │ │ │ │ │ ├── JVMStatsMXBean.java │ │ │ │ │ ├── gc │ │ │ │ │ │ ├── CollectionUsageListener.java │ │ │ │ │ │ ├── GCOverhead.java │ │ │ │ │ │ ├── GCPauseTime.java │ │ │ │ │ │ ├── GCStats.java │ │ │ │ │ │ ├── GCStatsMXBean.java │ │ │ │ │ │ ├── GCTimeBean.java │ │ │ │ │ │ └── GarbageCollectorMXBeanHelper.java │ │ │ │ │ ├── heap │ │ │ │ │ │ ├── HeapStats.java │ │ │ │ │ │ ├── HeapStatsMXBean.java │ │ │ │ │ │ └── HeapUtilisation.java │ │ │ │ │ ├── memory │ │ │ │ │ │ ├── MemoryPoolAllocationRate.java │ │ │ │ │ │ ├── MemoryPoolMXBeanHelper.java │ │ │ │ │ │ ├── MemoryPoolUsageBean.java │ │ │ │ │ │ ├── MemoryPoolUsageTracker.java │ │ │ │ │ │ ├── MemoryStats.java │ │ │ │ │ │ ├── MemoryStatsMXBean.java │ │ │ │ │ │ ├── MemorySurvivorBean.java │ │ │ │ │ │ └── MemorySurvivorRate.java │ │ │ │ │ └── threads │ │ │ │ │ │ ├── BlockedThread.java │ │ │ │ │ │ ├── BlockedThreadMXBean.java │ │ │ │ │ │ ├── HotMethod.java │ │ │ │ │ │ ├── HotMethodMXBean.java │ │ │ │ │ │ ├── HotMethodTracker.java │ │ │ │ │ │ ├── HotMethods.java │ │ │ │ │ │ ├── MethodTimeMap.java │ │ │ │ │ │ ├── ThreadStats.java │ │ │ │ │ │ ├── ThreadStatsMXBean.java │ │ │ │ │ │ ├── ThreadTimeMap.java │ │ │ │ │ │ ├── ThreadUsage.java │ │ │ │ │ │ ├── TopThread.java │ │ │ │ │ │ └── TopThreadMXBean.java │ │ │ │ └── logger │ │ │ │ │ ├── StatsLogWriter.java │ │ │ │ │ ├── StatsLogger.java │ │ │ │ │ └── StatsLoggerMXBean.java │ │ │ │ ├── messaging │ │ │ │ └── LoggerQueue.java │ │ │ │ ├── profiler │ │ │ │ ├── CPUTimer.java │ │ │ │ └── CpuTime.java │ │ │ │ ├── test │ │ │ │ ├── CollatorTest.java │ │ │ │ ├── MemTest.java │ │ │ │ ├── MultiThreadedTest.java │ │ │ │ └── Test.java │ │ │ │ └── utils │ │ │ │ ├── GarbageCollectorNames.java │ │ │ │ ├── MBeanHelper.java │ │ │ │ ├── MBeanInfo.java │ │ │ │ ├── MemoryPoolNames.java │ │ │ │ └── ThreadHelper.java │ │ └── resources │ │ │ └── default-top4j.properties │ └── test │ │ ├── java │ │ ├── JunitTest.java │ │ └── JvmAgentTest.java │ │ ├── resources │ │ ├── assertion-data.csv │ │ └── top4j-test.properties │ │ └── scripts │ │ ├── jmapCollector.sh │ │ ├── listGarbageCollectorNames.sh │ │ ├── listMemoryPoolNames.sh │ │ ├── logging.properties │ │ ├── runCollatorTest.sh │ │ ├── runMTCMSTest.sh │ │ ├── runMTG1Test.sh │ │ ├── runMemReport.sh │ │ ├── runMemTest.sh │ │ ├── runMultiThreadedTest.sh │ │ ├── runMultiThreadedTestNoAgent.sh │ │ ├── runSoakTest.sh │ │ ├── setenv.sh │ │ └── top4j.properties └── top4j-javaagent.iml └── top4j-parent.iml /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | insert_final_newline = true 6 | charset = utf-8 7 | 8 | [*.java] 9 | indent_style = space 10 | indent_size = 4 11 | continuation_indent_size = 8 -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "maven" 9 | directory: "/" # Location of package manifests 10 | schedule: 11 | interval: "weekly" 12 | day: "friday" 13 | - package-ecosystem: "github-actions" 14 | directory: "/" 15 | schedule: 16 | interval: "weekly" 17 | day: "friday" 18 | -------------------------------------------------------------------------------- /.github/workflows/maven.yml: -------------------------------------------------------------------------------- 1 | # This workflow will build a Java project with Maven, and cache/restore any dependencies to improve the workflow execution time 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven 3 | 4 | name: Java CI with Maven 5 | 6 | on: 7 | push: 8 | branches: [ "master" ] 9 | pull_request: 10 | branches: [ "master" ] 11 | 12 | jobs: 13 | build: 14 | 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - uses: actions/checkout@v3 19 | - name: Set up JDK 8 20 | uses: actions/setup-java@v3 21 | with: 22 | java-version: '8' 23 | distribution: 'temurin' 24 | cache: maven 25 | - name: Build with Maven 26 | run: mvn -B package --file pom.xml 27 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .project 2 | .classpath 3 | .settings 4 | target/ 5 | */.project 6 | */.classpath 7 | */.settings 8 | */target/ 9 | pom.xml.tag 10 | pom.xml.releaseBackup 11 | pom.xml.versionsBackup 12 | pom.xml.next 13 | release.properties 14 | dependency-reduced-pom.xml 15 | buildNumber.properties 16 | .mvn/timing.properties 17 | **/top4j-stats/ 18 | 19 | # IntelliJ Stuff 20 | 21 | # User-specific stuff 22 | .idea/**/workspace.xml 23 | .idea/**/tasks.xml 24 | .idea/**/usage.statistics.xml 25 | .idea/**/dictionaries 26 | .idea/**/shelf 27 | 28 | # Generated files 29 | .idea/**/contentModel.xml 30 | 31 | # Sensitive or high-churn files 32 | .idea/**/dataSources/ 33 | .idea/**/dataSources.ids 34 | .idea/**/dataSources.local.xml 35 | .idea/**/sqlDataSources.xml 36 | .idea/**/dynamic.xml 37 | .idea/**/uiDesigner.xml 38 | .idea/**/dbnavigator.xml 39 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /.idea/copyright/Apache_Copyright_Notice.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__commons_cli_commons_cli_1_4.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__commons_lang_commons_lang_2_6.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__jline_jline_2_14_5.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__junit_junit_4_12.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_apache_commons_commons_lang3_3_8_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_cyclopsgroup_jmxterm_1_0_0.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_hamcrest_hamcrest_core_1_3.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenAnswers/top4j/2191c1c618fba204b9566b05f56f09c8c15e1ec9/.travis.yml -------------------------------------------------------------------------------- /docs/CONFIGURATION.md: -------------------------------------------------------------------------------- 1 | Configuration 2 | ============= 3 | The Top4J Java Agent is configured via a standard [Java properties file](https://docs.oracle.com/javase/tutorial/essential/environment/properties.html). 4 | 5 | The Top4J Java Agent ships with a set of default properties configured via a file called `default-top4j.properties` which can be found within the Top4J source code [here](../top4j-javaagent/src/main/resources/default-top4j.properties). 6 | 7 | The default Top4J properties can be overridden in one of two ways: 8 | 9 | 1. By providing a custom Top4J properties file called `top4j.properties` within the current working directory of the target JVM. 10 | 1. By adding additional arguments to the `java -javaagent` JVM command-line argument, for example.... 11 | 12 | ```bash 13 | java -javaagent:/top4j-javaagent-0.0.8.jar=stats.logger.enabled=true,top.thread.count=10 14 | ``` 15 | 16 | **NOTE:** The default location and name of the override `top4j.properties` file can be modified via the `-javaagent` command line argument `config.file`, for example.... 17 | 18 | ```bash 19 | java -javaagent:/top4j-javaagent-0.0.8.jar=config.file=/custom/config/location/top4j.properties 20 | ``` 21 | 22 | The full set of configurable properties, along with a brief description of each property, can be accessed via the [default-top4j.properties file](../top4j-javaagent/src/main/resources/default-top4j.properties). 23 | 24 | -------------------------------------------------------------------------------- /docs/LOGGING.md: -------------------------------------------------------------------------------- 1 | Logging 2 | ======= 3 | The Top4J Java Agent can be configured to log performance metrics to the local file system. 4 | 5 | This feature is disabled by default but can be easily enabled via the Top4J configuration property `stats.logger.enabled=true`. 6 | 7 | The `stats.logger.enabled` override property can be set in one of two ways: 8 | 9 | 1. By creating a custom top4j.properties file containing `stats.logger.enabled=true` - see the [Top4J Configuration](/docs/CONFIGURATION.md) documentation for more details. 10 | 1. By adding an additional argument to the `java -javaagent` command-line argument, for example.... 11 | 12 | ```bash 13 | java -javaagent:/top4j-javaagent-0.0.8.jar=stats.logger.enabled=true 14 | ``` 15 | 16 | The Top4J stats logger will log to a directory called `top4j-stats` within the JVMs current working directory by default. However, the default location can be overridden via the Top4J configuration property `stats.logger.directory`, for example.... 17 | 18 | ```bash 19 | java -javaagent:/top4j-javaagent-0.0.8.jar=stats.logger.enabled=true,stats.logger.directory=/var/log/top4j-stats 20 | ``` 21 | 22 | **NOTE:** Make sure the `stats.logger.directory` is writable by the Java process owner. 23 | 24 | The Top4J stats logger creates one log file per [Top4J MBean](/docs/JMX_INTERFACE.md) per day. The stats (MBean attributes) are recorded as comma-separated values (CSV) by default. The stats log files are automatically rolled at midnight. 25 | 26 | Here is an example Top4J stats file listing.... 27 | 28 | ```bash 29 | -bash-4.1$ ls -1 *20190917.csv 30 | AgentStats.20190917.csv 31 | BlockedThread-1.20190917.csv 32 | BlockedThread-10.20190917.csv 33 | BlockedThread-2.20190917.csv 34 | BlockedThread-3.20190917.csv 35 | BlockedThread-4.20190917.csv 36 | BlockedThread-5.20190917.csv 37 | BlockedThread-6.20190917.csv 38 | BlockedThread-7.20190917.csv 39 | BlockedThread-8.20190917.csv 40 | BlockedThread-9.20190917.csv 41 | GCStats.20190917.csv 42 | HeapStats.20190917.csv 43 | MemoryStats.20190917.csv 44 | ThreadStats.20190917.csv 45 | TopThread-1.20190917.csv 46 | TopThread-10.20190917.csv 47 | TopThread-2.20190917.csv 48 | TopThread-3.20190917.csv 49 | TopThread-4.20190917.csv 50 | TopThread-5.20190917.csv 51 | TopThread-6.20190917.csv 52 | TopThread-7.20190917.csv 53 | TopThread-8.20190917.csv 54 | TopThread-9.20190917.csv 55 | ``` 56 | 57 | Here are some example Top4J stats.... 58 | 59 | ```bash 60 | -bash-4.1$ head ThreadStats.20190917.csv 61 | Timestamp,BlockedThreadCount,CpuUsage,MBeanCpuTime,RunnableThreadCount,SysCpuUsage,ThreadCount,TimedWaitingThreadCount,UserCpuUsage,WaitingThreadCount 62 | 2019-09-17T00:00:02.685+0100,999,0.8090,473.8873,3,0.1449,1007,2,0.6641,3 63 | 2019-09-17T00:01:02.407+0100,999,0.5729,315.9774,3,0.1210,1007,2,0.4519,3 64 | 2019-09-17T00:02:02.455+0100,999,0.6128,345.2138,3,0.1131,1007,2,0.4996,3 65 | 2019-09-17T00:03:02.450+0100,999,0.6369,357.5654,3,0.1035,1007,2,0.5334,3 66 | 2019-09-17T00:04:02.400+0100,999,0.5635,314.5569,3,0.0965,1007,2,0.4670,3 67 | 2019-09-17T00:05:02.755+0100,999,0.9344,570.6357,3,0.1718,1007,2,0.7626,3 68 | 2019-09-17T00:06:02.343+0100,999,0.5960,265.6631,3,0.0933,1007,2,0.5027,3 69 | 2019-09-17T00:07:02.400+0100,999,0.5593,314.1110,3,0.1097,1007,2,0.4496,3 70 | 2019-09-17T00:08:02.461+0100,999,0.6450,368.6486,3,0.1289,1007,2,0.5162,3 71 | ``` 72 | 73 | 74 | -------------------------------------------------------------------------------- /docs/SCREENSHOTS.md: -------------------------------------------------------------------------------- 1 | Screenshots 2 | =========== 3 | **Screenshot of Top4J top threads screen using Remote Attach command line interface:** 4 | ![Top4J Top Threads Screenshot](../images/top4j-top-threads-screenshot.png) 5 | 6 | **Screenshot of Top4J blocked threads screen using Remote Attach command line interface:** 7 | ![Top4J Top Threads Screenshot](../images/top4j-blocked-threads-screenshot.png) 8 | 9 | **Screenshot of Top4J thread stack trace screen using Remote Attach command line interface:** 10 | ![Top4J Top Threads Screenshot](../images/top4j-thread-stack-trace-screenshot.png) 11 | 12 | **Screenshot of Top4J top threads screen using -t command-line option to display more than 10 top threads:** 13 | ![Top4J Top Threads Screenshot](../images/top4j-top-threads-t-option-screenshot.png) 14 | 15 | **Screenshot of Top4J top threads screen using -I command-line option to display system threads:** 16 | ![Top4J Top Threads Screenshot](../images/top4j-top-threads-I-option-screenshot.png) 17 | 18 | -------------------------------------------------------------------------------- /docs/_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-slate -------------------------------------------------------------------------------- /images/top4j-blocked-threads-screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenAnswers/top4j/2191c1c618fba204b9566b05f56f09c8c15e1ec9/images/top4j-blocked-threads-screenshot.png -------------------------------------------------------------------------------- /images/top4j-icon-panther-style.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenAnswers/top4j/2191c1c618fba204b9566b05f56f09c8c15e1ec9/images/top4j-icon-panther-style.png -------------------------------------------------------------------------------- /images/top4j-thread-stack-trace-screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenAnswers/top4j/2191c1c618fba204b9566b05f56f09c8c15e1ec9/images/top4j-thread-stack-trace-screenshot.png -------------------------------------------------------------------------------- /images/top4j-top-threads-I-option-screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenAnswers/top4j/2191c1c618fba204b9566b05f56f09c8c15e1ec9/images/top4j-top-threads-I-option-screenshot.png -------------------------------------------------------------------------------- /images/top4j-top-threads-screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenAnswers/top4j/2191c1c618fba204b9566b05f56f09c8c15e1ec9/images/top4j-top-threads-screenshot.png -------------------------------------------------------------------------------- /images/top4j-top-threads-t-option-screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenAnswers/top4j/2191c1c618fba204b9566b05f56f09c8c15e1ec9/images/top4j-top-threads-t-option-screenshot.png -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | 4 | io.top4j 5 | top4j-parent 6 | 1.1.2-SNAPSHOT 7 | pom 8 | 9 | Top4J Parent 10 | 11 | Top4J is a lightweight, low overhead, production-ready performance analysis tool for the Java runtime environment. 12 | 13 | https://github.com/OpenAnswers/top4j 14 | 15 | 16 | 17 | The Apache License, Version 2.0 18 | http://www.apache.org/licenses/LICENSE-2.0.txt 19 | 20 | 21 | 22 | 23 | 24 | Ryan Young 25 | ryan@openanswers.co.uk 26 | Open Answers 27 | https://www.openanswers.co.uk/ 28 | 29 | 30 | 31 | 32 | UTF-8 33 | 34 | releases 35 | snapshots 36 | Releases 37 | Snapshots 38 | 39 | 40 | 41 | top4j-javaagent 42 | top4j-cli 43 | 44 | 45 | 46 | 47 | 48 | 49 | org.apache.maven.plugins 50 | maven-compiler-plugin 51 | 3.10.1 52 | 53 | 1.7 54 | 1.7 55 | 56 | 57 | 58 | org.apache.maven.plugins 59 | maven-release-plugin 60 | 2.5.3 61 | 62 | @{project.version} 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | ${repository.deploy.releases.id} 72 | ${repository.deploy.releases.name} 73 | ${repository.deploy.releases.url} 74 | 75 | 76 | ${repository.deploy.snapshots.id} 77 | ${repository.deploy.snapshots.name} 78 | ${repository.deploy.snapshots.url} 79 | 80 | 81 | 82 | scm:git:https://${SCM_USERNAME}:${SCM_PASSWORD}@github.com/OpenAnswers/top4j.git 83 | HEAD 84 | 85 | 86 | 87 | 88 | junit 89 | junit 90 | 4.13.2 91 | test 92 | 93 | 94 | 95 | -------------------------------------------------------------------------------- /top4j-cli/.gitignore: -------------------------------------------------------------------------------- 1 | .project 2 | .classpath 3 | .settings 4 | target/ 5 | */.project 6 | */.classpath 7 | */.settings 8 | */target/ 9 | pom.xml.tag 10 | pom.xml.releaseBackup 11 | pom.xml.versionsBackup 12 | pom.xml.next 13 | release.properties 14 | dependency-reduced-pom.xml 15 | buildNumber.properties 16 | .mvn/timing.properties 17 | **/top4j-stats/ 18 | 19 | # IntelliJ Stuff 20 | 21 | # User-specific stuff 22 | .idea/**/workspace.xml 23 | .idea/**/tasks.xml 24 | .idea/**/usage.statistics.xml 25 | .idea/**/dictionaries 26 | .idea/**/shelf 27 | 28 | # Generated files 29 | .idea/**/contentModel.xml 30 | 31 | # Sensitive or high-churn files 32 | .idea/**/dataSources/ 33 | .idea/**/dataSources.ids 34 | .idea/**/dataSources.local.xml 35 | .idea/**/sqlDataSources.xml 36 | .idea/**/dynamic.xml 37 | .idea/**/uiDesigner.xml 38 | .idea/**/dbnavigator.xml 39 | -------------------------------------------------------------------------------- /top4j-cli/.idea/.name: -------------------------------------------------------------------------------- 1 | top4j-cli -------------------------------------------------------------------------------- /top4j-cli/.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /top4j-cli/.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /top4j-cli/.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /top4j-cli/.idea/libraries/Maven__avalon_framework_avalon_framework_4_1_3.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /top4j-cli/.idea/libraries/Maven__classworlds_classworlds_1_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /top4j-cli/.idea/libraries/Maven__classworlds_classworlds_boot_1_0.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /top4j-cli/.idea/libraries/Maven__commons_beanutils_commons_beanutils_1_7_0.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /top4j-cli/.idea/libraries/Maven__commons_cli_commons_cli_1_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /top4j-cli/.idea/libraries/Maven__commons_collections_commons_collections_3_2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /top4j-cli/.idea/libraries/Maven__commons_io_commons_io_1_3_2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /top4j-cli/.idea/libraries/Maven__commons_lang_commons_lang_2_6.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /top4j-cli/.idea/libraries/Maven__commons_logging_commons_logging_1_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /top4j-cli/.idea/libraries/Maven__io_top4j_top4j_javaagent_0_0_1_SNAPSHOT.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /top4j-cli/.idea/libraries/Maven__javax_servlet_servlet_api_2_3.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /top4j-cli/.idea/libraries/Maven__jline_jline_2_12.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /top4j-cli/.idea/libraries/Maven__junit_junit_3_8_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /top4j-cli/.idea/libraries/Maven__log4j_log4j_1_2_12.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /top4j-cli/.idea/libraries/Maven__logkit_logkit_1_0_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /top4j-cli/.idea/libraries/Maven__org_cyclopsgroup_jcli_1_0_alpha_3.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /top4j-cli/.idea/libraries/Maven__org_cyclopsgroup_jmxterm_1_0_alpha_4.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /top4j-cli/.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 1.8.0_45 31 | 32 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /top4j-cli/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /top4j-cli/.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /top4j-cli/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | 4 | 5 | io.top4j 6 | top4j-parent 7 | 1.1.2-SNAPSHOT 8 | 9 | 10 | top4j-cli 11 | jar 12 | 13 | Top4J CLI 14 | 15 | Top4J is a lightweight, low overhead, production-ready performance analysis tool for the Java runtime environment. 16 | 17 | https://github.com/OpenAnswers/top4j 18 | 19 | 20 | 21 | UTF-8 22 | 23 | 24 | 25 | 26 | 27 | org.apache.maven.plugins 28 | maven-jar-plugin 29 | 3.3.0 30 | 31 | 32 | 33 | io.top4j.cli.Top4J 34 | 35 | 36 | 37 | 38 | 39 | org.apache.maven.plugins 40 | maven-shade-plugin 41 | 3.4.0 42 | 43 | 44 | package 45 | 46 | shade 47 | 48 | 49 | 50 | 51 | junit:junit 52 | classworlds:classworlds 53 | classworlds:classworlds-boot 54 | javax.servlet:servlet-api 55 | log4j:log4j:jar: 56 | commons-beanutils:commons-beanutils 57 | commons-collections:commons-collections 58 | commons-io:commons-io 59 | commons-logging 60 | logkit:logkit 61 | avalon-framework:avalon-framework 62 | org.cyclopsgroup:jcli 63 | com.google.guava:guava 64 | org.apache.commons:commons-collections4 65 | org.apache.commons:commons-configuration2 66 | org.apache.commons:commons-text 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | jline 79 | jline 80 | 2.14.6 81 | 82 | 83 | com.sun 84 | tools 85 | 1.7.0_79 86 | system 87 | ${java.home}/../lib/tools.jar 88 | 89 | 90 | org.cyclopsgroup 91 | jmxterm 92 | 1.0.3 93 | 94 | 95 | commons-lang 96 | commons-lang 97 | 2.6 98 | 99 | 100 | org.apache.commons 101 | commons-lang3 102 | 3.12.0 103 | 104 | 105 | commons-cli 106 | commons-cli 107 | 1.5.0 108 | 109 | 110 | io.top4j 111 | top4j-javaagent 112 | ${project.version} 113 | 114 | 115 | 116 | -------------------------------------------------------------------------------- /top4j-cli/src/main/java/io/top4j/cli/ConsoleControllerTask.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021 Open Answers Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.top4j.cli; 18 | 19 | import java.util.TimerTask; 20 | 21 | public class ConsoleControllerTask extends TimerTask { 22 | 23 | private final ConsoleController controller; 24 | 25 | public ConsoleControllerTask(ConsoleController controller) { 26 | this.controller = controller; 27 | } 28 | 29 | public void run() { 30 | this.controller.run(); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /top4j-cli/src/main/java/io/top4j/cli/DisplayConfig.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 Open Answers Ltd. https://www.openanswers.co.uk 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.top4j.cli; 18 | 19 | public class DisplayConfig { 20 | 21 | private int threadCount; 22 | private int jvmPid; 23 | private String displayName; 24 | 25 | public DisplayConfig(int threadCount, int jvmPid, String displayName) { 26 | this.threadCount = threadCount; 27 | this.jvmPid = jvmPid; 28 | this.displayName = displayName; 29 | } 30 | 31 | public int getThreadCount() { 32 | return threadCount; 33 | } 34 | 35 | public void setThreadCount(int threadCount) { 36 | this.threadCount = threadCount; 37 | } 38 | 39 | public int getJvmPid() { 40 | return jvmPid; 41 | } 42 | 43 | public void setJvmPid(int jvmPid) { 44 | this.jvmPid = jvmPid; 45 | } 46 | 47 | public String getDisplayName() { 48 | return displayName; 49 | } 50 | 51 | public void setDisplayName(String displayName) { 52 | this.displayName = displayName; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /top4j-cli/src/main/java/io/top4j/cli/UserInput.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 Open Answers Ltd. https://www.openanswers.co.uk 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.top4j.cli; 18 | 19 | import java.util.concurrent.locks.ReentrantLock; 20 | 21 | public class UserInput { 22 | 23 | private volatile String text = "t"; 24 | private volatile String screenId = "t"; 25 | private volatile boolean isDigit = false; 26 | 27 | ReentrantLock consoleLock = new ReentrantLock(); 28 | 29 | public void setText(String text) { 30 | this.text = text; 31 | } 32 | 33 | public String getText() { 34 | return text; 35 | } 36 | 37 | public boolean isDigit() { 38 | return isDigit; 39 | } 40 | 41 | public void setIsDigit(boolean isDigit) { 42 | this.isDigit = isDigit; 43 | } 44 | 45 | public String getScreenId() { 46 | return screenId; 47 | } 48 | 49 | public void setScreenId(String screenId) { 50 | this.screenId = screenId; 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /top4j-cli/src/main/java/io/top4j/cli/exception/ScreenUpdateException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 Open Answers Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.top4j.cli.exception; 18 | 19 | public class ScreenUpdateException extends RuntimeException { 20 | 21 | private static final long serialVersionUID = 1L; 22 | 23 | public ScreenUpdateException(String message) { 24 | super(message); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /top4j-cli/src/main/java/io/top4j/vm/Jdk9JavaProcess.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 Open Answers Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.top4j.vm; 18 | 19 | import com.sun.tools.attach.AttachNotSupportedException; 20 | import com.sun.tools.attach.VirtualMachine; 21 | import org.cyclopsgroup.jmxterm.JavaProcess; 22 | 23 | import java.io.IOException; 24 | import java.util.Properties; 25 | 26 | /** 27 | * JDK9 specific java process 28 | */ 29 | 30 | public class Jdk9JavaProcess implements JavaProcess { 31 | 32 | private final int id; 33 | private final String name; 34 | private String address; 35 | private static final String LOCAL_CONNECTOR_ADDRESS_PROP = 36 | "com.sun.management.jmxremote.localConnectorAddress"; 37 | 38 | public Jdk9JavaProcess(int jvmid, String displayName, String address) { 39 | this.id = jvmid; 40 | this.name = displayName; 41 | this.address = address; 42 | } 43 | 44 | @Override 45 | public String getDisplayName() { 46 | return this.name; 47 | } 48 | 49 | @Override 50 | public int getProcessId() { 51 | return this.id; 52 | } 53 | 54 | @Override 55 | public boolean isManageable() { 56 | return (address != null); 57 | } 58 | 59 | @Override 60 | public void startManagementAgent() throws IOException { 61 | 62 | if (address != null) { 63 | // management agent already started 64 | return; 65 | } 66 | 67 | // load management agent 68 | loadManagementAgent(); 69 | 70 | // failed to load or start the management agent 71 | if (address == null) { 72 | throw new IOException("Failed to start the JVM management agent"); 73 | } 74 | } 75 | 76 | @Override 77 | public String toUrl() { 78 | return address; 79 | } 80 | 81 | // load the management agent into the target VM 82 | private void loadManagementAgent() throws IOException { 83 | VirtualMachine vm; 84 | String name = String.valueOf(id); 85 | try { 86 | // attach to JVM using VirtualMachine API 87 | vm = VirtualMachine.attach(name); 88 | } catch (AttachNotSupportedException e) { 89 | IOException ioe = new IOException(e.getMessage()); 90 | ioe.initCause(e); 91 | throw ioe; 92 | } 93 | 94 | // start the JVM JMX management agent 95 | vm.startLocalManagementAgent(); 96 | 97 | // get the connector address 98 | Properties agentProps = vm.getAgentProperties(); 99 | address = (String) agentProps.get(LOCAL_CONNECTOR_ADDRESS_PROP); 100 | 101 | vm.detach(); 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /top4j-cli/src/main/java/io/top4j/vm/Jdk9JavaProcessManager.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 Open Answers Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.top4j.vm; 18 | 19 | import com.sun.tools.attach.AttachNotSupportedException; 20 | import com.sun.tools.attach.VirtualMachine; 21 | import com.sun.tools.attach.VirtualMachineDescriptor; 22 | import org.cyclopsgroup.jmxterm.JavaProcess; 23 | import org.cyclopsgroup.jmxterm.JavaProcessManager; 24 | 25 | import java.io.IOException; 26 | import java.util.*; 27 | 28 | /** 29 | * JDK9 specific java process manager 30 | */ 31 | 32 | public class Jdk9JavaProcessManager extends JavaProcessManager { 33 | 34 | private static final String LOCAL_CONNECTOR_ADDRESS_PROP = 35 | "com.sun.management.jmxremote.localConnectorAddress"; 36 | 37 | @Override 38 | public JavaProcess get(int pid) { 39 | // retrieve list of attachable Java processes 40 | Map javaProcessMap = getAttachableVMs(); 41 | // return Java process with pid process ID 42 | return javaProcessMap.get(pid); 43 | } 44 | 45 | @Override 46 | public List list() { 47 | // instantiate list of javaProcesses to return 48 | List javaProcesses = new ArrayList<>(); 49 | // retrieve list of running Java processes via VirtualMachine API 50 | List virtualMachineDescriptors = VirtualMachine.list(); 51 | String jvmid; 52 | String displayName; 53 | String address = null; 54 | int processId; 55 | for (VirtualMachineDescriptor virtualMachineDescriptor : virtualMachineDescriptors) { 56 | // get JVM ID 57 | jvmid = virtualMachineDescriptor.id(); 58 | // get JVM display name 59 | displayName = virtualMachineDescriptor.displayName(); 60 | try { 61 | // attach to JVM using VirtualMachine API 62 | VirtualMachine vm = VirtualMachine.attach(jvmid); 63 | // get JVM agent properties 64 | Properties agentProps = vm.getAgentProperties(); 65 | // get JVM JMX local connector address 66 | address = (String) agentProps.get(LOCAL_CONNECTOR_ADDRESS_PROP); 67 | // detach from JVM 68 | vm.detach(); 69 | } catch (AttachNotSupportedException e) { 70 | // not attachable 71 | } catch (IOException e) { 72 | // ignore 73 | } 74 | try { 75 | processId = Integer.parseInt(jvmid); 76 | } catch (NumberFormatException e) { 77 | // do not support JVMs where jvmid is different to PID 78 | continue; 79 | } 80 | // create new JavaProcess and add it to list of javaProcesses 81 | javaProcesses.add(new Jdk9JavaProcess(processId, displayName, address)); 82 | } 83 | // return list of attachable Java processes 84 | return javaProcesses; 85 | } 86 | 87 | /** 88 | * Get Map containing list of attachable Java processes 89 | * 90 | * @return Map A Map containing a list of attachable Java processes 91 | */ 92 | private Map getAttachableVMs() { 93 | // retrieve list of attachable Java processes 94 | List javaProcesses = list(); 95 | // instantiate new Map to store list of attachable Java processes 96 | Map javaProcessMap = new HashMap<>(); 97 | int processId; 98 | for (JavaProcess javaProcess : javaProcesses) { 99 | // get Java process ID (PID) 100 | processId = javaProcess.getProcessId(); 101 | // add Java process to javaProcessMap 102 | javaProcessMap.put(processId, javaProcess); 103 | } 104 | return javaProcessMap; 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /top4j-cli/src/main/scripts/top4j: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # top4j 4 | # 5 | # - Top4J wrapper script 6 | # 7 | # Arguments: 8 | # 9 | # 1. JVM_PID (optional): The JVM process ID to attach to 10 | # 11 | # Example Usage: 12 | # 13 | # Run the top4j wrapper script with no arguments to auto-detect running JVMs and select the appropriate JVM from a numbered list.... 14 | # 15 | # ./top4j 16 | # 17 | # Alternatively, if you alreday know the JVM PID, you can specify it on the command line.... 18 | # 19 | # ./top4j 468 20 | # 21 | # Environment Variable Prerequisites: 22 | # 23 | # JAVA_HOME Must point at your Java Development Kit installation. 24 | # 25 | 26 | JVM_PID=$1 27 | INSTALL_DIR=`dirname $BASH_SOURCE` 28 | TOP4J_JAR=`ls -t ${INSTALL_DIR}/top4j-cli-[0-9]*.[0-9]*.[0-9]*.jar | head -1` 29 | # NOTE: Override JAVA_HOME here if it's not part of the local runtime environment 30 | #JAVA_HOME=/usr/java/jdk1.8.0_60 31 | JAVA_BIN_DIR=${JAVA_HOME}/bin 32 | JAVA_LIB_DIR=${JAVA_HOME}/lib 33 | JAVA=${JAVA_BIN_DIR}/java 34 | TOOLS_JAR=${JAVA_LIB_DIR}/tools.jar 35 | 36 | # check JAVA_HOME 37 | if [[ -z ${JAVA_HOME} ]] 38 | then 39 | echo "ERROR: JAVA_HOME environment variable NOT defined." 40 | echo "HINT: A Java JDK installation is required to run this program. Please set JAVA_HOME env var to a local JDK installation location." 41 | exit 1 42 | fi 43 | 44 | # check JAVA 45 | if [[ ! -x ${JAVA} ]] 46 | then 47 | echo "ERROR: Java command not found under configured JAVA_HOME bin directory - ${JAVA_BIN_DIR}" 48 | echo "HINT: A Java JDK installation is required to run this program. Please set JAVA_HOME env var to a local JDK installation location." 49 | exit 1 50 | fi 51 | 52 | # check TOP4J_JAR 53 | if [[ ! -f ${TOP4J_JAR} ]] 54 | then 55 | echo "ERROR: Top4j jar not found under top4j INSTALL_DIR location - ${INSTALL_DIR}" 56 | exit 1 57 | fi 58 | 59 | # check TOOLS_JAR 60 | if [[ ! -f ${TOOLS_JAR} ]] 61 | then 62 | echo "ERROR: JDK tools.jar not found under JAVA_HOME lib directory - ${JAVA_LIB_DIR}." 63 | echo "HINT: A Java JDK installation is required to run this program. Please set JAVA_HOME env var to a local JDK installation location." 64 | exit 1 65 | fi 66 | 67 | 68 | # launch top4j against JVM_PID 69 | ${JAVA} -jar ${TOP4J_JAR} ${JVM_PID} 70 | 71 | -------------------------------------------------------------------------------- /top4j-cli/top4j-cli.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /top4j-javaagent/.gitignore: -------------------------------------------------------------------------------- 1 | .project 2 | .classpath 3 | .settings 4 | target/ 5 | */.project 6 | */.classpath 7 | */.settings 8 | */target/ 9 | pom.xml.tag 10 | pom.xml.releaseBackup 11 | pom.xml.versionsBackup 12 | pom.xml.next 13 | release.properties 14 | dependency-reduced-pom.xml 15 | buildNumber.properties 16 | .mvn/timing.properties 17 | **/top4j-stats/ 18 | 19 | # IntelliJ Stuff 20 | 21 | # User-specific stuff 22 | .idea/**/workspace.xml 23 | .idea/**/tasks.xml 24 | .idea/**/usage.statistics.xml 25 | .idea/**/dictionaries 26 | .idea/**/shelf 27 | 28 | # Generated files 29 | .idea/**/contentModel.xml 30 | 31 | # Sensitive or high-churn files 32 | .idea/**/dataSources/ 33 | .idea/**/dataSources.ids 34 | .idea/**/dataSources.local.xml 35 | .idea/**/sqlDataSources.xml 36 | .idea/**/dynamic.xml 37 | .idea/**/uiDesigner.xml 38 | .idea/**/dbnavigator.xml 39 | -------------------------------------------------------------------------------- /top4j-javaagent/.idea/.name: -------------------------------------------------------------------------------- 1 | top4j-javaagent 2 | -------------------------------------------------------------------------------- /top4j-javaagent/.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /top4j-javaagent/.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /top4j-javaagent/.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /top4j-javaagent/.idea/libraries/Maven__junit_junit_4_12.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /top4j-javaagent/.idea/libraries/Maven__org_hamcrest_hamcrest_core_1_3.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /top4j-javaagent/.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 1.8.0_45 31 | 32 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /top4j-javaagent/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /top4j-javaagent/.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /top4j-javaagent/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | 4 | 5 | io.top4j 6 | top4j-parent 7 | 1.1.2-SNAPSHOT 8 | 9 | 10 | top4j-javaagent 11 | jar 12 | 13 | Top4J JavaAgent 14 | 15 | Top4J is a lightweight, low overhead, production-ready performance analysis tool for the Java runtime environment. 16 | 17 | https://github.com/OpenAnswers/top4j 18 | 19 | 20 | UTF-8 21 | 22 | 23 | 24 | 25 | 26 | org.apache.maven.plugins 27 | maven-jar-plugin 28 | 3.3.0 29 | 30 | 31 | 32 | io.top4j.javaagent.controller.Agent 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /top4j-javaagent/sonar-project.properties: -------------------------------------------------------------------------------- 1 | # must be unique in a given SonarQube instance 2 | sonar.projectKey=top4j-javaagent 3 | # this is the name displayed in the SonarQube UI 4 | sonar.projectName=Top4J Java Agent 5 | sonar.projectVersion=0.0.1-SNAPSHOT 6 | 7 | # Path is relative to the sonar-project.properties file. Replace "\" by "/" on Windows. 8 | # Since SonarQube 4.2, this property is optional if sonar.modules is set. 9 | # If not set, SonarQube starts looking for source code from the directory containing 10 | # the sonar-project.properties file. 11 | sonar.sources=. 12 | 13 | # Encoding of the source code. Default is default system encoding 14 | #sonar.sourceEncoding=UTF-8 15 | -------------------------------------------------------------------------------- /top4j-javaagent/src/main/java/io/top4j/javaagent/config/Constants.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 Open Answers Ltd. https://www.openanswers.co.uk 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.top4j.javaagent.config; 18 | 19 | public final class Constants { 20 | 21 | // JMX MXBean domain name 22 | public static final String DOMAIN = "io.top4j"; 23 | 24 | // JMX MXBean JVM stats type 25 | public static final String JVM_STATS_TYPE = "JVM"; 26 | 27 | // JMX MXBean top thread stats type 28 | public static final String TOP_THREAD_STATS_TYPE = "TopThread"; 29 | 30 | // JMX MXBean blocked thread stats type 31 | public static final String BLOCKED_THREAD_STATS_TYPE = "BlockedThread"; 32 | 33 | // JMX MXBean hot method stats type 34 | public static final String HOT_METHOD_STATS_TYPE = "HotMethod"; 35 | 36 | // JMX MXBean threads stats type 37 | public static final String THREADS_STATS_TYPE = "ThreadStats"; 38 | 39 | // JMX MXBean memory stats type 40 | public static final String MEMORY_STATS_TYPE = "MemoryStats"; 41 | 42 | // JMX MXBean heap stats type 43 | public static final String HEAP_STATS_TYPE = "HeapStats"; 44 | 45 | // JMX MXBean GC stats type 46 | public static final String GC_STATS_TYPE = "GCStats"; 47 | 48 | // JMX MXBean agent type 49 | public static final String AGENT_TYPE = "Agent"; 50 | 51 | // JMX MXBean agent stats type 52 | public static final String AGENT_STATS_TYPE = "AgentStats"; 53 | 54 | // JMX MXBean stats logger type 55 | public static final String STATS_LOGGER_TYPE = "StatsLogger"; 56 | 57 | // file path separator 58 | public static final String FILE_SEPARATOR = System.getProperty("file.separator"); 59 | 60 | // default properties file name 61 | public static final String DEFAULT_PROPERTIES_FILE_NAME = "default-top4j.properties"; 62 | 63 | // properties file name 64 | public static final String PROPERTIES_FILE_NAME = "top4j.properties"; 65 | 66 | // test properties file name 67 | public static final String TEST_PROPERTIES_FILE_NAME = "top4j-test.properties"; 68 | 69 | // properties file name argument token (used to specify properties file location via agent argument) 70 | public static final String PROPERTIES_FILE_NAME_ARG = "config.file"; 71 | 72 | // 1 Mega Byte 73 | public static final int ONE_MEGA_BYTE = 1048576; 74 | 75 | private Constants() { 76 | throw new AssertionError(); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /top4j-javaagent/src/main/java/io/top4j/javaagent/controller/Agent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 Open Answers Ltd. https://www.openanswers.co.uk 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.top4j.javaagent.controller; 18 | 19 | import java.lang.instrument.Instrumentation; 20 | import java.lang.management.ManagementFactory; 21 | import java.util.logging.*; 22 | 23 | import io.top4j.javaagent.config.Configurator; 24 | 25 | import javax.management.MBeanServer; 26 | 27 | public class Agent { 28 | 29 | private static final Logger LOGGER = Logger.getLogger(Agent.class.getName()); 30 | 31 | public static void premain(String agentArgs, Instrumentation inst) { 32 | 33 | // get platform MBean server 34 | MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); 35 | 36 | // initialise configurator 37 | Configurator config = new Configurator(mbs, agentArgs); 38 | 39 | // create and start controller thread 40 | Controller controller = new Controller(config); 41 | controller.start(); 42 | 43 | LOGGER.info("Top4J: Java agent activated."); 44 | 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /top4j-javaagent/src/main/java/io/top4j/javaagent/controller/Collector.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 Open Answers Ltd. https://www.openanswers.co.uk 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.top4j.javaagent.controller; 18 | 19 | import java.lang.management.ManagementFactory; 20 | import java.util.TimerTask; 21 | 22 | import javax.management.JMX; 23 | import javax.management.MBeanServer; 24 | import javax.management.MalformedObjectNameException; 25 | import javax.management.ObjectName; 26 | 27 | import io.top4j.javaagent.config.Configurator; 28 | import io.top4j.javaagent.config.Constants; 29 | import io.top4j.javaagent.exception.MBeanAccessException; 30 | import io.top4j.javaagent.mbeans.jvm.JVMStatsMXBean; 31 | 32 | public class Collector extends TimerTask { 33 | 34 | private JVMStatsMXBean jvmStats; 35 | private boolean statsLoggerEnabled; 36 | 37 | public Collector(Configurator config) throws MBeanAccessException { 38 | 39 | this.statsLoggerEnabled = config.isStatsLoggerEnabled(); 40 | 41 | // create JVMStats objectName 42 | try { 43 | ObjectName jvmStatsObjectName = new ObjectName(Constants.DOMAIN + ":type=" + Constants.AGENT_TYPE + ",statsType=" + Constants.JVM_STATS_TYPE); 44 | 45 | // instantiate new JVMStatsMXBean proxy based on jvmStatsObjectName 46 | MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); 47 | 48 | this.jvmStats = JMX.newMBeanProxy(mbs, jvmStatsObjectName, JVMStatsMXBean.class); 49 | 50 | } catch (MalformedObjectNameException e) { 51 | throw new MBeanAccessException(e, "JMX MalformedObjectNameException: " + e.getMessage()); 52 | } 53 | 54 | } 55 | 56 | @Override 57 | public void run() { 58 | 59 | // update stats 60 | updateStats(); 61 | if (statsLoggerEnabled) { 62 | // log stats 63 | logStats(); 64 | } 65 | 66 | } 67 | 68 | private void logStats() { 69 | 70 | // log JVM stats 71 | jvmStats.log(); 72 | 73 | } 74 | 75 | private void updateStats() { 76 | 77 | // update JVM stats 78 | jvmStats.update(); 79 | 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /top4j-javaagent/src/main/java/io/top4j/javaagent/controller/Controller.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 Open Answers Ltd. https://www.openanswers.co.uk 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.top4j.javaagent.controller; 18 | 19 | import java.util.Timer; 20 | import java.util.TimerTask; 21 | import java.util.logging.Logger; 22 | 23 | import io.top4j.javaagent.config.Configurator; 24 | import io.top4j.javaagent.config.Constants; 25 | import io.top4j.javaagent.mbeans.jvm.JVMStats; 26 | import io.top4j.javaagent.messaging.LoggerQueue; 27 | import io.top4j.javaagent.utils.MBeanHelper; 28 | 29 | import javax.management.MBeanServer; 30 | 31 | public final class Controller extends Thread { 32 | 33 | private LoggerQueue loggerQueue; 34 | private Configurator config; 35 | private long interval; 36 | private boolean statsLoggerEnabled; 37 | 38 | private static final Logger LOGGER = Logger.getLogger(LoggerThread.class.getName()); 39 | 40 | /** 41 | * Create a polling thread to track JVM stats. 42 | * @param config the Top4J JavaAgent configuration 43 | */ 44 | public Controller(Configurator config) { 45 | super("Top4J Monitor"); 46 | this.config = config; 47 | this.interval = Long.parseLong(config.get("collector.poll.frequency")); 48 | this.statsLoggerEnabled = config.isStatsLoggerEnabled(); 49 | if (statsLoggerEnabled) { 50 | // create LoggerQueue 51 | this.loggerQueue = new LoggerQueue(100); 52 | } 53 | 54 | try { 55 | // instantiate new MBeanHelper used to access JVMStats MBean attributes and operations 56 | MBeanHelper jvmStatsMBeanHelper = new MBeanHelper(Constants.AGENT_TYPE, Constants.JVM_STATS_TYPE); 57 | // instantiate new JVMStats MBean 58 | JVMStats jvmStatsMBean = new JVMStats(config, loggerQueue); 59 | // register JVMStats MBean with MBean server 60 | jvmStatsMBeanHelper.registerMBean(jvmStatsMBean); 61 | 62 | } catch (Exception e) { 63 | LOGGER.severe("Failed to initialise JVM stats MBean due to " + e.getMessage()); 64 | } 65 | 66 | setDaemon(true); 67 | } 68 | 69 | /** 70 | * Run the thread until interrupted. 71 | */ 72 | @Override 73 | public void run() { 74 | 75 | if (statsLoggerEnabled) { 76 | try { 77 | // create and start logger thread 78 | LoggerThread statsLogger = new LoggerThread(config, loggerQueue); 79 | statsLogger.start(); 80 | } catch (Exception e) { 81 | LOGGER.severe("Failed to initialise LoggerThread due to " + e.getMessage()); 82 | } 83 | } 84 | 85 | try { 86 | // create new TimerTask to run JVM stats collector 87 | TimerTask collector = new Collector(config); 88 | // create new Timer to schedule JVM stats collector 89 | Timer timer = new Timer("Top4J Stats Collector", true); 90 | // run JVM stats collector at fixed interval 91 | timer.scheduleAtFixedRate(collector, 0, interval); 92 | } catch (Exception e) { 93 | LOGGER.severe("Failed to initialise stats Collector thread due to " + e.getMessage()); 94 | } 95 | 96 | } 97 | 98 | } 99 | -------------------------------------------------------------------------------- /top4j-javaagent/src/main/java/io/top4j/javaagent/controller/LoggerThread.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 Open Answers Ltd. https://www.openanswers.co.uk 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.top4j.javaagent.controller; 18 | 19 | import io.top4j.javaagent.config.Configurator; 20 | import io.top4j.javaagent.config.Constants; 21 | import io.top4j.javaagent.exception.MBeanAccessException; 22 | import io.top4j.javaagent.mbeans.logger.StatsLoggerMXBean; 23 | import io.top4j.javaagent.messaging.LoggerQueue; 24 | 25 | import javax.management.JMX; 26 | import javax.management.MBeanServer; 27 | import javax.management.MalformedObjectNameException; 28 | import javax.management.ObjectName; 29 | import java.lang.management.ManagementFactory; 30 | import java.util.logging.Logger; 31 | 32 | public class LoggerThread extends Thread { 33 | 34 | private LoggerQueue loggerQueue; 35 | private long interval; 36 | private boolean statsLoggerEnabled; 37 | private StatsLoggerMXBean statsLogger; 38 | 39 | private static final Logger LOGGER = Logger.getLogger(LoggerThread.class.getName()); 40 | 41 | public LoggerThread(Configurator config, LoggerQueue loggerQueue) throws Exception { 42 | 43 | super("Top4J Stats LoggerThread"); 44 | LOGGER.fine("Initialising Top4J Stats LoggerThread...."); 45 | this.loggerQueue = loggerQueue; 46 | this.interval = Long.parseLong(config.get("stats.logger.poll.timeout")); 47 | this.statsLoggerEnabled = config.isStatsLoggerEnabled(); 48 | MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); 49 | // create StatsLogger objectName 50 | ObjectName statsLoggerObjectName = null; 51 | try { 52 | statsLoggerObjectName = new ObjectName(Constants.DOMAIN + ":" + "type=" + Constants.AGENT_TYPE + ",statsType=" + Constants.STATS_LOGGER_TYPE); 53 | } catch (MalformedObjectNameException e) { 54 | throw new MBeanAccessException(e, "JMX MalformedObjectNameException: " + e.getMessage()); 55 | } 56 | // instantiate new statsLoggerMXBean proxy based on statsLoggerObjectName 57 | this.statsLogger = JMX.newMBeanProxy(mbs, statsLoggerObjectName, StatsLoggerMXBean.class); 58 | setDaemon(true); 59 | } 60 | 61 | /** 62 | * Run the thread until interrupted. 63 | */ 64 | @Override 65 | public void run() { 66 | while (!isInterrupted()) { 67 | // poll loggerQueue for log stats notification 68 | String notification = loggerQueue.poll(interval); 69 | if (notification != null && statsLoggerEnabled) { 70 | // log JVM stats 71 | statsLogger.update(); 72 | } 73 | } 74 | } 75 | 76 | } 77 | -------------------------------------------------------------------------------- /top4j-javaagent/src/main/java/io/top4j/javaagent/exception/MBeanAccessException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 Open Answers Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.top4j.javaagent.exception; 18 | 19 | import javax.management.MBeanException; 20 | 21 | public class MBeanAccessException extends MBeanException { 22 | 23 | private static final long serialVersionUID = 1L; 24 | 25 | public MBeanAccessException(Exception e) { 26 | super(e); 27 | } 28 | 29 | public MBeanAccessException(Exception e, String message) { 30 | super(e, message); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /top4j-javaagent/src/main/java/io/top4j/javaagent/exception/MBeanDiscoveryException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 Open Answers Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.top4j.javaagent.exception; 18 | 19 | public class MBeanDiscoveryException extends IllegalStateException { 20 | 21 | private static final long serialVersionUID = 1L; 22 | 23 | public MBeanDiscoveryException(String message) { 24 | super(message); 25 | } 26 | 27 | public MBeanDiscoveryException(String message, Throwable cause) { 28 | super(message, cause); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /top4j-javaagent/src/main/java/io/top4j/javaagent/exception/MBeanInitException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 Open Answers Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.top4j.javaagent.exception; 18 | 19 | import javax.management.MBeanRegistrationException; 20 | 21 | public class MBeanInitException extends MBeanRegistrationException { 22 | 23 | private static final long serialVersionUID = 1L; 24 | 25 | public MBeanInitException(Exception e) { 26 | super(e); 27 | } 28 | 29 | public MBeanInitException(Exception e, String message) { 30 | super(e, message); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /top4j-javaagent/src/main/java/io/top4j/javaagent/exception/MBeanRuntimeException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 Open Answers Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.top4j.javaagent.exception; 18 | 19 | import javax.management.MBeanException; 20 | 21 | public class MBeanRuntimeException extends MBeanException { 22 | 23 | private static final long serialVersionUID = 1L; 24 | 25 | public MBeanRuntimeException(Exception e) { 26 | super(e); 27 | } 28 | 29 | public MBeanRuntimeException(Exception e, String message) { 30 | super(e, message); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /top4j-javaagent/src/main/java/io/top4j/javaagent/listener/CollectionListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 Open Answers Ltd. https://www.openanswers.co.uk 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.top4j.javaagent.listener; 18 | 19 | import java.lang.management.MemoryNotificationInfo; 20 | import java.util.logging.Logger; 21 | 22 | import javax.management.MBeanServerConnection; 23 | import javax.management.Notification; 24 | import javax.management.openmbean.CompositeData; 25 | 26 | import io.top4j.javaagent.exception.MBeanInitException; 27 | import io.top4j.javaagent.mbeans.jvm.gc.GarbageCollectorMXBeanHelper; 28 | import io.top4j.javaagent.mbeans.jvm.memory.MemoryPoolMXBeanHelper; 29 | import io.top4j.javaagent.mbeans.jvm.memory.MemoryPoolUsageTracker; 30 | 31 | public class CollectionListener implements javax.management.NotificationListener { 32 | 33 | private GarbageCollectorMXBeanHelper gcMXBeanHelper; 34 | private MemoryPoolUsageTracker nurseryPoolUsageTracker; 35 | private MemoryPoolUsageTracker survivorPoolUsageTracker; 36 | private MemoryPoolUsageTracker tenuredPoolUsageTracker; 37 | private String survivorPoolName; 38 | private String tenuredPoolName; 39 | 40 | private static final Logger LOGGER = Logger.getLogger(CollectionListener.class.getName()); 41 | 42 | public CollectionListener(MBeanServerConnection mbsc, 43 | MemoryPoolUsageTracker nurseryPoolUsageTracker, 44 | MemoryPoolUsageTracker survivorPoolUsageTracker, 45 | MemoryPoolUsageTracker tenuredPoolUsageTracker) throws Exception { 46 | 47 | this.nurseryPoolUsageTracker = nurseryPoolUsageTracker; 48 | this.survivorPoolUsageTracker = survivorPoolUsageTracker; 49 | this.tenuredPoolUsageTracker = tenuredPoolUsageTracker; 50 | 51 | // instantiate new MemoryPoolMXBeanHelper 52 | MemoryPoolMXBeanHelper memoryPoolMxBeanHelper = new MemoryPoolMXBeanHelper(mbsc); 53 | 54 | // instantiate new GarbageCollectorMXBeanHelper 55 | try { 56 | this.gcMXBeanHelper = new GarbageCollectorMXBeanHelper(mbsc); 57 | } catch (Exception e) { 58 | throw new MBeanInitException(e, "Failed to initialise Collection Listener due to: " + e.getMessage()); 59 | } 60 | 61 | // get survivor pool name 62 | this.survivorPoolName = memoryPoolMxBeanHelper.getSurvivorSpacePoolName(); 63 | 64 | // get tenured pool name 65 | this.tenuredPoolName = memoryPoolMxBeanHelper.getTenuredPoolName(); 66 | 67 | } 68 | 69 | @Override 70 | public void handleNotification(Notification notification, Object handback) { 71 | 72 | String notifType = notification.getType(); 73 | if (notifType.equals(MemoryNotificationInfo.MEMORY_THRESHOLD_EXCEEDED) || 74 | notifType.equals(MemoryNotificationInfo.MEMORY_COLLECTION_THRESHOLD_EXCEEDED)) { 75 | LOGGER.finer("MEMORY_THRESHOLD_EXCEEDED"); 76 | 77 | // retrieve the memory notification information 78 | CompositeData cd = (CompositeData) notification.getUserData(); 79 | MemoryNotificationInfo info = MemoryNotificationInfo.from(cd); 80 | String poolName = info.getPoolName(); 81 | 82 | if (poolName.equals(survivorPoolName)) { 83 | 84 | try { 85 | LOGGER.finer("Collection Listener Nursery GC Count = " + gcMXBeanHelper.getNurseryGCCount()); 86 | } catch (Exception e) { 87 | LOGGER.fine("Unable to retrieve Nursery GC Count"); 88 | } 89 | // update nursery pool usage tracker 90 | nurseryPoolUsageTracker.update(); 91 | LOGGER.finer("Collection Listener Nursery Pool Usage = " + nurseryPoolUsageTracker.getMemoryPoolIntervalUsage()); 92 | 93 | try { 94 | LOGGER.finer("Collection Listener Survivor GC Count = " + gcMXBeanHelper.getNurseryGCCount()); 95 | } catch (Exception e) { 96 | LOGGER.fine("Unable to retrieve Survivor GC Count"); 97 | } 98 | // update survivor pool usage tracker 99 | survivorPoolUsageTracker.update(); 100 | LOGGER.finer("Collection Listener Survivor Pool Usage = " + survivorPoolUsageTracker.getMemoryPoolIntervalUsage()); 101 | 102 | } 103 | 104 | if (poolName.equals(tenuredPoolName)) { 105 | 106 | try { 107 | LOGGER.finer("Collection Listener Tenured GC Count = " + gcMXBeanHelper.getTenuredGCCount()); 108 | } catch (Exception e) { 109 | LOGGER.fine("Unable to retrieve Tenured GC Count"); 110 | } 111 | // update tenured pool usage tracker 112 | tenuredPoolUsageTracker.update(); 113 | LOGGER.finer("Tenured Pool Usage = " + tenuredPoolUsageTracker.getMemoryPoolIntervalUsage()); 114 | 115 | } 116 | 117 | } 118 | 119 | } 120 | 121 | } 122 | -------------------------------------------------------------------------------- /top4j-javaagent/src/main/java/io/top4j/javaagent/mbeans/StatsMXBean.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 Open Answers Ltd. https://www.openanswers.co.uk 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.top4j.javaagent.mbeans; 18 | 19 | /** 20 | * Base stats MBean used to define MBean attributes and operations common to all Top4J MBeans. 21 | */ 22 | public interface StatsMXBean { 23 | 24 | /** 25 | ** Update MBean attributes with latest data. 26 | */ 27 | void update(); 28 | 29 | /** 30 | * Sets the amount of CPU time in milliseconds consumed by the MBean update() operation per invocation. 31 | * @param mBeanCpuTime the amount of CPU time in milliseconds 32 | */ 33 | void setMBeanCpuTime(double mBeanCpuTime); 34 | 35 | /** 36 | * Returns the amount of CPU time in milliseconds consumed by the MBean update() operation per invocation. 37 | * @return the amount of CPU time in milliseconds 38 | */ 39 | double getMBeanCpuTime(); 40 | 41 | /** 42 | * Sets whether the MBean is enabled (true) or disabled (false). 43 | *

44 | * Disabled MBeans will no longer receive updates via the MBean update() operation or the Top4J Java Agent stats update process. 45 | * An MBean will be marked as disabled if the update() operation encounters an unexpected exception. 46 | * @param enabled whether the MBean is enabled (true) or disabled (false). 47 | */ 48 | void setEnabled(boolean enabled); 49 | 50 | /** 51 | * Returns whether the MBean is enabled (true) or disabled (false). 52 | *

53 | * Disabled MBeans will no longer receive updates via the MBean update() operation or the Top4J Java Agent stats update process. 54 | * @return whether the MBean is enabled (true) or disabled (false) 55 | */ 56 | boolean getEnabled(); 57 | 58 | /** 59 | * Sets the MBean failure reason. 60 | * If the update() operation encounters an unexpected exception the failure reason will be stored within the FailureReason MBean attribute. 61 | * @param failureReason the failure reason 62 | */ 63 | void setFailureReason(String failureReason); 64 | 65 | /** 66 | * Returns the MBean failure reason. 67 | * If the update() operation encounters an unexpected exception the failure reason will be stored within the FailureReason MBean attribute. 68 | * @return the failure reason 69 | */ 70 | String getFailureReason(); 71 | 72 | } 73 | -------------------------------------------------------------------------------- /top4j-javaagent/src/main/java/io/top4j/javaagent/mbeans/agent/AgentMXBean.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 Open Answers Ltd. https://www.openanswers.co.uk 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.top4j.javaagent.mbeans.agent; 18 | 19 | public interface AgentMXBean { 20 | 21 | void stop(); 22 | 23 | void start(); 24 | 25 | String setStatus(String status); 26 | 27 | String getStatus(); 28 | 29 | } 30 | -------------------------------------------------------------------------------- /top4j-javaagent/src/main/java/io/top4j/javaagent/mbeans/agent/AgentStatsMXBean.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 Open Answers Ltd. https://www.openanswers.co.uk 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.top4j.javaagent.mbeans.agent; 18 | 19 | import io.top4j.javaagent.mbeans.StatsMXBean; 20 | 21 | /** 22 | * Used to store and expose stats relating to the Top4J JavaAgent run-time. 23 | */ 24 | 25 | public interface AgentStatsMXBean extends StatsMXBean { 26 | 27 | /** 28 | * Sets the amount of CPU time in milliseconds consumed by all MBean update() operations per invocation. 29 | * @param cpuTime CPU time in milliseconds 30 | */ 31 | void setAgentCpuTime(double cpuTime); 32 | 33 | /** 34 | * Returns the amount of CPU time in milliseconds consumed by all MBean update() operations per invocation. 35 | * @return the CPU time in milliseconds 36 | */ 37 | double getAgentCpuTime(); 38 | 39 | /** 40 | * Sets the percentage CPU utilisation of the Top4J JavaAgent background threads. 41 | * @param cpuUtil CPU utilisation as a percentage of wall clock time 42 | */ 43 | void setAgentCpuUtil(double cpuUtil); 44 | 45 | /** 46 | * Returns the percentage CPU utilisation of the Top4J JavaAgent background threads. 47 | * @return CPU utilisation as a percentage of wall clock time 48 | */ 49 | double getAgentCpuUtil(); 50 | 51 | /** 52 | * Sets the number of Top4J JavaAgent stats update iterations since the JavaAgent was enabled. 53 | * @param iterations the number of iterations 54 | */ 55 | void setIterations(long iterations); 56 | 57 | /** 58 | * Returns the number of Top4J JavaAgent stats update iterations since the JavaAgent was enabled. 59 | * @return the number of iterations 60 | */ 61 | long getIterations(); 62 | 63 | } 64 | -------------------------------------------------------------------------------- /top4j-javaagent/src/main/java/io/top4j/javaagent/mbeans/jvm/JVMStatsMXBean.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 Open Answers Ltd. https://www.openanswers.co.uk 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.top4j.javaagent.mbeans.jvm; 18 | 19 | import io.top4j.javaagent.mbeans.StatsMXBean; 20 | 21 | public interface JVMStatsMXBean extends StatsMXBean { 22 | 23 | void log(); 24 | 25 | } 26 | -------------------------------------------------------------------------------- /top4j-javaagent/src/main/java/io/top4j/javaagent/mbeans/jvm/gc/CollectionUsageListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 Open Answers Ltd. https://www.openanswers.co.uk 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.top4j.javaagent.mbeans.jvm.gc; 18 | 19 | import java.lang.management.MemoryNotificationInfo; 20 | import java.util.logging.Logger; 21 | 22 | import javax.management.MBeanServerConnection; 23 | import javax.management.Notification; 24 | 25 | import io.top4j.javaagent.exception.MBeanInitException; 26 | import io.top4j.javaagent.mbeans.jvm.memory.MemoryPoolMXBeanHelper; 27 | import io.top4j.javaagent.mbeans.jvm.memory.MemorySurvivorBean; 28 | 29 | public class CollectionUsageListener implements javax.management.NotificationListener { 30 | 31 | private MemoryPoolMXBeanHelper memoryPoolMxBeanHelper; 32 | private GarbageCollectorMXBeanHelper gcMXBeanHelper; 33 | private MemorySurvivorBean memorySurvivor; 34 | 35 | private static final Logger LOGGER = Logger.getLogger(CollectionUsageListener.class.getName()); 36 | 37 | public CollectionUsageListener(MBeanServerConnection mbsc, MemorySurvivorBean memorySurvivor) throws Exception { 38 | 39 | this.memorySurvivor = memorySurvivor; 40 | 41 | // instantiate new MemoryPoolMXBeanHelper 42 | try { 43 | this.memoryPoolMxBeanHelper = new MemoryPoolMXBeanHelper(mbsc); 44 | } catch (Exception e) { 45 | throw new MBeanInitException(e, "Failed to initialise Collection Usage Listener due to: " + e.getMessage()); 46 | } 47 | 48 | // instantiate new GarbageCollectorMXBeanHelper 49 | try { 50 | this.gcMXBeanHelper = new GarbageCollectorMXBeanHelper(mbsc); 51 | } catch (Exception e) { 52 | throw new MBeanInitException(e, "Failed to initialise Collection Usage Listener due to: " + e.getMessage()); 53 | } 54 | } 55 | 56 | @Override 57 | public void handleNotification(Notification notification, Object handback) { 58 | 59 | String notifType = notification.getType(); 60 | if (notifType.equals(MemoryNotificationInfo.MEMORY_COLLECTION_THRESHOLD_EXCEEDED)) { 61 | LOGGER.fine("MEMORY_COLLECTION_THRESHOLD_EXCEEDED"); 62 | long survivorCollectionUsed = 0; 63 | try { 64 | survivorCollectionUsed = memoryPoolMxBeanHelper.getSurvivorCollectionUsed(); 65 | } catch (Exception e) { 66 | LOGGER.fine("Unable to retrieve Survivor Collection Used."); 67 | } 68 | memorySurvivor.addSurvivors(survivorCollectionUsed); 69 | LOGGER.fine("Survivor Collection Used = " + Long.valueOf(survivorCollectionUsed).toString()); 70 | try { 71 | LOGGER.fine("Survivor GC Count = " + gcMXBeanHelper.getNurseryGCCount()); 72 | } catch (Exception e) { 73 | LOGGER.fine("Unable to retrieve Survivor GC Count."); 74 | } 75 | } 76 | 77 | } 78 | 79 | } 80 | -------------------------------------------------------------------------------- /top4j-javaagent/src/main/java/io/top4j/javaagent/mbeans/jvm/gc/GCOverhead.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 Open Answers Ltd. https://www.openanswers.co.uk 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.top4j.javaagent.mbeans.jvm.gc; 18 | 19 | import io.top4j.javaagent.exception.MBeanInitException; 20 | 21 | import javax.management.MBeanServerConnection; 22 | import java.util.logging.Logger; 23 | 24 | public class GCOverhead { 25 | 26 | volatile private double gcOverhead; 27 | private GCTimeBean gcTimeBean; 28 | private GarbageCollectorMXBeanHelper gcMXBeanHelper; 29 | 30 | private static final Logger LOGGER = Logger.getLogger(GCOverhead.class.getName()); 31 | 32 | public GCOverhead(MBeanServerConnection mbsc) throws Exception { 33 | 34 | LOGGER.fine("Initialising GC Overhead...."); 35 | 36 | // instantiate new GarbageCollectorMXBeanHelper and GCTimeBean 37 | try { 38 | this.gcMXBeanHelper = new GarbageCollectorMXBeanHelper(mbsc); 39 | this.gcTimeBean = new GCTimeBean(mbsc); 40 | } catch (Exception e) { 41 | throw new MBeanInitException(e, "Failed to initialise GC Overhead stats collector due to: " + e.getMessage()); 42 | } 43 | 44 | } 45 | 46 | /** 47 | * Update GC Overhead. 48 | */ 49 | public void update() { 50 | 51 | long systemTime = System.currentTimeMillis(); 52 | long gcTime; 53 | long intervalGCTime; 54 | long intervalSystemTime; 55 | 56 | gcTime = gcMXBeanHelper.getGCTime(); 57 | intervalGCTime = gcTime - gcTimeBean.getLastGCTime(); 58 | intervalSystemTime = systemTime - gcTimeBean.getLastSystemTime(); 59 | LOGGER.finer("GC Overhead Interval GC Time = " + intervalGCTime); 60 | LOGGER.finer("GC Overhead Interval System Time = " + intervalSystemTime); 61 | gcOverhead = calculateGCOverhead(intervalGCTime, intervalSystemTime); 62 | LOGGER.fine("GC Overhead = " + gcOverhead + "%"); 63 | gcTimeBean.setLastGCTime(gcTime); 64 | gcTimeBean.setLastSystemTime(systemTime); 65 | 66 | } 67 | 68 | public double getGcOverhead() { 69 | return gcOverhead; 70 | } 71 | 72 | public void setGcOverhead(double gcOverhead) { 73 | this.gcOverhead = gcOverhead; 74 | } 75 | 76 | private double calculateGCOverhead(long intervalGCTime, long intervalSystemTime) { 77 | 78 | return ((double) intervalGCTime / intervalSystemTime) * 100; 79 | 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /top4j-javaagent/src/main/java/io/top4j/javaagent/mbeans/jvm/gc/GCPauseTime.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 Open Answers Ltd. https://www.openanswers.co.uk 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.top4j.javaagent.mbeans.jvm.gc; 18 | 19 | import io.top4j.javaagent.exception.MBeanInitException; 20 | 21 | import javax.management.MBeanServerConnection; 22 | import java.util.logging.Logger; 23 | 24 | public class GCPauseTime { 25 | 26 | volatile private double meanNurseryGCTime; 27 | volatile private double meanTenuredGCTime; 28 | private GCTimeBean gcTimeBean; 29 | private GarbageCollectorMXBeanHelper gcMXBeanHelper; 30 | 31 | private static final Logger LOGGER = Logger.getLogger(GCPauseTime.class.getName()); 32 | 33 | public GCPauseTime(MBeanServerConnection mbsc) throws Exception { 34 | 35 | LOGGER.fine("Initialising GC Pause Time...."); 36 | 37 | // instantiate new GarbageCollectorMXBeanHelper and GCTimeBean 38 | try { 39 | this.gcMXBeanHelper = new GarbageCollectorMXBeanHelper(mbsc); 40 | this.gcTimeBean = new GCTimeBean(mbsc); 41 | } catch (Exception e) { 42 | throw new MBeanInitException(e, "Failed to initialise GC Pause Time stats collector due to: " + e.getMessage()); 43 | } 44 | 45 | } 46 | 47 | /** 48 | * Update GC Pause Time. 49 | */ 50 | public void update() { 51 | 52 | long nurseryGCCount = 0; 53 | long nurseryGCTime = 0; 54 | long tenuredGCCount = 0; 55 | long tenuredGCTime = 0; 56 | long intervalNurseryGCTime; 57 | long intervalNurseryGCCount; 58 | long intervalTenuredGCTime; 59 | long intervalTenuredGCCount; 60 | 61 | try { 62 | // calculate mean nursery GC pause time 63 | nurseryGCTime = gcMXBeanHelper.getNurseryGCTime(); 64 | intervalNurseryGCTime = nurseryGCTime - gcTimeBean.getLastNurseryGCTime(); 65 | nurseryGCCount = gcMXBeanHelper.getNurseryGCCount(); 66 | intervalNurseryGCCount = nurseryGCCount - gcTimeBean.getLastNurseryGCCount(); 67 | if (intervalNurseryGCCount > 0) { 68 | meanNurseryGCTime = (double) intervalNurseryGCTime / intervalNurseryGCCount; 69 | } 70 | LOGGER.fine("Mean Nursery GC Time = " + meanNurseryGCTime + "ms"); 71 | } catch (Exception e) { 72 | LOGGER.fine("WARNING: Unable to update nursery GC pause time due to: " + e.getMessage()); 73 | } 74 | gcTimeBean.setLastNurseryGCTime(nurseryGCTime); 75 | gcTimeBean.setLastNurseryGCCount(nurseryGCCount); 76 | 77 | try { 78 | // calculate mean tenured GC pause time 79 | tenuredGCTime = gcMXBeanHelper.getTenuredGCTime(); 80 | intervalTenuredGCTime = tenuredGCTime - gcTimeBean.getLastTenuredGCTime(); 81 | tenuredGCCount = gcMXBeanHelper.getTenuredGCCount(); 82 | intervalTenuredGCCount = tenuredGCCount - gcTimeBean.getLastTenuredGCCount(); 83 | if (intervalTenuredGCCount > 0) { 84 | meanTenuredGCTime = (double) intervalTenuredGCTime / intervalTenuredGCCount; 85 | } 86 | LOGGER.fine("Mean Tenured GC Time = " + meanTenuredGCTime + "ms"); 87 | } catch (Exception e) { 88 | LOGGER.fine("WARNING: Unable to update tenured GC pause time due to: " + e.getMessage()); 89 | } 90 | gcTimeBean.setLastTenuredGCTime(tenuredGCTime); 91 | gcTimeBean.setLastTenuredGCCount(tenuredGCCount); 92 | 93 | } 94 | 95 | public double getMeanNurseryGCTime() { 96 | return meanNurseryGCTime; 97 | } 98 | 99 | public void setMeanNurseryGCTime(double meanNurseryGCTime) { 100 | this.meanNurseryGCTime = meanNurseryGCTime; 101 | } 102 | 103 | public double getMeanTenuredGCTime() { 104 | return meanTenuredGCTime; 105 | } 106 | 107 | public void setMeanTenuredGCTime(double meanTenuredGCTime) { 108 | this.meanTenuredGCTime = meanTenuredGCTime; 109 | } 110 | 111 | } 112 | -------------------------------------------------------------------------------- /top4j-javaagent/src/main/java/io/top4j/javaagent/mbeans/jvm/gc/GCStats.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 Open Answers Ltd. https://www.openanswers.co.uk 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.top4j.javaagent.mbeans.jvm.gc; 18 | 19 | import io.top4j.javaagent.profiler.CpuTime; 20 | 21 | import javax.management.MBeanServerConnection; 22 | import java.util.logging.*; 23 | 24 | 25 | public class GCStats implements GCStatsMXBean { 26 | 27 | private GCOverhead gcOverhead; 28 | private GCPauseTime gcPauseTime; 29 | private CpuTime cpuTime = new CpuTime(); 30 | private double mBeanCpuTime; 31 | private boolean enabled = true; 32 | private String failureReason; 33 | 34 | private static final Logger LOGGER = Logger.getLogger(GCStats.class.getName()); 35 | 36 | public GCStats(MBeanServerConnection mbsc) throws Exception { 37 | 38 | LOGGER.fine("Initialising GC stats...."); 39 | 40 | // instantiate new GC Overhead 41 | GCOverhead gcOverhead = new GCOverhead(mbsc); 42 | 43 | // instantiate new GC Pause Time 44 | GCPauseTime gcPauseTime = new GCPauseTime(mbsc); 45 | 46 | this.gcOverhead = gcOverhead; 47 | this.gcPauseTime = gcPauseTime; 48 | 49 | } 50 | 51 | /** 52 | * Update GC stats. 53 | */ 54 | public synchronized void update() { 55 | 56 | if (enabled) { 57 | try { 58 | // update GC stats 59 | updateGCStats(); 60 | } catch (Exception e) { 61 | // something went wrong - record failure reason and disable any further updates 62 | this.failureReason = e.getMessage(); 63 | this.enabled = false; 64 | LOGGER.severe("TOP4J ERROR: Failed to update GCStats MBean due to: " + e.getMessage()); 65 | LOGGER.severe("TOP4J ERROR: Further GCStats MBean updates will be disabled from now on."); 66 | } 67 | } 68 | 69 | } 70 | 71 | private synchronized void updateGCStats() { 72 | 73 | // initialise thread CPU timer 74 | cpuTime.init(); 75 | 76 | LOGGER.fine("Updating GC stats...."); 77 | 78 | // update GC Overhead 79 | gcOverhead.update(); 80 | 81 | // update GC pause time stats 82 | gcPauseTime.update(); 83 | 84 | // update GC stats CPU time 85 | mBeanCpuTime = cpuTime.getMillis(); 86 | 87 | } 88 | 89 | @Override 90 | public void setMBeanCpuTime(double agentCpuTime) { 91 | this.mBeanCpuTime = agentCpuTime; 92 | } 93 | 94 | @Override 95 | public double getMBeanCpuTime() { 96 | return mBeanCpuTime; 97 | } 98 | 99 | @Override 100 | public void setEnabled(boolean enabled) { 101 | this.enabled = enabled; 102 | } 103 | 104 | @Override 105 | public boolean getEnabled() { 106 | return this.enabled; 107 | } 108 | 109 | @Override 110 | public void setFailureReason(String failureReason) { 111 | this.failureReason = failureReason; 112 | } 113 | 114 | @Override 115 | public String getFailureReason() { 116 | return this.failureReason; 117 | } 118 | 119 | @Override 120 | public void setGcOverhead(double gcOverhead) { 121 | this.gcOverhead.setGcOverhead(gcOverhead); 122 | 123 | } 124 | 125 | @Override 126 | public double getGcOverhead() { 127 | return this.gcOverhead.getGcOverhead(); 128 | } 129 | 130 | @Override 131 | public void setMeanNurseryGCTime(double meanNurseryGCTime) { 132 | this.gcPauseTime.setMeanNurseryGCTime(meanNurseryGCTime); 133 | } 134 | 135 | @Override 136 | public double getMeanNurseryGCTime() { 137 | return this.gcPauseTime.getMeanNurseryGCTime(); 138 | } 139 | 140 | @Override 141 | public void setMeanTenuredGCTime(double meanTenuredGCTime) { 142 | gcPauseTime.setMeanTenuredGCTime(meanTenuredGCTime); 143 | } 144 | 145 | @Override 146 | public double getMeanTenuredGCTime() { 147 | return this.gcPauseTime.getMeanTenuredGCTime(); 148 | } 149 | 150 | } 151 | -------------------------------------------------------------------------------- /top4j-javaagent/src/main/java/io/top4j/javaagent/mbeans/jvm/gc/GCStatsMXBean.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 Open Answers Ltd. https://www.openanswers.co.uk 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.top4j.javaagent.mbeans.jvm.gc; 18 | 19 | import io.top4j.javaagent.mbeans.StatsMXBean; 20 | 21 | /** 22 | * Used to store and expose stats relating to the performance of the JVM Garbage Collector. 23 | */ 24 | 25 | public interface GCStatsMXBean extends StatsMXBean { 26 | 27 | /** 28 | * Sets the GC overhead which is calculated as the percentage of real time (wall clock time) the JVM spends in garbage collection. 29 | *

30 | * Only stop-the-world garbage collection pauses contribute to the GC overhead. This, therefore, equates to the percentage of real time 31 | * that the application is stopped whilst garbage collection takes place. This is a key performance indicator of the impact of garbage collection 32 | * on a running Java application. A high GC overhead overhead can lead to poor application performance as there is less time available to process 33 | * application tasks and application threads can be blocked waiting to allocate memory (i.e. create objects). 34 | * @param gcOverhead the GC overhead 35 | */ 36 | void setGcOverhead(double gcOverhead); 37 | 38 | /** 39 | * Returns the GC overhead which is calculated as the percentage of real time (wall clock time) the JVM spends in garbage collection. 40 | *

41 | * Only stop-the-world garbage collection pauses contribute to the GC overhead. This, therefore, equates to the percentage of real time 42 | * that the application is stopped whilst garbage collection takes place. This is a key performance indicator of the impact of garbage collection 43 | * on a running Java application. A high GC overhead overhead can lead to poor application performance as there is less time available to process 44 | * application tasks and application threads can be blocked waiting to allocate memory (i.e. create objects). 45 | * @return the GC overhead 46 | */ 47 | double getGcOverhead(); 48 | 49 | /** 50 | * Sets the mean time in milliseconds spent during a single nursery or eden or new stop-the-world GC event during the last iteration. 51 | * This time is not available for application processing and should therefore be kept to a minimum. 52 | * @param meanNurseryGCTime the mean nursery GC time in milliseconds 53 | */ 54 | void setMeanNurseryGCTime(double meanNurseryGCTime); 55 | 56 | /** 57 | * Returns the mean time in milliseconds spent during a single nursery or eden or new stop-the-world GC event during the last iteration. 58 | * This time is not available for application processing and should therefore be kept to a minimum. 59 | * @return the mean nursery GC time in milliseconds 60 | */ 61 | double getMeanNurseryGCTime(); 62 | 63 | /** 64 | * Sets the mean time in milliseconds spent during a single tenured or full or old stop-the-world GC event during the last iteration. 65 | * This time is not available for application processing and should therefore be kept to a minimum. 66 | * @param meanTenuredGCTime the mean tenured GC time in milliseconds 67 | */ 68 | void setMeanTenuredGCTime(double meanTenuredGCTime); 69 | 70 | /** 71 | * Returns the mean time in milliseconds spent during a single tenured or full or old stop-the-world GC event during the last iteration. 72 | * This time is not available for application processing and should therefore be kept to a minimum. 73 | * @return the mean tenured GC time in milliseconds 74 | */ 75 | double getMeanTenuredGCTime(); 76 | 77 | } 78 | -------------------------------------------------------------------------------- /top4j-javaagent/src/main/java/io/top4j/javaagent/mbeans/jvm/gc/GCTimeBean.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 Open Answers Ltd. https://www.openanswers.co.uk 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.top4j.javaagent.mbeans.jvm.gc; 18 | 19 | import javax.management.MBeanServerConnection; 20 | import java.io.IOException; 21 | import java.lang.management.*; 22 | import java.util.List; 23 | 24 | public class GCTimeBean { 25 | 26 | private long lastGCTime; 27 | private long lastGCCount; 28 | private long lastNurseryGCTime; 29 | private long lastNurseryGCCount; 30 | private long lastTenuredGCTime; 31 | private long lastTenuredGCCount; 32 | private long lastSystemTime; 33 | 34 | public GCTimeBean(MBeanServerConnection mbsc) throws IOException { 35 | 36 | final List gcbeans = 37 | ManagementFactory.getPlatformMXBeans(mbsc, GarbageCollectorMXBean.class); 38 | long currentGCTime = 0; 39 | long currentGCCount = 0; 40 | long currentNurseryGCTime = 0; 41 | long currentNurseryGCCount = 0; 42 | long currentTenuredGCTime = 0; 43 | long currentTenuredGCCount = 0; 44 | for (GarbageCollectorMXBean gcbean : gcbeans) { 45 | String name = gcbean.getName(); 46 | if (name.equals("Copy") || name.equals("PS Scavenge")) { 47 | currentNurseryGCTime = gcbean.getCollectionTime(); 48 | currentNurseryGCCount = gcbean.getCollectionCount(); 49 | } 50 | if (name.equals("MarkSweepCompact") || name.equals("PS MarkSweep")) { 51 | currentTenuredGCTime = gcbean.getCollectionTime(); 52 | currentTenuredGCCount = gcbean.getCollectionCount(); 53 | } 54 | currentGCTime += gcbean.getCollectionTime(); 55 | currentGCCount += gcbean.getCollectionCount(); 56 | } 57 | this.setLastGCTime(currentGCTime); 58 | this.setLastGCCount(currentGCCount); 59 | this.setLastNurseryGCTime(currentNurseryGCTime); 60 | this.setLastNurseryGCCount(currentNurseryGCCount); 61 | this.setLastTenuredGCTime(currentTenuredGCTime); 62 | this.setLastTenuredGCCount(currentTenuredGCCount); 63 | this.setLastSystemTime(System.currentTimeMillis()); 64 | 65 | } 66 | 67 | public void setLastGCTime(long lastGCTime) { 68 | this.lastGCTime = lastGCTime; 69 | } 70 | 71 | public long getLastGCTime() { 72 | return lastGCTime; 73 | } 74 | 75 | public void setLastSystemTime(long lastSystemTime) { 76 | this.lastSystemTime = lastSystemTime; 77 | } 78 | 79 | public long getLastSystemTime() { 80 | return lastSystemTime; 81 | } 82 | 83 | public void setLastGCCount(long lastGCCount) { 84 | this.lastGCCount = lastGCCount; 85 | } 86 | 87 | public long getLastGCCount() { 88 | return lastGCCount; 89 | } 90 | 91 | public void setLastNurseryGCTime(long lastNurseryGCTime) { 92 | this.lastNurseryGCTime = lastNurseryGCTime; 93 | } 94 | 95 | public long getLastNurseryGCTime() { 96 | return lastNurseryGCTime; 97 | } 98 | 99 | public void setLastNurseryGCCount(long lastNurseryGCCount) { 100 | this.lastNurseryGCCount = lastNurseryGCCount; 101 | } 102 | 103 | public long getLastNurseryGCCount() { 104 | return lastNurseryGCCount; 105 | } 106 | 107 | public void setLastTenuredGCTime(long lastTenuredGCTime) { 108 | this.lastTenuredGCTime = lastTenuredGCTime; 109 | } 110 | 111 | public long getLastTenuredGCTime() { 112 | return lastTenuredGCTime; 113 | } 114 | 115 | public void setLastTenuredGCCount(long lastTenuredGCCount) { 116 | this.lastTenuredGCCount = lastTenuredGCCount; 117 | } 118 | 119 | public long getLastTenuredGCCount() { 120 | return lastTenuredGCCount; 121 | } 122 | 123 | } 124 | -------------------------------------------------------------------------------- /top4j-javaagent/src/main/java/io/top4j/javaagent/mbeans/jvm/heap/HeapStats.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 Open Answers Ltd. https://www.openanswers.co.uk 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.top4j.javaagent.mbeans.jvm.heap; 18 | 19 | import io.top4j.javaagent.exception.MBeanRuntimeException; 20 | import io.top4j.javaagent.profiler.CpuTime; 21 | 22 | import javax.management.MBeanServerConnection; 23 | import java.util.logging.Logger; 24 | 25 | public class HeapStats implements HeapStatsMXBean { 26 | 27 | private HeapUtilisation heapUtilisation; 28 | private CpuTime cpuTime = new CpuTime(); 29 | private double mBeanCpuTime; 30 | private boolean enabled = true; 31 | private String failureReason; 32 | 33 | private static final Logger LOGGER = Logger.getLogger(HeapStats.class.getName()); 34 | 35 | public HeapStats(MBeanServerConnection mbsc) throws Exception { 36 | 37 | LOGGER.fine("Initialising Heap Stats...."); 38 | 39 | // instantiate new HeapUtilisation to store heap utilisation 40 | this.heapUtilisation = new HeapUtilisation(mbsc); 41 | 42 | } 43 | 44 | /** 45 | * Update Heap stats. 46 | */ 47 | public synchronized void update() { 48 | 49 | if (enabled) { 50 | try { 51 | // update heap stats 52 | updateHeapStats(); 53 | } catch (Exception e) { 54 | // something went wrong - record failure reason and disable any further updates 55 | this.failureReason = e.getMessage(); 56 | this.enabled = false; 57 | LOGGER.severe("TOP4J ERROR: Failed to update HeapStats MBean due to: " + e.getMessage()); 58 | LOGGER.severe("TOP4J ERROR: Further HeapStats MBean updates will be disabled from now on."); 59 | } 60 | } 61 | } 62 | 63 | private synchronized void updateHeapStats() throws MBeanRuntimeException { 64 | 65 | // initialise thread CPU timer 66 | cpuTime.init(); 67 | 68 | LOGGER.fine("Updating Heap stats...."); 69 | 70 | // update heap utilisation 71 | this.heapUtilisation.update(); 72 | 73 | // update heap stats CPU time 74 | mBeanCpuTime = cpuTime.getMillis(); 75 | 76 | } 77 | 78 | @Override 79 | public void setMBeanCpuTime(double agentCpuTime) { 80 | this.mBeanCpuTime = agentCpuTime; 81 | } 82 | 83 | @Override 84 | public double getMBeanCpuTime() { 85 | return mBeanCpuTime; 86 | } 87 | 88 | @Override 89 | public void setEdenSpaceUtil(double edenSpaceUtil) { 90 | this.heapUtilisation.setEdenSpaceUtil(edenSpaceUtil); 91 | } 92 | 93 | @Override 94 | public double getEdenSpaceUtil() { 95 | return this.heapUtilisation.getEdenSpaceUtil(); 96 | } 97 | 98 | @Override 99 | public void setSurvivorSpaceUtil(double survivorSpaceUtil) { 100 | this.heapUtilisation.setSurvivorSpaceUtil(survivorSpaceUtil); 101 | } 102 | 103 | @Override 104 | public double getSurvivorSpaceUtil() { 105 | return this.heapUtilisation.getSurvivorSpaceUtil(); 106 | } 107 | 108 | @Override 109 | public void setTenuredHeapUtil(double tenuredHeapUtil) { 110 | this.heapUtilisation.setTenuredHeapUtil(tenuredHeapUtil); 111 | } 112 | 113 | @Override 114 | public double getTenuredHeapUtil() { 115 | return this.heapUtilisation.getTenuredHeapUtil(); 116 | } 117 | 118 | @Override 119 | public void setEnabled(boolean enabled) { 120 | this.enabled = enabled; 121 | } 122 | 123 | @Override 124 | public boolean getEnabled() { 125 | return this.enabled; 126 | } 127 | 128 | @Override 129 | public void setFailureReason(String failureReason) { 130 | this.failureReason = failureReason; 131 | } 132 | 133 | @Override 134 | public String getFailureReason() { 135 | return this.failureReason; 136 | } 137 | 138 | public boolean isSingleGenerationHeap() { 139 | return this.heapUtilisation.isSingleGenerationHeap(); 140 | } 141 | 142 | } 143 | -------------------------------------------------------------------------------- /top4j-javaagent/src/main/java/io/top4j/javaagent/mbeans/jvm/heap/HeapStatsMXBean.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 Open Answers Ltd. https://www.openanswers.co.uk 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.top4j.javaagent.mbeans.jvm.heap; 18 | 19 | import io.top4j.javaagent.mbeans.StatsMXBean; 20 | 21 | /** 22 | * Used to store and expose stats relating to the JVM heap utilisation. The heap utilisation is calculated as the percentage of heap used following the most recent garbage collection event. In other words.... ( heapUsed / heapCommitted ) * 100. 23 | */ 24 | 25 | public interface HeapStatsMXBean extends StatsMXBean { 26 | 27 | /** 28 | * Sets the eden (or nursery or new) heap space utilisation following the most recent garbage collection event. 29 | *

30 | * This is effectively the residual heap occupied by live objects within the eden space which can't be garbage collected because they are 31 | * still referenced by one or more other objects. The eden heap utilisation is typically very low as most objects created within the eden 32 | * heap space are either garbage collected (cleared up) or promoted to one of the survivor spaces at each nursery GC event. 33 | * @param edenSpaceUtil the eden heap space utilisation 34 | */ 35 | void setEdenSpaceUtil(double edenSpaceUtil); 36 | 37 | /** 38 | * Returns the eden (or nursery or new) heap space utilisation following the most recent garbage collection event. 39 | *

40 | * This is effectively the residual heap occupied by live objects within the eden space which can't be garbage collected because they are 41 | * still referenced by one or more other objects. The eden heap utilisation is typically very low as most objects created within the eden 42 | * heap space are either garbage collected (cleared up) or promoted to one of the survivor spaces at each nursery GC event. 43 | * @return the eden heap space utilisation 44 | */ 45 | double getEdenSpaceUtil(); 46 | 47 | /** 48 | * Sets the survivor heap space utilisation following the most recent garbage collection event. 49 | *

50 | * This is effectively the residual heap occupied by live objects within the survivor spaces which can't be garbage collected because they are 51 | * still referenced by one or more other objects. 52 | * @param survivorSpaceUtil the survivor heap space utilisation 53 | */ 54 | void setSurvivorSpaceUtil(double survivorSpaceUtil); 55 | 56 | /** 57 | * Returns the survivor heap space utilisation following the most recent garbage collection event. 58 | *

59 | * This is effectively the residual heap occupied by live objects within the survivor spaces which can't be garbage collected because they are 60 | * still referenced by one or more other objects. 61 | * @return the survivor heap space utilisation 62 | */ 63 | double getSurvivorSpaceUtil(); 64 | 65 | /** 66 | * Sets the tenured (or old) heap space utilisation following the most recent garbage collection event. 67 | * This is effectively the residual heap occupied by live objects within the tenured (or old) space which can't be garbage collected because they are 68 | * still referenced by one or more other objects. High tenured heap space utilisation can be an indication that the JVM is running low on memory. 69 | * A high tenured heap utilisation can lead to frequent garbage collection events which will typically lead to a high GC overhead and therefore poor 70 | * application performance/memory throughput. See GCOverhead attribute above for more details. 71 | * @param tenuredHeapUtil the tenured heap space utilisation 72 | */ 73 | void setTenuredHeapUtil(double tenuredHeapUtil); 74 | 75 | /** 76 | * Returns the tenured (or old) heap space utilisation following the most recent garbage collection event. 77 | *

78 | * This is effectively the residual heap occupied by live objects within the tenured (or old) space which can't be garbage collected because they are 79 | * still referenced by one or more other objects. High tenured heap space utilisation can be an indication that the JVM is running low on memory. 80 | * A high tenured heap utilisation can lead to frequent garbage collection events which will typically lead to a high GC overhead and therefore poor 81 | * application performance/memory throughput. See GCOverhead attribute above for more details. 82 | * @return the tenured heap space utilisation 83 | */ 84 | double getTenuredHeapUtil(); 85 | 86 | /** 87 | * @return true if the heap is a single-generation (thus no survivor/tenured generations). 88 | */ 89 | boolean isSingleGenerationHeap(); 90 | 91 | } 92 | -------------------------------------------------------------------------------- /top4j-javaagent/src/main/java/io/top4j/javaagent/mbeans/jvm/memory/MemoryStatsMXBean.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 Open Answers Ltd. https://www.openanswers.co.uk 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.top4j.javaagent.mbeans.jvm.memory; 18 | 19 | import io.top4j.javaagent.mbeans.StatsMXBean; 20 | 21 | /** 22 | * Used to store and expose stats relating to the JVM memory pool usage. 23 | */ 24 | 25 | public interface MemoryStatsMXBean extends StatsMXBean { 26 | 27 | /** 28 | * Sets the memory allocation rate which represents the amount of memory consumed by the Java application whilst creating new objects over time. 29 | * It is measured in MB per second (MB/s). A high memory allocation rate can be an indication that the Java application is creating too many new 30 | * objects and as a result putting pressure on the JVM memory management sub-system which can cause more frequent GC events and associated GC overhead. 31 | * @param memoryAllocationRate the memory allocation rate in MB/s 32 | */ 33 | void setMemoryAllocationRate(double memoryAllocationRate); 34 | 35 | /** 36 | * Returns the memory allocation rate which represents the amount of memory consumed by the Java application whilst creating new objects over time. 37 | * It is measured in MB per second (MB/s). A high memory allocation rate can be an indication that the Java application is creating too many new 38 | * objects and as a result putting pressure on the JVM memory management sub-system which can cause more frequent GC events and associated GC overhead. 39 | * @return the memory allocation rate in MB/s 40 | */ 41 | double getMemoryAllocationRate(); 42 | 43 | /** 44 | * Sets the memory survivor rate represents the amount of memory that survives a nursery (or new) GC event and is promoted to one of the survivor spaces over time. 45 | * It is measured in MB per second (MB/s). A high memory survivor rate can be an indication that too many objects are being promoted to the survivor spaces which 46 | * can be an indication that the eden space is undersized or the memory allocation rate (to eden) is too high. 47 | * @param memorySurvivorRate the memory survivor rate in MB/s 48 | */ 49 | void setMemorySurvivorRate(double memorySurvivorRate); 50 | 51 | /** 52 | * Returns the memory survivor rate represents the amount of memory that survives a nursery (or new) GC event and is promoted to one of the survivor spaces over time. 53 | * It is measured in MB per second (MB/s). A high memory survivor rate can be an indication that too many objects are being promoted to the survivor spaces which 54 | * can be an indication that the eden space is undersized or the memory allocation rate (to eden) is too high. 55 | * @return the memory survivor rate in MB/s 56 | */ 57 | double getMemorySurvivorRate(); 58 | 59 | /** 60 | * Sets the memory promotion rate represents the amount of memory that survives one or more nursery (or new) GC events and is promoted to the tenured (or old) space over time. 61 | * It is measured in MB per second (MB/s). A high memory promotion rate can be an indication that too many objects are being promoted to the tenured space which 62 | * can be an indication that the eden space is undersized or the memory allocation rate (to eden) is too high. 63 | * @param memoryPromotionRate the memory promotion rate in MB/s 64 | */ 65 | void setMemoryPromotionRate(double memoryPromotionRate); 66 | 67 | /** 68 | * Returns the memory promotion rate represents the amount of memory that survives one or more nursery (or new) GC events and is promoted to the tenured (or old) space over time. 69 | * It is measured in MB per second (MB/s). A high memory promotion rate can be an indication that too many objects are being promoted to the tenured space which 70 | * can be an indication that the eden space is undersized or the memory allocation rate (to eden) is too high. 71 | * @return the memory promotion rate in MB/s 72 | */ 73 | double getMemoryPromotionRate(); 74 | 75 | } 76 | -------------------------------------------------------------------------------- /top4j-javaagent/src/main/java/io/top4j/javaagent/mbeans/jvm/memory/MemorySurvivorBean.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 Open Answers Ltd. https://www.openanswers.co.uk 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.top4j.javaagent.mbeans.jvm.memory; 18 | 19 | public class MemorySurvivorBean { 20 | 21 | private long survivors; 22 | private long lastGCCount; 23 | private long lastSystemTime; 24 | 25 | public MemorySurvivorBean() { 26 | 27 | this.setSurvivors(0); 28 | this.setLastGCCount(0); 29 | 30 | } 31 | 32 | public synchronized long getSurvivors() { 33 | return survivors; 34 | } 35 | 36 | public synchronized void setSurvivors(long survivors) { 37 | this.survivors = survivors; 38 | } 39 | 40 | public synchronized void resetSurvivors() { 41 | this.survivors = 0; 42 | } 43 | 44 | public synchronized void addSurvivors(long survivors) { 45 | this.survivors += survivors; 46 | } 47 | 48 | public synchronized long getAndResetSurvivors() { 49 | 50 | long survivors = this.survivors; 51 | this.survivors = 0; 52 | return survivors; 53 | 54 | } 55 | 56 | public long getLastGCCount() { 57 | return lastGCCount; 58 | } 59 | 60 | public void setLastGCCount(long lastGCCount) { 61 | this.lastGCCount = lastGCCount; 62 | } 63 | 64 | public long getLastSystemTime() { 65 | return lastSystemTime; 66 | } 67 | 68 | public void setLastSystemTime(long lastSystemTime) { 69 | this.lastSystemTime = lastSystemTime; 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /top4j-javaagent/src/main/java/io/top4j/javaagent/mbeans/jvm/memory/MemorySurvivorRate.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 Open Answers Ltd. https://www.openanswers.co.uk 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.top4j.javaagent.mbeans.jvm.memory; 18 | 19 | import java.lang.management.ManagementFactory; 20 | import java.lang.management.MemoryMXBean; 21 | import java.util.logging.Logger; 22 | 23 | import javax.management.MBeanServerConnection; 24 | import javax.management.NotificationEmitter; 25 | 26 | import io.top4j.javaagent.mbeans.jvm.gc.CollectionUsageListener; 27 | 28 | public class MemorySurvivorRate { 29 | 30 | volatile private double memorySurvivorRate; 31 | private MemorySurvivorBean memorySurvivor; 32 | 33 | private static final Logger LOGGER = Logger.getLogger(MemorySurvivorRate.class.getName()); 34 | 35 | public MemorySurvivorRate(MBeanServerConnection mbsc) throws Exception { 36 | 37 | // instantiate new MemorySurvivorBean 38 | MemorySurvivorBean memorySurvivor = new MemorySurvivorBean(); 39 | 40 | // instantiate new MemoryPoolMXBeanHelper 41 | MemoryPoolMXBeanHelper memoryPoolMxBeanHelper = new MemoryPoolMXBeanHelper(mbsc); 42 | 43 | // Register CollectionUsageListener with MemoryMXBean 44 | MemoryMXBean memoryMXBean = ManagementFactory.getPlatformMXBean(mbsc, MemoryMXBean.class); 45 | NotificationEmitter emitter = (NotificationEmitter) memoryMXBean; 46 | CollectionUsageListener listener = new CollectionUsageListener(mbsc, memorySurvivor); 47 | emitter.addNotificationListener(listener, null, null); 48 | 49 | long threshold = 1; 50 | memoryPoolMxBeanHelper.setSurvivorCollectionUsageThreshold(threshold); 51 | 52 | this.memorySurvivor = memorySurvivor; 53 | 54 | } 55 | 56 | public double getMemorySurvivorRate() { 57 | return memorySurvivorRate; 58 | } 59 | 60 | public void setMemorySurvivorRate(double memorySurvivorRate) { 61 | this.memorySurvivorRate = memorySurvivorRate; 62 | } 63 | 64 | /** 65 | * Update Memory Survivor Rate. 66 | */ 67 | public void update() { 68 | 69 | long systemTime = System.currentTimeMillis(); 70 | double intervalSystemTimeSecs; 71 | long intervalSurvivors; 72 | 73 | // calculate intervalSystemTimeSecs in seconds 74 | intervalSystemTimeSecs = ((double) systemTime - (double) memorySurvivor.getLastSystemTime()) / 1000; 75 | LOGGER.finest("Survivor Rate System Time = " + systemTime); 76 | LOGGER.finest("Survivor Rate Last System Time = " + memorySurvivor.getLastSystemTime()); 77 | 78 | // get and reset intervalSurvivors 79 | intervalSurvivors = memorySurvivor.getAndResetSurvivors(); 80 | 81 | // calculate memory survivor rate 82 | this.memorySurvivorRate = calculateMemorySurvivorRate(intervalSurvivors, intervalSystemTimeSecs); 83 | 84 | this.memorySurvivor.setLastSystemTime(systemTime); 85 | 86 | } 87 | 88 | private double calculateMemorySurvivorRate(long intervalSurvivors, double intervalSystemTimeSecs) { 89 | 90 | return ((double) intervalSurvivors / intervalSystemTimeSecs) / 1048576; 91 | 92 | } 93 | 94 | } 95 | -------------------------------------------------------------------------------- /top4j-javaagent/src/main/java/io/top4j/javaagent/mbeans/jvm/threads/BlockedThread.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 Open Answers Ltd. https://www.openanswers.co.uk 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.top4j.javaagent.mbeans.jvm.threads; 18 | 19 | import io.top4j.javaagent.utils.ThreadHelper; 20 | 21 | import javax.management.MBeanServerConnection; 22 | import java.io.IOException; 23 | import java.lang.Thread.State; 24 | 25 | 26 | public class BlockedThread implements BlockedThreadMXBean { 27 | 28 | volatile private String threadName; 29 | volatile private long threadId; 30 | volatile private State threadState; 31 | volatile private long threadBlockedTime; 32 | volatile private double threadBlockedPercentage; 33 | private ThreadHelper threadHelper; 34 | 35 | public BlockedThread(MBeanServerConnection mbsc) throws IOException { 36 | 37 | this.threadHelper = new ThreadHelper(mbsc); 38 | 39 | } 40 | 41 | public void setThreadName(String threadName) { 42 | this.threadName = threadName; 43 | } 44 | 45 | public String getThreadName() { 46 | return threadName; 47 | } 48 | 49 | public void setThreadId(long threadId) { 50 | this.threadId = threadId; 51 | } 52 | 53 | public long getThreadId() { 54 | return threadId; 55 | } 56 | 57 | public void setThreadState(State threadState) { 58 | this.threadState = threadState; 59 | } 60 | 61 | public State getThreadState() { 62 | return threadState; 63 | } 64 | 65 | @Override 66 | public void setThreadBlockedTime(long threadBlockedTime) { 67 | 68 | this.threadBlockedTime = threadBlockedTime; 69 | 70 | } 71 | 72 | @Override 73 | public long getThreadBlockedTime() { 74 | return threadBlockedTime; 75 | } 76 | 77 | @Override 78 | public void setThreadBlockedPercentage(double threadBlockedPercentage) { 79 | 80 | this.threadBlockedPercentage = threadBlockedPercentage; 81 | 82 | } 83 | 84 | @Override 85 | public double getThreadBlockedPercentage() { 86 | return threadBlockedPercentage; 87 | } 88 | 89 | public String getStackTrace(int maxDepth) { 90 | 91 | return threadHelper.getStackTrace(threadId, maxDepth); 92 | 93 | } 94 | 95 | public String getStackTraceWithContext(int maxDepth) { 96 | 97 | return threadHelper.getStackTraceWithContext(threadId, maxDepth); 98 | 99 | } 100 | 101 | } 102 | -------------------------------------------------------------------------------- /top4j-javaagent/src/main/java/io/top4j/javaagent/mbeans/jvm/threads/BlockedThreadMXBean.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 Open Answers Ltd. https://www.openanswers.co.uk 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.top4j.javaagent.mbeans.jvm.threads; 18 | 19 | /** 20 | * Used to store and expose stats relating to a thread that has been blocked for some time during the last iteration. 21 | * Each blocked thread is ranked between 1 and N via the "rank" attribute on the BlockedThread MBean Object Name, 22 | * where 1 is the thread that has been blocked the most and N is the thread that has been blocked the least 23 | * (out of the top ranked blocked threads). 24 | */ 25 | 26 | public interface BlockedThreadMXBean { 27 | 28 | /** 29 | * Sets the name of the blocked thread. 30 | * @param threadName the thread name 31 | */ 32 | public void setThreadName(String threadName); 33 | 34 | /** 35 | * Returns the name of the blocked thread. 36 | * @return the thread name 37 | */ 38 | public String getThreadName(); 39 | 40 | /** 41 | * Sets the thread ID of the blocked thread. 42 | * @param threadId the thread ID 43 | */ 44 | public void setThreadId(long threadId); 45 | 46 | /** 47 | * Returns the thread ID of the blocked thread. 48 | * @return the thread ID 49 | */ 50 | public long getThreadId(); 51 | 52 | /** 53 | * Sets the thread state as defined by the java.lang.Thread.State Enum. 54 | * @param threadState the thread state 55 | */ 56 | public void setThreadState(Thread.State threadState); 57 | 58 | /** 59 | * Sets the thread state as defined by the java.lang.Thread.State Enum. 60 | * @return the thread state 61 | */ 62 | public Thread.State getThreadState(); 63 | 64 | /** 65 | * Sets the time in milliseconds that the thread has been in a blocked state during the last iteration. 66 | * @param threadBlockedTime blocked time in milliseconds 67 | */ 68 | public void setThreadBlockedTime(long threadBlockedTime); 69 | 70 | /** 71 | * Returns the time in milliseconds that the thread has been in a blocked state during the last iteration. 72 | * @return blocked time in milliseconds 73 | */ 74 | public long getThreadBlockedTime(); 75 | 76 | /** 77 | * Sets the percentage of time that the thread has been in a blocked state during the last iteration. 78 | *

79 | * A high thread blocked percentage can be an indicator of thread lock contention. 80 | * For example, threads blocked waiting to access a synchronised method or code block. 81 | * @param threadBlockedPercentage the thread blocked percentage 82 | */ 83 | public void setThreadBlockedPercentage(double threadBlockedPercentage); 84 | 85 | /** 86 | * Returns the percentage of time that the thread has been in a blocked state during the last iteration. 87 | *

88 | * A high thread blocked percentage can be an indicator of thread lock contention. 89 | * For example, threads blocked waiting to access a synchronised method or code block. 90 | * @return the thread blocked percentage 91 | */ 92 | public double getThreadBlockedPercentage(); 93 | 94 | /** 95 | * Returns the stack trace for this blocked thread with a maximum frame depth of maxDepth. 96 | * @param maxDepth maximum frame depth 97 | * @return a String representation of the stack trace 98 | */ 99 | public String getStackTrace(int maxDepth); 100 | 101 | /** 102 | * Returns the stack trace for this blocked thread with context, e.g. thread name and thread state, with a maximum frame depth of maxDepth. 103 | * @param maxDepth maximum frame depth 104 | * @return a String representation of the stack trace with some additional context 105 | */ 106 | public String getStackTraceWithContext(int maxDepth); 107 | 108 | } 109 | -------------------------------------------------------------------------------- /top4j-javaagent/src/main/java/io/top4j/javaagent/mbeans/jvm/threads/HotMethod.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 Open Answers Ltd. https://www.openanswers.co.uk 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.top4j.javaagent.mbeans.jvm.threads; 18 | 19 | import io.top4j.javaagent.utils.ThreadHelper; 20 | 21 | import javax.management.MBeanServerConnection; 22 | import java.io.IOException; 23 | 24 | public class HotMethod implements HotMethodMXBean { 25 | 26 | volatile private String methodName; 27 | volatile private String threadName; 28 | volatile private long threadId; 29 | volatile private double loadProfile; 30 | volatile private StackTraceElement[] stackTrace; 31 | private ThreadHelper threadHelper; 32 | 33 | public HotMethod(MBeanServerConnection mbsc) throws IOException { 34 | 35 | this.threadHelper = new ThreadHelper(mbsc); 36 | 37 | } 38 | 39 | @Override 40 | public void setMethodName(String methodName) { 41 | this.methodName = methodName; 42 | } 43 | 44 | @Override 45 | public String getMethodName() { 46 | return methodName; 47 | } 48 | 49 | @Override 50 | public void setThreadName(String threadName) { 51 | this.threadName = threadName; 52 | } 53 | 54 | @Override 55 | public String getThreadName() { 56 | return threadName; 57 | } 58 | 59 | @Override 60 | public void setThreadId(long threadId) { 61 | this.threadId = threadId; 62 | } 63 | 64 | @Override 65 | public long getThreadId() { 66 | return threadId; 67 | } 68 | 69 | @Override 70 | public void setLoadProfile(double loadProfile) { 71 | this.loadProfile = loadProfile; 72 | } 73 | 74 | @Override 75 | public double getLoadProfile() { 76 | return loadProfile; 77 | } 78 | 79 | @Override 80 | public String getStackTrace(int maxDepth) { 81 | return threadHelper.getStackTraceAsString(stackTrace); 82 | } 83 | 84 | public void setStackTrace(StackTraceElement[] stackTrace) { 85 | if (stackTrace != null) { 86 | this.stackTrace = stackTrace.clone(); 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /top4j-javaagent/src/main/java/io/top4j/javaagent/mbeans/jvm/threads/HotMethodMXBean.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 Open Answers Ltd. https://www.openanswers.co.uk 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.top4j.javaagent.mbeans.jvm.threads; 18 | 19 | /** 20 | * Used to store and expose stats relating to a Java method that has been determined to have executed frequently. 21 | */ 22 | 23 | public interface HotMethodMXBean { 24 | 25 | /** 26 | * Sets the hot method name. 27 | * @param methodName the method name 28 | */ 29 | void setMethodName(String methodName); 30 | 31 | /** 32 | * Returns the hot method name. 33 | * @return the method name 34 | */ 35 | String getMethodName(); 36 | 37 | /** 38 | * Sets the name of the thread that has executed the method most recently. 39 | * @param threadName the thread name 40 | */ 41 | void setThreadName(String threadName); 42 | 43 | /** 44 | * Returns the name of the thread that has executed the method most recently. 45 | * @return the thread name 46 | */ 47 | String getThreadName(); 48 | 49 | /** 50 | * Sets the ID of the thread that has executed the method most recently. 51 | * @param threadId the thread ID 52 | */ 53 | void setThreadId(long threadId); 54 | 55 | /** 56 | * Returns the ID of the thread that has executed the method most recently. 57 | * @return the thread ID 58 | */ 59 | long getThreadId(); 60 | 61 | /** 62 | * Sets the hot method load profile which is an indication of how hot the method has been during the last iteration. 63 | *

64 | * The load profile is calculated as the CPU time used by a top thread that has executed a hot method as 65 | * a percentage of the total CPU time used by all top threads during the last iteration. 66 | * @param loadProfile the load profile 67 | */ 68 | void setLoadProfile(double loadProfile); 69 | 70 | /** 71 | * Returns the hot method load profile which is an indication of how hot the method has been during the last iteration. 72 | *

73 | * The load profile is calculated as the CPU time used by a top thread that has executed a hot method as 74 | * a percentage of the total CPU time used by all top threads during the last iteration. 75 | * @return the load profile 76 | */ 77 | double getLoadProfile(); 78 | 79 | /** 80 | * Returns the most recent stack trace for the hot method. 81 | * @param maxDepth the stack trace maximum frame depth 82 | * @return a String representation of the stack trace 83 | */ 84 | String getStackTrace(int maxDepth); 85 | 86 | } 87 | -------------------------------------------------------------------------------- /top4j-javaagent/src/main/java/io/top4j/javaagent/mbeans/jvm/threads/HotMethodTracker.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 Open Answers Ltd. https://www.openanswers.co.uk 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.top4j.javaagent.mbeans.jvm.threads; 18 | 19 | import io.top4j.javaagent.profiler.CpuTime; 20 | 21 | import java.util.Map; 22 | import java.util.TimerTask; 23 | import java.util.logging.Logger; 24 | 25 | public class HotMethodTracker extends TimerTask { 26 | 27 | private Map topThreadMap; 28 | private HotMethods hotMethods; 29 | private CpuTime cpuTime = new CpuTime(); 30 | 31 | private static final Logger LOGGER = Logger.getLogger(HotMethodTracker.class.getName()); 32 | 33 | public HotMethodTracker(Map topThreadMap, HotMethods hotMethods) { 34 | 35 | // store topThreadMap 36 | this.topThreadMap = topThreadMap; 37 | // store hotMethods 38 | this.hotMethods = hotMethods; 39 | 40 | } 41 | 42 | @Override 43 | public void run() { 44 | 45 | // initialise thread CPU timer 46 | cpuTime.init(); 47 | 48 | // iterate over topThreadsMap 49 | for (TopThread topThread : topThreadMap.values()) { 50 | 51 | // get topThread stack trace 52 | StackTraceElement[] stackTrace = topThread.getStackTraceElements(); 53 | // get topThread name 54 | String threadName = topThread.getThreadName(); 55 | // get topThread Id 56 | long threadId = topThread.getThreadId(); 57 | // get topThread state 58 | Thread.State threadState = topThread.getThreadState(); 59 | if (stackTrace != null && threadName != null && threadId != 0 && threadState.equals(Thread.State.RUNNABLE)) { 60 | // add top thread stack trace, name and ID to hotMethods 61 | hotMethods.addHotMethod(topThread.getStackTraceElements(), topThread.getThreadName(), topThread.getThreadId()); 62 | } 63 | } 64 | 65 | LOGGER.finer("Hot Method Tracker CPU Time: " + cpuTime.getMillis() + " ms"); 66 | // update hot method tracker CPU time 67 | hotMethods.addMBeanCpuTime(cpuTime.getMillis()); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /top4j-javaagent/src/main/java/io/top4j/javaagent/mbeans/jvm/threads/MethodTimeMap.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 Open Answers Ltd. https://www.openanswers.co.uk 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.top4j.javaagent.mbeans.jvm.threads; 18 | 19 | import java.util.*; 20 | 21 | public class MethodTimeMap { 22 | 23 | // Map key = method count, Map value = list of method names 24 | NavigableMap> methodTimeMap = new TreeMap<>(); 25 | 26 | public void put(Long methodTime, String methodName) { 27 | 28 | // get list of method names with this methodTime 29 | List existingMethodNameList = methodTimeMap.get(methodTime); 30 | 31 | if (existingMethodNameList == null) { 32 | 33 | // create new methodNameList 34 | List newMethodNameList = new ArrayList<>(); 35 | // add methodName to methodNameList 36 | newMethodNameList.add(methodName); 37 | // add methodTime and methodNameList to methodTimeMap 38 | methodTimeMap.put(methodTime, newMethodNameList); 39 | 40 | } else { 41 | 42 | // add methodName to methodNameList 43 | existingMethodNameList.add(methodName); 44 | // add methodTime and methodNameList to methodTimeMap 45 | methodTimeMap.put(methodTime, existingMethodNameList); 46 | 47 | } 48 | 49 | } 50 | 51 | public List get(long methodTime) { 52 | 53 | return methodTimeMap.get(methodTime); 54 | 55 | } 56 | 57 | public int size() { 58 | 59 | return methodTimeMap.size(); 60 | 61 | } 62 | 63 | public NavigableSet descendingKeySet() { 64 | 65 | return methodTimeMap.descendingKeySet(); 66 | 67 | } 68 | 69 | public String toString() { 70 | 71 | return methodTimeMap.toString(); 72 | 73 | } 74 | 75 | public NavigableMap> getMethodTimeMap() { 76 | 77 | return methodTimeMap; 78 | 79 | } 80 | 81 | } 82 | -------------------------------------------------------------------------------- /top4j-javaagent/src/main/java/io/top4j/javaagent/mbeans/jvm/threads/ThreadTimeMap.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 Open Answers Ltd. https://www.openanswers.co.uk 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.top4j.javaagent.mbeans.jvm.threads; 18 | 19 | import java.util.ArrayList; 20 | import java.util.List; 21 | import java.util.NavigableMap; 22 | import java.util.NavigableSet; 23 | import java.util.TreeMap; 24 | 25 | public class ThreadTimeMap { 26 | 27 | // Map key = thread time, Map value = list of thread IDs 28 | NavigableMap> threadTimeMap = new TreeMap<>(); 29 | 30 | public void put(Long threadTime, Long threadId) { 31 | 32 | // get list of thread IDs with this threadTime 33 | List existingThreadIdList = threadTimeMap.get(threadTime); 34 | 35 | if (existingThreadIdList == null) { 36 | 37 | // create new threadIdList 38 | List newThreadIdList = new ArrayList<>(); 39 | // add threadId to threadIdList 40 | newThreadIdList.add(threadId); 41 | // add threadTime and threadIdList to threadTimeMap 42 | threadTimeMap.put(threadTime, newThreadIdList); 43 | 44 | } else { 45 | 46 | // add threadId to threadIdList 47 | existingThreadIdList.add(threadId); 48 | // add threadTime and threadIdList to threadTimeMap 49 | threadTimeMap.put(threadTime, existingThreadIdList); 50 | 51 | } 52 | 53 | } 54 | 55 | public List get(Long threadTime) { 56 | 57 | return threadTimeMap.get(threadTime); 58 | 59 | } 60 | 61 | public int size() { 62 | 63 | return threadTimeMap.size(); 64 | 65 | } 66 | 67 | public NavigableSet descendingKeySet() { 68 | 69 | return threadTimeMap.descendingKeySet(); 70 | 71 | } 72 | 73 | public String toString() { 74 | 75 | return threadTimeMap.toString(); 76 | 77 | } 78 | 79 | public NavigableMap> getThreadTimeMap() { 80 | 81 | return threadTimeMap; 82 | 83 | } 84 | 85 | } 86 | -------------------------------------------------------------------------------- /top4j-javaagent/src/main/java/io/top4j/javaagent/mbeans/jvm/threads/TopThread.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 Open Answers Ltd. https://www.openanswers.co.uk 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.top4j.javaagent.mbeans.jvm.threads; 18 | 19 | import io.top4j.javaagent.utils.ThreadHelper; 20 | 21 | import javax.management.MBeanServerConnection; 22 | import java.io.IOException; 23 | import java.lang.Thread.State; 24 | import java.lang.management.ThreadInfo; 25 | 26 | 27 | public class TopThread implements TopThreadMXBean { 28 | 29 | volatile private String threadName; 30 | volatile private long threadId; 31 | volatile private State threadState; 32 | volatile private double threadCpuUsage; 33 | private ThreadHelper threadHelper; 34 | private ThreadInfo threadInfo; 35 | 36 | public TopThread(MBeanServerConnection mbsc) throws IOException { 37 | 38 | this.threadHelper = new ThreadHelper(mbsc); 39 | 40 | } 41 | 42 | public void setThreadName(String threadName) { 43 | this.threadName = threadName; 44 | } 45 | 46 | public String getThreadName() { 47 | return threadName; 48 | } 49 | 50 | public void setThreadId(long threadId) { 51 | this.threadId = threadId; 52 | } 53 | 54 | public long getThreadId() { 55 | return threadId; 56 | } 57 | 58 | public void setThreadState(State threadState) { 59 | this.threadState = threadState; 60 | } 61 | 62 | public State getThreadState() { 63 | 64 | // get current thread state 65 | State threadState = threadHelper.getThreadState(threadId); 66 | if (threadState != null) { 67 | // return current thread state 68 | return threadState; 69 | } else { 70 | // return cached thread state 71 | return this.threadState; 72 | } 73 | } 74 | 75 | public void setThreadCpuUsage(double threadCpuUsage) { 76 | this.threadCpuUsage = threadCpuUsage; 77 | } 78 | 79 | public double getThreadCpuUsage() { 80 | return threadCpuUsage; 81 | } 82 | 83 | public String getStackTrace(int maxDepth) { 84 | 85 | return threadHelper.getStackTrace(threadId, maxDepth); 86 | 87 | } 88 | 89 | public String getStackTraceWithContext(int maxDepth) { 90 | 91 | return threadHelper.getStackTraceWithContext(threadId, maxDepth); 92 | 93 | } 94 | 95 | public StackTraceElement[] getStackTraceElements(int maxDepth) { 96 | 97 | return threadHelper.getStackTraceElements(threadId, maxDepth); 98 | 99 | } 100 | 101 | public StackTraceElement[] getStackTraceElements() { 102 | 103 | return threadHelper.getStackTraceElements(threadId); 104 | 105 | } 106 | 107 | public ThreadInfo getThreadInfo() { 108 | return threadInfo; 109 | } 110 | 111 | public void setThreadInfo(ThreadInfo threadInfo) { 112 | this.threadInfo = threadInfo; 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /top4j-javaagent/src/main/java/io/top4j/javaagent/mbeans/jvm/threads/TopThreadMXBean.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 Open Answers Ltd. https://www.openanswers.co.uk 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.top4j.javaagent.mbeans.jvm.threads; 18 | 19 | /** 20 | * Used to store and expose stats relating to a thread that has been determined as a top CPU consumer during the last iteration. 21 | * Each top thread is ranked between 1 and N via the "rank" attribute on the TopThread MBean Object Name, where 1 is the thread 22 | * that has consumed the most CPU and N is the thread that has consumed the least (out of the top ranked threads). 23 | */ 24 | 25 | public interface TopThreadMXBean { 26 | 27 | /** 28 | * Sets the name of the top thread. 29 | * @param threadName the thread name 30 | */ 31 | void setThreadName(String threadName); 32 | 33 | /** 34 | * Returns the name of the top thread. 35 | * @return the thread name 36 | */ 37 | String getThreadName(); 38 | 39 | /** 40 | * Sets the thread ID of the top thread. 41 | * @param threadId the thread ID 42 | */ 43 | void setThreadId(long threadId); 44 | 45 | /** 46 | * Returns the thread ID of the top thread. 47 | * @return the thread ID 48 | */ 49 | long getThreadId(); 50 | 51 | /** 52 | * Sets the thread state as defined by the java.lang.Thread.State Enum. 53 | * @param threadState the thread state 54 | */ 55 | void setThreadState(Thread.State threadState); 56 | 57 | /** 58 | * Returns the thread state as defined by the java.lang.Thread.State Enum. 59 | * @return the thread state 60 | */ 61 | Thread.State getThreadState(); 62 | 63 | /** 64 | * Sets the thread CPU time as a percentage of the total CPU time available during the last iteration. 65 | *

66 | * The thread CPU usage is calculated as the total CPU time consumed by a thread divided by the total CPU time available (wall clock time) multiplied by 100. 67 | * In other words.... ( threadCpuTime / elapsedTime ) * 100 68 | * @param threadCpuUsage the thread CPU usage 69 | */ 70 | void setThreadCpuUsage(double threadCpuUsage); 71 | 72 | /** 73 | * Returns the thread CPU time as a percentage of the total CPU time available during the last iteration. 74 | *

75 | * The thread CPU usage is calculated as the total CPU time consumed by a thread divided by the total CPU time available (wall clock time) multiplied by 100. 76 | * In other words.... ( threadCpuTime / elapsedTime ) * 100 77 | * @return the thread CPU usage 78 | */ 79 | double getThreadCpuUsage(); 80 | 81 | /** 82 | * Returns the stack trace for this top thread with a maximum frame depth of maxDepth. 83 | * @param maxDepth maximum frame depth 84 | * @return a String representation of the stack trace 85 | */ 86 | String getStackTrace(int maxDepth); 87 | 88 | /** 89 | * Returns the stack trace for this blocked thread with context, e.g. thread name and thread state, with a maximum frame depth of maxDepth. 90 | * @param maxDepth maximum frame depth 91 | * @return a String representation of the stack trace with some additional context 92 | */ 93 | String getStackTraceWithContext(int maxDepth); 94 | 95 | } 96 | -------------------------------------------------------------------------------- /top4j-javaagent/src/main/java/io/top4j/javaagent/mbeans/logger/StatsLogWriter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 Open Answers Ltd. https://www.openanswers.co.uk 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.top4j.javaagent.mbeans.logger; 18 | 19 | import java.io.File; 20 | import java.io.FileOutputStream; 21 | import java.io.IOException; 22 | import java.io.PrintWriter; 23 | import java.util.logging.Logger; 24 | 25 | public class StatsLogWriter { 26 | 27 | private PrintWriter printWriter; 28 | private FileOutputStream fileOutputStream; 29 | private String fileName; 30 | 31 | private static final Logger LOGGER = Logger.getLogger(StatsLogWriter.class.getName()); 32 | 33 | public StatsLogWriter(String fileName) throws Exception { 34 | 35 | // init new PrintWriter 36 | init(fileName, null); 37 | } 38 | 39 | public StatsLogWriter(String fileName, String header) throws Exception { 40 | 41 | // init new PrintWriter 42 | init(fileName, header); 43 | } 44 | 45 | private void init(String fileName, String header) throws Exception { 46 | 47 | PrintWriter printWriter = null; 48 | 49 | File file = new File(fileName); 50 | try { 51 | if (!file.exists()) { 52 | // create new file 53 | LOGGER.finer("Creating new stats log file " + fileName); 54 | if (header != null) { 55 | printWriter = createNewFile(file, header); 56 | } else { 57 | printWriter = createNewFile(file, null); 58 | } 59 | } else { 60 | // create new printWriter 61 | LOGGER.finer("Stats log file " + fileName + " already exists."); 62 | fileOutputStream = new FileOutputStream(fileName, true); 63 | printWriter = new PrintWriter(fileOutputStream); 64 | } 65 | 66 | } catch (IOException ioe) { 67 | throw new IllegalAccessException("Unable to create stats log file " + fileName + " due to: " + ioe.getMessage()); 68 | } 69 | 70 | // store print writer 71 | this.printWriter = printWriter; 72 | 73 | // store file name 74 | this.fileName = fileName; 75 | 76 | } 77 | 78 | private PrintWriter createNewFile(File file, String header) throws Exception { 79 | 80 | PrintWriter printWriter = null; 81 | try { 82 | file.createNewFile(); 83 | printWriter = new PrintWriter(new FileOutputStream(file.getAbsolutePath(), true)); 84 | if (header != null) { 85 | printWriter.println(header); 86 | } 87 | } catch (IOException ioe) { 88 | throw new IllegalAccessException("Unable to create stats log file " + fileName + " due to: " + ioe.getMessage()); 89 | } finally { 90 | if (printWriter != null) { 91 | printWriter.flush(); 92 | } 93 | } 94 | return printWriter; 95 | } 96 | 97 | public void println(String logEntry) { 98 | 99 | if (printWriter != null) { 100 | // write logEntry to stats log file via printWriter 101 | printWriter.println(logEntry); 102 | // and flush to disk 103 | printWriter.flush(); 104 | } 105 | } 106 | 107 | public void close() { 108 | 109 | if (printWriter != null) { 110 | // close the printWriter 111 | printWriter.close(); 112 | } 113 | if (fileOutputStream != null) { 114 | // and the fileOutputStream 115 | try { 116 | fileOutputStream.close(); 117 | } catch (IOException ioe) { 118 | LOGGER.severe("Unable to close file output stream for stats log file " + fileName + " due to: " + ioe.getMessage()); 119 | } 120 | } 121 | } 122 | 123 | } 124 | -------------------------------------------------------------------------------- /top4j-javaagent/src/main/java/io/top4j/javaagent/mbeans/logger/StatsLoggerMXBean.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 Open Answers Ltd. https://www.openanswers.co.uk 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.top4j.javaagent.mbeans.logger; 18 | 19 | import io.top4j.javaagent.mbeans.StatsMXBean; 20 | 21 | public interface StatsLoggerMXBean extends StatsMXBean { 22 | 23 | } 24 | -------------------------------------------------------------------------------- /top4j-javaagent/src/main/java/io/top4j/javaagent/messaging/LoggerQueue.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 Open Answers Ltd. https://www.openanswers.co.uk 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.top4j.javaagent.messaging; 18 | 19 | import java.util.concurrent.LinkedBlockingQueue; 20 | import java.util.concurrent.TimeUnit; 21 | import java.util.logging.Logger; 22 | 23 | public class LoggerQueue { 24 | 25 | private LinkedBlockingQueue loggerQueue; 26 | 27 | private static final Logger LOGGER = Logger.getLogger(LoggerQueue.class.getName()); 28 | 29 | public LoggerQueue(int capacity) { 30 | 31 | this.loggerQueue = new LinkedBlockingQueue<>(capacity); 32 | 33 | } 34 | 35 | public boolean send(String notification) { 36 | 37 | // send notification to loggerQueue 38 | return loggerQueue.offer(notification); 39 | 40 | } 41 | 42 | public boolean hasElements() { 43 | 44 | // test if the loggerQueue has elements 45 | if (loggerQueue.isEmpty()) { 46 | return false; 47 | } else { 48 | return true; 49 | } 50 | 51 | } 52 | 53 | public int size() { 54 | 55 | // return the size of the loggerQueue 56 | return loggerQueue.size(); 57 | 58 | } 59 | 60 | public String poll(long timeout) { 61 | 62 | // Retrieve and remove the head of the loggerQueue, or return null if the dispatchQueue is empty 63 | try { 64 | return loggerQueue.poll(timeout, TimeUnit.SECONDS); 65 | } catch (InterruptedException e) { 66 | LOGGER.fine("Logger Queue poll interrupted."); 67 | } 68 | return null; 69 | 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /top4j-javaagent/src/main/java/io/top4j/javaagent/profiler/CPUTimer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 Open Answers Ltd. https://www.openanswers.co.uk 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.top4j.javaagent.profiler; 18 | 19 | import java.lang.management.ManagementFactory; 20 | import java.lang.management.ThreadMXBean; 21 | import java.util.logging.Logger; 22 | 23 | import io.top4j.javaagent.mbeans.logger.StatsLogger; 24 | 25 | public class CPUTimer { 26 | 27 | private long lastCurrentTime; 28 | private long lastCPUTime; 29 | private ThreadMXBean threadMXBean; 30 | 31 | private static final Logger LOGGER = Logger.getLogger(StatsLogger.class.getName()); 32 | 33 | public CPUTimer() { 34 | 35 | ThreadMXBean threadMXBean = 36 | ManagementFactory.getThreadMXBean(); 37 | this.threadMXBean = threadMXBean; 38 | 39 | } 40 | 41 | /* 42 | * start CPU timer 43 | * 44 | */ 45 | public void start() { 46 | 47 | // get current thread CPU time 48 | long cpuTime = threadMXBean.getCurrentThreadCpuTime(); 49 | 50 | // store CPU time 51 | this.lastCPUTime = cpuTime; 52 | 53 | // get current system time 54 | long currentTime = System.nanoTime(); 55 | 56 | // store system time 57 | this.lastCurrentTime = currentTime; 58 | 59 | } 60 | 61 | /* 62 | * stop CPU timer 63 | * 64 | */ 65 | public void stop() { 66 | 67 | // get current thread CPU time 68 | long cpuTime = threadMXBean.getCurrentThreadCpuTime(); 69 | 70 | // get current system time 71 | long currentTime = System.nanoTime(); 72 | 73 | // calculate CPU burn in milliseconds 74 | long cpuBurn = cpuTime - lastCPUTime; 75 | 76 | // calculate elapsed time in milliseconds 77 | long elapsedTime = currentTime - lastCurrentTime; 78 | 79 | // log cpuBurn and elapsedTime 80 | LOGGER.info("CPU Burn = " + cpuBurn + " ns, Elapsed Time = " + elapsedTime + " ns"); 81 | 82 | } 83 | 84 | } 85 | -------------------------------------------------------------------------------- /top4j-javaagent/src/main/java/io/top4j/javaagent/profiler/CpuTime.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 Open Answers Ltd. https://www.openanswers.co.uk 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.top4j.javaagent.profiler; 18 | 19 | import java.lang.management.ManagementFactory; 20 | import java.lang.management.ThreadMXBean; 21 | 22 | public class CpuTime { 23 | 24 | private long lastCPUTime; 25 | private ThreadMXBean threadMXBean; 26 | 27 | public CpuTime() { 28 | 29 | ThreadMXBean threadMXBean = 30 | ManagementFactory.getThreadMXBean(); 31 | this.threadMXBean = threadMXBean; 32 | // initialise CPU time 33 | init(); 34 | 35 | } 36 | 37 | /* 38 | * reset CPU time 39 | * 40 | */ 41 | public void init() { 42 | 43 | // get and store current thread CPU time 44 | this.lastCPUTime = threadMXBean.getCurrentThreadCpuTime(); 45 | 46 | } 47 | 48 | /* 49 | * get CPU time 50 | * 51 | */ 52 | public long get() { 53 | 54 | // get current thread CPU time 55 | long cpuTime = threadMXBean.getCurrentThreadCpuTime(); 56 | 57 | // calculate CPU burn in nanoseconds 58 | long cpuBurn = cpuTime - lastCPUTime; 59 | 60 | return cpuBurn; 61 | 62 | } 63 | 64 | /* 65 | * get CPU time in milliseconds 66 | * 67 | */ 68 | public double getMillis() { 69 | 70 | // get current thread CPU time 71 | long cpuTime = threadMXBean.getCurrentThreadCpuTime(); 72 | 73 | // calculate CPU burn in milliseconds 74 | double cpuBurn = ((double) cpuTime - lastCPUTime) / 1000000; 75 | 76 | return cpuBurn; 77 | 78 | } 79 | 80 | } 81 | -------------------------------------------------------------------------------- /top4j-javaagent/src/main/java/io/top4j/javaagent/test/CollatorTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 Open Answers Ltd. https://www.openanswers.co.uk 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.top4j.javaagent.test; 18 | 19 | import java.util.NavigableMap; 20 | import java.util.Random; 21 | import java.util.TreeMap; 22 | 23 | public class CollatorTest { 24 | 25 | /** 26 | * Run collator test 27 | * @param args list of command-line arguments 28 | */ 29 | public static void main(String[] args) { 30 | 31 | log("Running Collator Test...."); 32 | NavigableMap sortedMap = new TreeMap(); 33 | Random randomGenerator = new Random(); 34 | 35 | for (int idx = 1; idx <= 10; ++idx) { 36 | int randomInt = randomGenerator.nextInt(100000); 37 | long randomLong = randomGenerator.nextLong(); 38 | log("Generated : " + randomLong + " -> " + randomInt); 39 | sortedMap.put(randomLong, randomInt); 40 | } 41 | 42 | for (Long key : sortedMap.descendingKeySet()) { 43 | log(String.valueOf(key) + " -> " + sortedMap.get(key)); 44 | } 45 | 46 | } 47 | 48 | private static void log(String aMessage) { 49 | System.out.println(aMessage); 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /top4j-javaagent/src/main/java/io/top4j/javaagent/test/MemTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 Open Answers Ltd. https://www.openanswers.co.uk 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.top4j.javaagent.test; 18 | 19 | public class MemTest { 20 | 21 | static String DATA = "THIS IS A TEST STRING!! THIS IS A TEST STRING!! THIS IS A TEST STRING!! THIS IS A TEST STRING!! THIS IS A TEST STRING!! THIS IS A TEST STRING!! THIS IS A TEST STRING!! THIS IS A TEST STRING!! THIS IS A TEST STRING!! THIS IS A TEST STRING!! THIS IS A TEST STRING!! THIS IS A TEST STRING!! THIS IS A TEST STRING!! THIS IS A TEST STRING!! THIS IS A TEST STRING!! THIS IS A TEST STRING!! THIS IS A TEST STRING!! THIS IS A TEST STRING!! THIS IS A TEST STRING!! THIS IS A TEST STRING!! THIS IS A TEST STRING!! THIS IS A TEST STRING!! THIS IS A TEST STRING!! THIS IS A TEST STRING!! THIS IS A TEST STRING!! THIS IS A TEST STRING!! THIS IS A TEST STRING!! THIS IS A TEST STRING!! THIS IS A TEST STRING!! THIS IS A TEST STRING!! THIS IS A TEST STRING!! THIS IS A TEST STRING!! THIS IS A TEST STRING!! THIS IS A TEST STRING!! THIS IS A TEST STRING!! THIS IS A TEST STRING!! THIS IS A TEST STRING!! THIS IS A TEST STRING!! THIS IS A TEST STRING!! THIS IS A TEST STRING!!"; 22 | 23 | /** 24 | * Run memory test 25 | * @param args list of command-line arguments 26 | */ 27 | public static void main(String[] args) { 28 | 29 | System.out.println("Firing up JavaAgent memory test...."); 30 | 31 | int iterations = 30000; 32 | 33 | for (int i = 0; i < iterations; i++) { 34 | 35 | churnMemory(); 36 | 37 | try { 38 | Thread.sleep(1); 39 | } catch (InterruptedException e) { 40 | System.err.println("Thread sleep interrupted."); 41 | } 42 | 43 | } 44 | 45 | } 46 | 47 | public static void churnMemory() { 48 | 49 | StringBuilder sb = new StringBuilder(); 50 | int iterations = 100; 51 | 52 | for (int i = 0; i < iterations; i++) { 53 | 54 | sb.append(DATA); 55 | 56 | } 57 | 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /top4j-javaagent/src/main/java/io/top4j/javaagent/test/Test.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 Open Answers Ltd. https://www.openanswers.co.uk 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.top4j.javaagent.test; 18 | 19 | public class Test { 20 | 21 | /** 22 | * Run JavaAgent test 23 | * @param args list of command-line arguments 24 | */ 25 | public static void main(String[] args) { 26 | System.out.println("Firing up JavaAgent test...."); 27 | try { 28 | Thread.sleep(300000); 29 | } catch (InterruptedException e) { 30 | System.err.println("Thread sleep interrupted."); 31 | } 32 | 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /top4j-javaagent/src/main/java/io/top4j/javaagent/utils/GarbageCollectorNames.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 Open Answers Ltd. https://www.openanswers.co.uk 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.top4j.javaagent.utils; 18 | 19 | import io.top4j.javaagent.mbeans.jvm.gc.GarbageCollectorMXBeanHelper; 20 | 21 | import javax.management.MBeanServer; 22 | import java.lang.management.ManagementFactory; 23 | import java.util.List; 24 | 25 | public class GarbageCollectorNames { 26 | 27 | public static void main(String[] args) { 28 | 29 | // list garbage collector names 30 | list(); 31 | } 32 | 33 | private static void list() { 34 | 35 | // get platform MBean server 36 | MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); 37 | 38 | // instantiate new GarbageCollectorMXBeanHelper 39 | GarbageCollectorMXBeanHelper gcMxBeanHelper = null; 40 | try { 41 | gcMxBeanHelper = new GarbageCollectorMXBeanHelper(mbs); 42 | } catch (Exception e) { 43 | System.err.println("ERROR: Unable to initialise GarbageCollectorMXBeanHelper due to : " + e.getMessage()); 44 | } 45 | 46 | // get list of garbage collector names 47 | List gcNames = gcMxBeanHelper.listGarbageCollectorNames(); 48 | 49 | System.out.println("JVM Garbage Collector Names"); 50 | System.out.println("==========================="); 51 | for (String gcName : gcNames) { 52 | 53 | // print mpName to stdout 54 | System.out.println(gcName); 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /top4j-javaagent/src/main/java/io/top4j/javaagent/utils/MBeanInfo.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 Open Answers Ltd. https://www.openanswers.co.uk 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.top4j.javaagent.utils; 18 | 19 | import java.util.Collection; 20 | 21 | import javax.management.ObjectName; 22 | 23 | public class MBeanInfo { 24 | 25 | private ObjectName objectName; 26 | private String keyPropertyList; 27 | private Collection attributeNames; 28 | private String statsType; 29 | 30 | public ObjectName getObjectName() { 31 | return objectName; 32 | } 33 | 34 | public void setObjectName(ObjectName objectName) { 35 | this.objectName = objectName; 36 | } 37 | 38 | public String getKeyPropertyList() { 39 | return keyPropertyList; 40 | } 41 | 42 | public void setKeyPropertyList(String keyPropertyList) { 43 | this.keyPropertyList = keyPropertyList; 44 | } 45 | 46 | public Collection getAttributeNames() { 47 | return attributeNames; 48 | } 49 | 50 | public void setAttributeNames(Collection attributeNames) { 51 | this.attributeNames = attributeNames; 52 | } 53 | 54 | public String getStatsType() { 55 | return statsType; 56 | } 57 | 58 | public void setStatsType(String statsType) { 59 | this.statsType = statsType; 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /top4j-javaagent/src/main/java/io/top4j/javaagent/utils/MemoryPoolNames.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 Open Answers Ltd. https://www.openanswers.co.uk 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.top4j.javaagent.utils; 18 | 19 | import io.top4j.javaagent.mbeans.jvm.memory.MemoryPoolMXBeanHelper; 20 | 21 | import javax.management.MBeanServer; 22 | import java.lang.management.ManagementFactory; 23 | import java.util.List; 24 | 25 | public class MemoryPoolNames { 26 | 27 | public static void main(String[] args) { 28 | 29 | // list memory pool names 30 | list(); 31 | } 32 | 33 | private static void list() { 34 | 35 | // get platform MBean server 36 | MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); 37 | 38 | // instantiate new MemoryPoolMXBeanHelper 39 | MemoryPoolMXBeanHelper memoryPoolMxBeanHelper = null; 40 | try { 41 | memoryPoolMxBeanHelper = new MemoryPoolMXBeanHelper(mbs); 42 | } catch (Exception e) { 43 | System.err.println("ERROR: Unable to initialise MemoryPoolMXBeanHelper due to : " + e.getMessage()); 44 | } 45 | 46 | // get list of memory pool names 47 | List memoryPoolNames = memoryPoolMxBeanHelper.listMemoryPoolNames(); 48 | 49 | System.out.println("JVM Memory Pool Names"); 50 | System.out.println("====================="); 51 | for (String mpName : memoryPoolNames) { 52 | 53 | // print mpName to stdout 54 | System.out.println(mpName); 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /top4j-javaagent/src/test/java/JunitTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 Open Answers Ltd. https://www.openanswers.co.uk 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import org.junit.Test; 18 | 19 | import static org.junit.Assert.assertEquals; 20 | 21 | public class JunitTest { 22 | @Test 23 | public void testJunit() { 24 | String str = "Junit is working fine"; 25 | assertEquals("Junit is working fine", str); 26 | System.out.println("JUnit test complete."); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /top4j-javaagent/src/test/resources/assertion-data.csv: -------------------------------------------------------------------------------- 1 | # 2 | # assertion-data.csv 3 | # 4 | # Fields: 5 | # 6 | # 1. StatsType - the Top4J stats type 7 | # 2. Attribute - the Top4J MBean attribute name 8 | # 3. Comparator - the assertion comparator, where gt = greater than, ge = greater than or equal to, lt = less than, le = less than or equal to, eq = equal to 9 | # 4. AssertionType - the data type of the assertion data 10 | # 5. AssertionData - the assertion data 11 | # 12 | GCStats,GcOverhead,gt,double,0.0 13 | GCStats,MeanNurseryGCTime,gt,double,0.1 14 | GCStats,MeanTenuredGCTime,eq,double,0.0 15 | #GCStats,MBeanCpuTime,gt,double,0.1 16 | MemoryStats,MemoryAllocationRate,gt,double,1.0 17 | MemoryStats,MemoryPromotionRate,ge,double,0.0 18 | MemoryStats,MemorySurvivorRate,gt,double,0.0 19 | #MemoryStats,MBeanCpuTime,gt,double,1.0 20 | HeapStats,EdenSpaceUtil,eq,double,0.0 21 | HeapStats,SurvivorSpaceUtil,gt,double,0.1 22 | HeapStats,TenuredHeapUtil,eq,double,0.0 23 | #HeapStats,MBeanCpuTime,gt,double,0.1 24 | AgentStats,AgentCpuUtil,gt,double,0.0 25 | AgentStats,AgentCpuTime,gt,double,10.0 26 | AgentStats,Iterations,gt,long,0 27 | #AgentStats,MBeanCpuTime,gt,double,0.1 28 | ThreadStats,CpuUsage,gt,double,0.0 29 | ThreadStats,UserCpuUsage,gt,double,0.0 30 | ThreadStats,SysCpuUsage,ge,double,0.0 31 | ThreadStats,ThreadCount,gt,long,10 32 | ThreadStats,RunnableThreadCount,gt,long,1 33 | ThreadStats,BlockedThreadCount,gt,long,1 34 | ThreadStats,WaitingThreadCount,gt,long,1 35 | ThreadStats,TimedWaitingThreadCount,gt,long,0 36 | ThreadStats,MBeanCpuTime,gt,double,10.0 37 | -------------------------------------------------------------------------------- /top4j-javaagent/src/test/scripts/jmapCollector.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # jmapCollector.sh 4 | # 5 | # - collect jmap heap dumps at regular intervals 6 | # 7 | 8 | JVM_PID=$1 9 | JMAP_COMMAND="jmap -histo:live" 10 | INTERVAL=600 11 | 12 | # check args 13 | if [[ ! ${JVM_PID} =~ [0-9]+ ]] 14 | then 15 | echo "USAGE: $0 " 16 | exit 1 17 | fi 18 | 19 | # check JVM_PID is running 20 | if ! `ps -p ${JVM_PID} | grep -q java` 21 | then 22 | echo "ERROR: Unable to find JVM process with PID ${JVM_PID}" 23 | exit 2 24 | fi 25 | 26 | echo "Running jmap heap dumps against JVM PID ${JVM_PID}...." 27 | ps -fp ${JVM_PID} 28 | 29 | i=1 30 | 31 | while true 32 | do 33 | echo "Taking JVM PID ${JVM_PID} heap dump @ `date`" 34 | ${JMAP_COMMAND} ${JVM_PID} > jmap.${JVM_PID}-${i}.txt 35 | if [[ $? -gt 0 ]] 36 | then 37 | echo "ERROR: Problem running jmap command....exiting" 38 | exit 3 39 | fi 40 | (( i=i+1 )) 41 | sleep ${INTERVAL} 42 | done 43 | 44 | -------------------------------------------------------------------------------- /top4j-javaagent/src/test/scripts/listGarbageCollectorNames.sh: -------------------------------------------------------------------------------- 1 | . `dirname $0`/setenv.sh 2 | java -classpath "../../../target/top4j-javaagent-0.0.1-SNAPSHOT.jar" ${JAVA_OPTS} $@ io.top4j.javaagent.utils.GarbageCollectorNames 3 | -------------------------------------------------------------------------------- /top4j-javaagent/src/test/scripts/listMemoryPoolNames.sh: -------------------------------------------------------------------------------- 1 | . `dirname $0`/setenv.sh 2 | java -classpath "../../../target/top4j-javaagent-0.0.1-SNAPSHOT.jar" ${JAVA_OPTS} $@ io.top4j.javaagent.utils.MemoryPoolNames 3 | -------------------------------------------------------------------------------- /top4j-javaagent/src/test/scripts/logging.properties: -------------------------------------------------------------------------------- 1 | ############################################################ 2 | # Default Logging Configuration File 3 | # 4 | # You can use a different file by specifying a filename 5 | # with the java.util.logging.config.file system property. 6 | # For example java -Djava.util.logging.config.file=myfile 7 | ############################################################ 8 | 9 | ############################################################ 10 | # Global properties 11 | ############################################################ 12 | 13 | # "handlers" specifies a comma separated list of log Handler 14 | # classes. These handlers will be installed during VM startup. 15 | # Note that these classes must be on the system classpath. 16 | # By default we only configure a ConsoleHandler, which will only 17 | # show messages at the INFO and above levels. 18 | handlers= java.util.logging.ConsoleHandler 19 | 20 | # To also add the FileHandler, use the following line instead. 21 | #handlers= java.util.logging.FileHandler, java.util.logging.ConsoleHandler 22 | 23 | # Default global logging level. 24 | # This specifies which kinds of events are logged across 25 | # all loggers. For any given facility this global level 26 | # can be overriden by a facility specific level 27 | # Note that the ConsoleHandler also has a separate level 28 | # setting to limit messages printed to the console. 29 | .level= INFO 30 | 31 | ############################################################ 32 | # Handler specific properties. 33 | # Describes specific configuration info for Handlers. 34 | ############################################################ 35 | 36 | # default file output is in user's home directory. 37 | java.util.logging.FileHandler.pattern = %h/java%u.log 38 | java.util.logging.FileHandler.limit = 50000 39 | java.util.logging.FileHandler.count = 1 40 | java.util.logging.FileHandler.formatter = java.util.logging.XMLFormatter 41 | 42 | # Limit the message that are printed on the console to INFO and above. 43 | java.util.logging.ConsoleHandler.level = INFO 44 | java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter 45 | 46 | # Example to customize the SimpleFormatter output format 47 | # to print one-line log message like this: 48 | # : [] 49 | # 50 | # java.util.logging.SimpleFormatter.format=%4$s: %5$s [%1$tc]%n 51 | java.util.logging.SimpleFormatter.format=%4$s %1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS Top4J JavaAgent: %5$s%6$s%n 52 | 53 | ############################################################ 54 | # Facility specific properties. 55 | # Provides extra control for each logger. 56 | ############################################################ 57 | 58 | # For example, set the com.xyz.foo logger to only log SEVERE 59 | # messages: 60 | com.xyz.foo.level = SEVERE 61 | -------------------------------------------------------------------------------- /top4j-javaagent/src/test/scripts/runCollatorTest.sh: -------------------------------------------------------------------------------- 1 | java -classpath "../../../target/top4j-javaagent-0.0.1-SNAPSHOT.jar" io.top4j.javaagent.test.CollatorTest 2 | -------------------------------------------------------------------------------- /top4j-javaagent/src/test/scripts/runMTCMSTest.sh: -------------------------------------------------------------------------------- 1 | export JAVA_OPTS="-XX:+UseConcMarkSweepGC -Xms6m -Xmx6m -XX:+PrintGCTimeStamps -XX:+PrintGCDetails -verbosegc" 2 | `dirname $0`/runMultiThreadedTest.sh $* 3 | -------------------------------------------------------------------------------- /top4j-javaagent/src/test/scripts/runMTG1Test.sh: -------------------------------------------------------------------------------- 1 | export JAVA_OPTS="-XX:+UseG1GC -Xms4m -Xmx4m -XX:+PrintGCTimeStamps -XX:+PrintGCDetails -verbosegc" 2 | `dirname $0`/runMultiThreadedTest.sh $* 3 | -------------------------------------------------------------------------------- /top4j-javaagent/src/test/scripts/runMemReport.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/bash 2 | # 3 | # runMemReport.sh 4 | # 5 | 6 | HEAP_SIZE=$1 7 | 8 | if [[ -z $HEAP_SIZE ]] 9 | then 10 | HEAP_SIZE=128 11 | fi 12 | 13 | RUN_MEM_TEST=`dirname $0`/runMemTest.sh 14 | 15 | # run mem test 16 | 17 | ${RUN_MEM_TEST} ${HEAP_SIZE} 2>&1 | \ 18 | 19 | egrep " Rate|GC Overhead|GC Time" | \ 20 | 21 | gawk ' { 22 | 23 | if ($0 ~ /GC Overhead/) { 24 | 25 | gsub("%", "") 26 | total["gcOverhead"]+=$9 27 | count["gcOverhead"]++ 28 | 29 | } 30 | 31 | if ($0 ~ /Memory Allocation Rate/) { 32 | 33 | total["memAllocRate"]+=$10 34 | count["memAllocRate"]++ 35 | 36 | } 37 | 38 | if ($0 ~ /Memory Survivor Rate/) { 39 | 40 | total["memSurvivorRate"]+=$10 41 | count["memSurvivorRate"]++ 42 | 43 | } 44 | 45 | if ($0 ~ /Memory Promotion Rate/) { 46 | 47 | total["memPromoRate"]+=$10 48 | count["memPromoRate"]++ 49 | 50 | } 51 | 52 | if ($0 ~ /Mean Nursery GC Time/) { 53 | 54 | gsub("ms", "") 55 | total["yGCTime"]+=$11 56 | count["yGCTime"]++ 57 | 58 | } 59 | 60 | if ($0 ~ /Mean Tenured GC Time/) { 61 | 62 | gsub("ms", "") 63 | total["oGCTime"]+=$11 64 | count["oGCTime"]++ 65 | 66 | } 67 | 68 | 69 | } 70 | 71 | END { 72 | 73 | #print "Mean GC Overhead = " total["gcOverhead"]/count["gcOverhead"] "%" 74 | #print "Mean Memory Allocation Rate = " total["memAllocRate"]/count["memAllocRate"] " MB/s" 75 | #print "Mean Survivor Survivor Rate = " total["memSurvivorRate"]/count["memSurvivorRate"] " MB/s" 76 | #print "Mean Survivor Promotion Rate = " total["memPromoRate"]/count["memPromoRate"] " MB/s" 77 | 78 | meanGCOverhead=total["gcOverhead"]/count["gcOverhead"] 79 | meanMemAllocRate=total["memAllocRate"]/count["memAllocRate"] 80 | meanMemSurvivorRate=total["memSurvivorRate"]/count["memSurvivorRate"] 81 | meanMemPromoRate=total["memPromoRate"]/count["memPromoRate"] 82 | meanYGCTime=total["yGCTime"]/count["yGCTime"] 83 | meanOGCTime=total["oGCTime"]/count["oGCTime"] 84 | 85 | print "Mean Memory Allocation Rate, Mean Survivor Survivor Rate, Mean Survivor Promotion Rate, Mean GC Overhead, Mean Nursery GC Time, Mean Tenured GC Time" 86 | print meanMemAllocRate "," meanMemSurvivorRate "," meanMemPromoRate "," meanGCOverhead "," meanYGCTime "," meanOGCTime 87 | 88 | } ' 89 | 90 | exit 91 | 92 | INFO 2014-03-14 21:41:30 Top4J JavaAgent: GC Overhead = 2.6812313803376364% 93 | INFO 2014-03-14 21:41:30 Top4J JavaAgent: Mean Nursery GC Time = 9.0ms 94 | INFO 2014-03-14 21:41:30 Top4J JavaAgent: Mean Tenured GC Time = 0.0ms 95 | INFO 2014-03-14 21:41:31 Top4J JavaAgent: Memory Allocation Rate = 4544.242048216198 MB/s 96 | INFO 2014-03-14 21:41:31 Top4J JavaAgent: Memory Survivor Rate = 14.399205561072494 MB/s 97 | INFO 2014-03-14 21:41:31 Top4J JavaAgent: Memory Promotion Rate = 29.830281050226542 MB/s 98 | 99 | -------------------------------------------------------------------------------- /top4j-javaagent/src/test/scripts/runMemTest.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # runMemTest.sh 4 | # 5 | 6 | HEAP_SIZE=$1 7 | 8 | if [[ -z $HEAP_SIZE ]] 9 | then 10 | HEAP_SIZE=128 11 | fi 12 | 13 | java -Xms${HEAP_SIZE}m -Xmx${HEAP_SIZE}m -XX:+PrintGCTimeStamps -XX:+PrintGCDetails -verbosegc -Djava.util.logging.config.file=logging.properties -Dcom.sun.management.jmxremote -javaagent:../../../target/top4j-javaagent-0.0.9-SNAPSHOT.jar io.top4j.javaagent.test.MemTest 14 | -------------------------------------------------------------------------------- /top4j-javaagent/src/test/scripts/runMultiThreadedTest.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # runMultiThreadedTest.sh 4 | # 5 | # - run Top4J multi-threaded test harness 6 | # 7 | # Arguments: 8 | # 9 | # 1. NUM_THREADS: Number of threads, e.g. 10 10 | # 2. NUM_ITERATIONS: Number of iterations per thread, e.g. 100 11 | # 3. PAUSE_TIME: Pause time between iterations in milliseconds, e.g. 10 12 | # 13 | # Example Usage: 14 | # 15 | # ./runMultiThreadedTest.sh 10 100 10 16 | # 17 | 18 | TOP4J_JAVAAGENT_JAR=`ls -1rt ../../../target/top4j-javaagent-*.jar | tail -1` 19 | ARG_COUNT=$# 20 | NUM_THREADS=$1 21 | NUM_ITERATIONS=$2 22 | PAUSE_TIME=$3 23 | SYNCHRONISED=$4 24 | 25 | if [[ ! -f ${TOP4J_JAVAAGENT_JAR} ]] 26 | then 27 | echo "ERROR: Unable to find Top4J java agent jar." 28 | echo "HINT: Try building the top4j-javaagent Maven project via \"mvn clean package\"" 29 | exit 1 30 | fi 31 | 32 | if [[ ${ARG_COUNT} -ne 3 ]] && [[ ${ARG_COUNT} -ne 4 ]] 33 | then 34 | echo "USAGE: [synchronised]" 35 | exit 1 36 | fi 37 | 38 | java -classpath "${TOP4J_JAVAAGENT_JAR}" -javaagent:${TOP4J_JAVAAGENT_JAR}=test.property=test,top.thread.count=10 -Djava.util.logging.config.file=logging.properties ${JAVA_OPTS} io.top4j.javaagent.test.MultiThreadedTest ${NUM_THREADS} ${NUM_ITERATIONS} ${PAUSE_TIME} ${SYNCHRONISED} 39 | 40 | -------------------------------------------------------------------------------- /top4j-javaagent/src/test/scripts/runMultiThreadedTestNoAgent.sh: -------------------------------------------------------------------------------- 1 | java -classpath "../../../target/top4j-javaagent-0.0.1-SNAPSHOT.jar" -Djava.util.logging.config.file=logging.properties ${JAVA_OPTS} io.top4j.javaagent.test.MultiThreadedTest $* 2 | -------------------------------------------------------------------------------- /top4j-javaagent/src/test/scripts/runSoakTest.sh: -------------------------------------------------------------------------------- 1 | java -classpath "../../../target/top4j-javaagent-0.0.1-SNAPSHOT.jar" -javaagent:../../../target/top4j-javaagent-0.0.1-SNAPSHOT.jar=top.thread.count=10,blocked.thread.count=10,collector.poll.frequency=1000 -Djava.util.logging.config.file=logging.properties ${JAVA_OPTS} io.top4j.javaagent.test.MultiThreadedTest 1000 350 10000 2 | -------------------------------------------------------------------------------- /top4j-javaagent/src/test/scripts/setenv.sh: -------------------------------------------------------------------------------- 1 | # use G1 garbage collector 2 | #export JAVA_OPTS="${JAVA_OPTS} -XX:+UseG1GC" 3 | # use concurrent mark and sweep collecor 4 | #export JAVA_OPTS="${JAVA_OPTS} -XX:+UseConcMarkSweepGC" 5 | -------------------------------------------------------------------------------- /top4j-javaagent/src/test/scripts/top4j.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Top4J configuration file 3 | # 4 | collector.poll.frequency=3000 5 | stats.logger.poll.timeout=600 6 | stats.logger.enabled=true 7 | # stats.logger.format: 8 | # csv or console 9 | stats.logger.format=csv 10 | # stats log directory 11 | stats.logger.directory=top4j-stats 12 | # stats logger log file name date stamp format - the datestamp that appears within the stats log file name 13 | stats.logger.log.file.name.date.format=yyyyMMdd 14 | # stats logger date stamp format 15 | stats.logger.date.format=yyyy-MM-dd'T'HH:mm:ss.SSSZ 16 | # stats logger field separator 17 | stats.logger.field.separator=, 18 | # use this logger.format for debugging 19 | #logger.format=%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS %4$s %2$s: %5$s%6$s%n 20 | # use this logger.format for production 21 | logger.format=%4$s %1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS Top4J JavaAgent: %5$s%6$s%n 22 | # top thread count - the number of top threads to track via TopThreads MBean 23 | top.thread.count=5 24 | # top threads stack trace logging on/off switch 25 | top.threads.stack.trace.logging.enabled=true 26 | # top threads stack trace CPU util threshold 27 | # - log stack trace if CPU util threshold exceeded 28 | top.threads.stack.trace.cpu.threshold=1 29 | # the number of top thread stack frames to log 30 | top.threads.stack.trace.frames=10 31 | # thread contention monitoring on/off switch 32 | thread.contention.monitoring.enabled=true 33 | # blocked thread count - the number of blocked threads to track via BlockedThreads MBean 34 | blocked.thread.count=10 35 | # blocked threads stack trace logging on/off switch 36 | blocked.threads.stack.trace.logging.enabled=true 37 | # blocked threads stack trace blocked percentage threshold 38 | # - log stack trace if blocked percentage threshold exceeded 39 | blocked.threads.stack.trace.blocked.percentage.threshold=10 40 | # the number of blocked thread stack frames to log 41 | blocked.threads.stack.trace.frames=10 42 | # hot method profiling on/off switch 43 | hot.method.profiling.enabled=false 44 | # hot method profiler poll frequency in ms 45 | hot.method.poll.frequency=10 46 | -------------------------------------------------------------------------------- /top4j-javaagent/top4j-javaagent.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /top4j-parent.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | --------------------------------------------------------------------------------