Messages : 2,824
Sujets : 56
Inscription : Mar 2016
Type: Particulier
09-12-2024, 11:07 AM
(Modification du message : 09-17-2024, 01:26 PM par Bear.)
(09-11-2024, 04:03 PM)zaurux a écrit : Il m'a gentiment renvoyé vers GentooPlayer et me dit qu'il faut avoir les sources pour compiler sous Arch.
Là je suis d'accord mais je ne sais ù les trouver.
Une piste ?
Et excuse moi pour le HS Fedora 
Bonjour Stéphane,
Yu a publié sur son site Preview des liens de téléchargement automatiques vers les dernières versions.
(09-11-2024, 09:00 PM)Le dom a écrit : Si tu veux partir sur une distribution ArchLinux, je te conseille Audiolinux beaucoup plus abouti que ArchQ. De plus Audiolinux supporte Diretta.
Bonjour Le Dom,
As-tu essayé ArchQ ?
Certes Audiolinux est une bonne distro, mais elle est payante.
Du coup, ArchQ vaut peut-être le coup d'être testé tu ne penses pas ?
Concernant la compilation des drivers Diretta est assez simple, du moment que l'on dispose des outils nécessaires, et en particulier de la copie du noyau.
Messages : 3,768
Sujets : 32
Inscription : Jan 2017
Type: Particulier
Localisation: Près de Dax (40)
09-12-2024, 09:57 PM
(Modification du message : 09-12-2024, 10:08 PM par Le dom.)
J’ai regardé vite fait et j’ai l’impression que l’on ne peut pas y installer ce que l’on veut.
J’y jetterai un coup d’œil à l’occasion pour voir ce que l’on peut faire avec.
Source: PC CPU AMD Ryzen 9 5900X Audiolinux v3 7.00 - Alim JCAT OPTIMO S ATX + Target Diretta Ustars C19 avec AL RPI 4.40 + Clock by FLR - alim DIY 4 x 5V avec transfos Toroïdy Audio Grade Supreme et composants Audio Grade pour C19, clock FLR, carte JCAT Net Card XE.
DAC: Holo Audio Spring 3 Level 2 - Ampli intégré: La Rosita Maverick -Switches RJ45: Reddo Audio + HNE MagicNet D1 Supreme - Enceintes: AudioPhysic Cardeas - Câblage: vers full Murmure Audio.
Messages : 2,824
Sujets : 56
Inscription : Mar 2016
Type: Particulier
09-13-2024, 08:18 AM
(Modification du message : 09-13-2024, 08:19 AM par Bear.)
Une autre distro ArchLinux me semble digne d'intérêt: CachyOS Linux.
Ils annoncent en effet des noyaux optimisés autour du micro-code des version X86-v3, X86-v4 et même Zen4: https://cachyos.org/blog/2407-july-release/
Ils cherchent à optimiser le scheduler ainsi qu'à réduire la latence.
Cela me parait une alternative plus ouverte et en tous cas assez efficace au plan de l'optimisation du noyau.
Elle a été benchmarkée par Phoronix: https://www.phoronix.com/review/cachyos-x86-64-v3-v4
Concernant ArchQ, j'ai un doute sur la validité du claim du développeur concernant l'optimisation du noyau à 352kHz qui éviterait l'upsampling... Mais je trouve cela amusant et lorsque j'aurai un peu de temps, je testerai...
Messages : 3,768
Sujets : 32
Inscription : Jan 2017
Type: Particulier
Localisation: Près de Dax (40)
En fait Audiolinux 6.10 v3 et v4 sont basés sur une structure CachyOS.
Source: PC CPU AMD Ryzen 9 5900X Audiolinux v3 7.00 - Alim JCAT OPTIMO S ATX + Target Diretta Ustars C19 avec AL RPI 4.40 + Clock by FLR - alim DIY 4 x 5V avec transfos Toroïdy Audio Grade Supreme et composants Audio Grade pour C19, clock FLR, carte JCAT Net Card XE.
DAC: Holo Audio Spring 3 Level 2 - Ampli intégré: La Rosita Maverick -Switches RJ45: Reddo Audio + HNE MagicNet D1 Supreme - Enceintes: AudioPhysic Cardeas - Câblage: vers full Murmure Audio.
Messages : 2,824
Sujets : 56
Inscription : Mar 2016
Type: Particulier
Merci pour cette précision. Cela fait du sens et permet de mieux comprendre l'enthousiasme partagé autour de ces nouvelles architectures de processeurs
Messages : 4,257
Sujets : 82
Inscription : Mar 2019
Type: Particulier
Localisation: Côte d'Or
09-17-2024, 10:15 AM
(Modification du message : 09-17-2024, 01:10 PM par Steph44200.
Raison de la modification: lien supprimé
)
Je vous donne la réponse "in extenso" du développeur d'ArchQ qui est assez réactif ( via GitHub).
Citation :This is Diretta box driver(alsa_bridge.ko) for ArchQ Q441 kernel.
You can download the file and auto extract it as below command.
modéré
to install the driver.
Hope this driver works well.
Messages : 4,257
Sujets : 82
Inscription : Mar 2019
Type: Particulier
Localisation: Côte d'Or
Mea culpa, maxima culpa... et la démarche était purement personne.. à usage personnel.
J'aurai juste du m'en ternir à des échanges privés sans les partager.
A noter, que cette distribution même si elle apparait incomplète n'a aucune velléité commerciale et respecte totalement le texte de YU, cité ci-dessus.
Dans tous les cas, il convient de ne pas polluer le fil de Bear.
Messages : 2,824
Sujets : 56
Inscription : Mar 2016
Type: Particulier
Bonjour,
Les distros d'Audio-Linux et de GentooPlayer offrent des noyaux 'customisés' qui sont en général facturés séparément, et renchérissent le montant de l'abonnement.
Il est maintenant assez facile d'optimiser son propre noyau lors de la compilation.
Un user-guide facile à suivre pour Fedora se trouve ici: https://linuxconfig.org/how-to-compile-v...-on-fedora
Les sources de la dernière version du noyau sont ici: https://git.kernel.org/pub/scm/linux/ker...linux.git/
On peut facilement spécifier dans la phase "make menuconfig" que l'on souhaite un noyau temps réel.
Enfin, si l'on souhaite encore affiner, on peut s'appuyer sur les moteurs d'IA pour nous aider.
J'ai ainsi trouvé sur Grok, le moteur concurrent de ChatGPT, le tuto suivant pour optimiser pour un processeur Zen 4 d'AMD.
To optimize the Linux kernel for the AMD Zen 4 architecture in Linux kernel version 6.12, you can follow these steps:
1. **Kernel Configuration:**
- **Use Custom Compilation:**
When compiling the kernel, you need to set specific compiler flags that target the Zen 4 architecture. This can be done by modifying the kernel's make configuration:
```bash
make menuconfig
```
Navigate to:
- **Processor type and features**
- Here, you might not find an explicit option for Zen 4 (znver4) in older or standard kernel configurations, but you can manually set the architecture for compilation:
- **Advanced options**
- **Kernel .config support**
- Set `CONFIG_MZEN4=y` if available. This would typically enable optimizations for the Zen 4 architecture.
- **If `CONFIG_MZEN4` is not available:**
You might need to edit the `.config` file directly or add it to the `Kconfig` if you're customizing the kernel setup. However, for Zen 4, you would usually use:
```bash
echo "CONFIG_MARCH_ZNVER4=y" >> .config
```
Or ensure your make command includes these flags:
```bash
make -j $(nproc) KCFLAGS="-march=znver4 -mtune=znver4" LOCALVERSION=-zn4
```
2. **Compiler Optimization:**
- When building the kernel or any other software for Zen 4, ensure your GCC compiler supports the `-march=znver4` flag. This flag tells the compiler to generate code specifically optimized for Zen 4.
- Check your GCC version for support:
```bash
gcc --target-help | grep znver4
```
- If supported, use:
```bash
export CFLAGS="-march=znver4 -mtune=znver4 -O2 -pipe"
```
This should be added to your environment or included in the kernel's build process.
3. **Microcode Update:**
- Ensure your system's microcode is up-to-date for Zen 4. Although this doesn't directly involve the kernel compilation, having the latest microcode can provide better performance and stability.
- Check for microcode updates in your distribution or manually update via `iucode-tool`.
4. **Performance Monitoring:**
- Utilize perf tools optimized for Zen 4. Linux 6.2 and later versions include enhanced perf counters for AMD Zen 4, which can help in identifying performance bottlenecks.
5. **Documentation and Patches:**
- Review the Linux kernel documentation and any patches specific to Zen 4 optimizations, as these might include tweaks or new features beneficial for your hardware.
6. **Community Resources:**
- Check online forums like Reddit's r/archlinux, Linux Mint forums, or other Linux communities where users might share custom patches or configurations for Ryzen CPUs.
Remember, while these steps can help optimize for Zen 4, the performance gains might be marginal in day-to-day use unless you're running very specific workloads that benefit from the architecture's enhancements. Also, ensure you have backups before experimenting with custom kernel builds, as incorrect configurations can lead to system instability.
Voilà. Plutôt cool de se compiler son propre noyau et de l'installer sur son serveur
Messages : 2,824
Sujets : 56
Inscription : Mar 2016
Type: Particulier
10-30-2025, 01:46 PM
(Modification du message : 10-30-2025, 02:37 PM par Bear.)
Je ré-ouvre ce sujet par un script de compilation du noyau en version RT.
J'ai écrit ce script avec l'aide de l'IA pour me permettre de suivre les nouvelles versions de noyau qui sont publiées par Linus Torvald toutes les semaines.
Il suffit de télécharger le noyau ici: https://git.kernel.org/pub/scm/linux/ker...linux.git/
de le décompresser (tar -xvf ...), de copier le fichier de configuration de sa machine vers le répertoire créé, d'y copier le script ci-dessous après l'avoir rendu exécutable, et de le faire tourner.
Ce script sélectionne par défaut les options RT (PREEMP_RT) et rajoute une fréquence à 2000 Hz pour le scheduler.
Sous toutes réserves. Enjoy
Code : #!/bin/bash
set -e
# ============================================
# CHECK DEPENDENCIES
# ============================================
echo "=== Checking build dependencies ==="
REQUIRED_TOOLS=(
"make"
"gcc"
"bc"
"bison"
"flex"
"libelf-dev"
"libssl-dev"
"rpm-build"
"ncurses-dev"
)
MISSING_DEPS=()
for tool in "${REQUIRED_TOOLS[@]}"; do
# Check if package-based tool
if [[ "$tool" == *-dev ]]; then
# For .deb systems (convert to package name check)
pkg_name="${tool%-dev}"
if ! dpkg -l | grep -qw "$pkg_name" 2>/dev/null; then
MISSING_DEPS+=("$tool")
fi
else
# Check if command exists
if ! command -v "$tool" &> /dev/null; then
MISSING_DEPS+=("$tool")
fi
fi
done
if [ ${#MISSING_DEPS[@]} -gt 0 ]; then
echo "✗ Missing dependencies:"
printf ' - %s\n' "${MISSING_DEPS[@]}"
echo ""
echo "Install with:"
echo " sudo dnf install gcc make bc bison flex elfutils-libelf-devel openssl-devel rpm-build ncurses-devel"
exit 1
fi
echo "✓ All dependencies satisfied"
echo ""
echo "=== Audio-Optimized RT Kernel Build Script ==="
echo ""
# ============================================
# DETECT CPU ARCHITECTURE
# ============================================
echo "=== Detecting CPU Architecture ==="
CPU_VENDOR=$(lscpu | grep "Vendor ID" | awk '{print $3}')
CPU_MODEL=$(lscpu | grep "Model name" | cut -d: -f2 | xargs)
CPU_FAMILY=$(lscpu | grep "CPU family" | awk '{print $3}')
CPU_MODEL_NUM=$(lscpu | grep -w "Model:" | awk '{print $2}')
echo "CPU Vendor: $CPU_VENDOR"
echo "CPU Model: $CPU_MODEL"
echo "CPU Family: $CPU_FAMILY"
echo "CPU Model Number: $CPU_MODEL_NUM"
# Detect Zen4 (Family 25, Model >= 96)
# Zen4: Ryzen 7000 series, EPYC 9004 series
IS_ZEN4=false
if [ "$CPU_VENDOR" = "AuthenticAMD" ]; then
if [ "$CPU_FAMILY" = "25" ] && [ "$CPU_MODEL_NUM" -ge 96 ]; then
IS_ZEN4=true
elif echo "$CPU_MODEL" | grep -Eq "Ryzen.*(7[0-9]{3}|9[0-9]{3})"; then
IS_ZEN4=true
elif echo "$CPU_MODEL" | grep -Eq "EPYC.*9[0-9]{3}"; then
IS_ZEN4=true
fi
fi
if [ "$IS_ZEN4" = true ]; then
echo ""
echo "✓ Zen4 architecture detected!"
echo " Enabling optimizations: -march=x86-64-v4 -mtune=znver4 -O3"
KCFLAGS="-march=x86-64-v4 -mtune=znver4 -O3"
else
echo ""
echo "→ Non-Zen4 CPU detected"
echo " Using standard compilation flags"
KCFLAGS=""
fi
echo ""
# ============================================
# CLEAN BUILD ENVIRONMENT
# ============================================
echo "=== Cleaning build environment ==="
make mrproper
# ============================================
# PATCH 1: kernel/Kconfig.hz for HZ_2000
# ============================================
echo "=== Patching Kconfig.hz for HZ_2000 ==="
KCONFIG_HZ="kernel/Kconfig.hz"
if [ ! -f "$KCONFIG_HZ" ]; then
echo "✗ Error: $KCONFIG_HZ not found"
echo "Are you in the kernel source directory?"
exit 1
fi
if grep -q "config HZ_2000" "$KCONFIG_HZ"; then
echo "✓ HZ_2000 already present"
else
echo "⚠ Adding HZ_2000 support..."
cp "$KCONFIG_HZ" "${KCONFIG_HZ}.backup"
# Insert HZ_2000 config option after HZ_1000
awk '
/config HZ_1000/ { in_hz1000=1 }
in_hz1000 && /^$/ && !hz2000_added {
print "\tconfig HZ_2000"
print "\t\tbool \"2000 HZ\""
print "\thelp"
print "\t 2000 Hz is suited for audio production and low-latency applications."
print ""
hz2000_added=1
}
{ print }
' "${KCONFIG_HZ}.backup" > "$KCONFIG_HZ.tmp"
# Add default 2000 case
awk '
/^config HZ$/ { in_hz_section=1 }
in_hz_section && /default 1000 if HZ_1000/ {
print
print "\tdefault 2000 if HZ_2000"
next
}
{ print }
' "$KCONFIG_HZ.tmp" > "$KCONFIG_HZ"
rm "$KCONFIG_HZ.tmp"
echo "✓ HZ_2000 patch applied"
fi
echo ""
# ============================================
# PATCH 2: ATO_BITS in inet_connection_sock.h
# ============================================
echo "=== Patching ATO_BITS for better network performance ==="
INET_SOCK_H="include/net/inet_connection_sock.h"
if [ ! -f "$INET_SOCK_H" ]; then
echo "✗ Error: $INET_SOCK_H not found"
exit 1
fi
# Check current ATO_BITS value (more robust check)
CURRENT_ATO_LINE=$(grep -n "#define[[:space:]]*ATO_BITS" "$INET_SOCK_H" 2>/dev/null | head -1)
if [ -z "$CURRENT_ATO_LINE" ]; then
echo "✗ Error: ATO_BITS definition not found in $INET_SOCK_H"
echo "File may have changed. Manual inspection required."
exit 1
fi
CURRENT_ATO_VALUE=$(echo "$CURRENT_ATO_LINE" | awk '{print $NF}')
if [ "$CURRENT_ATO_VALUE" = "10" ]; then
echo "✓ ATO_BITS already set to 10"
elif [ "$CURRENT_ATO_VALUE" = "8" ]; then
echo "⚠ Changing ATO_BITS from 8 to 10..."
# Backup
cp "$INET_SOCK_H" "${INET_SOCK_H}.backup"
# Change ATO_BITS 8 to 10
sed -i 's/\(#define[[:space:]]*ATO_BITS[[:space:]]*\)8/\110/' "$INET_SOCK_H"
# Verify change
NEW_ATO=$(grep "#define[[:space:]]*ATO_BITS" "$INET_SOCK_H" | awk '{print $NF}')
if [ "$NEW_ATO" = "10" ]; then
echo "✓ Changed: #define ATO_BITS 10"
else
echo "✗ Patch failed! Restoring backup..."
mv "${INET_SOCK_H}.backup" "$INET_SOCK_H"
exit 1
fi
else
echo "⚠ Warning: ATO_BITS is $CURRENT_ATO_VALUE (expected 8 or 10)"
read -p "Continue anyway? [y/N] " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
exit 1
fi
fi
echo ""
# ============================================
# Generate base config from loaded modules
# ============================================
echo "=== Generating localmodconfig ==="
make localmodconfig
# Backup config AFTER localmodconfig
echo "=== Backing up config ==="
cp .config .config.backup
# ============================================
# Apply optimizations
# ============================================
echo ""
echo "=== Configuring Audio-Optimized RT Kernel ==="
# CRITICAL: Remove debug symbols
scripts/config --enable DEBUG_INFO_NONE
scripts/config --disable DEBUG_INFO_DWARF5
scripts/config --disable DEBUG_INFO_BTF
scripts/config --disable DEBUG_INFO_BTF_MODULES
scripts/config --disable GDB_SCRIPTS
# Size reduction
scripts/config --disable MAXSMP
scripts/config --set-val NR_CPUS 24
scripts/config --disable SECURITY_SELINUX
scripts/config --disable SECURITY_APPARMOR
scripts/config --disable IMA
scripts/config --disable AUDIT
scripts/config --disable FTRACE
scripts/config --disable KVM
# RT settings (CRITICAL for audio)
scripts/config --enable PREEMPT_RT
scripts/config --enable HZ_2000
scripts/config --enable HIGH_RES_TIMERS
scripts/config --enable NO_HZ_FULL
scripts/config --enable RCU_BOOST
# Network optimizations
scripts/config --enable TCP_CONG_BBR
scripts/config --set-str DEFAULT_TCP_CONG "bbr"
# ============================================
# CIFS/SMB SUPPORT - ADDED
# ============================================
echo ""
echo "=== Enabling CIFS/SMB Support ==="
# Core CIFS module
scripts/config --module CIFS
# Essential CIFS features
scripts/config --enable CIFS_ALLOW_INSECURE_LEGACY # SMB1 support (if needed)
scripts/config --enable CIFS_WEAK_PW_HASH # Legacy password hashing
scripts/config --enable CIFS_UPCALL # Kerberos/SPNEGO support
scripts/config --enable CIFS_XATTR # Extended attributes
scripts/config --enable CIFS_POSIX # POSIX extensions
scripts/config --enable CIFS_DEBUG # Debug support
scripts/config --enable CIFS_DEBUG2 # Additional debugging
scripts/config --enable CIFS_DFS_UPCALL # DFS support
# Optional features (comment out if not needed)
# scripts/config --enable CIFS_SMB_DIRECT # RDMA support (needs INFINIBAND)
# scripts/config --enable CIFS_FSCACHE # FS-Cache support
# Required crypto dependencies (should already be enabled)
scripts/config --enable CRYPTO_MD5
scripts/config --enable CRYPTO_SHA256
scripts/config --enable CRYPTO_SHA512
scripts/config --enable CRYPTO_AES
scripts/config --enable CRYPTO_CMAC
scripts/config --enable CRYPTO_ECB
scripts/config --enable CRYPTO_HMAC
echo "✓ CIFS configuration applied"
# Update config with all changes
make olddefconfig
# ============================================
# Verify critical settings
# ============================================
echo ""
echo "=== Verifying Configuration ==="
check_config() {
local option=$1
local expected=$2
local actual=$(grep "^CONFIG_${option}=" .config 2>/dev/null | cut -d= -f2)
if [ -z "$actual" ]; then
actual=$(grep "^# CONFIG_${option} is not set" .config 2>/dev/null)
if [ -n "$actual" ] && [ "$expected" = "n" ]; then
echo "✓ CONFIG_${option} is not set (as expected)"
return 0
fi
echo "⚠ CONFIG_${option} not set"
return 1
elif [ "$actual" = "$expected" ]; then
echo "✓ CONFIG_${option}=${actual}"
return 0
else
echo "✗ CONFIG_${option}=${actual} (expected: ${expected})"
return 1
fi
}
VERIFY_OK=true
# RT and performance settings
check_config "PREEMPT_RT" "y" || VERIFY_OK=false
check_config "HZ_2000" "y" || VERIFY_OK=false
check_config "HZ" "2000" || VERIFY_OK=false
check_config "HIGH_RES_TIMERS" "y" || VERIFY_OK=false
check_config "NO_HZ_FULL" "y" || VERIFY_OK=false
check_config "RCU_BOOST" "y" || VERIFY_OK=false
check_config "DEBUG_INFO_NONE" "y" || VERIFY_OK=false
check_config "NR_CPUS" "24" || VERIFY_OK=false
# CIFS verification
echo ""
echo "=== CIFS Configuration ==="
check_config "CIFS" "m" || VERIFY_OK=false
check_config "CIFS_XATTR" "y" || VERIFY_OK=false
check_config "CIFS_POSIX" "y" || VERIFY_OK=false
check_config "CIFS_UPCALL" "y" || VERIFY_OK=false
# Verify patches were applied to source files
echo ""
echo "=== Source Code Patches ==="
HZ_2000_CHECK=$(grep -c "config HZ_2000" "$KCONFIG_HZ")
ATO_BITS_CHECK=$(grep "^#define[[:space:]]*ATO_BITS" "$INET_SOCK_H" | awk '{print $3}')
if [ "$HZ_2000_CHECK" -ge 1 ]; then
echo "✓ HZ_2000 option present in Kconfig.hz"
else
echo "✗ HZ_2000 option missing from Kconfig.hz"
VERIFY_OK=false
fi
if [ "$ATO_BITS_CHECK" = "10" ]; then
echo "✓ ATO_BITS set to 10 in inet_connection_sock.h"
else
echo "✗ ATO_BITS is $ATO_BITS_CHECK (expected 10)"
VERIFY_OK=false
fi
echo ""
echo "=== Configuration Summary ==="
echo "Architecture: $CPU_MODEL"
if [ "$IS_ZEN4" = true ]; then
echo "Optimizations: Zen4 (-march=x86-64-v4 -mtune=znver4 -O3) ✓"
else
echo "Optimizations: Standard (generic x86_64)"
fi
echo "PREEMPT_RT: ENABLED ✓"
echo "HZ: 2000 ✓"
echo "ATO_BITS: 10 ✓"
echo "CIFS/SMB: ENABLED (module) ✓"
echo "Debug symbols: DISABLED ✓"
echo "NR_CPUS: 24 ✓"
echo ""
if [ "$VERIFY_OK" = false ]; then
echo "⚠ WARNING: Some verification checks failed"
echo ""
read -p "Continue with build anyway? [y/N] " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
echo "Build cancelled. You can:"
echo " - Review .config manually: make menuconfig"
echo " - Check patches: cat ${KCONFIG_HZ}.backup"
echo " - Restore config: cp .config.backup .config"
exit 1
fi
fi
# ============================================
# Final confirmation before build
# ============================================
read -p "Configuration complete. Proceed with build? [y/N] " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
echo "Build cancelled. Configuration saved in .config"
echo "To build later, run:"
if [ "$IS_ZEN4" = true ]; then
echo " make KCFLAGS=\"-march=x86-64-v4 -mtune=znver4 -O3\" -j\$(nproc)"
else
echo " make -j\$(nproc)"
fi
exit 0
fi
# ============================================
# Build kernel
# ============================================
echo ""
echo "=== Building Kernel ==="
if [ -n "$KCFLAGS" ]; then
echo "Compiler flags: $KCFLAGS"
fi
echo "Parallel jobs: $(nproc)"
echo "Started: $(date)"
echo ""
START_TIME=$(date +%s)
# Build kernel with architecture-specific flags
if [ "$IS_ZEN4" = true ]; then
echo "Building with Zen4 optimizations..."
make KCFLAGS="-march=x86-64-v4 -mtune=znver4 -O3" -j$(nproc) || {
echo "✗ Kernel build failed!"
exit 1
}
else
echo "Building with standard flags..."
make -j$(nproc) || {
echo "✗ Kernel build failed!"
exit 1
}
fi
# Build RPM package
echo ""
echo "=== Building RPM Package ==="
if [ "$IS_ZEN4" = true ]; then
make KCFLAGS="-march=x86-64-v4 -mtune=znver4 -O3" -j$(nproc) binrpm-pkg || {
echo "⚠ RPM package build failed, but kernel image is OK"
}
else
make -j$(nproc) binrpm-pkg || {
echo "⚠ RPM package build failed, but kernel image is OK"
}
fi
END_TIME=$(date +%s)
BUILD_TIME=$((END_TIME - START_TIME))
BUILD_MIN=$((BUILD_TIME / 60))
BUILD_SEC=$((BUILD_TIME % 60))
echo ""
echo "=== Build Complete ==="
echo "Finished: $(date)"
echo "Build time: ${BUILD_MIN}m ${BUILD_SEC}s"
echo ""
# ============================================
# Show results
# ============================================
if [ -f arch/x86/boot/bzImage ]; then
echo "=== Kernel Image ==="
ls -lh arch/x86/boot/bzImage
KERNEL_SIZE=$(stat -c%s arch/x86/boot/bzImage)
KERNEL_MB=$((KERNEL_SIZE / 1024 / 1024))
echo "Size: ${KERNEL_MB} MB"
echo ""
if [ $KERNEL_MB -lt 20 ]; then
echo "✓ Size optimal (expected: 10-15 MB with RT)"
elif [ $KERNEL_MB -lt 50 ]; then
echo "⚠ Size acceptable but larger than expected"
echo " Consider checking if debug symbols are fully disabled"
else
echo "✗ Size too large (${KERNEL_MB} MB)"
echo " Debug symbols may still be enabled!"
echo " Check: grep DEBUG_INFO .config"
fi
else
echo "✗ Error: Kernel image not found!"
echo "Build may have failed"
exit 1
fi
echo ""
echo "=== RPM Packages ==="
RPM_DIR="${PWD}/rpmbuild/RPMS/x86_64"
if [ -d "$RPM_DIR" ]; then
RPM_COUNT=$(find "$RPM_DIR" -name "kernel*.rpm" -mtime -1 2>/dev/null | wc -l)
if [ "$RPM_COUNT" -gt 0 ]; then
echo "Found $RPM_COUNT package(s):"
find "$RPM_DIR" -name "kernel*.rpm" -mtime -1 -exec ls -lh {} \;
else
echo "⚠ No recent RPM packages found"
echo "Check: ls -la $RPM_DIR"
fi
else
echo "⚠ RPM directory not found: $RPM_DIR"
echo "RPM package may not have been created"
fi
echo ""
echo "=== Optimizations Applied ==="
echo "✓ HZ=2000 (0.5ms timer resolution)"
echo "✓ PREEMPT_RT (real-time scheduling)"
echo "✓ ATO_BITS=10 (better network ACK handling)"
echo "✓ CIFS/SMB support (module)"
echo "✓ Debug info removed (97% size reduction)"
echo "✓ BBR TCP congestion control"
if [ "$IS_ZEN4" = true ]; then
echo "✓ Zen4 optimizations:"
echo " • -march=x86-64-v4 (AVX-512, AVX2, FMA, BMI)"
echo " • -mtune=znver4 (Zen4 instruction scheduling)"
echo " • -O3 (aggressive optimization)"
fi
echo ""
echo "=== Performance Expectations ==="
echo "Audio latency: <5ms ✓"
echo "Network latency: Improved ✓"
echo "Real-time performance: Optimal ✓"
echo "CIFS/SMB mounts: Supported ✓"
if [ "$IS_ZEN4" = true ]; then
echo "CPU performance: +10-20% (Zen4 optimized) ✓"
fi
echo ""
echo "=== Installation Steps ==="
if [ -d "$RPM_DIR" ] && [ "$RPM_COUNT" -gt 0 ]; then
echo "1. sudo rpm -ivh $RPM_DIR/kernel-*.rpm"
echo "2. sudo grub2-mkconfig -o /boot/grub2/grub.cfg"
else
echo "1. sudo make modules_install"
echo "2. sudo make install"
fi
echo "3. sudo reboot"
echo "4. Select new kernel from GRUB menu"
echo ""
echo "=== Verification After Boot ==="
echo "# Check kernel version and config:"
echo "uname -r"
echo "grep CONFIG_HZ= /boot/config-\$(uname -r)"
echo "grep CONFIG_PREEMPT_RT /boot/config-\$(uname -r)"
echo ""
echo "# Verify CIFS module:"
echo "modinfo cifs"
echo "lsmod | grep cifs"
echo ""
echo "# Test CIFS mount (example):"
echo "sudo mount -t cifs //server/share /mnt/point -o username=user"
echo ""
echo "# Check patches applied:"
echo "grep ATO_BITS /usr/src/kernels/\$(uname -r)/include/net/inet_connection_sock.h"
echo ""
if [ "$IS_ZEN4" = true ]; then
echo "# Verify Zen4 optimizations:"
echo "cat /proc/cpuinfo | grep -E 'avx512|avx2' | head -1"
fi
echo ""
echo "=== Backup Files Created ==="
echo ".config.backup - Kernel configuration backup"
echo "${KCONFIG_HZ}.backup - Original Kconfig.hz"
echo "${INET_SOCK_H}.backup - Original inet_connection_sock.h"
Et pour ceux qui sont tentés par l'optimisation de leur serveur sous Linux, voici la façon que j'ai trouvée optimale d'isoler les processeurs et de les affecter aux tâches HQPlayer et direttaAlsa.
Cette façon de procéder est compatible avec les dernières versions du noyau et permet une cohabitation harmonieuse de HQPlayer et de DirettaAlsa.
Voir ici la référence de départ: https://documentation.ubuntu.com/real-ti...st/how-to/
CPU Isolation Strategy for Real-Time Audio Processing
A Modern, Persistent Approach Using Systemd Slices and Cgroups v2
---
Overview
This guide implements CPU isolation for real-time audio workloads (HQPlayer, Diretta) on Fedora/Ubuntu with RT kernels. It leverages systemd slices and cgroup v2 for robust, persistent isolation that survives reboots and updates.
Key Benefits:
- [x] Persistence across reboots
- [x] Systemd-native configuration
- [x] Minimal latency for audio processing
- [x] Proper inheritance to subprocesses/threads
---
System Architecture
Target System: AMD Ryzen 7 7700X (16 logical CPUs: 8 cores × 2 threads)
CPU Allocation:
- CPUs 0, 8: Housekeeping (IRQs, system tasks)
- CPUs 1-2, 9-10: Diretta ALSA (2 cores + SMT)
- CPUs 3-7, 11-15: HQPlayer (5 cores + SMT)
---
Prerequisites
### Stop Running Services
Code : sudo systemctl stop hqplayerd
sudo systemctl stop diretta_sync_host # Adjust name as needed
### Backup Existing Configurations
Code : sudo cp /lib/systemd/system/multi-user.target.wants/hqplayerd.service \
/lib/systemd/system/multi-user.target.wants/hqplayerd.service.bak
### Verify Cgroup v2
Code : cat /sys/fs/cgroup/cgroup.controllers
# Should list "cpuset" among controllers
---
## Step 1: Kernel Boot Parameters
Edit GRUB configuration:
Code : sudo nano /etc/default/grub
Add/modify the following line:
Code : GRUB_CMDLINE_LINUX="rhgb quiet zswap.enabled=0 amd_pstate=enable audit=0 ibt=off nosoftlockup skew_tick=1 default_hugepagesz=1G isolcpus=io_queue,1-7,9-15 nohz=on nohz_full=1-7,9-15 rcu_nocbs=1-7,9-15 irqaffinity=0,8"
**Parameter Explanation:**
- isolcpus=io_queue,1-7,9-15 - Isolates CPUs from general scheduler
- nohz_full=1-7,9-15 - Disables periodic timer ticks (reduces interrupts)
- rcu_nocbs=1-7,9-15 - Offloads RCU callbacks to housekeeping CPUs
- irqaffinity=0,8 - Restricts hardware interrupts to CPUs 0 and 8
Update GRUB and reboot:
Code : sudo grub2-mkconfig -o /boot/grub2/grub.cfg
sudo reboot
---
## Step 2: Create Systemd Configuration Directories
Code : sudo mkdir -p /etc/systemd/system/init.scope.d/
sudo mkdir -p /etc/systemd/system/system.slice.d/
sudo mkdir -p /etc/systemd/system/user.slice.d/
---
## Step 3: Restrict System Tasks to Housekeeping CPUs
### Init Scope Configuration
Code : sudo nano /etc/systemd/system/init.scope.d/50-cpu-isolation.conf
Code : [Scope]
AllowedCPUs=0,8
### System Slice Configuration
Code : sudo nano /etc/systemd/system/system.slice.d/50-cpu-isolation.conf
Code : [Slice]
AllowedCPUs=0,8
### User Slice Configuration
Code : sudo nano /etc/systemd/system/user.slice.d/50-cpu-isolation.conf
Code : [Slice]
AllowedCPUs=0,8
---
## Step 4: Create Custom Workload Slices
### Diretta Slice
Code : sudo nano /etc/systemd/system/diretta.slice
Code : [Slice]
AllowedCPUs=1-2,9-10
### HQPlayer Slice
Code : sudo nano /etc/systemd/system/hqplayer.slice
Code : [Slice]
AllowedCPUs=3-7,11-15
CPUQuota=100%
---
## Step 5: Configure Service Files
### Diretta ALSA Service
Code : sudo nano /etc/systemd/system/diretta_sync_host.service
Code : [Unit]
Description=Diretta Synchro ALSA Host
After=network-online.target
ConditionPathExists=/home/User/DirettaAlsaHost
[Service]
Slice=diretta.slice
ExecStart=/home/User/DirettaAlsaHost/syncAlsa_gcc15_x64_zen4 /home/User/DirettaAlsaHost/setting.inf
ExecStop=/home/User/DirettaAlsaHost/syncAlsa_gcc15_x64_zen4 kill
Restart=always
Type=simple
[Install]
WantedBy=multi-user.target
### HQPlayer Service
Code : sudo nano /etc/systemd/system/multi-user.target.wants/hqplayerd.service
Code : [Unit]
Description=HQPlayer Embedded daemon
Requires=network-online.target sound.target systemd-udev-settle.service NetworkManager-wait-online.service
After=network-online.target sound.target systemd-udev-settle.service local-fs.target remote-fs.target
[Service]
Type=simple
Slice=hqplayer.slice
ExecStart=/usr/bin/hqplayerd
Restart=always
RestartSec=2
EnvironmentFile=-/etc/default/hqplayerd
User=hqplayer
IOSchedulingClass=realtime
LimitMEMLOCK=4G
LimitNICE=-10
LimitRTPRIO=98
CPUSchedulingPolicy=rr
CPUSchedulingPriority=99
Nice=-20
[Install]
WantedBy=multi-user.target
**Key Settings:**
- Slice=hqplayer.slice - Assigns to custom slice with isolated CPUs
- CPUSchedulingPolicy=rr - Real-time round-robin scheduling
- CPUSchedulingPriority=99 - Maximum RT priority
- LimitMEMLOCK=4G - Prevents memory paging
---
## Step 6: IRQ Affinity Management
### Create IRQ Affinity Script
Code : sudo nano /usr/local/bin/set-irq-affinity.sh
Code : #!/bin/bash
# Set IRQ affinities to housekeeping cores for isolation
HOUSEKEEPING_CPUS="0,8"
LOG_FILE="/var/log/irq-affinity.log"
echo "$(date): Starting IRQ affinity setup" | tee -a "$LOG_FILE"
# Set global default affinity
echo "$HOUSEKEEPING_CPUS" > /proc/irq/default_smp_affinity_list 2>> "$LOG_FILE" && \
echo "Set default IRQ affinity to $HOUSEKEEPING_CPUS" | tee -a "$LOG_FILE" || \
echo "Error setting default affinity" | tee -a "$LOG_FILE"
# Set affinity for all existing IRQs
for irq_dir in /proc/irq/*; do
if [ -f "$irq_dir/smp_affinity_list" ]; then
irq=$(basename "$irq_dir")
echo "$HOUSEKEEPING_CPUS" > "$irq_dir/smp_affinity_list" 2>> "$LOG_FILE" && \
echo "Set IRQ $irq to $HOUSEKEEPING_CPUS" | tee -a "$LOG_FILE" || \
echo "Error setting IRQ $irq" | tee -a "$LOG_FILE"
fi
done
# Show current IRQ mappings
echo "" | tee -a "$LOG_FILE"
echo "Current IRQ affinity:" | tee -a "$LOG_FILE"
for i in $(find /proc/irq/ -name smp_affinity_list | grep -v "default_smp_affinity"); do
irq=$(basename $(dirname $i))
affinity=$(cat $i)
echo "IRQ $irq: $affinity" | tee -a "$LOG_FILE"
done
Make executable:
Code : sudo chmod +x /usr/local/bin/set-irq-affinity.sh
### Create Systemd Service
Code : sudo nano /etc/systemd/system/set-irq-affinity.service
Code : [Unit]
Description=Set IRQ affinity for audio isolation
After=network.target
[Service]
Type=oneshot
ExecStart=/usr/local/bin/set-irq-affinity.sh
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
Enable the service:
Code : sudo systemctl daemon-reload
sudo systemctl enable set-irq-affinity.service
---
## Step 7: CPU Frequency Scaling
### Create Performance Governor Service
Code : sudo nano /etc/systemd/system/cpu-performance.service
Code : [Unit]
Description=Set CPU governor to performance for audio cores
After=multi-user.target
[Service]
Type=oneshot
ExecStart=/bin/bash -c 'for i in 1 2 3 4 5 6 7 9 10 11 12 13 14 15; do echo performance > /sys/devices/system/cpu/cpu$i/cpufreq/scaling_governor; done'
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
Enable:
Code : sudo systemctl daemon-reload
sudo systemctl enable cpu-performance.service
---
## Step 8: Apply Configuration
Code : sudo systemctl daemon-reload
sudo systemctl restart hqplayerd
sudo systemctl restart diretta_sync_host
sudo systemctl start set-irq-affinity.service
sudo systemctl start cpu-performance.service
---
## Step 9: Verification
### Check CPU Affinity
Code : # HQPlayer threads
ps -eLo psr,comm | grep hqplayerd | awk '{print $1}' | sort -nu
# Diretta threads
ps -eLo psr,comm | grep syncAlsa | awk '{print $1}' | sort -nu
# Expected: HQPlayer on 3-7,11-15; Diretta on 1-2,9-10
### Verify Systemd Configuration
Code : # Check slice settings
systemctl show hqplayer.slice -p AllowedCPUs
systemctl show diretta.slice -p AllowedCPUs
systemctl show system.slice -p AllowedCPUs
# Check service inheritance
systemctl show hqplayerd -p AllowedCPUs
systemctl show diretta_sync_host -p AllowedCPUs
### Check IRQ Distribution
Code : # View IRQ affinity log
sudo tail -n 50 /var/log/irq-affinity.log
# Check specific IRQ
cat /proc/interrupts | grep -E "CPU0|CPU8"
### Verify CPU Governor
Code : for i in {1..7} {9..15}; do
echo "CPU $i: $(cat /sys/devices/system/cpu/cpu$i/cpufreq/scaling_governor)"
done
---
## Step 10: Performance Testing
### Latency Test with Cyclictest
Code : sudo ./cyclictest -q -l 600000 -m -Sp98 -i100 -d0
**Target Metrics:**
- Max latency < 50μs on isolated CPUs
- Consistent performance during audio playback
### Monitor During Playback
Code : # Real-time CPU usage
htop -d 5
# Per-thread affinity
watch -n 1 'ps -eLo pid,tid,psr,comm,args | grep -E "hqplayer|syncAlsa"'
---
## Troubleshooting
### Configuration Not Applied
**Check systemd loaded configurations:**
Code : systemctl cat init.scope
systemctl cat system.slice
systemctl cat hqplayer.slice
**Verify cgroup effective CPUs:**
Code : cat /sys/fs/cgroup/system.slice/cpuset.cpus.effective
cat /sys/fs/cgroup/hqplayer.slice/cpuset.cpus.effective
### Services on Wrong CPUs
**Force daemon reload:**
Code : sudo systemctl daemon-reload
sudo systemctl restart system.slice # Warning: Restarts all system services
**Check for conflicting configurations:**
Code : systemd-delta --type=extended | grep -E "slice|scope"
### Reverting Changes
**Remove configuration files:**
Code : sudo rm -rf /etc/systemd/system/init.scope.d/
sudo rm -rf /etc/systemd/system/system.slice.d/
sudo rm -rf /etc/systemd/system/user.slice.d/
sudo rm /etc/systemd/system/diretta.slice
sudo rm /etc/systemd/system/hqplayer.slice
sudo systemctl daemon-reload
**Restore original kernel parameters:**
Code : sudo nano /etc/default/grub
# Remove isolation parameters
sudo grub2-mkconfig -o /boot/grub2/grub.cfg
sudo reboot
---
## Technical Notes
### Why This Approach Works
- Cgroup v2 Hierarchy: AllowedCPUs in slices creates hard CPU boundaries that inherit to all child processes/threads
- Kernel Isolation: isolcpus prevents scheduler from automatically placing tasks on isolated CPUs
- RT Scheduling: SCHED_RR priority 99 ensures audio tasks preempt all normal-priority work
Messages : 2,824
Sujets : 56
Inscription : Mar 2016
Type: Particulier
Hier, 11:15 PM
(Modification du message : Il y a 11 heures par Bear.)
Pour vous permettre de faire vos premiers pas dans l'optimisation de Diretta en mode DDS, voici un programme python qui calcule une proposition de fichier de paramètres adaptés. N'oubliez pas de démarrer à très bas volume pour ne pas griller vos enceintes. Je dégage toute responsabilité...
Code : #!/usr/bin/env python3
"""
Diretta DDS Configuration Calculator
Based on real working configuration with adaptive CycleTime
Optimized settings: periodMin=4, periodMax=8, syncBufferCount=6
Usage:
python3 diretta_calc.py # Default optimized settings
python3 diretta_calc.py --period-max 6 # Lower latency
python3 diretta_calc.py --pcm # PCM instead of DSD
python3 diretta_calc.py --help # Show all options
"""
import argparse
from typing import Dict, List, Tuple
class DirettaCalculator:
"""Calculate Diretta configuration parameters"""
# Ethernet frame overhead
ETH_HEADER = 14
DIRETTA_HEADER = 2
VLAN_OVERHEAD = 4
FCS = 4
def __init__(self, mtu: int = 9024):
self.mtu = mtu
self.overhead = self.ETH_HEADER + self.DIRETTA_HEADER + self.VLAN_OVERHEAD
self.available_payload = mtu - self.overhead
def calculate_frame_params(self, sample_rate: int, is_dsd: bool = True) -> Dict:
"""
Calculate frame parameters for a given sample rate
Args:
sample_rate: Sample rate in Hz (e.g., 12288000 for DSD256×48k)
is_dsd: True for DSD, False for PCM
Returns:
Dictionary with frame parameters
"""
# Bytes per sample (stereo)
if is_dsd:
bytes_per_sample = 0.25 # 1 bit/sample × 2 channels = 2 bits = 0.25 bytes
else:
bytes_per_sample = 6 # 24 bit/sample × 2 channels = 48 bits = 6 bytes
# Calculate samples that fit in available payload
# Align to 64-bit (8 byte) boundary
audio_bytes_max = (int(self.available_payload / 8) * 8)
samples_per_frame = int(audio_bytes_max / bytes_per_sample)
# Actual audio bytes after alignment
audio_bytes = int(samples_per_frame * bytes_per_sample)
# Calculate cycle time (time to transmit one frame)
cycle_time_us = (samples_per_frame / sample_rate) * 1_000_000
# Packet rate (packets per second)
packet_rate_hz = sample_rate / samples_per_frame
# Total frame size
total_frame_size = self.ETH_HEADER + self.DIRETTA_HEADER + audio_bytes + self.FCS
return {
'sample_rate': sample_rate,
'sample_rate_mhz': sample_rate / 1_000_000,
'samples_per_frame': samples_per_frame,
'audio_bytes': audio_bytes,
'total_frame_size': total_frame_size,
'cycle_time_us': cycle_time_us,
'cycle_time_ms': cycle_time_us / 1000,
'packet_rate_hz': packet_rate_hz,
'bytes_per_sample': bytes_per_sample,
'is_dsd': is_dsd,
}
def find_target_cycle_time(self, base_rates: List[int], is_dsd: bool = True) -> Tuple[int, Dict]:
"""
Find a target CycleTime that works well across multiple base rates
Args:
base_rates: List of base sample rates (e.g., [44100, 48000])
is_dsd: True for DSD, False for PCM
Returns:
Tuple of (recommended_cycle_time_us, analysis_dict)
"""
results = {}
for base_rate in base_rates:
# For DSD256, multiply by 256; for PCM 8fs, multiply by 8
multiplier = 256 if is_dsd else 8
sample_rate = base_rate * multiplier
params = self.calculate_frame_params(sample_rate, is_dsd)
results[base_rate] = params
# Find the cycle time that's closest to average
cycle_times = [p['cycle_time_us'] for p in results.values()]
avg_cycle = sum(cycle_times) / len(cycle_times)
# Round to nearest 5 microseconds for cleaner config
target_cycle = int(round(avg_cycle / 5) * 5)
return target_cycle, results
def print_header():
"""Print program header"""
print("""
╔═══════════════════════════════════════════════════════════════════════════════╗
║ DIRETTA DDS CONFIGURATION CALCULATOR ║
║ Low Latency Optimizer ║
╚═══════════════════════════════════════════════════════════════════════════════╝
""")
def print_analysis_table(calculator: DirettaCalculator, configs: List[Dict]):
"""Print analysis table for different sample rates"""
print(f"\n{'='*100}")
print(f"SAMPLE RATE ANALYSIS (MTU = {calculator.mtu} bytes)")
print(f"{'='*100}")
print(f"\n{'Format':<20} {'Sample Rate':<15} {'Samples/':<12} {'Cycle':<12} {'Packet':<12} {'Audio':<10}")
print(f"{'':20} {'(MHz)':<15} {'Frame':<12} {'(μs)':<12} {'Rate (Hz)':<12} {'Bytes':<10}")
print("-" * 100)
for config in configs:
params = calculator.calculate_frame_params(config['sample_rate'], config['is_dsd'])
print(f"{config['name']:<20} "
f"{params['sample_rate_mhz']:>8.6f} "
f"{params['samples_per_frame']:>8} "
f"{params['cycle_time_us']:>8.1f} "
f"{params['packet_rate_hz']:>8.2f} "
f"{params['audio_bytes']:>6}")
def print_latency_table(calculator: DirettaCalculator, configs: List[Dict],
period_min: int, period_max: int, sync_buffer: int):
"""Print detailed latency table for all configurations"""
print(f"\n{'='*100}")
print(f"LATENCY COMPARISON TABLE")
print(f"{'='*100}")
buffer_configs = [
("Ultra Conservative", 6, 12, 10),
("Conservative", 5, 10, 8),
("Optimized (recommended)", 4, 8, 6),
("Lower Latency", 3, 6, 5),
("Aggressive", 3, 6, 4),
]
# Highlight the current settings
current_config = (f"Your Settings", period_min, period_max, sync_buffer)
print(f"\n{'Configuration':<25} {'Periods':<12} {'Sync':<8} {'48kHz':<12} {'44.1kHz':<12} {'Notes'}")
print(f"{'':25} {'(min/max)':<12} {'Buf':<8} {'Latency':<12} {'Latency':<12}")
print("-" * 100)
# Find DSD256 configs for latency calculation
dsd256_48k = None
dsd256_441k = None
for config in configs:
if config['sample_rate'] == 12288000:
dsd256_48k = calculator.calculate_frame_params(config['sample_rate'], True)
elif config['sample_rate'] == 11289600:
dsd256_441k = calculator.calculate_frame_params(config['sample_rate'], True)
for name, pmin, pmax, sync in buffer_configs:
lat_48k = dsd256_48k['cycle_time_ms'] * pmax if dsd256_48k else 0
lat_441k = dsd256_441k['cycle_time_ms'] * pmax if dsd256_441k else 0
is_current = (pmin == period_min and pmax == period_max and sync == sync_buffer)
marker = ">>> " if is_current else " "
notes = ""
if pmax >= 10:
notes = "Very stable"
elif pmax == 8:
notes = "Good balance"
elif pmax == 6:
notes = "Monitor closely"
else:
notes = "Risky!"
print(f"{marker}{name:<21} "
f"{pmin:>3}/{pmax:<7} "
f"{sync:>4} "
f"{lat_48k:>7.2f} ms "
f"{lat_441k:>7.2f} ms "
f"{notes}")
# Add your current settings if they're custom
if not any(pmin == period_min and pmax == period_max and sync == sync_buffer
for _, pmin, pmax, sync in buffer_configs):
lat_48k = dsd256_48k['cycle_time_ms'] * period_max if dsd256_48k else 0
lat_441k = dsd256_441k['cycle_time_ms'] * period_max if dsd256_441k else 0
print(f">>> Your Settings "
f"{period_min:>3}/{period_max:<7} "
f"{sync_buffer:>4} "
f"{lat_48k:>7.2f} ms "
f"{lat_441k:>7.2f} ms "
f"Custom")
def print_improvement_comparison():
"""Show improvement from conservative to optimized settings"""
print(f"\n{'='*100}")
print("LATENCY IMPROVEMENT: Conservative → Optimized")
print(f"{'='*100}")
print("\nConservative Settings (periodMin=5, periodMax=10, syncBufferCount=8):")
print(" 48kHz family: ~29.4 ms")
print(" 44.1kHz family: ~32.0 ms")
print("\nOptimized Settings (periodMin=4, periodMax=8, syncBufferCount=6):")
print(" 48kHz family: ~23.5 ms (↓ 5.9 ms, 20% faster)")
print(" 44.1kHz family: ~25.6 ms (↓ 6.4 ms, 20% faster)")
print("\nWhat Changed:")
print(" • periodMax: 10 → 8 (2 fewer periods)")
print(" • periodMin: 5 → 4 (tighter ratio)")
print(" • syncBufferCount: 8 → 6 (2 fewer buffers)")
print(" • CycleTime: 2935 μs (unchanged - proven stable)")
print("\nStability Analysis:")
print(" ✓ periodMin/Max ratio: 4:8 = 1:2 (good balance)")
print(" ✓ Total buffering: 8 periods (reasonable)")
print(" ✓ Sync buffer: 6 (adequate for clock drift)")
print(" ⚠ Monitor for underruns on congested networks")
def generate_config(cycle_time: int, period_min: int = 4, period_max: int = 8,
period_size_min: int = 2048, period_size_max: int = 8192,
sync_buffer: int = 6, latency_buffer: int = 0,
thred_mode: int = 257, interface: str = 'enp5s0',
cpu_send: int = 1, cpu_other: int = 2,
margin_us: int = 20) -> str:
"""Generate Diretta configuration file content"""
cycle_min = cycle_time - margin_us
config = f"""[global]
Interface={interface}
TargetProfileLimitTime=0
ThredMode={thred_mode}
InfoCycle=100000
FlexCycle=max
CycleTime={cycle_time}
CycleMinTime={cycle_min}
Debug=stdout
periodMax={period_max}
periodMin={period_min}
periodSizeMax={period_size_max}
periodSizeMin={period_size_min}
syncBufferCount={sync_buffer}
alsaUnderrun=enable
unInitMemDet=disable
CpuSend={cpu_send}
CpuOther={cpu_other}
LatencyBuffer={latency_buffer}
"""
return config
def print_usage_guide():
"""Print usage and monitoring guide"""
print(f"\n{'='*100}")
print("USAGE GUIDE")
print(f"{'='*100}")
print("""
1. SAVE CONFIGURATION
sudo nano ~/DirettaAlsaHost/setting.inf
(paste the configuration shown above)
2. RESTART DIRETTA
sudo systemctl restart diretta_sync_host.service
3. MONITOR OPERATION
journalctl -u diretta_sync_host -f
Look for these indicators:
✓ "start cycle=XXXXusec" - shows actual cycle time
✓ "info rcv" - timing statistics (should be stable)
✗ "Buffer underrun" - indicates buffers too small
✗ Timing jitter >100μs - network congestion
4. VERIFY EXPECTED BEHAVIOR
• CycleTime will auto-adjust per sample rate
• 48kHz: ~2938 μs (340 packets/sec)
• 44.1kHz: ~3198 μs (313 packets/sec)
• This is normal and expected!
5. TROUBLESHOOTING
Buffer underruns occur:
→ Increase periodMax: --period-max 10
→ Increase syncBuffer: --sync-buffer 8
Want lower latency:
→ Decrease periodMax: --period-max 6
→ Decrease syncBuffer: --sync-buffer 5
→ Monitor closely for underruns!
6. NETWORK OPTIMIZATION
• Ensure jumbo frames enabled: ip link set enp5s0 mtu 9024
• Disable offloading: ethtool -K enp5s0 gro off lro off
• Check no packet loss: ethtool -S enp5s0 | grep errors
• Isolate Diretta traffic on dedicated network
""")
def print_key_concepts():
"""Explain key concepts"""
print(f"\n{'='*100}")
print("KEY CONCEPTS EXPLAINED")
print(f"{'='*100}")
print("""
CYCLE TIME (Adaptive)
• You configure: CycleTime=2935 (target value)
• Diretta adjusts: Actual cycle varies by sample rate
• Purpose: Maintains constant packet size (9024 bytes)
• Why adaptive: Different sample rates need different timing
PERIOD BUFFERS
• periodMin/Max: Range of buffering depth
• Each period = one CycleTime
• periodMax determines total latency
• Example: 8 periods × 2.938 ms = 23.5 ms latency
SYNC BUFFER
• syncBufferCount: Additional buffer for clock sync
• Compensates for clock drift between sender/receiver
• Too small: Sync issues, clicks/pops
• Too large: Added latency
PACKET STRUCTURE
• Total frame: 9024 bytes (jumbo frame)
• Overhead: 20 bytes (ethernet + diretta headers)
• Audio payload: ~9004 bytes
• Samples per packet: Varies by sample rate
LATENCY CALCULATION
• Total latency = CycleTime × periodMax
• Does NOT include:
- DAC processing time
- Network propagation delay (usually <1ms)
- USB/SPDIF converter latency
• Actual end-to-end: Add ~2-5ms for complete chain
""")
def main():
parser = argparse.ArgumentParser(
description='Diretta DDS Configuration Calculator - Optimized Settings',
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
Examples:
%(prog)s # Default optimized config
%(prog)s --period-max 6 --sync-buffer 5 # Lower latency (experimental)
%(prog)s --period-max 10 --sync-buffer 8 # More conservative
%(prog)s --pcm # PCM instead of DSD
%(prog)s --mtu 1500 # Standard ethernet MTU
%(prog)s --config-only # Just show config file
"""
)
parser.add_argument('--mtu', type=int, default=9024,
help='MTU size (default: 9024 for jumbo frames)')
parser.add_argument('--pcm', action='store_true',
help='Calculate for PCM instead of DSD')
parser.add_argument('--period-min', type=int, default=4,
help='periodMin value (default: 4)')
parser.add_argument('--period-max', type=int, default=8,
help='periodMax value (default: 8)')
parser.add_argument('--sync-buffer', type=int, default=6,
help='syncBufferCount value (default: 6)')
parser.add_argument('--latency-buffer', type=int, default=0,
help='LatencyBuffer value (default: 0)')
parser.add_argument('--period-size-min', type=int, default=2048,
help='periodSizeMin value (default: 2048)')
parser.add_argument('--period-size-max', type=int, default=8192,
help='periodSizeMax value (default: 8192)')
parser.add_argument('--config-only', action='store_true',
help='Only generate config, skip analysis')
parser.add_argument('--thred-mode', type=int, default=257,
help='ThredMode value (default: 257)')
parser.add_argument('--interface', type=str, default='enp5s0',
help='Network interface (default: enp5s0)')
parser.add_argument('--cpu-send', type=int, default=1,
help='CPU core for send thread (default: 1)')
parser.add_argument('--cpu-other', type=int, default=2,
help='CPU core for other threads (default: 2)')
args = parser.parse_args()
calculator = DirettaCalculator(mtu=args.mtu)
is_dsd = not args.pcm
format_type = "DSD" if is_dsd else "PCM"
# Define sample rate configurations
if is_dsd:
configs = [
{'name': 'DSD256 × 48kHz', 'sample_rate': 48000 * 256, 'is_dsd': True},
{'name': 'DSD256 × 44.1kHz', 'sample_rate': 44100 * 256, 'is_dsd': True},
{'name': 'DSD128 × 48kHz', 'sample_rate': 48000 * 128, 'is_dsd': True},
{'name': 'DSD128 × 44.1kHz', 'sample_rate': 44100 * 128, 'is_dsd': True},
{'name': 'DSD64 × 48kHz', 'sample_rate': 48000 * 64, 'is_dsd': True},
{'name': 'DSD64 × 44.1kHz', 'sample_rate': 44100 * 64, 'is_dsd': True},
]
else:
configs = [
{'name': 'PCM 384kHz (8×48k)', 'sample_rate': 48000 * 8, 'is_dsd': False},
{'name': 'PCM 352.8kHz (8×44.1k)', 'sample_rate': 44100 * 8, 'is_dsd': False},
{'name': 'PCM 192kHz (4×48k)', 'sample_rate': 48000 * 4, 'is_dsd': False},
{'name': 'PCM 176.4kHz (4×44.1k)', 'sample_rate': 44100 * 4, 'is_dsd': False},
{'name': 'PCM 96kHz (2×48k)', 'sample_rate': 48000 * 2, 'is_dsd': False},
{'name': 'PCM 88.2kHz (2×44.1k)', 'sample_rate': 44100 * 2, 'is_dsd': False},
]
# Find target cycle time
base_rates = [44100, 48000]
target_cycle_us, analysis = calculator.find_target_cycle_time(base_rates, is_dsd)
# Print analysis unless config-only
if not args.config_only:
print_header()
print(f"Format Type: {format_type}")
print(f"MTU: {args.mtu} bytes")
print(f"Target CycleTime: {target_cycle_us} μs")
print(f"\nBuffer Configuration:")
print(f" periodMin: {args.period_min}")
print(f" periodMax: {args.period_max}")
print(f" syncBufferCount: {args.sync_buffer}")
print_analysis_table(calculator, configs)
print_latency_table(calculator, configs, args.period_min, args.period_max, args.sync_buffer)
if args.period_min == 4 and args.period_max == 8 and args.sync_buffer == 6:
print_improvement_comparison()
print_key_concepts()
# Generate and display configuration
print(f"\n{'='*100}")
print(f"CONFIGURATION FILE ({format_type} mode)")
print(f"{'='*100}")
# Calculate expected latencies
dsd256_48k = calculator.calculate_frame_params(12288000 if is_dsd else 384000, is_dsd)
dsd256_441k = calculator.calculate_frame_params(11289600 if is_dsd else 352800, is_dsd)
lat_48k = dsd256_48k['cycle_time_ms'] * args.period_max
lat_441k = dsd256_441k['cycle_time_ms'] * args.period_max
print(f"\nExpected Latency:")
print(f" 48kHz family: ~{lat_48k:.1f} ms")
print(f" 44.1kHz family: ~{lat_441k:.1f} ms")
config = generate_config(
cycle_time=target_cycle_us,
period_min=args.period_min,
period_max=args.period_max,
period_size_min=args.period_size_min,
period_size_max=args.period_size_max,
sync_buffer=args.sync_buffer,
latency_buffer=args.latency_buffer,
thred_mode=args.thred_mode,
interface=args.interface,
cpu_send=args.cpu_send,
cpu_other=args.cpu_other,
)
print(config)
if not args.config_only:
print_usage_guide()
print(f"\n{'='*100}")
print("NEXT STEPS")
print(f"{'='*100}")
print(f"""
1. Copy the configuration above to ~/DirettaAlsaHost/setting.inf
2. Restart Diretta: sudo systemctl restart diretta_sync_host.service
3. Monitor: journalctl -u diretta_sync_host -f
4. Verify ~4ms latency achieved
For different configurations:
• Lower latency: python3 {__file__} --period-max 6 --sync-buffer 5
• More conservative: python3 {__file__} --period-max 10 --sync-buffer 8
• Standard MTU: python3 {__file__} --mtu 1500
• PCM mode: python3 {__file__} --pcm
""")
if __name__ == "__main__":
main()
|