为了减轻内核或跨进程内存泄露(Spectre攻击),Linux内核1将使用新选项进行编译,-mindirect-branch=thunk-extern引入以gcc通过所谓的retpoline执行间接调用.
这似乎是一个新发明的术语,因为Google搜索仅在最近的使用中出现(通常都是在2018年).
什么是retpoline?它如何防止最近的内核信息泄露攻击?
1然而,它不是特定于Linux的 - 类似或相同的构造似乎被用作其他操作系统的缓解策略的一部分.
是否有一种简短而甜蜜的方式来生成一个List<Integer>或者一个 Integer[]或者int[]从某个start值到end值的连续值?
也就是说,短于,但相当于以下1:
void List<Integer> makeSequence(int begin, int end) {
List<Integer> ret = new ArrayList<>(end - begin + 1);
for (int i=begin; i<=end; i++) {
ret.add(i);
}
return ret;
}
Run Code Online (Sandbox Code Playgroud)
番石榴的使用很好.
更新:
由于这个问题已经收到了几个很好的答案,无论是使用本机Java 8还是第三方库,我都认为我会测试所有解决方案的性能.
第一个测试只是[1..10]使用以下方法测试创建10个元素的列表:
List<Integer>而是创造一个ContiguousSet<Integer>- 但由于它Iterable<Integer>按顺序实现,它主要用于我的目的.IntStream.rangeClosed()- 这是在Java 8中引入的.对于任何对象类型T,它总是sizeof(T)至少与大小一样大alignof(T)吗?
直观地看起来如此,因为即使你调整对象的对齐方式,例如:
struct small {
char c;
};
Run Code Online (Sandbox Code Playgroud)
通常情况下,它们的"大小"也会向上调整,以便在保持对齐的同时,阵列中对象之间的关系是有意义的(至少在我的测试中.例如:
struct alignas(16) small16 {
char c;
};
Run Code Online (Sandbox Code Playgroud)
两者的大小和对齐都是16.
可以在函数内以简单的方式获得函数的返回类型吗?
例如,给定:
template <typename P>
static inline auto foo(P p) -> typename std::remove_reference<decltype(*p)>::type {
typename std::remove_reference<decltype(*p)>::type f{}; // <-- here
...
}
Run Code Online (Sandbox Code Playgroud)
在C++ 11可以参考我的大讨厌的返回类型foo,内foo本身,而无需重复它,在线条为标志// <-- here?
鉴于以下课程:
class?Foo?{
public?volatile?int?number;
public?int?method1()?{
int?ret?=?number?=?1;
return?ret;
}
public?int?method2()?{
int?ret?=?number?=?2;
return?ret;
}
}
Run Code Online (Sandbox Code Playgroud)
并且在同一个实例上调用多个线程method1()并method2()同时执行Foo,对method1()的调用是否可以返回除1以外的任何内容?
我有一个非常奇怪的编译器行为,其中G ++将计算拉入热循环,严重降低了生成的代码的性能.这里发生了什么?
考虑这个功能:
#include <cstdint>
constexpr bool noLambda = true;
void funnyEval(const uint8_t* columnData, uint64_t dataOffset, uint64_t dictOffset, int32_t iter, int32_t limit, int32_t* writer,const int32_t* dictPtr2){
// Computation X1
const int32_t* dictPtr = reinterpret_cast<const int32_t*>(columnData + dictOffset);
// Computation X2
const uint16_t* data = (const uint16_t*)(columnData + dataOffset);
// 1. The less broken solution without lambda
if (noLambda) {
for (;iter != limit;++iter){
int32_t t=dictPtr[data[iter]];
*writer = t;
writer++;
}
}
// 2. The totally broken solution with lambda
else …Run Code Online (Sandbox Code Playgroud) 如果允许在输入缓冲区末尾读取少量数据,则可以(并且)简化在高性能算法中找到的许多方法.这里,"少量"通常意味着W - 1超过结束的字节,其中W是算法的字节大小(例如,对于处理64位块中的输入的算法,最多7个字节).
很明显,写入输入缓冲区的末尾通常是不安全的,因为您可能会破坏缓冲区1之外的数据.同样清楚的是,在缓冲区的末尾读取到另一页面可能会触发分段错误/访问冲突,因为下一页可能不可读.
但是,在读取对齐值的特殊情况下,页面错误似乎是不可能的,至少在x86上是这样.在该平台上,页面(以及因此内存保护标志)具有4K粒度(较大的页面,例如2MiB或1GiB,可能,但这些是4K的倍数),因此对齐的读取将仅访问与有效页面相同的页面中的字节缓冲区的一部分.
这是一个循环的规范示例,它对齐其输入并在缓冲区末尾读取最多7个字节:
int processBytes(uint8_t *input, size_t size) {
uint64_t *input64 = (uint64_t *)input, end64 = (uint64_t *)(input + size);
int res;
if (size < 8) {
// special case for short inputs that we aren't concerned with here
return shortMethod();
}
// check the first 8 bytes
if ((res = match(*input)) >= 0) {
return input + res;
}
// align pointer to the next 8-byte …Run Code Online (Sandbox Code Playgroud) 我有这样的课:
struct event_counts {
uint64_t counts[MAX_COUNTERS];
event_counts() : counts{} {}
// more stuff
};
Run Code Online (Sandbox Code Playgroud)
通常我想默认(零)初始化counts数组,如图所示。
但是,在通过性能分析确定的选定位置,我想抑制数组初始化,因为我知道数组即将被覆盖,但是编译器不够聪明,无法弄清楚它。
创建这样的“辅助”零参数构造函数的惯用而有效的方法是什么?
当前,我正在使用uninit_tag作为伪参数传递的标记类,如下所示:
struct uninit_tag{};
struct event_counts {
uint64_t counts[MAX_COUNTERS];
event_counts() : counts{} {}
event_counts(uninit_tag) {}
// more stuff
};
Run Code Online (Sandbox Code Playgroud)
然后,像event_counts c(uninit_tag{});想抑制构造时一样,调用no-init构造函数。
我对不涉及创建哑类或以某种方式更有效的解决方案持开放态度。
现代x86 CPU将传入的指令流分解为微操作(uops 1),然后在输入准备就绪时将这些uop 无序调度.虽然基本思路很清楚,但我想了解准备好指令的具体细节,因为它会影响微优化决策.
例如,采取以下玩具循环2:
top:
lea eax, [ecx + 5]
popcnt eax, eax
add edi, eax
dec ecx
jnz top
Run Code Online (Sandbox Code Playgroud)
这基本上实现了循环(具有以下对应关系:) eax -> total, c -> ecx:
do {
total += popcnt(c + 5);
} while (--c > 0);
Run Code Online (Sandbox Code Playgroud)
通过查看uop细分,依赖链延迟等,我熟悉优化任何小循环的过程.在上面的循环中,我们只有一个携带的依赖链:dec ecx.环路(前三指令lea,imul,add)是开始新鲜每个环一个依赖关系链的一部分.
决赛dec和jne融合.因此,我们总共有4个融合域uop,以及一个仅循环携带的依赖链,延迟为1个周期.因此,基于该标准,似乎循环可以在1个周期/迭代时执行.
但是,我们也应该关注港口压力:
lea能够在端口1和5执行add可以在端口0,1,5和6执行jnz在端口6上执行因此,要进行1次循环/迭代,您几乎需要执行以下操作:
lea 必须 …考虑以下简单程序:
#include <cstring>
#include <cstdio>
#include <cstdlib>
void replace(char *str, size_t len) {
for (size_t i = 0; i < len; i++) {
if (str[i] == '/') {
str[i] = '_';
}
}
}
const char *global_str = "the quick brown fox jumps over the lazy dog";
int main(int argc, char **argv) {
const char *str = argc > 1 ? argv[1] : global_str;
replace(const_cast<char *>(str), std::strlen(str));
puts(str);
return EXIT_SUCCESS;
}
Run Code Online (Sandbox Code Playgroud)
它在命令行上使用(可选)字符串并打印它,并/替换为字符_.该替换功能由c_repl功能1实现.例如, …
c++ ×5
x86 ×4
assembly ×3
optimization ×3
performance ×3
c++11 ×2
java ×2
alignof ×1
arrays ×1
c ×1
collections ×1
concurrency ×1
constructor ×1
gcc ×1
guava ×1
icc ×1
intel ×1
jls ×1
security ×1
simd ×1