Entra

View Full Version : Opteron Dual Core: il lancio tra alcune settimane


Redazione di Hardware Upg
09-04-2005, 09:26
Link alla notizia: http://news.hwupgrade.it/14380.html

Si avvicina il debutto della prossima generazione di processori AMD Opteron, dotati di architettura Dual Core. A 2 anni esatti dal debutto delle prime cpu Opteron

Click sul link per visualizzare la notizia.

Crisidelm
09-04-2005, 09:30
Suppongo che quello a 851 dollari sia il 265, non il 275 :)

Sig. Stroboscopico
09-04-2005, 09:57
Sarebbe interessante sapere quante postazioni Opteron verranno upgradate col dual core... nel main stream non penso che si usi molto, ma sta diventando veramente un'ottima opportunità...

Ciao

Zerk
09-04-2005, 10:37
Mamma mia che prezzi! 5 Milioni per un processore.. se poi penso che ne verranno motati 8 in un singolo server.. e si raggiungono i 40 Milioni.. solo di processore.. cavolo sto male.

Dreadnought
09-04-2005, 10:49
Se pensi poi che un server di quelle dimensioni in genere costa 1/3 del suo contratto di assistenza per 3 anni puoi stare male ancora di più :D

Michelangelo_C
09-04-2005, 12:21
Originariamente inviato da Zerk
Mamma mia che prezzi! 5 Milioni per un processore.. se poi penso che ne verranno motati 8 in un singolo server.. e si raggiungono i 40 Milioni.. solo di processore.. cavolo sto male.
8 CPU opteron 875 2649*8=21192€!!:sofico: :eekk: :eekk: :eekk:
Porca miseria, non ho mai nemmeno pensato una cifra così alta solo per le CPU. A questo punto il prezzo dei restanti componenti, anche se di alta qualità (tipo HD SCSI in RAID o meglio SAS se non sbaglio) è del tutto trascurabile.:p :p

aLLaNoN81
09-04-2005, 12:41
non direi proprio se si parla di controller raid + hd scsi seri ;)

joe4th
09-04-2005, 14:13
Originariamente inviato da Michelangelo_C
8 CPU opteron 875 2649*8=21192€!!:sofico: :eekk: :eekk: :eekk:
Porca miseria, non ho mai nemmeno pensato una cifra così alta solo per le CPU. A questo punto il prezzo dei restanti componenti, anche se di alta qualità (tipo HD SCSI in RAID o meglio SAS se non sbaglio) è del tutto trascurabile.:p :p

Siamo sicuri che 8 processori fisici si possono mettere, per
un totale di 16CPU? L'architettura Opteron non era limitata a 8 CPU in totale?
Comunque secondo me il prezzo per l'875 e' sicuramente
eccessivo e si va molto vicini alla fascia di prezzo dell'Itanium2.

Una motherboard quadriprocessore tipo la Tyan 4882 o la Iwill
QK8S, dovrebbe costare sui 1500-1600E.

La IWill fa anche modelli 8-way, la QK8S-8P; mi chiedo
se supportera' 8 processori dual core (quindi 16CPU). Ma chissa quanto
costa. Tra l'altro se ho ben capito, nella QK8S-8P, le
8 vie vengono raggiunte prendendo una motherboard
4-way (ossia con i 4 processori sulla stessa piastra) e
aggiungendo altre quattro motherboard ciascuna
con 1 processore e memorie, connesse attraverso
un bridge HTX Pro.

E tra l'altro mi chiedo. Le configurazioni possibili sono
solo 2, 4, 8 (ed eventualmente 16), o sono anche possibili
configurazioni miste, tipo a 6(3) processori?

joe4th
09-04-2005, 14:38
Su un sito giapponese danno:

Opteron 165 @ 1.8Ghz
170 @ 2.0Ghz
175 @ 2.2Ghz
180 @ 2.4Ghz

Opteron 265 @ 1.8Ghz ($851)
270 @ 2.0Ghz
275 @ 2.2Ghz ($1299)
280 @ 2.4Ghz

Opteron 865 @ 1.8Ghz ($1514)
870 @ 2.0Ghz
875 @ 2.2Ghz ($2649)
880 @ 2.4Ghz

Visti i prezzi, secondo me sono ancora fuori!
Praticamente costa sempre meno comprare
due Opteron 244@1.8Ghz (costo 200-240$)
anziche' 1 Opteron 265 (costo $851). Mi sembra
che AMD e Intel stiano cominciando a fare
"cartello"...

Lucrezio
09-04-2005, 14:42
Ma avete idea di quanto costi un itanium?
:D

joe4th
09-04-2005, 14:59
Originariamente inviato da Lucrezio
Ma avete idea di quanto costi un itanium?
:D

Se non erro gli Itanium2 a 1.5Ghz con 6M di cache L3 sono
sui 6-7000$. Mentre quelli a 1.3Ghz con meno cache siamo
sui 2600$.

cionci
09-04-2005, 15:05
Originariamente inviato da joe4th
Visti i prezzi, secondo me sono ancora fuori!
Praticamente costa sempre meno comprare
due Opteron 244@1.8Ghz (costo 200-240$)
anziche' 1 Opteron 265 (costo $851). Mi sembra
che AMD e Intel stiano cominciando a fare
"cartello"...
Forse non hai contato la scheda madre... Il costo della scheda madre aumenta quasi esponenzialmente con il numero di socket...

Un Opteron 165 permette di creare un server dual processor con veramente pochi euro...
Pensa quanto fa risparmiare prendere due Opteron 265...

Inoltre i termini del tuo confronto sono sbagliati... Confronta il costo di due Opteron 265 + scheda madre con quello di quattro Opteron 844 + scheda madre...

joe4th
09-04-2005, 15:27
Originariamente inviato da cionci
Forse non hai contato la scheda madre... Il costo della scheda madre aumenta quasi esponenzialmente con il numero di socket...

Un Opteron 165 permette di creare un server dual processor con veramente pochi euro...
Pensa quanto fa risparmiare prendere due Opteron 265...


Il fatto e' che i processori Opteron di 1.8Ghz sono ampiamente
superati. Attulamente gli 1.8Ghz li hanno riesumati con il dual core, ma
chi va su Opteron raramente l'ho visto sotto il 246 (2Ghz).

Sulle dual * 275 hai ragione, siamo sui 2*1300+250/500 cioe' sui
3000E per una quadriprocessore (senza RAM e dischi).

Quanto alla scheda madre, resta ancora da capire
se quelle attuali Opteron rimarranno
compatibili. In fondo se andiamo a vedere modelli come
le Tyan 2875 e 2885 (queste due le ho con 2*246 e 2*250)
e 4882 sono di fine 2003. Fin'ora le uniche che ho letto di
compatibili con dual-core (dual Core di Athlon64/939
non Opteron/940) sono quelle su Nforce4.

cionci
09-04-2005, 15:38
Originariamente inviato da joe4th
Il fatto e' che i processori Opteron di 1.8Ghz sono ampiamente
superati. Attulamente gli 1.8Ghz li hanno riesumati con il dual core, ma
chi va su Opteron raramente l'ho visto sotto il 246 (2Ghz).
Ma certo...era per fare un confronto...

Sulla compatibilità bisogna ancora vedere....

Riguardo alla possibilità di montare fino a 16 core in 8 CPU... Il limite di CPU è dato dalle connessioni HyperTransport verso l'esterno... Rimanendo quindi il nuemro di connessioni HyperTransport uguale sarà possibile montare fino a 16 core senza alcun problema...

joe4th
09-04-2005, 16:04
Originariamente inviato da cionci
Ma certo...era per fare un confronto...

Sulla compatibilità bisogna ancora vedere....

Riguardo alla possibilità di montare fino a 16 core in 8 CPU... Il limite di CPU è dato dalle connessioni HyperTransport verso l'esterno... Rimanendo quindi il nuemro di connessioni HyperTransport uguale sarà possibile montare fino a 16 core senza alcun problema...

Tutto sommato credo che le configurazioni che costavano
un accidenti, come le 4 processori, adesso costano sempre un accidenti
ma sono 8 processori. Sulle 8-way che diventano
16, credo che si esca dagli standard
dell'assemblaggio che ti puoi fare tu o il rivenditore (per esempio che razza di case e alimentatori ci vogliono?)

Per esempio per un 4-way 848/850 con 8GB di RAM, credo ci
volessero almeno 10000Euro (1600+4*1500+300*8). Adesso con un cifra
molto simile, anziche' tentare l'8-way, conviene forse
prendere 2 macchine biprocessori con Opteron 275 e con 8GB di RAM ciascuno:
(500+2*1300+8*300): la motherboard viene enormemente
semplificata, passando da 16x13" (4 Socket 940) a 12x13" (2 Socket940),
come pure il case, e l'alimentatore (in tal caso basta un Enermax EG-851 da 660W
mentre per la Quadriprocessore, prob. non bastava).

joe4th
09-04-2005, 16:15
Originariamente inviato da cionci
Ma certo...era per fare un confronto...

Sulla compatibilità bisogna ancora vedere....


Ho scovato un'intervista a John Nguyen, PR di Tyan, del 27/1/2005:

http://www.linuxhardware.org/article.pl?sid=05/01/26/2240235&mode=thread

in cui dice:


Tyan) Dual core support on Tyan's Opteron platforms, is a feature we are very much looking forward to providing to all of our current and future customers. Unfortunately while its not possible at this time to directly comment on whether support will be implemented on the S2885, S2895 or other models from Tyan, customers should be pleased to know we are working to ensure compatibility on platforms going forward.

cionci
09-04-2005, 16:21
Originariamente inviato da joe4th
Sulle 8-way che diventano
16, credo che si esca dagli standard
dell'assemblaggio che ti puoi fare tu o il rivenditore (per esempio che razza di case e alimentatori ci vogliono?)

Chiaro...sicuramente non si trovano da assemblare... Si parla ovviamente di brand come IBM e HP...

xeal
10-04-2005, 01:48
Originariamente inviato da Cionci
Riguardo alla possibilità di montare fino a 16 core in 8 CPU... Il limite di CPU è dato dalle connessioni HyperTransport verso l'esterno... Rimanendo quindi il nuemro di connessioni HyperTransport uguale sarà possibile montare fino a 16 core senza alcun problema...

Lo credo anch'io.

In generale, penso che un eventuale calo di prestazioni dovuto alla condivisione del memory controller e delle linee HyperTransport, rispetto a una soluzione single core con un numero equivalente di cpu, potrebbe essere compensato dalle comunicazioni più veloci tra i core adiacenti. In tal senso potrebbe giovare uno scheduling oculato dei thread da parte dell'OS (a tal proposito mi viene in mente il problema di cui si parlava poco tempo fa relativamente agli OS MS (win xp 64?) e Hyper Threading su più cpu fisiche, dovuto a una "visione" indistinta di core logici e fisici (veniva allocato un nuovo processo sul primo core logico disponibile, anche sulla stessa cpu fisica): una impostazione del genere credo sia da evitare (ovviamente per motivi diversi: thread che condividono risorse dovrebbero essere destinati, per quanto possibile/conveniente, ai core di una stessa cpu, distinguendo appunto tra core e cpu fisiche)).

xeal
10-04-2005, 02:02
Originariamente inviato da joe4th
Comunque secondo me il prezzo per l'875 e' sicuramente
eccessivo e si va molto vicini alla fascia di prezzo dell'Itanium2.

Però l'875 (Dual @2.2Ghz) costa praticamente quanto un singolo Itanium2 a 1.3 Ghz, probabilmente se la gioca tranquillamente anche con applicazioni fpu intensive, il vero cavallo di battaglia di Itanium (anche se a questo punto il salasso arriverebbe con i costi delle licenze sw...).

BEMPINO
10-04-2005, 07:48
I prezzi sono Giusti e molto concorrenti AMD mette a segno un altro duro colpo per INTEL gli va ad intaccare la categoria server dove INTEL fa da padrona, complimenti per AMD

Per i prezzi, Considerate che a ogni processore del genere va associato dai 4 agli 8 Giga di ram register PER OGNI PROCESSORE.

Fx
10-04-2005, 09:53
Originariamente inviato da xeal
Però l'875 (Dual @2.2Ghz) costa praticamente quanto un singolo Itanium2 a 1.3 Ghz, probabilmente se la gioca tranquillamente anche con applicazioni fpu intensive, il vero cavallo di battaglia di Itanium (anche se a questo punto il salasso arriverebbe con i costi delle licenze sw...).

se vai sul sito della SPEC (www.spec.org) scoprirai che due opteron 248 hanno un fp_rate di oltre 32, due itanium 2 a 1.4 invece arrivano a circa 38: è lecito aspettarsi che un opteron dual core a 2.2 ghz performi molto meglio rispetto a un itanium 2 a 1.3 ghz anche sulla virgola mobile, oltre che sul resto.

