Ds4windows: DS4Win eats all CPU performance. Potential problem in ViGem driver level with Dualshock4 virtual controller type.

Created on 13 Aug 2019  路  16Comments  路  Source: Ryochan7/DS4Windows

DS4Windows: V1.7.15
ViGem driver: V1.16.112 (installer 1.16.115)
OS: Windows 10 - 64 bit

Following issue talked about RAM memory usage of DS4Windows application. The discussion and tests made by users revealed another problem (not directly related to RAM usage). Sometimes DS4Windows app may eat all CPU performance.
https://github.com/Ryochan7/DS4Windows/issues/774#issuecomment-520231721

It turn out that this may happen under certain circumstances: "User or DS4Windows auto-profile switching changes profiles AND a profile has Dualshock4 virtual output controller type"

The issue doesn't seem to happen if profiles use Xbox360 output controller type.

After investigating the issue I was able to pinpoint this problem to Vigem Dualshock4Controller object and its Connect/Disconnect procedures. But is the problem in VigEm.NET.Client DLL library package or in VigEmVBus driver level? Don't know yet.

I have created a simple test app (ie. nothing to do with DS4Windows app) and the same problem can be seen with this test app having 10 lines of code (opening XBox and DS4 Vigem controller and doing nothing but Connect and Disconnect).

I will try to reach out for Nefarius and provide him the test app for further analysing. If the issue is in VigEmVBus driver level then we need his help to fix the issue and it may take some time because of Microsoft driver signing practices.

All 16 comments

Sample app code:

ViGEmClient vigemTestClient = new ViGEmClient();
for (int idx = 0; idx < 20; idx++)
{
    DualShock4Controller contDS4 = new DualShock4Controller(vigemTestClient);
    contDS4.Connect();
    Task.Delay(2 * 1000).Wait();
    contDS4.Disconnect();
    contDS4 = null;
}

I've also tested this with the option " " set in config. It unfortunately still increases thread counts. I do have a Bat file setup now to restart d4w now, so that's at least helping when thread count starts lagging up the system again.

Are you using the stock ViGEm.NET library with the test code? DS4Windows uses a custom version of the library that was made before the library added the NotificationRequestPool. 4 overlapped structures are used in the custom version and the library manages the pointers to the data. I wouldn't want any custom bits that I added to the library to skew anything.These are the changes I made to an old stock version of the library.

https://gist.github.com/Ryochan7/f41bd345c5592d88f37ff24773e1e882

Debugging the ViGEm.NET library and the ViGEmBus driver was a major pain before.

After the most recent tirade on Discord, I guess never mind worrying about it.

Yes. I found the thread cleanup bug in the custom vigemClient library and fixed it. However I鈥檓 going to verify the latest official version and change commit there if it works also. But I鈥檓 going to keep the custom interface of vigem.Net library because the new official interface a bit different and doesn鈥檛 quite fit the needs of Ds4Win

After the backlash occurred when you mentioned your progress diagnosing the problem on Discord, I am done being a part of that community. I have left the ViGEm Discord server and I do not plan to make any attempt to provide fixes to any ViGEm component in the future. As it is now, DS4Windows is mostly in the same situation that it was in when ScpVBus was still being used.

@mika-n
Awesome job Mika-n! Thanks for looking into this bug. Glad I could help you figure out what it was! Sorry I couldn't provide more help. I'm just not a good programmer. T.T

@Ryochan7
That's unfortunate about the ViGEm Discord, I saw the messages. I was gonna ask myself, but I'm glad I didn't! O.O Mika at least offered to help find a solution (And DID!) and they blew up about people asking and not helping. Maybe he had a bad day, dunno. Thank you anyway for looking into it. I try to mention a thanks everytime you help, because I know it's difficult to find these little bugs. :D

Hopefully mika-n's fix works well. I'll keep an eye out for a test build or update to download.

@Yohoki Here is a test version of DS4Windows with an updated ViGemClient component. This should fix the "phantom left over threads eat all CPU cycles" issue. The current "official" ViGemClient driver has a bug how it cleans up internal threads and objects when a connection is closed (for example due to changing a profile with x360 controller option to a profile with ds4 controller option).

You can drop-in the DS4Windows.exe and Nefarius.Vigem.Client.dll files over the existing files and re-use all other files from your existing installation. You may want to take a backup copy of the original files before overwriting those files.

If you want to test this version then please post here your findings and reports about the CPU issue. Thx.

DS4Windows_1.7.15dev1_VigemClientTestVer.zip

