1
0
mirror of https://github.com/open-telemetry/opentelemetry-go.git synced 2025-01-18 03:22:12 +02:00

Remove bound metric instruments from the API (new champion) (#2399)

* Remove bound metric instruments from the API

* Removed dead code

* Added changelog message

* Added PR number

Co-authored-by: Joshua MacDonald <jmacd@lightstep.com>
Co-authored-by: Tyler Yahn <MrAlias@users.noreply.github.com>
This commit is contained in:
Aaron Clawson 2021-11-17 09:51:04 -06:00 committed by GitHub
parent b663c7c2bd
commit 034956199a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 19 additions and 528 deletions

View File

@ -11,6 +11,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
### Removed ### Removed
- Remove the metric Processor's ability to convert cumulative to delta aggregation temporality. (#2350) - Remove the metric Processor's ability to convert cumulative to delta aggregation temporality. (#2350)
- Remove the metric Bound Instruments interface and implementations. (#2399)
## [1.2.0] - 2021-11-12 ## [1.2.0] - 2021-11-12

View File

@ -41,10 +41,6 @@ import (
// in the MeterProvider and Meters ensure that each instrument has a delegate // in the MeterProvider and Meters ensure that each instrument has a delegate
// before the global provider is set. // before the global provider is set.
// //
// Bound instrument operations are implemented by delegating to the
// instrument after it is registered, with a sync.Once initializer to
// protect against races with Release().
//
// Metric uniqueness checking is implemented by calling the exported // Metric uniqueness checking is implemented by calling the exported
// methods of the api/metric/registry package. // methods of the api/metric/registry package.
@ -108,19 +104,9 @@ type AsyncImpler interface {
AsyncImpl() sdkapi.AsyncImpl AsyncImpl() sdkapi.AsyncImpl
} }
type syncHandle struct {
delegate unsafe.Pointer // (*sdkapi.BoundInstrumentImpl)
inst *syncImpl
labels []attribute.KeyValue
initialize sync.Once
}
var _ metric.MeterProvider = &meterProvider{} var _ metric.MeterProvider = &meterProvider{}
var _ sdkapi.MeterImpl = &meterImpl{} var _ sdkapi.MeterImpl = &meterImpl{}
var _ sdkapi.InstrumentImpl = &syncImpl{} var _ sdkapi.InstrumentImpl = &syncImpl{}
var _ sdkapi.BoundSyncImpl = &syncHandle{}
var _ sdkapi.AsyncImpl = &asyncImpl{} var _ sdkapi.AsyncImpl = &asyncImpl{}
func (inst *instrument) Descriptor() sdkapi.Descriptor { func (inst *instrument) Descriptor() sdkapi.Descriptor {
@ -241,28 +227,6 @@ func (inst *syncImpl) Implementation() interface{} {
return inst return inst
} }
func (inst *syncImpl) Bind(labels []attribute.KeyValue) sdkapi.BoundSyncImpl {
if implPtr := (*sdkapi.SyncImpl)(atomic.LoadPointer(&inst.delegate)); implPtr != nil {
return (*implPtr).Bind(labels)
}
return &syncHandle{
inst: inst,
labels: labels,
}
}
func (bound *syncHandle) Unbind() {
bound.initialize.Do(func() {})
implPtr := (*sdkapi.BoundSyncImpl)(atomic.LoadPointer(&bound.delegate))
if implPtr == nil {
return
}
(*implPtr).Unbind()
}
// Async delegation // Async delegation
func (m *meterImpl) NewAsyncInstrument( func (m *meterImpl) NewAsyncInstrument(
@ -325,37 +289,11 @@ func (inst *syncImpl) RecordOne(ctx context.Context, number number.Number, label
} }
} }
// Bound instrument initialization
func (bound *syncHandle) RecordOne(ctx context.Context, number number.Number) {
instPtr := (*sdkapi.SyncImpl)(atomic.LoadPointer(&bound.inst.delegate))
if instPtr == nil {
return
}
var implPtr *sdkapi.BoundSyncImpl
bound.initialize.Do(func() {
implPtr = new(sdkapi.BoundSyncImpl)
*implPtr = (*instPtr).Bind(bound.labels)
atomic.StorePointer(&bound.delegate, unsafe.Pointer(implPtr))
})
if implPtr == nil {
implPtr = (*sdkapi.BoundSyncImpl)(atomic.LoadPointer(&bound.delegate))
}
// This may still be nil if instrument was created and bound
// without a delegate, then the instrument was set to have a
// delegate and unbound.
if implPtr == nil {
return
}
(*implPtr).RecordOne(ctx, number)
}
func AtomicFieldOffsets() map[string]uintptr { func AtomicFieldOffsets() map[string]uintptr {
return map[string]uintptr{ return map[string]uintptr{
"meterProvider.delegate": unsafe.Offsetof(meterProvider{}.delegate), "meterProvider.delegate": unsafe.Offsetof(meterProvider{}.delegate),
"meterImpl.delegate": unsafe.Offsetof(meterImpl{}.delegate), "meterImpl.delegate": unsafe.Offsetof(meterImpl{}.delegate),
"syncImpl.delegate": unsafe.Offsetof(syncImpl{}.delegate), "syncImpl.delegate": unsafe.Offsetof(syncImpl{}.delegate),
"asyncImpl.delegate": unsafe.Offsetof(asyncImpl{}.delegate), "asyncImpl.delegate": unsafe.Offsetof(asyncImpl{}.delegate),
"syncHandle.delegate": unsafe.Offsetof(syncHandle{}.delegate),
} }
} }

View File

@ -137,97 +137,6 @@ func TestDirect(t *testing.T) {
) )
} }
func TestBound(t *testing.T) {
global.ResetForTest()
// Note: this test uses opposite Float64/Int64 number kinds
// vs. the above, to cover all the instruments.
ctx := context.Background()
glob := metricglobal.Meter(
"test",
metric.WithInstrumentationVersion("semver:test-1.0"),
metric.WithSchemaURL("schema://url"),
)
labels1 := []attribute.KeyValue{attribute.String("A", "B")}
counter := Must(glob).NewFloat64Counter("test.counter")
boundC := counter.Bind(labels1...)
boundC.Add(ctx, 1)
boundC.Add(ctx, 1)
histogram := Must(glob).NewInt64Histogram("test.histogram")
boundM := histogram.Bind(labels1...)
boundM.Record(ctx, 1)
boundM.Record(ctx, 2)
provider := metrictest.NewMeterProvider()
metricglobal.SetMeterProvider(provider)
boundC.Add(ctx, 1)
boundM.Record(ctx, 3)
library := metrictest.Library{
InstrumentationName: "test",
InstrumentationVersion: "semver:test-1.0",
SchemaURL: "schema://url",
}
require.EqualValues(t,
[]metrictest.Measured{
{
Name: "test.counter",
Library: library,
Labels: metrictest.LabelsToMap(labels1...),
Number: asFloat(1),
},
{
Name: "test.histogram",
Library: library,
Labels: metrictest.LabelsToMap(labels1...),
Number: asInt(3),
},
},
metrictest.AsStructs(provider.MeasurementBatches))
boundC.Unbind()
boundM.Unbind()
}
func TestUnbind(t *testing.T) {
// Tests Unbind with SDK never installed.
global.ResetForTest()
glob := metricglobal.Meter("test")
labels1 := []attribute.KeyValue{attribute.String("A", "B")}
counter := Must(glob).NewFloat64Counter("test.counter")
boundC := counter.Bind(labels1...)
histogram := Must(glob).NewInt64Histogram("test.histogram")
boundM := histogram.Bind(labels1...)
boundC.Unbind()
boundM.Unbind()
}
func TestUnbindThenRecordOne(t *testing.T) {
global.ResetForTest()
ctx := context.Background()
provider := metrictest.NewMeterProvider()
meter := metricglobal.Meter("test")
counter := Must(meter).NewInt64Counter("test.counter")
boundC := counter.Bind()
metricglobal.SetMeterProvider(provider)
boundC.Unbind()
require.NotPanics(t, func() {
boundC.Add(ctx, 1)
})
require.Equal(t, 0, len(provider.MeasurementBatches))
}
type meterProviderWithConstructorError struct { type meterProviderWithConstructorError struct {
metric.MeterProvider metric.MeterProvider
} }

