[Solved] Weird issue in Console app


Ehem. I tried running the code at my HTPC, a different computer from the one I coded this on, and now I cannot reproduce the problem. That is, I do observe the burst leading to just a step, but that is due to a logical error in my code (when the report interval is reached it sets burst to -1). It’s hard to believe I did not set my breakpoint, stepped through, and saw the variable get destroyed, because I know how weird that would be and tried several times to be sure I saw what I thought I saw. But it’s also hard to believe I had stumbled upon such a weird and deep bug in the framework/clr, especially considering that my code had a bug that causes the thing that got me attaching the debugger in the first place..

In any case, I’ll mark it as closed. And post the revised code here if anyone wants to play with it. I’ve fixed the bug and made the output a bit more compact so it works better on less generous screens than the 22″ full-HD_one I did this on. It now uses 8 columns regardless of the console width, on the probably safe assumption that most people use standard 80-char width, into which 8 columns now fit.

If anyone would care run this and post their findings (just press P to quickly get stable frequencies, the step/burst thing is for silly stuff like seeing what the distribution looks like after fewer generations). On my HTPC, I get this result:

0x00 - 0x3f  0.34%
0x40 - 0x4f  0.73%
0x50 - 0x7f  0.34%
0x80 - 0xbf  0.44%
0xc0 - 0xff  0.34%

This means: Bytes 0x00 to 0x3f each made up 0.34% of all the bytes in all the guids generated (509,194 in this particular case, but I get this result every time with more than 100,000 guids or so). There are 3 very distinct groups, and maybe if I now go and read about Guids on wikipedia I will understand why that is. But it wouldn’t be as much fun to do this if my “discovery” was something I knew before I began. 🙂

using System;
using System.Diagnostics;
using System.Threading;

namespace ConsoleApplication1
{
    class Program
    {
        static bool running, exit;
        static int burst;
        static long guidCount = 0;
        static long[] counts = new long[256];
        static DateTime nextReport = DateTime.MinValue;
        static readonly TimeSpan reportInterval = TimeSpan.FromSeconds(1);


        static void Main(string[] args)
        {
            Console.WindowHeight = (int)(0.8 * Console.LargestWindowHeight);

            WriteLine(ConsoleColor.White, "X - Exit | P - Run/Pause | S - Step (hold for Slow) | B - Burst");
            WriteLine("Press P, S or B to make something happen.", reportInterval);

            Guid guid;
            byte[] bytes;

            var cursorPos = new CursorLocation();

            while (!exit)
            {
                if (Console.KeyAvailable)
                {
                    ProcessKey(Console.ReadKey(true));
                }

                if (running || burst > 0)
                {
                    guid = Guid.NewGuid();
                    bytes = guid.ToByteArray();
                    ++guidCount;

                    for (int i = 0; i < 16; i++)
                    {
                        var b = bytes[i];
                        ++counts[b];
                    }

                    if (burst > 0) --burst;

                    if (burst == 0 && DateTime.Now > nextReport)
                    {
                        cursorPos.MoveCursor();
                        ReportFrequencies();
                    }
                }
                else
                    Thread.Sleep(20);
            }
        }


        static void ProcessKey(ConsoleKeyInfo keyInfo)
        {
            switch (keyInfo.Key)
            {
                case ConsoleKey.P:
                    running = !running;
                    break;

                case ConsoleKey.B:
                    burst = 100;
                    break;

                case ConsoleKey.S:
                    burst = 1;
                    break;

                case ConsoleKey.X:
                    exit = true;
                    break;
            }
        }


        static void ReportFrequencies()
        {
            Write("\r\n{0} GUIDs generated. Frequencies (%):\r\n\r\n", guidCount);

            const int itemWidth = 11;
            const int colCount = 8; // Console.WindowWidth / (itemWidth + 2);

            for (int i = 0; i < 256; i++)
            {
                var f = (double)counts[i] / (16 * guidCount);
                var c = GetFrequencyColor(f);
                Write(c, RightAdjust(3, "{0:x}", i));
                Write(c, " {0:0.00}".PadRight(itemWidth), f*100);
                if ((i + 1) % colCount == 0) Write("\r\n");
            }

            nextReport = DateTime.Now + reportInterval;
        }


        static ConsoleColor GetFrequencyColor(double f)
        {
            if (f < 0.003) return ConsoleColor.DarkRed;
            if (f < 0.004) return ConsoleColor.Green;
            if (f < 0.005) return ConsoleColor.Yellow;
            return ConsoleColor.White;
        }


        static string RightAdjust(int w, string s, params object[] args)
        {
            if (args.Length > 0)
                s = string.Format(s, args);
            return s.PadLeft(w);
        }

        #region From my library, so I need not include that here...
        class CursorLocation
        {
            public int X, Y;
            public CursorLocation()
            {
                X = Console.CursorLeft;
                Y = Console.CursorTop;
            }

            public void MoveCursor()
            {
                Console.CursorLeft = X;
                Console.CursorTop = Y;
            }
        }


        static public void Write(string s, params object[] args)
        {
            if (args.Length > 0) s = string.Format(s, args);
            Console.Write(s);
        }


        static public void Write(ConsoleColor c, string s, params object[] args)
        {
            var old = Console.ForegroundColor;
            Console.ForegroundColor = c;
            Write(s, args);
            Console.ForegroundColor = old;
        }


        static public void WriteNewline(int count = 1)
        {
            while (count-- > 0) Console.WriteLine();
        }


        static public void WriteLine(string s, params object[] args)
        {
            Write(s, args);
            Console.Write(Environment.NewLine);
        }


        static public void WriteLine(ConsoleColor c, string s, params object[] args)
        {
            Write(c, s, args);
            Console.Write(Environment.NewLine);
        }
        #endregion
    }
}

Post your results, ladies and gentlemen. 🙂

1

solved Weird issue in Console app