{"id":99,"date":"2024-03-19T18:33:00","date_gmt":"2024-03-19T18:33:00","guid":{"rendered":"https:\/\/permutationcity.co.uk\/bp\/?p=99"},"modified":"2024-04-28T12:02:50","modified_gmt":"2024-04-28T12:02:50","slug":"benchmarking-tool","status":"publish","type":"post","link":"https:\/\/permutationcity.co.uk\/bp\/2024\/03\/19\/benchmarking-tool\/","title":{"rendered":"Benchmarking tool"},"content":{"rendered":"\n<p>I&#8217;ve written before about <a href=\"https:\/\/permutationcity.co.uk\/bp\/2024\/01\/08\/400000000-times-faster\/\">when and how to optimise code<\/a>. I think there are often more important aspects to a project than code performance. Servers, desktops, laptops and even new mobile phones are many times more powerful than an old computer. Instead you need to decide whether the performance is good enough. That could be how long a batch process takes to run, is a user interface responsive enough, or are the cloud compute costs too high.<\/p>\n\n\n\n<p>If you have decided that a specific piece of code needs to be optimised then\n<a href=\"https:\/\/quick-bench.com\/\">Quick C++ Benchmark<\/a> might help.\nIt&#8217;s an online tool that lets you write C++, run benchmark tests and get a lovely graph at the end.\nThere are various options so you can select a compiler, language version and what optimisation level to use.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"handy-example\">Handy example<\/h2>\n\n\n\n<p>I was experimenting with something recently and needed a basic string join function.\nThis is not something that needed optimising, it was just a handy example.\nSomething like this:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-c++src&quot;,&quot;theme&quot;:&quot;material&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:true,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;C++&quot;,&quot;language&quot;:&quot;C++&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;cpp&quot;}\">std::string Join(const std::vector&lt;std::string&gt;&amp; strings, const std::string&amp; separator) {\n  std::string result;\n  for (size_t i = 0; i &lt; strings.size(); i++) {\n    if (i != 0) {\n      result += separator;\n    }\n    result += strings[i];\n  }\n  return result;\n}<\/pre><\/div>\n\n\n\n<p>Which you <a href=\"https:\/\/quick-bench.com\/q\/yTCVb0ZYQ6xFRsChHyC2kTouIao\">benchmark online<\/a>.\nI thought the most obvious thing that might be slowing things down was re-allocation of the string.\nIf I pre-calculated the required size I can avoid that:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-c++src&quot;,&quot;theme&quot;:&quot;material&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:true,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;C++&quot;,&quot;language&quot;:&quot;C++&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;cpp&quot;}\">size_t JoinSize(const std::vector&lt;std::string&gt;&amp; strings, const std::string&amp; separator) {\n  size_t size = separator.size() * (strings.size() - 1);\n  for (size_t i = 0; i &lt; strings.size(); i++) {\n    size += strings[i].size();\n  }\n  return size;\n}\n\nstd::string Join(const std::vector&lt;std::string&gt;&amp; strings, const std::string&amp; separator) {\n  std::string result;\n  result.reserve(JoinSize(strings, separator));\n  for (size_t i = 0; i &lt; strings.size(); i++) {\n    if (i != 0) {\n      result += separator;\n    }\n    result += strings[i];\n  }\n  return result;\n}<\/pre><\/div>\n\n\n\n<p>Hmm, that&#8217;s only <a href=\"https:\/\/quick-bench.com\/q\/TORp9L6W_GLIq99WuYcYXHSabTM\">fractionally faster<\/a>.\nThis might seem oddly similar but what about:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-c++src&quot;,&quot;theme&quot;:&quot;material&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:true,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;C++&quot;,&quot;language&quot;:&quot;C++&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;cpp&quot;}\">size_t JoinSize(const std::vector&lt;std::string&gt;&amp; strings, const std::string&amp; separator) {\n  size_t size = separator.size() * (strings.size() - 1);\n  for (const auto&amp; string : strings) {\n    size += string.size();\n  }\n  return size;\n}<\/pre><\/div>\n\n\n\n<p>It&#8217;s a tiny change but it is <a href=\"https:\/\/quick-bench.com\/q\/1bEbwxIXd9PlG44tK821vqq2j5g\">still faster<\/a>. Maybe try using something better suited to building a string. There isn&#8217;t a <code>StringBuffer<\/code> but what about this:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-c++src&quot;,&quot;theme&quot;:&quot;material&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:true,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;C++&quot;,&quot;language&quot;:&quot;C++&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;cpp&quot;}\">std::string Join(const std::vector&lt;std::string&gt;&amp; strings, const std::string&amp; separator) {\n  std::stringstream stream;\n  for (size_t i = 0; i &lt; strings.size(); i++) {\n    if (i != 0) {\n      stream &lt;&lt; separator;\n    }\n    stream &lt;&lt; strings[i];\n  }\n  return stream.str();\n}<\/pre><\/div>\n\n\n\n<p>That&#8217;s terrible, <a href=\"https:\/\/quick-bench.com\/q\/E5_V54wPxx7oD_zDvHQpw8wpihs\">just terrible<\/a>.\nForget that and go back.\nCan we use the looping trick again?\nNot as easily because we still have to check whether to add the separator:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-c++src&quot;,&quot;theme&quot;:&quot;material&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:true,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;C++&quot;,&quot;language&quot;:&quot;C++&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;cpp&quot;}\">std::string Join(const std::vector&lt;std::string&gt;&amp; strings, const std::string&amp; separator) {\n  std::string result;\n  result.reserve(JoinSize(strings, separator));\n  for (auto i = strings.begin(); i != strings.end(); i++) {\n    if (i == strings.begin()) {\n      result += separator;\n    }\n    result += *i;\n  }\n  return result;\n}<\/pre><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">In the end<\/h2>\n\n\n\n<p>What can we learn from all this:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Simple changes can bring small performance boosts. However you might have to experiment to find out what&#8217;s best.<\/li>\n\n\n\n<li>This probably wasn&#8217;t a good target to choose. Unless it&#8217;s in a tight loop it probably won&#8217;t make much of a difference. However a library function is a good place to get lots of little boosts.<\/li>\n\n\n\n<li>Exactly what loops you use matters. Fortunately the ranged-based for loop is easy to read, understand and is fast as well.<\/li>\n\n\n\n<li>Overall this code is more complex. Unless it&#8217;s a problem I&#8217;d just let the string grow automatically.<\/li>\n\n\n\n<li>Looking back why did my loop in <code>JoinSize<\/code> not start out as a ranged-based for loop? It&#8217;s because I used copy-paste, <a href=\"https:\/\/permutationcity.co.uk\/bp\/2024\/03\/12\/how-often\/\">which is problematic<\/a>.<\/li>\n\n\n\n<li>If I was persuing this further I&#8217;d want to know why some loops were slower and some were faster.<\/li>\n<\/ul>\n\n\n\n<p>You could do all of this locally but being able to show your findings can be handy.<br>If you want to persuade someone to change their loops, do it here and show them it <strong>is<\/strong> faster.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I&#8217;ve written before about when and how to optimise code. I think there are often more important aspects to a project than code performance. Servers, desktops, laptops and even new mobile phones are many times more powerful than an old computer. Instead you need to decide whether the performance is good enough. That could be [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_import_markdown_pro_load_document_selector":0,"_import_markdown_pro_submit_text_textarea":"","footnotes":""},"categories":[1],"tags":[7,18,21],"class_list":["post-99","post","type-post","status-publish","format-standard","hentry","category-general","tag-performance","tag-tools","tag-websites"],"_links":{"self":[{"href":"https:\/\/permutationcity.co.uk\/bp\/wp-json\/wp\/v2\/posts\/99","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/permutationcity.co.uk\/bp\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/permutationcity.co.uk\/bp\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/permutationcity.co.uk\/bp\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/permutationcity.co.uk\/bp\/wp-json\/wp\/v2\/comments?post=99"}],"version-history":[{"count":5,"href":"https:\/\/permutationcity.co.uk\/bp\/wp-json\/wp\/v2\/posts\/99\/revisions"}],"predecessor-version":[{"id":205,"href":"https:\/\/permutationcity.co.uk\/bp\/wp-json\/wp\/v2\/posts\/99\/revisions\/205"}],"wp:attachment":[{"href":"https:\/\/permutationcity.co.uk\/bp\/wp-json\/wp\/v2\/media?parent=99"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/permutationcity.co.uk\/bp\/wp-json\/wp\/v2\/categories?post=99"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/permutationcity.co.uk\/bp\/wp-json\/wp\/v2\/tags?post=99"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}