EThernet Shield: temps de réponse

Bonjour,

J'expérimente qq lenteurs avec l'ethernet shield micro-sdcard officiel. Je le trouve lent, voire très lent mais peut-etre est-ce normal. Si j'utilise ce tuto: http://www.ladyada.net/learn/arduino/ethfiles.html et que j'ai sur ma sd card des fichiers textes à visualiser, je trouve le chargement très long, voire même avec une connexion qui se reset, et donc je ne parviens plus à lire certains fichiers jusqu'au bout sans perdre la connexion. Y a t il eu des essais effectués sur ce point (temps de transmission de différents fichiers, de tailles différentes), avec éventuellement un comparatif entre différents shields ethernet + SD CARD ?

Merci pour vos suggestions

hello mon sujet ne passionne pas les foules, pourtant le temps de réponse d'un serveur est quand même qq chose d'important. y a t il un "arduinote" sympa qui pourrait faire l'essai avec différents fichiers textes ( 1Ko, 10ko et 100ko par exemple), en mesurant le temps nécessaire pour le transfert de chaque fichier et en utilisant le sketch de ladyada cité ci-dessus ?

merci de votre aide, car pour le moment, je ne sais pas si les lenteurs de mon serveur son "normales" ou bien si mon shield ethernet a un pb.

Salut,

je veux bien faire un test pour toi, mais lequel ? le “Browsing files” du lien ladyada ?

Gromain

