benchmark_test.go 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. // Copyright (C) 2016 The Protocol Authors.
  2. package protocol
  3. import (
  4. "crypto/tls"
  5. "encoding/binary"
  6. "net"
  7. "testing"
  8. "github.com/syncthing/syncthing/lib/dialer"
  9. )
  10. func BenchmarkRequestsRawTCP(b *testing.B) {
  11. // Benchmarks the rate at which we can serve requests over a single,
  12. // unencrypted TCP channel over the loopback interface.
  13. // Get a connected TCP pair
  14. conn0, conn1, err := getTCPConnectionPair()
  15. if err != nil {
  16. b.Fatal(err)
  17. }
  18. defer conn0.Close()
  19. defer conn1.Close()
  20. // Bench it
  21. benchmarkRequestsConnPair(b, conn0, conn1)
  22. }
  23. func BenchmarkRequestsTLSoTCP(b *testing.B) {
  24. conn0, conn1, err := getTCPConnectionPair()
  25. if err != nil {
  26. b.Fatal(err)
  27. }
  28. defer conn0.Close()
  29. defer conn1.Close()
  30. benchmarkRequestsTLS(b, conn0, conn1)
  31. }
  32. func benchmarkRequestsTLS(b *testing.B, conn0, conn1 net.Conn) {
  33. // Benchmarks the rate at which we can serve requests over a single,
  34. // TLS encrypted channel over the loopback interface.
  35. // Load a certificate, skipping this benchmark if it doesn't exist
  36. cert, err := tls.LoadX509KeyPair("../../test/h1/cert.pem", "../../test/h1/key.pem")
  37. if err != nil {
  38. b.Skip(err)
  39. return
  40. }
  41. /// TLSify them
  42. conn0, conn1 = negotiateTLS(cert, conn0, conn1)
  43. // Bench it
  44. benchmarkRequestsConnPair(b, conn0, conn1)
  45. }
  46. func benchmarkRequestsConnPair(b *testing.B, conn0, conn1 net.Conn) {
  47. // Start up Connections on them
  48. c0 := NewConnection(LocalDeviceID, conn0, conn0, new(fakeModel), "c0", CompressMetadata)
  49. c0.Start()
  50. c1 := NewConnection(LocalDeviceID, conn1, conn1, new(fakeModel), "c1", CompressMetadata)
  51. c1.Start()
  52. // Satisfy the assertions in the protocol by sending an initial cluster config
  53. c0.ClusterConfig(ClusterConfig{})
  54. c1.ClusterConfig(ClusterConfig{})
  55. // Report some useful stats and reset the timer for the actual test
  56. b.ReportAllocs()
  57. b.SetBytes(128 << 10)
  58. b.ResetTimer()
  59. // Request 128 KiB blocks, which will be satisfied by zero copy from the
  60. // other side (we'll get back a full block of zeroes).
  61. var buf []byte
  62. var err error
  63. for i := 0; i < b.N; i++ {
  64. // Use c0 and c1 for each alternating request, so we get as much
  65. // data flowing in both directions.
  66. if i%2 == 0 {
  67. buf, err = c0.Request("folder", "file", int64(i), 128<<10, nil, 0, false)
  68. } else {
  69. buf, err = c1.Request("folder", "file", int64(i), 128<<10, nil, 0, false)
  70. }
  71. if err != nil {
  72. b.Fatal(err)
  73. }
  74. if len(buf) != 128<<10 {
  75. b.Fatal("Incorrect returned buf length", len(buf), "!=", 128<<10)
  76. }
  77. // The fake model is supposed to tag the end of the buffer with the
  78. // requested offset, so we can verify that we get back data for this
  79. // block correctly.
  80. if binary.BigEndian.Uint64(buf[128<<10-8:]) != uint64(i) {
  81. b.Fatal("Bad data returned")
  82. }
  83. }
  84. }
  85. // returns the two endpoints of a TCP connection over lo0
  86. func getTCPConnectionPair() (net.Conn, net.Conn, error) {
  87. lst, err := net.Listen("tcp", "127.0.0.1:0")
  88. if err != nil {
  89. return nil, nil, err
  90. }
  91. // We run the Accept in the background since it's blocking, and we use
  92. // the channel to make the race thingies happy about writing vs reading
  93. // conn0 and err0.
  94. var conn0 net.Conn
  95. var err0 error
  96. done := make(chan struct{})
  97. go func() {
  98. conn0, err0 = lst.Accept()
  99. close(done)
  100. }()
  101. // Dial the connection
  102. conn1, err := net.Dial("tcp", lst.Addr().String())
  103. if err != nil {
  104. return nil, nil, err
  105. }
  106. // Check any error from accept
  107. <-done
  108. if err0 != nil {
  109. return nil, nil, err0
  110. }
  111. // Set the buffer sizes etc as usual
  112. dialer.SetTCPOptions(conn0)
  113. dialer.SetTCPOptions(conn1)
  114. return conn0, conn1, nil
  115. }
  116. func negotiateTLS(cert tls.Certificate, conn0, conn1 net.Conn) (net.Conn, net.Conn) {
  117. cfg := &tls.Config{
  118. Certificates: []tls.Certificate{cert},
  119. NextProtos: []string{"bep/1.0"},
  120. ClientAuth: tls.RequestClientCert,
  121. SessionTicketsDisabled: true,
  122. InsecureSkipVerify: true,
  123. MinVersion: tls.VersionTLS12,
  124. CipherSuites: []uint16{
  125. tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
  126. tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
  127. tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
  128. tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
  129. tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
  130. tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
  131. },
  132. }
  133. tlsc0 := tls.Server(conn0, cfg)
  134. tlsc1 := tls.Client(conn1, cfg)
  135. return tlsc0, tlsc1
  136. }
  137. // The fake model does nothing much
  138. type fakeModel struct{}
  139. func (m *fakeModel) Index(deviceID DeviceID, folder string, files []FileInfo) {
  140. }
  141. func (m *fakeModel) IndexUpdate(deviceID DeviceID, folder string, files []FileInfo) {
  142. }
  143. func (m *fakeModel) Request(deviceID DeviceID, folder, name string, size int32, offset int64, hash []byte, weakHash uint32, fromTemporary bool) (RequestResponse, error) {
  144. // We write the offset to the end of the buffer, so the receiver
  145. // can verify that it did in fact get some data back over the
  146. // connection.
  147. buf := make([]byte, size)
  148. binary.BigEndian.PutUint64(buf[len(buf)-8:], uint64(offset))
  149. return &fakeRequestResponse{buf}, nil
  150. }
  151. func (m *fakeModel) ClusterConfig(deviceID DeviceID, config ClusterConfig) {
  152. }
  153. func (m *fakeModel) Closed(conn Connection, err error) {
  154. }
  155. func (m *fakeModel) DownloadProgress(deviceID DeviceID, folder string, updates []FileDownloadProgressUpdate) {
  156. }