feat(tools/benchmark): introduce benchmark module (#24021)
Co-authored-by: Alex | Interchain Labs <alex@interchainlabs.io>
This commit is contained in:
co-authored by
Alex | Interchain Labs
parent
8bf5430d7e
commit
9539caae6e
@@ -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
|
||||
@@ -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.
|
||||
@@ -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")
|
||||
)
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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")
|
||||
}
|
||||
}
|
||||
@@ -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 => ../../
|
||||
)
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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() {}
|
||||
@@ -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")
|
||||
)
|
||||
Reference in New Issue
Block a user