On Sun, 4 Jun 2023 21:39:58 GMT, Kelvin Nilsen <kdnil...@openjdk.org> wrote:

>> OpenJDK Colleagues:
>> 
>> Please review this proposed integration of Generational mode for Shenandoah 
>> GC under https://bugs.openjdk.org/browse/JDK-8307314.
>> 
>> Generational mode of Shenandoah is enabled by adding 
>> `-XX:+UnlockExperimentalVMOptions -XX:ShenandoahGCMode=generational` to a 
>> command line that already specifies ` -XX:+UseShenandoahGC`.  The 
>> implementation automatically adjusts the sizes of old generation and young 
>> generation to efficiently utilize the entire heap capacity.  Generational 
>> mode of Shenandoah resembles G1 in the following regards:
>> 
>> 1. Old-generation marking runs concurrently during the time that multiple 
>> young generation collections run to completion.
>> 2. After old-generation marking completes, we perform a sequence of mixed 
>> collections.  Each mixed collection combines collection of young generation 
>> with evacuation of a portion of the old-generation regions identified for 
>> collection based on old-generation marking information.
>> 3. Unlike G1, young-generation collections and evacuations are entirely 
>> concurrent, as with single-generation Shenandoah.
>> 4. As with single-generation Shenandoah, there is no explicit notion of eden 
>> and survivor space within the young generation.  In practice, regions that 
>> were most recently allocated tend to have large amounts of garbage and these 
>> regions tend to be collected with very little effort.  Young-generation 
>> objects that survive garbage collection tend to accumulate in regions that 
>> hold survivor objects.  These regions tend to have smaller amounts of 
>> garbage, and are less likely to be collected.  If they survive a sufficient 
>> number of young-generation collections, the “survivor” regions are promoted 
>> into the old generation.
>> 
>> We expect to refine heuristics as we gain experience with more production 
>> workloads.  In the future, we plan to remove the “experimental” qualifier 
>> from generational mode, at which time we expect that generational mode will 
>> become the default mode for Shenandoah.
>> 
>> **Testing**: We continuously run jtreg tiers 1-4 + hotspot_gc_shenandoah, 
>> gcstress, jck compiler, jck runtime, Dacapo, SpecJBB, SpecVM, Extremem, 
>> HyperAlloc, and multiple AWS production workload simulators. We test on 
>> Linux x64 and aarch64, Alpine x64 and aarch64, macOS x64 and aarch64, and 
>> Windows x64.
>
> Kelvin Nilsen has updated the pull request incrementally with one additional 
> commit since the last revision:
> 
>   Remove three asserts making comparisons between atomic volatile variables
>   
>   Though changes to the volatile variables are individually protected by
>   Atomic load and store operations, these asserts were not assuring
>   atomic access to multiple volatile variables, each of which could be
>   modified independently of the others.  The asserts were therefore not
>   trustworthy, as has been confirmed by more extensive testing.

I wrote an LRU program back in 2017 which allocates trees and stores them in an 
array in a round robin fashion, freeing the last allocated.  At the time this 
was written it's purpose was to show how generational GCs can hit the wall and 
start performing very badly.  I ran this on a clean openjdk build, a genshen 
build in generational mode and a genshen  build in non-generational mode.   
These results are repeatable for me. 

I would like to understand where the degradation is coming from before moving 
forward with this patch since it appears to penalize those who wish to just run 
traditional Shenandoah.

Clean
cflood@fedora java_programs]$ 
~/genshen/cleanjdk/build/linux-x86_64-server-release/images/jdk/bin/java  
-XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC LRU 1000 1000
Took 341892ms to allocate 1000000 trees in a cache of 1000

Genshen generational (we expect this to be bad)
[cflood@fedora java_programs]$ 
~/genshen/jdk/build/linux-x86_64-server-release/images/jdk/bin/java  
-XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC 
-XX:ShenandoahGCMode=generational LRU 1000 1000
Took 442012ms to allocate 1000000 trees in a cache of 1000

Genshen non-generational (shows what I feel is a significant degradation from 
the clean build)
[cflood@fedora java_programs]$ 
~/genshen/jdk/build/linux-x86_64-server-release/images/jdk/bin/java  
-XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC LRU 1000 1000
Took 395679ms to allocate 1000000 trees in a cache of 1000

I think that generational Shenandoah can be a big win for some applications, 
but I want to fully understand the cost for all applications.

I can't attach a .java file so here it is inline in the post.

class TreeNode {
    public TreeNode left, right;
    public int val;
}


public class LRU {
    static int cache_size;
    static int reps;
    static int tree_height=16;

    private static TreeNode[] trees;

    private static int getIndex(int i) {return i % cache_size;}
    private static TreeNode makeTree(int h) {
        if (h == 0) { return null;}
        else {
            TreeNode res = new TreeNode();
            res.left = makeTree(h - 1);
            res.right = makeTree(h - 1);
            res.val = h;
            return res;
        }
    }

    public static void main(String[] args) {
        if (args.length != 2) {
            System.err.println("LRU requires args: cache_size reps");
            return;
        }
        cache_size = Integer.parseInt(args[0]);
        reps = Integer.parseInt(args[1]) * cache_size;
        trees = new TreeNode[cache_size];

        long start = System.currentTimeMillis();
        for (int i = 0; i < reps; i++)
            trees[getIndex(i)] = makeTree(tree_height);
        long end = System.currentTimeMillis();
        long ms = end - start;

        System.out.println("Took " + ms + "ms to allocate " + reps + " trees in 
a cache of " + cache_size);
    }
}

-------------

PR Comment: https://git.openjdk.org/jdk/pull/14185#issuecomment-1579278537

Reply via email to