# Copyright 2020 Signal Messenger, LLC
# SPDX-License-Identifier: AGPL-3.0-only

name: Benchmark
on:
  push:
    branches:
      - development
      - main
      - '[0-9]+.[0-9]+.x'
  pull_request:
  schedule:
    - cron: '0 */12 * * *'

jobs:
  linux:
    strategy:
      matrix:
        metric:
          - startup
          - send
          - groupSend
          - largeGroupSendWithBlocks
          - largeGroupSend
          - convoOpen
          - callHistorySearch
          - backup
        include:
          - metric: startup
            script: ts/test-mock/benchmarks/startup_bench.node.js
            runCount: 10
          - metric: send
            script: ts/test-mock/benchmarks/send_bench.node.js
            runCount: 100
          - metric: groupSend
            script: ts/test-mock/benchmarks/group_send_bench.node.js
            runCount: 100
            conversationSize: 500
          - metric: largeGroupSendWithBlocks
            script: ts/test-mock/benchmarks/group_send_bench.node.js
            runCount: 50
            conversationSize: 500
            groupSize: 500
            contactCount: 500
            blockedCount: 10
            discardCount: 2
          - metric: largeGroupSend
            script: ts/test-mock/benchmarks/group_send_bench.node.js
            runCount: 20
            conversationSize: 50
            groupSize: 500
            contactCount: 500
            discardCount: 2
          - metric: convoOpen
            script: ts/test-mock/benchmarks/convo_open_bench.node.js
            runCount: 100
          - metric: callHistorySearch
            script: ts/test-mock/benchmarks/call_history_search_bench.node.js
            runCount: 100
          - metric: backup
            script: ts/test-mock/benchmarks/backup_bench.node.js

    runs-on: ubuntu-22.04-8-cores
    if: ${{ github.repository == 'signalapp/Signal-Desktop-Private' && (!github.event.schedule || github.ref == 'refs/heads/main') }}
    timeout-minutes: 30

    steps:
    - name: Get system specs
      run: lsb_release -a
    - name: Get other system specs
      run: uname -a

    - name: Clone Desktop repo
      uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5

    # - name: Setup sccache
    #   uses: mozilla-actions/sccache-action@054db53350805f83040bf3e6e9b8cf5a139aa7c9 # v0.0.7
    # - name: Restore sccache
    #   uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
    #   id: cache-sccache
    #   with:
    #     path: ${{ env.SCCACHE_PATH }}
    #     key: sccache-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml', 'patches/**') }}

    - name: Setup pnpm
      uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4
    - name: Setup node.js
      uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6
      with:
        node-version-file: '.nvmrc'
        cache: 'pnpm'
        cache-dependency-path: 'pnpm-lock.yaml'
    - name: Cache .electron-gyp
      uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
      with:
        path: ~/.electron-gyp
        key: electron-gyp-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
    - name: Install xvfb and libpulse0
      run: sudo apt-get install xvfb libpulse0 || (sudo apt-get update && sudo apt-get install xvfb libpulse0)

    - name: Install Desktop node_modules
      run: pnpm install
      env:
        # CC: sccache gcc
        # CXX: sccache g++
        # SCCACHE_GHA_ENABLED: "true"
        NPM_CONFIG_LOGLEVEL: verbose

    - name: Build typescript
      run: pnpm run generate
    - name: Bundle
      run: pnpm run build:esbuild:prod
    - name: Create preload cache
      run: xvfb-run --auto-servernum pnpm run build:preload-cache

    - name: Set MAX_CYCLES=2 on main
      if: ${{ github.ref == 'refs/heads/main' }}
      run: |
        echo "MAX_CYCLES=2" >> "$GITHUB_ENV"

    - name: Run ${{ matrix.metric }}
      run: |
        set -o pipefail
        xvfb-run --auto-servernum node ${{ matrix.script }} | tee benchmark.log
      timeout-minutes: 10
      env:
        NODE_ENV: production
        ELECTRON_ENABLE_STACK_DUMPING: on
        DEBUG: 'mock:benchmarks'
        ARTIFACTS_DIR: artifacts/${{ matrix.metric }}
        GROUP_SIZE: ${{ matrix.groupSize }}
        CONTACT_COUNT: ${{ matrix.contactCount }}
        BLOCKED_COUNT: ${{ matrix.blockedCount }}
        DISCARD_COUNT: ${{ matrix.discardCount }}
        RUN_COUNT: ${{ matrix.runCount }}
        CONVERSATION_SIZE: ${{ matrix.conversationSize }}

    - name: Upload benchmark logs on failure
      if: failure()
      uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
      with:
        name: logs
        path: artifacts

    - name: Clone benchmark repo
      uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
      with:
        repository: 'signalapp/Signal-Desktop-Benchmarks-Private'
        path: 'benchmark-results'
        token: ${{ secrets.AUTOMATED_GITHUB_PAT }}

    - name: Build benchmark repo
      working-directory: benchmark-results
      run: |
        pnpm install
        pnpm run build

    - name: Publish
      working-directory: benchmark-results
      run: |
        node ./bin/publish.js ../benchmark.log desktop.ci.performance.${{ matrix.metric }}
      env:
        OTEL_EXPORTER_OTLP_ENDPOINT: ${{ secrets.OTEL_EXPORTER_OTLP_ENDPOINT }}
        OTEL_EXPORTER_OTLP_PROTOCOL: ${{ secrets.OTEL_EXPORTER_OTLP_PROTOCOL }}
        OTEL_EXPORTER_OTLP_HEADERS: ${{ secrets.OTEL_EXPORTER_OTLP_HEADERS }}