la vitesse peut aussi être altérée par la nature de ton câble (j'ai déjà vu une "rallonge" RJ45 faite avec du câble téléphonique standard, et tout le monde se demandait pourquoi on n'arrivait pas à s'approcher du débit théorique prévu en cat6), par les parasites "haute tension" si ton câble RJ est trop proche d'un câble secteur, etc...

Sans parler de ton FAI, qui souvent bride le débit vers ta page perso ou qui limite le nombre de connexions simultanées (avec Free, par exemple, je crois que c'est 2 ou 3, donc si tu envoies vers le site + tu lis le site , ça fait déjà 2 connexions)

Pour mémoire, la vitesse de transmission est égale à la vitesse admissible par le maillon le plus faible de la chaine (ça sert à rien d'avoir du câble et des prises cat6 si la rallonge entre le routeur et la carte est en cat5 ou pire)

@Taddot:
Nous sommes bien en présence de lenteurs extremes. On est à des années lumieres des maximums théoriques.
Concernant ma config, je suis sur mon réseau perso et local avec freebox.
J’ai l’habitude de l’utiliser pour transferer des fichiers par ailleurs entre différents ordis sans pb.

@Gromain:

Merci de ton aide.
procédure:

1/ Crée 3 fichiers textes sur ta micro sd card, de 1Ko, 10Ko et 100Ko
2/ Utilise ce sketch (ci-après) qui liste les fichiers et repertoires presents sur ta carte en te rendant sur le web serveur de ta carte via ton navigateur.
3/ En cliquant sur les liens , tu peux afficher les contenus des fichiers textes dans ton navigateur. Mon objectif est de mesurer le temps de téléchargement complet de chaque fichier.

Merci de donner tes résultats. Je fais de même.
Je précise que j’ai un ethernet shield officiel (wiznet).

A+ et encore merci

/*
* This sketch will list all files in the root directory and
* then do a recursive list of all directories on the SD card.
*
*/
#include <SPI.h>
#include <SdFat.h>
#include <SdFatUtil.h>
#include <Ethernet.h>

/************ ETHERNET STUFF ************/
byte mac[] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55 };
byte ip[] = { 192, 168, 0, 5 };
Server server(80);


/************ SDCARD STUFF ************/
Sd2Card card;
SdVolume volume;
SdFile root;
SdFile file;

// store error strings in flash to save RAM
#define error(s) error_P(PSTR(s))

void error_P(const char* str) {
  PgmPrint("error: ");
  SerialPrintln_P(str);
  if (card.errorCode()) {
    PgmPrint("SD error: ");
    Serial.print(card.errorCode(), HEX);
    Serial.print(',');
    Serial.println(card.errorData(), HEX);
  }
  while(1);
}

void setup() {
  Serial.begin(9600);
 
  PgmPrint("Free RAM: ");
  Serial.println(FreeRam());  
  
  // initialize the SD card at SPI_HALF_SPEED to avoid bus errors with
  // breadboards.  use SPI_FULL_SPEED for better performance.
  pinMode(10, OUTPUT);                       // set the SS pin as an output (necessary!)
  digitalWrite(10, HIGH);                    // but turn off the W5100 chip!

  if (!card.init(SPI_HALF_SPEED, 4)) error("card.init failed!");
  
  // initialize a FAT volume
  if (!volume.init(&card)) error("vol.init failed!");

  PgmPrint("Volume is FAT");
  Serial.println(volume.fatType(),DEC);
  Serial.println();
  
  if (!root.openRoot(&volume)) error("openRoot failed");

  // list file in root with date and size
  PgmPrintln("Files found in root:");
  root.ls(LS_DATE | LS_SIZE);
  Serial.println();
  
  // Recursive list of all directories
  PgmPrintln("Files found in all dirs:");
  root.ls(LS_R);
  
  Serial.println();
  PgmPrintln("Done");
  
  // Debugging complete, we start the server!
  Ethernet.begin(mac, ip);
  server.begin();
}

void ListFiles(Client client, uint8_t flags) {
  // This code is just copied from SdFile.cpp in the SDFat library
  // and tweaked to print to the client output in html!
  dir_t p;
  
  root.rewind();
  client.println("<ul>");
  while (root.readDir(p) > 0) {
    // done if past last used entry
    if (p.name[0] == DIR_NAME_FREE) break;

    // skip deleted entry and entries for . and  ..
    if (p.name[0] == DIR_NAME_DELETED || p.name[0] == '.') continue;

    // only list subdirectories and files
    if (!DIR_IS_FILE_OR_SUBDIR(&p)) continue;

    // print any indent spaces
    client.print("<li><a href=\"");
    for (uint8_t i = 0; i < 11; i++) {
      if (p.name[i] == ' ') continue;
      if (i == 8) {
        client.print('.');
      }
      client.print(p.name[i]);
    }
    client.print("\">");
    
    // print file name with possible blank fill
    for (uint8_t i = 0; i < 11; i++) {
      if (p.name[i] == ' ') continue;
      if (i == 8) {
        client.print('.');
      }
      client.print(p.name[i]);
    }
    
    client.print("</a>");
    
    if (DIR_IS_SUBDIR(&p)) {
      client.print('/');
    }

    // print modify date/time if requested
    if (flags & LS_DATE) {
       root.printFatDate(p.lastWriteDate);
       client.print(' ');
       root.printFatTime(p.lastWriteTime);
    }
    // print size if requested
    if (!DIR_IS_SUBDIR(&p) && (flags & LS_SIZE)) {
      client.print(' ');
      client.print(p.fileSize);
    }
    client.println("</li>");
  }
  client.println("</ul>");
}

// How big our line buffer should be. 100 is plenty!
#define BUFSIZ 100

void loop()
{
  char clientline[BUFSIZ];
  int index = 0;
  
  Client client = server.available();
  if (client) {
    // an http request ends with a blank line
    boolean current_line_is_blank = true;
    
    // reset the input buffer
    index = 0;
    
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        
        // If it isn't a new line, add the character to the buffer
        if (c != '\n' && c != '\r') {
          clientline[index] = c;
          index++;
          // are we too big for the buffer? start tossing out data
          if (index >= BUFSIZ) 
            index = BUFSIZ -1;
          
          // continue to read more data!
          continue;
        }
        
        // got a \n or \r new line, which means the string is done
        clientline[index] = 0;
        
        // Print it out for debugging
        Serial.println(clientline);
        
        // Look for substring such as a request to get the root file
        if (strstr(clientline, "GET / ") != 0) {
          // send a standard http response header
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println();
          
          // print all the files, use a helper to keep it clean
          client.println("<h2>Files:</h2>");
          ListFiles(client, LS_SIZE);
        } else if (strstr(clientline, "GET /") != 0) {
          // this time no space after the /, so a sub-file!
          char *filename;
          
          filename = clientline + 5; // look after the "GET /" (5 chars)
          // a little trick, look for the " HTTP/1.1" string and 
          // turn the first character of the substring into a 0 to clear it out.
          (strstr(clientline, " HTTP"))[0] = 0;
          
          // print the file we want
          Serial.println(filename);

          if (! file.open(&root, filename, O_READ)) {
            client.println("HTTP/1.1 404 Not Found");
            client.println("Content-Type: text/html");
            client.println();
            client.println("<h2>File Not Found!</h2>");
            break;
          }
          
          Serial.println("Opened!");
                    
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/plain");
          client.println();
          
          int16_t c;
          while ((c = file.read()) > 0) {
              // uncomment the serial to debug (slow!)
              //Serial.print((char)c);
              client.print((char)c);
          }
          file.close();
        } else {
          // everything else is a 404
          client.println("HTTP/1.1 404 Not Found");
          client.println("Content-Type: text/html");
          client.println();
          client.println("<h2>File Not Found!</h2>");
        }
        break;
      }
    }
    // give the web browser time to receive the data
    delay(1);
    client.stop();
  }
}

