Browse Source

r15693@tombo: nickm | 2007-12-25 19:11:29 -0500
Here, have some terribly clever new buffer code. It uses a mbuf-like strategy rather than a ring buffer strategy, so it should require far far less extra memory to hold any given amount of data. Also, it avoids access patterns like x=malloc(1024);x=realloc(x,1048576);x=realloc(x,1024);append_to_freelist(x) that might have been contributing to memory fragmentation. I've tested it out a little on peacetime, and it seems to work so far. If you want to benchmark it for speed, make sure to remove the #define PARANOIA; #define NOINLINE macros at the head of the module.


svn:r12983

Nick Mathewson 16 years ago
parent
commit
a7ef07b4bd
6 changed files with 423 additions and 537 deletions
  1. 8 0
      ChangeLog
  2. 390 512
      src/or/buffers.c
  3. 8 9
      src/or/connection.c
  4. 2 2
      src/or/main.c
  5. 2 1
      src/or/or.h
  6. 13 13
      src/or/test.c

+ 8 - 0
ChangeLog

@@ -1,3 +1,11 @@
+Changes in version 0.2.0.16-alpha - 2008-01-??
+  o Major performance improvements:
+    - Switch our old ring buffer implementation for one more like that
+      used by free Unix kernels.  The wasted space in a buffer with
+      1mb of data will now be more like 8k than 1mb.  The new
+      implementation also avoids realloc();realloc(); patterns that
+      can contribute to memory fragmentation.
+
 Changes in version 0.2.0.15-alpha - 2007-12-25
   o Major bugfixes:
     - Fix several remotely triggerable asserts based on DirPort requests

File diff suppressed because it is too large
+ 390 - 512
src/or/buffers.c


+ 8 - 9
src/or/connection.c

@@ -1873,7 +1873,7 @@ static int
 connection_read_to_buf(connection_t *conn, int *max_to_read)
 {
   int result, at_most = *max_to_read;
-  size_t bytes_in_buf, more_to_read;
+  size_t slack_in_buf, more_to_read;
   size_t n_read = 0, n_written = 0;
 
   if (at_most == -1) { /* we need to initialize it */
@@ -1882,11 +1882,11 @@ connection_read_to_buf(connection_t *conn, int *max_to_read)
     at_most = connection_bucket_read_limit(conn, time(NULL));
   }
 
-  bytes_in_buf = buf_capacity(conn->inbuf) - buf_datalen(conn->inbuf);
+  slack_in_buf = buf_slack(conn->inbuf);
  again:
-  if ((size_t)at_most > bytes_in_buf && bytes_in_buf >= 1024) {
-    more_to_read = at_most - bytes_in_buf;
-    at_most = bytes_in_buf;
+  if ((size_t)at_most > slack_in_buf && slack_in_buf >= 1024) {
+    more_to_read = at_most - slack_in_buf;
+    at_most = slack_in_buf;
   } else {
     more_to_read = 0;
   }
@@ -1997,8 +1997,7 @@ connection_read_to_buf(connection_t *conn, int *max_to_read)
   connection_buckets_decrement(conn, time(NULL), n_read, n_written);
 
   if (more_to_read && result == at_most) {
-    bytes_in_buf = buf_capacity(conn->inbuf) - buf_datalen(conn->inbuf);
-    tor_assert(bytes_in_buf < 1024);
+    slack_in_buf = buf_slack(conn->inbuf);
     at_most = more_to_read;
     goto again;
   }
@@ -2785,11 +2784,11 @@ connection_dump_buffer_mem_stats(int severity)
     ++n_conns_by_type[tp];
     if (c->inbuf) {
       used_by_type[tp] += buf_datalen(c->inbuf);
-      alloc_by_type[tp] += buf_capacity(c->inbuf);
+      alloc_by_type[tp] += buf_allocation(c->inbuf);
     }
     if (c->outbuf) {
       used_by_type[tp] += buf_datalen(c->outbuf);
-      alloc_by_type[tp] += buf_capacity(c->outbuf);
+      alloc_by_type[tp] += buf_allocation(c->outbuf);
     }
   });
   for (i=0; i <= _CONN_TYPE_MAX; ++i) {

+ 2 - 2
src/or/main.c

@@ -1606,13 +1606,13 @@ dumpstats(int severity)
           "Conn %d: %d bytes waiting on inbuf (len %d, last read %d secs ago)",
           i,
           (int)buf_datalen(conn->inbuf),
-          (int)buf_capacity(conn->inbuf),
+          (int)buf_allocation(conn->inbuf),
           (int)(now - conn->timestamp_lastread));
       log(severity,LD_GENERAL,
           "Conn %d: %d bytes waiting on outbuf "
           "(len %d, last written %d secs ago)",i,
           (int)buf_datalen(conn->outbuf),
-          (int)buf_capacity(conn->outbuf),
+          (int)buf_allocation(conn->outbuf),
           (int)(now - conn->timestamp_lastwritten));
     }
     circuit_dump_by_conn(conn, severity); /* dump info about all the circuits

+ 2 - 1
src/or/or.h

@@ -2439,7 +2439,8 @@ void buf_shrink_freelists(int free_all);
 void buf_dump_freelist_sizes(int severity);
 
 size_t buf_datalen(const buf_t *buf);
-size_t buf_capacity(const buf_t *buf);
+size_t buf_allocation(const buf_t *buf);
+size_t buf_slack(const buf_t *buf);
 const char *_buf_peek_raw_buffer(const buf_t *buf);
 
 int read_to_buf(int s, size_t at_most, buf_t *buf, int *reached_eof);

+ 13 - 13
src/or/test.c

@@ -127,7 +127,7 @@ test_buffers(void)
   if (!(buf = buf_new()))
     test_fail();
 
-  test_eq(buf_capacity(buf), 4096);
+  //test_eq(buf_capacity(buf), 4096);
   test_eq(buf_datalen(buf), 0);
 
   /****
@@ -169,25 +169,25 @@ test_buffers(void)
 
   /* Okay, now make sure growing can work. */
   buf = buf_new_with_capacity(16);
