diff --git a/addons/frag/ACE_Settings.hpp b/addons/frag/ACE_Settings.hpp
index 6a782de2f9..bbf0398cfb 100644
--- a/addons/frag/ACE_Settings.hpp
+++ b/addons/frag/ACE_Settings.hpp
@@ -1,15 +1,33 @@
 class ACE_Settings {
-    class GVAR(enabled) {
+    class GVAR(Enabled) {
         displayName = "$STR_ACE_frag_EnableFrag";
         description = "$STR_ACE_frag_EnableFrag_Desc";
         typeName = "BOOL";
         value = 1;
     };
-    
-    class GVAR(spallEnabled) {
+    class GVAR(SpallEnabled) {
         displayName = "$STR_ACE_frag_EnableSpall";
         description = "$STR_ACE_frag_EnableSpall_Desc";
         typeName = "BOOL";
         value = 1;
     };
+    class GVAR(maxTrack) {
+        displayName = "$STR_ACE_frag_MaxTrack";
+        description = "$STR_ACE_frag_MaxTrack_Desc";
+        typeName = "SCALAR";
+        value = 500;
+    };
+    class GVAR(MaxTrackPerFrame) {
+        displayName = "$STR_ACE_frag_MaxTrackPerFrame";
+        description = "$STR_ACE_frag_MaxTrackPerFrame_Desc";
+        typeName = "SCALAR";
+        value = 50;
+    };
+    
+    class GVAR(EnableDebugTrace) {
+        displayName = "$STR_ACE_frag_EnableDebugTrace";
+        description = "$STR_ACE_frag_EnableDebugTrace_Desc";
+        typeName = "BOOL";
+        value = 0;
+    };
 };
diff --git a/addons/frag/CfgAmmo.hpp b/addons/frag/CfgAmmo.hpp
index 7f4c4b38b3..41734d2806 100644
--- a/addons/frag/CfgAmmo.hpp
+++ b/addons/frag/CfgAmmo.hpp
@@ -9,8 +9,6 @@ class CfgAmmo {
     //    GVAR(skip) = 1;
     //};
     
-    #include "CfgAmmoReflections.hpp"
-    
     class Bo_GBU12_LGB;
     class ACE_GBU12 : Bo_GBU12_LGB {
         GVAR(enabled) = 1;
@@ -473,4 +471,6 @@ class CfgAmmo {
     class ACE_frag_spall_huge: ACE_frag_huge {
         timeToLive = 0.3;
     };
+    
+    #include "CfgAmmoReflections.hpp"
 };
diff --git a/addons/frag/CfgAmmoReflections.hpp b/addons/frag/CfgAmmoReflections.hpp
index 8e481a9cd0..f59d67f89a 100644
--- a/addons/frag/CfgAmmoReflections.hpp
+++ b/addons/frag/CfgAmmoReflections.hpp
@@ -1,7 +1,6 @@
 //CfgAmmoReflections.hpp
 
 #define ACE_EXPLOSION_REFLECTION(range, hit) class ace_explosion_reflection_##range##_##hit : ace_explosion_reflection_base { indirectHitRange = range; indirectHit = hit; dangerRadiusHit = range*3; suppressionRadiusHit = range*2; };
-class Sh_120mm_HE;
 class ace_explosion_reflection_base : Sh_120mm_HE {
     CraterWaterEffects = "";
     CraterEffects = "";
diff --git a/addons/frag/XEH_postInit.sqf b/addons/frag/XEH_postInit.sqf
index 0c6a1845b6..95c921df64 100644
--- a/addons/frag/XEH_postInit.sqf
+++ b/addons/frag/XEH_postInit.sqf
@@ -1,5 +1,10 @@
 #include "script_component.hpp"
 
+if(GVAR(EnableDebugTrace) && !isMultiplayer) then {
+    GVAR(traceFrags) = true;
+    GVAR(autoTrace) = true;
+};
+
 if(isServer) then {
     [QGVAR(frag_eh), { _this call FUNC(frago); }] call ace_common_fnc_addEventHandler;
 };
diff --git a/addons/frag/XEH_preInit.sqf b/addons/frag/XEH_preInit.sqf
index a2d1e38c1b..cdd9342ffd 100644
--- a/addons/frag/XEH_preInit.sqf
+++ b/addons/frag/XEH_preInit.sqf
@@ -15,7 +15,7 @@ GVAR(TOTALFRAGS) = 0;
 GVAR(spallHPData) = [];
 GVAR(spallIsTrackingCount) = 0;
 
-GVAR(autoTrace) = true;
+GVAR(autoTrace) = false;
 GVAR(traceID) = -1;
 GVAR(traces) = [];
 GVAR(tracesStarted) = false;
@@ -43,6 +43,7 @@ PREP(doExplosions);
 PREP(doReflections);
 
 
+GVAR(lastIterationIndex) = 0;
 GVAR(objects) = [];
 GVAR(objectTypes) = [];
 GVAR(arguments) = [];
diff --git a/addons/frag/functions/fnc_addPfhRound.sqf b/addons/frag/functions/fnc_addPfhRound.sqf
index 81454edf97..7530b8f062 100644
--- a/addons/frag/functions/fnc_addPfhRound.sqf
+++ b/addons/frag/functions/fnc_addPfhRound.sqf
@@ -1,20 +1,21 @@
+//#define DEBUG_MODE_FULL
 #include "script_component.hpp"
 
-private ["_enabled", "_gun", "_type", "_round", "_doFragTrack", "_doSpall", "_spallTrack", "_spallTrackID"];
+private ["_enabled","_doFragTrack", "_doSpall", "_spallTrack", "_spallTrackID"];
+PARAMS_3(_gun,_type,_round);
 
 if (!GVAR(enabled)) exitWith {};
 
-_gun = _this select 0;
-_type = _this select 1;
-_round = _this select 2;
-
-_enabled = getNumber (configFile >> "CfgAmmo" >> _type >> QGVAR(enabled));
-if(_enabled < 1) exitWith {};
+//_enabled = getNumber (configFile >> "CfgAmmo" >> _type >> QGVAR(enabled));
+//if(_enabled < 1) exitWith {};
 
 if(_round in GVAR(blackList)) exitWith {
     GVAR(blackList) = GVAR(blackList) - [_round];
 };
 
+// Exit on max track
+if( (count GVAR(objects)) > GVAR(MaxTrack)) exitWith { };
+
 _doFragTrack = false;
 if(_gun == ACE_player) then {
     _doFragTrack = true;
@@ -27,7 +28,7 @@ if(_gun == ACE_player) then {
         };
     };
 };
-if(GVAR(spallEnabled)) then {
+if(GVAR(SpallEnabled)) then {
     if(GVAR(spallIsTrackingCount) <= 0) then {
         GVAR(spallHPData) = [];
     };
@@ -40,12 +41,15 @@ if(GVAR(spallEnabled)) then {
 };
 // ACE_player sideChat format["c: %1", GVAR(spallIsTrackingCount)];
 
-#ifdef DEBUG_MODE_FULL
-[ACE_player, _round, [1,0,0,1]] call FUNC(addTrack);
-#endif
+if(GVAR(autoTrace)) then {
+    [ACE_player, _round, [1,0,0,1]] call FUNC(addTrack);
+};
 
 // We only do the single track object check here.
-if(_doFragTrack && alive _round && {!(_round in GVAR(objects))} ) then {
+// We should do an {!(_round in GVAR(objects))}  
+// But we leave that out here for optimization. So this cannot be a framework function
+// Otherwise, it should only be added once and from the FiredEH
+if(_doFragTrack && alive _round) then {
     _spallTrack = [];
     _spallTrackID = [];
     
@@ -57,12 +61,12 @@ if(_doFragTrack && alive _round && {!(_round in GVAR(objects))} ) then {
             (getNumber (configFile >> "CfgAmmo" >> _type >> QGVAR(force))),
             (getNumber(configFile >> "CfgAmmo" >> _type >> "indirecthit")*(sqrt((getNumber (configFile >> "CfgAmmo" >> _type >> "indirectHitRange")))))
         ];
-    
+    TRACE_1("Initializing track", _round);
     GVAR(objects) pushBack _round;
     GVAR(arguments) pushBack _args;
     
     if(_doSpall) then {
-        [_round, 2, _spallTrack, _spallTrackID] call FUNC(spallTrack);
+        [_round, 1, _spallTrack, _spallTrackID] call FUNC(spallTrack);
     };
     // ACE_player sideChat "WTF2";
 };
diff --git a/addons/frag/functions/fnc_doSpall.sqf b/addons/frag/functions/fnc_doSpall.sqf
index 717b629e53..1e8e87bcb3 100644
--- a/addons/frag/functions/fnc_doSpall.sqf
+++ b/addons/frag/functions/fnc_doSpall.sqf
@@ -1,14 +1,10 @@
 //fnc_doSpall.sqf
 #include "script_component.hpp"
-#ifdef DEBUG_MODE_FULL
-    GVAR(traceFrags) = true;
-#endif
 // ACE_player sideChat "WAAAAAAAAAAAAAAAAAAAAA";    
 
 private ["_params", "_hitData", "_initialData", "_hpData", "_object", "_foundObjects", "_index", "_foundObjecsts", "_roundType", "_round", "_caliber", "_explosive", "_idh", "_alive", "_exit", "_vm", "_velocity", "_oldVelocity", "_curVelocity", "_diff", "_polar", "_unitDir", "_spallPos", "_pos1", "_i", "_pos2", "_blah", "_data", "_spallPolar", "_warn", "_c", "_m", "_k", "_gC", "_fragPower", "_fragTypes", "_spread", "_spallCount", "_elev", "_dir", "_vel", "_spallFragVect", "_fragType", "_fragment", "_pos"];
 
 _params = _this select 0;
-[(_this select 1)] call cba_fnc_removePerFrameHandler;
 _hitData = _params select 0;
 _initialData = GVAR(spallHPData) select (_hitData select 0);
 _hpData = (_hitData select 1) select (_params select 1);
diff --git a/addons/frag/functions/fnc_frago.sqf b/addons/frag/functions/fnc_frago.sqf
index 415b75e790..5b5cf89bbe 100644
--- a/addons/frag/functions/fnc_frago.sqf
+++ b/addons/frag/functions/fnc_frago.sqf
@@ -163,11 +163,8 @@ if(_isArmed && (count _objects) > 0) then {
                             _fragObj setPosASL _lastPos;
                             _fragObj setVectorDir _vec;
                             _fragObj setVelocity _vel;
-                            #ifdef DEBUG_MODE_FULL
-                                GVAR(TOTALFRAGS) = GVAR(TOTALFRAGS) + 1;
-                                GVAR(traceFrags) = true;
-                            #endif
                             if(GVAR(traceFrags)) then {
+                                GVAR(TOTALFRAGS) = GVAR(TOTALFRAGS) + 1;
                                 [ACE_player, _fragObj, [1,0,0,1]] call FUNC(addTrack);
                             };
                             _fragCount = _fragCount + 1;
@@ -200,11 +197,9 @@ if(_isArmed && (count _objects) > 0) then {
             _fragObj setPosASL _lastPos;
             _fragObj setVectorDir _vec;
             _fragObj setVelocity _vel;
-            #ifdef DEBUG_MODE_FULL
-                GVAR(TOTALFRAGS) = GVAR(TOTALFRAGS) + 1;
-                GVAR(traceFrags) = true;
-            #endif
+            
             if(GVAR(traceFrags)) then {
+                GVAR(TOTALFRAGS) = GVAR(TOTALFRAGS) + 1;
                 [ACE_player, _fragObj, [1,0.5,0,1]] call FUNC(addTrack);
             };
             _fragCount = _fragCount + 1;
diff --git a/addons/frag/functions/fnc_masterPFH.sqf b/addons/frag/functions/fnc_masterPFH.sqf
index d511325e15..4e81c4c609 100644
--- a/addons/frag/functions/fnc_masterPFH.sqf
+++ b/addons/frag/functions/fnc_masterPFH.sqf
@@ -9,36 +9,48 @@
  * Return Value:
  * None
  */
+//#define DEBUG_MODE_FULL
 #include "script_component.hpp"
-PARAMS_2(_pfhArgs,_handle);
+//PARAMS_2(_pfhArgs,_handle);
 
 if (!GVAR(enabled)) exitWith {};
 
 private["_gcIndex"];
 _gcIndex = [];
-{
+
+_iter = 0;
+while { (count GVAR(objects)) > 0 &&  { _iter < GVAR(MaxTrackPerFrame) } } do {
     private["_object", "_args"];
-    _object = _x;
+    if(GVAR(lastIterationIndex) >= (count GVAR(objects))) then {
+        GVAR(lastIterationIndex) = 0;
+    };
+    _object = GVAR(objects) select GVAR(lastIterationIndex);
+    
     if(!isNil "_object") then {
         if(isNull _object) then {
-            _gcIndex pushBack _forEachIndex;
+            _gcIndex pushBack GVAR(lastIterationIndex);
         } else {
-            _args = GVAR(arguments) select _forEachIndex;
+            _args = GVAR(arguments) select GVAR(lastIterationIndex);
             
-            _args call FUNC(pfhRound);
-        };
-        
-        if(!alive _object) then {
-            _gcIndex pushBack _forEachIndex;
+            if(!(_args call FUNC(pfhRound))) then {
+                _gcIndex pushBack GVAR(lastIterationIndex);    // Add it to the GC if it returns false
+            };
+            // If its not alive anymore, remove it from the queue, it already ran once on dead
+            if(!alive _object) then {
+                _gcIndex pushBack GVAR(lastIterationIndex);
+            };
         };
     };
-} forEach GVAR(objects);
+    _iter = _iter + 1;
+    GVAR(lastIterationIndex) = GVAR(lastIterationIndex) + 1;
+};
 
 // clean up dead object references
 private["_deletionCount", "_deleteIndex"];
 _deletionCount = 0;
 {
-    _deleteIndex = _gcIndex - _deletionCount;
+    TRACE_1("GC Projectile", _x);
+    _deleteIndex = _x - _deletionCount;
     GVAR(objects) deleteAt _deleteIndex;
     GVAR(arguments) deleteAt _deleteIndex;
     
diff --git a/addons/frag/functions/fnc_pfhRound.sqf b/addons/frag/functions/fnc_pfhRound.sqf
index df6f618ac5..8cc9457842 100644
--- a/addons/frag/functions/fnc_pfhRound.sqf
+++ b/addons/frag/functions/fnc_pfhRound.sqf
@@ -1,25 +1,28 @@
 #include "script_component.hpp"
-private ["_params", "_round", "_lastPos", "_lastVel", "_type", "_time", "_doSpall", "_spallTrack", "_foundObjectHPIds", "_skip", "_explosive", "_indirectRange", "_force", "_fragPower"];
-_params = _this select 0;
-_round = _params select 0;
-_lastPos = _params select 1;
-_lastVel = _params select 2;
-_type = _params select 3;
-_time = _params select 4;
-_doSpall = _params select 6;
-_spallTrack = _params select 7;
-_foundObjectHPIds = _params select 8;
-_skip = _params select 9;
-_explosive = _params select 10;
-_indirectRange = _params select 11;
-_force = _params select 12;
-_fragPower = _params select 13;
+private ["_round", "_lastPos", "_lastVel", "_type", "_time", "_doSpall", "_spallTrack", "_foundObjectHPIds", "_skip", "_explosive", "_indirectRange", "_force", "_fragPower"];
+_round = _this select 0;
+_lastPos = _this select 1;
+_lastVel = _this select 2;
+_type = _this select 3;
+_time = _this select 4;
+_doSpall = _this select 6;
+_spallTrack = _this select 7;
+_foundObjectHPIds = _this select 8;
+_skip = _this select 9;
+_explosive = _this select 10;
+_indirectRange = _this select 11;
+_force = _this select 12;
+_fragPower = _this select 13;
+
+if(_round in GVAR(blackList)) exitWith { 
+    false
+};
 
 if (!alive _round) then {
-    if(_time != time && {!(_round in GVAR(blackList))}) then {
+    if(_time != time) then {
         if(_skip == 0) then {
             if((_explosive > 0.5 && {_indirectRange >= 4.5} && {_fragPower >= 35}) || {_force == 1} ) then {
-                [QGVAR(frag_eh), _params] call ace_common_fnc_serverEvent;
+                [QGVAR(frag_eh), _this] call ace_common_fnc_serverEvent;
             };
         };
     };
@@ -33,13 +36,14 @@ if (!alive _round) then {
         } forEach _spallTrack;
     };
 } else {
-    if(_round in GVAR(blackList)) exitWith { 
-        [_round] call FUNC(removePfhRound);
-    };
-    
+
     _params set[1, (getPosASL _round)];
     _params set[2, (velocity _round)];
     if(_doSpall) then {
-        [_round, 1, _spallTrack, _foundObjectHPIds] call FUNC(spallTrack);
+        private["_scale"];
+        _scale = ( (count GVAR(objects)) / GVAR(MaxTrackPerFrame) ) max 0.1;
+        [_round, _scale, _spallTrack, _foundObjectHPIds] call FUNC(spallTrack);
     };
 };
+
+true
\ No newline at end of file
diff --git a/addons/frag/functions/fnc_spallTrack.sqf b/addons/frag/functions/fnc_spallTrack.sqf
index 4b7a06bc65..afe4bc1931 100644
--- a/addons/frag/functions/fnc_spallTrack.sqf
+++ b/addons/frag/functions/fnc_spallTrack.sqf
@@ -22,7 +22,7 @@ if (count _intersectsWith > 0) then {
         if(!(_x in _foundObjects)) then {
             // diag_log text format["Adding HP: %1", _x];
             _index = (count GVAR(spallHPData));
-            _hpId = _x addEventHandler ["hitPart", format["[%1, _this] call " + QUOTE(FUNC(spallHP)), _index]];
+            _hpId = _x addEventHandler ["hitPart", compile format["[%1, _this] call " + QUOTE(FUNC(spallHP)), _index]];
             _foundObjects set[(count _foundObjects), _x];
             _foundObjectHPIds set[(count _foundObjectHPIds), _hpId];
             _data = [_hpId, _x, typeOf _round, _round, _curPos, _velocity, 0, _foundObjects, _foundObjectHPIds];
diff --git a/addons/frag/stringtable.xml b/addons/frag/stringtable.xml
index e267685869..5b49b0e192 100644
--- a/addons/frag/stringtable.xml
+++ b/addons/frag/stringtable.xml
@@ -3,19 +3,33 @@
     <Package name="Frag">
         <Key ID="STR_ACE_frag_EnableFrag">
             <English>Fragmentation Simulation</English>
- 
         </Key>
         <Key ID="STR_ACE_frag_EnableFrag_Desc">
             <English>Enable the ACE Fragmentation Simulation</English>
- 
         </Key>
         <Key ID="STR_ACE_frag_EnableSpall">
             <English>Spalling Simulation</English>
- 
         </Key>
         <Key ID="STR_ACE_frag_EnableSpall_Desc">
             <English>Enable the ACE Spalling Simulation</English>
- 
+        </Key>
+        <Key ID="STR_ACE_frag_MaxTrack">
+            <English>Maximum Projectiles Tracked</English>
+        </Key>
+        <Key ID="STR_ACE_frag_MaxTrack_Desc">
+            <English>This setting controls the maximum amount of projectiles the fragmentation & spalling system will track at any given time. If more projectiles are fired, they will not be tracked. Lower this setting if you do not want FPS drops at high-count projectile scenarios ( >200 rounds in the air at once)</English>
+        </Key>
+        <Key ID="STR_ACE_frag_MaxTrackPerFrame">
+            <English>Maximum Projectiles Per Frame</English>
+        </Key>
+        <Key ID="STR_ACE_frag_MaxTrackPerFrame_Desc">
+            <English>The number of spall track calculations to perform in any given frame. This helps spread the FPS impact of tracking spall rounds across multiple frames, limiting its impact even further.</English>
+        </Key>
+        <Key ID="STR_ACE_frag_EnableDebugTrace">
+            <English>(SP Only) Frag/Spall Debug Tracing</English>
+        </Key>
+        <Key ID="STR_ACE_frag_EnableDebugTrace_Desc">
+            <English>(SP Only) Requires a mission/editor restart. Enables visual tracing of fragmentation and spalling rounds in SP game mode only.</English>
         </Key>
     </Package>
 </Project>