Coder Social home page Coder Social logo

whitingjr / type-pollution-agent Goto Github PK

View Code? Open in Web Editor NEW

This project forked from franz1981/type-pollution-agent

0.0 1.0 0.0 55 KB

Agent to detect type pollution due to instanceof/checkcast misuses

License: Apache License 2.0

Java 100.00%

type-pollution-agent's Introduction

Java agent to diagnose JDK-8180450

What is JDK-8180450?

See the issue for full details... But briefly, the problem is that the OpenJDK JVM caches the supertype of a class/interface on the JRE's Klass structure when evaluating things like instanceof or checking type casts and while that usually results in a performance win (because a slower traversal of the whole hierarchy can be avoided), in certain circumstances involving multiple inheritance of interfaces the cache is worse than useless. CPU will be expended updating the cache, but the cached value won't help avoiding the slow path. It's a problem because the surprising and significant difference in performance between the ideal and worst case behaviours means programmers can easily write poorly performing code without realising the costs (usually instanceof is very cheap, for example).

What is this?

It's a Java agent which can be used to identify code which may be suffering from this problem. It attempts to count the number of times an a particular concrete class is used in instanceof (and similar) expressions with a different test type. For example at one point in the code you might have foo instanceof I1 and somewhere else bar instanceof I2 (where foo and bar have the same concrete type). The agent will estimate the number of times the cached supertype (I1 and I2) is changing, i.e. how often you're hitting the slower path.

Build

$ # From the root dir
$ mvn package

Run

$ # From the root dir
$ $ java -javaagent:agent/target/type-pollution-agent-0.1-SNAPSHOT.jar -XX:-Inline -XX:-TieredCompilation -jar example/target/type-pollution-example-0.1-SNAPSHOT.jar 

The output, with a default agent configuration, is:

--------------------------
Type Pollution Statistics:
--------------------------
1:      io.type.pollution.example.B
Count:  5364580
Types:
        io.type.pollution.example.I2
        io.type.pollution.example.I3
        io.type.pollution.example.I1
Traces:
        io.type.pollution.example.Main.goo(Main.java:71)
                class: io.type.pollution.example.I2
                count: 1822574
                class: io.type.pollution.example.I3
                count: 1800163
        io.type.pollution.example.Main.foo(Main.java:66)
                class: io.type.pollution.example.I1
                count: 1741843
--------------------------
2:      io.type.pollution.example.C
Count:  3642662
Types:
        io.type.pollution.example.I2
        io.type.pollution.example.I1
Traces:
        io.type.pollution.example.Main.castToI2(Main.java:83)
                class: io.type.pollution.example.I2
                count: 1836278
        io.type.pollution.example.Main.castToI1(Main.java:79)
                class: io.type.pollution.example.I1
                count: 1806384
--------------------------
  • Count: is the number of observed successful checkcast/instanceof/Class::isAssignableFrom/Class::cast/Class::isInstance against a different (interface) type from the last seen
  • Types: is the list of different (interface) types observed
  • Traces: is a list of top method stack traces along with the interface class seen and related count (ie observed secondary super cache invalidations).

note Traces format is compatible with Idea IntelliJ Stack Trace Viewer

The report is an ordered list which types are ordered by increasing Count ie io.type.pollution.example.B is the top type based on it and more likely the one with the highest chance to cause scalability issues.

But what about OpenJDK JIT optimizations that could save any check to be performed?

The agent can use an (imprecise/naive/eager/experimental) heuristic that mimic some JIT optimizations and save false-positive statistics; it can be enabled by adding

-Dio.type.pollution.cleanup=true

to the list of JVM argument, turning the previous output into:

 # THIS IS EMPTY ON PURPOSE!!

An empty statistics?

Yes, because each call-site always observe a single concrete type; meaning that OpenJDK C2 compiler "should"โ„ข be able to constant fold all the checks (precomputed) and add a guard + uncommon trap check instead.

Full stack traces are available?

Yes! To enable full-stack trace sampling (now defaulted at 10 ms sampling for each concrete type) just add

-Dio.type.pollution.full.traces=true

And, the output will become:

--------------------------
Type Pollution Statistics:
--------------------------
1:      io.type.pollution.example.B
Count:  5364580
Types:
        io.type.pollution.example.I2
        io.type.pollution.example.I3
        io.type.pollution.example.I1
Traces:
        io.type.pollution.example.Main.goo(Main.java:71)
                class: io.type.pollution.example.I2
                count: 1822574
                class: io.type.pollution.example.I3
                count: 1800163
        io.type.pollution.example.Main.foo(Main.java:66)
                class: io.type.pollution.example.I1
                count: 1741843
Full Traces:
        --------------------------
        io.type.pollution.example.Main.foo(Main.java:66)
        io.type.pollution.example.Main.lambda$main$0(Main.java:55)
        java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
        java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
        java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
        java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
        java.base/java.lang.Thread.run(Thread.java:829)
        --------------------------
        io.type.pollution.example.Main.goo(Main.java:71)
        io.type.pollution.example.Main.lambda$main$0(Main.java:56)
        java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
        java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
        java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
        java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
        java.base/java.lang.Thread.run(Thread.java:829)
--------------------------        
# Rest omitted for brevity....

type-pollution-agent's People

Contributors

franz1981 avatar tombentley avatar barreiro avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.