changeset 11268:e0ddd5124002 draft

(svn r15617) -Change [FS#2694]: vehicle variables 40-43 weren't cached (though spec stated they are). Caching these variables can yield a 10+% speed increase when those vehicle variables are queried often.
author rubidium <rubidium@openttd.org>
date Wed, 04 Mar 2009 23:32:23 +0000
parents 1d456bf484a1
children 9fc6ae841a4d
files src/misc_cmd.cpp src/newgrf_engine.cpp src/train_cmd.cpp src/vehicle_base.h
diffstat 4 files changed, 104 insertions(+), 62 deletions(-) [+]
line wrap: on
line diff
--- a/src/misc_cmd.cpp
+++ b/src/misc_cmd.cpp
@@ -19,6 +19,7 @@
 #include "company_base.h"
 #include "company_gui.h"
 #include "settings_type.h"
+#include "vehicle_base.h"
 
 #include "table/strings.h"
 
@@ -118,6 +119,12 @@
 		}
 		ResetVehicleColourMap();
 		MarkWholeScreenDirty();
+
+		/* Company colour data is indirectly cached. */
+		Vehicle *v;
+		FOR_ALL_VEHICLES(v) {
+			if (v->owner == _current_company) v->cache_valid = 0;
+		}
 	}
 	return CommandCost();
 }
--- a/src/newgrf_engine.cpp
+++ b/src/newgrf_engine.cpp
@@ -442,10 +442,35 @@
 	return l->colour1 + l->colour2 * 16;
 }
 
