2014-12-24 6 views
5

Ich schrieb Programme, um die Zeit von Seitenfehlern in einem Linux-System zu zählen. Genauer gesagt, der Zeitkern führt die Funktion __do_page_fault aus.
Und irgendwie schrieb ich zwei globale Variablen, genannt pfcount_at_beg und pfcount_at_end, die einmal erhöhen, wenn die Funktion __do_page_fault an verschiedenen Stellen der Funktion ausgeführt wird.Verwirrendes Ergebnis vom Zählen von Seitenfehlern in Linux

Zur Veranschaulichung, geht die modifizierte Funktion als:

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 
} 

ich, dass der Wert von pfcount_at_end erwartet ist kleiner als der Wert von pfcount_at_beg.

Weil ich denke, jedes Mal, wenn Kernel die Anweisungen des Codes pfcount_at_end++ ausführt, muss es pfcount_at_beg++ ausgeführt haben (Jede Funktion beginnt ganz am Anfang des Codes).
Auf der anderen Seite gibt es viele bedingte return zwischen diesen beiden Codezeilen.

Das Ergebnis ergibt sich jedoch entgegengesetzt. Der Wert pfcount_at_end ist größer als der Wert pfcount_at_beg.
Ich verwende printk, um diese Kernelvariablen über eine selbst definierte syscall zu drucken. Und ich schrieb das Benutzerlevelprogramm, um die system call anzurufen.

Hier ist meine einfache syscall und User-Level-Programm:

// 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; 
} 

Gibt es jemand, der genau weiß, was während dies geschehen?

Gerade jetzt habe ich den Code geändert, um pfcount_at_beg und pfcount_at_endstatic zu machen. Das Ergebnis hat sich jedoch nicht geändert, d. H. Der Wert pfcount_at_end ist größer als der Wert pfcount_at_beg. So möglicherweise könnte es durch atomare Operation von Inkrement verursacht werden. Wäre es besser, wenn ich Lese-Schreib-Sperre verwende?

+0

Ich denke, dass die wahrscheinlichste Möglichkeit hier ist, dass Sie einen Fehler in Ihrem 'syscall'- oder Benutzerlevel-Programm haben und dass Sie die Variablen dort durcheinander bringen. Eine andere Sache, die Sie in Betracht ziehen sollten, ist, ob Sie auf die beiden Variablen atomar zugreifen und ob nicht, ob zwischenzeitlich Seitenfehler vorliegen. – Graeme

+0

@Graeme Ich habe mein 'syscall'-Programm und das Benutzerlevel-Programm in der Frage hinzugefügt. Sie sind relativ einfach, weil es eine Übung war, um zu erfahren, wie 'syscall' implementiert wird. –

+0

Ist das der echte Syscall-Code? Dem printk fehlen die tatsächlichen zu druckenden Werte. –

Antwort

0

Der Operator ++ ist nicht garantiert atomar, daher können Ihre Zähler gleichzeitig Zugriff haben und falsche Werte haben. Sie sollten Ihr Inkrement als kritischen Abschnitt schützen oder den atomic_t-Typ verwenden, der in <asm/atomic.h> definiert ist, und die zugehörigen Funktionen atomic_set() und atomic_add() (und vieles mehr).

Nicht direkt mit Ihrem Problem verbunden, aber mit einem bestimmten Syscall ist Overkill (aber vielleicht ist es eine Übung). Eine leichtere Lösung könnte ein /proc Eintrag sein (auch eine interessante Übung).

Verwandte Themen