我正在计算进程/线程正在使用的cpu时间与调用某个函数之间的差值。
我为进程cpu时间获得了不可能的值,有时候下一次调用返回较小的cpu时间,这是不可能的。
这是我用来计算cpu时间的代码:
u64 CpuTime::calculateCpuTime(bool a_thread)
{
struct rusage l_rusage;
int retVal;
if(a_thread)
{
retVal = getrusage(1, &l_rusage); //1 = RUSAGE_THREAD
}
else
{
retVal = getrusage(0, &l_rusage); //0 = RUSAGE_SELF
}
ASSERT(retVal==0);
u64 userUSeconds = (static_cast<u64>(l_rusage.ru_utime.tv_sec)*1000000)+
(static_cast<u64>(l_rusage.ru_utime.tv_usec));
u64 systemUSeconds = (static_cast<u64>(l_rusage.ru_stime.tv_sec)*1000000)+
(static_cast<u64>(l_rusage.ru_stime.tv_usec));
if(a_thread)
{
return userUSeconds + systemUSeconds;
}
return (userUSeconds + systemUSeconds) / ACE_OS::num_processors_online();
}
计算检索它的函数也是异步的,一次只能有1个线程访问它。
这是不可能的输出(过程)的一个例子:
2016/03/23 13:39:05.187 - #2 - 15471/15055 - ThreadDeltaCpuTime = 6000 ThreadCpuTime = 46756013 ProcessCpuTime = 39820759 deltaProcessCpuTime = 250
2016/03/23 13:39:05.386 - #2 - 15470/15055 - ThreadDeltaCpuTime = 5000 ThreadCpuTime = 46663013 ProcessCpuTime = 39699759 deltaProcessCpuTime = 18446744073709430616
delta计算是一个简单的newValue - oldValue,带有unsigned int,它会导致这些数字。
无法线程输出的示例:
2016/03/23 13:38:59.183 - #2 - 15472 / 15055 - ThreadDeltaCpuTime = 6000 ThreadCpuTime = 47541012 ProcessCpuTime = 39658134 deltaProcessCpuTime = 5250
2016/03/23 13:38:59.382 - #2 - 15472 / 15055 - ThreadDeltaCpuTime = 1844年 6744073708557617 ThreadCpuTime = 46547013 ProcessCpuTime = 39663009 deltaProcessCpuTime = 4625
我已经加粗了线程ID,也可以看到该函数在第一个1之后已经执行了200ms。
我正在寻找发生这种情况的线索,我也试过使用ACE_OS rusage,结果相同(有意义),我可以通过忽略&#34;坏&#34;来解决这个问题。价值观,但我想知道为什么会这样。
编辑:
这是我进行实际打印的地方:
u64 computeCpuTime()
{
u64 deltaCpuTime= CpuTime::getThreadDeltaCpuTime();
u64 CpuTime= getThreadCpuTime();
u64 ProcessCpuTime= getProcessCpuTime();
u64 deltaProcessCpuTime= CpuTime::getProcessDeltaCpuTime();
Log<<value(deltaCpuTime)<<value(CpuTime)<<value(ProcessCpuTime)<<value(deltaProcessCpuTime)<<endlog;
return deltaCpuTime;
}
此计算中使用的其余函数:
u64 CpuTime::getThreadDeltaCpuTime()
{
pid_t thisThread = (pid_t) syscall (SYS_gettid);
u64& val = m_threadsCpuMap[thisThread];
u64 oldValue =val;
val = calculateCpuTime(true);
return val - oldValue;
}
u64 CpuTime::getProcessDeltaCpuTime()
{
u64 oldValue = m_processCpu;
m_processCpu = calculateCpuTime(false);
return m_processCpu - oldValue;
}
u64 getThreadCpuTime()
{
return CpuTime::calculateCpuTime(true);
}
u64 getProcessCpuTime()
{
return CpuTime::calculateCpuTime(false);
}
执行系统调用的对象(&#34; m_cpuTime&#34;)是一个单例,受互斥锁保护,一次只能有1个线程访问它。
它包含线程cpu用法的映射,m_threadsCpuMap(用于delta),以及最后一个进程cpu用法,m_processCpu。
另一个编辑:
我通过一个简单的测试简化了它,使用单个线程,通过活动cpu删除了除法,并且只检查Process Cpu时间,但结果仍然不可能。
以下是更新的功能:
测试:
for(int i = 0; i < 100000 ; i++)
{
for(int k = 0; k < 1000000; k++)
m = k % i;
cpuTime = CpuTime::instance()->getProcessDeltaCpuTime();
}
测试中使用的函数:
u64 CpuTime::getProcessDeltaCpuTime()
{
u64 oldValue = m_processCpu;
m_processCpu = calculateCpuTime(eThisProcess);
Log<<value(oldValue)<<value(m_processCpu)<value( m_processCpu - oldValue)<<endlog;
return m_processCpu - oldValue;
}
u64 CpuTime::calculateCpuTime(int a_type)
{
struct rusage l_rusage;
int retVal;
if(a_type == eThisThread)
{
retVal = /*ACE_OS::*/getrusage(1, &l_rusage);
}
else
{
retVal = /*ACE_OS::*/getrusage(0, &l_rusage);
}
u64 userUSeconds = (static_cast<u64>(l_rusage.ru_utime.tv_sec)*1000000)+
(static_cast<u64>(l_rusage.ru_utime.tv_usec));
u64 systemUSeconds = (static_cast<u64>(l_rusage.ru_stime.tv_sec)*100000)+
(static_cast<u64>(l_rusage.ru_stime.tv_usec));
if(a_type == eThisThread)
{
return userUSeconds + systemUSeconds;
}
return (userUSeconds + systemUSeconds)/* / ACE_OS::num_processors_online()*/;
这是日志的一个例子,我已经删除了delta为0的所有时间
2016/03/29 08:07:05.198 - #2 - 24011/24011 - CpuTime :: getProcessDeltaCpuTime:oldValue = 14797750 m_processCpu = 14798749 m_process Cpu - oldValue = 999
2016/03/29 08:07:05.199 - #2 - 24011/24011 - CpuTime :: getProcessDeltaCpuTime:oldValue = 14798749 m_processCpu = 14799749 m_process Cpu - oldValue = 1000
2016年3月29日 08:07:05.200 - #2 - 24011/24011 - CpuTime :: getProcessDeltaCpuTime: oldValue = 14799749 m_processCpu = 14800749 m_process Cpu - oldValue = 1000
2016/03/29 08:07:05.201 - #2 - 24011/24011 - CpuTime :: getProcessDeltaCpuTime:oldValue = 14800749 m_processCpu = 14801749 m_process Cpu - oldValue = 1000
2016/03/29 08:07:05.202 - #2 - 24011/24011 - CpuTime :: getProcessDeltaCpuTime:oldValue = 14801749 m_processCpu = 14802749 m_process Cpu - oldValue = 1000
2016/03/29 08:07:05.203 - #2 - 24011/24011 - CpuTime :: getProcessDeltaCpuTime: oldValue = 14802749 m_processCpu = 13903748 m_process Cpu - oldValue = 18446744073708652615
2016/03/29 08:07:05.204 - #2 - 24011/24011 - CpuTime :: getProcessDeltaCpuTime:oldValue = 13903748 m_processCpu = 13904748 m_process Cpu - oldValue = 1000
2016/03/29 08:07:05.205 - #2 - 24011/24011 - CpuTime :: getProcessDeltaCpuTime:oldValue = 13904748 m_processCpu = 13905748 m_process Cpu - oldValue = 1000
这次在100000次迭代中只有 1 的错误值时间。 之后所有以下计算也都较小,例如它是这样的: 1 2 3 4 5 6 7 8 9 10 不良值,6 7 8 9 10 ... 好像这个过程失去了数量,然后回去,然后继续正常。
YET ANOUTHER编辑:
我完全分开了代码,尽可能简单地编译它。问题没有发生,可能是概率问题(以前是1/100000)。 这是代码:
int main()
{
long int n = 0;
long int oldValue = 0;
long int newValue = 0;
unsigned long int deltaValue = 0;
for(int i = 0; i < 1000000; i++)
{
for(long int m = 0; m <10000; m++)
n = m + i;
struct rusage l_rusage;
int retVal;
retVal = getrusage(0, &l_rusage);
if(retVal != 0) return 0;
long int userUSeconds = l_rusage.ru_utime.tv_sec*1000000 + l_rusage.ru_utime.tv_usec;
long int systemUSeconds = l_rusage.ru_stime.tv_sec*100000 + l_rusage.ru_stime.tv_usec;
oldValue = newValue;
newValue = userUSeconds + systemUSeconds;
deltaValue = newValue - oldValue;
if(deltaValue != 0)
std::cout<<"Old value: "<< oldValue <<" New Value: "<< newValue <<" Delta value: "<<deltaValue<<"\n";
}
std::cout<<n;
return 0;
}
通过进一步研究早期的测试(使用我们的单元测试框架),问题总是发生在大约相同的CPU时间。 这意味着这种情况正在发生,我只是无法弄清楚在那个确切的时间会发生什么,这可能会导致这样的事情。 或者如何引起这样的事情。
我对linux内核不太熟悉,无法理解如何进行此计算。
另一个见解 - 使用clock()来获取进程。它不会发生,甚至更多 - 似乎直到那一刻价值大致相同,在这一点之后它们不是:
2016/03/29 12:36:19.158 - #2 - 20544/20544 - CpuTime :: getProcessDeltaCpuTime:oldValue = 14598780 m_processCpu = 14598780 m_processCpu - oldValue = 0 oldClockTime = 14580000 m_clockTime = 14580000 m_clockTime - oldClockTime = 0
2016/03/29 12:36:19.158 - #2 - 20544/20544 - CpuTime :: getProcessDeltaCpuTime: oldValue = 14598780 m_processCpu = 13699779 m_processCpu - oldValue = 18446744073708652615 oldClockTime = 14580000 m_clockTime = 14590000 m_clockTime - oldClockTime = 10000
2016/03/29 12:36:19.158 - #2 - 20544/20544 - CpuTime :: getProcessDeltaCpuTime:oldValue = 13699779 m_processCpu = 13699779 m_processCpu - oldValue = 0 oldClockTime = 14590000 m_clockTime = 14590000 m_clockTime - oldClockTime = 0
这引出了一个不同的问题,如何计算rusage,以及clock()如何?什么可能导致他们之间的差异?
我已经解决了这个问题,使用clock_gettime测量它,如果有任何1感兴趣,这里是代码:
u64 CpuMeasure::calculateCpuTime(int a_type)
{
struct timespec ts;
if(a_type == eThisThread)
{
if (ACE_OS::clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts) == 0)
{
return (u64)ts.tv_sec * 1000000 + (u64)ts.tv_nsec / 1000; //From nano to mili seconds
}
}
else
{
if (ACE_OS::clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts) == 0)
{
return (u64)ts.tv_sec * 1000000 + (u64)ts.tv_nsec / 1000;
}
}
ASSERT(false); //we cant be here, unless some thing bad happened
return 0;
}
我使用ACE_OS来实现可移植性,但它可以使用sys / time.h中的默认函数
然而,我仍然对 rusage奇怪的行为有疑问,这可能会导致它给出这些价值。
答案 0 :(得分:4)
仔细检查这些行:您将系统时间秒乘以10万而不是100万:
u64 userUSeconds = (static_cast<u64>(l_rusage.ru_utime.tv_sec)*1000000)+
(static_cast<u64>(l_rusage.ru_utime.tv_usec));
u64 systemUSeconds = (static_cast<u64>(l_rusage.ru_stime.tv_sec)*100000)+
(static_cast<u64>(l_rusage.ru_stime.tv_usec));
他们在你所展示的三个例子中有两个(不在第一个例子中)。
然而,这可以解释奇数序列:
2016/03/29 08:07:05.201 - #2 - 24011/24011 - CpuTime :: getProcessDeltaCpuTime:oldValue = 14800749 m_processCpu = 14801749 m_process Cpu - oldValue = 1000
2016/03/29 08:07:05.202 - #2 - 24011/24011 - CpuTime :: getProcessDeltaCpuTime:oldValue = 14801749 m_processCpu = 14802749 m_process Cpu - oldValue = 1000
2016/03/29 08:07:05.203 - #2 - 24011/24011 - CpuTime :: getProcessDeltaCpuTime:oldValue = 14802749 m_processCpu = 13903748 m_process Cpu - oldValue = 18446744073708652615
2016/03/29 08:07:05.204 - #2 - 24011/24011 - CpuTime :: getProcessDeltaCpuTime:oldValue = 13903748 m_processCpu = 13904748 m_process Cpu - oldValue = 1000
每次迭代都会增加1000美元。但我想,只要系统时间超过一秒,就只增加1/10秒,导致-0.9秒的移位恰好为14.8 - > 13.9秒。
事实上:
18446744073708652615 - 2^64 + 1 = -899000
即-900000(0.9秒)+ 1000 us