Skip to content
This repository was archived by the owner on Jan 24, 2025. It is now read-only.

Commit 6c0e69b

Browse files
authored
Merge pull request #965 from iotaledger/feat/add-tools
Add more tools
2 parents ebb1105 + 4e53bd7 commit 6c0e69b

File tree

9 files changed

+470
-19
lines changed

9 files changed

+470
-19
lines changed

Diff for: go.mod

+6-4
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ replace github.com/goccy/go-graphviz => github.com/alexsporn/go-graphviz v0.0.0-
66

77
require (
88
github.com/VictoriaMetrics/fastcache v1.12.2
9+
github.com/dustin/go-humanize v1.0.1
910
github.com/fjl/memsize v0.0.2
1011
github.com/goccy/go-graphviz v0.1.2
1112
github.com/golang-jwt/jwt v3.2.2+incompatible
@@ -26,6 +27,7 @@ require (
2627
github.com/iotaledger/hive.go/serializer/v2 v2.0.0-rc.1.0.20240425095808-113b21573349
2728
github.com/iotaledger/hive.go/sql v0.0.0-20240425095808-113b21573349
2829
github.com/iotaledger/hive.go/stringify v0.0.0-20240425095808-113b21573349
30+
github.com/iotaledger/hive.go/web v0.0.0-20240425095808-113b21573349
2931
github.com/iotaledger/inx-app v1.0.0-rc.3.0.20240425100742-5c85b6d16701
3032
github.com/iotaledger/inx/go v1.0.0-rc.2.0.20240425100432-05e1bf8fc089
3133
github.com/iotaledger/iota.go/v4 v4.0.0-20240503105040-c86882e71808
@@ -45,7 +47,8 @@ require (
4547
github.com/zyedidia/generic v1.2.1
4648
go.uber.org/atomic v1.11.0
4749
go.uber.org/dig v1.17.1
48-
golang.org/x/crypto v0.22.0
50+
golang.org/x/crypto v0.23.0
51+
golang.org/x/term v0.20.0
4952
google.golang.org/grpc v1.63.2
5053
google.golang.org/protobuf v1.33.0
5154
gorm.io/gorm v1.25.9
@@ -63,7 +66,6 @@ require (
6366
github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c // indirect
6467
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect
6568
github.com/docker/go-units v0.5.0 // indirect
66-
github.com/dustin/go-humanize v1.0.1 // indirect
6769
github.com/eclipse/paho.mqtt.golang v1.4.3 // indirect
6870
github.com/elastic/gosigar v0.14.3 // indirect
6971
github.com/ethereum/go-ethereum v1.14.0 // indirect
@@ -183,8 +185,8 @@ require (
183185
golang.org/x/mod v0.17.0 // indirect
184186
golang.org/x/net v0.24.0 // indirect
185187
golang.org/x/sync v0.7.0 // indirect
186-
golang.org/x/sys v0.19.0 // indirect
187-
golang.org/x/text v0.14.0 // indirect
188+
golang.org/x/sys v0.20.0 // indirect
189+
golang.org/x/text v0.15.0 // indirect
188190
golang.org/x/time v0.5.0 // indirect
189191
golang.org/x/tools v0.20.0 // indirect
190192
gonum.org/v1/gonum v0.15.0 // indirect

Diff for: go.sum

+10-6
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,8 @@ github.com/iotaledger/hive.go/sql v0.0.0-20240425095808-113b21573349 h1:+bHqh0gC
321321
github.com/iotaledger/hive.go/sql v0.0.0-20240425095808-113b21573349/go.mod h1:nEwIUQIvNMUs2DwM2870Er3foVQTzwPDUtzEKy+evGg=
322322
github.com/iotaledger/hive.go/stringify v0.0.0-20240425095808-113b21573349 h1:9cuEF+WvxB/xBLkQu6H3/pHYE5KAqY98oniUFYezvzc=
323323
github.com/iotaledger/hive.go/stringify v0.0.0-20240425095808-113b21573349/go.mod h1:O4p7UmsfoeLqtAUwrKbq0lXMxjY/MLQSpZSavvvvGig=
324+
github.com/iotaledger/hive.go/web v0.0.0-20240425095808-113b21573349 h1:LrLWPsUcbZjR3kF5NJbuou84l+aCm8dPx4S5pQ/9bJ0=
325+
github.com/iotaledger/hive.go/web v0.0.0-20240425095808-113b21573349/go.mod h1:YhGg68kOBM083FzmxjhQD3n/8AeG/4xr4fgM6qq1q9I=
324326
github.com/iotaledger/inx-app v1.0.0-rc.3.0.20240425100742-5c85b6d16701 h1:YWIaqOp7+DjxG4O6797Uw+K8rPRJN56rbwX6KpWsvEc=
325327
github.com/iotaledger/inx-app v1.0.0-rc.3.0.20240425100742-5c85b6d16701/go.mod h1:oqSLTV1hlpdLdi0MWt39c+EFgERdPM34ACAYM+4g3Oc=
326328
github.com/iotaledger/inx/go v1.0.0-rc.2.0.20240425100432-05e1bf8fc089 h1:+NRPSbH6tkop8p+MhjCR9nvs8ng3Oo2yju5FXcDEkBY=
@@ -750,8 +752,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
750752
golang.org/x/crypto v0.0.0-20200602180216-279210d13fed/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
751753
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
752754
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
753-
golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30=
754-
golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
755+
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
756+
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
755757
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
756758
golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f h1:99ci1mjWVBWwJiEKYY6jWa4d2nTQVIEhZIptnrVb1XY=
757759
golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f/go.mod h1:/lliqkxwWAhPjf5oSOIJup2XcqJaw8RGS6k3TGEc7GI=
@@ -854,18 +856,20 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc
854856
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
855857
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
856858
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
857-
golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
858-
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
859+
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
860+
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
859861
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
862+
golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw=
863+
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
860864
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
861865
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
862866
golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
863867
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
864868
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
865869
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
866870
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
867-
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
868-
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
871+
golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
872+
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
869873
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
870874
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
871875
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=

Diff for: pkg/toolset/benchmark.go

+175
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
package toolset
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"os"
7+
"runtime"
8+
"sync"
9+
"time"
10+
11+
"github.com/dustin/go-humanize"
12+
flag "github.com/spf13/pflag"
13+
14+
"github.com/iotaledger/hive.go/app/configuration"
15+
"github.com/iotaledger/hive.go/db"
16+
"github.com/iotaledger/hive.go/kvstore"
17+
"github.com/iotaledger/iota-core/pkg/storage/database"
18+
iotago_tpkg "github.com/iotaledger/iota.go/v4/tpkg"
19+
)
20+
21+
// estimateRemainingTime estimates the remaining time for a running operation and returns the finished percentage.
22+
func estimateRemainingTime(timeStart time.Time, current int64, total int64) (percentage float64, remaining time.Duration) {
23+
ratio := float64(current) / float64(total)
24+
totalTime := time.Duration(float64(time.Since(timeStart)) / ratio)
25+
remaining = time.Until(timeStart.Add(totalTime))
26+
27+
return ratio * 100.0, remaining
28+
}
29+
30+
func benchmarkIO(args []string) error {
31+
fs := configuration.NewUnsortedFlagSet("", flag.ContinueOnError)
32+
objectsCountFlag := fs.Int(FlagToolBenchmarkCount, 500000, "objects count")
33+
objectsSizeFlag := fs.Int(FlagToolBenchmarkSize, 1000, "objects size in bytes")
34+
35+
fs.Usage = func() {
36+
fmt.Fprintf(os.Stderr, "Usage of %s:\n", ToolBenchmarkIO)
37+
fs.PrintDefaults()
38+
println(fmt.Sprintf("\nexample: %s --%s %d --%s %d",
39+
ToolBenchmarkIO,
40+
FlagToolBenchmarkCount,
41+
500000,
42+
FlagToolBenchmarkSize,
43+
1000))
44+
}
45+
46+
if err := parseFlagSet(fs, args); err != nil {
47+
return err
48+
}
49+
50+
objectCnt := *objectsCountFlag
51+
size := *objectsSizeFlag
52+
53+
tempDir, err := os.MkdirTemp("", "benchmarkIO")
54+
if err != nil {
55+
return fmt.Errorf("can't create temp dir: %w", err)
56+
}
57+
58+
defer func() { _ = os.RemoveAll(tempDir) }()
59+
60+
store, err := database.StoreWithDefaultSettings(tempDir, true, db.EngineRocksDB, db.EngineRocksDB)
61+
if err != nil {
62+
return fmt.Errorf("database initialization failed: %w", err)
63+
}
64+
65+
batchWriter := kvstore.NewBatchedWriter(store)
66+
writeDoneWaitGroup := &sync.WaitGroup{}
67+
writeDoneWaitGroup.Add(objectCnt)
68+
69+
ts := time.Now()
70+
71+
lastStatusTime := time.Now()
72+
for i := 0; i < objectCnt; i++ {
73+
// one read operation and one write operation per cycle
74+
batchWriter.Enqueue(newBenchmarkObject(store, writeDoneWaitGroup, iotago_tpkg.RandBytes(32), iotago_tpkg.RandBytes(size)))
75+
76+
if time.Since(lastStatusTime) >= printStatusInterval {
77+
lastStatusTime = time.Now()
78+
79+
duration := time.Since(ts)
80+
bytes := uint64(i * (32 + size))
81+
totalBytes := uint64(objectCnt * (32 + size))
82+
bytesPerSecond := uint64(float64(bytes) / duration.Seconds())
83+
objectsPerSecond := uint64(float64(i) / duration.Seconds())
84+
percentage, remaining := estimateRemainingTime(ts, int64(i), int64(objectCnt))
85+
fmt.Printf("Average IO speed: %s/s (%dx 32+%d byte chunks, total %s/%s, %d objects/s, %0.2f%%. %v left ...)\n", humanize.Bytes(bytesPerSecond), i, size, humanize.Bytes(bytes), humanize.Bytes(totalBytes), objectsPerSecond, percentage, remaining.Truncate(time.Second))
86+
}
87+
}
88+
89+
writeDoneWaitGroup.Wait()
90+
91+
if err := store.Flush(); err != nil {
92+
return fmt.Errorf("flush database failed: %w", err)
93+
}
94+
95+
if err := store.Close(); err != nil {
96+
return fmt.Errorf("close database failed: %w", err)
97+
}
98+
99+
te := time.Now()
100+
duration := te.Sub(ts)
101+
totalBytes := uint64(objectCnt * (32 + size))
102+
bytesPerSecond := uint64(float64(totalBytes) / duration.Seconds())
103+
objectsPerSecond := uint64(float64(objectCnt) / duration.Seconds())
104+
105+
fmt.Printf("Average IO speed: %s/s (%dx 32+%d byte chunks, total %s/%s, %d objects/s, took %v)\n", humanize.Bytes(bytesPerSecond), objectCnt, size, humanize.Bytes(totalBytes), humanize.Bytes(totalBytes), objectsPerSecond, duration.Truncate(time.Millisecond))
106+
107+
return nil
108+
}
109+
110+
func benchmarkCPU(args []string) error {
111+
fs := configuration.NewUnsortedFlagSet("", flag.ContinueOnError)
112+
cpuThreadsFlag := fs.Int(FlagToolBenchmarkThreads, runtime.NumCPU(), "thread count")
113+
durationFlag := fs.Duration(FlagToolBenchmarkDuration, 1*time.Minute, "duration")
114+
115+
fs.Usage = func() {
116+
fmt.Fprintf(os.Stderr, "Usage of %s:\n", ToolBenchmarkCPU)
117+
fs.PrintDefaults()
118+
println(fmt.Sprintf("\nexample: %s --%s %d --%s 1m0s",
119+
ToolBenchmarkCPU,
120+
FlagToolBenchmarkThreads,
121+
2,
122+
FlagToolBenchmarkDuration))
123+
}
124+
125+
if err := parseFlagSet(fs, args); err != nil {
126+
return err
127+
}
128+
129+
threads := *cpuThreadsFlag
130+
duration := *durationFlag
131+
132+
benchmarkCtx, benchmarkCtxCancel := context.WithTimeout(context.Background(), duration)
133+
defer benchmarkCtxCancel()
134+
135+
ts := time.Now()
136+
137+
// doBenchmarkCPU mines with blake2b until the context has been canceled.
138+
// it returns the number of calculated hashes.
139+
doBenchmarkCPU := func(ctx context.Context, numWorkers int) uint64 {
140+
var counter uint64
141+
var wg sync.WaitGroup
142+
143+
// random digest
144+
powDigest := iotago_tpkg.RandBytes(32)
145+
146+
go func() {
147+
for ctx.Err() == nil {
148+
time.Sleep(printStatusInterval)
149+
150+
elapsed := time.Since(ts)
151+
percentage, remaining := estimateRemainingTime(ts, elapsed.Milliseconds(), duration.Milliseconds())
152+
megahashesPerSecond := float64(counter) / (elapsed.Seconds() * 1000000)
153+
fmt.Printf("Average CPU speed: %0.2fMH/s (%d thread(s), %0.2f%%. %v left ...)\n", megahashesPerSecond, numWorkers, percentage, remaining.Truncate(time.Second))
154+
}
155+
}()
156+
157+
for i := 0; i < numWorkers; i++ {
158+
wg.Add(1)
159+
go func() {
160+
defer wg.Done()
161+
162+
cpuBenchmarkWorker(ctx, powDigest, &counter)
163+
}()
164+
}
165+
wg.Wait()
166+
167+
return counter
168+
}
169+
170+
hashes := doBenchmarkCPU(benchmarkCtx, threads)
171+
megahashesPerSecond := float64(hashes) / (duration.Seconds() * 1000000)
172+
fmt.Printf("Average CPU speed: %0.2fMH/s (%d thread(s), took %v)\n", megahashesPerSecond, threads, duration.Truncate(time.Millisecond))
173+
174+
return nil
175+
}

Diff for: pkg/toolset/benchmark_cpu.go

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package toolset
2+
3+
import (
4+
"context"
5+
"crypto"
6+
"sync/atomic"
7+
8+
"golang.org/x/crypto/blake2b"
9+
)
10+
11+
const (
12+
// Hash defines the hash function that is used to compute the PoW digest.
13+
Hash = crypto.BLAKE2b_256
14+
)
15+
16+
func cpuBenchmarkWorker(ctx context.Context, powDigest []byte, counter *uint64) {
17+
for {
18+
select {
19+
case <-ctx.Done():
20+
return
21+
22+
default:
23+
result := blake2b.Sum256(powDigest)
24+
powDigest = result[:]
25+
atomic.AddUint64(counter, 1)
26+
}
27+
}
28+
}

Diff for: pkg/toolset/benchmark_io.go

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package toolset
2+
3+
import (
4+
"fmt"
5+
"sync"
6+
7+
"github.com/iotaledger/hive.go/kvstore"
8+
iotago_tpkg "github.com/iotaledger/iota.go/v4/tpkg"
9+
)
10+
11+
type benchmarkObject struct {
12+
store kvstore.KVStore
13+
writeDoneWaitGroup *sync.WaitGroup
14+
key []byte
15+
value []byte
16+
}
17+
18+
func newBenchmarkObject(store kvstore.KVStore, writeDoneWaitGroup *sync.WaitGroup, key []byte, value []byte) *benchmarkObject {
19+
return &benchmarkObject{
20+
store: store,
21+
writeDoneWaitGroup: writeDoneWaitGroup,
22+
key: key,
23+
value: value,
24+
}
25+
}
26+
27+
func (bo *benchmarkObject) BatchWrite(batchedMuts kvstore.BatchedMutations) {
28+
if err := batchedMuts.Set(bo.key, bo.value); err != nil {
29+
panic(fmt.Errorf("write operation failed: %w", err))
30+
}
31+
}
32+
33+
func (bo *benchmarkObject) BatchWriteDone() {
34+
// do a read operation after the batchwrite is done,
35+
// so the write and read operations are equally distributed over the whole benchmark run.
36+
if _, err := bo.store.Has(iotago_tpkg.RandBytes(32)); err != nil {
37+
panic(fmt.Errorf("read operation failed: %w", err))
38+
}
39+
40+
bo.writeDoneWaitGroup.Done()
41+
}
42+
43+
func (bo *benchmarkObject) BatchWriteScheduled() bool {
44+
return false
45+
}
46+
47+
func (bo *benchmarkObject) ResetBatchWriteScheduled() {
48+
// do nothing
49+
}

0 commit comments

Comments
 (0)