Skip to content

Commit eee3ad6

Browse files
authored
Merge pull request #345 from jimklimov/JENKINS-75967
WithThreadName: add a way to disable with a JVM property [JENKINS-75967]
2 parents 66c1843 + 13b7db4 commit eee3ad6

2 files changed

Lines changed: 59 additions & 1 deletion

File tree

README.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,30 @@ This plugin provides APIs that are used by core Pipeline plugins for features su
77
## Version History
88

99
See [the changelog](CHANGELOG.md).
10+
11+
## Caveat emptor
12+
13+
### Overheads of WithThreadName feature
14+
15+
Some consumers of this plugin improve readability of JVM thread dumps by using
16+
the `org.jenkinsci.plugins.workflow.support.concurrent.WithThreadName` feature
17+
to temporarily clarify the purpose of that thread.
18+
19+
This ends up calling `Thread.setName()` => `JVM_SetNativeThreadName()` => some
20+
native OS implementation (via `pthreads` or otherwise), both to enter and exit
21+
a context with this feature.
22+
23+
In some use-cases, e.g. with a generated `parallel` pipeline with hundreds of
24+
stages then waiting in a Jenkins queue for considerable time, this can amount
25+
to tens of thousands of native (not very efficient on some systems) calls per
26+
second just for this troubleshooting aid, and can cause considerable slow-down
27+
of the Jenkins controller.
28+
29+
If you suspect your controller's performance is impacted by this, please
30+
configure a JVM property or context setting
31+
`org.jenkinsci.plugins.workflow.support.concurrent.WithThreadName.enabled=false`
32+
to disable the feature's native calls.
33+
34+
You can still trace attempts to rename the threads by adding a Jenkins log
35+
listener for the class name at `FINE` or louder level, and watching the
36+
log entry stream via Web UI or automatically-rotating files on the controller.

src/main/java/org/jenkinsci/plugins/workflow/support/concurrent/WithThreadName.java

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,20 +24,45 @@
2424

2525
package org.jenkinsci.plugins.workflow.support.concurrent;
2626

27+
import java.lang.*;
28+
import java.util.logging.Logger;
29+
30+
import jenkins.util.SystemProperties;
31+
2732
/**
2833
* Utility to temporarily append some information to the name of the current thread.
2934
* This is helpful for making thread dumps more readable and informative:
3035
* stack trace elements do not contain any information about object identity.
3136
*/
3237
public final class WithThreadName implements AutoCloseable {
33-
38+
/** Save original thread name to recover it in {@link #close} call.
39+
* Remains {@code null} if activity of this class is explicitly not
40+
* {@link #enabled} on a particular deployment.
41+
*/
3442
private final String original;
3543

44+
/** Optional toggle via JVM properties to skip work here,
45+
* and forfeit easy debugging, e.g. on systems where
46+
* java.lang.Thread.setNativeName(Native Method) aka
47+
* JVM_SetNativeThreadName() and further platform
48+
* specific implementation takes inexplicably long.
49+
*/
50+
private final static boolean enabled = SystemProperties.getBoolean(WithThreadName.class.getName() + ".enabled", true);
51+
52+
/** Help gauge how much and how often this code gets called */
53+
private static final Logger LOGGER = Logger.getLogger(WithThreadName.class.getName());
54+
3655
/**
3756
* Sets the current thread’s name.
3857
* @param suffix text to append to the original name
3958
*/
4059
public WithThreadName(String suffix) {
60+
if (!enabled) {
61+
original = null;
62+
LOGGER.fine(() -> "SKIP: Neutered WithThreadName(\"" + (suffix == null ? "(null)" : suffix) + "\")");
63+
return;
64+
}
65+
4166
Thread t = Thread.currentThread();
4267
original = t.getName();
4368
t.setName(original + suffix);
@@ -47,6 +72,12 @@ public WithThreadName(String suffix) {
4772
* Restores the original name.
4873
*/
4974
@Override public void close() {
75+
if (!enabled) {
76+
/* We did not track origin nor suffix here to be fast when skipping, so eh */
77+
LOGGER.fine(() -> "SKIP: Neutered WithThreadName.close()");
78+
return;
79+
}
80+
5081
Thread.currentThread().setName(original);
5182
}
5283

0 commit comments

Comments
 (0)