Network Server – I need more speed scotty

Status
Not open for further replies.

Pointy

Well-known member
Having got my project up and running, the only remaining issue is speed. A simple test page with a 50KB image takes about 3.5 seconds to load, when hosted on the SD card on a Teensy 3.1 using the Wiz820 SD adapter. The code is based on part 11 of this tutorial. I did try another SD library, which didn’t make any difference so I am guessing it’s the code or network. I think all of the web server samples I have found use the same method of reading 1 byte at a time, which I guess is the bottleneck. Has anyone done anything similar and improved the code for better speed? (I did some searches on these forums and did see Paul mention about improving the Ethernet library, did this ever happen?)

Here's the code...

Code:
/*--------------------------------------------------------------
  Program:      eth_websrv_SD_image

  Description:  Arduino web server that serves up a basic web
                page that displays an image.
  
  Hardware:     Arduino Uno and official Arduino Ethernet
                shield. Should work with other Arduinos and
                compatible Ethernet shields.
                2Gb micro SD card formatted FAT16
                
  Software:     Developed using Arduino 1.0.5 software
                Should be compatible with Arduino 1.0 +
                
                Requires index.htm, page2.htm and pic.jpg to be
                on the micro SD card in the Ethernet shield
                micro SD card socket.
  
  References:   - WebServer example by David A. Mellis and 
                  modified by Tom Igoe
                - SD card examples by David A. Mellis and
                  Tom Igoe
                - Ethernet library documentation:
                  http://arduino.cc/en/Reference/Ethernet
                - SD Card library documentation:
                  http://arduino.cc/en/Reference/SD

  Date:         7 March 2013
  Modified:     17 June 2013
 
  Author:       W.A. Smith, http://startingelectronics.com
--------------------------------------------------------------*/

#include <SPI.h>
#include <Ethernet.h>
#include <SD.h>

// size of buffer used to capture HTTP requests
#define REQ_BUF_SZ   20

// MAC address from Ethernet shield sticker under board
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip(192, 168, 0, 20); // IP address, may need to change depending on network
EthernetServer server(80);  // create a server at port 80
File webFile;
char HTTP_req[REQ_BUF_SZ] = {0}; // buffered HTTP request stored as null terminated string
char req_index = 0;              // index into HTTP_req buffer

void setup()
{
    // disable Ethernet chip
    pinMode(10, OUTPUT);
    digitalWrite(10, HIGH);
    
    Serial.begin(9600);       // for debugging
    
    // initialize SD card
    Serial.println("Initializing SD card...");
    if (!SD.begin(4)) {
        Serial.println("ERROR - SD card initialization failed!");
        return;    // init failed
    }
    Serial.println("SUCCESS - SD card initialized.");
    // check for index.htm file
    if (!SD.exists("test.htm")) {
        Serial.println("ERROR - Can't find test.htm file!");
        return;  // can't find index file
    }
    Serial.println("SUCCESS - Found index.htm file.");
    
    Ethernet.begin(mac, ip);  // initialize Ethernet device
    server.begin();           // start to listen for clients
}

