ulfben icon

Classroom refactoring exercise (day 1)

ulfben | PRO | 11/27/18 01:09:36 PM UTC | 0 ⭐ | 1334 👁️ | Never ⏰ | []
C++ |

8.34 KB

|

None

|

0 👍

/

0 👎

/*
2018-11-27 classroom refactoring exercise
- replaced char* with const char* in all arguments
- removed dependency on "TextBox", replacing it with std::string outputBuffer.
- inverted needlessly long branches to reduce the amount of nested scopes
- turned the global functions into static class methods
- made "internal" functions private
- changed all const char* arguments to const std::string&
- fixed smell: multiple output parameters (GetProfileFromHistory(const string&, float*, float*, float*)) 
------by creating a SamplePoint type and making use of structured bindings
- Changed char* members in ProfileSampleHistory and ProfileSample for std::string
--- allowing us to remove all strcmp and strln-calls.
*/
#ifndef _PROFILE_H
#define _PROFILE_H
#include <string>
class Profile { 
    struct SamplePoint{
        float ave{ 0 }, min{ 0 }, max{ 0 };
    };
    static void StoreProfileInHistory(const std::string& name, float percent);
    static SamplePoint GetProfileFromHistory(const std::string& name);
public:
    static void Init(void);
    static void Begin(const std::string& name);
    static void End(const std::string& name);
    static void DumpOutputToBuffer(void);
    static void Draw(void);
};
#endif //_PROFILE_H
 
/* Copyright (C) Steve Rabin, 2000.
 * All rights reserved worldwide.
 *
 * This software is provided "as is" without express or implied
 * warranties. You may freely copy and compile this source into
 * applications you distribute provided that the copyright text
 * below is included in the resulting source code, for example:
 * "Portions Copyright (C) Steve Rabin, 2000"
 */
#include "profile.h"
#include "custom_time.h"
#include <assert.h>
#include <string.h>
#include <stdio.h>
#include <iostream>
#include <string>
#include <sstream>
#include <iomanip>
typedef struct {
    bool bValid;                 //Whether this data is valid
    unsigned int iProfileInstances;      //# of times ProfileBegin called
    int iOpenProfiles;           //# of times ProfileBegin w/o ProfileEnd
    std::string szName;            //Name of sample
    float fStartTime;            //The current open profile start time
    float fAccumulator;          //All samples this frame added together
    float fChildrenSampleTime;   //Time taken by all children
    unsigned int iNumParents;            //Number of profile parents
} ProfileSample;
 
typedef struct {
    bool bValid;        //Whether the data is valid
    std::string szName;   //Name of the sample
    float fAve;         //Average time per frame (percentage)
    float fMin;         //Minimum time per frame (percentage)
    float fMax;         //Maximum time per frame (percentage)
} ProfileSampleHistory;
 
#define NUM_PROFILE_SAMPLES 50
ProfileSample g_samples[NUM_PROFILE_SAMPLES];
ProfileSampleHistory g_history[NUM_PROFILE_SAMPLES];
float g_startProfile = 0.0f;
float g_endProfile = 0.0f;
std::string outputBuffer = "";
 
void Profile::Init(void) {
    for (unsigned int i = 0; i < NUM_PROFILE_SAMPLES; i++) {
        g_samples[i].bValid = false;
        g_history[i].bValid = false;
    }
    g_startProfile = GetExactTime();
}
 
void Profile::Begin(const std::string& name) {
    unsigned int i = 0;
    while (i < NUM_PROFILE_SAMPLES && g_samples[i].bValid == true) {
        if (g_samples[i].szName == name) {
            //Found the sample
            g_samples[i].iOpenProfiles++;
            g_samples[i].iProfileInstances++;
            g_samples[i].fStartTime = GetExactTime();
            assert(g_samples[i].iOpenProfiles == 1); //max 1 open at once
            return;
        }
        i++;
    }
 
    if (i >= NUM_PROFILE_SAMPLES) {
        assert(!"Exceeded Max Available Profile Samples");
        return;
    }
 
    g_samples[i].szName = name;
    g_samples[i].bValid = true;
    g_samples[i].iOpenProfiles = 1;
    g_samples[i].iProfileInstances = 1;
    g_samples[i].fAccumulator = 0.0f;
    g_samples[i].fStartTime = GetExactTime();
    g_samples[i].fChildrenSampleTime = 0.0f;
}
 
 
void Profile::End(const std::string& name) {
    unsigned int i = 0;
    unsigned int numParents = 0;
    while (i < NUM_PROFILE_SAMPLES && g_samples[i].bValid == true) {
        if (g_samples[i].szName != name) {
            i++;
            continue; // not the sample we want, go to the next
        }
        unsigned int inner = 0;
        int parent = -1;
        float fEndTime = GetExactTime();
        g_samples[i].iOpenProfiles--;
 
        //Count all parents and find the immediate parent
        while (g_samples[inner].bValid == true) {
            if (g_samples[inner].iOpenProfiles > 0) {  //Found a parent (any open profiles are parents)
                numParents++;
                if (parent < 0) {  //Replace invalid parent (index)
                    parent = inner;
                }
                else if (g_samples[inner].fStartTime >= g_samples[parent].fStartTime) {
                    //Replace with more immediate parent
                    parent = inner;
                }
            }
            inner++;
        }
        g_samples[i].iNumParents = numParents; //Remember the current number of parents of the sample
 
        if (parent >= 0) {  //Record this time in fChildrenSampleTime (add it in)
            g_samples[parent].fChildrenSampleTime += fEndTime - g_samples[i].fStartTime;
        }
        //Save sample time in accumulator
        g_samples[i].fAccumulator += fEndTime - g_samples[i].fStartTime;
        return;
    }
}
 
