Transport Tycoon Forums

The place to talk about Transport Tycoon
It is currently Thu Sep 02, 2010 6:16 pm

All times are UTC




Post new topic Reply to topic  [ 40 posts ]  Go to page 1, 2  Next
Author Message
 Post subject: [patch] train collision cache
PostPosted: Sat Jun 02, 2007 11:44 am 
Engineer
Engineer
Offline

Joined: Thu May 20, 2004 5:21 pm
Posts: 116
The basic idea is this:

- Use 2 bits in the map array to store if there are 0, 1, 2, 3 or more trains on a tile

- More than 1 > do collision checking, in normal situations this only happens when you have diagonal track and two trains pass eachother.

- When leaving and state 3 is active, it will check if it's actually number 3 (somewhat expensive, but very rare).

- Also handle bridges and tunnels (toggle the other side as well, since trains actually remain on the ramp tile as far as the game is concerned).

GOAL: Improve performance of trains, sorry this was unclear.

NOTE: This could use testing now, try to load your old savegames (preferably with a lot of trains) and let it run at max speed for a few minutes. Play with it. If it asserts, please provide assert messsage and savegame. Post your experiences, even if they are good. Multiplayer experience is also good.


Attachments:
train_cache_rev10075.patch [14.16 KiB]
Downloaded 115 times


Last edited by madman2003 on Sat Jun 09, 2007 8:06 am, edited 13 times in total.
Top
 Profile  
 
 Post subject:
PostPosted: Sat Jun 02, 2007 12:03 pm 
Engineer
Engineer
Offline

Joined: Thu May 20, 2004 5:21 pm
Posts: 116
With profiling i have a rough estimate of reduction:

(FindTrainCollideEnum and GetVehicleFromPos are the functions i look at)

Previously it used ~13% of cpu time, this was reduced to ~1%.

I included the savegame, which is from openttdcoop(iirc), you'll probably need their grf pack.

When looking at real cpu usage, that went from ~45% to ~35%.
This is just to give you an idea, don't quote me on this ;-)


Attachments:
PublicServerGame_34_Final.sav [257.56 KiB]
Downloaded 133 times
Top
 Profile  
 
 Post subject:
PostPosted: Sat Jun 02, 2007 2:09 pm 
Engineer
Engineer
User avatar
Offline

Joined: Tue Jun 27, 2006 11:07 pm
Posts: 64
Looks like a nice reduction :)


Top
 Profile  
 
 Post subject:
PostPosted: Sat Jun 02, 2007 4:07 pm 
Route Supervisor
Route Supervisor
Offline

Joined: Mon Apr 02, 2007 8:13 pm
Posts: 399
Location: Nørup, Denmark
First of all I would like to say that even though I don't know what it all means, then I like what I do understand in there.
One thing might be improved though.
As I remember it then GetPrevVehicleInChain is somewhat expensive performance wise because vehicle is a linked list, not a double linked list.
This means that it iterates over all vehicles in the train until it finds the vehicle that has u as ->next.

