feat(tools/benchmark): introduce benchmark module (#24021)

Co-authored-by: Alex | Interchain Labs <alex@interchainlabs.io>
This commit is contained in:
Đông Liều 2025-03-20 21:56:03 +07:00 committed by GitHub
parent 8bf5430d7e
commit 9539caae6e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
19 changed files with 7451 additions and 0 deletions

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,928 @@
// Code generated by protoc-gen-go-pulsar. DO NOT EDIT.
package benchmarkv1
import (
fmt "fmt"
runtime "github.com/cosmos/cosmos-proto/runtime"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoiface "google.golang.org/protobuf/runtime/protoiface"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
io "io"
reflect "reflect"
sync "sync"
)
var (
md_Op protoreflect.MessageDescriptor
fd_Op_seed protoreflect.FieldDescriptor
fd_Op_actor protoreflect.FieldDescriptor
fd_Op_key_length protoreflect.FieldDescriptor
fd_Op_value_length protoreflect.FieldDescriptor
fd_Op_iterations protoreflect.FieldDescriptor
fd_Op_delete protoreflect.FieldDescriptor
fd_Op_exists protoreflect.FieldDescriptor
)
func init() {
file_cosmos_benchmark_v1_benchmark_proto_init()
md_Op = File_cosmos_benchmark_v1_benchmark_proto.Messages().ByName("Op")
fd_Op_seed = md_Op.Fields().ByName("seed")
fd_Op_actor = md_Op.Fields().ByName("actor")
fd_Op_key_length = md_Op.Fields().ByName("key_length")
fd_Op_value_length = md_Op.Fields().ByName("value_length")
fd_Op_iterations = md_Op.Fields().ByName("iterations")
fd_Op_delete = md_Op.Fields().ByName("delete")
fd_Op_exists = md_Op.Fields().ByName("exists")
}
var _ protoreflect.Message = (*fastReflection_Op)(nil)
type fastReflection_Op Op
func (x *Op) ProtoReflect() protoreflect.Message {
return (*fastReflection_Op)(x)
}
func (x *Op) slowProtoReflect() protoreflect.Message {
mi := &file_cosmos_benchmark_v1_benchmark_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
var _fastReflection_Op_messageType fastReflection_Op_messageType
var _ protoreflect.MessageType = fastReflection_Op_messageType{}
type fastReflection_Op_messageType struct{}
func (x fastReflection_Op_messageType) Zero() protoreflect.Message {
return (*fastReflection_Op)(nil)
}
func (x fastReflection_Op_messageType) New() protoreflect.Message {
return new(fastReflection_Op)
}
func (x fastReflection_Op_messageType) Descriptor() protoreflect.MessageDescriptor {
return md_Op
}
// Descriptor returns message descriptor, which contains only the protobuf
// type information for the message.
func (x *fastReflection_Op) Descriptor() protoreflect.MessageDescriptor {
return md_Op
}
// Type returns the message type, which encapsulates both Go and protobuf
// type information. If the Go type information is not needed,
// it is recommended that the message descriptor be used instead.
func (x *fastReflection_Op) Type() protoreflect.MessageType {
return _fastReflection_Op_messageType
}
// New returns a newly allocated and mutable empty message.
func (x *fastReflection_Op) New() protoreflect.Message {
return new(fastReflection_Op)
}
// Interface unwraps the message reflection interface and
// returns the underlying ProtoMessage interface.
func (x *fastReflection_Op) Interface() protoreflect.ProtoMessage {
return (*Op)(x)
}
// Range iterates over every populated field in an undefined order,
// calling f for each field descriptor and value encountered.
// Range returns immediately if f returns false.
// While iterating, mutating operations may only be performed
// on the current field descriptor.
func (x *fastReflection_Op) Range(f func(protoreflect.FieldDescriptor, protoreflect.Value) bool) {
if x.Seed != uint64(0) {
value := protoreflect.ValueOfUint64(x.Seed)
if !f(fd_Op_seed, value) {
return
}
}
if x.Actor != "" {
value := protoreflect.ValueOfString(x.Actor)
if !f(fd_Op_actor, value) {
return
}
}
if x.KeyLength != uint64(0) {
value := protoreflect.ValueOfUint64(x.KeyLength)
if !f(fd_Op_key_length, value) {
return
}
}
if x.ValueLength != uint64(0) {
value := protoreflect.ValueOfUint64(x.ValueLength)
if !f(fd_Op_value_length, value) {
return
}
}
if x.Iterations != uint32(0) {
value := protoreflect.ValueOfUint32(x.Iterations)
if !f(fd_Op_iterations, value) {
return
}
}
if x.Delete != false {
value := protoreflect.ValueOfBool(x.Delete)
if !f(fd_Op_delete, value) {
return
}
}
if x.Exists != false {
value := protoreflect.ValueOfBool(x.Exists)
if !f(fd_Op_exists, value) {
return
}
}
}
// Has reports whether a field is populated.
//
// Some fields have the property of nullability where it is possible to
// distinguish between the default value of a field and whether the field
// was explicitly populated with the default value. Singular message fields,
// member fields of a oneof, and proto2 scalar fields are nullable. Such
// fields are populated only if explicitly set.
//
// In other cases (aside from the nullable cases above),
// a proto3 scalar field is populated if it contains a non-zero value, and
// a repeated field is populated if it is non-empty.
func (x *fastReflection_Op) Has(fd protoreflect.FieldDescriptor) bool {
switch fd.FullName() {
case "cosmos.benchmark.v1.Op.seed":
return x.Seed != uint64(0)
case "cosmos.benchmark.v1.Op.actor":
return x.Actor != ""
case "cosmos.benchmark.v1.Op.key_length":
return x.KeyLength != uint64(0)
case "cosmos.benchmark.v1.Op.value_length":
return x.ValueLength != uint64(0)
case "cosmos.benchmark.v1.Op.iterations":
return x.Iterations != uint32(0)
case "cosmos.benchmark.v1.Op.delete":
return x.Delete != false
case "cosmos.benchmark.v1.Op.exists":
return x.Exists != false
default:
if fd.IsExtension() {
panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.benchmark.v1.Op"))
}
panic(fmt.Errorf("message cosmos.benchmark.v1.Op does not contain field %s", fd.FullName()))
}
}
// Clear clears the field such that a subsequent Has call reports false.
//
// Clearing an extension field clears both the extension type and value
// associated with the given field number.
//
// Clear is a mutating operation and unsafe for concurrent use.
func (x *fastReflection_Op) Clear(fd protoreflect.FieldDescriptor) {
switch fd.FullName() {
case "cosmos.benchmark.v1.Op.seed":
x.Seed = uint64(0)
case "cosmos.benchmark.v1.Op.actor":
x.Actor = ""
case "cosmos.benchmark.v1.Op.key_length":
x.KeyLength = uint64(0)
case "cosmos.benchmark.v1.Op.value_length":
x.ValueLength = uint64(0)
case "cosmos.benchmark.v1.Op.iterations":
x.Iterations = uint32(0)
case "cosmos.benchmark.v1.Op.delete":
x.Delete = false
case "cosmos.benchmark.v1.Op.exists":
x.Exists = false
default:
if fd.IsExtension() {
panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.benchmark.v1.Op"))
}
panic(fmt.Errorf("message cosmos.benchmark.v1.Op does not contain field %s", fd.FullName()))
}
}
// Get retrieves the value for a field.
//
// For unpopulated scalars, it returns the default value, where
// the default value of a bytes scalar is guaranteed to be a copy.
// For unpopulated composite types, it returns an empty, read-only view
// of the value; to obtain a mutable reference, use Mutable.
func (x *fastReflection_Op) Get(descriptor protoreflect.FieldDescriptor) protoreflect.Value {
switch descriptor.FullName() {
case "cosmos.benchmark.v1.Op.seed":
value := x.Seed
return protoreflect.ValueOfUint64(value)
case "cosmos.benchmark.v1.Op.actor":
value := x.Actor
return protoreflect.ValueOfString(value)
case "cosmos.benchmark.v1.Op.key_length":
value := x.KeyLength
return protoreflect.ValueOfUint64(value)
case "cosmos.benchmark.v1.Op.value_length":
value := x.ValueLength
return protoreflect.ValueOfUint64(value)
case "cosmos.benchmark.v1.Op.iterations":
value := x.Iterations
return protoreflect.ValueOfUint32(value)
case "cosmos.benchmark.v1.Op.delete":
value := x.Delete
return protoreflect.ValueOfBool(value)
case "cosmos.benchmark.v1.Op.exists":
value := x.Exists
return protoreflect.ValueOfBool(value)
default:
if descriptor.IsExtension() {
panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.benchmark.v1.Op"))
}
panic(fmt.Errorf("message cosmos.benchmark.v1.Op does not contain field %s", descriptor.FullName()))
}
}
// Set stores the value for a field.
//
// For a field belonging to a oneof, it implicitly clears any other field
// that may be currently set within the same oneof.
// For extension fields, it implicitly stores the provided ExtensionType.
// When setting a composite type, it is unspecified whether the stored value
// aliases the source's memory in any way. If the composite value is an
// empty, read-only value, then it panics.
//
// Set is a mutating operation and unsafe for concurrent use.
func (x *fastReflection_Op) Set(fd protoreflect.FieldDescriptor, value protoreflect.Value) {
switch fd.FullName() {
case "cosmos.benchmark.v1.Op.seed":
x.Seed = value.Uint()
case "cosmos.benchmark.v1.Op.actor":
x.Actor = value.Interface().(string)
case "cosmos.benchmark.v1.Op.key_length":
x.KeyLength = value.Uint()
case "cosmos.benchmark.v1.Op.value_length":
x.ValueLength = value.Uint()
case "cosmos.benchmark.v1.Op.iterations":
x.Iterations = uint32(value.Uint())
case "cosmos.benchmark.v1.Op.delete":
x.Delete = value.Bool()
case "cosmos.benchmark.v1.Op.exists":
x.Exists = value.Bool()
default:
if fd.IsExtension() {
panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.benchmark.v1.Op"))
}
panic(fmt.Errorf("message cosmos.benchmark.v1.Op does not contain field %s", fd.FullName()))
}
}
// Mutable returns a mutable reference to a composite type.
//
// If the field is unpopulated, it may allocate a composite value.
// For a field belonging to a oneof, it implicitly clears any other field
// that may be currently set within the same oneof.
// For extension fields, it implicitly stores the provided ExtensionType
// if not already stored.
// It panics if the field does not contain a composite type.
//
// Mutable is a mutating operation and unsafe for concurrent use.
func (x *fastReflection_Op) Mutable(fd protoreflect.FieldDescriptor) protoreflect.Value {
switch fd.FullName() {
case "cosmos.benchmark.v1.Op.seed":
panic(fmt.Errorf("field seed of message cosmos.benchmark.v1.Op is not mutable"))
case "cosmos.benchmark.v1.Op.actor":
panic(fmt.Errorf("field actor of message cosmos.benchmark.v1.Op is not mutable"))
case "cosmos.benchmark.v1.Op.key_length":
panic(fmt.Errorf("field key_length of message cosmos.benchmark.v1.Op is not mutable"))
case "cosmos.benchmark.v1.Op.value_length":
panic(fmt.Errorf("field value_length of message cosmos.benchmark.v1.Op is not mutable"))
case "cosmos.benchmark.v1.Op.iterations":
panic(fmt.Errorf("field iterations of message cosmos.benchmark.v1.Op is not mutable"))
case "cosmos.benchmark.v1.Op.delete":
panic(fmt.Errorf("field delete of message cosmos.benchmark.v1.Op is not mutable"))
case "cosmos.benchmark.v1.Op.exists":
panic(fmt.Errorf("field exists of message cosmos.benchmark.v1.Op is not mutable"))
default:
if fd.IsExtension() {
panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.benchmark.v1.Op"))
}
panic(fmt.Errorf("message cosmos.benchmark.v1.Op does not contain field %s", fd.FullName()))
}
}
// NewField returns a new value that is assignable to the field
// for the given descriptor. For scalars, this returns the default value.
// For lists, maps, and messages, this returns a new, empty, mutable value.
func (x *fastReflection_Op) NewField(fd protoreflect.FieldDescriptor) protoreflect.Value {
switch fd.FullName() {
case "cosmos.benchmark.v1.Op.seed":
return protoreflect.ValueOfUint64(uint64(0))
case "cosmos.benchmark.v1.Op.actor":
return protoreflect.ValueOfString("")
case "cosmos.benchmark.v1.Op.key_length":
return protoreflect.ValueOfUint64(uint64(0))
case "cosmos.benchmark.v1.Op.value_length":
return protoreflect.ValueOfUint64(uint64(0))
case "cosmos.benchmark.v1.Op.iterations":
return protoreflect.ValueOfUint32(uint32(0))
case "cosmos.benchmark.v1.Op.delete":
return protoreflect.ValueOfBool(false)
case "cosmos.benchmark.v1.Op.exists":
return protoreflect.ValueOfBool(false)
default:
if fd.IsExtension() {
panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.benchmark.v1.Op"))
}
panic(fmt.Errorf("message cosmos.benchmark.v1.Op does not contain field %s", fd.FullName()))
}
}
// WhichOneof reports which field within the oneof is populated,
// returning nil if none are populated.
// It panics if the oneof descriptor does not belong to this message.
func (x *fastReflection_Op) WhichOneof(d protoreflect.OneofDescriptor) protoreflect.FieldDescriptor {
switch d.FullName() {
default:
panic(fmt.Errorf("%s is not a oneof field in cosmos.benchmark.v1.Op", d.FullName()))
}
panic("unreachable")
}
// GetUnknown retrieves the entire list of unknown fields.
// The caller may only mutate the contents of the RawFields
// if the mutated bytes are stored back into the message with SetUnknown.
func (x *fastReflection_Op) GetUnknown() protoreflect.RawFields {
return x.unknownFields
}
// SetUnknown stores an entire list of unknown fields.
// The raw fields must be syntactically valid according to the wire format.
// An implementation may panic if this is not the case.
// Once stored, the caller must not mutate the content of the RawFields.
// An empty RawFields may be passed to clear the fields.
//
// SetUnknown is a mutating operation and unsafe for concurrent use.
func (x *fastReflection_Op) SetUnknown(fields protoreflect.RawFields) {
x.unknownFields = fields
}
// IsValid reports whether the message is valid.
//
// An invalid message is an empty, read-only value.
//
// An invalid message often corresponds to a nil pointer of the concrete
// message type, but the details are implementation dependent.
// Validity is not part of the protobuf data model, and may not
// be preserved in marshaling or other operations.
func (x *fastReflection_Op) IsValid() bool {
return x != nil
}
// ProtoMethods returns optional fastReflectionFeature-path implementations of various operations.
// This method may return nil.
//
// The returned methods type is identical to
// "google.golang.org/protobuf/runtime/protoiface".Methods.
// Consult the protoiface package documentation for details.
func (x *fastReflection_Op) ProtoMethods() *protoiface.Methods {
size := func(input protoiface.SizeInput) protoiface.SizeOutput {
x := input.Message.Interface().(*Op)
if x == nil {
return protoiface.SizeOutput{
NoUnkeyedLiterals: input.NoUnkeyedLiterals,
Size: 0,
}
}
options := runtime.SizeInputToOptions(input)
_ = options
var n int
var l int
_ = l
if x.Seed != 0 {
n += 1 + runtime.Sov(uint64(x.Seed))
}
l = len(x.Actor)
if l > 0 {
n += 1 + l + runtime.Sov(uint64(l))
}
if x.KeyLength != 0 {
n += 1 + runtime.Sov(uint64(x.KeyLength))
}
if x.ValueLength != 0 {
n += 1 + runtime.Sov(uint64(x.ValueLength))
}
if x.Iterations != 0 {
n += 1 + runtime.Sov(uint64(x.Iterations))
}
if x.Delete {
n += 2
}
if x.Exists {
n += 2
}
if x.unknownFields != nil {
n += len(x.unknownFields)
}
return protoiface.SizeOutput{
NoUnkeyedLiterals: input.NoUnkeyedLiterals,
Size: n,
}
}
marshal := func(input protoiface.MarshalInput) (protoiface.MarshalOutput, error) {
x := input.Message.Interface().(*Op)
if x == nil {
return protoiface.MarshalOutput{
NoUnkeyedLiterals: input.NoUnkeyedLiterals,
Buf: input.Buf,
}, nil
}
options := runtime.MarshalInputToOptions(input)
_ = options
size := options.Size(x)
dAtA := make([]byte, size)
i := len(dAtA)
_ = i
var l int
_ = l
if x.unknownFields != nil {
i -= len(x.unknownFields)
copy(dAtA[i:], x.unknownFields)
}
if x.Exists {
i--
if x.Exists {
dAtA[i] = 1
} else {
dAtA[i] = 0
}
i--
dAtA[i] = 0x38
}
if x.Delete {
i--
if x.Delete {
dAtA[i] = 1
} else {
dAtA[i] = 0
}
i--
dAtA[i] = 0x30
}
if x.Iterations != 0 {
i = runtime.EncodeVarint(dAtA, i, uint64(x.Iterations))
i--
dAtA[i] = 0x28
}
if x.ValueLength != 0 {
i = runtime.EncodeVarint(dAtA, i, uint64(x.ValueLength))
i--
dAtA[i] = 0x20
}
if x.KeyLength != 0 {
i = runtime.EncodeVarint(dAtA, i, uint64(x.KeyLength))
i--
dAtA[i] = 0x18
}
if len(x.Actor) > 0 {
i -= len(x.Actor)
copy(dAtA[i:], x.Actor)
i = runtime.EncodeVarint(dAtA, i, uint64(len(x.Actor)))
i--
dAtA[i] = 0x12
}
if x.Seed != 0 {
i = runtime.EncodeVarint(dAtA, i, uint64(x.Seed))
i--
dAtA[i] = 0x8
}
if input.Buf != nil {
input.Buf = append(input.Buf, dAtA...)
} else {
input.Buf = dAtA
}
return protoiface.MarshalOutput{
NoUnkeyedLiterals: input.NoUnkeyedLiterals,
Buf: input.Buf,
}, nil
}
unmarshal := func(input protoiface.UnmarshalInput) (protoiface.UnmarshalOutput, error) {
x := input.Message.Interface().(*Op)
if x == nil {
return protoiface.UnmarshalOutput{
NoUnkeyedLiterals: input.NoUnkeyedLiterals,
Flags: input.Flags,
}, nil
}
options := runtime.UnmarshalInputToOptions(input)
_ = options
dAtA := input.Buf
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow
}
if iNdEx >= l {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: Op: wiretype end group for non-group")
}
if fieldNum <= 0 {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: Op: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 0 {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field Seed", wireType)
}
x.Seed = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow
}
if iNdEx >= l {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
x.Seed |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
case 2:
if wireType != 2 {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field Actor", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow
}
if iNdEx >= l {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength
}
postIndex := iNdEx + intStringLen
if postIndex < 0 {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength
}
if postIndex > l {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF
}
x.Actor = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 3:
if wireType != 0 {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field KeyLength", wireType)
}
x.KeyLength = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow
}
if iNdEx >= l {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
x.KeyLength |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
case 4:
if wireType != 0 {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field ValueLength", wireType)
}
x.ValueLength = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow
}
if iNdEx >= l {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
x.ValueLength |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
case 5:
if wireType != 0 {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field Iterations", wireType)
}
x.Iterations = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow
}
if iNdEx >= l {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
x.Iterations |= uint32(b&0x7F) << shift
if b < 0x80 {
break
}
}
case 6:
if wireType != 0 {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field Delete", wireType)
}
var v int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow
}
if iNdEx >= l {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
v |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
x.Delete = bool(v != 0)
case 7:
if wireType != 0 {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field Exists", wireType)
}
var v int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow
}
if iNdEx >= l {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
v |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
x.Exists = bool(v != 0)
default:
iNdEx = preIndex
skippy, err := runtime.Skip(dAtA[iNdEx:])
if err != nil {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err
}
if (skippy < 0) || (iNdEx+skippy) < 0 {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength
}
if (iNdEx + skippy) > l {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF
}
if !options.DiscardUnknown {
x.unknownFields = append(x.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)
}
iNdEx += skippy
}
}
if iNdEx > l {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF
}
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, nil
}
return &protoiface.Methods{
NoUnkeyedLiterals: struct{}{},
Flags: protoiface.SupportMarshalDeterministic | protoiface.SupportUnmarshalDiscardUnknown,
Size: size,
Marshal: marshal,
Unmarshal: unmarshal,
Merge: nil,
CheckInitialized: nil,
}
}
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.27.0
// protoc (unknown)
// source: cosmos/benchmark/v1/benchmark.proto
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
// Op is a message describing a benchmark operation.
type Op struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Seed uint64 `protobuf:"varint,1,opt,name=seed,proto3" json:"seed,omitempty"`
Actor string `protobuf:"bytes,2,opt,name=actor,proto3" json:"actor,omitempty"`
KeyLength uint64 `protobuf:"varint,3,opt,name=key_length,json=keyLength,proto3" json:"key_length,omitempty"`
ValueLength uint64 `protobuf:"varint,4,opt,name=value_length,json=valueLength,proto3" json:"value_length,omitempty"`
Iterations uint32 `protobuf:"varint,5,opt,name=iterations,proto3" json:"iterations,omitempty"`
Delete bool `protobuf:"varint,6,opt,name=delete,proto3" json:"delete,omitempty"`
Exists bool `protobuf:"varint,7,opt,name=exists,proto3" json:"exists,omitempty"`
}
func (x *Op) Reset() {
*x = Op{}
if protoimpl.UnsafeEnabled {
mi := &file_cosmos_benchmark_v1_benchmark_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Op) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Op) ProtoMessage() {}
// Deprecated: Use Op.ProtoReflect.Descriptor instead.
func (*Op) Descriptor() ([]byte, []int) {
return file_cosmos_benchmark_v1_benchmark_proto_rawDescGZIP(), []int{0}
}
func (x *Op) GetSeed() uint64 {
if x != nil {
return x.Seed
}
return 0
}
func (x *Op) GetActor() string {
if x != nil {
return x.Actor
}
return ""
}
func (x *Op) GetKeyLength() uint64 {
if x != nil {
return x.KeyLength
}
return 0
}
func (x *Op) GetValueLength() uint64 {
if x != nil {
return x.ValueLength
}
return 0
}
func (x *Op) GetIterations() uint32 {
if x != nil {
return x.Iterations
}
return 0
}
func (x *Op) GetDelete() bool {
if x != nil {
return x.Delete
}
return false
}
func (x *Op) GetExists() bool {
if x != nil {
return x.Exists
}
return false
}
var File_cosmos_benchmark_v1_benchmark_proto protoreflect.FileDescriptor
var file_cosmos_benchmark_v1_benchmark_proto_rawDesc = []byte{
0x0a, 0x23, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x62, 0x65, 0x6e, 0x63, 0x68, 0x6d, 0x61,
0x72, 0x6b, 0x2f, 0x76, 0x31, 0x2f, 0x62, 0x65, 0x6e, 0x63, 0x68, 0x6d, 0x61, 0x72, 0x6b, 0x2e,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x13, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x62, 0x65,
0x6e, 0x63, 0x68, 0x6d, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x22, 0xc0, 0x01, 0x0a, 0x02, 0x4f,
0x70, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x65, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52,
0x04, 0x73, 0x65, 0x65, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x02,
0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x1d, 0x0a, 0x0a, 0x6b,
0x65, 0x79, 0x5f, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52,
0x09, 0x6b, 0x65, 0x79, 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x12, 0x21, 0x0a, 0x0c, 0x76, 0x61,
0x6c, 0x75, 0x65, 0x5f, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04,
0x52, 0x0b, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x12, 0x1e, 0x0a,
0x0a, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28,
0x0d, 0x52, 0x0a, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x16, 0x0a,
0x06, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x64,
0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x65, 0x78, 0x69, 0x73, 0x74, 0x73, 0x18,
0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x65, 0x78, 0x69, 0x73, 0x74, 0x73, 0x42, 0xc9, 0x01,
0x0a, 0x17, 0x63, 0x6f, 0x6d, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x62, 0x65, 0x6e,
0x63, 0x68, 0x6d, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x42, 0x0e, 0x42, 0x65, 0x6e, 0x63, 0x68,
0x6d, 0x61, 0x72, 0x6b, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x30, 0x63, 0x6f, 0x73,
0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x63, 0x6f,
0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x62, 0x65, 0x6e, 0x63, 0x68, 0x6d, 0x61, 0x72, 0x6b, 0x2f, 0x76,
0x31, 0x3b, 0x62, 0x65, 0x6e, 0x63, 0x68, 0x6d, 0x61, 0x72, 0x6b, 0x76, 0x31, 0xa2, 0x02, 0x03,
0x43, 0x42, 0x58, 0xaa, 0x02, 0x13, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x42, 0x65, 0x6e,
0x63, 0x68, 0x6d, 0x61, 0x72, 0x6b, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x13, 0x43, 0x6f, 0x73, 0x6d,
0x6f, 0x73, 0x5c, 0x42, 0x65, 0x6e, 0x63, 0x68, 0x6d, 0x61, 0x72, 0x6b, 0x5c, 0x56, 0x31, 0xe2,
0x02, 0x1f, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x5c, 0x42, 0x65, 0x6e, 0x63, 0x68, 0x6d, 0x61,
0x72, 0x6b, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74,
0x61, 0xea, 0x02, 0x15, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x3a, 0x3a, 0x42, 0x65, 0x6e, 0x63,
0x68, 0x6d, 0x61, 0x72, 0x6b, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x33,
}
var (
file_cosmos_benchmark_v1_benchmark_proto_rawDescOnce sync.Once
file_cosmos_benchmark_v1_benchmark_proto_rawDescData = file_cosmos_benchmark_v1_benchmark_proto_rawDesc
)
func file_cosmos_benchmark_v1_benchmark_proto_rawDescGZIP() []byte {
file_cosmos_benchmark_v1_benchmark_proto_rawDescOnce.Do(func() {
file_cosmos_benchmark_v1_benchmark_proto_rawDescData = protoimpl.X.CompressGZIP(file_cosmos_benchmark_v1_benchmark_proto_rawDescData)
})
return file_cosmos_benchmark_v1_benchmark_proto_rawDescData
}
var file_cosmos_benchmark_v1_benchmark_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
var file_cosmos_benchmark_v1_benchmark_proto_goTypes = []interface{}{
(*Op)(nil), // 0: cosmos.benchmark.v1.Op
}
var file_cosmos_benchmark_v1_benchmark_proto_depIdxs = []int32{
0, // [0:0] is the sub-list for method output_type
0, // [0:0] is the sub-list for method input_type
0, // [0:0] is the sub-list for extension type_name
0, // [0:0] is the sub-list for extension extendee
0, // [0:0] is the sub-list for field type_name
}
func init() { file_cosmos_benchmark_v1_benchmark_proto_init() }
func file_cosmos_benchmark_v1_benchmark_proto_init() {
if File_cosmos_benchmark_v1_benchmark_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_cosmos_benchmark_v1_benchmark_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Op); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_cosmos_benchmark_v1_benchmark_proto_rawDesc,
NumEnums: 0,
NumMessages: 1,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_cosmos_benchmark_v1_benchmark_proto_goTypes,
DependencyIndexes: file_cosmos_benchmark_v1_benchmark_proto_depIdxs,
MessageInfos: file_cosmos_benchmark_v1_benchmark_proto_msgTypes,
}.Build()
File_cosmos_benchmark_v1_benchmark_proto = out.File
file_cosmos_benchmark_v1_benchmark_proto_rawDesc = nil
file_cosmos_benchmark_v1_benchmark_proto_goTypes = nil
file_cosmos_benchmark_v1_benchmark_proto_depIdxs = nil
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,127 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.5.1
// - protoc (unknown)
// source: cosmos/benchmark/v1/tx.proto
package benchmarkv1
import (
context "context"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
)
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
// Requires gRPC-Go v1.64.0 or later.
const _ = grpc.SupportPackageIsVersion9
const (
Msg_LoadTest_FullMethodName = "/cosmos.benchmark.v1.Msg/LoadTest"
)
// MsgClient is the client API for Msg service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
//
// Msg defines the benchmark Msg service.
type MsgClient interface {
// LoadTest defines a method for executing a sequence of load test operations.
LoadTest(ctx context.Context, in *MsgLoadTest, opts ...grpc.CallOption) (*MsgLoadTestResponse, error)
}
type msgClient struct {
cc grpc.ClientConnInterface
}
func NewMsgClient(cc grpc.ClientConnInterface) MsgClient {
return &msgClient{cc}
}
func (c *msgClient) LoadTest(ctx context.Context, in *MsgLoadTest, opts ...grpc.CallOption) (*MsgLoadTestResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(MsgLoadTestResponse)
err := c.cc.Invoke(ctx, Msg_LoadTest_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
// MsgServer is the server API for Msg service.
// All implementations must embed UnimplementedMsgServer
// for forward compatibility.
//
// Msg defines the benchmark Msg service.
type MsgServer interface {
// LoadTest defines a method for executing a sequence of load test operations.
LoadTest(context.Context, *MsgLoadTest) (*MsgLoadTestResponse, error)
mustEmbedUnimplementedMsgServer()
}
// UnimplementedMsgServer must be embedded to have
// forward compatible implementations.
//
// NOTE: this should be embedded by value instead of pointer to avoid a nil
// pointer dereference when methods are called.
type UnimplementedMsgServer struct{}
func (UnimplementedMsgServer) LoadTest(context.Context, *MsgLoadTest) (*MsgLoadTestResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method LoadTest not implemented")
}
func (UnimplementedMsgServer) mustEmbedUnimplementedMsgServer() {}
func (UnimplementedMsgServer) testEmbeddedByValue() {}
// UnsafeMsgServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to MsgServer will
// result in compilation errors.
type UnsafeMsgServer interface {
mustEmbedUnimplementedMsgServer()
}
func RegisterMsgServer(s grpc.ServiceRegistrar, srv MsgServer) {
// If the following call pancis, it indicates UnimplementedMsgServer was
// embedded by pointer and is nil. This will cause panics if an
// unimplemented method is ever invoked, so we test this at initialization
// time to prevent it from happening at runtime later due to I/O.
if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
t.testEmbeddedByValue()
}
s.RegisterService(&Msg_ServiceDesc, srv)
}
func _Msg_LoadTest_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(MsgLoadTest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(MsgServer).LoadTest(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: Msg_LoadTest_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(MsgServer).LoadTest(ctx, req.(*MsgLoadTest))
}
return interceptor(ctx, in, info, handler)
}
// Msg_ServiceDesc is the grpc.ServiceDesc for Msg service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var Msg_ServiceDesc = grpc.ServiceDesc{
ServiceName: "cosmos.benchmark.v1.Msg",
HandlerType: (*MsgServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "LoadTest",
Handler: _Msg_LoadTest_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "cosmos/benchmark/v1/tx.proto",
}

View File

@ -0,0 +1,43 @@
syntax = "proto3";
package cosmos.benchmark.module.v1;
import "cosmos/app/v1alpha1/module.proto";
// Module is the config object of the benchmark module.
message Module {
option (cosmos.app.v1alpha1.module) = {
go_import: "cosmossdk.io/tools/benchmark"
};
GeneratorParams genesis_params = 1;
}
// GenesisParams defines the genesis parameters for the benchmark module.
message GeneratorParams {
// seed is the seed for the random number generator.
uint64 seed = 1;
// bucket_count is the number of store keys to uniformly distribute genesis_count keys across.
uint64 bucket_count = 2;
// key_mean is the mean size (in normal distribution) of keys in each bucket.
uint64 key_mean = 3;
// key_std_dev is the standard deviation of key sizes in each bucket.
uint64 key_std_dev = 4;
// value_mean is the mean size (in normal distribution) of values in each bucket.
uint64 value_mean = 6;
// value_std_dev is the standard deviation of value sizes in each bucket.
uint64 value_std_dev = 7;
// genesis_count is the number of keys to insert in the store, distributed across all buckets.
uint64 genesis_count = 8;
// insert_weight is the weight of insert operations.
float insert_weight = 9;
// update_weight is the weight of update operations.
float update_weight = 10;
// get_weight is the weight of get operations.
float get_weight = 12;
// delete_weight is the weight of delete operations.
float delete_weight = 11;
}

View File

@ -0,0 +1,17 @@
syntax = "proto3";
package cosmos.benchmark.v1;
option go_package = "cosmossdk.io/tools/benchmark";
// Op is a message describing a benchmark operation.
message Op {
uint64 seed = 1;
string actor = 2;
uint64 key_length = 3;
uint64 value_length = 4;
uint32 iterations = 5;
bool delete = 6;
bool exists = 7;
}

View File

@ -0,0 +1,33 @@
syntax = "proto3";
package cosmos.benchmark.v1;
import "cosmos/benchmark/v1/benchmark.proto";
import "cosmos/msg/v1/msg.proto";
import "amino/amino.proto";
option go_package = "cosmossdk.io/tools/benchmark";
// MsgLoadTestOps defines a message containing a sequence of load test operations.
message MsgLoadTest {
option (cosmos.msg.v1.signer) = "caller";
option (amino.name) = "cosmos-sdk/tools/benchmark/v1/MsgLoadTest";
bytes caller = 1;
repeated Op ops = 2;
}
// MsgLoadTestResponse defines a message containing the results of a load test operation.
message MsgLoadTestResponse {
uint64 total_time = 1;
uint64 total_errors = 2;
}
// Msg defines the benchmark Msg service.
service Msg {
option (cosmos.msg.v1.service) = true;
// LoadTest defines a method for executing a sequence of load test operations.
rpc LoadTest(MsgLoadTest) returns (MsgLoadTestResponse);
}

View File

@ -0,0 +1,30 @@
<!--
Guiding Principles:
Changelogs are for humans, not machines.
There should be an entry for every single version.
The same types of changes should be grouped.
Versions and sections should be linkable.
The latest version comes first.
The release date of each version is displayed.
Mention whether you follow Semantic Versioning.
Usage:
Change log entries are to be added to the Unreleased section under the
appropriate stanza (see below). Each entry should ideally include a tag and
the Github issue reference in the following format:
* (<tag>) [#<issue-number>] Changelog message.
Types of changes (Stanzas):
"Features" for new features.
"Improvements" for changes in existing functionality.
"Deprecated" for soon-to-be removed features.
"Bug Fixes" for any bug fixes.
"API Breaking" for breaking exported APIs used by developers building on SDK.
Ref: https://keepachangelog.com/en/1.0.0/
-->
# Changelog
## [Unreleased]
## [v0.2.0-rc.1](https://github.com/cosmos/cosmos-sdk/releases/tag/tools/benchmark/v0.2.0-rc.1) - 2024-12-18
* [#22778](https://github.com/cosmos/cosmos-sdk/pull/22778) - Initial commit

24
tools/benchmark/README.md Normal file
View File

@ -0,0 +1,24 @@
# cosmossdk.io/tools/benchmark
A benchmark module to test chain and storage performance. It can be used to holistically test
the end to end performance of a node. Given an initial configuration tools/benchmark provides:
* A possibly enormous sequence of key-value sets in InitGenesis distributed across n storekeys,
e.g. 20M keys across 5 store keys
* A client which syncs to genesis state then deterministically generates txs which contain a
configurable sequence of get, insert, update & delete operations
* A keeper which processes the above transactions and emits some telemetry data about them.
Client invocation looks like:
```bash
simdv2 tx benchmark load-test --from bob --yes --ops 1000 --pause 10 -v
```
On exit it dumps the generator state so that running again should still be in sync. It assumes
that any transaction accepted by the network was processed, which may not be the case, so miss
rate will probably increase over time. This isn't really a problem for tests.
Obviously this module is built to DOS a node by testing the upper bounds of chain performance;
when testing gas limits should be increased. It should not be included in chains by default but
is enabled in simapp for testing.

View File

@ -0,0 +1,545 @@
// Code generated by protoc-gen-gogo. DO NOT EDIT.
// source: cosmos/benchmark/v1/benchmark.proto
package benchmark
import (
fmt "fmt"
proto "github.com/cosmos/gogoproto/proto"
io "io"
math "math"
math_bits "math/bits"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package
// Op is a message describing a benchmark operation.
type Op struct {
Seed uint64 `protobuf:"varint,1,opt,name=seed,proto3" json:"seed,omitempty"`
Actor string `protobuf:"bytes,2,opt,name=actor,proto3" json:"actor,omitempty"`
KeyLength uint64 `protobuf:"varint,3,opt,name=key_length,json=keyLength,proto3" json:"key_length,omitempty"`
ValueLength uint64 `protobuf:"varint,4,opt,name=value_length,json=valueLength,proto3" json:"value_length,omitempty"`
Iterations uint32 `protobuf:"varint,5,opt,name=iterations,proto3" json:"iterations,omitempty"`
Delete bool `protobuf:"varint,6,opt,name=delete,proto3" json:"delete,omitempty"`
Exists bool `protobuf:"varint,7,opt,name=exists,proto3" json:"exists,omitempty"`
}
func (m *Op) Reset() { *m = Op{} }
func (m *Op) String() string { return proto.CompactTextString(m) }
func (*Op) ProtoMessage() {}
func (*Op) Descriptor() ([]byte, []int) {
return fileDescriptor_dca1624628907df9, []int{0}
}
func (m *Op) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
}
func (m *Op) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
if deterministic {
return xxx_messageInfo_Op.Marshal(b, m, deterministic)
} else {
b = b[:cap(b)]
n, err := m.MarshalToSizedBuffer(b)
if err != nil {
return nil, err
}
return b[:n], nil
}
}
func (m *Op) XXX_Merge(src proto.Message) {
xxx_messageInfo_Op.Merge(m, src)
}
func (m *Op) XXX_Size() int {
return m.Size()
}
func (m *Op) XXX_DiscardUnknown() {
xxx_messageInfo_Op.DiscardUnknown(m)
}
var xxx_messageInfo_Op proto.InternalMessageInfo
func (m *Op) GetSeed() uint64 {
if m != nil {
return m.Seed
}
return 0
}
func (m *Op) GetActor() string {
if m != nil {
return m.Actor
}
return ""
}
func (m *Op) GetKeyLength() uint64 {
if m != nil {
return m.KeyLength
}
return 0
}
func (m *Op) GetValueLength() uint64 {
if m != nil {
return m.ValueLength
}
return 0
}
func (m *Op) GetIterations() uint32 {
if m != nil {
return m.Iterations
}
return 0
}
func (m *Op) GetDelete() bool {
if m != nil {
return m.Delete
}
return false
}
func (m *Op) GetExists() bool {
if m != nil {
return m.Exists
}
return false
}
func init() {
proto.RegisterType((*Op)(nil), "cosmos.benchmark.v1.Op")
}
func init() {
proto.RegisterFile("cosmos/benchmark/v1/benchmark.proto", fileDescriptor_dca1624628907df9)
}
var fileDescriptor_dca1624628907df9 = []byte{
// 249 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x4c, 0x90, 0xb1, 0x4e, 0x84, 0x40,
0x10, 0x86, 0x99, 0x93, 0x43, 0x6f, 0xd4, 0x66, 0x35, 0x66, 0x0b, 0xdd, 0xa0, 0x36, 0x54, 0x90,
0x8b, 0x89, 0x0f, 0x60, 0x6d, 0x62, 0x42, 0x69, 0x63, 0x38, 0x98, 0x78, 0x04, 0x8e, 0xb9, 0xb0,
0x2b, 0xf1, 0xde, 0xc2, 0x47, 0xb2, 0xb4, 0xbc, 0xd2, 0xd2, 0xc0, 0x8b, 0x18, 0x77, 0xcf, 0x1c,
0xdd, 0x7c, 0x5f, 0xbe, 0x66, 0x7e, 0xbc, 0xcd, 0x59, 0xaf, 0x58, 0x27, 0x0b, 0x6a, 0xf2, 0xe5,
0x2a, 0x6b, 0xab, 0xa4, 0x9b, 0xef, 0x21, 0x5e, 0xb7, 0x6c, 0x58, 0x9c, 0xb9, 0x28, 0xde, 0xfb,
0x6e, 0x7e, 0xf3, 0x09, 0x38, 0x79, 0x5a, 0x0b, 0x81, 0xbe, 0x26, 0x2a, 0x24, 0x84, 0x10, 0xf9,
0xa9, 0xbd, 0xc5, 0x39, 0x4e, 0xb3, 0xdc, 0x70, 0x2b, 0x27, 0x21, 0x44, 0xb3, 0xd4, 0x81, 0xb8,
0x42, 0xac, 0x68, 0xf3, 0x52, 0x53, 0xf3, 0x6a, 0x96, 0xf2, 0xc0, 0xf6, 0xb3, 0x8a, 0x36, 0x8f,
0x56, 0x88, 0x6b, 0x3c, 0xe9, 0xb2, 0xfa, 0x8d, 0xfe, 0x03, 0xdf, 0x06, 0xc7, 0xd6, 0xed, 0x12,
0x85, 0x58, 0x1a, 0x6a, 0x33, 0x53, 0x72, 0xa3, 0xe5, 0x34, 0x84, 0xe8, 0x34, 0x1d, 0x19, 0x71,
0x81, 0x41, 0x41, 0x35, 0x19, 0x92, 0x41, 0x08, 0xd1, 0x51, 0xba, 0xa3, 0x3f, 0x4f, 0xef, 0xa5,
0x36, 0x5a, 0x1e, 0x3a, 0xef, 0xe8, 0xe1, 0xfe, 0xab, 0x57, 0xb0, 0xed, 0x15, 0xfc, 0xf4, 0x0a,
0x3e, 0x06, 0xe5, 0x6d, 0x07, 0xe5, 0x7d, 0x0f, 0xca, 0x7b, 0xbe, 0x74, 0x1f, 0xeb, 0xa2, 0x8a,
0x4b, 0x4e, 0x0c, 0x73, 0x3d, 0x9a, 0x68, 0x11, 0xd8, 0x59, 0xee, 0x7e, 0x03, 0x00, 0x00, 0xff,
0xff, 0x76, 0x0b, 0x27, 0x18, 0x3d, 0x01, 0x00, 0x00,
}
func (m *Op) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalToSizedBuffer(dAtA[:size])
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *Op) MarshalTo(dAtA []byte) (int, error) {
size := m.Size()
return m.MarshalToSizedBuffer(dAtA[:size])
}
func (m *Op) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i := len(dAtA)
_ = i
var l int
_ = l
if m.Exists {
i--
if m.Exists {
dAtA[i] = 1
} else {
dAtA[i] = 0
}
i--
dAtA[i] = 0x38
}
if m.Delete {
i--
if m.Delete {
dAtA[i] = 1
} else {
dAtA[i] = 0
}
i--
dAtA[i] = 0x30
}
if m.Iterations != 0 {
i = encodeVarintBenchmark(dAtA, i, uint64(m.Iterations))
i--
dAtA[i] = 0x28
}
if m.ValueLength != 0 {
i = encodeVarintBenchmark(dAtA, i, uint64(m.ValueLength))
i--
dAtA[i] = 0x20
}
if m.KeyLength != 0 {
i = encodeVarintBenchmark(dAtA, i, uint64(m.KeyLength))
i--
dAtA[i] = 0x18
}
if len(m.Actor) > 0 {
i -= len(m.Actor)
copy(dAtA[i:], m.Actor)
i = encodeVarintBenchmark(dAtA, i, uint64(len(m.Actor)))
i--
dAtA[i] = 0x12
}
if m.Seed != 0 {
i = encodeVarintBenchmark(dAtA, i, uint64(m.Seed))
i--
dAtA[i] = 0x8
}
return len(dAtA) - i, nil
}
func encodeVarintBenchmark(dAtA []byte, offset int, v uint64) int {
offset -= sovBenchmark(v)
base := offset
for v >= 1<<7 {
dAtA[offset] = uint8(v&0x7f | 0x80)
v >>= 7
offset++
}
dAtA[offset] = uint8(v)
return base
}
func (m *Op) Size() (n int) {
if m == nil {
return 0
}
var l int
_ = l
if m.Seed != 0 {
n += 1 + sovBenchmark(uint64(m.Seed))
}
l = len(m.Actor)
if l > 0 {
n += 1 + l + sovBenchmark(uint64(l))
}
if m.KeyLength != 0 {
n += 1 + sovBenchmark(uint64(m.KeyLength))
}
if m.ValueLength != 0 {
n += 1 + sovBenchmark(uint64(m.ValueLength))
}
if m.Iterations != 0 {
n += 1 + sovBenchmark(uint64(m.Iterations))
}
if m.Delete {
n += 2
}
if m.Exists {
n += 2
}
return n
}
func sovBenchmark(x uint64) (n int) {
return (math_bits.Len64(x|1) + 6) / 7
}
func sozBenchmark(x uint64) (n int) {
return sovBenchmark(uint64((x << 1) ^ uint64((int64(x) >> 63))))
}
func (m *Op) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowBenchmark
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: Op: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: Op: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field Seed", wireType)
}
m.Seed = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowBenchmark
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.Seed |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
case 2:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Actor", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowBenchmark
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthBenchmark
}
postIndex := iNdEx + intStringLen
if postIndex < 0 {
return ErrInvalidLengthBenchmark
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Actor = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 3:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field KeyLength", wireType)
}
m.KeyLength = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowBenchmark
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.KeyLength |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
case 4:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field ValueLength", wireType)
}
m.ValueLength = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowBenchmark
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.ValueLength |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
case 5:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field Iterations", wireType)
}
m.Iterations = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowBenchmark
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.Iterations |= uint32(b&0x7F) << shift
if b < 0x80 {
break
}
}
case 6:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field Delete", wireType)
}
var v int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowBenchmark
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
v |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
m.Delete = bool(v != 0)
case 7:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field Exists", wireType)
}
var v int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowBenchmark
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
v |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
m.Exists = bool(v != 0)
default:
iNdEx = preIndex
skippy, err := skipBenchmark(dAtA[iNdEx:])
if err != nil {
return err
}
if (skippy < 0) || (iNdEx+skippy) < 0 {
return ErrInvalidLengthBenchmark
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func skipBenchmark(dAtA []byte) (n int, err error) {
l := len(dAtA)
iNdEx := 0
depth := 0
for iNdEx < l {
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowBenchmark
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
wireType := int(wire & 0x7)
switch wireType {
case 0:
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowBenchmark
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
iNdEx++
if dAtA[iNdEx-1] < 0x80 {
break
}
}
case 1:
iNdEx += 8
case 2:
var length int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowBenchmark
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
length |= (int(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
if length < 0 {
return 0, ErrInvalidLengthBenchmark
}
iNdEx += length
case 3:
depth++
case 4:
if depth == 0 {
return 0, ErrUnexpectedEndOfGroupBenchmark
}
depth--
case 5:
iNdEx += 4
default:
return 0, fmt.Errorf("proto: illegal wireType %d", wireType)
}
if iNdEx < 0 {
return 0, ErrInvalidLengthBenchmark
}
if depth == 0 {
return iNdEx, nil
}
}
return 0, io.ErrUnexpectedEOF
}
var (
ErrInvalidLengthBenchmark = fmt.Errorf("proto: negative length found during unmarshaling")
ErrIntOverflowBenchmark = fmt.Errorf("proto: integer overflow")
ErrUnexpectedEndOfGroupBenchmark = fmt.Errorf("proto: unexpected end of group")
)

View File

@ -0,0 +1,186 @@
package cli
import (
"context"
"errors"
"os"
"os/signal"
"syscall"
"time"
"github.com/spf13/cobra"
modulev1 "cosmossdk.io/api/cosmos/benchmark/module/v1"
"cosmossdk.io/tools/benchmark"
gen "cosmossdk.io/tools/benchmark/generator"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
clienttx "github.com/cosmos/cosmos-sdk/client/tx"
)
func NewTxCmd(params *modulev1.GeneratorParams) *cobra.Command {
txCmd := &cobra.Command{
Use: "benchmark",
Short: "benchmark transaction subcommands",
DisableFlagParsing: true,
SuggestionsMinimumDistance: 2,
RunE: client.ValidateCmd,
}
txCmd.AddCommand(
NewLoadTestCmd(params),
)
return txCmd
}
func NewLoadTestCmd(params *modulev1.GeneratorParams) *cobra.Command {
var (
verbose bool
pause int64
numOps uint64
)
cmd := &cobra.Command{
Use: "load-test",
RunE: func(cmd *cobra.Command, args []string) (runErr error) {
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}
ctx, cancelFn := context.WithCancel(cmd.Context())
go func() {
sigCh := make(chan os.Signal, 1)
signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM)
select {
case sig := <-sigCh:
cancelFn()
cmd.Printf("caught %s signal\n", sig.String())
case <-ctx.Done():
cancelFn()
}
}()
var (
successCount int
errCount int
since = time.Now()
last int
)
defer func() {
cmd.Printf("done! success_tx=%d err_tx=%d\n", successCount, errCount)
}()
accNum, accSeq, err := clientCtx.AccountRetriever.GetAccountNumberSequence(clientCtx, clientCtx.FromAddress)
if err != nil {
return err
}
txf, err := clienttx.NewFactoryCLI(clientCtx, cmd.Flags())
if err != nil {
return err
}
txf = txf.WithAccountNumber(accNum).WithChainID(clientCtx.ChainID).WithGas(1_000_000_000)
storeKeys, err := gen.StoreKeys("benchmark", params.Seed, params.BucketCount)
if err != nil {
return err
}
var seed uint64
for _, c := range clientCtx.FromAddress {
// root the generator seed in the account address
seed += uint64(c)
}
g := gen.NewGenerator(gen.Options{
HomeDir: clientCtx.HomeDir,
GeneratorParams: params,
InsertWeight: 0.25,
DeleteWeight: 0.05,
UpdateWeight: 0.50,
GetWeight: 0.20,
},
gen.WithGenesis(),
gen.WithSeed(seed),
)
if err = g.Load(); err != nil {
return err
}
defer func() {
if err = g.Close(); err != nil {
runErr = errors.Join(runErr, err)
}
}()
begin := time.Now()
ops := make([]*benchmark.Op, numOps)
for {
select {
case <-ctx.Done():
return nil
default:
}
if time.Since(since) > 5*time.Second {
cmd.Printf(
"success_tx=%d err_tx=%d seq=%d rate=%.2f/s overall=%.2f/s\n",
successCount, errCount, accSeq,
float64(successCount-last)/time.Since(since).Seconds(),
float64(successCount)/time.Since(begin).Seconds(),
)
since = time.Now()
last = successCount
}
for j := range numOps {
bucket, op, err := g.Next()
if err != nil {
return err
}
op.Actor = storeKeys[bucket]
ops[j] = op
}
msg := &benchmark.MsgLoadTest{
Caller: clientCtx.FromAddress,
Ops: ops,
}
txf = txf.WithSequence(accSeq)
tx, err := txf.BuildUnsignedTx(msg)
if err != nil {
return err
}
err = clienttx.Sign(clientCtx.CmdContext, txf, clientCtx.From, tx, true)
if err != nil {
return err
}
txBytes, err := clientCtx.TxConfig.TxEncoder()(tx.GetTx())
if err != nil {
return err
}
res, err := clientCtx.BroadcastTxAsync(txBytes)
if err != nil {
return err
}
if res.Code != 0 {
if verbose {
err = clientCtx.PrintProto(res)
if err != nil {
return err
}
}
errCount++
} else {
accSeq++
successCount++
}
if pause > 0 {
time.Sleep(time.Duration(pause) * time.Microsecond)
}
}
},
}
flags.AddTxFlagsToCmd(cmd)
cmd.Flags().BoolVarP(&verbose, "verbose", "v", false, "print the response")
cmd.Flags().Uint64Var(&numOps, "ops", 1, "number of operations per transaction")
cmd.Flags().Int64Var(&pause, "pause", 0, "pause between transactions in microseconds")
return cmd
}

