-
-
Notifications
You must be signed in to change notification settings - Fork 3.7k
HHH-19240 Reduce allocation rate of HQL parser #10894
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
Open
beikov
wants to merge
9
commits into
hibernate:main
Choose a base branch
from
beikov:HHH-19240
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+632
−227
Open
Changes from 1 commit
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
a5a6823
HHH-19240 Test memory consumption of HQL parser
beikov 7043a2c
HHH-19240 Reduce memory consumption by left factoring some HQL parse …
beikov c3b58a0
HHH-19240 Simplify queryExpression grammar rule
beikov 541cdc6
HHH-19758 Don't reset lexer on SLL parse error
beikov 445cd64
HHH-19240 Refactor IS predicate to single UnaryIsPredicate rule
beikov 8850494
HHH-19240 Left-factor CONTAINS/INCLUDES/INTERSECTS to single BinaryEx…
beikov 52e26da
HHH-19240 Fold ComparisonPredicate into BinaryExpressionPredicate rule
beikov dc2429d
HHH-19240 Fold IsDistinctFromPredicate into BinaryExpressionPredicate…
beikov 03ea090
HHH-19240 Improve memory consumption testing
beikov File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
53 changes: 53 additions & 0 deletions
53
...nate-testing/src/main/java/org/hibernate/testing/memory/GlobalMemoryUsageSnapshotter.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
/* | ||
* SPDX-License-Identifier: Apache-2.0 | ||
* Copyright Red Hat Inc. and Hibernate Authors | ||
*/ | ||
package org.hibernate.testing.memory; | ||
|
||
import java.lang.management.ManagementFactory; | ||
import java.lang.management.MemoryPoolMXBean; | ||
import java.util.List; | ||
|
||
final class GlobalMemoryUsageSnapshotter implements MemoryAllocationSnapshotter { | ||
|
||
private static final GlobalMemoryUsageSnapshotter INSTANCE = new GlobalMemoryUsageSnapshotter( | ||
ManagementFactory.getMemoryPoolMXBeans() | ||
); | ||
|
||
private final List<MemoryPoolMXBean> heapPoolBeans; | ||
private final Runnable gcAndWait; | ||
|
||
private GlobalMemoryUsageSnapshotter(List<MemoryPoolMXBean> heapPoolBeans) { | ||
this.heapPoolBeans = heapPoolBeans; | ||
this.gcAndWait = () -> { | ||
for (int i = 0; i < 3; i++) { | ||
System.gc(); | ||
try { Thread.sleep(50); } catch (InterruptedException ignored) {} | ||
} | ||
}; | ||
} | ||
|
||
public static GlobalMemoryUsageSnapshotter getInstance() { | ||
return INSTANCE; | ||
} | ||
|
||
@Override | ||
public MemoryAllocationSnapshot snapshot() { | ||
final long peakUsage = heapPoolBeans.stream().mapToLong(p -> p.getPeakUsage().getUsed()).sum(); | ||
gcAndWait.run(); | ||
final long retainedUsage = heapPoolBeans.stream().mapToLong(p -> p.getUsage().getUsed()).sum(); | ||
heapPoolBeans.forEach(MemoryPoolMXBean::resetPeakUsage); | ||
return new GlobalMemoryAllocationSnapshot( peakUsage, retainedUsage ); | ||
} | ||
|
||
record GlobalMemoryAllocationSnapshot(long peakUsage, long retainedUsage) implements MemoryAllocationSnapshot { | ||
|
||
@Override | ||
public long difference(MemoryAllocationSnapshot before) { | ||
// When doing the "before" snapshot, the peak usage is reset. | ||
// Since this object is the "after" snapshot, we can simply estimate the memory usage of an operation | ||
// to be the peak usage of that operation minus the usage after GC | ||
return peakUsage - retainedUsage; | ||
} | ||
} | ||
} |
95 changes: 95 additions & 0 deletions
95
...ing/src/main/java/org/hibernate/testing/memory/HotspotPerThreadAllocationSnapshotter.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
/* | ||
* SPDX-License-Identifier: Apache-2.0 | ||
* Copyright Red Hat Inc. and Hibernate Authors | ||
*/ | ||
package org.hibernate.testing.memory; | ||
|
||
import org.checkerframework.checker.nullness.qual.Nullable; | ||
|
||
import java.lang.management.ManagementFactory; | ||
import java.lang.management.ThreadMXBean; | ||
import java.lang.reflect.Method; | ||
import java.util.HashMap; | ||
|
||
record HotspotPerThreadAllocationSnapshotter(ThreadMXBean threadMXBean) implements MemoryAllocationSnapshotter { | ||
|
||
private static final @Nullable HotspotPerThreadAllocationSnapshotter INSTANCE; | ||
private static final Method GET_THREAD_ALLOCATED_BYTES; | ||
|
||
static { | ||
ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean(); | ||
Method method = null; | ||
try { | ||
@SuppressWarnings("unchecked") | ||
Class<? extends ThreadMXBean> hotspotInterface = | ||
(Class<? extends ThreadMXBean>) Class.forName( "com.sun.management.ThreadMXBean" ); | ||
try { | ||
method = hotspotInterface.getMethod( "getThreadAllocatedBytes", long[].class ); | ||
} | ||
catch (Exception e) { | ||
// Ignore | ||
} | ||
|
||
if ( !hotspotInterface.isInstance( threadMXBean ) ) { | ||
threadMXBean = ManagementFactory.getPlatformMXBean( hotspotInterface ); | ||
} | ||
} | ||
catch (Throwable e) { | ||
// Ignore | ||
} | ||
|
||
GET_THREAD_ALLOCATED_BYTES = method; | ||
|
||
HotspotPerThreadAllocationSnapshotter instance = null; | ||
if ( method != null && threadMXBean != null ) { | ||
try { | ||
instance = new HotspotPerThreadAllocationSnapshotter( threadMXBean ); | ||
instance.snapshot(); | ||
} | ||
catch (Exception e) { | ||
instance = null; | ||
} | ||
} | ||
INSTANCE = instance; | ||
} | ||
|
||
public static @Nullable HotspotPerThreadAllocationSnapshotter getInstance() { | ||
return INSTANCE; | ||
} | ||
|
||
@Override | ||
public MemoryAllocationSnapshot snapshot() { | ||
long[] threadIds = threadMXBean.getAllThreadIds(); | ||
try { | ||
return new PerThreadMemoryAllocationSnapshot( | ||
threadIds, | ||
(long[]) GET_THREAD_ALLOCATED_BYTES.invoke( threadMXBean, (Object) threadIds ) | ||
); | ||
} | ||
catch (Exception e) { | ||
throw new RuntimeException( e ); | ||
} | ||
} | ||
|
||
record PerThreadMemoryAllocationSnapshot(long[] threadIds, long[] threadAllocatedBytes) | ||
implements MemoryAllocationSnapshot { | ||
|
||
@Override | ||
public long difference(MemoryAllocationSnapshot before) { | ||
final PerThreadMemoryAllocationSnapshot other = (PerThreadMemoryAllocationSnapshot) before; | ||
final HashMap<Long, Integer> previousThreadIdToIndexMap = new HashMap<>(); | ||
for ( int i = 0; i < other.threadIds.length; i++ ) { | ||
previousThreadIdToIndexMap.put( other.threadIds[i], i ); | ||
} | ||
long allocatedBytes = 0; | ||
for ( int i = 0; i < threadIds.length; i++ ) { | ||
allocatedBytes += threadAllocatedBytes[i]; | ||
final Integer previousThreadIndex = previousThreadIdToIndexMap.get( threadIds[i] ); | ||
if ( previousThreadIndex != null ) { | ||
allocatedBytes -= other.threadAllocatedBytes[previousThreadIndex]; | ||
} | ||
} | ||
return allocatedBytes; | ||
} | ||
} | ||
} |
83 changes: 83 additions & 0 deletions
83
...esting/src/main/java/org/hibernate/testing/memory/HotspotTotalThreadBytesSnapshotter.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
/* | ||
* SPDX-License-Identifier: Apache-2.0 | ||
* Copyright Red Hat Inc. and Hibernate Authors | ||
*/ | ||
package org.hibernate.testing.memory; | ||
|
||
import org.checkerframework.checker.nullness.qual.Nullable; | ||
|
||
import java.lang.management.ManagementFactory; | ||
import java.lang.management.ThreadMXBean; | ||
import java.lang.reflect.Method; | ||
|
||
record HotspotTotalThreadBytesSnapshotter(ThreadMXBean threadMXBean) implements MemoryAllocationSnapshotter { | ||
|
||
private static final @Nullable HotspotTotalThreadBytesSnapshotter INSTANCE; | ||
private static final Method GET_TOTAL_THREAD_ALLOCATED_BYTES; | ||
|
||
static { | ||
ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean(); | ||
Method method = null; | ||
try { | ||
@SuppressWarnings("unchecked") | ||
Class<? extends ThreadMXBean> hotspotInterface = | ||
(Class<? extends ThreadMXBean>) Class.forName( "com.sun.management.ThreadMXBean" ); | ||
try { | ||
method = hotspotInterface.getMethod( "getTotalThreadAllocatedBytes" ); | ||
} | ||
catch (Exception e) { | ||
// Ignore | ||
} | ||
|
||
if ( !hotspotInterface.isInstance( threadMXBean ) ) { | ||
threadMXBean = ManagementFactory.getPlatformMXBean( hotspotInterface ); | ||
} | ||
} | ||
catch (Throwable e) { | ||
// Ignore | ||
} | ||
|
||
GET_TOTAL_THREAD_ALLOCATED_BYTES = method; | ||
|
||
HotspotTotalThreadBytesSnapshotter instance = null; | ||
if ( method != null && threadMXBean != null ) { | ||
try { | ||
instance = new HotspotTotalThreadBytesSnapshotter( threadMXBean ); | ||
instance.snapshot(); | ||
} | ||
catch (Exception e) { | ||
instance = null; | ||
} | ||
} | ||
INSTANCE = instance; | ||
} | ||
|
||
public static @Nullable HotspotTotalThreadBytesSnapshotter getInstance() { | ||
return INSTANCE; | ||
} | ||
|
||
@Override | ||
public MemoryAllocationSnapshot snapshot() { | ||
try { | ||
return new GlobalMemoryAllocationSnapshot( (long) GET_TOTAL_THREAD_ALLOCATED_BYTES.invoke( threadMXBean ) ); | ||
} | ||
catch (Exception e) { | ||
throw new RuntimeException( e ); | ||
} | ||
} | ||
|
||
record GlobalMemoryAllocationSnapshot(long allocatedBytes) implements MemoryAllocationSnapshot { | ||
|
||
GlobalMemoryAllocationSnapshot { | ||
if ( allocatedBytes == -1L ) { | ||
throw new IllegalArgumentException( "getTotalThreadAllocatedBytes is disabled" ); | ||
} | ||
} | ||
|
||
@Override | ||
public long difference(MemoryAllocationSnapshot before) { | ||
final GlobalMemoryAllocationSnapshot other = (GlobalMemoryAllocationSnapshot) before; | ||
return Math.max( allocatedBytes - other.allocatedBytes, 0L ); | ||
} | ||
} | ||
} |
9 changes: 9 additions & 0 deletions
9
hibernate-testing/src/main/java/org/hibernate/testing/memory/MemoryAllocationSnapshot.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
/* | ||
* SPDX-License-Identifier: Apache-2.0 | ||
* Copyright Red Hat Inc. and Hibernate Authors | ||
*/ | ||
package org.hibernate.testing.memory; | ||
|
||
interface MemoryAllocationSnapshot { | ||
long difference(MemoryAllocationSnapshot before); | ||
} |
9 changes: 9 additions & 0 deletions
9
...rnate-testing/src/main/java/org/hibernate/testing/memory/MemoryAllocationSnapshotter.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
/* | ||
* SPDX-License-Identifier: Apache-2.0 | ||
* Copyright Red Hat Inc. and Hibernate Authors | ||
*/ | ||
package org.hibernate.testing.memory; | ||
|
||
interface MemoryAllocationSnapshotter { | ||
MemoryAllocationSnapshot snapshot(); | ||
} |
27 changes: 27 additions & 0 deletions
27
hibernate-testing/src/main/java/org/hibernate/testing/memory/MemoryUsageUtil.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
/* | ||
* SPDX-License-Identifier: Apache-2.0 | ||
* Copyright Red Hat Inc. and Hibernate Authors | ||
*/ | ||
package org.hibernate.testing.memory; | ||
|
||
public class MemoryUsageUtil { | ||
|
||
private static final MemoryAllocationSnapshotter SNAPSHOTTER; | ||
|
||
static { | ||
MemoryAllocationSnapshotter snapshotter = HotspotTotalThreadBytesSnapshotter.getInstance(); | ||
if ( snapshotter == null ) { | ||
snapshotter = HotspotPerThreadAllocationSnapshotter.getInstance(); | ||
} | ||
if ( snapshotter == null ) { | ||
snapshotter = GlobalMemoryUsageSnapshotter.getInstance(); | ||
} | ||
SNAPSHOTTER = snapshotter; | ||
} | ||
|
||
public static long estimateMemoryUsage(Runnable runnable) { | ||
final MemoryAllocationSnapshot beforeSnapshot = SNAPSHOTTER.snapshot(); | ||
runnable.run(); | ||
return SNAPSHOTTER.snapshot().difference( beforeSnapshot ); | ||
} | ||
} |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It might be useful to log which snapshotter implementation is selected, in case one proves more prone to failures than others.
System.out.println("MemoryUsageUtil: Using " + snapshotter.getClass().getSimpleName());