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

05574 d busy time metric #5798

Merged
merged 27 commits into from May 4, 2023
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
33 changes: 33 additions & 0 deletions platform-sdk/docs/base/metrics/busy-time-metric.md
lpetrovic05 marked this conversation as resolved.
Show resolved Hide resolved
@@ -0,0 +1,33 @@
### Background

There are a number of critical threads in our pipeline whose performance must be monitored closely. Investigating
performance issues often requires a lot of time to narrow down the issue.

### Problems with previous approaches

- In many places we track the average time something takes. This number by itself is not that useful, without the
knowledge how many times it has been executed on a particular thread.
- Metrics are often updated when the work is done. This means that if a thread is blocked, we have no insight into what
is going on. This also means that some work that takes a long time within one sampling period might be reported in a
subsequent sampling period, giving us misleading information.
- Some attempts have been made to unify this with cycle metrics. These are a collection of metrics updated through a
single instance.
- Since they all need to be updated through a single class, this would mean that all classes executing on a
particular thread need a dependency to it.
- Since they track cyclical work, they do not handle situations where a thread does different type of work

## Busy time metric

- All thread work is tracked by percentages (or fractions)
- All subtasks of a thread are tracked individually
- The metric tracks the current status of the thread, so that accurate information can sampled even if the thread is
lpetrovic05 marked this conversation as resolved.
Show resolved Hide resolved
stuck
- it is lock-free and garbage-free. The metric implementation that stores all relevant information within an integer
lpetrovic05 marked this conversation as resolved.
Show resolved Hide resolved
pair that can be updated atomically.
- This can track the overall busyness of a thread
- It can also track each part of the execution to get more detailed information about where a thread is spending its
time

### Example diagram

![](busy-time.svg)
4 changes: 4 additions & 0 deletions platform-sdk/docs/base/metrics/busy-time.svg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
lpetrovic05 marked this conversation as resolved.
Show resolved Hide resolved
Expand Up @@ -16,14 +16,16 @@

package com.swirlds.common.metrics;

import static com.swirlds.base.ArgumentUtils.throwArgNull;
import static com.swirlds.common.metrics.Metric.ValueType.VALUE;
import static com.swirlds.common.utility.CommonUtils.throwArgNull;
import static org.apache.commons.lang3.builder.ToStringStyle.SHORT_PREFIX_STYLE;

import java.util.EnumSet;
import java.util.function.BiFunction;
import java.util.function.IntBinaryOperator;
import java.util.function.IntSupplier;
import java.util.function.IntUnaryOperator;
import java.util.function.LongBinaryOperator;
import org.apache.commons.lang3.builder.ToStringBuilder;