View File

@ -0,0 +1,381 @@
package gen
import (
"encoding"
"encoding/binary"
"errors"
"fmt"
"io"
"iter"
"math/rand/v2"
"os"
"github.com/cespare/xxhash/v2"
module "cosmossdk.io/api/cosmos/benchmark/module/v1"
"cosmossdk.io/tools/benchmark"
)
// Options is the configuration for the generator.
type Options struct {
*module.GeneratorParams
// HomeDir is for reading/writing state
HomeDir string
InsertWeight float64
UpdateWeight float64
GetWeight float64
DeleteWeight float64
}
// State is the state of the generator.
// It can be marshaled and unmarshaled to/from a binary format.
type State struct {
Src interface {
rand.Source
encoding.BinaryMarshaler
encoding.BinaryUnmarshaler
}
Keys [][]Payload
}
// Marshal writes the state to w.
func (s *State) Marshal(w io.Writer) error {
srcBz, err := s.Src.MarshalBinary()
if err != nil {
return err
}
var n int
n, err = w.Write(srcBz)
if err != nil {
return err
}
if n != 20 {
return fmt.Errorf("expected 20 bytes, got %d", n)
}
if err = binary.Write(w, binary.LittleEndian, uint64(len(s.Keys))); err != nil {
return err
}
for _, bucket := range s.Keys {
if err = binary.Write(w, binary.LittleEndian, uint64(len(bucket))); err != nil {
return err
}
for _, key := range bucket {
if err = binary.Write(w, binary.LittleEndian, key); err != nil {
return err
}
}
}
return nil
}
// Unmarshal reads the state from r.
func (s *State) Unmarshal(r io.Reader) error {
srcBz := make([]byte, 20)
if _, err := r.Read(srcBz); err != nil {
return err
}
s.Src = rand.NewPCG(0, 0)
if err := s.Src.UnmarshalBinary(srcBz); err != nil {
return err
}
var n uint64
if err := binary.Read(r, binary.LittleEndian, &n); err != nil {
return err
}
s.Keys = make([][]Payload, n)
for i := uint64(0); i < n; i++ {
var m uint64
if err := binary.Read(r, binary.LittleEndian, &m); err != nil {
return err
}
s.Keys[i] = make([]Payload, m)
for j := uint64(0); j < m; j++ {
if err := binary.Read(r, binary.LittleEndian, &s.Keys[i][j]); err != nil {
return err
}
}
}
return nil
}
// Generator generates operations for a benchmark transaction.
// The generator is stateful, keeping track of which keys have been inserted
// so that meaningful gets and deletes can be generated.
type Generator struct {
Options
rand *rand.Rand
state *State
}
type opt func(*Generator)
// NewGenerator creates a new generator with the given options.
func NewGenerator(opts Options, f ...opt) *Generator {
g := &Generator{
Options: opts,
state: &State{
Src: rand.NewPCG(opts.Seed, opts.Seed>>32),
},
}
g.rand = rand.New(g.state.Src)
for _, fn := range f {
fn(g)
}
return g
}
// WithGenesis sets the generator state to the genesis seed.
// When the generator is created, it will sync to genesis state.
// The benchmark client needs to do this so that it can generate meaningful tx operations.
func WithGenesis() func(*Generator) {
return func(g *Generator) {
// sync state to genesis seed
g.state.Keys = make([][]Payload, g.BucketCount)
if g.GeneratorParams != nil {
for kv := range g.GenesisSet() {
g.state.Keys[kv.StoreKey] = append(g.state.Keys[kv.StoreKey], kv.Key)
}
}
}
}
// WithSeed sets the seed for the generator.
func WithSeed(seed uint64) func(*Generator) {
return func(g *Generator) {
g.state.Src = rand.NewPCG(seed, seed>>32)
g.rand = rand.New(g.state.Src)
}
}
// Load loads the generator state from disk.
func (g *Generator) Load() error {
f := fmt.Sprintf("%s/data/generator_state.bin", g.HomeDir)
r, err := os.Open(f)
if err != nil {
if errors.Is(err, os.ErrNotExist) {
return nil
}
return err
}
return g.state.Unmarshal(r)
}
// Payload is a 2-tuple of seed and length.
// A seed is uint64 which is used to generate a byte slice of size length.
type Payload [2]uint64
// Seed returns the seed in the payload.
func (p Payload) Seed() uint64 {
return p[0]
}
// Length returns the length in the payload.
func (p Payload) Length() uint64 {
return p[1]
}
// Bytes returns the byte slice generated from the seed and length.
// The underlying byte slice is deterministically generated using the (very fast) xxhash algorithm.
func (p Payload) Bytes() []byte {
return Bytes(p.Seed(), p.Length())
}
func (p Payload) String() string {
return fmt.Sprintf("(%d, %d)", p.Seed(), p.Length())
}
func NewPayload(seed, length uint64) Payload {
return Payload{seed, length}
}
// KV is a key-value pair with a store key.
type KV struct {
StoreKey uint64
Key Payload
Value Payload
}
func (g *Generator) fetchKey(bucket uint64) (idx uint64, key Payload, err error) {
bucketLen := uint64(len(g.state.Keys[bucket]))
if bucketLen == 0 {
return 0, Payload{}, fmt.Errorf("no keys in bucket %d", bucket)
}
idx = g.rand.Uint64N(bucketLen)
return idx, g.state.Keys[bucket][idx], nil
}
func (g *Generator) deleteKey(bucket, idx uint64) {
g.state.Keys[bucket] = append(g.state.Keys[bucket][:idx], g.state.Keys[bucket][idx+1:]...)
}
func (g *Generator) setKey(bucket uint64, payload Payload) {
g.state.Keys[bucket] = append(g.state.Keys[bucket], payload)
}
// GenesisSet returns a sequence of key-value pairs for the genesis state.
// It is called by the server during InitGenesis to generate and set the initial state.
// The client uses WithGenesis to sync to the genesis state.
func (g *Generator) GenesisSet() iter.Seq[*KV] {
return func(yield func(*KV) bool) {
for range g.GenesisCount {
seed := g.rand.Uint64()
if !yield(&KV{
StoreKey: g.UintN(g.BucketCount),
Key: NewPayload(seed, g.getLength(g.KeyMean, g.KeyStdDev)),
Value: NewPayload(seed, g.getLength(g.ValueMean, g.ValueStdDev)),
}) {
return
}
}
}
}
// Next generates the next benchmark operation.
// The operation is one of insert, update, get, or delete.
// The tx client calls this function to deterministically generate the next operation.
func (g *Generator) Next() (uint64, *benchmark.Op, error) {
if g.InsertWeight+g.UpdateWeight+g.GetWeight+g.DeleteWeight != 1 {
return 0, nil, fmt.Errorf("weights must sum to 1")
}
var (
err error
key Payload
)
x := g.rand.Float64()
bucket := g.UintN(g.BucketCount)
op := &benchmark.Op{
Exists: true,
}
switch {
case x < g.InsertWeight:
// insert
op.Seed = g.rand.Uint64()
op.KeyLength = g.getLength(g.KeyMean, g.KeyStdDev)
op.ValueLength = g.getLength(g.ValueMean, g.ValueStdDev)
op.Exists = false
g.setKey(bucket, NewPayload(op.Seed, op.KeyLength))
case x < g.InsertWeight+g.UpdateWeight:
// update
_, key, err = g.fetchKey(bucket)
if err != nil {
return 0, nil, err
}
op.Seed = key.Seed()
op.KeyLength = key.Length()
op.ValueLength = g.getLength(g.ValueMean, g.ValueStdDev)
case x < g.InsertWeight+g.UpdateWeight+g.GetWeight:
// get
_, key, err = g.fetchKey(bucket)
if err != nil {
return 0, nil, err
}
op.Seed = key.Seed()
op.KeyLength = key.Length()
default:
// delete
var idx uint64
idx, key, err = g.fetchKey(bucket)
if err != nil {
return 0, nil, err
}
op.Delete = true
op.Seed = key.Seed()
op.KeyLength = key.Length()
g.deleteKey(bucket, idx)
}
return bucket, op, nil
}
// NormUint64 returns a random uint64 with a normal distribution.
func (g *Generator) NormUint64(mean, stdDev uint64) uint64 {
return uint64(g.rand.NormFloat64()*float64(stdDev) + float64(mean))
}
func (g *Generator) getLength(mean, stdDev uint64) uint64 {
length := g.NormUint64(mean, stdDev)
if length == 0 {
length = 1
}
return length
}
// UintN returns a random uint64 in the range [0, n).
func (g *Generator) UintN(n uint64) uint64 {
return g.rand.Uint64N(n)
}
func (g *Generator) Close() error {
f := fmt.Sprintf("%s/data/generator_state.bin", g.HomeDir)
w, err := os.Create(f)
if err != nil {
return err
}
return g.state.Marshal(w)
}
func encodeUint64(x uint64) []byte {
var b [8]byte
b[0] = byte(x)
b[1] = byte(x >> 8)
b[2] = byte(x >> 16)
b[3] = byte(x >> 24)
b[4] = byte(x >> 32)
b[5] = byte(x >> 40)
b[6] = byte(x >> 48)
b[7] = byte(x >> 56)
return b[:]
}
const maxStoreKeyGenIterations = 100
// StoreKeys deterministically generates a set of unique store keys from seed.
func StoreKeys(prefix string, seed, count uint64) ([]string, error) {
r := rand.New(rand.NewPCG(seed, seed>>32))
keys := make([]string, count)
seen := make(map[string]struct{})
var i, j uint64
for i < count {
if j > maxStoreKeyGenIterations {
return nil, fmt.Errorf("failed to generate %d unique store keys", count)
}
sk := fmt.Sprintf("%s_%x", prefix, Bytes(r.Uint64(), 8))
if _, ok := seen[sk]; ok {
j++
continue
}
keys[i] = sk
seen[sk] = struct{}{}
i++
j++
}
return keys, nil
}
// Bytes generates a byte slice of length length from seed.
// The byte slice is deterministically generated using the (very fast) xxhash algorithm.
func Bytes(seed, length uint64) []byte {
b := make([]byte, length)
rounds := length / 8
remainder := length % 8
var h uint64
for i := uint64(0); i < rounds; i++ {
h = xxhash.Sum64(encodeUint64(seed + i))
for j := uint64(0); j < 8; j++ {
b[i*8+j] = byte(h >> (8 * j))
}
}
if remainder > 0 {
h = xxhash.Sum64(encodeUint64(seed + rounds))
for j := uint64(0); j < remainder; j++ {
b[rounds*8+j] = byte(h >> (8 * j))
}
}
return b
}

