dotnet / crank

Benchmarking infrastructure for applications
MIT License
975 stars 103 forks source link

Add pre and post command support #666

Closed caaavik-msft closed 7 months ago

caaavik-msft commented 9 months ago

Summary

This PR adds a feature to crank that allows you to define commands that should be run on the controller machine before and after the run. With this feature, it now becomes possible to write commands to pre-organise or pre-build things on the controller machine before the run starts.

Motivation

The motivation for this was the work towards being able to run benchmarks using crank from the dotnet/performance repository against a local build of the dotnet runtime. Since the runtime is very large, and takes a long time to build, it is better if instead the dotnet runtime is built locally first, and then the build output folder is uploaded to the crank agent and run against that instead. This means that every time before the crank command is run, the developer will need to re-build the runtime each time. With this functionality, it means that we can add pre-commands to crank that will trigger a rebuild of the runtime using all the correct build arguments needed for our scenarios.

Another use case might be that the files that you want to be uploaded to crank may all live in different folders and you don't want to upload all those folders if they contain irrelevant files in them. With this, you could write a pre-command that copies all the files into a temporary directory so that it can be uploaded to the crank agent, then a post-command could then delete that folder afterwards if preferred.

Implementation

An example of a yaml file with commands is below:

commands:
  echoHello:
    - condition: job.environment.platform == "windows"
      shell: batch
      script: echo Hello
      continueOnError: true
    - condition: job.environment.platform != "windows"
      shell: bash
      script: echo "Hello"
      continueOnError: true

jobs:
  myJob:
    variables:
      architecture: x64
    commands:
      build:
        - condition: job.environment.platform == "windows"
          shell: batch
          script: build.cmd --architecture {{ architecture }}
        - condition: job.environment.platform != "windows"
          shell: bash
          script: build.sh --architecture {{ architecture }}
    preCommandOrder:
      - echoHello
      - build
    postCommandOrder:
      - echoHello

Commands are defined under commands either at the root level or at the job level. The command definitions are merged together with the job-level definitions taking precedence over the root-level definitions. Each command has a name, and multiple definitions where each definition has a condition in the form of a javascript expression. Global properties such as job and configuration exist to use in the javascript expression to be able to change the command that is run. If multiple command definitions are true for a given run, the first one that appears in the list will be the one invoked. Also as shown in the sample, it is possible to make use of the job variables inside a command definition.

These are all the properties available inside a command definition:

condition: str # a condition expression to check to see if this definition applies
shell: bash | batch | powershell # what shell to run the script or file in
script: string # the script contents to run
file: string # a path to a file where the script lives
continueOnError: bool # whether or not the run should continue if the script returns an error code (default: false)
successExitCodes: [int] # A list of integers that represent the successful exit codes for use with continueOnError (default: [0])

The PR also adds a new field under Job called Environment which has two fields: Platform which has a value of windows | linux | osx | other and Architecture which has values X86 | X64 | ARM | ARM64. These are useful to use from the conditions which will most likely need to be different for each platform.

Some other design decisions

I've verified all this functionality locally on my machine as well and it works quite well, but I'm open to changing the design here as well if needed.

sebastienros commented 9 months ago

/azp run

azure-pipelines[bot] commented 9 months ago
Azure Pipelines successfully started running 1 pipeline(s).
sebastienros commented 7 months ago

We'll need some doc/sample to remember how it works.