mirror of
https://github.com/kovidgoyal/kitty
synced 2026-07-26 18:22:09 +02:00
Start work on simple benchmark tool
This commit is contained in:
149
tools/cmd/benchmark/main.go
Normal file
149
tools/cmd/benchmark/main.go
Normal file
@@ -0,0 +1,149 @@
|
|||||||
|
// License: GPLv3 Copyright: 2023, Kovid Goyal, <kovid at kovidgoyal.net>
|
||||||
|
|
||||||
|
package benchmark
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"math/rand"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"kitty/tools/cli"
|
||||||
|
"kitty/tools/tty"
|
||||||
|
"kitty/tools/tui/loop"
|
||||||
|
"kitty/tools/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ = fmt.Print
|
||||||
|
|
||||||
|
const reset = "\x1b]\x1b\\\x1bc"
|
||||||
|
|
||||||
|
type benchmark_options struct {
|
||||||
|
alternate_screen bool
|
||||||
|
repeat_count int
|
||||||
|
}
|
||||||
|
|
||||||
|
func default_benchmark_options() benchmark_options {
|
||||||
|
return benchmark_options{alternate_screen: true, repeat_count: 10}
|
||||||
|
}
|
||||||
|
|
||||||
|
func benchmark_data(data string, opts benchmark_options) (duration time.Duration, err error) {
|
||||||
|
term, err := tty.OpenControllingTerm(tty.SetRaw)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
defer term.RestoreAndClose()
|
||||||
|
state := loop.TerminalStateOptions{Alternate_screen: opts.alternate_screen}
|
||||||
|
if _, err = term.WriteString(state.SetStateEscapeCodes()); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
defer func() { _, _ = term.WriteString(state.ResetStateEscapeCodes() + reset) }()
|
||||||
|
lock := sync.Mutex{}
|
||||||
|
const count = 3
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
lock.Lock()
|
||||||
|
defer lock.Unlock()
|
||||||
|
buf := make([]byte, 8192)
|
||||||
|
var data []byte
|
||||||
|
q := []byte(strings.Repeat("\x1b[0n", count))
|
||||||
|
for !bytes.Contains(data, q) {
|
||||||
|
n, err := term.Read(buf)
|
||||||
|
if err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
data = append(data, buf[:n]...)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
start := time.Now()
|
||||||
|
repeat_count := opts.repeat_count
|
||||||
|
for ; repeat_count > 0; repeat_count-- {
|
||||||
|
if _, err = term.WriteString(data); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if _, err = term.WriteString(strings.Repeat("\x1b[5n", count)); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
lock.Lock()
|
||||||
|
duration = time.Since(start) / time.Duration(opts.repeat_count)
|
||||||
|
lock.Unlock()
|
||||||
|
return duration, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func random_string_of_bytes(n int, alphabet string) string {
|
||||||
|
var src = rand.NewSource(time.Now().UnixNano())
|
||||||
|
const (
|
||||||
|
letterIdxBits = 7 // 7 bits to represent a letter index
|
||||||
|
letterIdxMask = 1<<letterIdxBits - 1 // All 1-bits, as many as letterIdxBits
|
||||||
|
letterIdxMax = 63 / letterIdxBits // # of letter indices fitting in 63 bits
|
||||||
|
)
|
||||||
|
b := make([]byte, n)
|
||||||
|
// A src.Int63() generates 63 random bits, enough for letterIdxMax characters!
|
||||||
|
for i, cache, remain := n-1, src.Int63(), letterIdxMax; i >= 0; {
|
||||||
|
if remain == 0 {
|
||||||
|
cache, remain = src.Int63(), letterIdxMax
|
||||||
|
}
|
||||||
|
if idx := int(cache & letterIdxMask); idx < len(alphabet) {
|
||||||
|
b[i] = alphabet[idx]
|
||||||
|
i--
|
||||||
|
}
|
||||||
|
cache >>= letterIdxBits
|
||||||
|
remain--
|
||||||
|
}
|
||||||
|
return utils.UnsafeBytesToString(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
type result struct {
|
||||||
|
desc string
|
||||||
|
data_sz int
|
||||||
|
duration time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
func simple_ascii() (r result, err error) {
|
||||||
|
data := random_string_of_bytes(1024*1024+13, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ \n\t\r `~!@#$%^&*()_+-=[]{}\\|;:'\",<.>/?")
|
||||||
|
duration, err := benchmark_data(data, default_benchmark_options())
|
||||||
|
if err != nil {
|
||||||
|
return result{}, err
|
||||||
|
}
|
||||||
|
return result{"Simple ascii characters", len(data), duration}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func present_result(r result) {
|
||||||
|
rate := float64(r.data_sz) / float64(r.duration)
|
||||||
|
rate *= 1e3
|
||||||
|
fmt.Println("\t"+r.desc+":", r.duration, fmt.Sprintf("%.2f", rate), "GiB/s")
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() (err error) {
|
||||||
|
var results []result
|
||||||
|
var r result
|
||||||
|
if r, err = simple_ascii(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
results = append(results, r)
|
||||||
|
|
||||||
|
fmt.Println(reset + "Results:")
|
||||||
|
for _, r := range results {
|
||||||
|
present_result(r)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func EntryPoint(root *cli.Command) {
|
||||||
|
sc := root.AddSubCommand(&cli.Command{
|
||||||
|
Name: "__benchmark__",
|
||||||
|
ShortDescription: "Run various benchmarks",
|
||||||
|
Hidden: true,
|
||||||
|
Run: func(cmd *cli.Command, args []string) (ret int, err error) {
|
||||||
|
if err = main(); err != nil {
|
||||||
|
ret = 1
|
||||||
|
}
|
||||||
|
return
|
||||||
|
},
|
||||||
|
})
|
||||||
|
_ = sc
|
||||||
|
}
|
||||||
@@ -18,6 +18,7 @@ import (
|
|||||||
"kitty/kittens/unicode_input"
|
"kitty/kittens/unicode_input"
|
||||||
"kitty/tools/cli"
|
"kitty/tools/cli"
|
||||||
"kitty/tools/cmd/at"
|
"kitty/tools/cmd/at"
|
||||||
|
"kitty/tools/cmd/benchmark"
|
||||||
"kitty/tools/cmd/edit_in_kitty"
|
"kitty/tools/cmd/edit_in_kitty"
|
||||||
"kitty/tools/cmd/mouse_demo"
|
"kitty/tools/cmd/mouse_demo"
|
||||||
"kitty/tools/cmd/pytest"
|
"kitty/tools/cmd/pytest"
|
||||||
@@ -121,4 +122,5 @@ func KittyToolEntryPoints(root *cli.Command) {
|
|||||||
return
|
return
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
benchmark.EntryPoint(root)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -129,12 +129,12 @@ func (self *Loop) RemoveTimer(id IdType) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *Loop) NoAlternateScreen() *Loop {
|
func (self *Loop) NoAlternateScreen() *Loop {
|
||||||
self.terminal_options.alternate_screen = false
|
self.terminal_options.Alternate_screen = false
|
||||||
return self
|
return self
|
||||||
}
|
}
|
||||||
|
|
||||||
func NoAlternateScreen(self *Loop) {
|
func NoAlternateScreen(self *Loop) {
|
||||||
self.terminal_options.alternate_screen = false
|
self.terminal_options.Alternate_screen = false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Loop) OnlyDisambiguateKeys() *Loop {
|
func (self *Loop) OnlyDisambiguateKeys() *Loop {
|
||||||
@@ -268,7 +268,7 @@ func (self *Loop) Run() (err error) {
|
|||||||
}
|
}
|
||||||
fmt.Fprintf(os.Stderr, "%s\r\n\t%s:%d\r\n", frame.Function, frame.File, frame.Line)
|
fmt.Fprintf(os.Stderr, "%s\r\n\t%s:%d\r\n", frame.Function, frame.File, frame.Line)
|
||||||
}
|
}
|
||||||
if self.terminal_options.alternate_screen {
|
if self.terminal_options.Alternate_screen {
|
||||||
term, err := tty.OpenControllingTerm(tty.SetRaw)
|
term, err := tty.OpenControllingTerm(tty.SetRaw)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
defer term.RestoreAndClose()
|
defer term.RestoreAndClose()
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ var SIGNULL unix.Signal
|
|||||||
|
|
||||||
func new_loop() *Loop {
|
func new_loop() *Loop {
|
||||||
l := Loop{controlling_term: nil}
|
l := Loop{controlling_term: nil}
|
||||||
l.terminal_options.alternate_screen = true
|
l.terminal_options.Alternate_screen = true
|
||||||
l.terminal_options.restore_colors = true
|
l.terminal_options.restore_colors = true
|
||||||
l.terminal_options.kitty_keyboard_mode = DISAMBIGUATE_KEYS | REPORT_ALTERNATE_KEYS | REPORT_ALL_KEYS_AS_ESCAPE_CODES | REPORT_TEXT_WITH_KEYS
|
l.terminal_options.kitty_keyboard_mode = DISAMBIGUATE_KEYS | REPORT_ALTERNATE_KEYS | REPORT_ALL_KEYS_AS_ESCAPE_CODES | REPORT_TEXT_WITH_KEYS
|
||||||
l.escape_code_parser.HandleCSI = l.handle_csi
|
l.escape_code_parser.HandleCSI = l.handle_csi
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type TerminalStateOptions struct {
|
type TerminalStateOptions struct {
|
||||||
alternate_screen, restore_colors bool
|
Alternate_screen, restore_colors bool
|
||||||
mouse_tracking MouseTracking
|
mouse_tracking MouseTracking
|
||||||
kitty_keyboard_mode KeyboardStateBits
|
kitty_keyboard_mode KeyboardStateBits
|
||||||
}
|
}
|
||||||
@@ -114,7 +114,7 @@ func reset_modes(sb *strings.Builder, modes ...Mode) {
|
|||||||
func (self *TerminalStateOptions) SetStateEscapeCodes() string {
|
func (self *TerminalStateOptions) SetStateEscapeCodes() string {
|
||||||
var sb strings.Builder
|
var sb strings.Builder
|
||||||
sb.Grow(256)
|
sb.Grow(256)
|
||||||
if self.alternate_screen {
|
if self.Alternate_screen {
|
||||||
sb.WriteString(SAVE_CURSOR)
|
sb.WriteString(SAVE_CURSOR)
|
||||||
}
|
}
|
||||||
sb.WriteString(SAVE_PRIVATE_MODE_VALUES)
|
sb.WriteString(SAVE_PRIVATE_MODE_VALUES)
|
||||||
@@ -126,7 +126,7 @@ func (self *TerminalStateOptions) SetStateEscapeCodes() string {
|
|||||||
IRM, DECKM, DECSCNM, BRACKETED_PASTE, FOCUS_TRACKING,
|
IRM, DECKM, DECSCNM, BRACKETED_PASTE, FOCUS_TRACKING,
|
||||||
MOUSE_BUTTON_TRACKING, MOUSE_MOTION_TRACKING, MOUSE_MOVE_TRACKING, MOUSE_UTF8_MODE, MOUSE_SGR_MODE)
|
MOUSE_BUTTON_TRACKING, MOUSE_MOTION_TRACKING, MOUSE_MOVE_TRACKING, MOUSE_UTF8_MODE, MOUSE_SGR_MODE)
|
||||||
set_modes(&sb, DECARM, DECAWM, DECTCEM)
|
set_modes(&sb, DECARM, DECAWM, DECTCEM)
|
||||||
if self.alternate_screen {
|
if self.Alternate_screen {
|
||||||
set_modes(&sb, ALTERNATE_SCREEN)
|
set_modes(&sb, ALTERNATE_SCREEN)
|
||||||
sb.WriteString(CLEAR_SCREEN)
|
sb.WriteString(CLEAR_SCREEN)
|
||||||
}
|
}
|
||||||
@@ -153,7 +153,7 @@ func (self *TerminalStateOptions) ResetStateEscapeCodes() string {
|
|||||||
var sb strings.Builder
|
var sb strings.Builder
|
||||||
sb.Grow(64)
|
sb.Grow(64)
|
||||||
sb.WriteString("\033[<u")
|
sb.WriteString("\033[<u")
|
||||||
if self.alternate_screen {
|
if self.Alternate_screen {
|
||||||
sb.WriteString(ALTERNATE_SCREEN.EscapeCodeToReset())
|
sb.WriteString(ALTERNATE_SCREEN.EscapeCodeToReset())
|
||||||
} else {
|
} else {
|
||||||
sb.WriteString(SAVE_CURSOR)
|
sb.WriteString(SAVE_CURSOR)
|
||||||
|
|||||||
Reference in New Issue
Block a user