personalmente penso che l'unica pecca che ha l'opteron è che non ci siano delle versioni con una cache l2 più generosa, anche se c'è da dire che con la quantità di banda che si ritrova a disposizione di sicuro è meno determinante che su processori come lo xeon, il quale ha un bus decisamente inadeguato (ed è un motivo per cui è meno scalabile dell'opteron)

mrt75
10-04-2005, 19:10
non vedo l'ora che escano anche gli altri :sofico:

xeal
10-04-2005, 22:52
Originariamente inviato da Fx
personalmente penso che l'unica pecca che ha l'opteron è che non ci siano delle versioni con una cache l2 più generosa, anche se c'è da dire che con la quantità di banda che si ritrova a disposizione di sicuro è meno determinante che su processori come lo xeon, il quale ha un bus decisamente inadeguato (ed è un motivo per cui è meno scalabile dell'opteron)

Considera che i K8 non sono particolarmente "sensibili" agli aumenti di cache, sia per la banda passante e le basse latenze di accesso alla memoria, sia perchè hanno le pipeline abbastanza corte, ragion per cui hanno un elevato valore di instruction per cycle e, se qualcosa va storto nella predizione di un salto, non devono buttare a mare (e sostituire con altro codice ricercato nella cache o in memoria) troppi dati ;). Certo, ci saranno sicuramente dei casi in cui una cache più ampia porterebbe qualche vantaggio in più (anche se farebbe crescere le latenze di ricerca), però è anche vero che chi produce cpu gioca sempre un po' al "risparmio" e cerca di non mettere cose che "non servono" (o che ragionevolmente si potrebbero non mettere). Non credo che la cache di un processore venga progettata mai come la più grande possibile, né in base al principio "meglio abbondare", ma piuttosto come la minima indispensabile per ottenere le prestazioni volute in un certo ambito, tanto, se serve, si può sempre "revisionare" il core aggiungendo quella che serve (entro i limiti di progettazione). Ricordo, ad esempio, che l'aumento della cache in Itanium, tempo fa, consentiva, tra l'altro, alle cpu meno veloci di recuperare qualcosa nel calcolo degli interi, che non è certo la "specialità della casa" per questa architettura, almeno stando alle dichiarazioni di Intel (che sembravano un po' esagarate per un semplice aumento di cache, ma questi sono altri discorsi).;)


X BEMPINO: credo che joe4th certi dettagli li conosca bene, da quel che ho capito lui con i server ci lavora (e li compra anche...) :D Più che altro, si facevano considerazioni sul prezzo in relazione al segmento di destinazione ;)

Bye :)

Fx
12-04-2005, 22:21
xeal: sono d'accordo. il punto è che se è vero che l'opteron è estremamente competitivo per il segmento workstation / server x86, lascia campo aperto agli itanium per il segmento superiore. imho, vedendo le performance di cui è capace, una versione con ampia dotazione di cache e arricchita delle feature che servono potrebbe esser capace di andare a infastidire parecchio sia gli itanium 2 che i power5 in quel segmento. in quel segmento i vantaggi di avere tanta cache sono molti e superano di molto gli svantaggi (che hai correttamente sottolineato).

xeal
13-04-2005, 00:49
x Fx: sul calcolo intero (basialare, ad esempio, per la gestione dei database) Opteron non sfigura in nessun segmento (e in questo campo Itanium non è certo un fulmine di guerra). C'è poca storia sul calcolo in virgola mobile, ma li una cache più grande cambierebbe ben poco: il fatto è che Itanium ha una fpu veramente mostruosa, c'è poco da dire (e da fare); l'unità in virgola mobile dei K8 è molto buona (e mi pare che abbia delle affinità con quelle dei risk), ma putroppo nel mondo degli x86 si è affermato il ricorso a unità supplementari (le unità SIMD: mmx, sse, 3dnow...) e difficilmente si avrà un'inversione di rotta (specialmente in tempi brevi), per cui per l'introduzione (in versioni future) di una fpu estremamente efficiente la vedo dura (a meno di creare una cpu server che non abbia nulla a che spartire con quelle destinate al settore desktop/workstation). Del resto, per come la vedo io, non è che Itanium è avvantaggiato rispetto a Opteron perchè ha una cache più grande, ma sarebbe (in misura variabile a seconda del contesto, ovviamente) svantaggiato se così non fosse (e in qualsiasi segmento), o comunque ha un quantitativo di cache che è il "minimo indispensabile" per avere buone prestazioni (in ogni scenario d'uso), così come l'opteron (non a caso i quantitativi più grandi, fino a 24 MB credo, sono previsti per gli Itanium multicore).

Naturalmente ci saranno degli scenari in cui una cache più grande gioverebbe, ma potrebbero essere pochi nel complesso (come nel caso del PM avvantaggiato dai suoi 2MB di L2 nel superPI con precisione fissata a "1 million" perchè l'applicazione e i suoi dati stanno tutti nella cache per la durata dell'esecuzione del test: si tratta di un caso, in generale la L2 in quel processore sopperisce alla limitata ampiezza di bus, e in ambito server una situazione del genere si verifica raramente): sicuramente i progettisti di AMD avranno fatto "quattro calcoli" per dimensionare la cache, e in ambito desktop, per avere un raffronto, nel passare da 512 KB a 1 MB, come dal single al dual channel, è difficile registrare distacchi abissale (laddove ce ne siano), proprio in virtù dell'ampia banda passante grazie all'integrazione del controller della memoria. Del resto, non sottovaluterei troppo l'aumento della latenza di ricerca con l'aumentare della dimensione della cache (essendo organizzata come un database molto efficiente, i dati vanno in qualche modo ricercati in essa, non vi si può accedere proprio "a colpo sicuro" ): se non ricordo male, Itanium impiega una ventina di cicli di clock per trovare i dati nella cache, mentre presumo che Opteron (non ricordo i valori), avendo una cache più piccola, necessiti di qualche ciclo in meno, e di conseguenza, a fronte di una banda verso la memoria notevole, molto vicina nei valori reali ai limiti teorici (e resa ancor più ampia dal NUMA, ove supportato), un aumento della cache e delle latenze di ricerca dei dati potrebbe non essere particolarmente vantaggioso (lo so, sto un po' cavillando, ma non conoscendo valori certi posso solo fare supposizioni, del resto, i progettisti dei K8 avranno fatto le dovute considerazioni e se pensassero di poter insidiare pesantemente itanium e gli altri risk-like in quel segmento semplicemente sovradimensionando la cache - che comunque ha dei limiti progettuali, non ricordo quali siano - credo che non ci penserebbero due volte ;) ).

Comunque, non conosco con esattezza gli scenari di calcolo di quel particolare settore, quindi mi baso solo su quel che conosco delle architetture di questi processori, fidandomi delle capacità dei progettisti, sia per quanto riguarda gli ingegneri di AMD, sia per quanto riguarda quelli di Intel-HP.

Ciao :)

Fx
13-04-2005, 01:42
un solo appunto: nei server di quella fascia una grossa quantità di cache ti serve non solo come pezza ai vari colli di bottiglia che comunque i processori intel tradizionalmente hanno ma anche e soprattutto per tenere "a portata di mano" le informazioni più usate, esattamente come per la cache di una cpu desktop; la differenza è che nei server di quella fascia vengono fatti girare numeri enormi di processi, che si "mangiano" ognuno una fettina di cache: una volta che l'hanno finita, per i restanti processi è come (circa :D ) se la cpu non avesse la cache. e se hai "finito" la cache, anche se l'opteron lavorare efficacemente con la ram comunque non è bello :D

cdimauro
13-04-2005, 13:27
In futuro potrebbero anche esserci processori Opteron con 4 o più core: non ci sarebbe alcun problema nell'usarli negli attuali sistemi a 1, 2, 4 o 8 "socket". Fisicamente, quindi, non ci sarebbe alcun problema: al più i processori si contenderebbero maggiormente la banda dell'unico memory controller e dei vari bus hyper transport disponibili.

Quanto al confronto con Itanium, come è stato sottolineato da xeal, gli Opteron sono decisamente meno sensibili al quantitivo di cache integrato rispetto a questi concorrenti: la cache potrebbe essere importante soltanto in particolari ambiti.
Infatti altre CPU per server sono dotate di notevoli quantità di cache proprio perché devono condividere il bus, e quindi la banda di memoria, fra di loro, mentre gli Opteron, essendo dotati ognuno di un proprio controller per la memoria, possono accedere in maniera esclusiva alla memoria localmente installata, con i vantaggi che si possono immaginare.
Per questo motivo la banda aggregata totale del sistema si ritrova moltiplicata per il numero di Opteron presenti, e infatti mentre le altre CPU incorrono in un degrado prestazionale consistente all'aumentare dei processori, gli Opteron presentano un degrado nettamente inferiore (anzi, le applicazioni SMP che sfruttano il NUMA possono funzionare anche meglio).
Quantità di cache maggiori potrebbero aver senso soltanto per sistemi dual o multicore, per gli stessi motivi per cui ne fanno ricorso le altre CPU, ma in generale gli attuali sistemi a n vie basati su Opteron partono col vantaggio di avere, appunto, ognuno n accessi "concorrenti" alla memoria.

Michelangelo_C
13-04-2005, 20:16
Non ho capito una cosa: ogni opteron ha un memory controller integrato nella CPU, quindi ogni processore può fare un accesso alla memoria a sè, indipendentemente dagli altri. Però questo mi sembra strano, perchè a quanto sopevo può essere effettuato un solo accesso per volta alla memoria, non è così?

xeal
13-04-2005, 22:45
Originariamente inviato da Fx
un solo appunto: nei server di quella fascia una grossa quantità di cache ti serve non solo come pezza ai vari colli di bottiglia che comunque i processori intel tradizionalmente hanno ma anche e soprattutto per tenere "a portata di mano" le informazioni più usate, esattamente come per la cache di una cpu desktop; la differenza è che nei server di quella fascia vengono fatti girare numeri enormi di processi, che si "mangiano" ognuno una fettina di cache: una volta che l'hanno finita, per i restanti processi è come (circa :D) se la cpu non avesse la cache. e se hai "finito" la cache, anche se l'opteron lavorare efficacemente con la ram comunque non è bello :D

