Advertisement
ulfben

Classroom refactoring exercise (day 1)

Nov 27th, 2018
363
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 8.34 KB | None | 0 0
  1. /*
  2. 2018-11-27 classroom refactoring exercise
  3. - replaced char* with const char* in all arguments
  4. - removed dependency on "TextBox", replacing it with std::string outputBuffer.
  5. - inverted needlessly long branches to reduce the amount of nested scopes
  6. - turned the global functions into static class methods
  7. - made "internal" functions private
  8. - changed all const char* arguments to const std::string&
  9. - fixed smell: multiple output parameters (GetProfileFromHistory(const string&, float*, float*, float*))
  10. ------by creating a SamplePoint type and making use of structured bindings
  11. - Changed char* members in ProfileSampleHistory and ProfileSample for std::string
  12. --- allowing us to remove all strcmp and strln-calls.
  13. */
  14. #ifndef _PROFILE_H
  15. #define _PROFILE_H
  16. #include <string>
  17. class Profile {
  18.     struct SamplePoint{
  19.         float ave{ 0 }, min{ 0 }, max{ 0 };
  20.     };
  21.     static void StoreProfileInHistory(const std::string& name, float percent);
  22.     static SamplePoint GetProfileFromHistory(const std::string& name);
  23. public:
  24.     static void Init(void);
  25.     static void Begin(const std::string& name);
  26.     static void End(const std::string& name);
  27.     static void DumpOutputToBuffer(void);
  28.     static void Draw(void);
  29. };
  30. #endif //_PROFILE_H
  31.  
  32. /* Copyright (C) Steve Rabin, 2000.
  33.  * All rights reserved worldwide.
  34.  *
  35.  * This software is provided "as is" without express or implied
  36.  * warranties. You may freely copy and compile this source into
  37.  * applications you distribute provided that the copyright text
  38.  * below is included in the resulting source code, for example:
  39.  * "Portions Copyright (C) Steve Rabin, 2000"
  40.  */
  41. #include "profile.h"
  42. #include "custom_time.h"
  43. #include <assert.h>
  44. #include <string.h>
  45. #include <stdio.h>
  46. #include <iostream>
  47. #include <string>
  48. #include <sstream>
  49. #include <iomanip>
  50. typedef struct {
  51.     bool bValid;                 //Whether this data is valid
  52.     unsigned int iProfileInstances;      //# of times ProfileBegin called
  53.     int iOpenProfiles;           //# of times ProfileBegin w/o ProfileEnd
  54.     std::string szName;            //Name of sample
  55.     float fStartTime;            //The current open profile start time
  56.     float fAccumulator;          //All samples this frame added together
  57.     float fChildrenSampleTime;   //Time taken by all children
  58.     unsigned int iNumParents;            //Number of profile parents
  59. } ProfileSample;
  60.  
  61. typedef struct {
  62.     bool bValid;        //Whether the data is valid
  63.     std::string szName;   //Name of the sample
  64.     float fAve;         //Average time per frame (percentage)
  65.     float fMin;         //Minimum time per frame (percentage)
  66.     float fMax;         //Maximum time per frame (percentage)
  67. } ProfileSampleHistory;
  68.  
  69. #define NUM_PROFILE_SAMPLES 50
  70. ProfileSample g_samples[NUM_PROFILE_SAMPLES];
  71. ProfileSampleHistory g_history[NUM_PROFILE_SAMPLES];
  72. float g_startProfile = 0.0f;
  73. float g_endProfile = 0.0f;
  74. std::string outputBuffer = "";
  75.  
  76. void Profile::Init(void) {
  77.     for (unsigned int i = 0; i < NUM_PROFILE_SAMPLES; i++) {
  78.         g_samples[i].bValid = false;
  79.         g_history[i].bValid = false;
  80.     }
  81.     g_startProfile = GetExactTime();
  82. }
  83.  
  84. void Profile::Begin(const std::string& name) {
  85.     unsigned int i = 0;
  86.     while (i < NUM_PROFILE_SAMPLES && g_samples[i].bValid == true) {
  87.         if (g_samples[i].szName == name) {
  88.             //Found the sample
  89.             g_samples[i].iOpenProfiles++;
  90.             g_samples[i].iProfileInstances++;
  91.             g_samples[i].fStartTime = GetExactTime();
  92.             assert(g_samples[i].iOpenProfiles == 1); //max 1 open at once
  93.             return;
  94.         }
  95.         i++;
  96.     }
  97.  
  98.     if (i >= NUM_PROFILE_SAMPLES) {
  99.         assert(!"Exceeded Max Available Profile Samples");
  100.         return;
  101.     }
  102.  
  103.     g_samples[i].szName = name;
  104.     g_samples[i].bValid = true;
  105.     g_samples[i].iOpenProfiles = 1;
  106.     g_samples[i].iProfileInstances = 1;
  107.     g_samples[i].fAccumulator = 0.0f;
  108.     g_samples[i].fStartTime = GetExactTime();
  109.     g_samples[i].fChildrenSampleTime = 0.0f;
  110. }
  111.  
  112.  
  113. void Profile::End(const std::string& name) {
  114.     unsigned int i = 0;
  115.     unsigned int numParents = 0;
  116.     while (i < NUM_PROFILE_SAMPLES && g_samples[i].bValid == true) {
  117.         if (g_samples[i].szName != name) {
  118.             i++;
  119.             continue; // not the sample we want, go to the next
  120.         }
  121.         unsigned int inner = 0;
  122.         int parent = -1;
  123.         float fEndTime = GetExactTime();
  124.         g_samples[i].iOpenProfiles--;
  125.  
  126.         //Count all parents and find the immediate parent
  127.         while (g_samples[inner].bValid == true) {
  128.             if (g_samples[inner].iOpenProfiles > 0) {  //Found a parent (any open profiles are parents)
  129.                 numParents++;
  130.                 if (parent < 0) {  //Replace invalid parent (index)
  131.                     parent = inner;
  132.                 }
  133.                 else if (g_samples[inner].fStartTime >= g_samples[parent].fStartTime) {
  134.                     //Replace with more immediate parent
  135.                     parent = inner;
  136.                 }
  137.             }
  138.             inner++;
  139.         }
  140.         g_samples[i].iNumParents = numParents; //Remember the current number of parents of the sample
  141.  
  142.         if (parent >= 0) {  //Record this time in fChildrenSampleTime (add it in)
  143.             g_samples[parent].fChildrenSampleTime += fEndTime - g_samples[i].fStartTime;
  144.         }
  145.         //Save sample time in accumulator
  146.         g_samples[i].fAccumulator += fEndTime - g_samples[i].fStartTime;
  147.         return;
  148.     }
  149. }
  150.  
  151. void Profile::DumpOutputToBuffer(void) {
  152.     unsigned int i = 0;
  153.     g_endProfile = GetExactTime();
  154.     outputBuffer.clear();
  155.     outputBuffer += "  Ave :   Min :   Max :   # : Profile Name\n";
  156.     outputBuffer += "--------------------------------------------\n";
  157.     while (i < NUM_PROFILE_SAMPLES && g_samples[i].bValid == true) {
  158.         unsigned int indent = 0;
  159.         float sampleTime, percentTime;
  160.         char line[256], name[256];
  161.         std::string indentedName;
  162.         char ave[16], min[16], max[16], num[16];
  163.  
  164.         if (g_samples[i].iOpenProfiles < 0) { assert(!"ProfileEnd() called without a ProfileBegin()"); }
  165.         else if (g_samples[i].iOpenProfiles > 0) { assert(!"ProfileBegin() called without a ProfileEnd()"); }
  166.  
  167.         sampleTime = g_samples[i].fAccumulator - g_samples[i].fChildrenSampleTime;
  168.         percentTime = (sampleTime / (g_endProfile - g_startProfile)) * 100.0f;
  169.        
  170.  
  171.         //Add new measurement into the history and get the ave, min, and max
  172.         StoreProfileInHistory(g_samples[i].szName, percentTime);
  173.         auto [aveTime, minTime, maxTime] = GetProfileFromHistory(g_samples[i].szName);
  174.  
  175.         //TODO Format the data
  176.         /*std::stringstream output;
  177.         output << std::setprecision(4) <<;*/
  178.         sprintf_s(ave, "%3.1f", aveTime);
  179.         sprintf_s(min, "%3.1f", minTime);
  180.         sprintf_s(max, "%3.1f", maxTime);
  181.         sprintf_s(num, "%3d", g_samples[i].iProfileInstances);
  182.  
  183.         indentedName = g_samples[i].szName;
  184.         for (indent = 0; indent < g_samples[i].iNumParents; indent++) {
  185.             sprintf_s(name, "   %s", indentedName.c_str());
  186.             indentedName = name;
  187.         }
  188.         sprintf_s(line, "%3s : %3s : %3s : %3s : %s\n", ave, min, max, num, indentedName.c_str());
  189.         outputBuffer += line;   //Send the line to text buffer
  190.         i++;
  191.     }
  192.     {  //Reset samples for next frame
  193.         unsigned int j;
  194.         for (j = 0; j < NUM_PROFILE_SAMPLES; j++) {
  195.             g_samples[j].bValid = false;
  196.         }
  197.         g_startProfile = GetExactTime();
  198.     }
  199. }
  200.  
  201. void Profile::StoreProfileInHistory(const std::string& name, float percent) {
  202.     unsigned int i = 0;
  203.     float oldRatio;
  204.     float newRatio = 0.8f * GetElapsedTime();
  205.     if (newRatio > 1.0f) {
  206.         newRatio = 1.0f;
  207.     }
  208.     oldRatio = 1.0f - newRatio;
  209.     // TODO: replace with std::find
  210.     for (auto& sample : g_history) {
  211.         if (!sample.bValid) {
  212.             break;
  213.         }
  214.         if (sample.szName != name) {
  215.             i++;
  216.             continue;
  217.         }
  218.  
  219.         //Found the sample
  220.         sample.fAve = (sample.fAve*oldRatio) + (percent*newRatio);
  221.         if (percent > sample.fMax) {
  222.             sample.fMax = percent;
  223.         }
  224.         if (percent < sample.fMin) {
  225.             sample.fMin = percent;
  226.         }
  227.         else {
  228.             sample.fMin = (sample.fMin*oldRatio) + (percent*newRatio);
  229.         }
  230.         if (sample.fMin < 0.0f) {
  231.             sample.fMin = 0.0f;
  232.         }
  233.         else {
  234.             sample.fMax = (sample.fMax*oldRatio) + (percent*newRatio);
  235.         }
  236.         return;
  237.     }
  238.  
  239.     if (i < NUM_PROFILE_SAMPLES) {  //Add to history
  240.         g_history[i].szName = name;
  241.         g_history[i].bValid = true;
  242.         g_history[i].fAve = g_history[i].fMin = g_history[i].fMax = percent;
  243.     }
  244.     else {
  245.         assert(!"Exceeded Max Available Profile Samples!");
  246.     }
  247. }
  248.  
  249. Profile::SamplePoint Profile::GetProfileFromHistory(const std::string& name) {
  250.     SamplePoint result{};
  251.     for (auto& sample : g_history){
  252.         if (sample.bValid == true && sample.szName == name) {
  253.             result.ave = sample.fAve;
  254.             result.max = sample.fMax;
  255.             result.min = sample.fMin;
  256.  
  257.             return result;
  258.         }
  259.     }
  260.     return result;
  261. }
  262.  
  263. void Profile::Draw(void) {
  264.     std::cout << outputBuffer << '\n';
  265. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement