From: Juan Perez-Sanchez <lithoxs@gmail.com>
To: linux-8086 <linux-8086@vger.kernel.org>
Subject: [PATCH] Improvements in speed and readability of fork functions
Date: Sat, 7 Jul 2012 09:59:00 -0500 [thread overview]
Message-ID: <CAD6VGube6U-p027UFhxtRjLFy4KWYkYvG2s=YmJABRn7t2oncQ@mail.gmail.com> (raw)
[-- Attachment #1: Type: text/plain, Size: 1776 bytes --]
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.
[-- Attachment #2: elksK.patch --]
[-- Type: application/octet-stream, Size: 7370 bytes --]
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 };
reply other threads:[~2012-07-07 14:59 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to='CAD6VGube6U-p027UFhxtRjLFy4KWYkYvG2s=YmJABRn7t2oncQ@mail.gmail.com' \
--to=lithoxs@gmail.com \
--cc=linux-8086@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).