CsCheck/Check.cs
/// <summary>Assert the first Func gives the same result and is faster than the second to a given sigma (defaults to 6) across a sample of input data.</summary>
/// <param name="gen">The input data generator.</param>
/// <param name="faster">The presumed faster code to test.</param>
/// <param name="slower">The presumed slower code to test.</param>
/// <param name="assertEqual">An assert test of if the faster and slower code returns an equal value (default Check.Equal).</param>
/// <param name="sigma">The sigma is the number of standard deviations from the null hypothosis (default 6).</param>
/// <param name="threads">The number of threads to run the code on (default number logical CPUs).</param>
/// <param name="repeat">The number of times to call each of the actions in each iteration if they are too quick to accurately measure (default 1).</param>
/// <param name="timeout">The number of seconds to wait before timing out (default 60).</param>
/// <param name="seed">The initial seed to use for the first iteration.</param>
/// <param name="raiseexception">If set an exception will be raised with statistics if slower is actually the fastest (default true).</param>
Assert the first Func gives the same result and is faster than the second to a given sigma (defaults to 6) across a sample of input data.
Assert the first Func gives the same result and is faster than the second to a given sigma ( defaults to 6 ) across a sample of input data .
public static FasterResult Faster<T, R>(this Gen<T> gen, Func<T, R> faster, Func<T, R> slower, Action<R, R> assertEqual = null,
            double sigma = -1.0, int threads = -1, int repeat = 1, int timeout = 60, string seed = null, bool raiseexception = true)
        {
            if (sigma == -1.0) sigma = Sigma;
            sigma *= sigma; 
            if (seed is null) seed = Seed;
            if (threads == -1) threads = Threads;
            if (threads == -1) threads = Environment.ProcessorCount;
            var r = new FasterResult { Median = new MedianEstimator() };
            var mre = new ManualResetEventSlim();
            Exception exception = null;
            while (threads-- > 0)
                ThreadPool.UnsafeQueueUserWorkItem(__ =>
                {
                    var pcg = seed is null ? PCG.ThreadPCG : PCG.Parse(seed);
                    ulong state = 0;
                    T t = default;
                    try
                    {
                        while (!mre.IsSet)
                        {
                            state = pcg.State;
                            t = gen.Generate(pcg, null, out _);
                            long tf = 0L, ts = 0L, st = 0L;
                            for (int i = 1; i < repeat; i++)
                            {
                                st = Stopwatch.GetTimestamp();
                                faster(t);
                                tf += Stopwatch.GetTimestamp() - st;
                                st = Stopwatch.GetTimestamp();
                                slower(t);
                                ts += Stopwatch.GetTimestamp() - st;
                                if (mre.IsSet) return;
                            }
                            st = Stopwatch.GetTimestamp();
                            var vf = faster(t);
                            tf += Stopwatch.GetTimestamp() - st;
                            st = Stopwatch.GetTimestamp();
                            var vs = slower(t);
                            ts += Stopwatch.GetTimestamp() - st;
                            if (mre.IsSet) return;
                            if (assertEqual is null)
                            {
                                if (!Equal(vf, vs))
                                {
                                    var vfs = Print(vf);
                                    vfs = vfs.Length > 30 ? "\nFaster=" + vfs : " Faster=" + vfs;
                                    var vss = Print(vs);
                                    vss = vss.Length > 30 ? "\nSlower=" + vss : " Slower=" + vss;
                                    exception = new CsCheckException("Return values differ: CsCheck_Seed = \"" + pcg.ToString(state) + "\"" + vfs + vss);
                                    mre.Set();
                                    return;
                                }
                            }
                            else
                            {
                                try
                                {
                                    assertEqual(vf, vs);
                                }
                                catch (Exception ex)
                                {
                                    exception = new CsCheckException("Return values differ: CsCheck_Seed = \"" + pcg.ToString(state) + "\"", ex);
                                    mre.Set();
                                    return;
                                }
                            }
                            r.Add(tf, ts);
                            if (r.SigmaSquared >= sigma) mre.Set();
                        }
                    }
                    catch (Exception e)
                    {
                        var tstring = Print(t);
                        if (tstring.Length > 100) tstring = tstring.Substring(0, 100);
                        exception = new CsCheckException("CsCheck_Seed = \"" + pcg.ToString(state) + "\" T=" + tstring, e);
                        mre.Set();
                    }
                }, null);
            var completed = mre.Wait(timeout * 1000);
            if (raiseexception)
            {
                if (!completed) throw new CsCheckException("Timeout! " + r.ToString());
                if (exception is not null || r.Slower > r.Faster || r.Median.Median < 0.0) throw exception ?? new CsCheckException(r.ToString());
            }
            return r;
        }