View File

@ -260,11 +260,6 @@ type syncInstrument struct {
instrument sdkapi.SyncImpl instrument sdkapi.SyncImpl
} }
// syncBoundInstrument contains a BoundSyncImpl.
type syncBoundInstrument struct {
boundInstrument sdkapi.BoundSyncImpl
}
// asyncInstrument contains a AsyncImpl. // asyncInstrument contains a AsyncImpl.
type asyncInstrument struct { type asyncInstrument struct {
instrument sdkapi.AsyncImpl instrument sdkapi.AsyncImpl
@ -280,10 +275,6 @@ func (s syncInstrument) SyncImpl() sdkapi.SyncImpl {
return s.instrument return s.instrument
} }
func (s syncInstrument) bind(labels []attribute.KeyValue) syncBoundInstrument {
return newSyncBoundInstrument(s.instrument.Bind(labels))
}
func (s syncInstrument) float64Measurement(value float64) Measurement { func (s syncInstrument) float64Measurement(value float64) Measurement {
return sdkapi.NewMeasurement(s.instrument, number.NewFloat64Number(value)) return sdkapi.NewMeasurement(s.instrument, number.NewFloat64Number(value))
} }
@ -296,15 +287,6 @@ func (s syncInstrument) directRecord(ctx context.Context, number number.Number,
s.instrument.RecordOne(ctx, number, labels) s.instrument.RecordOne(ctx, number, labels)
} }
func (h syncBoundInstrument) directRecord(ctx context.Context, number number.Number) {
h.boundInstrument.RecordOne(ctx, number)
}
// Unbind calls SyncImpl.Unbind.
func (h syncBoundInstrument) Unbind() {
h.boundInstrument.Unbind()
}
// checkNewAsync receives an AsyncImpl and potential // checkNewAsync receives an AsyncImpl and potential
// error, and returns the same types, checking for and ensuring that // error, and returns the same types, checking for and ensuring that
// the returned interface is not nil. // the returned interface is not nil.
@ -340,12 +322,6 @@ func checkNewSync(instrument sdkapi.SyncImpl, err error) (syncInstrument, error)
}, err }, err
} }
func newSyncBoundInstrument(boundInstrument sdkapi.BoundSyncImpl) syncBoundInstrument {
return syncBoundInstrument{
boundInstrument: boundInstrument,
}
}
// wrapInt64CounterInstrument converts a SyncImpl into Int64Counter. // wrapInt64CounterInstrument converts a SyncImpl into Int64Counter.
func wrapInt64CounterInstrument(syncInst sdkapi.SyncImpl, err error) (Int64Counter, error) { func wrapInt64CounterInstrument(syncInst sdkapi.SyncImpl, err error) (Int64Counter, error) {
common, err := checkNewSync(syncInst, err) common, err := checkNewSync(syncInst, err)
@ -392,34 +368,6 @@ type Int64Counter struct {
syncInstrument syncInstrument
} }
// BoundFloat64Counter is a bound instrument for Float64Counter.
//
// It inherits the Unbind function from syncBoundInstrument.
type BoundFloat64Counter struct {
syncBoundInstrument
}
// BoundInt64Counter is a boundInstrument for Int64Counter.
//
// It inherits the Unbind function from syncBoundInstrument.
type BoundInt64Counter struct {
syncBoundInstrument
}
// Bind creates a bound instrument for this counter. The labels are
// associated with values recorded via subsequent calls to Record.
func (c Float64Counter) Bind(labels ...attribute.KeyValue) (h BoundFloat64Counter) {
h.syncBoundInstrument = c.bind(labels)
return
}
// Bind creates a bound instrument for this counter. The labels are
// associated with values recorded via subsequent calls to Record.
func (c Int64Counter) Bind(labels ...attribute.KeyValue) (h BoundInt64Counter) {
h.syncBoundInstrument = c.bind(labels)
return
}
// Measurement creates a Measurement object to use with batch // Measurement creates a Measurement object to use with batch
// recording. // recording.
func (c Float64Counter) Measurement(value float64) Measurement { func (c Float64Counter) Measurement(value float64) Measurement {
@ -444,18 +392,6 @@ func (c Int64Counter) Add(ctx context.Context, value int64, labels ...attribute.
c.directRecord(ctx, number.NewInt64Number(value), labels) c.directRecord(ctx, number.NewInt64Number(value), labels)
} }
// Add adds the value to the counter's sum using the labels
// previously bound to this counter via Bind()
func (b BoundFloat64Counter) Add(ctx context.Context, value float64) {
b.directRecord(ctx, number.NewFloat64Number(value))
}
// Add adds the value to the counter's sum using the labels
// previously bound to this counter via Bind()
func (b BoundInt64Counter) Add(ctx context.Context, value int64) {
b.directRecord(ctx, number.NewInt64Number(value))
}
// Float64UpDownCounter is a metric instrument that sums floating // Float64UpDownCounter is a metric instrument that sums floating
// point values. // point values.
type Float64UpDownCounter struct { type Float64UpDownCounter struct {
@ -467,34 +403,6 @@ type Int64UpDownCounter struct {
syncInstrument syncInstrument
} }
// BoundFloat64UpDownCounter is a bound instrument for Float64UpDownCounter.
//
// It inherits the Unbind function from syncBoundInstrument.
type BoundFloat64UpDownCounter struct {
syncBoundInstrument
}
// BoundInt64UpDownCounter is a boundInstrument for Int64UpDownCounter.
//
// It inherits the Unbind function from syncBoundInstrument.
type BoundInt64UpDownCounter struct {
syncBoundInstrument
}
// Bind creates a bound instrument for this counter. The labels are
// associated with values recorded via subsequent calls to Record.
func (c Float64UpDownCounter) Bind(labels ...attribute.KeyValue) (h BoundFloat64UpDownCounter) {
h.syncBoundInstrument = c.bind(labels)
return
}
// Bind creates a bound instrument for this counter. The labels are
// associated with values recorded via subsequent calls to Record.
func (c Int64UpDownCounter) Bind(labels ...attribute.KeyValue) (h BoundInt64UpDownCounter) {
h.syncBoundInstrument = c.bind(labels)
return
}
// Measurement creates a Measurement object to use with batch // Measurement creates a Measurement object to use with batch
// recording. // recording.
func (c Float64UpDownCounter) Measurement(value float64) Measurement { func (c Float64UpDownCounter) Measurement(value float64) Measurement {
@ -519,18 +427,6 @@ func (c Int64UpDownCounter) Add(ctx context.Context, value int64, labels ...attr
c.directRecord(ctx, number.NewInt64Number(value), labels) c.directRecord(ctx, number.NewInt64Number(value), labels)
} }
// Add adds the value to the counter's sum using the labels
// previously bound to this counter via Bind()
func (b BoundFloat64UpDownCounter) Add(ctx context.Context, value float64) {
b.directRecord(ctx, number.NewFloat64Number(value))
}
// Add adds the value to the counter's sum using the labels
// previously bound to this counter via Bind()
func (b BoundInt64UpDownCounter) Add(ctx context.Context, value int64) {
b.directRecord(ctx, number.NewInt64Number(value))
}
// Float64Histogram is a metric that records float64 values. // Float64Histogram is a metric that records float64 values.
type Float64Histogram struct { type Float64Histogram struct {
syncInstrument syncInstrument
@ -541,34 +437,6 @@ type Int64Histogram struct {
syncInstrument syncInstrument
} }
// BoundFloat64Histogram is a bound instrument for Float64Histogram.
//
// It inherits the Unbind function from syncBoundInstrument.
type BoundFloat64Histogram struct {
syncBoundInstrument
}
// BoundInt64Histogram is a bound instrument for Int64Histogram.
//
// It inherits the Unbind function from syncBoundInstrument.
type BoundInt64Histogram struct {
syncBoundInstrument
}
// Bind creates a bound instrument for this Histogram. The labels are
// associated with values recorded via subsequent calls to Record.
func (c Float64Histogram) Bind(labels ...attribute.KeyValue) (h BoundFloat64Histogram) {
h.syncBoundInstrument = c.bind(labels)
return
}
// Bind creates a bound instrument for this Histogram. The labels are
// associated with values recorded via subsequent calls to Record.
func (c Int64Histogram) Bind(labels ...attribute.KeyValue) (h BoundInt64Histogram) {
h.syncBoundInstrument = c.bind(labels)
return
}
// Measurement creates a Measurement object to use with batch // Measurement creates a Measurement object to use with batch
// recording. // recording.
func (c Float64Histogram) Measurement(value float64) Measurement { func (c Float64Histogram) Measurement(value float64) Measurement {
@ -594,15 +462,3 @@ func (c Float64Histogram) Record(ctx context.Context, value float64, labels ...a
func (c Int64Histogram) Record(ctx context.Context, value int64, labels ...attribute.KeyValue) { func (c Int64Histogram) Record(ctx context.Context, value int64, labels ...attribute.KeyValue) {
c.directRecord(ctx, number.NewInt64Number(value), labels) c.directRecord(ctx, number.NewInt64Number(value), labels)
} }
// Record adds a new value to the Histogram's distribution using the labels
// previously bound to the Histogram via Bind().
func (b BoundFloat64Histogram) Record(ctx context.Context, value float64) {
b.directRecord(ctx, number.NewFloat64Number(value))
}
// Record adds a new value to the Histogram's distribution using the labels
// previously bound to the Histogram via Bind().
func (b BoundInt64Histogram) Record(ctx context.Context, value int64) {
b.directRecord(ctx, number.NewInt64Number(value))
}

View File

@ -250,11 +250,9 @@ func TestCounter(t *testing.T) {
ctx := context.Background() ctx := context.Background()
labels := []attribute.KeyValue{attribute.String("A", "B")} labels := []attribute.KeyValue{attribute.String("A", "B")}
c.Add(ctx, 1994.1, labels...) c.Add(ctx, 1994.1, labels...)
boundInstrument := c.Bind(labels...)
boundInstrument.Add(ctx, -742)
meter.RecordBatch(ctx, labels, c.Measurement(42)) meter.RecordBatch(ctx, labels, c.Measurement(42))
checkSyncBatches(ctx, t, labels, provider, number.Float64Kind, sdkapi.CounterInstrumentKind, c.SyncImpl(), checkSyncBatches(ctx, t, labels, provider, number.Float64Kind, sdkapi.CounterInstrumentKind, c.SyncImpl(),
1994.1, -742, 42, 1994.1, 42,
) )
}) })
t.Run("int64 counter", func(t *testing.T) { t.Run("int64 counter", func(t *testing.T) {
@ -263,11 +261,9 @@ func TestCounter(t *testing.T) {
ctx := context.Background() ctx := context.Background()
labels := []attribute.KeyValue{attribute.String("A", "B"), attribute.String("C", "D")} labels := []attribute.KeyValue{attribute.String("A", "B"), attribute.String("C", "D")}
c.Add(ctx, 42, labels...) c.Add(ctx, 42, labels...)
boundInstrument := c.Bind(labels...)
boundInstrument.Add(ctx, 4200)
meter.RecordBatch(ctx, labels, c.Measurement(420000)) meter.RecordBatch(ctx, labels, c.Measurement(420000))
checkSyncBatches(ctx, t, labels, provider, number.Int64Kind, sdkapi.CounterInstrumentKind, c.SyncImpl(), checkSyncBatches(ctx, t, labels, provider, number.Int64Kind, sdkapi.CounterInstrumentKind, c.SyncImpl(),
42, 4200, 420000, 42, 420000,
) )
}) })
@ -277,11 +273,9 @@ func TestCounter(t *testing.T) {
ctx := context.Background() ctx := context.Background()
labels := []attribute.KeyValue{attribute.String("A", "B"), attribute.String("C", "D")} labels := []attribute.KeyValue{attribute.String("A", "B"), attribute.String("C", "D")}
c.Add(ctx, 100, labels...) c.Add(ctx, 100, labels...)
boundInstrument := c.Bind(labels...)
boundInstrument.Add(ctx, -100)
meter.RecordBatch(ctx, labels, c.Measurement(42)) meter.RecordBatch(ctx, labels, c.Measurement(42))
checkSyncBatches(ctx, t, labels, provider, number.Int64Kind, sdkapi.UpDownCounterInstrumentKind, c.SyncImpl(), checkSyncBatches(ctx, t, labels, provider, number.Int64Kind, sdkapi.UpDownCounterInstrumentKind, c.SyncImpl(),
100, -100, 42, 100, 42,
) )
}) })
t.Run("float64 updowncounter", func(t *testing.T) { t.Run("float64 updowncounter", func(t *testing.T) {
@ -290,11 +284,9 @@ func TestCounter(t *testing.T) {
ctx := context.Background() ctx := context.Background()
labels := []attribute.KeyValue{attribute.String("A", "B"), attribute.String("C", "D")} labels := []attribute.KeyValue{attribute.String("A", "B"), attribute.String("C", "D")}
c.Add(ctx, 100.1, labels...) c.Add(ctx, 100.1, labels...)
boundInstrument := c.Bind(labels...)
boundInstrument.Add(ctx, -76)
meter.RecordBatch(ctx, labels, c.Measurement(-100.1)) meter.RecordBatch(ctx, labels, c.Measurement(-100.1))
checkSyncBatches(ctx, t, labels, provider, number.Float64Kind, sdkapi.UpDownCounterInstrumentKind, c.SyncImpl(), checkSyncBatches(ctx, t, labels, provider, number.Float64Kind, sdkapi.UpDownCounterInstrumentKind, c.SyncImpl(),
100.1, -76, -100.1, 100.1, -100.1,
) )
}) })
} }
@ -306,11 +298,9 @@ func TestHistogram(t *testing.T) {
ctx := context.Background() ctx := context.Background()
labels := []attribute.KeyValue{} labels := []attribute.KeyValue{}
m.Record(ctx, 42, labels...) m.Record(ctx, 42, labels...)
boundInstrument := m.Bind(labels...)
boundInstrument.Record(ctx, 0)
meter.RecordBatch(ctx, labels, m.Measurement(-100.5)) meter.RecordBatch(ctx, labels, m.Measurement(-100.5))
checkSyncBatches(ctx, t, labels, provider, number.Float64Kind, sdkapi.HistogramInstrumentKind, m.SyncImpl(), checkSyncBatches(ctx, t, labels, provider, number.Float64Kind, sdkapi.HistogramInstrumentKind, m.SyncImpl(),
42, 0, -100.5, 42, -100.5,
) )
}) })
t.Run("int64 histogram", func(t *testing.T) { t.Run("int64 histogram", func(t *testing.T) {
@ -319,11 +309,9 @@ func TestHistogram(t *testing.T) {
ctx := context.Background() ctx := context.Background()
labels := []attribute.KeyValue{attribute.Int("I", 1)} labels := []attribute.KeyValue{attribute.Int("I", 1)}
m.Record(ctx, 173, labels...) m.Record(ctx, 173, labels...)
boundInstrument := m.Bind(labels...)
boundInstrument.Record(ctx, 80)
meter.RecordBatch(ctx, labels, m.Measurement(0)) meter.RecordBatch(ctx, labels, m.Measurement(0))
checkSyncBatches(ctx, t, labels, provider, number.Int64Kind, sdkapi.HistogramInstrumentKind, m.SyncImpl(), checkSyncBatches(ctx, t, labels, provider, number.Int64Kind, sdkapi.HistogramInstrumentKind, m.SyncImpl(),
173, 80, 0, 173, 0,
) )
}) })
} }