void Profile::DumpOutputToBuffer(void) {
    unsigned int i = 0;
    g_endProfile = GetExactTime();
    outputBuffer.clear();
    outputBuffer += "  Ave :   Min :   Max :   # : Profile Name\n";
    outputBuffer += "--------------------------------------------\n";
    while (i < NUM_PROFILE_SAMPLES && g_samples[i].bValid == true) {
        unsigned int indent = 0;
        float sampleTime, percentTime;
        char line[256], name[256];
        std::string indentedName;
        char ave[16], min[16], max[16], num[16];
 
        if (g_samples[i].iOpenProfiles < 0) { assert(!"ProfileEnd() called without a ProfileBegin()"); }
        else if (g_samples[i].iOpenProfiles > 0) { assert(!"ProfileBegin() called without a ProfileEnd()"); }
 
        sampleTime = g_samples[i].fAccumulator - g_samples[i].fChildrenSampleTime;
        percentTime = (sampleTime / (g_endProfile - g_startProfile)) * 100.0f;
        
 
        //Add new measurement into the history and get the ave, min, and max
        StoreProfileInHistory(g_samples[i].szName, percentTime);
        auto [aveTime, minTime, maxTime] = GetProfileFromHistory(g_samples[i].szName);
 
        //TODO Format the data
        /*std::stringstream output;
        output << std::setprecision(4) <<;*/
        sprintf_s(ave, "%3.1f", aveTime);
        sprintf_s(min, "%3.1f", minTime);
        sprintf_s(max, "%3.1f", maxTime);
        sprintf_s(num, "%3d", g_samples[i].iProfileInstances);
 
        indentedName = g_samples[i].szName;
        for (indent = 0; indent < g_samples[i].iNumParents; indent++) {
            sprintf_s(name, "   %s", indentedName.c_str());
            indentedName = name;
        }
        sprintf_s(line, "%3s : %3s : %3s : %3s : %s\n", ave, min, max, num, indentedName.c_str());
        outputBuffer += line;   //Send the line to text buffer
        i++;
    }
    {  //Reset samples for next frame
        unsigned int j;
        for (j = 0; j < NUM_PROFILE_SAMPLES; j++) {
            g_samples[j].bValid = false;
        }
        g_startProfile = GetExactTime();
    }
}
 
void Profile::StoreProfileInHistory(const std::string& name, float percent) {
    unsigned int i = 0;
    float oldRatio;
    float newRatio = 0.8f * GetElapsedTime();
    if (newRatio > 1.0f) {
        newRatio = 1.0f;
    }
    oldRatio = 1.0f - newRatio;
    // TODO: replace with std::find
    for (auto& sample : g_history) {
        if (!sample.bValid) {
            break;
        }
        if (sample.szName != name) {
            i++;
            continue;
        }
 
        //Found the sample
        sample.fAve = (sample.fAve*oldRatio) + (percent*newRatio);
        if (percent > sample.fMax) {
            sample.fMax = percent;
        }
        if (percent < sample.fMin) {
            sample.fMin = percent;
        }
        else {
            sample.fMin = (sample.fMin*oldRatio) + (percent*newRatio);
        }
        if (sample.fMin < 0.0f) {
            sample.fMin = 0.0f;
        }
        else {
            sample.fMax = (sample.fMax*oldRatio) + (percent*newRatio);
        }
        return;
    }
 
    if (i < NUM_PROFILE_SAMPLES) {  //Add to history
        g_history[i].szName = name;
        g_history[i].bValid = true;
        g_history[i].fAve = g_history[i].fMin = g_history[i].fMax = percent;
    }
    else {
        assert(!"Exceeded Max Available Profile Samples!");
    }
}
 
Profile::SamplePoint Profile::GetProfileFromHistory(const std::string& name) {
    SamplePoint result{};
    for (auto& sample : g_history){
        if (sample.bValid == true && sample.szName == name) {
            result.ave = sample.fAve;
            result.max = sample.fMax;
            result.min = sample.fMin;
 
            return result;
        }
    }
    return result;
}
 
void Profile::Draw(void) {
    std::cout << outputBuffer << '\n';
}

Comments

  • Gyqizv icon
    04/02/26 06:21:05 PM UTC
    text |

    0 B

    |

    0 👍

    /

    0 👎

    Best t33n active cpx link daily updates!
     Copy and paste the link in a new browser tab and then hit enter!
     https://crazyporn.@xxx/members/157354/?asgtbndr=1&play=true&spon=adworld&zone=400
     Remove the @ 
  • Yuizcko icon
    05/18/26 01:06:29 PM UTC
    text |

    0 B

    |

    0 👍

    /

    0 👎

    Best t33n active cpx link daily updates!
     Copy and paste the link in a new browser tab and then hit enter!
     https://crazyporn.xxx/members/157354/?asgtbndr=1&play=true&spon=adworld&zone=400