引用自https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html:
-falign-标签
-falign-标签=正
将所有分支目标对齐为二次幂边界,跳过n个字节,如-falign-functions.此选项可以轻松地使代码变慢,因为它必须在通常的代码流中到达分支目标时插入虚拟操作.
-fno-align-labels和-falign-labels = 1是等效的,表示标签未对齐.
如果-falign-loops或-falign-jumps适用且大于此值,则使用它们的值.
如果未指定n或为零,则使用机器相关的默认值,该默认值很可能为"1",表示没有对齐.
在-O2,-O3级别启用.
考虑这个标志会使它失去更多的意义......有引发代码缓存未命中的后果,甚至启用意味着何时参数采用数值(1 ..)?
I'm moving some C++17 code to be used in a project that is built with Qt, on Windows, using MinGW 7.3.0, and noticed something weird happening in the 32bit builds:
#include <cstddef>
#include <iostream>
int main() {
std::cout << __STDCPP_DEFAULT_NEW_ALIGNMENT__ << std::endl;
std::cout << __BIGGEST_ALIGNMENT__ << std::endl;
std::cout << sizeof(std::max_align_t) << std::endl;
std::cout << alignof(std::max_align_t) << std::endl;
std::cout << "----------------------------------------" << std::endl;
for (int i = 0; i < 8; ++i) {
const uintptr_t ptr = uintptr_t(new char);
static const …Run Code Online (Sandbox Code Playgroud) 我正在为二进制协议(Javad GRIL协议)编写解码器.它由大约一百条消息组成,数据格式如下:
struct MsgData {
uint8_t num;
float x, y, z;
uint8_t elevation;
...
};
Run Code Online (Sandbox Code Playgroud)
这些字段是ANSI编码的二进制数,它们彼此之间没有间隙.解析此类消息的最简单方法是将输入的字节数组转换为适当的类型.问题是流中的数据是打包的,即未对齐的.
在x86上,这可以通过使用来解决#pragma pack(1).但是,这在某些其他平台上不起作用,或者由于未对齐数据而导致性能开销.
另一种方法是为每种消息类型编写一个特定的解析函数,但正如我所提到的,该协议包含数百条消息.
另一种选择是使用类似Perl unpack()函数的东西并在某处存储消息格式.说,我们可以#define MsgDataFormat "CfffC"再打电话unpack(pMsgBody, MsgDataFormat).这要短得多,但仍然容易出错并且多余.此外,格式可能更复杂,因为消息可以包含数组,因此解析器将是缓慢而复杂的.
有没有共同有效的解决方案?我已经阅读了这篇文章,并用Google搜索,但没有找到更好的方法来做到这一点.
也许C++有一个解决方案?
我有一个配置结构我想保存在ARM cortex M3的内部闪存上.根据规格,数据保存在内部闪存中,必须与32bit对齐.因为我有很多boolean和chars在我的结构中,我不想使用32位存储8位...我决定使用__packed预处理器编译指示打包结构,然后当我将它保存为整个结构时,我只需要确保结构大小可被4整除(4个字节= 32位),如果需要,我可以通过添加填充字节来实现.目前,在开发过程中我经常更改结构,并使其与32位对齐,我需要一直更改填充字节.目前,结构看起来很像
typedef __packed struct
{
uint8_t status;
uint16_t delay;
uint32_t blabla;
uint8_t foo[5];
uint8_t padding[...] // this has to be changed every time I alter the structure.
} CONFIG;
Run Code Online (Sandbox Code Playgroud)
有没有更好的方法来实现我正在做的事情?我是嵌入式编程的新手,我想确保我没有犯错误.
编辑:请注意.数据在内部闪存结束时保留,因此省略填充将无法正常工作......
我试图理解未对齐的内存访问(UMA)如何在现代处理器(即x86-64和ARM体系结构)上工作.我知道我可能遇到UMA问题,从性能下降到CPU故障.我阅读posix_memalign并缓存行.
我找不到的是当我的请求超出页面边界时,现代系统/硬件如何处理这种情况?
这是一个例子:
malloc()是一块8KB的内存.malloc()没有足够的内存和sbrk()8KB的话.movq (offset + $0xffc), %rax 我从第4092字节开始请求8个字节,这意味着我需要从第一页末尾开始的4个字节和从第二页开始开始的4个字节.物理内存:
---|---------------|---------------|-->
|... 4b| | |4b ...|-->
Run Code Online (Sandbox Code Playgroud)
我需要在页面边界分割的8个字节.
x86-64和ARM上的MMU如何处理这个问题?内核MM中是否有任何机制以某种方式为这种请求做准备?是否有某种保护malloc?处理器做什么?他们取两页吗?
我的意思是完成这样的请求MMU必须将一个虚拟地址转换为两个物理地址.它如何处理这样的请求?
如果我是软件程序员,我应该关心这些事情吗?为什么?
我正在阅读谷歌,SO,drepper的cpumemory.pdf和gorman的Linux VMM书中的很多链接.但它是一个信息的海洋.如果您至少向我提供一些我可以使用的指针或关键字,那将会很棒.
我遵循 Stefanus Du Toit 的沙漏模式,即在 C++ 中实现 C API,然后再次将其包装在 C++ 中。这与pimpl idiom非常相似,它对用户也是透明的,但可以防止更多与 ABI 相关的问题并允许更广泛的外语绑定。
与实现指针的方法一样,底层对象的大小和布局在编译时不被外界所知,因此它所在的内存必须动态分配(主要是)。然而,与pimpl情况不同,在pimpl情况下,对象已在分配点完全定义,这里它的属性完全隐藏在不透明指针后面。
获得的内存std::malloc是“适合任何标量类型”,这使得它不适合任务。我不确定new-expression。引自链接页面的分配部分:
此外,如果 new 表达式用于分配一个 char 数组或一个 unsigned char 数组,它可能会在必要时从分配函数中请求额外的内存,以保证不大于请求的数组大小的所有类型的对象的正确对齐,如果稍后将一个放入分配的数组中。
这是否意味着以下代码是合规的?
size_t object_size ( void ); // return sizeof(internal_object);
size_t object_alignment ( void ); // return alignof(internal_object);
void object_construct ( void * p ); // new (p) internal_object();
void object_destruct ( void * p ); // …Run Code Online (Sandbox Code Playgroud) 第151页的新书中的Stroustrup显示了以下使用类型说明符的示例alignas:
有时,我们必须在声明中使用对齐,其中不允许使用诸如alignof(x + y)之类的表达式.相反,我们可以使用类型说明符alignas:alignas(T)表示"就像T一样对齐" 例如,我们可以为某些类型X预留未初始化的存储,如下所示:
void user(const vector<X>& vx)
{
constexpr int bufmax = 1024;
alignas(X) char buffer[bufmax]; // unitialized
const int max = min(vx.size(), bufmax/sizeof(X));
unitialized_copy(vx.begin(), vx.begin() + max, buffer);
...
}
Run Code Online (Sandbox Code Playgroud) 是sizeof(Type)始终整除alignof(Type)
这样的陈述永远是真的吗? sizeof(Type) % alignof(Type) == 0
最近,我意识到的潜在问题内存对齐为固定大小的矢量化的本征对象。
class Foo
{
...
Eigen::Vector2d v;
...
public:
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
};
...
Foo *foo = new Foo;
Run Code Online (Sandbox Code Playgroud)
我想知道这个代码是否可以?
class Foo2
{
...
Foo foo;
...
};
...
Foo2 *foo = new Foo2; //?
Run Code Online (Sandbox Code Playgroud)
还是应该EIGEN_MAKE_ALIGNED_OPERATOR_NEW在Foo2类中再次添加?这就是建议在这里我想:
如果我们添加 EIGEN_MAKE_ALIGNED_OPERATOR_NEW,这只能解决 Cartographer 库本身的问题。该库的用户还必须将 EIGEN_MAKE_ALIGNED_OPERATOR_NEW 添加到包含矢量化 Cartographer 类的类中。这听起来像是一场维护噩梦。
我没有新运算符重载的经验。我认为这个问题更笼统,并且以某种方式与 new 运算符在 C++ 中的工作方式有关。例如,重载的 new 运算符 inFoo是否被默认的 new 运算符 in 调用Foo2?继承呢?如果Foo2从继承Foo,要我们把同样EIGEN_MAKE_ALIGNED_OPERATOR_NEW的Foo2? …
我不习惯在互联网上发布任何问题,所以如果我做错了什么,请告诉我。
如何在 CPU 缓存行大小为 64 字节的 64 位架构上正确防止错误共享?
C++ 'alignas' 关键字和简单字节数组(例如:char[64])的使用如何影响多线程效率?
在研究Single Consumer Single Producer Queue的非常有效的实现时,我在对我的代码进行基准测试时遇到了 GCC 编译器的不合逻辑行为。
我希望有人有必要的知识来解释正在发生的事情。
我目前在 arch linux 上使用 GCC 10.2.0 及其 C++ 20 实现。我的笔记本电脑是带有 i7-7500U 处理器的联想 T470S。
让我从数据结构开始:
class SPSCQueue
{
public:
...
private:
alignas(64) std::atomic<size_t> _tail { 0 }; // Tail accessed by both producer and consumer
Buffer _buffer {}; // Buffer cache for the producer, equivalent to _buffer2
std::size_t _headCache { 0 }; // Head cache for the …Run Code Online (Sandbox Code Playgroud)