Home > Back-end >  CodeQL analysis for Windows is too slow if I need to compile the C project. How to solve this?
CodeQL analysis for Windows is too slow if I need to compile the C project. How to solve this?

Time:06-28

I am trying to setup a CodeQL analysis workflow for my project on Github. I would like to analyze the code for Windows, Ubuntu and MacOS all together and therefore I decided to split the compile-part into three parallel ways, since I have to run the analysis separately for each OS. So far, I set-up the workflow in this way:

name: "CodeQL"

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]
  schedule:
    - cron: '45 22 * * 0'

jobs:
  analyze:
    name: Analyze
    runs-on: ${{ matrix.os }}
    permissions:
      actions: read
      contents: read
      security-events: write

    strategy:
      fail-fast: false
      matrix:
        os: [ubuntu-latest, windows-latest, macos-latest]
        language: [ 'cpp' ]

    steps:
    - name: Checkout repository
      uses: actions/checkout@v2

    - name: Initialize CodeQL
      uses: github/codeql-action/init@v2
      with:
        languages: ${{ matrix.language }}
    
    - name: Installing extra dependencies and compiling (Ubuntu)
      if: matrix.os == 'ubuntu-latest'
      run: |
       sudo apt install build-essential g   libboost-all-dev wget unzip doctest-dev

       exprtk_sha1=ca5c577917646ddba3f71ce6d5dd7d01f351ee80
       wget https://github.com/ArashPartow/exprtk/archive/$exprtk_sha1.zip
       mv $exprtk_sha1.zip exprtk-$exprtk_sha1.zip
       unzip exprtk-$exprtk_sha1.zip
       sudo cp exprtk-$exprtk_sha1/exprtk.hpp /usr/include/
       rm -rf exprtk-*

       make

    - name: Installing extra dependencies and compiling (MacOS)
      if: matrix.os == 'macos-latest'
      run: |
       brew install boost doctest
       
       exprtk_sha1=ca5c577917646ddba3f71ce6d5dd7d01f351ee80
       wget https://github.com/ArashPartow/exprtk/archive/$exprtk_sha1.zip
       mv $exprtk_sha1.zip exprtk-$exprtk_sha1.zip
       unzip exprtk-$exprtk_sha1.zip
       sudo cp exprtk-$exprtk_sha1/exprtk.hpp /usr/local/include
       rm -rf exprtk-*

       make

    - name: Installing extra dependencies and compiling (Windows)
      if: matrix.os == 'windows-latest'
      run: |
       choco install unzip wget

       mkdir C:/install
       cd C:/install
       wget https://boostorg.jfrog.io/artifactory/main/release/1.79.0/source/boost_1_79_0.zip | Out-Null
       unzip boost_1_79_0.zip | Out-Null
       mkdir C:/boost-build
       mkdir C:/install/boost_1_79_0/boost-build
       mkdir C:/boost
       cd -
       cd C:/install/boost_1_79_0/tools/build
       .\bootstrap.bat gcc
       .\b2 --prefix="C:/boost-build" install
       $Env:PATH =";C:/boost-build/bin"
       cd -
       cd C:/install/boost_1_79_0
       b2 --build-dir="C:/install/boost_1_79_0/build" --build-type=complete --prefix="C:/boost" toolset=gcc install
       cd -
       cp -r C:/boost/include/boost-1_79/boost C:/ProgramData/Chocolatey/lib/mingw/tools/install/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/include/c  
       cp C:/boost/lib/* C:/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64/opt/lib
       $Env:PATH =";C:/ProgramData/Chocolatey/lib/mingw/tools/install/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/include/c  "
       $Env:PATH =";C:/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64/opt/lib"
       $Env:PATH =";C:/ProgramData/Chocolatey/lib/mingw/tools/install/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/include/c  "
       $Env:PATH =";C:/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64/opt/lib"
       rd -r C:/install
       rd -r C:/boost-build

       wget https://github.com/doctest/doctest/archive/refs/heads/master.zip | Out-Null
       unzip master.zip | Out-Null
       mkdir C:/ProgramData/Chocolatey/lib/mingw/tools/install/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/include/c  /doctest
       cp doctest-master/doctest/doctest.h C:/ProgramData/Chocolatey/lib/mingw/tools/install/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/include/c  /doctest
       rd -r doctest-master

       make
    - name: Perform CodeQL Analysis
      uses: github/codeql-action/analyze@v2

It works well, but the problem is that in the Windows part, it employs more than 4 hours to complete, since I have to download and build the boost library every time, in order to correctly compile the code.

Is there a way to speed-up the process?

I already tried with package managers (even if many libraries are not founded on Windows), but the situation doesn't change, or other complications occur: like the fact that I have to find every time the installation of the dependencies and add them to the system path, but since they are not easy to find, I have to re-launch the workflow many and many times to debug.

CodePudding user response:

If downloading and building boost is the bottleneck, I think you could get a substantial speedup by caching that dependency, especially since its version or contents aren't changing frequently in your CI flow. I've split up your boost dependency and project build step into 2 different steps and cached the former below. In this case, you're essentially perma-caching your boost dependency since you have the version and its path hard-coded, so the cache key is arbitrary - I just used its path as a string so it's easy to find and replace if you update your boost version in the future. After cache hit & load, or cache miss and redownload & rebuild, your workflow continues with the rest of the build steps.

    - name: Cache boost
      if: matrix.os == 'windows-latest'
      id: cache-boost
      uses: actions/cache@v3
      with:
        path: C:/boost/include/boost-1_79/boost
        key: 'C:/boost/include/boost-1_79/boost' # this key is arbitrary
    - name: Installing boost upon cache miss (Windows)
      if: matrix.os == 'windows-latest' && steps.cache-boost.outputs.cache-hit != 'true'
      run: |
       choco install unzip wget

       mkdir C:/install
       cd C:/install
       wget https://boostorg.jfrog.io/artifactory/main/release/1.79.0/source/boost_1_79_0.zip | Out-Null
       unzip boost_1_79_0.zip | Out-Null
       mkdir C:/boost-build
       mkdir C:/install/boost_1_79_0/boost-build
       mkdir C:/boost
       cd -
       cd C:/install/boost_1_79_0/tools/build
       .\bootstrap.bat gcc
       .\b2 --prefix="C:/boost-build" install
       $Env:PATH =";C:/boost-build/bin"
       cd -
       cd C:/install/boost_1_79_0
       b2 --build-dir="C:/install/boost_1_79_0/build" --build-type=complete --prefix="C:/boost" toolset=gcc install
       cd -
    - name: Other build steps
      if: matrix.os == 'windows-latest'
      run: |
       cp -r C:/boost/include/boost-1_79/boost C:/ProgramData/Chocolatey/lib/mingw/tools/install/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/include/c  
       cp C:/boost/lib/* C:/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64/opt/lib
       $Env:PATH =";C:/ProgramData/Chocolatey/lib/mingw/tools/install/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/include/c  "
       $Env:PATH =";C:/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64/opt/lib"
       $Env:PATH =";C:/ProgramData/Chocolatey/lib/mingw/tools/install/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/include/c  "
       $Env:PATH =";C:/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64/opt/lib"
       rd -r C:/install
       rd -r C:/boost-build

       wget https://github.com/doctest/doctest/archive/refs/heads/master.zip | Out-Null
       unzip master.zip | Out-Null
       mkdir C:/ProgramData/Chocolatey/lib/mingw/tools/install/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/include/c  /doctest
       cp doctest-master/doctest/doctest.h C:/ProgramData/Chocolatey/lib/mingw/tools/install/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/include/c  /doctest
       rd -r doctest-master

I'm not very knowledgeable about C , so if you have other dependencies you're pulling in that are essentially hardcoded by version or path, you could cache those too.

2 caveats to be aware of is that there's a 10GB limit on cached data and there's a 1-week eviction on the cache. If your cache exceeds that size limit, you'll always get a cache miss and thus the cache-miss step will always execute. In this scenario, I think you might be able to compress your boost directory before caching it (remember to decompress in your final project build step) to try and get below that size limit. actions/cache uses its own compression already, though, so ymmv with how much this actually helps (maybe try a different compression tool?). In the absolute worst case you could dump your boost files into blob storage if you have cloud storage somewhere and pull it down, essentially creating your own cache - the latency between GitHub Actions and Azure tends to be pretty low since a lot of the platform infrastructure is hosted there. If you do this, you don't need to split up your build step per se, you'll just need to modify your build step to instead pull down the data from your storage provider.

Sources:

  • Related