首页 > 其他分享 >clang在指定-O2时对函数局部变量的优化

clang在指定-O2时对函数局部变量的优化

时间:2024-03-06 23:13:49浏览次数:26  
标签:函数 ++ 局部变量 clang gdb main O2

在我们将编译器从g++迁移到clang++的过程中,遇到一个问题,有个工具程序只要一运行就会出现core dump问题,并且用gdb调试core文件也无法获得任何有用的堆栈信息。
通过不断尝试,发现只有在clang++使用-O2编译时得到的程序才会发生这个问题,使用clang++ -O0或者g++编译时不会发生问题。
然后我们又尝试将bash的默认stack size调大到1000M后去执行程序,就不会出现core dump。

从stack size这个方向来看,应该是栈空间不够大导致的,但是问题在于在main函数第一个指令执行之前就会出现core,此时还没有申明或者使用任何函数局部变量。据本人目前了解的知识来推测可能有以下两种可能:

  1. 是不是有超大的__thread类型的变量导致的?
  2. 某个函数中使用了什么特殊代码导致clang++ -O2优化到main执行前的过程了?
    先对第1种猜想进行排查代码后,没有发生有这么大的线程局部变量,先搁置。
    然后考虑第2种猜想,此时没有其他好的办法只能从main函数中使用二分法进行排查,从后往前删代码,看看是哪段代码导致的。果然发现一个函数只要出现在main函数中,就会导致问题(该函数只有在特定的一种情况下才会被调用,出core的情况下不会调用到该函数)。

然后对该函数进行研究,发现它有个很大的局部类对象,sizeof的长度达到600M。将该对象改造为堆对象后,问题解决了。

以下是探究这个问题后得到的结论:
clang++ -O2编译的程序中,一个未被实际调用到的函数中的局部变量如果可能被调用到,那进程会在main执行前就将可能的最大栈空间预先分配。

示例代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void func_1()
{
    char tmp[1024*1024*500];
    memset(tmp, 0, sizeof(tmp));
    printf("func_1() tmp=%s\n", tmp);
}

void func_2()
{
    printf("func_2()\n");
}

int main(int argc, char *argv[])
{
    int opt = atoi(argv[1]);
    if (opt == 1)
    {
        func_1();
    }
    else if (opt == 2)
    {
        func_2();
    }
    return 0;
}

编译命令:

clang++ -g -O2 test.cpp -o test

使用gdb进行调试,查看在刚刚进入main函数时,栈空间是多大:

gdb --args ./test 2

(gdb) b main
(gdb) r
(gdb) p argv
$1 = (char **) 0x7fffffffe2b8 #此地址是保存命令行参数字符串值的起始位置,可以近似认为是程序实际使用到的栈空间起始位置,不过紧临它之前还会有很多环境变量字符串的信息,可能也会有几KB长度,先不考虑它
(gdb) n
(gdb) info proc mappings #此命令可以看到stack段的实际申请大小,从下面可以看到stack的大小0x1f402000(单位为KB)已经达到了512MB
      0x7fff8f34a000     0x7fff8f34c000     0x2000        0x0 [vdso]
      0x7fff8f34c000     0x7fff8f34d000     0x1000    0x21000 /usr/lib64/ld-2.17.so
      0x7fff8f34d000     0x7fff8f34e000     0x1000    0x22000 /usr/lib64/ld-2.17.so
      0x7fff8f34e000     0x7fff8f34f000     0x1000        0x0 
      0x7fffe0bfd000     0x7ffffffff000 0x1f402000        0x0 [stack]
  0xffffffffff600000 0xffffffffff601000     0x1000        0x0 [vsyscall]

从实际测试情况来看,优化策略会将函数栈中所有可能用到的栈空间进行计算得到一个最大值,然后在main执行之前就预先申请这么大的栈空间。如果是递归函数的话就直接忽略不去计算。

还有种情况是多线程的时候,只有主线程会计算这个最大栈空间大小去扩展stack区域的长度,对于子线程而言它们会按照ulimit -s的大小去申请栈空间。

标签:函数,++,局部变量,clang,gdb,main,O2
From: https://www.cnblogs.com/lifewithlight/p/18028347

