Program to benchmark the speed of the different file system options versus placing data directly into arrays.

Dependencies:   DMBasicGUI DMSupport

This program is used to measure the performance of the different file system options on the LPC4088 Display Module.

The performance wiki page and more specifically the software part describes this program and the output.

As the program doesn't use the display at all it can be used on both the 4.3" and 5" display modules.

Revision:
2:ddc1aa3bea3d
Parent:
1:b000ac168e46
Child:
3:1716747cba16
--- a/main.cpp	Thu Mar 12 09:25:33 2015 +0100
+++ b/main.cpp	Thu Mar 12 10:24:35 2015 +0100
@@ -146,6 +146,7 @@
     }
     if (written != BENCHMARK_INPUT[i].size) {
       log->printf("Failed to write %u (only wrote %u) bytes to %s - ABORTING\n", BENCHMARK_INPUT[i].size, written, buff);
+      fclose(f);
       return false;
     }
     fclose(f);
@@ -303,7 +304,7 @@
   }
 }
 
-static void runBenchmarks() {
+static void runReadBenchmarks() {
   RtosLog* log = DMBoard::instance().logger();
   uint32_t times[NUM_BENCHMARKS][5] = {0};
   uint32_t tmp;
@@ -416,6 +417,149 @@
   }
   
   log->printf("\n\n---\n");
+  
+  free(dest);
+}
+
+static uint32_t writeFile(const char* fname, int benchId, Timer* t, uint8_t* buff) {
+  uint32_t size = BENCHMARK_INPUT[benchId].size;
+
+  // For uSD cards it is not possible to read the data from QSPI flash.
+  // To make all tests equal all source data is copied to external SDRAM
+  // and from there to the destination file. Only the time from SDRAM to
+  // file is meassured.
+  if (BENCHMARK_INPUT[benchId].iflash_direct == NULL) {
+    memcpy(buff, BENCHMARK_INPUT[benchId].qspi_direct, size);
+  } else {
+    memcpy(buff, BENCHMARK_INPUT[benchId].iflash_direct, size);
+  }
+
+  uint32_t time = t->read_us();  
+  int written = 0;
+  FILE* f = fopen(fname, "w");
+  if (f != NULL) {
+    written = fwrite(buff, 1, size, f);
+    fclose(f);
+  }
+  if (written == size) {
+    return t->read_us() - time;      
+  } else {
+    DMBoard::instance().logger()->printf("Failed to write %s (only wrote %u of %u bytes). Aborting\n", fname, written, size);
+    return 0;
+  }
+}
+
+static void runWriteBenchmarks() {
+  RtosLog* log = DMBoard::instance().logger();
+  uint32_t times[NUM_BENCHMARKS][3] = {0};
+  char buff[512];
+  Timer t;
+
+  // For uSD cards it is not possible to read the data from QSPI flash.
+  // To make all tests equal all source data is copied to external SDRAM
+  // and from there to the destination file. Only the time from SDRAM to
+  // file is meassured.
+  uint8_t* dest = (uint8_t*)malloc(COPYBUF_SIZE);
+  if (dest == NULL) {
+    log->printf("Failed to allocate 10MBytes as buffer\n");
+    return;
+  }
+  
+  // Clear the entire QSPI file system
+  if (qspifs->format(QSPIFS_SIZE_MB) == 0) {
+    log->printf("Formatting successful\n");
+  } else {
+    log->printf("Failed to format QSPI file system!\n");
+    return;
+  }
+  
+  // For uSD and USB formatting is a bad idea as the memory
+  // might contain other important file. Just delete the files
+  // we are using instead.
+  for (int i = 0; i < NUM_BENCHMARKS; i++) {
+    // MCI
+    sprintf(buff, "/mci/%s", BENCHMARK_INPUT[i].fname);
+    remove(buff);
+      
+    //USB
+    sprintf(buff, "/usb/%s", BENCHMARK_INPUT[i].fname);
+    remove(buff);
+  }
+  
+  t.start();
+  
+  // Do the benchmarking
+  for (int i = 0; i < NUM_BENCHMARKS; i++) {
+    // MCI
+    sprintf(buff, "/mci/%s", BENCHMARK_INPUT[i].fname);
+    memset(dest, 0, COPYBUF_SIZE);
+    times[i][0] = writeFile(buff, i, &t, dest);
+    log->printf("Benchmarking %-25s took %8uus\n", buff, times[i][0]);
+      
+    //USB
+    sprintf(buff, "/usb/%s", BENCHMARK_INPUT[i].fname);
+    memset(dest, 0, COPYBUF_SIZE);
+    times[i][1] = writeFile(buff, i, &t, dest);
+    log->printf("Benchmarking %-25s took %8uus\n", buff, times[i][1]);
+
+    //QSPIFS
+    sprintf(buff, "/qspi/%s", BENCHMARK_INPUT[i].fname);
+    memset(dest, 0, COPYBUF_SIZE);
+    times[i][2] = writeFile(buff, i, &t, dest);
+    log->printf("Benchmarking %-25s took %8uus\n", buff, times[i][2]);
+  }
+  
+  log->printf("\n\n----\nSummary:\n");
+  
+  log->printf("\n  File Information\n");
+  log->printf("%18s %10s\n", "Filename", "Size");
+  log->printf("%18s %10s\n", "--------", "----");
+  for (int i = 0; i < NUM_BENCHMARKS; i++) {
+    log->printf("%18s %10d bytes\n", BENCHMARK_INPUT[i].fname, BENCHMARK_INPUT[i].size);
+  }
+
+  log->printf("\n  Write times (in us)\n");
+  log->printf("%18s %10s %10s %10s\n", "Filename", "uSD Card", "USB", "QSPI FS");
+  log->printf("%18s %10s %10s %10s\n", "--------", "--------", "---", "-------");
+  for (int i = 0; i < NUM_BENCHMARKS; i++) {
+    char* p = (char*)dest;
+    for (int x = 0; x < 3; x++) {
+      if (times[i][x] == 0) {
+        p += sprintf(p, "%10s ", "N/A");
+      } else {
+        p += sprintf(p, "%10d ", times[i][x]);
+      }
+    }
+    log->printf("%18s %s\n", BENCHMARK_INPUT[i].fname, dest);
+  }
+
+  log->printf("\n  Write speeds\n");
+  log->printf("%18s  %-12s %-12s %-12s\n", "Filename", "uSD Card", "USB", "QSPI FS");
+  log->printf("%18s  %s %s %s\n", "--------", "------------", "------------", "------------");
+  for (int i = 0; i < NUM_BENCHMARKS; i++) {
+    char* p = (char*)dest;
+    for (int x = 0; x < 3; x++) {
+      if (times[i][x] == 0) {
+        p += sprintf(p, "%12s ", "N/A ");
+      } else {
+        double t = times[i][x];
+        double s = BENCHMARK_INPUT[i].size;
+        double v = (s*1000000)/t;
+        if (v < 10000) {
+          p += sprintf(p, "%#7.2F b/s  ", v);
+        } else if (v < 10000000) {
+          p += sprintf(p, "%#7.2F Kb/s ", v/1024.0);
+        } else {
+          p += sprintf(p, "%#7.2F Mb/s ", v/(1024.0*1024.0));
+        }
+      }
+    }
+    log->printf("%18s  %s \n", BENCHMARK_INPUT[i].fname, dest);
+  }
+  
+  log->printf("\n\n---\n");
+
+  free(dest);
 }
 
 /******************************************************************************
@@ -443,7 +587,18 @@
       break;
     }
     
-    runBenchmarks();
+    runReadBenchmarks();
+    
+    Thread::wait(1000);
+    log->printf("Press the USER button to run WRITE tests!\n");
+    while(!board->buttonPressed()) {
+      Thread::wait(20);
+    }
+    while(board->buttonPressed()) {
+      Thread::wait(20);
+    }
+    
+    runWriteBenchmarks();
     
   } while(false);