Optimizing selection of track sound type Significantly reducing CPU load
#1
Posted 05 February 2016 - 09:10 AM
This selection uses an absolutely unoptimized method: at every update for every sound region defined within all loaded world sound files a traveller is generated and through the traveller the distance from the train to the sound region is computed. This is done by first moving forward, and if the sound region is not found a reverse traveller is generated and the distance is computed.
When the triple loop has passed all sound regions the sound region at the minimum distance is selected as the one defining the track sound type.
I did a simple test on my not too fast notebook with a crowded route (many tracks, many sound regions, many switches, about 15 trains): improvement of about 30% in FPS with GetTType immediately returning track type 0. This is an important speedup. Other cases gave smaller improvements, but anyhow interesting ones.
There are various possibilities to improve the algorithm. One could be that at ws file load, or even better at OR start, for every track node (not the trNode defined in GetTType, but the track node as defined in the .tdb file, that is the tracks between two switches or between a switch and a track end) the starting and ending sound region track items are calculated and stored (in addition to the already present intermediate sound region track items, if any), so that, knowing in whick track node the train is, it is very fast to determine the applicable sound region.
A first simpler improvement could be as follows: if the train is within a track node that already has sound region track items defined, and if it is between two of such track items, the applicable sound region can be immediately derived, without needing to analyze all sound regions.
An even simpler improvement is the one of testing if the train speed is = 0: in this case one keeps the old track sound type.
I am not very keen to candidate about this (except for the most simple improvement, train at 0 speed, one line of code to be changed), because it is not an elementary thing ; but it would be nice if someone could work on this.
I have opened a blueprint here https://blueprints.l...rack-sound-type .
#2
Posted 05 February 2016 - 10:35 AM
Csantucci, on 05 February 2016 - 09:10 AM, said:
This selection uses an absolutely unoptimized method: at every update for every sound region defined within all loaded world sound files a traveller is generated and through the traveller the distance from the train to the sound region is computed. This is done by first moving forward, and if the sound region is not found a reverse traveller is generated and the distance is computed.
When the triple loop has passed all sound regions the sound region at the minimum distance is selected as the one defining the track sound type.
That is indeed a pretty slow method of finding things. I'm just glad the "DistanceTo" calls have a limit set (even if it is 8km).
Am I right in thinking that these sound region items simply change the sound as you pass over them (if your direction and the sound region direction are similar)?
If so, this code is just not the right way to things IMHO. Instead, I think we should compare line-of-sight distance from the train (front or rear as appropriate) with each sound region: add a method on to the TrItem class which returns a WorldLocation and do WorldLocation.Within(trainLocation, trItemLocation, 1 /* meters */) and check the orientation. Anything within 1m and oriented correctly is a match or, if no match is found, return the previous value.
#3
Posted 05 February 2016 - 11:28 PM
#4
Posted 06 February 2016 - 09:17 AM
Csantucci, on 05 February 2016 - 09:10 AM, said:
As the one who produced the patch that could detect when each car passed the sound region marker I'm fairly sure that I put in a test for zero speed (actually between -0.1m/sec and +0.1m/sec because sometimes trains oscillate back and forth for a while). Lines 176 and 182 in X3423 sound.cs.
I also have a private patch that removes the need for the lock in GetTType();
Edit:
I've occasionally looked at improving GetTType() but the fact that I don't know enough about the TDB has stumped me.
Dennis
#5
Posted 06 February 2016 - 10:21 AM
dennisat, on 06 February 2016 - 09:17 AM, said:
I also have a private patch that removes the need for the lock in GetTType();
Edit:
I've occasionally looked at improving GetTType() but the fact that I don't know enough about the TDB has stumped me.
Dennis
I found no trace of the test for zero speed, at least for the leading car.
I'll try to implement James' suggestion.
#6
Posted 06 February 2016 - 10:28 AM
Csantucci, on 06 February 2016 - 10:21 AM, said:
I'll try to implement James' suggestion.
The test is in UpdateTType() in sound.cs which calls GetTType(). The code is below.
Dennis
public void UpdateTType() { if (_prevTType == -1) InitInitials(); if (Car != null && Car.Train != null) { int CarIncr = 0; int CarLeading = 0; if (Car.Train.SpeedMpS > 0.1f) { CarIncr = 1; CarLeading = 0; } else if (Car.Train.SpeedMpS < -0.1f) { CarIncr = -1; CarLeading = Car.Train.Cars.Count - 1; } else return;
#8
Posted 06 February 2016 - 01:50 PM
gpz, on 05 February 2016 - 11:28 PM, said:
Yes, although it's more likely the searching through up to 8km of track in both directions for each and every possible sound region is where all the CPU time is going. :)
#9
Posted 07 February 2016 - 01:07 AM
Considering in a very worse case a train running at 300 Km/h and a FPS of 10, you get more than 8 meters at every update. So using 1 meter may let you lose the new sound region. However you can't increase the 1 meter threshold, else you can get also sound regions of nearby tracks (e.g. after a switch).
#10
Posted 07 February 2016 - 02:06 AM
James Ross, on 06 February 2016 - 01:50 PM, said:
Looking at the resource usage charts in the F5 displays, in my experience the sound task usage is usually very small compared to render and update. This is the case even on routes like Dorset Coast and MEP that make very heavy use of sound regions. Admittedly I have a fairly powerful PC at the moment.
Dennis
#12
Posted 07 February 2016 - 03:20 AM
Csantucci, on 07 February 2016 - 01:07 AM, said:
Considering in a very worse case a train running at 300 Km/h and a FPS of 10, you get more than 8 meters at every update. So using 1 meter may let you lose the new sound region. However you can't increase the 1 meter threshold, else you can get also sound regions of nearby tracks (e.g. after a switch).
That's fine, you can still use a traveller to confirm things. Let's say we go with 10 meters as the "check distance", you find all sound regions line-of-sight closer than 10m (usually none or very few will match), then check with a traveller using a distance limit of 10m also, then check orientation.
dennisat, on 07 February 2016 - 02:06 AM, said:
Is this with or without your private patch? I am also quite wary of the locks in the sound process and the complex code to "break out" of a long sound update loop because other code wants the lock, which could be causing rendering interruptions, for example. Anything that reduces the time locks are held is good. :)
#13
Posted 07 February 2016 - 03:54 AM
As of now I show what I have obtained by leaving the basic algorithm as it is, but by avoiding to run it at next updates if some conditions apply, that is:
1) first front sound region track sound = first back sound region track sound when algorithm run last time
2) train on same track section as when algorithm run last time
3) if train moving forward, train distance moved less than distance from front track sound when algorithm run last time; if train moving backward, train distance moved less than initial distance from rear track sound.
In fact, if these conditions are satisfied, the front car is still between the same two sound regions, and so it is not needed to re-run the algorithm.
Here is the patch:

Number of downloads: 404
and here an example of application:
No patch:

Patch:

The comparison is done between two local builds, to ensure parity of conditions.
As can be seen, FPS doesn't change very much, but sound process CPU occupation decreases significantly.
#14
Posted 07 February 2016 - 04:43 AM
James Ross, on 07 February 2016 - 03:20 AM, said:
My observations are with my patches installed. If you like, I can disentangle the soundregion lock mod from amongst my other changes and you can vet it. It removes the need for two consecutive locks to add and delete soundregions and removes the need to lock soundregions for the GetTType() method.
Csantucci, on 07 February 2016 - 03:54 AM, said:
1) first front sound region track sound = first back sound region track sound when algorithm run last time
2) train on same track section as when algorithm run last time
3) if train moving forward, train distance moved less than distance from front track sound when algorithm run last time; if train moving backward, train distance moved less than initial distance from rear track sound.
This looks like a great idea, I wish I'd thought of that. I'll try it as soon as I can.
Dennis
#15
Posted 07 February 2016 - 05:30 AM
dennisat, on 07 February 2016 - 04:43 AM, said:
Probably not worth it if Carlo's work is as good as it appears. We should remove the locks eventually but outside of Render/Updater it is not critical.