00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #include "NvApplicationProfiler.h"
00030 #include <fstream>
00031 #include <sstream>
00032 #include <pthread.h>
00033 #include <string.h>
00034 #include <sys/types.h>
00035 #include <unistd.h>
00036
00037 #define GOVERNOR_SYS_FILE "/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor"
00038 #define CPU_FREQ_FILE "/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq"
00039 #define REQUIRED_GOVERNOR "performance"
00040
00041 #define TIMESPEC_DIFF_USEC(timespec1, timespec2) \
00042 (timespec1.tv_sec - timespec2.tv_sec) * 1000000.0 + \
00043 (timespec1.tv_nsec - timespec2.tv_nsec) / 1000.0
00044
00045 using namespace std;
00046
00047 NvApplicationProfiler::NvApplicationProfiler()
00048 {
00049 char governor[64];
00050 uint64_t cpu_freq_khz;
00051
00052 memset(&data, 0, sizeof(data));
00053
00054 running = false;
00055
00056 data.max_cpu_usage = 0;
00057 data.min_cpu_usage = 100;
00058 sampling_interval = DefaultSamplingInterval;
00059
00060 profiling_thread = 0;
00061 pthread_mutex_init(&thread_lock, NULL);
00062 check_cpu_usage = true;
00063
00064 ifstream cpu_governor_file(GOVERNOR_SYS_FILE, std::ifstream::in);
00065 cpu_governor_file >> governor;
00066 if (strcmp(governor, REQUIRED_GOVERNOR))
00067 {
00068 cerr << "Set governor to " REQUIRED_GOVERNOR " before enabling profiler"
00069 << endl;
00070 check_cpu_usage = false;
00071 }
00072 num_cpu_cores = sysconf(_SC_NPROCESSORS_ONLN);
00073
00074 ifstream cpu_freq_file(CPU_FREQ_FILE, std::ifstream::in);
00075 cpu_freq_file >> cpu_freq_khz;
00076 cpu_freq = cpu_freq_khz / 1000;
00077 }
00078
00079 NvApplicationProfiler&
00080 NvApplicationProfiler::getProfilerInstance()
00081 {
00082 static NvApplicationProfiler profiler;
00083 return profiler;
00084 }
00085
00086 void
00087 NvApplicationProfiler::start(uint32_t sampling_interval_ms)
00088 {
00089
00090 pthread_mutex_lock(&thread_lock);
00091
00092 if (running)
00093 {
00094 pthread_mutex_unlock(&thread_lock);
00095 return;
00096 }
00097
00098 if (!check_cpu_usage)
00099 {
00100 cerr << "Set governor to " REQUIRED_GOVERNOR " before enabling profiler"
00101 << endl;
00102 pthread_mutex_unlock(&thread_lock);
00103 return;
00104 }
00105
00106 running = true;
00107 sampling_interval = sampling_interval_ms;
00108
00109 memset(&data, 0, sizeof(data));
00110
00111 gettimeofday(&data.start_time, NULL);
00112
00113 if (check_cpu_usage)
00114 {
00115 clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &data.start_proc_cpu_clock_time);
00116 clock_gettime(CLOCK_MONOTONIC, &data.start_cpu_clock_time);
00117 }
00118
00119 pthread_create(&profiling_thread, NULL, ProfilerThread, this);
00120
00121 pthread_mutex_unlock(&thread_lock);
00122 }
00123
00124 void
00125 NvApplicationProfiler::stop()
00126 {
00127 running = false;
00128 pthread_join(profiling_thread, NULL);
00129
00130 pthread_mutex_lock(&thread_lock);
00131 gettimeofday(&data.stop_time, NULL);
00132 pthread_mutex_unlock(&thread_lock);
00133 }
00134
00135 void
00136 NvApplicationProfiler::profile()
00137 {
00138 if (check_cpu_usage)
00139 {
00140 struct timespec cur_proc_cpu_clock_time;
00141 struct timespec cur_cpu_clock_time;
00142
00143 clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &cur_proc_cpu_clock_time);
00144 clock_gettime(CLOCK_MONOTONIC, &cur_cpu_clock_time);
00145
00146 if (data.num_readings)
00147 {
00148 float proc_cpu_time = TIMESPEC_DIFF_USEC(cur_proc_cpu_clock_time,
00149 data.stop_proc_cpu_clock_time);
00150
00151 float total_cpu_time = TIMESPEC_DIFF_USEC(cur_cpu_clock_time,
00152 data.stop_cpu_clock_time);
00153
00154 float cpu_usage = proc_cpu_time * 100 / total_cpu_time;
00155 if (cpu_usage < data.min_cpu_usage && cpu_usage > 0)
00156 {
00157 data.min_cpu_usage = cpu_usage;
00158 }
00159 if (cpu_usage > data.max_cpu_usage)
00160 {
00161 data.max_cpu_usage = cpu_usage;
00162 }
00163 }
00164
00165 data.stop_proc_cpu_clock_time = cur_proc_cpu_clock_time;
00166 data.stop_cpu_clock_time = cur_cpu_clock_time;
00167 }
00168 data.num_readings++;
00169 }
00170
00171 void *
00172 NvApplicationProfiler::ProfilerThread(void * data)
00173 {
00174 NvApplicationProfiler *profiler = (NvApplicationProfiler *) data;
00175 struct timespec next_profile_time;
00176 struct timeval now;
00177 pthread_cond_t sleep_cond;
00178
00179 pthread_cond_init(&sleep_cond, NULL);
00180
00181 gettimeofday(&now, NULL);
00182 next_profile_time.tv_sec = now.tv_sec;
00183 next_profile_time.tv_nsec = now.tv_usec * 1000L;
00184
00185 pthread_mutex_lock(&profiler->thread_lock);
00186 while (profiler->running)
00187 {
00188 pthread_cond_timedwait(&sleep_cond, &profiler->thread_lock,
00189 &next_profile_time);
00190 profiler->profile();
00191
00192 next_profile_time.tv_sec += profiler->sampling_interval / 1000;
00193 next_profile_time.tv_nsec += (profiler->sampling_interval % 1000) * 1000000L;
00194 next_profile_time.tv_sec += next_profile_time.tv_nsec / 1000000000L;
00195 next_profile_time.tv_nsec %= 1000000000L;
00196
00197 }
00198 pthread_mutex_unlock(&profiler->thread_lock);
00199
00200 return NULL;
00201 }
00202
00203 void
00204 NvApplicationProfiler::getProfilerData(NvAppProfilerData &pdata)
00205 {
00206 pthread_mutex_lock(&thread_lock);
00207
00208 memset (&pdata, 0, sizeof(pdata));
00209
00210 if (check_cpu_usage)
00211 {
00212 float proc_cpu_time = TIMESPEC_DIFF_USEC(data.stop_proc_cpu_clock_time,
00213 data.start_proc_cpu_clock_time);
00214
00215 float total_cpu_time = TIMESPEC_DIFF_USEC(data.stop_cpu_clock_time,
00216 data.start_cpu_clock_time);
00217
00218 pdata.peak_cpu_usage = data.max_cpu_usage / num_cpu_cores;
00219 pdata.avg_cpu_usage = proc_cpu_time * 100 / total_cpu_time / num_cpu_cores;
00220
00221 pdata.total_time.tv_sec = data.stop_time.tv_sec - data.start_time.tv_sec;
00222 pdata.total_time.tv_usec = data.stop_time.tv_usec - data.start_time.tv_usec;
00223 if (pdata.total_time.tv_usec < 0)
00224 {
00225 pdata.total_time.tv_sec--;
00226 pdata.total_time.tv_usec += 1000000;
00227 }
00228
00229 pdata.num_cpu_cores = num_cpu_cores;
00230 pdata.cpu_freq_mhz = cpu_freq;
00231 }
00232
00233 pthread_mutex_unlock(&thread_lock);
00234 }
00235 void
00236 NvApplicationProfiler::printProfilerData(std::ostream &outstream)
00237 {
00238 NvAppProfilerData data;
00239 getProfilerData(data);
00240 outstream << "************************************" << endl;
00241 outstream << "Total Profiling Time = " <<
00242 (data.total_time.tv_sec + 0.000001 * data.total_time.tv_usec) <<
00243 " sec" << endl;
00244 if (check_cpu_usage)
00245 {
00246 outstream << "Peak CPU Usage = " << data.peak_cpu_usage << "%" << endl;
00247 outstream << "Avg CPU Usage = " << data.avg_cpu_usage << "%" << endl;
00248 outstream << "Num. of Cores = " << data.num_cpu_cores << endl;
00249 outstream << "CPU frequency = " << data.cpu_freq_mhz << "MHz" << endl;
00250 }
00251 outstream << "************************************" << endl;
00252 }
00253