• 设为首页
  • 收藏本站
  • 积分充值
  • VIP赞助
  • 手机版
  • 微博
  • 微信
    微信公众号 添加方式:
    1:搜索微信号(888888
    2:扫描左侧二维码
  • 快捷导航
    福建二哥 门户 查看主题

    使用Go语言实现benchmark解析器

    发布者: 涵韵3588 | 发布时间: 2025-8-14 13:20| 查看数: 65| 评论数: 0|帖子模式

    简介

    1. Go
    复制代码
    编写的
    1. benchmark
    复制代码
    输出解析器,功能如下

    • 读取
      1. go test -bench=. -benchmem
      复制代码
      的输出文件(如
      1. benchmark.txt
      复制代码

    • 解析出每行数据
    • 写入成
      1. CSV
      复制代码
      文件(如
      1. benchmark.csv
      复制代码

      1. Web UI
      复制代码
      可视化数据

    仅Go解析器
    1. package main

    2. import (
    3.         "bufio"
    4.         "encoding/csv"
    5.         "fmt"
    6.         "os"
    7.         "regexp"
    8. )

    9. type BenchmarkResult struct {
    10.         Name        string
    11.         Runs        string
    12.         NsPerOp     string
    13.         BytesPerOp  string
    14.         AllocsPerOp string
    15. }

    16. func main() {
    17.         inputFile := "benchmark.txt"
    18.         outputFile := "benchmark.csv"

    19.         file, err := os.Open(inputFile)
    20.         if err != nil {
    21.                 fmt.Println("读取文件失败:", err)
    22.                 return
    23.         }
    24.         defer file.Close()

    25.         // 匹配 benchmark 输出行
    26.         re := regexp.MustCompile(`^Benchmark(\w+)-\d+\s+(\d+)\s+(\d+)\s+ns/op\s+(\d+)\s+B/op\s+(\d+)\s+allocs/op`)

    27.         var results []BenchmarkResult

    28.         scanner := bufio.NewScanner(file)
    29.         for scanner.Scan() {
    30.                 line := scanner.Text()
    31.                 matches := re.FindStringSubmatch(line)
    32.                 if len(matches) == 6 {
    33.                         results = append(results, BenchmarkResult{
    34.                                 Name:        matches[1],
    35.                                 Runs:        matches[2],
    36.                                 NsPerOp:     matches[3],
    37.                                 BytesPerOp:  matches[4],
    38.                                 AllocsPerOp: matches[5],
    39.                         })
    40.                 }
    41.         }

    42.         if err := scanner.Err(); err != nil {
    43.                 fmt.Println("读取行失败:", err)
    44.                 return
    45.         }

    46.         // 写入 CSV
    47.         outFile, err := os.Create(outputFile)
    48.         if err != nil {
    49.                 fmt.Println("创建 CSV 文件失败:", err)
    50.                 return
    51.         }
    52.         defer outFile.Close()

    53.         writer := csv.NewWriter(outFile)
    54.         defer writer.Flush()

    55.         headers := []string{"name", "runs", "ns_per_op", "bytes_per_op", "allocs_per_op"}
    56.         if err := writer.Write(headers); err != nil {
    57.                 fmt.Println("写入 CSV 头失败:", err)
    58.                 return
    59.         }

    60.         for _, r := range results {
    61.                 row := []string{r.Name, r.Runs, r.NsPerOp, r.BytesPerOp, r.AllocsPerOp}
    62.                 if err := writer.Write(row); err != nil {
    63.                         fmt.Println("写入行失败:", err)
    64.                         return
    65.                 }
    66.         }

    67.         fmt.Println("✅ 成功导出 CSV:", outputFile)
    68. }
    复制代码
    使用方法
    保存为
    1. main.go
    复制代码
    编译运行:
    1. go run main.go
    复制代码
    或编译为可执行文件:
    1. go build -o benchparser
    2. ./benchparser
    复制代码
    确保
    1. benchmark.txt
    复制代码
    在同目录,输出会生成
    1. benchmark.csv
    复制代码


    使用 Web UI 可视化数据


    功能需求


    • 支持输入:

        1. benchmark.txt
        复制代码
        文件读取
      • 从标准输入读取(如管道输入)

    • 解析
      1. go test -bench=. -benchmem
      复制代码
      输出
    • 提供一个
      1. Web UI
      复制代码


      • 显示
        1. ns/op
        复制代码
        1. B/op
        复制代码
        1. allocs/op
        复制代码
        的柱状图
      • 支持切换不同维度视图


    项目结构设计(Go + HTML + JS)
    1. benchmark-visualizer/├── main.go                 ← 启动解析器 + Web Server├── static/│   ├── index.html          ← Web 页面│   ├── chart.js            ← Chart.js 库│   └── main.js             ← 渲染图表的 JS 脚本
    复制代码
    Go 服务器(main.go)
    1. package main

    2. import (
    3.         "bufio"
    4.         "encoding/json"
    5.         "fmt"
    6.         "net/http"
    7.         "os"
    8.         "regexp"
    9. )

    10. type BenchmarkResult struct {
    11.         Name        string `json:"name"`
    12.         Runs        int    `json:"runs"`
    13.         NsPerOp     float64`json:"ns_per_op"`
    14.         BytesPerOp  int    `json:"bytes_per_op"`
    15.         AllocsPerOp int    `json:"allocs_per_op"`
    16. }

    17. var results []BenchmarkResult

    18. func parseBenchmark(input *os.File) ([]BenchmarkResult, error) {
    19.         re := regexp.MustCompile(`^(Benchmark\S*)\s+(\d+)\s+([\d\.]+)\s+ns/op\s+(\d+)\s+B/op\s+(\d+)\s+allocs/op`)
    20.         scanner := bufio.NewScanner(input)
    21.         var parsed []BenchmarkResult

    22.         for scanner.Scan() {
    23.                 line := scanner.Text()
    24.         matches := re.FindStringSubmatch(line)
    25.         if len(matches) == 6 {
    26.             var r BenchmarkResult
    27.             r.Name = matches[1]
    28.             fmt.Sscanf(matches[2], "%d", &r.Runs)
    29.             fmt.Sscanf(matches[3], "%f", &r.NsPerOp)
    30.             fmt.Sscanf(matches[4], "%d", &r.BytesPerOp)
    31.             fmt.Sscanf(matches[5], "%d", &r.AllocsPerOp)
    32.             parsed = append(parsed, r)
    33.         }
    34.         }

    35.         return parsed, scanner.Err()
    36. }

    37. func dataHandler(w http.ResponseWriter, r *http.Request) {
    38.         w.Header().Set("Content-Type", "application/json")
    39.         json.NewEncoder(w).Encode(results)
    40. }

    41. func main() {
    42.         // 判断是否有标准输入
    43.         stat, _ := os.Stdin.Stat()
    44.         var err error

    45.         if (stat.Mode() & os.ModeCharDevice) == 0 {
    46.                 // 从标准输入读取
    47.                 results, err = parseBenchmark(os.Stdin)
    48.         } else {
    49.                 // 默认读取 benchmark.txt 文件
    50.                 file, err := os.Open("benchmark.txt")
    51.                 if err != nil {
    52.                         fmt.Println("打开 benchmark.txt 失败:", err)
    53.                         return
    54.                 }
    55.                 defer file.Close()
    56.                 results, err = parseBenchmark(file)
    57.         }

    58.         if err != nil {
    59.                 fmt.Println("解析失败:", err)
    60.                 return
    61.         }

    62.         fs := http.FileServer(http.Dir("./static"))
    63.         http.Handle("/", fs)
    64.         http.HandleFunc("/data", dataHandler)

    65.         fmt.Println("🚀 服务器已启动:http://localhost:8080")
    66.         http.ListenAndServe(":8080", nil)
    67. }
    复制代码
    Web 页面(static/index.html)
    1. <!DOCTYPE html>
    2. <html>
    3. <head>
    4.   <meta charset="utf-8">
    5.   <title>Go Benchmark 可视化</title>
    6.   <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
    7.   <script src="main.js" defer></script>
    8. </head>
    9. <body>
    10.   <h2>Go Benchmark 可视化结果</h2>
    11.   <select id="metric-select">
    12.     <option value="ns_per_op">ns/op</option>
    13.     <option value="bytes_per_op">B/op</option>
    14.     <option value="allocs_per_op">allocs/op</option>
    15.   </select>
    16.   <canvas id="benchmarkChart" width="900" height="500"></canvas>
    17. </body>
    18. </html>
    复制代码
    Chart 渲染脚本(static/main.js)
    1. let chart;
    2. const ctx = document.getElementById('benchmarkChart').getContext('2d');

    3. function renderChart(data, metric = "ns_per_op") {
    4.   const labels = data.map(item => item.name);
    5.   const values = data.map(item => item[metric]);

    6.   if (chart) chart.destroy();

    7.   chart = new Chart(ctx, {
    8.     type: 'bar',
    9.     data: {
    10.       labels: labels,
    11.       datasets: [{
    12.         label: metric,
    13.         data: values,
    14.         backgroundColor: 'rgba(54, 162, 235, 0.6)'
    15.       }]
    16.     },
    17.     options: {
    18.       scales: {
    19.         y: {
    20.           beginAtZero: true
    21.         }
    22.       }
    23.     }
    24.   });
    25. }

    26. fetch('/data')
    27.   .then(res => res.json())
    28.   .then(data => {
    29.     renderChart(data);
    30.     document.getElementById('metric-select').addEventListener('change', (e) => {
    31.       renderChart(data, e.target.value);
    32.     });
    33.   });
    复制代码
    运行方式

    方法 1:从文件读取
    1. go run main.go
    2. # 或
    3. go build -o benchvis && ./benchvis
    复制代码
    方法 2:从标准输入读取
    1. go test -bench=. -benchmem | go run main.go
    复制代码
    然后访问:
    1. http://localhost:8080
    复制代码
    效果如图:


    benchmark.txt文件示例
    1. goos: darwingoarch: arm64pkg: echocpu: Apple M1BenchmarkEchoAll1-8         271656          4631 ns/op       21080 B/op          99 allocs/opBenchmarkEchoAll2-8         224186          5874 ns/op       31560 B/op          99 allocs/opBenchmarkEchoAll3-8        1273263           836.1 ns/op         640 B/op           1 allocs/opBenchmarkEchoAll4-8        1457311           809.8 ns/op        1912 B/op           8 allocs/opPASSok      echo    9.128s
    复制代码
    到此这篇关于使用Go语言实现benchmark解析器和Web UI数据可视化的文章就介绍到这了,更多相关Go benchmark解析内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

    来源:互联网
    免责声明:如果侵犯了您的权益,请联系站长(1277306191@qq.com),我们会及时删除侵权内容,谢谢合作!

    本帖子中包含更多资源

    您需要 登录 才可以下载或查看,没有账号?立即注册

    ×

    最新评论

    浏览过的版块

    QQ Archiver 手机版 小黑屋 福建二哥 ( 闽ICP备2022004717号|闽公网安备35052402000345号 )

    Powered by Discuz! X3.5 © 2001-2023

    快速回复 返回顶部 返回列表