diff --git a/spectator-api/src/jmh/java/com/netflix/spectator/perf/ArrayTagSetSort.java b/spectator-api/src/jmh/java/com/netflix/spectator/perf/ArrayTagSetSort.java new file mode 100644 index 000000000..b70ae5929 --- /dev/null +++ b/spectator-api/src/jmh/java/com/netflix/spectator/perf/ArrayTagSetSort.java @@ -0,0 +1,174 @@ +/* + * Copyright 2014-2023 Netflix, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.netflix.spectator.perf; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.infra.Blackhole; + +import java.util.Arrays; + +/** + *
+ * sort1_single thrpt 5 231987417.092 ± 1461766.430 ops/s + * sort2_single thrpt 5 231390816.374 ± 2900091.223 ops/s + * + * sort1_two thrpt 5 127862169.706 ± 3004299.720 ops/s + * sort2_two thrpt 5 107286992.610 ± 499836.589 ops/s + * + * sort1_four thrpt 5 45448061.771 ± 214688.930 ops/s + * sort2_four thrpt 5 45801768.604 ± 399120.395 ops/s + * + * sort1_many thrpt 5 7013914.451 ± 476174.932 ops/s + * sort2_many thrpt 5 7093001.872 ± 136273.382 ops/s + *+ */ +@State(Scope.Thread) +public class ArrayTagSetSort { + + private static void insertionSort1(String[] ts, int length) { + if (length == 4) { + // Two key/value pairs, swap if needed + if (ts[0].compareTo(ts[2]) > 0) { + // Swap key + String tmp = ts[0]; + ts[0] = ts[2]; + ts[2] = tmp; + + // Swap value + tmp = ts[1]; + ts[1] = ts[3]; + ts[3] = tmp; + } + } else if (length > 4) { + // One entry is already sorted. Two entries handled above, for larger arrays + // use insertion sort. + for (int i = 2; i < length; i += 2) { + String k = ts[i]; + String v = ts[i + 1]; + int j = i - 2; + for (; j >= 0 && ts[j].compareTo(k) > 0; j -= 2) { + ts[j + 2] = ts[j]; + ts[j + 3] = ts[j + 1]; + } + ts[j + 2] = k; + ts[j + 3] = v; + } + } + } + + private static void insertionSort2(String[] ts, int length) { + for (int i = 2; i < length; i += 2) { + String k = ts[i]; + String v = ts[i + 1]; + int j = i - 2; + for (; j >= 0 && ts[j].compareTo(k) > 0; j -= 2) { + ts[j + 2] = ts[j]; + ts[j + 3] = ts[j + 1]; + } + ts[j + 2] = k; + ts[j + 3] = v; + } + } + + private final String[] tagsArraySingle = new String[] { + "country", "US" + }; + + private final String[] tagsArrayTwo = new String[] { + "status", "200", + "client", "ab" + }; + + private final String[] tagsArrayFour = new String[] { + "country", "US", + "device", "xbox", + "status", "200", + "client", "ab" + }; + + private final String[] tagsArrayMany = new String[] { + "nf.app", "test_app", + "nf.cluster", "test_app-main", + "nf.asg", "test_app-main-v042", + "nf.stack", "main", + "nf.ami", "ami-0987654321", + "nf.region", "us-east-1", + "nf.zone", "us-east-1e", + "nf.node", "i-1234567890", + "country", "US", + "device", "xbox", + "status", "200", + "client", "ab" + }; + + @Benchmark + public void sort1_single(Blackhole bh) { + String[] tags = Arrays.copyOf(tagsArraySingle, tagsArraySingle.length); + insertionSort1(tags, tags.length); + bh.consume(tags); + } + + @Benchmark + public void sort2_single(Blackhole bh) { + String[] tags = Arrays.copyOf(tagsArraySingle, tagsArraySingle.length); + insertionSort2(tags, tags.length); + bh.consume(tags); + } + + @Benchmark + public void sort1_two(Blackhole bh) { + String[] tags = Arrays.copyOf(tagsArrayTwo, tagsArrayTwo.length); + insertionSort1(tags, tags.length); + bh.consume(tags); + } + + @Benchmark + public void sort2_two(Blackhole bh) { + String[] tags = Arrays.copyOf(tagsArrayTwo, tagsArrayTwo.length); + insertionSort2(tags, tags.length); + bh.consume(tags); + } + + @Benchmark + public void sort1_four(Blackhole bh) { + String[] tags = Arrays.copyOf(tagsArrayFour, tagsArrayFour.length); + insertionSort1(tags, tags.length); + bh.consume(tags); + } + + @Benchmark + public void sort2_four(Blackhole bh) { + String[] tags = Arrays.copyOf(tagsArrayFour, tagsArrayFour.length); + insertionSort2(tags, tags.length); + bh.consume(tags); + } + + @Benchmark + public void sort1_many(Blackhole bh) { + String[] tags = Arrays.copyOf(tagsArrayMany, tagsArrayMany.length); + insertionSort1(tags, tags.length); + bh.consume(tags); + } + + @Benchmark + public void sort2_many(Blackhole bh) { + String[] tags = Arrays.copyOf(tagsArrayMany, tagsArrayMany.length); + insertionSort2(tags, tags.length); + bh.consume(tags); + } +}