home *** CD-ROM | disk | FTP | other *** search
/ ftp.parl.clemson.edu / 2015-02-07.ftp.parl.clemson.edu.tar / ftp.parl.clemson.edu / pub / pvfs2 / orangefs-2.8.3-20110323.tar.gz / orangefs-2.8.3-20110323.tar / orangefs / src / io / bmi / bmi_ib / mem.c < prev    next >
C/C++ Source or Header  |  2008-02-22  |  11KB  |  404 lines

  1. /*
  2.  * InfiniBand BMI method, memory allocation and caching.
  3.  *
  4.  * Copyright (C) 2004-6 Pete Wyckoff <pw@osc.edu>
  5.  *
  6.  * See COPYING in top-level directory.
  7.  */
  8. #include <src/common/gen-locks/gen-locks.h>
  9. #include "pvfs2-internal.h"
  10. #include "ib.h"
  11.  
  12. #ifdef __PVFS2_SERVER__
  13. #  define ENABLE_MEMCACHE 1
  14. #else
  15. #  define ENABLE_MEMCACHE 1
  16. #endif
  17.  
  18. /*
  19.  * This internal state structure is allocated when the init function
  20.  * is called.  The device hangs onto it and gives it back to us as
  21.  * needed.
  22.  *
  23.  * TODO: Use an rbtree here instead.  Also deregister refcnt==0 regions
  24.  * when new ones come along that overlap, much like dreg, as an indication
  25.  * that application buffers have changed.
  26.  */
  27. typedef struct {
  28.     struct qlist_head list;
  29.     gen_mutex_t mutex;
  30.     struct qlist_head free_chunk_list;
  31.     int (*mem_register)(memcache_entry_t *c);
  32.     void (*mem_deregister)(memcache_entry_t *c);
  33. } memcache_device_t;
  34.  
  35. #if ENABLE_MEMCACHE
  36. /*
  37.  * Create and link a new memcache entry.  Assumes lock already held.
  38.  * Initializes count to 1.
  39.  */
  40. static memcache_entry_t *
  41. memcache_add(memcache_device_t *memcache_device, void *buf, bmi_size_t len)
  42. {
  43.     memcache_entry_t *c;
  44.  
  45.     c = malloc(sizeof(*c));
  46.     if (bmi_ib_likely(c)) {
  47.     c->buf = buf;
  48.     c->len = len;
  49.     c->count = 1;
  50.     qlist_add_tail(&c->list, &memcache_device->list);
  51.     }
  52.     return c;
  53. }
  54.  
  55. /*
  56.  * Just undo the creation of the entry, in cases where memory registration
  57.  * fails, for instance.
  58.  */
  59. static void memcache_del(memcache_device_t *memcache_device __unused,
  60.              memcache_entry_t *c)
  61. {
  62.     qlist_del(&c->list);
  63.     free(c);
  64. }
  65.  
  66. /*
  67.  * See if an entry exists that totally covers the request.  Assumes lock
  68.  * already held.  These criteria apply:
  69.  *   1. existing bounds must cover potential new one
  70.  *   2. prefer higest refcnt (hoping for maximal reuse)
  71.  *   3. prefer tightest bounds among matching refcnt
  72.  */
  73. static memcache_entry_t *
  74. memcache_lookup_cover(memcache_device_t *memcache_device, const void *const buf, bmi_size_t len)
  75. {
  76.     struct qlist_head *l;
  77.     const char *end = (const char *) buf + len;
  78.     memcache_entry_t *cbest = 0;
  79.  
  80.     qlist_for_each(l, &memcache_device->list) {
  81.     memcache_entry_t *c = qlist_entry(l, memcache_entry_t, list);
  82.     if (!(c->buf <= buf && end <= (const char *)c->buf + c->len))
  83.         continue;
  84.     if (!cbest)
  85.         goto take;
  86.     if (c->count < cbest->count)
  87.         continue;  /* discard lower refcnt one */
  88.     if (c->count > cbest->count)
  89.         goto take; /* prefer higher refcnt */
  90.     /* equal refcnt, prefer tighter bounds */
  91.     if (c->len < cbest->len)
  92.         goto take;
  93.     continue;
  94.       take:
  95.     cbest = c;
  96.     }
  97.     return cbest;
  98. }
  99.  
  100. /*
  101.  * See if the exact entry exists.  There must never be more than one
  102.  * of the same entry.  Used only for BMI_ib_memfree.
  103.  */
  104. static memcache_entry_t *
  105. memcache_lookup_exact(memcache_device_t *memcache_device, const void *const buf, bmi_size_t len)
  106. {
  107.     struct qlist_head *l;
  108.  
  109.     qlist_for_each(l, &memcache_device->list) {
  110.     memcache_entry_t *c = qlist_entry(l, memcache_entry_t, list);
  111.     if (c->buf == buf && c->len == len)
  112.         return c;
  113.     }
  114.     return 0;
  115. }
  116. #endif  /* ENABLE_MEMCACHE */
  117.  
  118. /*
  119.  * BMI malloc and free routines.  If the region is big enough, pin
  120.  * it now to save time later in the actual send or recv routine.
  121.  * These are only ever called from PVFS internal functions to allocate
  122.  * buffers, on the server, or on the client for non-user-supplied
  123.  * buffers.
  124.  *
  125.  * Standard sizes will appear frequently, thus do not free them.  Use
  126.  * a separate list sorted by sizes that can be used to reuse one.
  127.  */
  128. void *
  129. memcache_memalloc(void *md, bmi_size_t len, int eager_limit)
  130. {
  131.     memcache_device_t *memcache_device = md;
  132.     void *buf;
  133.  
  134.     debug(4, "%s: len %lld limit %d", __func__, lld(len), eager_limit);
  135.  
  136.     /* search in size cache first */
  137. #if ENABLE_MEMCACHE
  138.     if (len > eager_limit) {
  139.     memcache_entry_t *c;
  140.     gen_mutex_lock(&memcache_device->mutex);
  141.     qlist_for_each_entry(c, &memcache_device->free_chunk_list, list) {
  142.         if (c->len == len) {
  143.         debug(4, "%s: recycle free chunk, buf %p", __func__, c->buf);
  144.         qlist_del(&c->list);
  145.         qlist_add_tail(&c->list, &memcache_device->list);
  146.         ++c->count;
  147.         buf = c->buf;
  148.         gen_mutex_unlock(&memcache_device->mutex);
  149.         goto out;
  150.         }
  151.     }
  152.     gen_mutex_unlock(&memcache_device->mutex);
  153.     }
  154. #endif
  155.  
  156.     buf = malloc(len);
  157.  
  158. #if ENABLE_MEMCACHE
  159.     if (bmi_ib_unlikely(!buf))
  160.     goto out;
  161.     if (len > eager_limit) {
  162.     memcache_entry_t *c;
  163.  
  164.     gen_mutex_lock(&memcache_device->mutex);
  165.     /* could be recycled buffer */
  166.     c = memcache_lookup_cover(memcache_device, buf, len);
  167.     if (c) {
  168.         ++c->count;
  169.         debug(4, "%s: reuse reg, buf %p, count %d", __func__, c->buf,
  170.               c->count);
  171.     } else {
  172.         c = memcache_add(memcache_device, buf, len);
  173.         if (bmi_ib_unlikely(!c)) {
  174.         free(buf);
  175.         buf = NULL;
  176.         } else {
  177.         int ret = memcache_device->mem_register(c);
  178.         if (ret) {
  179.             memcache_del(memcache_device, c);
  180.             free(buf);
  181.             buf = NULL;
  182.         }
  183.         debug(4, "%s: new reg, buf %p", __func__, c->buf);
  184.         }
  185.     }
  186.     gen_mutex_unlock(&memcache_device->mutex);
  187.     }
  188.   out:
  189. #endif  /* ENABLE_MEMCACHE */
  190.     return buf;
  191. }
  192.  
  193. int
  194. memcache_memfree(void *md, void *buf, bmi_size_t len)
  195. {
  196. #if ENABLE_MEMCACHE
  197.     memcache_device_t *memcache_device = md;
  198.     memcache_entry_t *c;
  199.  
  200.     gen_mutex_lock(&memcache_device->mutex);
  201.     /* okay if not found, just not cached; perhaps an eager-size buffer */
  202.     c = memcache_lookup_exact(memcache_device, buf, len);
  203.     if (c) {
  204.     debug(4, "%s: cache free buf %p len %lld", __func__, c->buf,
  205.           lld(c->len));
  206.     bmi_ib_assert(c->count == 1, "%s: buf %p len %lld count %d, expected 1",
  207.               __func__, c->buf, lld(c->len), c->count);
  208.     /* cache it */
  209.     --c->count;
  210.     qlist_del(&c->list);
  211.     qlist_add(&c->list, &memcache_device->free_chunk_list);
  212.     gen_mutex_unlock(&memcache_device->mutex);
  213.     return 0;
  214.     }
  215.     gen_mutex_unlock(&memcache_device->mutex);
  216. #endif
  217.     free(buf);
  218.     return 0;
  219. }
  220.  
  221. /*
  222.  * Interface for bmi_ib send and recv routines in ib.c.  Takes a buflist
  223.  * and looks up each entry in the memcache, adding it if not yet pinned.
  224.  */
  225. void
  226. memcache_register(void *md, ib_buflist_t *buflist)
  227. {
  228.     int i, ret;
  229.     memcache_device_t *memcache_device = md;
  230.  
  231.     buflist->memcache = bmi_ib_malloc(buflist->num *
  232.                       sizeof(*buflist->memcache));
  233.     gen_mutex_lock(&memcache_device->mutex);
  234.     for (i=0; i<buflist->num; i++) {
  235. #if ENABLE_MEMCACHE
  236.     memcache_entry_t *c;
  237.     c = memcache_lookup_cover(memcache_device, buflist->buf.send[i],
  238.                               buflist->len[i]);
  239.     if (c) {
  240.         ++c->count;
  241.         debug(2, "%s: hit [%d] %p len %lld (via %p len %lld) refcnt now %d",
  242.           __func__, i, buflist->buf.send[i], lld(buflist->len[i]), c->buf,
  243.           lld(c->len), c->count);
  244.     } else {
  245.         debug(2, "%s: miss [%d] %p len %lld", __func__, i,
  246.           buflist->buf.send[i], lld(buflist->len[i]));
  247.         c = memcache_add(memcache_device, buflist->buf.recv[i],
  248.                          buflist->len[i]);
  249.         /* XXX: replace error with return values, let caller deal */
  250.         if (!c)
  251.         error("%s: no memory for cache entry", __func__);
  252.         ret = memcache_device->mem_register(c);
  253.         if (ret) {
  254.         memcache_del(memcache_device, c);
  255.         error("%s: could not register memory", __func__);
  256.         }
  257.     }
  258.     buflist->memcache[i] = c;
  259. #else
  260.     memcache_entry_t cp = bmi_ib_malloc(sizeof(*cp));
  261.     cp->buf = buflist->buf.recv[i];
  262.     cp->len = buflist->len[i];
  263.     cp->type = type;
  264.     ret = memcache_device->mem_register(cp);
  265.     if (ret) {
  266.         free(cp);
  267.         error("%s: could not register memory", __func__);
  268.     }
  269.     buflist->memcache[i] = cp;
  270. #endif
  271.     }
  272.     gen_mutex_unlock(&memcache_device->mutex);
  273. }
  274.  
  275. /*
  276.  * Similar to the normal register call, but does not use a buflist,
  277.  * just adds an entry to the cache for use by later registrations.
  278.  * Also does not add a refcnt on any entry.
  279.  */
  280. void memcache_preregister(void *md, const void *buf, bmi_size_t len,
  281.                           enum PVFS_io_type rw __unused)
  282. {
  283. #if ENABLE_MEMCACHE
  284.     memcache_device_t *memcache_device = md;
  285.     memcache_entry_t *c;
  286.  
  287.     gen_mutex_lock(&memcache_device->mutex);
  288.     c = memcache_lookup_cover(memcache_device, buf, len);
  289.     if (c) {
  290.     debug(2, "%s: hit %p len %lld (via %p len %lld) refcnt now %d",
  291.           __func__, buf, lld(len), c->buf, lld(c->len), c->count);
  292.     } else {
  293.     int ret;
  294.  
  295.     debug(2, "%s: miss %p len %lld", __func__, buf, lld(len));
  296.     c = memcache_add(memcache_device, (void *)(uintptr_t) buf, len);
  297.     if (!c)
  298.         error("%s: no memory for cache entry", __func__);
  299.     ret = memcache_device->mem_register(c);
  300.     c->count = 0;  /* drop ref */
  301.     if (ret)
  302.         memcache_del(memcache_device, c);
  303.     }
  304.     gen_mutex_unlock(&memcache_device->mutex);
  305. #endif
  306. }
  307.  
  308. void
  309. memcache_deregister(void *md, ib_buflist_t *buflist)
  310. {
  311.     int i;
  312.     memcache_device_t *memcache_device = md;
  313.  
  314.     gen_mutex_lock(&memcache_device->mutex);
  315.     for (i=0; i<buflist->num; i++) {
  316. #if ENABLE_MEMCACHE
  317.     memcache_entry_t *c = buflist->memcache[i];
  318.     --c->count;
  319.     debug(2,
  320.        "%s: dec refcount [%d] %p len %lld (via %p len %lld) refcnt now %d",
  321.        __func__, i, buflist->buf.send[i], lld(buflist->len[i]),
  322.        c->buf, lld(c->len), c->count);
  323.     /* let garbage collection do ib_mem_deregister(c) for refcnt==0 */
  324. #else
  325.     memcache_device->mem_deregister(buflist->memcache[i]);
  326.     free(buflist->memcache[i]);
  327. #endif
  328.     }
  329.     free(buflist->memcache);
  330.     gen_mutex_unlock(&memcache_device->mutex);
  331. }
  332.  
  333. /*
  334.  * Initialize.
  335.  */
  336. void *memcache_init(int (*mem_register)(memcache_entry_t *),
  337.                     void (*mem_deregister)(memcache_entry_t *))
  338. {
  339.     memcache_device_t *memcache_device;
  340.  
  341.     memcache_device = bmi_ib_malloc(sizeof(*memcache_device));
  342.     INIT_QLIST_HEAD(&memcache_device->list);
  343.     gen_mutex_init(&memcache_device->mutex);
  344.     INIT_QLIST_HEAD(&memcache_device->free_chunk_list);
  345.     memcache_device->mem_register = mem_register;
  346.     memcache_device->mem_deregister = mem_deregister;
  347.     return memcache_device;
  348. }
  349.  
  350. /*
  351.  * Remove all mappings in preparation for closing the pd.
  352.  */
  353. void memcache_shutdown(void *md)
  354. {
  355.     memcache_device_t *memcache_device = md;
  356.     memcache_entry_t *c, *cn;
  357.  
  358.     gen_mutex_lock(&memcache_device->mutex);
  359.     qlist_for_each_entry_safe(c, cn, &memcache_device->list, list) {
  360.     memcache_device->mem_deregister(c);
  361.     qlist_del(&c->list);
  362.     free(c);
  363.     }
  364.     qlist_for_each_entry_safe(c, cn, &memcache_device->free_chunk_list, list) {
  365.     memcache_device->mem_deregister(c);
  366.     qlist_del(&c->list);
  367.     free(c->buf);
  368.     free(c);
  369.     }
  370.     gen_mutex_unlock(&memcache_device->mutex);
  371.     free(memcache_device);
  372. }
  373.  
  374. /*
  375.  * Used to flush the cache when a NIC returns -ENOMEM on mem_reg.  Must
  376.  * hold the device lock on entry here.
  377.  */
  378. void memcache_cache_flush(void *md)
  379. {
  380.     memcache_device_t *memcache_device = md;
  381.     memcache_entry_t *c, *cn;
  382.  
  383.     debug(4, "%s", __func__);
  384.     qlist_for_each_entry_safe(c, cn, &memcache_device->list, list) {
  385.         debug(4, "%s: list c->count %x c->buf %p", __func__, c->count, c->buf);
  386.         if (c->count == 0) {
  387.             memcache_device->mem_deregister(c);
  388.             qlist_del(&c->list);
  389.             free(c);
  390.         }
  391.     }
  392.     qlist_for_each_entry_safe(c, cn, &memcache_device->free_chunk_list, list) {
  393.         debug(4, "%s: free list c->count %x c->buf %p", __func__,
  394.           c->count, c->buf);
  395.         if (c->count == 0) {
  396.             memcache_device->mem_deregister(c);
  397.             qlist_del(&c->list);
  398.             free(c->buf);
  399.             free(c);
  400.         }
  401.     }
  402. }
  403.  
  404.