OSDN Git Service

Reduce CPU utilization from ~60% to ~10% on busy HCI reads.
authorSharvil Nanavati <sharvil@google.com>
Sat, 13 Jun 2015 09:12:08 +0000 (02:12 -0700)
committerAndre Eisenbach <eisenbach@google.com>
Tue, 16 Jun 2015 15:33:26 +0000 (15:33 +0000)
This patch improves RFCOMM throughput and reduces CPU utilization.
Instead of using a counting semaphore to measure bytes and reading
one at a time from the eager reader's buffer, read in bulk based
on the incoming read request size.

Change-Id: I17046bfbc3ca49576a9c82b38911aeb84234881a

osi/src/eager_reader.c

index 6f0a88f..63b190e 100644 (file)
@@ -85,7 +85,7 @@ eager_reader_t *eager_reader_new(
   ret->allocator = allocator;
   ret->inbound_fd = fd_to_read;
 
-  ret->bytes_available_fd = eventfd(0, EFD_SEMAPHORE);
+  ret->bytes_available_fd = eventfd(0, 0);
   if (ret->bytes_available_fd == INVALID_FD) {
     LOG_ERROR("%s unable to create output reading semaphore.", __func__);
     goto error;
@@ -170,31 +170,46 @@ size_t eager_reader_read(eager_reader_t *reader, uint8_t *buffer, size_t max_siz
   assert(reader != NULL);
   assert(buffer != NULL);
 
-  size_t bytes_read = 0;
+  // If the caller wants nonblocking behavior, poll to see if we have
+  // any bytes available before reading.
+  if (!block && !has_byte(reader))
+    return 0;
 
-  while (bytes_read < max_size) {
-    if (!block && !has_byte(reader))
-      return bytes_read;
+  // Find out how many bytes we have available in our various buffers.
+  eventfd_t bytes_available;
+  if (eventfd_read(reader->bytes_available_fd, &bytes_available) == -1) {
+    LOG_ERROR("%s unable to read semaphore for output data.", __func__);
+    return 0;
+  }
 
-    eventfd_t value;
-    if (eventfd_read(reader->bytes_available_fd, &value) == -1)
-      LOG_ERROR("%s unable to read semaphore for output data.", __func__);
+  if (max_size > bytes_available)
+    max_size = bytes_available;
 
+  size_t bytes_consumed = 0;
+  while (bytes_consumed < max_size) {
     if (!reader->current_buffer)
       reader->current_buffer = fixed_queue_dequeue(reader->buffers);
 
-    buffer[bytes_read] = reader->current_buffer->data[reader->current_buffer->offset];
-    reader->current_buffer->offset++;
-    bytes_read++;
+    size_t bytes_to_copy = reader->current_buffer->length - reader->current_buffer->offset;
+    if (bytes_to_copy > (max_size - bytes_consumed))
+      bytes_to_copy = max_size - bytes_consumed;
+
+    memcpy(&buffer[bytes_consumed], &reader->current_buffer->data[reader->current_buffer->offset], bytes_to_copy);
+    bytes_consumed += bytes_to_copy;
+    reader->current_buffer->offset += bytes_to_copy;
 
-    // Prep for next byte
     if (reader->current_buffer->offset >= reader->current_buffer->length) {
       reader->allocator->free(reader->current_buffer);
       reader->current_buffer = NULL;
     }
   }
 
-  return bytes_read;
+  bytes_available -= bytes_consumed;
+  if (eventfd_write(reader->bytes_available_fd, bytes_available) == -1) {
+    LOG_ERROR("%s unable to write back bytes available for output data.", __func__);
+  }
+
+  return bytes_consumed;
 }
 
 static bool has_byte(const eager_reader_t *reader) {