CsCheck/Causal.cs
/// <summary>Run causal profiling on a the code in action for a number of iterations or time.</summary>
/// <param name="action">The code to be causal profiled.</param>
/// <param name="iter">The number of iteration to collect statistics.</param>
/// <param name="time">The number of seconds to collect statistics.</param>
Run causal profiling on a the code in action for a number of iterations or time.
Run causal profiling on a the code in action for a number of iterations or time .
public static Result Profile(Action action, long iter = -1, int time = -1)
        {
            if (iter == -1) iter = Check.Iter;
            if (time == -1) time = Check.Time;
            int Run(RunType run, string name, int time)
            {
                runType = run;
                delayName = name;
                delayTime = time;
                onSince = 0L;
                delayCount = 0;
                totalDelay = 0L;
                var start = Stopwatch.GetTimestamp();
                action();
                return (int)(Stopwatch.GetTimestamp() - start - totalDelay);
            }
            Run(RunType.CollectTimes, null, 0);
            var summary = times.Select(i => i.Item1).Distinct().Select(i => new Result.Row { Region = i }).ToArray();
            times.Clear();
            for (int j = 0; j < SUMMARY_STAT_COUNT; j++)
            {
                var totalTimePct = Run(RunType.CollectTimes, null, 0) * Environment.ProcessorCount * 0.01;
                foreach (var row in summary)
                    foreach (var (s, t) in times)
                        if (row.Region == s)
                        {
                            row.Count++;
                            row.Time += t / totalTimePct;
                        }
                times.Clear();
            }
            var delays = new (string, int, MedianEstimator)[1 + 6 * summary.Length];
            delays[0] = (null, 0, new());
            int i = 1;
            foreach (var row in summary)
            {
                row.Count /= SUMMARY_STAT_COUNT;
                row.Time /= SUMMARY_STAT_COUNT;
                delays[i] = (row.Region, 5, new());
                delays[i + summary.Length] = (row.Region, -5, new());
                delays[i + summary.Length * 2] = (row.Region, 10, new());
                delays[i + summary.Length * 3] = (row.Region, -10, new());
                delays[i + summary.Length * 4] = (row.Region, -15, new());
                delays[i++ + summary.Length * 5] = (row.Region, -20, new());
            }
            if (time < 0)
            {
                for (i = 0; i < iter; i++)
                    foreach (var (name, delay, estimator) in delays)
                        estimator.Add(Run(RunType.Delay, name, delay));
            }
            else
            {
                long target = Stopwatch.GetTimestamp() + time * Stopwatch.Frequency;
                while (Stopwatch.GetTimestamp() < target)
                    foreach (var (name, delay, estimator) in delays)
                        estimator.Add(Run(RunType.Delay, name, delay));
            }
            runType = RunType.Nothing;
            MedianEstimate Estimate(int i) => new(delays[i].Item3);
            var totalPct = Estimate(0) * 0.01;
            for (i = 0; i < summary.Length; i++)
            {
                var row = summary[i];
                row.P5 = 100.0 - Estimate(1 + i) / totalPct;
                row.N5 = 100.0 - Estimate(1 + i + summary.Length) / totalPct;
                row.P10 = 100.0 - Estimate(1 + i + summary.Length * 2) / totalPct;
                row.N10 = 100.0 - Estimate(1 + i + summary.Length * 3) / totalPct;
                row.N15 = 100.0 - Estimate(1 + i + summary.Length * 4) / totalPct;
                row.N20 = 100.0 - Estimate(1 + i + summary.Length * 5) / totalPct;
            }
            return new Result { Rows = summary };
        }
public static Result Profile ( Action action , long iter = - 1 , int time = - 1 ) { if ( iter == - 1 ) iter = Check . Iter ; if ( time == - 1 ) time = Check . Time ; int Run ( RunType run , string name , int time ) { runType = run ; delayName = name ; delayTime = time ; onSince = 0L ; delayCount = 0 ; totalDelay = 0L ; var start = Stopwatch . GetTimestamp ( ) ; action ( ) ; return ( int ) ( Stopwatch . GetTimestamp ( ) - start - totalDelay ) ; } Run ( RunType . CollectTimes , null , 0 ) ; var summary = times . Select ( i => i . Item1 ) . Distinct ( ) . Select ( i => new Result . Row { Region = i } ) . ToArray ( ) ; times . Clear ( ) ; for ( int j = 0 ; j < SUMMARY_STAT_COUNT ; j ++ ) { var totalTimePct = Run ( RunType . CollectTimes , null , 0 ) * Environment . ProcessorCount * 0.01 ; foreach ( var row in summary ) foreach ( var ( s , t ) in times ) if ( row . Region == s ) { row . Count ++ ; row . Time += t / totalTimePct ; } times . Clear ( ) ; } var delays = new ( string , int , MedianEstimator ) [ 1 + 6 * summary . Length ] ; delays [ 0 ] = ( null , 0 , new ( ) ) ; int i = 1 ; foreach ( var row in summary ) { row . Count /= SUMMARY_STAT_COUNT ; row . Time /= SUMMARY_STAT_COUNT ; delays [ i ] = ( row . Region , 5 , new ( ) ) ; delays [ i + summary . Length ] = ( row . Region , - 5 , new ( ) ) ; delays [ i + summary . Length * 2 ] = ( row . Region , 10 , new ( ) ) ; delays [ i + summary . Length * 3 ] = ( row . Region , - 10 , new ( ) ) ; delays [ i + summary . Length * 4 ] = ( row . Region , - 15 , new ( ) ) ; delays [ i ++ + summary . Length * 5 ] = ( row . Region , - 20 , new ( ) ) ; } if ( time < 0 ) { for ( i = 0 ; i < iter ; i ++ ) foreach ( var ( name , delay , estimator ) in delays ) estimator . Add ( Run ( RunType . Delay , name , delay ) ) ; } else { long target = Stopwatch . GetTimestamp ( ) + time * Stopwatch . Frequency ; while ( Stopwatch . GetTimestamp ( ) < target ) foreach ( var ( name , delay , estimator ) in delays ) estimator . Add ( Run ( RunType . Delay , name , delay ) ) ; } runType = RunType . Nothing ; MedianEstimate Estimate ( int i ) => new ( delays [ i ] . Item3 ) ; var totalPct = Estimate ( 0 ) * 0.01 ; for ( i = 0 ; i < summary . Length ; i ++ ) { var row = summary [ i ] ; row . P5 = 100.0 - Estimate ( 1 + i ) / totalPct ; row . N5 = 100.0 - Estimate ( 1 + i + summary . Length ) / totalPct ; row . P10 = 100.0 - Estimate ( 1 + i + summary . Length * 2 ) / totalPct ; row . N10 = 100.0 - Estimate ( 1 + i + summary . Length * 3 ) / totalPct ; row . N15 = 100.0 - Estimate ( 1 + i + summary . Length * 4 ) / totalPct ; row . N20 = 100.0 - Estimate ( 1 + i + summary . Length * 5 ) / totalPct ; } return new Result { Rows = summary } ; }
Run causal profiling on a the code in action for a number of iterations or time.
Run causal profiling on a the code in action for a number of iterations or time .
action
Action
The code to be causal profiled.
The code to be causal profiled .
iter
long
The number of iteration to collect statistics.
The number of iteration to collect statistics .
time
int
The number of seconds to collect statistics.
The number of seconds to collect statistics .