/**
Expand Down Expand Up @@ -109,11 +111,12 @@ final class Config<T> extends MetricConfig<IntegerPairAccumulator<T>, IntegerPai

private final IntBinaryOperator leftAccumulator;
private final IntBinaryOperator rightAccumulator;
private final LongBinaryOperator combinedAccumulator;

private final IntSupplier leftInitializer;
private final IntSupplier rightInitializer;
private final IntUnaryOperator leftReset;
lpetrovic05 marked this conversation as resolved.
Show resolved Hide resolved
private final IntUnaryOperator rightReset;

private static final IntSupplier DEFAULT_INITIALIZER = () -> 0;
private static final IntUnaryOperator DEFAULT_INITIALIZER = i -> 0;

/**
* Constructor of {@code IntegerPairAccumulator.Config}
Expand All @@ -137,8 +140,9 @@ public Config(
this.resultFunction = throwArgNull(resultFunction, "resultFunction");
this.leftAccumulator = Integer::sum;
this.rightAccumulator = Integer::sum;
this.leftInitializer = DEFAULT_INITIALIZER;
this.rightInitializer = DEFAULT_INITIALIZER;
this.leftReset = DEFAULT_INITIALIZER;
this.rightReset = DEFAULT_INITIALIZER;
this.combinedAccumulator = null;
}

private Config(
Expand All @@ -151,16 +155,23 @@ private Config(
final BiFunction<Integer, Integer, T> resultFunction,
final IntBinaryOperator leftAccumulator,
final IntBinaryOperator rightAccumulator,
final IntSupplier leftInitializer,
final IntSupplier rightInitializer) {
final LongBinaryOperator combinedAccumulator,
final IntUnaryOperator leftReset,
final IntUnaryOperator rightReset) {

super(category, name, description, unit, format);
this.type = throwArgNull(type, "type");
this.resultFunction = throwArgNull(resultFunction, "resultFunction");
this.leftAccumulator = throwArgNull(leftAccumulator, "leftAccumulator");
this.rightAccumulator = throwArgNull(rightAccumulator, "rightAccumulator");
this.leftInitializer = throwArgNull(leftInitializer, "leftInitializer");
this.rightInitializer = throwArgNull(rightInitializer, "rightInitializer");
if (combinedAccumulator == null) {
this.leftAccumulator = throwArgNull(leftAccumulator, "leftAccumulator");
this.rightAccumulator = throwArgNull(rightAccumulator, "rightAccumulator");
} else {
this.leftAccumulator = null;
this.rightAccumulator = null;
}
this.combinedAccumulator = combinedAccumulator;
this.leftReset = throwArgNull(leftReset, "leftInitializer");
this.rightReset = throwArgNull(rightReset, "rightInitializer");
}

/**
Expand All @@ -178,8 +189,9 @@ public IntegerPairAccumulator.Config<T> withDescription(final String description
getResultFunction(),
getLeftAccumulator(),
getRightAccumulator(),
getLeftInitializer(),
getRightInitializer());
getCombinedAccumulator(),
getLeftReset(),
getRightReset());
}

/**
Expand All @@ -197,8 +209,9 @@ public IntegerPairAccumulator.Config<T> withUnit(final String unit) {
getResultFunction(),
getLeftAccumulator(),
getRightAccumulator(),
getLeftInitializer(),
getRightInitializer());
getCombinedAccumulator(),
getLeftReset(),
getRightReset());
}

/**
Expand All @@ -219,8 +232,9 @@ public IntegerPairAccumulator.Config<T> withFormat(final String format) {
getResultFunction(),
getLeftAccumulator(),
getRightAccumulator(),
getLeftInitializer(),
getRightInitializer());
getCombinedAccumulator(),
getLeftReset(),
getRightReset());
}

/**
Expand Down Expand Up @@ -257,6 +271,9 @@ public IntBinaryOperator getLeftAccumulator() {
* @return a new configuration-object with updated {@code leftAccumulator}
*/
public IntegerPairAccumulator.Config<T> withLeftAccumulator(final IntBinaryOperator leftAccumulator) {
if (combinedAccumulator != null) {
throw new IllegalStateException("Cannot set leftAccumulator when combinedAccumulator is set");
}
return new IntegerPairAccumulator.Config<>(
getCategory(),
getName(),
Expand All @@ -267,8 +284,9 @@ public IntegerPairAccumulator.Config<T> withLeftAccumulator(final IntBinaryOpera
getResultFunction(),
leftAccumulator,
getRightAccumulator(),
getLeftInitializer(),
getRightInitializer());
null,
getLeftReset(),
getRightReset());
}

/**
Expand All @@ -287,6 +305,9 @@ public IntBinaryOperator getRightAccumulator() {
* @return a new configuration-object with updated {@code rightAccumulator}
*/
public IntegerPairAccumulator.Config<T> withRightAccumulator(final IntBinaryOperator rightAccumulator) {
if (combinedAccumulator != null) {
throw new IllegalStateException("Cannot set rightAccumulator when combinedAccumulator is set");
}
return new IntegerPairAccumulator.Config<>(
getCategory(),
getName(),
Expand All @@ -297,17 +318,49 @@ public IntegerPairAccumulator.Config<T> withRightAccumulator(final IntBinaryOper
getResultFunction(),
getLeftAccumulator(),
rightAccumulator,
getLeftInitializer(),
getRightInitializer());
null,
getLeftReset(),
getRightReset());
}

