2015-07-03 9 views
18

Possiedo un laptop con CPU Intel Core 2 Duo a 2,4 GHz e moduli DDR3 2x4 Gb a 1066 MHz.Il programma supera la velocità teorica di trasferimento della memoria

mi aspetto che questa memoria potrebbe funzionare a velocità 1067 MiB/sec, e fintanto che vi sono due canali, la velocità massima è 2134 MiB/sec (nel caso dispatcher memoria OS permetterà).

Ho fatto una piccola applicazione Java per verificare che:

private static final int size = 256 * 1024 * 1024; // 256 Mb 
private static final byte[] storage = new byte[size]; 

private static final int s = 1024; // 1Kb 
private static final int duration = 10; // 10sec 

public static void main(String[] args) { 
    long start = System.currentTimeMillis(); 
    Random rnd = new Random(); 
    byte[] buf1 = new byte[s]; 
    rnd.nextBytes(buf1); 
    long count = 0; 
    while (System.currentTimeMillis() - start < duration * 1000) { 
     long begin = (long) (rnd.nextDouble() * (size - s)); 
     System.arraycopy(buf1, 0, storage, (int) begin, s); 
     ++count; 
    } 
    double totalSeconds = (System.currentTimeMillis() - start)/1000.0; 
    double speed = count * s/totalSeconds/1024/1024; 
    System.out.println(count * s + " bytes transferred in " + totalSeconds + " secs (" + speed + " MiB/sec)"); 

    byte[] buf2 = new byte[s]; 
    count = 0; 
    start = System.currentTimeMillis(); 
    while (System.currentTimeMillis() - start < duration * 1000) { 
     long begin = (long) (rnd.nextDouble() * (size - s)); 
     System.arraycopy(storage, (int) begin, buf2, 0, s); 
     Arrays.fill(buf2, (byte) 0); 
     ++count; 
    } 
    totalSeconds = (System.currentTimeMillis() - start)/1000.0; 
    speed = count * s/totalSeconds/1024/1024; 
    System.out.println(count * s + " bytes transferred in " + totalSeconds + " secs (" + speed + " MiB/sec)"); 
} 

mi aspettavo il risultato di essere sotto 2134 MiB/sec comunque ho ottenuto il seguente:

17530212352 bytes transferred in 10.0 secs (1671.811328125 MiB/sec) 
31237926912 bytes transferred in 10.0 secs (2979.080859375 MiB/sec) 

come è possibile quella velocità era di quasi 3 GiB/sec?

DDR3 module photo

+5

hai dimenticato la cache della CPU. c'è l1, l2 e anche cache l3 ... solo perché stai curiosando in modo casuale non significa che di tanto in tanto non riuscirai a ottenere un successo nella cache. –

+0

la frequenza di clock di DDR non viene interpretata in questo modo ... – HuStmpHrrr

+1

@MarcB Giusto sei. Ecco perché creo memoria buffer 256MiB. – Antonio

risposta

8

Il vostro metodo di prova è mal progettato in molti aspetti, come pure la vostra interpretazione del voto RAM.

Iniziamo con la valutazione; dall'introduzione di SDRam, marketing nomina i moduli dopo la specifica del bus, ovvero la frequenza di clock del bus, associata alla velocità di trasferimento burst. Questo è il caso migliore, e in pratica non può essere sostenuto continuamente.

parametri omessi da tale etichetta sono reali tempo accesso (alias. Latenza) e tempo totale del ciclo (alias. Tempo di precarica). Questi possono essere capiti guardando effettivamente le specifiche del "timing" (le cose 2-3-3). Cerca un articolo che spiega dettagliatamente queste cose. In realtà, la CPU non trasferisce normalmente singoli byte, ma intere linee di cache (ad esempio 8 voci per 8 byte = 64 byte).

