Skip to content

Commit

Permalink
Improved memory allocations in meter cache (#42)
Browse files Browse the repository at this point in the history
* Improved memory allocations in meter cache by avoiding frequent linkToTargetMethod allocations by lambda executions.
  • Loading branch information
onukristo authored Oct 3, 2023
1 parent d65ccc2 commit 2bc56d1
Show file tree
Hide file tree
Showing 7 changed files with 100 additions and 13 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [1.12.0] - 2023-10-03

### Changed

* Improved memory allocations in meter cache by avoiding frequent linkToTargetMethod allocations by lambda executions.

## [1.11.1] - 2023-08-17

### Fixed
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1 +1 @@
version=1.11.1
version=1.12.0
Binary file modified gradle/wrapper/gradle-wrapper.jar
Binary file not shown.
3 changes: 2 additions & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
15 changes: 10 additions & 5 deletions gradlew
Original file line number Diff line number Diff line change
Expand Up @@ -83,10 +83,8 @@ done
# This is normally unused
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit

# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit

# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
Expand Down Expand Up @@ -133,10 +131,13 @@ location of your Java installation."
fi
else
JAVACMD=java
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
if ! command -v java >/dev/null 2>&1
then
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
fi

# Increase the maximum file descriptors if we can.
Expand Down Expand Up @@ -197,6 +198,10 @@ if "$cygwin" || "$msys" ; then
done
fi


# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'

# Collect all arguments for the java command;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,20 +23,60 @@ public interface IMeterCache {
* Allows to also cache Objects, which contain multiple meters.
*
* <p>Even when those can be cached by other means, it is convenient, that meterCache.clear() will also clear those.
*
* @deprecated in a favor of {@link #metersContainer(String, TagsSet, MeterContainerCreator)}.
*/
@Deprecated(forRemoval = true)
<T> T metersContainer(String name, TagsSet tags, Supplier<T> collectionCreator);

<T> T metersContainer(String name, TagsSet tags, MeterContainerCreator<T> meterContainerCreator);

DistributionSummary summary(String name, TagsSet tags);

/**
* Returns a DistributionSummary.
*
* @deprecated in a favor of {@link #summary(String, TagsSet, MeterCreator)} .
*/
@Deprecated(forRemoval = true)
DistributionSummary summary(String name, TagsSet tags, Supplier<DistributionSummary> supplier);

DistributionSummary summary(String name, TagsSet tags, MeterCreator<DistributionSummary> meterCreator);

Timer timer(String name, TagsSet tags);

/**
* Returns a counter.
*
* @deprecated in a favor of {@link #timer(String, TagsSet, MeterCreator)} .
*/
@Deprecated(forRemoval = true)
Timer timer(String name, TagsSet tags, Supplier<Timer> supplier);

Timer timer(String name, TagsSet tags, MeterCreator<Timer> meterCreator);


Counter counter(String name, TagsSet tags);

/**
* Returns a counter.
*
* @deprecated in a favor of {@link #counter(String, TagsSet, MeterCreator)} .
*/
@Deprecated(forRemoval = true)
Counter counter(String name, TagsSet tags, Supplier<Counter> supplier);

Counter counter(String name, TagsSet tags, MeterCreator<Counter> meterCreator);

MeterRegistry getMeterRegistry();

interface MeterCreator<M extends Meter> {

M create(String name, TagsSet tags);
}

interface MeterContainerCreator<T> {

T create(String name, TagsSet tags);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,28 @@
import io.micrometer.core.instrument.Timer;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Supplier;
import org.apache.commons.lang3.tuple.Pair;

public class MeterCache implements IMeterCache {

private Map<Pair<String, TagsSet>, Meter> metersMap = new ConcurrentHashMap<>();
private final Map<Pair<String, TagsSet>, Meter> metersMap = new ConcurrentHashMap<>();

private Map<Pair<String, TagsSet>, Object> metersContainersMap = new ConcurrentHashMap<>();
private final Map<Pair<String, TagsSet>, Object> metersContainersMap = new ConcurrentHashMap<>();

private MeterRegistry meterRegistry;
/*
Following 2 are meant to avoid creating linkToTargetMethod instances on every lambda invocation.
*/
private Function<Pair<String, TagsSet>, Counter> counterCreaterFunction;
private Function<Pair<String, TagsSet>, Timer> timerCreaterFunction;

private final MeterRegistry meterRegistry;

public MeterCache(MeterRegistry meterRegistry) {
this.meterRegistry = meterRegistry;
this.counterCreaterFunction = k -> meterRegistry.counter(k.getKey(), k.getValue().getMicrometerTags());
this.timerCreaterFunction = k -> meterRegistry.timer(k.getKey(), k.getValue().getMicrometerTags());
}

@Override
Expand Down Expand Up @@ -49,41 +58,67 @@ public Object removeMetersContainer(String name, TagsSet tags) {
}

@Override
@Deprecated(forRemoval = true)
@SuppressWarnings("unchecked")
public <T> T metersContainer(String name, TagsSet tags, Supplier<T> containerCreator) {
return (T) metersContainersMap.computeIfAbsent(Pair.of(name, tags), k -> containerCreator.get());
}

@Override
@SuppressWarnings("unchecked")
public <T> T metersContainer(String name, TagsSet tags, MeterContainerCreator<T> meterContainerCreator) {
return (T) metersContainersMap.computeIfAbsent(Pair.of(name, tags), k -> meterContainerCreator.create(k.getKey(), k.getValue()));
}

@Override
public DistributionSummary summary(String name, TagsSet tags) {
return (DistributionSummary) metersMap.computeIfAbsent(Pair.of(name, tags), k -> meterRegistry.summary(name, tags.getMicrometerTags()));
return (DistributionSummary) metersMap.computeIfAbsent(Pair.of(name, tags),
k -> meterRegistry.summary(k.getKey(), k.getValue().getMicrometerTags()));
}

@Override
@Deprecated(forRemoval = true)
public DistributionSummary summary(String name, TagsSet tags, Supplier<DistributionSummary> metricCreator) {
return (DistributionSummary) metersMap.computeIfAbsent(Pair.of(name, tags), k -> metricCreator.get());
}

@Override
public DistributionSummary summary(String name, TagsSet tags, MeterCreator<DistributionSummary> meterCreator) {
return (DistributionSummary) metersMap.computeIfAbsent(Pair.of(name, tags), k -> meterCreator.create(k.getKey(), k.getValue()));
}

@Override
public Timer timer(String name, TagsSet tags) {
return (Timer) metersMap.computeIfAbsent(Pair.of(name, tags), k -> meterRegistry.timer(name, tags.getMicrometerTags()));
return (Timer) metersMap.computeIfAbsent(Pair.of(name, tags), timerCreaterFunction);
}

@Override
@Deprecated(forRemoval = true)
public Timer timer(String name, TagsSet tags, Supplier<Timer> metricCreator) {
return (Timer) metersMap.computeIfAbsent(Pair.of(name, tags), k -> metricCreator.get());
}

@Override
public Timer timer(String name, TagsSet tags, MeterCreator<Timer> meterCreator) {
return (Timer) metersMap.computeIfAbsent(Pair.of(name, tags), k -> meterCreator.create(k.getKey(), k.getValue()));
}

@Override
public Counter counter(String name, TagsSet tagsSet) {
return (Counter) metersMap.computeIfAbsent(Pair.of(name, tagsSet), k -> meterRegistry.counter(name, tagsSet.getMicrometerTags()));
return (Counter) metersMap.computeIfAbsent(Pair.of(name, tagsSet), counterCreaterFunction);
}

@Override
@Deprecated(forRemoval = true)
public Counter counter(String name, TagsSet tags, Supplier<Counter> metricCreator) {
return (Counter) metersMap.computeIfAbsent(Pair.of(name, tags), k -> metricCreator.get());
}

@Override
public Counter counter(String name, TagsSet tags, MeterCreator<Counter> meterCreator) {
return (Counter) metersMap.computeIfAbsent(Pair.of(name, tags), k -> meterCreator.create(k.getKey(), k.getValue()));
}

@Override
public MeterRegistry getMeterRegistry() {
return meterRegistry;
Expand Down

0 comments on commit 2bc56d1

Please sign in to comment.