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

improve service support, + miscellaneous changes #32

Merged
merged 20 commits into from
Jul 7, 2024
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ __pycache__/
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
Expand All @@ -27,6 +26,12 @@ share/python-wheels/
*.egg
MANIFEST

# autoconf files
autom4te.cache/
configure
config.status


# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
Expand Down
85 changes: 85 additions & 0 deletions INSTALL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@

# Dependencies
At build time: `autoconf`
At runtime: `python`, `numpy`, `click`, `rich` and `pyyaml`

Our standard builds use pyproject, mainly with poetry.

# Preparing the sources
The dist files are template files, which means you must first `autoconf` them. You could also just `sed` all the `.in` files if you don't want to use autotools.

``` sh
git clone https://github.com/mcgillij/amdfan.git
cd amdfan

autoconf
./configure --prefix=/usr --libdir=/usr/lib
```

# Service files
There are two ways to obtain the systemd service file. One is available during runtime, through the `amdfan --service` command, but takes some assumptions of your system. May not work.

``` sh
amdfan print-default --service | sudo tee /usr/lib/systemd/system/amdfan.service
```

If you ran `./configure` succesfully, you'll also find the service files for OpenRC and systemd under `dist/${init}/`.


# Configuration files
Similiar to above, you can obtain the sources from the runtime. This is not necessary, as this file is generated automatically after the daemon runs for the first time.

``` bash
amdfan print-default --configuration | sudo tee /etc/amdfan.yml
```


# Executable files
The executable files are contained within amdfan. This directory is a python module, and can either be loaded as `python -m amdgpu`. If you want to import the module, you may be interested in checking out `amdfan.commands`, which contains most of the subcommands.
Copy link
Owner

Choose a reason for hiding this comment

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

Suggested change
The executable files are contained within amdfan. This directory is a python module, and can either be loaded as `python -m amdgpu`. If you want to import the module, you may be interested in checking out `amdfan.commands`, which contains most of the subcommands.
The executable files are contained within amdfan. This directory is a python module, and can either be loaded as `python -m amdfan`. If you want to import the module, you may be interested in checking out `amdfan.commands`, which contains most of the subcommands.


Otherwise, just use python-exec with something like

```python
import sys
from amdfan.__main__ import main

if __name__ == '__main__':
sys.exit(main())
```



# Installing from PyPi
You can also install amdfan from pypi using something like poetry.

``` bash
poetry init
poetry add amdfan
poetry run amdfan --help
```

