This is the sixth day of my participation in the August Text Challenge.More challenges in August

Benchmark Tests a program against benchmarks: Benchmark

code

package aes import ( "bytes" "crypto/aes" "crypto/cipher" "encoding/base64" "fmt" "log" "os" "testing" ) func AesEncryptA(aesKey, IV, origin []byte) []byte { block, err := aes.NewCipher(aesKey) if err ! = nil { return nil } blocksize := block.BlockSize() blockMode := cipher.NewCBCEncrypter(block, IV) originData := PKCS5Padding(origin, blocksize) crypted := make([]byte, len(originData)) blockMode.CryptBlocks(crypted, originData) return crypted } func AesEncryptB(aesKey, IV, origin []byte) []byte { block, err := aes.NewCipher(aesKey) if err ! = nil { return nil } blocksize := block.BlockSize() blockMode := cipher.NewCBCEncrypter(block, IV) originData := PKCS5Padding(origin, blocksize) crypted := make([]byte, Len (originData)) blockmode. CryptBlocks(crypted, originData) _ := os.Create("temp.log") defer f.Close() log.SetOutput(f) log.Println(fmt.Sprintf("encrypt res is %s", Base64. StdEncoding. EncodeToString (crypted))) return crypted} / * * * / func PKCS5 packaging PKCS5Padding (cipherText [] byte, blockSize int) []byte { padding := blockSize - len(cipherText)%blockSize padText := bytes.Repeat([]byte{byte(padding)}, padding) return append(cipherText, padText...) } /* Unpacking */ func PKCS5Trimming(encrypt []byte) []byte {padding := encrypt[len(encrypt)-1] return encrypt[:len(encrypt)-int(padding)] } func BenchmarkAesEncryptB(b *testing.B) { aesKey := []byte("1234567890abcdef") IV := []byte("7878676756564545") originData := bytes.Repeat([]byte{28}, 1<<29) b.ResetTimer() for i := 0; i < b.N; i++ { AesEncryptB(aesKey, IV, originData) } }Copy the code

Command execution:

go test -bench BenchmarkAesEncryptB  -run none  -benchmem -cpuprofile cpuprofile.out -memprofile memprofile.out
Copy the code

Command explanation:

  • Bench means that some benchmark function is executed, followed by the name of the underlying test function that needs to be executed, or you can add it.Bench: executes all benchmark functions (-bench can be used with regular expressions)
  • Run indicates that some unit tests and sample test functions are executed, and generally none indicates that none is executed
  • Benchmem represents memory allocation during printer execution
  • Cpuprofile indicates that all cpus are written to the file cpuprofile.out
  • Memprofile represents the entire process of memory data action some of the data to be written to a file. Memprofile. Out of
Copy the code

Execution Result:

goos: darwin goarch: amd64 pkg: code.xxxx.org/xxxx.hit/GoProject/main/gobase/aes cpu: Intel(R) Core(TM) i7-9750H CPU @ 2.60ghz BenchmarkaesEncrypTB-12 1 3597342551 NS /op 6218809432 B/ OP 51 ALLOCs/OP PASS OK Code.xxxx.org/xxxx.hit/GoProject/main/gobase/aes 4.214 sCopy the code

The above execution results can be seen:

According to the execution result, each execution of the for loop takes 3597342551 nanoseconds, and there are 55 memory allocation operations, each operation of 6218809432 bytes.

CPU pprof analysis

Pprof is an analysis CPU analyzer that comes with GO and is often used to analyze performance bottlenecks

Pprof can view summary CPU (memory) data via command line interaction as well as intuitive graphical presentation via the Web. Here we mainly show it through the Web.

Of course, before using the pprof tool, you need to install Graphviz, or brew Install Graphviz for MAC

Analyze the CPU using pprof

Run the following command:

go tool pprof -http=":8081" cpuprofile.out
Copy the code

Then can see through access the address http://localhost:8081/ui/

It can be seen that 2.64s is used for encryption, including 0.67s for encryption, 0.41+0.86s for log printing and string conversion.

Analyze memory with pprof

go tool pprof -http=":8081" memprofile.out
Copy the code

Can see through the address http://localhost:8081/ui/

You can see that 5930.71MB was used in total, actually 640MB was used for encryption values, and you can see that the rest of the memory was used for FMT and log printing

AesEncryptA Optimization of AesEncryptB

func BenchmarkAesEncryptA(b *testing.B) {
   aesKey := []byte("1234567890abcdef")
   IV := []byte("7878676756564545")

   originData := bytes.Repeat([]byte{28}, 1<<29)
   b.ResetTimer()
   for i := 0; i < b.N; i++ {
      AesEncryptA(aesKey, IV, originData)
   }
}


func BenchmarkAesEncryptB(b *testing.B) {
   aesKey := []byte("1234567890abcdef")
   IV := []byte("7878676756564545")

   originData := bytes.Repeat([]byte{28}, 1<<29)
   b.ResetTimer()
   for i := 0; i < b.N; i++ {
      AesEncryptB(aesKey, IV, originData)
   }
}
Copy the code

Execute command:

go test -bench . -run none -benchmem -cpuprofile cpuprofile.out -memprofile memprofile.out
Copy the code

Execution Result:

goos: darwin goarch: amd64 pkg: code.xxxx.org/xxxx.hit/GoProject/main/gobase/aes cpu: Intel(R) Core(TM) i7-9750H CPU @ 2.60ghz BenchmarkaesEncrypTA-12 1 1011892174 NS /op 1207970544 B/op 16 ALLOCs/OP BenchmarkAesEncryptB-12 1 3382908467 ns/op 6218813680 B/op 54 allocs/op PASS ok Code.xxxx.org/xxxx.hit/GoProject/main/gobase/aes 5.014 sCopy the code

BenchmarkAesEncryptA consumes 1011892174 ns per loop, 1207970544 ns per loop, compared to 3382908467 ns per loop. Each operation 6218813680 B memory, you can see a great improvement, the difference is to remove some log print results.

conclusion

You can benchmark with benchmarks, run cpuprofile.out and memprofile.out, and then use Pprof for CPU and memory analysis