<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:atom="https://www.w3.org/2005/Atom" xmlns:sy="https://purl.org/rss/1.0/modules/syndication/" xmlns:dc="https://purl.org/dc/elements/1.1/" xmlns:content="https://purl.org/rss/1.0/modules/content/" xmlns:wfw="https://wellformedweb.org/CommentAPI/" xmlns:slash="https://purl.org/rss/1.0/modules/slash/"
  version="2.0">
  <channel>
    <title>Feng Yuan (袁峰)</title>
    <atom:link
      href="https://docs.microsoft.com/archive/blogs/fyuan/feed.xml"
      rel="self"
      type="application/rss+xml" />
    <link>https://docs.microsoft.com/archive/blogs/fyuan/feed.xml</link>
    <description>CLR, Performance, Debugging, Parallel Computing, WPF, XPS, GDI, GDI+, Printing (www.fengyuan.com)</description>
    <lastBuildDate>Tue, 16 Apr 2019 05:07:06 GMT</lastBuildDate>
    <language>en-US</language>
    <sy:updatePeriod>hourly</sy:updatePeriod>
    <sy:updateFrequency>1</sy:updateFrequency>
    <item>
      <title>XPS Again</title>
      <link>https://docs.microsoft.com/archive/blogs/fyuan/xps-again</link>
      <pubDate>Wed, 12 Sep 2012 22:04:00 GMT</pubDate>
      <dc:creator><![CDATA[Feng Yuan]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/fyuan/2012/09/12/xps-again/</guid>
      <description><![CDATA[I needed to generate images for an HTML document I'm generating, for which I use create a...]]></description>
      <content:encoded><![CDATA[<p>I needed to generate images for an HTML document I'm generating, for which I use create a DrawingVisual and render it to a RenderTargetBitmap before saving to a PNG file. Now I would like to save the same visual to an XPS document. The benefit of having an XPS document is that you can zoom it at any size you wand or even print it out. So after working on the original XPS implementation seven years ago, I'm back with XPS again.</p>
<p>Here is the code I'm using:</p>
<pre>RenderTargetBitmap image = new RenderTargetBitmap(m_width, m_height, 96, 96, PixelFormats.Pbgra32);
                        
image.Render(m_visual);

string pngFile = fileName + ".png";

using (FileStream stream = new FileStream(pngFile, FileMode.Create))
{
    PngBitmapEncoder encoder = new PngBitmapEncoder();

    encoder.Frames.Add(BitmapFrame.Create(image));
    encoder.Save(stream);
}

string xpsFile = fileName + ".xps";

using (Package container = Package.Open(xpsFile, FileMode.Create))
{
    using (XpsDocument xpsDoc = new XpsDocument(container, CompressionOption.Maximum))
    {
         XpsDocumentWriter writer = XpsDocument.CreateXpsDocumentWriter(xpsDoc);

         VisualPaginator page = new VisualPaginator(m_visual, m_width, m_height);

         writer.Write(page);
    }
}
</pre>
<p>&nbsp;Although XpsDocumentWriter can directly handle an Visual as input, there is no easy way to specifiy a custom page size. So I'm using a VisualPaginator class:</p>
<pre>public class VisualPaginator : DocumentPaginator
{
    Size   m_size;
    Visual m_visual;

    public VisualPaginator(Visual visual, double width, double height)
    {
        m_visual = visual;
        m_size   = new Size(width, height);
    }

    public override IDocumentPaginatorSource Source 
    {
        get 
        { 
            return null; 
        }
    }

    public override DocumentPage GetPage(int pageNumber)
    {
        Rect box = new Rect(0, 0, m_size.Width, m_size.Height);

        return new DocumentPage(m_visual, m_size, box, box);
    }

    public override bool IsPageCountValid
    {
        get 
        { 
            return true; 
        }
    }

    public override int PageCount
    {
        get 
        { 
            return 1; 
        }
    }

    public override System.Windows.Size PageSize
    {
        get
        {
            return m_size;
        }
        set
        {
            m_size = value;
        }
    }

}
</pre>
<p>&nbsp;</p>
<p>&nbsp;</p>]]></content:encoded>
    </item>
    <item>
      <title>Performance Tips: Faster than StringBuilder?</title>
      <link>https://docs.microsoft.com/archive/blogs/fyuan/performance-tips-faster-than-stringbuilder</link>
      <pubDate>Tue, 14 Aug 2012 23:02:00 GMT</pubDate>
      <dc:creator><![CDATA[Feng Yuan]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/fyuan/2012/08/14/performance-tips-faster-than-stringbuilder/</guid>
      <description><![CDATA[The web has tons of articles about how StringBuilder is much faster than string concatenation using...]]></description>
      <content:encoded><![CDATA[<p>The web has tons of articles about how StringBuilder is much faster than string concatenation using '+' operator or String.Concat functions when there are enough strings to ber merged. Here is an MSDN article on this topic: <a href="https://support.microsoft.com/kb/306822">https://support.microsoft.com/kb/306822</a></p>
<p>But actually, if all you want is concatenating strings, there is a more efficient way of doing so, the String.Join method. String.Join is more efficient in both memory and CPU. Here is a test program:</p>
<pre><code class="csharp"> const int sLen = 30, Loops = 5000;<br /> <br /> System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch();<br /> <br /> string sSource = new String('X', sLen);<br /> string sDest = "";<br /> <br /> // Time string concatenation.<br /> // <br /> watch.Restart();<br /> for (int i = 0; i &lt; Loops; i++) sDest += sSource;<br /> watch.Stop();<br /> Console.WriteLine("Concatenation took {0,8:N3} ms. {1} chars", watch.Elapsed.TotalMilliseconds, sDest.Length);<br /> <br /> // Time StringBuilder.<br /> // <br /> watch.Restart();<br /> System.Text.StringBuilder sb = new System.Text.StringBuilder(sLen * Loops);<br /> for (int i = 0; i &lt; Loops; i++) sb.Append(sSource);<br /> sDest = sb.ToString();<br /> watch.Stop();<br /> Console.WriteLine("StringBuilder took {0,8:N3} ms. {1} chars", watch.Elapsed.TotalMilliseconds, sDest.Length);<br /> <br /> // Time String.Join.<br /> // <br /> watch.Restart();<br /> string[] list = new string[Loops];<br /> for (int i = 0; i &lt; Loops; i++) list[i] = sSource;<br /> sDest = String.Join(String.Empty, list, 0, Loops);<br /> watch.Stop();<br /> Console.WriteLine("String.Join took {0,8:N3} ms. {1} chars", watch.Elapsed.TotalMilliseconds, sDest.Length);<br /> </code></pre>
<p>&nbsp;Result:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</p>
<pre class="scroll"><code class="csharp"> Concatenation took 524.630 ms. 150000 chars<br /> StringBuilder took 0.426 ms. 150000 chars<br /> String.Join took 0.310 ms. 150000 chars</code></pre>
<p>StringBuilder.Append takes 0.426 ms, copying string data twice. String.Join takes 0.310 ms, 27% less, copying string data only once.</p>
<p>StringBuilder uses 300 kb (30 * 5000 * 2) extra memory (in StringBuilder object), String.Join only uses 20 kb (5000 * pointer size) extra memory (in list).</p>
<p>So, if you only need to merge full strings, give String.Join a try. But StringBuilder is much much&nbsp;more powerful than just merging full strings.</p>]]></content:encoded>
    </item>
    <item>
      <title>Performance Tips: System.Text.StringBuilder and String.Concat</title>
      <link>https://docs.microsoft.com/archive/blogs/fyuan/performance-tips-system-text-stringbuilder-and-string-concat</link>
      <pubDate>Sun, 12 Aug 2012 22:05:00 GMT</pubDate>
      <dc:creator><![CDATA[Feng Yuan]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/fyuan/2012/08/12/performance-tips-system-text-stringbuilder-and-string-concat/</guid>
      <description><![CDATA[Much has been written about the benefits of using StringBuilder over string concatenation. So much...]]></description>
      <content:encoded><![CDATA[<p>Much has been written about the benefits of using StringBuilder over string concatenation. So much so that there seems to be overuse of StringBuilder class, causing performance issues again.</p>
<p>If you're using StringBuilder and string concatenation a lot in your program, here are a few more things to ponder:</p>
<ol>
<li>String.Concat(str1, str2) is a perfect string concatenation function for two strings, so do not use StringBuilder for two strings.</li>
<li>String.Concat(str1, str2, str3) and String.Concat(str1, str2, str3, str4) are almost perfect for concatenating three or four strings. Do not use StringBuiider for those cases.</li>
<li>Even if your code has complicated conditions to determine the strings to concatenate, as long as they're no more than 4 strings, it still pays to use string addition or String.Concat. You can have empty strings in the expression.</li>
<li>If you're concatenate an array of strings, String.Join(<span style="color: blue;">string</span> separator, <span style="color: blue;">string</span>[] value, <span style="color: blue;">int</span> startIndex, <span style="color: blue;">int</span> count) is the perfect method for them.</li>
<li>String Concat works best when all operands are string objects, non-objects will be boxed, non strings will be converted to String using ToString() method. Try to avoid such conversions. For example, path + '\\' + filename should be converted to path + "\\" + filename.</li>
<li>Do not use StringBuilder.Append(expr1 + expr2 + expr3), use Append(expr1).Append(expr2).Append(expr3) instead.</li>
<li>StringBuilder.ToString always generate a new string, be aware of possible string duplications. As comparison, String.Concat(str1, str2) does not generate a new string if either operand is empty.</li>
<li>When StringBuilder is out of memory, it allocates a new array of its current size, thus doubling its capacity. So on average, 25% space is wasted unless you specify the right size for it.</li>
<li>String.Format is implemented using StringBuilder.AppendFormat. Do not use it for simple formatting expressions like "{0}.{1}". It's much better to use expr1 + "." + expr2. Exception to this rule: the format strings need to be put into a resource code for things like customization/localization.</li>
<li>If StringBuilder is used often, consider recycle it for reuse, instead of re-creating them everytime. Be careful about possible threading issues. This is one of the optimization implemented in .Net 4.5.</li>
</ol>
<p>Examples:</p>
<p>Bad</p>
<p><span style="font-family: courier new,courier;">&nbsp;&nbsp;&nbsp; String.Format("{0}.{1}", DeclaringType.FullName, Name) </span></p>
<p><span style="font-family: courier new,courier;">Better</span></p>
<p><span style="font-family: courier new,courier;">&nbsp;&nbsp;&nbsp; DeclaringType.FullName + "." +&nbsp;Name</span></p>
<p><span style="font-family: courier new,courier;">Bad:</span></p>
<p><span style="font-family: courier new,courier;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; StringBuilder sb = new StringBuilder();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bool first = true;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (GetFlag((int) PolicyStatementAttribute.Exclusive ))<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sb.Append( "Exclusive" );<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; first = false;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (GetFlag((int) PolicyStatementAttribute.LevelFinal ))<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (!first)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sb.Append( " " );<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sb.Append( "LevelFinal" );<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return sb.ToString();<br /></span><span style="font-family: courier new,courier;"></span></p>
<p><span style="font-family: courier new,courier;">This version is more costly for several reasons:</span></p>
<ol>
<li><span style="font-family: courier new,courier;">StringBuilder object is created.</span></li>
<li><span style="font-family: courier new,courier;">Strings are copied when calling StringBuilder.Append</span></li>
<li><span style="font-family: courier new,courier;">No size is given, so a smaller buffer is allocated automatically and then new allocations are made during Append calls.</span></li>
<li><span style="font-family: courier new,courier;">A new string is always generated, even if it's just either "Exclusive" or "LevelFinal".</span></li>
</ol>
<p><span style="font-family: courier new,courier;">Better: if you use string + operator, there will be no StringBuilder object, no extra copy, no new buffer allocation, and best of all no new string is generated if it's just a single word.</span></p>
<p><span style="font-family: courier new,courier;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String p1 = null;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String p2 = null;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String p3 = null;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (GetFlag((int) PolicyStatementAttribute.Exclusive))<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; p1 = "Exclusive";<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (GetFlag((int) PolicyStatementAttribute.LevelFinal))<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (p1 != null)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; p2 = " ";<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; p3 = "LevelFinal";<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return p1 + p2 + p3;<br /></span></p>]]></content:encoded>
    </item>
    <item>
      <title>Performance Tips: String.Split</title>
      <link>https://docs.microsoft.com/archive/blogs/fyuan/performance-tips-string-split</link>
      <pubDate>Sun, 12 Aug 2012 21:05:46 GMT</pubDate>
      <dc:creator><![CDATA[Feng Yuan]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/fyuan/2012/08/12/performance-tips-string-split/</guid>
      <description><![CDATA[String.Split methods are provided in .Net as a convenient way of dividing string into parts. Here...]]></description>
      <content:encoded><![CDATA[<p>String.Split methods are provided in .Net as a convenient way of dividing string into parts. Here are two basic forms of String.Split methods:</p>
<p><span style="color: blue;">public</span> <span style="color: blue;">string</span>[] Split(<span style="color: blue;">char</span>[] separator, <span style="color: blue;">int</span> count, StringSplitOptions options);</p>
<p><span style="color: blue;">public</span> <span style="color: blue;">string</span>[] Split(<span style="color: blue;">string</span>[] separator, <span style="color: blue;">int</span> count, StringSplitOptions options);</p>
<p>Also String.Split methods are quite easy to use, there are hidde performance issues you should be aware of if you use them a lot:</p>
<ol>
<li>The first parameter is an array of characters, or array of strings. If the same seperators are used over and over again, do not recreate the seperator array in each call; create once and reuse them.</li>
<li>The second paramter is maximum number of segments to return. If your scenario, pass-in the right value will limit the amount of work Split has to do.</li>
<li>If you do not want empty items, use StringSplitOptions.RemoveEmptyEntries so they do not need to be stored.</li>
<li>String.Split allocates internal workspace according to the length of the string, beware that this can create lots of garbage for long strings. Avoiding calling String.Split for really long strings.</li>
<li>If there is a high chance of the seperators not present in the string at all, check for this condition and handle seperately before calling String.Split.</li>
<li>As String.Split returns all the strings through the string array, they will be held in memory until there is no reference to the array. Try to limit this duration, otherwise more strings will be promoted to Generation 1 or Generation 2. It will be a good idea to null references to processed strings in the array.t</li>
<li>If you're using String.Split to process a large file or stream, there will be lots of duplicated strings. Try not to store those strings directly in your data structure. Instead, convert them to low cost versions, e.g. scalar values; or merge them into unique strings.</li>
<li>If your data is supposed to be not case sensitive, do not try to call String.ToLower/ToUpper on strings returned from String.Split, use non-case sensitive containers or non-case sensitive comparisons.</li>
<li>If you suspect String.Split is causing performance issue for your scenarios, measure performance using tools like PerfView.</li>
<li>If performance is still not optimal after these optimizations, avoid using String.Split or reimplement your own versions.</li>
</ol>]]></content:encoded>
    </item>
    <item>
      <title>TextWriter.WriteLine(string, object[]) in less memory, less time</title>
      <link>https://docs.microsoft.com/archive/blogs/fyuan/textwriter-writelinestring-object-in-less-memory-less-time</link>
      <pubDate>Sat, 04 Aug 2012 23:08:00 GMT</pubDate>
      <dc:creator><![CDATA[Feng Yuan]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/fyuan/2012/08/04/textwriter-writelinestring-object-in-less-memory-less-time/</guid>
      <description><![CDATA[I found myself increasingly generating reports in .csv format, and then use Excel to analyze the...]]></description>
      <content:encoded><![CDATA[<p>I found myself increasingly generating reports in .csv format, and then use Excel to analyze the reports. With large amount of data written to the .csv file, file generation time becomes more and more noticable. So I took some time to check what is taking so much time and how can it be reduced.</p>
<p>For one .csv file I'm generating, the report generation is essentially a big loop with tons of TextWriter.WriteLine calls:</p>
<pre>static public void Version0()
{
    for (int i = 0; i &lt; count; i++)
    {
        writer.WriteLine(
            "\"{0:x8}\",{1},{2},\"{3}\",\"{4}\",\"{5}\"",
            Data.Column1(i), Data.Column2(i), Data.Column3(i),
            Data.Column4(i), Data.Column5(i), Data.Column6(i));
    }
}
</pre>
<p><span style="font-family: andale mono,times;">Profiling shows that TextWriter.WriteLine(string, object[]) forms a string first, and then calls WriteLine(string). But the latter allocates&nbsp;a char array for the string plus "\r\n", sending combined data to the basestream. It's nice that the lines would now be completed in a single call, but there is extra memory and CPU cost. Given that we're not writing to a console, and there is only a single writer, here is the next version:</span></p>
<pre>static public void Version1()
{
    for (int i = 0; i &lt; count; i++)
    {
        writer.Write(
            "\"{0:x8}\",{1},{2},\"{3}\",\"{4}\",\"{5}\"",
            Data.Column1(i), Data.Column2(i), Data.Column3(i),
            Data.Column4(i), Data.Column5(i), Data.Column6(i));

        writer.WriteLine();
    }
}
</pre>
<p><span style="font-family: andale mono,times;">The change here is quite simple: splitting a single WriteLine call into two calls, char[] allocation is gone. Now the program is that TextWriter is creating a StringBuilder to form the output string, and string is converted to char[] before writing to the base stream. Given that it's important to our scenario, we can remove those extra cost too:</span></p>
<p></p>
<pre>static public void Version2()
{
    StringBuilder sb = new StringBuilder(512);
    char[] buffer = new char[512];

    for (int i = 0; i &lt; count; i++)
    {
        sb.Clear();
        sb.AppendFormat(
            "\"{0:x8}\",{1},{2},\"{3}\",\"{4}\",\"{5}\"",
            Data.Column1(i), Data.Column2(i), Data.Column3(i),
            Data.Column4(i), Data.Column5(i), Data.Column6(i));

        sb.CopyTo(0, buffer, 0, sb.Length);
        writer.Write(buffer, 0, sb.Length);
        writer.WriteLine();
    }
}
</pre>
<p><span style="font-family: andale mono,times;">In this version, a StringBuilder and char[] array is created outside of the loop, and reused for each line in the .csv file. After a line is formed in the StringBuilder, we copy the result to the char[] array instead of converting it to string first.</span></p>
<p><span style="font-family: andale mono,times;">At this stage, the biggest spender is calling AppendFormat. To pass data for the 6 columns to AppendFormat, C# generates code to allocate an Object[] array, and then boxes up three integers. Within AppendFormat implementation, Int32.ToString method is called to convert integers to string with invariant culture info. It will cost less memory and CPU to call ToString outselves:</span></p>
<pre>static public void Version3()
{
    StringBuilder sb = new StringBuilder(512);
    char[] buffer = new char[512];

    CultureInfo info = CultureInfo.InvariantCulture;
                        
    for (int i = 0; i &lt; count; i++)
    {
        sb.Clear();
        sb.AppendFormat(
            "\"{0}\",{1},{2},\"{3}\",\"{4}\",\"{5}\"",
            Data.Column1(i).ToString("x8", info),
            Data.Column2(i).ToString(info),
            Data.Column3(i).ToString(info),
            Data.Column4(i), Data.Column5(i), Data.Column6(i));

        sb.CopyTo(0, buffer, 0, sb.Length);
        writer.Write(buffer, 0, sb.Length);
        writer.WriteLine();
    }
}
</pre>
<p><span style="font-family: andale mono,times;">If you profile the latest code again, you will find the three ToString calls consumes the most memory and CPU, it's time to replace them:</span></p>
<pre>static public void Version4()
{
    StringBuilder sb = new StringBuilder(512);
    char[] buffer = new char[512];

    CultureInfo info = CultureInfo.InvariantCulture;

    for (int i = 0; i &lt; count; i++)
    {
        sb.Clear();

        sb.Append('"');
        sb.AppendInt32(Data.Column1(i), 16, 8);
        sb.Append("\",");

        sb.AppendInt32(Data.Column2(i));
        sb.Append(',');

        sb.AppendInt32(Data.Column3(i));
        sb.Append(",\"");

        sb.Append(Data.Column4(i));
        sb.Append("\",\"");

        sb.Append(Data.Column5(i));
        sb.Append("\",\"");

        sb.Append(Data.Column6(i));
        sb.Append('"');

        sb.CopyTo(0, buffer, 0, sb.Length);
        writer.Write(buffer, 0, sb.Length);
        writer.WriteLine();
    }
}
</pre>
<p>If you wonder how much memory and CPU can these changes save us, here is the performance test result:</p>
<pre>WriteLine.exe

       WriteLine x  1,000,000   1292.942 ms 161 gc,  1,829,516 bytes
           Write x  1,000,000    989.864 ms 122 gc,  2,527,544 bytes
   StringBuilder x  1,000,000    925.884 ms  84 gc,    985,392 bytes
        ToString x  1,000,000    778.161 ms  43 gc,    415,552 bytes
       AppendInt x  1,000,000    638.102 ms   0 gc,    423,744 bytes
</pre>
<p>When generating a .csv file of 1 million rows, the original version takes 1.292 seconds, causing 161 garbage collections, and the final heap has 1.829 mb allocations. Subsequent versions reduce memory allocations and CPU time at the same time. The final version finishes in 0.638 seconds with not a single garbage collection. This indicates that the final version does not allocate any managed memory in the big loop.</p>
<p>Here&nbsp; are CPU sample events displayed in <a href="https://blogs.msdn.com/b/vancem/archive/2012/06/21/next-version-of-perfview-has-been-released.aspx">PerfView</a>:</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/37/15/3835.sample.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-37-15/3835.sample.png"><img border="0" alt="" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/37/15/3835.sample.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-37-15/3835.sample.png" /></a></p>
<p>Total program run takes 5.218 seconds, the original version takes 1.36 seconds (25.2% of total time), the final version takes 0.673 seconds.</p>
<p>Here are the CLR memory allocation tick events displayed in PerfView:</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/37/15/7652.aalloc.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-37-15/7652.aalloc.png"><img border="0" alt="" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/37/15/7652.aalloc.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-37-15/7652.aalloc.png" /></a></p>
<p>Total program run allocates 1.296 Gb of memory. The original version allocates 511 mb memory, StringBuilder.ToString allocates 130 mb, TextWrite.WriteLine allocates 117 mb. The final version (Version4) is not even shown here. CLR memory allocation tick event is fired once for every 100kb memory allocation or when big objects are allocated. Version4 only allocates a few small objects before entering the big loop, not enough to fire an event.</p>]]></content:encoded>
    </item>
    <item>
      <title>Problem: Better way to remove characters that aren't 32 to 175</title>
      <link>https://docs.microsoft.com/archive/blogs/fyuan/problem-better-way-to-remove-characters-that-arent-32-to-175</link>
      <pubDate>Wed, 18 Jul 2012 21:57:00 GMT</pubDate>
      <dc:creator><![CDATA[Feng Yuan]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/fyuan/2012/07/18/problem-better-way-to-remove-characters-that-arent-32-to-175/</guid>
      <description><![CDATA[There is a question on StackOverflow.com about better ways to remove characters in a string that are...]]></description>
      <content:encoded><![CDATA[<p>There is a question on StackOverflow.com about better ways to remove characters in a string that are outside the range of 32 to 175.</p>
<p>Quite a few fancy solutions are provided:</p>
<ol>
<li><span class="typ">Regex</span><span class="pun">.</span><span class="typ">Replace</span><span class="pun">(</span><span class="pln">myString</span><span class="pun">,</span><span class="pln"> </span><span class="str">@"[^\x20-\xaf]+"</span><span class="pun">,</span><span class="pln"> </span><span class="str">""</span><span class="pun">);</span></li>
<li><span class="pun"></span><span class="pln"><span class="kwd">new</span><span class="pln"> </span><span class="kwd">string</span><span class="pun">(</span><span class="pln">myString</span><span class="pun">.</span><span class="typ">Where</span><span class="pun">(</span><span class="pln">c </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">(</span><span class="pln">c </span><span class="pun">&gt;=</span><span class="pln"> </span><span class="lit">32</span><span class="pun">)</span><span class="pln"> </span><span class="pun">&amp;&amp;</span><span class="pln"> </span><span class="pun">(</span><span class="pln">c </span><span class="pun">&lt;=</span><span class="pln"> </span><span class="lit">175</span><span class="pun">)).</span><span class="typ">ToArray</span><span class="pun">());</span></span></li>
<li><span class="pln"><span class="pun"></span><span class="pln"><span class="kwd">string</span><span class="pln"> text </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">from</span><span class="pln"> c </span><span class="kwd">in</span><span class="pln"> myString&nbsp;</span><span class="pln">let i </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">int</span><span class="pun">)</span><span class="pln"> c where i </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">32</span><span class="pln"> </span><span class="pun">&amp;&amp;</span><span class="pln"> i </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">175</span><span class="pln"> </span><span class="kwd">select</span><span class="pln"> c</span><span class="pun">)</span><span class="pln">&nbsp;</span><span class="pun">.</span><span class="typ">Aggregate</span><span class="pun">(</span><span class="str">""</span><span class="pun">,</span><span class="pln"> </span><span class="pun">(</span><span class="pln">current</span><span class="pun">,</span><span class="pln"> c</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> current </span><span class="pun">+</span><span class="pln"> c</span><span class="pun">);</span><span class="pln">&nbsp;</span>&nbsp;</span>&nbsp;</span></li>
</ol>
<p><span class="pln">The fastest solution is filtering while walkng through the string and build result using StringBuilder. But there are still places this can be improved. So here would be my solution:</span></p>
<!-- code formatted by https://manoli.net/csharpformat/ -->
<pre class="csharpcode"><span class="kwrd">static</span> <span class="kwrd">unsafe</span> <span class="kwrd">string</span> TrimRange(<span class="kwrd">string</span> str, <span class="kwrd">char</span> <span class="kwrd">from</span>, <span class="kwrd">char</span> to)
{
    <span class="kwrd">int</span> count = 0;

    <span class="kwrd">for</span> (<span class="kwrd">int</span> i = 0; i &lt; str.Length; i++)
    {
        <span class="kwrd">char</span> ch = str[i];

        <span class="kwrd">if</span> ((ch &gt;= <span class="kwrd">from</span>) &amp;&amp; (ch &lt;= to))
        {
            count++;
        }
    }

    <span class="kwrd">if</span> (count == 0)
        <span class="kwrd">return</span> String.Empty;

    <span class="kwrd">if</span> (count == str.Length)
        <span class="kwrd">return</span> str;

    <span class="kwrd">char</span> * result = <span class="kwrd">stackalloc</span> <span class="kwrd">char</span>[count];

    count = 0;

    <span class="kwrd">for</span> (<span class="kwrd">int</span> i = 0; i &lt; str.Length; i++)
    {
        <span class="kwrd">char</span> ch = str[i];

        <span class="kwrd">if</span> ((ch &gt;= <span class="kwrd">from</span>) &amp;&amp; (ch &lt;= to))
        {
            result[count ++] = ch;
        }
    }

    <span class="kwrd">return</span> <span class="kwrd">new</span> String(result, 0, count);
}
</pre>
<p>The idea is quite simple: allocate managed memory only when really need.</p>
<p></p>]]></content:encoded>
    </item>
    <item>
      <title>Drawing bearing and distance property line using C#/SVG/IE9/Visio (V2)</title>
      <link>https://docs.microsoft.com/archive/blogs/fyuan/drawing-bearing-and-distance-property-line-using-csvgie9visio-v2</link>
      <pubDate>Wed, 01 Jun 2011 06:52:00 GMT</pubDate>
      <dc:creator><![CDATA[Feng Yuan]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/fyuan/2011/06/01/drawing-bearing-and-distance-property-line-using-csvgie9visio-v2/</guid>
      <description><![CDATA[Here is&nbsp;expanded version of&nbsp; my little&nbsp;C# program which converts property description...]]></description>
      <content:encoded><![CDATA[<p>Here is&nbsp;expanded version of&nbsp; my little&nbsp;C# program which converts property description in bearing and distance to SVG, which can then be viewed by IE9 or imported into Microsoft Visio:</p>
<p style="padding-left: 30px;"><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Components.PostAttachments/00/10/17/03/00/Program2E00cs" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-components-postattachments/00-10-17-03-00/Program_2E00_cs">Program.cs</a> (attached)</p>
<p>New features:</p>
<ul>
<li>endpath command to end a path with stroking</li>
<li>closepath command to end a path with stroking and filling</li>
<li>p command to store reference points</li>
<li>r command to recall reference points</li>
<li>Parsing and SVG generation seperated into two classes. We can later add generation of other formats.</li>
</ul>
<p>Sample input (two properties):</p>
<p style="padding-left: 30px;"><span style="font-family: courier new,courier;">S 893511 E 235.70</span><br /><span style="font-family: courier new,courier;">S 193826 E 28.68</span><br /><span style="font-family: courier new,courier;">endpath</span><br /><span style="font-family: courier new,courier;">S 614605 E 128.70</span><br /><span style="font-family: courier new,courier;">S 395224 E 72</span><br /><span style="font-family: courier new,courier;">S 340452 W 157.98</span><br /><span style="font-family: courier new,courier;">P0</span><br /><span style="font-family: courier new,courier;">N 534354 W 79.51</span><br /><span style="font-family: courier new,courier;">N 172709 w 87.74</span><br /><span style="font-family: courier new,courier;">n 652125 E 9.6</span><br /><span style="font-family: courier new,courier;">N 052600 E 112.75</span><br /><span style="font-family: courier new,courier;">closepath</span><br /><span style="font-family: courier new,courier;">R0</span><br /><span style="font-family: courier new,courier;">S 534354 E 75.40</span><br /><span style="font-family: courier new,courier;">S 063835 W 66.10</span><br /><span style="font-family: courier new,courier;">S 570654 E 64.04</span><br /><span style="font-family: courier new,courier;">N 535505 E 104.10</span><br /><span style="font-family: courier new,courier;">N 535505 E 52.90</span><br /><span style="font-family: courier new,courier;">N 382302 W 233.98</span><br /><span style="font-family: courier new,courier;">closepath</span></p>
<p><span style="font-family: courier new,courier;">Sample output:</span></p>
<p><span style="font-family: courier new,courier;"><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/37/15/0844.h31.gif" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-37-15/0844.h31.gif"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/37/15/0844.h31.gif" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-37-15/0844.h31.gif" border="0" /></a></span></p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Components.PostAttachments/00/10/17/03/00/Program.cs" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-components-postattachments/00-10-17-03-00/Program.cs">Program.cs</a></p>]]></content:encoded>
    </item>
    <item>
      <title>Drawing bearing and distance property line using C#/SVG/IE9.</title>
      <link>https://docs.microsoft.com/archive/blogs/fyuan/drawing-bearing-and-distance-property-line-using-csvgie9</link>
      <pubDate>Mon, 30 May 2011 14:30:00 GMT</pubDate>
      <dc:creator><![CDATA[Feng Yuan]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/fyuan/2011/05/30/drawing-bearing-and-distance-property-line-using-csvgie9/</guid>
      <description><![CDATA[If you read an official property legal desciption, property line are often described using bearing...]]></description>
      <content:encoded><![CDATA[<p>If you read an official property legal desciption, property line are often described using bearing and distance. Here is an example:</p>
<p>BEGINGING AT THE NORTHWEST CORNER OF SAID SOUTHWEST QUARTER OF THE SOUTHWEST QUARTER OF SECTION 9; THENCE SOUTH 89&deg;35'11" EAST; 246.35 FEET ALONG THE NORTH LINE THEREOF; THENCE SOUTH 19&deg;38'26" EAST, 36.08 FEET; ...</p>
<p>For each segment, the bearing part (e.g. <strong>SOUTH 89&deg;35'11" EAST</strong>) specifies the direction of the line, which is followed by the length of the line. The relative degree of the line is specific using sexagesimal system (base-60, degree/minute/second). So&nbsp;<strong>89&deg;35'11"</strong> is really 89 + 35 / 60 + 11 / 3600 degrees.&nbsp;<strong>SOUTH 89&deg;35'11" EAST </strong>means starting from south direction, turning 89.586 degrees to east.</p>
<p>Sometimes you can find a nicely drawn diagram (e.g. plat diagram, often as an TIFF image), but sometimes you just have the textual description and nothing else. The later is often the case in easement documents. Now the problem is how to convert such description into something we can visualize easily; </p>
<p>Here is a simple C# program which converts bearing and distance property description into SVG format, viewable using IE 9 (file attachment Program.cs).</p>
<p>Sample Input file:</p>
<p style="padding-left: 30px;">S 893511 E 246.35<br />S 193826 E 36.08<br />S 614605 E 113.79<br />S 492357 W 87.36<br />N 843400 W 58<br />N 052600 E 112.75<br />N 193826 w 18.03<br />n 893511 w 239.2</p>
<p>SVG output generated by the program:</p>
<pre><p style="padding-left: 30px;">&lt;?xml version="1.0" standalone="no"?&gt;<br />&lt;!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"&nbsp; "<a href="https://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">https://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd</a>"&gt;<br />&lt;svg width="640" height="480" viewBox="0 0 358.724254050077 146.439267225064" xmlns="<a href="https://www.w3.org/2000/svg">https://www.w3.org/2000/svg</a>" version="1.1"&gt;<br />&lt;line x1="0" y1="0" x2="400" y2="0" style="stroke:black;stroke-width:0.5;stroke-dasharray:1,1"/&gt;<br />&lt;line x1="0" y1="100" x2="400" y2="100" style="stroke:black;stroke-width:0.5;stroke-dasharray:1,1"/&gt;<br />&lt;line x1="0" y1="200" x2="400" y2="200" style="stroke:black;stroke-width:0.5;stroke-dasharray:1,1"/&gt;<br />&lt;line x1="0" y1="0" x2="0" y2="200" style="stroke:black;stroke-width:0.5;stroke-dasharray:1,1"/&gt;<br />&lt;line x1="100" y1="0" x2="100" y2="200" style="stroke:black;stroke-width:0.5;stroke-dasharray:1,1"/&gt;<br />&lt;line x1="200" y1="0" x2="200" y2="200" style="stroke:black;stroke-width:0.5;stroke-dasharray:1,1"/&gt;<br />&lt;line x1="300" y1="0" x2="300" y2="200" style="stroke:black;stroke-width:0.5;stroke-dasharray:1,1"/&gt;<br />&lt;line x1="400" y1="0" x2="400" y2="200" style="stroke:black;stroke-width:0.5;stroke-dasharray:1,1"/&gt;<br />&lt;path d="M 0 0<br />&nbsp; l 246.343581111762 1.77835458583686<br />&nbsp; l 12.1271482740708 33.9808574750359<br />&nbsp; l 100.253524664245 53.8274548199679<br />&nbsp; l -66.3291145282373 56.8526003442234<br />&nbsp; l -57.7394086754221 -5.49187452629729<br />&nbsp; l 10.6760147041382 -112.243419450928<br />&nbsp; l -6.0602129540326 -16.9810105397699<br />&nbsp; l -239.193767411948 -1.72674007279144<br />z" fill="yellow" fill-opacity="0.5" stroke="black" stroke-width="1" /&gt;<br />&lt;/svg&gt;</p>
</pre>
<p>SVG output rendered by IE9</p>
<p style="padding-left: 30px;"><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/37/15/4073.east.gif" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-37-15/4073.east.gif"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/37/15/4073.east.gif" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-37-15/4073.east.gif" border="1" /></a></p>
<p style="padding-left: 30px;">Surprise: The SVG file generated can be imported directly by Microsoft Visio. You can even ungroup it, and then change line and fill properties.</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Components.PostAttachments/00/10/16/97/10/Program.cs" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-components-postattachments/00-10-16-97-10/Program.cs">Program.cs</a></p>]]></content:encoded>
    </item>
    <item>
      <title>EWD637: Three Golden Rules for Successful Scientific Research</title>
      <link>https://docs.microsoft.com/archive/blogs/fyuan/ewd637-three-golden-rules-for-successful-scientific-research</link>
      <pubDate>Thu, 14 Apr 2011 07:54:16 GMT</pubDate>
      <dc:creator><![CDATA[Feng Yuan]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/fyuan/2011/04/14/ewd637-three-golden-rules-for-successful-scientific-research/</guid>
      <description><![CDATA[Here is something I read in graduate school and still thinks about from time to time:
Edsger W....]]></description>
      <content:encoded><![CDATA[<p>Here is something I read in graduate school and still thinks about from time to time:</p>
<p>Edsger W. Dijkstra's&nbsp;Three Golden Rules for Successful Scientific Research:</p>
<div class="date-posts">
<div class="post-outer">
<div class="post hentry">
<div class="post-body entry-content"><ol>
<li>Raise your quality standards as high as you can live with, avoid wasting your time on routine problems, and always works as closely as possible at the boundary of your abilities. Do this, because it is the only way of discovering how that boundary should be move forward.<br /></li>
<li>We all like our work to be socially relevant and scientifically sound. If we can find a topic satisfying both desires, we are lucky; if the two targets are in conflict with each other, let the requirement of scientific soundness prevail.<br /></li>
<li>Never tackle a problem of which you can be pretty sure that (now or in the near future) it will be tackled by others who are, in relation to that problem, at least as competent and well-equipped as you.</li>
</ol>
<hr />
(Ref: https://userweb.cs.utexas.edu/~EWD/transcriptions/EWD06xx/EWD637.html)<br /></div>
</div>
</div>
</div>]]></content:encoded>
    </item>
    <item>
      <title>Optimization Note (C++) 1: push, pop, call _chkstk</title>
      <link>https://docs.microsoft.com/archive/blogs/fyuan/optimization-note-c-1-push-pop-call-_chkstk</link>
      <pubDate>Sun, 03 Apr 2011 18:05:00 GMT</pubDate>
      <dc:creator><![CDATA[Feng Yuan]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/fyuan/2011/04/03/optimization-note-c-1-push-pop-call-_chkstk/</guid>
      <description><![CDATA[I was looking at assembly code trying to improve an important performance scenario when I found a...]]></description>
      <content:encoded><![CDATA[<p>I was looking at assembly code trying to improve an important performance scenario when I found a strange call to _chkstk</p>
<pre><span style="font-family: courier new,courier;">    011E100E push  10h
    011E1010 pop   eax
    011E1011 call  _chkstk (011E1810h)
    011E1016 mov   ecx,esp
</span></pre>
<p>My understanding is that _chkstk call is generatesd by C++ compiler when there are more than 4kb local variable allocation. But here the code is only allocating 16 bytes. This is important because _chkstk is not cheap:</p>
<pre style="padding-left: 30px;"><span style="font-family: courier new,courier;">011E1810  push        ecx
011E1811  lea         ecx, [esp+4]
011E1815&nbsp; sub&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ecx,eax&nbsp; <br />011E1817&nbsp; sbb&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; eax,eax&nbsp; <br />011E1819&nbsp; not&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; eax&nbsp; <br />011E181B&nbsp; and&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ecx,eax&nbsp; <br />011E181D&nbsp; mov&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; eax,esp&nbsp; <br />011E181F&nbsp; and&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; eax,0FFFFF000h&nbsp; <br />011E1824&nbsp; cmp&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ecx,eax&nbsp; <br />011E1826&nbsp; jb&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cs20 (011E1832h)&nbsp; <br />011E1828&nbsp; mov&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; eax,ecx&nbsp; <br />011E182A&nbsp; pop&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ecx&nbsp; <br />011E182B&nbsp; xchg&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; eax,esp&nbsp; <br />011E182C&nbsp; mov&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; eax,dword ptr [eax]&nbsp; <br />011E182E&nbsp; mov&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dword ptr [esp],eax&nbsp; <br />011E1831&nbsp; ret&nbsp; <br /></span><div></div>
<p>&nbsp;</p><div></div><p>After digging through layers of&nbsp; macros, I finally found out that this _chkstk call is generated by an _alloca call for 16-byte of storage. Here is a repro case:</p>
<p><span style="font-family: Consolas; color: #808080; font-size: x-small;"><span style="font-family: Consolas; color: #808080; font-size: x-small;"><span style="font-family: Consolas; color: #808080; font-size: x-small;"></span></span></span><span style="font-family: Consolas; color: #808080; font-size: x-small;"><span style="font-family: Consolas; color: #808080; font-size: x-small;"><span style="font-family: Consolas; color: #808080; font-size: x-small;"></span></span></span></p><p><span style="font-family: Consolas; color: #0000ff; font-size: x-small;"><span style="font-family: Consolas; color: #0000ff; font-size: x-small;"><span style="font-family: Consolas; color: #0000ff; font-size: x-small;"><span style="font-family: Consolas; color: #0000ff; font-size: x-small;"><span style="font-family: Consolas; color: #0000ff; font-size: x-small;"><span style="font-family: Consolas; color: #0000ff; font-size: x-small;">int&nbsp;</span></span></span></span></span></span><span style="font-family: Consolas; color: #800080; font-size: x-small;"><span style="font-family: Consolas; color: #800080; font-size: x-small;"><span style="font-family: Consolas; color: #800080; font-size: x-small;">_tmain</span></span></span><span style="font-family: Consolas; font-size: x-small;"><span style="font-family: Consolas; font-size: x-small;">(</span></span><span style="font-family: Consolas; color: #0000ff; font-size: x-small;"><span style="font-family: Consolas; color: #0000ff; font-size: x-small;"><span style="font-family: Consolas; color: #0000ff; font-size: x-small;">int</span></span></span><span style="font-family: Consolas; font-size: x-small;"><span style="font-family: Consolas; font-size: x-small;"> </span></span><i><span style="font-family: Consolas; color: #808080; font-size: x-small;"><span style="font-family: Consolas; color: #808080; font-size: x-small;"><span style="font-family: Consolas; color: #808080; font-size: x-small;">argc</span></span></span></i><span style="font-family: Consolas; font-size: x-small;"><span style="font-family: Consolas; font-size: x-small;">, </span></span><span style="font-family: Consolas; color: #008080; font-size: x-small;"><span style="font-family: Consolas; color: #008080; font-size: x-small;"><span style="font-family: Consolas; color: #008080; font-size: x-small;">_TCHAR</span></span></span><span style="font-family: Consolas; font-size: x-small;"><span style="font-family: Consolas; font-size: x-small;">* </span></span><i><span style="font-family: Consolas; color: #808080; font-size: x-small;"><span style="font-family: Consolas; color: #808080; font-size: x-small;"><span style="font-family: Consolas; color: #808080; font-size: x-small;">argv</span></span></span></i><span style="font-family: Consolas; font-size: x-small;"><span style="font-family: Consolas; font-size: x-small;">[])</span></span></p><p><span style="font-family: Consolas; font-size: x-small;"><span style="font-family: Consolas; font-size: x-small;">{
</span></span><span style="font-family: Consolas; color: #008080; font-size: x-small;"><span style="font-family: Consolas; color: #008080; font-size: x-small;"><span style="font-family: Consolas; color: #008080; font-size: x-small;">&nbsp;&nbsp;&nbsp; RECT</span></span></span><span style="font-family: Consolas; font-size: x-small;"><span style="font-family: Consolas; font-size: x-small;"> * </span></span><span style="font-family: Consolas; color: #808080; font-size: x-small;"><span style="font-family: Consolas; color: #808080; font-size: x-small;"><span style="font-family: Consolas; color: #808080; font-size: x-small;">pRect</span></span></span><span style="font-family: Consolas; font-size: x-small;"><span style="font-family: Consolas; font-size: x-small;"> = (</span></span><span style="font-family: Consolas; color: #008080; font-size: x-small;"><span style="font-family: Consolas; color: #008080; font-size: x-small;"><span style="font-family: Consolas; color: #008080; font-size: x-small;">RECT</span></span></span><span style="font-family: Consolas; font-size: x-small;"><span style="font-family: Consolas; font-size: x-small;"> *) _alloca(</span></span><span style="font-family: Consolas; color: #0000ff; font-size: x-small;"><span style="font-family: Consolas; color: #0000ff; font-size: x-small;"><span style="font-family: Consolas; color: #0000ff; font-size: x-small;">sizeof</span></span></span><span style="font-family: Consolas; font-size: x-small;"><span style="font-family: Consolas; font-size: x-small;">(</span></span><span style="font-family: Consolas; color: #008080; font-size: x-small;"><span style="font-family: Consolas; color: #008080; font-size: x-small;"><span style="font-family: Consolas; color: #008080; font-size: x-small;">RECT</span></span></span><span style="font-family: Consolas; font-size: x-small;"><span style="font-family: Consolas; font-size: x-small;">));<span style="font-family: Consolas; font-size: x-small;"><span style="font-family: Consolas; font-size: x-small;">
</span></span></span><span style="font-family: Consolas; font-size: x-small;"><p>&nbsp;</p></span></span><span style="font-family: Consolas; color: #808080; font-size: x-small;"><span style="font-family: Consolas; color: #808080; font-size: x-small;"><span style="font-family: Consolas; color: #808080; font-size: x-small;">&nbsp;&nbsp;&nbsp; pRect</span></span></span><span style="font-family: Consolas; font-size: x-small;"><span style="font-family: Consolas; font-size: x-small;">-&gt;</span></span><span style="font-family: Consolas; color: #e37a04; font-size: x-small;"><span style="font-family: Consolas; color: #e37a04; font-size: x-small;"><span style="font-family: Consolas; color: #e37a04; font-size: x-small;">left</span></span></span><span style="font-family: Consolas; font-size: x-small;"><span style="font-family: Consolas; font-size: x-small;"> = 10;</span></span>
</p><p><p><span style="font-family: Consolas; color: #0000ff; font-size: x-small;"><span style="font-family: Consolas; color: #0000ff; font-size: x-small;"><span style="font-family: Consolas; color: #0000ff; font-size: x-small;">&nbsp;&nbsp;&nbsp; return</span></span></span><span style="font-family: Consolas; font-size: x-small;"><span style="font-family: Consolas; font-size: x-small;"> </span></span><span style="font-family: Consolas; color: #808080; font-size: x-small;"><span style="font-family: Consolas; color: #808080; font-size: x-small;"><span style="font-family: Consolas; color: #808080; font-size: x-small;">pRect</span></span></span><span style="font-family: Consolas; font-size: x-small;"><span style="font-family: Consolas; font-size: x-small;">-&gt;</span></span><span style="font-family: Consolas; color: #e37a04; font-size: x-small;"><span style="font-family: Consolas; color: #e37a04; font-size: x-small;"><span style="font-family: Consolas; color: #e37a04; font-size: x-small;">left</span></span></span><span style="font-family: Consolas; font-size: x-small;"><span style="font-family: Consolas; font-size: x-small;">;</span></span></p><p>}</p>
<p>As the object is always needed, the fix is quite easy, just allocate on the stack together with other local variables (for free).
</p></p></pre>]]></content:encoded>
    </item>
  </channel>
</rss>