Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

examples: add the Benchmark tool for TiKV #1331

Open
wants to merge 34 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
53d8ecb
benchtool: basement of benchmarking tool for TiKV.
LykxSassinator Apr 30, 2024
e552ec0
Format and fix errors.
LykxSassinator Apr 30, 2024
70b6d84
Polish codes on rawkv part.
LykxSassinator May 6, 2024
b312db7
Add timeout.
LykxSassinator May 6, 2024
f87391b
Polish codes and the output format of RawKV.
LykxSassinator May 6, 2024
14d0c45
Polish output format of RawKV.
LykxSassinator May 6, 2024
ce1410e
Merge branch 'tikv:master' into bench_tool
LykxSassinator May 7, 2024
b0a74a1
Support batch cmds for RawKV workloads.
LykxSassinator May 7, 2024
d269823
Build basic framework for supporting txn workloads.
LykxSassinator May 9, 2024
ee2e154
Polish codes.
LykxSassinator May 9, 2024
4241a50
Polish codes.
LykxSassinator May 9, 2024
18ce51b
Fix bugs.
LykxSassinator May 9, 2024
968b610
Fix errs when cleaning up keys.
LykxSassinator May 9, 2024
d1f50b5
Remove unnecessary arguments.
LykxSassinator May 9, 2024
aafac36
Support pessimistic mode.
LykxSassinator May 13, 2024
b7b91f0
Support other RawKV commands expect xxx_ttl commands.
LykxSassinator May 16, 2024
08dcf3f
Polish codes.
LykxSassinator Jun 25, 2024
769d50a
Refactor and polish codes.
LykxSassinator Jun 26, 2024
2733847
Add basical framwork for supporting loading manual specifying workloa…
LykxSassinator Jun 27, 2024
b63c244
Support pattern workloads.
LykxSassinator Aug 7, 2024
2443cf2
Merge branch 'master' into bench_tool
LykxSassinator Aug 9, 2024
4b0963b
Merge branch 'master' into bench_tool
LykxSassinator Aug 22, 2024
769f5e5
Bugfix.
LykxSassinator Aug 22, 2024
38e82a5
Polish codes.
LykxSassinator Aug 22, 2024
cc845c4
Add logger.
LykxSassinator Aug 22, 2024
3ae05a4
Polish codes.
LykxSassinator Aug 22, 2024
31e4d8e
Fix the test example.
LykxSassinator Aug 22, 2024
be5d5e2
Merge branch 'master' into bench_tool
LykxSassinator Aug 23, 2024
07b849e
Polish codes.
LykxSassinator Aug 26, 2024
7865a2f
Add some extra annotations.
LykxSassinator Aug 26, 2024
6aef6c3
Polish codes.
LykxSassinator Sep 3, 2024
e8d9554
Add extra annotations for the performance results.
LykxSassinator Sep 3, 2024
0fc92e6
Fix cf setting bugs.
LykxSassinator Sep 13, 2024
2018333
Upload missing prs.
LykxSassinator Oct 23, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
152 changes: 152 additions & 0 deletions examples/benchtool/config/global.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
// Copyright 2024 TiKV Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package config

import (
"fmt"
"os"
"strconv"
"sync"
"time"

"github.com/pingcap/errors"
"github.com/pingcap/log"
"github.com/spf13/cobra"
"github.com/tikv/client-go/v2/config"
"go.uber.org/zap"
)

var initOnce = sync.Once{}

const (
WorkloadColumnFamilyDefault = "default"
WorkloadColumnFamilyWrite = "write"
WorkloadColumnFamilyLock = "lock"
)

type GlobalConfig struct {
ips []string
port int
host string

Threads int
TotalTime time.Duration
TotalCount int
DropData bool
IgnoreError bool
OutputInterval time.Duration
Silence bool
OutputStyle string

Targets []string
Security config.Security

// for log
LogLevel string
LogFile string
}

func (c *GlobalConfig) ParsePdAddrs() error {
if len(c.ips) == 0 && c.host == "" {
return fmt.Errorf("PD address is empty")
}
targets := make([]string, 0, len(c.ips))
for _, host := range c.ips {
targets = append(targets, host+":"+strconv.Itoa(c.port))
}
if c.host != "" {
targets = append(targets, c.host)
}
c.Targets = targets
return nil
}

