Jump to content

lag issues status


Recommended Posts

Hello all,

From last year when I last checked the game we still have this huge performance issue. What is the status on this? It seems to occurs when lots of units are moving. I have had a look and it doesn't seem to be due to the pathfinding at first sight but I am pretty new to the code. is pathfinding being called constantly for moving units? The lag occurs at every turn and doesn't seem to be altered if the turn length is changed.Does anyone know the game architecture? I know it has a turn system like age of empire but that's all my knowledge of it. It seems to me that the first frame of the turn has to do all the calculations which is causing all the lag. Is this something inherent to the game engine or is it fixable?

Also I have noticed a important framerate drop (10 fps out of 40) due to the drawing of the unit list panel (in javascript) which is the cause for the game running slower if units are selected.

Edited by ickylevel
Link to comment
Share on other sites

Hello,

I am using the latest trunk from svn. Actually i managed to improve performance significantly by having the pathfinder recompute only the short path when a unit gets stuck by colliding with another unit. it makes a 1v1 playable at 300 population WITHOUT formation (which is the laggiest in theory). it still a bit laggy when the population reach that level tough. I think i can achieve good results by making workers ignoring collisions when harvesting, a la starcraft 2.

Edited by ickylevel
Link to comment
Share on other sites

Well some of the commits removed the sdl includes. I don't know which one I just reverted a couple of revision and it works.

This is stuff that has been removed :

