1616
1717package com .google .cloud .spanner ;
1818
19+ import com .google .common .base .MoreObjects ;
1920import java .time .Duration ;
2021import java .util .ArrayList ;
2122import java .util .Collections ;
2425
2526public abstract class AbstractLatencyBenchmark {
2627
28+ static final String SELECT_QUERY = "SELECT ID FROM FOO WHERE ID = @id" ;
29+ static final String UPDATE_QUERY = "UPDATE FOO SET BAR=1 WHERE ID = @id" ;
30+ static final String ID_COLUMN_NAME = "id" ;
31+
32+ /**
33+ * Used to determine how many concurrent requests are allowed. For ex - To simulate a low QPS
34+ * scenario, using 1 thread means there will be 1 request. Use a value > 1 to have concurrent
35+ * requests.
36+ */
37+ static final int PARALLEL_THREADS =
38+ Integer .valueOf (
39+ MoreObjects .firstNonNull (System .getenv ("SPANNER_TEST_JMH_NUM_PARALLEL_THREADS" ), "30" ));
40+
41+ /**
42+ * Total number of reads per test run for 1 thread. Increasing the value here will increase the
43+ * duration of the benchmark. For ex - With PARALLEL_THREADS = 2, TOTAL_READS_PER_RUN = 200, there
44+ * will be 400 read requests (200 on each thread).
45+ */
46+ static final int TOTAL_READS_PER_RUN =
47+ Integer .valueOf (
48+ MoreObjects .firstNonNull (
49+ System .getenv ("SPANNER_TEST_JMH_NUM_READS_PER_THREAD" ), "48000" ));
50+
51+ /**
52+ * Total number of writes per test run for 1 thread. Increasing the value here will increase the
53+ * duration of the benchmark. For ex - With PARALLEL_THREADS = 2, TOTAL_WRITES_PER_RUN = 200,
54+ * there will be 400 write requests (200 on each thread).
55+ */
56+ static final int TOTAL_WRITES_PER_RUN =
57+ Integer .valueOf (
58+ MoreObjects .firstNonNull (
59+ System .getenv ("SPANNER_TEST_JMH_NUM_WRITES_PER_THREAD" ), "4000" ));
60+
61+ /**
62+ * Number of requests which are used to initialise/warmup the benchmark. The latency number of
63+ * these runs are ignored from the final reported results.
64+ */
65+ static final int WARMUP_REQUEST_COUNT = 1 ;
66+
67+ /**
68+ * Numbers of records in the sample table used in the benchmark. This is used in this benchmark to
69+ * randomly choose a primary key and ensure that the reads are randomly distributed. This is done
70+ * to ensure we don't end up reading/writing the same table record (leading to hot-spotting).
71+ */
72+ static final int TOTAL_RECORDS = 1000000 ;
73+
2774 /** Utility to print latency numbers. It computes metrics such as Average, P50, P95 and P99. */
2875 public void printResults (List <Duration > results ) {
2976 if (results == null ) {
@@ -33,23 +80,23 @@ public void printResults(List<Duration> results) {
3380 Collections .sort (orderedResults );
3481 System .out .println ();
3582 System .out .printf ("Total number of queries: %d\n " , orderedResults .size ());
36- System .out .printf ("Avg: %fs \n " , avg (results ));
37- System .out .printf ("P50: %fs \n " , percentile (50 , orderedResults ));
38- System .out .printf ("P95: %fs \n " , percentile (95 , orderedResults ));
39- System .out .printf ("P99: %fs \n " , percentile (99 , orderedResults ));
83+ System .out .printf ("Avg: %fms \n " , avg (results ));
84+ System .out .printf ("P50: %fms \n " , percentile (50 , orderedResults ));
85+ System .out .printf ("P95: %fms \n " , percentile (95 , orderedResults ));
86+ System .out .printf ("P99: %fms \n " , percentile (99 , orderedResults ));
4087 }
4188
4289 private double percentile (int percentile , List <Duration > orderedResults ) {
4390 int index = percentile * orderedResults .size () / 100 ;
4491 Duration value = orderedResults .get (index );
45- Double convertedValue = convertDurationToFractionInSeconds (value );
92+ Double convertedValue = convertDurationToFractionInMilliSeconds (value );
4693 return convertedValue ;
4794 }
4895
4996 /** Returns the average duration in seconds from a list of duration values. */
5097 private double avg (List <Duration > results ) {
5198 return results .stream ()
52- .collect (Collectors .averagingDouble (this ::convertDurationToFractionInSeconds ));
99+ .collect (Collectors .averagingDouble (this ::convertDurationToFractionInMilliSeconds ));
53100 }
54101
55102 private double convertDurationToFractionInSeconds (Duration duration ) {
@@ -59,4 +106,9 @@ private double convertDurationToFractionInSeconds(Duration duration) {
59106 double value = seconds + fraction ;
60107 return value ;
61108 }
109+
110+ private double convertDurationToFractionInMilliSeconds (Duration duration ) {
111+ long nanoseconds = duration .toNanos ();
112+ return nanoseconds / 1000000.0 ;
113+ }
62114}
0 commit comments