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

Implement a new toolchain #27

Merged
merged 8 commits into from
Jan 9, 2024
Merged

Implement a new toolchain #27

merged 8 commits into from
Jan 9, 2024

Conversation

kakkoyun
Copy link
Member

@kakkoyun kakkoyun commented Dec 6, 2023

This PR introduces a new toolchain to build all the binaries and generate the tables.

Now, we use https://www.jetpack.io/devbox for managing external and tool dependencies, such as the Go toolchain or C compiler. This tool has been chosen because it has all the benefits of Nix, but we don't have to deal with all the intricacies of Nix. It also has an excellent integration with direnv to load the environment automatically when you enter the directory.

If you don't want to use it on your local machine, you can use the provided Dockerfile to build a container to run the tasks. You can use make targets to handle the change seamlessly. For example, you can run make build to build all the binaries for all the architectures. You can also run make DOCKER=1 build to build all the binaries in a containerized environment.

# Devbox is a tool to manage development environment dependencies.
# See https://www.jetpack.io/devbox for more information.

# You can install devbox with the following command:
# make bootstrap
# It also installs direnv to automatically load devbox environment.

# If you don't want to use devbox, you can use a containerized version of devbox
# with all the necessary dependencies. To do so, you need to install docker (or podman, etc)
# and run the targets with DOCKER=1 prefix. For example:
# make DOCKER=1 build

Moreover, we use https://magefile.org to handle all the complex tasks. It is a Go-based tool that allows us to write tasks in Go. It is a bit more verbose than Makefiles, but it is much more powerful and easier to maintain.

Furthermore, we use Zig build system to compile binaries to generate the unwind tables. It is a drop-in replacement for gcc and clang. It does not require any additional dependencies to cross-compile binaries, e.g., libc. Check https://zig.news/kristoff/make-zig-your-c-c-build-system-28g5 for more.

Lastly, we migrated to https://docs.dagger.io/zenith/ for CI/CD and made the GH Actions a lean runner. 0509f3d

This is a proof-of-concept implementation that I would like to carry onto other Parca projects.


On top of that, there are some changes to the structure of the files. Each output directory now has subdirectories for each target architecture.

  • out: Built binaries.
  • vendored: Checked in binaries that were built by others.
  • tables: Generated unwind tables from all the

You can check out the entire directory tree:

.
├── build.go
├── devbox.json
├── devbox.lock
├── Dockerfile
├── out
│   ├── amd64
│   │   ├── basic-cpp
│   │   └── basic-go
│   └── arm64
│       ├── basic-cpp
│       └── basic-go
├── src
│   ├── basic-cpp.cpp
│   ├── basic-cpp-jit.cpp
│   ├── basic-cpp-multithreaded.cpp
│   ├── basic-cpp-plt.cpp
│   └── main.go
├── tables
│   ├── amd64
│   │   ├── compact
│   │   │   ├── basic-cpp-jit-no-fp.txt
│   │   │   └── ...
│   │   ├── final
│   │   │   ├── basic-cpp-jit-no-fp.txt
│   │   │   └── ...
│   │   └── normal
│   │       ├── basic-cpp-jit-no-fp.txt
│   │       └── ...
│   └── arm64
│       ├── compact
│       │   ├── basic-cpp-jit-no-fp.txt
│       │   └── ...
│       ├── final
│       │   ├── basic-cpp-jit-no-fp.txt
│       │   └── ...
│       └── normal
│           ├── basic-cpp-jit-no-fp.txt
│           └── ...
└── vendored
    ├── amd64
    │   ├── libc.so.6
    │   └── ...
    └── arm64
        ├── libc.so.6
        └── ...

@kakkoyun kakkoyun force-pushed the new_build_toolchain branch 2 times, most recently from af87f87 to 94dd65e Compare December 7, 2023 17:33
@kakkoyun kakkoyun changed the title --wip-- [skip ci] Implement a new toolchain Dec 7, 2023
Signed-off-by: Kemal Akkoyun <kakkoyun@gmail.com>
Signed-off-by: Kemal Akkoyun <kakkoyun@gmail.com>
This commit introduces a new continuous integration workflow that gets triggered on every push to the repository. The 'Build' workflow, defined in `.github/workflows/build.yml`, sets up a job that runs on the latest Ubuntu runner. It consists of the following steps:

- Checking out the codebase using `actions/checkout@v3`.
- Installing `devbox` via the `jetpack-io/devbox-install-action@v0.6.0`.
- Testing the `devbox` installation with a basic echo command.
- Executing the build process through `devbox`.
- Running a generate step, likely related to code or artifact generation.
- Finally, validating the changes by checking if there's any uncommitted difference in the repository state, which might mean generated files are not committed or unexpected changes happened.