E' un aspetto interessante, che però non ho voluto toccare in quanto non sono particolarmente "ferrato" sulla gestione della cache (credo che cdimauro possa dire qualcosa di più preciso in merito :)). Dipende tutto da come viene gestita: è probabile (o comunque possibile) che durante un context switch la cache venga svuotata (parzialmente o del tutto) per far posto alle informazioni necessarie al nuovo porcesso, e che quindi rimangano ben pochi dati a pronti all'uso per gli altri processi, a meno che non siano state appositamente bloccate alcune linee (se la banda verso la memoria è notevole, potrebbe risultare conveniente rispetto all'esecuzione di calcoli complessi per decidere come sistemare i dati nella cache e quali sostituire); comunque, ripeto, non ne so abbastanza sull'argomento, quindi rilancio la palla sperando che qualcuno possa chiarire meglio :D.

xeal
13-04-2005, 22:46
Originariamente inviato da cdimauro
In futuro potrebbero anche esserci processori Opteron con 4 o più core: non ci sarebbe alcun problema nell'usarli negli attuali sistemi a 1, 2, 4 o 8 "socket". Fisicamente, quindi, non ci sarebbe alcun problema: al più i processori si contenderebbero maggiormente la banda dell'unico memory controller e dei vari bus hyper transport disponibili.

Quindi potrebbe diventare sempre più utile "sistemare" in maniera conveniente gli algoritmi di scheduling della cpu (eventualmente modificando anche quelli interattivi) per tener conto dei "raggruppamenti" di core fisici al fine di limitare il possibile degrado prestazionale, sia cercando il più possibile di assegnare i thread "affini" allo stesso "gruppo" (ovvero alla stessa cpu fisica), sia tenendo conto, eventualmente, di "tendenze" a compiere IO-burst oppure cpu burst da parte dei processi, per fare in modo, ad esempio, che (forse si tratterebbe del caso più favorevole) due dei core presenti (la metà, in generale) si contendano il bus hyper transport e i rimanenti il bus verso la memoria. Naturalmente sempre che ciò non comporti un overhead eccessivo o comunque non renda gli algoritmi poco efficienti/precisi (un po' come succede, se non ricordo male, per le versioni adattate al time sharing, o comunque alla schedulazione a breve termine, dello shortest job first, buono invece per lo scheduling a medio termine, non troppo per quello a lungo termine). Magari poi risulta più conveniente lasciare le cose come stanno, specialmente in un cluster, dove le prestazioni complessive tendono a essere più influenzate dalle strutture di comunicazione tra le unità che si spartiscono il lavoro (per cui un sistema a 8 vie con cpu quad-core potrebbe anche avere prestazioni migliori rispetto a 4 sistemi analoghi con cpu single core), almeno credo...

xeal
13-04-2005, 22:46
Originariamente inviato da Michelangelo_C
Non ho capito una cosa: ogni opteron ha un memory controller integrato nella CPU, quindi ogni processore può fare un accesso alla memoria a sè, indipendentemente dagli altri. Però questo mi sembra strano, perchè a quanto sopevo può essere effettuato un solo accesso per volta alla memoria, non è così?

Per quanto ne so, in virtù del memory controller integrato gli Opteron possono gestire la memoria in maniera "proprietaria", ovvero puoi assegnare N GB di memoria a ogni processore, che gestisce solo quella come se non ci fossero né gli altri processori, né gli altri banchi (se poi un processore deve accedere alla memoria gestita da un altro interviene il bus hyper transport).

cdimauro
14-04-2005, 08:49
Non ho capito una cosa: ogni opteron ha un memory controller integrato nella CPU, quindi ogni processore può fare un accesso alla memoria a sè, indipendentemente dagli altri. Però questo mi sembra strano, perchè a quanto sopevo può essere effettuato un solo accesso per volta alla memoria, non è così?
Infatti è così: per Opteron intendo la CPU che integra i due core e l'unico memory controller.

cdimauro
14-04-2005, 08:57
E' un aspetto interessante, che però non ho voluto toccare in quanto non sono particolarmente "ferrato" sulla gestione della cache (credo che cdimauro possa dire qualcosa di più preciso in merito :)). Dipende tutto da come viene gestita: è probabile (o comunque possibile) che durante un context switch la cache venga svuotata (parzialmente o del tutto) per far posto alle informazioni necessarie al nuovo porcesso, e che quindi rimangano ben pochi dati a pronti all'uso per gli altri processi,
Infatti, è ciò che avviene normalmente.
a meno che non siano state appositamente bloccate alcune linee
In cache possono anche rimanere le linee di codice/dati relative a porzioni di memoria condivisa con altri processi / thread.
(se la banda verso la memoria è notevole, potrebbe risultare conveniente rispetto all'esecuzione di calcoli complessi per decidere come sistemare i dati nella cache e quali sostituire); comunque, ripeto, non ne so abbastanza sull'argomento, quindi rilancio la palla sperando che qualcuno possa chiarire meglio :D.
:) A mio avviso bloccare le linee di cache non è generalmente conveniente, perché:
- prima o poi un context switch si verificherebbe (e potrebbe anche essere in mezzo al pezzo di codice che ha bloccato quelle linee), e il nuovo processo / thread si troverebbe con parte della cache inutilizzabile, quindi incidendo negativamente sulle prestazioni;
- sarebbe necessario scrivere del codice in assembly per gestire le linee di cache;
- si legherebbe il codice a una particolare architettura / piattaforma.

La cosa migliore da fare è utilizzare delle tecniche di prefetching, rese disponibili ormai da tutte le implementazioni SIMD, per anticipare il caricamento dei dati necessari, in modo da renderli immediatamente disponibili al momento del bisogno, e per marcare alcuni dati in modo che non finiscano ad occupare inutilmente spazio nella cache (es: faccio un'operazione su certi dati, che poi sono sicuro di non usare più, e che quindi dovrebbero andare esclusivamente in memoria).

cionci
14-04-2005, 08:58
perchè a quanto sopevo può essere effettuato un solo accesso per volta alla memoria, non è così?
Il collegamento con la memoria è a doppio canale...quindi in teoria gli accessi contemporanei sono due...poi ogni CPU può accedere anche alla memoria delle altre CPU (in un sistema SMP), con una latenza maggiore, ma sempre con buone prestazioni...quindi considerando questo in teoria gli accessi contemporanei alla memoria possono essere anche di più... Inoltre metti che la presenza di 1152 Kb di cache L1+L2 fanno sì che raramente due task debbano accedere contemporaneamente alla memoria...

cdimauro
14-04-2005, 09:04
Quindi potrebbe diventare sempre più utile "sistemare" in maniera conveniente gli algoritmi di scheduling della cpu (eventualmente modificando anche quelli interattivi) per tener conto dei "raggruppamenti" di core fisici al fine di limitare il possibile degrado prestazionale, sia cercando il più possibile di assegnare i thread "affini" allo stesso "gruppo" (ovvero alla stessa cpu fisica), sia tenendo conto, eventualmente, di "tendenze" a compiere IO-burst oppure cpu burst da parte dei processi, per fare in modo, ad esempio, che (forse si tratterebbe del caso più favorevole) due dei core presenti (la metà, in generale) si contendano il bus hyper transport e i rimanenti il bus verso la memoria. Naturalmente sempre che ciò non comporti un overhead eccessivo o comunque non renda gli algoritmi poco efficienti/precisi (un po' come succede, se non ricordo male, per le versioni adattate al time sharing, o comunque alla schedulazione a breve termine, dello shortest job first, buono invece per lo scheduling a medio termine, non troppo per quello a lungo termine). Magari poi risulta più conveniente lasciare le cose come stanno, specialmente in un cluster, dove le prestazioni complessive tendono a essere più influenzate dalle strutture di comunicazione tra le unità che si spartiscono il lavoro (per cui un sistema a 8 vie con cpu quad-core potrebbe anche avere prestazioni migliori rispetto a 4 sistemi analoghi con cpu single core), almeno credo...
A mio avviso il problema della "sistemazione" dei processi/thread non dovrebbe essere delegato al s.o., ma all'applicazione, nel caso in cui questa abbia la possibilità di gestire più CPU per smistare loro il suo lavoro.

Questo perché chi ha scritto l'applicazione è la persona più indicata per stabilire, a seconda del sistema su cui gira (SMP "classico", SMP multi core, SMP multi core con HT, SMP multicore NUMA), in che modo da smistare il lavoro per trarne il maggior beneficio.

Invece un s.o. / scheduler ha una visione "statica", prestabilita da chi l'ha scritto, e le scelte che fa non sono valide e "ottimali" per tutti i casi.

Tutto questo IMHO, chiaramente... ;)

cdimauro
14-04-2005, 09:06
Il collegamento con la memoria è a doppio canale...quindi in teoria gli accessi contemporanei sono due...
Sì, ma non è possibile fare due accessi a locazioni di memorie diverse: la logica di indirizzamento della memoria è condivisa per entrambi i canali. ;)

cionci
14-04-2005, 09:07
Sì, ma non è possibile fare due accessi a locazioni di memorie diverse: la logica di indirizzamento della memoria è condivisa per entrambi i canali. ;)
Sicuro ? Quidni è possibile leggere 128 bit a partire da un dato indirizzo, ma non 64 bit da una aprte e 64 da un'altra ? Mi sembra strano...

cionci
14-04-2005, 09:12
Quindi il dual channel verrebbe utilizzato solo quando si spostano dati a 128 bit (SSE) o nelle letture in burst (solitamente da/verso le periferiche) ?

cdimauro
14-04-2005, 13:15
Sì, lo si usa per leggere il doppio dei dati, e quindi per riempire più velocemente la cache L2 (e quindi la L1). Non è necessario usare direttamente le SSE.

Purtroppo l'unica implementazione "parallela", che permetteva di avere accesso simultaneo a due diverse locazioni di memoria, mi sembra fosse quella dell'nForce (1 e/o 2?), se non ricordo male. Ed era anche la più costosa, ovviamente (richiedeva lo sdoppiamento di tutte le linee di controllo).

cionci
14-04-2005, 14:09
Sì, lo si usa per leggere il doppio dei dati, e quindi per riempire più velocemente la cache L2 (e quindi la L1).
In effetti non avevo pensato al fatto che anche la cache trasferisce a blocchi...quindi il doppio canale viene praticamente usato sempre ;)

Comunque di fatto è come avere due canali separati...perchè supponendo che entrambe le cache vogliano leggere + o - contemporaneamente un blocco la somma dei tempi dei trasferimenti di entrambi i blocchi è pari a quello che si avrebbe supponendo di assegnare un canale ad ogni cache.. Anzi...in questo modo una cache finisce prima... Quindi probabilmente l'implementazione più efficiente è questa...

xeal
14-04-2005, 22:54
Originariamente inviato da cdimauro
A mio avviso bloccare le linee di cache non è generalmente conveniente, perché:[...]

Infatti intendevo dire che può essere più conveniente "buttare a mare" anche tutto il contenuto della cache e ripristinarlo quando necessario, piuttosto che impelagarsi in algoritmi vari per ottimizzarne l'uso per tutti i processi (ammesso che sia possibile), aumentando l'overhead di context switch (ho posizionato male quella frase nel discorso :p)

A mio avviso il problema della "sistemazione" dei processi/thread non dovrebbe essere delegato al s.o., ma all'applicazione, nel caso in cui questa abbia la possibilità di gestire più CPU per smistare loro il suo lavoro.

Questo perché chi ha scritto l'applicazione è la persona più indicata per stabilire, a seconda del sistema su cui gira (SMP "classico", SMP multi core, SMP multi core con HT, SMP multicore NUMA), in che modo da smistare il lavoro per trarne il maggior beneficio.

Invece un s.o. / scheduler ha una visione "statica", prestabilita da chi l'ha scritto, e le scelte che fa non sono valide e "ottimali" per tutti i casi.

Tutto questo IMHO, chiaramente..

Da un certo punto di vista hai perfettamente ragione. Però temo che si rischierebbe di produrre dei conflitti con gli altri processi, ragion per cui lo scheduler è comunque necessario, e se avesse pochi poteri rispetto alle scelte operate a monte da chi ha sviluppato l'applicazione SMP si potrebbero verificare situazioni poco auspicabili, non so, magari un gruppo di thread si aspetta di essere eseguito su di un solo processore (con 4 core) ma per ragioni contingenti (per evitare starvation di altri processi) perde l'uso del suo core, e a motivo delle scelte fatte a monte dal programmatore (e dello spostamento del problema dallo scheduling alla gestione diretta da parte dell'applicazione) rimane in attesa invece di essere spostato su di un altro processore (anch'esso multicore), cosa che ne peggiorerebbe le prestazioni rispetto a quanto previsto dal progettista, ma sarebbe meglio dell'attendere inutilmente, tanto l'efficienza del raggruppamento sarebbe saltata comunque per motivi contingenti non previsti a priori. In questo senso, se è vero che lo sviluppatore ha una visione più "dinamica" (nel senso di più aderente alle caratteristiche e necessità effettive) della sua applicazione, è anche vero che non può conoscere a priori il contesto in cui il programma verrà eseguito, mentre lo scheduler del s.o., operando a runtime, ha una visione "statica" e generica di tutti i software in esecuzione, ma conosce meglio la dinamica contingente del sistema, ragion per cui, in un certo senso, forse, delegare il compito di smistare il lavoro alle varie cpu (e in genere la gestione delle risorse) alle singole applicazioni potrebbe essere un po' estrema, o comunque estremizzabile all'atto pratico, fino a renderla analoga a quella operata da itanium nei confronti dell'ordinamento delle istruzioni effettuato dal compilatore, il quale conosce a priori benissimo (e sicuramente meglio di qualunque unità per il riordino) le caratteristiche del codice che sta producendo, ma non ha idea di quale sia il contesto reale nel quale il codice verrà eseguito, rendendo di fatto preferibile, come tu stesso mi insegni, la logica out-of-order, specie se affiancata a un codice ben ordinato, da adeguare con poco sforzo al contesto (poi, magari, intendevi qualcosa di diverso e ho frainteso io :p).

Si potrebbe cercare una via di mezzo, ovvero creare un threading model che preveda (anche come opzionale) delle indicazioni, nella struttura dei thread, circa le caratteristiche da tenere in considerazione nella loro schedulazione, come la tendenza a compiere frequenti accessi in memoria, oppure frequenti operazioni di i/o o lunghe operazioni sui dati caricati mediante prefetching, fino ai raggruppamenti migliori per sfruttare al meglio un certo tipo di sistema (ed eventualmente alla possibilità di richiedere l'esecuzione forzata su un solo core/cpu fisica/logica per ottenere un software adattativo al sistema e al tipo di licenza scelta dall'utente, non ricordo se parlavi tu o qualcun altro di una soluzione del genere al problema delle licenze per il multi core); in questo modo lo scheduler avrebbe una cognizione migliore e dell'applicazine singola, e del contesto generale, potendo gestire in maniera ottimale (o comunque meglio ottimizzata) l'allocazione delle risorse (le cpu in particolare) ai vari processi/thread.

Imho, ovviamente :)

cionci
14-04-2005, 23:44
Su Windows e anche sugli ultimi Linux si può già assegnare un thread ad un determinato processore...e non solo...in XP a 64 bit ci sono sia le API per identificare i processori logici (HT) e che il supporto all'architettura NUMA per calcolarsi la composizione dei vari nodi...

cdimauro
15-04-2005, 10:11
In effetti non avevo pensato al fatto che anche la cache trasferisce a blocchi...quindi il doppio canale viene praticamente usato sempre ;)
Esatto: a prescindere da ciò che fa il processore... :)
Comunque di fatto è come avere due canali separati...perchè supponendo che entrambe le cache vogliano leggere + o - contemporaneamente un blocco la somma dei tempi dei trasferimenti di entrambi i blocchi è pari a quello che si avrebbe supponendo di assegnare un canale ad ogni cache.. Anzi...in questo modo una cache finisce prima... Quindi probabilmente l'implementazione più efficiente è questa...
Secondo me no: due canali completamente indipendenti al più posso lavorare esattamente come due canali "unificati", ma non è vero il contrario.

cdimauro
15-04-2005, 10:21
Infatti intendevo dire che può essere più conveniente "buttare a mare" anche tutto il contenuto della cache e ripristinarlo quando necessario, piuttosto che impelagarsi in algoritmi vari per ottimizzarne l'uso per tutti i processi (ammesso che sia possibile), aumentando l'overhead di context switch (ho posizionato male quella frase nel discorso :p)
Può anche essere che abbia capito male io... :)
Comunque adesso è chiaro, e sono perfettamente d'accordo. ;)
Da un certo punto di vista hai perfettamente ragione. Però temo che si rischierebbe di produrre dei conflitti con gli altri processi, ragion per cui lo scheduler è comunque necessario, e se avesse pochi poteri rispetto alle scelte operate a monte da chi ha sviluppato l'applicazione SMP si potrebbero verificare situazioni poco auspicabili, non so, magari un gruppo di thread si aspetta di essere eseguito su di un solo processore (con 4 core) ma per ragioni contingenti (per evitare starvation di altri processi) perde l'uso del suo core, e a motivo delle scelte fatte a monte dal programmatore (e dello spostamento del problema dallo scheduling alla gestione diretta da parte dell'applicazione) rimane in attesa invece di essere spostato su di un altro processore (anch'esso multicore), cosa che ne peggiorerebbe le prestazioni rispetto a quanto previsto dal progettista, ma sarebbe meglio dell'attendere inutilmente, tanto l'efficienza del raggruppamento sarebbe saltata comunque per motivi contingenti non previsti a priori.
Ma infatti questa è una cosa che non dovrebbe succedere nel modello di cui parlavo: se ho deciso di piazzare un thread nella CPU logica #3, deve rimanere lì. Se il s.o. s'intromette in questa scelta, è chiaro che non ha più senso nemmeno pensare di sprecare risorse per questo modello...
In questo senso, se è vero che lo sviluppatore ha una visione più "dinamica" (nel senso di più aderente alle caratteristiche e necessità effettive) della sua applicazione, è anche vero che non può conoscere a priori il contesto in cui il programma verrà eseguito, mentre lo scheduler del s.o., operando a runtime, ha una visione "statica" e generica di tutti i software in esecuzione, ma conosce meglio la dinamica contingente del sistema, ragion per cui, in un certo senso, forse, delegare il compito di smistare il lavoro alle varie cpu (e in genere la gestione delle risorse) alle singole applicazioni potrebbe essere un po' estrema, o comunque estremizzabile all'atto pratico, fino a renderla analoga a quella operata da itanium nei confronti dell'ordinamento delle istruzioni effettuato dal compilatore, il quale conosce a priori benissimo (e sicuramente meglio di qualunque unità per il riordino) le caratteristiche del codice che sta producendo, ma non ha idea di quale sia il contesto reale nel quale il codice verrà eseguito, rendendo di fatto preferibile, come tu stesso mi insegni, la logica out-of-order, specie se affiancata a un codice ben ordinato, da adeguare con poco sforzo al contesto (poi, magari, intendevi qualcosa di diverso e ho frainteso io :p).
Indubbiamente. Per questo motivo, se il s.o. è in grado di avere informazioni "dinamiche" utili all'attribuzione di un thread a un core piuttosto che a un altro, è bene che le renda disponibili come API alle applicazioni, per metterle quanto meno nelle stesse condizioni, e permettere di operare la scelta migliore, grazie alla "conoscenza intrinseca" che hanno del problema da risolvere... ;)
Si potrebbe cercare una via di mezzo, ovvero creare un threading model che preveda (anche come opzionale) delle indicazioni, nella struttura dei thread, circa le caratteristiche da tenere in considerazione nella loro schedulazione, come la tendenza a compiere frequenti accessi in memoria, oppure frequenti operazioni di i/o o lunghe operazioni sui dati caricati mediante prefetching, fino ai raggruppamenti migliori per sfruttare al meglio un certo tipo di sistema (ed eventualmente alla possibilità di richiedere l'esecuzione forzata su un solo core/cpu fisica/logica per ottenere un software adattativo al sistema e al tipo di licenza scelta dall'utente, non ricordo se parlavi tu o qualcun altro di una soluzione del genere al problema delle licenze per il multi core);
Ne parlavo io... ;)
in questo modo lo scheduler avrebbe una cognizione migliore e dell'applicazine singola, e del contesto generale, potendo gestire in maniera ottimale (o comunque meglio ottimizzata) l'allocazione delle risorse (le cpu in particolare) ai vari processi/thread.

Imho, ovviamente :)
Così sposteresti troppa complessità sullo scheduler, che verrebbe troppo penalizzato nel caso generico. Invece se è l'applicazione a gestire questa "complessità", perché lei e solo lei ha particolari esigenze, sarebbe meglio. Sempre IMHO. :)

cdimauro
15-04-2005, 10:22
Su Windows e anche sugli ultimi Linux si può già assegnare un thread ad un determinato processore...e non solo...in XP a 64 bit ci sono sia le API per identificare i processori logici (HT) e che il supporto all'architettura NUMA per calcolarsi la composizione dei vari nodi...
Ottimo. Non ero a conoscenza di questa caratteristica: grazie! :)

xeal
16-04-2005, 23:27
Originariamente inviato da cdimauro
Ma infatti questa è una cosa che non dovrebbe succedere nel modello di cui parlavo: se ho deciso di piazzare un thread nella CPU logica #3, deve rimanere lì. Se il s.o. s'intromette in questa scelta, è chiaro che non ha più senso nemmeno pensare di sprecare risorse per questo modello...

Temo però che lasciare i processi/thread completamente liberi di spartirsi le risorse possa dare luogo a conflitti difficilmente prevedibili prima dell'esecuzione: l'assegnazione di quel thread alla cpu logica #3 potrebbe essere la scelta migliore in condizioni "ideali" di massima autonomia e libertà d'azione, ma in un particolare contesto d'esecuzione potrebbero esserci, ad esempio, più thread (relativi a processi diversi) che abbiano scelto di usare la #3, perchè magari hanno bisogno di cooperare con i "fratelli" assegnati alle cpu logiche vicine, per cui devono spartirsi le stesse risorse di calcolo, mentre potrebbe essersi liberata nel frattempo la cpu logica x sul processore fisico y, o l'intero processore y, per cui potrebbe essere preferibile, in un dato istante, far migrare uno o più thread/processi su quel processore al fine di mantenere elevato il throughput di sistema. Quindi, più che dire "voglio lavorare su quel core" potrebbe essere interessante mettere il processo in condizioni di dire "voglio/non voglio lavorare vicino a questi altri thread", per ottimizzare il lavoro contemporaneo di un gruppo di thread su una data cpu multicore/multithreaded. Inoltre potrebbe essere necessario interrompere temporaneamente l'esecuzione di un thread/processo per consentire a un altro di lavorare, evitandone la starvation, su una data cpu/core, mentre gli alti previsti per una esecuzione contemporanea (e assegnati "manualmente" ad altre cpu) potrebbero continuare il loro lavoro senza interruzioni (in quel frangente), per cui la scelta aprioristica delle cpu cui assegnare i thread, senza intervento ulteriore del s.o., potrebbe non essere la migliore possibile, a meno di voler privilegiare una schedulazione a medio o lungo termine (ovvero tornare a una schedulazione a job, ma potrebbe non essere sempre la scelta più efficiente, specie per processi interattivi), oppure un modello di multitasking cooperativo, con richieste esplicite di sleep (et similia) da parte dei processi stessi per consentire agli altri di lavorare, senza possibilità di prelazione da parte del so, ma in questo modo temo che al più si avrebbe la scelta migliore del momento in cui sospendere l'esecuzione di un singolo processo, ma non dell'intero gruppo di processi (poichè un singolo thread/processo sa come gestire al meglio le sue operazioni, ma non come coordinarsi con processi di cui ignora l'esistenza o le caratteristiche), e inoltre potrebbero sorgere dei problemi: il processo potrebbe non richiedere affatto la sospensione (ci si affiderebbe alla buona volontà del programmatore) oppure andare in crash, "allooparsi", e in entrambi i casi un qualche intervento da parte del sistema operativo potrebbe rendersi comunque utile o necessario, se non inevitabile. Per questo pensavo di escogitare un modello intermedio, per dare ai processi l'opportunità di gestire le risorse disponibili nel modo più efficiente (studiato a priori) e al s.o. la possibilità di intervenire (alla meno peggio o alla "quasi meglio", a seconda del compromesso tra leggerezza dell'intervento ed efficienza scelto) laddove il contesto di esecuzione rendesse preferibile arrangiare diversamente l'assegnazione delle risorse.

Indubbiamente. Per questo motivo, se il s.o. è in grado di avere informazioni "dinamiche" utili all'attribuzione di un thread a un core piuttosto che a un altro, è bene che le renda disponibili come API alle applicazioni, per metterle quanto meno nelle stesse condizioni, e permettere di operare la scelta migliore, grazie alla "conoscenza intrinseca" che hanno del problema da risolvere.

Ma in questo modo non si sposta la complessità dello scheduler a ciascun processo? E non ci si affida alla "bontà" del codice eseguito? Cioè, ciascun processo dovrebbe passare una parte del tempo in esecuzione a decidere se è meglio restare nella coda di un certo core o spostarsi altrove e se conviene riordinare le code, secondo le proprie esigenze? Non c'è il rischio che i vari processi si incasinino gli uni con gli altri, sprecando tempo a cercare di creare una situazione generale che il processo successivo scombina appena può?

Io pensavo alla possibilità che fossero i thread a fornire al s.o. informazioni "dinamiche" sulla loro esecuzione, dicendo "su questo sistema, con queste risorse, prevedo di eseguire un tot di operazioni sui dati precaricati nella cache, un tot di accessi alla memoria e un tot di operazioni di input output, e preferirei lavorare con questi thread in esecuzione sullo stesso processore multicore e questi altri nella stessa coda di esecuzione", in modo che il sistema operativo cerchi di rispettare per quanto possibile la gestione prevista dall'applicazione, ripristinandola appena possibile, e avendo contemporaneamente a disposizione delle informazioni per calcolare il giusto "mix" di processi da allocare sulla stessa cpu multicore, presi anche da altre applicazioni.

Così sposteresti troppa complessità sullo scheduler, che verrebbe troppo penalizzato nel caso generico. Invece se è l'applicazione a gestire questa "complessità", perché lei e solo lei ha particolari esigenze, sarebbe meglio. Sempre IMHO.

Beh, si può sempre studiare il problema e cercare un compromesso soddisfacente. Se fosse troppo complicato, ci si potrebbe limitare ad assegnare le risorse ai processi secondo lo schema suggerito dai processi stessi finchè applicabile, per alterare tale schema quando indispensabile (anche nel modo più "classico" ) e quindi ripristinarlo appena possibile. Comunque pensavo ad un sistema che, in fin dei conti, potrebbe non essere troppo complesso. In genere il sistema operativo deve avere una qualche conoscenza delle caratteristiche del sistema per poterle gestire al meglio, per cui, parlando sempre di sistemi con più cpu e più core fisici e/o logici per ciascuna cpu, si potrebbe pensare di definire dei parametri per stabilire se un certo thread da assegnare a un core è compatibile con i thread assegnati al core vicino, pensando cioè (per certi versi) alla cpu multicore come se fosse formata da un unico macrocore e ai thread in esecuzione come facenti parte di un un macrothread, un unico blocco avente però una sua duttilità e fluidità, ovvero con i thread "interni" sostituibili con altri aventi caratteristiche simili (giudicate mediante i parametri di poc'anzi). I parametri potrebbero non essere altro che dei pesi attribuiti a determinate caratteristiche e calcolati dallo sviluppatore (eventualmente mediante profiling o comunque tool di sviluppo appositamente pensati) e comunicati al sistema operativo, mediante le sue api, al momento della creazione. A questo punto il sistema operativo potrebbe decidere o di assegnare le risorse nello stesso modo in cui vengono richieste dall'applicazione, oppure, se ciò non portasse a una buona distribuzione del carico di lavoro in relazione agli altri processi presenti, di alterare la distribuzione dei macrothread alle macrocpu o la composizione stessa dei macrothread (che diventerebbero eterogenei rispetto all'applicazione di appartenenza dei thread "interni" ) sommando i pesi di ciascun parametro con i pesi corrispondenti negli altri thread e calcolando, ad esempio, la media degli scarti rispetto al valore considerato ottimale per un dato parametro (ovvero sommo algebricamente tutti i pesi di un parametro - positivi - e il valore di riferimento - negativo - e faccio la media, eventualemnte azzerando i risultati negativi, su questo si può meditare), per determinare il gruppo di thread/processi da eseguire contemporaneamente su una certa cpu secondo un qualche algoritmo "first fit" (per limitare i calcoli): fissato il primo processo, si procede ad accostare gli altri via via (evitando permutazioni inutili) calcolando la media pesata dei parametri e scegliendo il gruppo che non supera il valore ideale oltre una certa soglia, o quello che supara la soglia per il valore più piccolo. Naturalmente questa dovrebbe essere la strategia generale dell'algoritmo, ma ai fatti, per quanto possibile, la meno frequente (nella forma più genereica che prevede la scelta di tutti i thread): la prima applicazione servita dal sistema operativo riceve le risorse così come le chiede, e così anche le successive, finchè non si ha uno sbilanciamento del carico su qualche cpu; a questo punto si procede allo spostamento di uno o più macrothread sulla cpu che lavora meno, finchè non diventa necessario intervenire all'interno dei macrothread (ad esempio perchè uno o più thread entrano in uno stato di wait e devono lasciare il posto ad altri (molto) prima che termini il time slice); quando questo accade, si sceglie il thread (o i thread) "migliore" per la sostituzione (o quello meno peggiore, il primo buono) tenendo conto delle caratteristiche di quelli ancora in esecuzione, tenendo conto anche di un termine che impedisca di scavalcare troppe volte uno stesso processo. Per quanto riguarda la visione del sistema per macrocpu e macrothread, li immagino come raggruppamenti logici, ovvero ciascun core continuerebbe ad avere una sua propria coda di processi da gestire (quasi) indipendentemente dalle altre, senza un impatto significativo sulla struttura dati usata (potrebbe continuare ad essere una lista, un vettore, una lista di vettori, o qualunque altra cosa già utilizzata; potrebbe essere utile comunque un qualche collegamento tra i "record" relativi ai processi di pari "profondità" nelle code, ma credo non sia strettamente necessario). Nel loro insieme le code relative a una stessa macrocpu potrebbero essere pensate come una sorta di matrice (con una o più righe incomplete) con p (numero di processi/thread in una coda) righe e c (numero di core logici/fisici della macrocpu, ovvero dimensione del macrothread logico) colonne: a intervalli prefissati (più lunghi di un normale time slice) alcuni macrothread potrebbero venire integralmente spostati su altre macrocpu (ed eventualmente essere spezzati o aggregati per adeguarsi a un diverso numero di core, ovvero una diversa dimensione della matrice dei processi, quindi riordinati) per bilanciare il carico. Al naturale scadere di un time slice contemporaneo per tutti i core di una macrocpu si avrebbe un normale context switch parallelo, per cui non verrebbe in alcun modo alterata la composizione già decisa dei macrothread (nessun overhead in questo caso); qualora uno dei thread in esecuzione non potesse proseguire (attende un'operazione di I/O o lo sblocco di un semaforo sui dati di cui necessita) si procederebbe alla sua sostituzione con uno prelevato dalla stessa coda, si determinerebbe (o potrebbe determinarsi, a seconda delle scelte) un'asincronia nei context switch, e in questo caso si dovrebbe scegliere il/i thread sostituto/i ad ogni context switch, ma si potrebbe ovviare con una regola di maggioranza, presupponendo che l'asincronia sia causata dalla minoranza dei thread interni al macrothread (i pesi dovrebbero essere ponderati per ottenere una situazione del genere o una sospensione "prematura" praticamente contemporanea di tutti i thread - se ne potrebbe tenere conto e sostituirli uno ad uno con quelli del macrothread successivo): la maggior parte dei thread porterebbe a termine il proprio quanto contemporaneamente e verrebbe sostituito in blocco, mentre i (pochi) thread, causa dell'asincronia, richiederebbero la ricerca di un sostituto (l'overhead nel context switch interesserebbe pochi core alla volta, non influendo troppo sulle prestazioni del sistema, e trattandosi di un numero limitato di thread da sostituire è probabile che verrebbero scelti tra quelli immediatamente successivi, ripristinando, pur con uno "sfasamento", il macrothread - alla lunga però l'overhead rischierebbe di interessare tutti i core della macrocpu, ma trattandosi di poche somme su dati già noti potrebbe avere un costo tuttosommato basso; inoltre, il termine di un time slice potrebbe implicare l'invio di un "segnale" - messaggio o interrupt vero e proprio - agli altri core, in modo che la ricerca, eventualmente in corso, di un sostituto (o, se conveniente, anche un context switch non completo) si interrompa se il totale dei core in fase di switch è sufficiente da giustificare la sostituzione immediata con i processi successivi nelle code; si può pensare anche ad un'attesa di pochi(ssimi) millisecondi per tentare di risincronizzare i macrothred (o una parte cospicua dei thread interni)). Si potrebbe anche pensare di schedulare, a intervalli più lunghi, per non incidere pesantemente sul throughput di sistema, un riordino globale dei thread nei macrothread della "matrice" associata a una macrocpu, stavolta effettuando spostamenti tra le colonne (le code dei core) e non più solo tra le righe in una stessa colonna, anche con un algoritmo di tipo best fit, o, meglio, bilanciando i risultati. Questo riordino "globale" si potrebbe fare in modo parziale, a blocchi, eventualmente si potrebbero sfruttare gli stati di idle di qualche core (eventualmente provocati da una diversa lunghezza nelle code dei processi all'interno della stessa macrocpu, partendo da un "livellamento" delle code e fermandosi al termine dei quanti negli altri core, per mantenere la sincronia), oppure (ma non necessariamente in alternativa, si potrebbero fare entrambe le cose), sospendendo temporaneamente l'attività della macrocpu per effettuare il riordino globale (credo che l'algoritmo di ricerca dei mix migliori bilanciati, ovvero omogenei, sempre sulla base della media pesata dei parametri, o operazioni semplici similari, si possa parallelizzare senza troppe difficoltà ), ad intervalli se necessario ancora più lunghi, per pochi istanti, facendo ripartire in maniera sincrona il "cronometraggio" dell'esecuzione (risincronizzando temporalmente l'esecuzione dei thread interni al macrothread). Infine, per far si che nel corso dei vari riordini questo algoritmo di scheduling tenda "spontaneamente" a ricostituire l'ordine d'esecuzione dei thread scelto da una certa applicazione, si potrebbe tener conto, tra i parametri, dell'appartenenza o meno dei thread a uno stesso programma e della "predilezione" degli stessi a lavorare in parallelo e sulla stessa macrocpu; per questo potrebbe bastare tener traccia in ciascun thread dell'id di uno degli altri thread facenti parte del gruppo originario - ad esempio il primo conosce l'id del secondo, il secondo quello del terzo... - e pesare in modo opportuno la presenza dei thread "richiesti" nel macrothread che si sta creando (sempre però con scelta di tipo first fit, per non appesantire i calcoli, salvo nei riordini globali).

Credo che un algoritmo del genere, ben implementato, potrebbe essere più semplice e meno oneroso di quanto io non sia riuscito a descrivere :p. Tutto, ancora, IMHO (di questo passo questa sarà la discussione con più imho di tutti i tempi :D)

cdimauro
18-04-2005, 10:54
ARGH! Ma dove lo trovi il tempo per scrivere questi mallopponi? :D

Le considerazioni sono ottime, non c'è che dire, ma a mio avviso bisogna puntare l'attenzione sullo scheduler, che è l'elemento su cui alla fine ruota tutta la discussione.

Questo "programma" del s.o. è molto delicato, viene richiamato parecchie volte al secondo (100 volte al secondo su molti s.o.), per cui dev'essere eseguito quanto più velocemente possibile. Infatti sullo scheduler e gli algoritmi di selezione / assegnazione dei task da eseguire c'è parecchia letteratura, ma la tendenza dal punto di vista implementativo è sempre quella perdere il minor tempo possibile; Linux, se non ricordo male, ha motivo di vanto nel suo algoritmo di scheduling che impiega un tempo "costante" (O(1)) per la selezione del task da eseguire.

Un algoritmo che permetta di bilanciare il carico del sistema in base all'attuale situazione in cui versa E alle caratteristiche intrinseche del software sarebbe decisamente troppo pesante, IMHO. Inoltre l'impiego di matrici per memorizzare lo stato e la "relazione" fra i vari thread non è dispendioso in termini di memoria occupata (qualche MB, al più: poca roba rispetto alla quantità di memoria presente anche in PC abbastanza vecchi), ma lo è sicuramente per le operazioni che riguardano questa struttura (inserimento, cancellazione, "spostamento" / aggiornamento dei dati, ecc.).

Per questo motivo pensavo che sarebbe meglio delegare all'applicazione e non allo scheduler il compito di smistare i thread in base al carico attuale del sistema e alle esigenze intrinseche della stessa. Se ci pensiamo bene, il fatto che un programma abbia particolari esigenze rispetto a tutti gli altri, è proprio affar suo: normalmente le politiche di gestione di task vanno più che bene, e finora lo hanno dimostrato.

E' chiaro che la situazione ideale / migliore in assoluto non esiste. Come programmatori quello su cui puntiamo prevalentemente l'attenzione è il caso medio, senza ovviamente trascurare il caso peggiore e il caso migliore: peggiorare il caso medio per migliorare il caso peggiore può andare bene se oggettivamente l'applicazione da far girare è "vitale", ossia quella che deve in assoluto girare meglio anche a spesa di tutte le altre, ma ciò non è sempre vero, anzi.

Chiaramente il tutto sempre IMHO... ;)

cionci
18-04-2005, 11:24
Io pensavo alla possibilità che fossero i thread a fornire al s.o. informazioni "dinamiche" sulla loro esecuzione, dicendo "su questo sistema, con queste risorse, prevedo di eseguire un tot di operazioni sui dati precaricati nella cache, un tot di accessi alla memoria e un tot di operazioni di input output, e preferirei lavorare con questi thread in esecuzione sullo stesso processore multicore e questi altri nella stessa coda di esecuzione", in modo che il sistema operativo cerchi di rispettare per quanto possibile la gestione prevista dall'applicazione, ripristinandola appena possibile, e avendo contemporaneamente a disposizione delle informazioni per calcolare il giusto "mix" di processi da allocare sulla stessa cpu multicore, presi anche da altre applicazioni
Come avevo scritto addietro...questo è già possibile... Ci sono API che permettono di selezionare il processore di default di un processo...oppure si da allo scheduler la possibilità di scegliere fra un pool di processi...

xeal
19-04-2005, 00:59
Originariamente inviato da cdimauro
ARGH! Ma dove lo trovi il tempo per scrivere questi mallopponi? :D

Ehm, io già mi sento in colpa perchè non riesco a concentrarmi abbastanza su quello che dovrei fare, adesso non mettertici pure tu! :D Diciamo che la questione mi ha appassionato... :fiufiu:

Questo "programma" del s.o. è molto delicato, viene richiamato parecchie volte al secondo (100 volte al secondo su molti s.o.), per cui dev'essere eseguito quanto più velocemente possibile.

