Advertisement
klassekatze

Prototype analytical gyro controller

Aug 1st, 2023
919
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 19.94 KB | None | 0 0
  1. /*
  2.  * R e a d m e
  3.  * -----------
  4.  * klassekatze was here
  5.  *
  6.  * Prototype analytical gyro control class. No PID! ONLY ANGLE
  7.  */
  8.  
  9.  
  10. public static Program gProgram;
  11.  
  12. public Program()
  13. {
  14.     gProgram = this;
  15.     //wsinit();
  16.     Runtime.UpdateFrequency = UpdateFrequency.Update1;
  17.  
  18.     log("test", LT.LOG_N);
  19. }
  20.  
  21.  
  22. class logmsg
  23. {
  24.     public logmsg(string m, LT l) { msg = m; level = l; }
  25.     public string msg = "";
  26.     public int c = 1;
  27.     public LT level = LT.LOG_N;
  28. }
  29.  
  30. List<logmsg> loggedMessages = new List<logmsg>();
  31. int MAX_LOG = 50;
  32. bool loggedMessagesDirty = true;
  33.  
  34.  
  35. public enum LT
  36. {
  37.     LOG_N = 0,
  38.     LOG_D,
  39.     LOG_DD
  40. }
  41.  
  42. public static LT LOG_LEVEL = LT.LOG_N;
  43.  
  44. public static void log(string s, LT level)
  45. {
  46.     if (level > LOG_LEVEL) return;
  47.  
  48.     if (s.Length > 50)
  49.     {
  50.         List<string> tok = new List<string>();
  51.         while (s.Length > 50)
  52.         {
  53.             int c = 0;
  54.             if (tok.Count > 0) c = 2;
  55.             tok.Add(s.Substring(0, 50 - c));
  56.             s = s.Substring(50 - c);
  57.         }
  58.         tok.Add(s);
  59.         s = string.Join("\n ", tok);
  60.     }
  61.     var p = gProgram;
  62.     logmsg l = null;
  63.     if (p.loggedMessages.Count > 0)
  64.     {
  65.         l = p.loggedMessages[p.loggedMessages.Count - 1];
  66.     }
  67.     if (l != null)
  68.     {
  69.         if (l.msg == s) l.c += 1;
  70.         else p.loggedMessages.Add(new logmsg(s, level));
  71.     }
  72.     else p.loggedMessages.Add(new logmsg(s, level));
  73.     if (p.loggedMessages.Count > p.MAX_LOG) p.loggedMessages.RemoveAt(0);
  74.     p.loggedMessagesDirty = true;
  75. }
  76.  
  77.  
  78. string loggedMessagesCache = "";
  79. string renderLoggedMessages()
  80. {
  81.     if (!loggedMessagesDirty) return loggedMessagesCache;
  82.  
  83.     string o = "";
  84.     foreach (var m in loggedMessages)//(int i = 0; i < loggedMessages.Count; i++)
  85.     {
  86.         o += m.msg;
  87.         if (m.c > 1) o += " (" + m.c + ")";
  88.         o += "\n";
  89.     }
  90.     loggedMessagesDirty = false;
  91.     loggedMessagesCache = o;
  92.     return o;
  93. }
  94.  
  95. List<IMyShipController> controllers = new List<IMyShipController>();
  96. List<IMyGyro> gyros = new List<IMyGyro>();
  97. IMyTextSurface consoleLog = null;
  98. IMyTextSurface statusLog = null;
  99. IMyTextSurface profileLog = null;
  100.  
  101. public bool isThis(IMyTerminalBlock b)
  102. {
  103.     return b.OwnerId == Me.OwnerId && b.CubeGrid == Me.CubeGrid;
  104. }
  105.  
  106. bool needsetup = true;
  107. public void loadBlocks()
  108. {
  109.     List<IMyTerminalBlock> LCDs = new List<IMyTerminalBlock>();
  110.     GridTerminalSystem.GetBlocksOfType<IMyTerminalBlock>(LCDs, b => (b is IMyTextSurface) && b.CubeGrid == Me.CubeGrid);
  111.     foreach (var b in LCDs)
  112.     {
  113.         IMyTextSurface s = b as IMyTextSurface;
  114.         if (b.CustomData.Contains("radarLog")) statusLog = s;
  115.         else if (b.CustomData.Contains("consoleLog")) consoleLog = s;
  116.         else if (b.CustomData.Contains("profileLog")) profileLog = s;
  117.     }
  118.  
  119.     controllers.Clear();
  120.     GridTerminalSystem.GetBlocksOfType(controllers, isThis);
  121.     gyros.Clear();
  122.     GridTerminalSystem.GetBlocksOfType(gyros, isThis);
  123.  
  124.     gyroECU = new GyroECU4(gyros, controllers[0], controllers[0]);
  125. }
  126. GyroECU4 gyroECU = null;
  127.  
  128. public void Save()
  129. {
  130.     // Called when the program needs to save its state. Use
  131.     // this method to save your state to the Storage field
  132.     // or some other means.
  133.     //
  134.     // This method is optional and can be removed if not
  135.     // needed.
  136. }
  137. static Profiler initP = new Profiler("init");
  138. static Profiler mainP = new Profiler("main");
  139.  
  140. static int tick = -1;
  141.  
  142. public void Main(string argument, UpdateType updateSource)
  143. {
  144.     tick += 1;
  145.     mainP.start();
  146.     main(argument, updateSource);
  147.     mainP.stop();
  148.     if (tick % 5 == 0)
  149.     {
  150.         Echo(tick.ToString());
  151.         if (profileLog != null) profileLog.WriteText("name:ms1t:ms60t\n" + Profiler.getAllReports());
  152.     }
  153.     if (consoleLog != null)// && tick % 6 == 0)
  154.     {
  155.         consoleLog.WriteText(renderLoggedMessages());
  156.     }
  157. }
  158. static Profiler gyroP = new Profiler("gyro");
  159. private void main(string arg, UpdateType upd)
  160. {
  161.     if (needsetup)
  162.     {
  163.         needsetup = false;
  164.         loadBlocks();
  165.     }
  166.  
  167.     if (arg == "test")
  168.     {
  169.         gyroECU.rotateToPosition(new Vector3D(4372.71,2861.67,-2820.26));
  170.     }else if (arg == "flip")
  171.     {
  172.         gyroECU.rotateToHeading(controllers[0].WorldMatrix.Forward * -1);
  173.     }
  174.     else if (arg == "left")
  175.     {
  176.         gyroECU.rotateToHeading(controllers[0].WorldMatrix.Left * -1);
  177.     }
  178.     gyroP.start();
  179.     gyroECU.update();
  180.     gyroP.stop();
  181. }
  182.  
  183.  
  184.  
  185.  
  186.  
  187. /// <summary>
  188.         /// Whip's GetRotationAnglesSimultaneous - Last modified: 07/05/2020
  189.         /// Gets axis angle rotation and decomposes it upon each cardinal axis.
  190.         /// Has the desired effect of not causing roll oversteer. Does NOT use
  191.         /// sequential rotation angles.
  192.         /// Set desiredUpVector to Vector3D.Zero if you don't care about roll.
  193.         /// Dependencies:
  194.         /// SafeNormalize
  195.         /// </summary>
  196. public static void GetRotationAnglesSimultaneous(Vector3D desiredForwardVector, Vector3D desiredUpVector, MatrixD worldMatrix, out double yaw, out double pitch, out double roll)
  197. {
  198.     desiredForwardVector = SafeNormalize(desiredForwardVector);
  199.  
  200.     MatrixD transposedWm;
  201.     MatrixD.Transpose(ref worldMatrix, out transposedWm);
  202.     Vector3D.Rotate(ref desiredForwardVector, ref transposedWm, out desiredForwardVector);
  203.     Vector3D.Rotate(ref desiredUpVector, ref transposedWm, out desiredUpVector);
  204.  
  205.     Vector3D leftVector = Vector3D.Cross(desiredUpVector, desiredForwardVector);
  206.     Vector3D axis;
  207.     double angle;
  208.     if (Vector3D.IsZero(desiredUpVector) || Vector3D.IsZero(leftVector))
  209.     {
  210.         axis = new Vector3D(desiredForwardVector.Y, -desiredForwardVector.X, 0);
  211.         angle = Math.Acos(MathHelper.Clamp(-desiredForwardVector.Z, -1.0, 1.0));
  212.     }
  213.     else
  214.     {
  215.         leftVector = SafeNormalize(leftVector);
  216.         Vector3D upVector = Vector3D.Cross(desiredForwardVector, leftVector);
  217.  
  218.         // Create matrix
  219.         MatrixD targetMatrix = MatrixD.Zero;
  220.         targetMatrix.Forward = desiredForwardVector;
  221.         targetMatrix.Left = leftVector;
  222.         targetMatrix.Up = upVector;
  223.  
  224.         axis = new Vector3D(targetMatrix.M23 - targetMatrix.M32,
  225.                             targetMatrix.M31 - targetMatrix.M13,
  226.                             targetMatrix.M12 - targetMatrix.M21);
  227.  
  228.         double trace = targetMatrix.M11 + targetMatrix.M22 + targetMatrix.M33;
  229.         angle = Math.Acos(MathHelper.Clamp((trace - 1) * 0.5, -1, 1));
  230.     }
  231.  
  232.     if (Vector3D.IsZero(axis))
  233.     {
  234.         angle = desiredForwardVector.Z < 0 ? 0 : Math.PI;
  235.         yaw = angle;
  236.         pitch = 0;
  237.         roll = 0;
  238.         return;
  239.     }
  240.  
  241.     axis = SafeNormalize(axis);
  242.     yaw = -axis.Y * angle;
  243.     pitch = axis.X * angle;
  244.     roll = -axis.Z * angle;
  245. }
  246.  
  247. public static Vector3D SafeNormalize(Vector3D a)
  248. {
  249.     if (Vector3D.IsZero(a))
  250.         return Vector3D.Zero;
  251.  
  252.     if (Vector3D.IsUnit(ref a))
  253.         return a;
  254.  
  255.     return Vector3D.Normalize(a);
  256. }
  257. static double d180bypi = (180 / Math.PI);
  258. public static double ConvertRadiansToDegrees(double radians)
  259. {
  260.     double degrees = d180bypi * radians;
  261.     return (degrees);
  262. }
  263. static double dpiby180 = (Math.PI / 180);
  264. public static double ConvertDegreesToRadians(double degrees)
  265. {
  266.     double radians = dpiby180 * degrees;
  267.     return (radians);
  268. }
  269. public static string v2ss(Vector3D v)
  270. {
  271.     return "<" + v.X.ToString("0.0000") + "," + v.Y.ToString("0.0000") + "," + v.Z.ToString("0.0000") + ">";
  272. }
  273. static public double VectorAngleBetween(Vector3D a, Vector3D b) //returns radians
  274. {
  275.     if (a.LengthSquared() == 0 || b.LengthSquared() == 0)
  276.         return 0;
  277.     else
  278.         return Math.Acos(MathHelper.Clamp(a.Dot(b) / a.Length() / b.Length(), -1, 1));
  279. }
  280.  
  281. public static void ApplyGyroOverride(double pitch_speed, double yaw_speed, double roll_speed, List<IMyGyro> gyro_list, IMyTerminalBlock reference)
  282. {
  283.     var rotationVec = new Vector3D(-pitch_speed, yaw_speed, roll_speed); //because keen does some weird stuff with signs
  284.     var shipMatrix = reference.WorldMatrix;
  285.     var relativeRotationVec = Vector3D.TransformNormal(rotationVec, shipMatrix);
  286.  
  287.     foreach (var thisGyro in gyro_list)
  288.     {
  289.         var gyroMatrix = thisGyro.WorldMatrix;
  290.         var transformedRotationVec = Vector3D.TransformNormal(relativeRotationVec, Matrix.Transpose(gyroMatrix));
  291.         //log("t:"+ transformedRotationVec.X.ToString("0.00") + "," + transformedRotationVec.Y.ToString("0.00") + "," + transformedRotationVec.Z.ToString("0.00"), LT.LOG_N);
  292.         thisGyro.Pitch = (float)transformedRotationVec.X;
  293.         thisGyro.Yaw = (float)transformedRotationVec.Y;
  294.         thisGyro.Roll = (float)transformedRotationVec.Z;
  295.         thisGyro.GyroOverride = true;
  296.     }
  297. }
  298.  
  299. public class GyroECU4
  300. {
  301.     public static double gyroMaxRPM = 3.1415;
  302.  
  303.     public double angleMultiplier = 1;
  304.  
  305.     List<IMyGyro> gyros = new List<IMyGyro>();
  306.     IMyTerminalBlock fwd_ref;
  307.     IMyShipController ctrl;
  308.  
  309.     public GyroECU4(List<IMyGyro> g, IMyTerminalBlock refer, IMyShipController c) : base()
  310.     {
  311.         angleMultiplier = c.CubeGrid.GridSizeEnum == VRage.Game.MyCubeSize.Small ? 2 : 1;
  312.         gyroMaxRPM *= angleMultiplier;
  313.         fwd_ref = refer;
  314.         gyros = g;
  315.         ctrl = c;
  316.         lastAngleRoll = lastAnglePitch = lastAngleYaw = 0;
  317.         lMPTRoll = lMPTPitch = lMPTYaw = 0;
  318.  
  319.         //debug telemetry
  320.         ybrakes=pbrakes=rbrakes = 0;
  321.     }
  322.     double lastAngleRoll, lastAnglePitch, lastAngleYaw;
  323.     double lMPTRoll, lMPTPitch, lMPTYaw;
  324.     double modr, modp, mody = 0;
  325.  
  326.     int ybrakes, pbrakes, rbrakes = 0;
  327.  
  328.  
  329.  
  330.     bool active = false;
  331.     Vector3D targetPosition;
  332.     Vector3D targetVelocity;
  333.  
  334.     Vector3D targetHeading;
  335.  
  336.     int startTick;
  337.  
  338.     private void flush()
  339.     {
  340.         if (!active)
  341.         {
  342.             active = true;
  343.             startTick = tick;
  344.             lastAngleRoll = lastAnglePitch = lastAngleYaw = 0;
  345.             lMPTRoll = lMPTPitch = lMPTYaw = 0;
  346.             modr = modp = mody = 0;
  347.         }
  348.     }
  349.     public void rotateToPosition(Vector3D tp, Vector3D tv = new Vector3D())
  350.     {
  351.         if(!active) log("GECU test init rtp", LT.LOG_N);
  352.         flush();
  353.         targetPosition = tp;
  354.         targetVelocity = tv;
  355.     }
  356.     public void rotateToHeading(Vector3D heading)
  357.     {
  358.         if (!active) log("GECU test init rth", LT.LOG_N);
  359.         flush();
  360.         targetPosition = targetVelocity = Vector3D.Zero;
  361.         targetHeading = heading;
  362.     }
  363.  
  364.     /*public void activate(Vector3D tp)//NOTE: targp too close to the reference block can cause problems, due to CoM fluctuations.
  365.             {
  366.                 active = true;
  367.                 startTick = tick;
  368.                 targetPosition = tp;
  369.  
  370.                 targetHeading = Vector3D.Normalize(targetPosition - ctrl.GetPosition());
  371.  
  372.                 lastAngleRoll = lastAnglePitch = lastAngleYaw = 0;
  373.                 lMPTRoll = lMPTPitch = lMPTYaw = 0;
  374.                 modr = modp = mody = 0;
  375.                 log("test init", LT.LOG_N);
  376.                 gProgram.Me.CustomData = "";
  377.             }*/
  378.     string dbg = "";
  379.     private void calculateAxisSpecificData(double now, ref double prior, ref double lastMPT, ref double mod, out bool ontarg, out bool braking, string p="")//, out double ticksToStop, out double ticksToTarget)
  380.     {
  381.         ontarg = false;
  382.  
  383.         var radMovedPerTick = Math.Abs(prior - now);
  384.         var ticksToTarget = Math.Abs(now) / radMovedPerTick;
  385.         var initVel = radMovedPerTick;
  386.         var rateOfDecel = Math.Abs(lastMPT - radMovedPerTick);
  387.         if (rateOfDecel > mod) mod = rateOfDecel;
  388.  
  389.         //if (Math.Abs(now) > nobrake_threshold) rateOfDecel *= 1.5;//overestimating here did not improve timings
  390.         var ticksToStop = initVel / rateOfDecel;
  391.         //mod - maximum observed decel - saved 0.1s on large sluggish ship but lost .3s on sg snappy ship.
  392.         //sticking to the conservative metric
  393.  
  394.         bool closing = Math.Abs(now) < Math.Abs(prior);
  395.  
  396.         if (!closing)
  397.         {
  398.             lastMPT = 0.0001;
  399.             mod = MathHelper.EPSILON;
  400.         }
  401.         else lastMPT = radMovedPerTick;
  402.  
  403.         if (closing)
  404.         {
  405.             if (ticksToStop > ticksToTarget + 1) braking = true;
  406.             else braking = false;
  407.         }
  408.         else braking = false;
  409.  
  410.         if (Math.Abs(now) < error_threshold)
  411.         {
  412.             braking = true;
  413.             if(radMovedPerTick < minVelThreshold)ontarg = true;
  414.         }
  415.         /*
  416.                 dbg += p + "rmpt=" + ConvertRadiansToDegrees(radMovedPerTick) + "\n";
  417.                 dbg += p + "lmpt=" + ConvertRadiansToDegrees(lastMPT) + "\n";
  418.                 dbg += p + "deg=" + ConvertRadiansToDegrees(now) + "\n";
  419.                 dbg += p + "closing=" + closing + "\n";
  420.                 dbg += p + "braking=" + braking + "\n";
  421.                 dbg += p + "ticksToTarget:" + ticksToTarget.ToString("0.00") + "\n";
  422.                 dbg += p + "initVel:" + ConvertRadiansToDegrees(initVel).ToString("0.00") + "\n";
  423.                 dbg += p + "rateOfDecel:" + ConvertRadiansToDegrees(rateOfDecel).ToString("0.00") + "\n";
  424.                 dbg += p + "ticksToStop:" + ticksToStop.ToString("0.00") + "\n";*/
  425.  
  426.         prior = now;
  427.     }
  428.  
  429.     double error_threshold = ConvertDegreesToRadians(0.25);
  430.     double minVelThreshold = ConvertDegreesToRadians(0.01);
  431.  
  432.     double nobrake_threshold = ConvertDegreesToRadians(45);
  433.     double amp_threshold = ConvertDegreesToRadians(5);
  434.  
  435.  
  436.     int minTicksOnTarget = 5;
  437.  
  438.     int ticksOnTarget = 0;
  439.  
  440.     public void update(bool up=false)
  441.     {
  442.         if (active)
  443.         {
  444.             dbg = "";
  445.  
  446.             Vector3D heading = fwd_ref.WorldMatrix.Forward;
  447.  
  448.  
  449.             if(!targetPosition.IsZero())targetHeading = Vector3D.Normalize(targetPosition - ctrl.GetPosition());
  450.  
  451.             double pitch, yaw, roll;
  452.             GetRotationAnglesSimultaneous(targetHeading, up ? fwd_ref.WorldMatrix.Up : Vector3D.Zero, fwd_ref.WorldMatrix, out yaw, out pitch, out roll);
  453.             //string dbg = "";
  454.             //dbg += pitch.ToString("0.0")+","+yaw.ToString("0.0"),roll.ToString("0.0")
  455.             bool yT, pT, rT, yB, pB, rB;
  456.             calculateAxisSpecificData(roll, ref lastAngleRoll, ref lMPTRoll, ref modr, out rT, out rB, "r-");
  457.             calculateAxisSpecificData(pitch, ref lastAnglePitch, ref lMPTPitch, ref modp, out pT, out pB,"p-");
  458.             calculateAxisSpecificData(yaw, ref lastAngleYaw, ref lMPTYaw, ref mody, out yT, out yB,"y-");
  459.  
  460.             /*ybrakes += yB?1:0;
  461.                     pbrakes += pB ? 1 : 0;
  462.                     rbrakes += rB ? 1 : 0;
  463.  
  464.                     dbg += "ybrakes:" + ybrakes + "\n";
  465.                     dbg += "pbrakes:" + pbrakes + "\n";
  466.                     dbg += "rbrakes:" + rbrakes + "\n";*/
  467.  
  468.             Vector3D a_impulse = new Vector3D(pB ? 0 : pitch, yB ? 0 : yaw, rB ? 0 : roll);
  469.             dbg += v2ss(d180bypi * a_impulse) + "\n";
  470.             if (a_impulse != Vector3D.Zero)
  471.             {
  472.                 var m = a_impulse.AbsMax();
  473.                 if (m > amp_threshold) m = gyroMaxRPM;
  474.                 else m = m / amp_threshold * gyroMaxRPM;
  475.  
  476.  
  477.                 a_impulse = a_impulse / a_impulse.AbsMax() * m;
  478.             }
  479.             dbg += v2ss(d180bypi * a_impulse) + "\n";
  480.  
  481.             ApplyGyroOverride(a_impulse.X, a_impulse.Y, a_impulse.Z, gyros, fwd_ref);
  482.  
  483.             if (yT && pT && rT)
  484.             {
  485.                 ticksOnTarget += 1;
  486.             }
  487.             else ticksOnTarget = 0;
  488.  
  489.             if (ticksOnTarget > minTicksOnTarget)
  490.             {
  491.                 active = false;
  492.                 foreach (var g in gyros) g.GyroOverride = false;
  493.                 log("GECU shutdown", LT.LOG_N);
  494.                 log("time: "+(tick - startTick) + "t (" + ((double)(tick - startTick) / 60).ToString("0.0") + "s)", LT.LOG_N);
  495.             }
  496.  
  497.             //debug nonsense
  498.             //if(gProgram.statusLog != null)gProgram.statusLog.WriteText(dbg);
  499.         }
  500.     }
  501. }
  502.  
  503. public class Profiler
  504. {
  505.  
  506.  
  507.     static bool PROFILING_ENABLED = true;
  508.     static List<Profiler> profilers = new List<Profiler>();
  509.     const int mstracklen = 60;
  510.     double[] mstrack = new double[mstracklen];
  511.     double msdiv = 1.0d / mstracklen;
  512.     int mscursor = 0;
  513.     DateTime start_time = DateTime.MinValue;
  514.     string Name = "";
  515.     string pre = "";
  516.     string post = "";
  517.     int _ticks_between_calls = 1;
  518.     int ltick = int.MinValue;
  519.     //..int callspertick = 1;
  520.  
  521.     static int base_sort_position_c = 0;
  522.     int base_sort_position = 0;
  523.  
  524.     bool nevercalled = true;
  525.     //bool closed = true;
  526.     public int getSortPosition()
  527.     {
  528.         if (nevercalled) return int.MaxValue;
  529.         int mult = (int)Math.Pow(10, 8 - (depth * 2));
  530.         if (parent != null) return parent.getSortPosition() + (base_sort_position * mult);
  531.  
  532.         return base_sort_position * mult;
  533.         //if (parent != null) return parent.getSortPosition() + (base_sort_position / (10 * depth));
  534.         //return base_sort_position;// * 1000;
  535.     }
  536.     /*public Profiler(string name, int ticks_between_calls) : this(name)
  537.             {
  538.                 _ticks_between_calls = ticks_between_calls;
  539.             }*/
  540.     static int basep = (int)Math.Pow(10, 5);
  541.     public Profiler(string name)
  542.     {
  543.         if (PROFILING_ENABLED)
  544.         {
  545.             Name = name;
  546.             profilers.Add(this);
  547.             base_sort_position = base_sort_position_c;
  548.             base_sort_position_c += 1;
  549.         }
  550.     }
  551.     public void s()
  552.     {
  553.         start();
  554.     }
  555.     public void e()
  556.     {
  557.         stop();
  558.     }
  559.  
  560.  
  561.     static List<Profiler> stack = new List<Profiler>();
  562.  
  563.     Profiler parent = null;
  564.     int depth = 0;
  565.  
  566.     bool adding = false;
  567.     public void start()
  568.     {
  569.         if (PROFILING_ENABLED)
  570.         {
  571.             //closed = false;
  572.             nevercalled = false;
  573.             if (tick != ltick)
  574.             {
  575.                 if (_ticks_between_calls == 1 && ltick != int.MinValue)
  576.                 {
  577.                     _ticks_between_calls = tick - ltick;
  578.                 }
  579.                 ltick = tick;
  580.                 //callspertick = 1;
  581.                 adding = false;
  582.             }
  583.             else
  584.             {
  585.                 adding = true;
  586.             }
  587.             if (depth == 0) depth = stack.Count;
  588.             if (depth > 11) depth = 11;
  589.             if (stack.Count > 0 && parent == null) parent = stack[stack.Count - 1];
  590.             stack.Add(this);
  591.             start_time = DateTime.Now;
  592.         }
  593.     }
  594.     double lastms = 0;
  595.     double average = 0;
  596.  
  597.  
  598.     /// <summary>
  599.             /// records a fake ms consumption for this timeframe - for tests or demo
  600.             /// </summary>
  601.     public double FAKE_stop(double fakems)
  602.     {
  603.         return stop(fakems);
  604.     }
  605.     /// <summary>
  606.             /// adds the elapsed time since start() to the records
  607.             /// </summary>
  608.     public double stop()
  609.     {
  610.         double time = 0;
  611.         if (PROFILING_ENABLED)
  612.         {
  613.             //closed = true;
  614.             time = (DateTime.Now - start_time).TotalMilliseconds;
  615.         }
  616.         return stop(time);
  617.     }
  618.  
  619.     private double stop(double _ms)
  620.     {
  621.         double time = 0;
  622.         if (PROFILING_ENABLED)
  623.         {
  624.             time = _ms;
  625.  
  626.             stack.Pop();
  627.             if (parent != null)
  628.             {
  629.                 depth = parent.depth + 1;
  630.             }
  631.  
  632.             //if(!adding)mscursor = (mscursor + 1) % mstracklen;
  633.  
  634.  
  635.             if (!adding) mstrack[mscursor] = 0;
  636.             mstrack[mscursor] += time;
  637.             if (!adding) mscursor = (mscursor + 1) % mstracklen;
  638.  
  639.             average = 0d;
  640.             foreach (double ms in mstrack) average += ms;
  641.             average *= msdiv;
  642.             average /= _ticks_between_calls;
  643.             lastms = time;
  644.         }
  645.         return time;
  646.     }
  647.     /// <summary>
  648.             /// generates a monospaced report text. If called every tick, every 120 ticks it will recalculate treeview data.
  649.             /// </summary>
  650.     //the treeview can be initially inaccurate as some profilers might not be called every tick, depending on program architecture
  651.     public string getReport()
  652.     {
  653.         if (PROFILING_ENABLED)
  654.         {
  655.             if (tick % 120 == 25)//recalculate hacky treeview data, delayed by 25 ticks from program start
  656.             {
  657.                 try
  658.                 {
  659.                     profilers.Sort(delegate (Profiler x, Profiler y)
  660.                     {
  661.                         return x.getSortPosition().CompareTo(y.getSortPosition());
  662.                     });
  663.                 }
  664.                 catch (Exception) { }
  665.  
  666.                 for (int i = 0; i < profilers.Count; i++)
  667.                 {
  668.                     Profiler p = profilers[i];
  669.  
  670.                     p.pre = "";
  671.                     if (p.depth > 0 && p.parent != null)
  672.                     {
  673.                         bool parent_has_future_siblings = false;
  674.                         bool has_future_siblings_under_parent = false;
  675.                         for (int b = i + 1; b < profilers.Count; b++)
  676.                         {
  677.                             if (profilers[b].depth == p.parent.depth) parent_has_future_siblings = true;
  678.                             if (profilers[b].depth == p.depth) has_future_siblings_under_parent = true;
  679.                             if (profilers[b].depth < p.depth) break;
  680.  
  681.                         }
  682.                         while (p.pre.Length < p.parent.depth)
  683.                         {
  684.                             if (parent_has_future_siblings) p.pre += "│";
  685.                             else p.pre += " ";
  686.                         }
  687.                         bool last = false;
  688.  
  689.                         if (!has_future_siblings_under_parent)
  690.                         {
  691.                             if (i < profilers.Count - 1)
  692.                             {
  693.                                 if (profilers[i + 1].depth != p.depth) last = true;
  694.                             }
  695.                             else last = true;
  696.                         }
  697.                         if (last) p.pre += "└";
  698.                         else p.pre += "├";
  699.  
  700.                         while (p.pre.Length < p.depth) p.pre += "─";
  701.  
  702.                         //if(!p.closed) p.pre = p.closed + p.pre;
  703.                         //p.pre = p.depth + p.pre;
  704.                     }
  705.                 }
  706.                 int mlen = 0;
  707.                 foreach (Profiler p in profilers) if (p.pre.Length + p.Name.Length > mlen) mlen = p.pre.Length + p.Name.Length;
  708.                 foreach (Profiler p in profilers)
  709.                 {
  710.                     p.post = "";
  711.                     int l = p.pre.Length + p.Name.Length + p.post.Length;
  712.                     if (l < mlen) p.post = new string('_', mlen - l);
  713.                 }
  714.             }
  715.             if (nevercalled) return "!!!!" + Name + "!!!!: NEVER CALLED!";
  716.  
  717.             /*string bsp = ""+getSortPosition();
  718.                     if (bsp.Length < 8) bsp = new string('0',8 - bsp.Length) + bsp;*/
  719.  
  720.             // return /*bsp+ */
  721.             return pre + Name + post + ": " + lastms.ToString("0.00") + ";" + average.ToString("0.00");
  722.         }
  723.         return "";
  724.     }
  725.     static public string getAllReports()
  726.     {
  727.         string r = "";
  728.         if (PROFILING_ENABLED)
  729.         {
  730.             foreach (Profiler watch in profilers)
  731.             {
  732.                 r += watch.getReport() + "\n";
  733.             }
  734.         }
  735.         if (stack.Count > 0)
  736.         {
  737.             r += "profile stack error:\n";
  738.             r += stack.Count + "\n";
  739.             foreach (var s in stack)
  740.             {
  741.                 r += s.Name + ",";
  742.             }
  743.         }
  744.         return r;
  745.     }
  746. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement