Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Drop usage of FileInput/OutputStreams - modules a* -> c* #295

Closed
wants to merge 1 commit into from

Conversation

mdindoffer
Copy link
Contributor

This change drops the usage of FileInputStream and FileOutputStream
in cluster modules "a*" through "c*".
The FIS/FOS are putting unnecesary pressure on the GC because of their finalize() method.
I've measured small, but fairly consistent improvements in GC pauses during the startup of the IDE with couple of projects opened:
Before: http://gceasy.io/my-gc-report.jsp?p=c2hhcmVkLzIwMTcvMTEvMjYvLS1nYXJiYWdlLWNvbGxlY3Rpb24tYmVmb3JlLXN0YXJ0dXAubG9nLS0yMC0xMS01OQ==
After: http://gceasy.io/my-gc-report.jsp?p=c2hhcmVkLzIwMTcvMTEvMjYvLS1nYXJiYWdlLWNvbGxlY3Rpb24tYWZ0ZXIxY29tbWl0LXN0YXJ0dXAubG9nLS0yMC0xMy01Mw==
In every module that required it (for the "Files" class workaround), theres a bump in javac source to version 7. Where appropriate I took the liberty of using try with resources blocks.
I may have also fixed a resource leak somewhere in there.
Further references: see JDK-8080225, HDFS-8526, JENKINS-42934

Copy link
Member

@emilianbold emilianbold left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks pretty. Was it manually done or do you have some .hints file to apply?

I wouldn't apply these alphabetically but per cluster or somewhat more logically.

For example, the theoretical speedup might only have happened due to a change in the core Platform modules.

Personally I would also split in separate patches the try-with-resources (which I like) and the java.nio.file.File usage (which I understand it must be more efficient but don't like so much).

}
// corrupted cache file, throw the cache away
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment seems to belong in the catch ClassNotFoundException block.

XMLUtil.LOG.log(Level.FINE, "Closing output stream for {0}", file);
super.close();
XMLUtil.LOG.log(
Level.INFO, "File installed {0}@{1}",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This logger here seems useful.

@@ -155,24 +156,24 @@ public void storeLicense(String name, String content) {

private String readLicenseFile(String name) {
File file = getLicenseFile(name);
FileInputStream fr = null;
InputStream is = null;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not preserve the fr name?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because the "fr" implies FileReader, which it is not. The fr naming is not really consistent with the naming in the rest of the modules I made changes at.

try {
fr.close();
is.close();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No try-with-resources here?

@@ -43,8 +45,9 @@
try {
File debugLog = new File(System.getProperty("java.io.tmpdir"), "TopLogging.log"); // NOI18N
System.err.println("Logging sent to: " + debugLog); // NOI18N
Files.newOutputStream(debugLog.toPath(), StandardOpenOption.APPEND);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line seems wrong.

@lbruun
Copy link
Contributor

lbruun commented Nov 27, 2017

I notice your tests use:

-XX:+UseCompressedClassPointers 
-XX:+UseCompressedOops 
-XX:-UseLargePagesIndividualAllocation 
-XX:+UseParallelGC  

Why? Does your test results depend on this?

@lbruun
Copy link
Contributor

lbruun commented Nov 27, 2017

One more thing: If Files.newInputStream() (with try-with-resources of course) is really that much preferable to new FileInputStream() then the IDE should have a hint for it. Right?

Must admit this whole thing is news to me. I can see that Stephen Conollly's blog post has gone viral and triggered many projects to review their usage of FileInputStream (or FileOutputStream). His article was later published on DZone were it triggered a minor discussion where Kirk Pepperdine also commented. I don't see Mr Pepperdine disputing that a finalizer causes GC but he seems to argue that it can hardly have that much of an impact. Anyway, that's why it will be interesting to see if there's any real impact on a large code base like NetBeans.

Bottom line: I think we should see some more test results before we begin changing every occurrence of FileInputStream.

Interesting stuff, mdindoffer !

@mdindoffer
Copy link
Contributor Author

mdindoffer commented Nov 27, 2017

@emilianbold Done manually. Sure there may be a place for a java hint in the future, but this was partly an experiment. Also, the code is kinda fragile and tangled up in some places, so I prefer to do this stuff manually.

The idea was to apply this change throughout the whole repo in one go, but it proved to be more time consuming than I thought. Yes, the speedup that seems to be present at the boot probably originates from the core. And maybe autoupdate too? If it checks for updates at startup, not entirely sure. However, the point is, if there's a benefit observable in one use case (boot), it should manifest itself in other use cases too, even if negligibly. I also planned to tackle code that touches file searching & replacing and benchmark that. I think the api.search* module (which I plowed through) houses most of the relevant code for this, but not all. However I am not that much familiar with the NB cluster structure to say that for sure.
"but don't like so much" - so, are you against this FI/OS change in general?

@lbruun
I did not touch the JVM / GC params apart from the Xmx and gc logging. The XXs you list are defaults for x64 Java 8.
The IDE hint seems like a good idea. But as you mentioned, the real life effect can be negligible for most of the use cases nowadays.
I will address the comments and then run some more tests.
BTW this post also provides some nice graphs

@emilianbold
Copy link
Member

"but don't like so much" - so, are you against this FI/OS change in general?

try-with-resources seems a clear gain because it removes so many finally blocks that just close the stream.

Files.newInputStream just looks more ugly with the extra path creation, StandardOpenOption flags, etc.

AFAIK FileInputStream is not outright deprecated and I'm curious if there's really any kind of noticeable impact during normal IDE usage (editing a source file, running the project, etc).

For startup having the most efficient code is important so it would be interesting to narrow down the core modules that need this upgrade.

Basically I would slice-and-dice this into more commits / PRs and even have places where the old code is left alone (because I'm not convinced it has a noticeable effect and there's really no urgent need to switch to the new API and abandon FileInputStream forever).

@mdindoffer mdindoffer force-pushed the dropfisfos branch 3 times, most recently from 8498a40 to 7aa2b0b Compare December 2, 2017 10:41
This change drops the usage of FileInputStream and FileOutputStream
in cluster modules "a*" through "c*".
The FIS/FOS are putting unnecesarry pressure on the GC because of their finalize() method.
I've measured small, but fairly consistent improvements in GC pauses during the startup of the IDE with couple of projects opened:
Before: http://gceasy.io/my-gc-report.jsp?p=c2hhcmVkLzIwMTcvMTEvMjYvLS1nYXJiYWdlLWNvbGxlY3Rpb24tYmVmb3JlLXN0YXJ0dXAubG9nLS0yMC0xMS01OQ==
After: http://gceasy.io/my-gc-report.jsp?p=c2hhcmVkLzIwMTcvMTEvMjYvLS1nYXJiYWdlLWNvbGxlY3Rpb24tYWZ0ZXIxY29tbWl0LXN0YXJ0dXAubG9nLS0yMC0xMy01Mw==
In every module that required it (for the "Files" class workaround), theres a bump in javac source to version 7.
Further references: see JDK-8080225, HDFS-8526, JENKINS-42934

Address comments from emilianbold
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants