Re: [naviserver-devel] Quest for malloc

2006-12-18 Thread Zoran Vasiljevic


On 16.12.2006, at 19:31, Vlad Seryakov wrote:

But if speed is not important to you, you can supply Tcl without  
zippy,

then no bloat, system is returned with reasonable speed, at least on
Linux, ptmalloc is not that bad



OK. I think I've reached the peace of mind with all this
alternate malloc implementations...

This is what I found:

On all plaforms (except the Mac OSX), it really does
not pay to use anything else beside system native
malloc. I mean, you can gain some percent of speed
with hoard/tcmalloc/nedmalloc/zippy and friends, but you
pay this with bloating memory. If you can afford it,
then go ahead. I believe, at least from what I've seen
from my tests, that zippy is quite fast and you gain
very little, if at all (speedwise) by replacing it.
You can gain some less memory fragmentation by using
something else, but this is not a thing that would
make me say: Wow!

Exception to that is really Mac OSX. The native Mac OSX
malloc sucks tremendously. The speed increase by zippy
and nedmalloc are so high that you can really see
(without any fancy measurements), how your application
flies! The nedmalloc also bloats less than zippy (normally,
as it clears per-thread cache on thread exit).
So for the Mac (at least for us) I will stick to nedmalloc.
It is lightingly fast and reasonably conservative with
memory fragmentation.

Conclusion:

   Linux/solaris = use system malloc
   Mac OSX = use nedmalloc

Ah, yes... windows... this I haven't tested but nedmalloc
author shows some very interesting numbers on his site.
I somehow tend to believe them as some I have seen by
myself when experimenting on unix platforms. So, most
probably the outcome will be:

   Windows = use nedmalloc

What this means to all of us:? I would say: very little.
We know that zippy is bloating and now we know that is
reasonably fast and on-pair with most of the other solutions
out there. For people concerned with speed, I believe this
is the right solution. For people concerned with speed AND
memory fragmentation (in that order) the best is to use some
alternative malloc routines. For people concerned with fragmentation
the best is to stay with system malloc; exception: Mac OSX.
There you just need to use something else and nedmalloc is the
only thing that compiles (and works) there, to my knowledge.

I hope I could help somebody with this report.

Cheers
Zoran







Re: [naviserver-devel] Quest for malloc

2006-12-18 Thread Vlad Seryakov
I tried to run this program, it crahses with all allocators on free when 
it was allocated in other thread. zippy does it as well, i amnot sure 
how Naviserver works then.



#include tcl.h

#define MemAlloc ckalloc
#define MemFree ckfree

int nbuffer = 16384;
int nloops = 5;
int nthreads = 4;

int gAllocs = 0;
void *gPtr = NULL;
Tcl_Mutex gLock;

void MemThread(void *arg)
{
int   i,n;
void *ptr = NULL;

for (i = 0; i  nloops; ++i) {
n = 1 + (int) (nbuffer * (rand() / (RAND_MAX + 1.0)));
if (ptr != NULL) {
MemFree(ptr);
}
ptr = MemAlloc(n);
// Testing inter-thread alloc/free
if (n % 5 == 0) {
Tcl_MutexLock(gLock);
if (gPtr != NULL) {
MemFree(gPtr);
}
gPtr = MemAlloc(n);
gAllocs++;
Tcl_MutexUnlock(gLock);
}
}
if (ptr != NULL) {
MemFree(ptr);
}
if (gPtr != NULL) {
MemFree(gPtr);
}
}

void MemTime()
{
int   i;
Tcl_ThreadId *tids;
tids = (Tcl_ThreadId *)malloc(sizeof(Tcl_ThreadId) * nthreads);

for (i = 0; i  nthreads; ++i) {
Tcl_CreateThread( tids[i], MemThread, NULL, 
TCL_THREAD_STACK_DEFAULT, TCL_THREAD_JOINABLE);

}
for (i = 0; i  nthreads; ++i) {
Tcl_JoinThread(tids[i], NULL);
}
}

int main (int argc, char **argv)
{
   MemTime();
}



Doesn't zippy also clear it's per-thread cache on exit?



It puts blocks into shared queue which other threads can re-use.
But shared cache never gets returned so conn threads exit will not help 
with memory bloat.



--
Vlad Seryakov
571 262-8608 office
[EMAIL PROTECTED]
http://www.crystalballinc.com/vlad/




Re: [naviserver-devel] Quest for malloc