Cioè ogni 10 ms? Credevo meno spesso... Suppongo che gli scheduler attuali impieghino circa 1 ms o meno per effettuare il context switch, onde evitare un degrado delle prestazioni (devo confessare che sull'argomento non so tantissimo, specie sulle implementazioni, se non che un time slice troppo breve rispetto al tempo di intervento dello scheduler peggiora le prestazioni, mentre uno troppo lungo darebbe risultati simili a FCFS, quindi sarebbe poco produttivo, e che un "costo" del 10% rispetto al tempo concesso alle applicazioni dovrebbe essere accettabile).

Un algoritmo che permetta di bilanciare il carico del sistema in base all'attuale situazione in cui versa E alle caratteristiche intrinseche del software sarebbe decisamente troppo pesante, IMHO.

Beh, la mia era solo un'idea: mica ho scritto l'algoritmo e ne ho calcolato la complessità computazionale! :p

Comunque forse non sono riuscito a esprimere bene quello che avevo in mente (mi stupirei del contrario, visto che mentre scrivevo cercavo di chiarirmi le idee :D), che potrebbe essere più semplice di quanto abbia scritto :D Provo a chiarirlo un po' meglio (sperando di non ripetermi), tanto per confrontarci ancora un po' sull'argomento che, come dicevo, mi ha un po' intrigato. Innanzi tutto, le caratteristiche intrinseche del software il sistema operativo dovrebbe conoscerle e non conoscerle: le conosce perchè il software le comunica appena entra in esecuzione o quando crea un nuovo thread/sottoprocesso (quindi sono dati precalcolati da chi scrive l'applicazione, dei parametri in più da fornire al so passandoli alla funzione "crea_tread"), non le conosce più approfonditamente di così perchè non fa nessun calcolo per valutarle (questa parte della complessità verrebbe "scaricata" sul programmatore, oppure su un linguaggio/ide pensato appositamente per agevolare la suddivisione del lavoro in parallelo fra thread che sfruttano al meglio un dato sistema - ovviamente la parallelizzazione degli algoritmi la fa il programmatore, i tool di sviluppo interverrebbero sull'eseguibile, come un compilatore che produce sezioni diverse per sistemi diversi, ma questi sono altri discorsi, sto divangando :D).

Per non complicare troppo il lavoro dello scheduler pensavo a dei parametri interi da sommare e mediare (una media "pesata" degli scarti: sommo tutti i valori di un parametro in tutti i thread che raggruppo e sottraggo il valore "ideale", ripeto per gli altri e calcolo la media confrontandola con un altro valore "ideale", sempre precalcolato per un dato sistema/cpu multicore), trattandosi di somme (in alternativa si potrebbe pensare a qualche operazione logica su maschere di bit) non dovrebbero richiedere un tempo troppo grande (la divisione finale si potrebbe sostituire con uno shift - i risultati finali dovrebbero sempre essere positivi - scegliendo un numero pari di parametri), soprattutto considerando il tempo poi necessario per caricare i dati nella cache (ove necessario, per dei thread magari c'è meno lavoro da fare in questo senso).

La complessità dovrebbe riguardare quindi più il numero di thread da esaminare e le combinazioni da valutare, ma a questo si può ovviare (credo) in qualche modo: innanzitutto, presumo che l'applicazione crei i thread e soprattutto i gruppi di thread con parametri ben bilanciati (inizialmente non ne modifico né composizione, né la destinazione, se non strettamente necessario per bilanciare il carico tra le varie cpu; tutt'al più si potrebbe valutare, progettando l'algoritmo, se non valga la pena di riordinare il gruppo destinato a una cpu multicore per far sì che i thread per i quali si prevede la possibilità che sospendano il lavoro "prima del tempo" finiscano nelle stesse code, ma non credo sia strettamente necessario farlo): se il gruppo (che chiamavo macrothread) è ben bilanciato mi aspetto che pochi thread, tra quelli destinati ai core di una stessa cpu (macrocpu), restino in attesa per un'operazione di input/output o per un semaforo sui dati, gli altri completerebbero il quanto contemporaneamente e verrebbero sostituiti (essendo la maggioranza) direttamente dai successori (un nuovo gruppo ben bilanciato: mi serve trovare il sostituto solo dell'unico/dei pochi thread che hanno "smesso" di lavorare prima degli altri; mi sorge un dubbio: in genere che si fa in questi casi? ciascun core/cpu ha un proprio timer per i processi? e per cpu multicore? e per core logici? l'esecuzione attualmente diventerebbe "asincrona" o si sostituirebbe il processo in stato di attesa in modo da risincronizzarsi con gli altri time slice paralleli? comunque sia, per il momento suppongo che si continui in maniera asincrona).

Supponiamo che l'esecuzione diventi asincrona (cioè risultino non contemporanei gli interventi dello scheduler sulle varie code) per un solo core (alla volta): il problema di trovare il raggruppamento migliore si ridurrebbe (considerando la "disottimizzazione" rispetto al calcolo su tutto il gruppo trascurabile, essendo gli altri thread ben accoppiati) a cercare il miglior sostituto nel gruppo ancora in esecuzione (ovvero il primo che si avvicina al valore ideale -> first fit), e la ricerca si potrebbe condurre su un numero limitato di processi successivi (considerando la lista come circolare), diciamo 4-5 (indicativamente, si dovrebbe valutare il numero in maniera opportuna, progettando l'algoritmo), sia per ridurre i calcoli, sia per evitare starvation - a tal fine i processi in coda avrebbero, tra i parametri caratterizzanti, un numero incrementato e decrementato opportunamente ogni volta che venissero "promossi" (scavalcando gli altri) o "retrocessi" (scavalcati a loro volta): quando si raggiunge il numero massimo previsto il processo non può più essere scavalcato, se non ce n'è uno migliore prima tocca a lui - si potrebbe anche valutare l'opportunità di spendere qualche nanosecondo per verificare quanto tempo manca al termine del time slice "generale" (sempre che, a lungo andare, ne rimanga uno), per decidere se cercare il sostituto nel gruppo attuale (manca molto tempo -> il processo sostituto lavorerà per la maggior parte del suo quanto insieme al gruppo in esecuzione), oppure richiamare direttamente il thread/processo successivo (quasi non c'è asincronia, per cui lavorerà quasi per tutto il quanto insieme ai suoi "fratelli" predestinati); è possibile che si finisca comunque per scegliere il processo successivo, dipenderebbe dalla soglia scelta per considerare accettabile la media degli scarti dalla combinazione migliore e da quanto ben bilanciato era, nel complesso, il gruppo in cui si è verificata l'asincronia.

In questo modo, se i processi che determinano l'asincronia si trovano tutti nella stessa coda (o nelle stesse code), il degrado dovuto alla scelta del successore migliore (che potrebbe anche essere trascurabile) riguarderebbe solo uno/pochi core, e risulterebbe poco rilevante per il sistema nel suo complesso; diversamente, a lungo andare si potrebbe generare un'asincronia generale, per cui l'algoritmo di ricerca del successore sarebbe applicato in ogni context switch, ma, anche in questo caso, potrebbe risultare poco oneroso ed essere eseguito senza troppe preoccupazioni, oppure si potrebbe pensare di risincronizzare tutto in qualche modo, ad esempio sospendendo l'esecuzione dei processi (o semplicemente lasciando che terminino il proprio quanto senza sostituirli per alcuni istanti) e approfittando dell'interruzione per riordinare tutte le code cercando i raggruppamenti migliori (ma si potrebbe decidere di non "sprecare" tempo né per i riordini, né per risincronizzare l'esecuzione dei gruppi, o di effettuare il riordino in altro modo). Questo calcolo sarebbe sicuramente oneroso, ma, nel caso in cui lo si ritenesse utile/necessario (considero il riordino globale un punto la cui opportunità si può sicuramente sindacare, come tutto il resto, naturalmente) potrebbe essere schedulato a intervalli sufficientemente lunghi da non incidere troppo: ad esempio (sparo dei numeri a caso) se per riordinare tutto (parlo della singola cpu multicore) occorresse 1 secondo e il riordino venisse operato ogni 10 secondi, inciderebbe per 1 ms in più ad ogni intervento dello scheduler (nell'ipotesi di 100 interventi al secondo), anzi, ancora meno, in proporzione al numero di core presenti sulla cpu oggetto del riordino (a meno che le altre non restino inoperose nel frattempo, cosa probabile o necessaria, temo); la durata del riordino (quindi il suo peso) risulterebbe minore se poi l'algoritmo adottato (per determinare le combinazioni possibili e calcolare il grado di bilanciamento - con la media di prima - per ciascun raggruppamento) risultasse parallelizzabile e/o venisse eseguito sfruttando qualche stato di idle dei core (ma si potrebbe decidere di non riordinare affatto le intere code).


Inoltre l'impiego di matrici per memorizzare lo stato e la "relazione" fra i vari thread non è dispendioso in termini di memoria occupata (qualche MB, al più: poca roba rispetto alla quantità di memoria presente anche in PC abbastanza vecchi), ma lo è sicuramente per le operazioni che riguardano questa struttura (inserimento, cancellazione, "spostamento" / aggiornamento dei dati, ecc.).

Qui ho combinato un po' di casino io nel malloppone di prima, parlando di matrici e di spostamento di processi tra righe e colonne :p

In realtà pensavo ad una visione logica, virtuale delle code (implementate mediante liste o qualunque cosa si ritenesse opportuna - qui mi viene in mente ai discorsi che faceva fek tempo fa sull'opportunità di usare dei vettori per velocizzare un eventuale riordino dei processi; in ogni caso, non mi pongo il problema di scegliere una certa struttura dati, e soprattutto non voglio modificare le scelte attuali, mi basta partire da una visione logica "a matrice"), al fine di bilanciare opportunamente (in modo in fondo del tutto simile a quanto fatto oggi, credo) il carico di lavoro tra i core di una stessa cpu e le migrazioni da una (macro)cpu all'altra: considero le code di processi di una cpu multicore come le colonne di una matrice, cercando di mantenerle per quanto possibile della stessa "lunghezza", se possibile pari alla lunghezza delle code sugli altri processori (multicore o single core), per far sì che tutti i core lavorino. Mi spiego meglio (anche perchè così sembra che io stia scoprendo l'uovo di Colombo... e in parte è così :D): sulla mia cpu multicore (diciamo, quad-core) ho un certo numero di thread (uguale) per ciascun core (così che le code, nel loro insieme, possano essere immaginate come una matrice); a un certo punto devo creare un nuovo task con due soli thread e li accodo alle prime due code (o nelle code richieste; c'è poco da fare); subito dopo arriva la richiesta per altri due thread, che richiedono entrambi (o uno di essi) di finire in una della coda degli altri due, ma invece di "accontentarli" li raggruppo insieme, in modo da ricostruire la struttura "a matrice", ovvero, con ogni nuovo (gruppo) thread "spaiato" che arriva riempio i buchi e bilancio il carico (potrei anche spezzare un gruppo completo e bilanciato, onde spostare sempre i buchi in coda, nell'ultima riga della matrice virtuale); a questo punto, appena arriva un gruppo di thread di dimensione "idonea", tento un riordino (limitato agli ultimi gruppi) per bilanciare il lavoro in base ai parametri d'esecuzione dichiarati; poichè uso una logica "first fit", appena ottengo un risultato soddisfaciente mi fermo. Analogamente, se devo bilanciare la ripartizione del carico su più cpu (multicore o non) nel sistema (supponendo di avere nel sistema cpu con un diverso numero di core), sposterò un numero congruo di thread, cioè, all'atto pratico, sposterò dalla cpu di partenza una intera riga della sua matrice virtuale dei processi (o più di una, a seconda delle esigenze), ma non dei processi di uno stesso gruppo (se lascio un gruppo incompleto potrei sprecare del tempo per un inutile intervento dello scheduler, ritrovandomi comunque con dei core privi di carico); le righe (macrothread) spostate verrebbero spezzate o accorpate, a seconda del numero di core presenti sulla cpu di destinazione, e in tal caso si effettuerebbe un riordino dei processi in base alle caratteristiche d'esecuzione (sempre mediante la media pesata di prima).

Sostanzialmente, ad ogni suo intervento lo scheduler "ragionerebbe" per gruppi di esecuzione parallela, in "orizzontale", oltre che in "verticale" per gestire ciascuna coda, pur cercando di non impiegare troppo tempo per farlo.

Per questo motivo pensavo che sarebbe meglio delegare all'applicazione e non allo scheduler il compito di smistare i thread in base al carico attuale del sistema e alle esigenze intrinseche della stessa. Se ci pensiamo bene, il fatto che un programma abbia particolari esigenze rispetto a tutti gli altri, è proprio affar suo: normalmente le politiche di gestione di task vanno più che bene, e finora lo hanno dimostrato

Capisco il tuo punto di vista e le ragioni di fondo del tuo ragionamento, però non riesco a togliermi dalla testa il sospetto che i processi rischierebbero di rompersi le uova nel paniere a vicenda (magari mi sbaglio :wtf: ). Comunque, in maggior lavoro necessario per gestire lo smistamento dei thread verrebbe si sgravato allo scheduler, ma comunque effettuato dall'applicazione (che vedrebbe comunque ridursi il tempo a sua disposizione per l'esecuzione), anche se è probabile che solo poche applicazioni sceglierebbero di farlo e solo in particolari circostanze, per cui il costo complessivo sarebbe minore rispetto a un costante overhead di lavoro per lo scheduler, credo che tu intenda questo.

[quoe]E' chiaro che la situazione ideale / migliore in assoluto non esiste. Come programmatori quello su cui puntiamo prevalentemente l'attenzione è il caso medio, senza ovviamente trascurare il caso peggiore e il caso migliore: peggiorare il caso medio per migliorare il caso peggiore può andare bene se oggettivamente l'applicazione da far girare è "vitale", ossia quella che deve in assoluto girare meglio anche a spesa di tutte le altre, ma ciò non è sempre vero, anzi.[/quote]

Vero, però se con qualche microsecondo in più di calcoli dello scheduler ad ogni intervento si riuscisse in qualche modo a ottimizzare lo sfruttamento di una cpu multicore non sarebbe male. Poi, ripeto, la mia era solo un'idea, magari interessante e da valutare, magari no.

Ecco: ho scritto un altro malloppone, non sono riuscito a contenerlo... Comunque mi sembra che manchi qualcosa...
Ah, già: IMHO :)
(ma non erano vietati dal regolamento i vari imo, condo, erzo... :p)

xeal
19-04-2005, 01:16
Originariamente inviato da cionci
Come avevo scritto addietro...questo è già possibile... Ci sono API che permettono di selezionare il processore di default di un processo...oppure si da allo scheduler la possibilità di scegliere fra un pool di processi...

Ma il pool di processi riguarda una singola coda (ovvero un certo core) oppure può riguardare tutti i core? Come dicevo prima, questo tipo di operazione è "orizzontale" o "verticale"? Io pensavo a una qualche modifica delle strategie attuali in senso "orizzontale", tenendo conto, cioè, dell'esecuzione contemporanea di più thread, in modo da bilanciare il carico sulle cpu multicore, visto che, stando ai progetti attuali, sembrano destinate a sostituire le single core, ovvero il multicore sembra dover diventare la "struttura" base di una cpu fisica, per cui mi domandavo se non fosse possibile studiare un'algoritmo di scheduling che, ad esempio, eviti che troppi thread/processi eseguiti contemporaneamente si contendano le stesse risorse a disposizione della singola (macro)cpu, come un eventuale MCH integrato. Poi, può darsi che qualcosa del genere si faccia già... e in tal caso, evita di rispondermi: "è già possibile", tanto non ammetterò mai di aver scoperto l'acqua calda :p :sofico: a costo di fare sfacciatamente del :mc: :asd:

Scherzi a parte, se sto scoprendo l'acqua calda ditemelo, così evito di spremermi le meningi... :p

Bye.

cionci
19-04-2005, 08:07
Intendevo "pool di processori" per un dato thread...
Guarda l'API SetThreadAffinityMask (mi sembra)...

Come ti dicevo...questa strategia (anzi, qualsiasi strategia) è già applicabile dal lato utente in Win XP 64 e Win Server 2003... E' già possibile identificare la composizione georafica della struttura NUMA...e di conseguenza sapere quali core stanno sulla stessa CPU...

Se questi SO usano particolari strategie di scheduling non lo so...ma suppongo che mettendo a disposizione quelle API il kernel stesso si crei una struttura statica che contiene lo schema fisico... Per verificare non resta che fare delle prove ;)

cdimauro
20-04-2005, 13:34
Come avevo già scritto, anche cercando di limitare al minimo il numero di thread da esaminare, si perderebbe comunque troppo tempo: impossibile pensare anche soltanto di avvicinarsi a un O(1) dello scheduler di Linux, ad esempio.

Peggio ancora pensando di utilizzare un qualche algoritmo di ordinamento (a meno di non fare delle assunzioni e utilizzare altri algoritmo di ordinamento non basati sulla selezione, ma che comunque richiedono un tempo lineare per essere eseguiti).

Utilizzare delle liste anziché delle matrici comporterebbe non pochi problemi (attualmente Linux utilizza un vettore per memorizzare gli ID dei processi, di dimensione fissa), e aumenterebbe il tempo di esecuzione nel caso si volesse utilizzare un algoritmo di ordinamento.

Quanto al timer, nel sistema ce n'è soltanto uno che viene usato per segnalare il context-switch, e viene assegnato / usato da un solo processore, che fa da "master"...

A mio avviso l'idea di spostare la complessità dell'algoritmo dallo scheduler all'applicazione "particolare" consente di risolvere il problema, non pesando assolutamente sullo scheduler, e quindi su tutto il sistema: è una cosa non da poco.
Basti pensare al numero di processi / thread che girano su un sistema moderno: sono davvero tanti, e praticamente nessuno ha esigenze particolari. Se lo scheduler dovesse pensare a risolvere il problema del bilanciamento, per quanto bene fosse implementato l'algoritmo, "peserebbe" comunque su tutti i processi / thread, anche quando non sarebbe assolutamente necessario (che il caso più frequente).

xeal
22-04-2005, 03:18
x cionci: si, la funzione è quella, ho dato un'occhiata sul sito msdn :). Sostanzialmente si scelgono i processori sui quali si desidera eseguire un certo thread, in maniera vincolante, però è sconsigliato farlo perchè potrebbe peggiorare le prestazioni del sistema (impedendo allo scheduler di spostare il thread su un altro processore per bilanciare il carico), a meno che non serva per sfruttare l'architettura NUMA: in tal caso potrebbe servire o ad assegnare i thread che condividono risorse su uno stesso nodo o a distribuirli su più nodi.

Oltre a pool di processori si possono creare pool di thread, ma non ho ben capito a cosa serva: sembrerebbe simile alla strategia master-worker o ad agenda (o meglio, la base per tali architetture) o forse serve a notificare più rapidamente (mediante dei thread che fanno da monitor) la possibilità di uscire dallo stato di wait a dei thread che si contendono delle risorse, un po' come succede chiamando notifyAll() in Java, ma non ho capito bene (anche perchè non ho approfondito le api per la sincronizzazione)...

Credo comunque che potrebbe essere interessante avere qualche "grado di libertà" in più potendo indicare quali e quanti thread si vorrebbero far eseguire in parallelo (ragionando, come dicevo, in "orizzontale") senza doverli vincolare a un certo processore (per non "interferire" con il bilanciamento del carico fatto dal processore, poi, magari, le api ci sono e non le ho notate io :p; pensandoci, forse un risultato parzialmente simile si può ottenere con SetThreadIdealProcessor, ma sarebbe comunque diverso). Sarebbe interessante poter specificare (in maniera vincolante) quanti thread al massimo si vogliono far eseguire in parallelo, ovvero quanti processori si vogliono far usare al massimo da un'applicazione, per ottenere un comportamento diverso in base al tipo di licenza a prescindere dal numero max di cpu presenti sul sistema (l'idea di Cesare) senza vincolarne l'esecuzione su cpu specifiche (laddove non necessario).

