Skip to content

Commit

Permalink
QueryPerformanceRecorder: Hold Batches With Care
Browse files Browse the repository at this point in the history
  • Loading branch information
nbauernfeind committed Nov 2, 2023
1 parent f8eedf3 commit d467857
Show file tree
Hide file tree
Showing 9 changed files with 389 additions and 85 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
package io.deephaven.engine.table.impl.perf;

import io.deephaven.base.verify.Assert;
import io.deephaven.engine.exceptions.CancellationException;
import io.deephaven.engine.table.Table;
import io.deephaven.util.QueryConstants;
import org.jetbrains.annotations.NotNull;

import java.util.List;

public class BatchQueryPerformanceRecorder extends QueryPerformanceRecorder {
private final QueryPerformanceRecorder batchRecorder;

public BatchQueryPerformanceRecorder(@NotNull final QueryPerformanceRecorder batchRecorder) {
this.batchRecorder = batchRecorder;
this.operationNuggets = null; // force NPE if accessed
}

@Override
public synchronized QueryPerformanceNugget getNugget(String name, long inputSize) {
synchronized (batchRecorder) {
if (batchRecorder.getState() != QueryState.RUNNING) {
return QueryPerformanceNugget.DUMMY_NUGGET;
}
if (Thread.interrupted()) {
throw new CancellationException("interrupted in QueryPerformanceNugget");
}
if (catchAllNugget != null) {
stopCatchAll(false);
}

final int parentOperationNumber =
userNuggetStack.size() > 0 ? userNuggetStack.getLast().getOperationNumber()
: QueryConstants.NULL_INT;

final QueryPerformanceNugget nugget = new QueryPerformanceNugget(
getEvaluationNumber(), batchRecorder.operationNuggets.size(), parentOperationNumber,
userNuggetStack.size(), name, true, inputSize);
batchRecorder.operationNuggets.add(nugget);
userNuggetStack.addLast(nugget);
return nugget;
}
}

@Override
synchronized boolean releaseNugget(QueryPerformanceNugget nugget) {
boolean shouldLog = nugget.shouldLogNugget(nugget == catchAllNugget);
if (!nugget.isUser()) {
return shouldLog;
}

final QueryPerformanceNugget removed = userNuggetStack.removeLast();
if (nugget != removed) {
throw new IllegalStateException(
"Released query performance nugget " + nugget + " (" + System.identityHashCode(nugget) +
") didn't match the top of the user nugget stack " + removed + " ("
+ System.identityHashCode(removed) +
") - did you follow the correct try/finally pattern?");
}

if (removed.shouldLogMeAndStackParents()) {
shouldLog = true;
if (userNuggetStack.size() > 0) {
userNuggetStack.getLast().setShouldLogMeAndStackParents();
}
}

synchronized (batchRecorder) {
if (userNuggetStack.isEmpty() && batchRecorder.getState() == QueryState.RUNNING) {
startCatchAll(getEvaluationNumber());
}
}

return shouldLog;
}

@Override
public void setQueryData(EntrySetter setter) {
final int evaluationNumber;
final int operationNumber;
boolean uninstrumented = false;

synchronized (this) {
synchronized (batchRecorder) {
evaluationNumber = getEvaluationNumber();

if (batchRecorder.getState() != QueryState.RUNNING) {
operationNumber = QueryConstants.NULL_INT;
} else {
// ensure UPL and QOPL are consistent/joinable.
if (userNuggetStack.size() > 0) {
final QueryPerformanceNugget current = userNuggetStack.getLast();
operationNumber = current.getOperationNumber();
current.setShouldLogMeAndStackParents();
} else {
uninstrumented = true;
operationNumber = QueryConstants.NULL_INT;
if (catchAllNugget != null) {
catchAllNugget.setShouldLogMeAndStackParents();
}
}
}
}
}

setter.set(evaluationNumber, operationNumber, uninstrumented);
}

@Override
void stopCatchAll(boolean abort) {
final boolean shouldLog;
if (abort) {
shouldLog = catchAllNugget.abort(this);
} else {
shouldLog = catchAllNugget.done(this);
}
if (shouldLog) {
synchronized (batchRecorder) {
catchAllNugget.setOperationNumber(batchRecorder.operationNuggets.size());
batchRecorder.operationNuggets.add(catchAllNugget);
}
}
catchAllNugget = null;
}

@Override
public int startQuery(String description) {
clear();
int evaluationNumber = batchRecorder.getEvaluationNumber();
startCatchAll(evaluationNumber);
return evaluationNumber;
}

@Override
public synchronized boolean endQuery() {
synchronized (batchRecorder) {
if (batchRecorder.getState() != QueryState.RUNNING) {
return false;
}

Assert.neqNull(catchAllNugget, "catchAllNugget");
stopCatchAll(false);
return true;
}
}

@Override
public int getEvaluationNumber() {
return batchRecorder.getEvaluationNumber();
}

@Override
public synchronized QueryState getState() {
return batchRecorder.getState();
}

@Override
public synchronized QueryPerformanceNugget getOuterNugget() {
return userNuggetStack.peekLast();
}

@Override
public Table getTimingResultsAsTable() {
return batchRecorder.getTimingResultsAsTable();
}

@Override
public QueryPerformanceNugget getQueryLevelPerformanceData() {
return unsupported("getQueryLevelPerformanceData");
}

@Override
public List<QueryPerformanceNugget> getOperationLevelPerformanceData() {
return unsupported("getOperationLevelPerformanceData");
}

@Override
public void abortQuery() {
unsupported("abortQuery");
}


private <T> T unsupported(final String methodName) {
throw new UnsupportedOperationException("BatchQueryPerformanceRecorder does not support " + methodName);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ public class QueryPerformanceNugget implements Serializable, AutoCloseable {
static final QueryPerformanceNugget DUMMY_NUGGET = new QueryPerformanceNugget();

private final int evaluationNumber;
private int operationNumber;
private final int parentOperationNumber;
private final int depth;
private final String description;
private final boolean isUser;
Expand Down Expand Up @@ -75,23 +77,33 @@ public class QueryPerformanceNugget implements Serializable, AutoCloseable {
* @param description The operation description
*/
QueryPerformanceNugget(final int evaluationNumber, final String description) {
this(evaluationNumber, NULL_INT, description, false, NULL_LONG);
this(evaluationNumber, 0, NULL_INT, NULL_INT, description, false, NULL_LONG);
}

/**
* Full constructor for nuggets.
*
* @param evaluationNumber A unique identifier for the query evaluation that triggered this nugget creation
* @param operationNumber A unique identifier for this nugget operation
* @param parentOperationNumber The unique identifier for this nugget's parent operation
* @param depth Depth in the evaluation chain for the respective operation
* @param description The operation description
* @param isUser Whether this is a "user" nugget or one created by the system
* @param inputSize The size of the input data
*/
QueryPerformanceNugget(final int evaluationNumber, final int depth,
final String description, final boolean isUser, final long inputSize) {
QueryPerformanceNugget(
final int evaluationNumber,
final int operationNumber,
final int parentOperationNumber,
final int depth,
final String description,
final boolean isUser,
final long inputSize) {
startMemorySample = new RuntimeMemory.Sample();
endMemorySample = new RuntimeMemory.Sample();
this.evaluationNumber = evaluationNumber;
this.operationNumber = operationNumber;
this.parentOperationNumber = parentOperationNumber;
this.depth = depth;
if (description.length() > MAX_DESCRIPTION_LENGTH) {
this.description = description.substring(0, MAX_DESCRIPTION_LENGTH) + " ... [truncated "
Expand Down Expand Up @@ -128,6 +140,8 @@ private QueryPerformanceNugget() {
startMemorySample = null;
endMemorySample = null;
evaluationNumber = NULL_INT;
operationNumber = NULL_INT;
parentOperationNumber = NULL_INT;
depth = 0;
description = null;
isUser = false;
Expand Down Expand Up @@ -229,6 +243,7 @@ private boolean close(final QueryState closingState, final QueryPerformanceRecor
@Override
public String toString() {
return evaluationNumber
+ ":" + operationNumber
+ ":" + description
+ ":" + callerLine;
}
Expand All @@ -237,6 +252,18 @@ public int getEvaluationNumber() {
return evaluationNumber;
}

public int getOperationNumber() {
return operationNumber;
}

public void setOperationNumber(int operationNumber) {
this.operationNumber = operationNumber;
}

public int getParentOperationNumber() {
return parentOperationNumber;
}

public int getDepth() {
return depth;
}
Expand Down Expand Up @@ -379,11 +406,18 @@ public void setShouldLogMeAndStackParents() {
shouldLogMeAndStackParents = true;
}

/**
* Set whether this nugget gets logged, alongside its stack of nesting operations.
*/
public void setShouldLogMeAndStackParents(boolean shouldLogMeAndStackParents) {
this.shouldLogMeAndStackParents = shouldLogMeAndStackParents;
}

/**
* @return true if this nugget triggers the logging of itself and every other nugget in its stack of nesting
* operations.
*/
public boolean shouldLogMenAndStackParents() {
public boolean shouldLogMeAndStackParents() {
return shouldLogMeAndStackParents;
}

Expand Down
Loading

0 comments on commit d467857

Please sign in to comment.