速通CSAPP(一)计算机系统漫游入门

CSAPP学习

前言

一门经典的计组课程,我却到了大四才学。

anyway,何时都不会晚。

博主参考的教程:本电子书信息 - 深入理解计算机系统(CSAPP) (gitbook.io),非常感谢作者的整理。

诚然去看英文版可以学到更多,不过一边翻译一边看的过程我觉得还是效率不高的,所以还是选择中文。

博主之前有一定的计算机基础,所以对一些简单概念可能跳得比较快,这里建议读者不懂的地方不要气馁“为什么这里三两句就讲掉了,但是我还没懂”。建议多多发掘自我检索能力,Search the Fxxking Web (STFW) 是计算机专业同学的一大重要能力。

Ch1. 计算机系统漫游

程序运行前4个阶段

相信尝试过一定编程学习的同学们都有过写、运行 helloworld 的经历。可能是用 Dev C++,VSCode,CLion 等 IDE,也可能是自己在命令行执行编译运行语句,本质都是一样的。

那么写了一个 helloworld.c,这个程序是怎么运行起来的呢?

首先计算机能直接运行的都是二进制文件,01010101110101……类似这样的文件。但是要是说让我们用这种语言(机器语言)编程,效率极低而且大概率会疯掉。

汇编语言是一种为了解决这个问题而诞生的低级语言,相对好理解一些,可以转换成机器语言。不过还是面向计算机的语言,编程习惯主要也是按照计算机的思维走,也比较难。

c语言是一种高级语言,是我们人类一定程度上能理解的编程语言,可以转换成汇编语言,再转成机器语言,供计算机运行。

gcc -o hello hello.c

这条命令行语句意思是用 gcc 翻译工具,把 hello.c 翻译成目标输出文件(output)hello,得到的可执行文件就是 hello。

翻译流程如下:

image-20231126214148576

