Newsgroup: it.comp.programmare
Titolo: [LUNGO] - Quesito Java per conto di un amico......

Riporto una email appena arrivatami da un amico che mi chiede aiuto. Io la
rigiro a voi, sperando possiate aiutarlo. E' una cosa abbastanza lunga.
Grazie.
INIZIO
Il programma di per se ?emplice.... devo implementare una macchina virtuale
(quindi simile alla jvm di java) in... java.
E' composto quindi da un thread principale che preleva l'istruzione
corrente, la decodifica e la esegue. Fin qui niente di strano... ho un ciclo
while all'interno di questo compio le elaborazioni necessarie....
public void run() {
    Istruzione cor;
    cor = ambiente.getIstruzione();
    while (cor.codop!=ALT) {
        switch (cor.codop) {
        case LOAD:
          istruzioneLOAD(cor.arg);
          break;
        case LOADPTR:
          istruzioneLOADPTR(cor.arg);
          break;
                ......
        case SYSCALL:
          istruzioneSYSCALL(cor.arg);
          break;
    }
    // legge la prossima istruzione
    cor = ambiente.getIstruzione();
}
Ora questo ?l metodo originario... usandolo pero in questa forma java mi
consuma il 99% della risorsa cpu... ho pensato quindi inizialmente di
introdurre (tanto per provare) un ritardo di un millisecondo prima di
reperire una nuova istruzione... in questo caso la cpu rimaneva libera per
gli altri processi... solo che ovviamente la macchina virtuale era fin
troppo lenta. (nell'ipotesi piu ottimistica avevo a che fare con un
"processore" con un clock di massimo di 1 KiloHertz... altro che ENIAC!!!)
Da questo ho cercato quindi di aggiungere un timer... in modo che la
macchina virtuale avesse a che fare con un vero e proprio clock. Ad ogni
colpo di clock veniva prelevata una istruzione e quindi eseguita... come in
pratica avviene nei processori reali.
Il problema pero ?he java nn mette a disposizione un timer con una elevata
granulosita... dai test effettuati mi ?isultato che l'intervallo MINIMO di
tempo rilevato dal timer di java ?i un millisecondo. Faccio notare che per
timer nn intendo uno strumento messo a disposizione da java stesso ma una
classe creata da me appositivamente...(qui di seguito riporto il codice).
public class ClockThread extends Thread {
   public boolean clockTick;
   public synchronized void doClockTick(boolean cond) {
      clockTick = cond;
      notifyAll();
   }
   public synchronized void waitTickClock() {
      while (clockTick==false)
      try {
         wait();
      }
      catch (InterruptedException e) {
      }
      clockTick = false;
   }
   public void run() {
      doClockTick(false);
      while (true) {
         try {
            sleep(0,250);
         }
         catch (InterruptedException e) {
         }
         doClockTick(true);
      }
   }
}
tramite l'utilizzo di questa classe la parte finale del ciclo principale
della macchina virtuale veniva modificato nel seguente modo:
    // attende il prossimo colpo di clock
    clockThread.waitClockTick();
    // legge la prossima istruzione
    cor = ambiente.getIstruzione();
Ma ovviamente anche tramite l'utilizzo di questa classe mi trovavo sempre
nella stessa situazione di quando usavo il delay di un millisecondo...
la macchina virtuale era troppo lenta.
Ho provato a diminuire la priorita del thread principale (in fondo ?n
processo sempre in esecuzione... quindi le priorita alte le dovrei lasciare
a processi critici come ad esempio l'input da utente) nonche ad usare la
chiamata YIELD per dare la precedenza ad altri processi... in un primo
momento (prima ancora di usare il delay) ho pensato che fosse il garbage
collector a farmi fuori tutta la cpu... in effetti usavo molto la memoria
(continue richieste di allocazione/deallocazione di memoria) ma anche
modificando il codice in modo che usi le stesse aree di memoria mi trovavo
sempre con un consumo enorme di cpu...
Basta infatti fare un ciclo del genere
while (true)
   ; // nessuna istruzione
che il consumo di cpu sale al 99%.. senza che venga effettuata alcuna reale
elaborazione
Ora come faccio a far funzionare la mia macchina virtuale con una velocita
decente e senza occupare tutta la cpu??? come si fanno a far eseguire
processi
in continua esecuzione senza che la cpu ne risenta troppo? Esite al limite
un modo per usare con piu precisione il timer? Faccio comunque presente
che nn mi importa la velocita della macchina virtuale... (oddio fino a un
certo limite) l'importante ?he nn mi consumi tutta la cpu ma allo stesso
tempo
che nn mi ritrovi ad eseguire codice virtuale a un velocita da lumaca..
Spero che qualcuno possa essermi di aiuto... nel frattempo vi ringrazio per
qualsiasi risposta.
FINE

Due cose:
a) innanzitutto devi capire che il timer "di sistema" di windows ha una
precisione "sui millisecondi", quindi non puoi pretendere troppo.
b) per quanto riguarda l'occupazione... E' molto semplice. Se tu hai un
programma che fa operazioni il più velocemente possibile, è chiaro che se lo
lanci da solo l'occupazione della CPU salirà al 100%. Il trucco però è che
se tu ne lanci due, ognuno di loro avrà un'occupazione di circa il 50%. Se
ne lanci 3 del 33%... E inoltre l'applicazione in "foreground" (quella in
cui l'utente sta digitando) probabilmente riceverà lo stesso abbastanza CPU
per poter lavorare. E quindi tu ti puoi chiedere: e perchè i programmi non
occupano il 100% della CPU? Perchè il 90% dei programmi passa il 99% del
loro tempo in attesa che l'utente faccia qualcosa. Mentre sono in attesa non
occupano CPU perchè il SO se ne accorge e li "sospende" fino a quando
l'utente non manda a questi programmi dei segnali (in realtà non è proprio
così: le interfacce grafiche si basano sullo scambio di messaggi. C'è un
comando che mette il programma nello stato di attesa per nuovi messaggi). Se
tu prendi un compilatore C e scrivi while (1) ; vedrai che la CPU occupata
sarà lo stesso del 100%. Non dipende dal linguaggio.
--- bye

Ok ho fatto leggere la risposta al mio amico, ma lui vorrebbe del
codice....se fosse possibile.
Grazie mille.

 codice....se fosse possibile.
Ti ho già detto che non si può. Ti ho anche spiegato il perchè. Il problema
non è solubile ed è giusto che sia così. Se vuole fare qualcosa di "decente"
allora deve mettere una nuova istruzione nel suo linguaggio, l'istruzione
yeld, che ovviamente fa una yeld! Se cmq ha paura di far andare a "scatti"
il sistema, digli di abbassare la priorità della macchina java (la mette su
bassa per esempio) e quindi essa si prenderà solo i cicli di clock che non
servono agli altri processi. Per vedere se è così può creare un altro
processo a priorità normale che impegni più CPU possibile (while (1) {} ) e
vedere chi si prende più CPU (ovviamente dando il focus a una terza
applicazione).
--- bye

 ha scritto nel messaggio
news:2b9fc.51781$hc5.2...@news3.tin.it...

Aho non ti arrabbiare :-)
Beh grazie.....spero che capisca quanto detto e si dia da fare per il
meglio.
Per quanto mi riguarda ho ripreso il Java da l'altro ieri percui manco mi
addentro nel merito della discussione.
Cmq grazie mille! :-P

 addentro nel merito della discussione.
Cmq volendo un "accrocchio c'è". Te lo faccio in pseudocodice:
timeslot = millisecondi di un ciclo
waittime = millisecondi della pausa fra due cicli
msecstart = millisecondi attuali
while (true) {
    esegui un istruzione
    msecattuali = millisecondi attuali
    se (msecattuali - msecstart) >= timeslot {
        attendi (waittime);
        msecstart = millisecondi attuali
    }
}
dove per esempio, per avere un'occupazione della CPU del 10%, potresti
provare con
timeslot = 4 msec
waittime = 36 msec
(9/10 del tempo vengono passati ad attendere)
--- bye