Memoria

di il
28 risposte

Memoria

Vorrei fare una funzione che mi deduca quale funzione mi conviene usare.
cosi come l'ho descritto non si capisce cerchero di spiegarlo con un esempio
ho due funzioni che fanno la stessa cosa a e b
adesso vorrei scrivere un altra funzione che mi dovrebbe dire
1) chi è la funzione più veloce se a o b.
2) chi tra a e b occupa meno spazio in memoria.
il punto 1 e una cavolata da fare basta chiedere al sistema l'ora di partenza e l'ora di fine di ogni funzione e poi fare la differenza.
il punto 2 sinceramente non ho proprio idea su come fare ho cercato un pò su qualche libro che ho.
ma in merito a questo non ho trovato niente.
grazi anticipatamente a chiunque mi sappia dare una mano.

28 Risposte

  • Re: Memoria

    Se ti accontenti di una scorciatoia puoi velocemente usare opportuni comandi da OS.
    Quale os usi?
  • Re: Memoria

    Uso windows 7 64 bit
    e per programmare uso visual studio 2012.
    però ho notato che ci sarebbero almeno 2 problemi.
    1) se le funzioni sono fatte in c++ come faccio a trovare le locazioni di inizio e fine ?
    2) per quanto riguarda l'assembler va bene che nello stack ho la locazione di ritorno ma come farei a capire quella di inizio ?
  • Re: Memoria

    Per la misura dell'uso della memoria e della velocità di esecuzione, In generale, hai bisogno di un oggetto che si chiama profiler, lo puoi trovare integrato in alcuni IDE o come applicativo a se stante o, infine, come libreria.
    • -Per la misura dell'uso della memoria, puoi utilizzare la funzione avanzata MonitoraggioRisorse di GestioneAttività. Crei due programmini con le due funzioni da testare e confronti l'uso delle risorse di entrambe con MonitoraggioRisorse (devi essere Amministratore della macchina).
      -Per la misura del tempo di esecuzione, per la prima volta mi autocito , qui:
      http://clessonsonline.blogspot.it/2012/11/come-si-misura-ill-tempo-di-esecuzione.html
  • Re: Memoria

    Io credo che tu abbia bisogno di leggere lo stack delle chiamate per vedere che succede. Anche se non capisco pienamente la tua domanda. Una funzione dopo il ret ha già svuotato lo stack quindi come puoi misurare la memoria utilizzata da una funzione già terminata?
    Guarda sto progetto magari fa a caso tuo
    http://www.codeproject.com/Articles/11132/Walking-the-callstack
  • Re: Memoria

    Scusatemi ma non c'è una funzione in c++ che possa leggere il registro eip ?
    cosi da poter fare :
    x = a( qui immetterei i miei parametri della funzione a + due parametri accessori che conterrebbero gli indirizzi di inizio e fine della funzione)
    memoria = fine - inizio.
  • Re: Memoria

    Orientativamente potresti scrivere
    
    void func()
    {
    	unsigned int start, stop;
    
    	_asm {
    		call geteip1
    	geteip1:
    		pop start
    	}
    
    	// Corpo della funzione
    
    	_asm {
    		call geteip2
    	geteip2:
    		pop stop
    	}
    
    	printf("%X\n", stop-start+1);
    }
    
    considerando che il valore ottenuto è maggiore di quello effettivo perché comprende il codice per la misurazione (comunque costante e quindi uguale in tutte le misurazioni).
  • Re: Memoria

    Purtroppo non va bene perchè in assembler, quello moderno, quando si fa una chiamata call alla sua ret fa terminare il programma. senza considerare ciò che sta dopo.
  • Re: Memoria

    Lo dici perché hai provato?

    Intanto non faccio una "call alla return" (che vuoi dire?).

    Quella è una normale call all'inizio di una routine che, per prima cosa, estrae l'indirizzo di ritorno, cosa fattibile con qualsiasi strumento di compilazione (io uso Visual C++ 2010, abbastanza moderno mi pare).

    Il codice viene perfettamente eseguito e, nel dettaglio, il codice mixed è
    
       _asm {
          call geteip1
    004113DE E8 00 00 00 00       call        geteip1 (4113E3h)  
       geteip1:
          pop start
    004113E3 8F 45 F8             pop         dword ptr [start]  
       }
    
       // Corpo della funzione
    
       _asm {
          call geteip2
    004113E6 E8 00 00 00 00       call        geteip2 (4113EBh)  
       geteip2:
          pop stop
    004113EB 8F 45 EC             pop         dword ptr [stop]  
       }
    
       printf("%X\n", stop-start+1);
    004113EE 8B 45 EC             mov         eax,dword ptr [stop]  
    004113F1 2B 45 F8             sub         eax,dword ptr [start]  
    004113F4 83 C0 01             add         eax,1  
    004113F7 8B F4                mov         esi,esp  
    004113F9 50                   push        eax  
    004113FA 68 3C 57 41 00       push        offset string "%X\n" (41573Ch)  
    004113FF FF 15 D4 82 41 00    call        dword ptr [__imp__printf (4182D4h)]  
    
  • Re: Memoria

    Certo che ho provato.
    l' ho scoperto per caso quando stavo studiando il passaggio di parametri tra c++ e assembler.
    sicomme nei miei programmi assembler metto sempre questa sequenza di codice.
    
    call can_reg
    ...............
    ................
    ................
    ret
    can_reg: ; serve per cancellare tutti i registri 
    xor eax,eax
    xor ebx,ebx
    xor ecx,ecx
    xor edx,edx
    xor edi,edi
    xor esi,esi
    ret
    
    ho notato che ogni volta che eseguiva la subroutine can_reg poi mi terminava il programma.
    ogni volta che si usa una call per restituire il controllo al flusso chiamante bisogna usare la ret
    non per niente la call inserisce nello stack il registro eip.
    al massimo dovrei fare
    call getip1
    .....
    ....
    getip1:
    pop dword ptr start
    push dword ptr start ; se non reinserisco eip nello stack quando il programma finirà l'esecuzione della routine tornea ad un punto non precisato della memoria e ciò provocerebbe dei problemi.
    ret
    questo codice e stato provato su visual studio 2012 windows 7 64bit
    e il tipo di assembler utilizzato e x86 .model 486
  • Re: Memoria

    Non ci siamo capiti.

    Il codice che ti ho proposto non l'ho inserito in una funzione (nel cui caso è necessario fare come dici tu rimettendo a posto il punto di rientro, ovviamente).

    Il codice che ti ho mostrato l'ho inserito all'interno del main per fare una prova e non in una funzione separata. In questo caso non esiste alcuna ret successiva che possa ritornare ad un punto indefinito della memoria.

    E in questo caso funziona perfettamente e restituisce il corretto risultato senza errori.

    Se la impostiamo all'interno di una funzione, deve essere previsto il rientro.
  • Re: Memoria

    smalldragon ha scritto:


    scusatemi ma non c'è una funzione in c++ che possa leggere il registro eip ?
    cosi da poter fare :
    x = a( qui immetterei i miei parametri della funzione a + due parametri accessori che conterrebbero gli indirizzi di inizio e fine della funzione)
    memoria = fine - inizio.
    Si vede che non hai prestato attenzione al link che ti ho passato.
  • Re: Memoria

    skynet ha scritto:


    smalldragon ha scritto:


    scusatemi ma non c'è una funzione in c++ che possa leggere il registro eip ?
    cosi da poter fare :
    x = a( qui immetterei i miei parametri della funzione a + due parametri accessori che conterrebbero gli indirizzi di inizio e fine della funzione)
    memoria = fine - inizio.
    Si vede che non hai prestato attenzione al link che ti ho passato.
    si l'attenzione ce l'avevo messa ma vedendo tutte le varie include nidificate che ci sono per utilizzare quella struttura.
    ho pensato ci drovrà pur essere un altro modo per fare quella cosa e non rischiare di perdermi nei meandri di tutte quelle librerie aggiuntive che per di più non so neanche dove siano!
    purtroppo quando ci sono troppe include mi perdo facilmente.
    per orion
    la funzione dovrebbe essere una cosa a se stante così la metto in una libreria e non dovrei ogni volta ricopiarla o usare gli include che quando sono troppi mi fanno perdere facilmente il flusso del programma.
    ecco anche perchè quella tecnica non va bene.
  • Re: Memoria

    smalldragon ha scritto:


    per orion
    oregon
    ecco anche perchè quella tecnica non va bene.
    Non capisco perché non vada, basta metterci la push dopo la pop per la ret.
  • Re: Memoria

    Vedo di farti un esempio per farti capire.
    modulo c++
    
    #include "stdafx.h"
    #include "iostream"
    using std::cin;
    using std::cout;
    using std::endl;
    extern "C" int __stdcall LenStringa(char*);
    extern "C" int __stdcall pleftstringa(char *,char *,int);
    int _tmain(int argc, _TCHAR* argv[])
      {
    char pippo[71],pluto[68];
    int ncar,indy,kindy,err,opz;
            ncar=0; err=0; kindy=0; opz=0;
        for (indy=0;indy < 71;indy++) { pippo[indy]=' '; }
        for (indy=0;indy < 68;indy++) { pluto[indy]=' '; }
    cout << "inserisci stringa una stringa max 70 caratteri : ";
        cin.getline(pippo,71);
    cout << "quanti caratteri vuoi prendere ? ";
                      cin >> ncar;
                      err = pleftstringa(pippo,pluto,ncar);
    cout << "hai preso i seguenti caratteri : " << pluto << "\n";
                                     return 0;
    }
    
    nella parte assembler
    .486
         .model flat,stdcall
          option casemap :none
         .code
    	  pleftstringa PROC Arg1:DWORD,Arg2:DWORD,Arg3:DWORD
              ; adesso se aggiungo
                    call geteip
                	mov ecx,Arg3
                    mov edi,Arg2
                    mov esi,Arg1
                    cmp ecx,0
                    jne uno
                    mov eax,2
                    jmp short fine
                uno:
                    cmp byte ptr [esi],0
                    jne due
                    mov eax,1
                    jmp short fine
                due:
                    xor eax,eax
                    rep movsb
                    mov dword ptr [edi],0
               fine:
                    ret
               getip:
                        pop eax
                        push eax
                        mov ebx,6 ; questo perchè questa routine in memoria, se ho fatto bene i calcoli,  occupa 6 byte
                        ret
          pleftstringa endp
                      end
    ; in teoria succederebbe che prende l'indirizzo del registro eip e lo mette in eax
    ; e poi continuerebbe con il flusso normale della routine assembler.
    ; ma in pratica mi esce dalla routine senza aver fatto niente!
    ;prende solo l'indirizzo eip
    ; cioè per il compilatore ogni volta che incontra una ret significa che è finita la routine assembler tornando al c++.
    
    la soluzione potrebbe consistere in una routine a se stante in un file a parte.
    ma cio' porterebbe ad un problema di memoria.
    infatti il modello flat a differenza dei modelli tiny,small e compact lascia molto spazio tra una routine e un altra a volte gli cambia anche il segmento,anche se a volte non ce ne accorgiamo dipende dalle dimensioni del programma.
    per questo motivo non va bene questa tecnica.
Devi accedere o registrarti per scrivere nel forum
28 risposte