Tag: 优化

实现最小化方法

我在2个变量x1,x2有一个函数 f = 3*x1^2 + 4*x2^2 + 5*x1 + 6*x2 + 10 考虑x是行向量,使得x = [x5,x6] ,其中x5,x6是向量的分量。 如果符号混淆,让我们考虑x = [x1,x1]但x1,x2可以是任意组件。 对于y ,同样的论点也适用。 然后我想找到a from (x + ay)这样它会使f最小化。 a是实常数, x和y是向量。 这在上面解释了。 如果这没有意义,那么让我们将x,y视为具有2个位置的1维数组。 因此,x(1),x(2),y(1),y(2)是它们的组成部分。 然后我想将数组y乘以符号变量a 。 例如, x=[4,5] , y=[-2,3]则, (x + ay) = (4,5) + a(-2,3) = (4-2a,5+3a) 。 a是这里未知的符号变量。 在f1替换(更清楚的是, f x1 = 4-2a的定义中的第一个参数,第二个参数x2=5+3a ) f1 […]

整数提升会影响64位性能吗?

以下面的代码为例: uint32_t fg; uint32_t bg; uint32_t mask; uint32_t dest; … dest = (fg & mask) | (bg & (~mask)); 现在这个片段的所有操作数都是32位无符号整数。 使用32位int大小的C编译器,不会发生整数提升,因此整个操作以32位执行。 我的问题是,例如在维基百科上 ,显示通常甚至64位机器都有使用32位int大小的编译器。 符合C标准,它们不会将操作数提升到64位整数,因此可能会编译成性能较差甚至更大的代码大小的东西(只是假设16位操作是如何更昂贵的循环和指令大小的32位x86)。 主要问题是:我是否需要担心? (我相信我可能没有,因为通过优化启用一个理智的编译器可能能够省略严格遵循C标准显示的多余的gunk。请参阅示例代码,并考虑一般我的信念可能会少一些地面) 如果是这样(我实际上需要关注),你能推荐一些涵盖这个领域的方法(书籍,网站,等等)吗? (嗯,我知道这对于SO来说有点过时了,但是如果我只得到一个三个字,那么我认为这个有用得多, 是的,你做了!作为接受的答案)

铿锵声中的静态预计算优化

我有 #include #include #include #include #include int fib(int n) { return n < 2 ? n : fib(n-1) + fib(n-2); } double clock_now() { struct timeval now; gettimeofday(&now, NULL); return (double)now.tv_sec + (double)now.tv_usec/1.0e6; } #define NITER 5 在我的main() ,我正在做一个像这样的简单基准: printf(“hi\n”); double t = clock_now(); int f = 0; double tmin = INFINITY; for (int i=0; […]

GCC的已知C / C ++优化是什么?

我有很多代码需要优化并使其运行得更快。 我用opreport告诉我代码花了很多时间。 我使用以下命令来获取统计信息 opreport -g -l -d 使用不同的标志可以获得建议以获得更好的统计数据,也许每个行号而不是function号找到它。 因此,我所看到的许多问题都与以下方面有关: 指针,多维数组 乘法 循环 我希望编译器能够更好地优化代码,从而帮助他。 我将一些代码块分解为带有字限制的函数,告诉编译器我的指针数组不重叠。 所以我正在寻找(a)可以使代码运行更长时间的常见C结构和(b)如何帮助编译器优化代码。 谢谢

C表示循环分段故障

当我尝试在gcc上编译此代码时,我收到了分段错误错误。 #include #include #define N_TIMES 600000 #define ARRAY_SIZE 10000 int main (void) { double *array = calloc(ARRAY_SIZE, sizeof(double)); double sum = 0; int i; double sum1 = 0; for (i = 0; i < N_TIMES; i++) { int j; for (j = 0; j < ARRAY_SIZE; j += 20) { sum += array[j] + array[j+1] […]

C fprintf / fscanf优化大文件的速度