2006-12-18 Thread Vlad Seryakov
Still, even without the last free and with mutex around it, it core 
dumps in free(gPtr) during the loop.


Stephen Deasey wrote:

On 12/18/06, Vlad Seryakov [EMAIL PROTECTED] wrote:

I tried to run this program, it crahses with all allocators on free when
it was allocated in other thread. zippy does it as well, i amnot sure
how Naviserver works then.



I don't think allocate in one thread, free in another is an unusual
strategy.  Googling around I see a lot of people doing it. There must
be some bugs in your program. Here's one:

At the end of MemThread() gPtr is checked and freed, but the gMutex is
not held. This thread may have finished it's tight loop, but the other
3 threads could still be running. Also, the gPtr is not set to NULL
after the free(), leading to a double free when the next thread checks
it.



#include tcl.h

#define MemAlloc ckalloc
#define MemFree ckfree

int nbuffer = 16384;
int nloops = 5;
int nthreads = 4;

int gAllocs = 0;
void *gPtr = NULL;
Tcl_Mutex gLock;

void MemThread(void *arg)
{
 int   i,n;
 void *ptr = NULL;

 for (i = 0; i  nloops; ++i) {
 n = 1 + (int) (nbuffer * (rand() / (RAND_MAX + 1.0)));
 if (ptr != NULL) {
 MemFree(ptr);
 }
 ptr = MemAlloc(n);
 // Testing inter-thread alloc/free
 if (n % 5 == 0) {
 Tcl_MutexLock(gLock);
 if (gPtr != NULL) {
 MemFree(gPtr);
 }
 gPtr = MemAlloc(n);
 gAllocs++;
 Tcl_MutexUnlock(gLock);
 }
 }
 if (ptr != NULL) {
 MemFree(ptr);
 }
 if (gPtr != NULL) {
 MemFree(gPtr);
 }
}

void MemTime()
{
 int   i;
 Tcl_ThreadId *tids;
 tids = (Tcl_ThreadId *)malloc(sizeof(Tcl_ThreadId) * nthreads);

 for (i = 0; i  nthreads; ++i) {
 Tcl_CreateThread( tids[i], MemThread, NULL,
TCL_THREAD_STACK_DEFAULT, TCL_THREAD_JOINABLE);
 }
 for (i = 0; i  nthreads; ++i) {
 Tcl_JoinThread(tids[i], NULL);
 }
}

int main (int argc, char **argv)
{
MemTime();
}


-
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT  business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.phpp=sourceforgeCID=DEVDEV
___
naviserver-devel mailing list
naviserver-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/naviserver-devel



--
Vlad Seryakov
571 262-8608 office
[EMAIL PROTECTED]
http://www.crystalballinc.com/vlad/




Re: [naviserver-devel] Quest for malloc

2006-12-18 Thread Stephen Deasey

On 12/18/06, Vlad Seryakov [EMAIL PROTECTED] wrote:

Still, even without the last free and with mutex around it, it core
dumps in free(gPtr) during the loop.



OK.  Still doesn't mean your program is bug free  :-)

There's a lot of extra stuff going on in your example program that
makes it hard to see what's going on. I simplified it to this:


#include tcl.h
#include stdlib.h
#include assert.h


#define MemAlloc ckalloc
#define MemFree  ckfree


void *gPtr = NULL;  /* Global pointer to memory. */

void
Thread(void *arg)
{
   assert(gPtr != NULL);

   MemFree(gPtr);
   gPtr = NULL;
}

int
main (int argc, char **argv)
{
   Tcl_ThreadId tid;
   int  i;

   for (i = 0; i  10; ++i) {

   gPtr = MemAlloc(1024);
   assert(gPtr != NULL);

   Tcl_CreateThread(tid, Thread, NULL,
TCL_THREAD_STACK_DEFAULT, TCL_THREAD_JOINABLE);
   Tcl_JoinThread(tid, NULL);

   assert(gPtr == NULL);
   }
}


Works for me.

I say you can allocate memory in one thread and free it in another.

Let me know what the bug turns out to be..!



