首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

go语言调度源代码情景分析之三:内存

内存由大量内存单元组成,内存单元大小为1个字节(1字节包含8个二进制位), 每个内存单元都有一个编号,更专业的说法是每一个内存单元都有一个地址,我们在编写汇编代码或编译把用高级语言所写的程序编译成汇编指令时...下面再用上一节讨论寄存时使用过的例子来帮助我们加深对内存的理解: c = a + b // go语言代码 mov (%rsp),%rdx #把变量a的值从内存中读取到寄存rdx...中 mov 0x8(%rsp),%rax #把变量b的值从内存中读取到寄存rax中 add %rdx,%rax #把寄存rdx和rax中的值相加,并把结果放回rax...寄存中 mov %rax,0x10(%rsp) #把寄存rax中的值写回变量c所在的内存 这里的4条指令有3条跟内存读写有关,指令中的rsp寄存里面存放的是一个内存地址,现假设这个内存地址是...X, 则第一条指令 mov (%rsp),%rdx 表示把从地址为X开始的8个内存单元中的值读取到rdx寄存中(因为rdx是一个64位寄存,这就隐含了要一次读取连续的8个字节,指令中的地址只是起始地址

79330

go调度源代码情景分析之九:操作系统线程及线程调度

本文是《go调度源代码情景分析》系列 第一章 预备知识的第九小节。...要深入理解goroutine的调度,就需要对操作系统线程有个大致的了解,因为go的调度系统是建立在操作系统线程之上的,所以接下来我们对其做一个简单的介绍。...如上所述,操作系统会把不同的线程调度到同一个CPU上运行,而每个线程运行时又都会使用CPU的寄存,但每个CPU却只有一组寄存,所以操作系统在把线程B调度到CPU上运行时需要首先把刚刚正在运行的线程A...线程调度时操作系统需要保存和恢复的寄存除了通用寄存之外,还包括指令指针寄存rip以及与栈相关的栈顶寄存rsp和栈基址寄存rbp,rip寄存决定了线程下一条需要执行的指令,2个栈寄存确定了线程执行时需要使用的栈内存...所以恢复CPU寄存的值就相当于改变了CPU下一条需要执行的指令,同时也切换了函数调用栈,因此从调度的角度来说,线程至少包含以下3个重要内容: 一组通用寄存的值 将要执行的下一条指令的地址 栈 所以操作系统对线程的调度可以简单的理解为内核调度对不同线程所使用的寄存和栈的切换

