Newsgroup: it.comp.lang.c++
Titolo: Misura dello Stack...

Vi spiego il contesto :
- Applicazione "server" con codice a 32-Bit (C/C++) x Windows Server
2003/2008 32/64 Bit.
- Utilizzo di MultiThread massiccio su un singolo processo (N.Thread >
2000).
- Uso intensivo di Memoria (3 GBytes di spazio virtuale con
l'attivazione dello switch /3GB).
Il problema odierno dei 32-Bit in contesti di questo tipo è
sicuramente la scalabilità.
Nonostante si abbiano a disposizione macchine con diversi GBytes di
RAM risulta problematico utilizzarli in modo completo ed efficace
senza stravolgere l'applicazione a causa della limitazione dei 32-Bit
sull'utilizzo massimo di 2/3 Gbytes di memoria virtuale per singolo
processo.
Quali soluzioni ?
1) Passare dal MultiThread al MultiProcess, ma il porting
dell'applicazione può non essere semplice e immediato.
2) Passare da 32 a 64 Bit, ma anche in questo caso il porting
dell'applicazione può non essere semplice e immediato.
3) Provare a fare tuning dell'applicazione riducendo la memoria usata,
il numero Thread e soprattutto la quantità di spazio sprecato dello
Stack dei vari Thread.
Essendo orientati nel breve termine sulla soluzione 3 (per poi passare
probabilmente alla soluzione 2) ci stiamo scontrando però con il
problema di dover in qualche modo stimare il valore corretto di Stack
da allocare per i vari Threads (di default il compilatore piazza una
dimensione da 1 MByte che è sovradimensionata per gran parte delle
applicazioni e che noi già abbiamo ridotto a 250 KBytes).
Esiste però qualche strumento in grado di agganciarsi al processo e
misurare la quantità di Stack massima usata dai vari Threads ?
Oppure qualche libreria integrabile nel codice che consenta di
effettuare tali misurazioni ?
O tutto si riduce al *faccio una stima e vado per tentativi* ?
Grazie,
Massimo

 Quali soluzioni ?
Mi rendo conto di non esserti di aiuto, ma io un'applicazione "server"
con *2000* thread in C++ considererei di ripensarla. Non e' Erlang.
-- 
-riko

 Massimo
Ciao  Manlio

Non so aiutarti.
Ma era anche l'unica risposta che mi interessava.
Grazie lo stesso.
Massimo



Sulla questione Threads ti rimando all'altra risposta che ho dato a
Manlio.
Massimo

 Ma era anche l'unica risposta che mi interessava.
Prova a lavorare con getrusage. Io probabilmente mi farei qualche script
dtrace.
-- 
-riko

 Massimo
Ciao  Manlio

dtrace.
Questo fa parte dei metodi "prova finchè trovi la quadra".
Fino a lì ci arrivo anche da solo, non avrei postato qua.
Massimo

misurare la memoria usata.
Purtroppo non è possibile.
Posso solo misurare la memoria usata e mediarla eventualmente sul
numero di Thread che stava girando, ma ovviamente non avrebbe senso in
quanto con la stessa media un Thread potrebbe usare pochissimo mentre
un altro potrebbe usare tantissimo.
Massimo

 effettuare tali misurazioni ?
Ci ho pensato un po su e io farei così:
con "poche" modifiche al codice, appena avviato il thread aggiungo una 
funzioncina che infarcisce tutto lo stack con un bit pattern noto.
Per sapere quanto stack ho da riempire potrei o inserirlo come costante 
usando lo stesso parametro che ho passato al linker o alla CreateThread, 
o continuare a riempire e tentare di intercettare lo stack overflow...
Poi alla fine del thread, scorro tutto lo stack "al contrario" e vado a 
vedere fino a che punto mi ritrovo il mio pattern "invariato". Con buona 
approssimazione, quello è il massimo "consumo" di stack del mio thread.
Non so se esiste qualche libreria da integrare al codice per fare quello 
che ho detto, ma mi sa che ci vuole poco a farsela in casa...
Ciao

 effettuare tali misurazioni ?
Ci ho pensato un po su e io farei così:


 effettuare tali misurazioni ?
Ci ho pensato un po su e io farei così:


 O tutto si riduce al *faccio una stima e vado per tentativi* ?
Rimanendo anche io perplesso che un sistemi con così tanti thread scali 
bene, il dimensionamento dello stack è una "caratteristica" prevista 
nel formato PE e quindi è "scritta" dentro l'eseguible. Ovvero è un 
settaggio a livello di linker del vostro compilatore.
Mi sembra altresì strano che non abbiate banalmente guardato nei 
settaggi del vostro compilatore per un sistema così complesso; ne 
deduco quindi che ho travisato la tua richiesta sul "misurare" lo 
stack, oppure ho travisato il senso delle opzioni "stack commit 
size"/"stack reserve size" del compilatore MS.
-- 
mio figlio: 
http://it.youtube.com/davideippopotamo
doppiatori: 
http://it.youtube.com/watch?v=hPGKNWZw0c0&feature=related
Articolo 33 della Costituzione italiana: L'arte e la scienza sono 
libere e libero ne è l'insegnamento.

 settaggio a livello di linker del vostro compilatore.
Tutto questo se passi 0 come dwStackSize alla CreateThread.
Altrimenti lo puoi decidere thread per thread con tale parametro.
Ma mi pare di capire che l'OP ci abbia già guardato (quando dice che al 
posto del default di 1MB hanno messo 250 kB)
E' anche vero che a questo punto siamo OT (questo vale per windows)

 E' anche vero che a questo punto siamo OT (questo vale per windows)
Tutto questo post è OT, ma ritengo ragionevole che sugli altri S.O. 
queste opzioni siano disponibili. In senso lato quindi, per me, 
ridiventa IT.
Mi perplime che qualcuno vada a "ravanare" sull'allocazione di default 
degli stack. Sopratutto mi perplime che se fai un sistema così 
complesso, sia quello che fa la differenza. Anzi, sopratutto, mi 
piacerebbe capire perché pensi che sia quello che fa la differenza.
Poi, per carità, capisco che è più semplice fare una pezza che mettere 
rifare il design di un applicativo che richiesto centinaia di anni uomo 
per essere messo in piede. Però questa storia dello stack mi perplime 
assai. Sarei curioso di sapere che dati statistici hanno raccolto, e 
che prove hanno fatto, per arrivare alla conclusione che è una strada 
che porta a dei risultati.
Perché mi sembra evidente che su un sistema così complesso non è che 
uno si sveglia la mattina e dice: cambiamo l'allocazione dello stack 
dei thread. Sicuramente hanno fatto delle prove e anno visto che: XYZ. 
Ecco anche se siamo su un ambiente windows quell'XYZ sicuramente ha un 
grosso significato che trascende il S.O. Lo dico per egoismo. La cosa 
mi interessa per motivi professionali.


 size" del compilatore MS.
Informazioni su come lo stack è gestito si trovano qui:
http://msdn.microsoft.com/en-us/library/ms686774(VS.85).aspx
E comunque questo non risolve il problema del OP.
Lui sta cercando un valore ideale per lo "stack reserve size", perchè è 
quello che consuma spazio nella memoria virtuale.
Non è un problema di memoria fisicamente consumata, ma di spazio di 
allocazione limitato su un sistema a 32 bit.
Ciao  Manlio Perillo

 allocazione limitato su un sistema a 32 bit.
2000 thread per un MiB a thread fa quasi 2 GB. Con il windows giusto 
puoi arrivare a 3 GB di allocazione virtuale. Il loro programma alloca 
più di un GB? Se la risposta è no, che gli frega dei 2 GB virtuali 
dello stack?
Poi, per come è scritto, anzi per quel che capisco io da quel leggo, 
sembra che basterebbe fare 1000 thread, in cui ogni thread usa due 
"fiber" per portare a zero il problema. Con una centinaio di righe di 
codice tamponano con per anni il codice; però mi sembra molto convinto 
che sia lo stack la soluzione giusta. Parlo di fiber perché mi sembra 
di capire che non ci siano problemi di multipiattaforma.
Non conoscendo il loro sistema rimango perplesso dai 2000 thread, ma 
anche ipotizzando che sia una scelta sensata, come minimo la memoria è 
pesantemente frammentata. Come minimo ci sono 2000 pagine di memoria 
dello stack allocate. Senza contare quelli della memoria nell'heap del 
thred stesso. Come minimo, ma dovrei guardare la documentazione 
tecnica, magari sono 4000 pagine a fronte di 2000 thread per il solo 
stack. Poi dipende da come gira lo scheduler del S.O. nella loro 
applicazione. Mi sembra ragionevole che ci siano un numero 
incredibilmente alto di cache missing. Oserei dire assurdamente alto.
Però lui dice che scala bene.
Io sto ristrutturando del software perché già con un centinaio di 
thread scala da schifo. Ma bisogna intendersi sul concetto "scala". E 
seguendo la sua definizione io poi scrivo software casareccio.


