I am writing a CAN bus logger application and need to format messages as quick as possible in order to prevent buffer overflows on our device. In some cases I am quick enough, but under heavy loads it is still pretty slow. I believe the bulk of the problem happens in my formatting block (I am using TPL to separate the tasks as much as possible). Here is my consumer block which takes a PassThruMsg[]
blocking collection, formats those messages, and passes them into a new blocking collection where they are later printed to a file:
private void FormatMessages(BlockingCollection<PassThruMsg[]> messages, BlockingCollection<string[]> formattedMessages)
{
try
{
PassThruMsg msg;
String[] formatted;
foreach (var item in messages.GetConsumingEnumerable(_cancellationTokenSource.Token))
{
formatted = new string[item.Length];
for (uint i = 0; i < item.Length; i++)
{
msg = item[i];
if (_firstTime == 0) _firstTime = msg.timestamp;
formatted[i] = ((msg.timestamp - _firstTime) / 1000000.0).ToString("0.000000 ");
// Assumed CAN Protocol
//TODO:
string canID = BitConverter.ToString(msg.data, 0, 4).Replace("-", "").TrimStart('0');
string data = msg.dataSize > 4 ? BitConverter.ToString(msg.data, 4, (int)msg.dataSize - 4).Replace("-", " ") : String.Empty;
formatted[i] += canID + " " + data;
}
formattedMessages.Add(formatted);
}
}
catch (OperationCanceledException)
{
//TODO:
}
}
If it is relevant, here is the snippet where I pass into the BlockingCollection
uint numMsgs;
while (!_cancellationTokenSource.IsCancellationRequested)
{
numMsgs = (uint)msgs.Length;
status = j2534.PassThruReadMsgs(channelID, msgs, ref numMsgs, 1000);
PassThruMsg[] copiedMessages = new PassThruMsg[numMsgs];
Array.Copy(msgs, copiedMessages, numMsgs);
if (status == Status.ERR_BUFFER_OVERFLOW)
{
_fileWriter.WriteLine("DEVICE INDICATED BUFFER OVERFLOW - MESSAGES LOST!");
logMessages.Add(copiedMessages);
}
else if (status == Status.STATUS_NOERROR || status == Status.ERR_TIMEOUT)
{
logMessages.Add(copiedMessages);
}
else if (status == Status.ERR_BUFFER_EMPTY)
{
throw new Exception(String.Format("PassThruReadMsgs Failed(0x{0:X})", status));
}
}
And the last node:
private void LogMessages(BlockingCollection<string[]> messages)
{
try
{
foreach (var item in messages.GetConsumingEnumerable(_cancellationTokenSource.Token))
{
if (item.Length > 0)
{
_fileWriter.WriteLine(String.Join(Environment.NewLine, item));
_fileWriter.Flush();
}
}
}
catch (OperationCanceledException)
{
//TODO:
}
}
I have looked this over several times and have been working on it for quite a while, but cannot find any places where this is bottle necking in a way that I can fix. I am just hoping a second set of eyes to review this will see performance issues that I don't.