Bon, j'ai fait le test que tu demandais et je constate les mêmes lenteurs (plusieurs secondes de chargement pour le fichier de 100Ko). Ca ressemble à un soucis de débit du SPI. As-tu testé en utilisant SPI_FULL_SPEED au lieu de SPI_HALF_SPEED ? J'essaierai dans la journée si je peux.

Gromain

Il est probable que ta lenteur provienne du SPI.
Tom Igoe (core arduino developper) a constaté le même problème, par contre ça va mieux avec l’ancienne lib MemoryCard library.

(pour l’instant personne n’a eu une idée pour résoudre le bug).

A+ Teiva

-------- Message original --------
Sujet: [Developers] SD or SPI problem?
Date : Thu, 20 Jan 2011 15:30:43 -0500
De : Tom Igoe tom.igoe@nyu.edu

We’ve been playing around with a LinkSprite camera here at ITP, and as part of it one of our researchers ran SparkFun’s example that writes to an SD card via the MemoryCard library. We took the same code, and changed it to the current SD library. Both libraries use sdfatlib under the hood.

With the MemoryCard library: Arduino Uno took approx. 6 seconds to write to an SD card, a 12K file.
With the SD library: took 260 seconds to write the same image to the same SD card.

Not sure if the problem is with the SD library, or the SPI library, but it bears some investigation. I recall we discsussed SPI modes, but can’t recall what we defaulted to. Anyone got an idea?

t.

J'ai fait des tests un peu plus poussé. Je pense que le goulot d'étranglement se situe plutôt au niveau Ethernet.

          while ((c = file.read()) > 0) {
              // uncomment the serial to debug (slow!)
              //Serial.print((char)c);
              client.print((char)c);
          }

Dans le code, on lit et envoie vers le client un caractère à la fois. On transporte donc 1 caractère à la fois dans une trame tcp/ip (avec en-tête et cie). J'ai fais le test avec un sniffer type wireshark, le nombre de paquet dépasse plusieurs milliers. Je pense qu'il faut d'abord rassembler les caractères lus par paquet dans un buffer, puis l'envoyer au client. Ca limitera le nombre de paquets, et le temps de chargement de la page. Reste à mettre en place un mécanisme pour gérer le buffer...

Gromain

Voici le résultat des mes essais:

temps de chargement moyen sur 3 essais par fichiers fichier 1Ko: 250ms fichier 10Ko: 2.5s fichier 100Ko: 25s

On est donc sur une base de 1Ko par 250ms. pour les petits fichiers, c'est pas gênant mais passé les 10Ko ca devient carrément limitatif et remet en cause la présence d'un connecteur sd card (plusieurs Go possibles !!). A quoi bon une telle mémoire si on ne peut l'utiliser sereinement via le serveur web. J'espère que l'avenir sera plus rapide ...

Gromain59, j'ai trouvé ceci: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1235991468/0 mais je n'ai pas encore essayé de patcher pour voir la différence. J'espère avoir avancé ce soir.

J'essaye aussi si possible ce dont parle Teiva

A+ et encore merci de votre aide

J'ai obtenu les mêmes résultats que toi.

Puis en bricolant un buffer pour envoyer par paquet de 100 octets, j'obtiens un chargement de la page de 100Ko en 5s, contre 25s auparavant ! En optimisant la taille du buffer par rapport à la RAM dispo dans ton arduino, je pense qu'on peut faire mieux encore.

Gromain

OK: avec Arduino TinyWebServer http://tinyurl.com/4qfx9rn 100Ko en 1.2s ca commence a ressembler à qq chose...

Je confirme, j’ai essayais hier avec des fichier text.
Le temps de response et tres rapide (moins d’une seconde).

Après étude de la librairie TinyWebServer, j'ai augmenté la taille des paquets TCP transmis. A l'origine donc, elle etait de 160 octets ce qui expliquait deja la rapidite (tout est relatif) de ce serveur. Mais on peut faire encore mieux, en modifiant TinyWebWerver.cpp ligne 26, et en passant de 160 à 1400, ce qui est proche de la limite recommandée pour la taille des paquets TCP. J'ai vérifié avec un sniffer réseau, mes paquets se transmettent maintenant par 1400 octets.

Merci je vais voir cela, ça me paraît cohérent qu'il s'agisse d'un problème de buffer d'après les erreurs que j'ai.

Je vais tenter de réduire le nombre max de connexions de 4 à 1 dans la librairie et augmenter le buffer à 8ko puisque je suis certain de n'utiliser qu'une seule connexion simultanée dans tout le programme.