Skip to content

Commit

Permalink
doc: add configuration docs
Browse files Browse the repository at this point in the history
  • Loading branch information
ilya-zlobintsev committed Dec 30, 2024
1 parent 08a3d5b commit 0b0921b
Show file tree
Hide file tree
Showing 8 changed files with 281 additions and 53 deletions.
49 changes: 0 additions & 49 deletions API.md

This file was deleted.

1 change: 1 addition & 0 deletions API.md
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ Current features:
- Viewing information about the GPU
- Power and thermals monitoring, power limit configuration
- Fan curve control
- Overclocking (GPU/VRAM clockspeed and voltage, currently AMD only)
- Overclocking (GPU/VRAM clockspeed and voltage)
- Power states configuration (AMD only)

Both AMD and Nvidia functionality works on X11, Wayland or even headless sessions.
Expand Down Expand Up @@ -75,7 +75,7 @@ However the following table shows what functionality can be expected for a given
| Vega | Supported | Supported | Supported | Supported | |
| RDNA1 (RX 5000) | Supported | Supported | Supported | Supported | |
| RDNA2 (RX 6000) | Supported | Supported | Supported | Supported | |
| RDNA3 (RX 7000) | Supported | Limited | Supported | Limited | Fan zero RPM mode is enabled by default even with a custom fan curve, and requires kernel 6.13 (`linux-next` when writing this) to be disabled. The power cap is sometimes reported lower than it should be. See [#255](https://github.com/ilya-zlobintsev/LACT/issues/255) for more info. |
| RDNA3 (RX 7000) | Supported | Limited | Supported | Limited | Fan zero RPM mode is enabled by default even with a custom fan curve, and requires kernel 6.13 to be disabled. The power cap is sometimes reported lower than it should be. See [#255](https://github.com/ilya-zlobintsev/LACT/issues/255) for more info. |

GPUs not listed here will still work, but might not have full functionality available.
Monitoring/system info will be available everywhere. Integrated GPUs might also only have basic configuration available.
Expand Down
49 changes: 49 additions & 0 deletions docs/API.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Description

The LACT Daemon exposes a JSON API over a unix socket or TCP, available on `/var/run/lactd.sock` or an arbitrary TCP port. You can configure who has access to the unix socket in `/etc/lact/config.yaml` in the `daemon.admin_groups` field. The TCP listener is disabled by default for security reasons, see [this README section](./README.md#remote-management) for how to enable it.

The API expects newline-separated JSON objects, and returns a JSON object for every request.

The general format of requests looks like:
```
{"command": "command_name", "args": {}}
```
Note that the type of `args` depends on the specific request, and may be ommited in some cases.

The response looks like this:
```
{"status": "ok|error", "data": {}}
```
Same as `args` in requests, `data` can be of a different type and may not be present depending on the specific request.

You can try sending commands to socket interactively with `ncat`:
```
echo '{"command": "list_devices"}' | ncat -U /run/lactd.sock
```
Example response:
```
{"status":"ok","data":[{"id":"1002:687F-1043:0555-0000:0b:00.0","name":"Vega 10 XL/XT [Radeon RX Vega 56/64]"}]}
```

Here's an example of calling the API with arguments to change a profile:
```
echo '{"command": "set_profile", "args": {"name":"name-of-the-profile"}}' | ncat -U /run/lactd.sock
```
In this code, `name-of-the-profile` should be replaced with the name of a profile that you've already created in LACT.


# Commands

For the full list of available commands and responses, you can look at the source code of the schema: [requests](lact-schema/src/request.rs), [the basic response structure](lact-schema/src/response.rs) and [all possible types](lact-schema/src/lib.rs).

It should also be fairly easy to figure out the API by trial and error, as the error message are quite verbose:

```
echo '{"command": "test"}' | ncat -U /run/lactd.sock
{"status":"error","data":"Failed to deserialize request: unknown variant `test`, expected one of `ping`, `list_devices`, `system_info`, `device_info`, `device_stats`, `device_clocks_info`, `set_fan_control`, `set_power_cap`, `set_performance_level`, `set_clocks_value` at line 1 column 18"}
```

# Rust

If you want to connect to the socket from a Rust program, you can simply import either the `lact-client` or `lact-schema` (if you want to write a custom client) crates from this repository.
155 changes: 155 additions & 0 deletions docs/CONFIG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
# Configuration

The LACT config file is located in `/etc/lact/config.yaml`, and contains all of the GPU settings that are typically edited in the GUI, as well as a few settings specifying the behaviour of the daemon.
LACT listens for config file changes and reloads all GPU settings automatically, but daemon-related settings such as the logging level or permissions require a service restart (`systemctl restart lactd`).

Full config file with all possible options:
```yaml
# WARNING: this is only an example of each possible setting. DO NOT COPY THIS CONFIG AS IS.
# Many options don't make sense to be used together, and depend on your hardware.
daemon:
# The logging level of the daemon.
# Possible values: `error`, `warn`, `info` (default), `debug`, `trace`
log_level: info
# User groups who should have access to the daemon.
# WARNING: only the first group from this list that is found on the system is used!
# This is made a list and not a single value to allow this config to work across
# different distros, which might have different groups for an "admin" user.
admin_groups:
- wheel
- sudo
# If set to `true`, this setting makes the LACT daemon not reset
# GPU clocks when changing other settings or when turning off the daemon.
# Can be used to work around a few very specific issues with
# some settings not applying on AMD GPUs.
disable_clocks_cleanup: false
# Daemon's TCP listening address. Not specified by default.
# By default TCP access is disabled, and only a unix socket is present.
# Specifying this option enables the TCP listener.
tcp_listen_address: 127.0.0.1:12853

# Period in seconds for how long settings should wait to be confirmed.
# Most GPU setting change commands require a confirmation command to be used
# in order to save these settings to the config.
# If a confirm command is not issued within the configured period (default: 5 seconds)
# the setting will be reverted.
apply_settings_timer: 5

# The main GPU configuration map, containing the list of GPUs and their settings.
gpus:
# A GPU config entry. This is the ID of the GPU.
# The ID is formed with a combination of a PCI device id,
# PCI subsystem id and PCI slot name to uniquely identify
# each GPU in the system, even if there are multiple of the same model.

# You can discover the id of your GPU by either:
# - Changing a setting in the UI, so it's written to the config
# - Using `lact cli list-gpus`
1002:687F-1043:0555-0000:0b:00.0:
# Whether the daemon should touch fan control settings at all.
# Setting this to `true` requires the `fan_control_settings` field to be present as well.
fan_control_enabled: true
fan_control_settings:
# Fan control mode. Can be either `curve` or `static`
mode: curve
# Static fan speed from 0 to 1. Used when `mode` is `static`
static_speed: 1.0
# The temperature sensor name to be used with a custom fan curve.
# This can be used to base the fan curve off the`junction` (hotspot)
# temperature instead of the default overall ("edge") tempreature.
# Applicable on most Vega and newer AMD GPUs.
temperature_key: edge
# Interval in milliseconds for how often the GPU temperature should be checked
# when adjusting the fan curve.
interval_ms: 500
# Custom fan curve used with `mode` set to `curve`.
# The format of the map is temperature to fan speed from 0 to 1.
# Note: on RDNA3+ AMD GPUs this must have 5 entries.
curve:
40: 0.2
50: 0.35
60: 0.5
70: 0.75
80: 1.0
# Hysteresis setting: when spinning down fans after a temperature drop,
# the target speed needs to be lower for at least this many milliseconds
# for the fan to actually slow down.
# This lets you avoid fan speed jumping around during short drops of load
# (e.g. loading screen in a game).
spindown_delay_ms: 0
# Hysteresis setting: the minimum temperature change in degrees
# to affect the fan speed. Also used to avoid rapid fan speed changes
# when the temperature only changes e.g. 1 degree.
change_threshold: 0
# Power management firmware options. Specific to RDNA3+ AMD GPUs.
# Most of these settings are only applied when not using a custom fan curve.
pmfw_options:
# This setting adjusts the PMFW’s behavior about the maximum speed in RPM the fan can spin.
acoustic_limit: 3200
# This setting adjusts the PMFW’s behavior about the maximum speed in RPM the fan can spin
# when the temperature is not greater than target temperature.
acoustic_target: 1450
# The minimum speed in RPM that the fan can spin at.
minimum_pwm: 15
# Target temperature for the GPU in degrees.
# Paring with the acoustic_target setting, they define the maximum speed in RPM
# the fan can spin when the temperature is not greater than target temperature.
target_temperature: 83
# When set to `true`, allows the fan to be turned turned off when below the
# `zero_rpm_threshold` temperature value.
zero_rpm: true
# Temperature in degrees below which the fan should be turned off when `zero_rpm` is set to true.
zero_rpm_threshold: 50
# Power limit in watts.
power_cap: 320.0
# Performance level option for AMD GPUs.
# Can be `auto`, `low`, `high` or `manual`.
performance_level: auto
# Index of an AMD power profile mode.
# Setting this requires `performance_level` to be set to `manual`.
power_profile_mode_index: 0
# Custom heuristic values when using the custom AMD power profile mode.
# TODO
custom_power_profile_mode_hueristics: []
# TODO
power_states: {}
# Minimum GPU clockspeed in MHz.
min_core_clock: 300
# Minimum VRAM clockspeed in MHz.
min_memory_clock: 500
# Minimum GPU voltage in mV.
min_voltage: 900
# Maximum GPU clockspeed in MHz.
max_core_clock: 1630
# Maximum VRAM clockspeed in MHz.
max_memory_clock: 800
# Maximum GPU voltage in mV.
max_voltage: 1200
# Voltage offset value in mV for RDNA and newer AMD GPUs.
voltage_offset: 0

# Settings profiles
profiles:
# Name of the profile
vkcube:
# GPU settings in this profile.
# It is the same config format that is used for the top-level `gpus` option.
gpus: {}
# Profile activation rule for when this profile shoule be activated
# when using automatic profile switching.
rule:
# Type of the rule. Can be either `process or `gamemode`.
type: process
# Process filter. This is not required when using the gamemode rule type.
filter:
# Name of the process.
name: vkcube
# Process arguments. Not required.
args: --my-arg

# Current profile to be used. Does not have effect when `auto_switch_profiles` is used.
# Omit this option or set to `null` to use the default profile (settings in the top-level `gpus` entry).
current_profile: vkcube
# If profiles should be switched between automatically based on their configured rules.
auto_switch_profiles: true
```
2 changes: 1 addition & 1 deletion lact-daemon/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ copes = { git = "https://gitlab.com/corectrl/copes" }
divan = { workspace = true }
pretty_assertions = { workspace = true }
lact-daemon = { path = ".", features = ["bench"] }
insta = { version = "1.41.1", features = ["json"] }
insta = { version = "1.41.1", features = ["json", "yaml"] }

[[bench]]
name = "daemon"
Expand Down
18 changes: 18 additions & 0 deletions lact-daemon/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,7 @@ fn default_apply_settings_timer() -> u64 {
mod tests {
use super::{ClocksConfiguration, Config, Daemon, FanControlSettings, Gpu};
use crate::server::gpu_controller::fan_control::FanCurve;
use insta::assert_yaml_snapshot;
use lact_schema::{FanControlMode, PmfwOptions};
use std::collections::HashMap;

Expand Down Expand Up @@ -395,6 +396,23 @@ mod tests {
assert_eq!(config, deserialized_config);
}

#[test]
fn parse_doc() {
let doc = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/../docs/CONFIG.md"));
let example_config_start = doc
.find("```yaml")
.expect("Could not find example config start")
+ 7;
let example_config_end = doc[example_config_start..]
.find("```")
.expect("Could not find example config end")
+ example_config_start;
let example_config = &doc[example_config_start..example_config_end];

let deserialized_config: Config = serde_yaml::from_str(&example_config).unwrap();
assert_yaml_snapshot!(deserialized_config);
}

#[test]
fn clocks_configuration_applied() {
let mut gpu = Gpu {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
---
source: lact-daemon/src/config.rs
expression: deserialized_config
---
daemon:
log_level: info
admin_groups:
- wheel
- sudo
disable_clocks_cleanup: false
tcp_listen_address: "127.0.0.1:12853"
apply_settings_timer: 5
gpus:
"1002:687F-1043:0555-0000:0b:00.0":
fan_control_enabled: true
fan_control_settings:
mode: curve
static_speed: 1
temperature_key: edge
interval_ms: 500
curve:
40: 0.2
50: 0.35
60: 0.5
70: 0.75
80: 1
spindown_delay_ms: 0
change_threshold: 0
pmfw_options:
acoustic_limit: 3200
acoustic_target: 1450
minimum_pwm: 15
target_temperature: 83
zero_rpm: true
zero_rpm_threshold: 50
power_cap: 320
performance_level: auto
min_core_clock: 300
min_memory_clock: 500
min_voltage: 900
max_core_clock: 1630
max_memory_clock: 800
max_voltage: 1200
voltage_offset: 0
power_profile_mode_index: 0
profiles:
vkcube:
rule:
type: process
filter:
name: vkcube
args: "--my-arg"
current_profile: vkcube
auto_switch_profiles: true
2 changes: 1 addition & 1 deletion lact/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ default = ["lact-gui"]
adw = ["lact-gui/adw"]

[dependencies]
lact-daemon = { path = "../lact-daemon", default-features = false }
lact-daemon = { path = "../lact-daemon" }
lact-schema = { path = "../lact-schema", features = ["args"] }
lact-cli = { path = "../lact-cli" }
lact-gui = { path = "../lact-gui", optional = true }
Expand Down

0 comments on commit 0b0921b

Please sign in to comment.