fusesource / jansi

Jansi is a small java library that allows you to use ANSI escape sequences to format your console output which works even on windows.
http://fusesource.github.io/jansi/
Apache License 2.0
1.11k stars 140 forks source link

use buffer to reduce number of flush() .. (this also needed to use Writer instead of OutputStream/PrintStream) #150

Closed Arnaud-Nauwynck closed 3 years ago

Arnaud-Nauwynck commented 5 years ago

Introducing FlushBufferedWriter between the AnsiPrintSteam and the underlying stdout to reduce the number of flush()

Also introducing similar FlushBufferedOutputSteam in deprecated AnsiOutputStream

Both classes still suffer from a problem of encoding, because they use java.io.OutputStream (to write byte,byte[]) instead of java.io.Writer (to write char,char[],String,CharSequence)

This is very infortunate that in java.io.PrintStream, the class is able to format both text oriented value and byte[] as it extends from java.io.OutputStream. For write(int) and write(int[]) methods, I pretend that the bytes should NOT be interpreted as chars, and should NOT be filtered by ansi escape code. I have HOWEVER left the feature as it was.

For print() and println() values, the class PrintStream formats values as String then encode as byte[] using OutputStreamWriter ... then using jdk-private method flushBuffer() transfers byte[] to the underlying OutputStream without flushing. This is the same logic to overwrite in the class jansi FilterPrintStream, using the same buffer mechanism.

Fragments of jdk code for flushBuffer() is copied here is this PR to allow both proper interpretation of char encoding, then avoid to many flush() on underlying stdout.

Arnaud-Nauwynck commented 5 years ago

I have split parts of the work done on my fork repo into several independent PRs, as asked by @hboutemy

This is the most important commit in terms of performance improvment.

There are still more PRs for me to submit if you want to also apply the refactoring to cleanup code duplication.

Please let me know if this work is worth doing it, if there is a chance you merge my pull-requests

This includes:

Dunemaster commented 5 years ago

@Arnaud-Nauwynck , what do you intend to do with the PR? Will you fix the conflicts?

Thank you

Arnaud-Nauwynck commented 4 years ago

Hi @Dunemaster

Sorry for being so long after your comments on Aug 3. I have merged the conflicts. Can you have a look? Notice I still have other PRs to rebase after this commit... in particular for using Writer(char) instead of OutputStream(byte) To test performance improvments, you need for example PR#149

Regards, Arnaud

Arnaud-Nauwynck commented 4 years ago

I have run the benchmark-test provided in PR#149 with and without the optim for this PR

mvn package cd benchmark-test java -cp "target/benchmark-test-1.19-SNAPSHOT.jar;../jansi/target/jansi-1.19-SNAPSHOT.jar" org.fusesource.jansi.BenchmarkMain

here are the results on a windows cmd.exe or powershell

-------- with optim buffer-write, in windows powershell terminal loop Stdout Before 5x100 took 40ms loop Jansi 5x100 took 199ms loop Stdout 5x100 took 47ms loop Jansi BigLines 5x100 took 148ms loop Stdout BigLines 5x100 took 6ms loop Jansi NoFlush 5x100 took 188ms loop Stdout NoFlush 5x100 took 16ms loop Overhead ansi + JansiPrintSteam 5x100 took 9ms loop Overhead Raw JansiPrintSteam 5x100 took 0ms count flush() ansi+JansiPrintStream 5x100 : 502 count flush() raw+JansiPrintStream 5x100 : 502

--------- witout the optim, in windows powershell terminal lloop Stdout Before 5x100 took 33ms loop Jansi 5x100 took 462ms loop Stdout 5x100 took 338ms loop Jansi BigLines 5x100 took 698ms loop Stdout BigLines 5x100 took 656ms loop Jansi NoFlush 5x100 took 527ms loop Stdout NoFlush 5x100 took 412ms loop Overhead ansi + JansiPrintSteam 5x100 took 15ms loop Overhead Raw JansiPrintSteam 5x100 took 7ms count flush() ansi+JansiPrintStream 5x100 : 2 count flush() raw+JansiPrintStream 5x100 : 2

--------- with the optim, and running with PASS_THROUGH mode on ConsoleEmu loop Stdout Before 5x100 took 136ms loop Jansi 5x100 took 422ms

interpretation: doing some printlns in windows powershell terminal without jansi : 40ms, with jansi : 462ms with jansi optimized: 199ms => there is an overhead when using jansi... but the optimization of this PR make it x2.5 faster than without

The performance is dependent on the terminal screen size (reducing to the minimum make it faster..). but jansi without the optim still have huge overhead (527ms) ... with the optim, the overhead is smaller (137ms) This is the worst case for jansi without the optim, showing an overhead of ~x20 slower than println !!

Summary:

The optimization of this PR make it x2.5 faster than without Jansi still have a significant overhead compared to println ~x2 ... so maybe more optimisations to come.

gnodet commented 3 years ago

Fixed by https://github.com/fusesource/jansi/commit/57aa84d4120395922458f61f20e741198f051087