[讨论] 想获得当前JVM所有线程的CPU时间却有问题

michael9527 2012-03-15
主要代码如下:
			for(ThreadInfo ti:threadInfo) {
				long id = ti.getThreadId();
//					long userCpuTime = threadXMbean.getThreadUserTime(id);
				long userCpuTime = threadXMbean.getThreadCpuTime(id);
				totalCpuTime += userCpuTime;
			}


其中新起了一个线程,执行一个死循环,之后由一个后台线程检查当前JVM的所有线程CPU时间,检查间隔是每10秒一次。
这里获得的 totalCpuTime 是毫微秒级的,当然这个不是重点,
重点是这个值居然会不断的增大。

我打出来的结果就是:
3078
10000
13078
19953
23015
29937
33000
39906
42968
49906
52968
59859
62968
69781
72968
79765
82953
89765
92937
99703
102921
109687

按理说应该是一个固定的值,至少波动不会很大,但是打出来的值却是明显在不断增长,这就很奇怪了。

RednaxelaFX 2012-03-15
感觉上下文不足…为什么你的测试的输出应该是个固定的值?

http://docs.oracle.com/javase/6/docs/api/java/lang/management/ThreadMXBean.html?is-external=true#getThreadCpuTime(long)
引用
Returns:
the total CPU time for a thread of the specified ID if the thread of the specified ID exists, the thread is alive, and CPU time measurement is enabled; -1 otherwise.

只要某个线程有在跑,它的CPU time肯定是不断增加的。没看懂你想得到的是什么数据…
michael9527 2012-03-16
呵呵,没说明白,我整理一下。
假设现在JVM里面只有2个我自己产生的线程,一个main线程,用于执行消耗CPU计算的一些任务,另外一个定时线程,每10秒检查一下当前JVM中所有线程的cpu时间,它会将所有线程的CPU时间相加,然后打印出来。

那个消耗CPU计算的线程执行了一些复杂的运算,首先随机产生10位的字符串,然后对这个字符串的每一位字符执行一些异或操作,再对其中的字符进行一些加加减减。这些运JVM应该不至于能优化掉。整个执行过程是一个while(true),所以大体来说这个线程消耗的时间应该相对固定,比如执行10秒钟,此线程会消耗三秒的CPU时间。

不过我打印出来,这个时间是会增长的,ok,那就减去。

public static final long _10SECOND = 10*1000L;
private static final int DIV_TIME_UNIT = 1000 * 1000;
long result = totalCpuTime/DIV_TIME_UNIT;
System.out.println("原始值:"+result+"   减去后的值:"+(result - _10SECOND * cycle++));


由于调用JMX获取的时间是毫微秒的所以需要除以 1000*1000。
最后打印的时间是:

原始值:2921   减去后的值:2921
原始值:12593   减去后的值:2593
原始值:22296   减去后的值:2296
原始值:31890   减去后的值:1890
原始值:41468   减去后的值:1468
原始值:51203   减去后的值:1203
原始值:60953   减去后的值:953
原始值:70531   减去后的值:531
原始值:80281   减去后的值:281
原始值:89859   减去后的值:-141
原始值:99578   减去后的值:-422

不清楚这个CPU时间增长是按照什么规律增长的。从前几次看这个线程每10秒 大约会消耗3秒左右的CPU时间。
RednaxelaFX 2012-03-16
首先,你的totalCpuTime是累计了所有线程的还是只累计了一个目标线程的CPU时间?希望是前者,不然最初的数据就已经无意义了。

其次,本来最初几轮跑得就是会慢一些的。最初所有Java方法都在解释器里跑,逐渐有些方法被动态编译了,跑得会快些。减去固定的“单位时间”×cycle数没啥意义,这模型本身就不对。
michael9527 2012-03-16
累计的是所有线程的值,获取了所有线程的cpu时间,当然相加。

我的目的就是想获得一个固定时间内,比如10秒,60秒内,JVM中所有线程的CPU时间。
所以需要减去一个固定的值。我试了一下启动的时候加了-Xint结果还是一样的,还是不断减小:(每十秒输出一次)
原始值:3171   减去后的值:3171
原始值:13015   减去后的值:3015
原始值:22984   减去后的值:2984
原始值:32937   减去后的值:2937
原始值:42906   减去后的值:2906
原始值:52828   减去后的值:2828
原始值:62796   减去后的值:2796
原始值:72796   减去后的值:2796
原始值:82781   减去后的值:2781
原始值:92781   减去后的值:2781
原始值:102781   减去后的值:2781
原始值:112781   减去后的值:2781
原始值:122765   减去后的值:2765
原始值:132718   减去后的值:2718
原始值:142640   减去后的值:2640


杯具,请教下RednaxelaFX ,如果想达到最初的目的,统计10秒内整个JVM中的所有线程CPU时间,这个实现应该怎么做好呢?
RednaxelaFX 2012-03-16
实在是无法理解…抱歉,我可能帮不上忙了,得找能理解你的需求的真正的高手上阵才行

无法理解的是你为什么要减去一个固定的值。那个值又没有足够的依据说明它是有意义的。得出的数据是什么来的?

为什么不每次记录下这次收集到的总时间,减去上次收集到的总时间得到一个差值,并根据收集数据两个时间点之间的时间间隔来调整输出,然后再输出结果?
如果这个结果有浮动,那可以再讨论。
另外执行的时间要足够长,前几轮的结果全部抛弃掉。如果是我来测的话我或许会抛弃掉头3分钟的结果。如果你的测试本身连半分钟都不到那我也不知道你想看的是什么…
michael9527 2012-03-16
即便是有一段时间的热身,输出的值还是有点怪异。
启动2个线程,一个消耗CPU的线程,一个计算所有线程CPU时间的线程。
计算CPU时间的线程是过了5分钟再启动的,之后每10秒打印一次结果。打印内容是这次计算的所有线程CPU时间总和 - 上次计算的所有线程CPU时间总和 。打印的结果是一个慢慢增加的:

288218
9500
297656
19171
307093
28843
316640
38437
326296
48062
336078
57500
345718
67281
355312
76734
364937
86328
374531
95921
384109
105484
393703
115000
403296
124671
412828
134156
422312
143906
431843
153500
441562
163156
451062
172796
460750
182468
470187
192078
479843
201765
489671
211250
499265
220718
508812
230125
518265
239718
527843
249421
537421
259156
547046
268781
556500
278515
566046

两次打印间隔就是10秒,看这个结果奇数次会大些,偶数次会小些,总体都不断变大。
因为是一个死循环执行一些耗时任务,所以每次的CPU时间应该不会差别很大,应该是在一个范围之内的,不过这个打印结果来看,可能还是我的计算方式不对。
Global site tag (gtag.js) - Google Analytics