summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Milde <daniel@milde.cz>2024-04-20 01:28:10 +0200
committerDaniel Milde <daniel@milde.cz>2024-04-20 01:30:14 +0200
commit32e516a464a391d3ea51313327b6cf11a94b89dc (patch)
tree92ff84cbb17139b651493bc5e5cfcdc0be621891
parentb8836d336b371e00c44ed61bec34fb3914abc709 (diff)
chore: benchmark for parallel deletiondundee/feat/bench-deletion
-rw-r--r--Makefile7
-rw-r--r--bench-delete.md4
-rw-r--r--cmd/deleter/main.go109
-rw-r--r--trace-parallel.outbin0 -> 7566 bytes
-rw-r--r--trace-single.outbin0 -> 6708 bytes
5 files changed, 120 insertions, 0 deletions
diff --git a/Makefile b/Makefile
index cf6b3a1..0d5a003 100644
--- a/Makefile
+++ b/Makefile
@@ -130,6 +130,13 @@ benchmark:
'gdu -npc ~' 'gdu -gnpc ~' 'gdu -npc --use-storage ~'
sudo cpupower frequency-set -g schedutil
+benchmark-deletion:
+ hyperfine \
+ --export-markdown=bench-delete.md \
+ --prepare 'cd test; git init . ; fallocate -l 1G .git/info/file ; dd if=/dev/urandom of=.git/refs/file bs=64M count=8 iflag=fullblock ; dd if=/dev/urandom of=.git/objects/file bs=64M count=8 iflag=fullblock ; cd ..' \
+ 'go run ./cmd/deleter/main.go ./test/.git' \
+ 'go run ./cmd/deleter/main.go --parallel ./test/.git'
+
clean:
go mod tidy
-rm coverage.txt
diff --git a/bench-delete.md b/bench-delete.md
new file mode 100644
index 0000000..584041c
--- /dev/null
+++ b/bench-delete.md
@@ -0,0 +1,4 @@
+| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
+|:---|---:|---:|---:|---:|
+| `go run ./cmd/deleter/main.go ./test/.git` | 840.3 ± 648.5 | 504.2 | 2137.6 | 1.00 |
+| `go run ./cmd/deleter/main.go --parallel ./test/.git` | 902.1 ± 885.1 | 476.1 | 3168.0 | 1.07 ± 1.34 |
diff --git a/cmd/deleter/main.go b/cmd/deleter/main.go
new file mode 100644
index 0000000..a9b36ad
--- /dev/null
+++ b/cmd/deleter/main.go
@@ -0,0 +1,109 @@
+package main
+
+import (
+ "flag"
+ "fmt"
+ "io"
+ "os"
+ "path/filepath"
+ "runtime/trace"
+ "time"
+
+ "github.com/dundee/gdu/v5/pkg/fs"
+ "github.com/dundee/gdu/v5/pkg/remove"
+)
+
+func main() {
+ inParallel := flag.Bool("parallel", false, "Delete in parallel")
+ tracing := flag.Bool("trace", false, "Collect CPU trace")
+ flag.Parse()
+ args := flag.Args()
+
+ if len(args) < 1 {
+ fmt.Println("Usage: [--parallel] directory_to_delete")
+ return
+ }
+
+ if info, err := os.Stat(args[0]); os.IsNotExist(err) {
+ fmt.Println("Path does not exist")
+ return
+ } else if !info.IsDir() {
+ fmt.Println("Path is not directory")
+ return
+ }
+ path, err := filepath.Abs(args[0])
+ if err != nil {
+ fmt.Println("Cannot convert to absolute: ", err.Error())
+ }
+
+ deleter := remove.RemoveItemFromDir
+ if *inParallel {
+ deleter = remove.RemoveItemFromDirParallel
+ }
+
+ if *tracing {
+ f, err := os.Create("trace.out")
+ if err != nil {
+ fmt.Println("Trace file cannot be created: ", err.Error())
+ return
+ }
+ trace.Start(f)
+ }
+
+ err = deleter(NewDeletedItem(""), NewDeletedItem(path))
+ if err != nil {
+ fmt.Println("Failed with: ", err.Error())
+ }
+ trace.Stop()
+}
+
+func NewDeletedItem(path string) fs.Item {
+ return &DeletedItem{
+ Path: path,
+ }
+}
+
+type DeletedItem struct {
+ Path string
+}
+
+func (p *DeletedItem) GetPath() string {
+ return p.Path
+}
+func (p *DeletedItem) GetFilesLocked() fs.Files {
+ var items []fs.Item
+ entries, err := os.ReadDir(p.Path)
+ if err != nil {
+ panic(err)
+ }
+
+ for _, entry := range entries {
+ path := filepath.Join(p.Path, entry.Name())
+ items = append(items, NewDeletedItem(path))
+ }
+ return items
+}
+func (p *DeletedItem) IsDir() bool { return true }
+func (f *DeletedItem) RemoveFile(item fs.Item) {}
+
+func (p *DeletedItem) GetName() string { panic("must not be called") }
+func (p *DeletedItem) GetFlag() rune { panic("must not be called") }
+func (p *DeletedItem) GetSize() int64 { panic("must not be called") }
+func (p *DeletedItem) GetType() string { panic("must not be called") }
+func (p *DeletedItem) GetUsage() int64 { panic("must not be called") }
+func (p *DeletedItem) GetMtime() time.Time { panic("must not be called") }
+func (p *DeletedItem) GetItemCount() int { panic("must not be called") }
+func (p *DeletedItem) GetParent() fs.Item { panic("must not be called") }
+func (p *DeletedItem) SetParent(fs.Item) { panic("must not be called") }
+func (p *DeletedItem) GetMultiLinkedInode() uint64 { panic("must not be called") }
+func (p *DeletedItem) EncodeJSON(writer io.Writer, topLevel bool) error { panic("must not be called") }
+func (p *DeletedItem) UpdateStats(linkedItems fs.HardLinkedItems) { panic("must not be called") }
+func (p *DeletedItem) AddFile(fs.Item) { panic("must not be called") }
+func (p *DeletedItem) GetFiles() fs.Files { panic("must not be called") }
+func (p *DeletedItem) RLock() func() { panic("must not be called") }
+func (p *DeletedItem) SetFiles(fs.Files) { panic("must not be called") }
+func (p *DeletedItem) GetItemStats(
+ linkedItems fs.HardLinkedItems,
+) (int, int64, int64) {
+ panic("must not be called")
+}
diff --git a/trace-parallel.out b/trace-parallel.out
new file mode 100644
index 0000000..132fe09
--- /dev/null
+++ b/trace-parallel.out
Binary files differ
diff --git a/trace-single.out b/trace-single.out
new file mode 100644
index 0000000..ed01939
--- /dev/null
+++ b/trace-single.out
Binary files differ