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:
3:1716747cba16
Parent:
2:ddc1aa3bea3d
Child:
5:788710a95951
--- a/main.cpp	Thu Mar 12 10:24:35 2015 +0100
+++ b/main.cpp	Mon Mar 16 11:00:15 2015 +0100
@@ -19,14 +19,15 @@
 #include "MCIFileSystem.h"
 #include "QSPIFileSystem.h"
 #include "USBHostMSD.h"
-#include "image_data.h"
-#include "image_data_qspi.h"
+#include "img_data.h"
+#include "Image.h"
 
 /******************************************************************************
  * Defines and typedefs
  *****************************************************************************/
 
 typedef struct {
+  bool           rw;  // use in the read/write test? Used in image tests regardless
   uint32_t       size;
   const char*    fname;
   const uint8_t* iflash_direct;
@@ -47,42 +48,219 @@
  *****************************************************************************/
 
 static bench_input_t BENCHMARK_INPUT[] = {
+    // The _red_ images
     {
-        .size = img_size_bench_600,
-        .fname = "bench_600.bmp",
-        .iflash_direct = img_bench_600,
-        .qspi_direct = qimg_bench_600,
+        .rw = true,
+        .size = img_size_iflash_32x32_red_bmp,
+        .fname = "32x32_red.bmp",
+        .iflash_direct = img_iflash_32x32_red_bmp,
+        .qspi_direct = img_qspi_32x32_red_bmp,
+    },
+    {
+        .rw = false,
+        .size = img_size_iflash_32x32_red_png,
+        .fname = "32x32_red.png",
+        .iflash_direct = img_iflash_32x32_red_png,
+        .qspi_direct = img_qspi_32x32_red_png,
+    },
+    {
+        .rw = false,
+        .size = img_size_iflash_32x32_red_raw,
+        .fname = "32x32_red.raw",
+        .iflash_direct = img_iflash_32x32_red_raw,
+        .qspi_direct = img_qspi_32x32_red_raw,
+    },
+    {
+        .rw = true,
+        .size = img_size_iflash_64x64_red_bmp,
+        .fname = "64x64_red.bmp",
+        .iflash_direct = img_iflash_64x64_red_bmp,
+        .qspi_direct = img_qspi_64x64_red_bmp,
+    },
+    {
+        .rw = false,
+        .size = img_size_iflash_64x64_red_png,
+        .fname = "64x64_red.png",
+        .iflash_direct = img_iflash_64x64_red_png,
+        .qspi_direct = img_qspi_64x64_red_png,
+    },
+    {
+        .rw = false,
+        .size = img_size_iflash_64x64_red_raw,
+        .fname = "64x64_red.raw",
+        .iflash_direct = img_iflash_64x64_red_raw,
+        .qspi_direct = img_qspi_64x64_red_raw,
     },
     {
-        .size = img_size_bench_10k,
-        .fname = "bench_10k.bmp",
-        .iflash_direct = img_bench_10k,
-        .qspi_direct = qimg_bench_10k,
+        .rw = true,
+        .size = img_size_qspi_128x128_red_bmp,
+        .fname = "128x128_red.bmp",
+        .iflash_direct = NULL,
+        .qspi_direct = img_qspi_128x128_red_bmp,
+    },
+    {
+        .rw = false,
+        .size = img_size_qspi_128x128_red_png,
+        .fname = "128x128_red.png",
+        .iflash_direct = NULL,
+        .qspi_direct = img_qspi_128x128_red_png,
+    },
+    {
+        .rw = false,
+        .size = img_size_qspi_128x128_red_raw,
+        .fname = "128x128_red.raw",
+        .iflash_direct = NULL,
+        .qspi_direct = img_qspi_128x128_red_raw,
+    },
+    {
+        .rw = false,
+        .size = img_size_qspi_480x272_red_bmp,
+        .fname = "480x272_red.bmp",
+        .iflash_direct = NULL,
+        .qspi_direct = img_qspi_480x272_red_bmp,
+    },
+    {
+        .rw = false,
+        .size = img_size_qspi_480x272_red_png,
+        .fname = "480x272_red.png",
+        .iflash_direct = NULL,
+        .qspi_direct = img_qspi_480x272_red_png,
+    },
+    {
+        .rw = true,
+        .size = img_size_qspi_480x272_red_raw,
+        .fname = "480x272_red.raw",
+        .iflash_direct = NULL,
+        .qspi_direct = img_qspi_480x272_red_raw,
+    },
+    {
+        .rw = true,
+        .size = img_size_qspi_800x480_red_bmp,
+        .fname = "800x480_red.bmp",
+        .iflash_direct = NULL,
+        .qspi_direct = img_qspi_800x480_red_bmp,
+    },
+    {
+        .rw = false,
+        .size = img_size_qspi_800x480_red_png,
+        .fname = "800x480_red.png",
+        .iflash_direct = NULL,
+        .qspi_direct = img_qspi_800x480_red_png,
     },
     {
-        .size = img_size_bench_100k,
-        .fname = "bench_100k.bmp",
-        .iflash_direct = img_bench_100k,
-        .qspi_direct = qimg_bench_100k,
+        .rw = false,
+        .size = img_size_qspi_800x480_red_raw,
+        .fname = "800x480_red.raw",
+        .iflash_direct = NULL,
+        .qspi_direct = img_qspi_800x480_red_raw,
+    },
+
+    // The _flowers_ images
+    {
+        .rw = false,
+        .size = img_size_iflash_32x32_flowers_bmp,
+        .fname = "32x32_flowers.bmp",
+        .iflash_direct = img_iflash_32x32_flowers_bmp,
+        .qspi_direct = img_qspi_32x32_flowers_bmp,
+    },
+    {
+        .rw = false,
+        .size = img_size_iflash_32x32_flowers_png,
+        .fname = "32x32_flowers.png",
+        .iflash_direct = img_iflash_32x32_flowers_png,
+        .qspi_direct = img_qspi_32x32_flowers_png,
     },
     {
-        .size = qimg_size_bench_350k,
-        .fname = "bench_350k.bmp",
-        .iflash_direct = NULL,
-        .qspi_direct = qimg_bench_350k,
+        .rw = false,
+        .size = img_size_iflash_32x32_flowers_raw,
+        .fname = "32x32_flowers.raw",
+        .iflash_direct = img_iflash_32x32_flowers_raw,
+        .qspi_direct = img_qspi_32x32_flowers_raw,
+    },
+    {
+        .rw = false,
+        .size = img_size_iflash_64x64_flowers_bmp,
+        .fname = "64x64_flowers.bmp",
+        .iflash_direct = img_iflash_64x64_flowers_bmp,
+        .qspi_direct = img_qspi_64x64_flowers_bmp,
+    },
+    {
+        .rw = false,
+        .size = img_size_iflash_64x64_flowers_png,
+        .fname = "64x64_flowers.png",
+        .iflash_direct = img_iflash_64x64_flowers_png,
+        .qspi_direct = img_qspi_64x64_flowers_png,
+    },
+    {
+        .rw = false,
+        .size = img_size_iflash_64x64_flowers_raw,
+        .fname = "64x64_flowers.raw",
+        .iflash_direct = img_iflash_64x64_flowers_raw,
+        .qspi_direct = img_qspi_64x64_flowers_raw,
     },
     {
-        .size = qimg_size_bench_1m,
-        .fname = "bench_1m.bmp",
+        .rw = false,
+        .size = img_size_qspi_128x128_flowers_bmp,
+        .fname = "128x128_flowers.bmp",
+        .iflash_direct = NULL,
+        .qspi_direct = img_qspi_128x128_flowers_bmp,
+    },
+    {
+        .rw = false,
+        .size = img_size_qspi_128x128_flowers_png,
+        .fname = "128x128_flowers.png",
         .iflash_direct = NULL,
-        .qspi_direct = qimg_bench_1m,
+        .qspi_direct = img_qspi_128x128_flowers_png,
+    },
+    {
+        .rw = false,
+        .size = img_size_qspi_128x128_flowers_raw,
+        .fname = "128x128_flowers.raw",
+        .iflash_direct = NULL,
+        .qspi_direct = img_qspi_128x128_flowers_raw,
+    },
+    {
+        .rw = false,
+        .size = img_size_qspi_480x272_flowers_bmp,
+        .fname = "480x272_flowers.bmp",
+        .iflash_direct = NULL,
+        .qspi_direct = img_qspi_480x272_flowers_bmp,
     },
     {
-        .size = qimg_size_bench_4m,
-        .fname = "bench_4m.bmp",
+        .rw = false,
+        .size = img_size_qspi_480x272_flowers_png,
+        .fname = "480x272_flowers.png",
+        .iflash_direct = NULL,
+        .qspi_direct = img_qspi_480x272_flowers_png,
+    },
+    {
+        .rw = false,
+        .size = img_size_qspi_480x272_flowers_raw,
+        .fname = "480x272_flowers.raw",
         .iflash_direct = NULL,
-        .qspi_direct = qimg_bench_4m,
+        .qspi_direct = img_qspi_480x272_flowers_raw,
+    },
+    {
+        .rw = false,
+        .size = img_size_qspi_800x480_flowers_bmp,
+        .fname = "800x480_flowers.bmp",
+        .iflash_direct = NULL,
+        .qspi_direct = img_qspi_800x480_flowers_bmp,
     },
+    {
+        .rw = false,
+        .size = img_size_qspi_800x480_flowers_png,
+        .fname = "800x480_flowers.png",
+        .iflash_direct = NULL,
+        .qspi_direct = img_qspi_800x480_flowers_png,
+    },
+    {
+        .rw = false,
+        .size = img_size_qspi_800x480_flowers_raw,
+        .fname = "800x480_flowers.raw",
+        .iflash_direct = NULL,
+        .qspi_direct = img_qspi_800x480_flowers_raw,
+    },    
 };
 
 static MCIFileSystem*  mcifs;
@@ -239,6 +417,7 @@
           break;
         } else {
           log->printf("One or more files missing, need to (re-)prepare the QSPI file system\n");
+          format = true;
         }      
       } else {
         log->printf("Found too small file system (only %dMB). Formatting...\n", (end-start)/(1024*1024));
@@ -319,13 +498,19 @@
   t.start();
   
   for (int i = 0; i < NUM_BENCHMARKS; i++) {
+    if (!BENCHMARK_INPUT[i].rw) {
+      // don't include the files for the image decoding in 
+      // the benchmark set
+      continue;
+    }
+
     // MCI
     sprintf(buff, "/mci/%s", BENCHMARK_INPUT[i].fname);
     memset(dest, 0, COPYBUF_SIZE);
     tmp = t.read_us();
     readFile(buff, dest);
     times[i][0] = t.read_us() - tmp;
-    log->printf("Benchmarking %-25s took %8uus\n", buff, times[i][0]);
+    log->printf("Benchmarking %-30s took %8uus\n", buff, times[i][0]);
       
     //USB
     sprintf(buff, "/usb/%s", BENCHMARK_INPUT[i].fname);
@@ -333,7 +518,7 @@
     tmp = t.read_us();
     readFile(buff, dest);
     times[i][1] = t.read_us() - tmp;
-    log->printf("Benchmarking %-25s took %8uus\n", buff, times[i][1]);
+    log->printf("Benchmarking %-30s took %8uus\n", buff, times[i][1]);
 
     //QSPIFS
     sprintf(buff, "/qspi/%s", BENCHMARK_INPUT[i].fname);
@@ -341,7 +526,7 @@
     tmp = t.read_us();
     readFile(buff, dest);
     times[i][2] = t.read_us() - tmp;
-    log->printf("Benchmarking %-25s took %8uus\n", buff, times[i][2]);
+    log->printf("Benchmarking %-30s took %8uus\n", buff, times[i][2]);
 
     //IFLASH
     sprintf(buff, "IFLASH /%s", BENCHMARK_INPUT[i].fname);
@@ -350,9 +535,9 @@
       tmp = t.read_us();
       memcpy(dest, BENCHMARK_INPUT[i].iflash_direct, BENCHMARK_INPUT[i].size);
       times[i][3] = t.read_us() - tmp;
-      log->printf("Benchmarking %-25s took %8uus\n", buff, times[i][3]);
+      log->printf("Benchmarking %-30s took %8uus\n", buff, times[i][3]);
     } else {
-      log->printf("Benchmarking %-25s skipped\n", buff);
+      log->printf("Benchmarking %-30s skipped\n", buff);
     }
 
     //QSPI
@@ -362,58 +547,64 @@
       tmp = t.read_us();
       memcpy(dest, BENCHMARK_INPUT[i].qspi_direct, BENCHMARK_INPUT[i].size);
       times[i][4] = t.read_us() - tmp;
-      log->printf("Benchmarking %-25s took %8uus\n", buff, times[i][4]);
+      log->printf("Benchmarking %-30s took %8uus\n", buff, times[i][4]);
     } else {
-      log->printf("Benchmarking %-25s skipped\n", buff);
+      log->printf("Benchmarking %-30s skipped\n", buff);
     }
   }
   
   log->printf("\n\n----\nSummary:\n");
   
   log->printf("\n  File Information\n");