View File

@ -0,0 +1,138 @@
package gen
import (
"bytes"
"testing"
"github.com/cespare/xxhash/v2"
"github.com/stretchr/testify/require"
benchmarkmodulev1 "cosmossdk.io/api/cosmos/benchmark/module/v1"
)
func Test_Genesis(t *testing.T) {
params := &benchmarkmodulev1.GeneratorParams{
Seed: 34,
BucketCount: 10,
GenesisCount: 2_000_000,
KeyMean: 64,
KeyStdDev: 8,
ValueMean: 1024,
ValueStdDev: 256,
}
g := NewGenerator(Options{GeneratorParams: params})
db := make(map[uint64]map[uint64]bool)
for kv := range g.GenesisSet() {
if _, ok := db[kv.StoreKey]; !ok {
db[kv.StoreKey] = make(map[uint64]bool)
}
db[kv.StoreKey][kv.Key[0]] = true
}
g = NewGenerator(Options{
GeneratorParams: params,
InsertWeight: 0.25,
DeleteWeight: 0.05,
UpdateWeight: 0.50,
GetWeight: 0.20,
}, WithGenesis())
for range 100_000 {
sk, op, err := g.Next()
require.NoError(t, err)
switch {
case op.Delete:
require.True(t, db[sk][op.Seed])
delete(db[sk], op.Seed)
case op.ValueLength > 0:
if op.Exists {
// update
require.True(t, db[sk][op.Seed])
} else {
// insert
require.False(t, db[sk][op.Seed])
}
db[sk][op.Seed] = true
case op.ValueLength == 0:
// get
require.True(t, db[sk][op.Seed])
default:
t.Fatalf("unexpected op: %v", op)
}
}
// Test state Marshal/Unmarshal
var buf bytes.Buffer
require.NoError(t, g.state.Marshal(&buf))
s := &State{}
require.NoError(t, s.Unmarshal(bytes.NewReader(buf.Bytes())))
require.Equal(t, len(g.state.Keys), len(s.Keys))
for i := range g.state.Keys {
require.Equal(t, len(g.state.Keys[i]), len(s.Keys[i]))
for j := range g.state.Keys[i] {
require.Equal(t, g.state.Keys[i][j], s.Keys[i][j])
}
}
}
func Test_Genesis_BytesKey(t *testing.T) {
params := &benchmarkmodulev1.GeneratorParams{
Seed: 34,
BucketCount: 10,
GenesisCount: 2_000_000,
KeyMean: 64,
KeyStdDev: 8,
ValueMean: 1024,
ValueStdDev: 256,
}
g := NewGenerator(Options{GeneratorParams: params})
db := make(map[uint64]map[uint64]bool)
for kv := range g.GenesisSet() {
if _, ok := db[kv.StoreKey]; !ok {
db[kv.StoreKey] = make(map[uint64]bool)
}
key := xxhash.Sum64(Bytes(kv.Key.Seed(), kv.Key.Length()))
db[kv.StoreKey][key] = true
}
g = NewGenerator(Options{
GeneratorParams: params,
InsertWeight: 0.25,
DeleteWeight: 0.05,
UpdateWeight: 0.50,
GetWeight: 0.20,
}, WithGenesis())
for range 1_000_000 {
sk, op, err := g.Next()
require.NoError(t, err)
key := xxhash.Sum64(Bytes(op.Seed, op.KeyLength))
switch {
case op.Delete:
require.True(t, db[sk][key])
delete(db[sk], key)
case op.ValueLength > 0:
if op.Exists {
// update
require.True(t, db[sk][key])
} else {
// insert
require.False(t, db[sk][key])
}
db[sk][key] = true
case op.ValueLength == 0:
// get
require.True(t, db[sk][key])
default:
t.Fatalf("unexpected op: %v", op)
}
}
}
func Test_Bytes_Deterministic(t *testing.T) {
seed := uint64(12345)
length := uint64(53)
expected := Bytes(seed, length)
for i := 0; i < 100; i++ {
result := Bytes(seed, length)
require.Equal(t, expected, result, "Bytes() should be deterministic")
}
}