-  test_eq(buf_capacity(buf), 16);
+  //test_eq(buf_capacity(buf), 16);
   write_to_buf(str+1, 255, buf);
-  test_eq(buf_capacity(buf), 256);
+  //test_eq(buf_capacity(buf), 256);
   fetch_from_buf(str2, 254, buf);
   test_memeq(str+1, str2, 254);
-  test_eq(buf_capacity(buf), 256);
+  //test_eq(buf_capacity(buf), 256);
   assert_buf_ok(buf);
   write_to_buf(str, 32, buf);
-  test_eq(buf_capacity(buf), 256);
+  //test_eq(buf_capacity(buf), 256);
   assert_buf_ok(buf);
   write_to_buf(str, 256, buf);
   assert_buf_ok(buf);
-  test_eq(buf_capacity(buf), 512);
+  //test_eq(buf_capacity(buf), 512);
   test_eq(buf_datalen(buf), 33+256);
   fetch_from_buf(str2, 33, buf);
   test_eq(*str2, str[255]);
 
   test_memeq(str2+1, str, 32);
-  test_eq(buf_capacity(buf), 512);
+  //test_eq(buf_capacity(buf), 512);
   test_eq(buf_datalen(buf), 256);
   fetch_from_buf(str2, 256, buf);
   test_memeq(str, str2, 256);
@@ -198,7 +198,7 @@ test_buffers(void)
   for (j=0;j<67;++j) {
     write_to_buf(str,255, buf);
   }
-  test_eq(buf_capacity(buf), 33668);
+  //test_eq(buf_capacity(buf), 33668);
   test_eq(buf_datalen(buf), 17085);
   for (j=0; j < 40; ++j) {
     fetch_from_buf(str2, 255,buf);
@@ -218,7 +218,7 @@ test_buffers(void)
   for (j=0;j<80;++j) {
     write_to_buf(str,255, buf);
   }
-  test_eq(buf_capacity(buf),33668);
+  //test_eq(buf_capacity(buf),33668);
   for (j=0; j < 120; ++j) {
     fetch_from_buf(str2, 255,buf);
     test_memeq(str2, str, 255);
@@ -275,14 +275,14 @@ test_buffers(void)
   printf("%s\n", strerror(errno));
   test_eq(i, 10);
   test_eq(eof, 0);
-  test_eq(buf_capacity(buf), 4096);
+  //test_eq(buf_capacity(buf), 4096);
   test_eq(buf_datalen(buf), 10);
 
   test_memeq(str, (char*)_buf_peek_raw_buffer(buf), 10);
 
   /* Test reading 0 bytes. */
   i = read_to_buf(s, 0, buf, &eof);
-  test_eq(buf_capacity(buf), 512*1024);
+  //test_eq(buf_capacity(buf), 512*1024);
   test_eq(buf_datalen(buf), 10);
   test_eq(eof, 0);
   test_eq(i, 0);
@@ -290,7 +290,7 @@ test_buffers(void)
   /* Now test when buffer is filled exactly. */
   buf2 = buf_new_with_capacity(6);
   i = read_to_buf(s, 6, buf2, &eof);
-  test_eq(buf_capacity(buf2), 6);
+  //test_eq(buf_capacity(buf2), 6);
   test_eq(buf_datalen(buf2), 6);
   test_eq(eof, 0);
   test_eq(i, 6);
@@ -300,7 +300,7 @@ test_buffers(void)
   /* Now test when buffer is filled with more data to read. */
   buf2 = buf_new_with_capacity(32);
   i = read_to_buf(s, 128, buf2, &eof);
-  test_eq(buf_capacity(buf2), 128);
+  //test_eq(buf_capacity(buf2), 128);
   test_eq(buf_datalen(buf2), 32);
   test_eq(eof, 0);
   test_eq(i, 32);

Some files were not shown because too many files changed in this diff