[PATCH] Avoid huge slowdown when many resources

Roberto Ragusa mail at robertoragusa.it
Sat Nov 24 06:41:46 PST 2012


Hi,
(please CC me, I'm not subscribed)

here is a patch to better handle a big number of resources.
In my case I had been experiencing a huge slowdown of the system
after a few days of uptime, which I tracked to an application (psi)
continuously pushing pixmaps to plasma-desktop to achieve a pulsating
icon in the system tray.

Maybe something is wrong with psi, with the toolkit, with plasma-desktop,
but the final result was that Xorg was not able to cope with
that number of resources. The entire machine starts crawling; and this
is a powerful machine (quad i7, 16GiB).

There are a few bug reports about the slowness of GetXIDRange.
This one is exactly my case:
  http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=677470
It was promptly closed because the reporter was using nvidia binary drivers.
I'm on Intel chipset, instead.

Look at this xrestop result (plasma-desktop is the interesting one):

xrestop - Display: localhost:0
          Monitoring 55 clients. XErrors: 0
          Pixmaps:  216340K total, Other:    5910K total, All:  222251K total

res-base Wins  GCs Fnts Pxms Misc   Pxm mem  Other   Total   PID Identifier
6c00000    71   51    1  905 1320    70962K     34K  70997K  2300 <<redacted>>
3600000    18   18    1   56   91    35631K      3K  35635K 25355 <<redacted>>
1c00000   310   40    1  130  984    27093K     32K  27125K 19902 <<redacted>>
2000000    87   86    1  115 244337    12414K   5731K  18145K 20349 plasma-desktop
5e00000    61   44    1  318  637    16431K     18K  16449K 11086 <<redacted>>
5c00000    39   53    1  260  527    13804K     15K  13819K  7176 <<redacted>>
7800000    43   48    1  119  221     9866K      8K   9874K 10198 <<redacted>>
6e00000    14   27    1   11   23     4541K      2K   4543K 17304 <<redacted>>
6200000    23   29    1   10   40     3907K      3K   3910K 23546 <<redacted>>
4400000    41    5    1   19   63     3587K      3K   3590K  1730 <<redacted>>
3e00000    47    6    1   35   74     3112K      3K   3116K 25842 <<redacted>>
1400000     6    5    0   19   22     2474K    792B   2474K  1981 <<redacted>>

The unpatched system becomes unusable at 180,000 misc resources.
The patched system is perfectly running at 244,337, at the moment.

For my curiosity, I would like to understand if this is a real leak, or
it is expected that numbers can go so high, and some kind of cleaning
is just not triggering because there is a lot memory available and these
are small objects.

Recipe for reproduction: run KDE, run psi, have psi trying to connect
for a few hours while flashing the icon in the systemtray, see
plasma-dekstop raise in xrestop results. (killing/restarting plasma-desktop
is a work-around to release the resources)

Here is the patch.
With MAXHASHSIZE=11 there are at most 2^11=2048 buckets, which means
more than 100 elements per bucket at 244k elements.
By increasing MAXHASHSIZE to 16 we have 2^16=65536 buckets, so about 4
elements per bucket at 244k elements.
(Note that the preexisting hash scale up logic triggers
when elements > 4*buckets)

By the way, could GetXIDRange be sped up in other ways?
I admit I'm not entirely sure why it does what it does
(this is the first time I've seen xorg-server source code).

diff --git a/dix/resource.c b/dix/resource.c
index eb9f049..bddb10a 100644
--- a/dix/resource.c
+++ b/dix/resource.c
@@ -159,7 +159,7 @@ static void RebuildTable(

 #define INITBUCKETS 64
 #define INITHASHSIZE 6
-#define MAXHASHSIZE 11
+#define MAXHASHSIZE 16

 typedef struct _Resource {
     struct _Resource   *next;
@@ -347,6 +347,16 @@ Hash(int client, XID id)
            return ((int)(0x3FF & (id ^ (id>>10))));
        case 11:
            return ((int)(0x7FF & (id ^ (id>>11))));
+       case 12:
+           return ((int)(0xFFF & (id ^ (id>>12))));
+       case 13:
+           return ((int)(0x1FFF & (id ^ (id>>13))));
+       case 14:
+           return ((int)(0x3FFF & (id ^ (id>>14))));
+       case 15:
+           return ((int)(0x7FFF & (id ^ (id>>15))));
+       case 16:
+           return ((int)(0xFFFF & (id ^ (id>>16))));
     }
     return -1;
 }

I can verify that hashsize correctly goes up to 16 with this
additional patch.

diff --git a/dix/resource.c b/dix/resource.c
index eb9f049..bddb10a 100644
--- a/dix/resource.c
+++ b/dix/resource.c
@@ -542,6 +552,7 @@ RebuildTable(int client)
        *tptr = rptr;
     }
     clientTable[client].hashsize++;
+    LogMessage(X_INFO, "new table size:%d\n",clientTable[client].hashsize);
     for (j = clientTable[client].buckets,
         rptr = clientTable[client].resources;
         --j >= 0;

Best regards.

-- 
   Roberto Ragusa    mail at robertoragusa.it


More information about the xorg-devel mailing list