]> git.apps.os.sepia.ceph.com Git - ceph-ci.git/commitdiff
os/bluestore/KernelDevice: batch aio submit
authorHaodong Tang <haodong.tang@intel.com>
Fri, 30 Jun 2017 05:08:15 +0000 (13:08 +0800)
committerHaodong Tang <haodong.tang@intel.com>
Fri, 30 Jun 2017 05:44:57 +0000 (13:44 +0800)
reduce unnessary system call(io_submit).

Signed-off-by: Haodong Tang <haodong.tang@intel.com>
src/os/bluestore/KernelDevice.cc
src/os/fs/aio.cc
src/os/fs/aio.h

index c6b9e5ad2898c33e32cb992113a8c408b8a8bb2e..032e2136253314414c4ec42f9a925ed92377d81c 100644 (file)
@@ -481,54 +481,46 @@ void KernelDevice::aio_submit(IOContext *ioc)
           << " pending " << ioc->num_pending.load()
           << " running " << ioc->num_running.load()
           << dendl;
+
   if (ioc->num_pending.load() == 0) {
     return;
   }
+
   // move these aside, and get our end iterator position now, as the
   // aios might complete as soon as they are submitted and queue more
   // wal aio's.
   list<aio_t>::iterator e = ioc->running_aios.begin();
   ioc->running_aios.splice(e, ioc->pending_aios);
-  list<aio_t>::iterator p = ioc->running_aios.begin();
 
   int pending = ioc->num_pending.load();
   ioc->num_running += pending;
   ioc->num_pending -= pending;
   assert(ioc->num_pending.load() == 0);  // we should be only thread doing this
+  assert(ioc->pending_aios.size() == 0);
+  
+  if (cct->_conf->bdev_debug_aio) {
+    list<aio_t>::iterator p = ioc->running_aios.begin();
+    while (p != e) {
+      for (auto& io : p->iov)
+       dout(30) << __func__ << "   iov " << (void*)io.iov_base
+                << " len " << io.iov_len << dendl;
 
-  bool done = false;
-  while (!done) {
-    aio_t& aio = *p;
-    aio.priv = static_cast<void*>(ioc);
-    dout(20) << __func__ << "  aio " << &aio << " fd " << aio.fd
-            << " 0x" << std::hex << aio.offset << "~" << aio.length
-            << std::dec << dendl;
-    for (auto& io : aio.iov)
-      dout(30) << __func__ << "   iov " << (void*)io.iov_base
-              << " len " << io.iov_len << dendl;
-
-    // be careful: as soon as we submit aio we race with completion.
-    // since we are holding a ref take care not to dereference txc at
-    // all after that point.
-    list<aio_t>::iterator cur = p;
-    ++p;
-    done = (p == e);
-
-    // do not dereference txc (or it's contents) after we submit (if
-    // done == true and we don't loop)
-    int retries = 0;
-    if (cct->_conf->bdev_debug_aio) {
       std::lock_guard<std::mutex> l(debug_queue_lock);
-      debug_aio_link(*cur);
-    }
-    int r = aio_queue.submit(*cur, &retries);
-    if (retries)
-      derr << __func__ << " retries " << retries << dendl;
-    if (r) {
-      derr << " aio submit got " << cpp_strerror(r) << dendl;
-      assert(r == 0);
+      debug_aio_link(*p++);
     }
   }
+
+  void *priv = static_cast<void*>(ioc);
+  int r, retries = 0;
+  r = aio_queue.submit_batch(ioc->running_aios.begin(), e, 
+                            ioc->num_running.load(), priv, &retries);
+  
+  if (retries)
+    derr << __func__ << " retries " << retries << dendl;
+  if (r < 0) {
+    derr << " aio submit got " << cpp_strerror(r) << dendl;
+    assert(r == 0);
+  }
 }
 
 int KernelDevice::_sync_write(uint64_t off, bufferlist &bl, bool buffered)
index a5edf62666558596a7d9268d84b24c37277bdc18..cfe0c5cf8c899f0fd71a7a46f6ef2c2a77711098 100644 (file)
@@ -5,14 +5,16 @@
 
 #if defined(HAVE_LIBAIO)
 
+
 int aio_queue_t::submit(aio_t &aio, int *retries)
 {
   // 2^16 * 125us = ~8 seconds, so max sleep is ~16 seconds
   int attempts = 16;
   int delay = 125;
   iocb *piocb = &aio.iocb;
+  int r;
   while (true) {
-    int r = io_submit(ctx, 1, &piocb);
+    r = io_submit(ctx, 1, &piocb);
     if (r < 0) {
       if (r == -EAGAIN && attempts-- > 0) {
        usleep(delay);
@@ -20,12 +22,43 @@ int aio_queue_t::submit(aio_t &aio, int *retries)
        (*retries)++;
        continue;
       }
-      return r;
     }
     assert(r == 1);
     break;
   }
-  return 0;
+  return r;
+}
+
+int aio_queue_t::submit_batch(aio_iter begin, aio_iter end, 
+                             uint16_t aios_size, void *priv, 
+                             int *retries)
+{
+  // 2^16 * 125us = ~8 seconds, so max sleep is ~16 seconds
+  int attempts = 16;
+  int delay = 125;
+
+  aio_iter cur = begin;
+  struct iocb *piocb[aios_size];
+  int r, pos = 0;
+  while (cur != end) {
+    cur->priv = priv;
+    *(piocb+pos) = &cur->iocb;
+    ++pos;
+    ++cur;
+  }
+  while (true) {
+    r = io_submit(ctx, pos, piocb);
+    if (r < 0) {
+      if (r == -EAGAIN && attempts-- > 0) {
+       usleep(delay);
+       delay *= 2;
+       (*retries)++;
+       continue;
+      }
+    }
+    break;
+  }
+  return r;
 }
 
 int aio_queue_t::get_next_completed(int timeout_ms, aio_t **paio, int max)
index c4757158cc90aa076699a09fe2db627d0133eae5..2517e5f64fbbb3789b8847b7665dfab08a1aacf2 100644 (file)
@@ -11,6 +11,7 @@
 #include <boost/container/small_vector.hpp>
 
 #include "include/buffer.h"
+#include "include/types.h"
 
 struct aio_t {
   struct iocb iocb;  // must be first element; see shenanigans in aio_queue_t
@@ -55,6 +56,8 @@ struct aio_queue_t {
   int max_iodepth;
   io_context_t ctx;
 
+  typedef list<aio_t>::iterator aio_iter;
+
   explicit aio_queue_t(unsigned max_iodepth)
     : max_iodepth(max_iodepth),
       ctx(0) {
@@ -83,6 +86,8 @@ struct aio_queue_t {
   }
 
   int submit(aio_t &aio, int *retries);
+  int submit_batch(aio_iter begin, aio_iter end, uint16_t aios_size, 
+                  void *priv, int *retries);
   int get_next_completed(int timeout_ms, aio_t **paio, int max);
 };