MATLAB: salvare diverse variabili su "-v7.3" (HDF5) .MAT-Files sembra essere più veloce quando si utilizza il flag "-append". Come mai?

StackOverflow https://stackoverflow.com/questions/4949939

Domanda

NOTA: Questa domanda si occupa di un problema osservato nel 2011 con una vecchia versione MATLAB (R2009A). Secondo l'aggiornamento di seguito da luglio 2016, il problema/bug in MATLAB sembra non esistere più (testato con R2016A; scorrere verso il basso fino alla fine della domanda per vedere l'aggiornamento).

Sto usando MATLAB R2009B e devo scrivere uno script più grande che converte il contenuto di un set più ampio di file .ZIP in file MAT v7.3 (con un HDF5-Datamodel sottostante). La lettura va bene. Il problema è con il salvataggio. E in realtà non ci sono problemi. I miei file salvano bene usando il Salva comando.

La mia domanda è più nel senso: perché sto osservando il seguente comportamento sorprendente (per me) in Matlab?

Diamo un'occhiata al mio problema in generale. In questo attuale test-scenario genererò un output: un file MAT -v7.3. Questo .Mat-file conterrà 40 blocchi come variabili individuali. Ogni variabile verrà denominata "block_nnn" da 1 a 40 e conterrà una struttura con campi cornici e Blockno. Campo cornici contiene una sequenza 480x240x65 di uint8 imagetata (qui solo dati casuali generati usando Randi). Campo Blockno contiene il numero di blocco.

Nota: Nella vera sceneggiatura (che devo ancora finire) farò quanto sopra al totale di 370 volte, convertendo un totale di 108 GB di dati grezzi. Ecco perché mi preoccupo di quanto segue.

Comunque, prima definisco alcune variabili generali:

% some sizes for dummy data and loops:
num_blockCount = 40;
num_blockLength = 65;
num_frameHeight = 480;
num_frameWidth = 240;

Quindi genero un codice fittizio che ha forma e dimensioni identiche ai dati grezzi effettivi:

% generate empty struct:
stu_data2disk = struct();

% loop over blocks:
for num_k = 1:num_blockCount

   % generate block-name:
   temp_str_blockName = sprintf('block_%03u', num_k);

   % generate temp struct for current block:
   temp_stu_value = struct();
   temp_stu_value.frames = randi( ...
      [0 255], ...
      [num_frameHeight num_frameWidth num_blockLength], ...
      'uint8' ...
   );
   temp_stu_value.blockNo = num_k;

   % using dynamic field names:
   stu_data2disk.(sprintf('block_%03u', num_k)) = temp_stu_value;

end

Ora ho tutti i miei dati di prova casuali in una struttura stu_data2disk. Ora vorrei salvare i dati utilizzando uno dei due possibili metodi.

Proviamo prima quello semplice:

% save data (simple):
disp('Save data the simple way:')
tic;
save converted.mat -struct stu_data2disk -v7.3;
toc;

Il file è scritto senza problemi (286 MB). L'output è:

Save data the simple way:
Elapsed time is 14.004449 seconds.

OK, poi mi sono ricordato che vorrei seguire la procedura di salvataggio sui 40 blocchi. Quindi, invece del loop I sopra sui blocchi e aggiungendoli in sequenza:

% save to file, using append:
disp('Save data using -append:')
tic;
for num_k = 1:num_blockCount

   % generate block-name:
   temp_str_blockName = sprintf('block_%03u', num_k);

   temp_str_appendToggle = '';
   if (num_k > 1)
      temp_str_appendToggle = '-append';
   end

   % generate save command:
   temp_str_saveCommand = [ ...
      'save ', ...
      'converted_append.mat ', ...
      '-struct stu_data2disk ', temp_str_blockName, ' '...
      temp_str_appendToggle, ' ', ...
      '-v7.3', ...
      ';' ...
   ];

   % evaluate save command:
   eval(temp_str_saveCommand);

end
toc;

E ancora il file risparmia bene (286 MB). L'output è:

Save data using -append:
Elapsed time is 0.956968 seconds.

È interessante notare che il metodo di append è molto più veloce? La mia domanda è perché?

Output da dir converted*.mat:

09-02-2011  20:38       300,236,392 converted.mat
09-02-2011  20:37       300,264,316 converted_append.mat
               2 File(s)    600,500,708 bytes

I file non sono di dimensioni identiche. E un test con fc In Windows 7 ha rivelato ... beh molte differenze binarie. Forse i dati sono stati spostati un po ', quindi questo non ci dice nulla.

Qualcuno ha un'idea di cosa sta succedendo qui? Il file aggiunto utilizza forse una struttura dati molto più ottimizzata? O forse Windows ha memorizzato la memorizzazione nella cache il file e lo rende molto più veloce?

Ho fatto lo sforzo di lettura del test anche dai due file. Senza presentare i numeri qui la versione aggiunta era un po 'più veloce (potrebbe significare qualcosa a lungo termine).

MODIFICARE: Ho appena provato a usare alcun flag di formato (impostazione predefinita su -v7 sul mio sistema) e non c'è più molta differenza:

Save data the simple way (-v7):
Elapsed time is 13.092084 seconds.
Save data using -append (-v7):
Elapsed time is 14.345314 seconds.

MODIFICARE: Ho corretto l'errore di cui sopra. In precedenza ho detto che le statistiche erano per -v6 ma mi sono sbagliato. Avevo appena rimosso il flag di formato e ho ipotizzato che il valore predefinito fosse -v6 ma in realtà è -v7.

