00001 #include <sys/time.h>
00002 #include <cstdlib>
00003 #include <cmath>
00004
00005 #include "mythlogging.h"
00006 #include "jitterometer.h"
00007
00008 #define UNIX_PROC_STAT "/proc/stat"
00009 #define MAX_CORES 8
00010
00011 Jitterometer::Jitterometer(const QString &nname, int ncycles)
00012 : count(0), num_cycles(ncycles), starttime_valid(0), last_fps(0),
00013 last_sd(0), name(nname), cpustat(NULL), laststats(NULL)
00014 {
00015 times.resize(num_cycles);
00016 memset(&starttime, 0, sizeof(struct timeval));
00017
00018 if (name.isEmpty())
00019 name = "Jitterometer";
00020
00021 #ifdef __linux__
00022 if (QFile::exists(UNIX_PROC_STAT))
00023 {
00024 cpustat = new QFile(UNIX_PROC_STAT);
00025 if (cpustat)
00026 {
00027 if (!cpustat->open(QIODevice::ReadOnly))
00028 {
00029 delete cpustat;
00030 cpustat = NULL;
00031 }
00032 else
00033 {
00034 laststats = new unsigned long long[MAX_CORES * 9];
00035 }
00036 }
00037 }
00038 #endif
00039 }
00040
00041 Jitterometer::~Jitterometer()
00042 {
00043 if (cpustat)
00044 cpustat->close();
00045 delete cpustat;
00046 delete [] laststats;
00047 }
00048
00049 void Jitterometer::SetNumCycles(int cycles)
00050 {
00051 num_cycles = cycles;
00052 times.resize(num_cycles);
00053 count = 0;
00054 }
00055
00056 bool Jitterometer::RecordCycleTime()
00057 {
00058 if (!num_cycles)
00059 return false;
00060 bool ret = RecordEndTime();
00061 RecordStartTime();
00062 return ret;
00063 }
00064
00065 bool Jitterometer::RecordEndTime()
00066 {
00067 if (!num_cycles)
00068 return false;
00069
00070 int cycles = num_cycles;
00071 struct timeval timenow;
00072 gettimeofday(&timenow, NULL);
00073
00074 if (starttime_valid)
00075 {
00076 times[count] = (timenow.tv_sec - starttime.tv_sec ) * 1000000 +
00077 (timenow.tv_usec - starttime.tv_usec) ;
00078 count++;
00079 }
00080
00081 starttime_valid = 0;
00082
00083 if (count >= cycles)
00084 {
00085
00086 double mean = 0, sum_of_squared_deviations=0;
00087 double standard_deviation;
00088 double tottime = 0;
00089 int i;
00090
00091
00092 for(i = 0; i < cycles; i++)
00093 mean += times[i];
00094
00095 tottime = mean;
00096 mean /= cycles;
00097
00098 if (tottime > 0)
00099 last_fps = cycles / tottime * 1000000;
00100
00101
00102 for(i = 0; i < cycles; i++)
00103 sum_of_squared_deviations += (mean - times[i]) * (mean - times[i]);
00104
00105
00106 standard_deviation = sqrt(sum_of_squared_deviations / (cycles - 1));
00107 if (mean > 0)
00108 last_sd = standard_deviation / mean;
00109
00110
00111 QString extra;
00112 lastcpustats = GetCPUStat();
00113 if (!lastcpustats.isEmpty())
00114 extra = QString("CPUs: ") + lastcpustats;
00115
00116 LOG(VB_GENERAL, LOG_INFO,
00117 name + QString("FPS: %1 Mean: %2 Std.Dev: %3 ")
00118 .arg(last_fps, 7, 'f', 2).arg((int)mean, 5)
00119 .arg((int)standard_deviation, 5) + extra);
00120
00121 count = 0;
00122 return true;
00123 }
00124 return false;
00125 }
00126
00127 void Jitterometer::RecordStartTime()
00128 {
00129 if (!num_cycles)
00130 return;
00131 gettimeofday(&starttime, NULL);
00132 starttime_valid = 1;
00133 }
00134
00135 QString Jitterometer::GetCPUStat(void)
00136 {
00137 if (!cpustat)
00138 return "N/A";
00139
00140 #ifdef __linux__
00141 QString res;
00142 cpustat->seek(0);
00143 cpustat->flush();
00144
00145 QByteArray line = cpustat->readLine(256);
00146 if (line.isEmpty())
00147 return res;
00148
00149 int cores = 0;
00150 int ptr = 0;
00151 line = cpustat->readLine(256);
00152 while (!line.isEmpty() && cores < MAX_CORES)
00153 {
00154 static const int size = sizeof(unsigned long long) * 9;
00155 unsigned long long stats[9];
00156 memset(stats, 0, size);
00157 int num = 0;
00158 if (sscanf(line.constData(),
00159 "cpu%30d %30llu %30llu %30llu %30llu %30llu "
00160 "%30llu %30llu %30llu %30llu %*5000s\n",
00161 &num, &stats[0], &stats[1], &stats[2], &stats[3],
00162 &stats[4], &stats[5], &stats[6], &stats[7], &stats[8]) >= 4)
00163 {
00164 float load = stats[0] + stats[1] + stats[2] + stats[4] +
00165 stats[5] + stats[6] + stats[7] + stats[8] -
00166 laststats[ptr + 0] - laststats[ptr + 1] -
00167 laststats[ptr + 2] - laststats[ptr + 4] -
00168 laststats[ptr + 5] - laststats[ptr + 6] -
00169 laststats[ptr + 7] - laststats[ptr + 8];
00170 float total = load + stats[3] - laststats[ptr + 3];
00171 if (total > 0)
00172 res += QString("%1% ").arg(load / total * 100, 0, 'f', 0);
00173 memcpy(&laststats[ptr], stats, size);
00174 }
00175 line = cpustat->readLine(256);
00176 cores++;
00177 ptr += 9;
00178 }
00179 return res;
00180 #else
00181 return "N/A";
00182 #endif
00183 }