From: Hubertus Franke <frankeh@watson.ibm.com>
To: linux-kernel@vger.kernel.org, lse-tech@lists.sourceforge.net
Subject: Fwd: [Lse-tech] get_pid() performance fix
Date: Mon, 4 Mar 2002 20:57:49 -0500 [thread overview]
Message-ID: <20020305145004.BFA503FE06@smtp.linux.ibm.com> (raw)
[-- 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);
}
next reply other threads:[~2002-03-05 14:50 UTC|newest]
Thread overview: 19+ messages / expand[flat|nested] mbox.gz Atom feed top
2002-03-05 1:57 Hubertus Franke [this message]
2002-03-05 16:26 ` Fwd: [Lse-tech] get_pid() performance fix 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
-- strict thread matches above, loose matches on Subject: below --
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
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=20020305145004.BFA503FE06@smtp.linux.ibm.com \
--to=frankeh@watson.ibm.com \
--cc=linux-kernel@vger.kernel.org \
--cc=lse-tech@lists.sourceforge.net \
/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