void loop()
{
    EthernetClient client = server.available();  // try to get client

    if (client) {  // got client?
        boolean currentLineIsBlank = true;
        while (client.connected()) {
            if (client.available()) {   // client data available to read
                char c = client.read(); // read 1 byte (character) from client
                // buffer first part of HTTP request in HTTP_req array (string)
                // leave last element in array as 0 to null terminate string (REQ_BUF_SZ - 1)
                if (req_index < (REQ_BUF_SZ - 1)) {
                    HTTP_req[req_index] = c;          // save HTTP request character
                    req_index++;
                }
                // print HTTP request character to serial monitor
                Serial.print(c);
                // last line of client request is blank and ends with \n
                // respond to client only after last line received
                if (c == '\n' && currentLineIsBlank) {
                    // open requested web page file
                    if (StrContains(HTTP_req, "GET / ")
                                 || StrContains(HTTP_req, "GET /index.htm")) {
                        client.println("HTTP/1.1 200 OK");
                        client.println("Content-Type: text/html");
                        client.println("Connnection: close");
                        client.println();
                        webFile = SD.open("test.htm");        // open web page file
                    }
                     else if (StrContains(HTTP_req, "GET /pic.jpg")) {
                        webFile = SD.open("pic.jpg");
                        if (webFile) {
                            client.println("HTTP/1.1 200 OK");
                            client.println();
                        }
                    }
                    if (webFile) {
                        while(webFile.available()) {
                            client.write(webFile.read()); // send web page to client
                        }
                        webFile.close();
                    }
                    // reset buffer index and all buffer elements to 0
                    req_index = 0;
                    StrClear(HTTP_req, REQ_BUF_SZ);
                    break;
                }
                // every line of text received from the client ends with \r\n
                if (c == '\n') {
                    // last character on line of received text
                    // starting new line with next character read
                    currentLineIsBlank = true;
                } 
                else if (c != '\r') {
                    // a text character was received from client
                    currentLineIsBlank = false;
                }
            } // end if (client.available())
        } // end while (client.connected())
        delay(1);      // give the web browser time to receive the data
        client.stop(); // close the connection
    } // end if (client)
}

// sets every element of str to 0 (clears array)
void StrClear(char *str, char length)
{
    for (int i = 0; i < length; i++) {
        str[i] = 0;
    }
}

// searches for the string sfind in the string str
// returns 1 if string found
// returns 0 if string not found
char StrContains(char *str, char *sfind)
{
    char found = 0;
    char index = 0;
    char len;

    len = strlen(str);
    
    if (strlen(sfind) > len) {
        return 0;
    }
    while (index < len) {
        if (str[index] == sfind[found]) {
            found++;
            if (strlen(sfind) == found) {
                return 1;
            }
        }
        else {
            found = 0;
        }
        index++;
    }

    return 0;
}

I have attached the test htm, image and sketch in a zip file for anyone wanting to test this.

Thanks in advance.

Les
 

Attachments

  • test.zip
    53.2 KB · Views: 175
Perhaps try changing this code?

Code:
                    if (webFile) {
                        while(webFile.available()) {
                            client.write(webFile.read()); // send web page to client
                        }
                        webFile.close();
                    }

This processes the entire file 1 byte at a time. Perhaps it would be faster if you used a buffer?

Maybe something like this?

Code:
                    if (webFile) {
                        byte buf[512];
                        while (1) {
                            int n = webFile.available();
                            if (n == 0) break;
                            if (n > 512) n = 512;
                            webFile.read(buf, n);
                            client.write(buf, n);
                        }
                        webFile.close();
                    }

This is untested. I just made it up for this message. Please let me know if it works, and what kind of speed difference it makes?
 
Thanks for the quick reply Paul.

That has made a massive difference.

On my Asus Prime tablet with the original code the page took 12 seconds to load. With your code it's 0.2 seconds. It's almost like it's cached now.

Regards,

Les
 
OK hopefully the last question on this.

I have multiple images on my web page, (about 20) any suggestions on the best way to deal with them? I don't think I want to write an if statement for each one, unless it will be the fastest way.

Regards,

Les
 
I'm glad that tiny chunk of code made a 60X speedup :)

A big if-else statement might be the fastest way. But speeding up that part probably makes little difference. It'd be slower to read the SD card to search for file names. Storing an array of names and looping through it for a search would probably be nearly as fast as the if-else code, but might make for smaller & simpler code.
 
I'm glad that tiny chunk of code made a 60X speedup :)

A big if-else statement might be the fastest way. But speeding up that part probably makes little difference. It'd be slower to read the SD card to search for file names. Storing an array of names and looping through it for a search would probably be nearly as fast as the if-else code, but might make for smaller & simpler code.

It's amazing the difference a few lines of code makes.:D

I was using an array for the images, but I have simplified things and sped it up even more by using a single image for the icons and using CSS sprites. I now only have 2 image requests instead of 15.

Thanks again for your help.

Les
 
Status
Not open for further replies.
Back
Top