1+ /*
2+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+ *
4+ * Licensed under the Apache License, Version 2.0 (the "License").
5+ * You may not use this file except in compliance with the License.
6+ * A copy of the License is located at
7+ *
8+ * http://aws.amazon.com/apache2.0
9+ *
10+ * or in the "license" file accompanying this file. This file is distributed
11+ * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12+ * express or implied. See the License for the specific language governing
13+ * permissions and limitations under the License.
14+ */
15+
16+ package software .amazon .awssdk .benchmark .checksum ;
17+
18+ import org .openjdk .jmh .annotations .Benchmark ;
19+ import org .openjdk .jmh .annotations .Param ;
20+ import org .openjdk .jmh .annotations .Scope ;
21+ import org .openjdk .jmh .annotations .Setup ;
22+ import org .openjdk .jmh .annotations .State ;
23+ import org .openjdk .jmh .infra .Blackhole ;
24+ import software .amazon .awssdk .checksums .DefaultChecksumAlgorithm ;
25+ import software .amazon .awssdk .checksums .SdkChecksum ;
26+ import software .amazon .awssdk .checksums .internal .CrcCloneOnMarkChecksum ;
27+ import software .amazon .awssdk .crt .checksums .CRC32C ;
28+
29+ /**
30+ * Benchmarks for testing CRT implementations of checksums.
31+ * <p>
32+ * There are pitfalls with passing buffers to and from native code since it could lead to lots of copying.
33+ */
34+ public class CrtChecksumBenchmark {
35+ private static final int KB = 1024 ;
36+ private static final int MB = 1024 * KB ;
37+ private static final int PAYLOAD_SIZE = 512 * MB ;
38+
39+ public enum Algorithm {
40+ CRC32C ,
41+ CRC64 ,
42+ ;
43+ }
44+
45+ public enum Size {
46+ SZ_512_KB (512 * KB ),
47+ SZ_1_MB (MB ),
48+ SZ_2_MB (2 * MB ),
49+ SZ_4_MB (4 * MB ),
50+ SZ_8_MB (8 * MB ),
51+ SZ_16_MB (16 * MB ),
52+ SZ_32_MB (32 * MB ),
53+ SZ_64_MB (64 * MB ),
54+ SZ_128_MB (128 * MB ),
55+ SZ_256_MB (256 * MB );
56+
57+ private int numBytes ;
58+
59+ Size (int bytes ) {
60+
61+ this .numBytes = bytes ;
62+ }
63+
64+ public int getNumBytes () {
65+ return numBytes ;
66+ }
67+ }
68+
69+ @ State (Scope .Benchmark )
70+ public static class ChunkedState {
71+ private SdkChecksum crc ;
72+
73+ private byte [] chunkData ;
74+
75+ @ Param ({"SZ_512_KB" ,
76+ "SZ_1_MB" ,
77+ "SZ_2_MB" ,
78+ "SZ_4_MB" ,
79+ "SZ_8_MB" ,
80+ "SZ_16_MB" ,
81+ "SZ_32_MB" ,
82+ "SZ_64_MB" ,
83+ "SZ_128_MB" ,
84+ "SZ_256_MB" })
85+ private Size chunkSize ;
86+
87+ @ Param ({"CRC64" , "CRC32C" })
88+ private Algorithm algorithm ;
89+
90+ @ Setup
91+ public void setup () {
92+ crc = getSdkChecksum (algorithm );
93+ chunkData = new byte [chunkSize .getNumBytes ()];
94+ }
95+ }
96+
97+ /**
98+ * Approximates where we feed a fixed number of bytes (PAYLOAD_BYTES), using different chunk sizes.
99+ */
100+ @ Benchmark
101+ public void chunked (ChunkedState s , Blackhole bh ) {
102+ int chunkSize = s .chunkSize .getNumBytes ();
103+
104+ int nChunks = PAYLOAD_SIZE / chunkSize ;
105+
106+ s .crc .reset ();
107+ for (int i = 0 ; i < nChunks ; ++i ) {
108+ s .crc .update (s .chunkData );
109+ }
110+ bh .consume (s .crc .getChecksumBytes ());
111+ }
112+
113+ /**
114+ * This benchmark approximates use cases where crc64.update(byte[], offset, length) is called where length is
115+ * smaller than the length of byte[]. For example, the application might have a *large* read buffer, but only fills
116+ * a small portion of it and calls crc64.update() with only that portion.
117+ */
118+ @ State (Scope .Benchmark )
119+ public static class FixedInputBufferSizeState {
120+ @ Param ({"SZ_32_MB" , "SZ_64_MB" , "SZ_128_MB" , "SZ_256_MB" })
121+ private Size fixedBufferSize ;
122+
123+ @ Param ({"SZ_512_KB" , "SZ_1_MB" , "SZ_2_MB" })
124+ private Size chunkSize ;
125+
126+ @ Param ({"CRC64" , "CRC32C" })
127+ private Algorithm algorithm ;
128+
129+ private byte [] buffer ;
130+
131+ private SdkChecksum crc ;
132+
133+ @ Setup
134+ public void setup () {
135+ buffer = new byte [fixedBufferSize .getNumBytes ()];
136+ crc = getSdkChecksum (algorithm );
137+ }
138+ }
139+
140+ @ Benchmark
141+ public void fixedBufferSize (FixedInputBufferSizeState s , Blackhole bh ) {
142+ int chunkSize = s .chunkSize .getNumBytes ();
143+
144+ int nChunks = PAYLOAD_SIZE / chunkSize ;
145+
146+ s .crc .reset ();
147+ for (int i = 0 ; i < nChunks ; ++i ) {
148+ s .crc .update (s .buffer , 0 , chunkSize );
149+ }
150+ bh .consume (s .crc .getChecksumBytes ());
151+ }
152+
153+ private static SdkChecksum getSdkChecksum (Algorithm algorithm ) {
154+ switch (algorithm ) {
155+ case CRC32C :
156+ // Construct directly instead of using forAlgorithm because it
157+ // will pick up the JVM provided one if it's available.
158+ return new CrcCloneOnMarkChecksum (new CRC32C ());
159+ case CRC64 :
160+ return SdkChecksum .forAlgorithm (DefaultChecksumAlgorithm .CRC64NVME );
161+ default :
162+ throw new RuntimeException ("Unsupported algorithm: " + algorithm );
163+ }
164+ }
165+ }
0 commit comments