--- [EMAIL PROTECTED] wrote:
> ----- Original Message ----
> > MemPage bitfield patch below. 
> > 
> > sizeof(MemPage) on Linux: 
> > 
> >   original: 84
> >   patched:  76
> > ...
> > Break-even for memory is 904/8 = 113 MemPage structs allocated.
> 
> I didn't look at the code, so mind me :)
> 
> If the MemPage are malloced individually (instead of being put in arrays), 
> then they are 16 byte
> aligned on most platforms, making the allocated block effectively the same 
> size (well, that
> depends on how many bytes are used by malloc before the user block in memory).

This patch does indeed save memory - on Linux at least.
Linux has a malloc mimimum resolution of 8 bytes, not 16.

The sqlite MemPage struct is appended to the end of each page, and the pages 
are malloc'ed individually via:

    pPg = sqliteMallocRaw( sizeof(*pPg) + pPager->pageSize
                            + sizeof(u32) + pPager->nExtra
                            + MEMDB*sizeof(PgHistory) );

Where nExtra is sizeof(MemPage) (more or less).

Linux's malloc() implementation, can support large non-power-of-2 
malloc blocks, as this non-portable program demonstrates:

#include <malloc.h>
#include <stdlib.h>
#include <stdio.h>
void test(int page_size, int sizeof_MemPage) {
   const int bytes_to_alloc = 48 + page_size + 4 + sizeof_MemPage;
   printf("page_size = %d, bytes_to_alloc = %d\n",
     page_size, bytes_to_alloc);
   int i;
   char* m1 = malloc(bytes_to_alloc);
   for (i = 0; i < 5; ++i) {
     char * m2 = malloc(bytes_to_alloc);
     printf("0x%p: malloc resolution = %d bytes\n", m2, (int)(m2-m1));
     m1 = m2;
   }
}
main() {
   int i=1024;
   for (; i <= 8192; i*=2) {
     test(i, 88); // test original struct size
     test(i, 80); // test bitfield struct size
   }
}

page_size = 1024, bytes_to_alloc = 1164
0x0x804a498: malloc resolution = 1168 bytes
0x0x804a928: malloc resolution = 1168 bytes
0x0x804adb8: malloc resolution = 1168 bytes
0x0x804b248: malloc resolution = 1168 bytes
0x0x804b6d8: malloc resolution = 1168 bytes
page_size = 1024, bytes_to_alloc = 1156
0x0x804bff0: malloc resolution = 1160 bytes
0x0x804c478: malloc resolution = 1160 bytes
0x0x804c900: malloc resolution = 1160 bytes
0x0x804cd88: malloc resolution = 1160 bytes
0x0x804d210: malloc resolution = 1160 bytes
page_size = 2048, bytes_to_alloc = 2188
0x0x804df28: malloc resolution = 2192 bytes
0x0x804e7b8: malloc resolution = 2192 bytes
0x0x804f048: malloc resolution = 2192 bytes
0x0x804f8d8: malloc resolution = 2192 bytes
0x0x8050168: malloc resolution = 2192 bytes
page_size = 2048, bytes_to_alloc = 2180
0x0x8051280: malloc resolution = 2184 bytes
0x0x8051b08: malloc resolution = 2184 bytes
0x0x8052390: malloc resolution = 2184 bytes
0x0x8052c18: malloc resolution = 2184 bytes
0x0x80534a0: malloc resolution = 2184 bytes
page_size = 4096, bytes_to_alloc = 4236
0x0x8054db8: malloc resolution = 4240 bytes
0x0x8055e48: malloc resolution = 4240 bytes
0x0x8056ed8: malloc resolution = 4240 bytes
0x0x8057f68: malloc resolution = 4240 bytes
0x0x8058ff8: malloc resolution = 4240 bytes
page_size = 4096, bytes_to_alloc = 4228
0x0x805b110: malloc resolution = 4232 bytes
0x0x805c198: malloc resolution = 4232 bytes
0x0x805d220: malloc resolution = 4232 bytes
0x0x805e2a8: malloc resolution = 4232 bytes
0x0x805f330: malloc resolution = 4232 bytes
page_size = 8192, bytes_to_alloc = 8332
0x0x8062448: malloc resolution = 8336 bytes
0x0x80644d8: malloc resolution = 8336 bytes
0x0x8066568: malloc resolution = 8336 bytes
0x0x80685f8: malloc resolution = 8336 bytes
0x0x806a688: malloc resolution = 8336 bytes
page_size = 8192, bytes_to_alloc = 8324
0x0x806e7a0: malloc resolution = 8328 bytes
0x0x8070828: malloc resolution = 8328 bytes
0x0x80728b0: malloc resolution = 8328 bytes
0x0x8074938: malloc resolution = 8328 bytes
0x0x80769c0: malloc resolution = 8328 bytes

Even though this sqlite page allocation scheme is fairly efficient 
on Linux, it may be completely inefficient on platforms that have a 
power-of-2 malloc allocator, such as some early BSD platforms.
On such a platform, a page_size of 8192 would result in 
a malloc of 8332 bytes, which would have to be bumped up to 
an effective 16384 bytes resulting in close to 50% memory 
wastage.

I would recommend that SQLite not perform this clever merging 
of page memory with PgHdr and MemPage because of its inefficiency 
on platforms with sucky malloc implementations.  These power-of-2
sqlite page_size'd raw page data should be individually seperately
allocated.

> Also, my take on bitfields is that they are not thread/multi processor 
> friendly (there is no
> atomic "set bit"), and also compilers typically don't optimize well with that 
> (so before
> applying this patch, I would test on other platforms than gcc linux x86).

Setting and reading individual bytes (u8 in sqlite-speak) are not 
threadsafe either. Only reading/setting entire entire words 
are threadsafe on most architectures.

It's moot anyway because generally one would not alter structs from 
different threads without a mutex for synchronization.



 
____________________________________________________________________________________
Food fight? Enjoy some healthy debate 
in the Yahoo! Answers Food & Drink Q&A.
http://answers.yahoo.com/dir/?link=list&sid=396545367

-----------------------------------------------------------------------------
To unsubscribe, send email to [EMAIL PROTECTED]
-----------------------------------------------------------------------------

Reply via email to