160
tools/benchmark/go.mod Normal file
View File

@ -0,0 +1,160 @@
module cosmossdk.io/tools/benchmark
go 1.23.5
require (
cosmossdk.io/api v0.8.2
cosmossdk.io/core v0.11.0
cosmossdk.io/depinject v1.1.0
cosmossdk.io/log v1.5.0
github.com/cespare/xxhash/v2 v2.3.0
github.com/cosmos/cosmos-sdk v0.53.0
github.com/cosmos/gogoproto v1.7.0
github.com/grpc-ecosystem/grpc-gateway v1.16.0
github.com/spf13/cobra v1.9.1
github.com/stretchr/testify v1.10.0
google.golang.org/grpc v1.71.0
)
require (
cosmossdk.io/collections v0.4.0 // indirect
cosmossdk.io/errors v1.0.1 // indirect
cosmossdk.io/math v1.5.0 // indirect
cosmossdk.io/store v1.1.1 // indirect
cosmossdk.io/x/tx v0.13.7 // indirect
filippo.io/edwards25519 v1.1.0 // indirect
github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect
github.com/99designs/keyring v1.2.2 // indirect
github.com/DataDog/datadog-go v3.2.0+incompatible // indirect
github.com/DataDog/zstd v1.5.6 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/bgentry/speakeasy v0.2.0 // indirect
github.com/bytedance/sonic v1.13.1 // indirect
github.com/bytedance/sonic/loader v0.2.4 // indirect
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
github.com/cloudwego/base64x v0.1.5 // indirect
github.com/cockroachdb/apd/v3 v3.2.1 // indirect
github.com/cockroachdb/errors v1.11.3 // indirect
github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce // indirect
github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect
github.com/cockroachdb/pebble v1.1.2 // indirect
github.com/cockroachdb/redact v1.1.5 // indirect
github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 // indirect
github.com/cometbft/cometbft v0.38.17 // indirect
github.com/cometbft/cometbft-db v0.14.1 // indirect
github.com/cosmos/btcutil v1.0.5 // indirect
github.com/cosmos/cosmos-db v1.1.1 // indirect
github.com/cosmos/cosmos-proto v1.0.0-beta.5 // indirect
github.com/cosmos/go-bip39 v1.0.0 // indirect
github.com/cosmos/gogogateway v1.2.0 // indirect
github.com/cosmos/iavl v1.2.2 // indirect
github.com/cosmos/ics23/go v0.11.0 // indirect
github.com/cosmos/ledger-cosmos-go v0.14.0 // indirect
github.com/danieljoos/wincred v1.1.2 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect
github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f // indirect
github.com/dgraph-io/badger/v4 v4.2.0 // indirect
github.com/dgraph-io/ristretto v0.1.1 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/dvsekhvalnov/jose2go v1.6.0 // indirect
github.com/emicklei/dot v1.6.2 // indirect
github.com/fatih/color v1.15.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/fsnotify/fsnotify v1.8.0 // indirect
github.com/getsentry/sentry-go v0.27.0 // indirect
github.com/go-kit/kit v0.13.0 // indirect
github.com/go-kit/log v0.2.1 // indirect
github.com/go-logfmt/logfmt v0.6.0 // indirect
github.com/go-viper/mapstructure/v2 v2.2.1 // indirect
github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect
github.com/gogo/googleapis v1.4.1 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/glog v1.2.4 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/google/btree v1.1.3 // indirect
github.com/google/flatbuffers v1.12.1 // indirect
github.com/google/go-cmp v0.7.0 // indirect
github.com/gorilla/handlers v1.5.2 // indirect
github.com/gorilla/mux v1.8.1 // indirect
github.com/gorilla/websocket v1.5.3 // indirect
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect
github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect
github.com/hashicorp/go-hclog v1.5.0 // indirect
github.com/hashicorp/go-immutable-radix v1.3.1 // indirect
github.com/hashicorp/go-metrics v0.5.4 // indirect
github.com/hashicorp/go-plugin v1.5.2 // indirect
github.com/hashicorp/golang-lru v1.0.2 // indirect
github.com/hashicorp/yamux v0.1.1 // indirect
github.com/hdevalence/ed25519consensus v0.2.0 // indirect
github.com/huandu/skiplist v1.2.1 // indirect
github.com/iancoleman/strcase v0.3.0 // indirect
github.com/improbable-eng/grpc-web v0.15.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jmhodges/levigo v1.0.0 // indirect
github.com/klauspost/compress v1.17.11 // indirect
github.com/klauspost/cpuid/v2 v2.2.10 // indirect
github.com/kr/pretty v0.3.1 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/linxGnu/grocksdb v1.8.14 // indirect
github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mitchellh/go-testing-interface v1.14.1 // indirect
github.com/mtibben/percent v0.2.1 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/oasisprotocol/curve25519-voi v0.0.0-20230904125328-1f23a7beb09a // indirect
github.com/oklog/run v1.1.0 // indirect
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
github.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/prometheus/client_golang v1.21.1 // indirect
github.com/prometheus/client_model v0.6.1 // indirect
github.com/prometheus/common v0.62.0 // indirect
github.com/prometheus/procfs v0.15.1 // indirect
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect
github.com/rogpeppe/go-internal v1.12.0 // indirect
github.com/rs/cors v1.11.1 // indirect
github.com/rs/zerolog v1.33.0 // indirect
github.com/sagikazarmark/locafero v0.7.0 // indirect
github.com/sasha-s/go-deadlock v0.3.5 // indirect
github.com/sourcegraph/conc v0.3.0 // indirect
github.com/spf13/afero v1.12.0 // indirect
github.com/spf13/cast v1.7.1 // indirect
github.com/spf13/pflag v1.0.6 // indirect
github.com/spf13/viper v1.20.0 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d // indirect
github.com/tendermint/go-amino v0.16.0 // indirect
github.com/tidwall/btree v1.7.0 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/zondax/hid v0.9.2 // indirect
github.com/zondax/ledger-go v0.14.3 // indirect
go.etcd.io/bbolt v1.4.0-alpha.0.0.20240404170359-43604f3112c5 // indirect
go.opencensus.io v0.24.0 // indirect
go.uber.org/multierr v1.10.0 // indirect
golang.org/x/arch v0.15.0 // indirect
golang.org/x/crypto v0.36.0 // indirect
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect
golang.org/x/net v0.35.0 // indirect
golang.org/x/sync v0.12.0 // indirect
golang.org/x/sys v0.31.0 // indirect
golang.org/x/term v0.30.0 // indirect
golang.org/x/text v0.23.0 // indirect
google.golang.org/genproto v0.0.0-20241118233622-e639e219e697 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20250218202821-56aae31c358a // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a // indirect
google.golang.org/protobuf v1.36.5 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
gotest.tools/v3 v3.5.2 // indirect
nhooyr.io/websocket v1.8.6 // indirect
pgregory.net/rapid v1.2.0 // indirect
sigs.k8s.io/yaml v1.4.0 // indirect
)
replace (
cosmossdk.io/api => ../../api
github.com/cosmos/cosmos-sdk => ../../
)