我合并了两个大的(每个8 GB左右)文件。 我尝试优化它,尽可能好。 void merge() { char *array[17]= {“q.out”,”b.out”}; // names of input files FILE *finpt1 = fopen(array[0],”r”), *finpt2 = fopen (array[1],”r”), *foutp = fopen(“final_.out”,”w”); u_int32_t a,b; fscanf(finpt1, “%u”, &a); fscanf(finpt2, “%u”, &b); int EOF1_my = 0, EOF2_my = 0; while (true) { if ( a>b ) { fprintf( foutp,”%u\n”, b); if ( fscanf(finpt2, “%u”, […]

缓存友好的矩阵移位function

我想将2D方阵的第一行移到最后一行。 所以如果我有像A这样的矩阵,我想得到B. 我可以使用两个简单的for循环来做到这一点。 例如 void shift(int M, int N, int A[M][N]){ int i, j,temp; for (i = 1; i < M; i++){ for (j = 0; j < N; j++){ temp=A[i][j]; A[i][j]=A[i-1][j]; A[i-1][j]=temp; } } } 但我希望尽可能少地缓存未命中数。 有关如何做到这一点的任何提示?

GCC:分段故障和调试程序,仅在优化时崩溃

这是线程的后续跟进: C:分段错误,也许GDB对我说谎 我有一个用-O0编译好的程序,但用-O1,-O2,-O3和Ofast编译段错误。 似乎堆栈在某种程度上会被破坏,但我无法弄清楚为什么或在哪里。 首先,这是我正在使用的结构的一部分。 它位于头文件中: typedef struct { GLuint nsHandle; } OGL_STATE_T; 这是主文件中相关的淡化部分: void init(OGL_STATE_T *state) { printf(“init: %p\n”, state); // Print pointer address make sure it’s the same. compileShaders(state); } int main(argc, char *argv[]) { static OGL_STATE_T _state, *state=&_state; printf(“main: %p\n”, state); // Print pointer address init(state); return 0; } 然后这是compileShaders函数。 这是指针地址损坏发生的地方: void […]

用于优化的编译器提示和语义

我花了最近几周优化数值算法。 通过预计算,内存对齐,编译器提示和标志以及试错实验的组合,我将运行时间降低了一个数量级。 我还没有使用内在函数或使用multithreading显式向量化。 经常在处理这类问题时,会有一个初始化例程,在此之后,许多参数变为常量。 这些可能是filter长度,switch语句的表达式,循环长度或迭代增量。 如果在编译时知道参数,编译器应该能够通过确切地知道如何展开循环,用指令中具有偏移量的指令替换索引计算来简化或消除表达式,从而更有效地进行优化。编译时,可能消除switch语句等。处理这个问题的最极端的方法是运行初始化例程(在运行时),然后在关键函数上运行编译器,使用某种插件进行优化允许迭代抽象语法树,用常量替换参数,最后动态链接到共享对象。 如果例程很短,可以使用许多工具在二进制文件中动态编译。 更实际的是,我非常依赖于对齐,gcc __builtin_assume_aligned,restrict,手动循环展开和编译器标志,以便编译器在编译时给定参数的未知值来执行我想要的操作。 我想知道还有哪些其他选项至少接近便携式。 我只使用内在函数作为最后的手段,因为它不便携并且工作量很大。 具体来说,如何使用语言语义,编译器扩展或外部工具为编译器(gcc)提供有关循环变量的附加信息,以便它可以更好地为我做优化。 类似地,有任何方法可以将变量限定为具有步幅,以便加载和存储始终对齐,从而更容易启用自动矢量化和循环展开过程。 这些问题经常出现,所以我希望有更优雅的解决方法。 以下是我手工优化的问题的例子,但我相信编译器应该能够为我做。 这些不是进一步的问题。 有时你有一个滤波器,其长度不是最长SIMD寄存器长度的倍数,也可能存在内存对齐问题。 在这种情况下,我要么(A)通过向量寄存器的倍数展开循环并调用结果/序言的未优化代码,或者(B)用零填充filter的开始或结束。 我最近学会了gcc和其他编译器有能力剥离循环。 从我能够找到的有限文档中,我相信使用编译器指令,你对剥离的最好的颗粒控制是整个函数(而不是单个循环)。 此外,您可以提供一些参数,但它主要只是展开量或生成的指令数的上限或下限。 为了真正了解展开/剥离或零填充的最佳方法,编译器需要了解循环的长度和/或增量的大小。 例如,知道循环可能长度大于一百万或小于100将是非常有帮助的。知道循环将总是运行32或34次将是有帮助的。 实际上,由于编译器比我更了解计算机体系结构,如果它根据我提供的有关循环变量的信息做出所有展开决策,会好得多。 我有一种情况,我希望编译器展开循环。 我特意给它了#pragma GCC optimize (“unroll-loops”)指令。 然而,它需要工作的也是语句N &= ~7 ,从而通知编译器循环长度是8的倍数。这不是语言的语义特征,并且它没有改变的效果N的值。严格地告知静态分析器编译器循环已经是AVX寄存器长度的倍数。 在这种情况下,我很幸运,它很有效,因为gcc非常聪明。 但在其他情况下,我的提示似乎不起作用(或者他们这样做,但是没有编译器反馈让我知道附加信息没有价值)。 在一种情况下,我必须明确地告诉编译器不要展开循环,因为外部循环非常短并且开销不值得。 在优化器处于最大设置状态时,通常唯一的方法是了解正在进行的操作是查看汇编列表,进行一些更改,然后再试一次。 在另一种情况下,我小心地展开了一个循环,因此编译器将使用AVX寄存器。 手动展开可能是必要的,因为编译器没有足够的关于循环长度的信息或者长度是特定倍数。 不幸的是,内部循环正在访问每组长度为4的浮点数的未对齐数组(16字节对齐)。 编译器仅使用传统的128位XMM寄存器。 在使用AVX内在函数进行向量化的弱尝试之后,我发现未对齐访问的额外开销使得性能不比gcc正在做的更好。 所以我想,我可以在缓存行的开头对齐每组浮点数,并使用等于缓存长度(或一半,即AVX寄存器的长度)的步幅来消除对齐问题。 但是,由于额外的内存带宽,这可能会变得无效。 这对我来说肯定更有意义。 它使代码更难理解。 并且,至少,正确的步伐将取决于我需要提供的编译时间常数。 我想知道是否有一些更简单的方法可以依靠编译器完成所有工作呢? 我愿意尝试它,如果它只意味着改变一行或两行代码。 如果我必须手动完成它(在这种情况下无论如何),这是不值得的。 (在我写这篇文章的过程中考虑它,我可以使用带有48个字节填充的联合或结构以及一些额外的代码行。我不得不考虑一下……)

将数据写入文件:fflush()需要花费大量时间

我有一个要求,我必须缓冲大量数据(以GB为单位),以备将来使用。 由于没有足够的RAM可用于缓冲如此大量的数据,我决定将数据存储在一个文件中。 现在的缺陷是,当我将数据写入文件时,其他线程可能需要“缓冲”数据,因此每次我写入内容时都必须刷​​新文件流。 确切地说,数据是我作为预先记录的数据(如TiVo)缓冲的video帧,其他线程可能或可能不想在任何给定的时间点写入它,但是当它们这样做时,它们会从文件和进程中fread框架。 在一般情况下, fwrite – fflush组合大约需要150 us,但偶尔(并且相当规律),组合需要超过1.5秒。 我无法负担这一点,因为我必须实时处理帧。 我在这里有很多问题: 我在文件中缓冲数据的方法是否正确? 我有什么替代品? 知道为什么fwrite-fflush操作在某些情况下会突然花费更多时间吗? 请注意,在1.5秒后,它会恢复到150 us。