{"id":48,"date":"2019-12-13T18:27:17","date_gmt":"2019-12-13T16:27:17","guid":{"rendered":"http:\/\/www.juustila.com\/antti\/?p=48"},"modified":"2019-12-13T18:36:44","modified_gmt":"2019-12-13T16:36:44","slug":"generating-test-data-with-c","status":"publish","type":"post","link":"https:\/\/www.juustila.com\/antti\/2019\/12\/13\/generating-test-data-with-c\/","title":{"rendered":"Generating test data with C++"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">The last time I held the Software Architectures course, I wanted to demonstrate students how to test the performance and reliability <a href=\"https:\/\/en.wikipedia.org\/wiki\/List_of_system_quality_attributes\">quality attributes<\/a> of a distributed software system. The system already had a feature to process data as a batch by reading data files and processing that data in the networked nodes. All I needed to do was to generate data files with thousands of records to read and process in the system. I implemented a small tool app to generate this test data.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">First of all, when generating thousands of records, I wanted to preallocate the necessary buffers to make sure that during data creation no unnecessary buffer allocations are made, making data generation faster:<\/p>\n\n\n\n<!-- HTML generated using hilite.me --><div style=\"background: #f8f8f8; overflow:auto;width:auto;border:solid gray;border-width:.1em .1em .1em .8em;padding:.2em .6em;\"><pre style=\"margin: 0; line-height: 125%\">std<span style=\"color: #666666\">::<\/span>vector<span style=\"color: #666666\">&lt;<\/span><span style=\"color: #B00040\">int<\/span><span style=\"color: #666666\">&gt;<\/span> generatedStudentNumbers;\n<span style=\"color: #008000; font-weight: bold\">if<\/span> (verbose) std<span style=\"color: #666666\">::<\/span>cout <span style=\"color: #666666\">&lt;&lt;<\/span> <span style=\"color: #BA2121\">\"Creating numbers for students...\"<\/span> <span style=\"color: #666666\">&lt;&lt;<\/span> std<span style=\"color: #666666\">::<\/span>endl;\ngeneratedStudentNumbers.resize(studentCount);\n<\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\"><code>resize()<\/code> allocates big enough vetor for the data. For creating student numbers (int), <code>std::iota<\/code> and <code>std::shuffle<\/code> are quite useful:<\/p>\n\n\n\n<!-- HTML generated using hilite.me --><div style=\"background: #f8f8f8; overflow:auto;width:auto;border:solid gray;border-width:.1em .1em .1em .8em;padding:.2em .6em;\"><pre style=\"margin: 0; line-height: 125%\"><span style=\"color: #408080; font-style: italic\">\/\/ Generate student numbers starting from one to studentCount.<\/span>\nstd<span style=\"color: #666666\">::<\/span>iota(generatedStudentNumbers.begin(), generatedStudentNumbers.end(), <span style=\"color: #666666\">1<\/span>);\n<span style=\"color: #408080; font-style: italic\">\/\/ Shuffle the numbers randomly.<\/span>\nstd<span style=\"color: #666666\">::<\/span>shuffle(generatedStudentNumbers.begin(), generatedStudentNumbers.end(), std<span style=\"color: #666666\">::<\/span>mt19937{std<span style=\"color: #666666\">::<\/span>random_device{}()});\n<\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\"><code>std::iota<\/code> fills the container with continuous values starting from 1 in this case. <code>std::shuffle<\/code> puts the numbers in random order. Voil\u00e1, you have a long vector of randomly ordered student numbers you can use in the data generation with only four lines of code!<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Next, I needed random names for the students for the data set. For that, I needed a vector of names and then randomly get a name from that vector when creating the student records:<\/p>\n\n\n\n<!-- HTML generated using hilite.me --><div style=\"background: #f8f8f8; overflow:auto;width:auto;border:solid gray;border-width:.1em .1em .1em .8em;padding:.2em .6em;\"><pre style=\"margin: 0; line-height: 125%\">std<span style=\"color: #666666\">::<\/span>vector<span style=\"color: #666666\">&lt;<\/span>std<span style=\"color: #666666\">::<\/span>string<span style=\"color: #666666\">&gt;<\/span> firstNames;\nfirstNames <span style=\"color: #666666\">=<\/span> {<span style=\"color: #BA2121\">\"Antti\"<\/span>, <span style=\"color: #BA2121\">\"Tiina\"<\/span>, <span style=\"color: #BA2121\">\"Pentti\"<\/span>, <span style=\"color: #BA2121\">\"Risto\"<\/span>, <span style=\"color: #BA2121\">\"P\u00e4ivi\"<\/span>, <span style=\"color: #BA2121\">\"Jaana\"<\/span>, <span style=\"color: #BA2121\">\"Jani\"<\/span>, <span style=\"color: #BA2121\">\"Esko\"<\/span>, <span style=\"color: #BA2121\">\"Hanna\"<\/span>, <span style=\"color: #BA2121\">\"Oskari\"<\/span>};\n\n<span style=\"color: #408080; font-style: italic\">\/\/ Initialize the random engine<\/span>\nstd<span style=\"color: #666666\">::<\/span>random_device rd;\nstd<span style=\"color: #666666\">::<\/span>default_random_engine generator(rd());\n\n<span style=\"color: #408080; font-style: italic\">\/\/ Generate a random int from a range<\/span>\n<span style=\"color: #B00040\">int<\/span>  <span style=\"color: #0000FF\">generateInt<\/span>(<span style=\"color: #B00040\">int<\/span> maxValue) {\n   std<span style=\"color: #666666\">::<\/span>uniform_int_distribution<span style=\"color: #666666\">&lt;<\/span><span style=\"color: #B00040\">int<\/span><span style=\"color: #666666\">&gt;<\/span> distribution(<span style=\"color: #666666\">0<\/span>,maxValue);\n   <span style=\"color: #008000; font-weight: bold\">return<\/span> distribution(generator);\n}\n\n<span style=\"color: #408080; font-style: italic\">\/\/ Pick one random name<\/span>\n<span style=\"color: #008000; font-weight: bold\">const<\/span> std<span style=\"color: #666666\">::<\/span>string <span style=\"color: #666666\">&amp;<\/span> getFirstName() {\n   <span style=\"color: #B00040\">int<\/span> index <span style=\"color: #666666\">=<\/span> generateInt(firstNames.size()<span style=\"color: #666666\">-1<\/span>);\n   <span style=\"color: #008000; font-weight: bold\">return<\/span> firstNames[index];\n}\n<\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\"><code>generateInt()<\/code> helper function is used to get a random name from the <code>firstNames<\/code> array. The same procedure was used to generate a last name and the study program name for the student. Then all these pieces of information was stored into a record, basically a tab separated <code>std::string<\/code>. Records, in turn, were contained in a vector of strings.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">What is then left is storing the test data records into a file:<\/p>\n\n\n\n<!-- HTML generated using hilite.me --><div style=\"background: #f8f8f8; overflow:auto;width:auto;border:solid gray;border-width:.1em .1em .1em .8em;padding:.2em .6em;\"><pre style=\"margin: 0; line-height: 125%\">std<span style=\"color: #666666\">::<\/span>ofstream datafile(fileName, isFirstRound <span style=\"color: #666666\">?<\/span> std<span style=\"color: #666666\">::<\/span>ios<span style=\"color: #666666\">::<\/span>trunc <span style=\"color: #666666\">:<\/span> std<span style=\"color: #666666\">::<\/span>ios<span style=\"color: #666666\">::<\/span>app);\n\n<span style=\"color: #408080; font-style: italic\">\/\/ Shuffle the records randomly.<\/span>\nstd<span style=\"color: #666666\">::<\/span>shuffle(buffer.begin(), buffer.end(), std<span style=\"color: #666666\">::<\/span>mt19937{std<span style=\"color: #666666\">::<\/span>random_device{}()});\n<span style=\"color: #008000; font-weight: bold\">auto<\/span> save <span style=\"color: #666666\">=<\/span> [<span style=\"color: #666666\">&amp;<\/span>datafile](<span style=\"color: #008000; font-weight: bold\">const<\/span> std<span style=\"color: #666666\">::<\/span>string <span style=\"color: #666666\">&amp;<\/span> entry) { <span style=\"color: #008000; font-weight: bold\">if<\/span> (entry.length() <span style=\"color: #666666\">&gt;<\/span> <span style=\"color: #666666\">0<\/span>) datafile <span style=\"color: #666666\">&lt;&lt;<\/span> entry <span style=\"color: #666666\">&lt;&lt;<\/span> std<span style=\"color: #666666\">::<\/span>endl; };\nstd<span style=\"color: #666666\">::<\/span>for_each(buffer.begin(), buffer.end(), save);\ndatafile.close();\n<\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">After opening the file stream, first again use <code>std::shuffle<\/code> to put the data into random order, then use the <code>save<\/code> lambda function to define what saving a record means. Then just pass this lambda to <code>std::for_each<\/code> to tell what to do to each of the data records &#8212; save them into the <code>std::ofstream<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Finally I made the data generator tool configurable with command line parameters, using <a href=\"https:\/\/github.com\/MayaPosch\/Sarge\">Sarge<\/a>:<\/p>\n\n\n\n<!-- HTML generated using hilite.me --><div style=\"background: #f8f8f8; overflow:auto;width:auto;border:solid gray;border-width:.1em .1em .1em .8em;padding:.2em .6em;\"><pre style=\"margin: 0; line-height: 125%\">Sarge sarge;\nsarge.setUsage(<span style=\"color: #BA2121\">\".\/GenerateTestData -[hv]s &lt;number&gt; [-e &lt;number&gt;]\"<\/span>);\nsarge.setDescription(<span style=\"color: #BA2121\">\"A test data generator for StudentPassing system. (c) Antti Juustila, 2019.<\/span><span style=\"color: #BB6622; font-weight: bold\">\\n<\/span><span style=\"color: #BA2121\">Uses Sarge Copyright (c) 2019, Maya Posch All rights reserved.\"<\/span>);\nsarge.setArgument(<span style=\"color: #BA2121\">\"h\"<\/span>, <span style=\"color: #BA2121\">\"help\"<\/span>, <span style=\"color: #BA2121\">\"Display help for using GenerateTestData.\"<\/span>, <span style=\"color: #008000\">false<\/span>);\nsarge.setArgument(<span style=\"color: #BA2121\">\"v\"<\/span>, <span style=\"color: #BA2121\">\"verbose\"<\/span>, <span style=\"color: #BA2121\">\"Display detailed messages of test data generation process.\"<\/span>, <span style=\"color: #008000\">false<\/span>);\nsarge.setArgument(<span style=\"color: #BA2121\">\"s\"<\/span>, <span style=\"color: #BA2121\">\"students\"<\/span>, <span style=\"color: #BA2121\">\"Number of students to generate in test data files.\"<\/span>, <span style=\"color: #008000\">true<\/span>);\nsarge.setArgument(<span style=\"color: #BA2121\">\"e\"<\/span>, <span style=\"color: #BA2121\">\"exercises\"<\/span>, <span style=\"color: #BA2121\">\"Number of exercises generated, default is 6 if option not provided.\"<\/span>, <span style=\"color: #008000\">true<\/span>);\nsarge.setArgument(<span style=\"color: #BA2121\">\"b\"<\/span>, <span style=\"color: #BA2121\">\"bufsize\"<\/span>, <span style=\"color: #BA2121\">\"Size of the buffer used in generating data\"<\/span>, <span style=\"color: #008000\">true<\/span>);\n<\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">I used the test data generator tool to generate up to 10 000 records and used those test data files to see and demonstrate students how the system manages high data throughput and what which performance. It was also interesting to see what the performance bottlenecks were in the system. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Next year (the last time teaching this course) I&#8217;ll demonstrate how to use a thread to read the data files, while at the same time reading test data from the network in another thread. There is a large impact on whether using std::thread.join() or .detach() to control how the networking and data file reading threads cooperate.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>The last time I held the Software Architectures course, I wanted to demonstrate students how to test the performance and reliability quality attributes of a distributed software system. The system already had a feature to process data as a batch by reading data files and processing that data in the networked nodes. All I needed &hellip; <a href=\"https:\/\/www.juustila.com\/antti\/2019\/12\/13\/generating-test-data-with-c\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;Generating test data with C++&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","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_post_was_ever_published":false},"categories":[2],"tags":[10,16,15,17],"class_list":["post-48","post","type-post","status-publish","format-standard","hentry","category-coding","tag-c","tag-test-data-generation","tag-testing","tag-threads"],"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/www.juustila.com\/antti\/wp-json\/wp\/v2\/posts\/48","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.juustila.com\/antti\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.juustila.com\/antti\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.juustila.com\/antti\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.juustila.com\/antti\/wp-json\/wp\/v2\/comments?post=48"}],"version-history":[{"count":3,"href":"https:\/\/www.juustila.com\/antti\/wp-json\/wp\/v2\/posts\/48\/revisions"}],"predecessor-version":[{"id":51,"href":"https:\/\/www.juustila.com\/antti\/wp-json\/wp\/v2\/posts\/48\/revisions\/51"}],"wp:attachment":[{"href":"https:\/\/www.juustila.com\/antti\/wp-json\/wp\/v2\/media?parent=48"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.juustila.com\/antti\/wp-json\/wp\/v2\/categories?post=48"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.juustila.com\/antti\/wp-json\/wp\/v2\/tags?post=48"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}