... | ... |
@@ -37,6 +37,9 @@ |
37 | 37 |
#endif |
38 | 38 |
#endif |
39 | 39 |
|
40 |
+#include <pthread.h> |
|
41 |
+ |
|
42 |
+ |
|
40 | 43 |
#include "others.h" |
41 | 44 |
#include "cltypes.h" |
42 | 45 |
|
... | ... |
@@ -54,9 +57,14 @@ |
54 | 54 |
/* FIXME: tune this stuff */ |
55 | 55 |
#define UNPAGE_THRSHLD_LO 4*1024*1024 |
56 | 56 |
#define UNPAGE_THRSHLD_HI 8*1024*1024 |
57 |
-#define DUMB_SIZE 1*1024*1024 |
|
57 |
+#define READAHEAD_PAGES 8 |
|
58 |
+ |
|
59 |
+/* FIXME: remove the malloc fallback, it only makes thing slower */ |
|
60 |
+#define DUMB_SIZE 0 |
|
61 |
+ |
|
62 |
+/* DON'T ASK ME */ |
|
63 |
+pthread_mutex_t fmap_mutex = PTHREAD_MUTEX_INITIALIZER; |
|
58 | 64 |
|
59 |
-#define READAHEAD_PAGES 4 |
|
60 | 65 |
|
61 | 66 |
static unsigned int fmap_align_items(unsigned int sz, unsigned int al) { |
62 | 67 |
return sz / al + (sz % al != 0); |
... | ... |
@@ -99,10 +107,15 @@ struct F_MAP *fmap(int fd, off_t offset, size_t len) { |
99 | 99 |
mapsz = pages * pgsz + hdrsz; |
100 | 100 |
#if HAVE_MMAP |
101 | 101 |
if(mapsz >= DUMB_SIZE) { |
102 |
- if ((m = (struct F_MAP *)mmap(NULL, mapsz, PROT_READ | PROT_WRITE, MAP_PRIVATE|ANONYMOUS_MAP, -1, 0)) == MAP_FAILED) |
|
102 |
+ pthread_mutex_lock(&fmap_mutex); |
|
103 |
+ if ((m = (struct F_MAP *)mmap(NULL, mapsz, PROT_READ | PROT_WRITE, MAP_PRIVATE|/*FIXME: MAP_POPULATE is ~8% faster but more memory intensive */ANONYMOUS_MAP, -1, 0)) == MAP_FAILED) |
|
103 | 104 |
m = NULL; |
104 |
- else |
|
105 |
+ else { |
|
105 | 106 |
dumb = 0; |
107 |
+ madvise(m, mapsz, MADV_RANDOM|MADV_DONTFORK); |
|
108 |
+ madvise(m, hdrsz, MADV_WILLNEED); |
|
109 |
+ } |
|
110 |
+ pthread_mutex_unlock(&fmap_mutex); |
|
106 | 111 |
} else |
107 | 112 |
#endif |
108 | 113 |
m = (struct F_MAP *)cli_malloc(mapsz); |
... | ... |
@@ -120,7 +133,13 @@ struct F_MAP *fmap(int fd, off_t offset, size_t len) { |
120 | 120 |
m->pgsz = pgsz; |
121 | 121 |
m->paged = 0; |
122 | 122 |
memset(m->bitmap, 0, sizeof(uint32_t) * pages); |
123 |
-// cli_errmsg("FMAPDBG: created %p - len %u pages %u hdrsz %u\n", m, len, pages, hdrsz); |
|
123 |
+#ifdef FMAPDEBUG |
|
124 |
+ m->page_needs = 0; |
|
125 |
+ m->page_reads = 0; |
|
126 |
+ m->page_locks = 0; |
|
127 |
+ m->page_unlocks = 0; |
|
128 |
+ m->page_unmaps = 0; |
|
129 |
+#endif |
|
124 | 130 |
return m; |
125 | 131 |
} |
126 | 132 |
|
... | ... |
@@ -179,8 +198,13 @@ static void fmap_aging(struct F_MAP *m) { |
179 | 179 |
m->bitmap[freeme[i]] = FM_MASK_SEEN; |
180 | 180 |
m->paged--; |
181 | 181 |
/* and we mmap the page over so the kernel knows there's nothing good in there */ |
182 |
+ pthread_mutex_lock(&fmap_mutex); |
|
182 | 183 |
if(mmap(pptr, m->pgsz, PROT_READ | PROT_WRITE, MAP_FIXED|MAP_PRIVATE|ANONYMOUS_MAP, -1, 0) == MAP_FAILED) |
183 | 184 |
cli_warnmsg("fmap_aging: kernel hates you\n"); |
185 |
+ pthread_mutex_unlock(&fmap_mutex); |
|
186 |
+#ifdef FMAPDEBUG |
|
187 |
+ m->page_unmaps++; |
|
188 |
+#endif |
|
184 | 189 |
} |
185 | 190 |
} |
186 | 191 |
free(freeme); |
... | ... |
@@ -192,9 +216,16 @@ static void fmap_aging(struct F_MAP *m) { |
192 | 192 |
static int fmap_readpage(struct F_MAP *m, unsigned int first_page, unsigned int count, unsigned int lock_count) { |
193 | 193 |
size_t readsz = 0, got; |
194 | 194 |
char *pptr = NULL; |
195 |
- uint32_t s; |
|
195 |
+ volatile uint32_t s; |
|
196 | 196 |
unsigned int i, page = first_page, force_read = 0; |
197 | 197 |
|
198 |
+ for(i=0; i<count; i++) { /* REAL MEN DON'T MADVISE: seriously, it sucks! */ |
|
199 |
+ volatile char faultme = ((char *)m)[(first_page+i) * m->pgsz + m->hdrsz]; |
|
200 |
+ } |
|
201 |
+#ifdef FMAPDEBUG |
|
202 |
+ m->page_needs += count; |
|
203 |
+ m->page_locks += lock_count; |
|
204 |
+#endif |
|
198 | 205 |
for(i=0; i<=count; i++, page++) { |
199 | 206 |
int lock; |
200 | 207 |
if(lock_count) { |
... | ... |
@@ -254,6 +285,9 @@ static int fmap_readpage(struct F_MAP *m, unsigned int first_page, unsigned int |
254 | 254 |
cli_warnmsg("pread fail: page %u pages %u map-offset %lu - asked for %lu bytes, got %lu\n", first_page, m->pages, (long unsigned int)m->offset, (long unsigned int)readsz, (long unsigned int)got); |
255 | 255 |
return 1; |
256 | 256 |
} |
257 |
+#ifdef FMAPDEBUG |
|
258 |
+ m->page_reads += count; |
|
259 |
+#endif |
|
257 | 260 |
pptr = NULL; |
258 | 261 |
force_read = 0; |
259 | 262 |
readsz = 0; |
... | ... |
@@ -285,12 +319,12 @@ static void *fmap_need(struct F_MAP *m, size_t at, size_t len, int lock) { |
285 | 285 |
char *ret; |
286 | 286 |
|
287 | 287 |
if(!len) { |
288 |
- cli_warnmsg("fmap: attempted void need\n"); |
|
288 |
+// cli_warnmsg("fmap: attempted void need\n"); |
|
289 | 289 |
return NULL; |
290 | 290 |
} |
291 | 291 |
|
292 | 292 |
if(!CLI_ISCONTAINED(0, m->len, at, len)) { |
293 |
- cli_warnmsg("fmap: attempted oof need\n"); |
|
293 |
+ // cli_warnmsg("fmap: attempted oof need\n"); |
|
294 | 294 |
return NULL; |
295 | 295 |
} |
296 | 296 |
|
... | ... |
@@ -304,8 +338,6 @@ static void *fmap_need(struct F_MAP *m, size_t at, size_t len, int lock) { |
304 | 304 |
if(last_page >= m->pages) last_page = m->pages - 1; |
305 | 305 |
#endif |
306 | 306 |
|
307 |
-// cli_errmsg("FMAPDBG: +++ map %p - len %u lock: %d (page %u to %u)\n", m, len, lock, first_page, last_page); |
|
308 |
- |
|
309 | 307 |
if(fmap_readpage(m, first_page, last_page-first_page+1, lock_count)) |
310 | 308 |
return NULL; |
311 | 309 |
|
... | ... |
@@ -315,19 +347,15 @@ static void *fmap_need(struct F_MAP *m, size_t at, size_t len, int lock) { |
315 | 315 |
} |
316 | 316 |
|
317 | 317 |
void *fmap_need_off(struct F_MAP *m, size_t at, size_t len) { |
318 |
-// cli_errmsg("FMAPDBG: need_off map %p at %u len %u\n", m, at, len); |
|
319 | 318 |
return fmap_need(m, at, len, 1); |
320 | 319 |
} |
321 | 320 |
void *fmap_need_off_once(struct F_MAP *m, size_t at, size_t len) { |
322 |
-// cli_errmsg("FMAPDBG: need_off_once map %p at %u len %u\n", m, at, len); |
|
323 | 321 |
return fmap_need(m, at, len, 0); |
324 | 322 |
} |
325 | 323 |
void *fmap_need_ptr(struct F_MAP *m, void *ptr, size_t len) { |
326 |
-// cli_errmsg("FMAPDBG: need_ptr map %p at %p len %u\n", m, ptr, len); |
|
327 | 324 |
return fmap_need_off(m, (char *)ptr - (char *)m - m->hdrsz, len); |
328 | 325 |
} |
329 | 326 |
void *fmap_need_ptr_once(struct F_MAP *m, void *ptr, size_t len) { |
330 |
-// cli_errmsg("FMAPDBG: need_ptr_once map %p at %p len %u\n", m, ptr, len); |
|
331 | 327 |
return fmap_need_off_once(m, (char *)ptr - (char *)m - m->hdrsz, len); |
332 | 328 |
} |
333 | 329 |
|
... | ... |
@@ -339,11 +367,12 @@ void *fmap_need_str(struct F_MAP *m, void *ptr, size_t len_hint) { |
339 | 339 |
static void fmap_unneed_page(struct F_MAP *m, unsigned int page) { |
340 | 340 |
uint32_t s = m->bitmap[page]; |
341 | 341 |
|
342 |
-// cli_errmsg("FMAPDBG: --- map %p - page %u status %u count %u\n", m, page, s>>30, s & FM_MASK_COUNT); |
|
343 |
- |
|
344 | 342 |
if((s & (FM_MASK_PAGED | FM_MASK_LOCKED)) == (FM_MASK_PAGED | FM_MASK_LOCKED)) { |
345 | 343 |
/* page is paged and locked: check lock count */ |
346 | 344 |
s &= FM_MASK_COUNT; |
345 |
+#ifdef FMAPDEBUG |
|
346 |
+ m->page_unlocks ++; |
|
347 |
+#endif |
|
347 | 348 |
if(s > 1) /* locked more than once: dec lock count */ |
348 | 349 |
m->bitmap[page]--; |
349 | 350 |
else if (s == 1) /* only one lock left: unlock and begin aging */ |
... | ... |
@@ -399,10 +428,16 @@ int fmap_readn(struct F_MAP *m, void *dst, size_t at, size_t len) { |
399 | 399 |
} |
400 | 400 |
|
401 | 401 |
void fmunmap(struct F_MAP *m) { |
402 |
+#ifdef FMAPDEBUG |
|
403 |
+ cli_errmsg("FMAPDEBUG: Needs:%u reads:%u locks:%u unlocks:%u unmaps:%u\n", m->page_needs, m->page_reads, m->page_locks, m->page_unlocks, m->page_unmaps); |
|
404 |
+#endif |
|
405 |
+ |
|
402 | 406 |
#if HAVE_MMAP |
403 | 407 |
if(!m->dumb) { |
404 | 408 |
size_t len = m->pages * m->pgsz + m->hdrsz; |
409 |
+ pthread_mutex_lock(&fmap_mutex); |
|
405 | 410 |
munmap((void *)m, len); |
411 |
+ pthread_mutex_unlock(&fmap_mutex); |
|
406 | 412 |
} else |
407 | 413 |
#endif |
408 | 414 |
free((void *)m); |
... | ... |
@@ -416,7 +451,7 @@ void *fmap_need_offstr(struct F_MAP *m, size_t at, size_t len_hint) { |
416 | 416 |
len_hint = m->len - at; |
417 | 417 |
|
418 | 418 |
if(!CLI_ISCONTAINED(0, m->len, at, len_hint)) { |
419 |
- cli_warnmsg("fmap: attempted oof need_str\n"); |
|
419 |
+ // cli_warnmsg("fmap: attempted oof need_str\n"); |
|
420 | 420 |
return NULL; |
421 | 421 |
} |
422 | 422 |
|
... | ... |
@@ -435,11 +470,12 @@ void *fmap_need_offstr(struct F_MAP *m, size_t at, size_t len_hint) { |
435 | 435 |
} |
436 | 436 |
if(i == first_page) { |
437 | 437 |
scanat = at % m->pgsz; |
438 |
- scansz = m->pgsz - scanat; |
|
438 |
+ scansz = MIN(len_hint, m->pgsz - scanat); |
|
439 | 439 |
} else { |
440 | 440 |
scanat = 0; |
441 |
- scansz = m->pgsz; |
|
441 |
+ scansz = MIN(len_hint, m->pgsz); |
|
442 | 442 |
} |
443 |
+ len_hint -= scansz; |
|
443 | 444 |
if(memchr(&thispage[scanat], 0, scansz)) |
444 | 445 |
return ptr; |
445 | 446 |
} |
... | ... |
@@ -447,3 +483,52 @@ void *fmap_need_offstr(struct F_MAP *m, size_t at, size_t len_hint) { |
447 | 447 |
fmap_unneed_page(m, i); |
448 | 448 |
return NULL; |
449 | 449 |
} |
450 |
+ |
|
451 |
+ |
|
452 |
+void *fmap_gets(struct F_MAP *m, char *dst, size_t *at, size_t max_len) { |
|
453 |
+ unsigned int i, first_page, last_page; |
|
454 |
+ char *src = (void *)((char *)m + m->hdrsz + *at), *endptr = NULL; |
|
455 |
+ size_t len = MIN(max_len-1, m->len - *at), fullen = len; |
|
456 |
+ |
|
457 |
+ if(!len || !CLI_ISCONTAINED(0, m->len, *at, len)) { |
|
458 |
+ //cli_warnmsg("fmap: attempted oof need_str\n"); |
|
459 |
+ return NULL; |
|
460 |
+ } |
|
461 |
+ |
|
462 |
+ fmap_aging(m); |
|
463 |
+ |
|
464 |
+ first_page = fmap_which_page(m, *at); |
|
465 |
+ last_page = fmap_which_page(m, *at + len - 1); |
|
466 |
+ |
|
467 |
+ for(i=first_page; i<=last_page; i++) { |
|
468 |
+ char *thispage = (char *)m + m->hdrsz + i * m->pgsz; |
|
469 |
+ unsigned int scanat, scansz; |
|
470 |
+ |
|
471 |
+ if(fmap_readpage(m, i, 1, 0)) |
|
472 |
+ return NULL; |
|
473 |
+ |
|
474 |
+ if(i == first_page) { |
|
475 |
+ scanat = *at % m->pgsz; |
|
476 |
+ scansz = MIN(len, m->pgsz - scanat); |
|
477 |
+ } else { |
|
478 |
+ scanat = 0; |
|
479 |
+ scansz = MIN(len, m->pgsz); |
|
480 |
+ } |
|
481 |
+ len -= scansz; |
|
482 |
+ |
|
483 |
+ if((endptr = memchr(&thispage[scanat], '\n', scansz))) { |
|
484 |
+ endptr++; |
|
485 |
+ break; |
|
486 |
+ } |
|
487 |
+ } |
|
488 |
+ if(endptr) { |
|
489 |
+ memcpy(dst, src, endptr - src); |
|
490 |
+ dst[endptr - src] = '\0'; |
|
491 |
+ *at += endptr - src; |
|
492 |
+ } else { |
|
493 |
+ memcpy(dst, src, fullen); |
|
494 |
+ dst[fullen] = '\0'; |
|
495 |
+ *at += fullen; |
|
496 |
+ } |
|
497 |
+ return dst; |
|
498 |
+} |