C语言中的GCC的优化和数组的存放方式、Cache机制、访问局部性

news2024/9/27 15:33:41

“我们仍需共生命的慷慨与繁华相爱,即使岁月以刻薄和荒芜相欺”

文章目录

  • 前言
    • 文章有误敬请斧正 不胜感恩!
    • 第一题:
      • ***什么是gcc:***
      • C 语言中,“gcc -O2”是使用 GCC 编译器时的一个编译选项。
      • 第一部分:为什么程序一输出0,而程序二输出1?
    • 第二题:
      • 第二部分:为什么两个循环版本的性能有差异?
    • Cache机制:
  • 总结


前言

写在开始:

前几天碰到了两个特别有意思的题目,关于C语言的GCC的优化和数组的存放方式、Cache机制、访问局部性.

话不多说我们一起来看一下这两道题目!
在这里插入图片描述


文章有误敬请斧正 不胜感恩!

以下是本篇文章正文内容,


第一题:

请添加图片描述
首先来看

什么是gcc:

在 C 语言中,GCC(GNU Compiler Collection)是一种常用的编译器。

一、编译过程

  1. 预处理:对 C 源文件中的预处理指令(如#include、#define 等)进行处理,生成扩展后的源代码。
  2. 编译:将预处理后的源代码转换为汇编代码。
  3. 汇编:把汇编代码转换为机器代码,生成目标文件。
  4. 链接:将多个目标文件以及所需的库文件链接在一起,生成可执行文件。

二、常用命令选项

  1. -o :指定输出文件的名称。例如,“gcc -o main main.c”将编译 main.c 并生成名为 main 的可执行文件。
  2. -Wall :开启所有警告信息,帮助开发者发现潜在的问题。
  3. -g :生成调试信息,以便在调试器中进行程序调试。

三、优势

  1. 开源免费:可以自由使用和修改,降低了开发成本。
  2. 跨平台:可在多种操作系统上运行,方便开发者进行移植。
  3. 功能强大:支持多种优化选项和高级语言特性,能够生成高效的代码。

C 语言中,“gcc -O2”是使用 GCC 编译器时的一个编译选项。

一、含义
“-O2”代表优化级别为 2。它指示编译器在编译代码时进行一定程度的优化,以提高生成的可执行程序的性能。

二、优化内容

  1. 函数内联:将一些小的、频繁调用的函数直接展开在调用处,减少函数调用的开销。
  2. 循环优化:对循环进行各种优化,如循环展开、强度削减等,以提高循环的执行效率。
  3. 常量传播:将已知的常量值传播到使用该常量的地方,减少计算量。

三、注意事项

1. 虽然优化可以提高性能,但也可能导致一些难以察觉的问题。例如,优化后的代码可能与未优化的代码在行为上略有不同,特别是在涉及未定义行为的情况下。
2. 在调试程序时,最好不要使用优化选项,因为优化后的代码可能会使调试变得更加困难。等程序调试完成后,再使用优化选项进行编译以提高性能。
3. 不同版本的 GCC 对优化的实现可能会有所不同,所以在使用“-O2”选项时,最好对生成的代码进行充分的测试,以确保其正确性和性能。

所以第一题的问题就出在这里。

乍一看,这两个程的运行结果应该是一样的,但是我我们可以发现
第二个程序,除了a和b的比较之外,增加了第三个f(10)调用赋值给c。
这就会牵涉到gcc的优化问题。

第一部分:为什么程序一输出0,而程序二输出1?

程序一与程序二的主要区别在于第三个f(10)的调用。由于优化级别是-O2,GCC编译器会进行一些优化操作。

  1. 程序一:两个变量ab分别调用了f(10)。虽然函数f是一个简单的数学计算(返回1.0 / x),但是编译器可能会将两次调用结果缓存或优化掉,因此a == b的比较可能总是返回1,输出为0的可能是由于浮点数比较的精度问题。

  2. 程序二:除了ab的比较之外,增加了第三个f(10)调用赋值给c。这个额外的调用可能改变了编译器的优化行为,使得浮点数比较更加精确,导致a == b判断为真,所以输出1。

由于浮点数计算中存在一定的精度误差,以及GCC的优化行为不同,程序一和程序二的输出结果可能会不同。这可能是因为浮点数运算在高优化级别下被进一步精简或缓存,导致结果不一致。

第二题:

请添加图片描述

第二部分:为什么两个循环版本的性能有差异?

首先?什么是二维数组,二维数组和一维数组一样,一维数组存放元素,二维数组存放一维数组,实质也是存储数据的一个容器对象。

public static void main(String [] args){
	//定义int类型的二维数组
	int[][] arrs= new int [3][2];
	System.out.println(arrs);
}
//赋值
arrs[0][0]=1;
arrs[0][0]=2;

arrs[1][0]=3;
arrs[1][1]=4;

arrs[2][0]=5;
arrs[2][1]=6;

赋值之后的数组:

在这里插入图片描述
有了这个理解,我们再讨论遍历
什么是遍历二维数组?
所谓的遍历二维数组,实际是遍历一维数组,然后遍历每个一维数组的信息。

按列顺序访问时,虽然算法逻辑上是正确的,(数据结构里面的,顺序结构逻辑上顺序和顺序存储,数据是,物理上顺序),
但每次访问的内存地址不连续,缓存命中率低,因此性能下降,执行速度会降低
(个人理解)
所以,第二个肯定更慢

详解:
两个程序的功能是相同的,只是嵌套循环的顺序不同:

  1. copyijfor(i = 0; i < 2048; i++) 外层循环遍历行,for(j = 0; j < 2048; j++) 内层循环遍历列。

  2. copyji:相反,外层遍历列,内层遍历行。

两者的计算复杂度都是O(n²),但是访问内存的方式不同:

  • Cache局部性:现代处理器在访问内存时使用缓存(cache)来加速操作。当连续访问相邻的内存地址时,缓存的命中率更高,速度更快。
    • copyij版本中,每次访问src[i][j]dst[i][j]时,内存访问是按行顺序进行的,这符合内存连续性,能更好地利用CPU缓存。
    • 而在copyji版本中,按列顺序访问时,虽然算法逻辑上是正确的,但每次访问的内存地址不连续,缓存命中率低,因此性能下降,执行速度变慢了。

所以:Cache机制是导致两个程序性能差异的关键。

Cache机制:

以下我们来详细谈谈Cache机制

Cache 机制即缓存机制。

一、定义与作用

  • 定义:Cache 是一种高速存储区域,用于临时存放数据,以减少对较慢存储设备的访问次数。
  • 作用:提高数据访问速度,减少系统响应时间,提升系统性能。例如,在计算机系统中,CPU 高速缓存可以大大加快数据处理速度;在网页浏览中,浏览器缓存可以快速加载之前访问过的页面资源。

二、工作原理
当系统需要访问数据时,首先会检查 Cache 中是否存在所需数据。如果存在,直接从 Cache 中读取,速度非常快;如果不存在,则从较慢的存储设备(如内存、硬盘等)中读取数据,并将其存入 Cache 中,以便下次访问时可以更快地获取。

三、常见类型

  1. CPU 缓存:分为一级缓存(L1 Cache)、二级缓存(L2 Cache)和三级缓存(L3 Cache)等,离 CPU 核心越近的缓存速度越快但容量越小。
  2. 浏览器缓存:存储网页的静态资源(如图片、脚本、样式表等),当再次访问同一页面时,可以直接从缓存中加载资源,减少网络请求。
  3. 数据库缓存:缓存数据库中的查询结果,当相同的查询再次执行时,可以直接返回缓存中的结果,提高数据库查询性能。

四、管理策略

  1. 替换策略:当 Cache 已满且需要存储新数据时,需要选择一个旧数据进行替换。常见的替换策略有先进先出(FIFO)、最近最少使用(LRU)和随机替换等。
  2. 写入策略:决定当数据在 Cache 中被修改后,如何同步到较慢的存储设备中。常见的写入策略有写直达(Write-through)和写回(Write-back)等。

总结

cache机制是我们解题的关键。以上,便是我们今天学习的内容,我们下篇文章再见。


在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2137683.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

利用yolov8模型实现的西红柿成熟程度检测系统包含源码+配置说明(基于YOLOv8的西红柿成熟程度检测系统)

西红柿成熟程度的检测对于农业生产尤为重要&#xff0c;可以提高收获效率和产品质量。本项目利用YOLOv8&#xff08;You Only Look Once v8&#xff09;模型实现了一个高效的西红柿成熟程度检测系统。该系统可以自动识别西红柿的颜色&#xff0c;从而判断其成熟程度。 关键特性…

pycharm从VCS获取项目报错unable to access:Recv failure:Connection was reset

&#xff08;已老实求放过&#xff09; 版本&#xff1a;PyCharm Community Edition 2024.2.1 【解决办法】取消Git的网络代理&#xff0c;在目标路径所在文件夹处右键选择Git Bash Here&#xff0c;输入以下命令&#xff1a; git config --global --unset http.proxy git …

2024最新版零基础学习Modbus通信协议(保姆级教程)

合集 - 上位机开发(2) 1.零基础学习Modbus通信协议09-13 2.RS485与ModbusRTU09-10 收起 大家好&#xff01;我是付工。 2012年开始接触Modbus协议&#xff0c;至今已经有10多年了&#xff0c;从开始的懵懂&#xff0c;到后来的顿悟&#xff0c;再到现在的开悟&#xff0c;…

STM32的寄存器深度解析

目录 一、STM32 寄存器概述 二、寄存器的定义与作用 三、寄存器分类 1.内核寄存器 2.外设寄存器 四、重要寄存器详解 1.GPIO 相关寄存器 2.定时器相关寄存器 3.中断相关寄存器 4.RCC 相关寄存器 五、寄存器操作方法 1.直接操作寄存器 2.使用库函数操作寄存器 六…

4个方法教你图片转PDF怎么弄。

我们有时候会接触了一些重要的图片文件或者资料&#xff0c;想要装换成可编辑的PDF格式&#xff0c;更方便自己管理。这时候就会需要转换的工具&#xff0c;我这里就有&#xff14;款可以完成这种转换的高效工具可以分享给大家。 1、365PDF转换软件 直通车&#xff1a;www.pdf…

软件设计之JavaWeb(3)

软件设计之JavaWeb(3) 此篇应在MySQL之后进行学习: 路线图推荐&#xff1a; 【Java学习路线-极速版】【Java架构师技术图谱】 尚硅谷全新JavaWeb教程&#xff0c;企业主流javaweb技术栈 资料可以去尚硅谷官网免费领取 此章节最好学完JDBC观看 学习内容&#xff1a; 请求转发…

jenkins流水线+k8s部署springcloud微服务架构项目

文章目录 1.k8s安装2.jenkins安装3.k8s重要知识1.简介2.核心概念3.重要命令1.查看集群消息2.命名空间3.资源创建/更新4.资源查看5.描述某个资源的详细信息6.资源编辑7.资源删除8.资源重启9.查看资源日志10.资源标签 4.k8s控制台1.登录2.界面基本操作1.选择命名空间2.查看命名空…

损耗金属件检测系统源码分享

损耗金属件检测检测系统源码分享 [一条龙教学YOLOV8标注好的数据集一键训练_70全套改进创新点发刊_Web前端展示] 1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 项目来源AACV Association for the Advancement of Computer V…

全球和局部精细化:提升大模型推理能力的新方法

人工智能咨询培训老师叶梓 转载标明出处 尽管大模型在数学、科学或编程任务上表现出优异的推理精细化能力&#xff0c;但它们在没有外部反馈的情况下&#xff0c;很难识别何时何地需要精细化。为了解决这一问题&#xff0c;来自Meta的FAIR团队和佐治亚理工学院的研究者们提出了…

智能营销才是营销的未来

智能营销新纪元&#xff1a;大模型如何为运营与产品经理赋能 在数字化浪潮席卷全球的今天&#xff0c;营销行业正经历着一场前所未有的变革。随着人工智能技术的飞速发展&#xff0c;特别是大模型技术的兴起&#xff0c;为产品经理和运营人员提供了前所未有的工具与视野&#…

雷·达利欧(Ray Dalio)的20条《原则》

达利欧在《原则》&#xff08;Principles&#xff09;一书中总结了许多实用的原则。这些原则被广泛认同&#xff0c;并且适用于多种情景。以下是20条核心原则的英语原文以及中文翻译&#xff1a; 1. Embrace reality and deal with it. 翻译: 拥抱现实并应对它。适合场景: 适用…

c++中的继承和多态

目录 Linux中的管道通信 ​编辑派生类的默认成员函数 继承 派生类的构造 隐藏 如何设计一个不能被继承的类 菱形继承 virtual virtual是如何解决的 内存对象模型 继承和组合 继承 组合 多态 概念 多态的构成条件 虚函数的重写 Linux中的管道通信 派生类的默认成…

[数据集][目标检测]俯拍航拍森林火灾检测数据集VOC+YOLO格式6116张2类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;6116 标注数量(xml文件个数)&#xff1a;6116 标注数量(txt文件个数)&#xff1a;6116 标注…

Lombok介绍

一、Lombok 1.1何为Lombok Lombok是Java的一个库&#xff0c;是一个工具&#xff0c;使用这个工具能够使得我们通过使用注解的方式减少Java中代码的开发。其简化主要是针对Java中的简单Java对象(就是无继承、无实现的)类。我们化简的就是这些类中重复冗余出现的构造函数&#…

运算符学习

ctrlaltL 自动格式化代码 原码反码补码 负数用反码去计算不会出错。跨零就会出错。补码解决了 字节-128到127

双指针的用法以及示例

当然可以&#xff01;双指针&#xff08;Two Pointers&#xff09;是一种常用的算法技巧&#xff0c;特别适用于处理数组或链表等线性数据结构的问题。以下是双指针用法的总结&#xff1a; 双指针用法总结 基本概念&#xff1a; 双指针技术使用两个指针在数据结构上进行遍历&a…

SpringBoot集成Thymeleaf模板引擎,为什么使用(详细介绍)

学习本技术第一件事&#xff1a;你为什么要使用&#xff0c;解决什么问题的&#xff1f; 1.为什么使用&#xff08;使用背景&#xff09;&#xff1f; 首先应用场景是单体项目&#xff0c;如果是前后端分离就不用关注这个了&#xff0c;因为单体项目你前后端都是写在一个项目…

关于决策树的一些介绍(二)

我之前写过一篇关于决策树的文章&#xff0c;但在那篇文章里没有提及基尼系数&#xff0c;信息熵与信息增益等相关问题&#xff0c;所以我将在这篇文章中进行补充。 一、 决策树的一份python代码 首先&#xff0c;我先给出一份最基础的决策树代码&#xff0c;在这里&#xff…

在 Python 画图中同时设置中英文字体

前言 在使用matplotlib.pyplot画图时&#xff0c;默认情况下都是黑体字&#xff0c;很不美观。如果含有中文&#xff0c;可能无法显示&#xff1b;显示了中文之后英文字体就不能使用。本文针对这些问题逐一给出解决方案。 同时设置中英文字体 我们都知道&#xff0c;按照下面的…

00898 互联网软件应用与开发自考复习

资料来自互联网软件应用与开发大纲 南京航空航天大学 高纲4295和JSP 应用与开发技术(第 3 版) 马建红、李学相 清华大学出版社2019年 识记:要求考生能够识别和记忆本课程中有关互联网软件开发与应用的概念性内容,并能够根据考核的不同要求,做出正确的表述、选择和判断。领会…