Thread.dump_to_file time
Dr Heinz M. Kabutz
heinz at javaspecialists.eu
Tue Sep 5 20:44:59 UTC 2023
On 2023/09/05 17:18, Alan Bateman wrote:
> On 05/09/2023 12:26, Dr Heinz M. Kabutz wrote:
>>
>> Hi,
>>
>> I was wondering about the cost of generating the thread dumps with
>> jcmd Thread.dump_to_file and how this would affect the practicality
>> of finding issues in thread dumps. I thus spun up more and more
>> virtual threads to see how long it would take to call jcmd
>> Thread.dump_to_file.
>>
>> No surprise that the time is linear. Also no surprise that json is
>> slower to generate than plain.
>>
>> What did surprise me was how much slower it was to generate these on
>> my MacBookPro vs my server. The machines are roughly the same speed,
>> and my MBP has a very fast SSD. I'm not sure why it would be so slow,
>> but the MBP is approximately 3x slower for generating the dumps:
>>
>>
> The Linux vs. macOS difference is surprising but maybe Andrew's guess
> explains it.
>
> As regards the time then some of it maybe related to the formatter,
> can you try the change below and see if it changes the times?
>
> We have prototyped APIs in this area that would allow
> filtering/de-duplication/processing by in-process tools and agents,
> probably something we will get back to at some point.
>
> -Alan
>
> --- a/src/java.base/share/classes/jdk/internal/vm/ThreadDumper.java
> +++ b/src/java.base/share/classes/jdk/internal/vm/ThreadDumper.java
> @@ -160,7 +160,7 @@ private static void dumpThread(Thread thread,
> PrintStream ps) {
> String suffix = thread.isVirtual() ? " virtual" : "";
> ps.format("#%d \"%s\"%s%n", thread.threadId(),
> thread.getName(), suffix);
> for (StackTraceElement ste : thread.getStackTrace()) {
> - ps.format(" %s%n", ste);
> + ps.println(" " + ste);
> }
> ps.println();
> }
> @@ -263,7 +263,7 @@ private static void dumpThreadToJson(Thread
> thread, PrintStream out, boolean mor
> int i = 0;
> StackTraceElement[] stackTrace = thread.getStackTrace();
> while (i < stackTrace.length) {
> - out.format(" \"%s\"",
> escape(stackTrace[i].toString()));
> + out.println(" \"" +
> escape(stackTrace[i].toString()) + "\"");
> i++;
> if (i < stackTrace.length) {
> out.println(",");
Hi Alan,
that makes a huge difference. I love format(), but when we call it
millions of times, it is of course preferable to use the indified String
concatenation.
For 128k virtual threads, I got the time down on Linux from 6s to 3.5s
(plain) and from 8s to 5.7s (json).
We can get it even faster if we turn autoflushing off for the
PrintStreams and convert a few more format()s to print()s (2.9s plain)
https://github.com/kabutz/jdk/blob/faster-thread-dump/src/java.base/share/classes/jdk/internal/vm/ThreadDumper.java
For 2m virtual threads, we reduced the plain time from 1m34s down to 43s.
For the Intel Mac, and 128k virtual threads, the time went down from 18s
to 9s for plain and from 39s to 18s for json. However, I don't give much
weight to the laptop results :-)
The additional cost of logging in JSON format is in proportion to the
size of the files, so I wouldn't worry about that difference too much.
What I am more concerned about is that in my experiment, I had all of
the threads wait whilst I took the thread dump. However, if we follow
the model that each virtual thread is a single task, we might create
them faster than we can dump them, thus getting a situation where the
dump_to_file never ends.
Heinz
More information about the loom-dev
mailing list