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

Regarding Java 11 and above, the accuracy issue of ObjectSampler in --total mode #873

Closed
yanglong1010 opened this issue Jan 3, 2024 · 2 comments
Labels

Comments

@yanglong1010
Copy link
Contributor

hi Andrei

In this code, the number of calls to testSmallAlloc and testLargeAlloc is different, but their total memory allocations in bytes are close, which can also be proven from the actual running logs.

public class AllocTest {
    private static volatile long n1 = 0;
    private static volatile long n2 = 0;
    private static Thread t1;

    public static void main(String[] args) throws Exception {
        testAlloc();
        while (true) {
            Thread.sleep(1000);
            System.out.println("small total: " + n1);
            System.out.println("large total: " + n2);
            System.out.println();
        }
    }

    private static void testAlloc() {
        t1 = new Thread(() -> {
            while (true) {
                for (int i = 0; i < 256; i++) {
                    n1 += testSmallAlloc(1024);
                }
                n2 += testLargeAlloc(1024 * 256);
            }
        });
        t1.start();
    }

    private static int testSmallAlloc(int size) {
        return realAlloc(size);
    }

    private static int testLargeAlloc(int size) {
        return realAlloc(size);
    }

    private static int realAlloc(int size) {
        byte[] arr = new byte[size];
        return arr.length;
    }
}
java11/bin/java -Xint AllocTest

small total: 2059834368
large total: 2060451840

small total: 4829180928
large total: 4829216768

small total: 7630267392
large total: 7630225408

small total: 10429923328
large total: 10429923328

Using --total mode, it is expected that the proportions of testSmallAlloc and testLargeAlloc should be close in the flame graph, but in fact testLargeAlloc is 99.91% while testSmallAlloc is only 0.81%.

/root/async-profiler-fork/build/bin/asprof --alloc 256k -f static/profile.html --total -d 10 jps

image

The reason is that size is used as counter in ObjectSampler::recordAllocation, which causes only the array size to be recorded during testSmallAlloc, which is actually the interval in JVMTI_EVENT_SAMPLED_OBJECT_ALLOC (here we ignore the randomness of interval in JVMTI).

Profiler::instance()->recordSample(NULL, size, event_type, &event);

I feel that event._total_size should be used as counter here. I verified it on my branch and it looks much normal after the modification.
image

if you think this optimization is feasible, I can create a PR.

@yanglong1010 yanglong1010 changed the title Regarding Java 11 and above, the accuracy issue of AllocSampler in --total mode Regarding Java 11 and above, the accuracy issue of ObjectSampler in --total mode Jan 3, 2024
@apangin
Copy link
Collaborator

apangin commented Jan 4, 2024

Thank you for the analysis. Your conclusion makes total sense. Feel free to submit a PR.

@zdyj3170101136
Copy link

i also noticed that the small_alloc frame is absent in --ctack=dwarf, but in --cstack=vm mode.

./asprof -d 30 -e cpu -o flamegraph -f cpu_vm.html --cstack vm 632756

截屏2024-01-05 下午4 06 38

./asprof -d 30 -e cpu -o flamegraph -f cpu_dwarf.html --cstack dwarf 632756

截屏2024-01-05 下午4 07 11

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

No branches or pull requests

3 participants