3

I need to convert an int to a byte array in Micro Framework so it can be streamed to serial. This is happening in a time-sensitive area of the code where a delay caused by the garbage collector could take too long.

Normally I’d cast the int to string and thence to a char array. But that creates a heap object that risks garbage collection.

Is there an efficient way to do this? I can do it in a loop that uses modulo 10 arithmetic but that would be slow. In C I've used sprintf to convert to a pre-allocated array, which would be fine.

Rajeesh Menoth
  • 1,704
  • 3
  • 17
  • 33
blearyeye
  • 255
  • 4
  • 14
  • Should I assume that `int` converted to `string` by some magic, which does not involve slow *modulo 10 arithmetic*? – user4003407 Feb 06 '16 at 13:45
  • How many different ints are there? If there are just a few common values you can preallocate all of that. Maintain a `Dic`. – usr Feb 06 '16 at 13:46
  • @PetSerAl: modulo 10 arithmetic in C# on MF is _way_ slower than modulo 10 arithmetic in native code. – blearyeye Feb 06 '16 at 15:11
  • @usr: the values are arbitrary. – blearyeye Feb 06 '16 at 15:13
  • When you say "streamed to serial" what do you mean? Do you have control over the protocol? Can't you revert to a binary protocol or use a non-base-10 (like base-64) encoding? There are very fast solutions for modulo 2^n arithmetic, possibly even faster than any `int.ToString()` implementation in C. – pid Feb 17 '16 at 09:05

2 Answers2

2

You can use BitConverter for such tasks.

But I'd advise you to take a look at ProtoBuf if you really need to squeeze every ounce of space/performance from the serialized binary. There's hardly a better/faster way to serialize data into binary blobs. Then you will be able to send that over the wire or save to disk, or store it in memory for caching purposes.

pid
  • 11,472
  • 6
  • 34
  • 63
  • I'm familiar with BitConverter. It can convert an int to an array of bytes that have the same bit value. I need something to convert it to decimal digits: the equivalent of intVal.ToString().ToCharArray() but without creating a heap object. ProtoBuf doesn't seem applicable to Micro Framework. – blearyeye Feb 07 '16 at 18:14
  • The heap object is most probably a string. Have you looked into internal strings and memory pinning? It may not be easy but maybe you can allocate say 16 bytes, pin it (no garbage collection) and write into that buffer. That wouldn't be thread safe and have many other drawbacks, but that's something doable. A `SecureString` is handled the same way to avoid garbage collection and disk swapping of sensitive data. Maybe you'll have to write your own converter but it's not difficult. The real culprit here is memory pinning as far as I've understood your problem. – pid Feb 08 '16 at 00:45
  • BTW efficiency is all to be tested, there's no guarantee that pinned memory is faster, because you have to cross a VM barrier and access it with direct pointer logic. I've no idea if this will speed up or slow down your code. – pid Feb 08 '16 at 00:48
  • Interesting thought. I'm not sure if Micro Framework supports this so will have to dig some. Thread safety isn't an issue in my particular case. – blearyeye Feb 08 '16 at 17:44
  • This is what I was refering to: http://stackoverflow.com/questions/1800695/c-sharp-securestring-question You'll find some explanations and code that shows how to copy into/outof pinned memory. Hope that helps. – pid Feb 09 '16 at 00:10
  • Thanks. I haven't been able to find any support in Micro Framework for pinning or SecureString so it looks like I'm stuck. There are ways to add new libraries written in C to MF and that's the route I might need to take. – blearyeye Feb 09 '16 at 17:59
  • Are you sure? [Here is looks](http://stackoverflow.com/questions/5302153/unsafe-c-sharp-trick-to-improve-speed) like unsafe code is available for the micro framework. You might want to just allocate a struct of chars instead of an array and address the cells directly instead of with an index. That's not too difficult to do. – pid Feb 09 '16 at 19:17
  • Yes, unsafe code is available and the example demonstrates how to do direct pointer manipulation to populate a byte array with tuples of shorts. My problem is that I want to convert an int to its decimal value as a string and thence to char[] and finally byte[] without risking garbage collection. I had hoped with pinning I might be able to pre-allocate space for a string and then convert the int into that space via a pointer (an unsafe operation). The main thing is that this would not require new space in the heap and hence could not trigger garbage collection. – blearyeye Feb 11 '16 at 15:20
  • I looked at [the link you sent](http://stackoverflow.com/questions/5302153/unsafe-c-sharp-trick-to-improve-speed) again. I had overlooked the use of the `fixed` keyword which does do pinning. Nice. However, I'm stuck at the point that the only choices to convert the string initially are `int.ToString()` which creates a heap object, or a modulo 10 loop which is slow. – blearyeye Feb 16 '16 at 21:35
  • I understand but there isn't much more you can do about it. You can trade space for time with a lookup table that contains all numerals in the valid range (say, all numerals from `0` to `100`). This way you use the `int` to lookup the pre-rendered string. But if the range too broad this eats away at memory like mad, and then you can get into disk thrashing which slows down everything. – pid Feb 17 '16 at 08:56
1

Not sure if it's available in the Micro Framework, but one of the BitConverter.GetBytes overloads should do the trick.