The introduction of this workflow automates the testing, building, generating, and validation processes, ensuring that every push is vetted through these steps.

Signed-off-by: Kemal Akkoyun <kakkoyun@gmail.com>
@kakkoyun kakkoyun marked this pull request as ready for review December 7, 2023 19:13
Signed-off-by: Kemal Akkoyun <kakkoyun@gmail.com>
Signed-off-by: Kemal Akkoyun <kakkoyun@gmail.com>
Signed-off-by: Kemal Akkoyun <kakkoyun@gmail.com>
@javierhonduco
Copy link
Contributor

Sorry for the late review!! As discussed before I think this is overall a good change, and it's a great testbed for improvements in the developer environment and beyond!

Some small comments here so far that I won't leave inline because the GitHub UI is erroring:

  • I suggest we change the name of the "normal" unwind tables to "human readable" or "default";
  • Really digging the "DOCKER=1" option! Why don't we make a default? That way we can pin the devbox version making all of our dev envs closer in behaviour. It will also help us identify trobleshoot issues with devbox if a bug or behaviour change is introduced;

@javierhonduco
Copy link
Contributor

Typically the current flow to update unwind tables is something like:

  • make a change to the table generation in the Agent repo;
  • produce unwind tables in this repo, and commit + push it;
  • update Agent to point to the latest testadata with the changes;

This works because we can choose the right "eh-frame" binary, but this PR doesn't allow to change the latest in the Agent to use a local one. What's the workflow you have planneed to update this?

@javierhonduco
Copy link
Contributor

javierhonduco commented Dec 18, 2023

Once again, sorry I can't seem to do the review in the UI:

+// generateTables generates all the tables for the given flags.
+func generateTables(src, dst string, flags ...string) error {
+       for _, target := range targets {
+               err := filepath.Walk(path.Join(src, target.goarch), func(p string, info os.FileInfo, err error) error {
+                       if err != nil {
+                               return err
+                       }
+                       if info.IsDir() {
+                               return nil
+                       }
+
+                       outputFilePath := fullTablesPath(target.goarch, path.Join(dst, fmt.Sprintf("ours_%s.txt", info.Name())))
+
+                       chaged, err := mgtarget.Path(outputFilePath, p)

nit: ^ chaged should be changed

@kakkoyun
Copy link
Member Author

This works because we can choose the right "eh-frame" binary, but this PR doesn't allow to change the latest in the Agent to use a local one. What's the workflow you have planneed to update this?

@javierhonduco You can always override the tooling by specifying the environment variable EH_FRAME. It could be a path, a branch, a tag, or a comment. Whatever go run actually lets us specify. In that sense, it could be even more flexible.

kakkoyun added a commit to parca-dev/parca-agent that referenced this pull request Jan 9, 2024
Signed-off-by: Kemal Akkoyun <kakkoyun@gmail.com>

> [!NOTE]
> This targets
https://github.com/parca-dev/parca-agent/tree/new_build_pipeline and
there will be a PR in the end targets the `main`.

From the users' perspective, this PR shouldn't change anything. If you
want to use specified dependencies please consider installing the devbox
and direnv (simply `make init`)

This brings the result of the experimentation for a new build pipeline
from parca-dev/testdata#27 to the agent.

At first, we will start by introducing the https://www.jetpack.io/devbox

> Now, we use https://www.jetpack.io/devbox for managing external and
tool dependencies, such as the Go toolchain or C compiler. This tool has
been chosen because it has all the benefits of
[Nix](https://nixos.org/), but we don't have to deal with all the
intricacies of Nix. It also has an excellent integration with
[direnv](https://direnv.net/) to load the environment automatically when
you enter the directory.

Moreover, this PR:
- Changes the directory structure a little bit to reduce the number of
top-level directories (I will introduce more) and group them.
- It also vendors in the dependencies of libbpf as git submodules and
compiles it. It's the same strategy as in
#1602 (that PR will be
deprecated). It is easier to manage than using some external tool.
Especially when we want to cross-compile them. (Makefile changes)
- The GH actions are updated to utilize the devbox.

### Test Plan
- See that CI is green.
- (Locally) Just run the make targets as before.
Signed-off-by: Kemal Akkoyun <kakkoyun@gmail.com>
@kakkoyun kakkoyun merged commit b1fea9c into main Jan 9, 2024
2 checks passed
@kakkoyun kakkoyun deleted the new_build_toolchain branch January 9, 2024 15:50
@kakkoyun kakkoyun mentioned this pull request Apr 24, 2024
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.

2 participants