Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Optimizing data stream to disk in C (also flash memory)

Tags:

c

linux

I have a C program running on Linux that acquires data from a USB device (sensor data), does some processing and streams the result to disk. Currently I save to a text file using fputs(), a line looks like this:

timestamp    value1    value2    ...    valueN

the sample rate being up to 250Hz.

The program should run on a RPi or similar board and possibly write the data to a flash memory (SD card).

I have following questions:

  1. Should I be optimizing the data stream or let the OS do the job? More specifically, should I be trying to minimize how often data is actually written to disk (also given the use of a flash memory)?
  2. I have read about setbuf() and setvbuf(), as I understand they should effectively delay writing until a "block" is filled. Are these appropriate or is there a better way other than perhaps implementing my own buffer?
  3. Which output function is best suited for data streaming with the above in mind (fputs() / fprintf() / write())?
  4. Should I be trying to increase randomness (as to use all sectors) when writing to a SD card? If yes what's the best way to achieve this?

Here some more thoughts:

  • I can consider using a binary format to decrease size, but I would prefer keeping the text format to simplify later data handling.
  • Using a hard drive is also an option in the final design, especially if a high acquisition rate is to be carried on over a long time.
  • The data rate being relatively low I do not expect bandwidth problem with either hard drive or SD card. It is possible that the rate will be higher in the future (kHz or more).

Thanks for your answers.

EDIT 20130128 Thank you for all the answers so far, they give me some good insight. I'll sum it up a bit:

  • In general I should not have bandwidth issues, however to avoid unnecessary large log files I might consider a binary format. Yes the log should be human readable, if not I'll make an export function or similar. Yes unwind's assumption is correct, about 10 or 15 data values each line.
  • The mentioned read/write cycles per cell should be enough for some time, at least in the testing phase, considering we don't always write and delete the same cells. I will play around with buffer size in setvbuf() and set the buffering mode to full buffering to see if I can optimize this while keeping a reasonable save interval (a few seconds or more also depending on sample rate).
  • In the final design I might use a hard drive to avoid most of the problems mentioned here, or a second SD card which can be easily replaced (might be also good to quickly retrieve the data). I will format this with one of the format suggested here (FAT or JFFS2/F2FS).
  • Following zmo's suggestion I will try to make the system as read only as possible (at least the system partition), I was already considering this.
  • A Beaglebone, also mentioned by zmo, is my next choice if I'm not happy with the RPi (I read that its USB bus is not always stable, USB is obviously very important for my application).
  • I have already implemented a UDP port to send data over network, still I would like to keep at least a local copy of that data and maybe only send a subset of or already processed data, as well as "control data".
like image 452
marcojovi Avatar asked Sep 17 '26 06:09

marcojovi


1 Answers

Should I be optimizing the data stream or let the OS do the job? More specifically, should I be trying to minimize how often data is actually written to disk (also given the use of a flash memory)?

Well, you can usually assume that the OS does a pretty awesome job at buffering and handling output to the hard drive… As long as you don't do unbuffered writes.

Though, from my experience, you should not write logs to a SD Card, because it definitely kills the SD Card faster than you can imagine. On my first projects, I had installed linux on beaglebones, and between 6 months to 12 months after, all my SD Cards had to be replaced…

Since then, I've learned to run read only systems on the SD card and send any kind of regular updates over the network, the trick being to use a ramdisk for /tmp and /var.

In your case, using a hard drive is an easy solution (which will works smoothly), but you can also use a secondary SD Card where you write the logs. Then you'll be able to use a "stupid" filesystem such as a FAT one where you'll write your data aligned, as your data will be the only thing to be written on the SD. What is killing a SDCard is lots of little read/writes that happen a lot with temporary files, and defragmentation of the drive.

I have read about setbuf() and setvbuf(), as I understand they should effectively delay writing until a "block" is filled. Are these appropriate or is there a better way other than perhaps implementing my own buffer?

well, just keep it to full buffering, it will help write your data aligned on the filesystem.

Which output function is best suited for data streaming with the above in mind (fputs() / fprintf() / write())?

they should all behave similarly for your problematic.

Should I be trying to increase randomness (as to use all sectors) when writing to a SD card? If yes what's the best way to achieve this?

the firmware of the sdcard should be taking care of that for you. The only thing would be to use a simpler filesystem like FAT (or JFFS2/F2FS like ivan-voras suggets), because ext2/ext3/ext4 filesystems do automatic defragmentation which basically is moving around inodes to keep everything aligned. Though I'm not sure if it disables that behavior with SDcards and SSDs.

like image 145
zmo Avatar answered Sep 19 '26 01:09

zmo