Skip to content

Commit 142c53e

Browse files
committed
Benchmark framework for evaluating ledger performance
https://jira.hyperledger.org/browse/FAB-1309 - Basic framework for creating and managing chains - Basic framework for transaction submission, block creation, and block commit - Benchmark tests for insert and read-write transactions - scripts for common functions - scripts for launching the benchmarks Change-Id: I03f09fa2eec4fde5a9b23fc2316718c9a33577b5 Signed-off-by: manish <[email protected]>
1 parent 78d59b1 commit 142c53e

File tree

15 files changed

+1137
-9
lines changed

15 files changed

+1137
-9
lines changed

common/ledger/testutil/test_helper.go

-9
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,12 @@ import (
2121

2222
"github.com/golang/protobuf/proto"
2323
"github.com/hyperledger/fabric/common/configtx/test"
24-
"github.com/hyperledger/fabric/common/configtx/tool/provisional"
2524
"github.com/hyperledger/fabric/common/util"
2625
lutils "github.com/hyperledger/fabric/core/ledger/util"
2726
"github.com/hyperledger/fabric/protos/common"
2827
pb "github.com/hyperledger/fabric/protos/peer"
2928
ptestutils "github.com/hyperledger/fabric/protos/testutils"
3029
"github.com/hyperledger/fabric/protos/utils"
31-
32-
genesisconfig "github.com/hyperledger/fabric/common/configtx/tool/localconfig"
3330
)
3431

3532
//BlockGenerator generates a series of blocks for testing
@@ -147,9 +144,3 @@ func newBlock(env []*common.Envelope, blockNum uint64, previousHash []byte) *com
147144

