扫码阅读
手机扫码阅读

CPU火焰图初探-优化0.1%

57 2024-04-13

早就听过CPU火焰图的强大功能,也听过几个火焰图工具,今天终于开始尝试使用CPU火焰图生成工具。

奈何由于各种原因,Intellij自带的火焰图插件并不能用,着实让人不快。故而找到一个async-profiler分析工具作为替代品。

当时正在测试随机数性能的,所以就用了一个动态QPS模型的Case,学习了async-profiler的使用。很意外地发现了一个性能可以优化的地方。经过尝试,CPU使用率降低了0.1%,也算是第一个成果了。

async-profiler

这个工具安装和使用教程,可以网上搜一下,建议去Github仓库看看Wiki,这里我就不多说。

Case code

下面是Case的代码,用了动态QPS模型。

class T extends SourceCode { static void main(String[] args) { def total = 1000_0000 def index = new AtomicInteger() int i = 0 def test = {
            i++ % total //            index.getAndIncrement() % total getRandomInt(total)
            sleep(0.01)
        } new FunQpsConcurrent(test, "测试随机性能").start()
    }
} 

下面是执行任务的方法com.okcoin.hickwall.presses.funtester.frame.execute.FunQpsConcurrent#start代码:

 void start() { if (executor == null) executor = ThreadPoolUtil.createCachePool(Constant.THREADPOOL_MAX, "Q") if (Common.PERF_PLATFORM) controller = new RedisController(this) if (controller == null) controller = new FunTester(); new Thread(controller, "receiver").start(); while (key) {
            ThreadPoolUtil.executeTask(executor, qps, produce, total, name)
        }
        stop()
    } 

优化过程

整个main线程差不多都在上面那个while循环中。我先生成了火焰图,看了main的火焰图,如下:

CPU火焰图(优化前)

可以看出com.okcoin.hickwall.presses.funtester.frame.execute.ThreadPoolUtil#executeTask方法使用了0.53%的CPU,这里看到一个getSecond方法里面使用CPU最多,而且创建了Calendar对象,代码如下:

 if (Time.getSecond() % COUNT_INTERVAL == 0) { int real = total.sumThenReset() / COUNT_INTERVAL as int def active = executor.getActiveCount()
            def count = active == 0 ? 1 : active
            log.info("{} design QPS:{},actual QPS:{} active thread:{} per thread efficiency:{}", name, qps, real, active, real / count as int)
        } 

这里本意是为了间隔几秒输出当前的设计QPS、实际QPS、活跃线程数等信息。这里我想是不是可以直接用时间戳实现这个需求,应该会更快。所以修改后的代码如下:

 if (SourceCode.getMark() % COUNT_INTERVAL == 0) { int real = total.sumThenReset() / COUNT_INTERVAL as int def active = executor.getActiveCount()
            def count = active == 0 ? 1 : active
            log.info("{} design QPS:{},actual QPS:{} active thread:{} per thread efficiency:{}", name, qps, real, active, real / count as int)
        } 

改完之后重新跑了一次,抓取火焰图,main线程部分如下:

CPU火焰图(优化后)

com.okcoin.hickwall.presses.funtester.frame.execute.ThreadPoolUtil#executeTask方法CPU使用率降低到0.29%,但是多了一部分使用使用,整体com.okcoin.hickwall.presses.funtester.frame.execute.FunQpsConcurrent#start方法的CPU使用率是0.44%,相比较之前的0.53%降低了0.09%。

四舍五入也就优化了0.1%,也算是优化效果,有所收获。然后我突然发现整个火焰图的中CPU占用的大多数都是那个sleep方法,可能这个之前 性能测试中的随机数性能问题探索中的结论可能不够明显,甚至忽略了三个方式的差异。后续我重新设计用例测一遍。

原文链接: http://mp.weixin.qq.com/s?__biz=MzU4MTE2NDEyMQ==&mid=2247498600&idx=1&sn=ffd79df118ff1eb06be8beaaa2d2e16c&chksm=fd49765eca3eff48637c104a5fe74e65796c62833cb6b20dbc4544fdf86eff55d458b1664127#rd