dsh*_*hin 6 c++ memory-alignment packed c++11
我有一个由模板参数组成的4个字段的结构:
template <typename T1, typename T2, typename T3, typename T4>
struct __attribute__((aligned(8))) four_tuple {
typedef struct {
T1 t1;
T2 t2;
T3 t3;
T4 t4;
} payload;
payload p;
};
Run Code Online (Sandbox Code Playgroud)
每种类型T1,T2,T3,和T4,保证是原始类型或four_tuple<...>::payload类型.保证是递归的 - 您可以将结构视为编码其叶节点是基本类型的四叉树.
我的目标是使结构具有最小可能性sizeof,但条件是所有叶节点都正确对齐.允许优化的工具是类模板特化,使用:
t1,t2,t3,t4packed上payload我觉得使用enable_if和SFINAE 这个问题有一个聪明的解决方案.谁能找到它?
为了说明这个问题,如果我们按原样使用上面的实现,那么using Foo = four_tuple<char,double,char,double>对于有效载荷和整体来说,我们的大小为32.如果我们只是声明有效载荷packed,那么它们double就不会很好地对齐.即重新安排场按递减顺序(在这里,A模板特double, double, char, char)会给出一个有效载荷和24整体大小,但它使用的是浪费,因为可以通过考虑可以看到额外的6个字节using Bar = four_tuple<Foo::payload,int,int,int>.以最佳的包装Bar可以装在32个字节,但该方案将需要40不客气地将现场与重新排序packed将导致错位int的中Bar-需要一些填料.
我知道,在一般的结构调整结构的字段的内存布局可以由于缓存的考虑性能的影响,而且在一般这些影响将至少从更好的堆积任何潜在收益为显著.不过,我想探讨这些权衡,如果不解决这个问题,我无法在我的背景下做到这一点.
小智 1
嵌套元组情况中的大问题是您希望有一个 类型的字段four_tuple<char,double,char,double>::payload,像 a 一样对齐four_tuple<char,double,char,double>,但不需要容器类型继承其对齐方式。这是复杂的。这样做是可能的,但它会使您的代码极难移植到 GCC 以外的任何地方。我想这没关系,因为您已经在问题中建议了 GCC 扩展。基本思想是位字段可用于插入填充以确保对齐:
struct __attribute__((packed)) S {
char c; // at offset 0
int i; // at offset 1, not aligned
int : 0;
int j; // at offset 8, aligned
int : 0;
int k; // at offset 12, no extra padding between j and k
};
Run Code Online (Sandbox Code Playgroud)
int当然是一个非常特定的类型,具有非常特定的对齐方式,并且您需要动态确定的对齐方式。幸运的是,GCC 允许 类型的位字段char(通常只强制字节对齐)与 组合alignas,以确保任意对齐。
完成此操作后,您可以检查所有 24 个可能的字段顺序,并选择总大小最小的有效负载。我将有效负载设置为全局类型,并为其提供了一个附加模板参数来指示字段顺序。这允许tuple4<T1, T2, T3, T4>按顺序检查tuple4_payload<T1, T2, T3, T4, 1234>、tuple4_payload<T1, T2, T3, T4, 1243>等并选择最好的。
template <typename...> struct smallest;
template <typename...T> using smallest_t = typename smallest<T...>::type;
template <typename T> struct smallest<T> { using type = T; };
template <typename T, typename...Ts> struct smallest<T, Ts...> { using type = std::conditional_t<sizeof(T) <= sizeof(smallest_t<Ts...>), T, smallest_t<Ts...>>; };
template <typename T1, typename T2, typename T3, typename T4> struct tuple4;
template <typename T1, typename T2, typename T3, typename T4, int fieldOrder> struct tuple4_payload;
template <typename T1, typename T2, typename T3, typename T4> struct tuple4_simple { T1 t1; T2 t2; T3 t3; T4 t4; };
template <typename T> struct extract_payload { using type = T; };
template <typename...T> struct extract_payload<tuple4<T...>> { using type = typename tuple4<T...>::payload; };
template <typename T> using extract_payload_t = typename extract_payload<T>::type;
#define PERMS \
PERM(1,2,3,4) PERM(1,2,4,3) PERM(1,3,2,4) PERM(1,3,4,2) PERM(1,4,2,3) PERM(1,4,3,2) \
PERM(2,1,3,4) PERM(2,1,4,3) PERM(2,3,1,4) PERM(2,3,4,1) PERM(2,4,1,3) PERM(2,4,3,1) \
PERM(3,1,2,4) PERM(3,1,4,2) PERM(3,2,1,4) PERM(3,2,4,1) PERM(3,4,1,2) PERM(3,4,2,1) \
PERM(4,1,2,3) PERM(4,1,3,2) PERM(4,2,1,3) PERM(4,2,3,1) PERM(4,3,1,2) PERM(4,3,2,1)
#define PERM(a,b,c,d) \
template <typename T1, typename T2, typename T3, typename T4> \
struct __attribute__((packed)) tuple4_payload<T1, T2, T3, T4, a##b##c##d> { \
char : 0 alignas(T##a); extract_payload_t<T##a> t##a; \
char : 0 alignas(T##b); extract_payload_t<T##b> t##b; \
char : 0 alignas(T##c); extract_payload_t<T##c> t##c; \
char : 0 alignas(T##d); extract_payload_t<T##d> t##d; \
};
PERMS
#undef PERM
#define PERM(a,b,c,d) , tuple4_payload<T1, T2, T3, T4, a##b##c##d>
template <typename, typename...T> using tuple4_smallest_payload_t = smallest_t<T...>;
template <typename T1, typename T2, typename T3, typename T4>
struct alignas(tuple4_simple<T1, T2, T3, T4>) tuple4 : tuple4_smallest_payload_t<void PERMS> {
using payload = tuple4_smallest_payload_t<void PERMS>;
};
#undef PERM
Run Code Online (Sandbox Code Playgroud)
在您的情况下,您可以将其用作tuple4<int, tuple4<char, double, char, double>, int, int>. 请注意,即使此处未明确提及有效负载类型,它仍将用于成员t2。
| 归档时间: |
|
| 查看次数: |
197 次 |
| 最近记录: |