Skip to content

Commit 62e4b1b

Browse files
authored
Pin containers to CPU cores and update license file headers (#92)
In this PR, we are pinning containers to specific CPU cores to avoid resource contention for performance test. Also we are updating logic for the license file headers as some files are unrelated to OTEL files. Testing: ``` >./gradlew test -i ... [Test worker] INFO io.opentelemetry.util.RuntimeUtil - Assume running on Linux. [Test worker] INFO io.opentelemetry.util.RuntimeUtil - Non-App Cores: 0-3. [Test worker] INFO io.opentelemetry.util.RuntimeUtil - App Cores: 4-7. ... OverheadTests > runAllTestConfigurations() > all-800-tps STANDARD_OUT ---------------------------------------------------------- Run at Fri Mar 01 21:24:39 UTC 2024 all-800-tps : Compares all DistroConfigs (800TPS test) 5 users, 10s duration ---------------------------------------------------------- DistroConfig : none app_signals_disabled app_signals_no_traces app_signals_traces Run duration : 00:00:12 00:00:13 00:00:13 00:00:12 Avg. CPU (user) % : 0.0 0.0 0.0 0.0 Max. CPU (user) % : 0.0 0.0 0.0 0.0 Avg. mch tot cpu % : 0.0 0.0 0.0 0.0 Startup time (ms) : 4012 5014 5014 5026 Total allocated MB : 0.00 0.00 0.00 0.00 Thread switch rate : 0.0 0.0 0.0 0.0 GC time (ms) : 0 0 0 0 GC pause time (ms) : 0 0 0 0 Req. mean (ms) : 103.00 102.45 102.21 103.55 Req. p95 (ms) : 389.91 389.93 389.89 389.93 Iter. mean (ms) : 1451.32 1443.18 1438.49 1459.08 Iter. p95 (ms) : 1570.30 1581.58 1622.25 1570.49 Net read avg (bps) : 0.00 0.00 0.00 0.00 Net write avg (bps) : 0.00 0.00 0.00 0.00 Peak threads : 0 0 0 0 Gradle Test Executor 3 finished executing tests. > Task :test Finished generating test XML results (0.049 secs) into: /workplace/thp/python-sdk/aws-otel-python-instrumentation/performance-tests/build/test-results/test Generating HTML test report... Finished generating test html results (0.053 secs) into: /workplace/thp/python-sdk/aws-otel-python-instrumentation/performance-tests/build/reports/tests/test Deprecated Gradle features were used in this build, making it incompatible with Gradle 9.0. You can use '--warning-mode all' to show the individual deprecation warnings and determine if they come from your own scripts or plugins. For more on this, please refer to https://docs.gradle.org/8.6/userguide/command_line_interface.html#sec:command_line_warnings in the Gradle documentation. BUILD SUCCESSFUL in 3m 28s 3 actionable tasks: 1 executed, 2 up-to-date ``` By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.
1 parent 7b61128 commit 62e4b1b

File tree

9 files changed

+107
-2
lines changed

9 files changed

+107
-2
lines changed

performance-tests/build.gradle.kts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,12 @@ plugins {
66
spotless {
77
java {
88
googleJavaFormat()
9+
licenseHeaderFile(rootProject.file("../scripts/spotless.modify_license.java"), "(package|import|public)")
10+
.named("modify_license")
11+
.onlyIfContentMatches("!.*RuntimeUtil.java")
912
licenseHeaderFile(rootProject.file("../scripts/spotless.license.java"), "(package|import|public)")
13+
.named("license")
14+
.onlyIfContentMatches(".*RuntimeUtil.java")
1015
target("src/**/*.java")
1116
}
1217
}

performance-tests/src/test/java/io/opentelemetry/containers/CollectorContainer.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
package io.opentelemetry.containers;
88

9+
import io.opentelemetry.util.RuntimeUtil;
910
import org.slf4j.Logger;
1011
import org.slf4j.LoggerFactory;
1112
import org.testcontainers.containers.GenericContainer;
@@ -33,6 +34,8 @@ public static GenericContainer<?> build(Network network) {
3334
.waitingFor(Wait.forHttp("/health").forPort(COLLECTOR_HEALTH_CHECK_PORT))
3435
.withCopyFileToContainer(
3536
MountableFile.forClasspathResource("collector.yaml"), "/etc/otel.yaml")
37+
.withCreateContainerCmdModifier(
38+
cmd -> cmd.getHostConfig().withCpusetCpus(RuntimeUtil.getNonApplicationCores()))
3639
.withCommand("--config /etc/otel.yaml");
3740
}
3841
}

performance-tests/src/test/java/io/opentelemetry/containers/ImageServiceContainer.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
package io.opentelemetry.containers;
88

9+
import io.opentelemetry.util.RuntimeUtil;
910
import org.slf4j.Logger;
1011
import org.slf4j.LoggerFactory;
1112
import org.testcontainers.containers.GenericContainer;
@@ -45,6 +46,8 @@ public GenericContainer<?> build() {
4546
.withEnv("AWS_SECRET_ACCESS_KEY", System.getenv("AWS_SECRET_ACCESS_KEY"))
4647
.withEnv("AWS_SESSION_TOKEN", System.getenv("AWS_SESSION_TOKEN"))
4748
.withEnv("S3_BUCKET", System.getenv("S3_BUCKET"))
49+
.withCreateContainerCmdModifier(
50+
cmd -> cmd.getHostConfig().withCpusetCpus(RuntimeUtil.getNonApplicationCores()))
4851
.withCommand(String.format("python3 manage.py runserver 0.0.0.0:%s --noreload", PORT));
4952
}
5053
}