C:\Users\ickylevel\work\0ad\libraries\win32\sdl
C:\Users\ickylevel\work\0ad\libraries\win32\sdl\include
C:\Users\ickylevel\work\0ad\libraries\win32\sdl\include\SDL
C:\Users\ickylevel\work\0ad\libraries\win32\sdl\include\SDL\SDL_config_macos.h
C:\Users\ickylevel\work\0ad\libraries\win32\sdl\include\SDL\SDL_config.h.default
C:\Users\ickylevel\work\0ad\libraries\win32\sdl\include\SDL\SDL_config_dreamcast.h
C:\Users\ickylevel\work\0ad\libraries\win32\sdl\include\SDL\SDL_error.h
C:\Users\ickylevel\work\0ad\libraries\win32\sdl\include\SDL\SDL_audio.h
C:\Users\ickylevel\work\0ad\libraries\win32\sdl\include\SDL\SDL_cpuinfo.h
C:\Users\ickylevel\work\0ad\libraries\win32\sdl\include\SDL\SDL_events.h
C:\Users\ickylevel\work\0ad\libraries\win32\sdl\include\SDL\SDL_video.h
C:\Users\ickylevel\work\0ad\libraries\win32\sdl\include\SDL\SDL_thread.h
C:\Users\ickylevel\work\0ad\libraries\win32\sdl\include\SDL\SDL_config.h.in
C:\Users\ickylevel\work\0ad\libraries\win32\sdl\include\SDL\SDL_rwops.h
C:\Users\ickylevel\work\0ad\libraries\win32\sdl\include\SDL\SDL_active.h
C:\Users\ickylevel\work\0ad\libraries\win32\sdl\include\SDL\begin_code.h
C:\Users\ickylevel\work\0ad\libraries\win32\sdl\include\SDL\SDL_timer.h
C:\Users\ickylevel\work\0ad\libraries\win32\sdl\include\SDL\SDL_stdinc.h
C:\Users\ickylevel\work\0ad\libraries\win32\sdl\include\SDL\SDL_opengl.h
C:\Users\ickylevel\work\0ad\libraries\win32\sdl\include\SDL\SDL_main.h
C:\Users\ickylevel\work\0ad\libraries\win32\sdl\include\SDL\SDL_version.h
C:\Users\ickylevel\work\0ad\libraries\win32\sdl\include\SDL\SDL_config_symbian.h
C:\Users\ickylevel\work\0ad\libraries\win32\sdl\include\SDL\SDL_config_win32.h
C:\Users\ickylevel\work\0ad\libraries\win32\sdl\include\SDL\SDL_config_os2.h
C:\Users\ickylevel\work\0ad\libraries\win32\sdl\include\SDL\SDL_getenv.h
C:\Users\ickylevel\work\0ad\libraries\win32\sdl\include\SDL\SDL_mouse.h
C:\Users\ickylevel\work\0ad\libraries\win32\sdl\include\SDL\close_code.h
C:\Users\ickylevel\work\0ad\libraries\win32\sdl\include\SDL\SDL_endian.h
C:\Users\ickylevel\work\0ad\libraries\win32\sdl\include\SDL\SDL_byteorder.h
C:\Users\ickylevel\work\0ad\libraries\win32\sdl\include\SDL\SDL_joystick.h
C:\Users\ickylevel\work\0ad\libraries\win32\sdl\include\SDL\SDL_keyboard.h
C:\Users\ickylevel\work\0ad\libraries\win32\sdl\include\SDL\SDL_mutex.h
C:\Users\ickylevel\work\0ad\libraries\win32\sdl\include\SDL\SDL_config_amiga.h
C:\Users\ickylevel\work\0ad\libraries\win32\sdl\include\SDL\SDL_types.h
C:\Users\ickylevel\work\0ad\libraries\win32\sdl\include\SDL\SDL_cdrom.h
C:\Users\ickylevel\work\0ad\libraries\win32\sdl\include\SDL\SDL_config.h
C:\Users\ickylevel\work\0ad\libraries\win32\sdl\include\SDL\SDL_copying.h
C:\Users\ickylevel\work\0ad\libraries\win32\sdl\include\SDL\SDL_config_nds.h
C:\Users\ickylevel\work\0ad\libraries\win32\sdl\include\SDL\SDL_config_minimal.h
C:\Users\ickylevel\work\0ad\libraries\win32\sdl\include\SDL\SDL_config_macosx.h
C:\Users\ickylevel\work\0ad\libraries\win32\sdl\include\SDL\SDL_name.h
C:\Users\ickylevel\work\0ad\libraries\win32\sdl\include\SDL\SDL.h
C:\Users\ickylevel\work\0ad\libraries\win32\sdl\include\SDL\SDL_loadso.h
C:\Users\ickylevel\work\0ad\libraries\win32\sdl\include\SDL\SDL_keysym.h
C:\Users\ickylevel\work\0ad\libraries\win32\sdl\include\SDL\SDL_quit.h
C:\Users\ickylevel\work\0ad\libraries\win32\sdl\include\SDL\SDL_syswm.h
C:\Users\ickylevel\work\0ad\libraries\win32\sdl\include\SDL\SDL_platform.h
C:\Users\ickylevel\work\0ad\libraries\win32\sdl\lib
C:\Users\ickylevel\work\0ad\libraries\win32\sdl\lib\SDL.lib
C:\Users\ickylevel\work\0ad\libraries\win32\sdl\lib\SDLmain.lib
  • Like 1
Link to comment
Share on other sites

I can't find what commit deleted them in the logs... But I have looked at every revision in it.


I am on windows 7 and I can't compile anymore: 7>c:\users\ickylevel\work\0ad\source\lib/sysdep/os/win/wsdl.h(33): fatal error C1083: Cannot open include file: 'SDL_keysym.h': ...

  • Like 1
Link to comment
Share on other sites

Isn't sdl2 the default for windows by now (and thus shouldn't be required with the --sdl2)? Please try again with the newest SVN version as Itms recently fixed a similar selection lag issue. (which doesn't mean that another issue could still remain) Sorry for the noise if that is what you already used.

Edited by Radagast.
Link to comment
Share on other sites

It doesn't help. But can you reproduce the issue by the way? Have like an army of 100, select them, make them move and then try selecting and deselecting to see the fps difference. Making them move is easier to spot the fps diff if you dont have a counter,

Edited by ickylevel
Link to comment
Share on other sites

To come back to the original question of this topic, my feeling is that the origin of the huge lag performance problems is still not quite clear and has different sources.

Sure, path finding is a source of problem. But I suspect another sources like the AI or stucked units...

An status of these issues would indeed help ;-)