View File

@ -86,10 +86,9 @@ type (
) )
var ( var (
_ sdkapi.SyncImpl = &Sync{} _ sdkapi.SyncImpl = &Sync{}
_ sdkapi.BoundSyncImpl = &Handle{} _ sdkapi.MeterImpl = &MeterImpl{}
_ sdkapi.MeterImpl = &MeterImpl{} _ sdkapi.AsyncImpl = &Async{}
_ sdkapi.AsyncImpl = &Async{}
) )
// NewDescriptor is a test helper for constructing test metric // NewDescriptor is a test helper for constructing test metric
@ -111,13 +110,6 @@ func (s *Sync) Implementation() interface{} {
return s return s
} }
func (s *Sync) Bind(labels []attribute.KeyValue) sdkapi.BoundSyncImpl {
return &Handle{
Instrument: s,
Labels: labels,
}
}
func (s *Sync) RecordOne(ctx context.Context, number number.Number, labels []attribute.KeyValue) { func (s *Sync) RecordOne(ctx context.Context, number number.Number, labels []attribute.KeyValue) {
s.meter.doRecordSingle(ctx, labels, s, number) s.meter.doRecordSingle(ctx, labels, s, number)
} }

View File

@ -22,12 +22,10 @@ import (
) )
type noopInstrument struct{} type noopInstrument struct{}
type noopBoundInstrument struct{}
type noopSyncInstrument struct{ noopInstrument } type noopSyncInstrument struct{ noopInstrument }
type noopAsyncInstrument struct{ noopInstrument } type noopAsyncInstrument struct{ noopInstrument }
var _ SyncImpl = noopSyncInstrument{} var _ SyncImpl = noopSyncInstrument{}
var _ BoundSyncImpl = noopBoundInstrument{}
var _ AsyncImpl = noopAsyncInstrument{} var _ AsyncImpl = noopAsyncInstrument{}
// NewNoopSyncInstrument returns a No-op implementation of the // NewNoopSyncInstrument returns a No-op implementation of the
@ -50,15 +48,5 @@ func (noopInstrument) Descriptor() Descriptor {
return Descriptor{} return Descriptor{}
} }
func (noopBoundInstrument) RecordOne(context.Context, number.Number) {
}
func (noopBoundInstrument) Unbind() {
}
func (noopSyncInstrument) Bind([]attribute.KeyValue) BoundSyncImpl {
return noopBoundInstrument{}
}
func (noopSyncInstrument) RecordOne(context.Context, number.Number, []attribute.KeyValue) { func (noopSyncInstrument) RecordOne(context.Context, number.Number, []attribute.KeyValue) {
} }

