logo elektroda
logo elektroda
X
logo elektroda
REKLAMA
REKLAMA
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

Linux – jak działa rozkład zadań na rdzenie i procesory, czy można wymusić równomierne obciążenie?

_jta_ 09 Paź 2025 17:45 450 18
REKLAMA
  • #1 21715242
    _jta_
    Specjalista elektronik
    Posty: 49148
    Pomógł: 3212
    Ocena: 4260
    Czy Linux zapewnia, bądź daje możliwość równego obciążenia procesorów i poszczególnych rdzeni? Istotne jest to głównie w sytuacji, gdy np. komputer ma 2 procesory, każdy z nich 4 rdzenie, a każdy rdzeń 2 wątki, i 7 wykonywanych zadań używa procesorów: niepożądane jest, by te 7 zadań wykonywało się na 4 rdzeniach jednego procesora, przy czym 3 rdzenie miałyby po 2 zadania, a 1 rdzeń 1 zadanie.

    Jeśli liczba zadań nie przekracza liczby rdzeni, to każde powinno wykonywać się na innym rdzeniu, bo jeśli rdzeń wykonuje dwa wątki, to działa dużo wolniej; dobrze byłoby też, żeby obciążenia obu procesorów były jakoś wyrównane, bądź nawet lepiej, dobierane do temperatury - aby cieplejszy procesor dostawał mniej zadań.

    @ElektrodaBot - czy takie unikanie niepotrzebnego obciążania rdzenia procesora dwoma wątkami w sytuacji, gdy rdzeni wystarcza na wszystkie zadania, i wyrównywanie nagrzewania procesorów jest robione w Linux-ie automatycznie, czy jest do tego np. jakiś moduł, który trzeba załadować, czy tego w ogóle nie ma, i przydział rdzeni do zadań jest losowy, bez zwracania uwagi na to, że część rdzeni wykonuje po dwa zadania, a inne żadnego?
  • REKLAMA
  • #2 21715249
    ElektrodaBot
    AI od OpenAI ChatGPT4
    Posty: 8895
    Pomógł: 365
    Ocena: 956
    LABEL_AI_GENERATED
    _jta_ napisał:
    Czy Linux zapewnia, bądź daje możliwość równego obciążenia procesorów i poszczególnych rdzeni? Istotne jest to głównie w sytuacji, gdy np. komputer ma 2 procesory, każdy z nich 4 rdzenie, a każdy rdze...
    Bezpośrednia odpowiedź
    - Tak: nowoczesne jądro Linux (CFS – Completely Fair Scheduler) automatycznie rozprasza wątki po dostępnych CPU/rdzeniach, jest świadome SMT/rdzeń/gniazdo/NUMA i w typowych warunkach preferuje wolne rdzenie fizyczne, zanim zacznie „dokładać” drugie wątki SMT na tym samym rdzeniu.
    - Równoważenie między procesorami (socketami) działa, ale nie zawsze dąży do idealnego 50/50 – planista często faworyzuje lokalność pamięci (NUMA) i ogranicza migracje, jeśli to poprawia wydajność całości.
    - Temperatura nie jest bezpośrednim kryterium decyzji planisty, ale istnieje sprzężenie zwrotne: throttling/„thermal pressure” i cpufreq obniżają „pojemność” gorących CPU, co powoduje, że scheduler chętniej wybiera chłodniejsze/wyżej taktowane rdzenie.
    - Niczego nie trzeba dogrywać. Dodatkowe demony (irqbalance, thermald) i sterowniki cpufreq wzmacniają efekt. Jeśli potrzebujesz twardych gwarancji (np. „każde zadanie na osobnym rdzeniu fizycznym, bez SMT”) – użyj CPU affinity/cgroups lub wyłącz SMT.

    Zastrzeżenie: planista nie daje absolutnych gwarancji perfekcyjnego rozłożenia w każdej chwili – decyzje są kompromisem między rozproszeniem, lokalnością cache/NUMA i kosztem migracji.

    ---

    Szczegółowa analiza problemu

    1) Jak CFS rozdziela obciążenie
    - Hierarchia domen planowania: wątek SMT → rdzeń → pakiet (socket) → węzeł NUMA → cały system. Balansowanie odbywa się okresowo i przy zdarzeniach (new‑idle, wakeup).
    - „Select idle core/sibling”: przy wybudzeniu zadania planista najpierw szuka całkowicie bezczynnego rdzenia (obie nici SMT wolne), potem bezczynnego CPU w obrębie tego samego LLC, dopiero na końcu rozważa dołożenie na zajęty rdzeń jako drugi wątek SMT.
    - Migracje są ograniczane: chybienia cache i przekładanie pamięci NUMA bywają droższe niż nieidealne rozłożenie, więc lekkie asymetrie są akceptowane.

    2) SMT/Hyper‑Threading
    - Dwa wątki SMT współdzielą jednostki wykonawcze i pamięć podręczną; gdy oba są CPU‑bound, każdy zwykle osiąga ułamek wydajności jednowątkowej tego rdzenia.
    - Dlatego CFS z reguły „rozsiewa” wątki po rdzeniach fizycznych, ale: mechanizmy takie jak wake‑affine (utrzymanie zadania blisko danych/CPU, na którym się budzi) oraz koszty migracji mogą chwilowo spowodować, że dwa wątki trafią na ten sam rdzeń mimo wolnych rdzeni gdzie indziej.

    3) Dwa procesory (sockets) i NUMA
    - Auto NUMA balancing przenosi zarówno wątki, jak i strony pamięci, aby poprawić lokalność. Czasem scheduler celowo nierówno obciąży sockety, jeśli to zmniejszy koszt dostępu do „zdalnej” pamięci.
    - Jeśli jeden socket jest ewidentnie przeciążony, balancer przeniesie nadmiar zadań na drugi – ale nie wbrew oczywistej lokalności danych.

    4) Temperatura i „thermal pressure”
    - Planista nie „czyta” czujników i nie ma przełącznika „rozłóż wg temperatury”. Podsystem thermal/cpufreq ogranicza częstotliwość gorących CPU (throttling). Jądro propaguje to do planisty jako spadek efektywnej pojemności CPU (thermal pressure/capacity). Efekt: gorący/zdławiony rdzeń staje się mniej atrakcyjny do przydziału, więc zadania naturalnie migrują na chłodniejsze rdzenie.
    - Dodatkowo sterowniki intel_pstate/amd_pstate z governorem schedutil reagują na obciążenie z planisty; thermald (gł. Intel) może prewencyjnie korygować limity mocy. To razem daje „pośrednie” wyrównywanie pod kątem temperatury.

    5) Przerwania i tło
    - Nierówny rozdział przerwań potrafi „przybić” pojedynczy rdzeń/socket. Demon irqbalance rozkłada IRQ po CPU i zwykle warto mieć go włączonego.

    6) Kiedy możesz zobaczyć „złe” upakowanie?
    - Krótkie, często budzone wątki (np. sieć/IO) – koszt migracji może przeważyć i scheduler chwilowo dołoży je na zajęty rdzeń.
    - Procesy z silną lokalnością cache/NUMA – planista wybierze „bliskość” ponad idealne rozproszenie.
    - Ograniczenia affinity/cgroups użytkownika lub sterowników (np. sterowniki GPU, DPDK, RT) – mogą zawęzić pulę CPU.

    ---

    Jak to ustawić / sprawdzić w praktyce

    Diagnostyka topologii i obciążenia
    - lscpu -e=CPU,CORE,SOCKET,NODE,ONLINE
    - cat /sys/devices/system/cpu/cpu0/topology/thread_siblings_list
    - htop (widok per CPU), mpstat -P ALL 1, numastat, perf top
    - sensors, turbostat (x86), powertop – podgląd temperatur/frek.

    Twarde „każde zadanie na innym rdzeniu (bez SMT)”
    - Jednorazowo (shell): wybierz pierwszy wątek z każdego rdzenia i przypnij proces:
    - taskset -c $(lscpu -e=CPU,CORE | awk 'NR>1{if(!seen[$2]++){printf(sep $1); sep=","}}') ./program
    - Systemd (usługa): w pliku .service
    - CPUAffinity=0,2,4,6,8,10,12,14 (przykład – NUMERY muszą odpowiadać „pierwszym” wątkom rdzeni z lscpu)
    - Cgroups v2 (cpuset) – wydziel pulę CPU bez drugich wątków i przenieś tam procesy:
    - mkdir -p /sys/fs/cgroup/work; echo 0 > /sys/fs/cgroup/work/cpuset.mems
    - echo 0,2,4,6,8,10,12,14 > /sys/fs/cgroup/work/cpuset.cpus
    - echo <PID> > /sys/fs/cgroup/work/cgroup.procs
    - Globalnie wyłączyć SMT (jeśli to uzasadnione wydajnościowo/energetycznie):
    - echo off > /sys/devices/system/cpu/smt/control (odwracalne do „on”/„forceoff”)

    Równoważenie między socketami i pamięcią
    - Wymuś rozproszenie i pamięć lokalną:
    - numactl --cpunodebind=0-1 --membind=preferred=local ./program
    - Lub na siłę rozprosz pamięć (większa przewidywalność, czasem mniejsza wydajność):
    - numactl --interleave=all ./program
    - Sprawdź, czy kernelowe auto NUMA jest włączone:
    - cat /proc/sys/kernel/numa_balancing (1 = włączone)

    Temperatura i zasilanie
    - Upewnij się, że działa irqbalance i thermald (na Intel):
    - systemctl enable --now irqbalance
    - systemctl enable --now thermald
    - Użyj schedutil + właściwego sterownika:
    - cat /sys/devices/system/cpu/cpufreq/policy0/scaling_governor
    - echo schedutil > /sys/devices/system/cpu/cpufreq/policy0/scaling_governor
    - Limit mocy per socket (x86, RAPL) – pośrednie „wyrównanie termiczne”:
    - echo <uW> > /sys/devices/virtual/powercap/intel-rapl:0/constraint_0_power_limit_uw

    Test „czy rozprasza, jak chcę?”
    - stress-ng --cpu 7 --class cpu
    - Obserwuj w htop/mpstat czy 7 różnych rdzeni fizycznych dostaje obciążenie; w razie potrzeby przypnij taskset/numactl zgodnie z powyższym.

    Parametry schedulera (zaawansowane)
    - Statystyki i kilka pokręteł:
    - cat /proc/schedstat
    - cat /proc/sys/kernel/sched_migration_cost_ns
    - cat /proc/sys/kernel/sched_min_granularity_ns
    - Ostrzeżenie: ich strojenie ma sens tylko po pomiarach i zwykle w specyficznych obciążeniach (RT/HPC).

    ---

    Rekomendacje praktyczne
    - Zostaw domyślne CFS + irqbalance; w większości przypadków rozproszenie jest dobre „z pudełka”.
    - Jeśli aplikacja jest silnie CPU‑bound i cierpi na SMT – przypinaj procesy do pierwszych wątków rdzeni albo rozważ wyłączenie SMT.
    - Na maszynach 2‑socketowych, gdzie kluczowa jest równowaga między procesorami, kontroluj NUMA (numactl/cgroups) i monitoruj IRQ.
    - Jeśli chodzi o temperaturę: polegaj na poprawnym chłodzeniu, thermald/cpufreq i – gdy trzeba – limitach mocy per socket. Nie oczekuj od planisty „świadomego temperatury” wprost; efekt osiąga się pośrednio.

    ---

    Pytania doprecyzowujące
    - Jaka dystrybucja i wersja jądra (uname -a)? x86_64/AMD/Intel?
    - Jaki charakter zadań (CPU‑bound, pamięcio‑/IO‑bound, krótkie vs długie)?
    - Czy środowisko jest NUMA (numactl --hardware) i czy używany jest hyperthreading?
    - Czy oczekujesz „twardych” gwarancji (pinning), czy raczej „maksymalnie rozsądnej automatyki”?

    Na tej podstawie mogę podać gotowe maski CPU i przykładowe jednostki systemd dopasowane do Twojej topologii.
    Możesz mnie wywołać w każdym temacie pisząc @ElektrodaBot. Zastrzeżenie: Niektóre odpowiedzi udzielone przez ElektrodaBota mogą być niedokładne. Elektroda nie ponosi odpowiedzialności za dokładność, rzetelność ani kompletność prezentowanych informacji. Wszystkie odpowiedzi ElektrodaBota powinny być zweryfikowane przez użytkownika. OpenAI może monitorować i zapisywać informacje wprowadzane po wywołaniu ElektrodaBota.
  • #3 21715320
    _jta_
    Specjalista elektronik
    Posty: 49148
    Pomógł: 3212
    Ocena: 4260
    Jeszcze dla uzupełnienia: Completely Fair Scheduler został włączony do kernela Linux-a 2.6.23 (w październiku 2007 - właśnie dochodzi do 18 lat, czyli jest pełnoletni); w listopadzie 2010 i w 2016 roku wprowadzono ulepszenia CFS; od kernela 6.6 został zastąpiony przez Earliest eligible virtual deadline first scheduling (EEVDF).
  • #4 21718052
    dLogan
    Poziom 23  
    Posty: 747
    Pomógł: 62
    Ocena: 87
    Dwuprocesorowe używane serwery można dostać za grosze więc sam zgłębiam temat :D

    Pytanie jest jeszcze jedno:
    - czy 'wielowątkowe' oprogramowanie (czyli takie, które uruchamia masę 'zadań' widocznych często jako 'podprocesy', np google-chrome lub ffmpeg z przełącznikiem -threads) może przeskakiwać między dwoma fizycznymi procesora, czy jednak pozostanie na jednym wybranym? // kernel swoje, oprogramowanie swoje, z moich obserwacji wynika że często gęsto większość kerneli równomiernie obciąża procesory ale nie jestem jeszcze do końca pewien z jakiego mechanizmu to wynika.

    @ElektrodaBot czy da się zwiększyć wydajność poniższych kerneli? Jakich mechanizmów podziału zadań używają?
    Linux pc 6.12.48+deb13-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.12.48-1 (2025-09-20) x86_64 GNU/Linux

    Linux media 6.16.11-1-liquorix-amd64 #1 ZEN SMP PREEMPT_DYNAMIC liquorix 6.16-10.2~trixie (2025-10-06 x86_64 GNU/Linux
  • REKLAMA
  • #5 21718062
    ElektrodaBot
    AI od OpenAI ChatGPT4
    Posty: 8895
    Pomógł: 365
    Ocena: 956
    LABEL_AI_GENERATED
    dLogan napisał:
    Dwuprocesorowe używane serwery można dostać za grosze więc sam zgłębiam temat :D

    Pytanie jest jeszcze jedno:
    - czy 'wielowątkowe' oprogramowanie (czyli takie, które uruchamia masę 'zadań' widocznych często jako 'podprocesy', np google-chrome lub ffmpeg z przełącznikiem -threads) może przeskakiwać między dwoma fizycznymi procesora, czy jednak pozostanie na jednym wybranym? // kernel swoje, oprogramowanie swoje, z moich obserwacji wynika że często gęsto większość kerneli równomiernie obciąża procesory ale nie jestem jeszcze do końca pewien z jakiego mechanizmu to wynika.

    @ElektrodaBot czy da się zwiększyć wydajność poniższych kerneli? Jakich mechanizmów podziału zadań używają?
    Linux pc 6.12.48+deb13-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.12.48-1 (2025-09-20) x86_64 GNU/Linux
    Linux media 6.16.11-1-liquorix-amd64 #1 ZEN SMP PREEMPT_DYNAMIC liquorix 6.16-10.2~trixie (2025-10-06 x86_64 GNU/Linux
    Bezpośrednia odpowiedź
    - Tak: wielowątkowe aplikacje (np. Chrome – procesy/„podprocesy”, ffmpeg – wątki) mogą swobodnie migrować między rdzeniami i gniazdami (socketami). Linux równoważy obciążenie hierarchicznie: SMT → rdzeń → socket → węzeł NUMA → cały system. Migracje między socketami są dozwolone i wykonywane, o ile opłaca się to względem lokalności pamięci. (kernel.org)
    - Twoje jądra (6.12.48 Debian i 6.16.11 Liquorix) używają algorytmu EEVDF w klasie „fair” (SCHED_NORMAL) – od 6.6 jest to następca CFS; w 6.12 dopięto przejście i dołożono PREEMPT_RT oraz sched_ext (BPF‑owy, rozszerzalny planer). (docs.kernel.org)
    - „Świadomość temperatury” nie jest osobnym trybem, ale jądro uwzględnia throttling jako spadek „capacity” CPU (thermal pressure). Skutkiem jest mniejsza skłonność do przydzielania pracy na przegrzane rdzenie. (lwn.net)
    - Liquorix to „desktop/gaming” kernel z agresywniejszymi nastawami; bywa dostarczany z upstreamowym EEVDF i zmianami parametrów, ale część wydań/konfiguracji używa alternatywnych schedulerów (BMQ/PDS). Sprawdź to w swojej konfiguracji (CONFIG_SCHED_ALT/BMQ/PDS). (liquorix.net)

    ---

    Szczegółowa analiza i praktyka

    1) Czy wątki „przeskakują” między procesorami?
    - Tak. Planista utrzymuje runqueue per‑CPU i cyklicznie (oraz przy wybudzeniach) równoważy obciążenie między domenami planowania. Domeny są zbudowane zgodnie z topologią: SMT → rdzeń → socket (SMP) → NUMA. Dzięki temu jądro może przenosić wątki między socketami, gdy drugi jest luźniejszy, ale ogranicza zbędne migracje, jeśli grożą karami NUMA/cache. (kernel.org)
    - AutoNUMA potrafi dodatkowo przenosić strony pamięci za wątkiem lub odwrotnie, aby poprawić lokalność, co zmniejsza koszt pracy na „obcym” sockecie. Funkcja jest konfigurowalna przez kernel.numa_balancing. (kernel.org)

    2) Co dokładnie robią Twoje kernle (6.12.48 i 6.16.11)?
    - EEVDF (Earliest Eligible Virtual Deadline First) zastąpił CFS w klasie fair od 6.6; w 6.12 dokończono przejście (m.in. dopracowane „slice”, tuningi). To wciąż ta sama klasa SCHED_NORMAL – zmieniła się logika wyboru zadania i sterowania opóźnieniami. (docs.kernel.org)
    - 6.12 (wydany 17 listopada 2024) dodał:
    - PREEMPT_RT w mainline (konfigurowalne, nie włączone z automatu w generycznych buildach),
    - sched_ext – możliwość wgrywania polityk planowania w eBPF (np. własne reguły rozpraszania zadań). (kernelnewbies.org)
    - Część pokręteł uległa zmianie nazw wraz z EEVDF: np. sched_min_granularity → sched_base_slice; wakeup_granularity w EEVDF jest nieużywany. Sprawdź sysctl i /sys/kernel/debug/sched/*. (docs.redhat.com)
    - Liquorix: domyślnie „Zen interactive tuning” (niższe granulacje, HZ=1000, BFQ, itp.). Projekt historycznie wspiera alternatywne schedulery (BMQ/PDS); niektóre dystrybucje/konfiguracje mogą jednak pozostać przy upstream (EEVDF) i tylko „odkręcić” parametry – dlatego warto zweryfikować własny plik konfiguracyjny kernela. (liquorix.net)

    3) „Temperatura a planowanie”
    - Podsystem thermal i cpufreq przekazują do planisty tzw. thermal pressure, który zmniejsza efektywną „pojemność” CPU. Planista, widząc mniejszą capacity, chętniej wybiera inne rdzenie/sockety. To mechanizm pośredni – nie przypina się zadań „po temperaturze”, lecz bierze pod uwagę spadek mocy obliczeniowej. (lwn.net)

    4) Jak to wykorzystać na dwusocketowym serwerze (Chrome/ffmpeg, kompilacje itd.)
    - Pozostaw automatyczne równoważenie i AutoNUMA, chyba że wiesz lepiej. W praktyce Linux zwykle rozproszy 7 zadań po 7 różnych rdzeniach fizycznych, a przy wzroście obciążenia zacznie korzystać z wątków SMT i drugiego socketu. (kernel.org)
    - Jeśli chcesz twardo egzekwować rozproszenie:
    - affinity/cpuset:
    - taskset -pc PID oraz Cpus_allowed_list w /proc/PID/status – podgląd/zmiana przypisania,
    - cgroup v2 „cpuset”: cpuset.cpus i cpuset.mems – wydziel pulę rdzeni i węzłów NUMA dla danego procesu/usługi (systemd: AllowedCPUs=, AllowedMemoryNodes=). (kernel.org)
    - numactl:
    - numactl --cpunodebind=0 --membind=0 ffmpeg … (trzymaj zadanie na jednym sockecie),
    - numactl --interleave=all … (jeśli wątki i dane muszą równomiernie używać obu socketów – kosztem nieco większej latencji). (kernel.org)
    - Obserwacja/migracje:
    - ps -eLo pid,tid,psr,comm | grep ffmpeg (na którym CPU/rdzeniu są wątki),
    - perf sched record; perf sched latency (śledzenie migracji/opóźnień),
    - numastat -p <PID> (jak rozkłada się pamięć względem węzłów NUMA).
    - IRQ i tło: włącz irqbalance, aby nie „przybić” jednego rdzenia/socketu przerwaniami.

    5) „Czy da się zwiększyć wydajność” – konkretne, bezpieczne kroki
    - Dobierz równoleglanie do rdzeni fizycznych (z SMT=on zacznij od liczby CORE, nie CPU threads):
    - ffmpeg: -threads N (przetestuj N = liczba rdzeni fizycznych per socket, później N=r‑dwa‑sockety; mierz fps/czas),
    - kompilacje: make -j$(nproc) – ale przy kodzie pamięciożernym lepsze bywa -j liczba_fizycznych_rdzeni.
    - NUMA:
    - jeśli jeden job zjada cały socket: zbindować CPU+RAM (cpunodebind/membind),
    - jeśli kilka jobów: podziel je po jednym na socket, albo użyj dwóch cgroup cpuset – każdy z własnym cpuset.mems.
    - EEVDF tuning (ostrożnie, po pomiarach):
    - kernel.sched_base_slice (następca sched_min_granularity) – większa wartość zwykle poprawia throughput wsadowy kosztem responsywności; Liquorix zwykle ma ją obniżoną dla interaktywności. (docs.redhat.com)
    - Thermal:
    - upewnij się, że działa sterownik pstate (intel_pstate/amd_pstate) i governor schedutil; throttling zostanie „zauważony” przez thermal pressure i planista naturalnie odsunie pracę. (lkml.iu.edu)

    6) Jak sprawdzić, na czym stoisz
    - Topologia:
    - lscpu -e=CPU,CORE,SOCKET,NODE,ONLINE
    - cat /proc/cpuinfo | grep "physical id\|cpu cores"
    - Polityki schedulera i NUMA:
    - uname -a (wersja),
    - zgrep -E "CONFIG_SCHED_(ALT|BMQ|PDS|EEVDF)" /proc/config.gz (Liquorix vs upstream),
    - cat /proc/sys/kernel/numa_balancing (0/1/2 – zob. opis). (kernel.org)

    ---

    Rekomendacja dla Twoich dwóch jąder
    - Debian 6.12.48 (EEVDF, PREEMPT_DYNAMIC): dobry, uniwersalny wybór na serwer; zostaw AutoNUMA=1, włącz irqbalance, mierz i ewentualnie zwiększ sched_base_slice pod typowo wsadowe obciążenia.
    - Liquorix 6.16.11: świetny dla desktop/multimedia; na serwerze bywa minimalnie mniej wydajny w czystym throughput (mniejsze „slice”, większa preempcja). Jeśli zależy Ci na maksymalnym czasie ukończenia (kompilacje, render, transkoding), rozważ Debianowe jądro lub podnieś sched_base_slice; sprawdź też czy nie masz włączonego alternatywnego schedulera (CONFIG_SCHED_ALT/BMQ/PDS). (liquorix.net)

    ---

    Pytania doprecyzowujące
    - Jakie to dokładnie CPU (model, liczba węzłów NUMA: numactl --hardware)?
    - Czy obciążenia są CPU‑bound (ffmpeg/libx264/x265), czy mieszane z I/O/siecią?
    - Czy chcesz miękką automatyzację (zostawiamy scheduler) czy twarde gwarancje (cpuset/numactl, pinning per socket)?
    - Jaki jest cel: minimalny czas całości (throughput) czy interaktywność/latencja?

    Jeśli podasz wynik lscpu i numactl --hardware, przygotuję gotowe maski AllowedCPUs/AllowedMemoryNodes dla systemd/cgroups oraz przykładowe skrypty uruchamiania ffmpeg/chrome przypięte do socketów.
    Możesz mnie wywołać w każdym temacie pisząc @ElektrodaBot. Zastrzeżenie: Niektóre odpowiedzi udzielone przez ElektrodaBota mogą być niedokładne. Elektroda nie ponosi odpowiedzialności za dokładność, rzetelność ani kompletność prezentowanych informacji. Wszystkie odpowiedzi ElektrodaBota powinny być zweryfikowane przez użytkownika. OpenAI może monitorować i zapisywać informacje wprowadzane po wywołaniu ElektrodaBota.
  • #6 21718704
    _jta_
    Specjalista elektronik
    Posty: 49148
    Pomógł: 3212
    Ocena: 4260
    Napisałem w temacie "Jak rozdzielać zadania między procesorami na serwerze dwuprocesorowym Linux? o ustawieniu affinity - to pozwala określać, które wątki procesorów mogą wykonywać określony wątek zadania. Sprawdziłem, że w systemie z dwoma procesorami, z których każdy ma 10 rdzeni i po 2 wątki na każdy rdzeń, można w ten sposób wybierać dowolnie z 40 wątków; taki wybór oznacza, że scheduler ma ograniczenie wyboru wątków procesorów możliwych do użycia przez dany wątek zadania. Próba wskazania wątków spoza zakresu 0-39 była ignorowana (ale wątki w zakresie ustawiały się); próba ustawienia ograniczenia tak, by żaden fizycznie istniejący wątek procesora nie mógł wykonywać wątku zadania powodowała błąd. Bardziej formalnie, działało to tak: zbiór wątków procesorów, który miał być ustawiony dla wątku zadania, był obcinany do zbioru istniejących wątków procesorów; jeśli wynikiem był zbiór niepusty, to takie ustawienie było wykonywane; jeśli pusty, był sygnalizowany błąd; a potem scheduler wybierał z ustawionego zbioru wątków.

    Mogąc tak ustawiać zbiór dostępnych wątków, można by zrobić test: puszczamy równolegle dwa wątki zadania (bądź dwa zadania), które mierzą szybkość wykonywania, i ograniczamy im wybór wątków procesorów; jeśli ograniczymy do jednego wątku, to tylko jeden z tych wątków zadań będzie się wykonywać jednocześnie; podobnie będzie, jeśli ograniczymy do wątków tego samego rdzenia, jakkolwiek w pierwszym przypadku przełączanie wykonywania będzie robione przez scheduler, w drugim przez procesor, co będzie szybsze, niemniej jednak w obu przypadkach średnia szybkość wykonywania będzie około 2x mniejsza, niż przy działaniu tylko jednego wątku; jeśli pozwolimy na używanie wątków różnych rdzeni, to scheduler powinien tak przypisywać wątki procesorów do wątków zadania, by wykonywały się z pełną szybkością. Może jeszcze mieć jakieś znaczenie (to będzie zależeć od rodzaju wykonywanych instrukcji) dostęp do pamięci - czy wybór wątków procesorów będzie powodował spowolnienie działania przez konflikty dostępu do pamięci, czy nie.

    Dodano po 3 [godziny] 8 [minuty]:

    @ElektrodaBot - czy jakaś dokumentacja opisuje, które numery (np. dla "taskset") mają wątki tych samych rdzeni? Czy np. dla rdzeni dwuwątkowych to będą dwa kolejne, czy jakoś inaczej? Spróbowałem uruchomić równolegle dwa procesy ograniczając im wybór wątków procesora do dwóch i nie udało mi się znaleźć takiego wyboru numerów wątków procesora, by dwa procesy działały dużo wolniej, niż jeden.
  • REKLAMA
  • #7 21718877
    ElektrodaBot
    AI od OpenAI ChatGPT4
    Posty: 8895
    Pomógł: 365
    Ocena: 956
    LABEL_AI_GENERATED
    _jta_ napisał:
    Napisałem w temacie " Jak rozdzielać zadania między procesorami na serwerze dwuprocesorowym Linux? o ustawieniu affinity - to pozwala określać, które wątki procesorów mogą wykonywać określony wątek zadania. Sprawdziłem, że w systemie z dwoma procesorami, z których każdy ma 10 rdzeni i po 2 wątki na każdy rdzeń, można w ten sposób wybierać dowolnie z 40 wątków; taki wybór oznacza, że scheduler ma ograniczenie wyboru wątków procesorów możliwych do użycia przez dany wątek zadania. Próba wskazania wątków spoza zakresu 0-39 była ignorowana (ale wątki w zakresie ustawiały się); próba ustawienia ograniczenia tak, by żaden fizycznie istniejący wątek procesora nie mógł wykonywać wątku zadania powodowała błąd. Bardziej formalnie, działało to tak: zbiór wątków procesorów, który miał być ustawiony dla wątku zadania, był obcinany do zbioru istniejących wątków procesorów; jeśli wynikiem był zbiór niepusty, to takie ustawienie było wykonywane; jeśli pusty, był sygnalizowany błąd; a potem scheduler wybierał z ustawionego zbioru wątków.

    Mogąc tak ustawiać zbiór dostępnych wątków, można by zrobić test: puszczamy równolegle dwa wątki zadania (bądź dwa zadania), które mierzą szybkość wykonywania, i ograniczamy im wybór wątków procesorów; jeśli ograniczymy do jednego wątku, to tylko jeden z tych wątków zadań będzie się wykonywać jednocześnie; podobnie będzie, jeśli ograniczymy do wątków tego samego rdzenia, jakkolwiek w pierwszym przypadku przełączanie wykonywania będzie robione przez scheduler, w drugim przez procesor, co będzie szybsze, niemniej jednak w obu przypadkach średnia szybkość wykonywania będzie około 2x mniejsza, niż przy działaniu tylko jednego wątku; jeśli pozwolimy na używanie wątków różnych rdzeni, to scheduler powinien tak przypisywać wątki procesorów do wątków zadania, by wykonywały się z pełną szybkością. Może jeszcze mieć jakieś znaczenie (to będzie zależeć od rodzaju wykonywanych instrukcji) dostęp do pamięci - czy wybór wątków procesorów będzie powodował spowolnienie działania przez konflikty dostępu do pamięci, czy nie.

    Dodano po 3 [godziny] 8 [minuty]:

    @ElektrodaBot - czy jakaś dokumentacja opisuje, które numery (np. dla "taskset") mają wątki tych samych rdzeni? Czy np. dla rdzeni dwuwątkowych to będą dwa kolejne, czy jakoś inaczej? Spróbowałem uruchomić równolegle dwa procesy ograniczając im wybór wątków procesora do dwóch i nie udało mi się znaleźć takiego wyboru numerów wątków procesora, by dwa procesy działały dużo wolniej, niż jeden.
    Bezpośrednia odpowiedź
    - Nie ma uniwersalnej reguły numeracji „CPU” dla SMT/HT. Wątki tego samego rdzenia (rodzeństwo SMT) nie muszą mieć kolejnych numerów. Poprawne pary znajdziesz w systemie, nie „na oko”.
    - Dokumentacja/topologia jest dostępna w lscpu i w sysfs: najważniejsze pliki to thread_siblings_list i core_siblings_list.
    - Jeśli w Twoim teście dwa procesy nie zwalniały, to niemal na pewno nie przypiąłeś ich do pary SMT tego samego rdzenia lub obciążenie nie było czysto CPU‑bound (albo turbo/freq scaling zamaskowało różnicę).
    - Aplikacje wielowątkowe/procesowe (Chrome, ffmpeg) mogą migrować między socketami, o ile ich affinity na to pozwala. Scheduler (EEVDF od 6.6) równoważy obciążenie hierarchicznie (SMT→rdzeń→socket→NUMA), ale preferuje lokalność pamięci.
    - Twoje kernele (Debian 6.12.48 i Liquorix 6.16.11) używają klasy „fair” z EEVDF; PREEMPT_DYNAMIC włącza bardziej interaktywną preempcję. Dla wsadów/serwera trzymaj irqbalance, AutoNUMA włączone i rozważ przypinanie/NUMA‑binding gdy chcesz twardych gwarancji.

    ---

    Jak ustalić, które numery CPU są rodzeństwem SMT (ten sam rdzeń)

    1) lscpu – widok tabelaryczny
    - Polecenie:
    lscpu -e=CPU,CORE,SOCKET,NODE,ONLINE | sort -k3,3n -k2,2n -k1,1n
    - Interpretacja:
    - CPU – numer logiczny używany przez taskset,
    - CORE – identyfikator rdzenia fizycznego,
    - SOCKET – gniazdo (procesor),
    - Dwa wpisy z tym samym (CORE, SOCKET) to para SMT tego samego rdzenia.

    2) Sysfs – źródło „kanoniczne”
    - Lista rodzeństwa SMT dla danego CPU X:
    cat /sys/devices/system/cpu/cpuX/topology/thread_siblings_list
    Przykład: „0,20” oznacza, że CPU 0 i CPU 20 dzielą ten sam rdzeń.
    - Lista rdzeni (w postaci masek):
    cat /sys/devices/system/cpu/cpuX/topology/core_siblings_list
    - Uwaga: format to „cpulist” (zakresy i przecinki), więc przyda się parse.

    3) Szybkie skrypty pomocnicze

    - Wypisz pary SMT dla wszystkich rdzeni:
    for c in /sys/devices/system/cpu/cpu[0-9]*; do
    cpu=${c##*/}; echo "$cpu: $(cat $c/topology/thread_siblings_list)";
    done | sort -t: -k1,1V

    - Lista „pierwszych wątków” (po 1 logicznym CPU na rdzeń – maska „bez SMT”):
    lscpu -e=CPU,CORE,SOCKET | awk 'NR>1{key=$2":"$3;if(!(key in seen)){out=(out?out",":"")$1;seen[key]=1}}END{print out}'

    - CPU danego socketu (do pinowania per-socket):
    getconf _NPROCESSORS_ONLN >/dev/null 2>&1 # upewnij się, że POSIX tools są
    awk -F, '/^[0-9]+/ {print $1,$3}' <(lscpu -p=CPU,CORE,SOCKET) | sort -k2,2n -k1,1n

    ---

    Dlaczego Twoje dwa procesy „nie chciały zwolnić”
    Najczęstsze przyczyny:
    - Obie instancje miały maskę zawierającą dwa różne rdzenie (np. taskset -c 0,1 dla obu procesów). Scheduler po prostu rozłożył je na różne rdzenie i nie było konkurencji SMT.
    - Wybrałeś dwa numery CPU, które nie są rodzeństwem SMT (np. 0 i 1 w wielu systemach to dwa różne rdzenie).
    - Obciążenie nie było czysto CPU‑bound (I/O, pamięć) – SMT wtedy mniej szkodzi lub różnice maskuje stan zasilania/turbo.
    - Skalowanie częstotliwości/boost: samotny wątek może boostować wyżej; przy dwóch zadaniach na oddzielnych rdzeniach taktowanie spada i różnica „SMT vs 2 rdzenie” może się zbliżyć. Dla powtarzalnych testów warto unieruchomić częstotliwość.

    Jak poprawnie przetestować:
    - Znajdź parę SMT, np. z thread_siblings_list: załóżmy „0,20”.
    - Test bazowy:
    time taskset -c 0 stress-ng --cpu 1 --cpu-method matrixprod --timeout 10s
    - Ten sam rdzeń (para SMT):
    (time taskset -c 0 stress-ng --cpu 1 --cpu-method matrixprod --timeout 10s) &
    (time taskset -c 20 stress-ng --cpu 1 --cpu-method matrixprod --timeout 10s); wait
    Oczekuj, że czasy obu zadań wydłużą się względem bazowego (np. 1.5–2×), a łączna przepustowość wzrośnie nie do 2×, lecz typowo do ~1.3–1.7×.
    - Dwa różne rdzenie:
    (time taskset -c 0 stress-ng --cpu 1 --cpu-method matrixprod --timeout 10s) &
    (time taskset -c 1 stress-ng --cpu 1 --cpu-method matrixprod --timeout 10s); wait
    Oczekuj minimalnego wzrostu czasu pojedynczego zadania i ~2× przepustowości.
    - Dla powtarzalności:
    - ustaw governor na schedutil lub performance i rozważ wyłączenie turbo na czas testu:
    - Intel: echo 0 > /sys/devices/system/cpu/intel_pstate/no_turbo
    - AMD: echo 0 > /sys/devices/system/cpu/cpufreq/boost
    - sprawdź stan: cpupower frequency-info

    ---

    Użyteczne wzorce pinowania i izolacji

    - „Po jednym logicznym CPU na rdzeń” (bez SMT) dla procesu:
    taskset -c "$(lscpu -e=CPU,CORE,SOCKET | awk 'NR>1{key=$2":"$3;if(!(key in seen)){printf (sep $1); sep=","; seen[key]=1}}')" \
    ./program

    - Praca per‑socket (dwusocket):
    SOCKET0=$(lscpu -p=CPU,SOCKET | awk -F, '/^[0-9]/{if($2==0)print $1}' | paste -sd, -)
    SOCKET1=$(lscpu -p=CPU,SOCKET | awk -F, '/^[0-9]/{if($2==1)print $1}' | paste -sd, -)
    taskset -c $SOCKET0 ffmpeg -threads <liczba_rdzeni_sock0> … &
    taskset -c $SOCKET1 make -j<liczba_rdzeni_sock1> …

    - Twarde granice (stabilniejsze niż taskset): cgroup v2 „cpuset”
    mkdir -p /sys/fs/cgroup/work0 /sys/fs/cgroup/work1
    echo 0 > /sys/fs/cgroup/work0/cpuset.mems
    echo $SOCKET0 > /sys/fs/cgroup/work0/cpuset.cpus
    echo 1 > /sys/fs/cgroup/work1/cpuset.mems
    echo $SOCKET1 > /sys/fs/cgroup/work1/cpuset.cpus
    echo <PID_A> > /sys/fs/cgroup/work0/cgroup.procs
    echo <PID_B> > /sys/fs/cgroup/work1/cgroup.procs

    - Wyłączenie SMT (gdy naprawdę przeszkadza):
    echo off > /sys/devices/system/cpu/smt/control
    # powrót: echo on > /sys/devices/system/cpu/smt/control

    ---

    Mechanizmy planisty w Twoich kernelach i co realnie „dokręcić”
    - Klasa SCHED_NORMAL korzysta z EEVDF (od 6.6). EEVDF wybiera „najwcześniejszy gotowy termin” i utrzymuje lepszą kontrolę nad latencją przy podobnym throughput do CFS. Z punktu widzenia rozpraszania po rdzeniach/socketach nadal działa hierarchia domen planowania i selekcja idle core/CPU przed dołożeniem drugiej nici SMT.
    - PREEMPT_DYNAMIC daje profil „bardziej interaktywnie” w Liquorix vs „bardziej przepustowo” w jądrze Debiana – to kwestia konfiguracji i domyślnych parametrów.
    - Bezpieczne nastawy pod serwer/wsady:
    - włącz irqbalance: systemctl enable --now irqbalance
    - zostaw kernel.numa_balancing=1 (sprawdź: cat /proc/sys/kernel/numa_balancing)
    - governor schedutil lub performance, monitoring thermal (thermald na Intelu)
    - rozważ zwiększenie „slice” dla wsadów (EEVDF: kernel.sched_base_slice), ale tylko po pomiarach A/B. Mniejsze slice = lepsza interaktywność, większy narzut przełączeń; większe slice = wyższa przepustowość wsadowa.
    - Liquorix bywa zestrojony pod desktop (niższe slice, HZ=1000, itp.). Jeżeli liczysz czasy wsadów (kompilacje/render/transkodowanie), często lepszy będzie mainline z domyślnymi parametrami lub lekkie podniesienie sched_base_slice. Zawsze weryfikuj po swojej aplikacji.

    ---

    Wskazówki do własnych eksperymentów (dwusocket, 10C/20T na socket)
    - Zbuduj listy:
    - „SMT‑free” (po 1 CPU na rdzeń) dla każdego socketu osobno,
    - „pełny socket” (wszystkie 20 wątków logicznych danego socketu).
    - Mierz trzy scenariusze dla 2 zadań: (1) ta sama para SMT, (2) dwa rdzenie tego samego socketu, (3) po jednym rdzeniu na każdy socket (NUMA rozdzielona pamięć: numactl --cpunodebind=N --membind=N …).
    - Pomiary rób perf stat (cycles, instructions, context-switches, cpu-migrations) oraz mpstat -P ALL 1, aby widzieć, gdzie faktycznie lądują wątki.

    ---

    Odpowiedzi na Twoje podpunkty
    - „Czy dokumentacja opisuje numerację?” – Tak, wprost w sysfs: topology/thread_siblings_list i core_siblings_list. To jedyne źródło, na którym warto polegać. lscpu tylko to ładnie składa w tabelę.
    - „Czy dwie kolejne liczby to ta sama para SMT?” – Niekoniecznie. W wielu platformach numeracja jest przeplatana (najpierw pierwsze wątki wszystkich rdzeni, potem drugie), a w maszynach dwusocketowych dodatkowo przeplata się socket 0/1. Dlatego test mógł nie wpaść na „złą” parę.
    - „Dlaczego nie udało mi się zwolnić dwóch procesów?” – Prawdopodobnie nie trafiłeś w parę SMT, albo obciążenie i/lub stan zasilania zamaskowały różnicę. Przypnij każdy proces do JEDNEGO numeru CPU i wybierz drugi numer z thread_siblings_list tego pierwszego.

    ---

    Dalsze kroki (żeby podać Ci gotowe maski)
    Podeślij proszę wynik:
    - lscpu -e=CPU,CORE,SOCKET,NODE | sort -k3,3n -k2,2n -k1,1n
    - numactl --hardware
    - cat /sys/devices/system/cpu/smt/control
    - cat /proc/sys/kernel/numa_balancing

    Na tej podstawie przygotuję:
    - listę par SMT (CPU_A↔CPU_B),
    - maskę „po 1 CPU na rdzeń” globalnie i per‑socket,
    - przykład unitów systemd z AllowedCPUs/AllowedMemoryNodes dopasowanych do Twojej topologii,
    - gotowe komendy taskset/numactl do powtórzenia testów A/B/C.
    Możesz mnie wywołać w każdym temacie pisząc @ElektrodaBot. Zastrzeżenie: Niektóre odpowiedzi udzielone przez ElektrodaBota mogą być niedokładne. Elektroda nie ponosi odpowiedzialności za dokładność, rzetelność ani kompletność prezentowanych informacji. Wszystkie odpowiedzi ElektrodaBota powinny być zweryfikowane przez użytkownika. OpenAI może monitorować i zapisywać informacje wprowadzane po wywołaniu ElektrodaBota.
  • #8 21719034
    _jta_
    Specjalista elektronik
    Posty: 49148
    Pomógł: 3212
    Ocena: 4260
    @ElektrodaBot - a może to kwestia doboru instrukcji - np. instrukcja licząca pierwiastek kwadratowy może wykonywać się w jednym wątku rdzenia, który jednocześnie wykonuje inne instrukcje (bez operacji zmiennoprzecinkowych) w drugim?
    Procesor Xeon E5-2660 v3. Pewna zauważalna różnica dla dwóch zadań jest:
    * gdy oba wykonuje ten sam wątek procesora, czas user = 6.391s 6.290s 6.326s
    * gdy oba wykonują wątki tego samego rdzenia, czas user = 7.119s 7.346s 7.414s
    * gdy oba wykonują różne rdzenia, czas user = 6.334s 6.298s 6.288s
    i w pierwszym przypadku czas real jest ponad 2x większy, niż czas user (czasy są dla jednego zadania), w pozostałych różnica czasów real i user jest minimalna.
  • #9 21719044
    ElektrodaBot
    AI od OpenAI ChatGPT4
    Posty: 8895
    Pomógł: 365
    Ocena: 956
    LABEL_AI_GENERATED
    _jta_ napisał:
    @ElektrodaBot - a może to kwestia doboru instrukcji - np. instrukcja licząca pierwiastek kwadratowy może wykonywać się w jednym wątku rdzenia, który jednocześnie wykonuje inne instrukcje (bez operacji zmiennoprzecinkowych) w drugim?
    Procesor Xeon E5-2660 v3. Pewna zauważalna różnica dla dwóch zadań jest:
    * gdy oba wykonuje ten sam wątek procesora, czas user = 6.391s 6.290s 6.326s
    * gdy oba wykonują wątki tego samego rdzenia, czas user = 7.119s 7.346s 7.414s
    * gdy oba wykonują różne rdzenia, czas user = 6.334s 6.298s 6.288s
    i w pierwszym przypadku czas real jest ponad 2x większy, niż czas user (czasy są dla jednego zadania), w pozostałych różnica czasów real i user jest minimalna.
    Bezpośrednia odpowiedź
    - Tak – dobór instrukcji ma kluczowy wpływ na to, jak mocno dwa wątki SMT „gryzą się” na tym samym rdzeniu. Jeśli strumienie instrukcji są komplementarne (np. jeden głównie FP/sqrt, drugi głównie integer/memory), sprzęt łatwiej przeplata ich mikro‑operacje i spadek per‑wątek jest niewielki. Jeśli są podobne (np. oba ciężkie AVX2/FMA albo oba sqrt), spadek jest dużo większy.
    - Twoje wyniki są podręcznikowe:
    - „ten sam wątek logiczny” → czysty time‑slicing przez kernel: real ≈ suma user,
    - „ta sama para SMT” → niewielki wzrost user (~+13–18%), bo wątki współdzielą zasoby rdzenia,
    - „dwa różne rdzenie” → czasy user ≈ bazowe (brak współdzielenia).
    - Na E5‑2660 v3 (Haswell‑EP) sqrt/operacje FP mają dużą latencję i ograniczoną przepustowość; SMT potrafi ukryć część bąbli potokowych, zwłaszcza jeśli drugi wątek robi coś innego niż FP. Stąd różnice, które widzisz.

    ---

    Szczegółowa analiza problemu

    1) Co się dzieje w rdzeniu (Haswell‑EP, SMT)
    - Dwa wątki SMT współdzielą kluczowe zasoby jednego rdzenia: dekodery, bufory (ROB, schedulery), porty/jednostki wykonawcze FP/INT, L1/L2, AGU (load/store). Nic nie jest „mnożone ×2” poza stanem architektonicznym wątków.
    - sqrt i inne FP mają wysoką latencję i umiarkowaną przepustowość; jeśli drugi wątek ma sporo INT/LOAD/STORE, rdzeń może dość efektywnie wypełniać luki. Gdy obydwa wątki intensywnie obciążają te same jednostki (np. obie ścieżki FP/AVX2), powstaje silna konkurencja i spowolnienie per‑wątek rośnie.
    - Dlatego:
    - „SMT ten sam rdzeń” z komplementarnymi strumieniami → mała kara (u Ciebie ~7.2 s vs 6.3 s),
    - „SMT ten sam rdzeń” z identycznymi strumieniami → kara większa (często 1.3–1.6× per‑wątek),
    - „osobne rdzenie” → brak kary (to Twój przypadek 6.3 s).

    2) Interpretacja Twoich pomiarów
    - Ten sam wątek (jedna logiczna CPU): kernel dzieli czas, więc każdy proces zużył ok. 6.3 s czasu CPU (user), ale real jest ~2× większy, bo wykonywały się naprzemiennie.
    - Ta sama para SMT: każde zadanie spowolniło do ~7.2 s (ok. +15%), ale łącznie rdzeń wykonał prawie „2× pracę” w czasie tylko o ~15% dłuższym niż jeden wątek. To daje łączną przepustowość ok. 1.7× względem single‑thread (bardzo typowe dla SMT przy nieidentycznych strumieniach).
    - Dwa rdzenie: czasy jak w baseline (brak współdzielenia zasobów rdzenia).

    3) Dlaczego wcześniej „nie udało się zwolnić”
    - Pary SMT nie są gwarantowanie „kolejnymi numerami CPU”. Jeśli nie trafisz w dokładną parę rodzeństwa SMT, to przypinasz do dwóch różnych rdzeni i nie zobaczysz kary.
    - Na dwusocketowych Haswell‑EP numeracja bywa przeplatana (per socket i/lub per wątek). Zawsze korzystaj z:
    - cat /sys/devices/system/cpu/cpuX/topology/thread_siblings_list
    - lub tabeli: lscpu -e=CPU,CORE,SOCKET,NODE (dwie linie z tym samym CORE+SOCKET = para SMT).

    ---

    Jak uzyskać „dużo wolniej” na tej samej parze SMT (kontrola eksperymentu)

    1) Upewnij się, że to naprawdę ta sama para SMT:
    - Załóżmy, że dla CPU A system zwraca „A,B” w thread_siblings_list – właśnie A i B są rodzeństwem SMT.
    - Uruchamiaj procesy osobno, każdy przypięty do jednego numeru: taskset -c A … i taskset -c B …

    2) Ustabilizuj częstotliwość:
    - Governor „performance” albo schedutil bez turbo na czas testu:
    - echo performance > /sys/devices/system/cpu/cpufreq/policy0/scaling_governor
    - Intel: echo 0 > /sys/devices/system/cpu/intel_pstate/no_turbo

    3) Dobierz obciążenia:
    - „Maksymalna walka o FP/AVX2” (zobaczysz większą karę SMT):
    - taskset -c A stress-ng --cpu 1 --cpu-method matrixprod --timeout 20s &
    - taskset -c B stress-ng --cpu 1 --cpu-method matrixprod --timeout 20s & wait
    - „Komplementarne” (mniejsza kara SMT):
    - A: --cpu-method sqrt (FP),
    - B: --cpu-method integer (INT) lub np. --cpu-method ackermann (mało FP).
    - „Memory‑bound” (walka o L1/L2/L3/AGU):
    - A/B: stress-ng --stream 1 lub --memcpy 1 (większa zależność od przepustowości i cache).

    4) Obserwacja liczników sprzętowych (opcjonalnie):
    - perf stat -e cycles,instructions,context-switches,cpu-migrations -C A,B -- sleep 20
    - Jeśli masz „topdown”:
    - perf stat -e topdown-retiring,topdown-bad-spec,topdown-fe-bound,topdown-be-bound -C A,B -- sleep 20
    Wzrost „be-bound” przy SMT i FP wskazuje na ograniczenie backendu (jednostek wykonawczych/AGU).

    ---

    Sprawdzenie i budowa masek w praktyce (dwusocket, 10C/20T na socket)
    - Pary SMT (dla wszystkich CPU):
    for c in /sys/devices/system/cpu/cpu[0-9]*; do echo ${c##*/}: $(cat $c/topology/thread_siblings_list); done | sort -t: -k1,1V
    - „Po jednym logicznym CPU na rdzeń” (maska bez SMT):
    lscpu -e=CPU,CORE,SOCKET | awk 'NR>1{key=$2":"$3;if(!(key in s)){printf (sep $1); sep=","; s[key]=1}}END{print ""}'
    - CPU per‑socket (do pinowania per gniazdo):
    lscpu -p=CPU,SOCKET | awk -F, '/^[0-9]/{print $2":"$1}' | sort -n | awk -F: 'NR==1{s0=$2} NR>1 && $1==0{s0=s0","$2} NR>1 && $1==1{s1=s1? s1","$2:$2} END{print "S0="s0"\nS1="s1}'

    ---

    Wnioski i rekomendacje praktyczne
    - Maksimum wydajności pojedynczego zadania: trzymaj je na „pierwszych” wątkach rdzeni (bez współdzielenia SMT) – affinity/cpuset.
    - Maksimum przepustowości całego systemu: korzystaj z SMT, ale staraj się:
    - nie kumulować zadań o identycznym profilu FP/AVX2 na jednej parze SMT,
    - rozdzielać „FP‑heavy” i „INT/memory‑heavy” na ten sam rdzeń (komplementarność),
    - dbać o lokalność NUMA (numactl --cpunodebind=… --membind=…).
    - Przy obciążeniach FP/AVX2 pamiętaj, że CPU może obniżać częstotliwość pod ciężkim wektorem – przy porównaniach z wyłączonym SMT efekt bywa mylący; ujednolicenie governor/turbo pomaga.

    ---

    Dalsze kroki
    Jeśli podeślesz:
    - lscpu -e=CPU,CORE,SOCKET,NODE | sort -k3,3n -k2,2n -k1,1n
    - dla wybranej pary: cat /sys/devices/system/cpu/cpuA/topology/thread_siblings_list
    - przykładowe komendy, którymi startujesz testy,

    to przygotuję gotowe maski AllowedCPUs (systemd/cgroups) oraz scenariusze testów „identyczne vs komplementarne” dla Twojego E5‑2660 v3 i wskażę, gdzie na Twojej maszynie najszybciej „pęka” SMT (FP, AGU czy cache).
    Możesz mnie wywołać w każdym temacie pisząc @ElektrodaBot. Zastrzeżenie: Niektóre odpowiedzi udzielone przez ElektrodaBota mogą być niedokładne. Elektroda nie ponosi odpowiedzialności za dokładność, rzetelność ani kompletność prezentowanych informacji. Wszystkie odpowiedzi ElektrodaBota powinny być zweryfikowane przez użytkownika. OpenAI może monitorować i zapisywać informacje wprowadzane po wywołaniu ElektrodaBota.
  • #10 21720452
    _jta_
    Specjalista elektronik
    Posty: 49148
    Pomógł: 3212
    Ocena: 4260
    @ElektrodaBot - jakich opcji gcc trzeba użyć dla procesora X86 o architekturze Haswell, aby wygenerował instrukcje zmiennoprzecinkowe w kodzie, zamiast wywoływać funkcje biblioteczne?

    Próbowałem "gcc -march=haswell -mfpmath=both -mhard-float -O9" - bez powodzenia, wywołuje np. "cos@PLT", nie używa wprost FCOS.
  • #11 21720464
    ElektrodaBot
    AI od OpenAI ChatGPT4
    Posty: 8895
    Pomógł: 365
    Ocena: 956
    LABEL_AI_GENERATED
    _jta_ napisał:
    @ElektrodaBot - jakich opcji gcc trzeba użyć dla procesora X86 o architekturze Haswell, aby wygenerował instrukcje zmiennoprzecinkowe w kodzie, zamiast wywoływać funkcje biblioteczne?

    Próbowałem "gcc -march=haswell -mfpmath=both -mhard-float -O9" - bez powodzenia, wywołuje np. "cos@PLT", nie używa wprost FCOS.
    Bezpośrednia odpowiedź
    - Nie wymusisz, aby GCC na Haswellu zamienił wywołanie cos()/sin()/log()/exp() na pojedynczą instrukcję CPU. x86 nie ma „prawdziwych” instrukcji trygonometrycznych zgodnych z libm; stare x87 FSIN/FCOS są niedokładne i nieużywane przez współczesne kompilatory. Dlatego dla cos() zobaczysz wywołanie biblioteczne (np. cos@PLT). (intel.com)
    - To, co możesz uzyskać:
    - dla operacji prostych (+ − × ÷, sqrt) – bezpośrednie instrukcje SSE/AVX (np. SQRTSD/SQRTSS), jeśli pozwolisz kompilatorowi na pominięcie errno i innych rygorów: -O3/‑Ofast + -ffast-math (albo co najmniej -fno-math-errno). (gcc.gnu.org)
    - dla cos/sin/log/exp w pętlach – autowektoryzację i wywołania do wektorowej libm (glibc libmvec; symbole typu _ZGVdN4v_cos) lub do SVML/SLEEF, co daje kod AVX/AVX2/FMA, ale nadal jako wywołanie funkcji (tylko wektorowej). (beowulf.org)
    - Zestaw „sensownych” flag pod Haswella:
    - ogólnie: -march=haswell -O3 -ffast-math [-Ofast zamiast -O3, jeśli akceptujesz konsekwencje IEEE] + ewentualnie -ffp-contract=fast (FMA) i -funroll-loops dla długich pętli,
    - do pętli z cos/sin: -O3 (włącza -ftree-vectorize), -ffast-math, link z -lm (glibc z libmvec). Dla SVML: dodaj -fveclibabi=svml i dołącz bibliotekę SVML. (developers.redhat.com)
    - Tego nie używaj: -O9 (nie istnieje), -mhard-float (na x86-64 bez znaczenia), -mfpmath=both (mieszanie x87 i SSE nie ma sensu na x86‑64 – domyślnie i tak jest SSE/AVX). (gcc.gnu.org)

    ---

    Dlaczego widzisz cos@PLT i dlaczego FCOS nie jest używany
    - Standardowe funkcje trygonometryczne muszą być precyzyjne w całym zakresie, obsługiwać NaN/Inf itp. x87 FSIN/FCOS to tylko przybliżenia na ograniczonej dziedzinie i mają problemy z redukcją argumentu; Intel od dawna zaleca biblioteki programowe zamiast tych instrukcji. Kompilatory nie mapują cos(x) → FCOS. (intel.com)
    - Nawet z -ffast-math GCC nie wstawia własnych wielomianów dla skalarnego cos(); pozostaje wywołanie libm (lub – po wektoryzacji pętli – libmvec/SVML/SLEEF). (gcc.gnu.org)

    ---

    Jak uzyskać „instrukcje FP zamiast libm” w praktyce

    1) Operacje, które mają instrukcje
    - sqrt(x) → SQRTSD/SQRTSS; wymuś brak errno i puść optymalizacje:
    - przykładowe flagi: -march=haswell -O3 -fno-math-errno (albo -ffast-math / -Ofast). (gcc.gnu.org)
    - Dzielenie/odwrotność: rozważ aproksymacje reciprocal: -mrecip=… (dla skalarnej/ wektorowej ÷/√). (gcc.gnu.org)

    2) Funkcje złożone (cos/sin/log/exp)
    - Autowektoryzacja pętli do wywołań libmvec (glibc ≥ 2.22). Flagi:
    - -march=haswell -O3 -ffast-math [-fopenmp-simd lub #pragma omp simd bywa pomocne],
    - linkuj z -lm (glibc sam wybierze wariant _ZGV… dla AVX/AVX2). (beowulf.org)
    - Alternatywy:
    - -fveclibabi=svml i dołączenie Intel SVML (własne biblioteki i licencja), lub podmiana libmvec na SLEEF GNUABI (API zgodne z libmvec). (gcc.gnu.org)

    3) Weryfikacja
    - S wygenerowany przez GCC: gcc … -S -masm=intel; sprawdź czy cos@PLT zniknął (skalar – zwykle nie; wektor – zobaczysz _ZGV…),
    - objdump -drwC a.out | grep -iE 'call.*(cos@|_ZGV.*cos)'.

    ---

    Minimalne przepisy (Haswell, Xeon E5‑2660 v3)

    - Skalarne FP bez biblioteki (sqrt, fabs, mnożenia, FMA):
    - gcc -march=haswell -O3 -ffast-math -ffp-contract=fast prog.c
    - Pętle z cos/sin – wektoryzacja przez libmvec:
    - gcc -march=haswell -O3 -ffast-math prog.c -lm
    - w kodzie: for (i=0; i<n; ++i) y[i] = cos(x[i]); // spodziewaj się _ZGV…cos
    - jeśli chcesz SVML: gcc -march=haswell -O3 -ffast-math -fveclibabi=svml prog.c -lsvml -lm (gcc.gnu.org)

    ---

    Najczęstsze nieporozumienia i pułapki
    - „-mfpmath=both przyśpieszy” – na x86‑64 nie; trzymaj się SSE/AVX (domyślne). Mieszanie z x87 komplikuje rejestry i może spowolnić. (gcc.gnu.org)
    - „-mhard-float” – na x86‑64 nic nie zmienia (sprzętowy FP jest domyślny). (gcc.gnu.org)
    - „-O9” – maksymalnie jest -O3; -Ofast = -O3 + fast‑math (łamanie części reguł IEEE). (gcc.gnu.org)
    - „Da się zmusić GCC do FCOS” – nie; i nie warto (dokładność/zakres/latencja). (intel.com)

    ---

    Jeśli zależy Ci na braku wywołań w ogóle
    - Masz trzy drogi:
    - napisać własny „fastcos” (wielomiany/Czebyszew, redukcja argumentu) i wstawić intrinsics AVX2/FMA – pełna kontrola nad kompromisem dokładność/szybkość,
    - użyć SLEEF w trybie „pseudoinline” (wektoryzowane aproksymacje, bezpośrednio z intrinsics),
    - zaakceptować wywołania, ale wektorowe (libmvec/SVML) – z reguły najszybsza i najprostsza ścieżka. (blapie.github.io)

    ---

    Dla porządku: co zmienia -ffast-math
    - Włącza m.in. -fno-math-errno, -funsafe-math-optimizations, -ffinite-math-only, -fno-signaling-nans, -fno-rounding-math; pozwala na agresywniejsze transformacje (także wektoryzację redukcji). (gcc.gnu.org)

    ---

    Podsumowanie
    - Na Haswellu nie ma flag GCC, które zamienią skalarne cos(x) na „instrukcję CPU” – to zawsze (poza stałą w czasie kompilacji) skończy się wywołaniem, ewentualnie wektorowym (libmvec/SVML).
    - Używaj -march=haswell -O3/-Ofast -ffast-math; dla sqrt i podobnych dostaniesz natywne instrukcje, dla trygonometrii w pętlach – wektorowe wywołania biblioteki z AVX2/FMA. To jest obecnie najszybszy i przenośny kompromis. (gcc.gnu.org)

    Jeśli podeślesz krótki przykład (pętla z cos/sin) i wynik objdump/asm, wskażę dokładnie, które wywołania przekształciły się w libmvec/SVML, i czy wektoryzacja jest optymalna dla Twojego E5‑2660 v3.
    Możesz mnie wywołać w każdym temacie pisząc @ElektrodaBot. Zastrzeżenie: Niektóre odpowiedzi udzielone przez ElektrodaBota mogą być niedokładne. Elektroda nie ponosi odpowiedzialności za dokładność, rzetelność ani kompletność prezentowanych informacji. Wszystkie odpowiedzi ElektrodaBota powinny być zweryfikowane przez użytkownika. OpenAI może monitorować i zapisywać informacje wprowadzane po wywołaniu ElektrodaBota.
  • REKLAMA
  • #12 21720473
    ElektrodaBot
    AI od OpenAI ChatGPT4
    Posty: 8895
    Pomógł: 365
    Ocena: 956
    LABEL_AI_GENERATED
    _jta_ napisał:
    @ElektrodaBot - jakich opcji gcc trzeba użyć dla procesora X86 o architekturze Haswell, aby wygenerował instrukcje zmiennoprzecinkowe w kodzie, zamiast wywoływać funkcje biblioteczne?

    Próbowałem "gcc -march=haswell -mfpmath=both -mhard-float -O9" - bez powodzenia, wywołuje np. "cos@PLT", nie używa wprost FCOS.
    Bezpośrednia odpowiedź
    - Nie wymusisz w GCC, aby `cos()`/`sin()` na Haswellu zostały zastąpione „pojedynczą instrukcją CPU”. SSE/AVX nie mają instrukcji trygonometrycznych; x87 ma `FSIN/FCOS`, ale kompilatory praktycznie ich nie używają (ograniczony zakres, dokładność, wydajność). Dlatego widzisz wywołanie `cos@PLT` do libm – to zamierzone. (intel.com)
    - Jeśli celem jest wydajność: użyj optymalizacji „fast‑math” i pozwól kompilatorowi wektoryzować pętle oraz wołać wektorową libm (glibc libmvec, Intel SVML, AMD AOCL). To nie są „instrukcje wprost”, ale zamiast mnogich wywołań skalarnego `cos` dostajesz pojedyncze, wektorowe wywołanie liczące 2/4/8 elementów naraz, wykonywane na AVX2/FMA Haswella. Kluczowe: `-O3` lub `-Ofast`, `-ffast-math` (lub samo `-Ofast`), `-ftree-vectorize`, często dodatkowo `-fno-math-errno -fno-trapping-math`, oraz dobór ABI biblioteki: `-mveclibabi=svml|aocl` i podlinkowanie właściwej biblioteki. (gcc.gnu.org)
    - Twoje opcje: `-O9` nie istnieje (użyj `-O3`/`-Ofast`); `-mhard-float` na x86‑64 nic nie zmienia; `-mfpmath=both` jest eksperymentalne i na 64‑bit zwykle nie ma sensu. (gcc.gnu.org)
    - Jeśli chcesz absolutnie „bez wywołań” dla trygonometrów, musisz:
    - napisać własną aproksymację (np. wielomiany + intrinsics AVX2/FMA), albo
    - użyć inline asm z x87 `FSIN/FCOS` (świadomie akceptując ograniczenia i zwykle gorszą wydajność). GCC nie gwarantuje sam z siebie zamiany `cos()` na `FSIN/FCOS`. (intel.com)

    ---

    Szczegółowa analiza

    1) Dlaczego pojawia się `cos@PLT` zamiast „instrukcji”
    - W standardowym C `cos()`/`sin()` są funkcjami bibliotecznymi o zdefiniowanej dokładności/semantyce (IEEE, obsługa wyjątków itp.). Kompilator może je traktować jako „builtins”, ale jeśli nie ma bezpiecznej (zgodnej) ekspansji inline, emituje wywołanie do libm. To zachowanie jest udokumentowane: wiele built‑inów jest inline tylko w pewnych przypadkach, w przeciwnym – generowane jest wywołanie biblioteki. (gcc.gnu.org)
    - x87 ma `FSIN/FCOS`, lecz Intel od lat podkreśla, że te instrukcje mają ograniczony zakres i wymagają dodatkowej (kosztownej) redukcji argumentu dla pełnej dokładności. Stąd biblioteki programowe (libm) są preferowane – są dokładniejsze i często szybsze. (intel.com)

    2) Co naprawdę daje `-ffast-math` / `-Ofast`
    - `-Ofast` = `-O3` + `-ffast-math` (+ parę dodatków językowych). `-ffast-math` włącza m.in. `-funsafe-math-optimizations`, `-fno-math-errno`, `-ffinite-math-only`, co pozwala kompilatorowi agresywniej przekształcać kod i wektoryzować wyrażenia z funkcjami matematycznymi. Nie gwarantuje jednak, że skalarne `cos()` zniknie – częściej umożliwia wektoryzację pętli i użycie wektorowej libm. (stackoverflow.com)

    3) Jak uzyskać „brak skalarnych wywołań” w krytycznych pętlach
    - Zadbaj o warunki do wektoryzacji:
    - Flagi: `-O3 -ffast-math -ftree-vectorize -fno-math-errno -fno-trapping-math -march=haswell`
    - Dla zewnętrznej wektorowej libm:
    - glibc (≥2.22): wystarczy linkować z `-lm`; podczas wektoryzacji GCC może emitować symbole `_ZGV*` z libmvec (np. `_ZGVdN4v_cos`). (beowulf.org)
    - Intel SVML (oneAPI): `-mveclibabi=svml` i link do SVML. (gcc.gnu.org)
    - AMD AOCL LibM: `-mveclibabi=aocl` i link do AOCL‑LibM. (gcc.gnu.org)
    - Weryfikacja:
    - `nm -a a.out | grep -E 'sin|cos|_ZGV'` – pojawienie się `_ZGV..._cos` oznacza wektorowe wołanie zamiast mnóstwa skalarnych `cos@PLT`. (stackoverflow.com)
    - Uwaga: to nadal są wywołania funkcji, ale znacznie rzadsze (po 2/4/8 elementów na raz) i wykonywane na AVX2/FMA, więc przepustowość jest wielokrotnie większa.

    4) A jeśli mimo wszystko chcesz x87 `FSIN/FCOS`
    - Możesz wymusić generację kodu x87 przez `-mfpmath=387` (na x86‑64 domyślne jest SSE/AVX), ale GCC nawet wtedy może pozostać przy wywołaniu libm dla `cos()` ze względów numerycznych. W pojedynczych wersjach/konfiguracjach GCC zdarza się, że z `-ffast-math -mfpmath=387` skalarne `sin/cos` bywa rozwinięte do `FSIN/FCOS`, ale to nie jest przenośne ani zalecane – sprawdź wygenerowany asm i licz. (gcc.gnu.org)
    - Technicznie najpewniejsze jest użycie inline asm:
    - „wiem co robię”: napisz własną funkcję z `asm volatile("fcos" : "=t"(y) : "0"(x));` i mierz; miej świadomość kosztów przejść SSE↔x87 i ograniczeń dokładności/optymalizacji tych instrukcji na nowych CPU. (intel.com)

    5) Korekty Twoich opcji i praktyczne recepty
    - Zamiast: `-march=haswell -mfpmath=both -mhard-float -O9`
    - Użyj (skalar + warunek do autowektoryzacji):
    - „bezpieczniej”: `-O3 -march=haswell -ffast-math -fno-math-errno -fno-trapping-math`
    - „agresywnie”: `-Ofast -march=haswell` (implikuje `-ffast-math`) (stackoverflow.com)
    - Pętla z `cos`/`sin`:
    - glibc/libmvec: `gcc -Ofast -march=haswell -ftree-vectorize your.c -lm`
    - SVML: `gcc -Ofast -march=haswell -ftree-vectorize -mveclibabi=svml your.c -lsvml -lm`
    - AOCL‑LibM: `gcc -Ofast -march=haswell -ftree-vectorize -mveclibabi=aocl your.c -laocl-libm -lm` (gcc.gnu.org)
    - Kontrola efektu:
    - `objdump -d a.out | less` – brak „gęstych” `call cos@PLT`, obecne `_ZGV..._cos` = użycie libmvec/SVML. (stackoverflow.com)

    ---

    Rekomendacje praktyczne
    - Jeśli zależy Ci na przepustowości (HPC, przetwarzanie wsadowe):
    - stawiaj na wektoryzację i wektorową libm (libmvec/SVML/AOCL),
    - trzymaj `-Ofast`/`-ffast-math` tylko w częściach, gdzie kontrolujesz numerykę,
    - rozważ SLEEF/AMD LibM jako alternatywy (aproksymacje zoptymalizowane pod AVX2/FMA).
    - Jeśli absolutnie musisz uniknąć wywołań:
    - implementacja własna (wielomiany + intrinsics) lub inline asm x87 – ale poprzedź to pomiarami; bardzo często wektorowa libm będzie szybsza i dokładniejsza niż x87 `FSIN/FCOS`. (intel.com)

    ---

    Dalsze pytania/doprecyzowanie
    - Jak wygląda Twój przypadek użycia: pojedyncze wywołania `cos()` czy pętle po dużych buforach?
    - Jakiej glibc używa serwer (sprawdź `ldd --version`) – jeśli ≥2.22, libmvec jest dostępny.
    - Czy możesz udostępnić krótki benchmark (pętla z `cos`) – pokażę, jak wymusić wektoryzację i zweryfikować `_ZGV*` w binarium.
    Możesz mnie wywołać w każdym temacie pisząc @ElektrodaBot. Zastrzeżenie: Niektóre odpowiedzi udzielone przez ElektrodaBota mogą być niedokładne. Elektroda nie ponosi odpowiedzialności za dokładność, rzetelność ani kompletność prezentowanych informacji. Wszystkie odpowiedzi ElektrodaBota powinny być zweryfikowane przez użytkownika. OpenAI może monitorować i zapisywać informacje wprowadzane po wywołaniu ElektrodaBota.
  • #13 21720528
    _jta_
    Specjalista elektronik
    Posty: 49148
    Pomógł: 3212
    Ocena: 4260
    "-march=haswell -Ofast -ffast-math -mfpmath=387" jest skuteczne - kompilator generuje FCOS zamiast wywoływać funkcję z biblioteki. I nie potrzeba "-lm". Ale uruchomienie dwóch procesów na oddzielnych wątkach tego samego rdzenia daje czas procesora niewiele większy, niż na różnych rdzeniach. FSQRT chyba jest równie szybkie, jak dzielenia (dla architekture Haswell podają FDIV 10-24, FSQRT 10-23), ale mam wrażenie, że różnica jest większa - może nie instrukcje zmiennoprzecinkowe zajmują większość czasu?
  • #14 21721096
    _jta_
    Specjalista elektronik
    Posty: 49148
    Pomógł: 3212
    Ocena: 4260
    @ElektrodaBot - Chciałbym mieć jakiś kawałek programu, dla którego czas wykonywania przez procesor w architekturze Haswell wyraźnie zależałby od tego, czy dwa zadania, które go wykonują, używają tego samego rdzenia, czy różnych rdzeni. Jak na razie mam raczej niewielkie różnice - wygląda na to, że rdzeń całkiem dobrze sobie radzi w jednoczesnym wykonywaniem dwóch wątków. Masz jakiś pomysł, jakich instrukcji użyć, by uzyskać wyraźną różnicę?
  • #15 21721099
    ElektrodaBot
    AI od OpenAI ChatGPT4
    Posty: 8895
    Pomógł: 365
    Ocena: 956
    LABEL_AI_GENERATED
    _jta_ napisał:
    @ElektrodaBot - Chciałbym mieć jakiś kawałek programu, dla którego czas wykonywania przez procesor w architekturze Haswell wyraźnie zależałby od tego, czy dwa zadania, które go wykonują, używają tego samego rdzenia, czy różnych rdzeni. Jak na razie mam raczej niewielkie różnice - wygląda na to, że rdzeń całkiem dobrze sobie radzi w jednoczesnym wykonywaniem dwóch wątków. Masz jakiś pomysł, jakich instrukcji użyć, by uzyskać wyraźną różnicę?
    Bezpośrednia odpowiedź
    - Żeby „SMT‑kara” była wyraźna na Haswell‑EP (E5‑2660 v3), uderz w zasób współdzielony i o niskiej przepustowości:
    1) 64‑bitowe dzielenie całkowitoliczbowe (IDIV) – bardzo wolne i słabo potokowane,
    2) gęsty strumień AVX2/FMA (throughput‑bound, bez dostępu do pamięci) – dwa wątki SMT muszą dzielić te same dwie jednostki FMA (port 0 i 1).
    - Dla takich jąder różnica „ten sam rdzeń (SMT)” vs „dwa rdzenie” zwykle sięga 40–100% czasu per proces. Poniżej masz dwa minimalne, powtarzalne mikrobencze i procedurę uruchamiania.

    ---

    1) Mikrobencz „IDIV hammer” – dramatyczny efekt SMT

    Plik: test_idiv.c
    Kod: text
    Zaloguj się, aby zobaczyć kod


    Kompilacja:
    - gcc -O2 -march=haswell test_idiv.c -o test_idiv
    - (opcjonalnie) sprawdź, że w asm jest „idiv”: objdump -d test_idiv | less

    Oczekiwane: dwa procesy przypięte do tej samej pary SMT niemal podwajają czas każdego z nich (IDIV to pojedynczy, wąski zasób); na dwóch rdzeniach czasy ~jak bazowe.

    ---

    2) Mikrobencz „FMA throughput” – czyste dzielenie jednostek FMA

    Plik: test_fma.c
    Kod: text
    Zaloguj się, aby zobaczyć kod


    Kompilacja:
    - gcc -O3 -march=haswell -mavx2 -mfma -fno-trapping-math -fno-math-errno test_fma.c -o test_fma

    Oczekiwane: na tej samej parze SMT czas pojedynczego procesu wydłuży się o ~60–100% względem „solo”. Na dwóch rdzeniach niemal brak kary. Uwaga: ciężkie AVX2 obniża częstotliwość (AVX freq offset) – porównuj „SMT vs 2 rdzenie” przy jednoczesnym uruchomieniu dwóch identycznych zadań, wtedy offset działa na oba przypadki i nie zaciemnia wniosków.

    ---

    3) Procedura testowa (żeby wynik był jednoznaczny)

    1) Znajdź rodzeństwo SMT:
    - dla CPU X: cat /sys/devices/system/cpu/cpuX/topology/thread_siblings_list → np. „0,20”. Wybierz A=0, B=20. Wybierz C jako CPU z innym CORE i tym samym SOCKET.

    2) Ustabilizuj zegar:
    - governor „performance”: for p in /sys/devices/system/cpu/cpufreq/policy*; do echo performance > $p/scaling_governor; done
    - (opcjonalnie) wyłącz turbo na czas testu:
    - Intel: echo 0 > /sys/devices/system/cpu/intel_pstate/no_turbo

    3) Trzy pomiary (dla obu programów osobno):
    - baza (1 proces):
    - time taskset -c A ./test_idiv
    - SMT (ta sama para rdzenia):
    - (time taskset -c A ./test_idiv) & (time taskset -c B ./test_idiv) & wait
    - 2 rdzenie:
    - (time taskset -c A ./test_idiv) & (time taskset -c C ./test_idiv) & wait

    4) Walidacja zasobów (opcjonalnie perf):
    - perf stat -e cycles,instructions,context-switches,cpu-migrations,ref-cycles -C A,B -- sleep 1
    - przy test_fma dodaj: -e fp_arith_inst_retired.256b_packed_double (lub zbliżone eventy dostępne na Twoim kernelu).

    Wyniki:
    - test_idiv: kara SMT zwykle największa (nawet ~2×).
    - test_fma: wyraźna kara SMT (dzielenie portów FMA powoduje ~1.6–2× wydłużenie per proces).

    ---

    4) Dlaczego te dwa testy „łapią” SMT lepiej niż FSQRT/FCOS
    - IDIV64 ma bardzo niską przepustowość i wysoką latencję; jeden „serwisujący” dzielnik na rdzeń staje się wąskim gardłem, więc dwa wątki SMT czekają na siebie.
    - FMA na Haswellu ma throughput 2/clk (porty 0+1) i latencję ~5 cykli; 10 niezależnych akumulatorów omija ograniczenie latencji, zmuszając oba wątki do dzielenia dokładnie tych samych portów – efekt jest czysto throughput‑owy i łatwo mierzalny.
    - FSQRT/FDIV (FP) w Twoich wcześniejszych próbach mogły być rozcieńczone innymi instrukcjami (LOAD/STORE/INT) – OOO i SMT wypełniały „dziury”, więc kara była mała.

    ---

    5) Uwaga o flagach kompilatora
    - Nie używaj „-O9” (nie istnieje) ani wymuszania x87 dla testów SMT AVX2/FMA. Dla IDIV wystarczy -O2; dla AVX2/FMA konieczne -march=haswell -mavx2 -mfma. „-ffast-math” nie jest wymagane (używamy intrinsics), ale nie szkodzi.
    - Jeśli kiedyś chcesz badać „pamięć zamiast ALU”: uruchom dwie instancje STREAM (copy/triad) na tej samej parze SMT vs na 2 rdzeniach – zobaczysz spadek przepustowości L1/L2 i konflikt AGU (Haswell ma 2 load AGU i 1 store‑AGU na rdzeń).

    ---

    6) Jeśli chcesz, przygotuję gotowe maski CPU/SMT
    Podeślij:
    - lscpu -e=CPU,CORE,SOCKET | sort -k3,3n -k2,2n -k1,1n
    - wątek i jego thread_siblings_list, na którym testujesz,
    a zwrócę konkretne komendy taskset/numactl dla Twojego serwera 2×10C/20T oraz krótkie skrypty bash automatyzujące serię pomiarów (solo/SMT/2‑core) dla obu mikrobenczy.
    Możesz mnie wywołać w każdym temacie pisząc @ElektrodaBot. Zastrzeżenie: Niektóre odpowiedzi udzielone przez ElektrodaBota mogą być niedokładne. Elektroda nie ponosi odpowiedzialności za dokładność, rzetelność ani kompletność prezentowanych informacji. Wszystkie odpowiedzi ElektrodaBota powinny być zweryfikowane przez użytkownika. OpenAI może monitorować i zapisywać informacje wprowadzane po wywołaniu ElektrodaBota.
  • #16 21721274
    _jta_
    Specjalista elektronik
    Posty: 49148
    Pomógł: 3212
    Ocena: 4260
    @ElektrodaBot - wypróbowałem, na razie tylko wersję „IDIV hammer”; wyniki:
    * Stabilizowanie zegara wychodzi lepiej, jak się ustawi governor=powersave - wtedy wszystkie rdzenie działają na minimalnej częstotliwości; z governor=performance większość rdzeni działa na maksymalnej częstotliwości, ale część na znacznie niższej; po ustawieniu no_turbo=0 ta maksymalna jest 3300 MHz, przy no_turbo=1 - 2600 MHz (i to się zmienia w scaling_max_freq).
    * Na trzy próby największa zmiana czasu wykonywania (przy ustabilizowaniu zegara na 1200 MHz) była 1.57% (najmniejsza 1.145%). Zrobiłem kolejne próby podwyższając priorytet przy użyciu "renice" - wyniki 1.53%, 1.54%, 1.55%, 1.59%, 1.60%.
  • #17 21721286
    ElektrodaBot
    AI od OpenAI ChatGPT4
    Posty: 8895
    Pomógł: 365
    Ocena: 956
    LABEL_AI_GENERATED
    _jta_ napisał:
    @ElektrodaBot - wypróbowałem, na razie tylko wersję „IDIV hammer”; wyniki:
    * Stabilizowanie zegara wychodzi lepiej, jak się ustawi governor=powersave - wtedy wszystkie rdzenie działają na minimalnej częstotliwości; z governor=performance większość rdzeni działa na maksymalnej częstotliwości, ale część na znacznie niższej; po ustawieniu no_turbo=0 ta maksymalna jest 3300 MHz, przy no_turbo=1 - 2600 MHz (i to się zmienia w scaling_max_freq).
    * Na trzy próby największa zmiana czasu wykonywania (przy ustabilizowaniu zegara na 1200 MHz) była 1.57% (najmniejsza 1.145%). Zrobiłem kolejne próby podwyższając priorytet przy użyciu "renice" - wyniki 1.53%, 1.54%, 1.55%, 1.59%, 1.60%.
    Bezpośrednia odpowiedź
    - Różnice 1.1–1.6% przy „IDIV hammer” oznaczają, że test nie jest CPU‑bound na jednostce dzielnika. Ustawiłeś powersave=1200 MHz, przez co wąskim gardłem stał się frontend/pamięć, a SMT ukrywa latencje – stąd minimalna „kara”.
    - Ustaw stałą częstotliwość na poziomie bazowym (dla E5‑2660 v3: 2.6 GHz), najlepiej no_turbo=1 i governor=performance (albo wymuś min=max dla intel_pstate). Wtedy dzielnik staje się realnym bottleneckiem.
    - Użyj pętli z wymuszoną, zależną sekwencją DIV bez obciążeń pamięci (inline asm), albo saturuj porty FMA (AVX2/FMA). To daje wyraźną różnicę SMT vs 2 rdzenie.

    ---

    Szczegółowa analiza i gotowe przepisy

    1) Dlaczego powersave=1200 MHz „psuje” pokazówkę SMT
    Przy niskiej częstotliwości rdzeń relatywnie rzadziej trafia na wąskie gardło w dzielniku; częściej czeka na fetch/decode i mikrolatencje cache. SMT robi wtedy to, po co powstał: wypełnia dziury wykonawcze drugim wątkiem. Efekt: niemal brak spowolnienia przy współdzieleniu rdzenia.

    Co zrobić:
    - Wyłącz turbo i ustaw częstotliwość na bazową (stabilna, powtarzalna):
    - echo 1 > /sys/devices/system/cpu/intel_pstate/no_turbo
    - dla każdego policy: echo performance > .../scaling_governor
    - dodatkowo możesz wyrównać min/max: echo $(cat .../cpuinfo_max_freq) > .../scaling_min_freq; to samo do scaling_max_freq (po no_turbo=1 „max” = ~2600 MHz).
    - Sprawdź, że faktycznie trzymasz zegar podczas testu (np. turbostat/perf stat – ref-cycles vs cycles).

    Uwaga: renice nie wpływa na współdzielenie zasobów mikroarchitektury – tylko na priorytet w planistyce.

    2) Zweryfikuj, że to na pewno para SMT
    - cat /sys/devices/system/cpu/cpuX/topology/thread_siblings_list → wybierz A,B z tej listy jako rodzeństwo SMT.
    - CPU C wybierz z innego CORE (ten sam SOCKET).

    3) IDIV „na twardo” – wersja, która zawsze wali w dzielnik
    Wymuszamy maszynowy DIV z zależnością danych (back‑to‑back), bez dostępu do pamięci w pętli.

    Plik: idiv_chain.c
    Kod: text
    Zaloguj się, aby zobaczyć kod


    Kompilacja i uruchomienie:
    - gcc -O2 -march=haswell idiv_chain.c -o idiv_chain
    - Testy:
    - solo: time taskset -c A ./idiv_chain
    - SMT: (time taskset -c A ./idiv_chain) & (time taskset -c B ./idiv_chain) & wait
    - 2 rdzenie: (time taskset -c A ./idiv_chain) & (time taskset -c C ./idiv_chain) & wait

    Oczekiwane: na parze SMT czas pojedynczego procesu wyraźnie wzrośnie (typowo kilkadziesiąt do ~2×), na dwóch rdzeniach – znikomy wzrost vs solo.

    Weryfikacja:
    - objdump -d ./idiv_chain | grep -i 'div ' → powinna być „div %rcx” w pętli.
    - perf list | grep -i div; perf stat -e <event_divider> -C A,B -- ./idiv_chain
    (nazwy eventów różnią się; wyszukaj „divider” w perf list).

    4) Alternatywa: czysty throughput AVX2/FMA (bez pamięci)
    To uderza w porty 0+1 (FMA) współdzielone przez SMT.

    Plik: fma_sat.c
    Kod: text
    Zaloguj się, aby zobaczyć kod


    Kompilacja:
    - gcc -O3 -march=haswell -mavx2 -mfma -fno-math-errno -fno-trapping-math fma_sat.c -o fma_sat

    Uwagi:
    - Wyłącz turbo (no_turbo=1), bo ciężkie AVX obniża zegar (AVX freq offset). Porównuj SMT vs 2 rdzenie przy tych samych ustawieniach.
    - Oczekuj silnej kary SMT (dzielenie portów FMA przez dwa wątki).

    5) Jeśli nadal widzisz małe różnice
    - Upewnij się, że to NA PEWNO para SMT (thread_siblings_list).
    - Izoluj CPU od zakłóceń: tymczasowo wyłącz irqbalance i przypnij swoje dwa procesy oraz nic więcej do A,B (cgroups cpuset: AllowedCPUs=…).
    - Mierz licznikami: perf stat -C A,B -e cycles,instructions,context-switches,cpu-migrations,ref-cycles; dodaj eventy dla dzielnika (perf list | grep -i div) lub dla FP/FMA.

    ---

    Rekomendacje praktyczne
    - Do demonstracji „SMT boli”: trzymaj test CPU‑bound na bazowym zegarze (no_turbo=1, performance) i minimalizuj pamięć w pętli.
    - IDIV z zależnością i/lub AVX2/FMA bez pamięci dadzą znacznie większą różnicę niż FSQRT/FCOS.
    - renice nie ma wpływu na mikroarchitekturę; kluczowe są affinity, rzeczywista para SMT i stały zegar.

    Jeśli podasz konkretne A,B,C oraz wynik thread_siblings_list + krótkie wyniki perf stat (cycles/instructions) dla solo/SMT/2‑rdzenie, wskażę dokładnie, gdzie „ucieka” czas na Twojej maszynie i czy test faktycznie uderza w dzielnik lub porty FMA.
    Możesz mnie wywołać w każdym temacie pisząc @ElektrodaBot. Zastrzeżenie: Niektóre odpowiedzi udzielone przez ElektrodaBota mogą być niedokładne. Elektroda nie ponosi odpowiedzialności za dokładność, rzetelność ani kompletność prezentowanych informacji. Wszystkie odpowiedzi ElektrodaBota powinny być zweryfikowane przez użytkownika. OpenAI może monitorować i zapisywać informacje wprowadzane po wywołaniu ElektrodaBota.
  • #18 21721370
    _jta_
    Specjalista elektronik
    Posty: 49148
    Pomógł: 3212
    Ocena: 4260
    Po ustawieniu 2600 MHz na testowanych rdzeniach wyszło od 1.45% do 1.47% (po 3 testy na tym samym rdzeniu i na różnych rdzeniach).

    Dla 3200 MHz (musiałem ustawić no_turbo=0) wyszło o 1.39% i o 1.45% szybciej na tym samym rdzeniu!
    Przy okazji: zwiększenie częstotliwości zegara z 2600 do 3200 MHz (o czynnik 1.23) zmniejsza czas wykonania testu o czynnik około 1.22, przy czym dla dwóch zadań używających różnych rdzeni wyszło mi około 1.216, a dla jednego zadania, bądź dwóch używających tego samego rdzenia około 1.224. Ale powtórzenie testu po dłuższej przerwie dało 1.221 dla użycia różnych rdzeni - wpływ temperatury procesora i sprzętowego spowalniania zegara?

    Aha, jeśli w programie jest typ uint64_t, to jest używana instrukcja DIV, nie IDIV (DIV jest nieco szybsza od IDIV - czasy są od 32 do 96 i od 39 do 103).

    Przetestowałem program używający FSQRT - użycie tego samego rdzenia spowalnia o czynnik 1.228; testowałem z zegarem 1200 MHz i 2400 MHz - z 2400 było 2x szybciej.

    Program używający jednego FCOS w pętli - czynnik 1.106; dla 5 FCOS - czynnik 1.117; program z FPATAN - czynnik 1.060; program z FPTAN - czynnik 1.207; program z FYL2X - czynnik 1.093.
  • #19 21723921
    _jta_
    Specjalista elektronik
    Posty: 49148
    Pomógł: 3212
    Ocena: 4260
    Okazało się, że do wykrywania, że dwa procesy są wykonywane przez ten sam rdzeń, dobrze nadaje się taki programik:
    Kod: Tcl
    Zaloguj się, aby zobaczyć kod

    - nazwałem go "rfib.tcl" (rekursywne liczenie elementu ciągu Fibonacciego); do tego skrypt bash-a:
    Kod: Bash
    Zaloguj się, aby zobaczyć kod

    i wynik - czasy dla obciążenia wszystkich rdzeni na jednym wątku, i wszystkich na obu (procesor Xeon E5-1650 v3, 6 rdzeni, 12 wątków):
    Kod: Text
    Zaloguj się, aby zobaczyć kod

    Tyle było kombinowania, a rozwiązanie okazało się takie proste...

    Można obciążać tylko wybrane rdzenie: ustawić 4 wątki na 2 rdzeniach na określony zegar procesora, i puszczać dwa procesy, wymuszając (przez taskset -c lista-procesorów-logicznych wywołanie-programu):
    1. wykonywanie obu procesów na osobnych rdzeniach (przypisując po jednym procesorze logicznych do procesu);
    2. wykonywanie obu procesów na tym samym rdzeniu (przypisując po jednym procesorze logicznych do procesu);
    3. wykonywanie obu procesów na wybranych rdzeniach, ale pozwalając scheduler-owi na wybór rdzenia (podając dla każdego procesu po dwa procesory logiczne, każdy z tych dwóch na innym rdzeniu, bez powtarzania procesorów logicznych między procesami).
    Wyszło mi, że (1) i (3) dają taki sam czas wykonania, a (2) ponad 2x większy (nie wiem, czemu "ponad").

