(Acest articol a fost publicat pentru prima dată pe R | Dr Tom Palmerși cu amabilitate a contribuit la R-bloggeri). (Puteți raporta problema legată de conținutul acestei pagini aici)
Doriți să vă distribuiți conținutul pe R-bloggeri? dați clic aici dacă aveți un blog, sau aici dacă nu aveți.
Introducere
În slujba mea anterioară, computerul meu de lucru era un desktop Windows – da, acelea au fost zilele dinaintea laptopurilor și a hotdesking-ului!
Doctorandul meu era interesat de metodele bayesiene și am creat un pachet R care includea câteva modele Stan. Am fost întotdeauna frustrat de cât de încet au fost compilate pe mașinile noastre Windows. Câțiva ani mai târziu, când am primit un MacBook Air, am fost șocat de cât de repede au compilat.
Pe mașina mea Windows, pachetul nostru mrbayes durează 3 minute și 55 de secunde pentru compilare și instalare. Pe MacBook Air meu M4 durează 1 minut și 16 secunde.
Următoarele sfaturi arată cum să îmbunătățiți aceste timpi.
Pentru a genera cronometrarile pe care le-am folosit
time R CMD INSTALL --preclean .
Câștig mare 1: Activați compilațiile paralele cu MAKEFLAGS variabila de mediu
Setați MAKEFLAGS variabilă de mediu în dvs ~/.Renviron fişier. Aceasta controlează câte make joburile rulează concomitent. Alegeți un număr nu mai mare decât numărul de nuclee de procesare pe care le are mașina dvs. Pentru a găsi această cursă
# Windows - in a Git Bash shell echo $NUMBER_OF_PROCESSORS # macOS sysctl -n hw.logicalcpu # Ubuntu Linux nproc
Un punct de plecare rezonabil este numărul dvs. de bază, sau câteva mai puține pentru a lăsa spațiu liber pentru orice altceva faceți în timpul unei compilații. De exemplu,
# In ~/.Renviron MAKEFLAGS=-j6
Închideți și reporniți R/RStudio după efectuarea acestei modificări.
Pe mașina mea Windows, acest lucru a redus construcția de la 3:55 la 1:15. Pentru a vă găsi propriul punct favorabil în mod empiric, vedeți exemplul de la sfârșitul Big win 2.
Câștig mare 2: activați memoria cache a compilatorului C/C++ folosind ccache
Instala
ccachemi se pare cel mai ușor să folosești un manager de pachete, de exemplu,
# macOS brew install ccache # Ubuntu/Debian Linux apt install ccache # Windows winget install ccache
Indiferent de metoda de instalare pe care o utilizați, asigurați-vă ccache este pe tine PATH după instalare. Puteți testa cu, să zicem,
ccache --version
Pentru a activa ccachepe macOS și Linux, aceasta intră ~/.R/Makevars; pe Windows este ~/.R/Makevars.win (creați directorul și fișierul dacă nu există), setați
# macOS CC = ccache clang CXX = ccache clang++ CXX17 = ccache clang++ # Windows and Linux # Most Linux users will be on gcc by default # Change to clang if you're using that CC = ccache gcc CXX = ccache g++ CXX17 = ccache g++
După o primă rulare de compilare pentru cache-ul care urmează să fie generat, compilațiile ulterioare sunt mult mai rapide.
- Windows, a doua compilație: 18 secunde
- M4 MacBook Air, a doua compilație: 5 secunde
Poate mai important, dacă, să zicem, pachetul tău are 5 modele și modifici codul doar pentru unul dintre ele, ccache știe să folosească memoria cache pentru cele 4 modele neschimbate.
- Windows, a doua compilație, doar 1 model editat: 1 minut și 10 secunde
- M4 MacBook Air, a doua compilație, doar 1 model editat: 19 secunde
Puteți verifica ccache funcţionează, observând scăderea timpului şi verificând ieşirea de
ccache -s
De asemenea, este util să zeroi statisticile ccache înainte de o rulare de sincronizare cu
ccache -z
Testarea care dintre modelele dvs. durează cel mai mult pentru compilare
Iată un script rapid pentru a testa ce model durează cel mai mult pentru compilare. Salvează-l așa cum se spune test.sh la nivelul superior al depozitului dvs. și adăugați ^test.sh$ la dvs .Rbuildignore fișier (pentru a evita un R CMD check NOTĂ despre fișierele necunoscute la nivelul superior).
for model in inst/stan/*.stan; do
cp "$model" "$model.bak"
# Insert at the top of the file
sed -i "1i // benchmark $(date +%s%N)" "$model"
ccache -z
SECONDS=0
R CMD INSTALL --preclean . >/dev/null 2>&1
echo "$(basename $model): ${SECONDS}s"
ccache -s | grep -E "Hits|Misses" | head -2
mv "$model.bak" "$model"
done
Găsindu-vă MAKEFLAGS punct dulce
Cu ccache instalat, acum puteți compara diferite -jN valorile curat (the ccache -C apelurile asigură că fiecare rulare este o compilare rece, astfel încât măsurați costul compilației brute mai degrabă decât accesările cache). Puteți crește secvența de numere până la numărul de nuclee de procesare pe care le are mașina dvs.
for j in 1 2 3 4 6 8 10; do
ccache -C >/dev/null
echo "=== -j$j ==="
SECONDS=0
MAKEFLAGS=-j$j R CMD INSTALL --preclean . >/dev/null 2>&1
echo "elapsed: ${SECONDS}s"
done
Timingurile de pe MacBook Air au fost
=== -j1 === elapsed: 76s === -j2 === elapsed: 48s === -j3 === elapsed: 35s === -j4 === elapsed: 36s === -j6 === elapsed: 27s === -j8 === elapsed: 27s === -j10 === elapsed: 28s
MacBook Air meu are 10 nuclee, dar doar 4 dintre acestea sunt nuclee de performanță, așa că m-am hotărât -j6 pentru că acolo s-au stabilit calendarele mele – și îmi lasă spațiu liber pentru mine inevitabil să-mi verific e-mailul în timpul unei compilații.
Marele câștig 3: combinarea acestora în fluxurile de lucru GitHub Actions
In mea .github/workflows/R-CMD-check.yaml Am pași pentru aceste accelerații. În primul rând, pentru a seta MAKEFLAGS.
- name: Set parallel compilation flags (Linux and macOS)
if: runner.os != 'Windows'
shell: bash
run: |
NCPUS=$(nproc 2>/dev/null || sysctl -n hw.logicalcpu)
echo "Detected ${NCPUS} processors"
echo "MAKEFLAGS=-j${NCPUS}" >> ~/.Renviron
- name: Set parallel compilation flags (Windows)
if: runner.os == 'Windows'
shell: pwsh
run: |
Write-Output "Detected $env:NUMBER_OF_PROCESSORS processors"
Add-Content -Path "$HOME.Renviron" -Value "MAKEFLAGS=-j$env:NUMBER_OF_PROCESSORS"
# ccache speeds up Stan model compilation dramatically on warm cache.
# Note: Windows support via ccache-action is documented as "probably works"
# rather than fully stable; if it causes issues, scope this step to non-Windows.
- name: Setup ccache
uses: hendrikmuhs/(email protected)
with:
# Key invalidates when Stan models or DESCRIPTION change.
# Older caches partially seed new ones via restore-keys.
key: ccache-${{ matrix.config.os }}-R-${{ matrix.config.r }}-${{ hashFiles('inst/stan/**/*.stan', 'DESCRIPTION') }}
restore-keys: |
ccache-${{ matrix.config.os }}-R-${{ matrix.config.r }}-
ccache-${{ matrix.config.os }}-R-
max-size: "2G"
- name: Configure R to use ccache (Linux and macOS)
if: runner.os != 'Windows'
shell: bash
run: |
mkdir -p ~/.R
if ( "$RUNNER_OS" = "macOS" ); then
cat >> ~/.R/Makevars <<'EOF'
CC = ccache clang
CXX = ccache clang++
CXX14 = ccache clang++
CXX17 = ccache clang++
CXX20 = ccache clang++
EOF
else
cat >> ~/.R/Makevars <<'EOF'
CC = ccache gcc
CXX = ccache g++
CXX14 = ccache g++
CXX17 = ccache g++
CXX20 = ccache g++
EOF
fi
echo "--- ~/.R/Makevars ---"
cat ~/.R/Makevars
- name: Configure R to use ccache (Windows)
if: runner.os == 'Windows'
shell: pwsh
run: |
New-Item -ItemType Directory -Force -Path "$HOME.R" | Out-Null
$makevars = @"
CC = ccache gcc
CXX = ccache g++
CXX14 = ccache g++
CXX17 = ccache g++
CXX20 = ccache g++
"@
Add-Content -Path "$HOME.RMakevars.win" -Value $makevars
Write-Output "--- ~/.R/Makevars.win ---"
Get-Content "$HOME.RMakevars.win"
Puteți vedea fișierul complet în depozitul meu.
Acest lucru mi-a redus cea mai recentă rulare a ubuntu pentru lansarea r de la 7 minute și 30 de secunde la 4 minute și 49 de secunde.
Câștig mare 4: Treci la clang
Am descoperit că trecând de la gcc la clang oferă o accelerare vizibilă; timpul de compilare single core a scăzut de la 3 minute și 55 de secunde la 3 minute plat pe computerul meu Windows.
Pentru a face acest lucru, trebuie să instalați clang. Pe Windows instalați clang în RTools45 — mai implicat decât pe Linux, dar fezabil.
# Windows within RTools45 Bash shell # Launch C:rtools45ucrt64.exe # You may need to close and reopen the shell after the first command pacman -Syu pacman -S mingw-w64-ucrt-x86_64-clang # Ubuntu/Debian Linux sudo apt install clang
În acest moment, pe Windows rulează
which clang
ar trebui să se întoarcă /ucrt/bin/clang.
Comutați la clang în ~/.R/Makevars (dacă nu utilizați ccache ștergeți prefixul respectiv)
# On Linux CC = ccache clang CXX = ccache clang++ CXX14 = ccache clang++ CXX17 = ccache clang++ CXX20 = ccache clang++
si in ~/.R/Makevars.win pe Windows
# On Windows CC = ccache C:/rtools45/ucrt64/bin/clang.exe CXX = ccache C:/rtools45/ucrt64/bin/clang++.exe CXX17 = ccache C:/rtools45/ucrt64/bin/clang++.exe
Utilizatorii Windows vor trebui să adauge următoarele la PATH
C:rtools45ucrt64bin C:rtools45usrbin
Puteți verifica că lucrurile funcționează rulând
R CMD config CXX17
Cred că ai nevoie clang versiunea 18 sau mai recentă pentru a vedea accelerațiile.
Câștig mic 1: utilizatorii WSL ar trebui să utilizeze sistemul de fișiere nativ
În cadrul WSL este posibil să accesați fișiere din sistemul său nativ de fișiere Linux, adică din interiorul /home/user/...precum și pe sistemul de fișiere Windows, de exemplu, în /mnt/c/.... Cred că operațiunile cu fișierele sunt considerabil mai rapide în interior /home/user/....
Ghiciri naive care nu au făcut nicio diferență
Mă întrebam dacă rulează o compilație non-debug cu spune
pkgbuild::compile_dll(debug = FALSE)
ar accelera lucrurile. Se pare că nu. Pentru modelele Stan, cea mai mare parte a timpului este cheltuit în instanțierea șablonului C++ de către compilator, nu în trecerile de optimizare – așa că dezactivarea semnalizatoarelor de depanare sau scăderea nivelului de optimizare abia dacă ajută.
De asemenea, m-am întrebat dacă folosirea R pe Windows Subsystem pentru Linux ar accelera lucrurile doar în virtutea faptului că sunt pe Linux. Nu a făcut-o, timpuri folosind gcc pe Windows și WSL Ubuntu erau în esență identice. Avantajul utilizării WSL este că este mai ușor să treceți la utilizare clang pe Linux.
(Bani fără obiect) Câștig mare 5: Treci la un Apple Silicon Mac
Mac-urile Apple silicon au performanțe excelente cu un singur thread, arhitectura lor unificată de memorie are o lățime de bandă foarte mare, au cache-uri L1 și L2 mari și SSD-uri NVMe rapide. Împreună, acestea produc timpi foarte rapidi de compilare a modelelor Stan, chiar și pe cele mai mici Mac-uri Apple Silicon.
Rezumat
Pe scurt, cinci câștiguri mari și un câștig mic pentru accelerarea compilației modelelor Stan în pachetele R.