performance-tests/src/test/java/io/opentelemetry/containers/K6Container.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import io.opentelemetry.config.TestConfig;
1010
import io.opentelemetry.distros.DistroConfig;
1111
import io.opentelemetry.util.NamingConventions;
12+
import io.opentelemetry.util.RuntimeUtil;
1213
import java.nio.file.Path;
1314
import java.time.Duration;
1415
import org.slf4j.Logger;
@@ -60,6 +61,8 @@ public GenericContainer<?> build() {
6061
"--summary-trend-stats",
6162
"avg,p(0),p(50),p(90),p(99),p(100),count",
6263
"/app/performanceTest.js")
64+
.withCreateContainerCmdModifier(
65+
cmd -> cmd.getHostConfig().withCpusetCpus(RuntimeUtil.getNonApplicationCores()))
6366
.withStartupCheckStrategy(
6467
new OneShotStartupCheckStrategy().withTimeout(Duration.ofMinutes(15)));
6568
}

performance-tests/src/test/java/io/opentelemetry/containers/PostgresContainer.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
package io.opentelemetry.containers;
88

9+
import io.opentelemetry.util.RuntimeUtil;
910
import org.slf4j.Logger;
1011
import org.slf4j.LoggerFactory;
1112
import org.testcontainers.containers.Network;
@@ -34,6 +35,8 @@ public PostgreSQLContainer<?> build() throws Exception {
3435
.withUsername(USERNAME)
3536
.withPassword(PASSWORD)
3637
.withDatabaseName(DATABASE_NAME)
38+
.withCreateContainerCmdModifier(
39+
cmd -> cmd.getHostConfig().withCpusetCpus(RuntimeUtil.getNonApplicationCores()))
3740
.withReuse(false);
3841
}
3942
}

performance-tests/src/test/java/io/opentelemetry/containers/VehicleInventoryServiceContainer.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
package io.opentelemetry.containers;
88