1007
tools/benchmark/go.sum Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,62 @@
package module
import (
"unsafe"
modulev1 "cosmossdk.io/api/cosmos/benchmark/module/v1"
"cosmossdk.io/core/appmodule"
"cosmossdk.io/core/store"
"cosmossdk.io/depinject"
"cosmossdk.io/depinject/appconfig"
"cosmossdk.io/log"
gen "cosmossdk.io/tools/benchmark/generator"
)
const (
ModuleName = "benchmark"
maxStoreKeyGenIterations = 100
)
func init() {
appconfig.RegisterModule(
&modulev1.Module{},
appconfig.Provide(
ProvideModule,
),
)
}
type KVStoreServiceFactory func([]byte) store.KVStoreService
type Input struct {
depinject.In
Logger log.Logger
Cfg *modulev1.Module
StoreFactory KVStoreServiceFactory
}
func ProvideModule(
in Input,
) (appmodule.AppModule, error) {
cfg := in.Cfg
kvMap := make(KVServiceMap)
storeKeys, err := gen.StoreKeys(ModuleName, cfg.GenesisParams.Seed, cfg.GenesisParams.BucketCount)
if err != nil {
return nil, err
}
for _, sk := range storeKeys {
kvService := in.StoreFactory(unsafeStrToBytes(sk))
kvMap[sk] = kvService
}
return NewAppModule(cfg.GenesisParams, storeKeys, kvMap, in.Logger), nil
}
type KVServiceMap map[string]store.KVStoreService
// unsafeStrToBytes uses unsafe to convert string into byte array. Returned bytes
// must not be altered after this function is called as it will cause a segmentation fault.
func unsafeStrToBytes(s string) []byte {
return unsafe.Slice(unsafe.StringData(s), len(s)) // ref https://github.com/golang/go/issues/53003#issuecomment-1140276077
}

