linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* Fwd: [Lse-tech] get_pid() performance fix
@ 2002-03-05  1:57 Hubertus Franke
  2002-03-05 16:26 ` OGAWA Hirofumi
  2002-03-07  3:56 ` Rusty Russell
  0 siblings, 2 replies; 19+ messages in thread
From: Hubertus Franke @ 2002-03-05  1:57 UTC (permalink / raw)
  To: linux-kernel, lse-tech

[-- Attachment #1: Type: text/plain, Size: 4033 bytes --]


Can somebody post why this patch shouldn't be picked up ?
The attached program shows the problem in user space 
and the patch is almost trivial ..

-- Hubertus

----------  Forwarded Message  ----------

Subject: [Lse-tech] get_pid() performance fix
Date: Tue, 26 Feb 2002 18:58:51 -0500
From: "Rajan Ravindran" <rajancr@us.ibm.com>
To: lse-tech@lists.sourceforge.net
Cc: linux-kernel@vger.kernel.org, davej@suse.de

Paul Larson posted a patch which fixes the get_pid() hang,
if we run out of available pids. Nevertheless, we have
observed that it takes a long time to find the next available
pid once the last pid reaches the PID_MAX. This is due to
a constant rescan of the task list while progressing only one
pid at time, yielding an O(n**2) problem.
Here is a patch (together with Paul's fix) which eliminates the
time taken to search for an available pid, by not constantly
restarting the search through the entire task list.

Attached is also a user level test program getpid.c),
by which one can simulate creation and deletion of processes.
This application will measure the time taken for the get_pid()
routine to find the next available process.

example:
      getpid -p 32770 -n 3

which will try to create 32770 process, eventually get_pid can't
find any free pid after 32767, so it will delete 3 pids randomly
from the existing list and start calculating the time taken to
find the available pid (which we deleted).

In getpid.c the new fixes  are inside the #define NEW_METHOD.
Try compiling the getpid.c with and without -DNEW_METHOD compile
option to see the performance improvement.

here is an example output for the old and the new algorithm and
their respective execution time to find a new pid.

(See attached file: output)

This can/should be applied to 2.5 and 2.4 kernels.


(See attached file: getpid.c)

Thanks,
Rajan


diff -Naur linux-2.5.5/kernel/fork.c linux-2.5.5-new/kernel/fork.c
--- linux-2.5.5/kernel/fork.c Tue Feb 19 21:10:55 2002
+++ linux-2.5.5-new/kernel/fork.c   Tue Feb 26 15:46:36 2002
@@ -24,6 +24,7 @@
 #include <linux/file.h>
 #include <linux/binfmts.h>
 #include <linux/fs.h>
+#include <linux/compiler.h>

 #include <asm/pgtable.h>
 #include <asm/pgalloc.h>
@@ -129,12 +130,13 @@
 {
      static int next_safe = PID_MAX;
      struct task_struct *p;
-     int pid;
+     int pid, beginpid;

      if (flags & CLONE_PID)
            return current->pid;

      spin_lock(&lastpid_lock);
+     beginpid = last_pid;
      if((++last_pid) & 0xffff8000) {
            last_pid = 300;         /* Skip daemons etc. */
            goto inside;
@@ -153,13 +155,18 @@
                              if(last_pid & 0xffff8000)
                                    last_pid = 300;
                              next_safe = PID_MAX;
+                             goto repeat;
                        }
-                       goto repeat;
+                       if(unlikely(last_pid == beginpid))
+                             goto nomorepids;
+                       continue;
                  }
                  if(p->pid > last_pid && next_safe > p->pid)
                        next_safe = p->pid;
                  if(p->pgrp > last_pid && next_safe > p->pgrp)
                        next_safe = p->pgrp;
+                 if(p->tgid > last_pid && next_safe > p->tgid)
+                       next_safe = p->tgid;
                  if(p->session > last_pid && next_safe > p->session)
                        next_safe = p->session;
            }
@@ -169,6 +176,11 @@
      spin_unlock(&lastpid_lock);

      return pid;
+
+nomorepids:
+     read_unlock(&tasklist_lock);
+     spin_unlock(&lastpid_lock);
+     return 0;
 }

 static inline int dup_mmap(struct mm_struct * mm)
@@ -667,6 +679,8 @@

      copy_flags(clone_flags, p);
      p->pid = get_pid(clone_flags);
+     if (p->pid == 0 && current->pid != 0)
+           goto bad_fork_cleanup;

      INIT_LIST_HEAD(&p->run_list);

-------------------------------------------------------



-- 
-- Hubertus Franke  (frankeh@watson.ibm.com)