预处理:把文件中的注释信息去掉(注释信息是给人看的,对计算机运行没啥帮助),把头文件展开(其实头文件 #include #define 这些就是对一些格式内容的拷贝),得到 .i 文件。

编译:把高级语言翻译成汇编语言。相同的程序用不同高级语言写,经过编译器后,得到的汇编语言是相同的,也就是计算机最终执行的具体行为都是一样的。感兴趣同学可以了解一下编译和翻译两种高级语言转汇编语言的方式。

汇编:把 .s 汇编文件转为 .o 目标文件,目标文件也是二进制形式。但是缺少一些外部链接的库,暂时不能执行(比如 printf 函数是在 printf.o 文件中定义的,我们自己没定义,所以不能自己直接用,需要外链 printf.o 文件才能使用)。

链接:如上所述,最终生成一个可执行的目标程序。

好现在是可以理解高级语言的作用(让我们不用理解计算机具体运行方式,就能较为简单的编程,生成可执行文件)。但是我们还是需要学习一下底层的编译、汇编等原理的:

  • 因为理解底层具体实现后,我们才知道怎样编写的程序运行更高效(同一个问题有许多解法,可以写许多种程序,比如 switch case 和 if else if,但是并不是能解决正确性的程序就是好程序了,我写一个跑一年才出结果的代码和跑1小时就出结果的代码价值也是完全不同的)。
  • 对程序理解更深,出现问题时我们也知道如何排查,bug 不全是只有中英文字符那种程度的哦。
  • 甚至有一些安全性问题是通过对底层原理进行攻击的。

CPU硬件运行方式

程序翻译成汇编语言类似这样:

main:
    subq $8, %rsp       ; 通过从栈指针(rsp)减去8字节,为栈分配空间。
    movl $.LC0, %edi    ; 将字符串".LC0"的地址加载到目标寄存器%edi中。
    call puts           ; 调用puts函数,该函数可能打印%edi寄存器指向的字符串。
    movl $0, %eax        ; 通过将0移动到%eax寄存器中,将返回值设置为0。
    addq $8, %rsp       ; 通过将8字节添加到栈指针(rsp),释放栈上的空间。
    ret                 ; 从main函数返回。

不用看懂。可以看到按照计算机思维,这个程序被拆成了这么多条要执行的指令。CPU 执行程序的时候就是一条条指令执行的。

具体是怎样执行?下图是 计算机基本组成的结构图。计算机五大组成部分:CPU(运算器+控制器),内存,输入,输出。

1701006354660

总线:在各个设备之间传输数据用。

输入设备:把信息输入给电脑的一些方式,比如键盘打字,鼠标点击,光盘U盘,我们写的程序存在磁盘上。

输出设备:电脑把信息输出给我们的方式,比如可以看到的显示器。输入输出设备统称 IO 设备。

主存:也叫内存,程序从磁盘里拿出来放到主存里运行。内存是衡量计算机运行快不快的一个重要指标因为内存小了每次能拿一小部分程序进来运行,再拿下一部分,效率比较低,内存大了磁盘和内存之间交互可能相对就快很多(磁盘里的内容往内存拿是比较占时间的)。

CPU:从主存里面拿一个个字节的数据进行处理。PC 是一个指针指向当前要拿的数据的位置;首先从 PC 所指向的主存地址中加载几个字节到 CPU 寄存器里,把寄存器中的内容复制到 ALU 中进行操作,比如取到了a和b的值算a+b;然后可能需要把一些数据存储写回到主存中,比如让 c=a+b,c的值变了,那么我们可能就需要把新值写回到主存中c的位置;最后 PC 跳转,指向下一部分要取的字节的位置。重复上述操作直到程序执行完。

比如想跑一个 helloworld 我们经历了这些步骤:

  1. 鼠标键盘输入,写了一个 helloworld 程序并点击运行或 shell 输入运行语句 ./helloworld。我们输入的运行指令也是先被放到主存,然后被 CPU 寄存器文件读取,CPU 解析后明白我们是想执行 helloworld 文件,然后再下指令从磁盘中取 helloworld 程序到主存里运行。
  2. helloworld 程序被加载到主存中(虽然 CPU 是计算机的大脑,中控中心,但是这里磁盘数据不用经过 CPU 可以直接给主存是利用了 DMA 技术),CPU 再取主存中的数据进行指令解析,执行。
  3. CPU 解析指令直到我们是想在终端打印 helloworld,于是驱动显示器输出设备输出显示 helloworld。

Cache 缓存

CPU 去主存取指令,和去磁盘取指令,其实都有一定的时间开销(去磁盘开销更大)。我们可以在 CPU 内部临时存一些近期可能要访问到的内容,这样当访问到这部分内容的时候不需要每次都去主存去磁盘拿,在自己这里就找得到就快很多。比如c=a+b;c=a+b;c=a+b;c=a+b; 执行这个指令,如果第一次执行的时候 CPU 猜测,a和b的值后面会不会还要用到,我先在缓存里存一下以备不时之需。第二次执行的时候可以直接拿到本地缓存 cache 中存储的 ab 值进行运算,不用去磁盘里再取一次了,第三次第四次也是,这样就比较节约时间开销。

1701007513400

当然缓存大小有限,以此来保证 CPU 芯片大小不会太大和缓存中查找不会太慢。因此我们要设计一些缓存存储算法来决定哪些内容优先被存入缓存,这个后面再细讲。

缓存结构其实是这样的,著名的缓存金字塔:

1701008756610

上面一层是下面一层的缓存。

操作系统

operating system,了解一些的同学可能知道,比如win系统,mac系统,linux系统,这玩意啥用处呢。主要是实现对资源的分配管理。

1701009194351

比如我qq应用程序,要调用键盘,调用摄像头,要调用键盘……首先应用程序直接去操作这些底层的 CPU,主存,IO 都比较麻烦,而且也不安全(比如qq崩溃异常状态下去调用这些设备)。操作系统负责中间管理,抽象出这些设备的接口供应用程序调用,也保护硬件不被失控应用程序滥用。

操作系统的抽象如下:

1701011455062

进程

一个正在运行的程序。操作系统会协调多个进程交错执行,比如我现在电脑上开着微信 浏览器 Typora,内核不停地切换这些进程的执行而我感觉不到。

进程切换需要保存当前进程状态,切换到下一个进程的状态继续运行,这个状态叫上下文 context。

1701011886237

一个进程可能包含多个线程,他们共享这个进程的资源。

GPT:

1701012069165

虚拟内存

操作系统让多个进程互不干扰的使用主存,对每个进程来说他们只看得到自己的主存占用范围,感觉好像只有自己在占用主存,这就叫虚拟内存。

1701012340917

如图是主存中的组成,从下往上地址逐渐增大。

内核虚拟内存:给操作系统用的。

用户栈:比如程序里的函数,存到这里入栈。

共享库内存:比如 printf 这种共用库。

堆:比如 malloc 申请的空间,存在这里,也是多个程序共用。

数据:存放程序数据。

虚拟内存具体实现方法后面讲解。

文件

字节序列。所有 IO 设备都可以看做是文件,我们可以往文件里读写数据进行 IO 操作。这样我们对磁盘进行读写的时候其实我们并不关心具体读写 IO 行为,我们只需要往磁盘文件夹里读写文件即可。

网络通信

其实网络也类似一个 IO 设备,我们给网络适配器写入数据流,网络适配器发送给另一台主机。

比如下例,好处在于我们可以把程序存在服务器上,在服务器上跑,我们只需要发送简单指令。比如学习深度学习,不用自己非得买一个牛逼电脑,可以租牛逼服务器(服务器其实也算是一种电脑,和我们的客户端电脑没啥区别)。

1701012804553

重要概念

Amdahl 定律

计算提升系统某一部分性能对整个系统所带来的效果。

α是某一部分在整个系统中占的比重,k是这部分的性能加速了多少。S是最终对整个系统提升的加速效果。

1701013272748

比如α=60%,k=3,这一部分提升了3倍速度,但是对整体速度的提升是1.67倍,可见想要提升系统整体速度,需要提升系统中大部分的速度。

并发 并行

并发:一个系统同时运行多个活动。

并行:利用并发来加速程序运行。

线程级并行

进程中多个任务的切换。

单处理器系统:模拟并发,即实际上是不断切换。

多处理器系统:确实可以并发运行,也可以加速用多线程方式写的单个程序。

超线程:也叫同时多线程,允许单核 CPU 执行多个控制流,多个控制流共享执行单元。比如单处理器切换线程,需要保存当前状态,切换 pc 指针,寄存器值……而超线程多个核对 pc,程序计数器等有拷贝,使得切换的时候不用那么麻烦,比如常规单处理器切换可能需要20000个周期,超线程一个周期就能切换。

指令级并行

有些系统硬件支持把一条指令拆成多个任务同时处理。

当指令周期小于1的时候(一个 CPU 时钟周期可以执行平均1条以上的指令)系统被称作超标量系统。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

谈谈中间件设计的思路

前言 想要设计和真正理解中间件的架构理论和思想。对于开发来说需要具备三个关键的能力 1:基础通用技术的深入理解和运用2:了解和熟悉常见中间件的设计思想,且有自己的感悟,并且能按照自己的理解模仿写一写3:业务的高度理解能力…

解密Spring Cloud微服务调用:如何轻松获取请求目标方的IP和端口

公众号「架构成长指南」,专注于生产实践、云原生、分布式系统、大数据技术分享。 目的 Spring Cloud 线上微服务实例都是2个起步,如果出问题后,在没有ELK等日志分析平台,如何确定调用到了目标服务的那个实例,以此来排…

使用elementPlus去除下拉框蓝色边框

// 下拉框去除蓝色边框 .el-select {--el-select-input-focus-border-color: none !important; }

生成EtherCAT从站XML图片信息方法

0 工具准备 1.PS CS6 2.Hex Editor Neo(文件Hex编辑器) 3.DM3E-556步进电机驱动器 4.TwinCAT(验证XML图片修改效果)1 准备一张需要生成图片信息的图片 根据EtherCAT从站XML图片格式规范,我们需要用到的元素名为ImageData16x14,它要求使用16x14分辨率、深度为16bit的bmp…

【Android Jetpack】Navigation的使用

引入 单个Activity嵌套多个Fragment的UI架构模式,非常非常普遍。但是,对Fragment的管理一直是一件比较麻烦的事情。工程师需要通过FragmentManager和FragmentTransaction来管理Fragment之间的切换。页面的切换通常还包括对应用程序App bar的管理、Fragme…

Java实现集合和Excel文件相互转换

目录 一、集合转化为Excel文件二、Excel文件转化为集合 一、集合转化为Excel文件 效果如下,是将集合转化为Excel文件,Excel包含合并单元格。 实体类: Data public class ClassGrade {/** 年级 */private String grade;/** 班主任 */privat…

智汇方象惠管家:提升电商系统与广告推广的效率,实现无代码开发的连接

无代码开发的连接优势 在当今快速发展的电商领域,商家们急需一个既能优化电商系统又能提升客服体验的解决方案。智汇方象的惠管家,一个基于云计算的SAAS服务,就是为了满足这一需求而生。这款工具通过无代码开发的方式,使得连接和…

中国北斗:守护萨雷兹湖一方安澜

中国北斗:守护萨雷兹湖一方安澜 在第三届“一带一路”国际合作高峰论坛数字经济高级别论坛上,由中国经济信息社、国家发展改革委高技术司、国家数据局联合编制的《数字“慧”就发展之路》中英文图文集正式发布,展现了中国与共建“一带一路”国…

Codeforces Round 911 (Div. 2) --- D题题解

D. Small GCD Problem - D - Codeforces 题目大意: 给你一个数组,你可以在里面任选三个数ai aj ak,要求i j k 互不相同, 现定义一个函数f(a,b,c)gcd(a,b),其中a 和 b为a,b,c中较小的两个。求f…

Callable、Future和FutrueTask详解

一、Callable介绍 1.1 Runnable介绍 Runnable是一个接口,里面声明了run方法。但是由于run方法返回值类型为void,所以在执行完成任务后,无法返回任何结果。 FunctionalInterface public interface Runnable {public abstract void run(); }…

SIFT尺度不变特征变换

SIFT(Scale-Invariant Feature Transform)是一种用于图像处理和计算机视觉中的特征提取和匹配的算法。它的主要优点是对图像的尺度、旋转和亮度变化具有较强的鲁棒性。 基本原理: Scale-space peak selection: Potential location for finding features.Keypoint Localizat…

Redis 命令处理过程

我们知道 Redis 是一个基于内存的高性能键值数据库, 它支持多种数据结构, 提供了丰富的命令, 可以用来实现缓存、消息队列、分布式锁等功能。 而在享受 Redis 带来的种种好处时, 是否曾好奇过 Redis 是如何处理我们发往它的命令的呢? 本文将以伪代码的形式简单分析…

【活动回顾】ABeam 德硕| 艾宾信息技术开发(西安)西北高校行——与西北三所高校签订校企合作协议

前言 INTRODUCTION 10月下旬,ABeam旗下艾宾信息技术开发(西安)校招团队来到宁夏大学、青海大学、兰州大学这三所高校,就校企合作达成多项共识并举行了隆重的签约仪式。ABeam大中华区董事长兼总经理中野洋辅先生也特意留出时间莅临…

【活动回顾】sCrypt在2023伦敦区块链大会上的精彩表现

2023伦敦区块链大会,是本年度最盛大的比特币及区块链行业活动。大会于2023年5月31日至6月2日,在伦敦女王伊丽莎白二世中心举行,旨在展示BSV区块链的真正潜力。 sCrypt Inc 的创始人兼 CEO 刘晓晖, 作为演讲嘉宾出席了会议。他向大…

FreeImage 编译安装

FreeImage下载: The FreeImage Project 点击第6行: Download FreeImage 3.18.0 或: wget http://downloads.sourceforge.net/freeimage/FreeImage3170.zip #解压 unzip FreeImage3170.zip -d freeImage 编译FreeImage源代码可能需要遵循…

抓包工具安装

charles的安装 参考链接:[Python3网络爬虫开发实战] 1.7.1-Charles的安装 | 静觅 说明: 1.电脑端+手机端 都需要安装证书,安装证书是为了能抓取https协议的接口 2.手机端设置wifi的网络代理 + 电脑端设置代理端口,即可实现抓包。 特定流量抓包 HttpCanary(安装在手机里…

echarts散点图(象限图)设置不同的颜色

如图所示&#xff1a; <template><div ref"sdtcmijy" :style"{height:scrollerHeight}"></div> </template> <script> import {getXxt} from ./../requestAPI.jsexport default {data(){return {params:{},seriesData:[],…

Vue快速实践总结 · 上篇

文章目录 模板语法数据绑定事件处理计算属性监视属性&#xff08;监听器&#xff09;条件渲染列表渲染数据监视原理内置指令总结生命周期组件化编程组件使用步骤组件的嵌套this指向单文件组件ref、props 脚手架(Vue CLI)render函数 参考自己的Vue专栏以及Vue官方文档 模板语法 …

10 个例子带你学会 AI 编程(含提示词)

大家好&#xff0c;我是伍六七。 AI 编程是一个程序员群体普遍关注的领域&#xff0c;但是真的使用 AI 编程实现提效的还是少数。 有的人没有大模型资源&#xff0c;有的人不知道可以在哪些方面使用 AI 进行提效&#xff0c;还有的人不相信使用 AI 可以提效。 今天&#xff…

用java实现王者荣耀

第一步是创建项目 项目名自拟 第二部创建个包名 来规范class 然后是创建类 GameFrame 运行类 package com.sxt; import java.awt.Graphics; import java.awt.Image; import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; impo…