-  log->printf("%18s %10s\n", "Filename", "Size");
-  log->printf("%18s %10s\n", "--------", "----");
+  log->printf("%20s %10s\n", "Filename", "Size");
+  log->printf("%20s %10s\n", "--------", "----");
   for (int i = 0; i < NUM_BENCHMARKS; i++) {
-    log->printf("%18s %10d bytes\n", BENCHMARK_INPUT[i].fname, BENCHMARK_INPUT[i].size);
+    if (BENCHMARK_INPUT[i].rw) {
+      log->printf("%20s %10d bytes\n", BENCHMARK_INPUT[i].fname, BENCHMARK_INPUT[i].size);
+    }
   }
 
   log->printf("\n  Read times (in us)\n");
-  log->printf("%18s %10s %10s %10s %10s %10s\n", "Filename", "uSD Card", "USB", "QSPI FS", "IFLASH[]", "QSPI[]");
-  log->printf("%18s %10s %10s %10s %10s %10s\n", "--------", "--------", "---", "-------", "--------", "------");
+  log->printf("%20s %10s %10s %10s %10s %10s\n", "Filename", "uSD Card", "USB", "QSPI FS", "IFLASH[]", "QSPI[]");
+  log->printf("%20s %10s %10s %10s %10s %10s\n", "--------", "--------", "---", "-------", "--------", "------");
   for (int i = 0; i < NUM_BENCHMARKS; i++) {
-    char* p = (char*)dest;
-    for (int x = 0; x < 5; x++) {
-      if (times[i][x] == 0) {
-        p += sprintf(p, "%10s ", "N/A");
-      } else {
-        p += sprintf(p, "%10d ", times[i][x]);
+    if (BENCHMARK_INPUT[i].rw) {
+      char* p = (char*)dest;
+      for (int x = 0; x < 5; x++) {
+        if (times[i][x] == 0) {
+          p += sprintf(p, "%10s ", "N/A");
+        } else {
+          p += sprintf(p, "%10d ", times[i][x]);
+        }
       }
+      log->printf("%20s %s\n", BENCHMARK_INPUT[i].fname, dest);
     }
-    log->printf("%18s %s\n", BENCHMARK_INPUT[i].fname, dest);
   }
 
   log->printf("\n  Read speeds\n");
-  log->printf("%18s  %-12s %-12s %-12s %-12s %-12s\n", "Filename", "uSD Card", "USB", "QSPI FS", "IFLASH[]", "QSPI[]");
-  log->printf("%18s  %s %s %s %s %s\n", "--------", "------------", "------------", "------------", "------------", "------------");
+  log->printf("%20s  %-12s %-12s %-12s %-12s %-12s\n", "Filename", "uSD Card", "USB", "QSPI FS", "IFLASH[]", "QSPI[]");
+  log->printf("%20s  %s %s %s %s %s\n", "--------", "------------", "------------", "------------", "------------", "------------");
   for (int i = 0; i < NUM_BENCHMARKS; i++) {
-    char* p = (char*)dest;
-    for (int x = 0; x < 5; 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);
+    if (BENCHMARK_INPUT[i].rw) {
+      char* p = (char*)dest;
+      for (int x = 0; x < 5; x++) {
+        if (times[i][x] == 0) {
+          p += sprintf(p, "%12s ", "N/A ");
         } else {
-          p += sprintf(p, "%#7.2F Mb/s ", v/(1024.0*1024.0));
+          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("%20s  %s \n", BENCHMARK_INPUT[i].fname, dest);
     }
-    log->printf("%18s  %s \n", BENCHMARK_INPUT[i].fname, dest);
   }
   
   log->printf("\n\n---\n");
@@ -454,6 +645,8 @@
   uint32_t times[NUM_BENCHMARKS][3] = {0};
   char buff[512];
   Timer t;
+  
+  log->printf("Preparing to run WRITE tests...\n");
 
   // 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
@@ -489,56 +682,223 @@
   t.start();
   
   // Do the benchmarking
-  for (int i = 0; i < NUM_BENCHMARKS; i++) {
+  for (int i = 0; i < NUM_BENCHMARKS; i++) {      
+    if (!BENCHMARK_INPUT[i].rw) {
+      // don't include the files for the image decoding in 
+      // the benchmark set
+      continue;
+    }
+
     // 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]);
+    log->printf("Benchmarking %-30s 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]);
+    log->printf("Benchmarking %-30s 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("Benchmarking %-30s 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", "--------", "----");
+  log->printf("%20s %10s\n", "Filename", "Size");
+  log->printf("%20s %10s\n", "--------", "----");
   for (int i = 0; i < NUM_BENCHMARKS; i++) {
-    log->printf("%18s %10d bytes\n", BENCHMARK_INPUT[i].fname, BENCHMARK_INPUT[i].size);
+    if (BENCHMARK_INPUT[i].rw) {
+      log->printf("%20s %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", "--------", "--------", "---", "-------");
+  log->printf("%20s %10s %10s %10s\n", "Filename", "uSD Card", "USB", "QSPI FS");
+  log->printf("%20s %10s %10s %10s\n", "--------", "--------", "---", "-------");
+  for (int i = 0; i < NUM_BENCHMARKS; i++) {
+    if (BENCHMARK_INPUT[i].rw) {
+      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("%20s %s\n", BENCHMARK_INPUT[i].fname, dest);
+    }
+  }
+
+  log->printf("\n  Write speeds\n");
+  log->printf("%20s  %-12s %-12s %-12s\n", "Filename", "uSD Card", "USB", "QSPI FS");
+  log->printf("%20s  %s %s %s\n", "--------", "------------", "------------", "------------");
+  for (int i = 0; i < NUM_BENCHMARKS; i++) {
+    if (BENCHMARK_INPUT[i].rw) {
+      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("%20s  %s \n", BENCHMARK_INPUT[i].fname, dest);
+    }
+  }
+  
+  log->printf("\n\n---\n");
+
+  free(dest);
+}
+
+static void runImageBenchmarks() {
+  RtosLog* log = DMBoard::instance().logger();
+  uint32_t times[NUM_BENCHMARKS][5] = {0};
+  uint32_t tmp;
+  char buff[512];
+  int result;
+  Image::ImageData_t imgData;
+  Timer t;
+  
+  t.start();
+  
   for (int i = 0; i < NUM_BENCHMARKS; i++) {
-    char* p = (char*)dest;
-    for (int x = 0; x < 3; x++) {
+
+    // MCI
+    sprintf(buff, "/mci/%s", BENCHMARK_INPUT[i].fname);
+    tmp = t.read_us();
+    result = Image::decode(buff, Image::RES_16BIT, &imgData);
+    times[i][0] = t.read_us() - tmp;
+    if (result == 0) {
+      log->printf("Decoding %-30s took %8uus\n", buff, times[i][0]);
+      if (imgData.pointerToFree != NULL) {
+        free(imgData.pointerToFree);
+        imgData.pointerToFree = NULL;
+      }
+    } else {
+      log->printf("Decoding %-30s failed\n", buff);
+      times[i][0] = 0;
+    }
+      
+    //USB
+    sprintf(buff, "/usb/%s", BENCHMARK_INPUT[i].fname);
+    tmp = t.read_us();
+    result = Image::decode(buff, Image::RES_16BIT, &imgData);
+    times[i][1] = t.read_us() - tmp;
+    if (result == 0) {
+      log->printf("Decoding %-30s took %8uus\n", buff, times[i][1]);
+      if (imgData.pointerToFree != NULL) {
+        free(imgData.pointerToFree);
+        imgData.pointerToFree = NULL;
+      }
+    } else {
+      log->printf("Decoding %-30s failed\n", buff);
+      times[i][1] = 0;
+    }
+
+    //QSPIFS
+    sprintf(buff, "/qspi/%s", BENCHMARK_INPUT[i].fname);
+    tmp = t.read_us();
+    result = Image::decode(buff, Image::RES_16BIT, &imgData);
+    times[i][2] = t.read_us() - tmp;
+    if (result == 0) {
+      log->printf("Decoding %-30s took %8uus\n", buff, times[i][2]);
+      if (imgData.pointerToFree != NULL) {
+        free(imgData.pointerToFree);
+        imgData.pointerToFree = NULL;
+      }
+    } else {
+      log->printf("Decoding %-30s failed\n", buff);
+      times[i][2] = 0;
+    }
+
+    //IFLASH
+    sprintf(buff, "IFLASH /%s", BENCHMARK_INPUT[i].fname);
+    if (BENCHMARK_INPUT[i].iflash_direct != NULL) {
+      tmp = t.read_us();
+      result = Image::decode(BENCHMARK_INPUT[i].iflash_direct, BENCHMARK_INPUT[i].size, Image::RES_16BIT, &imgData);
+      times[i][3] = t.read_us() - tmp;
+      if (result == 0) {
+        log->printf("Decoding %-30s took %8uus\n", buff, times[i][3]);
+        if (imgData.pointerToFree != NULL) {
+          free(imgData.pointerToFree);
+          imgData.pointerToFree = NULL;
+        }
+      } else {
+        log->printf("Decoding %-30s failed\n", buff);
+        times[i][3] = 0;
+      }
+    } else {
+      log->printf("Decoding %-30s skipped\n", buff);
+    }
+
+    //QSPI
+    sprintf(buff, "QSPI /%s", BENCHMARK_INPUT[i].fname);
+    if (BENCHMARK_INPUT[i].qspi_direct != NULL) {
+      tmp = t.read_us();
+      result = Image::decode(BENCHMARK_INPUT[i].qspi_direct, BENCHMARK_INPUT[i].size, Image::RES_16BIT, &imgData);
+      times[i][4] = t.read_us() - tmp;
+      if (result == 0) {
+        log->printf("Decoding %-30s took %8uus\n", buff, times[i][4]);
+        if (imgData.pointerToFree != NULL) {
+          free(imgData.pointerToFree);
+          imgData.pointerToFree = NULL;
+        }
+      } else {
+        log->printf("Decoding %-30s failed\n", buff);
+        times[i][4] = 0;
+      }
+    } else {
+      log->printf("Decoding %-30s skipped\n", buff);
+    }
+  }
+  
+  log->printf("\n\n----\nSummary:\n");
+  
+  log->printf("\n  File Information\n");
+  log->printf("%20s %10s\n", "Filename", "Size");
+  log->printf("%20s %10s\n", "--------", "----");
+  for (int i = 0; i < NUM_BENCHMARKS; i++) {
+    log->printf("%20s %10d bytes\n", BENCHMARK_INPUT[i].fname, BENCHMARK_INPUT[i].size);
+  }
+
+  log->printf("\n  Decode times (in us)\n");
+  log->printf("%20s %10s %10s %10s %10s %10s\n", "Filename", "uSD Card", "USB", "QSPI FS", "IFLASH[]", "QSPI[]");
+  log->printf("%20s %10s %10s %10s %10s %10s\n", "--------", "--------", "---", "-------", "--------", "------");
+  for (int i = 0; i < NUM_BENCHMARKS; i++) {
+    char* p = (char*)buff;
+    for (int x = 0; x < 5; 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("%20s %s\n", BENCHMARK_INPUT[i].fname, buff);
   }
 
-  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", "--------", "------------", "------------", "------------");
+  log->printf("\n  Decode speeds\n");
+  log->printf("%20s  %-12s %-12s %-12s %-12s %-12s\n", "Filename", "uSD Card", "USB", "QSPI FS", "IFLASH[]", "QSPI[]");
+  log->printf("%20s  %s %s %s %s %s\n", "--------", "------------", "------------", "------------", "------------", "------------");
   for (int i = 0; i < NUM_BENCHMARKS; i++) {
-    char* p = (char*)dest;
-    for (int x = 0; x < 3; x++) {
+    char* p = (char*)buff;
+    for (int x = 0; x < 5; x++) {
       if (times[i][x] == 0) {
         p += sprintf(p, "%12s ", "N/A ");
       } else {
@@ -554,12 +914,10 @@
         }
       }
     }
-    log->printf("%18s  %s \n", BENCHMARK_INPUT[i].fname, dest);
+    log->printf("%20s  %s \n", BENCHMARK_INPUT[i].fname, buff);
   }
   
   log->printf("\n\n---\n");
-
-  free(dest);
 }
 
 /******************************************************************************
@@ -588,6 +946,7 @@
     }
     
     runReadBenchmarks();
+    runImageBenchmarks();
     
     Thread::wait(1000);
     log->printf("Press the USER button to run WRITE tests!\n");