Made read over nfs faster by parallelizing the chunk fetching. Also
authorpravin shindep@inf.ethz.ch <pravin shindep@inf.ethz.ch>
Fri, 13 Jan 2012 17:17:25 +0000 (18:17 +0100)
committerpravin shindep@inf.ethz.ch <pravin shindep@inf.ethz.ch>
Fri, 13 Jan 2012 17:17:25 +0000 (18:17 +0100)
now using more fair wait_for_condition which does not block
waiting on events like timer without handling pending incoming packets.

Also, added test for measuring nfs throughput in harness.  And re-arranged
few files related to net_tests.

--HG--
rename : usr/tests/net_throughput/Hakefile => usr/tests/net_tests/nfs_throughput/Hakefile
rename : usr/tests/net_throughput/main.c => usr/tests/net_tests/nfs_throughput/nfs_cat.c
rename : usr/tests/net_openport_test/Hakefile => usr/tests/net_tests/openport_test/Hakefile
rename : usr/tests/net_openport_test/net_openport_test.c => usr/tests/net_tests/openport_test/net_openport_test.c

14 files changed:
include/lwip/init.h
lib/ethersrv/ethersrv_support.c
lib/lwip/src/barrelfish/idc_barrelfish.c
lib/lwip/src/barrelfish/idc_barrelfish.h
lib/lwip/src/core/init.c
lib/vfs/vfs_nfs.c
tools/harness/siteconfig/eth.py
tools/harness/tests/__init__.py
tools/harness/tests/nfscat.py [new file with mode: 0644]
usr/tests/net_tests/nfs_throughput/Hakefile [moved from usr/tests/net_throughput/Hakefile with 93% similarity]
usr/tests/net_tests/nfs_throughput/nfs_cat.c [moved from usr/tests/net_throughput/main.c with 59% similarity]
usr/tests/net_tests/openport_test/Hakefile [moved from usr/tests/net_openport_test/Hakefile with 100% similarity]
usr/tests/net_tests/openport_test/net_openport_test.c [moved from usr/tests/net_openport_test/net_openport_test.c with 100% similarity]
usr/tests/net_tests/udp_throughput/udp_test.c