[-- Attachment #2: output --]
[-- Type: application/octet-stream, Size: 1014 bytes --]

./getpid -p 32771 -n 4 

Output when compiled without -DNEW_METHOD
-----------------------------------------
nprocs: 32771, ndelete:0, nitems:4
start creating 32771 processes
reached max pid <32768> reset last_pid to <300>
removed pid: <17767>
removed pid: <9158>
removed pid: <6249>
removed pid: <18547>
spent 1.172945 seconds in finding free pid <6249>
spent 2.519057 seconds in finding free pid <9158>
spent 9.857908 seconds in finding free pid <17767>
spent 10.924213 seconds in finding free pid <18547>


Output when compiled with -DNEW_METHOD
--------------------------------------
nprocs: 32771, ndelete:0, nitems:4
start creating 32771 processes
reached max pid <32768> reset last_pid to <300>
removed pid: <17767>
removed pid: <9158>
spent 0.18468 seconds in finding free pid <17767>
removed pid: <6249>
removed pid: <18547>
spent 0.30833 seconds in finding free pid <6249>
spent 0.34572 seconds in finding free pid <9158>
spent 0.41594 seconds in finding free pid <18547>


[-- Attachment #3: getpid.c --]
[-- Type: application/octet-stream, Size: 4613 bytes --]

/* 
 * Program to measure the get_pid() function performance
 *
 */

#include <stdio.h>
#include <errno.h>
#include <sched.h>
#include <sys/types.h>
#include <sys/wait.h>         
#include <sys/time.h>         
#include <getopt.h>
#include <stdlib.h>

struct task_struct {
	int pid;
	struct task_struct *next_task;
};	

#define PID_MAX	0x8000
#define GETPID_MASK	0xffff8000
#define STACK_SIZE	8192

struct task_struct *tsk_head;
int last_pid;
unsigned long nprocs;
int verbose;
int start_del;

#define alloc_task_struct() \
	((struct task_struct *)malloc(sizeof(struct task_struct)))
#define for_each_task(p) \
        for (p = tsk_head ; (p = p->next_task) != tsk_head ; ) 

int create_task();
int (*ctask) (void *arg);

int __clone (int (*fn) (void *arg), void *thread_stack, int flags, void *arg); 

int get_pid()
{
	static int next_safe = PID_MAX;
	struct task_struct *p;
	static struct timeval stime, etime;
	static int start_search=0;
	int beginpid;
	long sec,usec;

	beginpid = last_pid;
	if((++last_pid) & GETPID_MASK) {
		printf("reached max pid <%d> reset last_pid to <300>\n", last_pid);
		last_pid = 300;		/* Skip daemons etc. */
		start_del = start_search =1;
        	gettimeofday(&stime, (struct timezone *) 0);   
		goto inside;
	}

#ifdef NEW_METHOD
	if(last_pid >= next_safe) {
inside:
		next_safe = PID_MAX;
	repeat:
       		for (p = tsk_head ; (p = p->next_task) != tsk_head ; ) {
			if(p->pid == last_pid) {
				if(++last_pid >= next_safe) {
					if(last_pid & GETPID_MASK)
					last_pid = 300;
					next_safe = PID_MAX;
					goto repeat;
				}
				continue;
			}
			if(p->pid > last_pid && next_safe > p->pid)
				next_safe = p->pid;
		}
	}
#else
	if(last_pid >= next_safe) {
inside:
		next_safe = PID_MAX;
	repeat:
       		for (p = tsk_head ; (p = p->next_task) != tsk_head ; ) {
			if(p->pid == last_pid) {
				if(++last_pid >= next_safe) {
					if(last_pid & GETPID_MASK)
						last_pid = 300;
					next_safe = PID_MAX;
				}
				goto repeat;
			}
		if(p->pid > last_pid && next_safe > p->pid)
				next_safe = p->pid;
		}
	}
#endif
	if (start_search) {
        	gettimeofday(&etime, (struct timezone *) 0);  
		if ((etime.tv_usec - stime.tv_usec) < 0) {
			sec = (etime.tv_sec - stime.tv_sec) -1;
			usec = stime.tv_usec - etime.tv_usec;
		}
		else {
			sec = (etime.tv_sec - stime.tv_sec);
			usec = etime.tv_usec - stime.tv_usec;
		}
		printf("spent %d.%02d seconds in finding free pid <%d>\n",
                                        sec, usec, last_pid);
	}
	return last_pid;
}

int create_task() {
	struct task_struct *p, *prev;
	unsigned int i;

	prev = tsk_head;
	tsk_head->pid = 0; tsk_head->next_task = tsk_head;
	printf("start creating %d processes\n", nprocs);
	for (i=0; i<nprocs; i++) {
		p = alloc_task_struct();
		p->next_task = tsk_head;
		p->pid = get_pid();
		if (verbose)
			printf("created <%d>\n", p->pid);
		prev->next_task = p;
		prev = prev->next_task;
	}
}

void delete_task(int nitems) {
	struct task_struct *p, *prev;
	unsigned int i;
	long int rand;

	while (!start_del);
	for (i=0; i < nitems; i++) {
		rand = random() % PID_MAX;
        	for (prev = p = tsk_head ; (p = p->next_task) != tsk_head ; ) { 
			if (p->pid == rand) {
				prev->next_task = p->next_task;
				printf("removed pid: <%d>\n", rand);
			}
			prev = p;
		}
	}
	start_del=0;	
}

void usage() {
	printf("Usage: getpid -p <nprocs> -n <npids> -s <seed> -v [verbose]\n");
	printf("       nprocs: number of process to create\n");
	printf("       npids: number of process to delete\n");
	printf("       verbose: print debug strings\n");
}

int main(int argc, char *argv[]) {
	int pid;
	char *stk;
	int wait_status, rc;
	int c, nitems=0;

        while ((c = getopt(argc, argv, "p:s:n:v:")) != -1) {
          switch(c) {
                case 'p': nprocs = atoi(optarg); break;
                case 'n': nitems = atoi(optarg); break;
		case 's': srand(atoi(optarg)); break;
                case 'v': verbose = 1; break;
                default: usage(); return 0;
          }
        }

	if ((nprocs == 0) || (nitems > PID_MAX)) {
		printf("Invalid parameter\n");
		usage();
		return 0;
	}
	tsk_head = alloc_task_struct();
	stk = (char *)malloc(2 * STACK_SIZE);

	ctask = create_task;
	pid = __clone(ctask, &stk[STACK_SIZE],  CLONE_VM | CLONE_FS | CLONE_SIGHAND, (void *)0);
	if (pid == -1)
		printf("errno=%d <%s>\n", errno,strerror(errno));
	
	delete_task(nitems);
	waitpid(-1, &wait_status, __WCLONE);
}

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: Fwd: [Lse-tech] get_pid() performance fix
  2002-03-05  1:57 Fwd: [Lse-tech] get_pid() performance fix Hubertus Franke
@ 2002-03-05 16:26 ` OGAWA Hirofumi
  2002-03-05 16:43   ` Hubertus Franke
  2002-03-07  3:56 ` Rusty Russell
  1 sibling, 1 reply; 19+ messages in thread
From: OGAWA Hirofumi @ 2002-03-05 16:26 UTC (permalink / raw)
  To: frankeh; +Cc: linux-kernel, lse-tech

Hubertus Franke <frankeh@watson.ibm.com> writes:

> @@ -153,13 +155,18 @@
>                               if(last_pid & 0xffff8000)
>                                     last_pid = 300;
>                               next_safe = PID_MAX;
> +                             goto repeat;
>                         }
> -                       goto repeat;
> +                       if(unlikely(last_pid == beginpid))
> +                             goto nomorepids;
> +                       continue;

It isn't guaranteed that pid is unique.

In the case:
	task->pid = 300, task->xxx = 301
	pid 301 is free

	This get_pid() returns 301.

Regards.
-- 
OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: Fwd: [Lse-tech] get_pid() performance fix
  2002-03-05 16:26 ` OGAWA Hirofumi
@ 2002-03-05 16:43   ` Hubertus Franke
  0 siblings, 0 replies; 19+ messages in thread
From: Hubertus Franke @ 2002-03-05 16:43 UTC (permalink / raw)
  To: OGAWA Hirofumi; +Cc: linux-kernel, lse-tech

On Tuesday 05 March 2002 11:26 am, OGAWA Hirofumi wrote:
> Hubertus Franke <frankeh@watson.ibm.com> writes:
> > @@ -153,13 +155,18 @@
> >                               if(last_pid & 0xffff8000)
> >                                     last_pid = 300;
> >                               next_safe = PID_MAX;
> > +                             goto repeat;
> >                         }
> > -                       goto repeat;
> > +                       if(unlikely(last_pid == beginpid))
> > +                             goto nomorepids;
> > +                       continue;
>
> It isn't guaranteed that pid is unique.
>
> In the case:
> 	task->pid = 300, task->xxx = 301
> 	pid 301 is free
>
> 	This get_pid() returns 301.
>
> Regards.

No the point of this patch was to limit the search time for finding
the next available pid. We are not mocking around with the 
logic that declares a pid available or not. That stays the same.
However, one doesn't need to start every single time from the
beginning to find the next available pid.

-- 
-- Hubertus Franke  (frankeh@watson.ibm.com)

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: Fwd: [Lse-tech] get_pid() performance fix
  2002-03-05  1:57 Fwd: [Lse-tech] get_pid() performance fix Hubertus Franke
  2002-03-05 16:26 ` OGAWA Hirofumi
@ 2002-03-07  3:56 ` Rusty Russell
  2002-03-07 14:35   ` Hubertus Franke
  2002-03-07 15:21   ` Dave McCracken
  1 sibling, 2 replies; 19+ messages in thread
From: Rusty Russell @ 2002-03-07  3:56 UTC (permalink / raw)
  To: frankeh; +Cc: linux-kernel, lse-tech

On Mon, 4 Mar 2002 20:57:49 -0500
Hubertus Franke <frankeh@watson.ibm.com> wrote:

> 
> Can somebody post why this patch shouldn't be picked up ?
> The attached program shows the problem in user space 
> and the patch is almost trivial ..

At a cursory glance, this seems to be three patches:
	1) Fix the get_pid() hang.
	2) Speed up get_pid().
	3) And this piece I'm not sure about:
> +                 if(p->tgid > last_pid && next_safe > p->tgid)
> +                       next_safe = p->tgid;

Please split, and send the fix get_pid() hang to trivial patch monkey,
and push optimization to Linus.

Cheers!
Rusty.
-- 
  Anyone who quotes me in their sig is an idiot. -- Rusty Russell.

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: Fwd: [Lse-tech] get_pid() performance fix
  2002-03-07  3:56 ` Rusty Russell
@ 2002-03-07 14:35   ` Hubertus Franke
  2002-03-07 14:54     ` Guest section DW
  2002-03-07 15:21   ` Dave McCracken
  1 sibling, 1 reply; 19+ messages in thread
From: Hubertus Franke @ 2002-03-07 14:35 UTC (permalink / raw)
  To: Rusty Russell, rajancr; +Cc: linux-kernel, lse-tech

On Wednesday 06 March 2002 10:56 pm, Rusty Russell wrote:
> On Mon, 4 Mar 2002 20:57:49 -0500
>
> Hubertus Franke <frankeh@watson.ibm.com> wrote:
> > Can somebody post why this patch shouldn't be picked up ?
> > The attached program shows the problem in user space
> > and the patch is almost trivial ..
>
> At a cursory glance, this seems to be three patches:
> 	1) Fix the get_pid() hang.
> 	2) Speed up get_pid().
>
> 	3) And this piece I'm not sure about:
> > +                 if(p->tgid > last_pid && next_safe > p->tgid)
> > +                       next_safe = p->tgid;
>
> Please split, and send the fix get_pid() hang to trivial patch monkey,
> and push optimization to Linus.
>
> Cheers!
> Rusty.

Thanks, patch was bad and not properly functioning as pointed out to us.
We are rewriting right now (actually <rajancr@us.ibm.com> 
is doing the coding. I am just there for idea bouncing
easy if the office is 2 doors away.

1) was done by Greg Larson and was already submitted
2) once properly done, we will circulate before bothering Linus again
3) this must have come in because of a wrong patch generation.

-- 
-- Hubertus Franke  (frankeh@watson.ibm.com)

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: Fwd: [Lse-tech] get_pid() performance fix
  2002-03-07 14:35   ` Hubertus Franke
@ 2002-03-07 14:54     ` Guest section DW
  2002-03-07 19:07       ` Hubertus Franke
  0 siblings, 1 reply; 19+ messages in thread
From: Guest section DW @ 2002-03-07 14:54 UTC (permalink / raw)
  To: Hubertus Franke; +Cc: Rusty Russell, rajancr, linux-kernel, lse-tech

On Thu, Mar 07, 2002 at 09:35:09AM -0500, Hubertus Franke wrote:
...

Long ago I submitted a patch that changed the max pid from 15 bits to
24 or 30 bits or so. (And of course removed the inefficiency noticed
by some people in the current thread.)
Probably this is a good moment to try and see what Linus thinks
about this today.

[Of course Albert Cahalan will object that this is bad for the columns
of ps output. Maybe Alan will mutter something about sysvipc.
Roughly speaking there are only advantages, especially since
I think we'll have to do this sooner or later, and in such cases
sooner is better.]

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: Fwd: [Lse-tech] get_pid() performance fix
  2002-03-07  3:56 ` Rusty Russell
  2002-03-07 14:35   ` Hubertus Franke
@ 2002-03-07 15:21   ` Dave McCracken
  1 sibling, 0 replies; 19+ messages in thread
From: Dave McCracken @ 2002-03-07 15:21 UTC (permalink / raw)
  To: frankeh, Rusty Russell, rajancr; +Cc: linux-kernel, lse-tech



--On Thursday, March 07, 2002 09:35:09 AM -0500 Hubertus Franke
<frankeh@watson.ibm.com> wrote:

>> At a cursory glance, this seems to be three patches:
>> 	1) Fix the get_pid() hang.
>> 	2) Speed up get_pid().
>> 
>> 	3) And this piece I'm not sure about:
>> > +                 if(p->tgid > last_pid && next_safe > p->tgid)
>> > +                       next_safe = p->tgid;

> 1) was done by Greg Larson and was already submitted
> 2) once properly done, we will circulate before bothering Linus again
> 3) this must have come in because of a wrong patch generation.

Actually that was Paul Larson, but close enough :)

3) is actually a separate bugfix.  I had a patch accepted some time back
that added the check for tgid, but missed adding it to the section below.
Paul caught it when he did his patch and added it for me.

Dave McCracken

======================================================================
Dave McCracken          IBM Linux Base Kernel Team      1-512-838-3059
dmccr@us.ibm.com                                        T/L   678-3059


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: Fwd: [Lse-tech] get_pid() performance fix
  2002-03-07 14:54     ` Guest section DW
@ 2002-03-07 19:07       ` Hubertus Franke
  2002-03-07 19:44         ` Richard B. Johnson
  2002-03-07 19:46         ` Guest section DW
  0 siblings, 2 replies; 19+ messages in thread
From: Hubertus Franke @ 2002-03-07 19:07 UTC (permalink / raw)
  To: Guest section DW; +Cc: Rusty Russell, rajancr, linux-kernel, lse-tech

On Thursday 07 March 2002 09:54 am, Guest section DW wrote:
> On Thu, Mar 07, 2002 at 09:35:09AM -0500, Hubertus Franke wrote:
> ...
>
> Long ago I submitted a patch that changed the max pid from 15 bits to
> 24 or 30 bits or so. (And of course removed the inefficiency noticed
> by some people in the current thread.)
> Probably this is a good moment to try and see what Linus thinks
> about this today.
>
> [Of course Albert Cahalan will object that this is bad for the columns
> of ps output. Maybe Alan will mutter something about sysvipc.
> Roughly speaking there are only advantages, especially since
> I think we'll have to do this sooner or later, and in such cases
> sooner is better.]

I don't think that will solve the N^2 problem you still have the algorithm
do the following:

       if (++last_pid > next_safe) {
 repeat:	
	last_pid++;
	foralltasks p:
		deal with wraparound;
		if (p uses last_pid) goto repeat
		determine next_safe
	}
[ last_pid  ... next_safe ) is the range that can be saftely used

By extending it to 24 or larger bits all you do is handle the wraparound
at some later point and less frequent It also becomes expensive if a large 
number of threads is present. 
Well, the problem can be fixed. Even in the current 16 bit approach.
What we are experimenting around
is a <mark-and-sweep> algorithm that would be invoked if the nr_threads is 
above a threshold. 
The algorithm would do something like this. Rajan will code it up and see
its efficacy.

if (last_pid >= next_safe) {
inside:
	if (nr_threads > threshold) {  // constant 
		last_pid = get_pid_map(last_pid,&next_safe);
	} else {
	 	.. <as now>
	}
}

static unsigned long pid_map[1<<12];

/* determine a range of pids that is available for sure 
 *   [ last_pid .. next_safe ) 
 * pid_map has stale information. some pids might be marked
 * as used even if they had been freed in the meantime
 */

int get_pid_map(int last_pid, int *next_safe)
{
	int again = 1;
repeat:
	for_each_task(p)
		mark_pids_in_bitmap;
		last_pid = ffz(pid_map);   /* we will start from last_pid with wraparound */
		if ((last_pid == -1) && (again)) {
			again = 0;
			memset(pid_map,0);
			goto repeat
		}
	}
	next_safe = first_non_zero(pid_map,last_pid); /* starting from last_pid */
	return last_pid;
}



Note, if the pid map is to large, it can be done in smaller sections or 
windows. Also, note keeping stale information is OK actually desirable, as
it avoids the sweep in almost all cases.
			
-- 
-- Hubertus Franke  (frankeh@watson.ibm.com)

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: Fwd: [Lse-tech] get_pid() performance fix
  2002-03-07 19:07       ` Hubertus Franke
@ 2002-03-07 19:44         ` Richard B. Johnson
  2002-03-07 19:46         ` Guest section DW
  1 sibling, 0 replies; 19+ messages in thread
From: Richard B. Johnson @ 2002-03-07 19:44 UTC (permalink / raw)
  To: Hubertus Franke
  Cc: Guest section DW, Rusty Russell, rajancr, linux-kernel, lse-tech

On Thu, 7 Mar 2002, Hubertus Franke wrote:

> On Thursday 07 March 2002 09:54 am, Guest section DW wrote:
> > On Thu, Mar 07, 2002 at 09:35:09AM -0500, Hubertus Franke wrote:
> > ...
> >
> > Long ago I submitted a patch that changed the max pid from 15 bits to
> > 24 or 30 bits or so. (And of course removed the inefficiency noticed
> > by some people in the current thread.)
> > Probably this is a good moment to try and see what Linus thinks
> > about this today.
> >
> > [Of course Albert Cahalan will object that this is bad for the columns
> > of ps output. Maybe Alan will mutter something about sysvipc.
> > Roughly speaking there are only advantages, especially since
> > I think we'll have to do this sooner or later, and in such cases
> > sooner is better.]
> 
> I don't think that will solve the N^2 problem you still have the algorithm
> do the following:
> 
>        if (++last_pid > next_safe) {
>  repeat:	
> 	last_pid++;
> 	foralltasks p:
> 		deal with wraparound;
> 		if (p uses last_pid) goto repeat
> 		determine next_safe
> 	}
> [ last_pid  ... next_safe ) is the range that can be saftely used
> 
> By extending it to 24 or larger bits all you do is handle the wraparound
> at some later point and less frequent It also becomes expensive if a large 
> number of threads is present. 
> Well, the problem can be fixed. Even in the current 16 bit approach.
> What we are experimenting around
> is a <mark-and-sweep> algorithm that would be invoked if the nr_threads is 
> above a threshold. 
> The algorithm would do something like this. Rajan will code it up and see
> its efficacy.
> 
> if (last_pid >= next_safe) {
> inside:
> 	if (nr_threads > threshold) {  // constant 
> 		last_pid = get_pid_map(last_pid,&next_safe);
> 	} else {
> 	 	.. <as now>
> 	}
> }
> 
> static unsigned long pid_map[1<<12];
> 
> /* determine a range of pids that is available for sure 
>  *   [ last_pid .. next_safe ) 
>  * pid_map has stale information. some pids might be marked
>  * as used even if they had been freed in the meantime
>  */
> 
> int get_pid_map(int last_pid, int *next_safe)
> {
> 	int again = 1;
> repeat:
> 	for_each_task(p)
> 		mark_pids_in_bitmap;
> 		last_pid = ffz(pid_map);   /* we will start from last_pid with wraparound */
> 		if ((last_pid == -1) && (again)) {
> 			again = 0;
> 			memset(pid_map,0);
> 			goto repeat
> 		}
> 	}
> 	next_safe = first_non_zero(pid_map,last_pid); /* starting from last_pid */
> 	return last_pid;
> }
> 
> 
> 
> Note, if the pid map is to large, it can be done in smaller sections or 
> windows. Also, note keeping stale information is OK actually desirable, as
> it avoids the sweep in almost all cases.
> 			
> -- 
> -- Hubertus Franke  (frankeh@watson.ibm.com)
> -

If security issues were not a concern, you save the last PID, freed at
_exit() and use that immediately. If it's already used, it's zeroed.
exit() just stuffs the exit() PID into the variable, overwriting any
previous, including zero. It needs to be handled under a lock, but
it gets a quick return on investment for the usual fork() exec() stuff
that interactive users use.

Cheers,
Dick Johnson

Penguin : Linux version 2.4.18 on an i686 machine (799.53 BogoMips).

	Bill Gates? Who?


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: Fwd: [Lse-tech] get_pid() performance fix
  2002-03-07 19:07       ` Hubertus Franke
  2002-03-07 19:44         ` Richard B. Johnson
@ 2002-03-07 19:46         ` Guest section DW
  2002-03-07 23:14           ` Hubertus Franke
  1 sibling, 1 reply; 19+ messages in thread
From: Guest section DW @ 2002-03-07 19:46 UTC (permalink / raw)
  To: Hubertus Franke; +Cc: Rusty Russell, rajancr, linux-kernel, lse-tech

On Thu, Mar 07, 2002 at 02:07:38PM -0500, Hubertus Franke wrote:
> On Thursday 07 March 2002 09:54 am, Guest section DW wrote:
> > On Thu, Mar 07, 2002 at 09:35:09AM -0500, Hubertus Franke wrote:
> > ...
> >
> > Long ago I submitted a patch that changed the max pid from 15 bits to
> > 24 or 30 bits or so. (And of course removed the inefficiency noticed
> > by some people in the current thread.)

> I don't think that will solve the N^2 problem

Do you understand "inefficiency"? And "remove"?

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: Fwd: [Lse-tech] get_pid() performance fix
  2002-03-07 19:46         ` Guest section DW
@ 2002-03-07 23:14           ` Hubertus Franke
  0 siblings, 0 replies; 19+ messages in thread
From: Hubertus Franke @ 2002-03-07 23:14 UTC (permalink / raw)
  To: Guest section DW; +Cc: Rusty Russell, rajancr, linux-kernel, lse-tech

On Thursday 07 March 2002 02:46 pm, Guest section DW wrote:
> On Thu, Mar 07, 2002 at 02:07:38PM -0500, Hubertus Franke wrote:
> > On Thursday 07 March 2002 09:54 am, Guest section DW wrote:
> > > On Thu, Mar 07, 2002 at 09:35:09AM -0500, Hubertus Franke wrote:
> > > ...
> > >
> > > Long ago I submitted a patch that changed the max pid from 15 bits to
> > > 24 or 30 bits or so. (And of course removed the inefficiency noticed
> > > by some people in the current thread.)
> >
> > I don't think that will solve the N^2 problem
>
> Do you understand "inefficiency"? And "remove"?


I do, what's your point ?
I haven't seen your patch picked up....

I do understand that when you occasionally get into this scenario
of the loop that particularly for large thread counts this stalls the system
for seconds (say 30, with the tasklock held).


-- 
-- Hubertus Franke  (frankeh@watson.ibm.com)

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: Fwd: [Lse-tech] get_pid() performance fix
@ 2002-03-07 22:37 Manfred Spraul
  0 siblings, 0 replies; 19+ messages in thread
From: Manfred Spraul @ 2002-03-07 22:37 UTC (permalink / raw)
  To: Guest section DW, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 512 bytes --]

