-
Notifications
You must be signed in to change notification settings - Fork 31
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improve events heap allocations #27
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -28,18 +28,28 @@ func NewEventManager() *EventManager { | |
return &EventManager{EmptyEvents()} | ||
} | ||
|
||
// Increase Capacity increases the capacity of the EventManager, | ||
// which is quite useful when many events are planned to be created. | ||
func (em *EventManager) IncreaseCapacity(capacity int) { | ||
events := em.events.getUnderlyingSlice() | ||
if cap(events) < capacity { | ||
em.events = make(Events, 0, capacity) | ||
em.events = append(em.events, events...) | ||
} | ||
} | ||
|
||
func (em *EventManager) Events() Events { return em.events } | ||
|
||
// EmitEvent stores a single Event object. | ||
// Deprecated: Use EmitTypedEvent | ||
func (em *EventManager) EmitEvent(event Event) { | ||
em.events = em.events.AppendEvent(event) | ||
em.events = append(em.events, event) | ||
} | ||
|
||
// EmitEvents stores a series of Event objects. | ||
// Deprecated: Use EmitTypedEvents | ||
func (em *EventManager) EmitEvents(events Events) { | ||
em.events = em.events.AppendEvents(events) | ||
em.events = append(em.events, events...) | ||
} | ||
|
||
// ABCIEvents returns all stored Event objects as abci.Event objects. | ||
|
@@ -153,7 +163,10 @@ type ( | |
// NewEvent creates a new Event object with a given type and slice of one or more | ||
// attributes. | ||
func NewEvent(ty string, attrs ...Attribute) Event { | ||
e := Event{Type: ty} | ||
e := Event{ | ||
Type: ty, | ||
Attributes: make([]abci.EventAttribute, 0, len(attrs)), | ||
} | ||
|
||
for _, attr := range attrs { | ||
e.Attributes = append(e.Attributes, attr.ToKVPair()) | ||
|
@@ -178,7 +191,7 @@ func (a Attribute) String() string { | |
|
||
// ToKVPair converts an Attribute object into a Tendermint key/value pair. | ||
func (a Attribute) ToKVPair() abci.EventAttribute { | ||
return abci.EventAttribute{Key: toBytes(a.Key), Value: toBytes(a.Value)} | ||
return abci.EventAttribute{Key: []byte(a.Key), Value: []byte(a.Value)} | ||
} | ||
|
||
// AppendAttributes adds one or more attributes to an Event. | ||
|
@@ -210,15 +223,9 @@ func (e Events) ToABCIEvents() []abci.Event { | |
return res | ||
} | ||
|
||
func toBytes(i interface{}) []byte { | ||
switch x := i.(type) { | ||
case []uint8: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I assume this case is never actually used? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, and it was bad to be casting to interface and then reflecting. |
||
return x | ||
case string: | ||
return []byte(x) | ||
default: | ||
panic(i) | ||
} | ||
// getUnderlyingSlice converts Events to its underlying []Event | ||
func (e Events) getUnderlyingSlice() []Event { | ||
return e | ||
} | ||
|
||
// Common event types and attribute keys | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -138,18 +138,16 @@ func (k BaseSendKeeper) InputOutputCoins(ctx sdk.Context, inputs []types.Input, | |
// SendCoins transfers amt coins from a sending account to a receiving account. | ||
// An error is returned upon failure. | ||
func (k BaseSendKeeper) SendCoins(ctx sdk.Context, fromAddr sdk.AccAddress, toAddr sdk.AccAddress, amt sdk.Coins) error { | ||
ctx.EventManager().EmitEvents(sdk.Events{ | ||
sdk.NewEvent( | ||
types.EventTypeTransfer, | ||
sdk.NewAttribute(types.AttributeKeyRecipient, toAddr.String()), | ||
sdk.NewAttribute(types.AttributeKeySender, fromAddr.String()), | ||
sdk.NewAttribute(sdk.AttributeKeyAmount, amt.String()), | ||
), | ||
sdk.NewEvent( | ||
sdk.EventTypeMessage, | ||
sdk.NewAttribute(types.AttributeKeySender, fromAddr.String()), | ||
), | ||
}) | ||
ctx.EventManager().EmitEvent(sdk.NewEvent( | ||
types.EventTypeTransfer, | ||
sdk.NewAttribute(types.AttributeKeyRecipient, toAddr.String()), | ||
sdk.NewAttribute(types.AttributeKeySender, fromAddr.String()), | ||
sdk.NewAttribute(sdk.AttributeKeyAmount, amt.String()), | ||
)) | ||
ctx.EventManager().EmitEvent(sdk.NewEvent( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Kind of annoying, but this also actually improved performance of the entire benchmark by a couple percent, and moreso the event sub-set of it. It avoids extra heap allocations on the argument, and then avoids a slice copy, instead you just append a stack element. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm is the extra There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh wait, you're not actually getting rid of it lol, just separating it into two EmitEvents. The diff got cut off lol. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ah woops, I should've copied more of the diff in the comment |
||
sdk.EventTypeMessage, | ||
sdk.NewAttribute(types.AttributeKeySender, fromAddr.String()), | ||
)) | ||
|
||
err := k.SubtractCoins(ctx, fromAddr, amt) | ||
if err != nil { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This had a signficant impact on performance!
However its still silly that we have to keep re-allocating heap space for the keys, when ~all the time, they are actually constants.
I think we should change the data-backend here to be using
[]byte
, at least until abci events use strings.