[PATCH] Improvements in speed and readability of fork functions
Juan Perez-Sanchez <[email protected]>
| Newsgroups | org.kernel.vger.linux-8086 |
|---|---|
| Message-ID | <CAD6VGube6U-p027UFhxtRjLFy4KWYkYvG2s=YmJABRn7t2oncQ@mail.gmail.com> |
Hi, Patch to make fork functions faster. Also improve readability of schedule() function. Greetings, Juan PREVIOUS OPERATION AND BUGS 1. Function "kernel/fork.c/find_empty_process()" search for an empty slot in "task" array. It examined every slot in the array and returned the index of the last empty slot, a very inefficient process. It also calculates the amount of empty slots. 2. Function "kernel/fork.c/get_pid()" returns a unique id number. It checked that the id number is unique by looking for it in all slots of the task array, even those marked as unused. It ran through the array using an index. 3. Function "kernel/sched.c/schedule()" used 2 different variables (prev and currentp) to hold the same information. Also, there was an unused variable at the top level of file sched.c. NEW OPERATION 1. A new variable keeps track of the amount of empty slots, modifying its value as slots are taken or released. Another new variable is a pointer to a slot very likely to be empty. The search stops with the first unused slot found, uses and return a pointer to "struct task_struct" instead of an integer index. As result, the new function is faster and more compact. 2. The new get_pid function does not check empty slots, and uses a pointer to "struct task_struct" instead of an integer index. Thus, it is faster and more compact. 3. In file schedule, consolidated the use of two variables with only one, improving readability. Removed unused top level variable. OTHER CHANGES 1. A small optimization to reduce code size was done in files irqtab.c, process.c and printk.c. There is a reduction in code size of 48 bytes. The Image builded without errors. The kernel was tested with QEMU and dioscuri emulators. Also in a PPro pc booting from floppy.
elksK.patch
(application/octet-stream, 7.2 KB)
diff -Nurb elks.orig/arch/i86/kernel/irqtab.c elks/arch/i86/kernel/irqtab.c
--- elks.orig/arch/i86/kernel/irqtab.c 2012-06-28 23:36:16.000000000 -0500
+++ elks/arch/i86/kernel/irqtab.c 2012-06-30 21:54:44.000000000 -0500
@@ -78,12 +78,10 @@
#ifndef CONFIG_CONSOLE_BIOS
- lea ax,_irq1 ;keyboard
seg es
- mov [36],ax
- mov ax,cs
+ mov [36],#_irq1 ;keyboard
seg es
- mov [38],ax
+ mov [38],cs
#endif
#if 0
@@ -95,12 +93,10 @@
mov [42],ax
#endif
- lea ax,_irq3 ;com2
seg es
- mov [44],ax
- mov ax,cs
+ mov [44],#_irq3 ;com2
seg es
- mov [46],ax
+ mov [46],cs
lea ax,_irq4 ;com1
seg es
diff -Nurb elks.orig/arch/i86/kernel/process.c elks/arch/i86/kernel/process.c
--- elks.orig/arch/i86/kernel/process.c 2012-06-28 23:36:05.000000000 -0500
+++ elks/arch/i86/kernel/process.c 2012-06-30 21:28:09.000000000 -0500
@@ -206,24 +206,22 @@
!
_ret_from_syscall:
cli
- mov dx,ax
mov bx,_current
!
-! At this point, the kernel stack is empty. Thus, there in no
+! At this point, the kernel stack is empty. Thus, there is no
! need to save the kernel stack pointer.
!
mov sp,TASK_USER_SP[bx]
- mov ax,TASK_USER_SS[bx]
+ mov bx,TASK_USER_SS[bx]
!
! User segment recovery
!
- mov ds,ax
- mov es,ax
- mov ss,ax
+ mov ds,bx
+ mov es,bx
+ mov ss,bx
!
! return with error info.
!
- mov ax,dx
iret
!
! Done.
@@ -272,19 +270,17 @@
mov bp,sp
mov bx,4[bp] ! new task ksp
mov ax,6[bp] ! new task start address
+ pop bp
mov -2[bx],ax ! Return address
- mov ax,[bp] ! Caller BP
- mov -4[bx],ax ! Save caller BP
+ mov -4[bx],bp ! Save caller BP
pushf
- pop ax
- mov -6[bx],ax ! Flags
+ pop -6[bx] ! Flags
mov -8[bx],di
mov -10[bx],si
mov -12[bx],bx
mov -14[bx],dx
mov ax,#14
- pop bp
ret
#endif
#endasm
@@ -465,8 +461,7 @@
#ifndef S_SPLINT_S
#asm
mov bx,[bp] ! bx = bp on entry to arch_build_stack
- mov ax,[bx] ! ax = bp on entry to do_fork = users bp (hopefully!)
- mov bx,ax
+ mov bx,[bx] ! ax = bp on entry to do_fork = users bp (hopefully!)
mov ax,[bx] ! ax = bp on entry to do_fork = users bp (hopefully!)
mov _saved_bp,ax
#endasm
diff -Nurb elks.orig/kernel/exit.c elks/kernel/exit.c
--- elks.orig/kernel/exit.c 2012-05-11 13:26:27.000000000 -0500
+++ elks/kernel/exit.c 2012-06-30 00:05:11.000000000 -0500
@@ -10,6 +10,9 @@
#include <linuxmt/errno.h>
#include <linuxmt/mm.h>
+extern int task_slots_unused;
+extern struct task_struct *next_task_slot;
+
/* Note: sys_wait only keeps *one* task in the task_struct right now...
* this is different than V7 symantics I think, but good enough for 0.0.51
* Whoops - we have to do wait3 for now :)
@@ -109,6 +112,8 @@
/* Now the task should never run again... - I hope this can still
* be used outside of an int... :) */
current->state = TASK_UNUSED;
+ next_task_slot = current;
+ task_slots_unused++;
wake_up(&parent->child_wait);
schedule();
panic("Returning from sys_exit!\n");
diff -Nurb elks.orig/kernel/fork.c elks/kernel/fork.c
--- elks.orig/kernel/fork.c 2012-05-11 13:26:27.000000000 -0500
+++ elks/kernel/fork.c 2012-06-30 00:05:11.000000000 -0500
@@ -5,31 +5,29 @@
#include <linuxmt/mm.h>
#include <linuxmt/sched.h>
+int task_slots_unused = MAX_TASKS - 2;
+struct task_struct *next_task_slot = &task[2];
+
/*
* Find a free task slot.
*/
-static pid_t find_empty_process(void)
+static struct task_struct *find_empty_process(void)
{
-/* register pid_t i, unused = 0; */
- register char *pi;
- register char *punused;
- pid_t n;
+ register struct task_struct *t;
- pi = punused = 0;
- do {
- if (task[(int)pi].state == TASK_UNUSED) {
- punused++;
- n = (int)pi;
+ if (task_slots_unused <= 1) {
+ printk("Only %d slots\n", task_slots_unused);
+ if (!task_slots_unused || current->uid)
+ return NULL;
}
- } while (((int)(++pi)) < MAX_TASKS);
-
- if (((int)punused) <= 1) {
- printk("Only %d slots\n", (int)punused);
- if (!punused || current->uid)
- return -EAGAIN;
+ t = next_task_slot;
+ while (t->state != TASK_UNUSED) {
+ if (++t >= &task[MAX_TASKS])
+ t = &task[1];
}
-
- return n;
+ next_task_slot = t;
+ task_slots_unused--;
+ return t;
}
@@ -37,21 +35,20 @@
{
register struct task_struct *p;
static pid_t last_pid = 0;
-/* register int i; */
- register char *pi;
repeat:
- if ( (++last_pid & 0x7fff) == 0 )
+ if (++last_pid < 0)
last_pid = 1;
- pi = 0;
+ p = &task[0];
do {
- p = &task[(int)pi];
+ if (p->state == TASK_UNUSED)
+ continue;
if (p->pid == last_pid || p->pgrp == last_pid ||
p->session == last_pid) {
goto repeat;
}
- } while (((int)(++pi)) < MAX_TASKS);
+ } while (++p < &task[MAX_TASKS]);
return last_pid;
}
@@ -62,14 +59,12 @@
pid_t do_fork(int virtual)
{
register struct task_struct *t;
- pid_t i = find_empty_process(), j;
+ pid_t j;
struct file *filp;
register __ptask currentp = current;
- if (i < 0)
- return i;
-
- t = &task[i];
+ if((t = find_empty_process()) == NULL)
+ return -EAGAIN;
/* Copy everything */
@@ -90,6 +85,8 @@
if (t->mm.dseg == NULL) {
mm_free(currentp->mm.cseg);
t->state = TASK_UNUSED;
+ task_slots_unused++;
+ next_task_slot = t;
return -ENOMEM;
}
diff -Nurb elks.orig/kernel/printk.c elks/kernel/printk.c
--- elks.orig/kernel/printk.c 2012-05-11 13:26:27.000000000 -0500
+++ elks/kernel/printk.c 2012-06-30 14:10:09.000000000 -0500
@@ -44,10 +44,10 @@
static void kputs(register char *buf)
{
- char ch, *p;
-
#ifdef CONFIG_DCON_ANSI_PRINTK
+ char *p;
+
/* Colourizing */
static char colour[8] = { 27, '[', '3', '0', ';', '4', '0', 'm' };
@@ -64,8 +64,8 @@
#endif
- while ((ch = *buf++))
- kputchar(ch);
+ while (*buf)
+ kputchar(*buf++);
}
/************************************************************************
diff -Nurb elks.orig/kernel/sched.c elks/kernel/sched.c
--- elks.orig/kernel/sched.c 2012-06-28 23:36:16.000000000 -0500
+++ elks/kernel/sched.c 2012-06-30 20:07:28.000000000 -0500
@@ -20,7 +20,7 @@
__task task[MAX_TASKS];
unsigned char nr_running;
-__ptask current, next, previous;
+__ptask current, previous;
extern int intr_count;
@@ -79,7 +79,6 @@
{
register __ptask prev;
register __ptask next;
- __ptask currentp = current;
jiff_t timeout = 0L;
prev = current;
@@ -87,7 +86,7 @@
if (prev->t_kstackm != KSTACK_MAGIC)
panic("Process %d exceeded kernel stack limit! magic %x\n",
- currentp->pid, currentp->t_kstackm);
+ prev->pid, prev->t_kstackm);
/* We have to let a task exit! */
if (prev->state == TASK_EXITING)
@@ -122,7 +121,7 @@
next = next->next_run;
}
- if (next != currentp) {
+ if (next != prev) {
struct timer_list timer;
if (timeout) {
@@ -161,7 +160,7 @@
* quite legal. We just dont switch then */
/* if (intr_count > 0) */
printk("Aiee: scheduling in interrupt %d - %d %d\n",
- intr_count, currentp->pid, prev->pid);
+ intr_count, next->pid, prev->pid);
}
struct timer_list tl_list = { NULL, NULL, 0L, 0, NULL };