* ss -p is much too slow
@ 2010-06-09 18:42 Steve Fink
2010-06-28 23:21 ` David Miller
0 siblings, 1 reply; 5+ messages in thread
From: Steve Fink @ 2010-06-09 18:42 UTC (permalink / raw)
To: netdev
I was recently working with a monitoring system, and one check
involved displaying what process(es) were listening on specific ports.
I was using a single call to ss -lntp and processing the output, but
it would often take several minutes to respond. netstat -lntp, on the
other hand, was immediate. I had a few thousand processes running on
the machine, and it could take 7 minutes or so.
On closer inspection, it appears that ss -p does a quadratic scan. It
rescans every entry in /proc/*/fd/* repeatedly (once per listening
port? per process? I don't remember what I figured out.)
I humbly suggest that this is not a good idea.
I am currently running iproute-2.6.27-2.fc10.i386, though my real test
case was on a different machine. I don't have a newer version to check
right now.
% strace ss -lntp |& fgrep /proc/3768/fd/10
readlink("/proc/3768/fd/10", "socket:[16214]"..., 63) = 14
readlink("/proc/3768/fd/10", "socket:[16214]"..., 63) = 14
readlink("/proc/3768/fd/10", "socket:[16214]"..., 63) = 14
readlink("/proc/3768/fd/10", "socket:[16214]"..., 63) = 14
readlink("/proc/3768/fd/10", "socket:[16214]"..., 63) = 14
readlink("/proc/3768/fd/10", "socket:[16214]"..., 63) = 14
readlink("/proc/3768/fd/10", "socket:[16214]"..., 63) = 14
readlink("/proc/3768/fd/10", "socket:[16214]"..., 63) = 14
readlink("/proc/3768/fd/10", "socket:[16214]"..., 63) = 14
readlink("/proc/3768/fd/10", "socket:[16214]"..., 63) = 14
readlink("/proc/3768/fd/10", "socket:[16214]"..., 63) = 14
readlink("/proc/3768/fd/10", "socket:[16214]"..., 63) = 14
readlink("/proc/3768/fd/10", "socket:[16214]"..., 63) = 14
readlink("/proc/3768/fd/10", "socket:[16214]"..., 63) = 14
readlink("/proc/3768/fd/10", "socket:[16214]"..., 63) = 14
readlink("/proc/3768/fd/10", "socket:[16214]"..., 63) = 14
readlink("/proc/3768/fd/10", "socket:[16214]"..., 63) = 14
readlink("/proc/3768/fd/10", "socket:[16214]"..., 63) = 14
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: ss -p is much too slow
2010-06-09 18:42 ss -p is much too slow Steve Fink
@ 2010-06-28 23:21 ` David Miller
2010-07-23 19:48 ` David Miller
2010-08-01 2:33 ` Stephen Hemminger
0 siblings, 2 replies; 5+ messages in thread
From: David Miller @ 2010-06-28 23:21 UTC (permalink / raw)
To: sphink; +Cc: netdev, stephen.hemminger
From: Steve Fink <sphink@gmail.com>
Date: Wed, 9 Jun 2010 11:42:38 -0700
> On closer inspection, it appears that ss -p does a quadratic scan. It
> rescans every entry in /proc/*/fd/* repeatedly (once per listening
> port? per process? I don't remember what I figured out.)
>
> I humbly suggest that this is not a good idea.
Yep, this is junk. Please give this patch a try:
ss: Avoid quadradic complexity with '-p'
Scan the process list of open sockets once, and store in a hash
table to be used by subsequent find_user() calls.
Reported-by: Steve Fink <sphink@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
diff --git a/misc/ss.c b/misc/ss.c
index 8a9663c..482b6bb 100644
--- a/misc/ss.c
+++ b/misc/ss.c
@@ -195,90 +195,147 @@ static FILE *ephemeral_ports_open(void)
return generic_proc_open("PROC_IP_LOCAL_PORT_RANGE", "sys/net/ipv4/ip_local_port_range");
}
-int find_users(unsigned ino, char *buf, int buflen)
+struct user_ent {
+ struct user_ent *next;
+ unsigned int ino;
+ int pid;
+ int fd;
+ char process[0];
+};
+
+#define USER_ENT_HASH_SIZE 256
+struct user_ent *user_ent_hash[USER_ENT_HASH_SIZE];
+
+static int user_ent_hashfn(unsigned int ino)
{
- char pattern[64];
- int pattern_len;
- char *ptr = buf;
- char name[1024];
- DIR *dir;
- struct dirent *d;
- int cnt = 0;
- int nameoff;
+ int val = (ino >> 24) ^ (ino >> 16) ^ (ino >> 8) ^ ino;
- if (!ino)
- return 0;
+ return val & (USER_ENT_HASH_SIZE - 1);
+}
+
+static void user_ent_add(unsigned int ino, const char *process, int pid, int fd)
+{
+ struct user_ent *p, **pp;
+ int str_len;
- sprintf(pattern, "socket:[%u]", ino);
- pattern_len = strlen(pattern);
+ str_len = strlen(process) + 1;
+ p = malloc(sizeof(struct user_ent) + str_len);
+ if (!p)
+ abort();
+ p->next = NULL;
+ p->ino = ino;
+ p->pid = pid;
+ p->fd = fd;
+ strcpy(p->process, process);
+
+ pp = &user_ent_hash[user_ent_hashfn(ino)];
+ p->next = *pp;
+ *pp = p;
+}
- strncpy(name, getenv("PROC_ROOT") ? : "/proc/", sizeof(name)/2);
- name[sizeof(name)/2] = 0;
- if (strlen(name) == 0 ||
- name[strlen(name)-1] != '/')
+static void user_ent_hash_build(void)
+{
+ const char *root = getenv("PROC_ROOT") ? : "/proc/";
+ struct dirent *d;
+ char name[1024];
+ int nameoff;
+ DIR *dir;
+
+ strcpy(name, root);
+ if (strlen(name) == 0 || name[strlen(name)-1] != '/')
strcat(name, "/");
+
nameoff = strlen(name);
- if ((dir = opendir(name)) == NULL)
- return 0;
+
+ dir = opendir(name);
+ if (!dir)
+ return;
while ((d = readdir(dir)) != NULL) {
- DIR *dir1;
struct dirent *d1;
- int pid;
- int pos;
- char crap;
char process[16];
+ int pid, pos;
+ DIR *dir1;
+ char crap;
if (sscanf(d->d_name, "%d%c", &pid, &crap) != 1)
continue;
- sprintf(name+nameoff, "%d/fd/", pid);
+ sprintf(name + nameoff, "%d/fd/", pid);
pos = strlen(name);
if ((dir1 = opendir(name)) == NULL)
continue;
- process[0] = 0;
+ process[0] = '\0';
while ((d1 = readdir(dir1)) != NULL) {
- int fd, n;
+ const char *pattern = "socket:[";
+ unsigned int ino;
char lnk[64];
+ int fd, n;
if (sscanf(d1->d_name, "%d%c", &fd, &crap) != 1)
continue;
sprintf(name+pos, "%d", fd);
n = readlink(name, lnk, sizeof(lnk)-1);
- if (n != pattern_len ||
- memcmp(lnk, pattern, n))
+ if (strncmp(lnk, pattern, strlen(pattern)))
continue;
- if (ptr-buf >= buflen-1)
- break;
+ sscanf(lnk, "socket:[%u]", &ino);
- if (process[0] == 0) {
+ if (process[0] == '\0') {
char tmp[1024];
FILE *fp;
- snprintf(tmp, sizeof(tmp), "%s/%d/stat",
- getenv("PROC_ROOT") ? : "/proc", pid);
+
+ snprintf(tmp, sizeof(tmp), "%s/%d/stat", root, pid);
if ((fp = fopen(tmp, "r")) != NULL) {
fscanf(fp, "%*d (%[^)])", process);
fclose(fp);
}
}
- snprintf(ptr, buflen-(ptr-buf), "(\"%s\",%d,%d),", process, pid, fd);
- ptr += strlen(ptr);
- cnt++;
+ user_ent_add(ino, process, pid, fd);
}
closedir(dir1);
}
closedir(dir);
+}
+
+int find_users(unsigned ino, char *buf, int buflen)
+{
+ struct user_ent *p;
+ int cnt = 0;
+ char *ptr;
+
+ if (!ino)
+ return 0;
+
+ p = user_ent_hash[user_ent_hashfn(ino)];
+ ptr = buf;
+ while (p) {
+ if (p->ino != ino)
+ goto next;
+
+ if (ptr - buf >= buflen - 1)
+ break;
+
+ snprintf(ptr, buflen - (ptr - buf),
+ "(\"%s\",%d,%d),",
+ p->process, p->pid, p->fd);
+ ptr += strlen(ptr);
+ cnt++;
+
+ next:
+ p = p->next;
+ }
+
if (ptr != buf)
- ptr[-1] = 0;
+ ptr[-1] = '\0';
+
return cnt;
}
-
/* Get stats from slab */
struct slabstat
@@ -2476,6 +2533,7 @@ int main(int argc, char *argv[])
break;
case 'p':
show_users++;
+ user_ent_hash_build();
break;
case 'd':
current_filter.dbs |= (1<<DCCP_DB);
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: ss -p is much too slow
2010-06-28 23:21 ` David Miller
@ 2010-07-23 19:48 ` David Miller
2010-07-23 20:01 ` Stephen Hemminger
2010-08-01 2:33 ` Stephen Hemminger
1 sibling, 1 reply; 5+ messages in thread
From: David Miller @ 2010-07-23 19:48 UTC (permalink / raw)
To: sphink; +Cc: netdev, stephen.hemminger
From: David Miller <davem@davemloft.net>
Date: Mon, 28 Jun 2010 16:21:39 -0700 (PDT)
> ss: Avoid quadradic complexity with '-p'
>
> Scan the process list of open sockets once, and store in a hash
> table to be used by subsequent find_user() calls.
>
> Reported-by: Steve Fink <sphink@gmail.com>
> Signed-off-by: David S. Miller <davem@davemloft.net>
Stephen, please apply this, it fixes the quadratic behavior and
has been sitting for a month.
It's in patchwork, just check your todo list.
Thanks.
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: ss -p is much too slow
2010-07-23 19:48 ` David Miller
@ 2010-07-23 20:01 ` Stephen Hemminger
0 siblings, 0 replies; 5+ messages in thread
From: Stephen Hemminger @ 2010-07-23 20:01 UTC (permalink / raw)
To: David Miller; +Cc: sphink, netdev, stephen.hemminger
On Fri, 23 Jul 2010 12:48:19 -0700 (PDT)
David Miller <davem@davemloft.net> wrote:
> From: David Miller <davem@davemloft.net>
> Date: Mon, 28 Jun 2010 16:21:39 -0700 (PDT)
>
> > ss: Avoid quadradic complexity with '-p'
> >
> > Scan the process list of open sockets once, and store in a hash
> > table to be used by subsequent find_user() calls.
> >
> > Reported-by: Steve Fink <sphink@gmail.com>
> > Signed-off-by: David S. Miller <davem@davemloft.net>
>
> Stephen, please apply this, it fixes the quadratic behavior and
> has been sitting for a month.
>
> It's in patchwork, just check your todo list.
>
I saw it but wanted to work out a more general solution,
will apply it next week if mine doesn't work.
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: ss -p is much too slow
2010-06-28 23:21 ` David Miller
2010-07-23 19:48 ` David Miller
@ 2010-08-01 2:33 ` Stephen Hemminger
1 sibling, 0 replies; 5+ messages in thread
From: Stephen Hemminger @ 2010-08-01 2:33 UTC (permalink / raw)
To: David Miller; +Cc: sphink, netdev, stephen.hemminger
On Mon, 28 Jun 2010 16:21:39 -0700 (PDT)
David Miller <davem@davemloft.net> wrote:
> From: Steve Fink <sphink@gmail.com>
> Date: Wed, 9 Jun 2010 11:42:38 -0700
>
> > On closer inspection, it appears that ss -p does a quadratic scan. It
> > rescans every entry in /proc/*/fd/* repeatedly (once per listening
> > port? per process? I don't remember what I figured out.)
> >
> > I humbly suggest that this is not a good idea.
>
> Yep, this is junk. Please give this patch a try:
>
> ss: Avoid quadradic complexity with '-p'
>
> Scan the process list of open sockets once, and store in a hash
> table to be used by subsequent find_user() calls.
>
> Reported-by: Steve Fink <sphink@gmail.com>
> Signed-off-by: David S. Miller <davem@davemloft.net>
Applied
--
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2010-08-01 2:33 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-06-09 18:42 ss -p is much too slow Steve Fink
2010-06-28 23:21 ` David Miller
2010-07-23 19:48 ` David Miller
2010-07-23 20:01 ` Stephen Hemminger
2010-08-01 2:33 ` Stephen Hemminger
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).