diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml
index 68299d5..37a4d8c 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.yml
+++ b/.github/ISSUE_TEMPLATE/bug_report.yml
@@ -14,9 +14,9 @@ body:
attributes:
label: "Checklist"
options:
- - label: "I am able to reproduce the bug with the [latest version](https://github.com/xdev-software/template-placeholder/releases/latest)"
+ - label: "I am able to reproduce the bug with the [latest version](https://github.com/xdev-software/hierarchical-stopwatch/releases/latest)"
required: true
- - label: "I made sure that there are *no existing issues* - [open](https://github.com/xdev-software/template-placeholder/issues) or [closed](https://github.com/xdev-software/template-placeholder/issues?q=is%3Aissue+is%3Aclosed) - which I could contribute my information to."
+ - label: "I made sure that there are *no existing issues* - [open](https://github.com/xdev-software/hierarchical-stopwatch/issues) or [closed](https://github.com/xdev-software/hierarchical-stopwatch/issues?q=is%3Aissue+is%3Aclosed) - which I could contribute my information to."
required: true
- label: "I have taken the time to fill in all the required details. I understand that the bug report will be dismissed otherwise."
required: true
diff --git a/.github/ISSUE_TEMPLATE/enhancement.yml b/.github/ISSUE_TEMPLATE/enhancement.yml
index 7523129..2949bb3 100644
--- a/.github/ISSUE_TEMPLATE/enhancement.yml
+++ b/.github/ISSUE_TEMPLATE/enhancement.yml
@@ -12,7 +12,7 @@ body:
attributes:
label: "Checklist"
options:
- - label: "I made sure that there are *no existing issues* - [open](https://github.com/xdev-software/template-placeholder/issues) or [closed](https://github.com/xdev-software/template-placeholder/issues?q=is%3Aissue+is%3Aclosed) - which I could contribute my information to."
+ - label: "I made sure that there are *no existing issues* - [open](https://github.com/xdev-software/hierarchical-stopwatch/issues) or [closed](https://github.com/xdev-software/hierarchical-stopwatch/issues?q=is%3Aissue+is%3Aclosed) - which I could contribute my information to."
required: true
- label: "I have taken the time to fill in all the required details. I understand that the feature request will be dismissed otherwise."
required: true
diff --git a/.github/ISSUE_TEMPLATE/question.yml b/.github/ISSUE_TEMPLATE/question.yml
index 6ecd6ad..e6c1707 100644
--- a/.github/ISSUE_TEMPLATE/question.yml
+++ b/.github/ISSUE_TEMPLATE/question.yml
@@ -12,7 +12,7 @@ body:
attributes:
label: "Checklist"
options:
- - label: "I made sure that there are *no existing issues* - [open](https://github.com/xdev-software/template-placeholder/issues) or [closed](https://github.com/xdev-software/template-placeholder/issues?q=is%3Aissue+is%3Aclosed) - which I could contribute my information to."
+ - label: "I made sure that there are *no existing issues* - [open](https://github.com/xdev-software/hierarchical-stopwatch/issues) or [closed](https://github.com/xdev-software/hierarchical-stopwatch/issues?q=is%3Aissue+is%3Aclosed) - which I could contribute my information to."
required: true
- label: "I have taken the time to fill in all the required details. I understand that the question will be dismissed otherwise."
required: true
diff --git a/.run/Run Demo.run.xml b/.run/Run Demo.run.xml
index 5fb2bc2..111c392 100644
--- a/.run/Run Demo.run.xml
+++ b/.run/Run Demo.run.xml
@@ -1,7 +1,7 @@
-
+
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e69de29..36e5456 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -0,0 +1,9 @@
+# 1.1.1
+* Minor performance improvements
+* Update dependencies
+
+# 1.1.0
+* Consolidated ``AutoCloseable`` into ``HierarchicalStopWatch``
+
+# 1.0.0
+Initial release
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index be2a186..4a5ffe8 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -34,10 +34,10 @@ You should have the following things installed:
* Ensure that the JDK/Java-Version is correct
-## Releasing [![Build](https://img.shields.io/github/actions/workflow/status/xdev-software/template-placeholder/release.yml?branch=master)](https://github.com/xdev-software/template-placeholder/actions/workflows/release.yml)
+## Releasing [![Build](https://img.shields.io/github/actions/workflow/status/xdev-software/hierarchical-stopwatch/release.yml?branch=master)](https://github.com/xdev-software/hierarchical-stopwatch/actions/workflows/release.yml)
Before releasing:
-* Consider doing a [test-deployment](https://github.com/xdev-software/template-placeholder/actions/workflows/test-deploy.yml?query=branch%3Adevelop) before actually releasing.
+* Consider doing a [test-deployment](https://github.com/xdev-software/hierarchical-stopwatch/actions/workflows/test-deploy.yml?query=branch%3Adevelop) before actually releasing.
* Check the [changelog](CHANGELOG.md)
If the ``develop`` is ready for release, create a pull request to the ``master``-Branch and merge the changes
diff --git a/README.md b/README.md
index eccf80b..3e3c286 100644
--- a/README.md
+++ b/README.md
@@ -1,12 +1,39 @@
-[![Latest version](https://img.shields.io/maven-central/v/software.xdev/template-placeholder?logo=apache%20maven)](https://mvnrepository.com/artifact/software.xdev/template-placeholder)
-[![Build](https://img.shields.io/github/actions/workflow/status/xdev-software/template-placeholder/check-build.yml?branch=develop)](https://github.com/xdev-software/template-placeholder/actions/workflows/check-build.yml?query=branch%3Adevelop)
-[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=xdev-software_template-placeholder&metric=alert_status)](https://sonarcloud.io/dashboard?id=xdev-software_template-placeholder)
+[![Latest version](https://img.shields.io/maven-central/v/software.xdev/hierarchical-stopwatch?logo=apache%20maven)](https://mvnrepository.com/artifact/software.xdev/hierarchical-stopwatch)
+[![Build](https://img.shields.io/github/actions/workflow/status/xdev-software/hierarchical-stopwatch/check-build.yml?branch=develop)](https://github.com/xdev-software/hierarchical-stopwatch/actions/workflows/check-build.yml?query=branch%3Adevelop)
+[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=xdev-software_hierarchical-stopwatch&metric=alert_status)](https://sonarcloud.io/dashboard?id=xdev-software_hierarchical-stopwatch)
-# template-placeholder
+# hierarchical-stopwatch
+A hierarchical Java stopwatch that supports nesting and can be used to track performance across methods and classes. It also supports async.
+
+Example output:
+```
+-------------------------------
+Root Parent Task
+-------------------------------
+100,00% 100,00% - Run dummy [42ms]
+ 11,20% 11,20% - Launch tasks [5ms]
+ 88,74% 88,74% - Wait for tasks [38ms]
+ ASYNC ASYNC - Process 1 [11ms]
+ 12,45% 46,81% - Fetch [5ms]
+ 14,01% 52,70% - Process [6ms]
+ 0,13% 0,49% ? unspecified [0ms]
+ ASYNC ASYNC - Process 2 [32ms]
+ 12,44% 16,36% - Fetch [5ms]
+ 49,53% 65,14% - Process [21ms]
+ 13,95% 18,35% - Finalize [6ms]
+ 0,11% 0,14% ? unspecified [0ms]
+ ASYNC ASYNC - Process 3 [22ms]
+ 12,44% 23,71% - Fetch [5ms]
+ 39,99% 76,20% - Process [17ms]
+ 0,05% 0,10% ? unspecified [0ms]
+ 0,06% 0,06% ? unspecified [0ms]
+```
+
+An [usage example is available in the demo project](./hierarchical-stopwatch-demo/src/main/java/software/xdev/Application.java).
## Installation
-[Installation guide for the latest release](https://github.com/xdev-software/template-placeholder/releases/latest#Installation)
+[Installation guide for the latest release](https://github.com/xdev-software/hierarchical-stopwatch/releases/latest#Installation)
## Support
If you need support as soon as possible and you can't wait for any pull request, feel free to use [our support](https://xdev.software/en/services/support).
@@ -15,4 +42,4 @@ If you need support as soon as possible and you can't wait for any pull request,
See the [contributing guide](./CONTRIBUTING.md) for detailed instructions on how to get started with our project.
## Dependencies and Licenses
-View the [license of the current project](LICENSE) or the [summary including all dependencies](https://xdev-software.github.io/template-placeholder/dependencies)
+View the [license of the current project](LICENSE) or the [summary including all dependencies](https://xdev-software.github.io/hierarchical-stopwatch/dependencies)
diff --git a/SECURITY.md b/SECURITY.md
index 34b9514..59faafd 100644
--- a/SECURITY.md
+++ b/SECURITY.md
@@ -2,4 +2,4 @@
## Reporting a Vulnerability
-Please report a security vulnerability [on GitHub Security Advisories](https://github.com/xdev-software/template-placeholder/security/advisories/new).
+Please report a security vulnerability [on GitHub Security Advisories](https://github.com/xdev-software/hierarchical-stopwatch/security/advisories/new).
diff --git a/template-placeholder-demo/pom.xml b/hierarchical-stopwatch-demo/pom.xml
similarity index 90%
rename from template-placeholder-demo/pom.xml
rename to hierarchical-stopwatch-demo/pom.xml
index 1af633c..493b84b 100644
--- a/template-placeholder-demo/pom.xml
+++ b/hierarchical-stopwatch-demo/pom.xml
@@ -6,12 +6,12 @@
software.xdev
- template-placeholder-root
- 1.0.0-SNAPSHOT
+ hierarchical-stopwatch-root
+ 1.1.2-SNAPSHOT
- template-placeholder-demo
- 1.0.0-SNAPSHOT
+ hierarchical-stopwatch-demo
+ 1.1.2-SNAPSHOT
jar
@@ -32,7 +32,7 @@
software.xdev
- template-placeholder
+ hierarchical-stopwatch
${project.version}
diff --git a/hierarchical-stopwatch-demo/src/main/java/software/xdev/Application.java b/hierarchical-stopwatch-demo/src/main/java/software/xdev/Application.java
new file mode 100644
index 0000000..b1d8a22
--- /dev/null
+++ b/hierarchical-stopwatch-demo/src/main/java/software/xdev/Application.java
@@ -0,0 +1,72 @@
+package software.xdev;
+
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+import java.util.stream.IntStream;
+
+import software.xdev.time.HierarchicalLoggingStopWatch;
+import software.xdev.time.HierarchicalStopWatch;
+
+
+public final class Application
+{
+ @SuppressWarnings("java:S106")
+ public static void main(final String[] args)
+ {
+ try(final HierarchicalStopWatch dummySw = HierarchicalLoggingStopWatch.createStarted(
+ "Run dummy",
+ System.out::println, // Could also be LOGGER::debug
+ true)) // Could also be LOGGER.isDebugEnabled()
+ {
+ final List> completableFutures;
+ try(final HierarchicalStopWatch ignored = dummySw.nested("Launch tasks"))
+ {
+ completableFutures = IntStream.of(1, 2, 3)
+ .mapToObj(i -> CompletableFuture.runAsync(() -> {
+ try(final var processSw = dummySw.nested("Process " + i, true))
+ {
+ try(final var ignore = processSw.nested("Fetch"))
+ {
+ sleep(5);
+ }
+
+ try(final var ignore = processSw.nested("Process"))
+ {
+ sleep(i * 5);
+ }
+
+ if(i % 2 == 0)
+ {
+ try(final var ignore = processSw.nested("Finalize"))
+ {
+ sleep(5);
+ }
+ }
+ }
+ }))
+ .toList();
+ }
+
+ try(final HierarchicalStopWatch ignore = dummySw.nested("Wait for tasks"))
+ {
+ completableFutures.forEach(CompletableFuture::join);
+ }
+ }
+ }
+
+ private static void sleep(final int ms)
+ {
+ try
+ {
+ Thread.sleep(ms);
+ }
+ catch(final InterruptedException iex)
+ {
+ Thread.currentThread().interrupt();
+ }
+ }
+
+ private Application()
+ {
+ }
+}
diff --git a/template-placeholder/pom.xml b/hierarchical-stopwatch/pom.xml
similarity index 92%
rename from template-placeholder/pom.xml
rename to hierarchical-stopwatch/pom.xml
index 2155875..a38fa61 100644
--- a/template-placeholder/pom.xml
+++ b/hierarchical-stopwatch/pom.xml
@@ -5,20 +5,20 @@
4.0.0
software.xdev
- template-placeholder
- 1.0.0-SNAPSHOT
+ hierarchical-stopwatch
+ 1.1.2-SNAPSHOT
jar
- template-placeholder
- template-placeholder
- https://github.com/xdev-software/template-placeholder
+ hierarchical-stopwatch
+ hierarchical-stopwatch
+ https://github.com/xdev-software/hierarchical-stopwatch
- https://github.com/xdev-software/template-placeholder
- scm:git:https://github.com/xdev-software/template-placeholder.git
+ https://github.com/xdev-software/hierarchical-stopwatch
+ scm:git:https://github.com/xdev-software/hierarchical-stopwatch.git
- 2023
+ 2024
XDEV Software
@@ -84,6 +84,14 @@
+
+
+ org.apache.commons
+ commons-lang3
+ 3.17.0
+
+
+
diff --git a/hierarchical-stopwatch/src/main/java/software/xdev/time/HierarchicalLoggingStopWatch.java b/hierarchical-stopwatch/src/main/java/software/xdev/time/HierarchicalLoggingStopWatch.java
new file mode 100644
index 0000000..bf6bfda
--- /dev/null
+++ b/hierarchical-stopwatch/src/main/java/software/xdev/time/HierarchicalLoggingStopWatch.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright © 2024 XDEV Software (https://xdev.software)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package software.xdev.time;
+
+import java.util.function.Consumer;
+
+
+/**
+ * Same as {@link HierarchicalStopWatch} but with a Consumer that handles
+ * {@link HierarchicalStopWatch#getPrettyPrinted()}
+ *
+ * @see HierarchicalStopWatch
+ */
+public class HierarchicalLoggingStopWatch extends HierarchicalStopWatch
+{
+ protected final Consumer logConsumer;
+
+ public HierarchicalLoggingStopWatch(
+ final String taskName,
+ final Consumer logConsumer,
+ final boolean async,
+ final boolean enabled)
+ {
+ super(taskName, async, enabled);
+ this.logConsumer = logConsumer;
+ }
+
+ @Override
+ public void close()
+ {
+ super.close();
+ this.stopAll();
+ if(this.isEnabled())
+ {
+ this.logConsumer.accept(this.getPrettyPrinted());
+ }
+ }
+
+ public static HierarchicalLoggingStopWatch createStarted(
+ final String taskName,
+ final Consumer logConsumer,
+ final boolean async,
+ final boolean enabled)
+ {
+ final HierarchicalLoggingStopWatch sw = new HierarchicalLoggingStopWatch(taskName, logConsumer, async,
+ enabled);
+ sw.start();
+ return sw;
+ }
+
+ public static HierarchicalLoggingStopWatch createStarted(
+ final String taskName,
+ final Consumer logConsumer,
+ final boolean enabled)
+ {
+ return createStarted(taskName, logConsumer, false, enabled);
+ }
+}
diff --git a/hierarchical-stopwatch/src/main/java/software/xdev/time/HierarchicalStopWatch.java b/hierarchical-stopwatch/src/main/java/software/xdev/time/HierarchicalStopWatch.java
new file mode 100644
index 0000000..3a56574
--- /dev/null
+++ b/hierarchical-stopwatch/src/main/java/software/xdev/time/HierarchicalStopWatch.java
@@ -0,0 +1,351 @@
+/*
+ * Copyright © 2024 XDEV Software (https://xdev.software)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package software.xdev.time;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+import org.apache.commons.lang3.time.StopWatch;
+
+
+/**
+ * Presents a hierarchical StopWatch
+ *
+ * Example:
+ *
+ * {@code
+ * 100,00% 100,00% - getIssueInfos[keys=[X-1000]] [391ms]
+ * 0,11% 0,11% - Check cache [0ms]
+ * 98,78% 98,78% - Get results of async processes [386ms]
+ * ASYNC ASYNC - Process issue[key=X-1000] async [386ms]
+ * 98,70% 100,00% - getIssueInfoByKeyInternal[key=X-1000] [386ms]
+ * 98,66% 99,96% - Fetch data [386ms]
+ * 98,22% 99,55% - getIssueByKey[key=X-1000] [384ms]
+ * 0,44% 0,45% ? unspecified [2ms]
+ * 0,03% 0,03% - Wait for hierarchy-asyncs [0ms]
+ * 0,00% 0,00% ? unspecified [0ms]
+ * 0,00% 0,00% ? unspecified [0ms]
+ * 0,38% 0,38% - Put cache [2ms]
+ * 0,73% 0,73% ? unspecified [3ms]
+ * }
+ *
+ *
+ */
+public class HierarchicalStopWatch implements AutoCloseable
+{
+ protected static final double NANOS_TO_MILLIS_FACTOR = 1000000.0;
+
+ protected final String taskName;
+ protected final boolean async;
+ protected final boolean enabled;
+
+ protected final StopWatch sw = new StopWatch();
+
+ protected final List nestedProfilers = Collections.synchronizedList(new ArrayList<>());
+
+ public HierarchicalStopWatch(final String taskName, final boolean async, final boolean enabled)
+ {
+ super();
+
+ this.taskName = Objects.requireNonNull(taskName);
+ this.async = async;
+ this.enabled = enabled;
+ }
+
+ public HierarchicalStopWatch(final String taskName, final boolean async)
+ {
+ this(taskName, async, true);
+ }
+
+ public HierarchicalStopWatch(final String taskName)
+ {
+ this(taskName, false);
+ }
+
+ protected String gettaskName()
+ {
+ return this.taskName;
+ }
+
+ public StopWatch getStopWatch()
+ {
+ return this.sw;
+ }
+
+ protected boolean isEnabled()
+ {
+ return this.enabled;
+ }
+
+ protected boolean isAsync()
+ {
+ return this.async;
+ }
+
+ protected boolean isNotAsync()
+ {
+ return !this.isAsync();
+ }
+
+ public void start()
+ {
+ if(!this.isEnabled())
+ {
+ return;
+ }
+ this.sw.start();
+ }
+
+ public void stop()
+ {
+ if(!this.sw.isStopped())
+ {
+ this.sw.stop();
+ }
+ }
+
+ @Override
+ public void close()
+ {
+ this.stop();
+ }
+
+ /**
+ * Tries to stop all nested profilers
+ */
+ public void stopAll()
+ {
+ this.stop();
+ for(final HierarchicalStopWatch hsw : this.nestedProfilers)
+ {
+ hsw.stopAll();
+ }
+ }
+
+ protected void addNested(final HierarchicalStopWatch nested, final boolean start)
+ {
+ if(!this.isEnabled())
+ {
+ return;
+ }
+
+ this.nestedProfilers.add(nested);
+
+ if(start)
+ {
+ nested.start();
+ }
+ }
+
+ /**
+ * Creates a new nested profiler
+ */
+ public HierarchicalStopWatch nested(final String taskName, final boolean async)
+ {
+ final HierarchicalStopWatch nested = new HierarchicalStopWatch(taskName, async, this.isEnabled());
+ this.addNested(nested, true);
+ return nested;
+ }
+
+ /**
+ * Creates a new nested profiler
+ */
+ public HierarchicalStopWatch nested(final String taskName)
+ {
+ return this.nested(taskName, false);
+ }
+
+ public String getPrettyPrinted()
+ {
+ if(!this.isEnabled())
+ {
+ return "";
+ }
+
+ final StringBuilder sb = new StringBuilder(100);
+ sb.append(System.lineSeparator())
+ .append("-------------------------------")
+ .append(System.lineSeparator())
+ .append("Root Parent Task")
+ .append(System.lineSeparator())
+ .append("-------------------------------")
+ .append(System.lineSeparator());
+
+ final long rootNanos = this.sw.getNanoTime();
+
+ sb.append(new TaskEntry(
+ rootNanos,
+ rootNanos,
+ 0,
+ "-",
+ this.gettaskName(),
+ rootNanos).format());
+ this.addNestedToStrBuilder(sb, rootNanos, 1);
+
+ return sb.toString();
+ }
+
+ protected void addNestedToStrBuilder(
+ final StringBuilder sb,
+ final long rootNanos,
+ final int hierarchicalPosition)
+ {
+ final Map> hierach =
+ this.nestedProfilers.stream().collect(
+ Collectors.groupingBy(
+ HierarchicalStopWatch::gettaskName,
+ LinkedHashMap::new,
+ Collectors.toList()));
+
+ final long currentNanos = this.sw.getNanoTime();
+
+ long leftNanos = currentNanos;
+ for(final Entry> entry : hierach.entrySet())
+ {
+ final long groupMinNanos = entry.getValue()
+ .stream()
+ .mapToLong(hsw -> hsw.getStopWatch().getNanoTime())
+ .min()
+ .orElse(0);
+ final long groupMaxNanos = entry.getValue()
+ .stream()
+ .mapToLong(hsw -> hsw.getStopWatch().getNanoTime())
+ .max()
+ .orElse(0);
+
+ final int count = entry.getValue().size();
+
+ final long groupNestedNanos = entry.getValue()
+ .stream()
+ .mapToLong(hsw -> hsw.getStopWatch().getNanoTime())
+ .sum();
+
+ sb.append(new TaskEntry(
+ rootNanos,
+ currentNanos,
+ hierarchicalPosition,
+ "-",
+ entry.getKey(),
+ count,
+ groupMinNanos,
+ groupMaxNanos,
+ groupNestedNanos,
+ entry.getValue().stream().anyMatch(HierarchicalStopWatch::isAsync)).format());
+
+ final long groupNestedNanosNotAsync = entry.getValue()
+ .stream()
+ .filter(HierarchicalStopWatch::isNotAsync)
+ .mapToLong(hsw -> hsw.getStopWatch().getNanoTime())
+ .sum();
+ leftNanos -= groupNestedNanosNotAsync;
+
+ for(final HierarchicalStopWatch hsw : entry.getValue())
+ {
+ hsw.addNestedToStrBuilder(sb, rootNanos, hierarchicalPosition + 1);
+ }
+ }
+
+ if(!hierach.isEmpty())
+ {
+ sb.append(new TaskEntry(
+ rootNanos,
+ currentNanos,
+ hierarchicalPosition,
+ "?",
+ "unspecified",
+ leftNanos).format());
+ }
+ }
+
+ public static HierarchicalStopWatch createStarted(final String taskName)
+ {
+ final HierarchicalStopWatch sw = new HierarchicalStopWatch(taskName);
+ sw.start();
+ return sw;
+ }
+
+ protected record TaskEntry(
+ long rootNanos,
+ long parentNanos,
+ int hierarchicalPosition,
+ String delimiter,
+ String taskName,
+ long count,
+ long minNanos,
+ long maxNanos,
+ long currentNanos,
+ boolean async
+ )
+ {
+ public TaskEntry(
+ final long rootNanos,
+ final long parentNanos,
+ final int hierarchicalPosition,
+ final String delimiter,
+ final String taskName,
+ final long currentNanos)
+ {
+ this(
+ rootNanos,
+ parentNanos,
+ hierarchicalPosition,
+ delimiter,
+ taskName,
+ 0,
+ 0,
+ 0,
+ currentNanos,
+ false
+ );
+ }
+
+ public String format()
+ {
+ final String percentFormat = "%6.2f%%";
+ final String asyncPercent = " ASYNC";
+
+ final String multipleInfo = this.count() <= 1
+ ? ""
+ : String.format(
+ "; %dx; min=%.0fms; max=%.0fms",
+ this.count(),
+ this.minNanos() / NANOS_TO_MILLIS_FACTOR,
+ this.maxNanos() / NANOS_TO_MILLIS_FACTOR);
+
+ final double currentNanosDouble = this.currentNanos();
+ return String.format(
+ "%s%s %s %s %s [%.0fms%s]%s",
+ " ".repeat(this.hierarchicalPosition()),
+ this.async()
+ ? asyncPercent
+ : String.format(percentFormat, currentNanosDouble / this.rootNanos() * 100.0),
+ this.async()
+ ? asyncPercent
+ : String.format(percentFormat, currentNanosDouble / this.parentNanos() * 100.0),
+ this.delimiter(),
+ this.taskName(),
+ currentNanosDouble / NANOS_TO_MILLIS_FACTOR,
+ multipleInfo,
+ System.lineSeparator());
+ }
+ }
+}
diff --git a/pom.xml b/pom.xml
index d069dc6..3d1166c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,8 +5,8 @@
4.0.0
software.xdev
- template-placeholder-root
- 1.0.0-SNAPSHOT
+ hierarchical-stopwatch-root
+ 1.1.2-SNAPSHOT
pom
@@ -15,8 +15,8 @@
- template-placeholder
- template-placeholder-demo
+ hierarchical-stopwatch
+ hierarchical-stopwatch-demo
diff --git a/renovate.json5 b/renovate.json5
index 2874d45..487db4e 100644
--- a/renovate.json5
+++ b/renovate.json5
@@ -4,7 +4,7 @@
"packageRules": [
{
"description": "Ignore project internal dependencies",
- "packagePattern": "^software.xdev:template-placeholder",
+ "packagePattern": "^software.xdev:hierarchical-stopwatch",
"datasources": [
"maven"
],