使用gcc 4.9,使用Linaro工具链对ARM进行交叉编译,我发现在添加public class HandPanel extends JPanel {
CardImage cardImage;
public HandPanel(Card card) {
cardImage = new CardImage(card);
}
@Override
public Dimension getPreferredSize() {
BufferedImage img = cardImage.getImage();
return img == null ? super.getPreferredSize() : new Dimension(img.getWidth(), img.getHeight());
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
BufferedImage img = cardImage.getImage();
g.drawImage(img, 0, 0, this);
}
}
时,vector.assign()
的编译结果会以一种造成严重性能问题的方式发生变化。
我尝试了几种不同的方式来执行此分配+复制,但只要我使用-std=c++14
执行此操作,所有这些方法都会遇到此性能问题。
我可以通过这个玩具示例重现问题:
VectorTest.h
std::vector
VectorTest.cpp
#include <stdint.h>
#include <stddef.h>
#include <vector>
struct VectorWrapper_t
{
VectorWrapper_t(uint8_t const* pData, size_t length);
std::vector<uint8_t> data;
};
gcc flags:
#include "VectorTest.h"
VectorWrapper_t::VectorWrapper_t(uint8_t const* pData, size_t length)
{
data.assign(pData, pData + length);
}
查看程序集,我可以看到原因:原始版本(C ++ 03,我假设?)调用-std=c++14 \
-mthumb -march=armv7-a -mtune=cortex-a9 \
-mlittle-endian -mfloat-abi=hard -mfpu=neon -Wa,-mimplicit-it=thumb \
-O2 -g
,而C ++ 14版本则添加了一个额外的循环看起来像手动复制数据。查看gcc与memmove
添加的.loc
代码,此循环中的说明来自-fverbose-asm
和stl_construct.h
。
更改为gcc 5.2.1(使用C ++ 14),它的编译几乎与C ++ 03示例完全相同,除了stl_uninitialized.h
而不是memcpy
。
我可以在此处使用memmove
代替std::unique_ptr<uint8_t[]>
来解决此问题。但是,我想深入研究这个问题的底部,以确定使用vector
的其他地方是否存在性能问题以及如何解决它们(更新到gcc 5.2并不实用)。 / p>
所以我的问题是:为什么在C ++ 11/14下编译的方式不同?
供参考,vector
报告:
gcc --version
。
这是生成的程序集gcc:
arm-linux-gnueabihf-gcc (Linaro GCC 4.9-2014.12) 4.9.3 20141205 (prerelease)
答案 0 :(得分:11)
这是4.9.2版本中的GCC错误,请参阅PR 64476。默认-std=gnu++03
模式与-std=c++14
之间的区别在于,对于C ++ 11及更高版本,它可能具有不可分配的普通类型(因为它们可以被删除)赋值运算符),它导致std::uninitialized_copy
的实现采用不同的(较慢的)代码路径。对可转让性的检查是错误的,这意味着当我们不需要时,我们采取了缓慢的路径。
两年前我为GCC 4.9.3修复了它,但是你的编译器基于4.9.2和4.9.3版本之间的快照,并且还有几周的时间来修复它。
你可以要求Linaro将他们的GCC 4.9编译器更新到4.9.4,或者至少应用补丁来修复这个bug。