Hallo zusammen,
Ich wollte den Performanceunterschied zwischen den Assembler-Instructionen "int" (im Folgenden als Interrupt bezeichet) und "syscall" (im Folgenden als Syscall bezeichet) messen. Dazu habe ich eine Schleife gemacht, die 100'000'000 mal durchlaufen wird. Einmal wird dann ein Interrupt ausgelöst und das andere Mal wird ein Syscall ausgeführt. Vor und nach der Schleife speichere ich die aktuelle Laufzeit des ganzen System ab und gib am Schluss die Differenz der beiden Werte aus, also die gesamte Zeit, die die Schleife benötigt hat. Die Uptime wird vom Handler, der die Interrupts vom PIT handelt, incrementiert. Der PIT löst jede Millisekunde einen Interrupt aus. Das funktioniert soweit sehr gut. In meiner Shell kann man die aktuelle Uptime ausgeben lassen und die stimmt.
Jetzt ist das Problem, dass die Anfangszeit der Schleife immer gleich ist wie die Endzeit, was dazu führt, dass 0ms ausgegeben wird, was nicht stimmen kann, da es schon ein paar Sekunden dauert bis die Schleife beendet ist. Nach ein bisschen Debuggen ist mir aufgefallen, dass während der Schleife keine Timer-Interrupts mehr ausgelöst werden und dadurch wird auch Uptime nicht mehr incrementiert.
Nach der Schleife wird Uptime wieder incrementiert. Dieses Verhalten habe ich sowohl mit Interrupts als auch mit Syscalls.
In den Syscalls und im entsprechenden Interrupt werden Interrupts nicht deaktiviert, also sollte Uptime hoch gezählt werden, was anscheinend nicht der Fall ist.
Wieso gibt es einen "Unterbruch" der Timer-Interrupts? Sind das zu viele Interrupts für die CPU? Aber wieso passiert das dann auch bei Syscall?
Hier die entsprechende Funktion:
static void perftest()
{
size_t i, count;
SIS start, end;
uint64_t time;
printf("Starting performance test:\n");
getSysInfo(&start);
for(i = 0; i < 100000000; i++)
{
asm volatile("int $48": "=a"(count): "D"(61));
}
getSysInfo(&end);
asm volatile("int $48":: "D"(62));
time = end.Uptime - start.Uptime;
printf("Interrupts: %zu in %lums => %f/s\n", count, time, count / (double)(time?:1000.0) * 1000);
getSysInfo(&start);
for(i = 0; i < 100000000; i++)
{
asm volatile("mov %1,%%rdi;syscall": "=a"(count): "i"(61): "rcx", "rdx", "rsi", "rdi", "r8", "r9", "r10", "r11");
}
getSysInfo(&end);
asm volatile("mov %0,%%rdi;syscall":: "i"(62): "rax", "rcx", "rdx", "rsi", "rdi", "r8", "r9", "r10", "r11");
time = end.Uptime - start.Uptime;
printf("Syscalls: %zu in %lums => %f/s\n", count, time, count / (double)(time?:1000.0) * 1000);
printf("End of performance test\n");
}
getSysInfo() ist die Funktion die mir die Uptime (und noch andere Infos) zurückgibt.
Hier die entsprechenden Funktionen, die durch Interrupts oder durch Syscalls aufgerufen werden (Funktionsnummer steht im rdi-Register):
static uint64_t count = 0;
static uint64_t perfTest() //Funktion 61
{
return ++count;
}
static void resetPerfTest() //Funktion 62
{
count = 0;
}
Das ganze läuft in meiner Shell im Userspace.
Ich hoffe ihr könnt mir helfen.
Ansonsten wünsche ich euch noch einen schönen Abend.