1 /* 2 * Copyright 2014 The gRPC Authors 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 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package io.grpc.benchmarks.netty; 18 19 import java.util.concurrent.atomic.AtomicBoolean; 20 import java.util.concurrent.atomic.AtomicLong; 21 import org.openjdk.jmh.annotations.AuxCounters; 22 import org.openjdk.jmh.annotations.Benchmark; 23 import org.openjdk.jmh.annotations.Fork; 24 import org.openjdk.jmh.annotations.Level; 25 import org.openjdk.jmh.annotations.Param; 26 import org.openjdk.jmh.annotations.Scope; 27 import org.openjdk.jmh.annotations.Setup; 28 import org.openjdk.jmh.annotations.State; 29 import org.openjdk.jmh.annotations.TearDown; 30 31 /** 32 * Benchmark using configuration intended to allow maximum QPS for unary calls. 33 */ 34 @State(Scope.Benchmark) 35 @Fork(1) 36 public class UnaryCallQpsBenchmark extends AbstractBenchmark { 37 38 @Param({"1", "2", "4", "8"}) 39 public int channelCount = 4; 40 41 @Param({"10", "100", "1000"}) 42 public int maxConcurrentStreams = 100; 43 44 private static AtomicLong callCounter; 45 private AtomicBoolean completed; 46 47 /** 48 * Use an AuxCounter so we can measure that calls as they occur without consuming CPU 49 * in the benchmark method. 50 */ 51 @AuxCounters 52 @State(Scope.Thread) 53 public static class AdditionalCounters { 54 55 @Setup(Level.Iteration) clean()56 public void clean() { 57 callCounter.set(0); 58 } 59 callsPerSecond()60 public long callsPerSecond() { 61 return callCounter.get(); 62 } 63 } 64 65 /** 66 * Setup with direct executors, small payloads and a large flow control window. 67 */ 68 @Setup(Level.Trial) setup()69 public void setup() throws Exception { 70 super.setup(ExecutorType.DIRECT, 71 ExecutorType.DIRECT, 72 MessageSize.SMALL, 73 MessageSize.SMALL, 74 FlowWindowSize.LARGE, 75 ChannelType.NIO, 76 maxConcurrentStreams, 77 channelCount); 78 callCounter = new AtomicLong(); 79 completed = new AtomicBoolean(); 80 startUnaryCalls(maxConcurrentStreams, callCounter, completed, 1); 81 } 82 83 /** 84 * Stop the running calls then stop the server and client channels. 85 */ 86 @Override 87 @TearDown(Level.Trial) teardown()88 public void teardown() throws Exception { 89 completed.set(true); 90 Thread.sleep(5000); 91 super.teardown(); 92 } 93 94 /** 95 * Measure throughput of unary calls. The calls are already running, we just observe a counter 96 * of received responses. 97 */ 98 @Benchmark unary(AdditionalCounters counters)99 public void unary(AdditionalCounters counters) throws Exception { 100 // No need to do anything, just sleep here. 101 Thread.sleep(1001); 102 } 103 104 /** 105 * Useful for triggering a subset of the benchmark in a profiler. 106 */ main(String[] argv)107 public static void main(String[] argv) throws Exception { 108 UnaryCallQpsBenchmark bench = new UnaryCallQpsBenchmark(); 109 bench.setup(); 110 Thread.sleep(30000); 111 bench.teardown(); 112 System.exit(0); 113 } 114 } 115