Stephen Deasey wrote:
 On 12/18/06, Vlad Seryakov [EMAIL PROTECTED] wrote:
 I tried to run this program, it crahses with all allocators on free when
 it was allocated in other thread. zippy does it as well, i amnot sure
 how Naviserver works then.


 I don't think allocate in one thread, free in another is an unusual
 strategy.  Googling around I see a lot of people doing it. There must
 be some bugs in your program. Here's one:

 At the end of MemThread() gPtr is checked and freed, but the gMutex is
 not held. This thread may have finished it's tight loop, but the other
 3 threads could still be running. Also, the gPtr is not set to NULL
 after the free(), leading to a double free when the next thread checks
 it.


 #include tcl.h

 #define MemAlloc ckalloc
 #define MemFree ckfree

 int nbuffer = 16384;
 int nloops = 5;
 int nthreads = 4;

 int gAllocs = 0;
 void *gPtr = NULL;
 Tcl_Mutex gLock;

 void MemThread(void *arg)
 {
  int   i,n;
  void *ptr = NULL;

  for (i = 0; i  nloops; ++i) {
  n = 1 + (int) (nbuffer * (rand() / (RAND_MAX + 1.0)));
  if (ptr != NULL) {
  MemFree(ptr);
  }
  ptr = MemAlloc(n);
  // Testing inter-thread alloc/free
  if (n % 5 == 0) {
  Tcl_MutexLock(gLock);
  if (gPtr != NULL) {
  MemFree(gPtr);
  }
  gPtr = MemAlloc(n);
  gAllocs++;
  Tcl_MutexUnlock(gLock);
  }
  }
  if (ptr != NULL) {
  MemFree(ptr);
  }
  if (gPtr != NULL) {
  MemFree(gPtr);
  }
 }

 void MemTime()
 {
  int   i;
  Tcl_ThreadId *tids;
  tids = (Tcl_ThreadId *)malloc(sizeof(Tcl_ThreadId) * nthreads);

  for (i = 0; i  nthreads; ++i) {
  Tcl_CreateThread( tids[i], MemThread, NULL,
 TCL_THREAD_STACK_DEFAULT, TCL_THREAD_JOINABLE);
  }
  for (i = 0; i  nthreads; ++i) {
  Tcl_JoinThread(tids[i], NULL);
  }
 }

 int main (int argc, char **argv)
 {
 MemTime();
 }

 -
 Take Surveys. Earn Cash. Influence the Future of IT
 Join SourceForge.net's Techsay panel and you'll get the chance to share your
 opinions on IT  business topics through brief surveys - and earn cash
 http://www.techsay.com/default.php?page=join.phpp=sourceforgeCID=DEVDEV
 ___
 naviserver-devel mailing list
 naviserver-devel@lists.sourceforge.net
 https://lists.sourceforge.net/lists/listinfo/naviserver-devel


--
Vlad Seryakov
571 262-8608 office
[EMAIL PROTECTED]
http://www.crystalballinc.com/vlad/


-
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT  business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.phpp=sourceforgeCID=DEVDEV
___
naviserver-devel mailing list
naviserver-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/naviserver-devel





Re: [naviserver-devel] Quest for malloc

2006-12-18 Thread Zoran Vasiljevic


On 18.12.2006, at 22:08, Stephen Deasey wrote:



Works for me.

I say you can allocate memory in one thread and free it in another.


Nice. Well I can say that nedmalloc works, that is, that small
program runs to end w/o coring when compiled with nedmalloc.
Does this prove anything?







Re: [naviserver-devel] Quest for malloc

2006-12-18 Thread Zoran Vasiljevic


On 18.12.2006, at 19:57, Stephen Deasey wrote:



Are you saying you tested your app on Linux with native malloc and
experienced no fragmentation/bloating?


No. I have seen bloating but less then on zippy. I saw some
bloating and fragmentation on all optimizing allocators I
have tested.



I think some people are experiencing fragmentation problems with
ptmalloc -- the Squid and OpenLDAP guys, for example.  There's also
the malloc-in-one-thread, free-in-another problem, which if your
threads don't exit is basically a leak.


Really a leak? Why? Wouln't that depend on the implementation?




Doesn't zippy also clear it's per-thread cache on exit?


No. It showels all the rest to shared pool. The shared
pool is never freed. Hence lots of bloating.



Actually, did you experiment with exiting the conn threads after X
requests? Seems to be one of the things AOL is recommending.


Most of our threads are Tcl threads, not conn threads. We create
them to do lots of different tasks. They are all rather short-lived.
Still, the mem footprint grows and grows...



One thing I wonder about this is, how do requests average out across
all threads? If you set the conn threads to exit after 10,000
requests, will they all quit at roughly the same time causing an
extreme load on the server?  Also, this is only an option for conn
threads. With scheduled proc threads, job threads etc. you get
nothing.



