Afinitatea procesorului , sau afinitatea procesorului , sau afinitatea cache , este o tehnologie care asigură că un proces sau un fir de execuție este fixat și detașat de un anumit nucleu CPU, CPU sau set de procesoare, astfel încât procesul sau firul de execuție să ruleze numai pe nucleul specificat , procesor sau procesoare și nu pe niciun procesor dintr-un sistem multiprocesor. Afinitatea procesorului poate fi considerată ca o modificare a algoritmului central de programare a cozii de sarcini într-un sistem de operare multiprocesor. Fiecare articol din coada de sarcini are asociată o etichetă , care specifică procesoarele „înrudite”.
Când resursele sunt alocate, fiecare sarcină este de preferință distribuită pentru execuție pe unul dintre procesoarele „înrudite”. Afinitatea procesorului exploatează faptul că datele și setările unui proces care rula anterior pe un anumit procesor pot fi mai rapid disponibile pentru acel procesor decât pentru altul. Acest lucru se poate întâmpla, de exemplu, datorită stocării în cache a datelor de proces în memoria cache a procesorului, precum și în alte situații. Programarea unui astfel de proces pentru a rula pe același procesor îi îmbunătățește performanța prin reducerea evenimentelor care degradează performanța, cum ar fi pierderile de cache.
În plus, în unele sisteme, fiecare dintre procesoare poate avea acces mai rapid la o regiune de RAM care este aproape de aceasta. În același timp, se dovedește a fi rațional să păstrăm o legătură constantă a procesului cu procesorul, al cărui acces la RAM, unde se află datele acestui proces, este mai rapid.
Un exemplu practic de afinitate cu procesorul este rularea mai multor instanțe ale unei aplicații fără fire, cum ar fi unele software de randare grafică.
Implementarea algoritmului de programare a sarcinilor, care oferă posibilitatea legării la procesor, este implementată ținând cont de caracteristicile procesoarelor specifice și de construcția unui sistem multiprocesor, care va fi controlat de un astfel de algoritm. Unele implementări, în anumite circumstanțe, vor permite ca o sarcină să fie transferată la un alt procesor, depășind legarea. Acest lucru se face în acele cazuri când, din punctul de vedere al planificatorului, o astfel de comutare va duce la o creștere a eficienței executării sarcinilor. De exemplu, atunci când două sarcini care necesită mult procesor (A și B) sunt legate de același procesor și celălalt procesor nu este utilizat, mulți programatori vor comuta sarcina B la al doilea procesor pentru a profita la maximum de procesor disponibil pentru sistem. . Legarea sarcinii B la noul procesor la un astfel de moment va fi stabilită de planificatorul însuși.
Afinitatea procesorului poate reduce în mod eficient problemele legate de intrarea datelor în sistem și/sau în memoria cache a procesorului. Dar nu oferă o soluție la problemele de echilibrare a sarcinii [1] . Afinitatea CPU este mai complexă în sistemele cu o arhitectură eterogenă, necesitând o logică de planificare mai sofisticată decât în sistemele complet omogene. De exemplu, un sistem cu două CPU -uri dual-core , fiecare dintre ele acceptând tehnologia Hyper-Threading , prezintă o problemă pentru algoritmul de planificare, care presupune afinitatea CPU. Dacă sistemul are un număr și mai mare de procesoare și, de exemplu, nu este complet simetric în sine, atunci complexitatea problemei planificării eficiente a sarcinilor crește și mai mult.
Pentru exemplul de mai sus cu două procesoare dual-core hyper-threaded, planificatorul trebuie să implementeze un sistem de legare pe două niveluri. În ceea ce privește eficiența cache-ului, lucrul în același nucleu pe fire diferite este echivalent, iar planificatorul are dreptul de a muta liber o sarcină de la thread la thread. Nivelul de „proximitate” al diferitelor nuclee dintr-un procesor este mai scăzut, deoarece acestea împart parțial un cache al procesorului comun, nivelul de „proximitate” al diferitelor procesoare este și mai mic. Deoarece sunt partajate și alte resurse, afinitatea CPU singură nu poate fi folosită ca bază pentru programarea sarcinilor. De exemplu, dacă un proces a rulat recent pe un CPU virtual hiper-threading într-un nucleu și acel CPU virtual este ocupat în prezent, dar un al doilea CPU virtual din același nucleu este inactiv, afinitatea CPU bazată pe eficiența cache-ului implică faptul că procesul trebuie transferat la un al doilea procesor virtual (nu rulează) din același nucleu. Cu toate acestea, cele două procesoare virtuale concurează pentru aproape toate resursele de calcul, memoria cache și resursele de memorie. În această situație, de regulă, ar fi mai eficient să atribuiți procesul unui alt nucleu sau CPU, dacă printre ele există și inactiv. Acest lucru poate duce la o pierdere unică de performanță din cauza faptului că procesul relocat va trebui să umple din nou memoria cache cu datele sale. Dar performanța generală poate fi mai bună, deoarece cele două procese nu trebuie să concureze pentru resurse în cadrul aceluiași CPU.
Pentru a obține o eficiență maximă, planificatorul de sarcini trebuie să țină cont de toate aceste aspecte. Sistemele cu niveluri și mai mari de asimetrie ( NUMA , clustere etc.) necesită și mai multă complexitate din partea programatorului.
Pe Linux, afinitatea procesorului unui proces poate fi găsită sau setată folosind utilitarul taskset [2] . Din punct de vedere programatic, aceleași acțiuni pot fi efectuate folosind apelurile de sistem sched_getaffinity și sched_setaffinity [3] . Afinitatea firului de execuție poate fi setată sau modificată folosind una dintre funcțiile bibliotecii: pthread_setaffinity_np [4] sau pthread_attr_setaffinity_np [5] .
Pe sistemele SGI , un proces ar putea fi asociat cu un set de procesoare folosind utilitarul dplace [6] .
În DragonFly BSD 1.9 (2007) și mai târziu, apelul de sistem usched_set [7] [8] poate fi utilizat pentru a controla afinitatea CPU . În NetBSD 5.0, FreeBSD 7.2, DragonFly BSD 4.7 și mai târziu, apelurile de sistem pthread_setaffinity_np și pthread_getaffinity_np [9] pot fi utilizate . În NetBSD , utilitarul [10] psrset setează afinitatea unui fir de execuție la un anumit set de procesoare. FreeBSD folosește utilitarul cpuset [11] pentru a crea seturi de procesoare și a atribui procese acelor seturi. În DragonFly BSD 3.1 (2012) și mai târziu, utilitarul usched poate fi utilizat pentru a atribui procese unui set specific de procesoare [12] .
Pe Windows NT și versiuni ulterioare, afinitățile firelor și proceselor pot fi setate separat folosind apelurile API SetThreadAffinityMask [13] și SetProcessAffinityMask [14] sau prin interfața Task Manager (doar pentru procese).
macOS oferă un API de legare [15] care oferă indicii nucleului sistemului de operare despre cum să programați firele de execuție în funcție de seturile de legare.
Pe Solaris , puteți controla legarea proceselor și proceselor ușoare la procesor folosind utilitarul pbind [16] . Este de asemenea furnizat apelul de sistem procesor_bind [17] . Sunt disponibile și apeluri de interfață de nivel superior, și anume pset_bind [18] sau lgrp_affinity_get [19] , folosind conceptele de set de procesoare și respectiv grup de localități.
Pe AIX , puteți gestiona legările de proces utilizând utilitarul bindprocessor [20] [21] și apelul de sistem bindprocessor [20 ] [ 22 ] .
z/OS implementează poate cel mai sofisticat programator de sarcini utilizat astăzi. Oferă o redistribuire în schimbare dinamică a resurselor hardware între procese, inclusiv cele bazate pe legarea proceselor la nuclee individuale de procesor, procesoare și grupurile acestora [23]
Biblioteca standard pentru limbajul de programare paralel Julia include suport experimental pentru afinitatea proces-la-procesor [24] .