From 4b93495b060d709f40f9a8a508983291ab108658 Mon Sep 17 00:00:00 2001 From: Arpan Mishra Date: Tue, 2 Apr 2024 10:46:34 +0530 Subject: [PATCH 1/3] chore: minor improvements to default benchmarks. --- .../spanner/AbstractLatencyBenchmark.java | 60 +++++++++++++++++-- .../cloud/spanner/DefaultBenchmark.java | 58 +++++------------- 2 files changed, 70 insertions(+), 48 deletions(-) diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/AbstractLatencyBenchmark.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/AbstractLatencyBenchmark.java index d7edf64030e..baf4a6be796 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/AbstractLatencyBenchmark.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/AbstractLatencyBenchmark.java @@ -16,6 +16,7 @@ package com.google.cloud.spanner; +import com.google.common.base.MoreObjects; import java.time.Duration; import java.util.ArrayList; import java.util.Collections; @@ -24,6 +25,48 @@ public abstract class AbstractLatencyBenchmark { + static final String SELECT_QUERY = "SELECT ID FROM FOO WHERE ID = @id"; + static final String UPDATE_QUERY = "UPDATE FOO SET BAR=1 WHERE ID = @id"; + static final String ID_COLUMN_NAME = "id"; + + /** + * Used to determine how many concurrent requests are allowed. For ex - To simulate a low QPS + * scenario, using 1 thread means there will be 1 request. Use a value > 1 to have concurrent + * requests. + */ + static final int PARALLEL_THREADS = + Integer.valueOf(MoreObjects.firstNonNull( + System.getenv("SPANNER_TEST_JMH_NUM_PARALLEL_THREADS"), "30")); + + /** + * Total number of reads per test run for 1 thread. Increasing the value here will increase the + * duration of the benchmark. For ex - With PARALLEL_THREADS = 2, TOTAL_READS_PER_RUN = 200, there + * will be 400 read requests (200 on each thread). + */ + static final int TOTAL_READS_PER_RUN = Integer.valueOf(MoreObjects.firstNonNull( + System.getenv("SPANNER_TEST_JMH_NUM_READS_PER_THREAD"), "48000")); + + /** + * Total number of writes per test run for 1 thread. Increasing the value here will increase the + * duration of the benchmark. For ex - With PARALLEL_THREADS = 2, TOTAL_WRITES_PER_RUN = 200, + * there will be 400 write requests (200 on each thread). + */ + static final int TOTAL_WRITES_PER_RUN = Integer.valueOf(MoreObjects.firstNonNull( + System.getenv("SPANNER_TEST_JMH_NUM_WRITES_PER_THREAD"), "4000")); + + /** + * Number of requests which are used to initialise/warmup the benchmark. The latency number of + * these runs are ignored from the final reported results. + */ + static final int WARMUP_REQUEST_COUNT = 1; + + /** + * Numbers of records in the sample table used in the benchmark. This is used in this benchmark to + * randomly choose a primary key and ensure that the reads are randomly distributed. This is done + * to ensure we don't end up reading/writing the same table record (leading to hot-spotting). + */ + static final int TOTAL_RECORDS = 1000000; + /** Utility to print latency numbers. It computes metrics such as Average, P50, P95 and P99. */ public void printResults(List results) { if (results == null) { @@ -33,23 +76,23 @@ public void printResults(List results) { Collections.sort(orderedResults); System.out.println(); System.out.printf("Total number of queries: %d\n", orderedResults.size()); - System.out.printf("Avg: %fs\n", avg(results)); - System.out.printf("P50: %fs\n", percentile(50, orderedResults)); - System.out.printf("P95: %fs\n", percentile(95, orderedResults)); - System.out.printf("P99: %fs\n", percentile(99, orderedResults)); + System.out.printf("Avg: %fms\n", avg(results)); + System.out.printf("P50: %fms\n", percentile(50, orderedResults)); + System.out.printf("P95: %fms\n", percentile(95, orderedResults)); + System.out.printf("P99: %fms\n", percentile(99, orderedResults)); } private double percentile(int percentile, List orderedResults) { int index = percentile * orderedResults.size() / 100; Duration value = orderedResults.get(index); - Double convertedValue = convertDurationToFractionInSeconds(value); + Double convertedValue = convertDurationToFractionInMilliSeconds(value); return convertedValue; } /** Returns the average duration in seconds from a list of duration values. */ private double avg(List results) { return results.stream() - .collect(Collectors.averagingDouble(this::convertDurationToFractionInSeconds)); + .collect(Collectors.averagingDouble(this::convertDurationToFractionInMilliSeconds)); } private double convertDurationToFractionInSeconds(Duration duration) { @@ -59,4 +102,9 @@ private double convertDurationToFractionInSeconds(Duration duration) { double value = seconds + fraction; return value; } + + private double convertDurationToFractionInMilliSeconds(Duration duration) { + long nanoseconds = duration.toNanos(); + return nanoseconds / 1000000.0; + } } diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DefaultBenchmark.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DefaultBenchmark.java index 84578dd3231..d966d58dbd5 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DefaultBenchmark.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DefaultBenchmark.java @@ -18,6 +18,8 @@ import static com.google.cloud.spanner.BenchmarkingUtilityScripts.collectResults; import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; import com.google.common.base.Stopwatch; import com.google.common.util.concurrent.ListenableFuture; @@ -37,6 +39,7 @@ import org.openjdk.jmh.annotations.Measurement; import org.openjdk.jmh.annotations.Mode; import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Param; import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.Setup; import org.openjdk.jmh.annotations.State; @@ -45,8 +48,8 @@ /** * Benchmarks for measuring existing latencies of various APIs using the Java Client. The benchmarks - * are bound to the Maven profile `benchmark` and can be executed like this: mvn clean test - * -DskipTests -Pbenchmark -Dbenchmark.name=DefaultBenchmark + * are bound to the Maven profile `benchmark` and can be executed like this: + * mvn clean test -DskipTests -Pbenchmark -Dbenchmark.name=DefaultBenchmark * Test Table Schema : * *

CREATE TABLE FOO ( id INT64 NOT NULL, BAZ INT64, BAR INT64, ) PRIMARY KEY(id); @@ -63,47 +66,9 @@ @Fork(value = 1, warmups = 0) @Measurement(batchSize = 1, iterations = 1, timeUnit = TimeUnit.MILLISECONDS) @OutputTimeUnit(TimeUnit.SECONDS) -@Warmup(iterations = 1) +@Warmup(iterations = 0) public class DefaultBenchmark extends AbstractLatencyBenchmark { - private static final String SELECT_QUERY = "SELECT ID FROM FOO WHERE ID = @id"; - private static final String UPDATE_QUERY = "UPDATE FOO SET BAR=1 WHERE ID = @id"; - private static final String ID_COLUMN_NAME = "id"; - - /** - * Used to determine how many concurrent requests are allowed. For ex - To simulate a low QPS - * scenario, using 1 thread means there will be 1 request. Use a value > 1 to have concurrent - * requests. - */ - private static final int PARALLEL_THREADS = 1; - - /** - * Total number of reads per test run for 1 thread. Increasing the value here will increase the - * duration of the benchmark. For ex - With PARALLEL_THREADS = 2, TOTAL_READS_PER_RUN = 200, there - * will be 400 read requests (200 on each thread). - */ - private static final int TOTAL_READS_PER_RUN = 12000; - - /** - * Total number of writes per test run for 1 thread. Increasing the value here will increase the - * duration of the benchmark. For ex - With PARALLEL_THREADS = 2, TOTAL_WRITES_PER_RUN = 200, - * there will be 400 write requests (200 on each thread). - */ - private static final int TOTAL_WRITES_PER_RUN = 4000; - - /** - * Number of requests which are used to initialise/warmup the benchmark. The latency number of - * these runs are ignored from the final reported results. - */ - private static final int WARMUP_REQUEST_COUNT = 1; - - /** - * Numbers of records in the sample table used in the benchmark. This is used in this benchmark to - * randomly choose a primary key and ensure that the reads are randomly distributed. This is done - * to ensure we don't end up reading/writing the same table record (leading to hot-spotting). - */ - private static final int TOTAL_RECORDS = 1000000; - @State(Scope.Thread) @AuxCounters(org.openjdk.jmh.annotations.AuxCounters.Type.EVENTS) public static class BenchmarkState { @@ -115,12 +80,20 @@ public static class BenchmarkState { private Spanner spanner; private DatabaseClientImpl client; + @Param({"100"}) + int minSessions; + + @Param({"400"}) + int maxSessions; + @Setup(Level.Iteration) public void setup() throws Exception { SpannerOptions options = SpannerOptions.newBuilder() .setSessionPoolOption( SessionPoolOptions.newBuilder() + .setMinSessions(minSessions) + .setMaxSessions(maxSessions) .setWaitForMinSessions(org.threeten.bp.Duration.ofSeconds(20)) .build()) .setHost(SERVER_URL) @@ -217,7 +190,8 @@ private java.time.Duration executeQuery(final BenchmarkState server) { try (ResultSet rs = server.client.singleUse().executeQuery(getRandomisedReadStatement())) { while (rs.next()) { - int count = rs.getColumnCount(); + assertEquals(1, rs.getColumnCount()); + assertNotNull(rs.getValue(0)); } } return watch.elapsed(); From 5ec7c34106527d29dd8b29c5b4d9c50af65b0ca0 Mon Sep 17 00:00:00 2001 From: Arpan Mishra Date: Tue, 2 Apr 2024 13:05:48 +0530 Subject: [PATCH 2/3] chore: lint issues fix. --- .../cloud/spanner/AbstractLatencyBenchmark.java | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/AbstractLatencyBenchmark.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/AbstractLatencyBenchmark.java index baf4a6be796..b57f3aa723d 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/AbstractLatencyBenchmark.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/AbstractLatencyBenchmark.java @@ -35,24 +35,28 @@ public abstract class AbstractLatencyBenchmark { * requests. */ static final int PARALLEL_THREADS = - Integer.valueOf(MoreObjects.firstNonNull( - System.getenv("SPANNER_TEST_JMH_NUM_PARALLEL_THREADS"), "30")); + Integer.valueOf( + MoreObjects.firstNonNull(System.getenv("SPANNER_TEST_JMH_NUM_PARALLEL_THREADS"), "30")); /** * Total number of reads per test run for 1 thread. Increasing the value here will increase the * duration of the benchmark. For ex - With PARALLEL_THREADS = 2, TOTAL_READS_PER_RUN = 200, there * will be 400 read requests (200 on each thread). */ - static final int TOTAL_READS_PER_RUN = Integer.valueOf(MoreObjects.firstNonNull( - System.getenv("SPANNER_TEST_JMH_NUM_READS_PER_THREAD"), "48000")); + static final int TOTAL_READS_PER_RUN = + Integer.valueOf( + MoreObjects.firstNonNull( + System.getenv("SPANNER_TEST_JMH_NUM_READS_PER_THREAD"), "48000")); /** * Total number of writes per test run for 1 thread. Increasing the value here will increase the * duration of the benchmark. For ex - With PARALLEL_THREADS = 2, TOTAL_WRITES_PER_RUN = 200, * there will be 400 write requests (200 on each thread). */ - static final int TOTAL_WRITES_PER_RUN = Integer.valueOf(MoreObjects.firstNonNull( - System.getenv("SPANNER_TEST_JMH_NUM_WRITES_PER_THREAD"), "4000")); + static final int TOTAL_WRITES_PER_RUN = + Integer.valueOf( + MoreObjects.firstNonNull( + System.getenv("SPANNER_TEST_JMH_NUM_WRITES_PER_THREAD"), "4000")); /** * Number of requests which are used to initialise/warmup the benchmark. The latency number of From e83f4633632c230e6b2abca18ad327661d4c087a Mon Sep 17 00:00:00 2001 From: Owl Bot Date: Tue, 2 Apr 2024 11:00:35 +0000 Subject: [PATCH 3/3] =?UTF-8?q?=F0=9F=A6=89=20Updates=20from=20OwlBot=20po?= =?UTF-8?q?st-processor?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 56d91c89705..85a9ec835bf 100644 --- a/README.md +++ b/README.md @@ -50,20 +50,20 @@ If you are using Maven without the BOM, add this to your dependencies: If you are using Gradle 5.x or later, add this to your dependencies: ```Groovy -implementation platform('com.google.cloud:libraries-bom:26.34.0') +implementation platform('com.google.cloud:libraries-bom:26.35.0') implementation 'com.google.cloud:google-cloud-spanner' ``` If you are using Gradle without BOM, add this to your dependencies: ```Groovy -implementation 'com.google.cloud:google-cloud-spanner:6.62.0' +implementation 'com.google.cloud:google-cloud-spanner:6.63.0' ``` If you are using SBT, add this to your dependencies: ```Scala -libraryDependencies += "com.google.cloud" % "google-cloud-spanner" % "6.62.0" +libraryDependencies += "com.google.cloud" % "google-cloud-spanner" % "6.63.0" ``` @@ -650,7 +650,7 @@ Java is a registered trademark of Oracle and/or its affiliates. [kokoro-badge-link-5]: http://storage.googleapis.com/cloud-devrel-public/java/badges/java-spanner/java11.html [stability-image]: https://img.shields.io/badge/stability-stable-green [maven-version-image]: https://img.shields.io/maven-central/v/com.google.cloud/google-cloud-spanner.svg -[maven-version-link]: https://central.sonatype.com/artifact/com.google.cloud/google-cloud-spanner/6.62.0 +[maven-version-link]: https://central.sonatype.com/artifact/com.google.cloud/google-cloud-spanner/6.63.0 [authentication]: https://github.com/googleapis/google-cloud-java#authentication [auth-scopes]: https://developers.google.com/identity/protocols/oauth2/scopes [predefined-iam-roles]: https://cloud.google.com/iam/docs/understanding-roles#predefined_roles