index 6823000..afe46c5 100644 (file)
@@ -89,6 +89,8 @@ extern "C" {
     int is_lwip_loaded(void);
     uint64_t lwip_packet_drop_count(void);
 
+uint64_t wrapper_perform_lwip_work(void);
+
 void lwip_benchmark_control(int connection, uint8_t state, uint64_t trigger,
         uint64_t cl);
 uint8_t lwip_driver_benchmark_state(int direction, uint64_t *delta,
index 8fd2300..b2c3168 100644 (file)
@@ -326,13 +326,7 @@ void benchmark_control_request(struct ether_binding *cc, uint8_t state,
             total_interrupt_time = 0;
             g_cl = cl;
             reset_client_closure_stat(cl);
-            // FIXME: Remove it, only for specific debugging!!!!
-            if (cl->spp_ptr->sp->read_reg.value != 0) {
-                printf("# D: reset_client_closure_stat: read_reg == %"PRIu64""
-                    "instead of 0\n",
-                cl->spp_ptr->sp->read_reg.value);
-            }
-//            assert(cl->spp_ptr->sp->read_reg.value == 0);
+//          assert(cl->spp_ptr->sp->read_reg.value == 0);
 
             cl->in_trigger_counter = trigger;
             cl->out_trigger_counter = trigger;
index a95b7c9..2c28144 100644 (file)
@@ -851,7 +851,7 @@ static void benchmark_control_response(struct ether_binding *b, uint8_t state,
 
 bool lwip_in_packet_received = false;
 
-static uint32_t handle_incoming_packets(struct ether_binding *b)
+static uint32_t handle_incoming_packets(void)
 {
 
     struct client_closure_NC *ccnc = (struct client_closure_NC *)
@@ -923,6 +923,16 @@ static uint32_t handle_incoming_packets(struct ether_binding *b)
     return count;
 } // end function: handle_incoming_packets
 
+
+// Does all the work related to incoming and outgoing packets
+uint64_t perform_lwip_work(void)
+{
+    handle_incoming_packets();
+    sp_process_tx_done(false);
+    return 0;
+} // end function: perform_lwip_work
+
+
 static void sp_notification_from_driver(struct ether_binding *b, uint64_t type,
         uint64_t rts)
 {
@@ -941,8 +951,7 @@ static void sp_notification_from_driver(struct ether_binding *b, uint64_t type,
         netbench_record_event_simple(nb, TX_A_SP_RN_CS, rts);
     }
 
-    handle_incoming_packets(b);
-    sp_process_tx_done(false);
+    perform_lwip_work();
 
     if (benchmark_mode > 0) {
         netbench_record_event_simple(nb, TX_A_SP_RN_T, ts);
index c5cd318..713f711 100644 (file)
@@ -84,6 +84,8 @@ void idc_print_cardinfo(void);
 void network_polling_loop(void);
 void idc_benchmark_control(int connection, uint8_t state, uint64_t trigger,
         uint64_t cl);
+uint64_t perform_lwip_work(void);
+
 uint8_t get_driver_benchmark_state(int direction, uint64_t *delta,
         uint64_t *cl);
 void debug_show_spp_status(int connection);
index 02f8f09..f266ceb 100644 (file)
@@ -479,6 +479,11 @@ void lwip_debug_show_spp_status(int connection)
 }
 
 
+uint64_t wrapper_perform_lwip_work(void)
+{
+    return perform_lwip_work();
+}
+
 void lwip_benchmark_control(int direction, uint8_t state, uint64_t trigger,
         uint64_t cl)
 {
index 0f72134..9cbee71 100644 (file)
 /// Define to enable asynchronous writes
 //#define ASYNC_WRITES
 
-//#define MAX_NFS_READ_BYTES   14000 /* 1330 */
+//#define MAX_NFS_READ_CHUNKS  4000  // FIXME: Not used anymore, should be removed
+
+//#define NONBLOCKING_NFS_READ   1
 #define MAX_NFS_READ_BYTES   1330 /*14000*//*workaround for breakage in lwip*/
-//#define MAX_NFS_READ_CHUNKS  50
-#define MAX_NFS_READ_CHUNKS  5000
+
 #define MAX_NFS_WRITE_BYTES  1330 /* workaround for breakage in lwip */
 #define MAX_NFS_WRITE_CHUNKS 1    /* workaround for breakage in lwip */
 #define NFS_WRITE_STABILITY  UNSTABLE
@@ -59,7 +60,27 @@ static struct thread_cond wait_cond = THREAD_COND_INITIALIZER;
 // XXX: lwip idc_barrelfish.c
 extern struct waitset *lwip_waitset;
 
-static void wait_for_condition (void)
+//#ifdef NONBLOCKING_NFS_READ
+static void check_and_handle_other_events(void)
+{
+    if (lwip_mutex == NULL) { // single-threaded
+        while (true) {
+            errval_t err = event_dispatch_non_block(lwip_waitset);
+            if (err == LIB_ERR_NO_EVENT) {
+                return;
+            }
+            if (err_is_fail(err)) {
+                DEBUG_ERR(err, "in event_dispatch_non_block");
+                break;
+            }
+        }
+    } else {
+        assert(!"NYI: ");
+    }
+}
+//#endif // NONBLOCKING_NFS_READ
+
+static void wait_for_condition(void)
 {
     if (lwip_mutex == NULL) { // single-threaded
         while (!wait_flag) {
@@ -72,6 +93,31 @@ static void wait_for_condition (void)
     }
 }
 
+// NOTE: just like above function, but it checks all events instead of
+// blocking on any perticular event
+// Above function was blocking on waiting for timer event even when there
+// are incoming packets to be processed. (only in the case of UMP)
+// FIXME: this is used only in read function and other functions are still
+// using above function. But this function should replace above function.
+static void wait_for_condition_fair(void)
+{
+    if (lwip_mutex == NULL) { // single-threaded
+        while (!wait_flag) {
+            check_and_handle_other_events();
+            wrapper_perform_lwip_work();
+            if (wait_flag) {
+                break;
+            }
+            errval_t err = event_dispatch(lwip_waitset);
+            assert(err_is_ok(err));
+        }
+        wait_flag = false;
+    } else {
+        assert(!"NYI: ");
+    }
+}
+
+
 static void signal_condition(void)
 {
     if (lwip_mutex == NULL) { // single-threaded
@@ -566,7 +612,8 @@ static errval_t read(void *st, vfs_handle_t inhandle, void *buffer,
 
     // start a parallel load of the file, wait for it to complete
     int chunks = 0;
-    while (fh.chunk_pos < fh.size && chunks < MAX_NFS_READ_CHUNKS) {
+//    while (fh.chunk_pos < fh.size && chunks < MAX_NFS_READ_CHUNKS) {
+    while (fh.chunk_pos < fh.size) {
         struct nfs_file_parallel_io_handle *pfh =
             malloc(sizeof(struct nfs_file_parallel_io_handle));
 
@@ -580,23 +627,27 @@ static errval_t read(void *st, vfs_handle_t inhandle, void *buffer,
                      pfh->chunk_size, read_callback, pfh);
 
         if (e == ERR_MEM) { // internal resource limit in lwip?
+            printf("read: error in nfs_read ran out of mem\n");
             fh.chunk_pos -= pfh->chunk_size;
             free(pfh);
             break;
         }
         assert(e == ERR_OK);
         chunks++;
+#ifdef NONBLOCKING_NFS_READ
+        check_and_handle_other_events();
+#endif // NONBLOCKING_NFS_READ
     }
     lwip_record_event_simple(NFS_READ_1_T, ts);
     uint64_t ts1 = rdtsc();
-    wait_for_condition();
+    wait_for_condition_fair();
     lwip_record_event_simple(NFS_READ_w_T, ts1);
 
     lwip_mutex_unlock();
 
     // check result
     if (fh.status != NFS3_OK) {
-        printf("read:vfs_nfs: fh.status issue %u\n", fh.status);
+  //      printf("read:vfs_nfs: fh.status issue %u\n", fh.status);
         return nfsstat_to_errval(fh.status);
     }
 
@@ -607,9 +658,10 @@ static errval_t read(void *st, vfs_handle_t inhandle, void *buffer,
     lwip_record_event_simple(NFS_READ_T, ts);
     if (fh.size == 0) {
         /* XXX: assuming this means EOF, but we really do know from NFS */
-        printf("read:vfs_nfs: EOF marking %"PRIuPTR" < %"PRIuPTR","
+/*        printf("read:vfs_nfs: EOF marking %"PRIuPTR" < %"PRIuPTR","
                 "parallel NFS chunks [%u]\n",
                 fh.size, bytes, MAX_NFS_READ_CHUNKS);
+*/
         return VFS_ERR_EOF;
     } else {
         return SYS_ERR_OK;
@@ -1210,7 +1262,8 @@ static errval_t read_block(void *st, vfs_handle_t inhandle, void *buffer,
 
     // start a parallel load of the file, wait for it to complete
     int chunks = 0;
-    while (fh.chunk_pos < fh.size && chunks < MAX_NFS_READ_CHUNKS) {
+//    while (fh.chunk_pos < fh.size && chunks < MAX_NFS_READ_CHUNKS) {
+    while (fh.chunk_pos < fh.size) {
         struct nfs_file_parallel_io_handle *pfh =
             malloc(sizeof(struct nfs_file_parallel_io_handle));
 
index 428e793..22d6fc1 100644 (file)
@@ -15,6 +15,7 @@ LOADGEN_HOSTS = ['ikq0%d.ethz.ch' % n for n in range(2,8)]
 class ETH(siteconfig.BaseSite):
     # site-specific configuration variables for ETH
     WEBSERVER_NFS_HOST = 'emmentaler.in.barrelfish.org'
+    NFS_SERVER_HOST = 'tomme1.in.barrelfish.org'
     WEBSERVER_NFS_PATH = '/home/netos/services/websites/barrelfish'
     WEBSERVER_LOCAL_PATH = WEBSERVER_NFS_PATH
     HTTPERF_PATH = '/home/netos/tools/i686-pc-linux-gnu/bin/httperf'
index 14d6385..bb1d167 100644 (file)
@@ -43,6 +43,6 @@ def add_test(t):
     return t
 
 import memtest, webserver, rpctests, splash_bomp, echoserver, \
-    skew, tsctests, vmkit, \
+    skew, tsctests, vmkit, nfscat, \
     rcce, routing, bulktests, tracing, buildall, bomp_sidebyside, \
     monitortest, phases, clockdrift, channel_cost, fputest, TimerTest, multihoptests
diff --git a/tools/harness/tests/nfscat.py b/tools/harness/tests/nfscat.py
new file mode 100644 (file)
index 0000000..32cbb18
--- /dev/null
@@ -0,0 +1,54 @@
+##########################################################################
+# Copyright (c) 2009, 2010, 2011, ETH Zurich.
+# All rights reserved.
+#
+# This file is distributed under the terms in the attached LICENSE file.
+# If you do not find this file, copies can be found by writing to:
+# ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+##########################################################################
+
+import socket, datetime
+import tests, siteconfig
+from common import TestCommon
+from results import PassFailResult
+
+use_emmentaler = False
+NFS_TIMEOUT = datetime.timedelta(minutes=5)
+
+@tests.add_test
+class NFSTest(TestCommon):
+    '''NFS benchmark'''
+    name = "nfscat"
+
+    def get_modules(self, build, machine):
+        cardName = "e1000"
+        modules = super(NFSTest, self).get_modules(build, machine)
+        modules.add_module("e1000n", ["core=%d" % machine.get_coreids()[1]])
+        modules.add_module("netd", ["core=%d" % machine.get_coreids()[2],
+                                    "cardname=%s"%cardName])
+        if use_emmentaler :
+            nfsip = socket.gethostbyname(siteconfig.get('WEBSERVER_NFS_HOST'))
+            nfspath = "/local/nfs/harness_nfs/"
+        else :
+            nfsip = socket.gethostbyname(siteconfig.get('NFS_SERVER_HOST'))
+            nfspath = "/shared/harness_nfs/"
+
+        modules.add_module("netthroughput",
+                ["core=%d" % machine.get_coreids()[2], "nfs://" + nfsip +
+                          nfspath , "/nfs/G1.file"])
+        return modules
+
+    def get_finish_string(self):
+        return "## Data size ="
+
+    def boot(self, *args):
+        super(NFSTest, self).boot(*args)
+        self.set_timeout(NFS_TIMEOUT)
+
+    def process_data(self, testdir, rawiter):
+        # the test passed iff the last line is the finish string
+        lastline = ''
+        for line in rawiter:
+            lastline = line
+        passed = lastline.startswith(self.get_finish_string())
+        return PassFailResult(passed)
similarity index 93%
rename from usr/tests/net_throughput/Hakefile
rename to usr/tests/net_tests/nfs_throughput/Hakefile
index 5e1e80a..d2b11c1 100644 (file)
@@ -11,7 +11,7 @@
 --------------------------------------------------------------------------
 
 [ build application { target = "netthroughput",
-                      cFiles = [ "main.c"],
+                      cFiles = [ "nfs_cat.c"],
                       addLibraries = ["vfs", "nfs", "lwip",
                       "contmng", "procon" ]
                     }
similarity index 59%
rename from usr/tests/net_throughput/main.c
rename to usr/tests/net_tests/nfs_throughput/nfs_cat.c
index d69a206..f6cd87d 100644 (file)
 #include <barrelfish/waitset.h>
 #include <contmng/netbench.h>
 
-#define DIRNAME   "/nfs"
-#define FILENAME   "/nfs/pravin/testfile.txt"
-//#define MAX_DATA   (1330 * 8)
-#define MAX_DATA   (130)
-//#define MAX_DATA   (1U << 12)
+#define MOUNT_DIR   "/nfs"
 
-uint8_t buf[1024 * 1024 * 2];
+//uint8_t buf[1024 * 1024];
+uint8_t buf[1024 * 128];
 
 // reads the file over nfs
 static int cat(char *path)
@@ -65,11 +62,11 @@ static int cat(char *path)
 
     // record stop time
     uint64_t stop = rdtsc();
-    printf("######## Everythin done\n");
-    printf("Data size = %f MB,  Processing time [%"PU"], speed [%f] MB/s\n",
+    printf("Everythin done\n");
+    lwip_print_interesting_stats();
+    printf("## Data size = %f MB,  Processing time [%"PU"], speed [%f] MB/s\n",
            filesize/(double)(1024 * 1024), in_seconds(stop - start),
            ((filesize/in_seconds(stop - start))/(1024 * 1024)));
-    lwip_print_interesting_stats();
 
     err = vfs_close(vh);
     if (err_is_fail(err)) {
@@ -79,60 +76,31 @@ static int cat(char *path)
     return filesize;
 }
 
-
 int main(int argc, char**argv)
 {
 
-    if(argc < 4) {
-        printf("Usage: %s mount-DIR  mount-URL filepath\n", argv[0]);
-        printf("Example: %s /nfs nfs://10.110.4.41/shared  /nfs/pravin/601.avi\n",
+    if(argc < 3) {
+        printf("Usage: %s mount-URL filepath\n", argv[0]);
+        printf("Example: %s nfs://10.110.4.41/shared  /nfs/pravin/601.avi\n",
                 argv[0]);
         exit(EXIT_FAILURE);
     }
 
-    errval_t err = vfs_mkdir(argv[1]);
+    errval_t err = vfs_mkdir(MOUNT_DIR);
     if(err_is_fail(err)) {
         DEBUG_ERR(err, "vfs_mount");
     }
 
-    printf("######## mkdir done\n");
-    err = vfs_mount(argv[1], argv[2]);
+    err = vfs_mount(MOUNT_DIR, argv[1]);
     if(err_is_fail(err)) {
         DEBUG_ERR(err, "vfs_mount");
     }
     assert(err_is_ok(err));
-    printf("######## mount done\n");
-
-    printf("######## reading file [%s]\n", argv[3]);
-
-    cat(argv[3]);
-
-#if 0
-    // Parse trace file into memory records
-    FILE *f = fopen(argv[3], "r");
-    assert(f != NULL);
-    //    printf("######## file opened[%s]\n", argv[3]);
+    printf("mount done\n");
 
-    /* FIXME: record start time */
-    uint64_t total_size = 0;
-    uint64_t start = rdtsc();
-    while(!feof(f)) {
-        char data[MAX_DATA];
-        int ret = fread(data, MAX_DATA, 1, f);
-        if (ret <= 0) {
-            printf("fread returned %d, so EOF\n", ret);
-            break;
-        }
-        total_size += ret;
-        data[ret] = '\0';
-        //        printf("%s", data);
-    }
-    uint64_t stop = rdtsc();
-    /* FIXME: record stop time */
-    printf("######## Everythin done\n");
-    printf("Data size = %"PRIu64",  Processing time [%"PRIu64"] [%"PU"]\n",
-           total_size, (stop - start), in_seconds(stop - start));
-#endif // 0
+    printf("reading file [%s]\n", argv[2]);
+    cat(argv[2]);
+    printf("Benchmark done.\n");
 
     struct waitset *ws = get_default_waitset();
     while (1) {
index 5a957a8..b724cd6 100644 (file)
@@ -32,9 +32,9 @@
 
 //#define TOTAL_DATA_SIZE  629188608
 #define MAX_DATA   1330
-#define MULTIPLIER 1
+#define MULTIPLIER 100
 
-#define TEST_BUFFER_MANAGEMENT      1
+//#define TEST_BUFFER_MANAGEMENT      1
 
 #ifdef TEST_BUFFER_MANAGEMENT
 #define TEST_TYPE   "With BUFF Mng"
@@ -405,7 +405,10 @@ int main(int argc, char *argv[])
 
      // Parse args
     if (argc != 5) {
-        printf("Usage: %s <direction> <IP> <Port> <packets>\n", argv[0]);
+        printf("Usage: %s <direction> <IP> <Port> <packets * %d>\n",
+                argv[0], MULTIPLIER);
+        printf("eg (to send microbenchmark): %s 1 10.110.4.41 3000 1000\n", argv[0]);
+        printf("eg (to recv microbenchmark): %s 0 10.110.4.41 3000 1000\n", argv[0]);
         return 1;
     }