2014-12-24 13 views
5

Stavo scrivendo programmi per contare il tempo di errori di pagina in un sistema Linux. Più precisamente, il kernel del tempo esegue la funzione __do_page_fault.
E in qualche modo ho scritto due variabili globali, denominate pfcount_at_beg e pfcount_at_end, che aumentano una volta quando viene eseguita la funzione __do_page_fault in diverse posizioni della funzione.Confusione del risultato del conteggio di errori di pagina in linux

Per illustrare la funzione modificata va come:

unsigned long pfcount_at_beg = 0; 
unsigned long pfcount_at_end = 0; 
static void __kprobes 
__do_page_fault(...) 
{ 
    struct vm_area_sruct *vma; 
    ... // VARIABLES DEFINITION 
    unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE; 
    pfcount_at_beg++;  // I add THIS 
    ... 
    ... 
    // ORIGINAL CODE OF THE FUNCTION 
    ... 
    pfcount_at_end++;  // I add THIS 
} 

ho aspettato che il valore di pfcount_at_end è inferiore al valore di pfcount_at_beg.

Perché, penso, ogni volta che il kernel esegue le istruzioni del codice pfcount_at_end++, deve aver eseguito pfcount_at_beg++ (Ogni funzione inizia proprio all'inizio del codice).
D'altra parte, poiché ci sono molti condizionali return tra queste due righe di codice.

Tuttavia, il risultato risulta opposto. Il valore di pfcount_at_end è maggiore del valore di pfcount_at_beg.
Io uso printk per stampare queste variabili del kernel attraverso un auto-definito syscall. E ho scritto il programma a livello utente per chiamare lo system call.

Qui è la mia semplice programma syscall e a livello utente:

// syscall 
asmlinkage int sys_mysyscall(void) 
{ 
    printk(KERN_INFO "total pf_at_beg%lu\ntotal pf_at_end%lu\n", pfcount_at_beg, pfcount_at_end) 
    return 0; 
} 

// user-level program 
#include<linux/unistd.h> 
#include<sys/syscall.h> 
#define __NR_mysyscall 223 
int main() 
{ 
    syscall(__NR_mysyscall); 
    return 0; 
} 

C'è qualcuno che sa cosa esattamente è accaduto durante questo?

Proprio ora ho modificato il codice, per rendere pfcount_at_beg e pfcount_at_endstatic. Tuttavia, il risultato non è cambiato, ad esempio il valore di pfcount_at_end è maggiore del valore di pfcount_at_beg. Probabilmente potrebbe essere causato dall'operazione di incremento in-atomico. Sarebbe meglio se usassi il blocco di lettura-scrittura?

+0

Penso che la possibilità più probabile sia che tu abbia un bug nel tuo 'syscall' o programma a livello utente e che le variabili siano mescolate lassù. Anche se un'altra cosa da considerare è se si sta accedendo alle due variabili atomicamente e, in caso contrario, se è probabile che vi siano errori di pagina nel frattempo. – Graeme

+0

@Graeme Ho aggiunto il mio programma 'syscall' e il programma a livello utente nella domanda. Sono relativamente semplici perché è stato un esercizio per sperimentare come 'syscall' è implementato. –

+0

È questo il vero codice syscall? Alla stampante mancano i valori effettivi da stampare. –

risposta

0

L'operatore ++ non è garantito per essere atomico, pertanto i contatori potrebbero subire accessi concorrenti e valori errati. È necessario proteggere l'incremento come sezione critica oppure utilizzare il tipo atomic_t definito in <asm/atomic.h> e le relative funzioni atomic_set() e atomic_add() (e molto altro ancora).

Non collegato direttamente al problema, ma l'uso di uno specifico syscall è eccessivo (ma forse è un esercizio). Una soluzione più leggera potrebbe essere quella di utilizzare una voce /proc (anche un esercizio interessante).