/**
* Getter of the {@code leftInitializer}
* Getter of the {@code combinedAccumulator}
*
* @return the {@code leftInitializer}
* @return the {@code combinedAccumulator}
*/
public IntSupplier getLeftInitializer() {
return leftInitializer;
public LongBinaryOperator getCombinedAccumulator() {
return combinedAccumulator;
}

/**
* Fluent-style setter of the combined accumulator.
*
* @param combinedAccumulator the accumulator method
* @return a new configuration-object with updated {@code combinedAccumulator}
*/
public IntegerPairAccumulator.Config<T> withCombinedAccumulator(final LongBinaryOperator combinedAccumulator) {
lpetrovic05 marked this conversation as resolved.
Show resolved Hide resolved
lpetrovic05 marked this conversation as resolved.
Show resolved Hide resolved
return new IntegerPairAccumulator.Config<>(
getCategory(),
getName(),
getDescription(),
getUnit(),
getFormat(),
getType(),
getResultFunction(),
null,
null,
combinedAccumulator,
getLeftReset(),
getRightReset());
}

/**
* Getter of the {@code leftReset}
*
* @return the {@code leftReset}
*/
public IntUnaryOperator getLeftReset() {
return leftReset;
}

/**
Expand All @@ -327,8 +380,9 @@ public IntegerPairAccumulator.Config<T> withLeftInitializer(final IntSupplier le
getResultFunction(),
getLeftAccumulator(),
getRightAccumulator(),
leftInitializer,
getRightInitializer());
getCombinedAccumulator(),
i -> leftInitializer.getAsInt(),
getRightReset());
}

/**
Expand All @@ -348,17 +402,40 @@ public IntegerPairAccumulator.Config<T> withLeftInitialValue(final int leftIniti
getResultFunction(),
getLeftAccumulator(),
getRightAccumulator(),
leftInitialValue == 0 ? DEFAULT_INITIALIZER : () -> leftInitialValue,
getRightInitializer());
getCombinedAccumulator(),
leftInitialValue == 0 ? DEFAULT_INITIALIZER : i -> leftInitialValue,
getRightReset());
}

/**
* Fluent-style setter of the left reset.
*
* @param leftReset the left reset
* @return a new configuration-object with updated {@code leftReset}
*/
public IntegerPairAccumulator.Config<T> withLeftReset(final IntUnaryOperator leftReset) {
lpetrovic05 marked this conversation as resolved.
Show resolved Hide resolved
return new IntegerPairAccumulator.Config<>(
getCategory(),
getName(),
getDescription(),
getUnit(),
getFormat(),
getType(),
getResultFunction(),
getLeftAccumulator(),
getRightAccumulator(),
getCombinedAccumulator(),
leftReset,
getRightReset());
}

/**
* Getter of the {@code rightInitializer}
* Getter of the {@code rightReset}
*
* @return the {@code rightInitializer}
* @return the {@code rightReset}
*/
public IntSupplier getRightInitializer() {
return rightInitializer;
public IntUnaryOperator getRightReset() {
return rightReset;
}

/**
Expand All @@ -378,8 +455,9 @@ public IntegerPairAccumulator.Config<T> withRightInitializer(final IntSupplier r
getResultFunction(),
getLeftAccumulator(),
getRightAccumulator(),
getLeftInitializer(),
rightInitializer);
getCombinedAccumulator(),
getLeftReset(),
i -> rightInitializer.getAsInt());
}

/**
Expand All @@ -399,8 +477,31 @@ public IntegerPairAccumulator.Config<T> withRightInitialValue(final int rightIni
getResultFunction(),
getLeftAccumulator(),
getRightAccumulator(),
getLeftInitializer(),
rightInitialValue == 0 ? DEFAULT_INITIALIZER : () -> rightInitialValue);
getCombinedAccumulator(),
getLeftReset(),
rightInitialValue == 0 ? DEFAULT_INITIALIZER : i -> rightInitialValue);
}

/**
* Fluent-style setter of the right reset.
*
* @param rightReset the right reset value
* @return a new configuration-object with updated {@code rightReset}
*/
public IntegerPairAccumulator.Config<T> withRightReset(final IntUnaryOperator rightReset) {
alittley marked this conversation as resolved.
Show resolved Hide resolved
return new IntegerPairAccumulator.Config<>(
getCategory(),
getName(),
getDescription(),
getUnit(),
getFormat(),
getType(),
getResultFunction(),
getLeftAccumulator(),
getRightAccumulator(),
getCombinedAccumulator(),
getLeftReset(),
rightReset);
}

/**
Expand Down