Name.contentEquals() performance

Maurizio Cimadamore maurizio.cimadamore at oracle.com
Wed Oct 3 13:16:00 UTC 2018


Hi,
If you are comparing names (to make sure of which requires an 
instanceof, which I guess adds its own cost), the interning trick seems 
to be the best IMHO. I'm a bit skeptical about adding a new field on 
Name; a simple compilation of an hello world program will create roughly 
3K names. In general you need a new name for each new field, variable, 
method, class/interface, type-variable, ... so the number of names can 
become big pretty rapidly.

(That said, out of curiosity I tried to instrument the JDK build to see 
how many names were created (this is a bit hard given that the build 
internally reuses java compilers using the sjavac server), but name 
creation seem to peak at around 33K, which would give an overhead of a 
couple of hundred of kB for an extra field like the one you suggest, 
which doesn't seem excessive in terms of footprint increase)

So, given the performance improvement you get out of this is rather 
limited, perhaps going for a more conservative fix (e.g. interning) 
could be the better?

As for your claim of less retained memory it's really hard to tell w/o 
looking at some targeted JMH benchmark - it's possible that the JIT 
might decide to escape analyze away the strings since they are thrown 
away immediately after the comparison, so that no real allocation 
actually occurs? In any case I would expect modern GCs to be able to 
cope quite well with this kind of throwaway allocation with TLABs etc. 
so I'm a bit on the fence.

Maurizio



On 03/10/18 12:20, Ron Shapiro wrote:
> In my profiling of javac compilations of large builds (>30 seconds), 
> I'm seeing about a noticeable amount of time being attributed to 
> com.sun.tools.javac.util.Name.contentEquals(), because it creates a 
> new String each time in it's toString().equals(cs.toString()) check. 
> I'm wondering if we can optimize this without much cost.
>
> I had suggested to Liam that we could add an `asString` variable that 
> is lazily computed in toString(). This would also benefit all of the 
> other CharSequence methods that delegate to the toString() representation.
>
> Liam had another idea that would avoid adding a field (and the 
> associated memory that comes with that), taking advantage of the fact 
> that Names are interned.
>
> if (cs instanceof Name) {
>   Name other = (Name) cs;
>   if (table == other.table) {
>     return this == other;
>   }
> }
> return toString().equals(cs.toString());
>
> The first option reduced builds that I tested of 45 seconds by 450ms 
> (1%). Liam's suggestion reduced bulilds by 400-420ms, so in the same 
> ballpark but a bit slower (but again, it allows for less retained 
> memory?).
>
> I figured both are simple, so I'd propose both.



More information about the compiler-dev mailing list