I think this might be better
Code:
+   /* Only the first may trigger it */
+   if (u == u->first) {


Or maybe this
Code:
+   /* Only the first may trigger it */
+   if (IsFrontEngine(u)) {

_________________
Code:
if (YouAreHappyAndYouKnowIt) {
    ClapYourHands();
}


Top
 Profile E-mail  
 
 Post subject:
PostPosted: Sat Jun 02, 2007 5:46 pm 
Engineer
Engineer
Offline

Joined: Thu May 20, 2004 5:21 pm
Posts: 116
@kaan: That is already changed in my local copy, i still need to work on strange cases like trains crossing each other. Once that's done i'll post another patch.


Top
 Profile  
 
 Post subject:
PostPosted: Sun Jun 03, 2007 10:27 am 
Engineer
Engineer
Offline

Joined: Thu May 20, 2004 5:21 pm
Posts: 116
Updated patch, what this doesn't do, is handle trains riding circles in themselves.

Any comments so far?

Besides the fact that the counting algoritm isn't perfect (i know that).


Last edited by madman2003 on Mon Jun 04, 2007 4:57 pm, edited 1 time in total.

Top
 Profile  
 
 Post subject:
PostPosted: Sun Jun 03, 2007 10:56 am 
Engineer
Engineer
Offline

Joined: Thu May 20, 2004 5:21 pm
Posts: 116
I did some testing, good news is that the extra checks don't seem to have much performance impact. Bad news, is the cpu usage comparison of the first test was wrong (visual details were different), diffirence is more in the order of 41% vs 35%. So i hope noone quoted me on that ;-) (this is why profiling is more important)


Top
 Profile  
 
 Post subject:
PostPosted: Sun Jun 03, 2007 4:04 pm 
Engineer
Engineer
Offline

Joined: Thu May 20, 2004 5:21 pm
Posts: 116
This should work for crossings, loops (including those with crossings in them).

Counting algoritm is fixed as far as i know (despite the old comment).

Please test, there are fprintf's in the code which could be usefull if you want to debug.


Last edited by madman2003 on Mon Jun 04, 2007 4:58 pm, edited 1 time in total.

Top
 Profile  
 
 Post subject:
PostPosted: Sun Jun 03, 2007 5:59 pm 
Engineer
Engineer
Offline

Joined: Thu May 20, 2004 5:21 pm
Posts: 116
Some fixes, some comment. Not perfect yet.


Last edited by madman2003 on Mon Jun 04, 2007 4:58 pm, edited 1 time in total.

Top
 Profile  
 
 Post subject:
PostPosted: Sun Jun 03, 2007 10:19 pm 
Engineer
Engineer
Offline

Joined: Thu May 20, 2004 5:21 pm
Posts: 116
Simplified version.


Last edited by madman2003 on Mon Jun 04, 2007 4:58 pm, edited 1 time in total.

Top
 Profile  
 
 Post subject:
PostPosted: Mon Jun 04, 2007 5:40 am 
Engineer
Engineer
Offline

Joined: Thu May 20, 2004 5:21 pm
Posts: 116
I forgot to cache if a train is crossing, otherwise you do quite a few last car checks.


Last edited by madman2003 on Mon Jun 04, 2007 7:08 pm, edited 2 times in total.

Top
 Profile  
 
 Post subject:
PostPosted: Mon Jun 04, 2007 6:29 am 
Engineer
Engineer
Offline

Joined: Sun May 13, 2007 12:31 pm
Posts: 38
Location: UK
There is an edit button so you don't have to post 7 times running...
Also update the 1st post so I don't go and try to compile the wrong thing again lol... *gets updated patch this time...*


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jun 04, 2007 7:36 pm 
Engineer
Engineer
Offline

Joined: Thu May 20, 2004 5:21 pm
Posts: 116
SyncViews wrote:
There is an edit button so you don't have to post 7 times running...
Also update the 1st post so I don't go and try to compile the wrong thing again lol... *gets updated patch this time...*


I will update the patch in the first post, as i have done now.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jun 05, 2007 9:12 am 
OpenTTD Developer
OpenTTD Developer
Offline

Joined: Mon Mar 08, 2004 1:10 pm
Posts: 2088
I just looked at this and decided to play a bit with it. I made the following modification to rail_map.h
Code:
ShowCostOrIncomeAnimation(TileX(t) * 16, TileY(t) * 16, (_m[t].type_height & 0x0F) * 8, GetOccupancy(t));
in SetOccupancy(). This means that it will have to be aware of GetOccupancy() (they are in the wrong order) and include functions.h.
Now a cost animation is printed on every tile that changes the train counter. If currency is set to punds, then the price will be the content of the counter. This makes a quick test a bit easier.

I did find some issues. Crashing two trains into each other can set the counter to 0 before it's done cleaning up the trains because the counter is decreased one for each vehicle that's removed. If a train has more than one vehicle in the tile, then it's substracted more than once.

Road crossings... now the road vehicle crash if the train is in the tile. It's good to test if there is a train by using the counter (fast) before checking if there is a collision, but the need for a collision check is still needed as a road vehicle and a train could be on the same tile without touching each other. The check should be (in that order)
Code:
if (GetOccupancy(tile) > 0 && VehicleFromPos(tile, v, EnumCheckRoadVehCrashTrain) != NULL)


Also I think the crossing train detection code can be made even simpler. Once a train front enters a tile where the train counter is more than 0, then it should loop though it's own consist to check if the tile is present. If it is, then set the crossing bool, else increase the counter for the tile.

DecreaseOccupancy() should assert if it is called when the count is already 0, not just do nothing. This should never happen, so just returning without doing anything is a bad solution that can hide bugs.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jun 05, 2007 10:52 am 
Engineer
Engineer
Offline

Joined: Thu May 20, 2004 5:21 pm
Posts: 116
In my local copy i have two functions now, one for tileenter and tileleave.
I have begun adding asserts in places were they are needed.

The proper roadveh crash stuff has been readded.

Good catch about the crash stuff.

I found out an issue in the savegame stuff, it also increases the counter inside depots, which aren't handled by a normal game.

I'll look at the possibility of simplifying the code further.

I will make some changes this evening.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jun 05, 2007 3:07 pm 
Route Supervisor
Route Supervisor
Offline

Joined: Mon Apr 02, 2007 8:13 pm
Posts: 399
Location: Nørup, Denmark
I would just like to say that I am full of admiration for your hard work on this non-trivial patch :)

_________________
Code:
if (YouAreHappyAndYouKnowIt) {
    ClapYourHands();
}


Top
 Profile E-mail  
 
 Post subject:
PostPosted: Tue Jun 05, 2007 7:32 pm 
Engineer
Engineer
Offline

Joined: Thu May 20, 2004 5:21 pm
Posts: 116
Fixed quite a few bugs, it's nearing an end, please give final comment please.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jun 05, 2007 8:42 pm 
OpenTTD Developer
OpenTTD Developer
Offline

Joined: Mon Mar 08, 2004 1:10 pm
Posts: 2088
for TrainEnterTile():
/* Check the entire train for cross points */.. about this check. Isn't it good enough to just loop though the train to see if (v->tile == gp.new_tile)? This would be easier to read and should be faster than making a vector of the train every time this happens.

If the train is crossing (still first if), then wouldn't it be possible to just set v->u.rail.crossing_self = true and then return?

*u in the argument... we usually call vehicles for *v :wink:

the function ends with return... there is no need to place return as the last line in a void function.

for TrainLeaveTile():
DEBUG(misc, 2, "[UpdateTrainCache] The last wagon of a car is somewhere it isn't registered"); <-- this sounds like a reason to assert to me.

I think it's possible to simplify this function some more. Checking if the train is crossing could just be if the tiles are matching, then set the crossing bool and break. No need to check if it is crossing in more than one place since the only change it will do is to set the bool again.

if the crossing bool is set after this, then loop though the train to see if gp.old_tile is present for any of the vehicles in the train to see if it can be cleared... or maybe it should be done in revered order (if the tile isn't present, then we know that the train wasn't crossing at that tile). Maybe both can be done during the same loop.

Add more comments on the idea behind the vector and the sort.

For the crashing into road vehicles: join the two ifs into one with && (it should still be on two lines though)

PossibleRailDepot() should be named IsRailDepot() (and we already have that function in rail_map.h)


That's what I found this time. I just read the diff and didn't actually apply it this time, so more stuff might show up.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jun 05, 2007 8:58 pm 
Engineer
Engineer
Offline

Joined: Thu May 20, 2004 5:21 pm
Posts: 116
Bjarni wrote:
for TrainEnterTile():
/* Check the entire train for cross points */.. about this check. Isn't it good enough to just loop though the train to see if (v->tile == gp.new_tile)? This would be easier to read and should be faster than making a vector of the train every time this happens.


Decent idea, i'll look at it.

Quote:
If the train is crossing (still first if), then wouldn't it be possible to just set v->u.rail.crossing_self = true and then return?

*u in the argument... we usually call vehicles for *v :wink:


Maybe for the TrainEnterTile.

Quote:

the function ends with return... there is no need to place return as the last line in a void function.



Ok

Quote:
for TrainLeaveTile():
DEBUG(misc, 2, "[UpdateTrainCache] The last wagon of a car is somewhere it isn't registered"); <-- this sounds like a reason to assert to me.



It's already gone, just didn't notice it for this diff.

Quote:

I think it's possible to simplify this function some more. Checking if the train is crossing could just be if the tiles are matching, then set the crossing bool and break. No need to check if it is crossing in more than one place since the only change it will do is to set the bool again.

if the crossing bool is set after this, then loop though the train to see if gp.old_tile is present for any of the vehicles in the train to see if it can be cleared... or maybe it should be done in revered order (if the tile isn't present, then we know that the train wasn't crossing at that tile). Maybe both can be done during the same loop.



As far as i know, i do need to know how many crossings there are, so i can put the vehicle in normal mode again.

Quote:
Add more comments on the idea behind the vector and the sort.

For the crashing into road vehicles: join the two ifs into one with && (it should still be on two lines though)


Ok.

Quote:

PossibleRailDepot() should be named IsRailDepot() (and we already have that function in rail_map.h)



This function also checks for IsTileType(t, MP_RAILWAY), it would be ugly having to do that a lot in the code itself (since it's also called on bridges for example). For other things, such double functions exist as well.

Quote:
That's what I found this time. I just read the diff and didn't actually apply it this time, so more stuff might show up.


End message ;-)


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jun 06, 2007 2:52 pm 
Engineer
Engineer
Offline

Joined: Thu May 20, 2004 5:21 pm
Posts: 116
I think i've got the bugs worked out now.

The question is, can this be committed if nothing turns up soon?


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 40 posts ]  Go to page 1, 2  Next

All times are UTC


Who is online

Users browsing this forum: Google Adsense [Bot] and 2 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Cheap Home Insurance | Submit articles | Lyrics | WoW Gold | Compare Mortgages
Powered by phpBB © 2000-2009 phpBB Group

Copyright © Owen Rudge/The Transport Tycoon Forums 2001-2010.
Hosted by Zernebok.