Well, if they all start to exit at the same time, they will
serialize at the point where per-thread cache is pushed to
the shared pool.




-- 
---

Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to  
share your

opinions on IT  business topics through brief surveys - and earn cash
http://www.techsay.com/default.php? 
page=join.phpp=sourceforgeCID=DEVDEV

___
naviserver-devel mailing list
naviserver-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/naviserver-devel






Re: [naviserver-devel] Quest for malloc

2006-12-18 Thread Vlad Seryakov
I suspect something i am doing wrong, but still it crashes and i do not 
see it why


#include tcl.h

#include stdlib.h
#include memory.h
#include unistd.h
#include signal.h
#include pthread.h

#define MemAlloc malloc
#define MemFree free

static int nbuffer = 16384;
static int nloops = 5;
static int nthreads = 4;

static void *gPtr = NULL;
static Tcl_Mutex gLock;

void MemThread(void *arg)
{
int   i,n;
void *ptr = NULL;

for (i = 0; i  nloops; ++i) {
n = 1 + (int) (nbuffer * (rand() / (RAND_MAX + 1.0)));
if (ptr != NULL) {
MemFree(ptr);
}
ptr = MemAlloc(n);
if (n % 50 == 0) {
Tcl_MutexLock(gLock);
if (gPtr != NULL) {
MemFree(gPtr);
gPtr = NULL;
} else {
gPtr = MemAlloc(n);
}
Tcl_MutexUnlock(gLock);
}
}
}

int main (int argc, char **argv)
{
int i;
Tcl_ThreadId *tids;

tids = (Tcl_ThreadId *)malloc(sizeof(Tcl_ThreadId) * nthreads);

for (i = 0; i  nthreads; ++i) {
Tcl_CreateThread( tids[i], MemThread, NULL, 
TCL_THREAD_STACK_DEFAULT, TCL_THREAD_JOINABLE);

}
for (i = 0; i  nthreads; ++i) {
Tcl_JoinThread(tids[i], NULL);
}
}



Stephen Deasey wrote:

On 12/18/06, Vlad Seryakov [EMAIL PROTECTED] wrote:

Still, even without the last free and with mutex around it, it core
dumps in free(gPtr) during the loop.



OK.  Still doesn't mean your program is bug free  :-)

There's a lot of extra stuff going on in your example program that
makes it hard to see what's going on. I simplified it to this:


#include tcl.h
#include stdlib.h
#include assert.h


#define MemAlloc ckalloc
#define MemFree  ckfree


void *gPtr = NULL;  /* Global pointer to memory. */

void
Thread(void *arg)
{
assert(gPtr != NULL);

MemFree(gPtr);
gPtr = NULL;
}

int
main (int argc, char **argv)
{
Tcl_ThreadId tid;
int  i;

for (i = 0; i  10; ++i) {

gPtr = MemAlloc(1024);
assert(gPtr != NULL);

Tcl_CreateThread(tid, Thread, NULL,
 TCL_THREAD_STACK_DEFAULT, TCL_THREAD_JOINABLE);
Tcl_JoinThread(tid, NULL);

assert(gPtr == NULL);
}
}


Works for me.

I say you can allocate memory in one thread and free it in another.

Let me know what the bug turns out to be..!



Stephen Deasey wrote:

On 12/18/06, Vlad Seryakov [EMAIL PROTECTED] wrote:

I tried to run this program, it crahses with all allocators on free when
it was allocated in other thread. zippy does it as well, i amnot sure
how Naviserver works then.


I don't think allocate in one thread, free in another is an unusual
strategy.  Googling around I see a lot of people doing it. There must
be some bugs in your program. Here's one:

At the end of MemThread() gPtr is checked and freed, but the gMutex is
not held. This thread may have finished it's tight loop, but the other
3 threads could still be running. Also, the gPtr is not set to NULL
after the free(), leading to a double free when the next thread checks
it.



#include tcl.h

#define MemAlloc ckalloc
#define MemFree ckfree

int nbuffer = 16384;
int nloops = 5;
int nthreads = 4;

int gAllocs = 0;
void *gPtr = NULL;
Tcl_Mutex gLock;