# Building Python package
Requires [poetry](https://python-poetry.org/) to be installed.

``` bash
git clone [email protected]:mcgillij/amdfan.git
cd amdfan/
poetry build
```

## Building Arch AUR package
Building the Arch package assumes you already have a chroot env setup to build packages.

```bash
git clone https://aur.archlinux.org/amdfan.git
cd amdfan/

autoconf --libdir=/usr
./configure
cp dist/pacman/PKGBUILD ./PKGBUILD

makechrootpkg -c -r $HOME/$CHROOT
sudo pacman -U --asdeps amdfan-*-any.pkg.tar.zst
```


164 changes: 31 additions & 133 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,102 +34,45 @@ Setting the card to system managed using the amdgpu_fan pegs your GPU fan at 100
These are all addressed in Amdfan, and as long as I’ve still got some AMD cards I intend to at least maintain this for myself. And anyone’s able to help out since this is open source. I would have liked to just contribute these fixes to the main project, but it’s now inactive.

# Documentation
## Usage

``` bash
Usage: amdfan.py [OPTIONS]
```help
Usage: amdfan [OPTIONS] COMMAND [ARGS]...

Options:
--daemon Run as daemon applying the fan curve
--monitor Run as a monitor showing temp and fan speed
--manual Manually set the fan speed value of a card
--configuration Prints out the default configuration for you to use
--service Prints out the amdfan.service file to use with systemd
--help Show this message and exit.
```
--help Show this message and exit.

## Daemon
Commands:
daemon Run the controller
monitor View the current temperature and speed
print-default Convenient defaults
set Manually override the fan speed
```

Amdfan is also runnable as a systemd service, with the provided ```amdfan.service```.
Each subcommand supports `--help` too, to get more details.

## Monitor
## Controlling the fans

You can use Amdfan to monitor your AMD video cards using the ```--monitor``` flag.
There are two ways to control your fans with Amdfan. Note that in order to control the fans, you will likely need to run either approach as root.

![screenshot](https://raw.githubusercontent.com/mcgillij/amdfan/main/images/screenshot.png)
The recommended way is through a system service started at boot. This will control the fans based on the detected temperature at a given interval.

## Manual
In case you don't want to use a service, you may also control the fans manually. While this is only adviced to do when first setting up your configuration, keep in mind you can also use it to temporarily take control away from the daemon until you revert the fan speed back to `auto`.

Alternatively if you don't want to set a fan curve, you can just apply a fan setting manually.
Also allows you to revert the fan control to the systems default behavior by using the "auto" parameter.
![screenshot](https://raw.githubusercontent.com/mcgillij/amdfan/main/images/manual.png)

## Configuration

This will dump out the default configuration that would get generated for `/etc/amdfan.yml` when you first run it as a service. This allows you to configure the settings prior to running it as a daemon if you wish.

Running `amdfan --configuration` will output the following block to STDOUT.

``` bash
#Fan Control Matrix.
# [<Temp in C>,<Fanspeed in %>]
speed_matrix:
- [4, 4]
- [30, 33]
- [45, 50]
- [60, 66]
- [65, 69]
- [70, 75]
- [75, 89]
- [80, 100]

# Current Min supported value is 4 due to driver bug
#
# Optional configuration options
#
# Allows for some leeway +/- temp, as to not constantly change fan speed
# threshold: 4
#
# Frequency will change how often we probe for the temp
# frequency: 5
#
# While frequency and threshold are optional, I highly recommend finding
# settings that work for you. I've included the defaults I use above.
#
# cards:
# can be any card returned from `ls /sys/class/drm | grep "^card[[:digit:]]$"`
# - card0
```
You can use this to generate your configuration by doing ``amdfan --configuration > amdfan.yml``, you can then modify the settings and place it in ``/etc/amdfan.yml`` for when you would like to run it as a service.

## Service

This is just a convenience method for dumping out the `amdfan.service` that would get installed if you used a package manager to install amdfan. Useful if you installed the module via `pip`, `pipenv` or `poetry`.

Running `amdfan --service` will output the following block to STDOUT.

``` bash
[Unit]
Description=amdfan controller

[Service]
ExecStart=/usr/bin/amdfan --daemon
Restart=always
## Monitor

[Install]
WantedBy=multi-user.target
```
You can use Amdfan to monitor your AMD video cards using the `monitor` flag. This does not require root privileges, usually.

# Note
![screenshot](https://raw.githubusercontent.com/mcgillij/amdfan/main/images/screenshot.png)

Monitoring fan speeds and temperatures can run with regular user permissions.
`root` permissions are required for changing the settings / running as a daemon.

# Recommended settings
## Configuration

Below is the settings that I use on my machines to control the fan curve without too much fuss, but you should find a frequency and threshold setting that works for your workloads.
Running `amdfan print-default --configuration` will dump out the default configuration that would get generated for `/etc/amdfan.yml` when you first run it as a service. If a value is not specified, it will use a default value if possible.

`/etc/amdfan.yml`
The following config is probably a reasonable setup:
``` bash
speed_matrix:
- [4, 4]
Expand All @@ -143,68 +86,23 @@ speed_matrix:

threshold: 4
frequency: 5
```

## Installing the systemd service
If you installed via the AUR, the service is already installed, and you just need to *start/enable* it. If you installed via pip/pipenv or poetry, you can generate your systemd service file with the following command.

``` bash
amdfan --service > amdfan.service && sudo mv amdfan.service /usr/lib/systemd/system/
```

## Starting the systemd service

To run the service, you can run the following commands to **start/enable** the service.

``` bash
sudo systemctl start amdfan
sudo systemctl enable amdfan
```

After you've started it, you may want to edit the settings found in `/etc/amdfan.yml`. Once your happy with those, you can restart amdfan with the following command.

``` bash
sudo systemctl restart amdfan
```

## Checking the status
You can check the systemd service status with the following command:

``` bash
systemctl status amdfan
# cards:
# - card0
```

If a configuration file is not found, a default one will be generated. If you want to make any changes to the default config before running it the daemon first, run `amdfan print-default --configuration | sudo tee /etc/amdfan.yml` and do your changes from there.

## Building Arch AUR package
- `speed_matrix` (required): a list of thresholds `[temperature, speed]` which are interpolated to calculate the fan speed.
- `threshold` (default `0`): allows for some leeway in temperatures, as to not constantly change fan speed
- `frequency` (default `5`): how often (in seconds) we wait between updates
- `cards` (required): a list of card names (from `/sys/class/drm`) which we want to control.

Building the Arch package assumes you already have a chroot env setup to build packages.
Note! You can send a SIGHUP signal to the daemon to request a reload of the config without restarting the whole service.

```bash
git clone https://aur.archlinux.org/amdfan.git
cd amdfan/
makechrootpkg -c -r $HOME/$CHROOT
```
# Install

## Installing the Arch package
Users: Use your package manager to install the package. It's available on Arch Linux and Gentoo. For other distributions, please request a maintainer to bring the package to your system, or read the installation notes at your own warranty.

``` bash
sudo pacman -U --asdeps amdfan-*-any.pkg.tar.zst
```
Maintainers: Check the [installation notes](INSTALL.md).

# Installing from PyPi
You can also install amdfan from pypi using something like poetry.

``` bash
poetry init
poetry add amdfan
poetry run amdfan --help
```

# Building Python package
Requires [poetry](https://python-poetry.org/) to be installed

``` bash
git clone [email protected]:mcgillij/amdfan.git
cd amdfan/
poetry build
```
File renamed without changes.
20 changes: 20 additions & 0 deletions amdfan/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#!/usr/bin/env python
""" entry point for amdfan """
# __main__.py
import click

from .commands import cli, monitor_cards, run_daemon, set_fan_speed


@click.group()
def main():
pass


main.add_command(cli)
main.add_command(run_daemon)
main.add_command(monitor_cards)
main.add_command(set_fan_speed)

if __name__ == "__main__":
main() # pylint: disable=no-value-for-parameter
Loading