Firstly I'm an engineer, not a computer scientist, so please be gentle. I currently have a C++ program which uses MySQL++. The program also incorporates the NI Visa runtime. One of the interrupt handlers receives data (1 byte) from a USB device about 200 times a second. I would like to store this data with a time stamp on each sample on a remote server. Is this feasible? Can anyone recommend a good approach? Regards, Michael
-
Is the data burst or continuous? – Jan 26 '10 at 11:45
-
I believe that one time stamp per byte is a waste of space and time, especially at 200 times per second. You may want to check your USB device to see if it can transfer more bytes per interrupt, e.g. 64 bytes per interrupt. This would allow more time for outside of interrupt code to execute. – Thomas Matthews Jan 26 '10 at 17:33
4 Answers
I think that performing 200 transactions/second against a remote server is asking a lot, especially when you consider that these transactions would be occurring in the context of an interrupt handler which has to do its job and get done quickly. I think it would be better to decouple your interrupt handler from your database access - perhaps have the interrupt handler store the incoming data and timestamp into some sort of in-memory data structure (array, circular linked list, or whatever, with appropriate synchronization) and have a separate thread that waits until data is available in the data structure and then pumps it to the database. I'd want to keep that interrupt handler as lean and deterministic as possible, and I'm concerned that database access across the network to a remote server would be too slow - or worse, would be OK most of the time, but sometimes would go to h*ll for no obvious reason.
This, of course, raises the question/problem of data overrun, where data comes in faster than it can be pumped to the database and the in-memory storage structure fills up. This could cause data loss. How bad a thing is it if you drop some samples?

- 48,992
- 9
- 77
- 110
I don't think you'll be able to maintain that speed with 1 separate insert per value, but if you batched them up into large enough batches you could send it all as one query and it should be fine.
INSERT INTO records(timestamp, value)
VALUES(1, 2), (3, 4), (5, 6), [...], (399, 400);
Just push the timestamp and value onto a buffer, and when the buffer hits 200 in size (or some other arbitrary figure), generate the SQL and send the whole lot off. Building this string up with sprintf shouldn't be too slow. Just beware of reading from a data structure that your interrupt routine might be writing to at the same time.
If you find that this SQL generation is too slow for some reason, and there's no quicker method using the API (eg. stored procedures), then you might want to run this concurrently with the data collection. Simplest is probably to stream the data across a socket or pipe to another process that performs the SQL generation. There are also multithreading approaches but they are more complex and error-prone.

- 18,290
- 7
- 46
- 74
-
I agree about the time stamp issue. I will buffer the samples and only add one timestamp for every 200 values. What storage mechanism would you suggest to store these values and read from them so as to avoid issues with the interrupt accessing it? – Jan 27 '10 at 10:01
-
I would need to be familiar with the hardware and operating system in question to provide an authoritative answer to the interrupt issue. Often there is a way to prevent interrupts from happening for a short period of time which would be long enough to transfer data out of the structure that your interrupt uses. Alternatively there might be an atomic instruction which can switch which of two buffers you are referring to, but again this is platform specific. I would hope that whatever provides this interrupt routine also provides a way to manage its execution. – Kylotan Jan 27 '10 at 11:24
-
In my opinion, you should do two things: 1. buffer the data and 2. one time stamp per buffer. The USB protocol is not byte based and more message based. If you are tracking messages, then time stamp the messages.
Also, databases would rather receive blocks or chunks of data than one byte at a time. There is overhead in the database with each transaction. To measure the efficiency, divide the overhead by the number of bytes in the transaction. You'll see that large blocks are more efficient than lots of little transactions.
Another option is to store the data into a file, then use the MySQL LOADFILE function to load the data into the the database. Also, there is storing the data into a buffer then using the MySQL C++ connector stream to load the data into the database.

- 56,849
- 17
- 98
- 154
-
I will do both 1 and 2 as you suggest. Regarding storing values locally in a file what do you suggest? SQlite? – Jan 27 '10 at 10:03
-
As for the format for storing values in a file, read up on MySQL *LOADFILE* function. It will tell the format of the file that it requires. For storing variables outside a program, on Windows you can use the Registry. Another method is storing in a file. You can use XML, INI or your own formats. I have not used SQLite, so I cannot comment on it. – Thomas Matthews Jan 28 '10 at 18:09
multi-threading doesn't guarantee being any faster than apartment even if you cached it correctly on server side unless there was some strange cpu priority preference. What about using shaders and letting the pass by reference value in windows.h be the time stamp