Skip to content

Commit

Permalink
Check scope existence lock free first (#110)
Browse files Browse the repository at this point in the history
  • Loading branch information
cdvr1993 authored Jan 18, 2023
1 parent 3164eb6 commit 5130e00
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 15 deletions.
21 changes: 14 additions & 7 deletions core/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -42,20 +42,27 @@ task runJmhTests(type: JavaExec, dependsOn: jmhClasses) {
args '-rff', resultFile

// Profile using GC, Threading profilers
args '-prof', 'gc'
args '-prof', 'hs_thr'
if (project.properties.get('busegc', 'true') == 'true') {
args '-prof', 'gc'
args '-prof', 'hs_thr'

// Force GC after every iterations, to make sure that one iteration
// doesn't affect the other one
args '-gc', 'true'
}


// Profile using async-profiling
//
// NOTE: For this to work you need to make sure that async-profiler's library is either
// - Available in LD_LIBRARY_PATH (Linux), DYLD_LIBRARY_PATH (Mac)
// - Available in '-Djava.library.path'
// - Explicitly specified with 'async:libPath=</path/libasyncProfiler.so>'
args '-prof', 'async:event=cpu;direction=forward;output=flamegraph'
args '-prof', project.properties.get('bprof', 'async:event=cpu;direction=forward;output=flamegraph')

// Force GC after every iterations, to make sure that one iteration
// doesn't affect the other one
args '-gc', 'true'
args '-bm', project.properties.get('bm', 'thrpt')
args '-t', project.properties.get('bthreads', '1')
args 'com.uber.m3.tally.' + project.properties.get('benchclass', '')
}

classes.finalizedBy(jmhClasses)
classes.finalizedBy(jmhClasses)
4 changes: 4 additions & 0 deletions core/jmhFixtures.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,8 @@ dependencies {
jmhFixturesUsageCompile project(project.path)
jmhFixturesCompile('org.openjdk.jmh:jmh-core:1.27')
jmhFixturesCompile('org.openjdk.jmh:jmh-generator-annprocess:1.27')

if (project.gradle.gradleVersion > '5') {
jmhAnnotationProcessor("org.openjdk.jmh:jmh-generator-annprocess:1.27")
}
}
53 changes: 53 additions & 0 deletions core/src/jmh/java/com/uber/m3/tally/ScopeImplConcurrent.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package com.uber.m3.tally;

import com.uber.m3.util.Duration;
import com.uber.m3.util.ImmutableMap;
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.infra.Blackhole;

import java.util.concurrent.TimeUnit;

@BenchmarkMode(Mode.Throughput)
@OutputTimeUnit(TimeUnit.MILLISECONDS)
@Fork(value = 2, jvmArgsAppend = { "-server", "-XX:+UseG1GC" })
public class ScopeImplConcurrent {
private static String KEYS[] = new String[]{
" ", "0", "@", "P",
};

@Benchmark
public void hotkeyLockContention(Blackhole bh, BenchmarkState state) {
ImmutableMap<String, String> common = new ImmutableMap.Builder<String, String>().build();
for (int i = 0; i < 10000; i++) {

for (String key : KEYS) {
Scope scope = state.scope.computeSubscopeIfAbsent(key, common);
assert scope != null;
bh.consume(scope);
}
}
}

@State(org.openjdk.jmh.annotations.Scope.Benchmark)
public static class BenchmarkState {

private ScopeImpl scope;

@Setup
public void setup() {
this.scope =
(ScopeImpl) new RootScopeBuilder()
.reporter(new TestStatsReporter())
.reportEvery(Duration.MAX_VALUE);

for (String key : KEYS) {
scope.computeSubscopeIfAbsent(key, new ImmutableMap.Builder<String, String>().build());
}
}

@TearDown
public void teardown() {
scope.close();
}
}
}
27 changes: 19 additions & 8 deletions core/src/main/java/com/uber/m3/tally/ScopeImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ public Histogram histogram(String name, @Nullable Buckets buckets) {
);
}


@Override
public Scope tagged(Map<String, String> tags) {
return subScopeHelper(prefix, tags);
Expand Down Expand Up @@ -280,15 +281,25 @@ private Scope subScopeHelper(String prefix, Map<String, String> tags) {

String key = keyForPrefixedStringMap(prefix, mergedTags);

return computeSubscopeIfAbsent(key, mergedTags);
}

// This method must only be called on unit tests or benchmarks
protected Scope computeSubscopeIfAbsent(String key, ImmutableMap<String, String> mergedTags) {
Scope scope = registry.subscopes.get(key);
if (scope != null) {
return scope;
}

return registry.subscopes.computeIfAbsent(
key,
(k) -> new ScopeBuilder(scheduler, registry)
.reporter(reporter)
.prefix(prefix)
.separator(separator)
.tags(mergedTags)
.defaultBuckets(defaultBuckets)
.build()
key,
(k) -> new ScopeBuilder(scheduler, registry)
.reporter(reporter)
.prefix(prefix)
.separator(separator)
.tags(mergedTags)
.defaultBuckets(defaultBuckets)
.build()
);
}

Expand Down

0 comments on commit 5130e00

Please sign in to comment.