From 8720ade6bd6efef6c2bfd4c47d0aac8a708b8d85 Mon Sep 17 00:00:00 2001 From: Guillaume Raffin Date: Fri, 27 Sep 2024 09:01:20 +0200 Subject: [PATCH] doc: Rewrite the readme and add a contributing guide --- CONTRIBUTING.md | 88 +++++++++++++++++++++++++++++++++++++++ README.md | 62 ++++++++++++++++----------- readme/alumet-banner.png | Bin 0 -> 35534 bytes 3 files changed, 126 insertions(+), 24 deletions(-) create mode 100644 CONTRIBUTING.md create mode 100644 readme/alumet-banner.png diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..a81b4cea --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,88 @@ +# Contributing guide + +Hello and thank you for your interest in contributing to the Alumet project! + +Here is what you need to know. + +## The repositories + +### Main repository (the one you are in) + +This repository is divided in several parts: +- The `alumet` crate contains the core of the measurement tool, as a Rust library. +- Binaries can be created from this library, in order to provide a runnable measurement software. The official binaries that we provide are defined in `app-agent`. Agents always depend on `alumet`. +- Plugins are defined in separate folders: `plugin-nvidia`, `plugin-rapl`, etc. Plugins always depend on `alumet`. +- Two more crates, `alumet-api-dynamic` and `alumet-api-macros`, ease the creation of dynamic plugins written in Rust. This is WIP (work in progress) = not finished yet. +- `test-dynamic-plugins` only exists for testing purposes. + +### Other repositories + +The [`alumet-dev` organization](https://github.com/alumet-dev) contains additional repositories for the website and the packaging of the tool. You'll find more information in each repository. + +## What you can do + +There are several categories of tasks that can help the Alumet projet. You don't necessarily need to code in Rust! + +### Report issues + +If you find a bug in the Alumet library or in one of the official agents, you should [open an issue on the `alumet` repository](https://github.com/alumet-dev/alumet/issues). Please use the search function to make sure that the bug you have found has not already been reported. For questions that are not bugs, or if you are not sure whether something is a bug or not, you can [open a discussion](https://github.com/alumet-dev/alumet/discussions). + +If you find a mistake or confusing point in the user book or in the developer book, you should open an issue on the `user-book` or `developer-book` repository. + +### Write documentation + +Writing documentation or tutorials that show how to use Alumet, in the [user book](https://github.com/alumet-dev/user-book), is very helpful to the project + +If you have a good understanding of Alumet internals, you can also explain how to write plugins and how to contribute to Alumet, in the [developer book](https://github.com/alumet-dev/developer-book). + +### Code 🧑‍💻 + +Using the open issues on GitHub, you can find something to work on. You should choose an issue that is not already assigned to someone. If unsure, feel free to ask in a comment or in a new discussion. + +If you are an external contributor, it works as follows: +1. Find something to work on using the [issues](https://github.com/alumet-dev/alumet/issues) or the [discussions](https://github.com/alumet-dev/alumet/discussions). +2. Fork the alumet repository. +3. Create a new git branch to work on. +4. On this branch, implement the fix or feature that you'd like Alumet to have. +5. Document new functions and types. Write [unit tests](https://doc.rust-lang.org/rust-by-example/testing/unit_testing.html) and/or integration tests. Run the tests with `cargo test`. +6. Format your code by running `cargo fmt` in the projet directory. We provide a `.rustfmt.toml` that will be automatically used by the formatting tool. +7. When you are ready, submit your work by opening a [Pull Request (PR)](https://github.com/alumet-dev/alumet/pulls). + +If your goal is to optimize somethings, please run benchmarks and provide [flame graphs](https://github.com/killercup/cargo-flamegraph) or other metrics to show your improvements. For micro-benchmarks, we recommend the tool [Criterion](https://bheisler.github.io/criterion.rs/book/index.html). + +## Rust good practices + +### Linting + +You should use [Clippy](https://doc.rust-lang.org/stable/clippy/index.html) to lint your code. The workspace `Cargo.toml` defines some lint rules, that must apply to every crate in the Alumet repository. + +Manual action required: if you add a crate (like a plugin) to the repository, add the following two lines to your `Cargo.toml`: + +```toml +[lints] +workspace = true +``` + +### Dependencies + +When you add a new plugin to the repository, make it depend on the `alumet` crate in a relative way, without specifying a version. That is, the `dependencies` section of its `Cargo.toml` should look like this: + +```toml +[dependencies] +alumet = { path = "../alumet" } +``` + +### Basic tips + +- For efficiency, avoid too much cloning. It's fine for a PoC but should be optimized before merging the PR. +- Use `anyhow` and `thiserror` to simplify error management. Alumet already uses those. +- Use [`log`](https://docs.rs/log/latest/log/) to log messages, not `println`. Example: +```rs +let value = (); +log::debug!("My value is: {value:?}"); +``` + +### Advanced tips + +- Alumet internally uses Tokio. To contribute to the core of Alumet, please first follow the [Tokio tutorial](https://tokio.rs/tokio/tutorial). This is not necessary for most plugins. +- If you get weird errors with `async` code, such as `higher-ranked lifetime error`, try to decompose your operation in several functions and variables, and write down the types of each step explicitly. This will help the compiler to figure out the types of the futures. diff --git a/README.md b/README.md index 9c56c75a..2357f29f 100644 --- a/README.md +++ b/README.md @@ -1,41 +1,55 @@ -# ALUMET +

