16
16
17
17
package com .google .cloud .spanner ;
18
18
19
+ import com .google .common .base .MoreObjects ;
19
20
import java .time .Duration ;
20
21
import java .util .ArrayList ;
21
22
import java .util .Collections ;
24
25
25
26
public abstract class AbstractLatencyBenchmark {
26
27
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
+
27
74
/** Utility to print latency numbers. It computes metrics such as Average, P50, P95 and P99. */
28
75
public void printResults (List <Duration > results ) {
29
76
if (results == null ) {
@@ -33,23 +80,23 @@ public void printResults(List<Duration> results) {
33
80
Collections .sort (orderedResults );
34
81
System .out .println ();
35
82
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 ));
40
87
}
41
88
42
89
private double percentile (int percentile , List <Duration > orderedResults ) {
43
90
int index = percentile * orderedResults .size () / 100 ;
44
91
Duration value = orderedResults .get (index );
45
- Double convertedValue = convertDurationToFractionInSeconds (value );
92
+ Double convertedValue = convertDurationToFractionInMilliSeconds (value );
46
93
return convertedValue ;
47
94
}
48
95
49
96
/** Returns the average duration in seconds from a list of duration values. */
50
97
private double avg (List <Duration > results ) {
51
98
return results .stream ()
52
- .collect (Collectors .averagingDouble (this ::convertDurationToFractionInSeconds ));
99
+ .collect (Collectors .averagingDouble (this ::convertDurationToFractionInMilliSeconds ));
53
100
}
54
101
55
102
private double convertDurationToFractionInSeconds (Duration duration ) {
@@ -59,4 +106,9 @@ private double convertDurationToFractionInSeconds(Duration duration) {
59
106
double value = seconds + fraction ;
60
107
return value ;
61
108
}
109
+
110
+ private double convertDurationToFractionInMilliSeconds (Duration duration ) {
111
+ long nanoseconds = duration .toNanos ();
112
+ return nanoseconds / 1000000.0 ;
113
+ }
62
114
}
0 commit comments