View File

@ -0,0 +1,119 @@
package module
import (
"context"
"fmt"
"cosmossdk.io/tools/benchmark"
gen "cosmossdk.io/tools/benchmark/generator"
"github.com/cosmos/cosmos-sdk/telemetry"
)
var (
_ benchmark.MsgServer = &Keeper{}
metricOpKey = []string{"benchmark", "op"}
metricGetKey = append(metricOpKey, "get")
metricDelete = append(metricOpKey, "delete")
metricInsertKey = append(metricOpKey, "insert")
metricUpdateKey = append(metricOpKey, "update")
metricTotalKey = []string{"benchmark", "total"}
metricMissKey = []string{"benchmark", "miss"}
)
type Keeper struct {
kvServiceMap KVServiceMap
validate bool
errExit bool
}
func NewKeeper(kvMap KVServiceMap) *Keeper {
k := &Keeper{
kvServiceMap: kvMap,
validate: false,
errExit: false,
}
return k
}
func (k *Keeper) LoadTest(ctx context.Context, msg *benchmark.MsgLoadTest) (*benchmark.MsgLoadTestResponse, error) {
res := &benchmark.MsgLoadTestResponse{}
for _, op := range msg.Ops {
telemetry.IncrCounter(1, metricTotalKey...)
err := k.executeOp(ctx, op)
if err != nil {
return res, err
}
}
return res, nil
}
func (k *Keeper) executeOp(ctx context.Context, op *benchmark.Op) error {
svc, ok := k.kvServiceMap[op.Actor]
key := gen.Bytes(op.Seed, op.KeyLength)
if !ok {
return fmt.Errorf("actor %s not found", op.Actor)
}
kv := svc.OpenKVStore(ctx)
switch {
case op.Delete:
telemetry.IncrCounter(1, metricDelete...)
if k.validate {
exists, err := kv.Has(key)
if err != nil {
return err
}
if !exists {
telemetry.IncrCounter(1, metricMissKey...)
if k.errExit {
return fmt.Errorf("key %d not found", op.Seed)
}
}
}
return kv.Delete(key)
case op.ValueLength > 0:
metricKey := metricInsertKey
if op.Exists {
metricKey = metricUpdateKey
}
telemetry.IncrCounter(1, metricKey...)
if k.validate {
exists, err := kv.Has(key)
if err != nil {
return err
}
if exists != op.Exists {
telemetry.IncrCounter(1, metricMissKey...)
if k.errExit {
return fmt.Errorf("key %d exists=%t, expected=%t", op.Seed, exists, op.Exists)
}
}
}
value := gen.Bytes(op.Seed, op.ValueLength)
return kv.Set(key, value)
case op.Iterations > 0:
return fmt.Errorf("iterator not implemented")
case op.ValueLength == 0:
telemetry.IncrCounter(1, metricGetKey...)
v, err := kv.Get(key)
if v == nil {
// always count a miss on GET since it requires no extra I/O
telemetry.IncrCounter(1, metricMissKey...)
if k.errExit {
return fmt.Errorf("key %s not found", key)
}
}
return err
default:
return fmt.Errorf("invalid op: %+v", op)
}
}
func (k *Keeper) set(ctx context.Context, actor string, key, value []byte) error {
svc, ok := k.kvServiceMap[actor]
if !ok {
return fmt.Errorf("actor %s not found", actor)
}
kv := svc.OpenKVStore(ctx)
return kv.Set(key, value)
}