+ +

+ +# **Adaptive, Lightweight, Unified Metrics.** -ALUMET is a generic measurement tool that brings together research and industry. -Interesting features include: -- true modularity: you can add new sources of measurements, data transforms and outputs without modifying the core of the tool -- pay only for what you need: by choosing the plugins that are included in the tool, you avoid bloat and stay lightweight -- performance: built in Rust, optimized for low latency and low memory consumption -- unification: one core, one interface for all your metrics on all your devices +**ALUMET** is a modular tool that measures energy consumption and performance metrics. It offers a new standard framework for all your measurements, with a very low overhead. [Learn more on the website](https://alumet.dev). + + + +## Why should I use it? -Learn more on [the website](https://alumet.dev). +- [x] I want to estimate the energy consumption of the software I run. +- [x] I want to measure the energy consumption of my CPU or GPU, _accurately_[^1]. +- [x] I need to export my measurements to local files or to a database. +- [x] I would like to choose the acquisition frequency and to be able to use frequencies above 1000 Hz. +- [x] I _don't_ want the measurement tool to eat up my CPU and consume too much power. +- [x] I _don't_ want to setup a different tool for each hardware component and software environment I have (laptops, Edge devices with GPUs, bare-metal HPC servers, K8S clusters, ...). -## What can I measure with it? +If you answer yes to any of these questions, Alumet is for you! -Alumet sources include: -- RAPL counters on x86 CPUS -- NVIDIA dedicated GPUs -- NVIDIA Jetson devices -- Linux perf_events for processes and cgroups -- Kubernetes pods (WIP) +We also have extra features (see the documentation). -If your favorite feature is not listed above, don't worry! The list of plugins is rapidly growing, and we have an ambitious roadmap. +[^1]: See the following research paper for a detailed analysis of some common errors in RAPL-based measurement tools: [Guillaume Raffin, Denis Trystram. Dissecting the software-based measurement of CPU energy consumption: a comparative analysis. 2024. ⟨hal-04420527v2⟩](https://hal.science/hal-04420527). ## How to use -Please read [the Alumet user book](https://alumet-dev.github.io/user-book/) to learn how to install and use Alumet. +Please read [the Alumet user book](https://alumet-dev.github.io/user-book/) to learn how to install and use the Alumet "agent" (the program that performs the measurements). + +If you have a question, feel free to ask on the [Discussions page](https://github.com/alumet-dev/alumet/discussions). + +## Extending Alumet -## This repository +The `alumet` crate provides a library with a plugin system. With plugins, you can extend Alumet in the following ways: +- read new sources of measurements +- apply arbitrary transformations to the data (such as energy attribution models) +- export the data to new outputs +- perform actions on startup and shutdown -ALUMET is divided in several parts: -- The `alumet` crate contains the core of the measurement tool, as a Rust library. -- Binaries can be created from this library, in order to provide a runnable measurement software, such as `app-agent`. -- Plugins are defined in separate folders: `plugin-nvidia`, `plugin-rapl`, etc. -- Two more crates, `alumet-api-dynamic` and `alumet-api-macros`, ease the creation of dynamic plugins written in Rust (WIP). -- `test-dynamic-plugins` only exists for testing purposes. +Please read [the Alumet developer book](https://alumet-dev.github.io/developer-book/) to learn how to make plugins. + +## Contributing + +Alumet is a joint project between the LIG (computer science laboratory of Grenoble) and Eviden (Atos HPC R&D). It is also open to external volunteers like you! + +Please go to the [contributing guide](./CONTRIBUTING.md) to get started. ## License Copyright 2024 Guillaume Raffin, BULL SAS, CNRS, INRIA, Grenoble INP-UGA. Licensed under the EUPL-1.2 or later. + +You can find [more information about the EUPL here](https://joinup.ec.europa.eu/collection/eupl/introduction-eupl-licence). The EUPL is compatible with many other open source licenses and shares some principles with the well-known LGPL. diff --git a/readme/alumet-banner.png b/readme/alumet-banner.png new file mode 100644 index 0000000000000000000000000000000000000000..e1eabb4241f7463a41df69ea38356dc81222d23d GIT binary patch literal 35534 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