{"id":375,"date":"2008-09-22T20:38:25","date_gmt":"2008-09-22T08:38:25","guid":{"rendered":"https:\/\/www.deltics.co.nz\/blog\/?p=375"},"modified":"2009-08-07T14:58:26","modified_gmt":"2009-08-07T02:58:26","slug":"delphi-2009-stringperformance-redux","status":"publish","type":"post","link":"https:\/\/www.deltics.co.nz\/blog\/posts\/375\/","title":{"rendered":"Delphi 2009 &#8211; StringPerformance Redux"},"content":{"rendered":"<span class=\"span-reading-time rt-reading-time\" style=\"display: block;\"><span class=\"rt-label rt-prefix\">[Estimated Reading Time: <\/span> <span class=\"rt-time\"> 3<\/span> <span class=\"rt-label rt-postfix\">minutes]<\/span><\/span><p>It looks like I may have jumped the gun with my conclusions from the previous exercise to benchmark string performance in Delphi 2009.\u00a0 Following a <a href=\"https:\/\/www.deltics.co.nz\/blog\/?p=349#comments\" target=\"_blank\">useful exchange in the comments with Kryvich<\/a> I corrected a small discrepancy in the tests and made some changes to the performance testing subsystem within the SmokeTest framework.\u00a0 I then re-ran my string performance benchmarks with some significant &#8211; and more encouraging &#8211; differences in the results.<\/p>\n<p><!--more--><\/p>\n<p>I shall not go into the specifics of the tests again &#8211; if you&#8217;re interested and missed it the first time around you can read my <a href=\"https:\/\/www.deltics.co.nz\/blog\/?p=349\" target=\"_blank\">previous post<\/a>.<\/p>\n<p>The major changes were made in the SmokeTest performance testing subsystem itself:<\/p>\n<p style=\"padding-left: 30px;\">1. Corrected a bug in the CPU affinity code (oops!)<\/p>\n<p style=\"padding-left: 30px;\">2. Implemented CPU instruction cache flushing<\/p>\n<p>The CPU affinity fix now correctly ensures that the code under test is executed on the 2nd processor in any N-core or N-processor hardware.\u00a0 The main thread of the SmokeTest framework application itself is assigned to the 1st CPU.<\/p>\n<p>This is intended to eliminate context switching artefacts and main thread impact from the code under test.\u00a0 The bug was that the main thread was inadvertently allowed to run on all available CPU&#8217;s &#8211; the impact on test results is negligible I think, but even so.<\/p>\n<p>The CPU instruction cache flushing has a much more significant impact and is performed following each execution of a method under test.\u00a0 This has had a significant impact on the raw numbers coming out of the test results (i.e. the number of executions completed per second) but should ensure that the performance of the code itself is tested, not the efficiency of the CPU cache.<\/p>\n<p>The source code being tested is essentially unchanged from that previously used, although it contained one minor correction to the Indexing test case already <a href=\"https:\/\/www.deltics.co.nz\/blog\/?p=349#comments\" target=\"_blank\">documented in the comments<\/a> of that previous post.<\/p>\n<p>I have updated the results download with the new data.\u00a0 This time I have included the Excel spreadsheet with the pretty formatting of the results data comparison and also all three of the raw results files emitted in CSV format by the test app itself.<\/p>\n<h2>Observations On The New Results<\/h2>\n<p>The new test results actually fit more intuitively with what we might expect, albeit still with one or two noteworthy results.<\/p>\n<p><a href=\"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/delphi2009-stringperformance-resultscapture-redux.jpg?ssl=1\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" class=\"size-full wp-image-380 alignleft\" title=\"delphi2009-stringperformance-resultscapture-redux\" src=\"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/delphi2009-stringperformance-resultscapture-redux.jpg?resize=300%2C281&#038;ssl=1\" alt=\"\" width=\"300\" height=\"281\" srcset=\"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/delphi2009-stringperformance-resultscapture-redux.jpg?w=847&amp;ssl=1 847w, https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/delphi2009-stringperformance-resultscapture-redux.jpg?resize=300%2C281&amp;ssl=1 300w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><a href=\"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/delphi2009-stringperformance-chart.jpg?ssl=1\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-385\" title=\"delphi2009-stringperformance-chart\" src=\"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/delphi2009-stringperformance-chart.jpg?resize=300%2C252&#038;ssl=1\" alt=\"\" width=\"300\" height=\"252\" srcset=\"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/delphi2009-stringperformance-chart.jpg?w=869&amp;ssl=1 869w, https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/delphi2009-stringperformance-chart.jpg?resize=300%2C252&amp;ssl=1 300w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<p style=\"text-align: center;\">\n<p style=\"text-align: center;\">[dm]10[\/dm]<\/p>\n<p style=\"padding-left: 30px;\">1. Overall Unicode string performance is about 5-10% less efficient than ANSI string handling in Delphi 2007 but is comparable to and in many cases generally improved when compared to Delphi 7.<\/p>\n<p style=\"padding-left: 30px;\">2. Char-wise operations are the most adversely affected as we might expect but, somewhat surprisingly, simple assignment of strings actually comes out as the most badly affected of the basic operations.<\/p>\n<p style=\"padding-left: 30px;\">3. ANSI string handling is generally as good as if not slightly better than Delphi 2007 overall, even more so when compared to Delphi 7.\u00a0 Notable exceptions to this remain in the form of the lack of an ANSI implementation for <strong>IntToStr()<\/strong> and a significantly slower <strong>Replace()<\/strong> implementation.<\/p>\n<p style=\"padding-left: 30px;\">4. There is still a question mark over the raison d&#8217;etre of TStringBuilder, although the difference in performance &#8211; whilst still very dramatic &#8211; is not perhaps as great as first it appeared.<\/p>\n<h2>Revised Conclusion<\/h2>\n<p>Concerns w.r.t the performance of ANSI strings were largely misplaced.<\/p>\n<p>There remain a couple of potential gotcha&#8217;s in the form of <strong>IntToStr()<\/strong> and <strong>Replace()<\/strong> but as previously noted, the <strong>FastReplace()<\/strong> implementation remains the gold standard for anyone concerned enough to use it (after taking care to ANSI-fy the API of FastStrings itself of course).<\/p>\n<p>Overall string handling performance at worst undoes some of the gains made in this area in Delphi 2007, but I think that is a reasonable trade for the Unicode capabilities added as a result.<\/p>\n<p>I have also learned some valuable lessons that have improved the utility of my SmokeTest framework into the bargain, so thanks to all who questioned and probed the previous results.<\/p>\n","protected":false},"excerpt":{"rendered":"<p><span class=\"span-reading-time rt-reading-time\" style=\"display: block;\"><span class=\"rt-label rt-prefix\">[Estimated Reading Time: <\/span> <span class=\"rt-time\"> 3<\/span> <span class=\"rt-label rt-postfix\">minutes]<\/span><\/span>It looks like I may have jumped the gun with my conclusions from the previous exercise to benchmark string performance in Delphi 2009.\u00a0 Following a useful exchange in the comments with Kryvich I corrected a small discrepancy in the tests and made some changes to the performance testing subsystem within the SmokeTest framework.\u00a0 I then [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_feature_clip_id":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2},"jetpack_post_was_ever_published":false},"categories":[4,7],"tags":[64,61,292,60,293,22,65],"class_list":["post-375","post","type-post","status-publish","format-standard","hentry","category-delphi","category-tiburon","tag-ansi","tag-ansistring","tag-delphi","tag-faststrings","tag-tiburon","tag-unicode","tag-unicodestring"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p1TKYv-63","jetpack_sharing_enabled":true,"jetpack-related-posts":[],"_links":{"self":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts\/375","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/comments?post=375"}],"version-history":[{"count":11,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts\/375\/revisions"}],"predecessor-version":[{"id":478,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts\/375\/revisions\/478"}],"wp:attachment":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/media?parent=375"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/categories?post=375"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/tags?post=375"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}