View File

@ -0,0 +1,105 @@
package module
import (
"encoding/json"
"github.com/grpc-ecosystem/grpc-gateway/runtime"
"github.com/spf13/cobra"
"google.golang.org/grpc"
modulev1 "cosmossdk.io/api/cosmos/benchmark/module/v1"
_ "cosmossdk.io/api/cosmos/benchmark/v1" // for some reason this is required to make msg server registration work
"cosmossdk.io/core/appmodule"
"cosmossdk.io/log"
"cosmossdk.io/tools/benchmark"
"cosmossdk.io/tools/benchmark/client/cli"
gen "cosmossdk.io/tools/benchmark/generator"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/codec"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/module"
"github.com/cosmos/cosmos-sdk/types/msgservice"
)
var (
_ appmodule.AppModule = &AppModule{}
_ module.HasGenesis = &AppModule{}
)
type AppModule struct {
keeper *Keeper
storeKeys []string
genesisParams *modulev1.GeneratorParams
log log.Logger
}
func NewAppModule(
genesisParams *modulev1.GeneratorParams,
storeKeys []string,
kvMap KVServiceMap,
logger log.Logger,
) *AppModule {
return &AppModule{
genesisParams: genesisParams,
keeper: NewKeeper(kvMap),
storeKeys: storeKeys,
log: logger,
}
}
func (a *AppModule) DefaultGenesis(_ codec.JSONCodec) json.RawMessage {
return nil
}
func (a *AppModule) ExportGenesis(_ sdk.Context, _ codec.JSONCodec) json.RawMessage {
return nil
}
func (a *AppModule) InitGenesis(ctx sdk.Context, _ codec.JSONCodec, _ json.RawMessage) {
a.genesisParams.BucketCount = uint64(len(a.storeKeys))
g := gen.NewGenerator(gen.Options{GeneratorParams: a.genesisParams})
i := 0
for kv := range g.GenesisSet() {
i++
if i%100_000 == 0 {
a.log.Warn("benchmark: init genesis", "progress", i, "total", a.genesisParams.GenesisCount)
}
sk := a.storeKeys[kv.StoreKey]
key := gen.Bytes(kv.Key.Seed(), kv.Key.Length())
value := gen.Bytes(kv.Value.Seed(), kv.Value.Length())
err := a.keeper.set(ctx, sk, key, value)
if err != nil {
panic(err)
}
}
}
func (a *AppModule) ValidateGenesis(_ codec.JSONCodec, _ client.TxEncodingConfig, _ json.RawMessage) error {
return nil
}
func (a *AppModule) RegisterGRPCGatewayRoutes(client.Context, *runtime.ServeMux) {
}
// RegisterServices registers module services.
func (a *AppModule) RegisterServices(registrar grpc.ServiceRegistrar) error {
benchmark.RegisterMsgServer(registrar, a.keeper)
return nil
}
func (a *AppModule) RegisterInterfaces(registry codectypes.InterfaceRegistry) {
registry.RegisterImplementations(
(*sdk.Msg)(nil),
&benchmark.MsgLoadTest{})
msgservice.RegisterMsgServiceDesc(registry, &benchmark.Msg_serviceDesc)
}
func (a *AppModule) GetTxCmd() *cobra.Command {
return cli.NewTxCmd(a.genesisParams)
}
func (a *AppModule) IsOnePerModuleType() {}
func (a *AppModule) IsAppModule() {}

670
tools/benchmark/tx.pb.go Normal file
View File