Link to comment
Share on other sites

  • 2 weeks later...

As I said obstructed units do too much calculations, so I propose this fix :

Index: simulation2/components/CCmpObstructionManager.cpp===================================================================--- simulation2/components/CCmpObstructionManager.cpp	(revision 15848)+++ simulation2/components/CCmpObstructionManager.cpp	(working copy)@@ -431,7 +431,7 @@ 		} 	} -	virtual bool TestLine(const IObstructionTestFilter& filter, entity_pos_t x0, entity_pos_t z0, entity_pos_t x1, entity_pos_t z1, entity_pos_t r);+	virtual bool TestLine(const IObstructionTestFilter& filter, entity_pos_t x0, entity_pos_t z0, entity_pos_t &x1, entity_pos_t &z1, entity_pos_t r); 	virtual bool TestStaticShape(const IObstructionTestFilter& filter, entity_pos_t x, entity_pos_t z, entity_pos_t a, entity_pos_t w, entity_pos_t h, std::vector<entity_id_t>* out); 	virtual bool TestUnitShape(const IObstructionTestFilter& filter, entity_pos_t x, entity_pos_t z, entity_pos_t r, std::vector<entity_id_t>* out); @@ -536,7 +536,7 @@  REGISTER_COMPONENT_TYPE(ObstructionManager) -bool CCmpObstructionManager::TestLine(const IObstructionTestFilter& filter, entity_pos_t x0, entity_pos_t z0, entity_pos_t x1, entity_pos_t z1, entity_pos_t r)+bool CCmpObstructionManager::TestLine(const IObstructionTestFilter& filter, entity_pos_t x0, entity_pos_t z0, entity_pos_t &x1, entity_pos_t &z1, entity_pos_t r) { 	PROFILE("TestLine"); @@ -559,8 +559,12 @@  		CFixedVector2D center(it->second.x, it->second.z); 		CFixedVector2D halfSize(it->second.r + r, it->second.r + r);-		if (Geometry::TestRayAASquare(CFixedVector2D(x0, z0) - center, CFixedVector2D(x1, z1) - center, halfSize))+		if (Geometry::TestRayAASquare(CFixedVector2D(x0, z0) - center, CFixedVector2D(x1, z1) - center, halfSize)) {+			x1 = center.X;+			z1 = center.Y; 			return true;+		}+			 	}  	std::vector<entity_id_t> staticShapes;Index: simulation2/components/CCmpPathfinder.cpp===================================================================--- simulation2/components/CCmpPathfinder.cpp	(revision 15848)+++ simulation2/components/CCmpPathfinder.cpp	(working copy)@@ -583,6 +583,8 @@ 	} } ++ void CCmpPathfinder::ProcessShortRequests(const std::vector<AsyncShortPathRequest>& shortRequests) { 	for (size_t i = 0; i < shortRequests.size(); ++i)Index: simulation2/components/CCmpPathfinder_Common.h===================================================================--- simulation2/components/CCmpPathfinder_Common.h	(revision 15848)+++ simulation2/components/CCmpPathfinder_Common.h	(working copy)@@ -260,7 +260,7 @@  	virtual CFixedVector2D GetNearestPointOnGoal(CFixedVector2D pos, const Goal& goal); -	virtual bool CheckMovement(const IObstructionTestFilter& filter, entity_pos_t x0, entity_pos_t z0, entity_pos_t x1, entity_pos_t z1, entity_pos_t r, pass_class_t passClass);+	virtual bool CheckMovement(const IObstructionTestFilter& filter, entity_pos_t x0, entity_pos_t z0, entity_pos_t &x1, entity_pos_t &z1, entity_pos_t r, pass_class_t passClass);  	virtual ICmpObstruction::EFoundationCheck CheckUnitPlacement(const IObstructionTestFilter& filter, entity_pos_t x, entity_pos_t z, entity_pos_t r, pass_class_t passClass); Index: simulation2/components/CCmpPathfinder_Tile.cpp===================================================================--- simulation2/components/CCmpPathfinder_Tile.cpp	(revision 15848)+++ simulation2/components/CCmpPathfinder_Tile.cpp	(working copy)@@ -420,7 +420,7 @@  		// Hack to avoid spending ages computing giant paths, particularly when 		// the destination is unreachable-		if (state.steps > 40000)+		if (state.steps > 10000) 			break;  		// If we ran out of tiles to examine, give upIndex: simulation2/components/CCmpPathfinder_Vertex.cpp===================================================================--- simulation2/components/CCmpPathfinder_Vertex.cpp	(revision 15848)+++ simulation2/components/CCmpPathfinder_Vertex.cpp	(working copy)@@ -851,7 +851,7 @@ }  bool CCmpPathfinder::CheckMovement(const IObstructionTestFilter& filter,-	entity_pos_t x0, entity_pos_t z0, entity_pos_t x1, entity_pos_t z1, entity_pos_t r,+	entity_pos_t x0, entity_pos_t z0, entity_pos_t &x1, entity_pos_t &z1, entity_pos_t r, 	pass_class_t passClass) { 	CmpPtr<ICmpObstructionManager> cmpObstructionManager(GetSystemEntity());Index: simulation2/components/CCmpUnitMotion.cpp===================================================================--- simulation2/components/CCmpUnitMotion.cpp	(revision 15848)+++ simulation2/components/CCmpUnitMotion.cpp	(working copy)@@ -629,6 +629,11 @@ 	ControlGroupMovementObstructionFilter GetObstructionFilter(bool forceAvoidMovingUnits = false);  	/**+	 * Returns an appropriate obstruction filter for use with path requests.+	 */+	ControlGroupMovementObstructionFilter GetObstructionFilterNoAvoid();++	/** 	 * Start moving to the given goal, from our current position 'from'. 	 * Might go in a straight line immediately, or might start an asynchronous 	 * path request.@@ -892,11 +897,17 @@ 		fixed maxSpeed = basicSpeed.Multiply(terrainSpeed);  		bool wasObstructed = false;+		bool wasObstructedTerrain = false;  		// We want to move (at most) maxSpeed*dt units from pos towards the next waypoint  		fixed timeLeft = dt; 		fixed zero = fixed::Zero();++		fixed targetX;+		fixed targetY;++		fixed maxdist; 		 		while (timeLeft > zero) 		{@@ -907,14 +918,18 @@ 			CFixedVector2D target(m_ShortPath.m_Waypoints.back().x, m_ShortPath.m_Waypoints.back().z); 			CFixedVector2D offset = target - pos; +			+ 			// Work out how far we can travel in timeLeft-			fixed maxdist = maxSpeed.Multiply(timeLeft);+			maxdist = maxSpeed.Multiply(timeLeft);  			// If the target is close, we can move there directly 			fixed offsetLength = offset.Length(); 			if (offsetLength <= maxdist) 			{-				if (cmpPathfinder->CheckMovement(GetObstructionFilter(), pos.X, pos.Y, target.X, target.Y, m_Radius, m_PassClass))+				targetX = target.X;+				targetY = target.Y;+				if (cmpPathfinder->CheckMovement(GetObstructionFilter(), pos.X, pos.Y, targetX, targetY, m_Radius, m_PassClass)) 				{ 					pos = target; @@ -927,7 +942,10 @@ 				else 				{ 					// Error - path was obstructed-					wasObstructed = true;+					if (target.X != targetX || target.Y != targetY)+						wasObstructed = true;+					else+						wasObstructedTerrain = true; 					break; 				} 			}@@ -936,8 +954,9 @@ 				// Not close enough, so just move in the right direction 				offset.Normalize(maxdist); 				target = pos + offset;--				if (cmpPathfinder->CheckMovement(GetObstructionFilter(), pos.X, pos.Y, target.X, target.Y, m_Radius, m_PassClass))+				targetX = target.X;+				targetY = target.Y;+				if (cmpPathfinder->CheckMovement(GetObstructionFilter(), pos.X, pos.Y, targetX, targetY, m_Radius, m_PassClass)) 				{ 					pos = target; 					break;@@ -945,12 +964,68 @@ 				else 				{ 					// Error - path was obstructed-					wasObstructed = true;+					if (target.X != targetX || target.Y != targetY)+						wasObstructed = true;+					else+						wasObstructedTerrain = true; 					break; 				} 			} 		} +		if (wasObstructed)+		{+			// Oops, we hit something (not terrain).+			//	const AsyncLongPathRequest& req = longRequests[i];++			/*+			ICmpPathfinder::Path pathf;+			m_PathState = PATHSTATE_WAITING_REQUESTING_LONG;+			cmpPathfinder->ComputePath(pos.X, pos.Y,  m_FinalGoal, m_PassClass, m_CostClass, pathf);+			PathResult(m_ExpectedPathTicket,pathf);+			*/++			m_PathState = PATHSTATE_FOLLOWING_REQUESTING_SHORT;+			ICmpPathfinder::Path path;+			ICmpPathfinder::Goal goal(m_FinalGoal);+			ICmpPathfinder::Waypoint way;+			//if (m_LongPath.m_Waypoints.size() > 0)+			//	way = m_LongPath.m_Waypoints.back();+			//else+				way = m_ShortPath.m_Waypoints.front();+			goal.x = way.x;+			goal.z = way.z;+			cmpPathfinder->ComputeShortPath(GetObstructionFilter(), pos.X, pos.Y, +				m_Radius, SHORT_PATH_SEARCH_RANGE, goal , m_PassClass, path);+			PathResult(m_ExpectedPathTicket,path);+	++			/*+			CFixedVector2D diffHit(targetX - pos.X,targetY - pos.Y);+			diffHit.Normalize();++			fixed pdistance = diffHit.X.Multiply(diffHit.X) + diffHit.Y.Multiply(diffHit.Y)  ;+			pdistance = pdistance.Sqrt();+			diffHit.X = -diffHit.X; +			diffHit.Y = -diffHit.Y;+			maxdist  = maxdist - pdistance;+			diffHit = diffHit.Multiply( maxdist ) + pos;+			targetX = diffHit.X;+			targetY = diffHit.Y;+			if (cmpPathfinder->CheckMovement(GetObstructionFilter(), pos.X, pos.Y, targetX, targetY, m_Radius, m_PassClass))+			{+				pos = diffHit;+			}+			*/+		}++		if (wasObstructedTerrain)+		{+			m_CurSpeed = zero;+			RequestLongPath(pos, m_FinalGoal);+			m_PathState = PATHSTATE_WAITING_REQUESTING_LONG;+		}+ 		// Update the Position component after our movement (if we actually moved anywhere) 		if (pos != initialPos) 		{@@ -964,20 +1039,7 @@ 			m_CurSpeed = cmpPosition->GetDistanceTravelled() / dt; 		} 		-		if (wasObstructed)-		{-			// Oops, we hit something (very likely another unit).-			// Stop, and recompute the whole path.-			// TODO: if the target has UnitMotion and is higher priority,-			// we should wait a little bit.-			-			m_CurSpeed = zero;-			RequestLongPath(pos, m_FinalGoal);-			m_PathState = PATHSTATE_WAITING_REQUESTING_LONG;--			return;-		}-+		 		// We successfully moved along our path, until running out of 		// waypoints or time. @@ -1229,8 +1291,19 @@ 	return ControlGroupMovementObstructionFilter(forceAvoidMovingUnits || ShouldAvoidMovingUnits(), group); } +ControlGroupMovementObstructionFilter CCmpUnitMotion::GetObstructionFilterNoAvoid()+{+	entity_id_t group;+	if (IsFormationMember())+		group = m_TargetEntity;+	else+		group = GetEntityId(); +	return ControlGroupMovementObstructionFilter(false, group);+} ++ void CCmpUnitMotion::BeginPathing(CFixedVector2D from, const ICmpPathfinder::Goal& goal) { 	// Cancel any pending path requestsIndex: simulation2/components/ICmpObstructionManager.h===================================================================--- simulation2/components/ICmpObstructionManager.h	(revision 15848)+++ simulation2/components/ICmpObstructionManager.h	(working copy)@@ -171,7 +171,7 @@ 	 * @param r radius (half width) of line 	 * @return true if there is a collision 	 */-	virtual bool TestLine(const IObstructionTestFilter& filter, entity_pos_t x0, entity_pos_t z0, entity_pos_t x1, entity_pos_t z1, entity_pos_t r) = 0;+	virtual bool TestLine(const IObstructionTestFilter& filter, entity_pos_t x0, entity_pos_t z0, entity_pos_t &x1, entity_pos_t &z1, entity_pos_t r) = 0;  	/** 	 * Collision test a static square shape against the current set of shapes.Index: simulation2/components/ICmpPathfinder.h===================================================================--- simulation2/components/ICmpPathfinder.h	(revision 15848)+++ simulation2/components/ICmpPathfinder.h	(working copy)@@ -148,7 +148,7 @@ 	 * or impassable terrain. 	 * Returns true if the movement is okay. 	 */-	virtual bool CheckMovement(const IObstructionTestFilter& filter, entity_pos_t x0, entity_pos_t z0, entity_pos_t x1, entity_pos_t z1, entity_pos_t r, pass_class_t passClass) = 0;+	virtual bool CheckMovement(const IObstructionTestFilter& filter, entity_pos_t x0, entity_pos_t z0, entity_pos_t &x1, entity_pos_t &z1, entity_pos_t r, pass_class_t passClass) = 0;  	/** 	 * Check whether a unit placed here is valid and doesn't hit any obstructions
Link to comment
Share on other sites

This is some very interesting stuff right here. I would like to try this out for myself if possible.

I've been messing around in single player a bit and indeed, large movements of units continue to be a thorn in the side of the game. I get ~110 fps in game throughout the game but as soon as units need to move you get freezes, the time it takes for the engine to calculate everything.

I'm still unable to code anything. I still have a question though.

Would it be possible to find a way to rewrite pathfinding code so that it's well-threaded? e.g. it will scale off more than one CPU core. This is what I get after playing a single player skirmish: http://i.imgur.com/0I5eoBs.png

I'm not sure how it would be possible though. I'm guessing that every unit would have to recalculate its path using the exact same equation or something? The only thing that changes for each unit's equation are the variables of the problem. Would that be well-threaded or something? Or perhaps task the thread for long-range path-finding to one core and then the other thread for short-range path-finding to another core. Everyone has at least two cores on their CPU. I understand it's difficult to make a task scale off more than one core obviously. However, shouldn't it be possible?

I actually have no idea what I'm talking about but maybe we can start a discussion or something, idk. Pathfinding and multiplayer lag are the two biggest issues with 0 AD which are, imo, the issues that need to be looked at the first. I understand that obviously, these are probably the most difficult problems to tackle. This is why I'd like to try out / discuss ickylevel's pathfinding solution. I understand there are certain rules that need to be followed, given that this is an open-source project (i.e. a continuity that everyone needs to follow). However maybe those rules should be tweaked to be more lenient.

Personally, with formations gone, units have interesting movement. I actually feel they're more realistic now, especially the way cavalry moves around the map. The way they clump up when they arrive at their destination is less than realistic though, I don't think that's a big issue though.

Edited by iNcog
  • Like 2
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...