> Maybe Alan will mutter something about sysvipc.
> Roughly speaking there are only advantages, especially since
> I think we'll have to do this sooner or later, and in such cases
> sooner is better.

The sysvipc situation isn't that bad. The new interfaces added for
32-bit uids also contain 32-bit pid values.
The semaphore code contains a stupid hack that assumes 16-bit uids,
appart from that apps linked against new glibc version should run fine.

[patch vs. 2.5.6-pre2 attached, but untested].

--
	Manfred

[-- Attachment #2: patch-sem --]
[-- Type: text/plain, Size: 1853 bytes --]

--- 2.5/ipc/sem.c	Sun Mar  3 12:04:00 2002
+++ build-2.5/ipc/sem.c	Thu Mar  7 23:33:02 2002
@@ -251,39 +251,39 @@
 	for (sop = sops; sop < sops + nsops; sop++) {
 		curr = sma->sem_base + sop->sem_num;
 		sem_op = sop->sem_op;
-
-		if (!sem_op && curr->semval)
+		result = curr->semval;
+  
+		if (!sem_op && result)
 			goto would_block;
 
-		curr->sempid = (curr->sempid << 16) | pid;
-		curr->semval += sem_op;
-		if (sop->sem_flg & SEM_UNDO)
-		{
+		result += sem_op;
+		if (result < 0)
+			goto would_block;
+		if (result > SEMVMX)
+			goto out_of_range;
+		if (sop->sem_flg & SEM_UNDO) {
 			int undo = un->semadj[sop->sem_num] - sem_op;
 			/*
 	 		 *	Exceeding the undo range is an error.
 			 */
 			if (undo < (-SEMAEM - 1) || undo > SEMAEM)
-			{
-				/* Don't undo the undo */
-				sop->sem_flg &= ~SEM_UNDO;
 				goto out_of_range;
-			}
-			un->semadj[sop->sem_num] = undo;
 		}
-		if (curr->semval < 0)
-			goto would_block;
-		if (curr->semval > SEMVMX)
-			goto out_of_range;
+		curr->semval = result;
 	}
 
-	if (do_undo)
-	{
-		sop--;
+	if (do_undo) {
 		result = 0;
 		goto undo;
 	}
-
+	sop--;
+	while (sop >= sops) {
+		sma->sem_base[sop->sem_num].sempid = pid;
+		if (sop->sem_flg & SEM_UNDO)
+			un->semadj[sop->sem_num] -= sop->sem_op;
+		sop--;
+	}
+	
 	sma->sem_otime = CURRENT_TIME;
 	return 0;
 
@@ -298,13 +298,9 @@
 		result = 1;
 
 undo:
+	sop--;
 	while (sop >= sops) {
-		curr = sma->sem_base + sop->sem_num;
-		curr->semval -= sop->sem_op;
-		curr->sempid >>= 16;
-
-		if (sop->sem_flg & SEM_UNDO)
-			un->semadj[sop->sem_num] += sop->sem_op;
+		sma->sem_base[sop->sem_num].semval -= sop->sem_op;
 		sop--;
 	}
 
@@ -624,7 +620,7 @@
 		err = curr->semval;
 		goto out_unlock;
 	case GETPID:
-		err = curr->sempid & 0xffff;
+		err = curr->sempid;
 		goto out_unlock;
 	case GETNCNT:
 		err = count_semncnt(sma,semnum);

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: Fwd: [Lse-tech] get_pid() performance fix
  2002-03-05 22:48         ` OGAWA Hirofumi
@ 2002-03-05 23:40           ` Hubertus Franke
  0 siblings, 0 replies; 19+ messages in thread
From: Hubertus Franke @ 2002-03-05 23:40 UTC (permalink / raw)
  To: OGAWA Hirofumi; +Cc: Rajan Ravindran, linux-kernel, lse-tech

On Tuesday 05 March 2002 05:48 pm, OGAWA Hirofumi wrote:
> Hubertus Franke <frankeh@watson.ibm.com> writes:
> > > > @@ -153,13 +155,18 @@
> > > >                               if(last_pid & 0xffff8000)
> > > >                                     last_pid = 300;
> > > >                               next_safe = PID_MAX;
> > > > +                             goto repeat;
> > > >                         }
> > > > -                       goto repeat;
> > > > +                       if(unlikely(last_pid == beginpid))
> > > > +                             goto nomorepids;
> > > > +                       continue;
> > >
> > > You changed it. No?
> >
> > Yes, we changed but only the logic that once a pid is busy we start
> > searching for every task again. This is exactly the O(n**2) problem.
> > Run the program and you'll see.
>
> Run the attached file.
>
> Result,
> 	new pid: 301, 300: pid 300, pgrp 301
>
> new pid == task(300)->pgrp. This get_pid() has bug.
> I'm missing something?

Yipp you are right. 
I stay corrected, we are missing something. Will work on it and see
whether we can correct it, either way we should be able to
get ride of the o(n**2) effect.

-- 
-- Hubertus Franke  (frankeh@watson.ibm.com)

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: Fwd: [Lse-tech] get_pid() performance fix
  2002-03-05 21:59       ` Hubertus Franke
@ 2002-03-05 22:48         ` OGAWA Hirofumi
  2002-03-05 23:40           ` Hubertus Franke
  0 siblings, 1 reply; 19+ messages in thread
From: OGAWA Hirofumi @ 2002-03-05 22:48 UTC (permalink / raw)
  To: frankeh; +Cc: Rajan Ravindran, linux-kernel, lse-tech

[-- Attachment #1: Type: text/plain, Size: 941 bytes --]

Hubertus Franke <frankeh@watson.ibm.com> writes:

> > > @@ -153,13 +155,18 @@
> > >                               if(last_pid & 0xffff8000)
> > >                                     last_pid = 300;
> > >                               next_safe = PID_MAX;
> > > +                             goto repeat;
> > >                         }
> > > -                       goto repeat;
> > > +                       if(unlikely(last_pid == beginpid))
> > > +                             goto nomorepids;
> > > +                       continue;
> >
> > You changed it. No?
> 
> Yes, we changed but only the logic that once a pid is busy we start searching 
> for every task again. This is exactly the O(n**2) problem.
> Run the program and you'll see.

Run the attached file.

Result,
	new pid: 301, 300: pid 300, pgrp 301

new pid == task(300)->pgrp. This get_pid() has bug.
I'm missing something?
-- 
OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: get_pid.c --]
[-- Type: text/x-csrc, Size: 3624 bytes --]

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>

#define spin_lock(x)
#define spin_unlock(x)
#define read_lock(x)
#define read_unlock(x)
#define unlikely(x)	(x)
#define SET_LINKS(p) do {			\
	(p)->next_task = &init_task;		\
	(p)->prev_task = init_task.prev_task;	\
	init_task.prev_task->next_task = (p);	\
	init_task.prev_task = (p);		\
} while (0)
#define REMOVE_LINKS(p) do {				\
	(p)->next_task->prev_task = (p)->prev_task;	\
	(p)->prev_task->next_task = (p)->next_task;	\
} while (0)
#define CLONE_PID	0x00001000	/* set if pid shared */
#define PID_MAX		0x8000

#define for_each_task(p) \
	for (p = &init_task ; (p = p->next_task) != &init_task ; )

struct task_struct {
	struct task_struct *next_task, *prev_task;
	pid_t pid;
	pid_t pgrp;
	pid_t session;
	pid_t tgid;
	int did_exec;
};

struct task_struct init_task = {
	next_task: 	&init_task,
	prev_task: 	&init_task,
	pid:		0,
	pgrp:		0,
	session:	0,
	tgid:		0,
	did_exec:	0,
};
struct task_struct *current = &init_task;
static pid_t last_pid;

static int get_pid(unsigned long flags)
{
	static int next_safe = PID_MAX;
	struct task_struct *p;
	int pid, beginpid;

	if (flags & CLONE_PID)
		return current->pid;

	spin_lock(&lastpid_lock);
	beginpid = last_pid;
	if((++last_pid) & 0xffff8000) {
		last_pid = 300;		/* Skip daemons etc. */
		goto inside;
	}
	if(last_pid >= next_safe) {
inside:
		next_safe = PID_MAX;
		read_lock(&tasklist_lock);
	repeat:
		for_each_task(p) {
			if(p->pid == last_pid	||
			   p->pgrp == last_pid	||
			   p->tgid == last_pid	||
			   p->session == last_pid) {
				if(++last_pid >= next_safe) {
					if(last_pid & 0xffff8000)
						last_pid = 300;
					next_safe = PID_MAX;
					goto repeat;
				}
				if(unlikely(last_pid == beginpid))
					goto nomorepids;
				continue;
			}
			if(p->pid > last_pid && next_safe > p->pid)
				next_safe = p->pid;
			if(p->pgrp > last_pid && next_safe > p->pgrp)
				next_safe = p->pgrp;
			if(p->tgid > last_pid && next_safe > p->tgid)
				next_safe = p->tgid;
			if(p->session > last_pid && next_safe > p->session)
				next_safe = p->session;
		}
		read_unlock(&tasklist_lock);
	}
	pid = last_pid;
	spin_unlock(&lastpid_lock);

	return pid;

nomorepids:
	read_unlock(&tasklist_lock);
	spin_unlock(&lastpid_lock);
	return 0;
}

static void fatal(char *msg)
{
	fprintf(stderr, "%s: %s", msg, strerror(errno));
	exit(1);
}

static struct task_struct *find_task_by_pid(pid_t pid)
{
	struct task_struct *tsk;

	for_each_task(tsk)
		if (tsk->pid == pid)
			return tsk;
	return NULL;
}

static struct task_struct *add_task(pid_t pid, pid_t pgrp, pid_t session,
				    pid_t tgid)
{
	struct task_struct *tsk;

	tsk = malloc(sizeof(struct task_struct));
	if (tsk == NULL)
		fatal("malloc");
	tsk->pid = pid;
	tsk->pgrp = pgrp;
	tsk->session = session;
	tsk->tgid = tgid;
	SET_LINKS(tsk);

	return tsk;
}

static void del_task(struct task_struct *tsk)
{
	REMOVE_LINKS(tsk);
	free(tsk);
}

int main()
{
	int i;
	pid_t pid, pgrp;
	struct task_struct *tsk;

	for (i = 1; i < PID_MAX; i++) {
		pid = get_pid(0);
		add_task(pid, pid, pid, pid);
	}
	/* exit() */
	tsk = find_task_by_pid(301);
	del_task(tsk);
	/* fork() */
	pgrp = pid = get_pid(0);
	add_task(pid, pid, pid, pid);
	/* exit() */
	tsk = find_task_by_pid(300);
	del_task(tsk);
	/* fork() */
	pid = get_pid(0);
	add_task(pid, pgrp, pid, pid);
	/* exit() */
	tsk = find_task_by_pid(301);
	del_task(tsk);

	/* fork() */
	pid = get_pid(0);
	add_task(pid, pgrp, pid, pid);

	tsk = find_task_by_pid(300);
	printf("new pid: %d, 300: pid %d, pgrp %d\n",
	       pid, tsk->pid, tsk->pgrp);

	return 0;
}

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: Fwd: [Lse-tech] get_pid() performance fix
  2002-03-05 20:10     ` OGAWA Hirofumi
@ 2002-03-05 21:59       ` Hubertus Franke
  2002-03-05 22:48         ` OGAWA Hirofumi
  0 siblings, 1 reply; 19+ messages in thread
From: Hubertus Franke @ 2002-03-05 21:59 UTC (permalink / raw)
  To: OGAWA Hirofumi; +Cc: Rajan Ravindran, linux-kernel, lse-tech

On Tuesday 05 March 2002 03:10 pm, OGAWA Hirofumi wrote:
> Hubertus Franke <frankeh@watson.ibm.com> writes:
> > > I said:
> > > 	task { pid = 300, pgrp = 301, };
> > > 	301 is free;
> > >
> > > 	get_pid() returns 301.
> > >
> > > "task 301" can't call setsid(). pid 301 is available?
> >
> > The original code is/was:
> >
> >                         if(p->pid == last_pid   ||
> >                            p->pgrp == last_pid  ||
> >                            p->tgid == last_pid  ||
> >                            p->session == last_pid) {
> >                                 if(++last_pid >= next_safe) {
> >                                         if(last_pid & 0xffff8000)
> >                                                 last_pid = 300;
> >                                         next_safe = PID_MAX;
> >                                 }
> >                                 goto repeat;
> >                         }
> >
> > if any process holds the pgrp=301 as in your case, 301 won't be eligible
> > due to (p->pgrp == last_pid) check.
>
> I know.
>
> > @@ -153,13 +155,18 @@
> >                               if(last_pid & 0xffff8000)
> >                                     last_pid = 300;
> >                               next_safe = PID_MAX;
> > +                             goto repeat;
> >                         }
> > -                       goto repeat;
> > +                       if(unlikely(last_pid == beginpid))
> > +                             goto nomorepids;
> > +                       continue;
>
> You changed it. No?

Yes, we changed but only the logic that once a pid is busy we start searching 
for every task again. This is exactly the O(n**2) problem.
Run the program and you'll see.

-- 
-- Hubertus Franke  (frankeh@watson.ibm.com)

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: Fwd: [Lse-tech] get_pid() performance fix
  2002-03-05 19:53   ` Hubertus Franke
@ 2002-03-05 20:10     ` OGAWA Hirofumi
  2002-03-05 21:59       ` Hubertus Franke
  0 siblings, 1 reply; 19+ messages in thread
From: OGAWA Hirofumi @ 2002-03-05 20:10 UTC (permalink / raw)
  To: frankeh; +Cc: Rajan Ravindran, linux-kernel, lse-tech

Hubertus Franke <frankeh@watson.ibm.com> writes:

> > I said:
> > 	task { pid = 300, pgrp = 301, };
> > 	301 is free;
> >
> > 	get_pid() returns 301.
> >
> > "task 301" can't call setsid(). pid 301 is available?
> 
> The original code is/was:
> 
>                         if(p->pid == last_pid   ||
>                            p->pgrp == last_pid  ||
>                            p->tgid == last_pid  ||
>                            p->session == last_pid) {
>                                 if(++last_pid >= next_safe) {
>                                         if(last_pid & 0xffff8000)
>                                                 last_pid = 300;
>                                         next_safe = PID_MAX;
>                                 }
>                                 goto repeat;
>                         }
> 
> if any process holds the pgrp=301 as in your case, 301 won't be eligible due 
> to (p->pgrp == last_pid) check.

I know.

> @@ -153,13 +155,18 @@
>                               if(last_pid & 0xffff8000)
>                                     last_pid = 300;
>                               next_safe = PID_MAX;
> +                             goto repeat;
>                         }
> -                       goto repeat;
> +                       if(unlikely(last_pid == beginpid))
> +                             goto nomorepids;
> +                       continue;

You changed it. No?
-- 
OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: Fwd: [Lse-tech] get_pid() performance fix
  2002-03-05 17:57 ` OGAWA Hirofumi
@ 2002-03-05 19:53   ` Hubertus Franke
  2002-03-05 20:10     ` OGAWA Hirofumi
  0 siblings, 1 reply; 19+ messages in thread
From: Hubertus Franke @ 2002-03-05 19:53 UTC (permalink / raw)
  To: OGAWA Hirofumi, Rajan Ravindran; +Cc: linux-kernel, lse-tech

On Tuesday 05 March 2002 12:57 pm, OGAWA Hirofumi wrote:
> "Rajan Ravindran" <rajancr@us.ibm.com> writes:
> > Yes, pid's are guaranteed to be unique.
> > Here the problem we focused is the time taken in finding the next
> > available free pid.
> > I really don't mean by your task->xxx.
>
> I'm confused.
>

yes you are .....

> I said:
> 	task { pid = 300, pgrp = 301, };
> 	301 is free;
>
> 	get_pid() returns 301.
>
> "task 301" can't call setsid(). pid 301 is available?

The original code is/was:

                        if(p->pid == last_pid   ||
                           p->pgrp == last_pid  ||
                           p->tgid == last_pid  ||
                           p->session == last_pid) {
                                if(++last_pid >= next_safe) {
                                        if(last_pid & 0xffff8000)
                                                last_pid = 300;
                                        next_safe = PID_MAX;
                                }
                                goto repeat;
                        }

if any process holds the pgrp=301 as in your case, 301 won't be eligible due 
to (p->pgrp == last_pid) check.

-- 
-- Hubertus Franke  (frankeh@watson.ibm.com)

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: Fwd: [Lse-tech] get_pid() performance fix
  2002-03-05 16:43 Rajan Ravindran
@ 2002-03-05 17:57 ` OGAWA Hirofumi
  2002-03-05 19:53   ` Hubertus Franke
  0 siblings, 1 reply; 19+ messages in thread
From: OGAWA Hirofumi @ 2002-03-05 17:57 UTC (permalink / raw)
  To: Rajan Ravindran; +Cc: linux-kernel, lse-tech

"Rajan Ravindran" <rajancr@us.ibm.com> writes:

> Yes, pid's are guaranteed to be unique.
> Here the problem we focused is the time taken in finding the next
> available free pid.
> I really don't mean by your task->xxx.

I'm confused.

I said:
	task { pid = 300, pgrp = 301, };
	301 is free;

	get_pid() returns 301.

"task 301" can't call setsid(). pid 301 is available?
-- 
OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: Fwd: [Lse-tech] get_pid() performance fix
@ 2002-03-05 16:43 Rajan Ravindran
  2002-03-05 17:57 ` OGAWA Hirofumi
  0 siblings, 1 reply; 19+ messages in thread
From: Rajan Ravindran @ 2002-03-05 16:43 UTC (permalink / raw)
  To: OGAWA Hirofumi; +Cc: linux-kernel, lse-tech



Yes, pid's are guaranteed to be unique.
Here the problem we focused is the time taken in finding the next
available free pid.
I really don't mean by your task->xxx.

-Rajan



Hubertus Franke <frankeh@watson.ibm.com> writes:

> @@ -153,13 +155,18 @@
>                               if(last_pid & 0xffff8000)
>                                     last_pid = 300;
>                               next_safe = PID_MAX;
> +                             goto repeat;
>                         }
> -                       goto repeat;
> +                       if(unlikely(last_pid == beginpid))
> +                             goto nomorepids;
> +                       continue;

It isn't guaranteed that pid is unique.

In the case:
             task->pid = 300, task->xxx = 301
             pid 301 is free

             This get_pid() returns 301.

Regards.
--
OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>

_______________________________________________
Lse-tech mailing list
Lse-tech@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/lse-tech





^ permalink raw reply	[flat|nested] 19+ messages in thread

end of thread, other threads:[~2002-03-07 23:13 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2002-03-05  1:57 Fwd: [Lse-tech] get_pid() performance fix Hubertus Franke
2002-03-05 16:26 ` OGAWA Hirofumi
2002-03-05 16:43   ` Hubertus Franke
2002-03-07  3:56 ` Rusty Russell
2002-03-07 14:35   ` Hubertus Franke
2002-03-07 14:54     ` Guest section DW
2002-03-07 19:07       ` Hubertus Franke
2002-03-07 19:44         ` Richard B. Johnson
2002-03-07 19:46         ` Guest section DW
2002-03-07 23:14           ` Hubertus Franke
2002-03-07 15:21   ` Dave McCracken
2002-03-05 16:43 Rajan Ravindran
2002-03-05 17:57 ` OGAWA Hirofumi
2002-03-05 19:53   ` Hubertus Franke
2002-03-05 20:10     ` OGAWA Hirofumi
2002-03-05 21:59       ` Hubertus Franke
2002-03-05 22:48         ` OGAWA Hirofumi
2002-03-05 23:40           ` Hubertus Franke
2002-03-07 22:37 Manfred Spraul

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 NNTP newsgroup(s).