@ -0,0 +1,670 @@
// Code generated by protoc-gen-gogo. DO NOT EDIT.
// source: cosmos/benchmark/v1/tx.proto
package benchmark
import (
context "context"
fmt "fmt"
_ "github.com/cosmos/cosmos-sdk/types/msgservice"
_ "github.com/cosmos/cosmos-sdk/types/tx/amino"
grpc1 "github.com/cosmos/gogoproto/grpc"
proto "github.com/cosmos/gogoproto/proto"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
io "io"
math "math"
math_bits "math/bits"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package
// MsgLoadTestOps defines a message containing a sequence of load test operations.
type MsgLoadTest struct {
Caller []byte `protobuf:"bytes,1,opt,name=caller,proto3" json:"caller,omitempty"`
Ops []*Op `protobuf:"bytes,2,rep,name=ops,proto3" json:"ops,omitempty"`
}
func (m *MsgLoadTest) Reset() { *m = MsgLoadTest{} }
func (m *MsgLoadTest) String() string { return proto.CompactTextString(m) }
func (*MsgLoadTest) ProtoMessage() {}
func (*MsgLoadTest) Descriptor() ([]byte, []int) {
return fileDescriptor_481e3d7f7138b75b, []int{0}
}
func (m *MsgLoadTest) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
}
func (m *MsgLoadTest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
if deterministic {
return xxx_messageInfo_MsgLoadTest.Marshal(b, m, deterministic)
} else {
b = b[:cap(b)]
n, err := m.MarshalToSizedBuffer(b)
if err != nil {
return nil, err
}
return b[:n], nil
}
}
func (m *MsgLoadTest) XXX_Merge(src proto.Message) {
xxx_messageInfo_MsgLoadTest.Merge(m, src)
}
func (m *MsgLoadTest) XXX_Size() int {
return m.Size()
}
func (m *MsgLoadTest) XXX_DiscardUnknown() {
xxx_messageInfo_MsgLoadTest.DiscardUnknown(m)
}
var xxx_messageInfo_MsgLoadTest proto.InternalMessageInfo
func (m *MsgLoadTest) GetCaller() []byte {
if m != nil {
return m.Caller
}
return nil
}
func (m *MsgLoadTest) GetOps() []*Op {
if m != nil {
return m.Ops
}
return nil
}
// MsgLoadTestResponse defines a message containing the results of a load test operation.
type MsgLoadTestResponse struct {
TotalTime uint64 `protobuf:"varint,1,opt,name=total_time,json=totalTime,proto3" json:"total_time,omitempty"`
TotalErrors uint64 `protobuf:"varint,2,opt,name=total_errors,json=totalErrors,proto3" json:"total_errors,omitempty"`
}
func (m *MsgLoadTestResponse) Reset() { *m = MsgLoadTestResponse{} }
func (m *MsgLoadTestResponse) String() string { return proto.CompactTextString(m) }
func (*MsgLoadTestResponse) ProtoMessage() {}
func (*MsgLoadTestResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_481e3d7f7138b75b, []int{1}
}
func (m *MsgLoadTestResponse) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
}
func (m *MsgLoadTestResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
if deterministic {
return xxx_messageInfo_MsgLoadTestResponse.Marshal(b, m, deterministic)
} else {
b = b[:cap(b)]
n, err := m.MarshalToSizedBuffer(b)
if err != nil {
return nil, err
}
return b[:n], nil
}
}
func (m *MsgLoadTestResponse) XXX_Merge(src proto.Message) {
xxx_messageInfo_MsgLoadTestResponse.Merge(m, src)
}
func (m *MsgLoadTestResponse) XXX_Size() int {
return m.Size()
}
func (m *MsgLoadTestResponse) XXX_DiscardUnknown() {
xxx_messageInfo_MsgLoadTestResponse.DiscardUnknown(m)
}
var xxx_messageInfo_MsgLoadTestResponse proto.InternalMessageInfo
func (m *MsgLoadTestResponse) GetTotalTime() uint64 {
if m != nil {
return m.TotalTime
}
return 0
}
func (m *MsgLoadTestResponse) GetTotalErrors() uint64 {
if m != nil {
return m.TotalErrors
}
return 0
}
func init() {
proto.RegisterType((*MsgLoadTest)(nil), "cosmos.benchmark.v1.MsgLoadTest")
proto.RegisterType((*MsgLoadTestResponse)(nil), "cosmos.benchmark.v1.MsgLoadTestResponse")
}
func init() { proto.RegisterFile("cosmos/benchmark/v1/tx.proto", fileDescriptor_481e3d7f7138b75b) }
var fileDescriptor_481e3d7f7138b75b = []byte{
// 322 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x49, 0xce, 0x2f, 0xce,
0xcd, 0x2f, 0xd6, 0x4f, 0x4a, 0xcd, 0x4b, 0xce, 0xc8, 0x4d, 0x2c, 0xca, 0xd6, 0x2f, 0x33, 0xd4,
0x2f, 0xa9, 0xd0, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x12, 0x86, 0xc8, 0xea, 0xc1, 0x65, 0xf5,
0xca, 0x0c, 0xa5, 0x94, 0xb1, 0x69, 0x41, 0xa8, 0x00, 0xeb, 0x94, 0x12, 0x87, 0x2a, 0xca, 0x2d,
0x4e, 0x07, 0x49, 0xe7, 0x16, 0xa7, 0x43, 0x25, 0x04, 0x13, 0x73, 0x33, 0xf3, 0xf2, 0xf5, 0xc1,
0x24, 0x44, 0x48, 0xa9, 0x9b, 0x91, 0x8b, 0xdb, 0xb7, 0x38, 0xdd, 0x27, 0x3f, 0x31, 0x25, 0x24,
0xb5, 0xb8, 0x44, 0x48, 0x8c, 0x8b, 0x2d, 0x39, 0x31, 0x27, 0x27, 0xb5, 0x48, 0x82, 0x51, 0x81,
0x51, 0x83, 0x27, 0x08, 0xca, 0x13, 0xd2, 0xe4, 0x62, 0xce, 0x2f, 0x28, 0x96, 0x60, 0x52, 0x60,
0xd6, 0xe0, 0x36, 0x12, 0xd7, 0xc3, 0xe2, 0x36, 0x3d, 0xff, 0x82, 0x20, 0x90, 0x1a, 0x2b, 0xcb,
0xa6, 0xe7, 0x1b, 0xb4, 0xa0, 0xfa, 0xba, 0x9e, 0x6f, 0xd0, 0xd2, 0x84, 0x28, 0xd6, 0x2d, 0x4e,
0xc9, 0xd6, 0x2f, 0xc9, 0xcf, 0xcf, 0x41, 0x73, 0x3d, 0x92, 0xed, 0x4a, 0xe1, 0x5c, 0xc2, 0x48,
0xdc, 0xa0, 0xd4, 0xe2, 0x82, 0xfc, 0xbc, 0xe2, 0x54, 0x21, 0x59, 0x2e, 0xae, 0x92, 0xfc, 0x92,
0xc4, 0x9c, 0xf8, 0x92, 0xcc, 0xdc, 0x54, 0xb0, 0xc3, 0x58, 0x82, 0x38, 0xc1, 0x22, 0x21, 0x99,
0xb9, 0xa9, 0x42, 0x8a, 0x5c, 0x3c, 0x10, 0xe9, 0xd4, 0xa2, 0xa2, 0xfc, 0x22, 0x90, 0x23, 0x41,
0x0a, 0xb8, 0xc1, 0x62, 0xae, 0x60, 0x21, 0xa3, 0x14, 0x2e, 0x66, 0xdf, 0xe2, 0x74, 0xa1, 0x30,
0x2e, 0x0e, 0xb8, 0x4f, 0x15, 0xb0, 0x7a, 0x02, 0xc9, 0x7a, 0x29, 0x0d, 0x42, 0x2a, 0x60, 0x0e,
0x94, 0x62, 0x6d, 0x78, 0xbe, 0x41, 0x8b, 0xd1, 0xc9, 0xec, 0xc4, 0x23, 0x39, 0xc6, 0x0b, 0x8f,
0xe4, 0x18, 0x1f, 0x3c, 0x92, 0x63, 0x9c, 0xf0, 0x58, 0x8e, 0xe1, 0xc2, 0x63, 0x39, 0x86, 0x1b,
0x8f, 0xe5, 0x18, 0xa2, 0xa0, 0x51, 0x5d, 0x9c, 0x92, 0xad, 0x97, 0x99, 0x8f, 0x1e, 0x0a, 0x49,
0x6c, 0xe0, 0xb8, 0x30, 0x06, 0x04, 0x00, 0x00, 0xff, 0xff, 0x15, 0x3a, 0xfe, 0x19, 0x11, 0x02,
0x00, 0x00,
}
// Reference imports to suppress errors if they are not otherwise used.
var _ context.Context
var _ grpc.ClientConn
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
const _ = grpc.SupportPackageIsVersion4
// MsgClient is the client API for Msg service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
type MsgClient interface {
// LoadTest defines a method for executing a sequence of load test operations.
LoadTest(ctx context.Context, in *MsgLoadTest, opts ...grpc.CallOption) (*MsgLoadTestResponse, error)
}
type msgClient struct {
cc grpc1.ClientConn
}
func NewMsgClient(cc grpc1.ClientConn) MsgClient {
return &msgClient{cc}
}
func (c *msgClient) LoadTest(ctx context.Context, in *MsgLoadTest, opts ...grpc.CallOption) (*MsgLoadTestResponse, error) {
out := new(MsgLoadTestResponse)
err := c.cc.Invoke(ctx, "/cosmos.benchmark.v1.Msg/LoadTest", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// MsgServer is the server API for Msg service.
type MsgServer interface {
// LoadTest defines a method for executing a sequence of load test operations.
LoadTest(context.Context, *MsgLoadTest) (*MsgLoadTestResponse, error)
}
// UnimplementedMsgServer can be embedded to have forward compatible implementations.
type UnimplementedMsgServer struct {
}
func (*UnimplementedMsgServer) LoadTest(ctx context.Context, req *MsgLoadTest) (*MsgLoadTestResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method LoadTest not implemented")
}
func RegisterMsgServer(s grpc1.Server, srv MsgServer) {
s.RegisterService(&_Msg_serviceDesc, srv)
}
func _Msg_LoadTest_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(MsgLoadTest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(MsgServer).LoadTest(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/cosmos.benchmark.v1.Msg/LoadTest",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(MsgServer).LoadTest(ctx, req.(*MsgLoadTest))
}
return interceptor(ctx, in, info, handler)
}
var Msg_serviceDesc = _Msg_serviceDesc
var _Msg_serviceDesc = grpc.ServiceDesc{
ServiceName: "cosmos.benchmark.v1.Msg",
HandlerType: (*MsgServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "LoadTest",
Handler: _Msg_LoadTest_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "cosmos/benchmark/v1/tx.proto",
}
func (m *MsgLoadTest) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalToSizedBuffer(dAtA[:size])
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *MsgLoadTest) MarshalTo(dAtA []byte) (int, error) {
size := m.Size()
return m.MarshalToSizedBuffer(dAtA[:size])
}
func (m *MsgLoadTest) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i := len(dAtA)
_ = i
var l int
_ = l
if len(m.Ops) > 0 {
for iNdEx := len(m.Ops) - 1; iNdEx >= 0; iNdEx-- {
{
size, err := m.Ops[iNdEx].MarshalToSizedBuffer(dAtA[:i])
if err != nil {
return 0, err
}
i -= size
i = encodeVarintTx(dAtA, i, uint64(size))
}
i--
dAtA[i] = 0x12
}
}
if len(m.Caller) > 0 {
i -= len(m.Caller)
copy(dAtA[i:], m.Caller)
i = encodeVarintTx(dAtA, i, uint64(len(m.Caller)))
i--
dAtA[i] = 0xa
}
return len(dAtA) - i, nil
}
func (m *MsgLoadTestResponse) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalToSizedBuffer(dAtA[:size])
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *MsgLoadTestResponse) MarshalTo(dAtA []byte) (int, error) {
size := m.Size()
return m.MarshalToSizedBuffer(dAtA[:size])
}
func (m *MsgLoadTestResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i := len(dAtA)
_ = i
var l int
_ = l
if m.TotalErrors != 0 {
i = encodeVarintTx(dAtA, i, uint64(m.TotalErrors))
i--
dAtA[i] = 0x10
}
if m.TotalTime != 0 {
i = encodeVarintTx(dAtA, i, uint64(m.TotalTime))
i--
dAtA[i] = 0x8
}
return len(dAtA) - i, nil
}
func encodeVarintTx(dAtA []byte, offset int, v uint64) int {
offset -= sovTx(v)
base := offset
for v >= 1<<7 {
dAtA[offset] = uint8(v&0x7f | 0x80)
v >>= 7
offset++
}
dAtA[offset] = uint8(v)
return base
}
func (m *MsgLoadTest) Size() (n int) {
if m == nil {
return 0
}
var l int
_ = l
l = len(m.Caller)
if l > 0 {
n += 1 + l + sovTx(uint64(l))
}
if len(m.Ops) > 0 {
for _, e := range m.Ops {
l = e.Size()
n += 1 + l + sovTx(uint64(l))
}
}
return n
}
func (m *MsgLoadTestResponse) Size() (n int) {
if m == nil {
return 0
}
var l int
_ = l
if m.TotalTime != 0 {
n += 1 + sovTx(uint64(m.TotalTime))
}
if m.TotalErrors != 0 {
n += 1 + sovTx(uint64(m.TotalErrors))
}
return n
}
func sovTx(x uint64) (n int) {
return (math_bits.Len64(x|1) + 6) / 7
}
func sozTx(x uint64) (n int) {
return sovTx(uint64((x << 1) ^ uint64((int64(x) >> 63))))
}
func (m *MsgLoadTest) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowTx
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: MsgLoadTest: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: MsgLoadTest: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Caller", wireType)
}
var byteLen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowTx
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
byteLen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if byteLen < 0 {
return ErrInvalidLengthTx
}
postIndex := iNdEx + byteLen
if postIndex < 0 {
return ErrInvalidLengthTx
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Caller = append(m.Caller[:0], dAtA[iNdEx:postIndex]...)
if m.Caller == nil {
m.Caller = []byte{}
}
iNdEx = postIndex
case 2:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Ops", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowTx
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return ErrInvalidLengthTx
}
postIndex := iNdEx + msglen
if postIndex < 0 {
return ErrInvalidLengthTx
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Ops = append(m.Ops, &Op{})
if err := m.Ops[len(m.Ops)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipTx(dAtA[iNdEx:])
if err != nil {
return err
}
if (skippy < 0) || (iNdEx+skippy) < 0 {
return ErrInvalidLengthTx
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func (m *MsgLoadTestResponse) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowTx
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: MsgLoadTestResponse: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: MsgLoadTestResponse: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field TotalTime", wireType)
}
m.TotalTime = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowTx
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.TotalTime |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
case 2:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field TotalErrors", wireType)
}
m.TotalErrors = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowTx
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.TotalErrors |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
default:
iNdEx = preIndex
skippy, err := skipTx(dAtA[iNdEx:])
if err != nil {
return err
}
if (skippy < 0) || (iNdEx+skippy) < 0 {
return ErrInvalidLengthTx
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func skipTx(dAtA []byte) (n int, err error) {
l := len(dAtA)
iNdEx := 0
depth := 0
for iNdEx < l {
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowTx
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
wireType := int(wire & 0x7)
switch wireType {
case 0:
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowTx
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
iNdEx++
if dAtA[iNdEx-1] < 0x80 {
break
}
}
case 1:
iNdEx += 8
case 2:
var length int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowTx
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
length |= (int(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
if length < 0 {
return 0, ErrInvalidLengthTx
}
iNdEx += length
case 3:
depth++
case 4:
if depth == 0 {
return 0, ErrUnexpectedEndOfGroupTx
}
depth--
case 5:
iNdEx += 4
default:
return 0, fmt.Errorf("proto: illegal wireType %d", wireType)
}
if iNdEx < 0 {
return 0, ErrInvalidLengthTx
}
if depth == 0 {
return iNdEx, nil
}
}
return 0, io.ErrUnexpectedEOF
}
var (
ErrInvalidLengthTx = fmt.Errorf("proto: negative length found during unmarshaling")
ErrIntOverflowTx = fmt.Errorf("proto: integer overflow")
ErrUnexpectedEndOfGroupTx = fmt.Errorf("proto: unexpected end of group")
)