[FIXED] Print.print(String) is 12 times slower than Print.write(buf*, len)

Hi everyone

I tested the YUN Datalogger official example in the Bridge Library folder and it worked OK because it has a builtin delay of 15 seconds between record writings. When I tried to increase the datalogging rate, I found that the max writing speed in the SD card was about 80 characters per second. I searched for the cause of the low writing speed and I found it.

The file.print() function used in the YUN Datalogger official example is not documented in the Bridge Library nor is found in FileIO.cpp nor in FileIO.h . The standard way to write in a file using the Bridge Library is the file.write() function.

Next time you want to use the YUN Datalogger official example as a stub for your project use the file.write() function instead.

By the way, if you want to write a String (dataString for example) in a File (dataFile for example) you need two aux variables: buf to convert the String to byte, and writeRef that returns the number of bytes written in the file. I use this:

uint8_t buf[dataString.length()+1];
dataString.getBytes(buf,dataString.length()+1);
int writeRet = dataFile.write(buf, dataString.length());

Hope you like it

Big hugs from Silvestre

Edited 22dec13 11:35. Replaced 50 chars/sec with 80 chars/sec as "print" speed. Replaced single sentence by three sentences as the example for String write. I made a mistake in the original post. Sorry

Was using write instead of print faster?
Function print is not listed in FileIO because it inherits from Stream that inherits from Print. It's Print that defined the print* functions

Hi Federico

Was using write instead of print faster?

I prepared a detailed test, which is explained down below, and it shows that for a String data record of 50 characters, file.write() speed is about 12 times faster than file.print().

Those are some plots of the time (milliseconds) spent in writing records of 28,56,81 characters using both methods.

Using file.print() the graph is:

It means that file.print(String) in our Yún takes an average of 12ms per character and 16ms for the writing overhead (file open and close).

Using file.write() the graph is:

It means that file.write(buf,len) in our Yún takes an average of 0.385ms per character and 30ms for the writing overhead (file open and close).

If we are working with a String data record of 50 characters, file.print() will take 616ms for a single record writing while file.write() will take 49ms, which is about 12 times faster.

This was the test I made:

Hardware: Arduino Yún + micro SD card 1GB (with no hi-speed code or marking)

File.Print() Code:

#include <FileIO.h>
#include <Bridge.h>
#define FileName "/mnt/sd/arduino/www/TestFile1.txt"
void setup() {
  // Setup code to run once:
  Bridge.begin();
  FileSystem.begin();
  Serial.begin(115200);
  while (!Serial); // wait for Leonardo enumeration, others continue immediately  
  //Ask for a character in Serial Monitor to start
  Serial.println("\nSend any character to begin...");
  while (Serial.available() && Serial.read()); // empty buffer
  while (!Serial.available());                 // wait for data
  while (Serial.available() && Serial.read()); // empty buffer again
}

void loop() {
  // Main code here, to run repeatedly:
  String dataString = "" ; 
  int count=0;
  int writeRet ;
  int steps = 3;
  uint8_t buf[steps*35];  //35 is character count of a single dataString rounded up
    while(true) { //cycle to write several single dataStrings at a time
      //Compose dataString as: millis,text = count
      count = count + 1;
      dataString = dataString + millis() ;
      dataString = dataString + ",Test string. Count =" ;
      dataString = dataString + count ;
      //Write when count = steps. When not append \n to dataString
      if (count==steps) {
          Serial.print("dataString length= ") ; Serial.println(dataString.length()) ;
          File dataFile = FileSystem.open(FileName, FILE_APPEND); 
          dataString = dataString + "\n" ;
          //dataString.getBytes(buf,dataString.length()+1);
          //buf[dataString.length()+1] = 0 ;
          if (dataFile) {
                //writeRet = dataFile.write(buf, dataString.length());
                dataFile.print(dataString) ;
                dataFile.close();
                //Serial.print("Written bytes= ");
                //Serial.println(writeRet) ;
                // if the file isn't open, pop up an error:
              } else {
                Serial.println("error opening datalog.txt");
              }
          //when dataString is written, start a new dataString    
          count = 0;
          dataString = "" ;  
  } else {
        //Not writing this time. Append LineFeed to dataString and compose next single dataString
        dataString = dataString + "\n" ;
  }  
  delay(0);

    }
    }

File.write() Code:

#include <FileIO.h>
#include <Bridge.h>
#define FileName "/mnt/sd/arduino/www/TestFile2.txt"
void setup() {
  // Setup code to run once:
  Bridge.begin();
  FileSystem.begin();
  Serial.begin(115200);
  while (!Serial); // wait for Leonardo enumeration, others continue immediately  
  //Ask for a character in Serial Monitor to start
  Serial.println("\nSend any character to begin...");
  while (Serial.available() && Serial.read()); // empty buffer
  while (!Serial.available());                 // wait for data
  while (Serial.available() && Serial.read()); // empty buffer again
}

void loop() {
  // Main code here, to run repeatedly:
  String dataString = "" ; 
  int count=0;
  int writeRet ;
  int steps = 3;
  uint8_t buf[steps*35];  //35 is character count of a single dataString rounded up
    while(true) { //cycle to write several single dataStrings at a time
      //Compose dataString as: millis,text = count
      count = count + 1;
      dataString = dataString + millis() ;
      dataString = dataString + ",Test string. Count =" ;
      dataString = dataString + count ;
      //Write when count = steps. When not append \n to dataString
      if (count==steps) {
          Serial.print("dataString length= ") ; Serial.println(dataString.length()) ;
          File dataFile = FileSystem.open(FileName, FILE_APPEND); 
          dataString = dataString + "\n" ;
          dataString.getBytes(buf,dataString.length()+1);
          if (dataFile) {
                int writeRet = dataFile.write(buf, dataString.length());
                dataFile.close();
                Serial.print("Written bytes= ");
                Serial.println(writeRet) ;
                 // if the file isn't open, pop up an error:
              } else {
                Serial.println("error opening datalog.txt");
              }
          //when dataString is written, start a new dataString    
          count = 0;
          dataString = "" ;  
  } else {
        //Not writing this time. Append LineFeed to dataString and compose next single dataString
        dataString = dataString + "\n" ;
  }  
  delay(0);

    }
    }

The file output for 81-84 characters (single string x 3) is like this:

9830,Test string. Count =1
9830,Test string. Count =2
9831,Test string. Count =3
10805,Test string. Count =1
10806,Test string. Count =2
10807,Test string. Count =3
11838,Test string. Count =1
11839,Test string. Count =2
11840,Test string. Count =3
12843,Test string. Count =1
12844,Test string. Count =2
12845,Test string. Count =3

The data is for file.print(). We see that the Yún takes 0-1ms to prepare a single String [millis at count==2 minus millis at count==1 and millis at count==3 minus millis at count==2] but takes a full second to prepare a single String and write 3 Strings in the file [millis at count==1 minus millis at count==3].

Function print is not listed in FileIO because it inherits from Stream that inherits from Print. It's Print that defined the print* functions

Uuuuu! Need a lot of time to realise that... I'm a Fortran-Basic-VB aficionado coder

Big hugs from Silvestre

Thank you Silvestrino, you're right. We've just fixed it. An updated IDE will be available starting tomorrow as a nightly build

Thank you Silvestrino, you're right. We've just fixed it. An updated IDE will be available starting tomorrow as a nightly build

Thanks to you Federico for fixing this issue.

I changed the thread name for a better description.

Big hugs from Silvestre