当我尝试在Win32或x64模式下使用Visual Studio 2010编译我的c ++项目时,我收到以下错误:
>C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\include\winnt.h(135): fatal error C1189: #error : "No Target Architecture"
我的预处理器定义说WIN32; _DEBUG; _CONSOLE;%(PreprocessorDefinitions)
导致此错误的原因是什么?如何解决?
// winnt.h: lines 127-136, MSVS says this is an inactive preprocessor block
#if defined(_WIN64)
#if defined(_AMD64_)
#define PROBE_ALIGNMENT( _s ) TYPE_ALIGNMENT( DWORD )
#elif defined(_IA64_)
#define PROBE_ALIGNMENT( _s ) (TYPE_ALIGNMENT( _s ) > TYPE_ALIGNMENT( DWORD ) ? \
TYPE_ALIGNMENT( _s ) : TYPE_ALIGNMENT( DWORD ))
#else
#error "No Target Architecture"
#endif
Run Code Online (Sandbox Code Playgroud)
更新:我创建了一个新的msvs项目并将我的代码复制到它.我不再拥有error : "No Target Architecture",但现在我有一堆涉及winnt.h和winbase.h的编译错误,并且没有涉及我的任何文件的编译错误.这些文件是否可能已损坏?我需要重新安装MSVS 2010吗?
更新2:所以我缩小了我的问题,发现它 …
我正在考虑以下问题(非常粗略的描述):
假设我们有一个图表,其中边缘被分配了一些非负成本,一个起始节点s和一些成本常数C.找出:
N,从到达s那里的最短路径的从开始节点的成本s在任何节点N不大于C.e集合 - 最短路径的成本.基本上Dijkstra有成本约束.
我的主要问题是:图论中这个问题的正确术语是什么?
我一直在关注"可访问性"或"可达性",但这些似乎是错误的关键字.
最后,我正在寻找一种算法,它可以在一个(不可修改的)但相当大的(可能约1亿个边缘)图形上并行地有效地回答许多这样的查询.我想查看文献,但需要提供正确的关键词提示.
更新:我的实际问题如下.
假设我们获得了一个大陆规模的道路网络(模拟为有向图,在边缘和节点上具有一些属性,如果它是行人路或高速公路).边缘成本是旅行时间.
我想回答用户查询,例如:从某个给定位置(图形节点)开始,哪些节点可在1小时内到达?
我也想非常快地(对于许多用户来说,如果可能的话,<200-300ms)(并且如果可能的话,> 200,如果可能)并行地回答这些查询.
我认为应该至少有两种可能的优化:
我自己有一些想法,但我首先要检查文献,以避免重新发明轮子.
我正在尝试使用AVX -AVX2指令集来查看连续阵列上的流媒体性能.所以我有下面的例子,我做基本的内存读取和存储.
#include <iostream>
#include <string.h>
#include <immintrin.h>
#include <chrono>
const uint64_t BENCHMARK_SIZE = 5000;
typedef struct alignas(32) data_t {
double a[BENCHMARK_SIZE];
double c[BENCHMARK_SIZE];
alignas(32) double b[BENCHMARK_SIZE];
}
data;
int main() {
data myData;
memset(&myData, 0, sizeof(data_t));
auto start = std::chrono::high_resolution_clock::now();
for (auto i = 0; i < std::micro::den; i++) {
for (uint64_t i = 0; i < BENCHMARK_SIZE; i += 1) {
myData.b[i] = myData.a[i] + 1;
}
}
auto end = std::chrono::high_resolution_clock::now();
std::cout << (end - start).count() / …Run Code Online (Sandbox Code Playgroud) 将参数传递给函数时,我总是假设逐个传递参数与传递它们包装在数组或结构或元组中没有什么不同.然而,一个简单的实验表明我错了.
使用GCC编译时的以下程序:
int test(int a, int b, int c, int d) {
return a + b + c + d;
}
int test(std::array<int, 4> arr) {
return arr[0] + arr[1] + arr[2] + arr[3];
}
struct abcd {
int a; int b; int c; int d;
};
int test(abcd s) {
return s.a + s.b + s.c + s.d;
}
int test(std::tuple<int, int, int, int> tup) {
return std::get<0>(tup) + std::get<1>(tup) + std::get<2>(tup) + std::get<3>(tup);
}
Run Code Online (Sandbox Code Playgroud)
...产生各种装配输出:
impl_test(int, int, …Run Code Online (Sandbox Code Playgroud) 当从连续的内存位置执行一系列_mm_stream_load_si128()调用(MOVNTDQA)时,硬件预取器是否仍会启动,或者我应该使用显式软件预取(使用NTA提示)以获得预取的好处,同时仍然避免缓存污染?
我问这个的原因是因为他们的目标似乎与我相矛盾.流加载将获取绕过缓存的数据,而预取器尝试主动将数据提取到缓存中.
当顺序迭代一个大型数据结构(处理过的数据不会在很长一段时间内被修饰)时,我有必要避免污染chache层次结构,但我不想因频繁出现频繁的~100次循环处罚-fetcher闲置.
目标架构是Intel SandyBridge
我正在处理3D网格中的大量数据,所以我想实现一个简单的迭代器而不是三个嵌套循环.但是,我遇到了性能问题:首先,我只使用int x,y和z变量实现了一个简单的循环.然后我实现了Vector3I结构并使用了 - 并且计算时间加倍.现在我正在努力解决这个问题 - 为什么会这样?我做错了什么?
复制示例:
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;
using System.Runtime.CompilerServices;
public struct Vector2I
{
public int X;
public int Y;
public int Z;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector2I(int x, int y, int z)
{
this.X = x;
this.Y = y;
this.Z = z;
}
}
public class IterationTests
{
private readonly int _countX;
private readonly int _countY;
private readonly int _countZ;
private Vector2I _Vector = new Vector2I(0, 0, 0);
public IterationTests()
{
_countX = 64;
_countY = 64;
_countZ …Run Code Online (Sandbox Code Playgroud) 考虑以下循环:
.loop:
add rsi, OFFSET
mov eax, dword [rsi]
dec ebp
jg .loop
Run Code Online (Sandbox Code Playgroud)
where OFFSET是一些非负整数,并rsi包含指向该bss部分中定义的缓冲区的指针.此循环是代码中唯一的循环.也就是说,它在循环之前没有被初始化或触摸.据推测,在Linux上,缓冲区的所有4K虚拟页面都将按需映射到同一物理页面.因此,缓冲区大小的唯一限制是虚拟页面的数量.因此,我们可以轻松地尝试非常大的缓冲区.
该循环由4条指令组成.每个指令在Haswell的融合和未融合域中被解码为单个uop.连续的实例之间也存在循环携带的依赖关系add rsi, OFFSET.因此,在负载总是在L1D中命中的空闲条件下,循环应该每次迭代执行大约1个循环.对于小偏移(步幅),这要归功于基于IP的L1流预取器和L2流预取器.但是,两个预取程序只能在4K页面内预取,并且L1预取程序支持的最大步幅为2K.因此,对于小步幅,每4K页面应该有大约1 L1未命中.随着步幅的增加,L1未命中和TLB未命中的总数将增加,并且性能将相应地恶化.
下图显示了0到128之间步幅的各种有趣的性能计数器(每次迭代).请注意,所有实验的迭代次数都是常量.仅缓冲区大小更改以适应指定的步幅.此外,仅计算用户模式性能事件.
这里唯一奇怪的事情是退役的uops数量随着步伐的增加而增加.它从每次迭代3次(如预期)到步幅128的11次.为什么?
如下图所示,事情只会越来越大.在此图中,步幅范围为32到8192,增量为32字节.首先,退出指令的数量在步长4096字节处从4线性增加到5,之后它保持不变.负载微量的数量从1增加到3,并且每次迭代L1D负载命中的数量保持为1.对于所有步幅,只有L1D负载未命中数才对我有意义.
较大步幅的两个明显效果是:
taskset或重复了所有实验,nice并得到了相同的结果.为了进一步调查,下图显示了微代码辅助的uop数.每次迭代的微代码辅助微动的数量增加,直到它达到步幅4096的最大值,就像其他性能事件一样.对于所有步幅,每4K虚拟页面的微代码辅助微操作数为506."Extra UOPS"行显示退役的uop数减去3(每次迭代的预期uop数).
该图表示额外微量的数量略大于所有步幅的微码辅助微量的一半.我不知道这意味着什么,但它可能与页面走路有关,可能是观察到扰动的原因.
为什么即使每次迭代的静态指令数相同,每次迭代的退出指令和uop的数量也会增加?来自哪里的干扰?
下图显示了每次迭代的周期数与不同步幅的每次迭代的退役uop数.循环次数的增加比退役的次数增加得快得多.通过使用线性回归,我发现:
cycles = 0.1773 * stride + 0.8521
uops = 0.0672 * stride + 2.9277
Run Code Online (Sandbox Code Playgroud)
采用两种功能的衍生物:
d(cycles)/d(stride) = 0.1773
d(uops)/d(stride) = 0.0672
Run Code Online (Sandbox Code Playgroud)
这意味着循环次数增加0.1773,退役微量数量增加0.0672,步幅每增加1个字节.如果中断和页面错误确实是(唯一)扰动的原因,那么两个速率是否应该非常接近?
在谈论ifs的表现时,我们通常会谈论错误预测如何阻止管道.我看到的推荐解决方案是:
我找不到的是我们是否能尽早计算出病情,以便在可能的情况下提供帮助.所以,而不是:
... work
if (a > b) {
... more work
}
Run Code Online (Sandbox Code Playgroud)
做这样的事情:
bool aGreaterThanB = a > b;
... work
if (aGreaterThanB) {
... more work
}
Run Code Online (Sandbox Code Playgroud)
这样的事情可能会完全避免这个条件的停顿(取决于管道的长度和我们可以放在bool和if之间的工作量)?这并不一定是因为我写的,但有什么办法,以评估条件语句早,所以CPU不必尝试和预测的分支?
此外,如果这有帮助,编译器可能会做什么呢?
language-agnostic performance cpu-architecture compiler-optimization branch-prediction
所以calloc()通过向操作系统询问一些虚拟内存来工作.操作系统正在使用MMU进行操作,并巧妙地响应虚拟内存地址,该地址实际上映射到一个写满了零的只读页面.当程序尝试写入该页面中的任何位置时,会发生页面错误(因为您无法写入只读页面),会创建该页面的副本,并且您的程序的虚拟内存将映射到这些全新的副本零.
既然Meltdown是一个东西,操作系统已被修补,因此不再可能跨内核用户边界推测性地执行.这意味着每当用户代码调用内核代码时,它就会有效地导致管道停顿.通常,当管道在循环中停顿时,它对性能造成破坏性,因为CPU最终会浪费时间等待数据,无论是来自缓存还是主存储器.
calloc(),并且重新映射到新的CoW页面时,是否正在执行内核代码?calloc()分配4GiB的内存,然后在紧密的循环中用一些任意值(比如说,0xFF而不是0x00)初始化它,我的(英特尔)CPU每次写入新页面时都会触及推测边界吗?performance memory-management cpu-architecture calloc page-fault
我已经看到这个答案和这个答案,但也显得清晰和明确有关的等价或不等价mfence和xchg没有非时间指示的假设下.
英特尔指令参考对于xchg提到这个指令是用于实现信号量或进程同步相似的数据结构有用,和其它参考文献的第8章卷3A.该参考文献陈述如下.
对于P6系列处理器,锁定操作会序列化所有未完成的加载和存储操作(即等待它们完成).对于奔腾4和英特尔至强处理器,此规则也是如此,但有一个例外.引用弱有序内存类型(例如WC内存类型)的加载操作可能无法序列化.
该mfence文件声称如下.
对MFENCE指令之前发出的所有内存加载和存储到内存指令执行序列化操作.此序列化操作保证在遵循MFENCE指令的任何加载或存储指令之前,按程序顺序在MFENCE指令之前的每个加载和存储指令都变为全局可见.1 MFENCE指令针对所有加载和存储指令,其他MFENCE指令,任何LFENCE和SFENCE指令以及任何序列化指令(例如CPUID指令)进行排序.MFENCE不会序列化指令流.
如果我们忽略弱有序的内存类型,xchg(暗示lock)是否包含了关于内存排序的所有mfence保证?
performance ×5
x86 ×5
assembly ×2
c++ ×2
intel-pmu ×2
avx2 ×1
c# ×1
calloc ×1
cpu-cache ×1
graph-theory ×1
intel ×1
page-fault ×1
prefetch ×1
sse ×1
visual-c++ ×1