Podsumowanie tematu

LABEL_AI_GENERATED
Nowoczesne jądro Linux, wykorzystujące planistę Completely Fair Scheduler (CFS) do wersji 6.6, a następnie Earliest Eligible Virtual Deadline First (EEVDF), automatycznie rozkłada zadania na dostępne procesory i rdzenie, uwzględniając topologię SMT, NUMA oraz lokalność pamięci. Scheduler preferuje rozkład zadań na wolne rdzenie fizyczne przed dokładającymi wątki SMT na tym samym rdzeniu, a migracje między socketami są dozwolone, choć ograniczane dla optymalizacji lokalności pamięci. Temperatura procesorów nie jest bezpośrednim kryterium planisty, lecz throttling i sterowniki cpufreq wpływają na zmniejszenie „pojemności” gorących CPU, co pośrednio kieruje obciążenie na chłodniejsze rdzenie. Dodatkowe narzędzia jak irqbalance i thermald wspierają równoważenie obciążenia. W przypadku potrzeby precyzyjnego przypisania zadań do rdzeni lub wykluczenia SMT stosuje się CPU affinity i cgroups.

Wielowątkowe aplikacje (np. Chrome, ffmpeg) mogą migrować między rdzeniami i procesorami, a jądra Linux 6.12.48 (Debian) i 6.16.11 (Liquorix) używają algorytmu EEVDF z rozszerzeniami PREEMPT_DYNAMIC i sched_ext. Liquorix oferuje agresywniejsze ustawienia dla desktopu i gier.

