Jarni
Posts: 3
Joined: Mon May 15, 2017 6:22 am

PI2 Raspbian linguaggio C: delay lettura file

Mon May 15, 2017 6:49 am

Devo leggere piccole quantità di byte da un file (nella scheda SD) ogni 50 ms.
All'inizio va bene, riesco a mantenere il ritmo, ma ogni tanto, casualmente, qualche lettura impiega 100, 300, anche 1000 ms.
L'unico modo che sono riuscito a trovare per far funzionare la lettura è "indurre" il caching del file da parte di linux.
In pratica "preleggo" tutto il file prima di iniziare la lettura vera e propria.
Non serve nemmeno che allochi lo spazio di tutto il file, basta che leggo qualcosa e lo memorizzo in un buffer, poi posso anche non utilizzarlo.
Praticamente questo:

Code: Select all

void preload(char filename)
{
    int file;
    char buffer[1000];

    file = open(filename, O_RDONLY);
    while(!eof(file))
    {
        read(file, buffer, 1000);
    }
    close(file);
}


int main()
{
    int filed;
    char buffer[11832];

    preload("blablabla");
    filed = open("blablabla", O_RDONLY);

    while(!eof(filed))
    {
        read(filed, buffer, 11832);
        delay_ms(50);
    }
    return 0;
}
La funzione preload() fa sì che linux cacherizzi il file in RAM, così le successive letture avverranno da lì e non dal file.
Ora, questa cosa va bene per file piccoli, ma se ho un file grosso, oltre al tempo perso per il preload, potrebbe non esserci abbastanza RAM e linux non avrebbe tutto il file in cache, quindi rischierei di avere ancora quei ritardi.
Perché read() ha questi delay?
Leggo solo 12000 byte ogni 50 ms, fanno 240000 B/s, è un flusso ridicolo.
Anche bufferizzando io stesso il file, cioè caricando qualche MB in un buffer e prendere i 12000 B da lì, non risolve il problema: ogni tanto la funzione read() si addormenta.

Come la risolvo?

willy_pinguino
Posts: 901
Joined: Sun Jan 22, 2017 9:11 pm

Re: PI2 Raspbian linguaggio C: delay lettura file

Mon May 15, 2017 11:49 am

ricordati che stai leggendo da una SD, e che le SD di solito sono ottimizzate per letture e scritture sequenziali di dati, non per accessi random veloci a piccoli files.

se intendi leggere files più grandi di un centinaio di MB non sarà la ram il tuo limite ma la velocità del processore ad elaborarli. files più piccoli (nell'ordine di decine di mb) non saranno un problema per la memoria (che è 1gb meno quello che allochi per la scheda grafica - di default sono 128mb), files più grossi sono un problema per il raspberry, quindi meglio se passi ad altro computer.

prendi una SD ottimizzata per le scritture random (quelle consigliate per tablet e cellulari vanno bene, quelle per macchine fotografiche e telecamere no) e vedrai dei miglioramenti.
oppure carica in ram i files a cui devi accedere (con il preload di tutto il file o creando un ramdisk e copiandoci i files che ti interessano in apertura di programma) e otterrai i risultati migliori.

tieni poi conto che Raspian non è un sistema in real time, ciò vuol dire che ogni operazione ha una sua prevalenza e che un task viene eseguito solo quando non c'è nulla di più urgente da fare, quindi dipende anche dal livello di urgenza che dai alla tua azione. oltre a ciò, le operazioni di sistema come le operazioni di rete hanno la prevalenza in genere, anche su lettura e scrittura di dati nello spazio utente.

Jarni
Posts: 3
Joined: Mon May 15, 2017 6:22 am

Re: PI2 Raspbian linguaggio C: delay lettura file

Mon May 15, 2017 7:50 pm

Aggiornamenti.
Non scrivo il file, lo leggo soltanto e per di più sequenzialmente, non random, proprio per questo non mi spiego il comportamento.

Ricordando meglio (questo problema risale a novembre scorso e fino ad adesso avevo lasciato il trucchetto del preload) questo problema veniva fuori solo al boot.
Mi spiego.
Il programma deve leggere il file continuamente, arrivato alla fine ricomincia dall'inizio, e l'esecuzione la facevo iniziare automaticamente ad ogni avvio tramite rc.local. Al boot il primo ciclo di lettura presentava questi fastidiosi delay, i successivi invece no, forse perché il file ormai era stato caricato in cache oppure perché qualcosa al boot interferiva con la lettura.

Infatti, successivamente ho cambiato modalità d'avvio e ho impostato systemd per caricare il programma come servizio.
Sto facendo delle prove e PARE che con systemd questo problema non ci sia più, quindi può essere veramente che un processo che va in esecuzione al boot tramite rc.local sia "disturbato" da qualcosa...

willy_pinguino
Posts: 901
Joined: Sun Jan 22, 2017 9:11 pm

Re: PI2 Raspbian linguaggio C: delay lettura file

Tue May 16, 2017 6:08 am

al boot ci sono tutte le sequenze di avvio del sistema operativo... caricamento dei moduli del kernel, caricamento dei drivers in userspace, test e verifica delle connessioni di rete, e avvio di tutti i vari demoni e servizi presenti in una normale distro...

la prevalenza e l'urgenza di alcuni di questi compiti è sicuramente più alta dell'esecuzione del tuo task, quindi è normale che tu abbia dei delay.

in fase si lettura o in fase di scrittura non cambiauna sd normale è ottimizzata per blocchi grandi e letture sequenziali, se leggi anche solo pochi byte il SO deve comunque accedere in lettura ad un certo blocco e leggerlo, poco importa se a te interessano pochi byte o mega e mega, il blocco lo deve leggere tutto, se poi il file è grande leggerà anche gli altri blocchi e diventerà più efficente, ma leggere solo un blocco e poi passare al blocco successivo che interessa te con una chiamata diversa (attento anche se sono 2 blocchi contigui per il SO sono comunque 2 blocchi diversi perchè l'operazione di accesso va ripetuta) comporta grosse perdite di tempo.

è ovvio che poi ogni file già letto una volta resta cacherato e quindi le successive letture saranno più veloci ma nel momento in cui ingrandirai la dimensione dei files, questa cache di lettura si riempirà velocemente e tornerai ad avere delle latenze, se non usi il preload e non allochi abbastanza memoria per tenere tutto in ram.

Jarni
Posts: 3
Joined: Mon May 15, 2017 6:22 am

Re: PI2 Raspbian linguaggio C: delay lettura file

Tue May 16, 2017 9:33 am

Per il discorso del boot sono arrivato alla stessa conclusione, evidentemente ora systemd fa in modo che il mio programma venga avviato al termine del boot, con meno processi in corso che possono dargli fastidio.

La struttura della SD non mi da problemi, anche leggere un blocco intero è un'operazione che viene eseguita molto velocemente con le nuove SD, ho fatto delle prove di lettura di pezzi di 12kB a oltranza e non ho mai superato il limite di 50ms per ogni operazione.

Volendo posso anche usare un doppio buffer di qualche centinaio di kB e prevedere un thread che mi riempie di dati il buffer che non sto usando. Un sistema ping pong, insomma...
Oppure un buffer circolare, sempre alimentato da un thread parallelo.
Comunque per ora lascio il preload, non ho tempo per esaminare meglio la situazione in questo momento.

Return to “Italiano”