public static FasterResult Faster < T , R > ( this Gen < T > gen , Func < T , R > faster , Func < T , R > slower , Action < R , R > assertEqual = null , double sigma = - 1.0 , int threads = - 1 , int repeat = 1 , int timeout = 60 , string seed = null , bool raiseexception = true ) { if ( sigma == - 1.0 ) sigma = Sigma ; sigma *= sigma ; if ( seed is null ) seed = Seed ; if ( threads == - 1 ) threads = Threads ; if ( threads == - 1 ) threads = Environment . ProcessorCount ; var r = new FasterResult { Median = new MedianEstimator ( ) } ; var mre = new ManualResetEventSlim ( ) ; Exception exception = null ; while ( threads -- > 0 ) ThreadPool . UnsafeQueueUserWorkItem ( __ => { var pcg = seed is null ? PCG . ThreadPCG : PCG . Parse ( seed ) ; ulong state = 0 ; T t = default ; try { while ( ! mre . IsSet ) { state = pcg . State ; t = gen . Generate ( pcg , null , out _ ) ; long tf = 0L , ts = 0L , st = 0L ; for ( int i = 1 ; i < repeat ; i ++ ) { st = Stopwatch . GetTimestamp ( ) ; faster ( t ) ; tf += Stopwatch . GetTimestamp ( ) - st ; st = Stopwatch . GetTimestamp ( ) ; slower ( t ) ; ts += Stopwatch . GetTimestamp ( ) - st ; if ( mre . IsSet ) return ; } st = Stopwatch . GetTimestamp ( ) ; var vf = faster ( t ) ; tf += Stopwatch . GetTimestamp ( ) - st ; st = Stopwatch . GetTimestamp ( ) ; var vs = slower ( t ) ; ts += Stopwatch . GetTimestamp ( ) - st ; if ( mre . IsSet ) return ; if ( assertEqual is null ) { if ( ! Equal ( vf , vs ) ) { var vfs = Print ( vf ) ; vfs = vfs . Length > 30 ? " \n " + vfs : " " + vfs ; var vss = Print ( vs ) ; vss = vss . Length > 30 ? " \n " + vss : " " + vss ; exception = new CsCheckException ( " \" " + pcg . ToString ( state ) + " \" " + vfs + vss ) ; mre . Set ( ) ; return ; } } else { try { assertEqual ( vf , vs ) ; } catch ( Exception ex ) { exception = new CsCheckException ( " \" " + pcg . ToString ( state ) + " \" " , ex ) ; mre . Set ( ) ; return ; } } r . Add ( tf , ts ) ; if ( r . SigmaSquared >= sigma ) mre . Set ( ) ; } } catch ( Exception e ) { var tstring = Print ( t ) ; if ( tstring . Length > 100 ) tstring = tstring . Substring ( 0 , 100 ) ; exception = new CsCheckException ( " \" " + pcg . ToString ( state ) + " \" " + tstring , e ) ; mre . Set ( ) ; } } , null ) ; var completed = mre . Wait ( timeout * 1000 ) ; if ( raiseexception ) { if ( ! completed ) throw new CsCheckException ( " " + r . ToString ( ) ) ; if ( exception is not null || r . Slower > r . Faster || r . Median . Median < 0.0 ) throw exception ?? new CsCheckException ( r . ToString ( ) ) ; } return r ; }
Assert the first Func gives the same result and is faster than the second to a given sigma (defaults to 6) across a sample of input data.
Assert the first Func gives the same result and is faster than the second to a given sigma ( defaults to 6 ) across a sample of input data .
// using sigma as sigma squared now
Gen<T>
this
faster
Func<T, R>
The presumed faster code to test.
The presumed faster code to test .
slower
Func<T, R>
The presumed slower code to test.
The presumed slower code to test .
assertEqual
Action<R, R>
An assert test of if the faster and slower code returns an equal value (default Check.Equal).
An assert test of if the faster and slower code returns an equal value ( default Check . Equal ) .
sigma
double
The sigma is the number of standard deviations from the null hypothosis (default 6).
The sigma is the number of standard deviations from the null hypothosis ( default 6 ) .
threads
int
The number of threads to run the code on (default number logical CPUs).
The number of threads to run the code on ( default number logical CPUs ) .
repeat
int
The number of times to call each of the actions in each iteration if they are too quick to accurately measure (default 1).
The number of times to call each of the actions in each iteration if they are too quick to accurately measure ( default 1 ) .
timeout
int
The number of seconds to wait before timing out (default 60).
The number of seconds to wait before timing out ( default 60 ) .
seed
string
The initial seed to use for the first iteration.
The initial seed to use for the first iteration .
raiseexception
bool
If set an exception will be raised with statistics if slower is actually the fastest (default true).
If set an exception will be raised with statistics if slower is actually the fastest ( default true ) .
gen
The input data generator.
The input data generator .