GM ha scritto:
...
Ovviamente chiedo venia per aver postato 3 volte lo stesso messaggio!
Per un attimo č impazzito il newsreader...

GM ha scritto:

La cosa mi ha incuriosito...
... e questo sembra funzionare con VS6.0
class CStackMeasure
{
public:
  CStackMeasure()
  {
   BYTE* p;
   __try
   {
    while(1)
    {
     __asm mov p, ESP
     __asm push 0AAAAAAAAh
    }
   }
   __except( 1 )
   {
   }
   m_MinESP = p;
   BYTE** p1;
   __asm mov p1, EBP;
   while(*p1 != NULL)
   {
    p1 = (BYTE**)*p1;
   }
   m_EBP = (BYTE*)p1;
  }
  ~CStackMeasure()
  {
  }
  size_t GetStackSize()
  {
   return (m_EBP - m_MinESP);
  }
  size_t GetStackMaxUsage()
  {
   BYTE* p = m_MinESP;
   while(*p == 0xAA)
    ++p;
   return (m_EBP - p);
  }
private:
  BYTE* m_EBP;
  BYTE* m_MinESP;
};
  //altrove...
  //...
  CStackMeasure sm;
  size_t s = sm.GetStackSize();
  size_t u1 = sm.GetStackMaxUsage();
 
  DoSomething();
  size_t u2 = sm.GetStackMaxUsage();
  //...

seguendo la sua definizione io poi scrivo software casareccio.
Non ho mai detto che tu scrivi software casereccio.
Ho detto che il nostro non è un software casereccio, il che è molto
diverso.
Massimo

allocazione limitato su un sistema a 32 bit.
Bingo !
Di memoria fisica ne abbiamo da 4-8 GBytes e piů sui Server.
Massimo

> Ci ho pensato un po su e io farei cosě:
Ottimo approccio, hai centrato appieno l'obbiettivo.
Mi sembra che sia una delle vie meno invasive e piů efficaci in
mancanza di uno strumento che lo faccia dall'esterno.
Per ora ti ringrazio e ti farň sapere i risultati.
Massimo

mi interessa per motivi professionali.
Esattamente, sappiamo di poter ridurre il valore, ma vogliamo poterlo
fare con criterio, in modo selettivo per ogni thread (a seconda di
cosa eseguono) e non per *tentativi* che potrebbero riservarci
problemi.
Massimo

 [...]
Ciao  Manlio

Operazioni I/O bound, o CPU bound?
Semplificando :
Il sistema dialoga con il mondo esterno via socket attraverso un set
di protocolli standardizzati. Diciamo che su un canale ci sono almeno
2 socket UDP nelle due direzioni e da 1 a N connessioni TCP
bidirezionali che dipendono dal servizio richiesto. Ogni connessione
può richiedere e fare cose diverse CPU/Memory/Time-Consuming e
*devono* essere gestite in parallelo tra loro. Ovviamente il numero di
tali connessioni lo prevede lo standard e noi non possiamo variarlo.
Inoltre i sistema a sua volta accede a WebServer esterni per lo
scaricamento di pagine di servizio che definiscono il livello
applicativo.
A livello locale viene fatto un uso medio dell'HardDisk per accedere a
database di dati necessari all'engine e per depositare risultati di
elaborazione che devono poter essere recuperati in un secondo tempo.
A livello computazionale si fa parecchio uso della potenza di calcolo
(integriamo le Intel IPP per sfruttare al meglio l'hardware), ma a
tratti, ovvero ci sono momenti in cui un canale fa poco o nulla.
Tipicamente un canale ha intervalli in cui calcola, intervalli in cui
dialoga con l'utente e intervalli in cui fa entrambe le cose,
intervalli in cui non fa assolutamente nulla.
L'applicativo gira come servizio e viene controllato via SNMP
attraverso una interfaccia grafica che è in grado di configurare a
caldo l'applicativo e di misurare tutta una serie di statistiche per
valutare se l'oggetto sta lavorando a dovere.
Massimo

 [...]
Ciao e grazie per i dettagli
Manlio Perillo

Oppure i vari servizi usano stato condiviso?
Dipende, alcune risorse hanno stati condivisi.
Massimo

   BYTE* p;
interessante soluzione