View File

@ -58,26 +58,10 @@ type InstrumentImpl interface {
type SyncImpl interface { type SyncImpl interface {
InstrumentImpl InstrumentImpl
// Bind creates an implementation-level bound instrument,
// binding a label set with this instrument implementation.
Bind(labels []attribute.KeyValue) BoundSyncImpl
// RecordOne captures a single synchronous metric event. // RecordOne captures a single synchronous metric event.
RecordOne(ctx context.Context, number number.Number, labels []attribute.KeyValue) RecordOne(ctx context.Context, number number.Number, labels []attribute.KeyValue)
} }
// BoundSyncImpl is the implementation-level interface to a
// generic bound synchronous instrument
type BoundSyncImpl interface {
// RecordOne captures a single synchronous metric event.
RecordOne(ctx context.Context, number number.Number)
// Unbind frees the resources associated with this bound instrument. It
// does not affect the metric this bound instrument was created through.
Unbind()
}
// AsyncImpl is an implementation-level interface to an // AsyncImpl is an implementation-level interface to an
// asynchronous instrument (e.g., Observer instruments). // asynchronous instrument (e.g., Observer instruments).
type AsyncImpl interface { type AsyncImpl interface {

View File

@ -60,16 +60,6 @@ func (f *benchFixture) meterMust() metric.MeterMust {
return metric.Must(f.meter) return metric.Must(f.meter)
} }
func makeManyLabels(n int) [][]attribute.KeyValue {
r := make([][]attribute.KeyValue, n)
for i := 0; i < n; i++ {
r[i] = makeLabels(1)
}
return r
}
func makeLabels(n int) []attribute.KeyValue { func makeLabels(n int) []attribute.KeyValue {
used := map[string]bool{} used := map[string]bool{}
l := make([]attribute.KeyValue, n) l := make([]attribute.KeyValue, n)
@ -123,50 +113,6 @@ func BenchmarkInt64CounterAddWithLabels_16(b *testing.B) {
// Note: performance does not depend on label set size for the // Note: performance does not depend on label set size for the
// benchmarks below--all are benchmarked for a single attribute. // benchmarks below--all are benchmarked for a single attribute.
func BenchmarkAcquireNewHandle(b *testing.B) {
fix := newFixture(b)
labelSets := makeManyLabels(b.N)
cnt := fix.meterMust().NewInt64Counter("int64.sum")
b.ResetTimer()
for i := 0; i < b.N; i++ {
cnt.Bind(labelSets[i]...)
}
}
func BenchmarkAcquireExistingHandle(b *testing.B) {
fix := newFixture(b)
labelSets := makeManyLabels(b.N)
cnt := fix.meterMust().NewInt64Counter("int64.sum")
for i := 0; i < b.N; i++ {
cnt.Bind(labelSets[i]...).Unbind()
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
cnt.Bind(labelSets[i]...)
}
}
func BenchmarkAcquireReleaseExistingHandle(b *testing.B) {
fix := newFixture(b)
labelSets := makeManyLabels(b.N)
cnt := fix.meterMust().NewInt64Counter("int64.sum")
for i := 0; i < b.N; i++ {
cnt.Bind(labelSets[i]...).Unbind()
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
cnt.Bind(labelSets[i]...).Unbind()
}
}
// Iterators // Iterators
var benchmarkIteratorVar attribute.KeyValue var benchmarkIteratorVar attribute.KeyValue
@ -241,20 +187,6 @@ func BenchmarkInt64CounterAdd(b *testing.B) {
} }
} }
func BenchmarkInt64CounterHandleAdd(b *testing.B) {
ctx := context.Background()
fix := newFixture(b)
labs := makeLabels(1)
cnt := fix.meterMust().NewInt64Counter("int64.sum")
handle := cnt.Bind(labs...)
b.ResetTimer()
for i := 0; i < b.N; i++ {
handle.Add(ctx, 1)
}
}
func BenchmarkFloat64CounterAdd(b *testing.B) { func BenchmarkFloat64CounterAdd(b *testing.B) {
ctx := context.Background() ctx := context.Background()
fix := newFixture(b) fix := newFixture(b)
@ -268,20 +200,6 @@ func BenchmarkFloat64CounterAdd(b *testing.B) {
} }
} }
func BenchmarkFloat64CounterHandleAdd(b *testing.B) {
ctx := context.Background()
fix := newFixture(b)
labs := makeLabels(1)
cnt := fix.meterMust().NewFloat64Counter("float64.sum")
handle := cnt.Bind(labs...)
b.ResetTimer()
for i := 0; i < b.N; i++ {
handle.Add(ctx, 1.1)
}
}
// LastValue // LastValue
func BenchmarkInt64LastValueAdd(b *testing.B) { func BenchmarkInt64LastValueAdd(b *testing.B) {
@ -297,20 +215,6 @@ func BenchmarkInt64LastValueAdd(b *testing.B) {
} }
} }
func BenchmarkInt64LastValueHandleAdd(b *testing.B) {
ctx := context.Background()
fix := newFixture(b)
labs := makeLabels(1)
mea := fix.meterMust().NewInt64Histogram("int64.lastvalue")
handle := mea.Bind(labs...)
b.ResetTimer()
for i := 0; i < b.N; i++ {
handle.Record(ctx, int64(i))
}
}
func BenchmarkFloat64LastValueAdd(b *testing.B) { func BenchmarkFloat64LastValueAdd(b *testing.B) {
ctx := context.Background() ctx := context.Background()
fix := newFixture(b) fix := newFixture(b)
@ -324,20 +228,6 @@ func BenchmarkFloat64LastValueAdd(b *testing.B) {
} }
} }
func BenchmarkFloat64LastValueHandleAdd(b *testing.B) {
ctx := context.Background()
fix := newFixture(b)
labs := makeLabels(1)
mea := fix.meterMust().NewFloat64Histogram("float64.lastvalue")
handle := mea.Bind(labs...)
b.ResetTimer()
for i := 0; i < b.N; i++ {
handle.Record(ctx, float64(i))
}
}
// Histograms // Histograms
func benchmarkInt64HistogramAdd(b *testing.B, name string) { func benchmarkInt64HistogramAdd(b *testing.B, name string) {
@ -353,20 +243,6 @@ func benchmarkInt64HistogramAdd(b *testing.B, name string) {
} }
} }
func benchmarkInt64HistogramHandleAdd(b *testing.B, name string) {
ctx := context.Background()
fix := newFixture(b)
labs := makeLabels(1)
mea := fix.meterMust().NewInt64Histogram(name)
handle := mea.Bind(labs...)
b.ResetTimer()
for i := 0; i < b.N; i++ {
handle.Record(ctx, int64(i))
}
}
func benchmarkFloat64HistogramAdd(b *testing.B, name string) { func benchmarkFloat64HistogramAdd(b *testing.B, name string) {
ctx := context.Background() ctx := context.Background()
fix := newFixture(b) fix := newFixture(b)
@ -380,20 +256,6 @@ func benchmarkFloat64HistogramAdd(b *testing.B, name string) {
} }
} }
func benchmarkFloat64HistogramHandleAdd(b *testing.B, name string) {
ctx := context.Background()
fix := newFixture(b)
labs := makeLabels(1)
mea := fix.meterMust().NewFloat64Histogram(name)
handle := mea.Bind(labs...)
b.ResetTimer()
for i := 0; i < b.N; i++ {
handle.Record(ctx, float64(i))
}
}
// Observers // Observers
func BenchmarkObserverRegistration(b *testing.B) { func BenchmarkObserverRegistration(b *testing.B) {
@ -447,36 +309,20 @@ func BenchmarkInt64MaxSumCountAdd(b *testing.B) {
benchmarkInt64HistogramAdd(b, "int64.minmaxsumcount") benchmarkInt64HistogramAdd(b, "int64.minmaxsumcount")
} }
func BenchmarkInt64MaxSumCountHandleAdd(b *testing.B) {
benchmarkInt64HistogramHandleAdd(b, "int64.minmaxsumcount")
}
func BenchmarkFloat64MaxSumCountAdd(b *testing.B) { func BenchmarkFloat64MaxSumCountAdd(b *testing.B) {
benchmarkFloat64HistogramAdd(b, "float64.minmaxsumcount") benchmarkFloat64HistogramAdd(b, "float64.minmaxsumcount")
} }
func BenchmarkFloat64MaxSumCountHandleAdd(b *testing.B) {
benchmarkFloat64HistogramHandleAdd(b, "float64.minmaxsumcount")
}
// Exact // Exact
func BenchmarkInt64ExactAdd(b *testing.B) { func BenchmarkInt64ExactAdd(b *testing.B) {
benchmarkInt64HistogramAdd(b, "int64.exact") benchmarkInt64HistogramAdd(b, "int64.exact")
} }
func BenchmarkInt64ExactHandleAdd(b *testing.B) {
benchmarkInt64HistogramHandleAdd(b, "int64.exact")
}
func BenchmarkFloat64ExactAdd(b *testing.B) { func BenchmarkFloat64ExactAdd(b *testing.B) {
benchmarkFloat64HistogramAdd(b, "float64.exact") benchmarkFloat64HistogramAdd(b, "float64.exact")
} }
func BenchmarkFloat64ExactHandleAdd(b *testing.B) {
benchmarkFloat64HistogramHandleAdd(b, "float64.exact")
}
// BatchRecord // BatchRecord
func benchmarkBatchRecord8Labels(b *testing.B, numInst int) { func benchmarkBatchRecord8Labels(b *testing.B, numInst int) {

View File

@ -483,16 +483,14 @@ func TestRecordPersistence(t *testing.T) {
meter, sdk, selector, _ := newSDK(t) meter, sdk, selector, _ := newSDK(t)
c := Must(meter).NewFloat64Counter("name.sum") c := Must(meter).NewFloat64Counter("name.sum")
b := c.Bind(attribute.String("bound", "true"))
uk := attribute.String("bound", "false") uk := attribute.String("bound", "false")
for i := 0; i < 100; i++ { for i := 0; i < 100; i++ {
c.Add(ctx, 1, uk) c.Add(ctx, 1, uk)
b.Add(ctx, 1)
sdk.Collect(ctx) sdk.Collect(ctx)
} }
require.Equal(t, 4, selector.newAggCount) require.Equal(t, 2, selector.newAggCount)
} }
func TestIncorrectInstruments(t *testing.T) { func TestIncorrectInstruments(t *testing.T) {

View File

@ -28,9 +28,7 @@ and asynchronous instruments. There are two constructors per instrument for
the two kinds of number (int64, float64). the two kinds of number (int64, float64).
Synchronous instruments are managed by a sync.Map containing a *record Synchronous instruments are managed by a sync.Map containing a *record
with the current state for each synchronous instrument. A bound with the current state for each synchronous instrument. A lock-free
instrument encapsulates a direct pointer to the record, allowing
bound metric events to bypass a sync.Map lookup. A lock-free
algorithm is used to protect against races when adding and removing algorithm is used to protect against races when adding and removing
items from the sync.Map. items from the sync.Map.
@ -45,7 +43,7 @@ record contains a set of recorders for every specific label set used in the
callback. callback.
A sync.Map maintains the mapping of current instruments and label sets to A sync.Map maintains the mapping of current instruments and label sets to
internal records. To create a new bound instrument, the SDK consults the Map to internal records. To find a record, the SDK consults the Map to
locate an existing record, otherwise it constructs a new record. The SDK locate an existing record, otherwise it constructs a new record. The SDK
maintains a count of the number of references to each record, ensuring maintains a count of the number of references to each record, ensuring
that records are not reclaimed from the Map while they are still active that records are not reclaimed from the Map while they are still active

View File

@ -138,10 +138,9 @@ type (
) )
var ( var (
_ sdkapi.MeterImpl = &Accumulator{} _ sdkapi.MeterImpl = &Accumulator{}
_ sdkapi.AsyncImpl = &asyncInstrument{} _ sdkapi.AsyncImpl = &asyncInstrument{}
_ sdkapi.SyncImpl = &syncInstrument{} _ sdkapi.SyncImpl = &syncInstrument{}
_ sdkapi.BoundSyncImpl = &record{}
// ErrUninitializedInstrument is returned when an instrument is used when uninitialized. // ErrUninitializedInstrument is returned when an instrument is used when uninitialized.
ErrUninitializedInstrument = fmt.Errorf("use of an uninitialized instrument") ErrUninitializedInstrument = fmt.Errorf("use of an uninitialized instrument")
@ -279,15 +278,10 @@ func (s *syncInstrument) acquireHandle(kvs []attribute.KeyValue, labelPtr *attri
} }
} }
// The order of the input array `kvs` may be sorted after the function is called.
func (s *syncInstrument) Bind(kvs []attribute.KeyValue) sdkapi.BoundSyncImpl {
return s.acquireHandle(kvs, nil)
}
// The order of the input array `kvs` may be sorted after the function is called. // The order of the input array `kvs` may be sorted after the function is called.
func (s *syncInstrument) RecordOne(ctx context.Context, num number.Number, kvs []attribute.KeyValue) { func (s *syncInstrument) RecordOne(ctx context.Context, num number.Number, kvs []attribute.KeyValue) {
h := s.acquireHandle(kvs, nil) h := s.acquireHandle(kvs, nil)
defer h.Unbind() defer h.unbind()
h.RecordOne(ctx, num) h.RecordOne(ctx, num)
} }
@ -490,7 +484,7 @@ func (m *Accumulator) RecordBatch(ctx context.Context, kvs []attribute.KeyValue,
labelsPtr = h.labels labelsPtr = h.labels
} }
defer h.Unbind() defer h.unbind()
h.RecordOne(ctx, meas.Number()) h.RecordOne(ctx, meas.Number())
} }
} }
@ -514,8 +508,7 @@ func (r *record) RecordOne(ctx context.Context, num number.Number) {
atomic.AddInt64(&r.updateCount, 1) atomic.AddInt64(&r.updateCount, 1)
} }
// Unbind implements sdkapi.SyncImpl. func (r *record) unbind() {
func (r *record) Unbind() {
r.refMapped.unref() r.refMapped.unref()
} }