Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Factor out incremental build prep into an action #143

Merged
merged 10 commits into from
Sep 26, 2024

Conversation

theihor
Copy link
Contributor

@theihor theihor commented Sep 12, 2024

Partially resolves #142

@chantra I've been testing this change in a simplified workflow on my fork.

Any suggestions how to verify kernel-patches/bpf CI would work with the change? I guess we could just push and see, but maybe there is a less disruptive way.

@chantra
Copy link
Collaborator

chantra commented Sep 13, 2024

Thanks @theihor

I have not fully reviewed the whole PR yet, but from quick pass, it seems fine so far.

Any suggestions how to verify kernel-patches/bpf CI would work with the change? I guess we could just push and see, but maybe there is a less disruptive way.

Yes, you should create a PR against kernel-patches/vmtest, apply the changes would expect to do when migrating to using the new action, but until this is landed, you will need to use an action path pointing to your repo/branch, e.g

theihor/libbpf-ci/prepare-incremental-build@prepare-incremental-build-action
instead of libbpf-ci/{action}@main.

@chantra chantra closed this Sep 13, 2024
@chantra chantra reopened this Sep 13, 2024
Copy link
Collaborator

@chantra chantra left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there is potentially 1 flaw that we were lucky to not hit so far. e.g if we were to run the action outside of the github repo.

For the case of kernel-patches/bpf... the workspace just happens to be a linux repo. For other projects, we do download the sources in the step above and move it in place, so we end up being lucky and having the workspace being a linux repo too.

I believe, if we had the action working properly, we should be able to skip the "move linux source in place" step. I think this is out of scope for this task, but somethign to keep in mind for later to make the action self-contained.

Finally, lets take the opportunity when working on actions to write a README.md in the action directory to document how to use it. Similarly to how actions in the marketplace do: https://github.com/actions/checkout/blob/main/README.md for instance.

repo-root:
description: "Root of the kernel repository"
required: true
default: ${{ github.workspace }}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in my experience, this does not work. We have it in a few places, but I don't think it works.

It may be worth testing separately through a simple action.

Based on https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/accessing-contextual-information-about-workflow-runs#context-availability , it is not mentioned that any contexts are available in the "inputs" part of an action. (It would work for a reusable workflow though).

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

replying to myself... on the other hand, there is things like https://github.com/actions/checkout/blob/6d193bf28034eafb982f37bd894289fe649468fc/action.yml#L6C5-L6C38 which suggests it should work, so mayke I did something wrong when testing.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it's not clear from the docs. I can double check, although in this case I think we can just remove the default and require this input to be specified.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

requiring would be fine too and probably preferred. We can do this here because it is a brand new action, it is more tricky when the action is already used.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

run: ${GITHUB_ACTION_PATH}/get-commit-metadata.sh ${{ inputs.base-branch }}

- name: Pull recent KBUILD_OUTPUT contents
uses: actions/cache@v4
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am pretty sure we should set the working-directory here too.
I believe we are lucky it works because the caller sets repo-root to github.workspace, which happens to be the default working directory.

Copy link
Contributor Author