func (c *GlobalConfig) Format() string {
return fmt.Sprintf("Host: %s, IPs: %v, Port: %d, Threads: %d, TotalTime: %v, TotalCount: %d, DropData: %t, IgnoreError: %t, OutputInterval: %v, Silence: %t, OutputStyle: %s",
c.host, c.ips, c.port, c.Threads, c.TotalTime, c.TotalCount, c.DropData, c.IgnoreError, c.OutputInterval, c.Silence, c.OutputStyle)
}

func (c *GlobalConfig) InitLogger() (err error) {
initOnce.Do(func() {
// Initialize the logger.
conf := &log.Config{
Level: c.LogLevel,
File: log.FileLogConfig{
Filename: c.LogFile,
MaxSize: 256,
},
}
lg, p, e := log.InitLogger(conf)
if e != nil {
err = e
return
}
log.ReplaceGlobals(lg, p)
})
return errors.Trace(err)
}

type CommandLineParser struct {
command *cobra.Command
config *GlobalConfig
}

func NewCommandLineParser() *CommandLineParser {
return &CommandLineParser{}
}

func (p *CommandLineParser) Initialize() {
var globalCfg = &GlobalConfig{}
var rootCmd = &cobra.Command{
Use: "bench-tool",
Short: "Benchmark tikv with different workloads",
PersistentPreRun: func(cmd *cobra.Command, args []string) {
if err := globalCfg.InitLogger(); err != nil {
log.Error("InitLogger failed", zap.Error(err))
}
},
}

rootCmd.PersistentFlags().StringSliceVarP(&globalCfg.ips, "ip", "I", []string{"127.0.0.1"}, "PD ips")
rootCmd.PersistentFlags().IntVarP(&globalCfg.port, "port", "P", 2379, "PD port")
rootCmd.PersistentFlags().StringVar(&globalCfg.host, "host", "127.0.0.1:2379", "PD address")

rootCmd.PersistentFlags().IntVarP(&globalCfg.Threads, "threads", "T", 1, "Thread concurrency")
rootCmd.PersistentFlags().DurationVar(&globalCfg.TotalTime, "time", 1<<63-1, "Total execution time")
rootCmd.PersistentFlags().IntVar(&globalCfg.TotalCount, "count", 0, "Total execution count, 0 means infinite")
rootCmd.PersistentFlags().BoolVar(&globalCfg.DropData, "dropdata", false, "Cleanup data before prepare")
rootCmd.PersistentFlags().BoolVar(&globalCfg.IgnoreError, "ignore-error", false, "Ignore error when running workload")
rootCmd.PersistentFlags().BoolVar(&globalCfg.Silence, "silence", false, "Don't print error when running workload")
rootCmd.PersistentFlags().DurationVar(&globalCfg.OutputInterval, "interval", 10*time.Second, "Output interval time")
rootCmd.PersistentFlags().StringVar(&globalCfg.OutputStyle, "output", "plain", "output style, valid values can be { plain | table | json }")

rootCmd.PersistentFlags().StringVar(&globalCfg.LogFile, "log-file", "record.log", "filename of the log file")
rootCmd.PersistentFlags().StringVar(&globalCfg.LogLevel, "log-level", "info", "log level { debug | info | warn | error | fatal }")

rootCmd.SetOut(os.Stdout)

cobra.EnablePrefixMatching = true

p.command = rootCmd
p.config = globalCfg
}

func (p *CommandLineParser) GetConfig() *GlobalConfig {
return p.config
}

func (p *CommandLineParser) GetCommand() *cobra.Command {
return p.command
}
154 changes: 154 additions & 0 deletions examples/benchtool/config/pattern.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
// Copyright 2024 TiKV Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package config

import (
"fmt"
"os"

"gopkg.in/yaml.v3"
)

const (
WorkloadTypeHybrid = "hybrid"
)

// TODO: convert the txnConfig and rawkvConfig to interfaces
type SubPatternConfig struct {
txnConfig *TxnKVConfig
rawkvConfig *RawKVConfig
workloads []string
name string
}

func (s *SubPatternConfig) GetName() string {
return s.name
}

func (s *SubPatternConfig) GetWorkloads() []string {
return s.workloads
}

func (s *SubPatternConfig) GetTxnKVConfig() *TxnKVConfig {
return s.txnConfig
}

func (s *SubPatternConfig) GetRawKVConfig() *RawKVConfig {
return s.rawkvConfig
}

