|
Hi!
Let me share with you the techniques we have used to go around some of the drawbacks you describe.
Our solution is consuming a LARGE amount of UDP traffic (MPEG2 streams) - over 200Mbps of data. It is also performing some heavy DSP processing and it taxes the garbage collector heavily.
Being UDP and with no retransmission protocol available - we are very sensitive to reading the data on time if we want to keep the quality of the video streams high. Reading the UDP traffic with managed code was a disaster.
Basically, we are taking advantage of the fact that an unmanaged thread is NOT suspended during garbage collection.
1. We used C++/CLI to write the multicast UDP reader code inside a non-managed class. We ensure that the CLR support is disabled for the .cpp file implementing the code that we don't want to be interrupted during garbage collection. This makes sure that the code is compiled to native code, otherwise it may get compiled to IL code and the unmanaged thread may be blocked once it transitions to IL space. Even if using the unmanaged pragma, the compiler creates managed thunks around the unmanaged code and we want to avoid IL completely for this generated code. The unmanaged thread that is reading the UDP traffic (using RIO for higher performance) runs inside this class. Note that unfortunately we can't take advantage of the .Net framework in this class, so we rely on Boost.
2. We keep the unmanaged code as simple as possible, basically we loop reading UDP packets and enqueue them. However, we make sure that we use a lockless queue for this purpose (we use a Boost lockless queue). This is vital because there will be a managed thread consuming the queue, bridging the data onto the managed world. This consumer thread will be suspendend during GC activity and we don't want the thread to be suspended while holding a lock for the queue (otherwise the unmanaged thread may block contending for the lock). Another plus is that using a lockless queue, we become immune to thread priority inversion, so we can boost the producer thread priority to the highest level possible.
3. Using C++/CLI we produce a .net friendly class. This class owns and instantiates the unmanaged class, and also implements the managed queue consumer thread. (It can seamlessly consume the Boost lockless queue and expose the unmanaged memory (the udp packets) in a managed friendly way. Now, no matter if the managed world is suspended, the unmanaged thread will keep filling the lockless queue.
We also tuned some relevant NIC parameters, and by using these techniques, we can proudly say we are losing less than 0.001% of the packets (when we were losing around 8% of the packets with our initial, purely-managed solution).
I think I may actually write an article (my first) on this technique. It may be useful to others.
Feel free to contact me if you want to try this approach!
|
|
|
|
|
Yeah, that's the Microsoft recommended way I think, either that or using classic unmanaged C++ and just calling into that but marshalling can be a problem depending on performance needs, so mixed mode/managed may be the way to go. The other option would probably be to write a custom marshaller for those methods, if you really don't want to mix manage/unmanaged code in the same assembly
I'd share it, because people may not be aware of the technique.
As far as the UDP I'm curious if you use any sort of QOS method on your UDP streaming?
uTP does, but to the opposite ends and goals as yours, although using something like it might smooth playback during network traffic spikes
When I was growin' up, I was the smartest kid I knew. Maybe that was just because I didn't know that many kids. All I know is now I feel the opposite.
|
|
|
|
|
so I took someone's advice here about the way i declare tuples. Redid everything using named tuples and now my code only works with .NET core.
FML.
Luckily i won't be releasing officially for like a year.
When I was growin' up, I was the smartest kid I knew. Maybe that was just because I didn't know that many kids. All I know is now I feel the opposite.
|
|
|
|
|
I just checked, and once I set my project to .NET 4.7.2 instead of 4.6.2 it compiled and worked perfectly:
private void FrmMain_Load(object sender, EventArgs e)
{
if ((ModifierKeys & Keys.Shift) == 0)
{
this.LoadLocation();
}
var loc = GetLocation("some address");
Console.WriteLine($"Lat: {loc.x}, Long: {loc.y}");
}
private (double x, double y) GetLocation(string address)
{
return (100, 100);
}
Sent from my Amstrad PC 1640
Never throw anything away, Griff
Bad command or file name. Bad, bad command! Sit! Stay! Staaaay...
AntiTwitter: @DalekDave is now a follower!
|
|
|
|
|
string interpolation != named tuples
(int First, int Last) intRage = (1,2);
like that.
Yeah, i think 4.7.2 might work. i'm installing now
When I was growin' up, I was the smartest kid I knew. Maybe that was just because I didn't know that many kids. All I know is now I feel the opposite.
|
|
|
|
|
The interpolation is just there for usage demo:
(int x, int y) v = (100, 200);
Console.WriteLine($"{v.x}, {v.y}");
Works fine as well.
Sent from my Amstrad PC 1640
Never throw anything away, Griff
Bad command or file name. Bad, bad command! Sit! Stay! Staaaay...
AntiTwitter: @DalekDave is now a follower!
|
|
|
|
|
ahh
well, it's not working in my .NET 4.7.1 target in VStudio. Only in .NET core 2.1+ target
which means it's using a newer version of the C# compiler
When I was growin' up, I was the smartest kid I knew. Maybe that was just because I didn't know that many kids. All I know is now I feel the opposite.
|
|
|
|
|
If its just two unnamed ints, return an array. If the two ints need names, create a class with two properties.
Will work with any framework.
Bastard Programmer from Hell
If you can't read my code, try converting it here[^]
"If you just follow the bacon Eddy, wherever it leads you, then you won't have to think about politics." -- Some Bell.
|
|
|
|
|
There's lots of nested data. like this
(int Accept, ((char First, char Last)[] Ranges, int Destination)[] Transitions, int[] PossibleAccepts)[]
I'm avoiding polluting the namespace with types the end user-dev will never touch.
Most of these are strictly for parse tables - machine generated data that will never be touched by human hands, or perused by human eyes.
If I start polluting the namespace with types, I've in a way, broken encapsulation. Now, i can make these types private, but then if you ever WANT to see or debug or peruse these tables, you basically can't.
Tuples give me a really nice compromise. They avoid polluting the namespace, and are still exposed enough that someone can use them and alter them if they really want to.
Keep in mind, this is not a general guideline for writing code - this is a very special case.
When I was growin' up, I was the smartest kid I knew. Maybe that was just because I didn't know that many kids. All I know is now I feel the opposite.
modified 14-May-19 10:28am.
|
|
|
|
|
|
It was probably a Russian meaning "Tupolev"
|
|
|
|
|
It is language feature and not Framework related...
Using C# 7.0 you have tuples, using 7.1 you have named tuples...
All you need is to configure your project (the easiest way is to pick a framework compiles with those features by default, like 4.7.2)...
"The only place where Success comes before Work is in the dictionary." Vidal Sassoon, 1928 - 2012
|
|
|
|
|
As you were tying that i did some research to find out which C# versions ship with which MS devstudio targeting packs.
And you're right, but i don't have those installed. Remedying now.
When I was growin' up, I was the smartest kid I knew. Maybe that was just because I didn't know that many kids. All I know is now I feel the opposite.
|
|
|
|
|
If you are using VS 2017, you can add named tuples via nuget: NuGet Gallery | System.ValueTuple 4.5.0[^]
Sent from my Amstrad PC 1640
Never throw anything away, Griff
Bad command or file name. Bad, bad command! Sit! Stay! Staaaay...
AntiTwitter: @DalekDave is now a follower!
|
|
|
|
|
it doesn't let the C# compiler use implicit naming though does it? that's a *language* feature that came AFTER c# 7.0. It's not a framework feature, although the ValueTuple type framework feature is usd by the compiler to support this.
When I was growin' up, I was the smartest kid I knew. Maybe that was just because I didn't know that many kids. All I know is now I feel the opposite.
|
|
|
|
|
Not sure - I'm using 2019 at the moment (I removed 2015 and 2017 when I installed the latest, just keeping 2013 in case ...)
Sent from my Amstrad PC 1640
Never throw anything away, Griff
Bad command or file name. Bad, bad command! Sit! Stay! Staaaay...
AntiTwitter: @DalekDave is now a follower!
|
|
|
|
|
I'm still on 2017, as i like to wait until many other devs have updated before i do.
When I was growin' up, I was the smartest kid I knew. Maybe that was just because I didn't know that many kids. All I know is now I feel the opposite.
|
|
|
|
|
I have to say it's been pretty stable so far - I've had fewer problems with it than with 2017 (which is why I didn't move to that or 2015). It's slower than 2013 to compile, but seems to load slightly faster.
And I like some of the UI addins such as "always visible" reference counts - even if some of the "improvements" it suggests are contradictory. Fuzzy searches are handy as well, as is Intellicode, when you get used to it (Intellisense on steroids).
Sent from my Amstrad PC 1640
Never throw anything away, Griff
Bad command or file name. Bad, bad command! Sit! Stay! Staaaay...
AntiTwitter: @DalekDave is now a follower!
|
|
|
|
|
I get refcounts in VS2017. The rest is new i think.
the reason i don't switch is it's harder for me to share code. not really a stability thing. A lot of devs are somewhat conservative about updating, so i try to hold off a little myself, so that we can exchange project files, like I can post them here and more people can use them without having to fiddle with recreating an older project file from the source code.
When I was growin' up, I was the smartest kid I knew. Maybe that was just because I didn't know that many kids. All I know is now I feel the opposite.
|
|
|
|
|
I know how you feel - I tend to wait as well, but 15 was so poor, and 17 was flaky - so I figured that I'd have to bite the bullet and move to 19. Not regretted it yet!
Sent from my Amstrad PC 1640
Never throw anything away, Griff
Bad command or file name. Bad, bad command! Sit! Stay! Staaaay...
AntiTwitter: @DalekDave is now a follower!
|
|
|
|
|
That's good to know. I've had luck with VS2017 for everything but VSIX projects. It stopped working after the first one i created so now if i want to make integrated "custom tools" i have to add them to that first VSIX i made!
i get some E_INVALIDARG message when I try to create a VSIX package anymore.
When I was growin' up, I was the smartest kid I knew. Maybe that was just because I didn't know that many kids. All I know is now I feel the opposite.
|
|
|
|
|
You can install 17 and 19 side by side on the same machine (provided 17 goes on first) so you could check if VSIX is working?
Sent from my Amstrad PC 1640
Never throw anything away, Griff
Bad command or file name. Bad, bad command! Sit! Stay! Staaaay...
AntiTwitter: @DalekDave is now a follower!
|
|
|
|
|
I could but frankly, i'm not into downloading all that right now.
When I was growin' up, I was the smartest kid I knew. Maybe that was just because I didn't know that many kids. All I know is now I feel the opposite.
|
|
|
|
|
adding, I keep VS2008 around for building VSTs. LOL. The newer c++ compilers do not like the old steinberg header code.
When I was growin' up, I was the smartest kid I knew. Maybe that was just because I didn't know that many kids. All I know is now I feel the opposite.
|
|
|
|
|
If you can't upgrade your project to .NET 4.7.2, you'll need to add a reference to the System.ValueTuple package:
NuGet Gallery | System.ValueTuple[^]
Looking at the dependencies, it claims to work as far back as .NET 4.5.
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|