Ho creato nuove statistiche di test per tutti i formati sul mio sistema utilizzando Fine Framework di Andrew (tutti i formati sono per gli stessi dati di test casuali, ora letti dal file):

15:15:51.422: Testing speed, format=-v6, R2009b on PCWIN, arch=x86, os=Microsoft Windows 7 Professional  6.1.7600 N/A Build 7600
15:16:00.829: Save the simple way:            0.358 sec
15:16:01.188: Save using multiple append:     7.432 sec
15:16:08.614: Save using one big append:      1.161 sec

15:16:24.659: Testing speed, format=-v7, R2009b on PCWIN, arch=x86, os=Microsoft Windows 7 Professional  6.1.7600 N/A Build 7600
15:16:33.442: Save the simple way:           12.884 sec
15:16:46.329: Save using multiple append:    14.442 sec
15:17:00.775: Save using one big append:     13.390 sec

15:17:31.579: Testing speed, format=-v7.3, R2009b on PCWIN, arch=x86, os=Microsoft Windows 7 Professional  6.1.7600 N/A Build 7600
15:17:40.690: Save the simple way:           13.751 sec
15:17:54.434: Save using multiple append:     3.970 sec
15:17:58.412: Save using one big append:      6.138 sec

E le dimensioni dei file:

10-02-2011  15:16       299,528,768 converted_format-v6.mat
10-02-2011  15:16       299,528,768 converted_append_format-v6.mat
10-02-2011  15:16       299,528,832 converted_append_batch_format-v6.mat
10-02-2011  15:16       299,894,027 converted_format-v7.mat
10-02-2011  15:17       299,894,027 converted_append_format-v7.mat
10-02-2011  15:17       299,894,075 converted_append_batch_format-v7.mat
10-02-2011  15:17       300,236,392 converted_format-v7.3.mat
10-02-2011  15:17       300,264,316 converted_append_format-v7.3.mat
10-02-2011  15:18       300,101,800 converted_append_batch_format-v7.3.mat
               9 File(s)  2,698,871,005 bytes

Quindi -v6 sembra essere il più veloce per la scrittura. Inoltre, non grandi differenze nelle dimensioni dei file. HDF5 ha un po 'di metodo di base incorporato per quanto ne so.

Hmm, probabilmente una certa ottimizzazione nelle funzioni sottostanti HDF5-Write?

Attualmente penso ancora che una funzione fondamentale HDF5-write sottostante sia ottimizzata per l'aggiunta set di dati a un file HDF5 (che è ciò che accade quando si aggiungono nuove variabili a un file -7.3). Credo di aver letto da qualche parte che HDF5 dovrebbe ottimizzare proprio in questo modo ... anche se non può esserne sicuro.

Altri dettagli da notare:

Il comportamento è molto sistemico come vediamo nella risposta di Andrew di seguito. Sembra anche abbastanza importante se si esegue o meno queste cose nell'ambito locale di una funzione o nel "globale" di uno script M. I miei primi risultati sono stati da un M-script in cui i file sono stati scritti alla directory corrente. Posso ancora riprodurre la scrittura di 1 secondo per -7,3 in M-Script. Apparentemente le fatture di funzione aggiungono un po 'di sovraccarico.

Aggiornamento luglio 2016:

L'ho trovato di nuovo e ho pensato che avrei potuto testarlo con il più recente matlab a me disponibile al momento. Con Matlab R2016A su Windows 7 X64 il problema sembra essere stato risolto:

14:04:06.277: Testing speed, imax=255, R2016a on PCWIN64, arch=AMD64, 16 GB, os=Microsoft Windows 7 Enterprise  Version 6.1 (Build 7601: Service Pack 1)
14:04:10.600: basic -v7.3:                    7.599 sec      5.261 GB used
14:04:18.229: basic -v7.3:                    7.894 sec      5.383 GB used
14:04:26.154: basic -v7.3:                    7.909 sec      5.457 GB used
14:04:34.096: basic -v7.3:                    7.919 sec      5.498 GB used
14:04:42.048: basic -v7.3:                    7.886 sec      5.516 GB used     286 MB file   7.841 sec mean
14:04:50.581: multiappend -v7.3:              7.928 sec      5.819 GB used
14:04:58.544: multiappend -v7.3:              7.905 sec      5.834 GB used
14:05:06.485: multiappend -v7.3:              8.013 sec      5.844 GB used
14:05:14.542: multiappend -v7.3:              8.591 sec      5.860 GB used
14:05:23.168: multiappend -v7.3:              8.059 sec      5.868 GB used     286 MB file   8.099 sec mean
14:05:31.913: bigappend -v7.3:                7.727 sec      5.837 GB used
14:05:39.676: bigappend -v7.3:                7.740 sec      5.879 GB used
14:05:47.453: bigappend -v7.3:                7.645 sec      5.884 GB used
14:05:55.133: bigappend -v7.3:                7.656 sec      5.877 GB used
14:06:02.824: bigappend -v7.3:                7.963 sec      5.871 GB used     286 MB file   7.746 sec mean

Questo è stato testato con Andrew Janke reproMatfileAppendSpeedup funzione nella risposta accettata di seguito (5 passa con il formato 7.3). Adesso, -append è ugualmente lento o più lento, a un singolo salvataggio, come dovrebbe essere. Forse è stato un problema con una costruzione iniziale del driver HDF5 utilizzato in R2009A.

Nessuna soluzione corretta

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top