1 /**********************************************************************
2 
3   Audacity: A Digital Audio Editor
4 
5   Profiler.cpp
6 
7   Created by Michael Chinen (mchinen) on 8/12/08
8   Audacity(R) is copyright (c) 1999-2008 Audacity Team.
9   License: GPL v2.  See License.txt.
10 
11 ******************************************************************//**
12 
13 \class Profiler
14 \brief A simple profiler to measure the average time lengths that a
15 particular task/function takes.  Currently not thread-safe and not thread-smart,
16 but it will probably work fine if you use it on a high level.
17 
18 \class TaskProfile
19 \brief a simple class to keep track of one task that may be called multiple times.
20 
21 *//*******************************************************************/
22 
23 
24 #include "Profiler.h"
25 
26 #include <stdio.h>
27 #include <string.h>
28 #include <wx/crt.h>
29 
30 ///write to a profile at the end of the test.
~Profiler()31 Profiler::~Profiler()
32 {
33    if(mTasks.size())
34    {
35       //print everything out.  append to a log.
36       FILE* log = fopen("AudacityProfilerLog.txt", "a");
37       time_t now;
38 
39       time(&now);
40       wxFprintf(log,"Audacity Profiler Run, Ended at ");
41       wxFprintf(log,"%s",ctime(&now));
42       wxFprintf(log,"****************************************\n");
43       //print out the tasks
44       for(int i=0;i<(int)mTasks.size();i++)
45       {
46          if(mTasks[i]->mNumHits>0)
47          {
48             wxFprintf(log,"Task: %s\n(begins at line %d in %s)\n\n",mTasks[i]->mDescription.get(), mTasks[i]->mLine, mTasks[i]->mFileName.get());
49             wxFprintf(log,"Number of times run: %d\n",mTasks[i]->mNumHits);
50             wxFprintf(log,"Total run time (seconds): %f\n", (double)mTasks[i]->mCumTime/CLOCKS_PER_SEC);
51             wxFprintf(log,"Average run time (seconds): %f\n",mTasks[i]->ComputeAverageRunTime());
52 
53             if(i < ((int)mTasks.size()) -1)
54                wxFprintf(log,"----------------------------\n");
55          }
56       }
57       wxFprintf(log,"\n****************************************\n\n\n");
58 
59       fclose(log);
60    }
61 }
62 
63 ///start the task timer.
Begin(const char * fileName,int lineNum,const char * taskDescription)64 void Profiler::Begin(const char* fileName, int lineNum, const char* taskDescription)
65 {
66    std::lock_guard<std::mutex> guard{ mTasksMutex };
67    GetOrCreateTaskProfile(fileName,lineNum)->Begin(fileName,lineNum,taskDescription);
68 }
69 
70 ///end the task timer.
End(const char * fileName,int lineNum,const char * taskDescription)71 void Profiler::End(const char* fileName, int lineNum, const char* taskDescription)
72 {
73    std::lock_guard<std::mutex> guard{ mTasksMutex };
74    TaskProfile* tp;
75    tp=GetTaskProfileByDescription(taskDescription);
76    if(tp)
77       tp->End(fileName,lineNum,taskDescription);
78 }
79 
80 ///Gets the singleton instance
Instance()81 Profiler* Profiler::Instance()
82 {
83    static Profiler pro;
84    //this isn't 100% threadsafe but I think Okay for this purpose.
85 
86    return &pro;
87 }
88 
89 ///find a taskProfile for the given task, otherwise create
GetOrCreateTaskProfile(const char * fileName,int lineNum)90 TaskProfile* Profiler::GetOrCreateTaskProfile(const char* fileName, int lineNum)
91 {
92    for(int i=0;i<(int)mTasks.size();i++)
93    {
94       if(strcmp(fileName, mTasks[i]->mFileName.get())==0 && lineNum == mTasks[i]->mLine)
95          return mTasks[i].get();
96    }
97 
98    auto tp = std::make_unique<TaskProfile>();
99    mTasks.push_back(std::move(tp));
100    return mTasks.back().get();
101 }
102 
GetTaskProfileByDescription(const char * description)103 TaskProfile* Profiler::GetTaskProfileByDescription(const char* description)
104 {
105    for(int i=0;i<(int)mTasks.size();i++)
106    {
107       if(strcmp(description, mTasks[i]->mDescription.get())==0)
108          return mTasks[i].get();
109    }
110 
111    return NULL;
112 
113 }
114 
115 
116 ///Task Profile
TaskProfile()117 TaskProfile::TaskProfile()
118 {
119    mCumTime=0;
120    mNumHits=0;
121 }
122 
~TaskProfile()123 TaskProfile::~TaskProfile()
124 {
125 }
126 
127 ///start the task timer.
Begin(const char * fileName,int lineNum,const char * taskDescription)128 void TaskProfile::Begin(const char* fileName, int lineNum, const char* taskDescription)
129 {
130    if(!mFileName)
131    {
132       mFileName.reinit( strlen(fileName) + 1 );
133       strcpy(mFileName.get(), fileName);
134       mDescription.reinit( strlen(taskDescription) + 1 );
135       strcpy(mDescription.get(), taskDescription);
136       mLine = lineNum;
137    }
138 
139    mLastTime = clock();
140 
141 }
142 
143 ///end the task timer.
End(const char * WXUNUSED (fileName),int WXUNUSED (lineNum),const char * WXUNUSED (taskDescription))144 void TaskProfile::End(const char* WXUNUSED(fileName), int WXUNUSED(lineNum), const char* WXUNUSED(taskDescription))
145 {
146    mCumTime += clock() - mLastTime;
147    mNumHits++;
148 }
149 
ComputeAverageRunTime()150 double TaskProfile::ComputeAverageRunTime()
151 {
152    if(mNumHits)
153       return (double) ((double)mCumTime/CLOCKS_PER_SEC)/mNumHits;
154    else
155       return 0.0;
156 }
157