相关文章

  • P9185 [USACO23OPEN] Rotate and Shift B 题解
    首先,我们很容易就能得出一个显而易见的结论:若令原数组为\(order\),\(K\)个活跃位置分别为\(A_1,A_2,...,A_K\),则\[order_{A_1}\toorder_{A_2},order_{A_2}\toorder_{A_3},...,order_{A_K}\toorder_{A_1}\]的操作就等价于将\(order\)数组顺时针旋转\(x\)次,即\[orde......
  • P9184 [USACO23OPEN] Moo Language B 题解
    恶♂趣♂味♂大♂模♂拟♂。首先是构造语句部分:开始肯定是尽可能地多用上不及物语句和及物语句;接着,因为及物语句的单词数量一定比不及物语句多,所以贪心地尽可能多地将不及物语句改为及物语句;然后,为了增加语句长度,再次贪心地在及物语句中尽可能多地添加名词和逗号即可。......
  • P9183 [USACO23OPEN] FEB B 题解
    由于只需要考虑相邻的位置,所以每一段连续的F是互不影响的,可以分别进行考虑。而连续的一段F又可以分成两类:靠边的和被夹在中间的。靠边的F段较为简单,假定有\(c\)个F,不难发现只要让EB交错出现就可以达到最少次数,而让所有的F都变成最近的非F就可以达到最多次数\(c......
  • P10187 [USACO24FEB] Palindrome Game B 题解
    挑战题解区最短代码回文数?数学题!打表找规律吧……显然,\(1\sim9\)都是回文数,先手赢(就一位你还想咋地啊)。然后是\(10\)。样例告诉我们,这个不行。接着是\(11\sim19\),发现随便减个\(1\sim9\)就可以变成\(10\),而\(10\)是后手赢。赢得就是后手的后手,那就是先手,可以。......
  • P10189 [USACO24FEB] Maximizing Productivity B 题解
    先说说暴力做法:每次遍历一遍,看看是否满足\(t_i+s\lec_i\),满足就计数,不满足就挂。单次时间复杂度显然为\(O(N)\),总得时间复杂度约为\(O(NQ)\),TLE是肯定的~暴力代码//Problem:Problem3.MaximizingProductivity//Contest:USACO-USACO2024FebruaryContest,......
  • 题解 P10196【[USACO24FEB] Lazy Cow P】
    总算铂金组场切一题。似乎做麻烦了,而且常数蛮大的,但是没啥思维难度,记录一下。对于每一个需求,我们将其放置在平面直角坐标系的\((m_i,b_i)\)位置。另外,自然有一个\((0,0)\)需求,也同样处理这个点。我们需要支持插入一个点的操作,并维护出答案。先考虑不需要动态插点,只在最后求......
  • P9370 APIO2023 cyberland
    题面:https://www.luogu.com.cn/problem/P9370显然只有从\(0\)出发不经过\(H\)能到达的点是有用的。首先,考虑跑多源最短路,将\(arr=0\)的点都作为源点(当然\(0\)也是源点)。不难发现这样转化后,这些点即可视作\(arr=1\)。对于\(arr=2\)的点,由于能使用除以二技能的次数很......
  • P10139 [USACO24JAN] Nap Sort G 题解
    DescriptionBessie正在尝试使用她自己的排序算法对一个整数数组进行排序。她有一堆共\(N\)(\(1\leN\le2\cdot10^5\))个整数\(a_1,a_2,\ldots,a_N\)(\(1\lea_i\le10^{11}\)),她将会按排序顺序将这些数放入一个单独的数组中。她反复查找这堆数中的最小数,将其删除,同时将其添加到......
  • P6646 [CCO2020] Shopping Plans 题解
    好好玩的题。思路对于前\(K\)小方案问题。我们可以考虑当前方案对下一个方案的转移。重点在于转移的最优化与不重不漏。只有一种种类假设没有\(l,r\)的限制怎么做。我们不妨把所有价格排序。发现一种状态转移到另一种状态,无异与将其中已选择的一个物品不选,选择他后面......
  • 2024年!vscode和clangd的配置
    前言Ubuntu20系统下,使用vscode和clangd来进行代码补全和拼写检查.安装vscode直接从Ubuntu的应用商店下载vscode.安装clangd$sudoaptinstallclangd安装vscode插件-clangdvscode安装clangd插件不需要对clangd插件进行配置.不需要对clangd插件进......