Il codice di test è mal progettato, poiché si sta eseguendo un accesso casuale con un blocco relativamente piccolo non allineato ai limiti effettivi dei dati. Questo accesso casuale comporta anche frequenti errori di pagina nella MMU (scopri cosa fa/fa il TLB). Quindi stai misurando una miscela selvaggia di diversi aspetti del sistema.

+1

In realtà era il mio obiettivo di testare la velocità quando il blocco di memoria desiderato non è nella cache. Lasciami avvolgere i tempi e tornerò. Grazie per la risposta. – Antonio

+1

Ho aggiunto una foto del modulo DDR. Non ci sono tempi per quanto posso vedere. – Antonio

+1

Dopo aver cercato su Google ho trovato CL = 7. Quindi come calcoleresti un limite? – Antonio

18

Qui ci sono più cose al lavoro.

Innanzitutto: il formula for memory transfer rate of DDR3 è

Per DDR3-1066 (che è temporizzato a 133⅓ MHz), si ottiene una larghezza di banda di memoria teorico 8533⅓ MB/s o 8138.02083333... MiB/s per singolo canale, e 17066⅔ MB/s o 16276.0416666... MiB/s per doppio -canale.

Secondo: il trasferimento di una grande porzione di dati è più rapido del trasferimento di molti piccoli blocchi di dati.

Terzo: gli effetti di memorizzazione nella cache ignorati, che possono verificarsi.

In quarto luogo: se si eseguono misurazioni del tempo, è necessario utilizzare System.nanoTime(). Questo metodo è più preciso.

Ho riscritto il programma di test .

import java.util.Random; 

public class Main { 
    public static void main(String... args) { 
     final int SIZE = 1024 * 1024 * 1024; 
     final int RUNS = 8; 
     final int THREADS = 8; 
     final int TSIZE = SIZE/THREADS; 
     assert (TSIZE * THREADS == THREADS) : "TSIZE must divide SIZE!"; 
     byte[] src = new byte[SIZE]; 
     byte[] dest = new byte[SIZE]; 
     Random r = new Random(); 
     long timeNano = 0; 

     Thread[] threads = new Thread[THREADS]; 
     for (int i = 0; i < RUNS; ++i) { 
      System.out.print("Initializing src... "); 
      for (int idx = 0; idx < SIZE; ++idx) { 
       src[idx] = ((byte) r.nextInt(256)); 
      } 
      System.out.println("done!"); 
      System.out.print("Starting test... "); 
      for (int idx = 0; idx < THREADS; ++idx) { 
       final int from = TSIZE * idx; 
       threads[idx] 
        = new Thread(() -> { 
            System.arraycopy(src 
                 , from 
                 , dest 
                 , 0 
                 , TSIZE); 
           }); 
      } 
      long start = System.nanoTime(); 
      for (int idx = 0; idx < THREADS; ++idx) { 
       threads[idx].start(); 
      } 
      for (int idx = 0; idx < THREADS; ++idx) { 
       try { 
        threads[idx].join(); 
       } catch (InterruptedException e) { 
        e.printStackTrace(); 
       } 
      } 
      timeNano += System.nanoTime() - start; 
      System.out.println("done!"); 
     } 
     double timeSecs = timeNano/1_000_000_000d; 

     System.out.println( "Transfered " + (long) SIZE * RUNS 
          + " bytes in " + timeSecs + " seconds."); 

     System.out.println( "-> " 
          + (long) SIZE * RUNS/timeSecs/1024/1024 /1024 
          + " GiB/s"); 
    } 
} 

In questo modo, a mitigare il più "altro calcolo" possibile e la misura (quasi) solo tasso di copia memoria tramite System.arraycopy(...). Questo algoritmo potrebbe avere ancora problemi relativi alla memorizzazione nella cache.

Per il mio sistema (Dual Channel DDR3-1600), ottengo qualcosa intorno a 6 GiB/s, mentre il limite teorico è di circa 25 GiB/s (incluso DualChannel).

