2
0

Added int8 binary decoding

Refactored benchmarks
This commit is contained in:
Jack Christensen
2013-07-08 17:56:14 -05:00
parent a6e742db24
commit 85ffca4fe0
4 changed files with 273 additions and 107 deletions
+230 -102
View File
@@ -6,22 +6,24 @@ import (
"testing"
)
var testDataLoaded bool
var testJoinsDataLoaded bool
var narrowTestDataLoaded bool
var int4TextVsBinaryTestDataLoaded bool
var int8TextVsBinaryTestDataLoaded bool
func loadTestData() {
if testDataLoaded {
func mustPrepare(b *testing.B, conn *Connection, name, sql string) {
if err := conn.Prepare(name, sql); err != nil {
b.Fatalf("Could not prepare %v: %v", name, err)
}
}
func createNarrowTestData(b *testing.B, conn *Connection) {
if narrowTestDataLoaded {
return
}
var err error
conn := getSharedConnection()
_, err = conn.Execute(`
if _, err := conn.Execute(`
drop table if exists narrow;
drop table if exists product_component;
drop table if exists component;
drop table if exists product;
create table narrow(
id serial primary key,
@@ -35,6 +37,98 @@ func loadTestData() {
select (random()*1000000)::int, (random()*1000000)::int, (random()*1000000)::int, (random()*1000000)::int
from generate_series(1, 10000);
analyze narrow;
`); err != nil {
panic(fmt.Sprintf("Unable to create narrow test data: %v", err))
}
mustPrepare(b, conn, "getNarrowById", "select * from narrow where id=$1")
mustPrepare(b, conn, "getMultipleNarrowById", "select * from narrow where id between $1 and $2")
narrowTestDataLoaded = true
}
func BenchmarkSelectRowSimpleNarrow(b *testing.B) {
conn := getSharedConnection()
createNarrowTestData(b, conn)
// Get random ids outside of timing
ids := make([]int32, b.N)
for i := 0; i < b.N; i++ {
ids[i] = 1 + rand.Int31n(9999)
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
if _, err := conn.SelectRow("select * from narrow where id=$1", ids[i]); err != nil {
b.Fatalf("Failure while benchmarking: %v", err)
}
}
}
func BenchmarkSelectRowPreparedNarrow(b *testing.B) {
conn := getSharedConnection()
createNarrowTestData(b, conn)
// Get random ids outside of timing
ids := make([]int32, b.N)
for i := 0; i < b.N; i++ {
ids[i] = 1 + rand.Int31n(9999)
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
if _, err := conn.SelectRow("getNarrowById", ids[i]); err != nil {
b.Fatalf("Failure while benchmarking: %v", err)
}
}
}
func BenchmarkSelectRowsSimpleNarrow(b *testing.B) {
conn := getSharedConnection()
createNarrowTestData(b, conn)
// Get random ids outside of timing
ids := make([]int32, b.N)
for i := 0; i < b.N; i++ {
ids[i] = 1 + rand.Int31n(9999)
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
if _, err := conn.SelectRows("select * from narrow where id between $1 and $2", ids[i], ids[i]+10); err != nil {
b.Fatalf("Failure while benchmarking: %v", err)
}
}
}
func BenchmarkSelectRowsPreparedNarrow(b *testing.B) {
conn := getSharedConnection()
createNarrowTestData(b, conn)
// Get random ids outside of timing
ids := make([]int32, b.N)
for i := 0; i < b.N; i++ {
ids[i] = 1 + rand.Int31n(9999)
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
if _, err := conn.SelectRows("getMultipleNarrowById", ids[i], ids[i]+10); err != nil {
b.Fatalf("Failure while benchmarking: %v", err)
}
}
}
func createJoinsTestData(b *testing.B, conn *Connection) {
if testJoinsDataLoaded {
return
}
if _, err := conn.Execute(`
drop table if exists product_component;
drop table if exists component;
drop table if exists product;
create table component(
id serial primary key,
@@ -82,22 +176,11 @@ func loadTestData() {
create index on product_component(component_id);
analyze;
`)
if err != nil {
`); err != nil {
panic(fmt.Sprintf("Unable to create test data: %v", err))
}
err = conn.Prepare("getNarrowById", "select * from narrow where id=$1")
if err != nil {
panic("Unable to prepare getNarrowById")
}
err = conn.Prepare("getMultipleNarrowById", "select * from narrow where id between $1 and $2")
if err != nil {
panic("Unable to prepare getMultipleNarrowById")
}
err = conn.Prepare("joinAggregate", `
mustPrepare(b, conn, "joinAggregate", `
select product.id, sum(cost*quantity) as total_cost
from product
join product_component on product.id=product_component.product_id
@@ -106,88 +189,13 @@ func loadTestData() {
having sum(weight*quantity) > 10
order by total_cost desc
`)
if err != nil {
panic("Unable to prepare joinAggregate")
}
testDataLoaded = true
}
func BenchmarkSelectRowSimpleNarrow(b *testing.B) {
loadTestData()
conn := getSharedConnection()
// Get random ids outside of timing
ids := make([]int32, b.N)
for i := 0; i < b.N; i++ {
ids[i] = 1 + rand.Int31n(9999)
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
if _, err := conn.SelectRow("select * from narrow where id=$1", ids[i]); err != nil {
b.Fatalf("Failure while benchmarking: %v", err)
}
}
}
func BenchmarkSelectRowPreparedNarrow(b *testing.B) {
loadTestData()
conn := getSharedConnection()
// Get random ids outside of timing
ids := make([]int32, b.N)
for i := 0; i < b.N; i++ {
ids[i] = 1 + rand.Int31n(9999)
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
if _, err := conn.SelectRow("getNarrowById", ids[i]); err != nil {
b.Fatalf("Failure while benchmarking: %v", err)
}
}
}
func BenchmarkSelectRowsSimpleNarrow(b *testing.B) {
loadTestData()
conn := getSharedConnection()
// Get random ids outside of timing
ids := make([]int32, b.N)
for i := 0; i < b.N; i++ {
ids[i] = 1 + rand.Int31n(9999)
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
if _, err := conn.SelectRows("select * from narrow where id between $1 and $2", ids[i], ids[i]+10); err != nil {
b.Fatalf("Failure while benchmarking: %v", err)
}
}
}
func BenchmarkSelectRowsPreparedNarrow(b *testing.B) {
loadTestData()
conn := getSharedConnection()
// Get random ids outside of timing
ids := make([]int32, b.N)
for i := 0; i < b.N; i++ {
ids[i] = 1 + rand.Int31n(9999)
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
if _, err := conn.SelectRows("getMultipleNarrowById", ids[i], ids[i]+10); err != nil {
b.Fatalf("Failure while benchmarking: %v", err)
}
}
testJoinsDataLoaded = true
}
func BenchmarkSelectRowsSimpleJoins(b *testing.B) {
loadTestData()
conn := getSharedConnection()
createJoinsTestData(b, conn)
sql := `
select product.id, sum(cost*quantity) as total_cost
@@ -208,8 +216,8 @@ func BenchmarkSelectRowsSimpleJoins(b *testing.B) {
}
func BenchmarkSelectRowsPreparedJoins(b *testing.B) {
loadTestData()
conn := getSharedConnection()
createJoinsTestData(b, conn)
b.ResetTimer()
for i := 0; i < b.N; i++ {
@@ -218,3 +226,123 @@ func BenchmarkSelectRowsPreparedJoins(b *testing.B) {
}
}
}
func createInt4TextVsBinaryTestData(b *testing.B, conn *Connection) {
if int4TextVsBinaryTestDataLoaded {
return
}
if _, err := conn.Execute(`
drop table if exists t;
create temporary table t(
a int4 not null,
b int4 not null,
c int4 not null,
d int4 not null,
e int4 not null
);
insert into t(a, b, c, d, e)
select
(random() * 1000000)::int4, (random() * 1000000)::int4, (random() * 1000000)::int4, (random() * 1000000)::int4, (random() * 1000000)::int4
from generate_series(1, 10);
`); err != nil {
b.Fatalf("Could not set up test data: %v", err)
}
int4TextVsBinaryTestDataLoaded = true
}
func BenchmarkInt4Text(b *testing.B) {
conn := getSharedConnection()
createInt4TextVsBinaryTestData(b, conn)
binaryDecoder := valueTranscoders[oid(23)].DecodeBinary
valueTranscoders[oid(23)].DecodeBinary = nil
defer func() { valueTranscoders[oid(23)].DecodeBinary = binaryDecoder }()
mustPrepare(b, conn, "selectInt32", "select * from t")
defer func() { conn.Deallocate("selectInt32") }()
b.ResetTimer()
for i := 0; i < b.N; i++ {
if _, err := conn.SelectRows("selectInt32"); err != nil {
b.Fatalf("Failure while benchmarking: %v", err)
}
}
}
func BenchmarkInt4Binary(b *testing.B) {
conn := getSharedConnection()
createInt4TextVsBinaryTestData(b, conn)
mustPrepare(b, conn, "selectInt32", "select * from t")
defer func() { conn.Deallocate("selectInt32") }()
b.ResetTimer()
for i := 0; i < b.N; i++ {
if _, err := conn.SelectRows("selectInt32"); err != nil {
b.Fatalf("Failure while benchmarking: %v", err)
}
}
}
func createInt8TextVsBinaryTestData(b *testing.B, conn *Connection) {
if int8TextVsBinaryTestDataLoaded {
return
}
if _, err := conn.Execute(`
drop table if exists t;
create temporary table t(
a int8 not null,
b int8 not null,
c int8 not null,
d int8 not null,
e int8 not null
);
insert into t(a, b, c, d, e)
select
(random() * 1000000)::int8, (random() * 1000000)::int8, (random() * 1000000)::int8, (random() * 1000000)::int8, (random() * 1000000)::int8
from generate_series(1, 10);
`); err != nil {
b.Fatalf("Could not set up test data: %v", err)
}
int8TextVsBinaryTestDataLoaded = true
}
func BenchmarkInt8Text(b *testing.B) {
conn := getSharedConnection()
createInt8TextVsBinaryTestData(b, conn)
binaryDecoder := valueTranscoders[oid(20)].DecodeBinary
valueTranscoders[oid(20)].DecodeBinary = nil
defer func() { valueTranscoders[oid(20)].DecodeBinary = binaryDecoder }()
mustPrepare(b, conn, "selectInt64", "select * from t")
defer func() { conn.Deallocate("selectInt64") }()
b.ResetTimer()
for i := 0; i < b.N; i++ {
if _, err := conn.SelectRows("selectInt64"); err != nil {
b.Fatalf("Failure while benchmarking: %v", err)
}
}
}
func BenchmarkInt8Binary(b *testing.B) {
conn := getSharedConnection()
createInt8TextVsBinaryTestData(b, conn)
mustPrepare(b, conn, "selectInt64", "select * from t")
defer func() { conn.Deallocate("selectInt64") }()
b.ResetTimer()
for i := 0; i < b.N; i++ {
if _, err := conn.SelectRows("selectInt64"); err != nil {
b.Fatalf("Failure while benchmarking: %v", err)
}
}
}
+17 -1
View File
@@ -281,6 +281,12 @@ func (c *Connection) Prepare(name, sql string) (err error) {
ps.ParameterOids = c.rxParameterDescription(r)
case rowDescription:
ps.FieldDescriptions = c.rxRowDescription(r)
for i := range ps.FieldDescriptions {
oid := ps.FieldDescriptions[i].DataType
if valueTranscoders[oid] != nil && valueTranscoders[oid].DecodeBinary != nil {
ps.FieldDescriptions[i].FormatCode = 1
}
}
case readyForQuery:
c.preparedStatements[name] = &ps
return
@@ -339,6 +345,7 @@ func (c *Connection) sendPreparedQuery(ps *PreparedStatement, arguments ...inter
buf.WriteByte(0)
buf.WriteString(ps.Name)
buf.WriteByte(0)
binary.Write(buf, binary.BigEndian, int16(len(ps.ParameterOids)))
for _, oid := range ps.ParameterOids {
transcoder := valueTranscoders[oid]
@@ -356,7 +363,16 @@ func (c *Connection) sendPreparedQuery(ps *PreparedStatement, arguments ...inter
}
transcoder.EncodeTo(buf, arguments[i])
}
binary.Write(buf, binary.BigEndian, int16(0))
binary.Write(buf, binary.BigEndian, int16(len(ps.FieldDescriptions)))
for _, fd := range ps.FieldDescriptions {
transcoder := valueTranscoders[fd.DataType]
if transcoder != nil && transcoder.DecodeBinary != nil {
binary.Write(buf, binary.BigEndian, int16(1))
} else {
binary.Write(buf, binary.BigEndian, int16(0))
}
}
err = c.txMsg('B', buf)
if err != nil {
+6
View File
@@ -30,6 +30,12 @@ func (r *MessageReader) ReadInt32() int32 {
return n
}
func (r *MessageReader) ReadInt64() int64 {
n := int64(binary.BigEndian.Uint64((*r)[:8]))
*r = (*r)[8:]
return n
}
func (r *MessageReader) ReadOid() oid {
n := oid(binary.BigEndian.Uint32((*r)[:4]))
*r = (*r)[4:]
+20 -4
View File
@@ -34,8 +34,9 @@ func init() {
// int8
valueTranscoders[oid(20)] = &valueTranscoder{
DecodeText: decodeInt8FromText,
EncodeTo: encodeInt8}
DecodeText: decodeInt8FromText,
DecodeBinary: decodeInt8FromBinary,
EncodeTo: encodeInt8}
// int2
valueTranscoders[oid(21)] = &valueTranscoder{
@@ -44,8 +45,9 @@ func init() {
// int4
valueTranscoders[oid(23)] = &valueTranscoder{
DecodeText: decodeInt4FromText,
EncodeTo: encodeInt4}
DecodeText: decodeInt4FromText,
DecodeBinary: decodeInt4FromBinary,
EncodeTo: encodeInt4}
// text
valueTranscoders[oid(25)] = &valueTranscoder{
@@ -97,6 +99,13 @@ func decodeInt8FromText(mr *MessageReader, size int32) interface{} {
return n
}
func decodeInt8FromBinary(mr *MessageReader, size int32) interface{} {
if size != 8 {
panic("Received an invalid size for an int8")
}
return mr.ReadInt64()
}
func encodeInt8(buf *bytes.Buffer, value interface{}) {
v := value.(int64)
s := strconv.FormatInt(int64(v), 10)
@@ -129,6 +138,13 @@ func decodeInt4FromText(mr *MessageReader, size int32) interface{} {
return int32(n)
}
func decodeInt4FromBinary(mr *MessageReader, size int32) interface{} {
if size != 4 {
panic("Received an invalid size for an int4")
}
return mr.ReadInt32()
}
func encodeInt4(buf *bytes.Buffer, value interface{}) {
v := value.(int32)
s := strconv.FormatInt(int64(v), 10)