Files
kopia/cli/command_benchmark_crypto.go
Jarek Kowalski 35d0f31c0d huge: replaced the use of allocated byte slices with populating gather.WriteBuffer in the repository (#1244)
This helps recycle buffers more efficiently during snapshots.
Also, improved memory tracking, enabled profiling flags and added pprof
by default.
2021-08-20 08:45:10 -07:00

106 lines
3.2 KiB
Go

package cli
import (
"context"
"sort"
atunits "github.com/alecthomas/units"
"github.com/kopia/kopia/internal/gather"
"github.com/kopia/kopia/internal/timetrack"
"github.com/kopia/kopia/internal/units"
"github.com/kopia/kopia/repo/content"
"github.com/kopia/kopia/repo/encryption"
"github.com/kopia/kopia/repo/hashing"
)
type commandBenchmarkCrypto struct {
blockSize atunits.Base2Bytes
repeat int
deprecatedAlgorithms bool
optionPrint bool
out textOutput
}
func (c *commandBenchmarkCrypto) setup(svc appServices, parent commandParent) {
cmd := parent.Command("crypto", "Run hash and encryption benchmarks")
cmd.Flag("block-size", "Size of a block to encrypt").Default("1MB").BytesVar(&c.blockSize)
cmd.Flag("repeat", "Number of repetitions").Default("100").IntVar(&c.repeat)
cmd.Flag("deprecated", "Include deprecated algorithms").BoolVar(&c.deprecatedAlgorithms)
cmd.Flag("print-options", "Print out options usable for repository creation").BoolVar(&c.optionPrint)
cmd.Action(svc.noRepositoryAction(c.run))
c.out.setup(svc)
}
func (c *commandBenchmarkCrypto) run(ctx context.Context) error {
type benchResult struct {
hash string
encryption string
throughput float64
}
var results []benchResult
data := make([]byte, c.blockSize)
var hashOutput [hashing.MaxHashSize]byte
var encryptOutput gather.WriteBuffer
defer encryptOutput.Close()
for _, ha := range hashing.SupportedAlgorithms() {
for _, ea := range encryption.SupportedAlgorithms(c.deprecatedAlgorithms) {
cr, err := content.CreateCrypter(&content.FormattingOptions{
Encryption: ea,
Hash: ha,
MasterKey: make([]byte, 32), // nolint:gomnd
HMACSecret: make([]byte, 32), // nolint:gomnd
})
if err != nil {
continue
}
log(ctx).Infof("Benchmarking hash '%v' and encryption '%v'... (%v x %v bytes)", ha, ea, c.repeat, len(data))
input := gather.FromSlice(data)
tt := timetrack.Start()
hashCount := c.repeat
for i := 0; i < hashCount; i++ {
contentID := cr.HashFunction(hashOutput[:0], input)
if encerr := cr.Encryptor.Encrypt(input, contentID, &encryptOutput); encerr != nil {
log(ctx).Errorf("encryption failed: %v", encerr)
break
}
}
_, bytesPerSecond := tt.Completed(float64(len(data)) * float64(hashCount))
results = append(results, benchResult{hash: ha, encryption: ea, throughput: bytesPerSecond})
}
}
sort.Slice(results, func(i, j int) bool {
return results[i].throughput > results[j].throughput
})
c.out.printStdout(" %-20v %-20v %v\n", "Hash", "Encryption", "Throughput")
c.out.printStdout("-----------------------------------------------------------------\n")
for ndx, r := range results {
c.out.printStdout("%3d. %-20v %-20v %v / second", ndx, r.hash, r.encryption, units.BytesStringBase2(int64(r.throughput)))
if c.optionPrint {
c.out.printStdout(", --block-hash=%s --encryption=%s", r.hash, r.encryption)
}
c.out.printStdout("\n")
}
c.out.printStdout("-----------------------------------------------------------------\n")
c.out.printStdout("Fastest option for this machine is: --block-hash=%s --encryption=%s\n", results[0].hash, results[0].encryption)
return nil
}