- Main Page
- Modules
- Namespaces
- Classes
- Files

- Search for |

- File List
- File Members

# samples/common/classes/NvApplicationProfiler.cpp

Go to the documentation of this file.

    00001 /*
    00002  * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
    00003  *
    00004  * Redistribution and use in source and binary forms, with or without
    00005  * modification, are permitted provided that the following conditions
    00006  * are met:
    00007  *  * Redistributions of source code must retain the above copyright
    00008  *    notice, this list of conditions and the following disclaimer.
    00009  *  * Redistributions in binary form must reproduce the above copyright
    00010  *    notice, this list of conditions and the following disclaimer in the
    00011  *    documentation and/or other materials provided with the distribution.
    00012  *  * Neither the name of NVIDIA CORPORATION nor the names of its
    00013  *    contributors may be used to endorse or promote products derived
    00014  *    from this software without specific prior written permission.
    00015  *
    00016  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
    00017  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    00018  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
    00019  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
    00020  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
    00021  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
    00022  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
    00023  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
    00024  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    00025  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    00026  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    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