Skip to content

Commit

Permalink
Merge pull request #9 from tdakkota/feat/unsafe-copying
Browse files Browse the repository at this point in the history
feat(proto): use memmove on amd64 for int columns
  • Loading branch information
ernado authored Dec 30, 2021
2 parents 0906ee7 + 95b7894 commit 8b4cb51
Show file tree
Hide file tree
Showing 74 changed files with 1,577 additions and 737 deletions.
42 changes: 33 additions & 9 deletions proto/cmd/ch-gen-col/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,14 @@ const (
)

type Variant struct {
Kind Kind
Signed bool
Bits int
Kind Kind
Signed bool
Bits int
GenerateUnsafe bool
}

func (v Variant) Bytes() int {
return v.Bits / 8
}

type Variants []Variant
Expand Down Expand Up @@ -197,6 +202,12 @@ var testTemplate string
//go:embed infer.tpl
var inferTemplate string

//go:embed safe.tpl
var safeTemplate string

//go:embed unsafe.tpl
var unsafeTemplate string

func write(name string, v interface{}, t *template.Template) error {
out := new(bytes.Buffer)
if err := t.Execute(out, v); err != nil {
Expand All @@ -214,9 +225,11 @@ func write(name string, v interface{}, t *template.Template) error {

func run() error {
var (
tpl = template.Must(template.New("main").Parse(mainTemplate))
tplInfer = template.Must(template.New("main").Parse(inferTemplate))
tplTest = template.Must(template.New("main").Parse(testTemplate))
tpl = template.Must(template.New("main").Parse(mainTemplate))
tplInfer = template.Must(template.New("main").Parse(inferTemplate))
tplSafe = template.Must(template.New("main").Parse(safeTemplate))
tplUnsafe = template.Must(template.New("main").Parse(unsafeTemplate))
tplTest = template.Must(template.New("main").Parse(testTemplate))
)
variants := Variants{
{ // Float32
Expand Down Expand Up @@ -305,11 +318,22 @@ func run() error {
}
}
for _, v := range variants {
base := "col_" + v.ElemLower() + "_gen"
if err := write(base, v, tpl); err != nil {
if v.Bits <= 64 && !v.Byte() {
v.GenerateUnsafe = true
}
base := "col_" + v.ElemLower()
if err := write(base+"_gen", v, tpl); err != nil {
return errors.Wrap(err, "write")
}
if err := write(base+"_safe_gen", v, tplSafe); err != nil {
return errors.Wrap(err, "write")
}
if err := write(base+"_test", v, tplTest); err != nil {
if v.GenerateUnsafe {
if err := write(base+"_unsafe_gen", v, tplUnsafe); err != nil {
return errors.Wrap(err, "write")
}
}
if err := write(base+"_gen_test", v, tplTest); err != nil {
return errors.Wrap(err, "write test")
}
}
Expand Down
51 changes: 2 additions & 49 deletions proto/cmd/ch-gen-col/main.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,11 @@ package proto
import (
"encoding/binary"
{{- if .IsFloat }}
"math"
"math"
{{- end }}
"github.com/go-faster/errors"
)

// ClickHouse uses LittleEndian.
var _ = binary.LittleEndian
var _ = binary.LittleEndian // clickHouse uses LittleEndian

// {{ .Type }} represents {{ .Name }} column.
type {{ .Type }} []{{ .ElemType }}
Expand Down Expand Up @@ -92,48 +90,3 @@ func (c {{ .Type }}) EncodeColumn(b *Buffer) {
}
{{- end }}
}

// DecodeColumn decodes {{ .Name }} rows from *Reader.
func (c *{{ .Type }}) DecodeColumn(r *Reader, rows int) error {
if rows == 0 {
return nil
}
{{- if .SingleByte }}
data, err := r.ReadRaw(rows)
{{- else }}
const size = {{ .Bits }} / 8
data, err := r.ReadRaw(rows * size)
{{- end }}
if err != nil {
return errors.Wrap(err, "read")
}
{{- if .Byte }}
*c = append(*c, data...)
{{- else if .SingleByte }}
v := *c
v = append(v, make([]{{ .ElemType }}, rows)...)
for i := range data {
v[i] = {{ .ElemType }}(data[i])
}
*c = v
{{- else }}
v := *c
// Move bound check out of loop.
//
// See https://github.com/golang/go/issues/30945.
_ = data[len(data)-size]
for i := 0; i <= len(data)-size; i += size {
v = append(v,
{{- if .IsFloat }}
math.{{ .Name }}frombits(bin.{{ .BinFunc }}(data[i:i+size])),
{{- else if .Cast }}
{{ .ElemType }}({{ .BinGet }}(data[i:i+size])),
{{- else }}
{{ .BinGet }}(data[i:i+size]),
{{- end }}
)
}
*c = v
{{- end }}
return nil
}
61 changes: 61 additions & 0 deletions proto/cmd/ch-gen-col/safe.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
{{- /*gotype: github.com/go-faster/ch/proto/cmd/ch-gen-col.Variant*/ -}}
{{ if .GenerateUnsafe }}//go:build !amd64 || nounsafe{{ end }}
// Code generated by ./cmd/ch-gen-int, DO NOT EDIT.

package proto

import (
"encoding/binary"
{{- if .IsFloat }}
"math"
{{- end }}

"github.com/go-faster/errors"
)

var _ = binary.LittleEndian // clickHouse uses LittleEndian

// DecodeColumn decodes {{ .Name }} rows from *Reader.
func (c *{{ .Type }}) DecodeColumn(r *Reader, rows int) error {
if rows == 0 {
return nil
}
{{- if .SingleByte }}
data, err := r.ReadRaw(rows)
{{- else }}
const size = {{ .Bits }} / 8
data, err := r.ReadRaw(rows * size)
{{- end }}
if err != nil {
return errors.Wrap(err, "read")
}
{{- if .Byte }}
*c = append(*c, data...)
{{- else if .SingleByte }}
v := *c
v = append(v, make([]{{ .ElemType }}, rows)...)
for i := range data {
v[i] = {{ .ElemType }}(data[i])
}
*c = v
{{- else }}
v := *c
// Move bound check out of loop.
//
// See https://github.com/golang/go/issues/30945.
_ = data[len(data)-size]
for i := 0; i <= len(data)-size; i += size {
v = append(v,
{{- if .IsFloat }}
math.{{ .Name }}frombits(bin.{{ .BinFunc }}(data[i:i+size])),
{{- else if .Cast }}
{{ .ElemType }}({{ .BinGet }}(data[i:i+size])),
{{- else }}
{{ .BinGet }}(data[i:i+size]),
{{- end }}
)
}
*c = v
{{- end }}
return nil
}
30 changes: 30 additions & 0 deletions proto/cmd/ch-gen-col/unsafe.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{{- /*gotype: github.com/go-faster/ch/proto/cmd/ch-gen-col.Variant*/ -}}
//go:build amd64 && !nounsafe
// Code generated by ./cmd/ch-gen-int, DO NOT EDIT.

package proto

import (
"unsafe"
"reflect"

"github.com/go-faster/errors"
)

// DecodeColumn decodes {{ .Name }} rows from *Reader.
func (c *{{ .Type }}) DecodeColumn(r *Reader, rows int) error {
if rows == 0 {
return nil
}
*c = append(*c, make([]{{ .ElemType }}, rows)...)
s := *(*reflect.SliceHeader)(unsafe.Pointer(c))
{{- if not .SingleByte }}
s.Len *= {{ .Bytes }}
s.Cap *= {{ .Bytes }}
{{- end }}
dst := *(*[]byte)(unsafe.Pointer(&s))
if err := r.ReadFull(dst); err != nil {
return errors.Wrap(err, "read full")
}
return nil
}
28 changes: 1 addition & 27 deletions proto/col_date32_gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

37 changes: 37 additions & 0 deletions proto/col_date32_safe_gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

28 changes: 28 additions & 0 deletions proto/col_date32_unsafe_gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

28 changes: 1 addition & 27 deletions proto/col_date_gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 8b4cb51

Please sign in to comment.