type SubPattern struct {
Name string `yaml:"name,omitempty"`
WorkloadType string `yaml:"workload_type,omitempty"`
Workloads []string `yaml:"workloads,omitempty"`

// for txnkv
Mode string `yaml:"mode,omitempty"`
LockTimeout int `yaml:"lock_timeout"`
ColumnSize int `yaml:"column_size"`
TxnSize int `yaml:"txn_size"`
// common
Count int `yaml:"count"`
KeyPrefix string `yaml:"key_prefix,omitempty"`
KeySize int `yaml:"key_size"`
ValueSize int `yaml:"value_size"`
BatchSize int `yaml:"batch_size"`
Threads int `yaml:"threads"`
Randomize bool `yaml:"random"`
}

func (s *SubPattern) ConvertBasedOn(global *GlobalConfig) *SubPatternConfig {
// Invalid workloads
if s.Workloads == nil {
return nil
}

globalCfg := &GlobalConfig{}
if global != nil {
globalCfg = global
}
globalCfg.TotalCount = s.Count
globalCfg.Threads = s.Threads

switch s.WorkloadType {
case WorkloadTypeTxnKV:
config := &TxnKVConfig{
TxnMode: s.Mode,
LockTimeout: s.LockTimeout,
// KeyPrefix: s.key_prefix,
KeySize: s.KeySize,
ValueSize: s.ValueSize,
ColumnSize: s.ColumnSize,
TxnSize: s.TxnSize,
}
config.Global = globalCfg
return &SubPatternConfig{
txnConfig: config,
workloads: s.Workloads,
name: s.Name,
}
case WorkloadTypeRawKV:
config := &RawKVConfig{
// KeyPrefix: s.key_prefix,
KeySize: s.KeySize,
BatchSize: s.BatchSize,
ValueSize: s.ValueSize,
Randomize: s.Randomize,
}
config.Global = globalCfg
return &SubPatternConfig{
rawkvConfig: config,
workloads: s.Workloads,
name: s.Name,
}
}
return nil
}

type PatternsConfig struct {
Items []*SubPattern `yaml:"patterns"`

FilePath string

Plans []*SubPatternConfig
Global *GlobalConfig
}

// Parse parses the yaml file.
func (p *PatternsConfig) Parse() error {
data, err := os.ReadFile(p.FilePath)
if err != nil {
return err
}
err = yaml.Unmarshal(data, p)
if err != nil {
return err
}
p.Plans = make([]*SubPatternConfig, 0, len(p.Items))
for _, item := range p.Items {
p.Plans = append(p.Plans, item.ConvertBasedOn(p.Global))
}
return nil
}

func (p *PatternsConfig) Validate() error {
if p.Global == nil {
return fmt.Errorf("global config is missing")
}
if p.Items == nil {
return fmt.Errorf("patterns config is missing")
}
return p.Global.ParsePdAddrs()
}
66 changes: 66 additions & 0 deletions examples/benchtool/config/rawkv.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// Copyright 2024 TiKV Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package config

import (
"fmt"
"time"
)

const (
WorkloadTypeRawKV = "rawkv"
)

const (
RawKVCommandTypePut = "put"
RawKVCommandTypeGet = "get"
RawKVCommandTypeDel = "del"
RawKVCommandTypeBatchPut = "batch_put"
RawKVCommandTypeBatchGet = "batch_get"
RawKVCommandTypeBatchDel = "batch_del"
RawKVCommandTypeScan = "scan"
RawKVCommandTypeReverseScan = "reverse_scan"
RawKVCommandTypeCAS = "cas"

RawKVCommandDefaultKey = "rawkv_key"
RawKVCommandDefaultEndKey = "rawkv_key`"
RawKVCommandDefaultValue = "rawkv_value"
)

type RawKVConfig struct {
KeySize int
ValueSize int
BatchSize int

ColumnFamily string
CommandType string
PrepareRetryCount int
PrepareRetryInterval time.Duration
Randomize bool

Global *GlobalConfig
}

func (c *RawKVConfig) Validate() error {
if c.KeySize <= 0 || c.ValueSize <= 0 {
return fmt.Errorf("key size or value size must be greater than 0")
}
if c.ColumnFamily != WorkloadColumnFamilyDefault &&
c.ColumnFamily != WorkloadColumnFamilyWrite &&
c.ColumnFamily != WorkloadColumnFamilyLock {
return fmt.Errorf("invalid column family: %s", c.ColumnFamily)
}
return c.Global.ParsePdAddrs()
}
Loading
Loading