void MemThread(void *arg)
{
 int   i,n;
 void *ptr = NULL;

 for (i = 0; i  nloops; ++i) {
 n = 1 + (int) (nbuffer * (rand() / (RAND_MAX + 1.0)));
 if (ptr != NULL) {
 MemFree(ptr);
 }
 ptr = MemAlloc(n);
 // Testing inter-thread alloc/free
 if (n % 5 == 0) {
 Tcl_MutexLock(gLock);
 if (gPtr != NULL) {
 MemFree(gPtr);
 }
 gPtr = MemAlloc(n);
 gAllocs++;
 Tcl_MutexUnlock(gLock);
 }
 }
 if (ptr != NULL) {
 MemFree(ptr);
 }
 if (gPtr != NULL) {
 MemFree(gPtr);
 }
}

void MemTime()
{
 int   i;
 Tcl_ThreadId *tids;
 tids = (Tcl_ThreadId *)malloc(sizeof(Tcl_ThreadId) * nthreads);

 for (i = 0; i  nthreads; ++i) {
 Tcl_CreateThread( tids[i], MemThread, NULL,
TCL_THREAD_STACK_DEFAULT, TCL_THREAD_JOINABLE);
 }
 for (i = 0; i  nthreads; ++i) {
 Tcl_JoinThread(tids[i], NULL);
 }
}

int main (int argc, char **argv)
{
MemTime();
}

-
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT  business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.phpp=sourceforgeCID=DEVDEV
___
naviserver-devel mailing list
naviserver-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/naviserver-devel


--
Vlad Seryakov
571 262-8608 office
[EMAIL PROTECTED]
http://www.crystalballinc.com/vlad/



Re: [naviserver-devel] Quest for malloc

2006-12-18 Thread Stephen Deasey

On 12/18/06, Zoran Vasiljevic [EMAIL PROTECTED] wrote:


On 18.12.2006, at 19:57, Stephen Deasey wrote:


 One thing I wonder about this is, how do requests average out across
 all threads? If you set the conn threads to exit after 10,000
 requests, will they all quit at roughly the same time causing an
 extreme load on the server?  Also, this is only an option for conn
 threads. With scheduled proc threads, job threads etc. you get
 nothing.


Well, if they all start to exit at the same time, they will
serialize at the point where per-thread cache is pushed to
the shared pool.


I was worried more about things like all the Tcl procs needing to be
recompiled in the new interp for the thread, and all the other stuff
which is cached.  If threads exit regularly, say after 10,000
requests, and the requests average out over all threads, then your
site will regularly go down, effectively. It would be nice if we could
make sure the thread exits were spread out.

Anyway...


 I think some people are experiencing fragmentation problems with
 ptmalloc -- the Squid and OpenLDAP guys, for example.  There's also
 the malloc-in-one-thread, free-in-another problem, which if your
 threads don't exit is basically a leak.

Really a leak? Why? Wouln't that depend on the implementation?


Yes, and I thought that was the case with Linux ptmalloc, but maybe I
got it wrong or this is old news...

This program allocates memory in a worker thread and frees it in the
main thread. If all free()'s put memory into a thread-local cache then
you would expect this program to bloat, but it doesn't, so I guess
it's not a problem (at least not on Fedora Core 5).


#include tcl.h
#include stdlib.h
#include stdio.h
#include assert.h


#define MemAlloc malloc
#define MemFree  free


void *gPtr = NULL;

static void Thread(void *arg);
static void PrintMemUsage(const char *msg);


int
main (int argc, char **argv)
{
   Tcl_ThreadId tid;
   int  i;

   PrintMemUsage(start);

   for (i = 0; i  10; ++i) {

   Tcl_CreateThread(tid, Thread, NULL,
TCL_THREAD_STACK_DEFAULT, TCL_THREAD_JOINABLE);
   Tcl_JoinThread(tid, NULL);

   MemFree(gPtr);
   gPtr = NULL;
   }

   PrintMemUsage(stop);
}

static void
Thread(void *arg)
{
   assert(gPtr == NULL);
   gPtr = MemAlloc(1024);
   assert(gPtr != NULL);
}

static void
PrintMemUsage(const char *msg)
{
   FILE *f;
   int   m;

   f = fopen(/proc/self/statm, r);
   if (f == NULL) {
   perror(fopen failed: );
   exit(-1);
   }
   if (fscanf(f, %d, m) != 1) {
   perror(fscanf failed: );
   exit(-1);
   }
   fclose(f);

   printf(%s: %d\n, msg, m);
}