85720
  • 您找到你想要的搜索结果了吗?
    是的
    没有找到

    go语言调度源代码情景分析之二:CPU寄存

    CPU对这16个通用寄存的用途没有做特殊规定,程序员和编译可以自定义其用途(下面会介绍,rsp/rbp寄存其实是有特殊用途的); 程序计数寄存(PC寄存,有时也叫IP寄存):rip寄存。...它用来存放下一条即将执行的指令的地址,这个寄存决定了程序的执行流程; 段寄存:fs和gs寄存。...一般用它来实现线程本地存储(TLS),比如AMD64 linux平台下go语言和pthread都使用fs寄存来实现系统线程的TLS,在本章线程本地存储一节和第二章详细分析goroutine调度的时候我们可以分别看到...32位的寄存,它使用的是rax寄存的低32位。...rsp 栈顶寄存和rbp栈基址寄存 这两个寄存都跟函数调用栈有关,其中rsp寄存一般用来存放函数调用栈的栈顶地址,而rbp寄存通常用来存放函数的栈帧起始地址,编译一般使用这两个寄存加一定偏移的方式来访问函数局部变量或函数参数

    1.1K40

    go语言调度源代码情景分析之五:汇编指令

    与高级编程语言一样,汇编语言也是一门完整的计算机编程语言,它所涉及的知识内容也很多,好在我们的主要目标是通过对本小节的学习而有能力去读懂汇编代码,而不是要用汇编语言去写代码,所以本节并不会全面介绍汇编语言...不过,虽然这里的介绍做了精简,但读者大可放心,熟练运用这些知识就足以应付本书将要分析的goroutine调度中的汇编代码了。...汇编指令格式 因为不同的CPU所支持的机器指令不一样,所以其汇编指令也不同,即使是相同的CPU,不同的汇编工具和平台所使用的汇编指令格式也有些差别,由于本书主要专注于AMD64 Linux平台下的go调度...)中的寄存的名字用括号括起来了,表示间接寻址,rsp的值是一个内存地址,这条指令的真实意图是把rax寄存中的值赋值给rsp寄存的值(内存地址)对应的内存,rsp寄存本身的值不会被修改,作为比较,...执行mov %rax, %rsp这条指令之前,rsp寄存的值是x,rax寄存的值是y,执行指令之后,rax寄存的值被复制给了rsp寄存,所以rsp寄存的值变成了y,可以看出,采用直接寻址方式时

    1.1K21

    调度及CFS调度

    如果调度支持就绪状态切换到执行状态,同时支持执行状态切换为就绪状态,就称该调度为抢占式调度。...:普通进程的调度策略,使我们task以最低优先级选择CFS调度调度运行 SCHED_DEADLINE:限期进程调度策略,使我们task选择Deadline调度调度运行 注:stop调度和DLE-task...调度,仅使用于内核,用户没有办法进行选择 CFS调度 完全公平调度算法体现在对待每个进程都是公平的,让每个进程都运行一段相同的时间片,这就是基于时间片轮询调度算法。...const struct sched_class *sched_class; // 表示该进程所属的调度类 CFS:完全公平调度。...周期性调度:根据频率自动调用scheduler_tick函数,根据进程运行时间触发调度 上下文切换:主要做两个事情(切换地址空间、切换寄存和栈空间) CFS调度

    1.1K40

    Go语言调度源代码情景分析之十:线程本地存储

    本文是《go调度源代码情景分析》系列 第一章 预备知识的第十小节,也是预备知识的最后一小节。...对于像这种由编译实现的特性,我们怎么开始研究呢?最快最直接的方法就是使用调试工具来调试程序的运行,这里我们使用gdb来调试。 bobo@ubuntu:~/study/c$ gdb ..../thread 首先在源代码的第20行(对应到源代码中的 g = 100)处下一个断点,然后运行程序,程序停在了断点处,反汇编一下main函数: (gdb) b thread.c:20 Breakpoint...fs段基址是多少,虽然我们可以用gdb命令查看fs寄存的值,但fs寄存里面存放的是段选择子(segment selector)而不是该段的起始地址,为了拿到这个基地址,我们需要加一点代码来获取它,修改后的代码如下...我们从汇编指令开始,一起讨论了寄存,内存,栈,函数调用过程,操作系统内核对线程的调度以及线程本地存储等内容,相信读者已经很好的掌握了这些基础知识,接下来就让我们一起来撩开goroutine调度的神秘面纱吧

    1.3K50

    go语言调度源代码情景分析之四:函数调用栈

    操作系统把磁盘上的可执行文件加载到内存运行之前,会做很多工作,其中很重要的一件事情就是把可执行文件中的代码,数据放在内存中合适的位置,并分配和初始化程序运行过程中所必须的堆栈,所有准备工作完成后操作系统才会调度程序起来运行...AMD64 CPU提供了2个与栈相关的寄存: rsp寄存,始终指向函数调用栈栈顶 rbp寄存,一般用来指向函数栈帧的起始位置 下面用两个图例来说明一下函数调用栈以及rsp/rbp与栈之间的关系。...; 有些编译比如gcc会把参数和返回值放在寄存中而不是栈中,go语言中函数的参数和返回值都是放在栈上的; 随着程序的运行,如果C、B两个函数都执行完成并返回到了A函数继续执行,则栈状态如下图: ?...,当它发现程序返回了某个局部变量的地址,编译会把这个变量放到堆上去,而不会放在栈上。...同样,这里我们还是需要注意rbp和rsp这两个寄存现在指向了D函数的栈帧。从上面的分析我们可以看出,寄存rbp和rsp始终指向正在执行的函数的栈帧。

    1.2K10

    【Linux 内核】CFS 调度 ④ ( 调度子系统组件模块 | 主调度、周期性调度 | 调度类 )

    文章目录 一、调度子系统组件模块 二、主调度、周期性调度 三、调度类 一、调度子系统组件模块 ---- 调度 需要对 被调度的进程 进行 排序 和 调度管理 , 进程管理过程需要 调度 的 组件模块..., 以及相关 算法 数据结构 来完成 , 如 : 执行队列 ; 二、主调度、周期性调度 ---- CPU 通过 " 上下文切换 " 选择 " 主调度 " 或 " 周期性调度 " , " 上下文切换..." 主要完成 切换地址空间 , 切换寄存 , 切换栈空间 工作 ; " 主调度 " 通过 调用 schedule() 方法 , 完成 进程的 调度 和 切换 ; " 周期性调度 " 根据 相应频率..., 自动调用 scheduler_tick() 函数 , 完成调度 , 这是根据 进程 运行时间 , 自动触发进程调度 ; 三、调度类 ---- 主调度 或 周期性调度 根据 不同的 " 选择进程..." 选择不同的 调度类 , 可选的调度类参考 【Linux 内核】调度 ⑦ ( 调度类型 | 停机调度类 stop_sched_class | 限期调度类 dl_sched_class | 实时调度

    3.2K10

    go语言调度源代码情景分析之六:go汇编语言

    go语言runtime(包括调度源代码中有部分代码是用汇编语言编写的,不过这些汇编代码并非针对特定体系结构的汇编代码,而是go语言引入的一种伪汇编,它同样也需要经过汇编转换成机器指令才能被CPU执行...除了这些跟AMD64 CPU硬件寄存一一对应的寄存外,go汇编还引入了几个没有任何硬件寄存与之对应的虚拟寄存,这些寄存一般用来存放内存地址,引入它们的主要目的是为了方便程序员和编译器用来定位内存中的代码和数据...first_arg+0(FP) 来引用调用者传递进来的第一个参数,用second_arg+8(FP)来引用第二个参数 ,以此类推,这里的first_arg和second_arg仅仅是一个帮助我们阅读源代码的符号...,对编译来说无实际意义,+0和+8表示相对于FP寄存的偏移量。...go汇编还有一些用法比较特别的地方,现在不讨论,等我们分析源代码遇到它们时再结合上下文做详细说明。

    1.4K31

    linux 进程调度(下) -- 调度演进

    O(n) 调度。...O(1) 调度 在 linux 内核采用 O(n) 调度的 4 年后,Linux2.6.0 采纳了 Rad Hat 公司设计的 O(1) 调度算法,这是一个基于上一篇文章中介绍的多级反馈队列算法的调度实现...4.1 调度分层思想 而事实证明,在公平策略调度基础上改进设计的 CFS 确实是一款优秀的调度,它的思想是将调度进行模块化,从而让操作系统中可以有多种调度以不同的策略和优先级来执行。...操作系统中,调度由此分为四层: DL 调度:采用 sched_deadline 策略; RT 调度:采用 sched_rr 和 sched_fifo 策略; CFS 调度:采用 sched_normal...O(n) 调度这类通过分配固定时间片的调度所不能实现的。

    2.2K20

    go语言调度源代码情景分析之七:函数调用过程

    解决了这些问题,我们对计算机执行程序的原理就有了一个大致的了解,这对于我们理解goroutine的调度有非常重要的作用。...为了更加清晰的理解程序的执行流程,现在我们开始模拟CPU从main函数的第一条指令开始,一直到执行完整个main函数。...main函数需要使用这个寄存来存放自己的栈基地址,而调用者在调用main函数之前也把它的栈基地址保存在了这个寄存里面,所以main函数需要把这个寄存里面的值先保存起来,等main执行完后返回时再把这个寄存恢复原样...该指令执行完成之后,从rsp所指位置到rbp所指的这一段栈内存就构成了main函数的完整栈帧,其大小为40字节(8字节用于保存调用者的rbp,另外32字节用于main函数的局部和临时变量),如下图: ?...第一条add指令负责执行加法运算并把结果3存入eax寄存,第二条指令负责把eax寄存的值保存到了s变量所在的内存,第三条指令又把s变量的值读取到eax寄存,可以看到局部变量s被编译安排在了rbp

    1.3K30

    【Linux 内核】调度 ① ( 调度概念 | 调度目的 | 调度主要工作 | 调度位置 | 进程优先级 | 抢占式调度 | Linux 进程状态 | Linux 内核进程状态 )

    文章目录 一、调度 0、调度概念 1、调度目的 2、调度主要工作 3、调度位置 4、进程优先级 5、抢占式调度 二、Linux 内核进程状态 API 简介 三、Linux 进程状态 一、调度...---- 0、调度概念 Linux 内核的 " 进程调度 " 是按照 设计好的调度算法 安排的 , 该算法对应的功能模块 称为 " 调度 " , 英文名称是 Scheduler ; 1、调度目的...进程调度 目的是 最大限度利用 CPU 资源 , 也就是 CPU 时间片 ; 2、调度主要工作 " 调度 " 主要的工作 : ① 就绪 -> 执行 : 选择 " 就绪状态 " 的进程执行 ; (..." , 主要是 " 就绪状态 " 与 " 执行状态 " 这两个状态之间相互切换 ; 3、调度位置 调度 在 如下的 进程状态图 中的位置是 " 就绪状态 " 与 " 运行状态 " 之间 ; 就绪状态..." 抢占式调度 " 概念 : 如果 " 调度 " 支持 " 就绪状态 " 与 " 运行状态 " 之间可以相互转换 , 则该调度称为 " 抢占式调度 " ; 二、Linux 内核进程状态 API

    5.6K20

    Go调度系列(2)宏观看调度

    上一篇文章《Go语言高阶:调度系列(1)起源》,学goroutine调度之前的一些背景知识,这篇文章则是为了对调度有个宏观的认识,从宏观的3个角度,去看待和理解调度是什么样子的,但仍然不涉及具体的调度原理...Scheduler的宏观组成 Tony Bai在《也谈goroutine调度》中的这幅图,展示了goroutine调度和系统调度的关系,而不是把二者割裂开来,并且从宏观的角度展示了调度的重要组成...Goroutine调度和OS调度是通过M结合起来的,每个M都代表了1个内核线程,OS调度负责把内核线程分配到CPU的核上执行。...调度的生命周期 接下来我们从另外一个宏观角度——生命周期,认识调度。 所有的Go程序运行都会经过一个完整调度生命周期:从创建到结束。 ?...总结时刻 这篇文章,从3个宏观的角度介绍了调度,也许你依然不知道调度的原理,心里感觉模模糊糊,没关系,一步一步走,通过这篇文章希望你了解了: Go调度和OS调度的关系 Go调度的生命周期/总体流程

    62950

    Go调度系列(2)宏观看调度

    上一篇文章《Go语言高阶:调度系列(1)起源》,学goroutine调度之前的一些背景知识,这篇文章则是为了对调度有个宏观的认识,从宏观的3个角度,去看待和理解调度是什么样子的,但仍然不涉及具体的调度原理...Scheduler的宏观组成 Tony Bai在《也谈goroutine调度》中的这幅图,展示了goroutine调度和系统调度的关系,而不是把二者割裂开来,并且从宏观的角度展示了调度的重要组成...Goroutine调度和OS调度是通过M结合起来的,每个M都代表了1个内核线程,OS调度负责把内核线程分配到CPU的核上执行。...调度的生命周期 接下来我们从另外一个宏观角度——生命周期,认识调度。 所有的Go程序运行都会经过一个完整调度生命周期:从创建到结束。 ?...总结时刻 这篇文章,从3个宏观的角度介绍了调度,也许你依然不知道调度的原理,心里感觉模模糊糊,没关系,一步一步走,通过这篇文章希望你了解了: Go调度和OS调度的关系 Go调度的生命周期/总体流程

    59031

    Goroutine调度

    这就涉及goroutine的G-P-M调度模型。 G-P-M调度模型 Golang能够拥有强大的并发能力需要归功于G-P-M调度模型,首先需要解释G、P、M分别代表什么: ?...P 代表Processor,逻辑处理。P维护Goroutine各种队列,mcache和状态。P的数量决定了最大可并行的Goroutine数量(前提:系统物理CPU核数>=P数量)。...调度逻辑 ? 从图中可以看出,一共有两个物理线程M,每个M都绑定一个处理P,每个P维护一个就绪状态的Goroutine队列,灰色的表示在等待P调度,蓝色的G代表正绑定P在M中执行。...当执行的Goroutine(G0)调度阻塞的系统调度时,P会切到另外的M'中,如果没有可用的M'就会创建一个,继续执行队列中的G。...总结 文章介绍了Golang自带的goroutine调度G-P-M调度模型,G-P-M调度算法最大限度的发挥了并发性能,同时在一些异常情况下也能正常快速调度

    46320

    调度增强

    SMP调度 多处理系统上,内核必须考虑几个额外的问题,以确保良好的调度。 CPU负荷必须尽可能公平地在所有的处理上共享。...特定于调度类的函数接下来建立一个迭代,使得核心调度能够遍历所有可能迁移到另一个队列的备选进程,但各个调度类的内部结构不能因为迭代而暴露给核心调度。...1.3 核心调度的改变 除了上述增加的特性之外,在SMP系统上还需要对核心调度的现存方法作一些修改。虽然到处都是一些小的细节变化,与单处理系统相比最重要的差别如下所示。...完全公平调度调度粒度与CPU的数目是成比例的。系统中处理越多,可以采用的调度粒度就越大。...调度域和控制组 在此前对调度代码的讨论中,调度并不直接与进程交互,而是处理可调度实体。这使得可以实现组调度:进程置于不同的组中,调度首先在这些组之间保证公平,然后在组中的所有进程之间保证公平。

    75510
    领券