99
import io.opentelemetry.distros.DistroConfig;
10+
import io.opentelemetry.util.RuntimeUtil;
1011
import org.slf4j.Logger;
1112
import org.slf4j.LoggerFactory;
1213
import org.testcontainers.containers.GenericContainer;
@@ -57,6 +58,8 @@ public GenericContainer<?> build() {
5758
.withEnv("IMAGE_BACKEND_SERVICE_PORT", Integer.toString(ImageServiceContainer.PORT))
5859
.withEnv(distroConfig.getAdditionalEnvVars())
5960
.dependsOn(collector)
61+
.withCreateContainerCmdModifier(
62+
cmd -> cmd.getHostConfig().withCpusetCpus(RuntimeUtil.getApplicationCores()))
6063
.withCommand("bash run.sh");
6164

6265
if (distroConfig.doInstrument()) {
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
/*
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.util;
7+
8+
import java.io.BufferedReader;
9+
import java.io.InputStreamReader;
10+
import org.slf4j.Logger;
11+
import org.slf4j.LoggerFactory;
12+
13+
public class RuntimeUtil {
14+
private static final Logger logger = LoggerFactory.getLogger(RuntimeUtil.class);
15+
private static final int CORE_COUNT = getCpuCoreCount();
16+
17+
/**
18+
* Get cores dedicated for application container being performance tested, to reduce chances of
19+
* CPU resource contention causing application slowdown. E.g. if 6 core system, "3-5"
20+
*/
21+
public static String getApplicationCores() {
22+
String cpus = String.format("%s-%s", CORE_COUNT / 2, CORE_COUNT - 1);
23+
logger.info(String.format("App Cores: %s.", cpus));
24+
return cpus;
25+
}
26+
27+
/** Get cores for all other containers. E.g. if 6 core system, "0-2" */
28+
public static String getNonApplicationCores() {
29+
String cpus = String.format("0-%s", CORE_COUNT / 2 - 1);
30+
logger.info(String.format("Non-App Cores: %s.", cpus));
31+
return cpus;
32+
}
33+
34+
private static int getCpuCoreCount() {
35+
String os = System.getProperty("os.name").toLowerCase();
36+
try {
37+
if (os.contains("mac")) {
38+
logger.info("Detected running on MacOS.");
39+
return getCoreCountMac();
40+
} else {
41+
logger.info("Assume running on Linux.");
42+
return getCoreCountLinux();
43+
}
44+
} catch (Exception e) {
45+
throw new RuntimeException(e);
46+
}
47+
}
48+
49+
private static int getCoreCountMac() throws Exception {
50+
String command = "sysctl -n hw.ncpu";
51+
String[] cmd = {"/bin/sh", "-c", command};
52+
Process process = Runtime.getRuntime().exec(cmd);
53+
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
54+
String line = reader.readLine();
55+
return !line.isEmpty() ? Integer.parseInt(line) : 0;
56+
}
57+
58+
private static int getCoreCountLinux() throws Exception {
59+
String command = "lscpu";
60+
Process process = Runtime.getRuntime().exec(command);
61+
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
62+
String line = reader.readLine();
63+
int threadsPerCore = 0;
64+
int coresPerSocket = 0;
65+
int sockets = 0;
66+
while (line != null) {
67+
if (line.contains("Thread(s) per core:")) {
68+
threadsPerCore = Integer.parseInt(line.split("\\s+")[line.split("\\s+").length - 1]);
69+
}
70+
if (line.contains("Core(s) per socket:")) {
71+
coresPerSocket = Integer.parseInt(line.split("\\s+")[line.split("\\s+").length - 1]);
72+
}
73+
if (line.contains("Socket(s):")) {
74+
sockets = Integer.parseInt(line.split("\\s+")[line.split("\\s+").length - 1]);
75+
}
76+
line = reader.readLine();
77+
}
78+
return threadsPerCore * coresPerSocket * sockets;
79+
}
80+
}

scripts/spotless.license.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
/*
2-
* Copyright The OpenTelemetry Authors
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
33
* SPDX-License-Identifier: Apache-2.0
4-
* Modifications Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
54
*/
65

scripts/spotless.modify_license.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
* Modifications Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
5+
*/
6+

0 commit comments

Comments
 (0)