benchmark_run.yaml 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. name: benchmark-run
  2. # Runs the committed benchmark (`just bench`) and records the numbers.
  3. #
  4. # This is a measurement, not a test: nothing here fails the build. Unlike
  5. # benchmark-ab, which compares two refs inside one job, this just reports the
  6. # absolute throughput of the current ref alongside Crow for reference.
  7. #
  8. # Absolute req/s is only meaningful against other runs on the same runner type,
  9. # so compare like with like when reading the history.
  10. #
  11. # Non-SSL only. Windows is excluded: benchmark/Makefile depends on `nc`, `&`
  12. # and `kill`, so it would need a PowerShell rewrite first.
  13. on:
  14. workflow_dispatch:
  15. inputs:
  16. duration:
  17. description: "Load duration per server"
  18. required: false
  19. default: "5s"
  20. connections:
  21. description: "Concurrent connections"
  22. required: false
  23. default: "10"
  24. crow:
  25. description: "Also benchmark Crow v1.3.1 for reference"
  26. type: boolean
  27. required: false
  28. default: true
  29. permissions:
  30. contents: read
  31. jobs:
  32. bench:
  33. strategy:
  34. fail-fast: false
  35. matrix:
  36. os: [ubuntu-latest, macos-latest]
  37. runs-on: ${{ matrix.os }}
  38. steps:
  39. - name: checkout
  40. uses: actions/checkout@v4
  41. # macos runners ship without Go.
  42. - name: setup Go
  43. uses: actions/setup-go@v5
  44. with:
  45. go-version: stable
  46. - name: install bombardier
  47. run: go install github.com/codesenberg/bombardier@latest
  48. # crow_all.h includes <asio.hpp>, which no runner has out of the box.
  49. - name: install asio
  50. if: ${{ inputs.crow }}
  51. run: |
  52. if [ "$RUNNER_OS" = "Linux" ]; then
  53. sudo apt-get update && sudo apt-get install -y libasio-dev
  54. else
  55. brew install asio
  56. fi
  57. - name: run benchmark
  58. run: |
  59. # Without pipefail the `tee` below swallows a build failure and the
  60. # job reports success having measured nothing.
  61. set -o pipefail
  62. export PATH="$(go env GOPATH)/bin:$PATH"
  63. CROW_FLAGS="-std=c++17"
  64. if [ "$RUNNER_OS" = "macOS" ]; then
  65. CROW_FLAGS="$CROW_FLAGS -I$(brew --prefix asio)/include"
  66. fi
  67. if [ "${{ inputs.crow }}" = "true" ]; then TARGET=bench-all; else TARGET=bench; fi
  68. make -C benchmark "$TARGET" \
  69. CROW_CXXFLAGS="$CROW_FLAGS" \
  70. BENCH="bombardier -c ${{ inputs.connections }} -d ${{ inputs.duration }} localhost:8080" \
  71. 2>&1 | tee /tmp/bench.txt
  72. # pipefail only catches a failed build. Each Makefile recipe ends in
  73. # `kill`, so a bombardier that never ran still leaves make happy — check
  74. # that the measurements are actually there.
  75. - name: check results were produced
  76. run: |
  77. expected=1
  78. if [ "${{ inputs.crow }}" = "true" ]; then expected=2; fi
  79. got=$(grep -c "Reqs/sec" /tmp/bench.txt || true)
  80. if [ "$got" -lt "$expected" ]; then
  81. echo "::error::expected $expected benchmark result(s), found $got"
  82. exit 1
  83. fi
  84. - name: record results
  85. if: always()
  86. run: |
  87. {
  88. echo "## Benchmark (${{ matrix.os }})"
  89. echo ""
  90. echo "- ref: \`${{ github.ref_name }}\` (${{ github.sha }})"
  91. echo "- connections=${{ inputs.connections }} duration=${{ inputs.duration }}"
  92. echo ""
  93. echo '```'
  94. cat /tmp/bench.txt
  95. echo '```'
  96. } >> "$GITHUB_STEP_SUMMARY"