--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Hi,I can not really reproduce your results. I rewrote your code to use the builtin benchmarking: http://sprunge.us/IfQcGiving, on my laptop:BenchmarkAssertion-4 1000000000 2.89 ns/opBenchmarkAssertionOK-4 500000000 2.66 ns/opBenchmarkBare-4 1000000000 2.22 ns/opBenchmarkIface-4 50000000 30.0 ns/opBenchmarkReflect-4 200000000 9.74 ns/opNote, that a) yes, there is an overhead of the type-assertion, but b) it's pretty small, especially compared to the other things you're trying and c) it can be further reduced by using the two-value form (so that there is never a need to consider stack-unwinding).Overall, this smells like a micro-benchmark. I wouldn't worry too much about it until you have specific evidence that it's slowing down a real program.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
On Thursday, February 2, 2017 at 4:58:32 PM UTC+8, Axel Wagner wrote:Hi,I can not really reproduce your results. I rewrote your code to use the builtin benchmarking: http://sprunge.us/IfQcGiving, on my laptop:BenchmarkAssertion-4 1000000000 2.89 ns/opBenchmarkAssertionOK-4 500000000 2.66 ns/opBenchmarkBare-4 1000000000 2.22 ns/opBenchmarkIface-4 50000000 30.0 ns/opBenchmarkReflect-4 200000000 9.74 ns/opNote, that a) yes, there is an overhead of the type-assertion, but b) it's pretty small, especially compared to the other things you're trying and c) it can be further reduced by using the two-value form (so that there is never a need to consider stack-unwinding).Overall, this smells like a micro-benchmark. I wouldn't worry too much about it until you have specific evidence that it's slowing down a real program.
The result on my machine for your test:
BenchmarkAssertion-4 500000000 17.9 ns/op
BenchmarkAssertionOK-4 500000000 17.9 ns/op
BenchmarkBare-4 2000000000 3.93 ns/op
BenchmarkIface-4 100000000 86.7 ns/op
BenchmarkReflect-4 500000000 15.6 ns/op
On Thursday, February 2, 2017 at 4:58:32 PM UTC+8, Axel Wagner wrote:Hi,I can not really reproduce your results. I rewrote your code to use the builtin benchmarking: http://sprunge.us/IfQcGiving, on my laptop:BenchmarkAssertion-4 1000000000 2.89 ns/opBenchmarkAssertionOK-4 500000000 2.66 ns/opBenchmarkBare-4 1000000000 2.22 ns/opBenchmarkIface-4 50000000 30.0 ns/opBenchmarkReflect-4 200000000 9.74 ns/opNote, that a) yes, there is an overhead of the type-assertion, but b) it's pretty small, especially compared to the other things you're trying and c) it can be further reduced by using the two-value form (so that there is never a need to consider stack-unwinding).Overall, this smells like a micro-benchmark. I wouldn't worry too much about it until you have specific evidence that it's slowing down a real program.The result on my machine for your test:BenchmarkAssertion-4 500000000 17.9 ns/opBenchmarkAssertionOK-4 500000000 17.9 ns/opBenchmarkBare-4 2000000000 3.93 ns/opBenchmarkIface-4 100000000 86.7 ns/opBenchmarkReflect-4 500000000 15.6 ns/op
I found that it is much faster if the dynamic values are pointers instead of non-pointer.
0.44ns/op is about 2.2.ghz, the compiler has optimised away your microbenchmark.
--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
func sum(x, y interface{}) (interface{}, error) {
return x.(uint64) + y.(uint64), nil
}
--
You received this message because you are subscribed to a topic in the Google Groups "golang-nuts" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/golang-nuts/Og8s9Y-Kif4/unsubscribe.
To unsubscribe from this group and all its topics, send an email to golang-nuts+unsubscribe@googlegroups.com.
--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
According to the profiler i := uint64(arg.(uint32))
is a major contributor
// Cast the integer argument to uint64 and call a "writer"
// The "writer" knows how many bytes to add to the binary stream
// Type casts from interface{} to integer consume 40% of the overall
// time. Can I do better? What is interface{} in Golang?
func (b *Binlog) writeArgumentToOutput(writer writer, arg interface{}, argKind reflect.Kind) error {
// unsafe pointer to the data depends on the data type
var err error
switch argKind {
case reflect.Int8:
i := uint64(arg.(int8))
err = writer.write(b.ioWriter, unsafe.Pointer(&i))
case reflect.Int16:
i := uint64(arg.(int16))
err = writer.write(b.ioWriter, unsafe.Pointer(&i))
case reflect.Int32:
i := uint64(arg.(int32))
err = writer.write(b.ioWriter, unsafe.Pointer(&i))
case reflect.Int64:
i := uint64(arg.(int64))
err = writer.write(b.ioWriter, unsafe.Pointer(&i))
case reflect.Uint8:
i := uint64(arg.(uint8))
err = writer.write(b.ioWriter, unsafe.Pointer(&i))
case reflect.Uint16:
i := uint64(arg.(uint16))
err = writer.write(b.ioWriter, unsafe.Pointer(&i))
case reflect.Uint32:
i := uint64(arg.(uint32))
err = writer.write(b.ioWriter, unsafe.Pointer(&i))
case reflect.Uint64:
i := uint64(arg.(uint64))
err = writer.write(b.ioWriter, unsafe.Pointer(&i))
case reflect.Int:
i := uint64(arg.(int))
err = writer.write(b.ioWriter, unsafe.Pointer(&i))
case reflect.Uint:
i := uint64(arg.(uint))
err = writer.write(b.ioWriter, unsafe.Pointer(&i))
default:
return fmt.Errorf("Unsupported type: %T\n", reflect.TypeOf(arg))
}
return err
}
--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
-j
No offense intended, but that code is wrong on so many levels...
I'd suggest simplyfunc (b *Binlog) writeArgumentToOutput(writer writer, arg uint64) error { /* do the writing */ }and doing the actual conversions at the call-site. It's type-safe, shorter, faster and more idiomatic - with the tiny downside of a `uint64()` here and there.Alternatively, use reflect as it's intended to - something likefunc writeArgumentToOutput(writer writer, arg interface{}) error {rv := reflect.ValueOf(arg)var v uint64if k := rv.Kind(); k >= reflect.Int && k < reflect.Uint {
Only slightly more verbose, but much easier to understand. But ultimate
Axel's first instinct is I think the right one -- just do the cast at
the call site.
switch arg := arg.(type) {
case int:
i := uint64(arg)
err = writer.write(b.ioWriter, unsafe.Pointer(&i))
case uint:
switch argKind {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
i := uint64(arg.(int))
err = writer.write(b.ioWriter, unsafe.Pointer(&i))
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
i := arg.(uint)
err = writer.write(b.ioWriter, unsafe.Pointer(&i))
func (b *Binlog) writeArgumentToOutput(writer writer, arg interface{}) error {
var err error
rv := reflect.ValueOf(arg)
var v uint64
if k := rv.Kind(); k >= reflect.Int && k < reflect.Uint {
v = uint64(rv.Int())
err = writer.write(b.ioWriter, unsafe.Pointer(&v))
} else if k <= reflect.Uintptr {
v = rv.Uint()
err = writer.write(b.ioWriter, unsafe.Pointer(&v))
} else {
return fmt.Errorf("Unsupported type: %T\n", reflect.TypeOf(arg))
}
/* write v */
return err
}
type iface struct {
tab *unsafe.Pointer
data *unsafe.Pointer
}
func getInterfaceData(arg interface{}) unsafe.Pointer {
return unsafe.Pointer((((*iface)(unsafe.Pointer(&arg))).data))
}
// Cast the integer argument to uint64 and call a "writer"
// The "writer" knows how many bytes to add to the binary stream
//
// Type casts from interface{} to integer consume 40% of the overall
// time. Can I do better? What is interface{} in Golang?
// Switching to args *[]interface makes the performance 2x worse
// Before you jump to conlusions see
// https://groups.google.com/forum/#!topic/golang-nuts/Og8s9Y-Kif4
func (b *Binlog) writeArgumentToOutput(writer writer, arg interface{}) error {
// unsafe pointer to the data depends on the data type
var
err error
err = writer.write(b.ioWriter, getInterfaceData(arg))
return err
}
-j
type iface struct {
tab *unsafe.Pointer
data *unsafe.Pointer
}
func getInterfaceData(arg interface{}) unsafe.Pointer {
return unsafe.Pointer((((*iface)(unsafe.Pointer(&arg))).data))
}
func (b *Binlog) writeArgumentToOutput(writer writer, arg interface{}) error {
// unsafe pointer to the data depends on the data type
var
err error
err = writer.write(b.ioWriter, getInterfaceData(arg))
return err
}
These are great tips! Thank you!This is the context for the code above https://github.com/larytet/binlog/blob/master/binlog.go#L548
ZAP is significantly slower than what I do. The binary log has an inherent edge.
For comparison call to Log() is 3x faster than fmt.Fprintf()
I have added BenchmarkSingleIntRogerPeppe() - 13ns more
// This is straight from the https://github.com/uber-go/zap plabook
func (b *Binlog) LogStructured(msg string, fields ...Field) error
type FieldType uint8
type Field struct {
Key string
Type FieldType
Integer int64
String string
Interface interface{}
}
const (
// UnknownType is the default field type. Attempting to add it to an encoder will panic.
UnknownType FieldType = iota
// Int64Type indicates that the field carries an int64.
Uint64Type
)
func Uint64(key string, val uint64) Field {
return Field{Key: key, Type: Uint64Type, Integer: int64(val)}
}
func handleFields(s string, fields ...Field) {
}
func BenchmarkZapApi(b *testing.B) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
handleFields("Hello ",
Uint64("world", 0),
Uint64("world", 1),
Uint64("world", 2),
)
}
b.StopTimer()
}
--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.