...

Source file src/github.com/jackc/pgconn/benchmark_test.go

Documentation: github.com/jackc/pgconn

     1  package pgconn_test
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"os"
     7  	"strings"
     8  	"testing"
     9  
    10  	"github.com/jackc/pgconn"
    11  	"github.com/stretchr/testify/require"
    12  )
    13  
    14  func BenchmarkConnect(b *testing.B) {
    15  	benchmarks := []struct {
    16  		name string
    17  		env  string
    18  	}{
    19  		{"Unix socket", "PGX_TEST_UNIX_SOCKET_CONN_STRING"},
    20  		{"TCP", "PGX_TEST_TCP_CONN_STRING"},
    21  	}
    22  
    23  	for _, bm := range benchmarks {
    24  		bm := bm
    25  		b.Run(bm.name, func(b *testing.B) {
    26  			connString := os.Getenv(bm.env)
    27  			if connString == "" {
    28  				b.Skipf("Skipping due to missing environment variable %v", bm.env)
    29  			}
    30  
    31  			for i := 0; i < b.N; i++ {
    32  				conn, err := pgconn.Connect(context.Background(), connString)
    33  				require.Nil(b, err)
    34  
    35  				err = conn.Close(context.Background())
    36  				require.Nil(b, err)
    37  			}
    38  		})
    39  	}
    40  }
    41  
    42  func BenchmarkExec(b *testing.B) {
    43  	expectedValues := [][]byte{[]byte("hello"), []byte("42"), []byte("2019-01-01")}
    44  	benchmarks := []struct {
    45  		name string
    46  		ctx  context.Context
    47  	}{
    48  		// Using an empty context other than context.Background() to compare
    49  		// performance
    50  		{"background context", context.Background()},
    51  		{"empty context", context.TODO()},
    52  	}
    53  
    54  	for _, bm := range benchmarks {
    55  		bm := bm
    56  		b.Run(bm.name, func(b *testing.B) {
    57  			conn, err := pgconn.Connect(bm.ctx, os.Getenv("PGX_TEST_CONN_STRING"))
    58  			require.Nil(b, err)
    59  			defer closeConn(b, conn)
    60  
    61  			b.ResetTimer()
    62  
    63  			for i := 0; i < b.N; i++ {
    64  				mrr := conn.Exec(bm.ctx, "select 'hello'::text as a, 42::int4 as b, '2019-01-01'::date")
    65  
    66  				for mrr.NextResult() {
    67  					rr := mrr.ResultReader()
    68  
    69  					rowCount := 0
    70  					for rr.NextRow() {
    71  						rowCount++
    72  						if len(rr.Values()) != len(expectedValues) {
    73  							b.Fatalf("unexpected number of values: %d", len(rr.Values()))
    74  						}
    75  						for i := range rr.Values() {
    76  							if !bytes.Equal(rr.Values()[i], expectedValues[i]) {
    77  								b.Fatalf("unexpected values: %s %s", rr.Values()[i], expectedValues[i])
    78  							}
    79  						}
    80  					}
    81  					_, err = rr.Close()
    82  
    83  					if err != nil {
    84  						b.Fatal(err)
    85  					}
    86  					if rowCount != 1 {
    87  						b.Fatalf("unexpected rowCount: %d", rowCount)
    88  					}
    89  				}
    90  
    91  				err := mrr.Close()
    92  				if err != nil {
    93  					b.Fatal(err)
    94  				}
    95  			}
    96  		})
    97  	}
    98  }
    99  
   100  func BenchmarkExecPossibleToCancel(b *testing.B) {
   101  	conn, err := pgconn.Connect(context.Background(), os.Getenv("PGX_TEST_CONN_STRING"))
   102  	require.Nil(b, err)
   103  	defer closeConn(b, conn)
   104  
   105  	expectedValues := [][]byte{[]byte("hello"), []byte("42"), []byte("2019-01-01")}
   106  
   107  	b.ResetTimer()
   108  
   109  	ctx, cancel := context.WithCancel(context.Background())
   110  	defer cancel()
   111  
   112  	for i := 0; i < b.N; i++ {
   113  		mrr := conn.Exec(ctx, "select 'hello'::text as a, 42::int4 as b, '2019-01-01'::date")
   114  
   115  		for mrr.NextResult() {
   116  			rr := mrr.ResultReader()
   117  
   118  			rowCount := 0
   119  			for rr.NextRow() {
   120  				rowCount++
   121  				if len(rr.Values()) != len(expectedValues) {
   122  					b.Fatalf("unexpected number of values: %d", len(rr.Values()))
   123  				}
   124  				for i := range rr.Values() {
   125  					if !bytes.Equal(rr.Values()[i], expectedValues[i]) {
   126  						b.Fatalf("unexpected values: %s %s", rr.Values()[i], expectedValues[i])
   127  					}
   128  				}
   129  			}
   130  			_, err = rr.Close()
   131  
   132  			if err != nil {
   133  				b.Fatal(err)
   134  			}
   135  			if rowCount != 1 {
   136  				b.Fatalf("unexpected rowCount: %d", rowCount)
   137  			}
   138  		}
   139  
   140  		err := mrr.Close()
   141  		if err != nil {
   142  			b.Fatal(err)
   143  		}
   144  	}
   145  }
   146  
   147  func BenchmarkExecPrepared(b *testing.B) {
   148  	expectedValues := [][]byte{[]byte("hello"), []byte("42"), []byte("2019-01-01")}
   149  
   150  	benchmarks := []struct {
   151  		name string
   152  		ctx  context.Context
   153  	}{
   154  		// Using an empty context other than context.Background() to compare
   155  		// performance
   156  		{"background context", context.Background()},
   157  		{"empty context", context.TODO()},
   158  	}
   159  
   160  	for _, bm := range benchmarks {
   161  		bm := bm
   162  		b.Run(bm.name, func(b *testing.B) {
   163  			conn, err := pgconn.Connect(bm.ctx, os.Getenv("PGX_TEST_CONN_STRING"))
   164  			require.Nil(b, err)
   165  			defer closeConn(b, conn)
   166  
   167  			_, err = conn.Prepare(bm.ctx, "ps1", "select 'hello'::text as a, 42::int4 as b, '2019-01-01'::date", nil)
   168  			require.Nil(b, err)
   169  
   170  			b.ResetTimer()
   171  
   172  			for i := 0; i < b.N; i++ {
   173  				rr := conn.ExecPrepared(bm.ctx, "ps1", nil, nil, nil)
   174  
   175  				rowCount := 0
   176  				for rr.NextRow() {
   177  					rowCount++
   178  					if len(rr.Values()) != len(expectedValues) {
   179  						b.Fatalf("unexpected number of values: %d", len(rr.Values()))
   180  					}
   181  					for i := range rr.Values() {
   182  						if !bytes.Equal(rr.Values()[i], expectedValues[i]) {
   183  							b.Fatalf("unexpected values: %s %s", rr.Values()[i], expectedValues[i])
   184  						}
   185  					}
   186  				}
   187  				_, err = rr.Close()
   188  
   189  				if err != nil {
   190  					b.Fatal(err)
   191  				}
   192  				if rowCount != 1 {
   193  					b.Fatalf("unexpected rowCount: %d", rowCount)
   194  				}
   195  			}
   196  		})
   197  	}
   198  }
   199  
   200  func BenchmarkExecPreparedPossibleToCancel(b *testing.B) {
   201  	conn, err := pgconn.Connect(context.Background(), os.Getenv("PGX_TEST_CONN_STRING"))
   202  	require.Nil(b, err)
   203  	defer closeConn(b, conn)
   204  
   205  	ctx, cancel := context.WithCancel(context.Background())
   206  	defer cancel()
   207  
   208  	_, err = conn.Prepare(ctx, "ps1", "select 'hello'::text as a, 42::int4 as b, '2019-01-01'::date", nil)
   209  	require.Nil(b, err)
   210  
   211  	expectedValues := [][]byte{[]byte("hello"), []byte("42"), []byte("2019-01-01")}
   212  
   213  	b.ResetTimer()
   214  
   215  	for i := 0; i < b.N; i++ {
   216  		rr := conn.ExecPrepared(ctx, "ps1", nil, nil, nil)
   217  
   218  		rowCount := 0
   219  		for rr.NextRow() {
   220  			rowCount += 1
   221  			if len(rr.Values()) != len(expectedValues) {
   222  				b.Fatalf("unexpected number of values: %d", len(rr.Values()))
   223  			}
   224  			for i := range rr.Values() {
   225  				if !bytes.Equal(rr.Values()[i], expectedValues[i]) {
   226  					b.Fatalf("unexpected values: %s %s", rr.Values()[i], expectedValues[i])
   227  				}
   228  			}
   229  		}
   230  		_, err = rr.Close()
   231  
   232  		if err != nil {
   233  			b.Fatal(err)
   234  		}
   235  		if rowCount != 1 {
   236  			b.Fatalf("unexpected rowCount: %d", rowCount)
   237  		}
   238  	}
   239  }
   240  
   241  // func BenchmarkChanToSetDeadlinePossibleToCancel(b *testing.B) {
   242  // 	conn, err := pgconn.Connect(context.Background(), os.Getenv("PGX_TEST_CONN_STRING"))
   243  // 	require.Nil(b, err)
   244  // 	defer closeConn(b, conn)
   245  
   246  // 	ctx, cancel := context.WithCancel(context.Background())
   247  // 	defer cancel()
   248  
   249  // 	b.ResetTimer()
   250  
   251  // 	for i := 0; i < b.N; i++ {
   252  // 		conn.ChanToSetDeadline().Watch(ctx)
   253  // 		conn.ChanToSetDeadline().Ignore()
   254  // 	}
   255  // }
   256  
   257  func BenchmarkCommandTagRowsAffected(b *testing.B) {
   258  	benchmarks := []struct {
   259  		commandTag   string
   260  		rowsAffected int64
   261  	}{
   262  		{"UPDATE 1", 1},
   263  		{"UPDATE 123456789", 123456789},
   264  		{"INSERT 0 1", 1},
   265  		{"INSERT 0 123456789", 123456789},
   266  	}
   267  
   268  	for _, bm := range benchmarks {
   269  		ct := pgconn.CommandTag(bm.commandTag)
   270  		b.Run(bm.commandTag, func(b *testing.B) {
   271  			var n int64
   272  			for i := 0; i < b.N; i++ {
   273  				n = ct.RowsAffected()
   274  			}
   275  			if n != bm.rowsAffected {
   276  				b.Errorf("expected %d got %d", bm.rowsAffected, n)
   277  			}
   278  		})
   279  	}
   280  }
   281  
   282  func BenchmarkCommandTagTypeFromString(b *testing.B) {
   283  	ct := pgconn.CommandTag("UPDATE 1")
   284  
   285  	var update bool
   286  	for i := 0; i < b.N; i++ {
   287  		update = strings.HasPrefix(ct.String(), "UPDATE")
   288  	}
   289  	if !update {
   290  		b.Error("expected update")
   291  	}
   292  }
   293  
   294  func BenchmarkCommandTagInsert(b *testing.B) {
   295  	benchmarks := []struct {
   296  		commandTag string
   297  		is         bool
   298  	}{
   299  		{"INSERT 1", true},
   300  		{"INSERT 1234567890", true},
   301  		{"UPDATE 1", false},
   302  		{"UPDATE 1234567890", false},
   303  		{"DELETE 1", false},
   304  		{"DELETE 1234567890", false},
   305  		{"SELECT 1", false},
   306  		{"SELECT 1234567890", false},
   307  		{"UNKNOWN 1234567890", false},
   308  	}
   309  
   310  	for _, bm := range benchmarks {
   311  		ct := pgconn.CommandTag(bm.commandTag)
   312  		b.Run(bm.commandTag, func(b *testing.B) {
   313  			var is bool
   314  			for i := 0; i < b.N; i++ {
   315  				is = ct.Insert()
   316  			}
   317  			if is != bm.is {
   318  				b.Errorf("expected %v got %v", bm.is, is)
   319  			}
   320  		})
   321  	}
   322  }
   323  

View as plain text