x cidimauro: come già detto, era solo un'idea, che mi sembra sempre meno fattibile, perchè a prescindere dal tempo d'esecuzione dello scheduler, sarebbe un caso limite l'avere a disposizione il "giusto" numero di thread con certe caratteristiche (non troppi che accedono spesso in memoria, non troppi che eseguono I/O, non troppi che devono sospendere l'esecuzione prima del context switch successivo...) da assegnare a un certo processore multicore. Comunque, speravo che effettuare qualche somma e una divisione, da ripetere al più un numero limitato di volte (e fisso, non variabile con il numero totale di thread) non comportasse un overhead significativo. Per l'ordinamento, pensavo di ottenere un risultato accettabile spalmando il tempo d'esecuzione su un numero sufficientemente grande di context switch (ovvero, eseguendolo una volta ogni n context switch). Non butterei via la possibilità di spostare i thread a blocchi, ovvero poter decidere quali evitare (se possibile) di schedulare sullo stesso processore, senza doverli vincolare a cpu specifiche, se non strettamente necessario.

Utilizzare delle liste anziché delle matrici comporterebbe non pochi problemi (attualmente Linux utilizza un vettore per memorizzare gli ID dei processi, di dimensione fissa), e aumenterebbe il tempo di esecuzione nel caso si volesse utilizzare un algoritmo di ordinamento.

Sei sicuro che Linux usi un vettore? Ricordavo che in una discussione (mi pare si parlasse dei pro e dei contro dell'uso del C o del C++ per scrivere un kernel, ma eravamo fortemente OT) si era detto (ilsensine? mi pare che inizialmente discutesse lui con fek della cosa) che linux usasse delle liste per ciascun processore, con interventi "programmati" per spostare un processo da una coda all'altra, riuscendo comunque a garantire ai processi accesso alle risorse in un tempo O(1). Forse però ricordo male... Comunque intendevo che, ai fini dell'algoritmo che pensavo, la struttura dati effettiva sarebbe stata secondaria, da non modificare rispetto alle scelte già fatte, volevo solo mettere in evidenza un modo di vedere i thread per "gruppi di esecuzione parallela", che poi sia fattibile o meno è un'altro discorso :p.

Quanto al timer, nel sistema ce n'è soltanto uno che viene usato per segnalare il context-switch, e viene assegnato / usato da un solo processore, che fa da "master"...

Thank you very much :) In tal caso, se un processo sospende l'esecuzione prima del termine del time slice come si procede? Come si coordina tutto?

A mio avviso l'idea di spostare la complessità dell'algoritmo dallo scheduler all'applicazione "particolare" consente di risolvere il problema, non pesando assolutamente sullo scheduler, e quindi su tutto il sistema: è una cosa non da poco.
Basti pensare al numero di processi / thread che girano su un sistema moderno: sono davvero tanti, e praticamente nessuno ha esigenze particolari. Se lo scheduler dovesse pensare a risolvere il problema del bilanciamento, per quanto bene fosse implementato l'algoritmo, "peserebbe" comunque su tutti i processi / thread, anche quando non sarebbe assolutamente necessario (che il caso più frequente).

Avevo intuito che intendevi questo. Per le api che ho visto, forse qualcosa del genere in Windows si può fare con i fiber, anche se in tal caso lo scheduling sarebbe totalmente a carico dell'applicazione e comunque la libertà d'azione limitata all'esecuzione del thread che li genera, senza possibilità di scegliere i processori. Forse, utilizzandoli con un thread genitore con un'elevata priorità si otterrebbe qualcosa di simile a quello che intendi, sempre che convenga farlo in questo modo, oltretutto mi pare di aver capito che non siano particolarmente consigliati, salvo fare il porting di qualche applicazione pensata per gestire autonomamente i propri thread.

Ciao :)

cdimauro
22-04-2005, 09:36
come già detto, era solo un'idea, che mi sembra sempre meno fattibile, perchè a prescindere dal tempo d'esecuzione dello scheduler, sarebbe un caso limite l'avere a disposizione il "giusto" numero di thread con certe caratteristiche (non troppi che accedono spesso in memoria, non troppi che eseguono I/O, non troppi che devono sospendere l'esecuzione prima del context switch successivo...) da assegnare a un certo processore multicore.
Infatti il problema della scheduling in generale è NP-Completo, se la memoria non m'inganna: funzionano bene soluzioni semplici e ben collaudate, ma all'aumentare delle variabili da tenere in considerazione la complessità aumenta inesorabilmente...
Comunque, speravo che effettuare qualche somma e una divisione, da ripetere al più un numero limitato di volte (e fisso, non variabile con il numero totale di thread) non comportasse un overhead significativo.
Qualche somma e divisione non sono un problema, se effettivamente sono limitate in numero e non dipendono dalla quantità di thread: in questo caso rientrebbero come costante nel calcolo della complessità dell'algoritmo di scheduling.
Per l'ordinamento, pensavo di ottenere un risultato accettabile spalmando il tempo d'esecuzione su un numero sufficientemente grande di context switch (ovvero, eseguendolo una volta ogni n context switch).
Sarebbe comunque troppo lento: O(n log2 n) è troppo. Infatti la situazione sarebbe la seguente:
1) farlo ogni n context switch comporterebbe un tempo di calcolo (ammortizzato) comunque troppo elevato (O(log2(n)));
2) farlo ogni n log2 n context switch comporterebbe un tempo di calcolo (ammortizzato) interessante (O(1)).

Per fare un esempio, supponendo di avere n = 1000 processi & thread e che il context switch avvenga 100 volte al secondo, l'operazione verrebbe effettuata:
1) ogni 10 secondi circa (ma al prezzo di O(10) per ogni context switch);
2) ogni 100 secondi circa (al prezzo di O(1) per ogni context switch).