Please note that the version in the zip file is based on V1.7.15 DS4Win release, but has couple not-yet-released devel features included. For example, special actions type of macro has couple new features (https://github.com/Ryochan7/DS4Windows/pull/786) and few other minor fixes. It could be that those new features never make it to the official DS4Win version or if they do make their way there then something is changed before a release. But, this devel version is fully backward compatible with all existing config and profile files, so no worries there.

@Ryochan7 Just for information. Here is a link to the change-diff of ViGemClient which should (based on my own tests) fix the phantom orphanaged thread issue and having different notification logic for x360 and ds4 controller objects in ViGemClient. If you see something alarming in this fix then please let me know. The .NET interface is drop-in replacement, so no need to change anything in DS4Win code base.
https://github.com/mika-n/ViGEmClient/commit/02552a5f24f1fe4e31a3fde08643e1fde88f7097

I have submitted a pull-request to ViGemClient team, but let's see how it goes once they have had time to review it. Anyway, using this version I could no longer generate random ViGemClient crashes when profiles are changed rapidly (several times per second) or phatom left over threads eating all CPU. If it takes time to include in the official version then DS4Win could deliver its own version of Nefarious.VigEm.Client 32bit and 64bit contour library files.

@mika-n Downloading and testing. At first glance, it looks to have fixed the issue. I'll leave it running for several days to see if anything pops up after running for long periods.

I did do some initial testing though. Cycling through x360 and ds4 mode rapidly no longer creates threads that are then stuck in limbo. In fact, PerfMon actually shows the thread count decreasing shortly before perfmon can realize a new thread is created to replace the old one. It seems very efficient to me. Looking at .NET CLR LocksAndThreads -> "Peak Queue Time" and "# Total Recognized Threads" shows and increase every time the swap is made, so it's definitely still creating new threads, but "# Current Recognized Threads" is flatlined, so it's properly closing old threads before (or while) creating new ones.

Well done, sir. I'll let you know in a couple days how it's going, so you don't have to leave your computer running 24/7 like I do. :D

@mika-n After a bit of using the new version, there's still some orphaned threads left in limbo it looks like, although nowhere near as much as it used to be. Over the past 3 hours, I've gained one extra thread, and 3 (I think) since starting it a day ago. It's currently sitting at 47 threads and I believe it was at 44 when I first opened it.

I'm not seeing a 100% chance to leave a thread in limbo anymore, so that's still a MAJOR improvement. But, there's still something causing it to gain a thread sometimes. Is it worth fixing, probably not in my book, but I'm not the programmer and you may choose otherwise. I'm still very pleased with how it's running now, regardless of the extremely slow raise in CPU. I think it would probably take weeks to get to the kind of levels where it's impacting games again, and I'll probably have to turn my computer off for one reason or another before it gets to that point anymore.

hmmmm.... There are other parts in the app creating threads and not just this ViGem driver releated thread logic. I haven't screen any ghost threads, but on the other hand I don't keep my PC running 24/7. I'll try to do some extra testing with this ViGem related fix. Although I'm quite sure that it should not leave ghost threads anymore hanging around. Some other parts of the app may have other issue, so maybe those ghost threads are coming from there. But what is it? Difficult to tell at this point.

The .NET engine itself does have number of threads which come and go and an application cannot control it. If there are couple extra threads for a while then those may be threads created by .NET engine also.

hmmmm.... There are other parts in the app creating threads and not just this ViGem driver releated thread logic. I haven't screen any ghost threads, but on the other hand I don't keep my PC running 24/7. I'll try to do some extra testing with this ViGem related fix. Although I'm quite sure that it should not leave ghost threads anymore hanging around. Some other parts of the app may have other issue, so maybe those ghost threads are coming from there. But what is it? Difficult to tell at this point.

The .NET engine itself does have number of threads which come and go and an application cannot control it. If there are couple extra threads for a while then those may be threads created by .NET engine also.

Yessir. I did not say that I thought it was the new ViGEm fix that caused them. I cannot force the app to orphan threads anymore, no matter how hard I try to keep switching profiles. I only report a small, almost in-existent, thread count rise over several hours.

Even with that, I'm very pleased with how it's been working. Going from almost 200 threads to only 3 orphaned threads is a great success in my book. Even if the ViGEm client is still what's causing it (which I doubt) it's a major improvement. :D

I did a test run with the new version using a following batch script. The script changes between x360 profile and ds4 profile in one second interval. I left it to run for a whole day.

The new version seemed to work OK now and no more ghost threads left behind. The num of threads remained pretty much the same the whole day. Only one or two extra theads every now and then, but those disappeared on their own. I guess those were some .NET core threads doing garbage collecting.

As a reference I run the same using the old version of DS4Win+VigemClient library. It went crazy with num of threads in 10 minutes (because of bugs in how it cleaned up notification threads in x360 and ds4 controller objects).

@echo off
:Loop1
DS4Windows.exe -command LoadProfile.1.FIFA
timeout /NOBREAK /T 1 >nul

DS4Windows.exe -command LoadProfile.1.Default
timeout /NOBREAK /T 1 >nul
goto Loop1

Note! DS4Windows app creates a new controller object if the current profile and the new profile has different output controller type. If both old and the new profile has the same output controller type then DS4Win doesn't close the existing controller object, so "thread cleanup bug" is not that obvious in those cases.

After another 2 days, still without restarting d4w since downloading, we are still in the double digit thread count, under 50. I think that's long enough to say that there's no issues with ViGEm client orphaning threads anymore. Thanks very much for the fix @mika-n !

If I read correctly, the ViGEm client is compatible with the normal versions of D4W? So if I were to do something like test the Gyro-Mouse build that @Ryochan7 has been working on, all I need to do is copy the new ViGEm file over?

@Yohoki Yes. The new version of Nefarious.VigemClient.dll file is plug-and-play compatible even with "an old" version of DS4Windows.exe executable. You can replace the old Nefarious.Vigem.Client.dll with the file in the test version.

The devel version of DS4Windows has a change commit already and hopefully it makes it through to an official version of DS4Win soon.
https://github.com/Ryochan7/DS4Windows/pull/794

@mika-n Good to hear. I'll keep using it then.

I did run the test on my end for a work-week and haven't had any issues with it under normal use. I just used it as I normally would, though, I didn't do a stress test like the bat file you made. XD Just watching my own perfmon thread counts going up while pressing up and down repeatedly on the profile selector was enough to confirm that this version worked much better than before. I can only imagine how quickly it went up with a loop like that!

I also haven't seen the thread count rise any higher than it has now. So it's very possible that it's normal GC coming and going as expected.

I'll have to restart my computer now to update VS so that I can build the dev version with Gyro controls now. :P

Was this page helpful?
0 / 5 - 0 ratings

Related issues

pralima87 picture pralima87  路  8Comments

zardini123 picture zardini123  路  7Comments

pralima87 picture pralima87  路  6Comments

thegamerx1 picture thegamerx1  路  8Comments

bison3 picture bison3  路  5Comments