148145
return block
149146
}
150-
151-
func MakeGenesisBlock() *common.Block {
152-
genConf := genesisconfig.Load(genesisconfig.SampleInsecureProfile)
153-
gb := provisional.New(genConf).GenesisBlock()
154-
return gb
155-
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
/*
2+
Copyright IBM Corp. 2017 All Rights Reserved.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package chainmgmt
18+
19+
import (
20+
"sync"
21+
22+
"github.com/golang/protobuf/proto"
23+
"github.com/hyperledger/fabric/protos/common"
24+
benchcommon "github.com/hyperledger/fabric/test/tools/ledgerbenchmarks/common"
25+
)
26+
27+
const (
28+
numConcurrentTxEnvCreators = 30
29+
)
30+
31+
type txEnvBytes []byte
32+
33+
// blkGenerator generates blocks in sequence. One instance of blkGenerator is maintained for each chain
34+
type blkGenerator struct {
35+
batchConf *BatchConf
36+
blockNum uint64
37+
previousBlockHash []byte
38+
39+
srQueue chan SimulationResult
40+
txQueue chan txEnvBytes
41+
wg *sync.WaitGroup
42+
}
43+
44+
func newBlkGenerator(batchConf *BatchConf, startingBlockNum uint64, previousBlockHash []byte) *blkGenerator {
45+
bg := &blkGenerator{
46+
batchConf,
47+
startingBlockNum,
48+
previousBlockHash,
49+
make(chan SimulationResult, batchConf.BatchSize),
50+
make(chan txEnvBytes, batchConf.BatchSize),
51+
&sync.WaitGroup{},
52+
}
53+
bg.startTxEnvCreators()
54+
return bg
55+
}
56+
57+
func (bg *blkGenerator) startTxEnvCreators() {
58+
for i := 0; i < numConcurrentTxEnvCreators; i++ {
59+
go bg.startTxEnvCreator()
60+
}
61+
}
62+
63+
func (bg *blkGenerator) startTxEnvCreator() {
64+
bg.wg.Add(1)
65+
for sr := range bg.srQueue {
66+
txEnv, err := createTxEnv(sr)
67+
benchcommon.PanicOnError(err)
68+
txEnvBytes, err := proto.Marshal(txEnv)
69+
benchcommon.PanicOnError(err)
70+
bg.txQueue <- txEnvBytes
71+
}
72+
bg.wg.Done()
73+
}
74+
75+
func (bg *blkGenerator) addTx(sr SimulationResult) {
76+
bg.srQueue <- sr
77+
}
78+
79+
func (bg *blkGenerator) nextBlock() *common.Block {
80+
block := common.NewBlock(bg.blockNum, bg.previousBlockHash)
81+
numTx := 0
82+
for txEnvBytes := range bg.txQueue {
83+
numTx++
84+
block.Data.Data = append(block.Data.Data, txEnvBytes)
85+
if numTx == bg.batchConf.BatchSize {
86+
break
87+
}
88+
}
89+
// close() has been called and no pending tx
90+
if len(block.Data.Data) == 0 {
91+
return nil
92+
}
93+
block.Header.DataHash = block.Data.Hash()
94+
block.Header.Number = bg.blockNum
95+
block.Header.PreviousHash = bg.previousBlockHash
96+
97+
bg.blockNum++
98+
bg.previousBlockHash = block.Header.Hash()
99+
return block
100+
}
101+
102+
func (bg *blkGenerator) close() {
103+
close(bg.srQueue)
104+
bg.wg.Wait()
105+
close(bg.txQueue)
106+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
/*
2+
Copyright IBM Corp. 2017 All Rights Reserved.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package chainmgmt
18+
19+
import (
20+
"fmt"
21+
"sync"
22+
23+
"github.com/hyperledger/fabric/common/configtx/test"
24+
"github.com/hyperledger/fabric/core/ledger"
25+
"github.com/hyperledger/fabric/core/ledger/ledgermgmt"
26+
"github.com/hyperledger/fabric/protos/common"
27+
benchcommon "github.com/hyperledger/fabric/test/tools/ledgerbenchmarks/common"
28+
)
29+
30+
// ChainID is a type used for the ids for the chains for experiments
31+
type ChainID int
32+
33+
func (chainID ChainID) String() string {
34+
return fmt.Sprintf("%s%04d", "chain_", chainID)
35+
}
36+
37+
// SimulationResult is a type used for simulation results
38+
type SimulationResult []byte
39+
40+
// chainsMgr manages chains for experiments
41+
type chainsMgr struct {
42+
mgrConf *ChainMgrConf
43+
batchConf *BatchConf
44+
initOp chainInitOp
45+
chainsMap map[ChainID]*Chain
46+
wg *sync.WaitGroup
47+
}
48+
49+
func newChainsMgr(mgrConf *ChainMgrConf, batchConf *BatchConf, initOp chainInitOp) *chainsMgr {
50+
ledgermgmt.Initialize()
51+
return &chainsMgr{mgrConf, batchConf, initOp, make(map[ChainID]*Chain), &sync.WaitGroup{}}
52+
}
53+
54+
func (m *chainsMgr) createOrOpenChains() []*Chain {
55+
var ledgerInitFunc func(string) (ledger.PeerLedger, error)
56+
switch m.initOp {
57+
case ChainInitOpCreate:
58+
ledgerInitFunc = createLedgerByID
59+
case ChainInitOpOpen:
60+
ledgerInitFunc = ledgermgmt.OpenLedger
61+
default:
62+
panic(fmt.Errorf("unknown chain init opeartion"))
63+
}
64+
65+
numChains := m.mgrConf.NumChains
66+
for i := 0; i < numChains; i++ {
67+
chainID := ChainID(i)
68+
peerLedger, err := ledgerInitFunc(chainID.String())
69+
benchcommon.PanicOnError(err)
70+
c := newChain(chainID, peerLedger, m)
71+
m.chainsMap[chainID] = c
72+
}
73+
return m.chains()
74+
}
75+
76+
func (m *chainsMgr) chains() []*Chain {
77+
chains := []*Chain{}
78+
for _, chain := range m.chainsMap {
79+
chains = append(chains, chain)
80+
}
81+
return chains
82+
}
83+
84+
func (m *chainsMgr) waitForChainsToExhaustAllBlocks() {
85+
m.wg.Wait()
86+
ledgermgmt.Close()
87+
}
88+
89+
// Chain extends ledger.PeerLedger and the experiments invoke ledger functions via a chain type
90+
type Chain struct {
91+
ledger.PeerLedger
92+
ID ChainID
93+
blkGenerator *blkGenerator
94+
m *chainsMgr
95+
}
96+
97+
func newChain(id ChainID, peerLedger ledger.PeerLedger, m *chainsMgr) *Chain {
98+
bcInfo, err := peerLedger.GetBlockchainInfo()
99+
benchcommon.PanicOnError(err)
100+
return &Chain{peerLedger, id, newBlkGenerator(m.batchConf, bcInfo.Height, bcInfo.CurrentBlockHash), m}
101+
}
102+
103+
func (c *Chain) startBlockPollingAndCommit() {
104+
c.m.wg.Add(1)
105+
go func() {
106+
defer c.close()
107+
for {
108+
block := c.blkGenerator.nextBlock()
109+
if block == nil {
110+
break
111+
}
112+
benchcommon.PanicOnError(c.PeerLedger.Commit(block))
113+
}
114+
}()
115+
}
116+
117+
// SubmitTx is expected to be called by an experiment for submitting the transactions
118+
func (c *Chain) SubmitTx(sr SimulationResult) {
119+
c.blkGenerator.addTx(sr)
120+
}
121+
122+
// Done is expected to be called by an experiment when the experiment does not have any more transactions to submit
123+
func (c *Chain) Done() {
124+
c.blkGenerator.close()
125+
}
126+
127+
// Commit overrides the Commit function in ledger.PeerLedger because,
128+
// experiments are not expected to call Commit directly to the ledger
129+
func (c *Chain) Commit(block *common.Block) {
130+
panic(fmt.Errorf("Commit should not be invoked directly"))
131+
}
132+
133+
func (c *Chain) close() {
134+
c.PeerLedger.Close()
135+
c.m.wg.Done()
136+
}
137+
138+
func createLedgerByID(ledgerid string) (ledger.PeerLedger, error) {
139+
gb, err := test.MakeGenesisBlock(ledgerid)
140+
benchcommon.PanicOnError(err)
141+
return ledgermgmt.CreateLedger(gb)
142+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
Copyright IBM Corp. 2017 All Rights Reserved.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package chainmgmt
18+
19+
// ChainMgrConf captures the configurations meant at the level of chainMgr
20+
// DataDir field specifies the filesystem location where the chains data is maintained
21+
// NumChains field specifies the number of chains to instantiate
22+
type ChainMgrConf struct {
23+
DataDir string
24+
NumChains int
25+
}
26+
27+
// BatchConf captures the batch related configurations
28+
// BatchSize specifies the number of transactions in one block
29+
// SignBlock specifies whether the transactions should be signed
30+
type BatchConf struct {
31+
BatchSize int
32+
SignBlock bool
33+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/*
2+
Copyright IBM Corp. 2017 All Rights Reserved.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package chainmgmt
18+
19+
import "github.com/spf13/viper"
20+
21+
// chainInitOp is a type that an experiment uses to specify how the chains
22+
// should be initialized at the beginning of the experiment. See below the
23+
// enum values for this type
24+
type chainInitOp uint8
25+
26+
const (
27+
// ChainInitOpCreate indicates that the chains should be creates afresh
28+
ChainInitOpCreate chainInitOp = iota + 1
29+
// ChainInitOpOpen indicates that the existing chains should be opened
30+
ChainInitOpOpen
31+
)
32+
33+
// TestEnv is a high level struct that the experiments are expeted to use as a starting point.
34+
// See one of the Benchmark tests for the intented usage
35+
type TestEnv struct {
36+
mgr *chainsMgr
37+
}
38+
39+
// InitTestEnv initialize TestEnv with given configurations. The initialization cuases
40+
// creation (or openning of existing) chains and the block creation and commit go routines
41+
// for each of the chains. For configurations options, see comments on specific configuration type
42+
func InitTestEnv(mgrConf *ChainMgrConf, batchConf *BatchConf, initOperation chainInitOp) *TestEnv {
43+
viper.Set("peer.fileSystemPath", mgrConf.DataDir)
44+
mgr := newChainsMgr(mgrConf, batchConf, initOperation)
45+
chains := mgr.createOrOpenChains()
46+
for _, chain := range chains {
47+
chain.startBlockPollingAndCommit()
48+
}
49+
return &TestEnv{mgr}
50+
}
51+
52+
// Chains returns handle to all the chains
53+
func (env TestEnv) Chains() []*Chain {
54+
return env.mgr.chains()
55+
}
56+
57+
// WaitForTestCompletion waits till all the transactions are committed
58+
// An experiment after launching all the goroutine should call this
59+
// so that the process is alive till all the goroutines complete
60+
func (env TestEnv) WaitForTestCompletion() {
61+
env.mgr.waitForChainsToExhaustAllBlocks()
62+
}

0 commit comments

Comments
 (0)