Skip to content

Conversation

@jasonk000
Copy link
Contributor

Introduce a ConcurrentBitField backed by an AtomicLongArray, and use it to do proper CAS-based state tracking in the concurrent ObjectMarker.

This is a potential fix to issue #57.

Introduce a ConcurrentBitField backed by an AtomicLongArray, and use it
to do proper CAS-based state tracking in the concurrent ObjectMarker.

This is a potential fix to issue #57.
import org.junit.Test;
import org.junit.rules.ExpectedException;

public class ConcurrentBitFieldTest
Copy link
Contributor Author

@jasonk000 jasonk000 Aug 11, 2025

Choose a reason for hiding this comment

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

Please suggest any additional / fixes to tests.

Bundle-SymbolicName: org.eclipse.mat.report;singleton:=true
Bundle-Version: 1.17.0.qualifier
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Bundle-RequiredExecutionEnvironment: JavaSE-17
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This was required to support compareAndExchange. If we cannot do xchg, it can be done with compareAndSet, but involves additional CAS operations.

// Therefore, we need to use full compare and exchange rather than
// compare and set.

while (true)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Appreciate any extra eyes on this!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

A colleague suggested adding a jcstress, did so in 9499a38.

Using a standalone project and readme since the jcstress modules are not
made available for use with tycho or packaged in orbit. Added a README
to explain.
@kgibm
Copy link
Member

kgibm commented Dec 17, 2025

@jasonk000 Sorry for the terribly long delay. I fell behind on everything for the last 5 months or so and I'm finally starting to dig out.

I reviewed the PR and it's quite impressive, especially all of the testing (I think splitting out jcstress is okay), so, overall, it looks good to me. I think it's fine to require later versions of Java (though I notice the pom.xml for jcstress has a javac.target of Java 8?). We can try this out on our support systems.

However, are we sure this is a concurrency issue? As I was re-familiarizing myself with this issue, I noticed that the symptoms that we saw showed single-threaded execution:

org.eclipse.mat.parser.internal.snapshot.ObjectMarker.countMarked
  |-org.eclipse.mat.parser.internal.snapshot.ObjectMarker.markSingleThreaded (100%)

And that's not changed in this latest PR:

    @Override
    public int markSingleThreaded()
    {
        int before = countMarked();

[...]

    int countMarked()
    {
        int marked = 0;
        for (boolean b : bits)
            if (b)
                marked++;
        return marked;
    }

This implementation counts as we go, previously it counted before and
after and used the difference as the marked count. If we had a sparse
set of bits to count, and a large heap, a lot of calls to mark might
result in us using a lot of time just in counting. Hopefully now we do
not spend any time in counting.
try
{
markMultiThreaded(1);
return (int) markMultiThreadedInner(1);
Copy link
Contributor Author

@jasonk000 jasonk000 Dec 22, 2025

Choose a reason for hiding this comment

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

This should be convertible to multi-thread-able if this works.

@jasonk000
Copy link
Contributor Author

jasonk000 commented Dec 22, 2025

@kgibm thanks for the feedback!

However, are we sure this is a concurrency issue? As I was re-familiarizing myself with this issue, I noticed that #57 (comment) showed single-threaded execution:

Yes, this is something I struggled to follow/understand what was going wrong.

With some time and your nudge, I realize now there's a solution to cover both the counting and the marking: count as we go, instead of counting repeatedly. --> see here d094d1d

I've done this by switching to a CountedCompleter implementation and the tests pass. I wonder if you can test this out against a slow hprof?

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.

3 participants