深度剖析Linux内核性能调优与宕机解决方案

145 阅读4分钟

Linux内核技术面试出现频率比较高问题???

  1. Kdump工作原理?

  2. 在x86_64架构里函数参数是如何传递?

  3. 在X86_64构架当中,MOV指令和LEA指令有什么区别?

  4. Softlockup/Hardlockup/Hung_task机制的实现原理是什么?

原文地址:深度剖析Linux内核性能调优与宕机解决方案 - 知乎 (zhihu.com)

一、解决x86_64宕机难题

  • 在x86_64架构中解决宕机问题,大家可以搭建一个实战环境:

1.操作系统:Ubuntu 18.04

2.内核版本:Linux 4.12

3.处理器:Intel x86_64处理器

4.Kdump和Crash工具

  • Kexec可以快速启动一个新的内核,它直接跳过bootloader或BIOS等引导程序的初始化阶段。通过这个特性可以让系统崩溃时快速切换到另一个备份的内核,第一个内核的内存就得到保留。第二个内核中可以对第一个内核产生的崩溃数据信息继续分析。通过如下图所示就更好理解Kdump工作原理。

  • 我们在使用Kdump+Crash工具之前,大家必须要知道它们适用范围:

  • Linux运维工程师(服务器管理员)、Linux内核嵌入式开发工程师。Linux物理机或者Linux虚拟机。Kdump主要用来分析黑屏、没有响应、宕机等等。使用工具前提条件是系统能够热启动,内存中的内容不会丢失。

5、x86_64架构知识

  • 通用寄存器

  • 32位x86处理器支持8个32位的通用寄存器:EAX、EBX、ECX、EDX、ESI、EDI、ESP、EBP。32位的x86处理器还有6个16位段寄存器、1个32位EFLAGS寄存器及1个32位EIP寄存器。

  • 64位的x86处理器通用寄存器扩展到16个。原来以E开头字母的寄存器换为R开头的字母。原E字母开头寄存器仍然可以使用,表示低32位寄存器,以R字母开头的寄存器表示64位,还新增R8-R15通用寄存器。

  • 64位x86处理器寄存组织结构:

  1. 16个64位通用寄存器

  2. 1个RIP寄存器(指令指针)

  3. 1个64位RFLAGS寄存器

  4. 6个128位XMM寄存器

  • 补充一下:

  • x86_64:RSP(SP寄存器),RBP(栈寄存器),RAX(临时寄存器)。平时我们所写函数代码调用的时候跟栈有什么关系,主要依赖栈的结构、RSP、RBP。比如函数调用关系main()-->FuncTest1()->FucnTest1(),在栈结构当中如何实现。

6、寻址方式

  • 寻址指令(有两条常用的指令:MOV指令和LEA指令)。MOV指令:数据搬移指令。LEA指令:加载有效地址指令。
  1. 直接寻址(通过地址来实现):mov address,%rax

  2. 间接寻址(通过寄存器指定的地址加载值):MOV (%rax),%rbx

  3. 基址寻址(偏移量的值(可以为正数也可以为负数)和寄存器的值相加之后再用寻址):MOV 12(%rax),%rbx

  4. LEA指令和MOV指令区别

  • LEA指令用来加载有效地址,而MOV指令用来搬移数据。

    MOV 20(%rbp),%rax

    C伪代码如下:

    long *px=%rbp+20

    %rax=*px

    LEA 20(%rbp),%rax

    %rax-%rbp+20

7、工程项目实战宕机案例分析如下(云服务器、线上服务器、嵌入式系统)

  1. 想到利用Crash工具来分析宕机问题

  2. 通过栈来获取参数或者局部变量的值

  3. 我们要分析和推导出来那个进程持有锁

  4. 我们要分析和推导出来那个进程在等待这个锁

具体案例源码分析如下:

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#define DECS_NAME "my_decs_dev"

struct mydecs_priv

{

struct device *dev;

struct miscdevice *miscdev;

struct mutex lock;

char *name;

};

static struct mydecs_priv *g_mydev;

/* 设计虚拟FIFO设备的缓冲区存储器 */

static char *device_buffer;

#define MAX_DEVICE_BUFFER_SIZE (100*PAGE_SIZE)

#define MYDEV_CMD_GET_BUFFSIZE 1

static int demodrv_open(struct inode*inode,struct file *file)

{

struct mydecs_priv *priv=g_mydev;

int major=MAJOR(inode->i_rdev);

int minor=MINOR(inode->i_rdev);

struct task_struct *task=current;

struct mm_struct *mm=task->mm;

down_read(&mm->mmap_sem);

printk("%s : major=%d,minor=%d,name=%s\n",__func__,major,priv->name);

return 0;

}