Nel primo caso, l'aggiornamento ogni 10 secondi potrebbe essere un buon compromesso, ma il prezzo da pagare sarebbe abbastanza salato in termini computazionali.
Nel secondo caso computazionalmente saremmo davanti al caso migliore, ma in 100 secondi le condizioni del sistema potrebbero essere cambiate troppe (anche in 10 secondi, ma "reagirebbe" più velocemente).
Non butterei via la possibilità di spostare i thread a blocchi, ovvero poter decidere quali evitare (se possibile) di schedulare sullo stesso processore, senza doverli vincolare a cpu specifiche, se non strettamente necessario.
E' sicuramente interessante. Bisognerebbe valutare quanto inciderebbe sullo scheduler.
Sei sicuro che Linux usi un vettore? Ricordavo che in una discussione (mi pare si parlasse dei pro e dei contro dell'uso del C o del C++ per scrivere un kernel, ma eravamo fortemente OT) si era detto (ilsensine? mi pare che inizialmente discutesse lui con fek della cosa) che linux usasse delle liste per ciascun processore, con interventi "programmati" per spostare un processo da una coda all'altra, riuscendo comunque a garantire ai processi accesso alle risorse in un tempo O(1). Forse però ricordo male...
Il thread era lo stesso, ma abbiamo dei ricordi diametralmente opposti. :D Vediamo se interviene ilsensine a chiarire la questione... :)
Comunque intendevo che, ai fini dell'algoritmo che pensavo, la struttura dati effettiva sarebbe stata secondaria, da non modificare rispetto alle scelte già fatte, volevo solo mettere in evidenza un modo di vedere i thread per "gruppi di esecuzione parallela", che poi sia fattibile o meno è un'altro discorso :p.
OK, è chiaro.
Thank you very much :) In tal caso, se un processo sospende l'esecuzione prima del termine del time slice come si procede? Come si coordina tutto?
Come sempre: il context switch avviene indifferentemente a causa dell'interrupt del timer o della chiamata di API che provoca la sospensione del processo.

xeal
25-04-2005, 22:11
Originariamente inviato da cdimauro
Infatti il problema della scheduling in generale è NP-Completo, se la memoria non m'inganna: funzionano bene soluzioni semplici e ben collaudate, ma all'aumentare delle variabili da tenere in considerazione la complessità aumenta inesorabilmente...

Già. Per questo pensavo ad una qualche analisi fatta a priori per determinare dei parametri "statici" da utilizzare in un certo sistema, o meglio, la presupponevo, dandola praticamente per scontato, per potermi focalizzare sulla "visione d'insieme" dei thread per blocchi che ne potrebbe derivare.

In pratica pensavo di stabilire a priori per un certo processore multicore quante richieste di accesso alla memoria "contemporanee" si potrebbero gestire per non ridurre troppo la banda verso la ram, quante operazioni di i/o, ecc. in relazione al tipo di bus (con o senza memory controller integrato, con o senza hyper transport), al tipo di comunicazione interna tra i core e alla presenza o meno di feature come hyper threading in ogni processore, per poter individuare un certo numero di parametri (non troppi) di cui tener conto e da misurare su una certa scala (la più piccola possibile) di valori interi (ad esempio: da 0 a X per il numero di accessi in memoria previsti su dati non presenti in cache, da 0 a X per determinare la tendenza a lavorare sui dati precaricati nella cache, da 0 a X per quantificare la necessità di fare più o meno spesso operazioni di I/O, dei parametri per determinare se i processi hanno necessità di comunicare mentre sono in esecuzione contemporanea o se devono contendere delle risorse per cui è meglio eseguirli sequenzialmente...): fatto questo, "basterebbe" (lo so, la "faccio facile" :D) determinare il valore ideale per la somma dei parametri di uno stesso tipo, in modo da poterli sommare sottraendo il valore ideale e poi calcolare la media degli scarti tra tutti i parametri e confrontarla con un valore di "soglia" precalcolato, anch'esso "ideale".

In questo modo si potrebbe rendere possibile una visione dei thread per gruppi da eseguire in parallelo (mi sono un po' fissato con il termine macrothread :p) e semplificare la ricerca di un sostituto in un gruppo (i valori dei parametri li dovrebbe determinare l'applicazione, non lo scheduler, il quale si limiterebbe a sommare, mediare - possibilmente con uno shift a sinistra - e accettare o scartare il thread). Però rimarrebbe il problema di fondo: quanto spesso nella realtà si presenterebbero applicazioni che producono thread ben raggruppati/raggruppabili, ovvero, fino a che punto sarebbe possibile affiancare a thread che fanno spesso I/O altri che fanno pochi accessi alla memoria e altri che ne fanno molti nel giusto numero, e questo non ad opera dello scheduler, ma già dell'applicazione e dello sviluppatore che sceglie gli algoritmi per risolvere un certo problema...

Qualche somma e divisione non sono un problema, se effettivamente sono limitate in numero e non dipendono dalla quantità di thread: in questo caso rientrebbero come costante nel calcolo della complessità dell'algoritmo di scheduling.

Pensavo alle somme di prima da ripetere un numero finito di volte, onde evitare problemi di starvtion: fissato il numero k dei thread da "esaminare" (calcolando la media pesata di cui parlavo prima, sui valori noti dei parametri), se tra i primi k - 1 non c'è un risultato migliore del k-esimo e il k-esimo non è un buon sostituto (la media degli "scarti" supera la soglia ideale), non si procede oltre nella ricerca e si sceglie proprio il k-esimo (in altri termini, un processo/thread non dovrebbe essere scavlacato più di k volte, con k << n, n numero dei thread in coda, salvo ovviamente ci siano pochi processi/thread in esecuzione - essendo k una costante). In realtà il calcolo dovrebbe essere fatto su una combinazione di thread, dipendente dal numero di thread da sostituire (<= c, numero dei core per processore), comunque in numero (massimo) finito e non dipendente dal numero totale dei thread (in ciascuna coda o in quella più lunga); le combinazioni possibili (da valutare) sarebbero poi limitate nel numero lasciando i thread nella propria coda (ovvero, se devo sostituire due thread valuterò le accoppiate che posso formare prendendo un thread da ciascuna delle code in cui si trovavano i thread non più pronti per l'esecuzione, non prenderò mai entrambi dalla stessa coda). Inoltre, mi aspetterei che il sistema dei parametri sia tale da far sì che in un "buon" raggruppamento (inizialmente i raggruppamenti verrebbero scelti dall'applicazione che li genera e lasciati invariati finchè non ve ne sia la necessità - cioè fino a quando alcuni thread del gruppo sospendano l'esecuzione oppure alcuni gruppi debbano essere spezzati o accorpati) sia "calibrato" (dall'applicazione, quindi dal programmatore) in modo tale che pochi thread, all'interno del gruppo, non siano in grado di portare a termine il time slice (i sostituti, se i parametri da valutare sono scelti, nella definizione di questo algoritmo, fossero accurati in tal senso, tenderebbero generalmente a ripristinare questa caratteristica). Naturalmente sempre che ciò abbia un senso...

Sarebbe comunque troppo lento[...]

E allora semplicemente rinunciamo al riordino, oppure facciamo delle assunzioni per renderlo più veloce, effettuandolo (eventualmente) in maniera parziale. Ad esempio, tenendo conto tra i parametri di scelta (i soliti da sommare, ecc., oppure inserendo un parametro da valutare a parte, o da far rientrare nella media solita assegnandogli un valore di volta in volta) di un id "di gruppo" (che determini l'appartenenza di un thread ad un certo gruppo, così come è stato generato da un'applicazione), ed eventualmente del numero di thread presenti nel gruppo, ci si potrebbe limitare a ripristinare i raggruppamenti originari (eventualmente senza scavalcare troppi thread), eseguendo al più un algoritmo di ordinamento "classico" su un numero (più o meno relativamente) piccolo di thread (eventualmente fissato, in modo da ridurre la complessità ) in presenza di raggruppamenti misti (con thread appartenenti a processi diversi). Sempre, ovviamente, che ne valga la pena.

Il thread era lo stesso, ma abbiamo dei ricordi diametralmente opposti. :D Vediamo se interviene ilsensine a chiarire la questione... :)

Sono riuscito a ripescare la discussione (news.hwupgrade.it/13336,1-120.html) :) :

ilsensine ha scritto:
Linux non ordina in base al tempo di cpu occupato, ma in base a fattori di priorità dinamici. Usa una struttura a liste circolari collegate (orrore? :D) per accorpare i processi con simile priorità. La struttura è alquanto complicata (soprattutto in ambiente smp, dove esistono varie runqueue per i diversi processori, e dove bisogna decidere "quando/se/perché spostare un task da una runqueue all'altra"), ma garantisce un accesso O(1) al nuovo task da mandare in esecuzione.

Ma torniamo al nostro discorso:

Come sempre: il context switch avviene indifferentemente a causa dell'interrupt del timer o della chiamata di API che provoca la sospensione del processo.

Il tempo non sfruttato dal processo/thread che entra in attesa viene recuperato in qualche modo (ovvero assegnato a un altro fino al successivo context switch "naturale" ) oppure la cpu entra in stato di idle (a questo punto, sospetto che avvenga proprio questo)?

In ogni caso, si potrebbe valutare la possibilità di far rientrare il processo, una volta tornato pronto per l'esecuzione, esattamente nel punto da cui era uscito dalla coda, ovvero fargli perdere, una volta terminata l'attesa, un "turno" intero, nel trattare i thread per gruppi d'esecuzione parallela potrebbe avere senso al fine di sfruttare i vantaggi che lo sviluppatore dell'applicazione di cui il thread fa parte avesse individuato nel far eseguire contemporaneamente proprio quei thread (sempre che gli altri non abbiano nel frattempo portato a termine la propria esecuzione); si potrebbe anche dare all'applicazione facoltà di scegliere se e per quali gruppi di thread seguire questa politica e per quali un'altra. Naturalmente bisognerebbe valutarne bene l'opportunità (non ho riflettuto su tutte le possibili implicazioni/conseguenze/controindicazioni, è solo un'idea che butto giù così ). Nell'ipotesi di implementare l'algoritmo di scheduling con il quale ho rotto finora (:p), ciò potrebbe rendere superfluo, almeno in parte, il riordino dei thread (nella versione "ridota" di prima).

Ciao :)

cdimauro
26-04-2005, 10:48
Nonostante tutti i casi che hai prospettato, trovo che ci siano sempre troppe variabili da tenere in considerazione per determinare il miglior bilanciamento dei thread per le varie CPU disponibili. Per me più variabili -> aumento della complessità della "scelta", con tutte le conseguenze che ciò si porta dietro per un compito delicato qual è lo scheduling. :)

Il tempo non sfruttato viene semplicemente assegnato a un altro thread, fino al verificarsi della successiva condizione che porti a un context switch.
Non credo che sia semplice né gestibile il fatto di far rientrare il processo/thread esattamente nella stessa posizione della coda da cui era stato rimosso: le condizioni cambiano troppo velocemente e ciò richiederebbe l'aggiunta di ulteriori controlli che complicherebbero (nuovamente! :D) l'operazione di scheduling... :p

xeal
28-04-2005, 22:13
Originariamente inviato da cdimauro
Nonostante tutti i casi che hai prospettato, trovo che ci siano sempre troppe variabili da tenere in considerazione per determinare il miglior bilanciamento dei thread per le varie CPU disponibili.

Può darsi, in fondo era un'idea buttata giù così. Speravo di poter "appioppare" in parte il lavoro di scelta del bilanciamento delle variabili agli sviluppatori e del sistema operativo (scelta delle variabili, della scala e dei valori ideali), e dell'applicazione (assegnazione di un valore a ciascuna variabile), in modo che lo scheduler si limitasse a sommare e confrontare dei valori già noti. Potrebbe comunque rivelarsi una soluzione inefficiente sia per il "peso" dei calcoli, sia per la staticità della valutazione delle variabili...

Non credo che sia semplice né gestibile il fatto di far rientrare il processo/thread esattamente nella stessa posizione della coda da cui era stato rimosso: le condizioni cambiano troppo velocemente e ciò richiederebbe l'aggiunta di ulteriori controlli che complicherebbero (nuovamente! :D) l'operazione di scheduling... :p

Una mezza idea ce l'avrei, ma temo che l'implementazione sarebbe lenta, avendo come obiettivo operazioni di scheduling in un tempo O(1) (ad occhio e croce direi che il reinserimento potrebbe costare O(N) nel caso peggiore, con molti thread "adiacenti" in stato di wait; poi, bisognerebbe vedere in che modo ciascun os gestisce il passaggio da wait a ready - verifica affidata al thread in questione, che eventualmente esegue un tentativo di accesso alla sezione critica, eventualmente a intervalli prefissati; notifica da parte del thread che ha bloccato le risorse agli altri che le contendono; interrupt, specie per le operazioni di I/O - e confesso di avere qualche lacuna in merito, ma dovresti essertene già accorto :p).

Bye.

cdimauro
29-04-2005, 08:31
:) Generalmente alla fine di un'operazione di I/O la periferica in questione lancia un interrupt, però è una cosa che non può fare un thread nei confronti degli altri.