Come indicato da MagicM18, la JVM presenta alcuni overhead. Pertanto, ci si aspetta che tu non sia in grado di raggiungere il limite teorico.


Nota a margine: Per eseguire il programma, bisogna dare la JVM più heapspace. Nel mio caso, 4096 MB erano sufficienti.

+0

Ho provato questo test. Dovuto ridurre SIZE a 256Mb. Ottenuto: 'Ha trasferito 2147483648 byte in 1,42 secondi. -> 1.41 GiB/s' – Antonio

+1

@Antonio perché hai diminuito il 'SIZE'? Per avvicinarsi al limite teorico, i blocchi dovrebbero essere il più grandi possibile. Sarebbe meglio dare alla JVM più spazio su heap ('java -Xmx4096m ...') che ridurre la dimensione del blocco. – Turing85

+0

Ho impostato la dimensione di archiviazione a 1 Gb e la durata a 30 sec. I risultati sono diventati quasi identici - 1.42GiB/sec. La CPU non è un collo di bottiglia (utilizzato dal 60%). – Antonio

1

In Wikipedia c'è un table of transfer rates. Questo particolare portatile ha le seguenti specifiche:

  • Tipo di modulo: PC3-8500 DDR3 SDRAM
  • Tipo di chip: DDR3-1066
  • memoria: 133 MHz
  • Velocità bus: 1.066GT/s
  • tasso di trasferimento (bit/s): 64 Gbit/s
  • tasso di trasferimento (decimale byte/s): 8 GB/s

Questo è per singolo modulo DDR3 per singolo canale.

1

Questa potrebbe essere una questione di configurazione hardware. Sulla base delle informazioni fornite ci sono due core e due moduli di memoria, ma il numero di canali di memoria non è chiaro. Anche se non ho mai visto test eseguiti sulla scala di un laptop, su sistemi più grandi la configurazione dei DIMM nei canali di memoria può avere un impatto significativo sui tassi di trasferimento della memoria.

Ad esempio su server moderni è possibile avere una configurazione DIMM DIMM (Channel ODPC) o DIMM per canale (TDPC). Ogni CPU fisica può avere più canali di memoria suddivisi tra i core fisici su detta CPU, e ciascun server potrebbe potenzialmente avere più CPU fisiche (in genere 2-4 nei server moderni).

La distribuzione della memoria tra questi canali, core e CPU/chip può avere un impatto significativo sulle prestazioni della memoria in base a ciò che viene misurato. Ad esempio, i sistemi con una configurazione ODPC avranno tempi di trasferimento significativamente migliorati (in termini di trasferimenti al secondo o MegaTransfer al secondo, MT/s) rispetto ai sistemi che dispongono di una configurazione TDPC nei casi in cui la quantità di memoria (in GB) in il sistema TDPC è uguale o maggiore della quantità di memoria nella configurazione ODPC.

Sulla base di questa conoscenza, è concepibile che un laptop configurato con 2 canali di memoria in un ODPC e un canale per core possa teoricamente raggiungere le prestazioni descritte.

Con tutto ciò che viene detto ci sono un certo numero di strumenti di analisi e profiling di memoria preconfezionati che possono essere eseguiti in modo non invasivo per ottenere informazioni sulle prestazioni della memoria sul sistema.Memtest è uno strumento molto potente, ben compreso e ben documentato per testare la memoria. Può essere scaricato su un disco avviabile di qualche tipo (USB, DVD, floppy, ecc.) Che può essere tranquillamente utilizzato per sottolineare la memoria su un sistema senza la possibilità di danneggiare o disturbare il sistema operativo. È inoltre incluso nel DVD di installazione per alcune distribuzioni Linux nonché per il salvataggio di DVD/immagini. È uno strumento molto potente che ho usato in molte occasioni per eseguire il debug e analizzare le prestazioni della memoria, anche se normalmente sui server.

Problemi correlati