UnaryThroughput.swift 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. /*
  2. * Copyright 2019, gRPC Authors 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. * 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. import GRPC
  17. import GRPCSampleData
  18. import NIOCore
  19. import NIOPosix
  20. /// Tests unary throughput by sending requests on a single connection.
  21. ///
  22. /// Requests are sent in batches of (up-to) 100 requests. This is due to
  23. /// https://github.com/apple/swift-nio-http2/issues/87#issuecomment-483542401.
  24. class Unary: ServerProvidingBenchmark {
  25. private let useNIOTSIfAvailable: Bool
  26. private let useTLS: Bool
  27. private var group: EventLoopGroup!
  28. private(set) var client: Echo_EchoNIOClient!
  29. let requestCount: Int
  30. let requestText: String
  31. init(requests: Int, text: String, useNIOTSIfAvailable: Bool, useTLS: Bool) {
  32. self.useNIOTSIfAvailable = useNIOTSIfAvailable
  33. self.useTLS = useTLS
  34. self.requestCount = requests
  35. self.requestText = text
  36. super.init(
  37. providers: [MinimalEchoProvider()],
  38. useNIOTSIfAvailable: useNIOTSIfAvailable,
  39. useTLS: useTLS
  40. )
  41. }
  42. override func setUp() throws {
  43. try super.setUp()
  44. if self.useNIOTSIfAvailable {
  45. self.group = PlatformSupport.makeEventLoopGroup(loopCount: 1)
  46. } else {
  47. self.group = MultiThreadedEventLoopGroup(numberOfThreads: 1)
  48. }
  49. let channel: ClientConnection
  50. if self.useTLS {
  51. #if canImport(NIOSSL)
  52. channel = ClientConnection.usingTLSBackedByNIOSSL(on: self.group)
  53. .withTLS(trustRoots: .certificates([SampleCertificate.ca.certificate]))
  54. .withTLS(serverHostnameOverride: "localhost")
  55. .connect(host: "127.0.0.1", port: self.server.channel.localAddress!.port!)
  56. #else
  57. fatalError("NIOSSL must be imported to use TLS")
  58. #endif
  59. } else {
  60. channel = ClientConnection.insecure(group: self.group)
  61. .connect(host: "127.0.0.1", port: self.server.channel.localAddress!.port!)
  62. }
  63. self.client = .init(channel: channel)
  64. }
  65. override func run() throws -> Int {
  66. var messages = 0
  67. let batchSize = 100
  68. for lowerBound in stride(from: 0, to: self.requestCount, by: batchSize) {
  69. let upperBound = min(lowerBound + batchSize, self.requestCount)
  70. let requests = (lowerBound ..< upperBound).map { _ in
  71. self.client.get(Echo_EchoRequest.with { $0.text = self.requestText }).response
  72. }
  73. messages += requests.count
  74. try EventLoopFuture.andAllSucceed(requests, on: self.group.next()).wait()
  75. }
  76. return messages
  77. }
  78. override func tearDown() throws {
  79. try self.client.channel.close().wait()
  80. try self.group.syncShutdownGracefully()
  81. try super.tearDown()
  82. }
  83. }
  84. /// Tests bidirectional throughput by sending requests over a single stream.
  85. class Bidi: Unary {
  86. let batchSize: Int
  87. init(requests: Int, text: String, batchSize: Int, useNIOTSIfAvailable: Bool, useTLS: Bool) {
  88. self.batchSize = batchSize
  89. super.init(
  90. requests: requests,
  91. text: text,
  92. useNIOTSIfAvailable: useNIOTSIfAvailable,
  93. useTLS: useTLS
  94. )
  95. }
  96. override func run() throws -> Int {
  97. var messages = 0
  98. let update = self.client.update { _ in }
  99. for _ in stride(from: 0, to: self.requestCount, by: self.batchSize) {
  100. let batch = (0 ..< self.batchSize).map { _ in
  101. Echo_EchoRequest.with { $0.text = self.requestText }
  102. }
  103. messages += batch.count
  104. update.sendMessages(batch, promise: nil)
  105. }
  106. update.sendEnd(promise: nil)
  107. _ = try update.status.wait()
  108. return messages
  109. }
  110. }