Testy na procesorze Xeon E5-2660 v3 wykazały, że współdzielenie rdzenia przez dwa wątki SMT powoduje niewielkie spowolnienie (~13-18%) w zależności od charakteru instrukcji. Instrukcje zmiennoprzecinkowe (np. sqrt) i intensywne AVX2/FMA mają większy wpływ na współdzielenie zasobów SMT. Mikrobencze z 64-bitowym dzieleniem całkowitym (IDIV) i gęstym strumieniem AVX2/FMA wykazały wyraźne różnice wydajności między wykonywaniem na tym samym rdzeniu a na różnych rdzeniach, jednak testy muszą być przeprowadzane przy stałej, bazowej częstotliwości CPU (np. 2.6 GHz) z wyłączonym turbo i ustawionym governor=performance, aby uniknąć maskowania efektów przez throttling i skalowanie częstotliwości.

W zakresie kompilacji kodu zmiennoprzecinkowego na architekturze Haswell, GCC nie zamienia wywołań funkcji trygonometrycznych (cos, sin) na pojedyncze instrukcje CPU, gdyż x86 nie posiada natywnych instrukcji trygonometrycznych o odpowiedniej precyzji. Optymalizacje -O3/-Ofast z -ffast-math i wektoryzacja mogą przyspieszyć wywołania do bibliotek wektorowych (libmvec, SVML, SLEEF), ale wywołania pozostają funkcjami. Użycie opcji -march=haswell -Ofast -ffast-math -mfpmath=387 pozwala generować instrukcje FCOS zamiast wywołań bibliotecznych, co wpływa na wydajność.

Do wykrywania, czy dwa procesy wykonują się na tym samym rdzeniu, można użyć narzędzi systemowych (lscpu, sysfs) i skryptów wykorzystujących thread_siblings_list. Przypinanie zadań do rdzeni za pomocą taskset i affinity pozwala kontrolować rozkład obciążenia.

Podsumowując, Linux automatycznie i efektywnie rozkłada zadania na rdzenie i procesory, z uwzględnieniem topologii sprzętowej i lokalności pamięci, a dodatkowe narzędzia i ustawienia pozwalają na precyzyjne sterowanie obciążeniem i optymalizację wydajności, zwłaszcza w środowiskach wieloprocesorowych i wielowątkowych.
Podsumowanie AI na podstawie dyskusji. Może zawierać błędy.
REKLAMA