+/**
+ * Helper to get the position of a vehicle within a chain of vehicles.
+ * @param v the vehicle to get the position of.
+ * @param consecutive whether to look at the whole chain or the vehicles
+ *                    with the same 'engine type'.
+ * @return the position in the chain from front and tail and chain length.
+ */
+static uint32 PositionHelper(const Vehicle *v, bool consecutive)
+{
+	const Vehicle *u;
+	byte chain_before = 0;
+	byte chain_after  = 0;
+
+	for (u = v->First(); u != v; u = u->Next()) {
+		chain_before++;
+		if (consecutive && u->engine_type != v->engine_type) chain_before = 0;
+	}
+
+	while (u->Next() != NULL && (!consecutive || u->Next()->engine_type == v->engine_type)) {
+		chain_after++;
+		u = u->Next();
+	}
+
+	return chain_before | chain_after << 8 | (chain_before + chain_after + consecutive) << 16;
+}
 
 static uint32 VehicleGetVariable(const ResolverObject *object, byte variable, byte parameter, bool *available)
 {
-	const Vehicle *v = GRV(object);
+	Vehicle *v = const_cast<Vehicle*>(GRV(object));
 
 	if (v == NULL) {
 		/* Vehicle does not exist, so we're in a purchase list */
@@ -476,80 +501,81 @@
 	/* Calculated vehicle parameters */
 	switch (variable) {
 		case 0x40: // Get length of consist
+			if (!HasBit(v->cache_valid, 0)) {
+				v->cached_var40 = PositionHelper(v, false);
+				SetBit(v->cache_valid, 0);
+			}
+			return v->cached_var40;
+
 		case 0x41: // Get length of same consecutive wagons
-			{
-				const Vehicle *u;
-				byte chain_before = 0;
-				byte chain_after  = 0;
+			if (!HasBit(v->cache_valid, 1)) {
+				v->cached_var41 = PositionHelper(v, true);
+				SetBit(v->cache_valid, 1);
+			}
+			return v->cached_var41;
 
-				for (u = v->First(); u != v; u = u->Next()) {
-					chain_before++;
-					if (variable == 0x41 && u->engine_type != v->engine_type) chain_before = 0;
-				}
+		case 0x42: // Consist cargo information
+			if (!HasBit(v->cache_valid, 2)) {
+				const Vehicle *u;
+				byte cargo_classes = 0;
+				CargoID common_cargo_best = CT_INVALID;
+				uint8 common_cargos[NUM_CARGO];
+				uint8 common_subtype_best = 0xFF; // Return 0xFF if nothing is carried
+				uint8 common_subtypes[256];
+				byte user_def_data = 0;
+				CargoID common_cargo_type = CT_PASSENGERS;
+				uint8 common_subtype = 0;
 
-				while (u->Next() != NULL && (variable == 0x40 || u->Next()->engine_type == v->engine_type)) {
-					chain_after++;
-					u = u->Next();
+				/* Reset our arrays */
+				memset(common_cargos, 0, sizeof(common_cargos));
+				memset(common_subtypes, 0, sizeof(common_subtypes));
+
+				for (u = v; u != NULL; u = u->Next()) {
+					if (v->type == VEH_TRAIN) user_def_data |= u->u.rail.user_def_data;
+
+					/* Skip empty engines */
+					if (u->cargo_cap == 0) continue;
+
+					cargo_classes |= GetCargo(u->cargo_type)->classes;
+					common_cargos[u->cargo_type]++;
 				}
 
-				return chain_before | chain_after << 8 | (chain_before + chain_after + (variable == 0x41)) << 16;
-			}
-
-		case 0x42: { // Consist cargo information
-			const Vehicle *u;
-			byte cargo_classes = 0;
-			CargoID common_cargo_best = CT_INVALID;
-			uint8 common_cargos[NUM_CARGO];
-			uint8 common_subtype_best = 0xFF; // Return 0xFF if nothing is carried
-			uint8 common_subtypes[256];
-			byte user_def_data = 0;
-			CargoID common_cargo_type = CT_PASSENGERS;
-			uint8 common_subtype = 0;
+				/* Pick the most common cargo type */
+				for (CargoID cargo = 0; cargo < NUM_CARGO; cargo++) {
+					if (common_cargos[cargo] > common_cargo_best) {
+						common_cargo_best = common_cargos[cargo];
+						common_cargo_type = cargo;
+					}
+				}
 
-			/* Reset our arrays */
-			memset(common_cargos, 0, sizeof(common_cargos));
-			memset(common_subtypes, 0, sizeof(common_subtypes));
-
-			for (u = v; u != NULL; u = u->Next()) {
-				if (v->type == VEH_TRAIN) user_def_data |= u->u.rail.user_def_data;
-
-				/* Skip empty engines */
-				if (u->cargo_cap == 0) continue;
-
-				cargo_classes |= GetCargo(u->cargo_type)->classes;
-				common_cargos[u->cargo_type]++;
-			}
+				/* Count subcargo types of common_cargo_type */
+				for (u = v; u != NULL; u = u->Next()) {
+					/* Skip empty engines and engines not carrying common_cargo_type */
+					if (u->cargo_cap == 0 || u->cargo_type != common_cargo_type) continue;
 
-			/* Pick the most common cargo type */
-			for (CargoID cargo = 0; cargo < NUM_CARGO; cargo++) {
-				if (common_cargos[cargo] > common_cargo_best) {
-					common_cargo_best = common_cargos[cargo];
-					common_cargo_type = cargo;
+					common_subtypes[u->cargo_subtype]++;
 				}
-			}
-
-			/* Count subcargo types of common_cargo_type */
-			for (u = v; u != NULL; u = u->Next()) {
-				/* Skip empty engines and engines not carrying common_cargo_type */
-				if (u->cargo_cap == 0 || u->cargo_type != common_cargo_type) continue;
 
-				common_subtypes[u->cargo_subtype]++;
-			}
+				/* Pick the most common subcargo type*/
+				for (uint i = 0; i < lengthof(common_subtypes); i++) {
+					if (common_subtypes[i] > common_subtype_best) {
+						common_subtype_best = common_subtypes[i];
+						common_subtype = i;
+					}
+				}
 
-			/* Pick the most common subcargo type*/
-			for (uint i = 0; i < lengthof(common_subtypes); i++) {
-				if (common_subtypes[i] > common_subtype_best) {
-					common_subtype_best = common_subtypes[i];
-					common_subtype = i;
-				}
+				uint8 common_bitnum = (common_cargo_type == CT_INVALID ? 0xFF : GetCargo(common_cargo_type)->bitnum);
+				v->cached_var42 = cargo_classes | (common_bitnum << 8) | (common_subtype << 16) | (user_def_data << 24);
+				SetBit(v->cache_valid, 2);
 			}
-
-			uint8 common_bitnum = (common_cargo_type == CT_INVALID ? 0xFF : GetCargo(common_cargo_type)->bitnum);
-			return cargo_classes | (common_bitnum << 8) | (common_subtype << 16) | (user_def_data << 24);
-		}
+			return v->cached_var42;
 
 		case 0x43: // Company information
-			return v->owner | (GetCompany(v->owner)->is_ai ? 0x10000 : 0) | (LiveryHelper(v->engine_type, v) << 24);
+			if (!HasBit(v->cache_valid, 3)) {
+				v->cached_var43 = v->owner | (GetCompany(v->owner)->is_ai ? 0x10000 : 0) | (LiveryHelper(v->engine_type, v) << 24);
+				SetBit(v->cache_valid, 3);
+			}
+			return v->cached_var43;
 
 		case 0x44: // Aircraft information
 			if (v->type != VEH_AIRCRAFT) return UINT_MAX;
--- a/src/train_cmd.cpp
+++ b/src/train_cmd.cpp
@@ -257,11 +257,13 @@
 
 		/* Set user defined data to its default value */
 		u->u.rail.user_def_data = rvi_u->user_def_data;
+		u->cache_valid = 0;
 	}
 
 	for (Vehicle *u = v; u != NULL; u = u->Next()) {
 		/* Update user defined data (must be done before other properties) */
 		u->u.rail.user_def_data = GetVehicleProperty(u, 0x25, u->u.rail.user_def_data);
+		u->cache_valid = 0;
 	}
 
 	for (Vehicle *u = v; u != NULL; u = u->Next()) {
@@ -347,6 +349,7 @@
 		if (!same_length) u->u.rail.cached_veh_length = veh_len;
 
 		v->u.rail.cached_total_length += u->u.rail.cached_veh_length;
+		u->cache_valid = 0;
 	}
 
 	/* store consist weight/max speed in cache */
--- a/src/vehicle_base.h
+++ b/src/vehicle_base.h
@@ -323,6 +323,12 @@
 		VehicleShip ship;
 	} u;
 
+	/* cached oftenly queried NewGRF values */
+	uint8 cache_valid;   ///< Whether the caches are valid
+	uint32 cached_var40; ///< Cache for NewGRF var 40
+	uint32 cached_var41; ///< Cache for NewGRF var 41
+	uint32 cached_var42; ///< Cache for NewGRF var 42
+	uint32 cached_var43; ///< Cache for NewGRF var 43
 
 	/**
 	 * Allocates a lot of vehicles.