@theihor theihor Sep 13, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My understading is that this particular step invoking actinons/cache@v4 does not have to be executed from the repository directory. The path to store the result of cache lookup (if it's a hit) is passed via path parameter:

    - name: Pull recent KBUILD_OUTPUT contents
      uses: actions/cache@v4
      with:
        path: ${{ inputs.kbuild-output }} # <-- THIS
        key: ...

And we pass it through as an action parameter, although my impression is it never changes for our workflows.

And then the next step (that runs prepare-incremental-builds.sh) expects to be executed in the repository root, but also expects KBUILD_OUTPUT env variable to point to the cached build.

    - name: Prepare incremental build
      shell: bash
      env:
        KBUILD_OUTPUT: ${{ inputs.kbuild-output }}
      working-directory: ${{ inputs.repo-root }} # and so here we do have to set path to the repository

I guess it is confusing that we do not set working-directory in cache step, but do set it for other steps, but the action should work either way.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not convinced path work as you are explaining it. Based on https://github.com/actions/cache?tab=readme-ov-file#inputs

my understanding is that it will extract the "kbuild-output" directory from the cache archive.

side note... we are not caching as part of libbpf/ci (e.g https://github.com/libbpf/ci/actions/caches shows no cache, we may want to also exercise this in the future.).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not convinced path work as you are explaining it. Based on https://github.com/actions/cache?tab=readme-ov-file#inputs

my understanding is that it will extract the "kbuild-output" directory from the cache archive.

Maybe I explained it badly, but I think we both understand it correctly.

The cache action is designed to store things like gradle caches (docs), so I am pretty sure its path input is used both for uploading to the "cloud" after job has finished, and then restoring to the same path later, if lookup key matches.

Although actually, if the path is relative, then working directory might be important. So to be on the safe side, I'll set working-directory to the kernel repo root.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The cache action is designed to store things like gradle caches (docs), so I am pretty sure its path input is used both for uploading to the "cloud" after job has finished, and then restoring to the same path later, if lookup key matches.

agreed

Although actually, if the path is relative, then working directory might be important. So to be on the safe side, I'll set working-directory to the kernel repo root.

I think this would make the composite action work as expected if the kernel-root does not happen to be the github.workspace.

On the other hand, kbuild-output could be anywhere on the filesystem and we should be able to build by providing the absolute path. If we remove the need for kbuild-output to be in kernel-root, we could leverage the cache for workflows outside of kernel-patches/bpf .But that should probably go in a separate PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It turns out that it is not possible to specify working-directory in a step that uses an action (as opposed to running a script). If you try, job fails on execution. So, in our case, passing an absolute path to actions/cache is the only good option really.

@theihor
Copy link
Contributor Author

theihor commented Sep 13, 2024

@chantra

For the case of kernel-patches/bpf... the workspace just happens to be a linux repo. For other projects, we do download the sources in the step above and move it in place, so we end up being lucky and having the workspace being a linux repo too.

I believe, if we had the action working properly, we should be able to skip the "move linux source in place" step. I think this is out of scope for this task, but somethign to keep in mind for later to make the action self-contained.

In the simplified workflow where I was testing this action, I deliberately checked out kernel-patches/bpf into a non-workspace directory, and then passed a path to that directory as action input (see here).

So, assuming I haven't missed anything, the action doesn't care how the linux source tree directory was created: via checkout or via "download linux source" steps. As long as the correct path to the git repo is passed, the action will try finding the cached build output.

Finally, lets take the opportunity when working on actions to write a README.md in the action directory to document how to use it. Similarly to how actions in the marketplace do: https://github.com/actions/checkout/blob/main/README.md for instance.

Will do.

@chantra
Copy link
Collaborator

chantra commented Sep 13, 2024

In the simplified workflow where I was testing this action, I deliberately checked out kernel-patches/bpf into a non-workspace directory, and then passed a path to that directory as action input (see here).

So, assuming I haven't missed anything, the action doesn't care how the linux source tree directory was created: via checkout or via "download linux source" steps. As long as the correct path to the git repo is passed, the action will try finding the cached build output.

yeah, I think we are missing something but it silently fails.
In your case, no cache was available: https://github.com/theihor/libbpf-ci/actions/runs/10836721377/job/30071091347#step:4:63
What I am afraid is that at best we would download the cache but in an directory which is not accessible when we do the build.
It is probably easier to test/validate with a actions/cache basic workflow.

@theihor
Copy link
Contributor Author

theihor commented Sep 14, 2024

yeah, I think we are missing something but it silently fails.
In your case, no cache was available: https://github.com/theihor/libbpf-ci/actions/runs/10836721377/job/30071091347#step:4:63
What I am afraid is that at best we would download the cache but in an directory which is not accessible when we do the build.
It is probably easier to test/validate with a actions/cache basic workflow.

In that workflow there was nothing to cache actually... I wrote another one, and there you can see the cache was

Btw, do we want workflows like that (created specifically to test a custom action) in libbpf/ci? I am not sure.

@theihor theihor marked this pull request as draft September 14, 2024 00:43
@chantra
Copy link
Collaborator

chantra commented Sep 14, 2024

Btw, do we want workflows like that (created specifically to test a custom action) in libbpf/ci? I am not sure.

Maybe not using the key used by the kernel. But given the hard time we have to validate it works as expected, I think it could be useful to have some integration workflows to avoid regression in the future.

Make `kbuild-output` a required input.  Pass an absolute path to
`kbuild-output` from kernel-build reusable workflow.

Introduce optional `cache-key-prefix` input.

Remove branch name parsing logic from `get-commit-metadata.sh`.
Accept the branch that is a target for caching as argument.
@theihor theihor marked this pull request as draft September 17, 2024 17:40
@theihor
Copy link
Contributor Author

theihor commented Sep 17, 2024

@chantra I noticed that artifacts produced by tar-artifact.sh contain two copies of selftests/bpf: tools/testing/selftests/bpf and selftests/bpf.

I found that one is copied into another here: https://github.com/libbpf/ci/blob/main/build-selftests/build_selftests.sh#L63-L66

Do you know if there is a reason for having two copies?

@theihor theihor force-pushed the prepare-incremental-build-action branch from 545e6fe to c646399 Compare September 18, 2024 17:02
There are two distinct KBUILD_OUTPUTs across libbpf/ci:

- $KBUILD_OUTPUT used by actions/cache (in prepare-incremental-build)
- $REPO_ROOT/kbuild-output used by ./run-vmtest

So far this difference wasn't important, because $KBUILD_OUTPUT
always pointed to $(pwd)/kbuild-output. And $(pwd) happened to be a
root of the linux source tree, also equal to github.workspace

However we don't want prepare-incremental-build action to put any
requirements on $KBUILD_OUTPUT path to allow for a convenient action
API.

With this, the difference becomes important, because only selected
files are put from $KBUILD_OUTPUT into kernel-build output artifacts,
while entire $KBUILD_OUTPUT has to be cached by
prepare-incremental-build.
@theihor theihor force-pushed the prepare-incremental-build-action branch from c646399 to db66d59 Compare September 18, 2024 17:27
@theihor theihor marked this pull request as ready for review September 18, 2024 19:27
@theihor theihor force-pushed the prepare-incremental-build-action branch from a8bcdf6 to 370d242 Compare September 18, 2024 20:49
@chantra
Copy link
Collaborator

chantra commented Sep 19, 2024

@chantra I noticed that artifacts produced by tar-artifact.sh contain two copies of selftests/bpf: tools/testing/selftests/bpf and selftests/bpf.

I found that one is copied into another here: https://github.com/libbpf/ci/blob/main/build-selftests/build_selftests.sh#L63-L66

Do you know if there is a reason for having two copies?

No, I don't think so. The artifact is downloadable from GH (when going to the summary of the run, there is a link to the artifacts). The content of vmlinux-x86_64-gcc is https://gist.github.com/chantra/0acb0ec04a58db3adea2debd47e73fee

I think it could be moved in place.
I know that we keep the "Makefile"s so later we can run make -s image_name to discover where the vmlinux file is. The rest, I am not too sure. Even in the selftests/bpf directory we may not need to keep everything that is compiled. At least not for the "artifact" that we re-use during the test run. We do need to keep it for when we update the cache though.

Copy link
Collaborator

@chantra chantra left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Before this lands, do you mind testing on the kernel-patches/vmtest repo by using this action, just to make sure we did not missed anything.

It looks like the tar logic as a whole needs to be re-assessed, but this is a separate story/change that can be followed-up later.

"tools/testing/selftests/bpf/"
"tools/include/"
"scripts/"
"tools/testing/selftests/bpf/"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe this one is not needed given that we add the "copied" selftest/bpf on line 97.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I thought about it, but didn't want to risk breaking something, before I'm sure this is unnecessary.

I agree with your suggestion to re-assess build artifacts in a separate change, as this one is quite big already.

mkdir -p "$(dirname "${local_kbuild_output}/${file}")"
cp -a "${stashed_kbuild_output}/${file}" "${local_kbuild_output}/${file}"
done

additional_file_list=()
if [ $archive_make_helpers -ne 0 ]; then
# Package up a bunch of additional infrastructure to support running
# 'make kernelrelease' and bpf tool checks later on.
mapfile -t additional_file_list < <(find . -iname Makefile)
additional_file_list+=(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suppose the end of the if block is here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean that only the makefiles should be included conditionally? I simply left the original logic.

Comment on lines +93 to +96
--exclude '*.cmd' \
--exclude '*.d' \
--exclude '*.h' \
--exclude '*.output' \
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

weird, at least in the paste, there were files ending with .d and .o: https://gist.github.com/chantra/0acb0ec04a58db3adea2debd47e73fee#file-gistfile0-txt-L3600

There may be something wrong with the pattern matching?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll have to double check this, but IIRC --exclude applies to the files after it is specified.

So tar -cf - foo --exclude="*.x" bar will filter out *.x only from bar.

In our case it means that the filters don't apply to additional_file_list. Whether this was intentional, I don't know. Probably not.

@theihor
Copy link
Contributor Author

theihor commented Sep 20, 2024

@chantra I noticed that artifacts produced by tar-artifact.sh contain two copies of selftests/bpf: tools/testing/selftests/bpf and selftests/bpf.
I found that one is copied into another here: https://github.com/libbpf/ci/blob/main/build-selftests/build_selftests.sh#L63-L66
Do you know if there is a reason for having two copies?

No, I don't think so. The artifact is downloadable from GH (when going to the summary of the run, there is a link to the artifacts). The content of vmlinux-x86_64-gcc is https://gist.github.com/chantra/0acb0ec04a58db3adea2debd47e73fee

I think it could be moved in place. I know that we keep the "Makefile"s so later we can run make -s image_name to discover where the vmlinux file is. The rest, I am not too sure. Even in the selftests/bpf directory we may not need to keep everything that is compiled. At least not for the "artifact" that we re-use during the test run. We do need to keep it for when we update the cache though.

I believe on kernel-patches/bpf CI only one of those two selftests/bpf copies is present. For example build job artifacts from this bpf-ci run contain only this inside:

$ tree -L 2
.
├── kbuild-output
│   ├── arch
│   ├── include
│   └── vmlinux
└── selftests
    └── bpf

And the flag controlling what's included in the tarball depends on the repository name.

So the question is why additional files are needed on kernel-patches/vmtest, but not on kernel-patches/bpf. I'll try to figure that out. If it's only for make image_name it seems silly, as we should be able to pass that name around as an input or env variable.

LGTM. Before this lands, do you mind testing on the kernel-patches/vmtest repo by using this action, just to make sure we did not missed anything.

I already did: kernel-patches/vmtest#287

I tagged you there, but wasn't able to add you as a reviewer.

@chantra
Copy link
Collaborator

chantra commented Sep 23, 2024

So the question is why additional files are needed on kernel-patches/vmtest, but not on kernel-patches/bpf. I'll try to figure that out. If it's only for make image_name it seems silly, as we should be able to pass that name around as an input or env variable.

make image_name only needs the Makefiles, and I don't think it needs anything related to selftests. So I think this is probably unrelated and just ended up there as an accident. As much as this PR is concerned, I think we should leave it like this, and follow-up in a separate PR.

I already did: kernel-patches/vmtest#287

I tagged you there, but wasn't able to add you as a reviewer.

Ha great. Thanks. If this works, then that's a high signal that everything should be fine :D

@chantra
Copy link
Collaborator

chantra commented Sep 23, 2024

Feel free to merge this whenever you want, we may want to keep an eye on both kernel-patches/bpf and libbpf/libbpf after it landed just to be safe.

@theihor
Copy link
Contributor Author

theihor commented Sep 23, 2024

Feel free to merge this whenever you want, we may want to keep an eye on both kernel-patches/bpf and libbpf/libbpf after it landed just to be safe.

Ok. Thank you for the review.

I'd like BPF CI to become stable before merging this.

@theihor theihor merged commit 939bc7d into libbpf:main Sep 26, 2024
14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

packages vmtest steps into libbpf/ci actions
2 participants