Index: binary-improvements2/WebServer/src/UrlHandlers/ItemIconHandler.cs
===================================================================
--- binary-improvements2/WebServer/src/UrlHandlers/ItemIconHandler.cs	(revision 399)
+++ binary-improvements2/WebServer/src/UrlHandlers/ItemIconHandler.cs	(revision 402)
@@ -3,5 +3,4 @@
 using System.IO;
 using System.Net;
-using AllocsFixes;
 using UnityEngine;
 using Object = UnityEngine.Object;
@@ -45,7 +44,16 @@
 				_context.Response.StatusCode = (int) HttpStatusCode.NotFound;
 				if (logMissingFiles) {
-					Log.Out ("[Web] IconHandler: FileNotFound: \"" + _context.RequestPath + "\" ");
+					Log.Out ($"[Web] IconHandler: FileNotFound: \"{_context.RequestPath}\" ");
 				}
 			}
+		}
+
+		private class LoadingStats {
+			public int Files;
+			public int Tints;
+			public readonly MicroStopwatch MswTotal = new MicroStopwatch (false);
+			public readonly MicroStopwatch MswLoading = new MicroStopwatch (false);
+			public readonly MicroStopwatch MswEncoding = new MicroStopwatch (false);
+			public readonly MicroStopwatch MswTinting = new MicroStopwatch (false);
 		}
 
@@ -57,5 +65,6 @@
 				}
 
-				MicroStopwatch microStopwatch = new MicroStopwatch ();
+				LoadingStats stats = new LoadingStats ();
+				stats?.MswTotal.Start ();
 
 				// Get list of used tints for all items
@@ -72,14 +81,14 @@
 
 					string name = ic.GetIconName ();
-					if (!tintedIcons.ContainsKey (name)) {
-						tintedIcons.Add (name, new List<Color> ());
+					if (!tintedIcons.TryGetValue (name, out List<Color> tintsList)) {
+						tintsList = new List<Color> ();
+						tintedIcons.Add (name, tintsList);
 					}
 
-					List<Color> list = tintedIcons [name];
-					list.Add (tintColor);
+					tintsList.Add (tintColor);
 				}
 
 				try {
-					loadIconsFromFolder (GameIO.GetGameDir ("Data/ItemIcons"), tintedIcons);
+					loadIconsFromFolder (GameIO.GetGameDir ("Data/ItemIcons"), tintedIcons, stats);
 				} catch (Exception e) {
 					Log.Error ("[Web] Failed loading icons from base game");
@@ -90,14 +99,28 @@
 				foreach (Mod mod in ModManager.GetLoadedMods ()) {
 					try {
-						string modIconsPath = mod.Path + "/ItemIcons";
-						loadIconsFromFolder (modIconsPath, tintedIcons);
+						string modIconsPath = $"{mod.Path}/ItemIcons";
+						loadIconsFromFolder (modIconsPath, tintedIcons, stats);
 					} catch (Exception e) {
-						Log.Error ("[Web] Failed loading icons from mod " + mod.ModInfo.Name.Value);
+						Log.Error ($"[Web] Failed loading icons from mod {mod.Name}");
 						Log.Exception (e);
 					}
 				}
+				
+				loaded = true;
 
-				loaded = true;
-				Log.Out ("[Web] IconHandler: Icons loaded - {0} ms", microStopwatch.ElapsedMilliseconds);
+				if (stats == null) {
+					Log.Out ($"[Web] IconHandler: Loaded {icons.Count} icons");
+				} else {
+					stats?.MswTotal.Stop ();
+					Log.Out ($"[Web] IconHandler: Loaded {icons.Count} icons ({stats.Files} source images with {stats.Tints} tints applied)");
+					Log.Out ($"[Web] IconHandler: Total time {stats.MswTotal.ElapsedMilliseconds} ms, loading files {stats.MswLoading.ElapsedMilliseconds} ms, tinting files {stats.MswTinting.ElapsedMilliseconds} ms, encoding files {stats.MswEncoding.ElapsedMilliseconds} ms");
+
+					int totalSize = 0;
+					foreach ((string _, byte[] iconData) in icons) {
+						totalSize += iconData.Length;
+					}
+					
+					Log.Out ($"[Web] IconHandler: Cached {totalSize / 1024} KiB");
+				}
 
 				return true;
@@ -105,5 +128,5 @@
 		}
 
-		private void loadIconsFromFolder (string _path, Dictionary<string, List<Color>> _tintedIcons) {
+		private void loadIconsFromFolder (string _path, Dictionary<string, List<Color>> _tintedIcons, LoadingStats _stats) {
 			if (!Directory.Exists (_path)) {
 				return;
@@ -118,9 +141,14 @@
 					string name = Path.GetFileNameWithoutExtension (file);
 					Texture2D tex = new Texture2D (1, 1, TextureFormat.ARGB32, false);
-					if (!tex.LoadImage (File.ReadAllBytes (file))) {
+					
+					_stats?.MswLoading.Start ();
+					byte[] sourceBytes = File.ReadAllBytes (file);
+					if (!tex.LoadImage (sourceBytes)) {
+						_stats?.MswLoading.Stop ();
 						continue;
 					}
+					_stats?.MswLoading.Stop ();
 
-					AddIcon (name, tex, _tintedIcons);
+					AddIcon (name, sourceBytes, tex, _tintedIcons, _stats);
 
 					Object.Destroy (tex);
@@ -131,13 +159,19 @@
 		}
 
-		private void AddIcon (string _name, Texture2D _tex, Dictionary<string, List<Color>> _tintedIcons) {
-			icons [_name + "__FFFFFF"] = _tex.EncodeToPNG ();
+		private void AddIcon (string _name, byte[] _sourceBytes, Texture2D _tex, Dictionary<string, List<Color>> _tintedIcons, LoadingStats _stats) {
+			_stats?.MswEncoding.Start ();
+			icons [$"{_name}__FFFFFF"] = _sourceBytes;
+			_stats?.MswEncoding.Stop ();
 
-			if (!_tintedIcons.ContainsKey (_name)) {
+			if (_stats != null) {
+				_stats.Files++;
+			}
+
+			if (!_tintedIcons.TryGetValue (_name, out List<Color> tintsList)) {
 				return;
 			}
 
-			foreach (Color c in _tintedIcons [_name]) {
-				string tintedName = _name + "__" + AllocsUtils.ColorToHex (c);
+			foreach (Color c in tintsList) {
+				string tintedName = $"{_name}__{c.ToHexCode ()}";
 				if (icons.ContainsKey (tintedName)) {
 					continue;
@@ -146,15 +180,20 @@
 				Texture2D tintedTex = new Texture2D (_tex.width, _tex.height, TextureFormat.ARGB32, false);
 
-				for (int x = 0; x < _tex.width; x++) {
-					for (int y = 0; y < _tex.height; y++) {
-						tintedTex.SetPixel (x, y, _tex.GetPixel (x, y) * c);
-					}
-				}
+				_stats?.MswTinting.Start ();
+				TextureUtils.ApplyTint (_tex, tintedTex, c);
+				_stats?.MswTinting.Stop ();
 
+				_stats?.MswEncoding.Start ();
 				icons [tintedName] = tintedTex.EncodeToPNG ();
+				_stats?.MswEncoding.Stop ();
 
 				Object.Destroy (tintedTex);
+
+				if (_stats != null) {
+					_stats.Tints++;
+				}
 			}
 		}
+		
 	}
 }
