<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>江州司马</title>
  
  <subtitle>同是天涯沦落人，相逢何必曾相识!</subtitle>
  <link href="/atom.xml" rel="self"/>
  
  <link href="https://hexo.yuanjh.cn/"/>
  <updated>2026-03-11T16:45:17.859Z</updated>
  <id>https://hexo.yuanjh.cn/</id>
  
  <author>
    <name>yuanjh</name>
    
  </author>
  
  <generator uri="https://hexo.io/">Hexo</generator>
  
  <entry>
    <title>基础知识_08hwmon子系统</title>
    <link href="https://hexo.yuanjh.cn/hexo/b849731a/"/>
    <id>https://hexo.yuanjh.cn/hexo/b849731a/</id>
    <published>2025-02-07T22:55:42.000Z</published>
    <updated>2026-03-11T16:45:17.859Z</updated>
    
    <content type="html"><![CDATA[<p>使用较为简单</p><h3 id="数据组织方式​"><a href="#数据组织方式​" class="headerlink" title="数据组织方式​"></a>数据组织方式​</h3><p>Linux的<code>hwmon</code>子系统将所有硬件传感器（温度、风扇、电压等）以​<strong>​文件形式​</strong>​暴露在<code>/sys/class/hwmon/</code>目录下，每个传感器设备对应一个<code>hwmonX</code>目录（如<code>hwmon0</code>、<code>hwmon7</code>等）。<br>每个目录中包含以下关键文件：</p><table><thead><tr><th>文件/目录名</th><th>作用</th><th>示例值/说明</th></tr></thead><tbody><tr><td>​<strong>​<code>name</code>​</strong>​</td><td>设备名称（驱动标识）</td><td><code>fan_control</code>、<code>k10temp</code></td></tr><tr><td>​<strong>​<code>label</code>​</strong>​</td><td>传感器标签（用户友好名称）</td><td><code>CPU Temp</code>、<code>Fan1</code></td></tr><tr><td>​<strong>​<code>pwm1</code>​</strong>​</td><td>风扇调速（PWM占空比）</td><td><code>93</code>（范围通常0-255或0-100）</td></tr><tr><td>​<strong>​<code>fan1_input</code>​</strong>​</td><td>风扇转速（RPM）</td><td><code>2500</code>（转/分钟）</td></tr><tr><td>​<strong>​<code>temp1_input</code>​</strong>​</td><td>温度（毫摄氏度）</td><td><code>45000</code>（表示45.0°C）</td></tr><tr><td>## 常用命令</td><td></td><td></td></tr><tr><td>name,label概览，大致包含那些数据</td><td></td><td></td></tr><tr><td><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br></pre></td><td class="code"><pre><span class="line">ls -alh  &#x2F;sys&#x2F;class&#x2F;hwmon&#x2F;hwmon*&#x2F;name</span><br><span class="line">cat &#x2F;sys&#x2F;class&#x2F;hwmon&#x2F;hwmon*&#x2F;name</span><br><span class="line"></span><br><span class="line">ls -alh  &#x2F;sys&#x2F;class&#x2F;hwmon&#x2F;hwmon*&#x2F;*label</span><br><span class="line">cat  &#x2F;sys&#x2F;class&#x2F;hwmon&#x2F;hwmon*&#x2F;*label</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">(base) john@john-HLYL-WXX9:&#x2F;sys&#x2F;class&#x2F;hwmon&#x2F;hwmon4$ ls -alh  &#x2F;sys&#x2F;class&#x2F;hwmon&#x2F;hwmon*&#x2F;name</span><br><span class="line">-r--r--r-- 1 root root 4.0K  4月 20 15:55 &#x2F;sys&#x2F;class&#x2F;hwmon&#x2F;hwmon0&#x2F;name</span><br><span class="line">-r--r--r-- 1 root root 4.0K  4月 20 15:55 &#x2F;sys&#x2F;class&#x2F;hwmon&#x2F;hwmon1&#x2F;name</span><br><span class="line">-r--r--r-- 1 root root 4.0K  4月 20 15:55 &#x2F;sys&#x2F;class&#x2F;hwmon&#x2F;hwmon2&#x2F;name</span><br><span class="line">-r--r--r-- 1 root root 4.0K  4月 20 15:55 &#x2F;sys&#x2F;class&#x2F;hwmon&#x2F;hwmon3&#x2F;name</span><br><span class="line">-r--r--r-- 1 root root 4.0K  4月 20 15:55 &#x2F;sys&#x2F;class&#x2F;hwmon&#x2F;hwmon4&#x2F;name</span><br><span class="line">-r--r--r-- 1 root root 4.0K  4月 20 15:55 &#x2F;sys&#x2F;class&#x2F;hwmon&#x2F;hwmon5&#x2F;name</span><br><span class="line">(base) john@john-HLYL-WXX9:&#x2F;sys&#x2F;class&#x2F;hwmon&#x2F;hwmon4$ cat &#x2F;sys&#x2F;class&#x2F;hwmon&#x2F;hwmon*&#x2F;name</span><br><span class="line">ACAD</span><br><span class="line">BAT1</span><br><span class="line">nvme</span><br><span class="line">k10temp</span><br><span class="line">amdgpu</span><br><span class="line">hidpp_battery_0</span><br><span class="line"></span><br><span class="line">(base) john@john-HLYL-WXX9:&#x2F;sys&#x2F;class&#x2F;hwmon&#x2F;hwmon4$ ls -alh  &#x2F;sys&#x2F;class&#x2F;hwmon&#x2F;hwmon*&#x2F;*label</span><br><span class="line">-r--r--r-- 1 root root 4.0K  4月 20 15:55 &#x2F;sys&#x2F;class&#x2F;hwmon&#x2F;hwmon2&#x2F;temp1_label</span><br><span class="line">-r--r--r-- 1 root root 4.0K  4月 20 15:55 &#x2F;sys&#x2F;class&#x2F;hwmon&#x2F;hwmon2&#x2F;temp2_label</span><br><span class="line">-r--r--r-- 1 root root 4.0K  4月 20 15:55 &#x2F;sys&#x2F;class&#x2F;hwmon&#x2F;hwmon2&#x2F;temp3_label</span><br><span class="line">-r--r--r-- 1 root root 4.0K  4月 20 15:55 &#x2F;sys&#x2F;class&#x2F;hwmon&#x2F;hwmon3&#x2F;temp1_label</span><br><span class="line">-r--r--r-- 1 root root 4.0K  4月 20 15:55 &#x2F;sys&#x2F;class&#x2F;hwmon&#x2F;hwmon4&#x2F;freq1_label</span><br><span class="line">-r--r--r-- 1 root root 4.0K  4月 20 15:55 &#x2F;sys&#x2F;class&#x2F;hwmon&#x2F;hwmon4&#x2F;in0_label</span><br><span class="line">-r--r--r-- 1 root root 4.0K  4月 20 15:55 &#x2F;sys&#x2F;class&#x2F;hwmon&#x2F;hwmon4&#x2F;in1_label</span><br><span class="line">-r--r--r-- 1 root root 4.0K  4月 20 15:55 &#x2F;sys&#x2F;class&#x2F;hwmon&#x2F;hwmon4&#x2F;power1_label</span><br><span class="line">-r--r--r-- 1 root root 4.0K  4月 20 15:55 &#x2F;sys&#x2F;class&#x2F;hwmon&#x2F;hwmon4&#x2F;temp1_label</span><br><span class="line">(base) john@john-HLYL-WXX9:&#x2F;sys&#x2F;class&#x2F;hwmon&#x2F;hwmon4$ cat  &#x2F;sys&#x2F;class&#x2F;hwmon&#x2F;hwmon*&#x2F;*label</span><br><span class="line">Composite</span><br><span class="line">Sensor 1</span><br><span class="line">Sensor 2</span><br><span class="line">Tctl</span><br><span class="line">sclk</span><br><span class="line">vddgfx</span><br><span class="line">vddnb</span><br><span class="line">PPT</span><br><span class="line">edge</span><br><span class="line">(base) john@john-HLYL-WXX9:&#x2F;sys&#x2F;class&#x2F;hwmon&#x2F;hwmon4$</span><br></pre></td></tr></table></figure></td><td></td><td></td></tr></tbody></table><p>温度数据有哪些</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br></pre></td><td class="code"><pre><span class="line">综合命令：</span><br><span class="line">ls &#x2F;sys&#x2F;class&#x2F;hwmon&#x2F;hwmon*&#x2F; | grep -i &quot;temp&quot;</span><br><span class="line">cat  &#x2F;sys&#x2F;class&#x2F;hwmon&#x2F;hwmon*&#x2F;temp*</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">(base) john@john-HLYL-WXX9:&#x2F;sys&#x2F;class&#x2F;hwmon&#x2F;hwmon4$ ls &#x2F;sys&#x2F;class&#x2F;hwmon&#x2F;hwmon*&#x2F; | grep -i &quot;temp&quot;</span><br><span class="line">temp1_alarm</span><br><span class="line">temp1_crit</span><br><span class="line">temp1_input</span><br><span class="line">temp1_label</span><br><span class="line">temp1_max</span><br><span class="line">temp1_min</span><br><span class="line">temp2_input</span><br><span class="line">temp2_label</span><br><span class="line">temp2_max</span><br><span class="line">temp2_min</span><br><span class="line">temp3_input</span><br><span class="line">temp3_label</span><br><span class="line">temp3_max</span><br><span class="line">temp3_min</span><br><span class="line">temp1_input</span><br><span class="line">temp1_label</span><br><span class="line">temp1_input</span><br><span class="line">temp1_label</span><br><span class="line">(base) john@john-HLYL-WXX9:&#x2F;sys&#x2F;class&#x2F;hwmon&#x2F;hwmon4$ cat  &#x2F;sys&#x2F;class&#x2F;hwmon&#x2F;hwmon*&#x2F;temp*</span><br><span class="line">0</span><br><span class="line">84850</span><br><span class="line">43850</span><br><span class="line">Composite</span><br><span class="line">83850</span><br><span class="line">-273150</span><br><span class="line">43850</span><br><span class="line">Sensor 1</span><br><span class="line">65261850</span><br><span class="line">-273150</span><br><span class="line">40850</span><br><span class="line">Sensor 2</span><br><span class="line">65261850</span><br><span class="line">-273150</span><br><span class="line">41000</span><br><span class="line">Tctl</span><br><span class="line">40000</span><br><span class="line">edge</span><br><span class="line">(base) john@john-HLYL-WXX9:&#x2F;sys&#x2F;class&#x2F;hwmon&#x2F;hwmon4$</span><br></pre></td></tr></table></figure><h2 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h2><p>Linux hwmon子系统分析之一 系统框架说明：<a href="https://blog.csdn.net/lickylin/article/details/106449262">https://blog.csdn.net/lickylin/article/details/106449262</a><br>Linux hwmon 子系统分析之三 新版本hwmon子系统说明；<a href="https://blog.csdn.net/lickylin/article/details/106449418">https://blog.csdn.net/lickylin/article/details/106449418</a></p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;使用较为简单&lt;/p&gt;
    
    </summary>
    
    
      <category term="08领域技术" scheme="https://hexo.yuanjh.cn/categories/08%E9%A2%86%E5%9F%9F%E6%8A%80%E6%9C%AF/"/>
    
      <category term="g芯片相关" scheme="https://hexo.yuanjh.cn/categories/08%E9%A2%86%E5%9F%9F%E6%8A%80%E6%9C%AF/g%E8%8A%AF%E7%89%87%E7%9B%B8%E5%85%B3/"/>
    
    
      <category term="08领域技术/g芯片相关/基础知识" scheme="https://hexo.yuanjh.cn/tags/08%E9%A2%86%E5%9F%9F%E6%8A%80%E6%9C%AF-g%E8%8A%AF%E7%89%87%E7%9B%B8%E5%85%B3-%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/"/>
    
  </entry>
  
  <entry>
    <title>交付琐碎_03硬件交付文档</title>
    <link href="https://hexo.yuanjh.cn/hexo/5bfd9bea/"/>
    <id>https://hexo.yuanjh.cn/hexo/5bfd9bea/</id>
    <published>2025-01-20T14:31:45.000Z</published>
    <updated>2026-03-11T16:45:17.859Z</updated>
    
    <content type="html"><![CDATA[<h2 id="som核心板-SCH图和pcb有什么区别，侧重哪些不同"><a href="#som核心板-SCH图和pcb有什么区别，侧重哪些不同" class="headerlink" title="som核心板 SCH图和pcb有什么区别，侧重哪些不同"></a>som核心板 SCH图和pcb有什么区别，侧重哪些不同</h2><p>在电子工程中，<strong>SCH图</strong>（原理图）和<strong>PCB</strong>（印刷电路板布局）是设计过程中两个重要的部分，它们各自承担不同的功能和作用。以下是它们之间的主要区别和侧重点：</p><h3 id="1-定义与功能"><a href="#1-定义与功能" class="headerlink" title="1. 定义与功能"></a>1. <strong>定义与功能</strong></h3><ul><li><p><strong>SCH图（原理图）</strong>：</p><ul><li><strong>定义</strong>：原理图是电子电路的图形表示，显示了电路中各个组件的连接关系。</li><li><strong>功能</strong>：用于描述电路的逻辑和功能，包含电路元件（如电阻、电容、IC等）及其引脚连接，同时显示信号流向和电气特性。</li><li><strong>侧重</strong>：重点在于电路的功能和信号的流动，不涉及物理尺寸和位置。</li></ul></li><li><p><strong>PCB（印刷电路板布局）</strong>：</p><ul><li><strong>定义</strong>：PCB 是将电路设计转化为实际电路板的布局，包含元件的物理位置、连接线和电源层等信息。</li><li><strong>功能</strong>：用于制造实际的电路板，最终实现电路的物理实现，确保电气连接和机械稳定性。</li><li><strong>侧重</strong>：重点在于物理布局、信号完整性、散热、制造可行性等。</li></ul></li></ul><h3 id="2-内容与细节"><a href="#2-内容与细节" class="headerlink" title="2. 内容与细节"></a>2. <strong>内容与细节</strong></h3><ul><li><p><strong>SCH图</strong>：</p><ul><li>包含电路元件符号（如电阻、电容、IC的符号）。</li><li>显示逻辑连接关系（如电源、地线、信号线）。</li><li>不涉及物理尺寸、元件位置、布线宽度等细节。</li><li>通常会包含一些注释、参数和电气特性说明。</li></ul></li><li><p><strong>PCB</strong>：</p><ul><li>包含元件的真实形状、尺寸和引脚布局（如元件封装）。</li><li>显示电路板的层次结构（如电源层、信号层、接地层）。</li><li>包含布线信息（如走线宽度、走线间距）和焊盘信息。</li><li>可能包括标识、丝印层、测试点等额外信息。</li></ul></li></ul><h3 id="3-设计流程中的位置"><a href="#3-设计流程中的位置" class="headerlink" title="3. 设计流程中的位置"></a>3. <strong>设计流程中的位置</strong></h3><ul><li><strong>设计流程</strong>：<ul><li>通常，设计流程是先绘制原理图（SCH图），然后基于原理图生成PCB布局。</li><li>原理图完成后，通过电子设计自动化（EDA）工具进行元件布局和布线，最终生成PCB设计。</li></ul></li></ul><h3 id="4-工具与软件"><a href="#4-工具与软件" class="headerlink" title="4. 工具与软件"></a>4. <strong>工具与软件</strong></h3><ul><li><strong>SCH图设计</strong>：常用软件包括 Altium Designer、Eagle、OrCAD、KiCAD 等。</li><li><strong>PCB设计</strong>：同样的软件也可以用于PCB设计，但在布局和布线的细节上会有所不同。</li></ul><h3 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h3><ul><li><strong>SCH图</strong> 侧重于电路的功能和逻辑连接，是设计电子电路的基础。</li><li><strong>PCB</strong> 侧重于实际的物理布局和制造，是将原理图转化为可实际使用的电路板的步骤。</li></ul><p>这两者是互补的，原理图为PCB设计提供必要的逻辑基础，而PCB设计则将这些逻辑转化为实际的硬件实施。</p><h2 id="som核心板的接口类型和定义-长什么样，一般包含哪些必须信息"><a href="#som核心板的接口类型和定义-长什么样，一般包含哪些必须信息" class="headerlink" title="som核心板的接口类型和定义(长什么样，一般包含哪些必须信息)"></a>som核心板的接口类型和定义(长什么样，一般包含哪些必须信息)</h2><p>在设计和使用系统级封装（SoM，System on Module）核心板时，接口类型和定义文档是非常重要的，它帮助工程师理解各个接口的功能、连接方式及其用法。以下是SoM核心板接口类型和定义的常见内容，以及文档通常包含的信息。</p><h3 id="1-接口类型"><a href="#1-接口类型" class="headerlink" title="1. 接口类型"></a>1. 接口类型</h3><p>SoM核心板通常会包含多种接口，以下是一些常见的接口类型：</p><ul><li><p><strong>电源接口</strong>：</p><ul><li>定义电源输入的电压和极性。</li><li>可能包括电源管理功能，如电源开关、稳压器等。</li></ul></li><li><p><strong>数据接口</strong>：</p><ul><li><strong>串行接口（UART、SPI、I2C）</strong>：<ul><li>用于串行通讯的接口，定义数据传输速率、协议和引脚配置。</li></ul></li><li><strong>USB接口</strong>：<ul><li>USB Host或Device接口，定义USB版本（如USB 2.0、USB 3.0），以及电源和数据引脚的配置。</li></ul></li><li><strong>网络接口（Ethernet、Wi-Fi）</strong>：<ul><li>定义网络连接的接口，包括以太网接口、Wi-Fi模块等。</li></ul></li></ul></li><li><p><strong>视频接口</strong>：</p><ul><li><strong>HDMI、DisplayPort、LVDS</strong>等视频输出接口，定义视频信号及其质量要求。</li></ul></li><li><p><strong>音频接口</strong>：</p><ul><li>定义音频输入/输出接口，如音频插孔、I2S接口等。</li></ul></li><li><p><strong>GPIO接口</strong>：</p><ul><li>通用输入输出接口，定义每个引脚的功能，如输入、输出、PWM等。</li></ul></li><li><p><strong>存储接口</strong>：</p><ul><li><strong>SD卡、eMMC、NAND</strong>等存储接口，定义存储介质的连接方式和协议。</li></ul></li></ul><h3 id="2-文档内容"><a href="#2-文档内容" class="headerlink" title="2. 文档内容"></a>2. 文档内容</h3><p>SoM核心板的接口定义文档通常包括以下内容：</p><ul><li><p><strong>封面</strong>：</p><ul><li>文档标题、版本号、日期和作者信息。</li></ul></li><li><p><strong>目录</strong>：</p><ul><li>列出文档中各部分的目录和页码。</li></ul></li><li><p><strong>引言</strong>：</p><ul><li>简要介绍SoM核心板的功能和用途。</li></ul></li><li><p><strong>接口概述</strong>：</p><ul><li>总体描述所有接口的类型与功能。</li></ul></li><li><p><strong>接口详细定义</strong>：</p><ul><li><strong>电源接口</strong>：<ul><li>接口引脚定义、输入电压范围、最大电流、连接方式等。</li></ul></li><li><strong>数据接口</strong>：<ul><li>每种数据接口的引脚定义、信号描述、协议细节和时序要求。</li></ul></li><li><strong>视频和音频接口</strong>：<ul><li>接口类型、引脚功能、信号标准等。</li></ul></li><li><strong>GPIO接口</strong>：<ul><li>每个GPIO引脚的功能、配置及电气特性。</li></ul></li><li><strong>存储接口</strong>：<ul><li>存储设备类型、连接引脚及协议。</li></ul></li></ul></li><li><p><strong>引脚分配图</strong>：</p><ul><li>图示化的引脚定义，通常包括所有接口，引脚编号，功能标记等。</li></ul></li><li><p><strong>机械与电气特性</strong>：</p><ul><li>物理尺寸、连接器类型、引脚间距等信息。</li></ul></li><li><p><strong>测试点和调试信息</strong>：</p><ul><li>提供调试和测试所需的特殊引脚定义和说明。</li></ul></li><li><p><strong>使用注意事项</strong>：</p><ul><li>对接口使用的一些建议和注意事项，例如最大负载、接地要求等。</li></ul></li><li><p><strong>附录</strong>：</p><ul><li>相关参考文献、标准、术语表等。</li></ul></li></ul><h3 id="文档示例"><a href="#文档示例" class="headerlink" title="文档示例"></a>文档示例</h3><p>一个SoM核心板的接口定义文档可能会按照以下结构组织：</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line">SoM核心板接口定义文档</span><br><span class="line"></span><br><span class="line">版本：1.0</span><br><span class="line">日期：2024年11月</span><br><span class="line">作者：XXX</span><br><span class="line"></span><br><span class="line">目录</span><br><span class="line">1. 引言</span><br><span class="line">2. 接口概述</span><br><span class="line">3. 接口详细定义</span><br><span class="line">   3.1 电源接口</span><br><span class="line">   3.2 数据接口</span><br><span class="line">       3.2.1 UART</span><br><span class="line">       3.2.2 SPI</span><br><span class="line">       3.2.3 I2C</span><br><span class="line">   3.3 视频接口</span><br><span class="line">   3.4 音频接口</span><br><span class="line">   3.5 GPIO接口</span><br><span class="line">   3.6 存储接口</span><br><span class="line">4. 引脚分配图</span><br><span class="line">5. 机械与电气特性</span><br><span class="line">6. 测试点和调试信息</span><br><span class="line">7. 使用注意事项</span><br><span class="line">8. 附录</span><br></pre></td></tr></table></figure><p>SoM核心板的接口定义文档是了解和使用该模块的重要资料，包含了电源、数据、视频、音频、GPIO和存储接口的详细定义，并提供了图示和电气特性信息。这些信息能够帮助开发人员正确连接和使用SoM核心板，确保系统的正常运行。</p>]]></content>
    
    <summary type="html">
    
      &lt;h2 id=&quot;som核心板-SCH图和pcb有什么区别，侧重哪些不同&quot;&gt;&lt;a href=&quot;#som核心板-SCH图和pcb有什么区别，侧重哪些不同&quot; class=&quot;headerlink&quot; title=&quot;som核心板 SCH图和pcb有什么区别，侧重哪些不同&quot;&gt;&lt;/a&gt;som核心板 SCH图和pcb有什么区别，侧重哪些不同&lt;/h2&gt;
    
    </summary>
    
    
      <category term="08领域技术" scheme="https://hexo.yuanjh.cn/categories/08%E9%A2%86%E5%9F%9F%E6%8A%80%E6%9C%AF/"/>
    
      <category term="g芯片相关" scheme="https://hexo.yuanjh.cn/categories/08%E9%A2%86%E5%9F%9F%E6%8A%80%E6%9C%AF/g%E8%8A%AF%E7%89%87%E7%9B%B8%E5%85%B3/"/>
    
    
      <category term="08领域技术/g芯片相关/交付琐碎" scheme="https://hexo.yuanjh.cn/tags/08%E9%A2%86%E5%9F%9F%E6%8A%80%E6%9C%AF-g%E8%8A%AF%E7%89%87%E7%9B%B8%E5%85%B3-%E4%BA%A4%E4%BB%98%E7%90%90%E7%A2%8E/"/>
    
  </entry>
  
  <entry>
    <title>交付琐碎_02海思Hi3559A</title>
    <link href="https://hexo.yuanjh.cn/hexo/e2585a0f/"/>
    <id>https://hexo.yuanjh.cn/hexo/e2585a0f/</id>
    <published>2025-01-04T21:45:49.000Z</published>
    <updated>2026-03-11T16:45:17.859Z</updated>
    
    <content type="html"><![CDATA[<p>文档名称：Hi3559A╱C V100 ultra-HD Mobile Camera SoC 用户指南(pm).pdf<br>下载路径：<a href="https://gitcode.com/Open-source-documentation-tutorial/5921c/blob/main/Hi3559A%E2%95%B1C%20V100%20ultra-HD%20Mobile%20Camera%20SoC%20%E7%94%A8%E6%88%B7%E6%8C%87%E5%8D%97(pm).pdf">GitCode - 全球开发者的开源社区,开源代码托管平台</a></p><h2 id="芯片功能模块-外设接口-解释"><a href="#芯片功能模块-外设接口-解释" class="headerlink" title="芯片功能模块(外设接口)解释"></a>芯片功能模块(外设接口)解释</h2><p><img src="/images/20250220201253.png" alt=""></p><p>用于与外部设备或其他芯片进行通信或实现特定功能。具体来说：</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">SPI（Serial Peripheral Interface）：用于与外围设备进行高速通信。  </span><br><span class="line">Nand：NAND Flash接口，用于连接NAND闪存。  </span><br><span class="line">I2C（Inter-Integrated Circuit）：用于连接低速外设。  </span><br><span class="line">LCD：液晶显示屏接口，用于驱动显示屏。  </span><br><span class="line">HDMI：高清多媒体接口，用于传输音视频信号。 </span><br><span class="line">SDIO 3.0：用于连接SD卡或其他SDIO设备。(sd卡)   </span><br><span class="line">UART（Universal Asynchronous Receiver&#x2F;Transmitter）：用于串行通信。  </span><br><span class="line">PCIe x2（Peripheral Component Interconnect Express）：高速接口，用于连接外部设备。  </span><br><span class="line">USB 2.0：通用串行总线接口，用于连接USB设备。  </span><br><span class="line">ISP（Image Signal Processor）：图像信号处理器，用于处理图像数据（一般返回原始yuv，rgb等数据，非编码数据）。  </span><br><span class="line">Audio Codec：音频编解码器，用于处理音频信号。  </span><br><span class="line"></span><br><span class="line">IR（Infrared）通常指**红外接口**，用于红外通信；  </span><br><span class="line">PMW（Pulse Width Modulation）是**脉宽调制**，常用于控制电机或调节LED亮度等。它们与上述外设接口一起，构成了芯片的多样化功能模块。</span><br></pre></td></tr></table></figure><p>这些模块共同构成了SoC的外设接口或功能单元，使芯片能够与外部设备交互并实现多种功能。</p><h3 id="uart-jtag区别"><a href="#uart-jtag区别" class="headerlink" title="uart,jtag区别"></a>uart,jtag区别</h3><table><thead><tr><th>特性</th><th>UART</th><th>JTAG</th></tr></thead><tbody><tr><td><strong>用途</strong></td><td>串行通信</td><td>芯片调试、测试和编程</td></tr><tr><td><strong>通信类型</strong></td><td>异步</td><td>同步</td></tr><tr><td><strong>信号线</strong></td><td>TX、RX（2 根）</td><td>TDI、TDO、TCK、TMS、TRST（4-5 根）</td></tr><tr><td><strong>复杂度</strong></td><td>简单</td><td>复杂</td></tr><tr><td><strong>应用场景</strong></td><td>设备间通信、调试输出</td><td>芯片调试、固件烧录、边界扫描测试</td></tr><tr><td><strong>带宽</strong></td><td>低（几百 bps 到几 Mbps）</td><td>高（取决于时钟频率）</td></tr></tbody></table><p><strong>UART</strong> 是一种简单的串行通信接口，适合设备间的数据传输。<br><strong>JTAG</strong> 是一种复杂的调试和测试接口，主要用于芯片开发和硬件调试。<br>两者在功能、复杂度和应用场景上有显著区别，通常不会互相替代。</p><h3 id="芯片逻辑框图"><a href="#芯片逻辑框图" class="headerlink" title="芯片逻辑框图"></a>芯片逻辑框图</h3><p><img src="/images/20250220205304.png" alt=""><br>LSADCs（Low-Speed Analog-to-Digital Converters，低速模数转换器）：<br>功能：将模拟信号转换为数字信号。<br>应用场景：适用于对采样速度要求不高的场景，如温度、压力等慢变信号的采集。</p><p>SSPs（Synchronous Serial Ports，同步串行端口）：<br>功能：实现同步串行通信，支持 SPI、I2C 等协议。<br>应用场景：用于与外部设备进行数据传输，如传感器、存储器等。</p><p>GMAC（Gigabit Media Access Control，千兆媒体访问控制）：<br>功能：控制以太网数据传输，确保数据在网络中的可靠传输。<br>应用场景：用于支持千兆以太网通信的芯片中，如网络处理器、SoC 等。</p><p>GPU@MP2：<br>GPU（Graphics Processing Unit）：图形处理单元，用于处理图形和图像相关的计算任务。<br>MP2（Multi-Processor 2）：可能指双核或多核处理器架构。<br>整体表示一个双核或多核的图形处理单元。</p><p>DSP/NNIE/IVE：<br>DSP（Digital Signal Processor）：数字信号处理器，用于处理音频、视频等信号。<br>NNIE（Neural Network Inference Engine）：神经网络推理引擎，用于加速深度学习模型的推理任务。<br>IVE（Intelligent Video Engine）：智能视频引擎，用于视频分析和处理（如运动检测、目标跟踪等）。</p><p>VPSS+VGS+GDC+AVSP：<br>VPSS（Video Processing Sub-System）：视频处理子系统，负责视频的输入、输出和预处理。<br>VGS（Video Graphics System）：视频图形系统，用于图形叠加和显示。<br>GDC（Geometric Distortion Correction）：几何失真校正，用于校正镜头畸变。<br>AVSP（Advanced Video Signal Processing）：高级视频信号处理，可能包括降噪、增强等功能。</p><p>ISP(3a/WDR)：<br>ISP（Image Signal Processor）：图像信号处理器，用于处理从摄像头传感器捕获的原始图像数据。<br>3A（Auto Exposure/Auto Focus/Auto White Balance）：自动曝光、自动对焦、自动白平衡。<br>WDR（Wide Dynamic Range）：宽动态范围，用于处理高对比度场景。</p><p>HDMI/MIPI/LCD：<br>HDMI（High-Definition Multimedia Interface）：高清多媒体接口，用于传输高清视频和音频信号。<br>MIPI（Mobile Industry Processor Interface）：移动行业处理器接口，用于连接摄像头、显示屏等。<br>LCD（Liquid Crystal Display）：液晶显示屏。</p><p>MIPI/LVDS/hIsPI：<br>LVDS（Low-Voltage Differential Signaling）：低压差分信号，用于高速数据传输。<br>hIsPI（High-Speed Serial Pixel Interface）：高速串行像素接口，用于传输图像数据。</p><p>slvs-EC：<br>SLVS-EC（Scalable Low-Voltage Signaling with Embedded Clock）：一种低功耗、高速的串行接口，用于传输图像和视频数据，通常用于摄像头模块。</p><h3 id="接口和协议"><a href="#接口和协议" class="headerlink" title="接口和协议"></a>接口和协议</h3><table><thead><tr><th><strong>特性</strong></th><th><strong>接口（Interface）</strong></th><th><strong>协议（Protocol）</strong></th></tr></thead><tbody><tr><td><strong>定义</strong></td><td>物理或逻辑连接点</td><td>通信规则和标准</td></tr><tr><td><strong>层级</strong></td><td>物理层</td><td>数据链路层及以上</td></tr><tr><td><strong>实现</strong></td><td>硬件实现（引脚、连接器等）</td><td>规则实现（硬件或软件）</td></tr><tr><td><strong>功能</strong></td><td>提供物理连接和信号传输</td><td>确保数据的正确传输和解释</td></tr><tr><td><strong>示例</strong></td><td>USB接口、HDMI接口</td><td>USB协议、I2C协议</td></tr></tbody></table><p><strong>I2C通信</strong>：I2C接口定义了SDA（数据线）和SCL（时钟线）的物理连接，而I2C协议定义了主从设备之间的数据传输规则。<br><strong>以太网</strong>：以太网接口（如RJ45）提供了物理连接，而以太网协议定义了数据包的格式和传输规则。<br>接口和协议在硬件通信中密不可分，接口是协议的物理基础，而协议是接口功能的逻辑实现。理解它们的区别和联系对于设计和分析硬件系统非常重要。</p><h3 id="1-4启动和升级方式"><a href="#1-4启动和升级方式" class="headerlink" title="1.4启动和升级方式"></a>1.4启动和升级方式</h3><p><img src="/images/20250220205610.png" alt=""></p><h3 id="1-5-地址空间映射"><a href="#1-5-地址空间映射" class="headerlink" title="1.5 地址空间映射"></a>1.5 地址空间映射</h3><p><img src="/images/20250220205648.png" alt=""></p><p>这个是干嘛用的？（为何需要些这个，做什么的时候用户需要了解，查阅这部分信息）</p><p>在SOC（System on Chip，片上系统）用户手册中，这样的地址表单主要是用来描述SOC芯片中各个功能模块的寄存器地址范围及其用途。以下是它的作用和用户需要了解的原因：</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">1. **寄存器地址映射**</span><br><span class="line">- SOC芯片中有许多功能模块（如VGS1、VEDU0、JPGE等），每个模块都有其对应的寄存器，用于控制和配置模块的行为。</span><br><span class="line">- 地址表单清晰地划分了每个模块的寄存器在内存地址空间中的范围。例如：</span><br><span class="line">    - &#96;0x0_1130_0000&#96; 到 &#96;0x0_1130_FFFF&#96; 是 VEDU0 寄存器的地址范围。</span><br><span class="line">    - &#96;0x0_1132_0000&#96; 到 &#96;0x0_1132_FFFF&#96; 是 JPGE 寄存器的地址范围。</span><br><span class="line">- 这种映射使得开发者能够准确地访问和控制这些寄存器。</span><br><span class="line"></span><br><span class="line">2. **保留区域**</span><br><span class="line">- 地址表单中标注为“保留”的区域表示这些地址范围目前未分配给任何功能模块，可能是为未来扩展或特定用途预留的。</span><br><span class="line">- 用户需要避免访问这些区域，以防止意外行为或错误。</span><br><span class="line"></span><br><span class="line">3. **寄存器大小**</span><br><span class="line">- 地址表单中通常还会标注每个模块的寄存器大小（如64KB、128KB）。这有助于开发者了解每个模块的寄存器空间大小，从而合理分配资源。</span><br><span class="line">- </span><br><span class="line">4. **硬件编程和调试**</span><br><span class="line">- 在开发嵌入式系统或驱动程序时，开发者需要直接与硬件寄存器交互，以配置和控制SOC的功能模块。</span><br><span class="line">- 例如，如果开发者需要配置JPGE模块（JPEG编解码器），他们需要查阅地址表单，找到JPGE寄存器的地址范围，然后根据手册中的寄存器描述进行编程。</span><br></pre></td></tr></table></figure><p>比如，0x0_1132_0000 0x0_1132_FFFF JPGE 寄存器。 64KB 为例<br>是否意味着最大处理jpeg图片为64kb？而且寄存器控制硬件行为时，需要精准的知道地址，而非这么庞大的地址范围。怎么理解呢？</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line">从以下几个方面来理解：</span><br><span class="line">1. **最大处理 JPEG 图片的大小**</span><br><span class="line">- 这个地址范围的大小（64KB）并不直接决定 JPEG 图片的最大处理大小。JPEG 图片的处理能力通常由硬件解码器的设计、内存带宽、处理器的性能等因素决定。</span><br><span class="line">- 如果这个地址范围是用于存储 JPEG 解码器的寄存器或数据缓冲区，那么 64KB 可能只是用来存放解码过程中的中间数据，而不是整个 JPEG 图片。</span><br><span class="line">- 实际的 JPEG 图片可能远远大于 64KB，解码器通常会分块处理图片数据，而不是一次性加载整个图片。</span><br><span class="line"></span><br><span class="line">2. **寄存器控制硬件行为**</span><br><span class="line">- 寄存器是硬件设备中用于控制和配置的小块内存区域。每个寄存器通常只有几字节大小，但它们的作用非常重要。</span><br><span class="line">- 你提到的地址范围（如 &#96;0x0_1132_0000&#96; 到 &#96;0x0_1132_FFFF&#96;）可能是一个寄存器组（Register Bank）的地址范围，而不是单个寄存器。寄存器组中可能包含多个寄存器，每个寄存器有特定的地址偏移。</span><br><span class="line">- 硬件驱动程序或固件在操作寄存器时，需要精确地知道每个寄存器的地址偏移。例如，如果寄存器组的基地址是 &#96;0x0_1132_0000&#96;，那么某个特定的寄存器可能是基地址加上一个偏移量，比如 &#96;0x0_1132_0004&#96;。</span><br><span class="line"></span><br><span class="line">3. **地址范围的庞大性**</span><br><span class="line">- 地址范围看起来很大，但实际上它只是硬件地址空间的一部分。硬件地址空间通常被划分为不同的区域，每个区域对应不同的硬件功能（如内存、寄存器、外设等）。</span><br><span class="line">- 在设计硬件时，地址范围的大小是为了预留足够的空间，以便未来扩展或支持更多的功能。实际使用的寄存器可能只占用了地址范围的一小部分。</span><br><span class="line"></span><br><span class="line">总结</span><br><span class="line">- 64KB 的地址范围并不直接限制 JPEG 图片的处理大小，它可能只是用于存放解码过程中的数据或寄存器组。</span><br><span class="line">- 寄存器控制硬件时需要精确的地址，但这些地址通常是基地址加上一个小的偏移量，而不是整个庞大的地址范围。</span><br><span class="line">- 地址范围的设计是为了预留空间和支持灵活性，实际使用的寄存器可能只占其中的一小部分。</span><br></pre></td></tr></table></figure><h2 id="2硬件特性"><a href="#2硬件特性" class="headerlink" title="2硬件特性"></a>2硬件特性</h2><h3 id="2-1封装-各角度视图-和管脚分布"><a href="#2-1封装-各角度视图-和管脚分布" class="headerlink" title="2.1封装(各角度视图)和管脚分布"></a>2.1封装(各角度视图)和管脚分布</h3><p><img src="/images/20250220210931.png" alt=""></p><h3 id="2-2焊接工艺，潮敏"><a href="#2-2焊接工艺，潮敏" class="headerlink" title="2.2焊接工艺，潮敏"></a>2.2焊接工艺，潮敏</h3><h3 id="2-5电气性能-典型场景和功耗信息"><a href="#2-5电气性能-典型场景和功耗信息" class="headerlink" title="2.5电气性能,典型场景和功耗信息,"></a>2.5电气性能,典型场景和功耗信息,</h3><p><img src="/images/20250220211046.png" alt=""></p><h3 id="2-6接口时序"><a href="#2-6接口时序" class="headerlink" title="2.6接口时序"></a>2.6接口时序</h3><p><img src="/images/20250220211306.png" alt=""></p><h2 id="3系统"><a href="#3系统" class="headerlink" title="3系统"></a>3系统</h2><h3 id="3-1复位"><a href="#3-1复位" class="headerlink" title="3.1复位"></a>3.1复位</h3><p><img src="/images/20250220211446.png" alt=""></p><h3 id="3-2时钟"><a href="#3-2时钟" class="headerlink" title="3.2时钟"></a>3.2时钟</h3><h3 id="3-3处理器子系统"><a href="#3-3处理器子系统" class="headerlink" title="3.3处理器子系统"></a>3.3处理器子系统</h3><h3 id="3-4中断系统"><a href="#3-4中断系统" class="headerlink" title="3.4中断系统"></a>3.4中断系统</h3><h3 id="3-5-系统控制器"><a href="#3-5-系统控制器" class="headerlink" title="3.5 系统控制器"></a>3.5 系统控制器</h3><h2 id="4存储器接口"><a href="#4存储器接口" class="headerlink" title="4存储器接口"></a>4存储器接口</h2><h2 id="todo找个简单模块看下主要讲的啥"><a href="#todo找个简单模块看下主要讲的啥" class="headerlink" title="todo找个简单模块看下主要讲的啥"></a>todo找个简单模块看下主要讲的啥</h2>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;文档名称：Hi3559A╱C V100 ultra-HD Mobile Camera SoC 用户指南(pm).pdf&lt;br&gt;下载路径：&lt;a href=&quot;https://gitcode.com/Open-source-documentation-tutorial/5921c/blob/main/Hi3559A%E2%95%B1C%20V100%20ultra-HD%20Mobile%20Camera%20SoC%20%E7%94%A8%E6%88%B7%E6%8C%87%E5%8D%97(pm).pdf&quot;&gt;GitCode - 全球开发者的开源社区,开源代码托管平台&lt;/a&gt;&lt;/p&gt;
    
    </summary>
    
    
      <category term="08领域技术" scheme="https://hexo.yuanjh.cn/categories/08%E9%A2%86%E5%9F%9F%E6%8A%80%E6%9C%AF/"/>
    
      <category term="g芯片相关" scheme="https://hexo.yuanjh.cn/categories/08%E9%A2%86%E5%9F%9F%E6%8A%80%E6%9C%AF/g%E8%8A%AF%E7%89%87%E7%9B%B8%E5%85%B3/"/>
    
    
      <category term="08领域技术/g芯片相关/交付琐碎" scheme="https://hexo.yuanjh.cn/tags/08%E9%A2%86%E5%9F%9F%E6%8A%80%E6%9C%AF-g%E8%8A%AF%E7%89%87%E7%9B%B8%E5%85%B3-%E4%BA%A4%E4%BB%98%E7%90%90%E7%A2%8E/"/>
    
  </entry>
  
  <entry>
    <title>交付琐碎_01制造和工艺</title>
    <link href="https://hexo.yuanjh.cn/hexo/8583d495/"/>
    <id>https://hexo.yuanjh.cn/hexo/8583d495/</id>
    <published>2024-12-28T21:45:24.000Z</published>
    <updated>2026-03-11T16:45:17.859Z</updated>
    
    <content type="html"><![CDATA[<p>目录页<br>Hi3559A V100R001C02SPC031原厂SDK包:<a href="https://www.ebaina.com/down/240000038810">https://www.ebaina.com/down/240000038810</a><br>海思HI3559A SDK文档说明:<a href="https://blog.csdn.net/tirvideo/article/details/86293786">https://blog.csdn.net/tirvideo/article/details/86293786</a></p><p>百度文库：<br><a href="https://wenku.baidu.com/view/0ffea690ba0d4a7302763a7c.html?_wkts_=1740049575128&amp;bdQuery=Hi3559AV100R001+%E4%BA%A4%E4%BB%98%E4%BB%B6%E6%B8%85%E5%8D%95.xlsx">https://wenku.baidu.com/view/0ffea690ba0d4a7302763a7c.html?_wkts_=1740049575128&amp;bdQuery=Hi3559AV100R001+%E4%BA%A4%E4%BB%98%E4%BB%B6%E6%B8%85%E5%8D%95.xlsx</a></p><p>Hi3559AV100ES 芯片硬件资料分享：助力高效硬件设计：<a href="https://blog.csdn.net/gitblog_09782/article/details/143297828">https://blog.csdn.net/gitblog_09782/article/details/143297828</a></p><p>老工程师经验分享：一套完整的硬件电路设计该怎么做？：<a href="https://zhuanlan.zhihu.com/p/270941578">Site Unreachable</a></p><h2 id="EVT-DVT-PVT"><a href="#EVT-DVT-PVT" class="headerlink" title="EVT,DVT,PVT"></a>EVT,DVT,PVT</h2><p>EVT、DVT和PVT是产品开发流程中的关键验证阶段，分别对应工程验证、设计验证和生产验证。以下是它们的详细解析：</p><h3 id="​1-EVT（Engineering-Verification-Test，工程验证测试）​"><a href="#​1-EVT（Engineering-Verification-Test，工程验证测试）​" class="headerlink" title="​1. EVT（Engineering Verification Test，工程验证测试）​"></a>​<strong>1. EVT（Engineering Verification Test，工程验证测试）​</strong></h3><ul><li>​<strong>目标</strong>：验证产品的核心功能与工程设计的可行性。</li><li>​<strong>阶段特点</strong>：<ul><li>​<strong>早期原型</strong>：制作少量工程样机（可能手工组装），测试基本功能。</li><li>​<strong>问题排查</strong>：发现并修复重大设计缺陷（如电路设计、结构问题）。</li><li>​<strong>快速迭代</strong>：设计频繁调整，可能进行多轮测试。</li></ul></li><li>​<strong>测试内容</strong>：<ul><li>功能性测试（如硬件通电、软件基础功能）。</li><li>初步环境测试（温湿度、振动等）。</li><li>兼容性与安全性初步评估。</li></ul></li></ul><h3 id="​2-DVT（Design-Verification-Test，设计验证测试）​"><a href="#​2-DVT（Design-Verification-Test，设计验证测试）​" class="headerlink" title="​2. DVT（Design Verification Test，设计验证测试）​"></a>​<strong>2. DVT（Design Verification Test，设计验证测试）​</strong></h3><ul><li>​<strong>目标</strong>：全面验证产品设计是否符合规格与用户需求。</li><li>​<strong>阶段特点</strong>：<ul><li>​<strong>接近量产的设计</strong>：样机采用量产材料与工艺，外观和结构定型。</li><li>​<strong>严格验证</strong>：通过大量测试确保设计可靠性。</li><li>​<strong>认证准备</strong>：启动法规认证（如CE、FCC）。</li></ul></li><li>​<strong>测试内容</strong>：<ul><li>性能参数全面测试（如电池续航、信号强度）。</li><li>环境与寿命测试（高低温循环、跌落测试）。</li><li>用户场景模拟（实际使用条件下的稳定性）。</li></ul></li></ul><h3 id="​3-PVT（Production-Verification-Test，生产验证测试）​"><a href="#​3-PVT（Production-Verification-Test，生产验证测试）​" class="headerlink" title="​3. PVT（Production Verification Test，生产验证测试）​"></a>​<strong>3. PVT（Production Verification Test，生产验证测试）​</strong></h3><ul><li>​<strong>目标</strong>：验证生产工艺的稳定性和量产可行性。</li><li>​<strong>阶段特点</strong>：<ul><li>​<strong>试量产</strong>：小批量生产（数百至千台），使用正式生产线。</li><li>​<strong>流程优化</strong>：解决装配效率、良率问题，优化质量控制。</li><li>​<strong>供应链验证</strong>：确保零部件供应稳定，供应商协作顺畅。</li></ul></li><li>​<strong>测试内容</strong>：<ul><li>生产线压力测试（如产能、故障率统计）。</li><li>产品一致性检查（尺寸、功能批次差异）。</li><li>包装与物流测试（运输损耗评估）。</li></ul></li></ul><hr><h3 id="​阶段对比与关联"><a href="#​阶段对比与关联" class="headerlink" title="​阶段对比与关联"></a>​<strong>阶段对比与关联</strong></h3><table><thead><tr><th>​<strong>阶段</strong></th><th>​<strong>重点</strong></th><th>​<strong>输出</strong></th><th>​<strong>风险控制</strong></th></tr></thead><tbody><tr><td>​<strong>EVT</strong></td><td>功能实现</td><td>原型机、问题清单</td><td>技术可行性</td></tr><tr><td>​<strong>DVT</strong></td><td>设计完整性</td><td>认证报告、定型设计</td><td>设计缺陷、合规风险</td></tr><tr><td>​<strong>PVT</strong></td><td>生产稳定性</td><td>量产流程、首批产品</td><td>良率、供应链风险</td></tr></tbody></table><hr><h3 id="​典型问题与过渡"><a href="#​典型问题与过渡" class="headerlink" title="​典型问题与过渡"></a>​<strong>典型问题与过渡</strong></h3><ul><li>​<strong>EVT→DVT</strong>：需解决所有关键设计问题，如散热不足需重新设计散热模块。</li><li>​<strong>DVT→PVT</strong>：完成所有设计冻结，确保生产文档（如BOM、工艺图）完备。</li><li>​<strong>PVT→MP（量产）​</strong>：通过良率目标（如95%以上），方可进入大规模生产。</li></ul><h2 id="pin-pad-ball-bump"><a href="#pin-pad-ball-bump" class="headerlink" title="pin,pad,ball,bump"></a>pin,pad,ball,bump</h2><p>DIE是一种半导体加工工艺，也就是说<strong>DIE完了以后直接拿出来的芯片叫裸DIE，是不能直接使用的，没有引脚，没有散热片</strong>。<br>Bumping?是指将凸点（Bump）添加到芯片的焊盘上，通常用于倒装芯片（Flip-chip）封装。在芯片制造过程中，Bumping是一个重要的步骤，它通过在芯片的焊盘上生长凸点，实现芯片与封装基板之间的电气连接。这些凸点通常由金属材料制成，如金、锡铅或无铅材料等?<br>在Bumping之后，裸die（裸芯片）需要进行封装。封装是将裸芯片放入一个保护外壳中，以保护芯片并使其能够与其他电子组件连接。常见的封装技术包括引线键合和凸点连接等?<br>具体到倒装芯片封装，Bumping后的裸die会通过凸点与封装基板进行连接，从而实现芯片的功能和性能?</p><p>pin pad ball bump区别<br>pin一般指封装上的引脚<br>pad一般指die上面的金属开窗，可以通过金线与pin相连<br>ball一般指bga封装基板下面的锡球<br>bump一般指pad上面长出来的锡球</p><p>PIN指芯片封装好后的管脚，即用户看到的管脚；<br>PAD是硅片的管脚，是封装在芯片内部的，用户看不到。<br>PAD到PIN之间还有一段导线连接的。<br>芯片(Chip)可直接在电路板面上进行反扣焊接(Filp Chip on Board)，以完成芯片与电路板的组装互连。这种反扣式的COB覆晶法，可以省掉芯片许多先行封装 (Package) 的制程及成本。但其与板面之各接点，除PCB需先备妥对应之焊接基地外，芯片本身之外围各对应点，也须先做上各种圆形或方形的微型”焊锡凸块”，当其凸块只安置在”芯片”四周外围时称为FCOB，若芯片全表面各处都有凸块皆布时，则其覆晶反扣焊法特称为”Controlled Collapsed Chip Connection”简称C4法。</p><p>pin pad ball bump区别：<a href="https://blog.csdn.net/weixin_50518899/article/details/139361566">https://blog.csdn.net/weixin_50518899/article/details/139361566</a><br>芯片资料中的pad,pin,bump:<a href="https://blog.csdn.net/qq_34110120/article/details/82690884/">https://blog.csdn.net/qq_34110120/article/details/82690884/</a></p><h2 id="原理图-NETLIST-PCB-BOM（物料清单）"><a href="#原理图-NETLIST-PCB-BOM（物料清单）" class="headerlink" title="原理图,NETLIST,PCB,BOM（物料清单）"></a>原理图,NETLIST,PCB,BOM（物料清单）</h2><p>硬件电路设计的三个部分：原理图、PCB和物料清单（BOM）表<br><strong>原理图</strong>设计，其实就是将前面的思路转化为电路原理图，它很像我们教科书上的电路图。<br>pcb涉及到实际的电路板，它根据原理图转化而来的netlist(<strong>网表是沟通原理图和pcb之间的桥梁</strong>)，而将具体的元器件的封装放置(布局)在电路板上，然后根据飞线(也叫预拉线)连接其电信号(布线)。完成了pcb布局布线后，要用到哪些<strong>元器件应该有所归纳，所以我们将用到BOM表</strong>。<br><strong>netlist是原理图与pcb之间的桥梁</strong>。原理图是我们能认知的形式，电脑要将其转化为pcb，就必须将原理图转化它认识的形式netlist，然后再处理、转化为pcb。</p><h2 id="layout-bom-钢网"><a href="#layout-bom-钢网" class="headerlink" title="layout,bom,钢网"></a>layout,bom,钢网</h2><h3 id="Layout（PCB设计）​​"><a href="#Layout（PCB设计）​​" class="headerlink" title="Layout（PCB设计）​​"></a>Layout（PCB设计）​​</h3><p>​​Layout​​ 是指 ​​PCB（印刷电路板）的物理设计​​，包括元件布局、走线、层叠结构等。通常使用EDA工具（如Altium Designer、Cadence Allegro、KiCad）完成。<br>​​作用​​</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">决定电路板的 ​​电气性能、信号完整性、散热、EMC（电磁兼容性）​​。 </span><br><span class="line">生成 ​​Gerber文件​​（用于PCB生产）和 ​​坐标文件​​（用于SMT贴片）。</span><br></pre></td></tr></table></figure><p>​​关键输出​​</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">​​Gerber文件​​（各层铜箔、丝印、阻焊等）  </span><br><span class="line">​​钻孔文件​​（Drill File）  </span><br><span class="line">​​Pick &amp; Place文件​​（元件坐标和角度）</span><br></pre></td></tr></table></figure><p>​</p><h3 id="2-BOM（物料清单，Bill-of-Materials）​​"><a href="#2-BOM（物料清单，Bill-of-Materials）​​" class="headerlink" title="2. BOM（物料清单，Bill of Materials）​​"></a>2. BOM（物料清单，Bill of Materials）​​</h3><p>​​BOM​​ 是 ​​所有元器件的详细清单​​，包括型号、数量、封装、供应商等信息。<br>通常由工程师在PCB设计完成后整理。<br>​​作用​​</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">指导采购部门购买元器件。</span><br><span class="line">确保SMT贴片时使用正确的元件。</span><br></pre></td></tr></table></figure><p>​​关键内容​</p><table><thead><tr><th>字段</th><th>说明</th></tr></thead><tbody><tr><td>​<strong>​位号（RefDes）​</strong>​</td><td>如R1、C2、U3</td></tr><tr><td>​<strong>​型号（Part Number）​</strong>​</td><td>如STM32F103C8T6</td></tr><tr><td>​<strong>​封装（Package）​</strong>​</td><td>如0805、QFN-48、SOT-23</td></tr><tr><td>​<strong>​数量（Quantity）​</strong>​</td><td>每个元件的用量</td></tr><tr><td>​<strong>​供应商（Supplier）​</strong>​</td><td>可选，如Digi-Key、LCSC</td></tr></tbody></table><h3 id="钢网（Stencil）​​"><a href="#钢网（Stencil）​​" class="headerlink" title="钢网（Stencil）​​"></a>钢网（Stencil）​​</h3><p>​​钢网​​ 是一块 ​​带有镂空图案的不锈钢薄片​​，用于在PCB焊盘上 ​​印刷锡膏​​。<br>根据PCB的 ​​Gerber文件（通常是阻焊层或焊盘层）​​ 制作。<br>​​作用​​</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">在SMT贴片前，将锡膏精准涂覆到焊盘上。</span><br><span class="line">影响焊接质量（如少锡、连锡等问题）。</span><br></pre></td></tr></table></figure><p>​​关键参数​​</p><table><thead><tr><th>参数</th><th>说明</th></tr></thead><tbody><tr><td>​<strong>​厚度​</strong>​</td><td>常见0.1mm~0.15mm</td></tr><tr><td>​<strong>​开口尺寸​</strong>​</td><td>略小于焊盘（防止锡膏扩散）</td></tr><tr><td>​<strong>​材料​</strong>​</td><td>不锈钢（激光切割或化学蚀刻）</td></tr></tbody></table><h3 id="三者的区别与联系​"><a href="#三者的区别与联系​" class="headerlink" title="三者的区别与联系​"></a>三者的区别与联系​</h3><table><thead><tr><th><strong>项目​</strong>​</th><th>​<strong>​Layout（PCB设计）​</strong>​</th><th>​<strong>​BOM（物料清单）​</strong>​</th><th>​<strong>​钢网（Stencil）​</strong>​</th></tr></thead><tbody><tr><td>​<strong>​阶段​</strong>​</td><td>设计阶段</td><td>设计完成后</td><td>PCB生产前</td></tr><tr><td>​<strong>​用途​</strong>​</td><td>定义电路板的物理和电气特性</td><td>列出所有需采购的元器件</td><td>用于SMT锡膏印刷</td></tr><tr><td>​<strong>​依赖关系​</strong>​</td><td>生成Gerber文件和坐标文件</td><td>依赖Layout的位号和封装信息</td><td>依赖Layout的焊盘设计</td></tr><tr><td>​<strong>​输出文件​</strong>​</td><td>Gerber、钻孔文件、坐标文件</td><td>Excel/CSV格式的清单</td><td>钢网Gerber（通常为焊盘层）</td></tr><tr><td>​<strong>​责任方​</strong>​</td><td>硬件工程师</td><td>硬件工程师/采购</td><td>PCB或SMT工厂</td></tr><tr><td>​​总结：</td><td></td><td></td><td></td></tr><tr><td>Layout​​ 是PCB的“蓝图”，决定电路如何实现。</td><td></td><td></td><td></td></tr><tr><td>​​BOM​​ 是元件的“采购清单”，确保所有物料正确。</td><td></td><td></td><td></td></tr><tr><td>​​钢网​​ 是SMT的“模具”，影响焊接质量。</td><td></td><td></td><td></td></tr><tr><td>​​三者必须严格匹配​​，否则会导致生产问题（如元件贴错、焊接不良）。</td><td></td><td></td><td></td></tr></tbody></table>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;目录页&lt;br&gt;Hi3559A V100R001C02SPC031原厂SDK包:&lt;a href=&quot;https://www.ebaina.com/down/240000038810&quot;&gt;https://www.ebaina.com/down/240000038810&lt;/a&gt;&lt;br&gt;海思HI3559A SDK文档说明:&lt;a href=&quot;https://blog.csdn.net/tirvideo/article/details/86293786&quot;&gt;https://blog.csdn.net/tirvideo/article/details/86293786&lt;/a&gt;&lt;/p&gt;
    
    </summary>
    
    
      <category term="08领域技术" scheme="https://hexo.yuanjh.cn/categories/08%E9%A2%86%E5%9F%9F%E6%8A%80%E6%9C%AF/"/>
    
      <category term="g芯片相关" scheme="https://hexo.yuanjh.cn/categories/08%E9%A2%86%E5%9F%9F%E6%8A%80%E6%9C%AF/g%E8%8A%AF%E7%89%87%E7%9B%B8%E5%85%B3/"/>
    
    
      <category term="08领域技术/g芯片相关/交付琐碎" scheme="https://hexo.yuanjh.cn/tags/08%E9%A2%86%E5%9F%9F%E6%8A%80%E6%9C%AF-g%E8%8A%AF%E7%89%87%E7%9B%B8%E5%85%B3-%E4%BA%A4%E4%BB%98%E7%90%90%E7%A2%8E/"/>
    
  </entry>
  
  <entry>
    <title>基础知识_07启动,烧写和sdk安装</title>
    <link href="https://hexo.yuanjh.cn/hexo/1d678ff7/"/>
    <id>https://hexo.yuanjh.cn/hexo/1d678ff7/</id>
    <published>2024-12-24T21:45:19.000Z</published>
    <updated>2026-03-11T16:45:17.859Z</updated>
    
    <content type="html"><![CDATA[<h2 id="启动介质烧写指南-pdf"><a href="#启动介质烧写指南-pdf" class="headerlink" title="启动介质烧写指南.pdf"></a>启动介质烧写指南.pdf</h2><h3 id="文件-etc-passwd-和-etc-shadow，内容解析"><a href="#文件-etc-passwd-和-etc-shadow，内容解析" class="headerlink" title="文件/etc/passwd 和/etc/shadow，内容解析"></a>文件/etc/passwd 和/etc/shadow，内容解析</h3><p>在Linux系统中，/etc/passwd和/etc/shadow是存储用户账户信息的核心文件，二者配合实现用户认证。以下是它们的详细解析：</p><table><thead><tr><th>特性</th><th><code>/etc/passwd</code></th><th><code>/etc/shadow</code></th></tr></thead><tbody><tr><td>​<strong>​权限​</strong>​</td><td>所有用户可读（<code>644</code>）</td><td>仅root可读（<code>600</code>或<code>400</code>）</td></tr><tr><td>​<strong>​密码存储​</strong>​</td><td>仅占位符<code>x</code></td><td>实际加密密码</td></tr><tr><td>​<strong>​安全作用​</strong>​</td><td>存储用户基本信息</td><td>专用于密码和账户策略</td></tr><tr><td>​<strong>​历史背景​</strong>​</td><td>早期存储密码（现已被shadow取代）</td><td>现代系统的密码管理文件</td></tr><tr><td>通过这种分离设计（passwd存基本信息+shadow存敏感数据），Linux实现了用户认证的安全分层。运维时应始终使用vipw等工具编辑这些文件，避免直接修改导致格式错误。</td><td></td><td></td></tr></tbody></table><h3 id="uboot的bootargs，bootcmd区别"><a href="#uboot的bootargs，bootcmd区别" class="headerlink" title="uboot的bootargs，bootcmd区别"></a>uboot的bootargs，bootcmd区别</h3><table><thead><tr><th>​<strong>​特性​</strong>​</th><th>​<strong>​<code>bootargs</code>​</strong>​</th><th>​<strong>​<code>bootcmd</code>​</strong>​</th></tr></thead><tbody><tr><td>​<strong>​用途​</strong>​</td><td>向内核传递参数</td><td>定义自动执行的启动命令序列</td></tr><tr><td>​<strong>​内容类型​</strong>​</td><td>键值对参数（字符串）</td><td>U-Boot命令（可包含多条命令）</td></tr><tr><td>​<strong>​执行时机​</strong>​</td><td>由<code>bootm</code>/<code>bootz</code>等命令传递给内核</td><td>U-Boot倒计时结束后自动执行</td></tr><tr><td>​<strong>​依赖关系​</strong>​</td><td>依赖<code>bootcmd</code>加载内核后才会生效</td><td>可独立定义，不依赖<code>bootargs</code></td></tr><tr><td>​<strong>​典型修改场景​</strong>​</td><td>调整根文件系统、控制台、内存等</td><td>切换启动介质（MMC/NET/NAND）、更新镜像</td></tr></tbody></table><p><strong>协同工作流程</strong>​​<br>​​U-Boot启动​​ → 执行bootcmd中的命令<br>（例如：从网络加载内核镜像zImage和设备树dtb到内存）<br>​​加载内核​​ → 通过bootm/bootz命令启动内核<br>​​参数传递​​ → 将bootargs的内容传递给内核<br>​​内核初始化​​ → 根据bootargs配置硬件和挂载根文件系统</p><h1 id="打印所有环境变量"><a href="#打印所有环境变量" class="headerlink" title="打印所有环境变量"></a>打印所有环境变量</h1><p>printenv</p><h1 id="单独查看"><a href="#单独查看" class="headerlink" title="单独查看"></a>单独查看</h1><p>printenv bootargs<br>printenv bootcmd</p><h2 id="SDK-安装及升级使用说明"><a href="#SDK-安装及升级使用说明" class="headerlink" title="SDK 安装及升级使用说明"></a>SDK 安装及升级使用说明</h2><h3 id="sudo-dpkg-reconfigure-dash，这个命令什么意思"><a href="#sudo-dpkg-reconfigure-dash，这个命令什么意思" class="headerlink" title="sudo dpkg-reconfigure dash，这个命令什么意思"></a>sudo dpkg-reconfigure dash，这个命令什么意思</h3><p>sudo dpkg-reconfigure dash 是一个用于 ​​重新配置系统默认 /bin/sh 解释器​​ 的 Debian/Ubuntu 系统命令。它的作用和工作原理如下：<br>安装系统时​​<br>Debian/Ubuntu 安装程序会默认将 /bin/sh 链接到 dash（而非 bash），因为：</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">dash 更快​​：启动速度快、内存占用低（适合系统初始化阶段）。  </span><br><span class="line">​​dash 更严格​​：遵循 POSIX 标准，避免脚本中依赖 bash 特有语法。</span><br></pre></td></tr></table></figure><p>​​</p>]]></content>
    
    <summary type="html">
    
      &lt;h2 id=&quot;启动介质烧写指南-pdf&quot;&gt;&lt;a href=&quot;#启动介质烧写指南-pdf&quot; class=&quot;headerlink&quot; title=&quot;启动介质烧写指南.pdf&quot;&gt;&lt;/a&gt;启动介质烧写指南.pdf&lt;/h2&gt;
    
    </summary>
    
    
      <category term="08领域技术" scheme="https://hexo.yuanjh.cn/categories/08%E9%A2%86%E5%9F%9F%E6%8A%80%E6%9C%AF/"/>
    
      <category term="g芯片相关" scheme="https://hexo.yuanjh.cn/categories/08%E9%A2%86%E5%9F%9F%E6%8A%80%E6%9C%AF/g%E8%8A%AF%E7%89%87%E7%9B%B8%E5%85%B3/"/>
    
    
      <category term="08领域技术/g芯片相关/基础知识" scheme="https://hexo.yuanjh.cn/tags/08%E9%A2%86%E5%9F%9F%E6%8A%80%E6%9C%AF-g%E8%8A%AF%E7%89%87%E7%9B%B8%E5%85%B3-%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/"/>
    
  </entry>
  
  <entry>
    <title>基础知识_06uboot,kernel和镜像编译</title>
    <link href="https://hexo.yuanjh.cn/hexo/ba3e494c/"/>
    <id>https://hexo.yuanjh.cn/hexo/ba3e494c/</id>
    <published>2024-12-22T21:45:02.000Z</published>
    <updated>2026-03-11T16:45:17.859Z</updated>
    
    <content type="html"><![CDATA[<h2 id="uboot-linux内核-dts设备树-rootfs区别和联系"><a href="#uboot-linux内核-dts设备树-rootfs区别和联系" class="headerlink" title="uboot,linux内核,dts设备树,rootfs区别和联系"></a>uboot,linux内核,dts设备树,rootfs区别和联系</h2><p><strong>1,关系表</strong></p><table><thead><tr><th>​<strong>组件</strong></th><th>​<strong>作用</strong></th><th>​<strong>文件类型</strong></th><th>​<strong>运行阶段</strong></th></tr></thead><tbody><tr><td>​<strong>U-Boot</strong></td><td>引导加载程序，初始化硬件、加载内核和设备树到内存，并启动内核</td><td>二进制可执行文件（如 <code>u-boot.bin</code>）</td><td>系统上电 → 内核启动前</td></tr><tr><td>​<strong>Linux 内核</strong></td><td>操作系统核心，管理硬件资源（CPU、内存、外设）、进程调度、驱动等</td><td>压缩的二进制文件（如 <code>Image</code>、<code>zImage</code>）</td><td>内核启动 → 用户空间启动前</td></tr><tr><td>​<strong>设备树（DTS）​</strong></td><td>描述硬件配置（CPU、外设、中断、寄存器地址等），供内核识别硬件</td><td>文本文件（<code>.dts</code>） → 编译为二进制（<code>.dtb</code>）</td><td>内核启动阶段解析</td></tr><tr><td>​<strong>rootfs</strong></td><td>根文件系统，包含用户空间程序（如 <code>/bin</code>、<code>/lib</code>）、配置文件、应用程序等</td><td>文件系统镜像（如 <code>ext4</code>、<code>squashfs</code>、<code>initramfs</code>）</td><td>内核启动后挂载，用户空间运行</td></tr></tbody></table><p><strong>2, 协作关系（启动流程）​</strong></p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">系统上电 → U-Boot → 加载内核和设备树 → 内核启动 → 解析设备树 → 挂载 rootfs → 启动用户空间（如 systemd）</span><br></pre></td></tr></table></figure><p><strong>3,关键步骤详解​</strong></p><ol><li>​<strong>U-Boot 阶段</strong></li></ol><ul><li>初始化 CPU、内存、存储设备（如 eMMC、SD 卡）、串口等基础硬件。</li><li>从存储设备（或网络）加载 ​<strong>内核镜像（Image）​</strong> 和 ​<strong>设备树二进制（.dtb）​</strong> 到内存。</li><li>通过 <code>bootm</code> 或 <code>bootz</code> 命令启动内核，并传递设备树的内存地址。</li></ul><ol start="2"><li>​<strong>Linux 内核阶段</strong></li></ol><ul><li>解析设备树（<code>.dtb</code>），识别 CPU 架构、外设地址、中断号等硬件信息。</li><li>初始化驱动（如网卡、存储控制器），挂载 ​<strong>rootfs</strong>​（从硬盘、网络或内存加载）。</li><li>启动第一个用户空间进程（如 <code>init</code> 或 <code>systemd</code>）。</li></ul><ol start="3"><li>​<strong>rootfs 阶段</strong></li></ol><ul><li>提供用户空间程序运行环境（如 <code>bash</code>、<code>systemd</code>、应用程序）。</li><li>包含动态链接库（<code>/lib</code>）、配置文件（<code>/etc</code>）、设备节点（<code>/dev</code>）等。</li></ul><h2 id="rootfs生成脚本-mmdebstrap-chroot"><a href="#rootfs生成脚本-mmdebstrap-chroot" class="headerlink" title="rootfs生成脚本(mmdebstrap,chroot)"></a>rootfs生成脚本(mmdebstrap,chroot)</h2><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">mmdebstrap --architectures&#x3D;riscv64 \</span><br><span class="line">      --include&#x3D;&quot;$PACKAGE_LIST&quot; \</span><br><span class="line">      --skip check&#x2F;empty \</span><br><span class="line">      sid $1 \  # $1参数为构建目标目录</span><br><span class="line">      &quot;deb [trusted&#x3D;yes] https:&#x2F;&#x2F;mirror.iscas.ac.cn&#x2F;rockos&#x2F;20250130&#x2F;rockos-gles&#x2F; rockos-gles main&quot; \</span><br><span class="line">      &quot;deb [trusted&#x3D;yes] https:&#x2F;&#x2F;mirror.iscas.ac.cn&#x2F;rockos&#x2F;20250130&#x2F;rockos-kernels&#x2F; rockos-kernels main&quot; \</span><br><span class="line">      &quot;deb [trusted&#x3D;yes] https:&#x2F;&#x2F;mirror.iscas.ac.cn&#x2F;rockos&#x2F;20250130&#x2F;rockos-addons&#x2F; rockos-addons main&quot; \</span><br><span class="line">      &quot;deb [trusted&#x3D;yes] https:&#x2F;&#x2F;mirror.iscas.ac.cn&#x2F;rockos&#x2F;20250130&#x2F;rockos-base&#x2F; sid main contrib non-free non-free-firmware&quot;</span><br></pre></td></tr></table></figure><p>问题</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">这部分代码：</span><br><span class="line">    # 挂载系统目录（构建chroot环境）</span><br><span class="line">    mount -t proc &#x2F;proc &quot;$CHROOT_TARGET&quot;&#x2F;proc    # 进程信息</span><br><span class="line">    mount --bind &#x2F;sys &quot;$CHROOT_TARGET&quot;&#x2F;sys       # 系统信息</span><br><span class="line">    mount --bind &#x2F;run &quot;$CHROOT_TARGET&quot;&#x2F;run       # 运行时文件</span><br><span class="line">    mount --bind &#x2F;dev &quot;$CHROOT_TARGET&quot;&#x2F;dev       # 设备文件</span><br><span class="line">    mount --bind &#x2F;dev&#x2F;pts &quot;$CHROOT_TARGET&quot;&#x2F;dev&#x2F;pts # 伪终端</span><br><span class="line"></span><br><span class="line">将宿主机的的sys,run,dev等挂载到&quot;$CHROOT_TARGET&quot;&#x2F;sys    （chroot的类虚拟机环境）不会有问题么？一个x86架构，一个riscv架构。，这么做为啥不报错，以及为何这么做（这么做目的时什么）</span><br></pre></td></tr></table></figure><h3 id="1-为什么不报错？——-内核接口的架构无关性"><a href="#1-为什么不报错？——-内核接口的架构无关性" class="headerlink" title="1. 为什么不报错？—— 内核接口的架构无关性"></a><strong>1. 为什么不报错？—— 内核接口的架构无关性</strong></h3><p>​<strong>虚拟文件系统的本质</strong></p><ul><li><code>/proc</code>、<code>/sys</code>、<code>dev</code> 等目录是 Linux 内核暴露给用户空间的 ​<strong>虚拟文件系统（Virtual File Systems）​</strong>：<ul><li><code>/proc</code>: 提供进程、系统状态等运行时信息（如 <code>cpuinfo</code>）。</li><li><code>/sys</code>: 暴露硬件设备、驱动、内核参数等层级化配置。</li><li><code>/dev</code>: 设备节点文件（如 <code>/dev/sda</code>）。</li></ul></li><li>​<strong>这些文件系统的内容由内核动态生成</strong>，与用户空间的 CPU 架构无关。例如：<ul><li><code>cat /proc/cpuinfo</code> 在 x86 和 RISC-V 上都会返回当前运行内核的 CPU 信息。</li><li><code>/sys/devices</code> 展示的是内核管理的设备树，与用户空间程序架构无关。</li></ul></li><li><em>架构无感知性*</em></li><li>​<strong>挂载操作只是映射内核接口</strong>，不涉及任何二进制代码执行。</li><li>即使宿主架构（x86）和目标架构（RISC-V）不同，内核仍能正确生成这些虚拟文件系统的内容，因为这些内容由宿主机的内核管理。</li></ul><h3 id="​2-为什么需要挂载？——-Chroot-环境的完整性"><a href="#​2-为什么需要挂载？——-Chroot-环境的完整性" class="headerlink" title="​2. 为什么需要挂载？—— Chroot 环境的完整性"></a>​<strong>2. 为什么需要挂载？—— Chroot 环境的完整性</strong></h3><p><strong>构建根文件系统的需求</strong></p><p>在 <code>chroot</code> 环境中执行操作（如安装软件、配置服务）时，需要：</p><ol><li>​<strong>设备访问</strong>：如挂载 <code>/dev</code> 以便在 chroot 内创建设备节点。</li><li>​<strong>系统信息查询</strong>：如通过 <code>/proc</code> 获取进程信息。</li><li>​<strong>依赖内核功能</strong>：如通过 <code>/sys</code> 配置硬件参数。</li></ol><p><strong>跨架构构建的特殊性</strong></p><ul><li><p>虽然宿主架构和目标架构不同，但 ​<strong>所有用户空间操作（如 <code>apt install</code>）实际由宿主机的内核通过二进制翻译（如 QEMU）执行</strong>：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 宿主机的内核通过 binfmt_misc 识别 RISC-V 二进制</span></span><br><span class="line"><span class="comment"># 并调用 qemu-riscv64-static 解释执行</span></span><br><span class="line">$ sudo update-binfmts --<span class="built_in">enable</span> qemu-riscv64</span><br></pre></td></tr></table></figure></li><li><p>挂载宿主机的 <code>/proc</code>、<code>/sys</code> 到 chroot 环境后：</p><ul><li>​<strong>用户空间程序（RISC-V）通过 QEMU 翻译执行</strong>。</li><li>​<strong>内核接口（如 sysfs）仍由宿主机内核提供</strong>，但用户空间程序会按 RISC-V 的预期解析这些接口。</li></ul></li></ul><h3 id="​3-潜在问题与规避"><a href="#​3-潜在问题与规避" class="headerlink" title="​3. 潜在问题与规避"></a>​<strong>3. 潜在问题与规避</strong></h3><p>​<strong>架构相关路径的冲突</strong></p><p>极少数情况下，内核接口的路径可能因架构不同产生差异，例如：</p><ul><li>​<strong>设备树路径</strong>：RISC-V 设备树路径 <code>/sys/firmware/devicetree/base</code> 可能与 x86 不同。</li><li>​<strong>CPU 拓扑信息</strong>：<code>/sys/devices/system/cpu</code> 的结构可能因架构而异。</li></ul><p>​<strong>解决方案</strong></p><ul><li>​<strong>动态生成配置</strong>：在 chroot 环境内通过脚本动态生成架构相关配置。</li><li>​<strong>避免硬编码路径</strong>：使用抽象接口（如 <code>lscpu</code> 替代直接读取 <code>/proc/cpuinfo</code>）。</li><li>​<strong>隔离关键目录</strong>：在构建完成后卸载宿主机的虚拟文件系统，确保目标系统首次启动时重新挂载自身的虚拟文件系统。</li></ul><h3 id="​4-操作的目的总结"><a href="#​4-操作的目的总结" class="headerlink" title="​4. 操作的目的总结"></a>​<strong>4. 操作的目的总结</strong></h3><table><thead><tr><th>​<strong>挂载操作</strong></th><th>​<strong>目的</strong></th></tr></thead><tbody><tr><td><code>mount -t proc /proc ...</code></td><td>允许 chroot 内程序查询进程和系统信息（如 <code>ps</code> 命令）</td></tr><tr><td><code>mount --bind /sys ...</code></td><td>提供硬件设备配置接口（如安装驱动时访问 <code>/sys/class</code>）</td></tr><tr><td><code>mount --bind /dev ...</code></td><td>创建设备节点（如 <code>/dev/null</code>, <code>/dev/console</code>）</td></tr><tr><td><code>mount --bind /dev/pts ...</code></td><td>支持伪终端操作（如 SSH 登录需要 <code>/dev/pts/0</code>）</td></tr><tr><td>### ​<strong>5. 完整工作流程示例</strong></td><td></td></tr><tr><td><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">宿主机 (x86_64)                          chroot 环境 (riscv64)</span><br><span class="line">+-----------------------------------+     +------------------------------+</span><br><span class="line">| 1. 挂载宿主机的 &#x2F;proc, &#x2F;sys, &#x2F;dev      | → | 提供内核接口，不依赖架构       |</span><br><span class="line">| 2. 通过 QEMU 解释执行 RISC-V 程序 | → | apt install 安装 RISC-V 软件包 |</span><br><span class="line">| 3. 卸载宿主机的虚拟文件系统        | ← | 生成完整的 riscv64 根文件系统  |</span><br><span class="line">+-----------------------------------+     +------------------------------+</span><br></pre></td></tr></table></figure></td><td></td></tr><tr><td>### ​<strong>结论</strong></td><td></td></tr><tr><td>* ​<strong>安全且必要</strong>：跨架构挂载虚拟文件系统是安全的，因为这些接口由宿主机的内核统一管理，与用户空间架构无关。</td><td></td></tr><tr><td>* ​<strong>依赖 QEMU</strong>：实际执行 RISC-V 二进制需要 QEMU 的二进制翻译支持，但挂载操作本身不直接涉及指令集转换。</td><td></td></tr><tr><td>* ​<strong>最佳实践</strong>：这种方法是构建跨架构根文件系统的标准操作，广泛用于嵌入式 Linux 开发和容器化构建（如 Docker 多架构构建）。</td><td></td></tr><tr><td>## uboot常用命令</td><td></td></tr><tr><td>### 1、信息查询命令</td><td></td></tr><tr><td>常用的信息查询有关的命令有三个：bdinfo、printenv、version。</td><td></td></tr></tbody></table><table><thead><tr><th>命令</th><th align="left">描述</th></tr></thead><tbody><tr><td>bdinfo</td><td align="left">查看板子信息</td></tr><tr><td>printenv</td><td align="left">输出环境变量信息</td></tr><tr><td>version</td><td align="left">查看uboot的版本号</td></tr></tbody></table><h3 id="2、环境变量操作命令"><a href="#2、环境变量操作命令" class="headerlink" title="2、环境变量操作命令"></a>2、环境变量操作命令</h3><p>环境变量的操作涉及到两个命令：setenv和saveenv。<br>setenv命令用于创建、修改环境变量的值，也可以用于删除环境变量；<br>saveenv命令用于保存修改后的环境变量。<br>一般环境变量是存放在外部flash中的，uboot启动的时候会将环境变量从flash读取到DRAM中，所以使用命令setenv修改的是DRAM中的环境变量值，修改后需使用saveenv命令将环境变量保存到flash中。<br>场景​​：误修改 bootcmd 导致无法启动，需恢复默认环境。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"># 进入 U-Boot 命令行</span><br><span class="line">&#x3D;&gt; env default -a    # 恢复所有变量</span><br><span class="line">&#x3D;&gt; saveenv           # 保存到存储设备</span><br><span class="line">&#x3D;&gt; reset             # 重启（可选）</span><br></pre></td></tr></table></figure><h3 id="3、内存操作命令"><a href="#3、内存操作命令" class="headerlink" title="3、内存操作命令"></a>3、内存操作命令</h3><p>内存操作命令就是用于直接对 DRAM 进行读写操作的，常用的内存操作命令有 md、 nm、mm、 mw、 cp 和 cmp。<br><img src="/images/20250310210114.png" alt=""></p><h3 id="4、网络操作命令"><a href="#4、网络操作命令" class="headerlink" title="4、网络操作命令"></a>4、网络操作命令</h3><p>uboot是支持网口的，在移植uboot的时候都要调通网络的功能，因为在移植linux内核的时候需要用到uboot的网络功能做调试。uboot支持的网络相关的命令有：dhcp、ping、nfs、ftfpboot。<br>使用网络调试前需先设置好下列几个环境变量。</p><table><thead><tr><th>环境变量</th><th align="left">描述</th></tr></thead><tbody><tr><td>ipaddr</td><td align="left">开发板的IP地址，可以通过dhcp命令从路由器获取IP</td></tr><tr><td>ethaddr</td><td align="left">开发板的MAC地址，一定要设置</td></tr><tr><td>gatewayip</td><td align="left">网关地址</td></tr><tr><td>netmask</td><td align="left">子网掩码</td></tr><tr><td>serverip</td><td align="left">服务器IP地址，也就是ubuntu主机的IP地址，用于调试</td></tr><tr><td><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">setenv ipaddr 192.168.1.50</span><br><span class="line">setenv ethaddr b8:ae:1d:01:00:00</span><br><span class="line">setenv gatewayip 192.168.1.1</span><br><span class="line">setenv netmask 255.255.255.0</span><br><span class="line">setenv serverip 192.168.1.253</span><br><span class="line">saveenv</span><br></pre></td></tr></table></figure></td><td align="left"></td></tr><tr><td><img src="/images/20250310210314.png" alt=""></td><td align="left"></td></tr></tbody></table><h3 id="5、EMMC和SD卡操作命令"><a href="#5、EMMC和SD卡操作命令" class="headerlink" title="5、EMMC和SD卡操作命令"></a>5、EMMC和SD卡操作命令</h3><p>uboot支持EMMC和SD卡，提供了EMMC和SD卡的操作命令。一般认为EMMC和SD卡就是同一个东西，所以没有特殊说明，统一使用MMC来代指EMMC和SD卡。uboot中常用于操作MMC设备的命令为：mmc。</p><p>mmc是一系列的命令，后面可以跟不同的参数，输入“? mmc”即可查看mmc有关的命令。如下图所示：<br><img src="/images/20250310210400.png" alt=""><br>mmc后面跟不同的参数可以实现不同的功能。</p><table><thead><tr><th>命令</th><th>描述</th></tr></thead><tbody><tr><td><code>mmc info</code></td><td>输出MMC设备信息</td></tr><tr><td><code>mmc read</code></td><td>读取MMC中的数据</td></tr><tr><td><code>mmc write</code></td><td>向MMC设备写入数据</td></tr><tr><td><code>mmc rescan</code></td><td>扫描MMC设备</td></tr><tr><td><code>mmc part</code></td><td>列出MMC设备的分区</td></tr><tr><td><code>mmc dev</code></td><td>切换MMC设备</td></tr><tr><td><code>mmc list</code></td><td>列出当前有效的所有MMC设备</td></tr><tr><td><code>mmc hwpartition</code></td><td>设置MMC设备的分区</td></tr><tr><td><code>mmc bootbus …</code></td><td>设置指定MMC设备的BOOT_BUS_WIDTH域的值</td></tr><tr><td><code>mmc bootpart …</code></td><td>设置指定MMC设备的boot和RPMB分区的大小</td></tr><tr><td><code>mmc partconf …</code></td><td>设置指定MMC设备的PARTITION_CONFG域的值</td></tr><tr><td><code>mmc rst</code></td><td>复位MMC设备</td></tr><tr><td><code>mmc setdsr</code></td><td>设置DSR寄存器的值</td></tr><tr><td></td><td></td></tr></tbody></table><p><strong>mmc rescan 命令</strong><br>mmc rescan 命令用于扫描当前开发板上所有的 MMC 设备，包括 EMMC 和 SD 卡，输入“mmc rescan”即可。<br><img src="/images/20250420135407.png" alt=""><br><strong>mmc list 命令</strong><br>mmc list 命令用于来查看当前开发板一共有几个 MMC 设备，输入“mmc list”<br><img src="/images/20250420135307.png" alt=""><br>可以看出当前开发板有两个 MMC 设备： FSL_SDHC:0 (SD)和 FSL_SDHC:1 (eMMC)，这是因为我现在用的是 EMMC 版本的核心板，加上 SD 卡一共有两个 MMC 设备， FSL_SDHC:0 是 SD卡， FSL_SDHC:1(eMMC)是 EMMC，。默认会将 EMMC 设置为当前 MMC 设备，要想查看 EMMC信息，就要使用命令“mmc dev”来将 EMMC卡设置为当前的 MMC 设备</p><p><strong>mmc dev 命令</strong><br>mmc dev 命令用于切换当前 MMC 设备，使用如下命令切换到 EMMC：<br><img src="/images/20250420135321.png" alt=""></p><p><strong>mmc info 命令</strong><br>mmc info 命令用于输出当前选中的 mmc info 设备的信息，输入命令“mmc info”即可，如下图所示:<br><img src="/images/20250420135352.png" alt=""><br>从上图可以看出，当前选中的 MMC设备是 SD卡，版本为 3.0，容量为 14.8GiB(EMMC为 4GB)，速度为 50000000Hz=50MHz， 4 位宽的总线。还有一个与 mmc info 命令相同功能的命令： mmcinfo，“mmc”和“info”之间没有空格。</p><p><strong>mmc part 命令</strong><br>有时候 SD 卡或者 EMMC 会有多个分区，可以使用命令“mmc part”来查看其分区，比如查看 EMMC 的分区情况，输入如下命令,结果如下图所示:<br><img src="/images/20250420135609.png" alt=""><br>从上图中可以看出，此时 EMMC 有两个分区，扇区 20480~ 262144 为第一个分区，扇区 282644~14987264 为第二个分区。如果 EMMC 里面烧写了 Linux 系统的话， EMMC 是有3 个分区的，第 0 个分区存放 uboot，第 1 个分区存放 Linux 镜像文件和设备树，第 2 个分区存放根文件系统。但是在图中只有两个分区，那是因为第 0 个分区没有格式化，所以识别不出来，实际上第 0 个分区是存在的。一个新的 SD 卡默认只有一个分区，那就是分区 0.</p><p>参考：<br>u-boot常用命令：<a href="https://blog.csdn.net/helaisun/article/details/128166820">https://blog.csdn.net/helaisun/article/details/128166820</a><br>史上最全的Uboot常用命令汇总（超全面！超详细！）收藏这一篇就够了「建议收藏」：<a href="https://cloud.tencent.cn/developer/article/2102295">https://cloud.tencent.cn/developer/article/2102295</a><br>U-Boot命令使用：<a href="https://blog.csdn.net/cike626/article/details/128430824">https://blog.csdn.net/cike626/article/details/128430824</a><br>U-Boot命令之EMMC和SD卡操作命令：<a href="https://blog.csdn.net/weixin_45309916/article/details/109178989">https://blog.csdn.net/weixin_45309916/article/details/109178989</a></p><h2 id="uboot环境变量解析"><a href="#uboot环境变量解析" class="headerlink" title="uboot环境变量解析"></a>uboot环境变量解析</h2><p><strong>样例信息</strong></p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br></pre></td><td class="code"><pre><span class="line">&gt; printenv</span><br><span class="line">arch&#x3D;riscv</span><br><span class="line">baudrate&#x3D;115200</span><br><span class="line">board&#x3D;eic7700_d314</span><br><span class="line">board_name&#x3D;eic7700_d314</span><br><span class="line">boot_conf_addr_r&#x3D;0xc0000000</span><br><span class="line">boot_conf_file&#x3D;&#x2F;extlinux&#x2F;extlinux.conf</span><br><span class="line">bootargs&#x3D;root&#x3D;&#x2F;dev&#x2F;nfs init&#x3D;&#x2F;linuxrc ip&#x3D;dhcp rw nfsroot&#x3D;10.10.192.205:&#x2F;srv&#x2F;nfs_server,proto&#x3D;tcp,nfsvers&#x3D;3,nolock console-ttyS0</span><br><span class="line">bootcmd&#x3D;sysboot mmc $&#123;emmc_dev&#125;:1 any $boot_conf_addr_r $boot_conf_file;</span><br><span class="line">bootdelay&#x3D;2</span><br><span class="line">console&#x3D;ttyS0</span><br><span class="line">cpu&#x3D;eic770x</span><br><span class="line">emmc_dev&#x3D;0</span><br><span class="line">ethact&#x3D;ethernet@50400000</span><br><span class="line">ethaddr&#x3D;8c:1f:64:13:c0:9c</span><br><span class="line">fdt_addr&#x3D;ed511150</span><br><span class="line">fdt_addr_r&#x3D;0x88000000</span><br><span class="line">fdt_high&#x3D;0xffffffffffffffff</span><br><span class="line">fdtaddr&#x3D;ed511150</span><br><span class="line">fdtcontroladdr&#x3D;ed511150</span><br><span class="line">fdtfile&#x3D;eswin&#x2F;eic7700-d314.dtb</span><br><span class="line">gpt_partition&#x3D;gpt write mmc $&#123;emmc_dev&#125; $partitions</span><br><span class="line">initrd_high&#x3D;0xffffffffffffffff</span><br><span class="line">kernel_addr_r&#x3D;0x84000000</span><br><span class="line">kernel_comp_addr_r&#x3D;0xa0000000</span><br><span class="line">kernel_comp_size&#x3D;0x4000000</span><br><span class="line">loadaddr&#x3D;0x80200000</span><br><span class="line">loadimage&#x3D;dhcp 0x90000000 fitImage</span><br><span class="line">nfsargs&#x3D;setenv bootargs root&#x3D;&#x2F;dev&#x2F;nfs init&#x3D;&#x2F;linuxrc ip&#x3D;dhcp rw nfsroot&#x3D;10.10.192.205:&#x2F;srv&#x2F;nfs_server,proto&#x3D;tcp,nfsvers&#x3D;3,nolock</span><br><span class="line">nfsboot&#x3D;echo Set nfs parameter ...;run nfsargs;run setimageload;run loadimage</span><br><span class="line">partitions&#x3D;name&#x3D;boot,start&#x3D;1MiB,size&#x3D;512MiB,type&#x3D;$&#123;typeid_efi&#125;,uuid&#x3D;$&#123;uuid_boot&#125;;name&#x3D;swap,size&#x3D;4096MiB,type&#x3D;$&#123;typeid_swap&#125;,uuid&#x3D;$&#123;uuid_swap&#125;;name&#x3D;root,size&#x3D;-,type&#x3D;$&#123;typeid_filesystem&#125;,uuid&#x3D;$&#123;uuid_root&#125;</span><br><span class="line">preboot&#x3D;setenv fdt_addr $&#123;fdtcontroladdr&#125;;fdt addr $&#123;fdtcontroladdr&#125;;usb start;sata init;nvme scan</span><br><span class="line">pxefile_addr_r&#x3D;0x88200000</span><br><span class="line">ram_size&#x3D;16</span><br><span class="line">ramdisk_addr_r&#x3D;0x88300000</span><br><span class="line">scriptaddr&#x3D;0x88100000</span><br><span class="line">sdupdate&#x3D;ext4load mmc 1:1 0x90000000 sdupdate.scr;source 0x90000000</span><br><span class="line">serverip&#x3D;10.10.192.205</span><br><span class="line">setimageload&#x3D;setenv loadimage dhcp 0x90000000 fitImage</span><br><span class="line">silent&#x3D;1</span><br><span class="line">splashimage&#x3D;0xe0000000</span><br><span class="line">splashpos&#x3D;1660,0</span><br><span class="line">stderr&#x3D;vidconsole,serial</span><br><span class="line">stdin&#x3D;serial,usbkbd</span><br><span class="line">stdout&#x3D;serial</span><br><span class="line">typeid_efi&#x3D;C12A7328-F81F-11D2-BA4B-00A0C93EC93B</span><br><span class="line">typeid_filesystem&#x3D;0FC63DAF-8483-4772-8E79-3D69D8477DE4</span><br><span class="line">typeid_swap&#x3D;0657FD6D-A4AB-43C4-84E5-0933C84B4F4F</span><br><span class="line">usbupdate&#x3D;ext4load usb 0 0x90000000 usbupdate.scr;source 0x90000000</span><br><span class="line">uuid_boot&#x3D;44b7cb94-f58c-4ba6-bfa4-7d2dce09a3a5</span><br><span class="line">uuid_root&#x3D;80a5a8e9-c744-491a-93c1-4f4194fd690a</span><br><span class="line">uuid_swap&#x3D;5ebcaaf0-e098-43b9-beef-1f8deedd135e</span><br><span class="line">vendor&#x3D;eswin</span><br><span class="line"></span><br><span class="line">Environment size: 2020&#x2F;524284 bytes</span><br></pre></td></tr></table></figure><p>4大部分</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">1. 硬件初始化</span><br><span class="line">   - 加载设备树: fdtfile&#x3D;eswin&#x2F;eic7700-d314.dtb</span><br><span class="line">   - 初始化存储: emmc_dev&#x3D;0, sata&#x2F;nvme</span><br><span class="line"></span><br><span class="line">2. 启动方式选择</span><br><span class="line">   - 默认启动: bootcmd → 从 eMMC 的 extlinux 配置启动</span><br><span class="line">   - NFS 启动: nfsboot → 从服务器 10.10.192.205 加载内核和根文件系统</span><br><span class="line"></span><br><span class="line">3. 内核加载</span><br><span class="line">   - 内核地址: kernel_addr_r&#x3D;0x84000000</span><br><span class="line">   - 设备树地址: fdt_addr_r&#x3D;0x88000000</span><br><span class="line"></span><br><span class="line">4. 根文件系统挂载</span><br><span class="line">   - NFS 挂载: root&#x3D;&#x2F;dev&#x2F;nfs, nfsroot&#x3D;10.10.192.205:&#x2F;srv&#x2F;nfs_server</span><br><span class="line">   - 本地挂载: root&#x3D;UUID&#x3D;80a5a8e9... (需配置 fstab)</span><br></pre></td></tr></table></figure><p><strong>1. 系统基础信息</strong></p><table><thead><tr><th>​<strong>变量</strong></th><th>​<strong>值</strong></th><th>​<strong>说明</strong></th></tr></thead><tbody><tr><td><code>arch</code></td><td><code>riscv</code></td><td>系统架构为 ​<strong>RISC-V</strong></td></tr><tr><td><code>board</code></td><td><code>eic7700_d314</code></td><td>硬件板型号（与设备树文件 <code>eic7700-d314.dtb</code> 匹配）</td></tr><tr><td><code>vendor</code></td><td><code>eswin</code></td><td>硬件厂商标识</td></tr><tr><td><code>cpu</code></td><td><code>eic770x</code></td><td>CPU 型号（可能为定制 SoC）</td></tr><tr><td><code>ram_size</code></td><td><code>16</code></td><td>系统内存容量为 ​<strong>16GB</strong></td></tr></tbody></table><p><strong>2. 启动流程控制</strong></p><table><thead><tr><th>​<strong>变量</strong></th><th>​<strong>值</strong></th><th>​<strong>说明</strong></th></tr></thead><tbody><tr><td><code>bootcmd</code></td><td><code>sysboot mmc ${emmc_dev}:1 any $boot_conf_addr_r $boot_conf_file;</code></td><td>​<strong>默认启动命令</strong>：<br>- 从 eMMC 的第 1 分区加载 extlinux 配置 (<code>/extlinux/extlinux.conf</code>)<br>- 使用 <code>sysboot</code> 执行配置的启动项</td></tr><tr><td><code>bootdelay</code></td><td><code>2</code></td><td>启动等待时间为 ​<strong>2 秒</strong>​（用户可按任意键中断自动启动）</td></tr><tr><td><code>boot_conf_file</code></td><td><code>/extlinux/extlinux.conf</code></td><td>U-Boot 启动菜单配置文件路径</td></tr><tr><td><code>bootargs</code></td><td><code>root=/dev/nfs ... console-ttyS0</code></td><td>​<strong>内核启动参数</strong>：<br>- 通过 NFS 挂载根文件系统 (<code>10.10.192.205:/srv/nfs_server</code>)<br>- 使用串口 <code>ttyS0</code> 作为控制台</td></tr></tbody></table><p><strong>3. 存储与分区</strong></p><table><thead><tr><th>​<strong>变量</strong></th><th>​<strong>值</strong></th><th>​<strong>说明</strong></th></tr></thead><tbody><tr><td><code>partitions</code></td><td><code>name=boot,start=1MiB,size=512MiB...</code></td><td>​<strong>GPT 分区定义</strong>：<br>- <code>boot</code> 分区：512MB，EFI 类型 (FAT32)<br>- <code>swap</code> 分区：4GB<br>- <code>root</code> 分区：剩余空间（ext4）</td></tr><tr><td><code>gpt_partition</code></td><td><code>gpt write mmc ${emmc_dev} $partitions</code></td><td>命令：将 <code>partitions</code> 变量定义的分区表写入 eMMC</td></tr><tr><td><code>emmc_dev</code></td><td><code>0</code></td><td>当前操作的 eMMC 设备编号（对应硬件上的存储控制器）</td></tr><tr><td><code>uuid_boot</code></td><td><code>44b7cb94-f58c-4ba6-bfa4-7d2dce09a3a5</code></td><td>Boot 分区的 UUID（与 <code>fstab</code> 中的配置匹配）</td></tr></tbody></table><p>​<strong>4. 网络配置</strong></p><table><thead><tr><th>​<strong>变量</strong></th><th>​<strong>值</strong></th><th>​<strong>说明</strong></th></tr></thead><tbody><tr><td><code>ethact</code></td><td><code>ethernet@50400000</code></td><td>当前激活的以太网设备（硬件寄存器地址 <code>0x50400000</code>）</td></tr><tr><td><code>ethaddr</code></td><td><code>8c:1f:64:13:c0:9c</code></td><td>MAC 地址（需确保与网络环境无冲突）</td></tr><tr><td><code>serverip</code></td><td><code>10.10.192.205</code></td><td>TFTP/NFS 服务器 IP（用于网络启动或文件传输）</td></tr><tr><td><code>nfsboot</code></td><td><code>run nfsargs; run loadimage</code></td><td>​<strong>NFS 启动命令</strong>：<br>1. 设置 NFS 参数 (<code>nfsargs</code>)<br>2. 加载内核镜像 (<code>loadimage</code>)</td></tr><tr><td><strong>5. 内核与设备树加载</strong></td><td></td><td></td></tr></tbody></table><table><thead><tr><th>​<strong>变量</strong></th><th>​<strong>值</strong></th><th>​<strong>说明</strong></th></tr></thead><tbody><tr><td><code>kernel_addr_r</code></td><td><code>0x84000000</code></td><td>内核镜像 (<code>fitImage</code>) 加载到内存的地址</td></tr><tr><td><code>fdt_addr_r</code></td><td><code>0x88000000</code></td><td>设备树文件 (<code>eic7700-d314.dtb</code>) 加载地址</td></tr><tr><td><code>fdtfile</code></td><td><code>eswin/eic7700-d314.dtb</code></td><td>设备树文件路径（需与硬件板型号匹配）</td></tr><tr><td><code>loadimage</code></td><td><code>dhcp 0x90000000 fitImage</code></td><td>从 TFTP 服务器下载内核镜像到内存 <code>0x90000000</code></td></tr></tbody></table><p><strong>6. 高级功能</strong></p><table><thead><tr><th>​<strong>变量</strong></th><th>​<strong>值</strong></th><th>​<strong>说明</strong></th></tr></thead><tbody><tr><td><code>sdupdate</code></td><td><code>ext4load mmc 1:1 0x90000000 sdupdate.scr; source 0x90000000</code></td><td>​<strong>SD 卡更新脚本</strong>：<br>- 从 SD 卡加载 <code>sdupdate.scr</code> 脚本并执行</td></tr><tr><td><code>usbupdate</code></td><td><code>ext4load usb 0 0x90000000 usbupdate.scr; source 0x90000000</code></td><td>​<strong>USB 更新脚本</strong>：<br>- 从 USB 设备加载 <code>usbupdate.scr</code> 并执行</td></tr><tr><td><code>preboot</code></td><td><code>sata init; nvme scan</code></td><td>启动前初始化 SATA/NVMe 设备（扩展存储支持）</td></tr></tbody></table>]]></content>
    
    <summary type="html">
    
      &lt;h2 id=&quot;uboot-linux内核-dts设备树-rootfs区别和联系&quot;&gt;&lt;a href=&quot;#uboot-linux内核-dts设备树-rootfs区别和联系&quot; class=&quot;headerlink&quot; title=&quot;uboot,linux内核,dts设备树,rootfs区别和联系&quot;&gt;&lt;/a&gt;uboot,linux内核,dts设备树,rootfs区别和联系&lt;/h2&gt;
    
    </summary>
    
    
      <category term="08领域技术" scheme="https://hexo.yuanjh.cn/categories/08%E9%A2%86%E5%9F%9F%E6%8A%80%E6%9C%AF/"/>
    
      <category term="g芯片相关" scheme="https://hexo.yuanjh.cn/categories/08%E9%A2%86%E5%9F%9F%E6%8A%80%E6%9C%AF/g%E8%8A%AF%E7%89%87%E7%9B%B8%E5%85%B3/"/>
    
    
      <category term="08领域技术/g芯片相关/基础知识" scheme="https://hexo.yuanjh.cn/tags/08%E9%A2%86%E5%9F%9F%E6%8A%80%E6%9C%AF-g%E8%8A%AF%E7%89%87%E7%9B%B8%E5%85%B3-%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/"/>
    
  </entry>
  
  <entry>
    <title>基础知识_05DTS设备树和驱动</title>
    <link href="https://hexo.yuanjh.cn/hexo/f0cf7d37/"/>
    <id>https://hexo.yuanjh.cn/hexo/f0cf7d37/</id>
    <published>2024-12-19T21:45:01.000Z</published>
    <updated>2026-03-11T16:45:17.859Z</updated>
    
    <content type="html"><![CDATA[<h2 id="一个设备树的全景视图"><a href="#一个设备树的全景视图" class="headerlink" title="一个设备树的全景视图"></a>一个设备树的全景视图</h2><p><img src="/images/20250220223106.png" alt=""></p><h2 id="设备树和驱动"><a href="#设备树和驱动" class="headerlink" title="设备树和驱动"></a>设备树和驱动</h2><table><thead><tr><th>特性</th><th>设备树（Device Tree）</th><th>驱动（Driver）</th><th></th></tr></thead><tbody><tr><td><strong>职责</strong></td><td>描述硬件配置</td><td>控制和管理硬件设备</td><td></td></tr><tr><td><strong>内容</strong></td><td>硬件地址、中断号、时钟等</td><td>初始化代码、操作函数、中断处理等</td><td></td></tr><tr><td><strong>形式</strong></td><td>文本文件（.dts）或二进制文件（.dtb）</td><td>内核模块代码（.c 文件）</td><td></td></tr><tr><td><strong>加载时机</strong></td><td>在内核启动时由 Bootloader 传递给内核</td><td>在内核启动或模块加载时初始化</td><td></td></tr><tr><td><strong>可移植性</strong></td><td>提高内核的可移植性，同一内核支持不同硬件</td><td>依赖设备树提供的硬件信息</td><td></td></tr></tbody></table><p><strong>设备树与驱动的联系</strong></p><ul><li><p><strong>设备树为驱动提供硬件信息</strong>：</p><ul><li>驱动通过设备树获取硬件的寄存器地址、中断号、时钟等资源。</li><li>设备树中的 <code>compatible</code> 属性用于匹配驱动和设备。</li></ul></li><li><p><strong>驱动依赖设备树</strong>：</p><ul><li>在嵌入式 Linux 中，设备树是驱动获取硬件信息的主要方式。</li><li>驱动通过内核提供的 API（如 <code>of_*</code> 系列函数）从设备树中读取信息。</li></ul></li><li><p><strong>共同完成硬件管理</strong>：</p><ul><li>设备树描述硬件，驱动操作硬件，二者协作完成硬件的初始化和控制。<h2 id="例子-简单版"><a href="#例子-简单版" class="headerlink" title="例子_简单版"></a>例子_简单版</h2>设备树（.dts）<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">&amp;i2c1 &#123;</span><br><span class="line">    status &#x3D; &quot;okay&quot;;</span><br><span class="line">    eeprom@50 &#123;</span><br><span class="line">        compatible &#x3D; &quot;atmel,24c02&quot;;</span><br><span class="line">        reg &#x3D; &lt;0x50&gt;;</span><br><span class="line">    &#125;;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>驱动（.c）<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line">#include &lt;linux&#x2F;module.h&gt;</span><br><span class="line">#include &lt;linux&#x2F;i2c.h&gt;</span><br><span class="line">#include &lt;linux&#x2F;of.h&gt;</span><br><span class="line"></span><br><span class="line">static int eeprom_probe(struct i2c_client *client, const struct i2c_device_id *id) &#123;</span><br><span class="line">    printk(&quot;EEPROM probed!\n&quot;);</span><br><span class="line">    &#x2F;&#x2F; 初始化硬件</span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">static int eeprom_remove(struct i2c_client *client) &#123;</span><br><span class="line">    printk(&quot;EEPROM removed!\n&quot;);</span><br><span class="line">    &#x2F;&#x2F; 释放资源</span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">static const struct of_device_id eeprom_match[] &#x3D; &#123;</span><br><span class="line">    &#123; .compatible &#x3D; &quot;atmel,24c02&quot; &#125;,</span><br><span class="line">    &#123; &#125;</span><br><span class="line">&#125;;</span><br><span class="line">MODULE_DEVICE_TABLE(of, eeprom_match);</span><br><span class="line"></span><br><span class="line">static struct i2c_driver eeprom_driver &#x3D; &#123;</span><br><span class="line">    .probe &#x3D; eeprom_probe,</span><br><span class="line">    .remove &#x3D; eeprom_remove,</span><br><span class="line">    .driver &#x3D; &#123;</span><br><span class="line">        .name &#x3D; &quot;eeprom&quot;,</span><br><span class="line">        .of_match_table &#x3D; eeprom_match,</span><br><span class="line">    &#125;,</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">module_i2c_driver(eeprom_driver);</span><br><span class="line"></span><br><span class="line">MODULE_LICENSE(&quot;GPL&quot;);</span><br><span class="line">MODULE_AUTHOR(&quot;Your Name&quot;);</span><br><span class="line">MODULE_DESCRIPTION(&quot;EEPROM Driver&quot;);</span><br></pre></td></tr></table></figure>总结<br>设备树 描述硬件信息，驱动 控制硬件设备。<br>设备树通过 compatible 属性与驱动匹配，驱动通过设备树获取硬件资源。<br>二者共同协作，完成硬件的初始化和操作。<h2 id="例子-复杂版"><a href="#例子-复杂版" class="headerlink" title="例子_复杂版"></a>例子_复杂版</h2>举例子稍微复杂例子，能体现出，设备树的配置信息如何被驱动识别，解析，处理的。</li></ul></li></ul><p>这个例子将涉及一个假设的 多功能设备，它包含以下功能：<br>一个 I2C 接口 的传感器。<br>一个 GPIO 引脚 用于控制设备状态。<br>一个 中断引脚 用于触发事件。<br><strong>设备树（.dts）</strong><br>设备树描述硬件信息，包括 I2C 地址、GPIO 引脚、中断号等。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">    compatible &#x3D; &quot;mycompany,myboard&quot;;</span><br><span class="line">    model &#x3D; &quot;MyBoard&quot;;</span><br><span class="line"></span><br><span class="line">    sensor: sensor@50 &#123;</span><br><span class="line">        compatible &#x3D; &quot;mycompany,my-sensor&quot;;</span><br><span class="line">        reg &#x3D; &lt;0x50&gt;; &#x2F;&#x2F; I2C 地址</span><br><span class="line">        interrupt-parent &#x3D; &lt;&amp;gpio1&gt;; &#x2F;&#x2F; 中断控制器</span><br><span class="line">        interrupts &#x3D; &lt;5 IRQ_TYPE_EDGE_RISING&gt;; &#x2F;&#x2F; GPIO1_5，上升沿触发</span><br><span class="line">        vdd-supply &#x3D; &lt;&amp;vdd_3v3&gt;; &#x2F;&#x2F; 电源</span><br><span class="line">        gpios &#x3D; &lt;&amp;gpio2 3 GPIO_ACTIVE_HIGH&gt;; &#x2F;&#x2F; GPIO2_3，用于控制设备状态</span><br><span class="line">    &#125;;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>设备树解析<br>compatible：”mycompany,my-sensor”，用于匹配驱动。<br>reg：I2C 设备的地址为 0x50。<br>interrupt-parent：中断控制器是 gpio1。<br>interrupts：中断引脚是 gpio1 的第 5 个引脚，触发方式为上升沿。<br>vdd-supply：设备的电源由 vdd_3v3 提供。<br>gpios：设备的控制引脚是 gpio2 的第 3 个引脚，高电平有效。</p><p><strong>驱动（.c）</strong><br>驱动通过设备树获取硬件信息，并初始化设备。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br></pre></td><td class="code"><pre><span class="line">#include &lt;linux&#x2F;module.h&gt;</span><br><span class="line">#include &lt;linux&#x2F;i2c.h&gt;</span><br><span class="line">#include &lt;linux&#x2F;gpio&#x2F;consumer.h&gt;</span><br><span class="line">#include &lt;linux&#x2F;interrupt.h&gt;</span><br><span class="line">#include &lt;linux&#x2F;of.h&gt;</span><br><span class="line">#include &lt;linux&#x2F;regulator&#x2F;consumer.h&gt;</span><br><span class="line"></span><br><span class="line">struct my_sensor_data &#123;</span><br><span class="line">    struct i2c_client *client;</span><br><span class="line">    struct gpio_desc *ctrl_gpio;</span><br><span class="line">    struct regulator *vdd;</span><br><span class="line">    int irq;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">static irqreturn_t my_sensor_interrupt(int irq, void *dev_id) &#123;</span><br><span class="line">    printk(&quot;Interrupt triggered!\n&quot;);</span><br><span class="line">    &#x2F;&#x2F; 处理中断事件</span><br><span class="line">    return IRQ_HANDLED;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">static int my_sensor_probe(struct i2c_client *client, const struct i2c_device_id *id) &#123;</span><br><span class="line">    struct device *dev &#x3D; &amp;client-&gt;dev;</span><br><span class="line">    struct my_sensor_data *data;</span><br><span class="line">    int ret;</span><br><span class="line"></span><br><span class="line">    &#x2F;&#x2F; 分配设备数据结构</span><br><span class="line">    data &#x3D; devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);</span><br><span class="line">    if (!data)</span><br><span class="line">        return -ENOMEM;</span><br><span class="line"></span><br><span class="line">    data-&gt;client &#x3D; client;</span><br><span class="line"></span><br><span class="line">    &#x2F;&#x2F; 获取 GPIO 控制引脚</span><br><span class="line">    data-&gt;ctrl_gpio &#x3D; devm_gpiod_get(dev, NULL, GPIOD_OUT_LOW);</span><br><span class="line">    if (IS_ERR(data-&gt;ctrl_gpio)) &#123;</span><br><span class="line">        dev_err(dev, &quot;Failed to get control GPIO\n&quot;);</span><br><span class="line">        return PTR_ERR(data-&gt;ctrl_gpio);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    &#x2F;&#x2F; 获取电源</span><br><span class="line">    data-&gt;vdd &#x3D; devm_regulator_get(dev, &quot;vdd&quot;);</span><br><span class="line">    if (IS_ERR(data-&gt;vdd)) &#123;</span><br><span class="line">        dev_err(dev, &quot;Failed to get regulator\n&quot;);</span><br><span class="line">        return PTR_ERR(data-&gt;vdd);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    &#x2F;&#x2F; 使能电源</span><br><span class="line">    ret &#x3D; regulator_enable(data-&gt;vdd);</span><br><span class="line">    if (ret) &#123;</span><br><span class="line">        dev_err(dev, &quot;Failed to enable regulator\n&quot;);</span><br><span class="line">        return ret;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    &#x2F;&#x2F; 获取中断号</span><br><span class="line">    data-&gt;irq &#x3D; gpiod_to_irq(data-&gt;ctrl_gpio);</span><br><span class="line">    if (data-&gt;irq &lt; 0) &#123;</span><br><span class="line">        dev_err(dev, &quot;Failed to get IRQ number\n&quot;);</span><br><span class="line">        return data-&gt;irq;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    &#x2F;&#x2F; 注册中断处理函数</span><br><span class="line">    ret &#x3D; devm_request_irq(dev, data-&gt;irq, my_sensor_interrupt,</span><br><span class="line">                           IRQF_TRIGGER_RISING, &quot;my-sensor&quot;, data);</span><br><span class="line">    if (ret) &#123;</span><br><span class="line">        dev_err(dev, &quot;Failed to request IRQ\n&quot;);</span><br><span class="line">        return ret;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    &#x2F;&#x2F; 初始化设备</span><br><span class="line">    gpiod_set_value(data-&gt;ctrl_gpio, 1); &#x2F;&#x2F; 设置 GPIO 为高电平</span><br><span class="line">    printk(&quot;Sensor initialized!\n&quot;);</span><br><span class="line"></span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">static int my_sensor_remove(struct i2c_client *client) &#123;</span><br><span class="line">    struct my_sensor_data *data &#x3D; i2c_get_clientdata(client);</span><br><span class="line"></span><br><span class="line">    &#x2F;&#x2F; 关闭电源</span><br><span class="line">    regulator_disable(data-&gt;vdd);</span><br><span class="line"></span><br><span class="line">    &#x2F;&#x2F; 设置 GPIO 为低电平</span><br><span class="line">    gpiod_set_value(data-&gt;ctrl_gpio, 0);</span><br><span class="line"></span><br><span class="line">    printk(&quot;Sensor removed!\n&quot;);</span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">static const struct of_device_id my_sensor_of_match[] &#x3D; &#123;</span><br><span class="line">    &#123; .compatible &#x3D; &quot;mycompany,my-sensor&quot; &#125;,</span><br><span class="line">    &#123; &#125;</span><br><span class="line">&#125;;</span><br><span class="line">MODULE_DEVICE_TABLE(of, my_sensor_of_match);</span><br><span class="line"></span><br><span class="line">static struct i2c_driver my_sensor_driver &#x3D; &#123;</span><br><span class="line">    .probe &#x3D; my_sensor_probe,</span><br><span class="line">    .remove &#x3D; my_sensor_remove,</span><br><span class="line">    .driver &#x3D; &#123;</span><br><span class="line">        .name &#x3D; &quot;my-sensor&quot;,</span><br><span class="line">        .of_match_table &#x3D; my_sensor_of_match,</span><br><span class="line">    &#125;,</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">module_i2c_driver(my_sensor_driver);</span><br><span class="line"></span><br><span class="line">MODULE_LICENSE(&quot;GPL&quot;);</span><br><span class="line">MODULE_AUTHOR(&quot;Your Name&quot;);</span><br><span class="line">MODULE_DESCRIPTION(&quot;My Sensor Driver&quot;);</span><br></pre></td></tr></table></figure><p><strong>驱动解析设备树的过程</strong><br>匹配设备：<br>驱动通过 of_device_id 中的 compatible 属性与设备树中的节点匹配。<br>匹配成功后，调用 probe 函数。</p><p>获取 GPIO：<br>使用 devm_gpiod_get 从设备树中获取 GPIO 控制引脚。</p><p>获取电源：<br>使用 devm_regulator_get 从设备树中获取电源。</p><p>获取中断：<br>使用 gpiod_to_irq 将 GPIO 引脚转换为中断号。<br>使用 devm_request_irq 注册中断处理函数。</p><p>初始化设备：<br>设置 GPIO 引脚状态。<br>使能电源。</p><p><strong>总结</strong><br>设备树 描述了硬件的详细信息（如 I2C 地址、GPIO 引脚、中断号等）。<br>驱动 通过内核提供的 API（如 devm_gpiod_get、devm_regulator_get、gpiod_to_irq 等）解析设备树中的信息，并初始化硬件。<br>设备树和驱动共同协作，完成硬件的配置和管理。<br>通过这个复杂一点的例子，可以更清楚地看到设备树和驱动如何配合工作，实现硬件的识别、解析和处理。</p><h2 id="dts和硬件层的衔接"><a href="#dts和硬件层的衔接" class="headerlink" title="dts和硬件层的衔接"></a>dts和硬件层的衔接</h2><p>dts文件，靠软件层衔接的是驱动，那么另一层次呢？靠近硬件那一层和谁是关联（或者什么文档，也就是谁来决定dts的，或者dts应该根据谁来写类似这样的关联方）</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line">在Linux系统中，设备树（Device Tree）用于描述硬件平台的配置信息，特别是对于嵌入式系统。设备树的描述文件通常以&#96;.dts&#96;（Device Tree Source）格式存在，并通过设备树编译器（DTC）编译为二进制格式的&#96;.dtb&#96;（Device Tree Blob），供内核在启动时使用。</span><br><span class="line"></span><br><span class="line">### 设备树的两层关系：</span><br><span class="line">1. **软件层（驱动层）**：</span><br><span class="line">   - 设备树通过内核的设备树解析机制与驱动程序进行衔接。</span><br><span class="line">   - 内核会根据设备树中的节点信息，匹配对应的驱动程序，并初始化硬件设备。</span><br><span class="line">   - 驱动程序通过设备树接口（如&#96;of_*&#96;系列函数）从设备树中获取硬件配置信息。</span><br><span class="line"></span><br><span class="line">2. **硬件层**：</span><br><span class="line">   - 设备树描述的是硬件平台的配置，因此它需要与硬件的实际设计保持一致。</span><br><span class="line">   - 设备树的内容通常由硬件设计团队或硬件工程师提供，他们根据硬件的实际设计（如SoC芯片手册、外设连接方式等）来决定设备树的内容。</span><br><span class="line">   - 设备树的编写需要参考硬件的技术文档，如芯片手册（Datasheet）、参考设计（Reference Design）等。</span><br><span class="line"></span><br><span class="line">### 设备树的编写依据：</span><br><span class="line">- **硬件设计文档**：设备树的编写需要根据硬件设计文档来进行，这些文档包括：</span><br><span class="line">  - SoC芯片手册（Datasheet）：描述了芯片的寄存器、外设、中断等信息。</span><br><span class="line">  - 硬件原理图（Schematic）：描述了硬件平台的电路连接方式。</span><br><span class="line">  - 参考设计（Reference Design）：提供了标准的硬件配置和连接方式。</span><br><span class="line">  </span><br><span class="line">- **硬件工程师**：硬件工程师通常会根据硬件设计文档提供设备树的初始版本，或者与软件工程师合作完成设备树的编写。</span><br><span class="line"></span><br><span class="line">### 设备树的决定因素：</span><br><span class="line">- **硬件设计**：设备树的节点和属性必须与硬件设计一致，硬件设计决定了设备树的内容。</span><br><span class="line">- **内核支持**：内核的驱动程序需要能够识别和解析设备树中的节点和属性，因此设备树的编写也需要考虑内核的支持情况。</span><br><span class="line"></span><br><span class="line">### 设备树的维护：</span><br><span class="line">- **硬件团队**：负责提供硬件设计的更新信息，确保设备树与硬件设计一致。</span><br><span class="line">- **软件团队**：负责根据硬件设计更新设备树，并确保内核能够正确解析和使用设备树。</span><br><span class="line"></span><br><span class="line">总结来说，设备树的编写主要依赖于硬件设计文档和硬件工程师的输入，同时需要与内核的驱动支持保持兼容。硬件设计是设备树的最终决定因素，而软件层（内核和驱动）则是设备树的使用方。</span><br></pre></td></tr></table></figure><h2 id="举例-硬件和dts"><a href="#举例-硬件和dts" class="headerlink" title="举例_硬件和dts"></a>举例_硬件和dts</h2><p>硬件结构<br>1个双核<code>ARM Cortex-A9</code>32位处理器；<br>ARM本地总线上的内存映射区域分布有两个串口（分别位于<code>0x101F1000</code>和<code>0x101F2000</code>）<br><code>GPIO</code>控制器（位于<code>0x101F3000</code>）<br><code>SPI</code>控制器（位于<code>0x10170000</code>）<br>中断控制器（位于<code>0x10140000</code>）<br>外部总线桥上连接的设备如下：<br>SMC <code>SMC91111</code>以太网（位于<code>0x10100000</code>）<br><code>I2C</code>控制器（位于<code>0x10160000</code>）<br>64MB NOR Flash（位于<code>0x30000000</code>）<br>外部总线桥上连接的I2C控制器所对应的I2C总线上又连接了<code>Maxim DS1338</code>实时钟（I2C地址为<code>0x58</code>）<br>具体如下图所示；<br><img src="/images/20250220222820.png" alt=""></p><p>设备树dts文件<br>那么，如何将上面的硬件结构，通过设备树语言描述成<code>dts</code>文件呢？具体我实现在下图，并且做出了详细的解释。其中需要注意的有以下几个属性：</p><ul><li><code>compatitable</code>：兼容性属性；</li><li><code>#address-cells</code>,<code>#size-cells</code>：地址编码所采用的格式；</li><li><code>节点名称@节点地址</code>：例如<code>gpio@101f3000</code>，这里名称和地址要和实际的对应起来；</li><li><code>标签</code>：例如<code>interrupt-parent = &lt;&amp;intc&gt;;</code>，这这里的<code>intc</code>就是一个标签(label)，通过<code>&amp;</code>可以获取它的值，这里可以简单的理解成一个变量，然后在下面需要对这个标签进行另外的解析，例如<code>intc:interrupt-controller@10140000</code>；所以，这两个地方的<code>intc</code>都是对应起来的。<br>最后，具体的实现可以参考下图；<br><img src="/images/20250220222904.png" alt=""></li></ul><h2 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h2><p>设备树与驱动的关系、设备树参数的介绍:<a href="https://zhuanlan.zhihu.com/p/8598598018">https://zhuanlan.zhihu.com/p/8598598018</a><br>linux设备树dts文件详解：<a href="https://blog.csdn.net/weixin_42031299/article/details/125813060">https://blog.csdn.net/weixin_42031299/article/details/125813060</a><br>linux 驱动简单案例：<a href="https://www.cnblogs.com/han-guang-xue/p/15769229.html">https://www.cnblogs.com/han-guang-xue/p/15769229.html</a><br>在Linux下写一个简单的驱动程序:<a href="https://www.cnblogs.com/kn-zheng/p/17168166.html">https://www.cnblogs.com/kn-zheng/p/17168166.html</a><br>Linux 设备树语法（.dts）及如何从设备树获取节点信息：<a href="https://www.cnblogs.com/fortunely/p/16405592.html#a-of_get_property">https://www.cnblogs.com/fortunely/p/16405592.html#a-of_get_property</a><br>Linux dts 设备树详解(二) 动手编写设备树dts：<a href="https://blog.csdn.net/u010632165/article/details/91488811">https://blog.csdn.net/u010632165/article/details/91488811</a><br>Device Tree (一) - dts基本概念和语法：<a href="https://blog.csdn.net/u011456016/article/details/136665769">https://blog.csdn.net/u011456016/article/details/136665769</a><br>Linux driver dts使用，实例驱动编写：<a href="https://blog.csdn.net/songyulong8888/article/details/78115512">https://blog.csdn.net/songyulong8888/article/details/78115512</a></p>]]></content>
    
    <summary type="html">
    
      &lt;h2 id=&quot;一个设备树的全景视图&quot;&gt;&lt;a href=&quot;#一个设备树的全景视图&quot; class=&quot;headerlink&quot; title=&quot;一个设备树的全景视图&quot;&gt;&lt;/a&gt;一个设备树的全景视图&lt;/h2&gt;
    
    </summary>
    
    
      <category term="08领域技术" scheme="https://hexo.yuanjh.cn/categories/08%E9%A2%86%E5%9F%9F%E6%8A%80%E6%9C%AF/"/>
    
      <category term="g芯片相关" scheme="https://hexo.yuanjh.cn/categories/08%E9%A2%86%E5%9F%9F%E6%8A%80%E6%9C%AF/g%E8%8A%AF%E7%89%87%E7%9B%B8%E5%85%B3/"/>
    
    
      <category term="08领域技术/g芯片相关/基础知识" scheme="https://hexo.yuanjh.cn/tags/08%E9%A2%86%E5%9F%9F%E6%8A%80%E6%9C%AF-g%E8%8A%AF%E7%89%87%E7%9B%B8%E5%85%B3-%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/"/>
    
  </entry>
  
  <entry>
    <title>基础知识_04SDK层编解码</title>
    <link href="https://hexo.yuanjh.cn/hexo/7f00ff3f/"/>
    <id>https://hexo.yuanjh.cn/hexo/7f00ff3f/</id>
    <published>2024-12-10T00:06:34.000Z</published>
    <updated>2026-03-11T16:45:17.859Z</updated>
    
    <content type="html"><![CDATA[<h2 id="RAW-BMP-PNG-JPG"><a href="#RAW-BMP-PNG-JPG" class="headerlink" title="RAW,BMP,PNG,JPG"></a>RAW,BMP,PNG,JPG</h2><p>常见图片格式基本知识及转换、显示工具:<a href="https://blog.csdn.net/sjnjab/article/details/134507551">https://blog.csdn.net/sjnjab/article/details/134507551</a><br>矢量图、位图、RGB、YUV、JPEG、PNG的理解：<a href="https://blog.csdn.net/kcstrong/article/details/81705693">https://blog.csdn.net/kcstrong/article/details/81705693</a><br>【FPGA图像处理实战】- YUV444与YUV422互转：<a href="https://fpga.eetrend.com/blog/2024/100579119.html">https://fpga.eetrend.com/blog/2024/100579119.html</a></p><h3 id="BMP-PNG-JPG"><a href="#BMP-PNG-JPG" class="headerlink" title="BMP,PNG,JPG"></a>BMP,PNG,JPG</h3><p>JPG：使用一种失真的压缩标准算法，可以选择压缩率，默认的压缩率在70%左右。一张图片在多次压缩解压后，会肉眼可见地失真。<br>PNG：无损数据压缩格式，包含8位、24位、32位三种格式，32位支持透明形式（多了8bits透明度alpha）。<br>BMP：原始图像数据，一般有header标识数据的存储结构。<br>同一张图片三种格式的占用空间:BMP&gt;PNG&gt;JPG</p><h3 id="raw原始数据文件"><a href="#raw原始数据文件" class="headerlink" title="raw原始数据文件"></a>raw原始数据文件</h3><p>raw原始pixel数据文件主要包含RGB和YUV两种数据格式，这两种数据格式的相关介绍很多，这里不再赘述。RGB包含RGB565，RGB888，ARGB8888，ABGR8888等，YUV包含YUV444，YUV422，YUV420等。<br>YUV的存储方式包含packed和planner两种方式。<br>packed：连续存储Y分量，然后依次交叉存储UV分量，常见的有NV12，NV21等；<br>planner：连续存储Y分量，然后再连续存储U分量（或V分量），最后存储V分量（或U分量）,常见的有I420，YV12等。</p><h2 id="RGB-YUV"><a href="#RGB-YUV" class="headerlink" title="RGB,YUV"></a>RGB,YUV</h2><h3 id="YUV的优势"><a href="#YUV的优势" class="headerlink" title="YUV的优势"></a>YUV的优势</h3><p>便于压缩编码。RGB表示的每种颜色都是由红光、绿光、蓝光组合而成的，我们分别使用R、G、B三个分量来表示红光、绿光、蓝光，<strong>每个像素的三个分量之间存在着相关性。所以通常会把RGB转换成YUV进行压缩</strong>。<br>数据量相对RGB来说更小。前面我们有分析过，同样分辨率的图像，YUV444存储的数据量与RGB相同，但YUV422和YUV420却只需要存储RGB的数据量的 2/3 和 1/2 。<br>能够兼容老式黑白电视。Y分量单独显示是其实就是黑白图像，因此YUV由彩色转黑白只需要去除UV相关的数据就可以了。</p><h3 id="YUV与RGB之间的转换"><a href="#YUV与RGB之间的转换" class="headerlink" title="YUV与RGB之间的转换"></a>YUV与RGB之间的转换</h3><p>YUV与RGB之间的转换是存在标准的，常见的标准有：</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">ITU-R BT.601（标清）</span><br><span class="line">ITU-R BT.709（高清）</span><br><span class="line">ITU-R BT.2020（超高清）。</span><br></pre></td></tr></table></figure><p>不同的标准有不同的准换公式，同时还要<strong>区分不同的Color Range</strong>。<br>Color Range用于指定RGB分量的取值范围，可分为Full Range（取值范围为0<del>255）和Limited Range（取值范围为16</del>235）。</p><h3 id="yuv444-422-420"><a href="#yuv444-422-420" class="headerlink" title="yuv444,422,420"></a>yuv444,422,420</h3><p>以黑点表示采样该像素点的Y分量，以空心圆圈表示采用该像素点的UV分量，如下图所示。<br>4:4:4 表示不降低色度（UV）通道的采样率。每个 Y 分量对应一组 UV 分量。<br>4:2:2 表示 2:1 水平下采样，没有垂直下采样。每两个 Y 分量共享一组 UV 分量。<br>4:2:0 表示 2:1 水平下采样，同时 2:1 垂直下采样。每四个 Y 分量共享一组 UV 分量。</p><p><img src="/images/20241113004111.png" alt=""></p><h3 id="YUV420-YUV420P-YUV420SP-NV12-NV21"><a href="#YUV420-YUV420P-YUV420SP-NV12-NV21" class="headerlink" title="YUV420,YUV420P,YUV420SP(,NV12,NV21)"></a>YUV420,YUV420P,YUV420SP(,NV12,NV21)</h3><p>常见的基于 YUV 4:2:0 采样的格式如下表：<br><img src="/images/Pasted%20image%2020241204235115.png" alt=""><br>基于 YUV 4:2:0 采样的格式主要有 YUV 420P 和 YUV 420SP 两种类型，每个类型又对应其他具体格式。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">YUV 420P 类型</span><br><span class="line">YU12 格式</span><br><span class="line">YV12 格式</span><br><span class="line">YUV 420SP 类型</span><br><span class="line">NV12 格式</span><br><span class="line">NV21 格式</span><br></pre></td></tr></table></figure><p>YUV 420P 和 YUV 420SP 都是基于 Planar 平面格式 进行存储的，先存储所有的 Y 分量后， YUV420P 类型就会先存储所有的 U 分量或者 V 分量，而 YUV420SP 则是按照 UV 或者 VU 的交替顺序进行存储了，具体查看看下图</p><h4 id="YUV420P-和YUV420SP"><a href="#YUV420P-和YUV420SP" class="headerlink" title="YUV420P 和YUV420SP"></a>YUV420P 和YUV420SP</h4><p>YUV420P 的格式：<br><img src="/images/20241204235328.png" alt=""><br>其在码流中的表现形式为：<br><img src="/images/20241204235334.png" alt=""><br>YUV420SP的格式：<br><img src="/images/20241204235404.png" alt=""></p><p>其在码流中的表现形式为：<br><img src="/images/20241204235412.png" alt=""></p><h4 id="YU12和YV12格式"><a href="#YU12和YV12格式" class="headerlink" title="YU12和YV12格式"></a>YU12和YV12格式</h4><p>YU12 和 YV12 格式都属于 <strong>YUV 420P</strong> 类型，即先存储 Y 分量，再存储 U、V 分量，区别在于：YU12 是先 Y 再 U 后 V，而 YV12 是先 Y 再 V 后 U 。YV 12 的存储格式如下图所示：<br><img src="/images/20241204235449.png" alt=""><br>YU 12 又称作 I420 格式，它的存储格式就是把 V 和 U 反过来了。</p><h4 id="NV12和NV21格式"><a href="#NV12和NV21格式" class="headerlink" title="NV12和NV21格式"></a>NV12和NV21格式</h4><p>NV12 和 NV21 格式都属于 YUV420SP 类型。它也是先存储了 Y 分量，但接下来并不是再存储所有的 U 或者 V 分量，而是把 UV 分量交替连续存储。<br><img src="/images/20241204235541.png" alt=""><br>需要注意的是，<br>NV12是iOS中有的模式，它的存储顺序是先存Y分量，再YV进行交替存储。<br>NV21是Android中有的模式，它的存储顺序是先存Y分量，再VU交替存储。</p><h2 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h2><p>视频图像格式 NV21-NV12-YUV420P 的区别:<a href="https://blog.csdn.net/linda012518/article/details/106636942">https://blog.csdn.net/linda012518/article/details/106636942</a><br>音视频编解码: YUV存储格式中的YUV420P,YUV420SP,NV12, NV21理解(转):<a href="https://www.cnblogs.com/yongdaimi/p/10696214.html">https://www.cnblogs.com/yongdaimi/p/10696214.html</a></p>]]></content>
    
    <summary type="html">
    
      &lt;h2 id=&quot;RAW-BMP-PNG-JPG&quot;&gt;&lt;a href=&quot;#RAW-BMP-PNG-JPG&quot; class=&quot;headerlink&quot; title=&quot;RAW,BMP,PNG,JPG&quot;&gt;&lt;/a&gt;RAW,BMP,PNG,JPG&lt;/h2&gt;
    
    </summary>
    
    
      <category term="08领域技术" scheme="https://hexo.yuanjh.cn/categories/08%E9%A2%86%E5%9F%9F%E6%8A%80%E6%9C%AF/"/>
    
      <category term="g芯片相关" scheme="https://hexo.yuanjh.cn/categories/08%E9%A2%86%E5%9F%9F%E6%8A%80%E6%9C%AF/g%E8%8A%AF%E7%89%87%E7%9B%B8%E5%85%B3/"/>
    
    
      <category term="08领域技术/g芯片相关/基础知识" scheme="https://hexo.yuanjh.cn/tags/08%E9%A2%86%E5%9F%9F%E6%8A%80%E6%9C%AF-g%E8%8A%AF%E7%89%87%E7%9B%B8%E5%85%B3-%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/"/>
    
  </entry>
  
  <entry>
    <title>基础知识_03系统接口API</title>
    <link href="https://hexo.yuanjh.cn/hexo/157c1877/"/>
    <id>https://hexo.yuanjh.cn/hexo/157c1877/</id>
    <published>2024-12-01T00:49:09.000Z</published>
    <updated>2026-03-11T16:45:17.859Z</updated>
    
    <content type="html"><![CDATA[<h2 id="V4L2"><a href="#V4L2" class="headerlink" title="V4L2"></a>V4L2</h2><p>V4L2全称video for linux 2，是linux系统之中用于处理视频设备的内核驱动程序接口。它提供了一种标准化的方式，使用户空间程序能够与视频设备（e.g. 摄像头、视频采集卡等）进行通信和交互。<br><strong>understanding：就是屏蔽掉底层摄像头的不同驱动实现，提供给用户空间统一的接口调用</strong><br>工作原理：在linux系统中<strong>所有的外设都被看成是一种特殊的文件</strong>，V4L2将一个视频采集设备以一个文件描述符给到用户空间。在V4L2的封装下，其支持三种方式来采集图像，<strong>内存映射方式（mmap）、直接读取方式（read）、用户指针</strong>。其中，<strong>read方式需要大量的复制操作，带来开销；用户指针方式对驱动工作较难，故一般采用mmap方式</strong>。此外，V4L2的一些重要数据结构都在#include&lt;linux/videodev2.h&gt;文件中进行定义（linux系统在内核编译阶段可以配置集成V4L2的能力）</p><p>V4L2的buffer管理是通过videobuf2来完成的，他充当用户空间和驱动之间的中间件，提供模块化的内存管理功能。<br>videobuf2其中主要包含以下数据结构：</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">vb2_queue：用于描述buffer的队列，描述buffer节点以及buffer的入队与出队</span><br><span class="line">vb2_buf_ops：buffer操作集</span><br><span class="line">vb2_mem_ops：内存buffer分配函数接口</span><br><span class="line">vb2_ops：vb2队列操作函数集</span><br></pre></td></tr></table></figure><p>其buffer的循环流程如下图</p><p><img src="/images/20241205001759.png" alt=""><br>V4L2的API以及操作主要包括<br><img src="/images/20241205001827.png" alt=""></p><h2 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h2><p>V4L2学习理解：<a href="https://zhuanlan.zhihu.com/p/668015169">https://zhuanlan.zhihu.com/p/668015169</a><br>v4l2应用程序接口：<a href="https://blog.csdn.net/weixin_68782273/article/details/126827820">https://blog.csdn.net/weixin_68782273/article/details/126827820</a></p><p>ffmpeg从v4l2获取frame数据：<br>FFMPEG（二） v4l2 数据格式装换：<a href="https://blog.csdn.net/li_wen01/article/details/67631687">https://blog.csdn.net/li_wen01/article/details/67631687</a><br>v4l2采集视频：<a href="https://blog.csdn.net/weixin_43147845/article/details/136899272">https://blog.csdn.net/weixin_43147845/article/details/136899272</a></p>]]></content>
    
    <summary type="html">
    
      &lt;h2 id=&quot;V4L2&quot;&gt;&lt;a href=&quot;#V4L2&quot; class=&quot;headerlink&quot; title=&quot;V4L2&quot;&gt;&lt;/a&gt;V4L2&lt;/h2&gt;
    
    </summary>
    
    
      <category term="08领域技术" scheme="https://hexo.yuanjh.cn/categories/08%E9%A2%86%E5%9F%9F%E6%8A%80%E6%9C%AF/"/>
    
      <category term="g芯片相关" scheme="https://hexo.yuanjh.cn/categories/08%E9%A2%86%E5%9F%9F%E6%8A%80%E6%9C%AF/g%E8%8A%AF%E7%89%87%E7%9B%B8%E5%85%B3/"/>
    
    
      <category term="08领域技术/g芯片相关/基础知识" scheme="https://hexo.yuanjh.cn/tags/08%E9%A2%86%E5%9F%9F%E6%8A%80%E6%9C%AF-g%E8%8A%AF%E7%89%87%E7%9B%B8%E5%85%B3-%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/"/>
    
  </entry>
  
  <entry>
    <title>基础知识_02内核kernel和驱动</title>
    <link href="https://hexo.yuanjh.cn/hexo/0b2d2c1f/"/>
    <id>https://hexo.yuanjh.cn/hexo/0b2d2c1f/</id>
    <published>2024-12-01T00:37:39.000Z</published>
    <updated>2026-03-11T16:45:17.859Z</updated>
    
    <content type="html"><![CDATA[<h2 id="linux-kernel中如何添加-编译驱动"><a href="#linux-kernel中如何添加-编译驱动" class="headerlink" title="linux kernel中如何添加/编译驱动"></a>linux kernel中如何添加/编译驱动</h2><h3 id="驱动源码-固定pattern-略"><a href="#驱动源码-固定pattern-略" class="headerlink" title="驱动源码(固定pattern,略)"></a>驱动源码(固定pattern,略)</h3><h3 id="方法一：整编内核"><a href="#方法一：整编内核" class="headerlink" title="方法一：整编内核"></a>方法一：整编内核</h3><p>01，源码复制到特目录：demo_driver.c程序拷贝到…/linux-2.6.32.2/drivers/char目录下<br>02，增加编译选项，触发新增源码的编译，修改…/linux-2.6.32.2/drivers/char目录下Makefile文件，在Makefile中增加如下代码：</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">obj-m +&#x3D; demo_driver.o</span><br></pre></td></tr></table></figure><p>03,启动内核编译 ，回到linux内核源码根目下…/linux-2.6.32.2 ，执行编译指令</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">make</span><br></pre></td></tr></table></figure><p>等待内核编译约20分钟…<br>最终得到demo_driver.ko<br><img src="/images/20241205003212.png" alt=""></p><p>整编内核的模式示意图如下：<br><img src="/images/20241205003241.png" alt=""></p><h3 id="方法二：单编ko"><a href="#方法二：单编ko" class="headerlink" title="方法二：单编ko"></a>方法二：单编ko</h3><p>01,make modules 指令为编译内核模块指令：该指令的功能是编译内核中所有配置为模块的程序得到模块ko文件，make modules 命令只能在内核源码顶层目录下执行。<br><img src="/images/20241205003330.png" alt=""><br>make modules是编译所有的内核模块，如何单独编译一个指定的模块呢？加M参数</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">make  M&#x3D;DIR modules</span><br></pre></td></tr></table></figure><p>“M=”参数的作用是以内核源码为基础编译一个外部模块。<strong>命令中“M=DIR”，程序会自动跳转到所指定的DIR目录中查找模块源码，编译生成ko文件</strong>。</p><p>02：编写Makefile： 单编KO的Makefile文件如下：</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"># .PHONY来显示地指明main clean是伪目标</span><br><span class="line">.PHONY:    main  clean</span><br><span class="line"></span><br><span class="line"># 定义了KERNELDIR ，PWD ，CROSS_ARCH 三个变量。</span><br><span class="line">KERNELDIR   :&#x3D;   &#x2F;home&#x2F;liwei&#x2F;v3_work&#x2F;project&#x2F;linux-2.6.32.2</span><br><span class="line">PWD   :&#x3D;   $(shell pwd)</span><br><span class="line">CROSS_ARCH :&#x3D; &#x2F;home&#x2F;liwei&#x2F;v3_work&#x2F;tools&#x2F;arm-linux-gcc-4.4.3&#x2F;opt&#x2F;FriendlyARM&#x2F;toolschain&#x2F;4.4.3&#x2F;bin&#x2F;arm-linux-gcc</span><br><span class="line"></span><br><span class="line"># 指定将demo_driver.c编译成demo_driver.ko文件。</span><br><span class="line">obj-m   +&#x3D;   demo_driver.o</span><br><span class="line"></span><br><span class="line"># main:是第一个伪目标，也就是默认目标</span><br><span class="line">main: </span><br><span class="line">$(MAKE) $(CROSS_ARCH) -C  $(KERNELDIR)   M&#x3D;$(PWD)   modules </span><br><span class="line"></span><br><span class="line"># clean是执行清除工作的伪目标。</span><br><span class="line">clean: </span><br><span class="line">rm   -rf   *.o   *~   core   .depend   .*.cmd   *.ko   *.mod.c   .tmp_versions *.symvers *.d *.markers *.order</span><br></pre></td></tr></table></figure><ul><li>$(MAKE) 为make</li><li>$(CROSS_ARCH) 为指定的编译工具</li><li>-C (KERNELDIR) 选项的作用是将工作目录转移到指定的KERNELDIR位置</li><li>-M=(PWD) modules ，作用是以内核源码为基础编译一个外部模块<br>将demo_driver.c和上述的Makefile文件放在同一个目录下（路径为任何路径，不需要一定放在内核目录中），执行make指令。</li></ul><p><img src="/images/20241205003622.png" alt=""><br>大约3秒钟，编译得到demo_driver.ko文件，<strong>单编KO的优势就是快</strong>（3秒钟）<br>最终得到了demo_driver.ko文件，我们将文件传输到开发板中并测试驱动ko文件。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">执行加载驱动：insmod demo_driver.ko </span><br><span class="line">查看驱动设备：cat &#x2F;proc&#x2F;devices</span><br></pre></td></tr></table></figure><p>单编KO的模式如下：<br><img src="/images/20241205003734.png" alt=""></p><h2 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h2><p>debian环境 源码如何编译为ko 驱动<br>【转】如何编译linux驱动ko：<a href="https://blog.csdn.net/weixin_45264425/article/details/130394724">https://blog.csdn.net/weixin_45264425/article/details/130394724</a><br>Linux编译ko文件详细教程 (linux 怎么编译ko文件):<a href="https://www.idc.net/help/123153/">https://www.idc.net/help/123153/</a><br>Linux 内核模块ko在内核源码外部编译的方法：<a href="https://blog.csdn.net/m0_67686953/article/details/128952347">https://blog.csdn.net/m0_67686953/article/details/128952347</a><br>Linux编译内核模块生成.KO驱动示例:<a href="https://blog.csdn.net/u011436603/article/details/138486727">https://blog.csdn.net/u011436603/article/details/138486727</a><br>在kernel中添加自定义驱动、无线网卡/声卡的配置：<a href="https://blog.csdn.net/weixin_38019025/article/details/103966224">https://blog.csdn.net/weixin_38019025/article/details/103966224</a><br>12-如何向Linux内核添加新的设备驱动：<a href="https://blog.csdn.net/weixin_42135087/article/details/139903669">https://blog.csdn.net/weixin_42135087/article/details/139903669</a></p>]]></content>
    
    <summary type="html">
    
      &lt;h2 id=&quot;linux-kernel中如何添加-编译驱动&quot;&gt;&lt;a href=&quot;#linux-kernel中如何添加-编译驱动&quot; class=&quot;headerlink&quot; title=&quot;linux kernel中如何添加/编译驱动&quot;&gt;&lt;/a&gt;linux kernel中如何添加/编译驱动&lt;/h2&gt;
    
    </summary>
    
    
      <category term="08领域技术" scheme="https://hexo.yuanjh.cn/categories/08%E9%A2%86%E5%9F%9F%E6%8A%80%E6%9C%AF/"/>
    
      <category term="g芯片相关" scheme="https://hexo.yuanjh.cn/categories/08%E9%A2%86%E5%9F%9F%E6%8A%80%E6%9C%AF/g%E8%8A%AF%E7%89%87%E7%9B%B8%E5%85%B3/"/>
    
    
      <category term="08领域技术/g芯片相关/基础知识" scheme="https://hexo.yuanjh.cn/tags/08%E9%A2%86%E5%9F%9F%E6%8A%80%E6%9C%AF-g%E8%8A%AF%E7%89%87%E7%9B%B8%E5%85%B3-%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/"/>
    
  </entry>
  
  <entry>
    <title>基础知识_01硬件接口和协议</title>
    <link href="https://hexo.yuanjh.cn/hexo/fc76085e/"/>
    <id>https://hexo.yuanjh.cn/hexo/fc76085e/</id>
    <published>2024-12-01T00:05:39.000Z</published>
    <updated>2026-03-11T16:45:17.859Z</updated>
    
    <content type="html"><![CDATA[<h2 id="M-2-PCIE-SATA-NVME-AHCI及区别和联系"><a href="#M-2-PCIE-SATA-NVME-AHCI及区别和联系" class="headerlink" title="M.2,PCIE,SATA,NVME,AHCI及区别和联系"></a>M.2,PCIE,SATA,NVME,AHCI及区别和联系</h2><p>关系图<br><img src="/images/20241205000108.png" alt=""><br>需要注意的是上图中：pcie，sata既是总线，其实也是接口（所以下部的接口图中，其实是少了pcie的，借用别人的图，意思大致理解就行）</p><p>M.2，U.2，AIC，Half slim，mSATA，2.5in等这些指的是SSD形态（尺寸），是根据不同的应用场景进行设计。<br>PCIe，SATA和SAS指的是SSD接口的形态，即数据传输通路，接口不同传输速率不同，即每秒能传输的数据量不同。<br>NVMe，AHCI是应用于数据传输通路上的协议。其中由于NVMe协议允许多队列，并且队列深度高，可以同时并行在多个数据传输通路上进行数据传输，可以更好地利用PCIe多通道的性能。AHCI只允许单队列，并且队列深度低，一次只能发送一个通道的数据，传输速率低。</p><p>简单理解：(物理)接口(M2,U2,AIC)=》总线(PCIe，SATA)=》协议(NVMe，AHCI)<br>其中pcie和nvme高度相关，SAta和AHCI高度相关，</p><h3 id="总线-通道-标准：SATA与PCIe"><a href="#总线-通道-标准：SATA与PCIe" class="headerlink" title="总线(通道)标准：SATA与PCIe"></a>总线(通道)标准：SATA与PCIe</h3><p>实际上，SATA与PCIe既可以说是总线（通道）标准，也可以说是接口。<br>当SATA和PCIe作为总线（通道）标准时，可以理解为它们就是数据走的通道或者“路”，数据是通过这个“通道”传输至固态硬盘存储区或者是PC端的。二者的区别是SATA“窄”/PCIe“宽”，因此使用PCIe的固态硬盘要比SATA固态硬盘数据传输要快得多，目前主流SSD使用的也是PCIe总线（通道）标准。</p><p><strong>PCIe和SATA是两种不同的接口标准</strong>，二者的本质的区别是通信架构的不同，PCIe属于全双工模式，而SATA是半双工模式。<br>简单的来说，全双工模式允许数据双向传输，而半双工模式只允许数据单向传输。全双工模式传输的优势就是传输速度快，延迟低。<br>从系统架构上来说，PCIe比SATA要简单。PCIe SSD硬盘在直接连在CPU上，不过，准确的来说，是CPU的小蜜，Root Complex。CPU作为系统的大脑，事务繁忙，日理万机。RC端帮助CPU处理与设备之间的交互。<br><strong>PCIE和SATA当然有自己的插槽形硬件接口</strong>，但现在都<strong>普遍用M.2接口，兼容PCIE和SATA</strong>，M.2接口一般金手指结构，金手指一般指内存条的金黄色导电触片。<br>与<strong>SATA接口(总线)对接系统接口AHCI(协议)不同，PCIe接口(总线)上层对接的系统接口标准是NVMe(协议)</strong>。NVMe与AHCI相比，具有很多的优势。延迟低，最大支持64K队列，命令执行更简单等等。这些优势存在让PCIe是如鱼得水。带NVMe的带领下，PCIe SSD拥有的更快的速度，更低的延迟。</p><h3 id="传输协议：NVMe与AHCI"><a href="#传输协议：NVMe与AHCI" class="headerlink" title="传输协议：NVMe与AHCI"></a>传输协议：NVMe与AHCI</h3><p>如果说SATA和PCIe是传输数据的“路”，那么NVMe与AHCI就是保证“路”有秩序的交通规则，同样也是固态硬盘性能和速度的保证。<strong>关系上传输协议与通道标准是一一对应的，AHCI对应SATA、NVMe对应PCIe</strong>（<strong>PCIe通道实际上是可以采用AHCI协议的</strong>，但是此类产品市面上几乎没有了）。<br>AHCI无法很好地为采用高速PCIe通道的SSD提供服务，因此针对PCIe通道设计了NVMe传输协议，专为PCIe的SSD服务。目前NVMe已经升级到1.3、1.4版本，低延迟、高性能。<br>总结一下，SATA和PCIe是传输数据的“路”，SATA（1.0、2.0、3.0）与PCIe（M.2、U.2、AIC）是物理接口，而NVMe与AHCI则是“交通规则”。</p><p>NVMe，AHCI是应用于数据传输通路上的协议。<strong>其中由于NVMe协议允许多队列，并且队列深度高，可以同时并行在多个数据传输通路上进行数据传输，可以更好地利用PCIe多通道的性能。AHCI只允许单队列，并且队列深度低，一次只能发送一个通道的数据，传输速率低</strong>。</p><h2 id="sata-msata-m2-pcie物理形态"><a href="#sata-msata-m2-pcie物理形态" class="headerlink" title="sata,msata,m2,pcie物理形态"></a>sata,msata,m2,pcie物理形态</h2><p><img src="/images/20250420130858.png" alt=""></p><h2 id="接口性能-速度是否满足的计算样例"><a href="#接口性能-速度是否满足的计算样例" class="headerlink" title="接口性能/速度是否满足的计算样例"></a>接口性能/速度是否满足的计算样例</h2><p>问题：已知有一个sdi转接pcie的设备，通过pcie取得nv12格式的sdi原始视频raw数据，1080p@60fps，,pcie gen2.0 x4(4通道)是否可以支撑这个传输需求，请给出计算步骤</p><p><strong>01，计算视频数据带宽（NV12 格式）​​</strong><br>​​NV12 是 YUV 4:2:0 格式，每个像素占用 ​​1.5 字节​​（Y 分量 1 字节，UV 分量共 0.5 字节）。<br>​​分辨率​​：1920 × 1080（1080p）<br>​​帧率​​：60 FPS</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">​​计算单帧数据量​​:单帧数据量&#x3D;宽度×高度×每像素字节数</span><br><span class="line">&#x3D;1920×1080×1.5字节</span><br><span class="line">&#x3D;3,110,400字节≈2.97MB</span><br><span class="line">​​计算每秒数据量（带宽需求）​​</span><br><span class="line">带宽&#x3D;单帧数据量×帧率</span><br><span class="line">&#x3D;2.97MB×60FPS</span><br><span class="line">&#x3D;178.2MB&#x2F;s</span><br><span class="line">​​换算成比特率（bit&#x2F;s）：​​</span><br><span class="line">178.2MB&#x2F;s×8&#x3D;1,425.6Mbps</span><br></pre></td></tr></table></figure><p><strong>02，计算 PCIe Gen2.0 x4 的理论带宽​​</strong><br>​​<img src="/images/20250420132519.png" alt=""><br><strong>带宽对比</strong>​​</p><table><thead><tr><th>项目</th><th>计算值</th><th>单位</th></tr></thead><tbody><tr><td>​<strong>​NV12 1080p@60fps 带宽​</strong>​</td><td>1,425.6</td><td>Mbps</td></tr><tr><td>​<strong>​PCIe Gen2.0 x4 带宽​</strong>​</td><td>16,000</td><td>Mbps</td></tr></tbody></table><p>1,425.6Mbps&lt;16,000Mbps<br>​​结论​​<br>​​PCIe Gen2.0 x4 的理论带宽（16 Gbps）远高于 1080p@60fps NV12 视频的带宽需求（1.425 Gbps）。​​<br>​​实际传输时，PCIe 2.0 x4 完全可以满足需求，甚至还有大量余量。​</p><h2 id="常见的MCU-MPU-SoC-DSP-FPGA的差别"><a href="#常见的MCU-MPU-SoC-DSP-FPGA的差别" class="headerlink" title="常见的MCU/MPU/SoC/DSP/FPGA的差别"></a>常见的MCU/MPU/SoC/DSP/FPGA的差别</h2><p>在芯片领域，​​MCU、MPU、SoC、DSP​​ 和 ​​FPGA​​ 是常见的处理器类型，它们各有特点，适用于不同场景。以下是它们的核心区别和联系：</p><h3 id="​1-MCU（Microcontroller-Unit，微控制器）​​"><a href="#​1-MCU（Microcontroller-Unit，微控制器）​​" class="headerlink" title="​1. MCU（Microcontroller Unit，微控制器）​​"></a><strong>​1. MCU（Microcontroller Unit，微控制器）​</strong>​</h3><ul><li>​<strong>​特点​</strong>​：<ul><li>​<strong>​高度集成​</strong>​：将 CPU、内存（RAM/Flash）、外设（GPIO、ADC、UART等）集成在单一芯片上。</li><li>​<strong>​低功耗​</strong>​：适合电池供电设备。</li><li>​<strong>​实时性​</strong>​：通常运行 RTOS（如 FreeRTOS）或裸机程序。</li></ul></li><li>​<strong>​应用场景​</strong>​：<ul><li>家电控制（如洗衣机）、传感器节点、小型嵌入式设备。</li></ul></li><li>​<strong>​代表型号​</strong>​：<ul><li>STM32（ST）、ESP32（乐鑫）、PIC（Microchip）。</li></ul></li></ul><h3 id="​​2-MPU（Microprocessor-Unit，微处理器）​​"><a href="#​​2-MPU（Microprocessor-Unit，微处理器）​​" class="headerlink" title="​​2. MPU（Microprocessor Unit，微处理器）​​"></a>​<strong>​2. MPU（Microprocessor Unit，微处理器）​</strong>​</h3><ul><li>​<strong>​特点​</strong>​：<ul><li>​<strong>​强计算能力​</strong>​：高性能 CPU 核心（如 ARM Cortex-A、x86），但需外接内存（DDR）和外围芯片。</li><li>​<strong>​运行操作系统​</strong>​：支持 Linux、Android 等复杂 OS。</li><li>​<strong>​高功耗​</strong>​：通常需要主动散热。</li></ul></li><li>​<strong>​应用场景​</strong>​：<ul><li>工业计算机、智能终端（如 POS 机）、边缘计算。</li></ul></li><li>​<strong>​代表型号​</strong>​：<ul><li>Raspberry Pi（博通 BCM）、i.MX（NXP）、Intel Atom。</li></ul></li></ul><h3 id="​​3-SoC（System-on-Chip，片上系统）​​"><a href="#​​3-SoC（System-on-Chip，片上系统）​​" class="headerlink" title="​​3. SoC（System on Chip，片上系统）​​"></a>​<strong>​3. SoC（System on Chip，片上系统）​</strong>​</h3><ul><li>​<strong>​特点​</strong>​：<ul><li>​<strong>​超高度集成​</strong>​：在单芯片上集成 CPU、GPU、NPU、内存控制器、高速接口（USB/PCIe）等。</li><li>​<strong>​异构计算​</strong>​：可能包含多个 CPU/GPU/DSP 核心。</li><li>​<strong>​定制化​</strong>​：部分 SoC 可针对特定场景优化（如 AI 芯片）。</li></ul></li><li>​<strong>​应用场景​</strong>​：<ul><li>智能手机（如骁龙、麒麟）、自动驾驶、AI 加速。</li></ul></li><li>​<strong>​代表型号​</strong>​：<ul><li>高通骁龙、华为麒麟、NVIDIA Jetson。</li></ul></li></ul><h3 id="​​4-DSP（Digital-Signal-Processor，数字信号处理器）​​"><a href="#​​4-DSP（Digital-Signal-Processor，数字信号处理器）​​" class="headerlink" title="​​4. DSP（Digital Signal Processor，数字信号处理器）​​"></a>​<strong>​4. DSP（Digital Signal Processor，数字信号处理器）​</strong>​</h3><ul><li>​<strong>​特点​</strong>​：<ul><li>​<strong>​专用计算​</strong>​：优化数字信号处理（如 FFT、滤波），擅长高吞吐量数学运算。</li><li>​<strong>​低延迟​</strong>​：硬件加速特定算法（如音频编解码）。</li><li>​<strong>​通常作为协处理器​</strong>​：与 MCU/MPU 协同工作。</li></ul></li><li>​<strong>​应用场景​</strong>​：<ul><li>音频处理（如降噪）、图像处理（如摄像头）、通信（5G 基带）。</li></ul></li><li>​<strong>​代表型号​</strong>​：<ul><li>TI C6000 系列、ADI SHARC。</li></ul></li></ul><h3 id="​​5-FPGA（Field-Programmable-Gate-Array，现场可编程门阵列）​​"><a href="#​​5-FPGA（Field-Programmable-Gate-Array，现场可编程门阵列）​​" class="headerlink" title="​​5. FPGA（Field Programmable Gate Array，现场可编程门阵列）​​"></a>​<strong>​5. FPGA（Field Programmable Gate Array，现场可编程门阵列）​</strong>​</h3><ul><li>​<strong>​特点​</strong>​：<ul><li>​<strong>​硬件可编程​</strong>​：通过 HDL（Verilog/VHDL）配置逻辑电路，灵活性极高。</li><li>​<strong>​并行计算​</strong>​：适合高速信号处理、协议加速。</li><li>​<strong>​高功耗​</strong>​：动态功耗随逻辑复杂度增加。</li></ul></li><li>​<strong>​应用场景​</strong>​：<ul><li>通信协议处理（如 5G）、原型验证、ASIC 流片前的替代方案。</li></ul></li><li>​<strong>​代表型号​</strong>​：<ul><li>Xilinx Zynq（SoC+FPGA）、Intel Cyclone。</li></ul></li></ul><h3 id="对比总结"><a href="#对比总结" class="headerlink" title="对比总结"></a>对比总结</h3><table><thead><tr><th><strong>​类型​</strong>​</th><th>​<strong>​核心特点​</strong>​</th><th>​<strong>​集成度​</strong>​</th><th>​<strong>​功耗​</strong>​</th><th>​<strong>​典型应用​</strong>​</th></tr></thead><tbody><tr><td>​<strong>​MCU​</strong>​</td><td>低功耗、外设丰富</td><td>高（All-in-One）</td><td>低</td><td>家电控制、传感器</td></tr><tr><td>​<strong>​MPU​</strong>​</td><td>高性能、需外接内存</td><td>低</td><td>中高</td><td>工业计算机、智能终端</td></tr><tr><td>​<strong>​SoC​</strong>​</td><td>异构计算、多核集成</td><td>极高</td><td>中高</td><td>手机、AI 加速</td></tr><tr><td>​<strong>​DSP​</strong>​</td><td>专用信号处理、数学优化</td><td>中</td><td>中</td><td>音频、图像处理</td></tr><tr><td>​<strong>​FPGA​</strong>​</td><td>硬件可编程、并行计算</td><td>可定制</td><td>高</td><td>通信、原型验证</td></tr><tr><td><strong>联系与协作</strong> ​​</td><td></td><td></td><td></td><td></td></tr></tbody></table><p>​​SoC 可能包含 MCU/MPU/DSP​​<br>例如：手机 SoC（如骁龙）包含 Cortex-A（MPU）、Cortex-M（MCU）、DSP 和 GPU。</p><p>​​FPGA 可与 MCU/MPU 协同​​<br>例如：Xilinx Zynq 集成了 ARM Cortex-A（MPU）和 FPGA 逻辑。</p><p>​​DSP 常作为协处理器​​<br>例如：摄像头模组用 MCU 控制，DSP 处理图像。</p><p><strong>​​如何选择？</strong> ​​<br>​​需要低功耗控制？​​ → ​​MCU​​<br>​​需要跑 Linux？​​ → ​​MPU/SoC​​<br>​​要做音视频处理？​​ → ​​DSP​​<br>​​需要灵活硬件加速？​​ → ​​FPGA​​<br>​​全功能智能设备？​​ → ​​SoC​</p><h2 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h2><p>M.2 PCIe NVMe三者的关系：<a href="https://blog.csdn.net/weixin_46129187/article/details/143429683">https://blog.csdn.net/weixin_46129187/article/details/143429683</a><br>小a科普｜固态硬盘术语：SATA、PCIe、AIC、U2、M.2、NVMe和AHCI:<a href="https://baijiahao.baidu.com/s?id=1711659897646763096&amp;wfr=spider&amp;for=pc">https://baijiahao.baidu.com/s?id=1711659897646763096&amp;wfr=spider&amp;for=pc</a><br>选购固态硬盘别犯难：一文搞懂 M.2、SATA、PCIe 和 NVMe：<a href="https://baijiahao.baidu.com/s?id=1804753527384413243&amp;wfr=spider&amp;for=pc">https://baijiahao.baidu.com/s?id=1804753527384413243&amp;wfr=spider&amp;for=pc</a><br>PCIe、SATA，M.2，NVMe、AHCI、IDE到底都是 些啥？（于2018.04）:<a href="https://www.douban.com/note/684877015/?_i=1403373xdAUCBL">https://www.douban.com/note/684877015/?_i=1403373xdAUCBL</a><br>硬盘MSATA和SATA和M2接口定义:<a href="https://post.smzdm.com/p/a94og7g5/">https://post.smzdm.com/p/a94og7g5/</a></p>]]></content>
    
    <summary type="html">
    
      &lt;h2 id=&quot;M-2-PCIE-SATA-NVME-AHCI及区别和联系&quot;&gt;&lt;a href=&quot;#M-2-PCIE-SATA-NVME-AHCI及区别和联系&quot; class=&quot;headerlink&quot; title=&quot;M.2,PCIE,SATA,NVME,AHCI及区别和联系&quot;&gt;&lt;/a&gt;M.2,PCIE,SATA,NVME,AHCI及区别和联系&lt;/h2&gt;
    
    </summary>
    
    
      <category term="08领域技术" scheme="https://hexo.yuanjh.cn/categories/08%E9%A2%86%E5%9F%9F%E6%8A%80%E6%9C%AF/"/>
    
      <category term="g芯片相关" scheme="https://hexo.yuanjh.cn/categories/08%E9%A2%86%E5%9F%9F%E6%8A%80%E6%9C%AF/g%E8%8A%AF%E7%89%87%E7%9B%B8%E5%85%B3/"/>
    
    
      <category term="08领域技术/g芯片相关/基础知识" scheme="https://hexo.yuanjh.cn/tags/08%E9%A2%86%E5%9F%9F%E6%8A%80%E6%9C%AF-g%E8%8A%AF%E7%89%87%E7%9B%B8%E5%85%B3-%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/"/>
    
  </entry>
  
  <entry>
    <title>性能工具05_lttng使用</title>
    <link href="https://hexo.yuanjh.cn/hexo/ca466b0b/"/>
    <id>https://hexo.yuanjh.cn/hexo/ca466b0b/</id>
    <published>2024-04-26T23:47:18.000Z</published>
    <updated>2026-03-11T16:45:17.863Z</updated>
    
    <content type="html"><![CDATA[<h2 id="简介"><a href="#简介" class="headerlink" title="简介"></a>简介</h2><p>LTTng: (Linux Trace Toolkit Next Generation),<strong>它是用于跟踪Linux内核、应用程序以及库的系统软件包</strong>.LTTng 主要由内核模块和动态链接库(用于应用程序和动态链接库的跟踪)组成。它<strong>由一个会话守护进程控制,该守护进程接受来自命令行接口的命令。babeltrace项目允许将追踪信息翻译成用户可读的日志,并提供一个读追踪库,即libbabletrace</strong>。ceph代码中大量嵌入了tracepoint，使用lttng进行跟踪。它整合了内核和用户态跟踪，对于大量的跟踪事件流有非常高的性能，并且有一系列的分析和抓取工具。<br>对于目前的Linux内核来说，LTTng只不过是众多Tracing工具的一个，它制造了太多重复的工作比如Rring Buffer(内核中已经有两个Ring buffer被perf和ftrace使用)，并且自己的系统调用接口(内核已经有此类的接口)，增加LTTng意味着更混乱的Tracing ABI在内核中。<br>相比较而言，<strong>LTTng进入内核比SystemTap和utrace更困难</strong>。<br><img src="/images/20230309182347216_17532.jpg" alt=""></p><h2 id="lttng展示可跟踪位置"><a href="#lttng展示可跟踪位置" class="headerlink" title="lttng展示可跟踪位置"></a>lttng展示可跟踪位置</h2><p>lttng跟踪必定是需要进程一直在运行状态，像mon、osd的自不必多说，如果跟踪是librbd就必须保证加载 librbd.so进程是在运行。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">.&#x2F;rbd_example ##一直在跑  </span><br><span class="line">lttng list –u</span><br></pre></td></tr></table></figure><h2 id="命令行参数"><a href="#命令行参数" class="headerlink" title="命令行参数"></a>命令行参数</h2><p>嵌入式 lttng使用详细说明：<a href="https://blog.csdn.net/skdkjzz/article/details/44564951">https://blog.csdn.net/skdkjzz/article/details/44564951</a></p><h2 id="跟踪并获取信息"><a href="#跟踪并获取信息" class="headerlink" title="跟踪并获取信息"></a>跟踪并获取信息</h2><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">mkdir -p traces ##创建存放  </span><br><span class="line">lttng create -o traces librbd ## 创建trace session  </span><br><span class="line">lttng enable-event -u &#39;librbd:*&#39; ## 使能感兴趣的event  </span><br><span class="line">lttng add-context -u -t pthread_id ## 加入 线程信息  </span><br><span class="line">lttng start ## 开始跟踪  </span><br><span class="line"></span><br><span class="line"># run RBD workload here  </span><br><span class="line">lttng stop ## 停止trace  </span><br><span class="line">lttng destroy ##销毁 session</span><br></pre></td></tr></table></figure><p>可以查看traces目录，是否有对应的记录生成</p><p>首先执行程序：</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">.&#x2F;self-ust</span><br></pre></td></tr></table></figure><p>然后开启跟踪：</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">lttng-sessiond --daemonize  </span><br><span class="line">lttng create myself-lttng-ust  </span><br><span class="line">lttng enable-event --userspace &#39;self\_lttng\_ust:main_tracepoint&#39;  </span><br><span class="line">lttng start  </span><br><span class="line"></span><br><span class="line"># wait  </span><br><span class="line">lttng destroy</span><br></pre></td></tr></table></figure><p>3.3 查看跟踪信息</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">babeltrace2 ~&#x2F;lttng-traces&#x2F;myself-lttng-ust*</span><br></pre></td></tr></table></figure><h2 id="使用babeltrace读取结果"><a href="#使用babeltrace读取结果" class="headerlink" title="使用babeltrace读取结果"></a>使用babeltrace读取结果</h2><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">babeltrace traces &gt; result.all  </span><br><span class="line">\[10:17:31.802322370\] (+?.?????????) XXXXXXXXX librbd:aio\_complete\_enter: &#123; cpu\_id &#x3D; 2 &#125;, &#123; pthread\_id &#x3D; 139658738509568 &#125;, &#123; completion &#x3D; 0x5635FA045920, rval &#x3D; 0 &#125;  </span><br><span class="line">\[10:17:31.802361060\] (+0.000038690) XXXXXXXXX librbd:aio\_get\_return\_value\_enter: &#123; cpu\_id &#x3D; 2 &#125;, &#123; pthread\_id &#x3D; 139658738509568 &#125;, &#123; completion &#x3D; 0x5635FA045920 &#125;  </span><br><span class="line">\[10:17:31.802362582\] (+0.000001522) XXXXXXXXX librbd:aio\_get\_return\_value\_exit: &#123; cpu\_id &#x3D; 2 &#125;, &#123; pthread\_id &#x3D; 139658738509568 &#125;, &#123; retval &#x3D; 0 &#125;  </span><br><span class="line">\[10:17:31.802399704\] (+0.000037122) XXXXXXXXX librbd:aio\_complete\_exit: &#123; cpu\_id &#x3D; 2 &#125;, &#123; pthread\_id &#x3D; 139658738509568 &#125;, &#123; &#125;  </span><br><span class="line">\[10:17:31.802522131\] (+0.000122427) XXXXXXXXX librbd:write\_exit: &#123; cpu\_id &#x3D; 2 &#125;, &#123; pthread_id &#x3D; 139659290902208 &#125;, &#123; retval &#x3D; 10485760 &#125;</span><br></pre></td></tr></table></figure><p><img src="/images/20230309182347091_9217.jpg" alt=""></p><h2 id="Error-Unable-to-list-kernel-events-Kernel-tracer-not-available"><a href="#Error-Unable-to-list-kernel-events-Kernel-tracer-not-available" class="headerlink" title="Error: Unable to list kernel events: Kernel tracer not available"></a>Error: Unable to list kernel events: Kernel tracer not available</h2><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">lttng list --kernel  </span><br><span class="line">Linux Trace Tool lttng on Raspbian: Kernel tracer not available:https:&#x2F;&#x2F;stackoverflow.com&#x2F;questions&#x2F;52386448&#x2F;linux-trace-tool-lttng-on-raspbian-kernel-tracer-not-available  </span><br><span class="line">cat &#x2F;boot&#x2F;config-\&#96;uname -r\&#96; &gt; myconfig</span><br></pre></td></tr></table></figure><p>查看当前Linux系统的内核编译config文件，生成编译驱动所需的内核头文件：<a href="https://blog.csdn.net/dumgeewang/article/details/128528790">https://blog.csdn.net/dumgeewang/article/details/128528790</a><br>相关编译选项的核实<br><img src="/images/20230309182346966_20198.jpg" alt=""><br>2.0 LTTng需要的内核配置（通过读取LTTng-module文档中的README了解）：<a href="https://www.shuzhiduo.com/A/QW5YBQMedm/">https://www.shuzhiduo.com/A/QW5YBQMedm/</a></p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">missing the kernel header for the 4.4.0-98-generic kernel.  </span><br><span class="line">sudo apt-get install linux-headers-4.4.0-98-generic  </span><br><span class="line">[https:&#x2F;&#x2F;lttng-dev.lttng.narkive.com&#x2F;7bDtQAkg&#x2F;error-unable-to-list-kernel-events-kernel-tracer-not-available](https:&#x2F;&#x2F;lttng-dev.lttng.narkive.com&#x2F;7bDtQAkg&#x2F;error-unable-to-list-kernel-events-kernel-tracer-not-available)  </span><br><span class="line">Download, build, and install the latest LTTng-modules 2.13:  </span><br><span class="line">cd $(mktemp -d) &amp;&amp;  </span><br><span class="line">wget https:&#x2F;&#x2F;lttng.org&#x2F;files&#x2F;lttng-modules&#x2F;lttng-modules-latest-2.13.tar.bz2 &amp;&amp;  </span><br><span class="line">tar -xf lttng-modules-latest-2.13.tar.bz2 &amp;&amp;  </span><br><span class="line">cd lttng-modules-2.13.* &amp;&amp;  </span><br><span class="line">make &amp;&amp;  </span><br><span class="line">sudo make modules_install &amp;&amp;  </span><br><span class="line">sudo depmod –a  </span><br><span class="line">[https:&#x2F;&#x2F;stackoverflow.com&#x2F;questions&#x2F;52386448&#x2F;linux-trace-tool-lttng-on-raspbian-kernel-tracer-not-available](https:&#x2F;&#x2F;stackoverflow.com&#x2F;questions&#x2F;52386448&#x2F;linux-trace-tool-lttng-on-raspbian-kernel-tracer-not-available)</span><br></pre></td></tr></table></figure><h2 id="Function-tracing-LTTng-UST-helper"><a href="#Function-tracing-LTTng-UST-helper" class="headerlink" title="Function tracing (LTTng-UST helper)"></a>Function tracing (LTTng-UST helper)</h2><p><a href="https://lttng.org/man/3/lttng-ust-cyg-profile/v2.10/">https://lttng.org/man/3/lttng-ust-cyg-profile/v2.10/</a><br>c c++ 函数入口和出口的hook(gcc 编译选项)，然后打印出函数调用关系的方法:<a href="https://www.cnblogs.com/welhzh/p/4904874.html">https://www.cnblogs.com/welhzh/p/4904874.html</a></p><h2 id="enter-exit函数拦截"><a href="#enter-exit函数拦截" class="headerlink" title="enter,exit函数拦截"></a>enter,exit函数拦截</h2><p><img src="/images/20230309182346841_23289.jpg" alt=""><br><img src="/images/20230309182346716_23542.jpg" alt=""><br>集成到自己程序则不行<br><img src="/images/20230309182346591_1681.jpg" alt=""></p><h2 id="追踪规则"><a href="#追踪规则" class="headerlink" title="追踪规则"></a>追踪规则</h2><p>1) 追踪内核所有的探测点和所有的系统调用事件(-k/–kernel)：<br># lttng enable-event -a –k<br>2) 追踪探测点事件，这里我们追踪 sched_switch和sched_wakeup为例 (-k/–kernel) 。<br># lttng enable-event sched_switch,sched_wakeup -k<br>或者追踪所有的探测点事件：<br># lttng enable-event -a -k –tracepoint<br>3) 追踪所有的系统调用：<br># lttng enable-event -a -k –syscall<br>4) 使用 kprobes 以及 （或） 其他追踪器作为lttng的源：<br>这是一个LTTng2.0内核追踪器的一个新特性，你可以使用一个动态probe作为源，probe的追踪结果会显示在lttng的追踪结果中。<br># lttng enable-event aname -k –probe symbol+0x0<br>or<br># lttng enable-event aname -k –probe 0xffff7260695<br>可以为probe制定一个准确的地址0xffff7260695或者 symbol+offset。<br>你也可以使用功能追踪（使用的Ftrace API），追踪结果也会显示在lttng的追踪结果中：<br># lttng enable-event aname -k –function<symbol_name><br>5) 打开一个事件的上下文信息：<br>这也是一个新特性，可以让你添加一个事件的上下文信息。比如说你可以添加PID：<br># lttng add-context -k -e sched_switch -t pid<br>你也可以使用多个上下文信息：<br># lttng add-context -k -e sched_switch -t pid -t nice -t tid<br>你可以使用’ lttng add-context –help ‘ 学习所有的上下文格式的用法。<br>6) 打开事件的Perf计数器：<br>这也是一个新的很强大的特性，为每个追踪的事件添加Perf计数器数据（使用Perf的API）。下面实例为为每个事件添加CPU周期：<br># lttng add-context -k -e sched_switch -t perf:cpu-cycles<br>注： 你需要使用 add-context 的help学习所有的perf计数器值的含义。</symbol_name></p><h2 id="专题function追踪"><a href="#专题function追踪" class="headerlink" title="专题function追踪"></a>专题function追踪</h2><h3 id="官方文档的只言片语"><a href="#官方文档的只言片语" class="headerlink" title="官方文档的只言片语"></a>官方文档的只言片语</h3><p><a href="https://lttng.org/docs/v2.13/#doc-liblttng-ust-cyg-profile">https://lttng.org/docs/v2.13/#doc-liblttng-ust-cyg-profile</a><br><img src="/images/20230309182346466_28910.png" alt=""><br><img src="/images/20230309182346323_23694.png" alt=""></p><h3 id="测试01-修改源码，不包含lttng任何信息"><a href="#测试01-修改源码，不包含lttng任何信息" class="headerlink" title="测试01:修改源码，不包含lttng任何信息"></a>测试01:修改源码，不包含lttng任何信息</h3><p>g++ -lpthread -c multi_thread.cpp<br>g++ -o app multi_thread.o -ldl -lpthread<br><img src="/images/20230309182346198_11027.png" alt=""><br><img src="/images/20230309182346073_31353.png" alt=""></p><h3 id="测试02-案例test02"><a href="#测试02-案例test02" class="headerlink" title="测试02:案例test02"></a>测试02:案例test02</h3><p><img src="/images/20230309182345948_13959.png" alt=""><br><img src="/images/20230309182345839_1187.jpg" alt=""><br><img src="/images/20230309182345714_7266.jpg" alt=""></p><h3 id="测试03-funcs"><a href="#测试03-funcs" class="headerlink" title="测试03:funcs"></a>测试03:funcs</h3><p>编译：g++ -o app multi_thread.o my_lttng_ele.o my_lttng_gst.o -llttng-ust -ldl -lpthread -finstrument-functions<br><img src="/images/20230309182345589_12888.jpg" alt=""><br>编译：g++ -o app multi_thread.o -ldl -lpthread -finstrument-functions<br>运行：LD_PRELOAD=liblttng-ust-cyg-profile.so ./app<br><img src="/images/20230309182345464_25622.jpg" alt=""><br>此基础上开启采集<br>836 lttng enable-event –userspace ‘lttng_ust_cyg_profile:func_exit’<br>837 lttng enable-event –userspace ‘lttng_ust_cyg_profile:func_entry’<br>838 lttng enable-event -a -k –syscall<br><img src="/images/20230309182345339_25441.jpg" alt=""><br>未采集到<br>这有一篇文章展示了 大概思路：<br>采集MySQL trace数据：<a href="https://www.hikunpeng.com/document/detail/zh/kunpengdevkithistory/vscodehistory/2.5.5/kunpengidevscode\_10\_0350.html">https://www.hikunpeng.com/document/detail/zh/kunpengdevkithistory/vscodehistory/2.5.5/kunpengidevscode\_10\_0350.html</a><br>调整代码循环内调用函数<br><img src="/images/20230309182345214_17411.jpg" alt=""><br><img src="/images/20230309182345089_6847.jpg" alt=""><br>添加采集字段，添加采集scehd切换信息<br>LD_PRELOAD=liblttng-ust-cyg-profile.so ./app<br>lttng create test03096<br>lttng enable-event –kernel sched_switch<br>lttng enable-event –userspace ‘lttng_ust_cyg_profile:func_exit’<br>lttng enable-event –userspace ‘lttng_ust_cyg_profile:func_entry’<br>lttng add-context –kernel –type=pid –type=tid –type=procname<br>lttng add-context –userspace –type=ip –type=pthread_id –type=procname<br>lttng start<br>lttng destroy<br>babeltrace2 ~/lttng-traces/test03096* | grep lttng_ust_cyg_profile<br><img src="/images/20230309182344964_23895.jpg" alt=""><br><img src="/images/20230309182344855_31396.jpg" alt=""></p><h2 id="图形工具"><a href="#图形工具" class="headerlink" title="图形工具"></a>图形工具</h2><h3 id="数据导入"><a href="#数据导入" class="headerlink" title="数据导入"></a>数据导入</h3><p><img src="/images/20230309182344714_16170.png" alt=""></p><h3 id="数据含义分析"><a href="#数据含义分析" class="headerlink" title="数据含义分析"></a>数据含义分析</h3><p><img src="/images/20230309182344589_7604.jpg" alt=""><br>Timestamp Channel CPU Event type Contents TID Prio PID Source<br>10:38:11.978 045 845 channel0_1 1 irq_handler_entry irq=27, name=virtio2-req.0, context.packet_seq_num=1, context.cpu_id=1 0 20<br><img src="/images/20230309182344464_11481.jpg" alt=""><br><img src="/images/20230309182344339_27004.jpg" alt=""><br><img src="/images/20230309182344214_25505.jpg" alt=""><br>Timestamp Channel CPU Event type Contents TID Prio PID Source<br>10:38:11.958 232 111 channel0_1 1 x86_irq_vectors_local_timer_entry vector=236, context.packet_seq_num=1, context.cpu_id=1<br><img src="/images/20230309182344090_13873.jpg" alt=""></p><h3 id="不同参数和现象"><a href="#不同参数和现象" class="headerlink" title="不同参数和现象"></a>不同参数和现象</h3><p>项目：Test4_ak<br>lttng enable-event -a –k<br>lttng enable-event –userspace ‘provider_my:enter_app’<br>323 lttng add-context –kernel –type=pid –type=tid –type=procname<br>324 lttng add-context –userspace –type=pthread_id<br><img src="/images/20230309182343965_23422.jpg" alt=""><br>项目：test03_k_syscall<br>lttng enable-event -a -k –syscall<br>lttng add-context –kernel –type=pid –type=tid –type=procname<br>lttng add-context –userspace –type=pthread_id<br><img src="/images/20230309182343840_26540.jpg" alt=""><br><img src="/images/20230309182343715_16197.jpg" alt=""></p><h3 id="问题"><a href="#问题" class="headerlink" title="问题"></a>问题</h3><p>关于时间区间来源：减法规则<br>关于关注的事件<br>Event 和syscall区别<br><img src="/images/20230309182343590_21412.png" alt=""> <img src="/images/20230309182343465_6142.jpg" alt=""></p><h3 id="Function追踪，知道具有功能，怎么用没例子"><a href="#Function追踪，知道具有功能，怎么用没例子" class="headerlink" title="Function追踪，知道具有功能，怎么用没例子"></a>Function追踪，知道具有功能，怎么用没例子</h3><h3 id="使用模拟方法gst，ele，tracepiont报异常"><a href="#使用模拟方法gst，ele，tracepiont报异常" class="headerlink" title="使用模拟方法gst，ele，tracepiont报异常"></a>使用模拟方法gst，ele，tracepiont报异常</h3><p><img src="/images/20230309182343324_4396.jpg" alt=""></p><h2 id="其他结果分析软件"><a href="#其他结果分析软件" class="headerlink" title="其他结果分析软件"></a>其他结果分析软件</h2><p>[LTTng学习之旅]——Trace View初探<br>View and analyze the recorded events<br>Once you have completed the Record Linux kernel events and Record user application events tutorials, you can inspect the recorded events.<br>There are many tools you can use to read LTTng traces:<br>Babeltrace 2<br>A rich, flexible trace manipulation toolkit which includes a versatile command-line interface (babeltrace2(1)), a C library, and Python 3 bindings so that you can easily process or convert an LTTng trace with your own script.<br>The Babeltrace 2 project ships with a plugin (babeltrace2-plugin-ctf(7)) which supports the format of the traces which LTTng produces, CTF.<br><strong>Trace Compass</strong><br>A graphical user interface for viewing and analyzing any type of logs or traces, including those of LTTng.<br><strong>LTTng analyses</strong><br>An experimental project which includes many high-level analyses of LTTng kernel traces, like scheduling statistics, interrupt frequency distribution, top CPU usage, and more.<br>Babeltrace我没尝试，看起来像是一个命令行工具。而且是LTTng自己出品的。<br>我们做技术研究的，一方面要向老板汇报。可视化当然要生动明确。另一方面要技术推广。太难上手也不行。即开即用最好。<br>我们直接来使用第二个 Trace Compass.<br>Trace Compass (eclipse.org)<br>icon-default.png?t=M4AD<a href="https://www.eclipse.org/tracecompass/">https://www.eclipse.org/tracecompass/</a><br>打开这个网页，下载一个对于host 操作系统版本的软件。<br>打开软件 新建 trace工程。然后导入之前生成Trace log 的目录。<br>就可以看了。。。。很容易。</p><p>几招教你如何使用lttng以及log分析cpeh:<a href="https://mp.weixin.qq.com/s/FY3ibq3ncDYq8V59B8nVxw">https://mp.weixin.qq.com/s/FY3ibq3ncDYq8V59B8nVxw</a><br>Linux内核之Tracepoint机制:<a href="https://zhuanlan.zhihu.com/p/547477490">https://zhuanlan.zhihu.com/p/547477490</a><br>lttng：简单易上手的 tracef:<a href="https://zhuanlan.zhihu.com/p/506236943">https://zhuanlan.zhihu.com/p/506236943</a><br>lttng：自定义 tracepoint:<a href="https://zhuanlan.zhihu.com/p/509848662">https://zhuanlan.zhihu.com/p/509848662</a><br>其他<br>原理，复杂，没懂<br>使用LTTng链接内核和用户空间应用程序追踪:<a href="https://blog.csdn.net/longerzone/article/details/12623359">https://blog.csdn.net/longerzone/article/details/12623359</a><br>[LTTng学习之旅]——Trace 数据提取和格式转换—Babeltrace 2 C 应用程序开发<br><a href="https://blog.csdn.net/kuno_y/article/details/125081883">https://blog.csdn.net/kuno_y/article/details/125081883</a><br>嵌入式设备源码编译<br>[LTTng学习之旅]——环境搭建:<a href="https://blog.csdn.net/kuno_y/article/details/124764840">https://blog.csdn.net/kuno_y/article/details/124764840</a><br>Lttng接口使用吐槽<br>比最差的API(ETW)更差的API(LTTng)是如何炼成的, 谈如何写一个好的接口：<a href="https://www.cnblogs.com/zkweb/p/8126303.html">https://www.cnblogs.com/zkweb/p/8126303.html</a><br>尝试使用LTTng+TraceCompass分析一下进程周期偏移：<a href="https://blog.csdn.net/kuno_y/article/details/128372695">https://blog.csdn.net/kuno_y/article/details/128372695</a><br>Versal ACAP AI 引擎编程环境 用户指南 (UG1076)<br><a href="https://docs.xilinx.com/r/2022.1-简体中文/ug1076-ai-engine-environment/Vitis-分析器中的-FIFO-深度可视化">https://docs.xilinx.com/r/2022.1-简体中文/ug1076-ai-engine-environment/Vitis-分析器中的-FIFO-深度可视化</a><br>Zephyr Tracing 追踪调试指南<br><a href="https://docs.panchip.com/pan1080dk-doc/0.5.0/04\_dev\_guides/zephyr\_tracing\_guidance.html">https://docs.panchip.com/pan1080dk-doc/0.5.0/04\_dev\_guides/zephyr\_tracing\_guidance.html</a><br>test02<br>[LTTng学习之旅]——在用户程序中简单的添加一个trace点<br><a href="https://blog.csdn.net/kuno_y/article/details/124983044">https://blog.csdn.net/kuno_y/article/details/124983044</a><br>使用trace compass分析ftrace<br><a href="https://pkemb.com/2022/09/analyze-ftrace-with-trace-compass/">https://pkemb.com/2022/09/analyze-ftrace-with-trace-compass/</a><br>如何使用lttng检查多线程用户应用程序的调度？<a href="https://cloud.tencent.com/developer/ask/sof/1800581/answer/2449880/comments">https://cloud.tencent.com/developer/ask/sof/1800581/answer/2449880/comments</a><br>【LTTng】lttng-gen-tp — Generate LTTng-UST tracepoint provider code<br><a href="https://blog.csdn.net/kuno_y/article/details/126853032">https://blog.csdn.net/kuno_y/article/details/126853032</a><br><a href="https://lttng.org/docs/v2.13/#doc-tracing-the-linux-kernel">https://lttng.org/docs/v2.13/#doc-tracing-the-linux-kernel</a><br><a href="https://wiki.eclipse.org/Linux_Tools_Project/LTTng2/User_Guide#LTTng_Tracer">https://wiki.eclipse.org/Linux_Tools_Project/LTTng2/User_Guide#LTTng_Tracer</a><br><a href="https://xy2401.com/local-doc-help.eclipse.org-2019-06.zh/org.eclipse.tracecompass.doc.user/doc/LTTng-Kernel-Analysis.html">https://xy2401.com/local-doc-help.eclipse.org-2019-06.zh/org.eclipse.tracecompass.doc.user/doc/LTTng-Kernel-Analysis.html</a><br><a href="https://xy2401.com/local-doc-help.eclipse.org-2019-06.zh/org.eclipse.tracecompass.doc.user/doc/LTTng-Tracer-Control.html">https://xy2401.com/local-doc-help.eclipse.org-2019-06.zh/org.eclipse.tracecompass.doc.user/doc/LTTng-Tracer-Control.html</a><br><a href="https://xy2401.com/local-doc-help.eclipse.org-2019-06.zh/org.eclipse.tracecompass.doc.user/doc/Trace-Compass-Main-Features.html#Project_Explorer_View">https://xy2401.com/local-doc-help.eclipse.org-2019-06.zh/org.eclipse.tracecompass.doc.user/doc/Trace-Compass-Main-Features.html#Project_Explorer_View</a><br><a href="https://xy2401.com/local-doc-help.eclipse.org-2019-06.zh/org.eclipse.tracecompass.doc.user/doc/LTTng-Kernel-Analysis.html#Resources_View">https://xy2401.com/local-doc-help.eclipse.org-2019-06.zh/org.eclipse.tracecompass.doc.user/doc/LTTng-Kernel-Analysis.html#Resources_View</a></p>]]></content>
    
    <summary type="html">
    
      &lt;h2 id=&quot;简介&quot;&gt;&lt;a href=&quot;#简介&quot; class=&quot;headerlink&quot; title=&quot;简介&quot;&gt;&lt;/a&gt;简介&lt;/h2&gt;
    
    </summary>
    
    
      <category term="07通用技术" scheme="https://hexo.yuanjh.cn/categories/07%E9%80%9A%E7%94%A8%E6%8A%80%E6%9C%AF/"/>
    
      <category term="w主机系统软件" scheme="https://hexo.yuanjh.cn/categories/07%E9%80%9A%E7%94%A8%E6%8A%80%E6%9C%AF/w%E4%B8%BB%E6%9C%BA%E7%B3%BB%E7%BB%9F%E8%BD%AF%E4%BB%B6/"/>
    
    
      <category term="07通用技术/w主机系统软件/性能工具" scheme="https://hexo.yuanjh.cn/tags/07%E9%80%9A%E7%94%A8%E6%8A%80%E6%9C%AF-w%E4%B8%BB%E6%9C%BA%E7%B3%BB%E7%BB%9F%E8%BD%AF%E4%BB%B6-%E6%80%A7%E8%83%BD%E5%B7%A5%E5%85%B7/"/>
    
  </entry>
  
  <entry>
    <title>性能工具04_lttng安装</title>
    <link href="https://hexo.yuanjh.cn/hexo/9be6b785/"/>
    <id>https://hexo.yuanjh.cn/hexo/9be6b785/</id>
    <published>2024-04-26T23:17:43.000Z</published>
    <updated>2026-03-11T16:45:17.863Z</updated>
    
    <content type="html"><![CDATA[<p>LTTng-tools阿里云主机上安装成功，最好采用源码安装，</p><h2 id="源码安装-ok-demo-ok"><a href="#源码安装-ok-demo-ok" class="headerlink" title="源码安装,ok,demo,ok"></a>源码安装,ok,demo,ok</h2><p>sudo apt install libpopt-dev<br>sudo apt install libxml2-dev<br>wget <a href="https://lttng.org/files/lttng-tools/lttng-tools-latest-2.13.tar.bz2">https://lttng.org/files/lttng-tools/lttng-tools-latest-2.13.tar.bz2</a><br>tar -xf lttng-tools-latest-2.13.tar.bz2<br>cd lttng-tools-2.13.*<br>./configure<br>make<br>sudo make install<br>sudo ldconfig<br>补充安装包<br>apt install pkg-config</p><h3 id="安装liburcu"><a href="#安装liburcu" class="headerlink" title="安装liburcu"></a>安装liburcu</h3><p>这里说明liburcu库没有安装<br>liburcu库官方网址：<a href="http://lttng.org/urcu">http://lttng.org/urcu</a><br>我们安装一下：<br>压缩包下载地址：<a href="https://lttng.org/files/urcu/?O=D">https://lttng.org/files/urcu/?O=D</a><br>我选择了<a href="https://lttng.org/files/urcu/userspace-rcu-0.13.0.tar.bz2">https://lttng.org/files/urcu/userspace-rcu-0.13.0.tar.bz2</a><br>在这里插入图片描述<br>解压并编译安装：</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">wget https:&#x2F;&#x2F;lttng.org&#x2F;files&#x2F;urcu&#x2F;userspace-rcu-0.13.0.tar.bz2  </span><br><span class="line">tar -xf userspace-rcu-0.13.0.tar.bz2  </span><br><span class="line">cd userspace-rcu-0.13.0&#x2F;  </span><br><span class="line">.&#x2F;configure  </span><br><span class="line">make  </span><br><span class="line">make install</span><br></pre></td></tr></table></figure><p>返回执行：LTTng-tools configure</p><h3 id="错误-configure-error-Package-requirements-lttng-ust-gt-2-13-were-not-met"><a href="#错误-configure-error-Package-requirements-lttng-ust-gt-2-13-were-not-met" class="headerlink" title="错误:configure: error: Package requirements (lttng-ust &gt;= 2.13) were not met"></a>错误:configure: error: Package requirements (lttng-ust &gt;= 2.13) were not met</h3><p><img src="/images/20230309182829211_30901.jpg" alt=""></p><h3 id="LTTng-UST"><a href="#LTTng-UST" class="headerlink" title="LTTng-UST"></a>LTTng-UST</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">wget https:&#x2F;&#x2F;lttng.org&#x2F;files&#x2F;lttng-ust&#x2F;lttng-ust-latest-2.13.tar.bz2  </span><br><span class="line">tar -xf lttng-ust-latest-2.13.tar.bz2  </span><br><span class="line">cd lttng-ust-2.13.*  </span><br><span class="line">.&#x2F;configure --disable-numa  </span><br><span class="line">make  </span><br><span class="line">make install</span><br></pre></td></tr></table></figure><p>补充安装：<br>apt-get install libnuma-dev(略)<br>返回执行：LTTng-tools configure，ok<br><img src="/images/20230309182829080_7397.jpg" alt=""><br>继续执行LTTng-tools make<br><img src="/images/20230309182828931_16632.jpg" alt=""><br>继续执行LTTng-tools make install<br><img src="/images/20230309182828795_15579.jpg" alt=""></p><h3 id="安装babeltrace2"><a href="#安装babeltrace2" class="headerlink" title="安装babeltrace2"></a>安装babeltrace2</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">apt-add-repository ppa:lttng&#x2F;ppa  </span><br><span class="line">apt-get update  </span><br><span class="line">apt-get install babeltrace2</span><br></pre></td></tr></table></figure><p><img src="/images/20230309182828650_9774.jpg" alt=""></p><h3 id="样例lttng-ust-tracef-，ok"><a href="#样例lttng-ust-tracef-，ok" class="headerlink" title="样例lttng_ust_tracef()，ok"></a>样例lttng_ust_tracef()，ok</h3><h2 id="简洁安装-安装ok-demo报错make-error"><a href="#简洁安装-安装ok-demo报错make-error" class="headerlink" title="简洁安装,安装ok,demo报错make error"></a>简洁安装,安装ok,demo报错make error</h2><p>从Ubuntu 12.04开始，LTTng的包可以直接从包管理器的仓库里找到，所以安装变得非常简单：<br>sudo aptitude install lttng-tools</p><h3 id="lttng-ust-tracef"><a href="#lttng-ust-tracef" class="headerlink" title="lttng_ust_tracef()"></a>lttng_ust_tracef()</h3><p><img src="/images/20230309182828500_2497.jpg" alt=""><br>aptitude install lttng-tools liblttng-ust-dev<br>再次make<br><img src="/images/20230309182828361_6443.jpg" alt=""></p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;LTTng-tools阿里云主机上安装成功，最好采用源码安装，&lt;/p&gt;
    
    </summary>
    
    
      <category term="07通用技术" scheme="https://hexo.yuanjh.cn/categories/07%E9%80%9A%E7%94%A8%E6%8A%80%E6%9C%AF/"/>
    
      <category term="w主机系统软件" scheme="https://hexo.yuanjh.cn/categories/07%E9%80%9A%E7%94%A8%E6%8A%80%E6%9C%AF/w%E4%B8%BB%E6%9C%BA%E7%B3%BB%E7%BB%9F%E8%BD%AF%E4%BB%B6/"/>
    
    
      <category term="07通用技术/w主机系统软件/性能工具" scheme="https://hexo.yuanjh.cn/tags/07%E9%80%9A%E7%94%A8%E6%8A%80%E6%9C%AF-w%E4%B8%BB%E6%9C%BA%E7%B3%BB%E7%BB%9F%E8%BD%AF%E4%BB%B6-%E6%80%A7%E8%83%BD%E5%B7%A5%E5%85%B7/"/>
    
  </entry>
  
  <entry>
    <title>性能工具03_tracef安装失败</title>
    <link href="https://hexo.yuanjh.cn/hexo/4964d845/"/>
    <id>https://hexo.yuanjh.cn/hexo/4964d845/</id>
    <published>2024-04-20T22:14:32.000Z</published>
    <updated>2026-03-11T16:45:17.863Z</updated>
    
    <content type="html"><![CDATA[<p>Tracef</p><h2 id="Tracef用途说明"><a href="#Tracef用途说明" class="headerlink" title="Tracef用途说明"></a>Tracef用途说明</h2><p>简单来说，分析程序各函数的运行准确时间，最简单的strace,但只能分析内核态的，无法分析用户态的。另一个常用的perf工具，存在较大缺陷（可以分析相对时间占比，但无法分析函数的绝对时间起点终点）。所以需要用户态的类似strace的工具，<br>找到这篇文章<br>用户空间程序的函数跟踪器 (Function Tracer)：<a href="https://www.cnblogs.com/slgkaifa/p/6919967.html">https://www.cnblogs.com/slgkaifa/p/6919967.html</a></p><h2 id="源码下载解压"><a href="#源码下载解压" class="headerlink" title="源码下载解压"></a>源码下载解压</h2><p>下载地址：<a href="https://i-red.info/docs/rpm/stray_rpms/tracef/">https://i-red.info/docs/rpm/stray_rpms/tracef/</a><br>解压：tar -xzvf tracef-0.16.org.tar.gz<br>后续安装流程</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">$ cd tracef-0.xx  </span><br><span class="line">$ .&#x2F;configure  </span><br><span class="line">$ cd src  </span><br><span class="line">$ make</span><br></pre></td></tr></table></figure><p>make结果生成的 src/tracef 就是追踪器。</p><h2 id="configure报错解决"><a href="#configure报错解决" class="headerlink" title="configure报错解决"></a>configure报错解决</h2><h3 id="报错：configure-error-libdwarf-is-not-found"><a href="#报错：configure-error-libdwarf-is-not-found" class="headerlink" title="报错：configure: error: libdwarf is not found"></a>报错：configure: error: libdwarf is not found</h3><p>解决：ubuntu中安装libdwarf：<a href="http://www.360doc.com/content/12/0530/10/9012802_214677679.shtml">www.360doc.com/content/12/0530/10/9012802_214677679.shtml</a><br>sudo apt-get install elfutils</p><h3 id="报错：configure-error-libiberty-is-not-found"><a href="#报错：configure-error-libiberty-is-not-found" class="headerlink" title="报错：configure: error: libiberty is not found"></a>报错：configure: error: libiberty is not found</h3><p>GCC编译器原理（一）03——GCC 工具：gprof、ld、libbfd、libiberty 和libopcodes:<a href="https://www.cnblogs.com/kele-dad/p/9471248.html">https://www.cnblogs.com/kele-dad/p/9471248.html</a><br>sudo apt-get install libiberty-dev<br>sudo apt-get install binutils-dev</p><h3 id="报错：configure-error-libboost-is-not-found"><a href="#报错：configure-error-libboost-is-not-found" class="headerlink" title="报错：configure: error: libboost is not found"></a>报错：configure: error: libboost is not found</h3><p>sudo apt-get install libboost-all-dev</p><h3 id="报错：configure-error-libelf-is-not-found"><a href="#报错：configure-error-libelf-is-not-found" class="headerlink" title="报错：configure: error: libelf is not found"></a>报错：configure: error: libelf is not found</h3><p>sudo apt install libelf-dev.</p><h3 id="又回到这个问题：configure-error-libdwarf-is-not-found"><a href="#又回到这个问题：configure-error-libdwarf-is-not-found" class="headerlink" title="又回到这个问题：configure: error: libdwarf is not found"></a>又回到这个问题：configure: error: libdwarf is not found</h3><p>参考：<br>编译安装 libdwarf 记录:<a href="https://blog.csdn.net/m0_47696151/article/details/121641019">https://blog.csdn.net/m0_47696151/article/details/121641019</a><br>还是不行，<br>再参考：<br>Install libdwarf.so on Ubuntu:<a href="https://askubuntu.com/questions/502749/install-libdwarf-so-on-ubuntu">https://askubuntu.com/questions/502749/install-libdwarf-so-on-ubuntu</a><br>sudo apt-get install libelf-dev libdwarf-dev</p><h3 id="至此-configure执行ok"><a href="#至此-configure执行ok" class="headerlink" title="至此./configure执行ok"></a>至此./configure执行ok</h3><p><img src="/images/20230309182735930_25405.jpg" alt=""></p><h2 id="Make报错解决"><a href="#Make报错解决" class="headerlink" title="Make报错解决"></a>Make报错解决</h2><h3 id="报错：prototype-add-elf"><a href="#报错：prototype-add-elf" class="headerlink" title="报错：prototype_add_elf"></a>报错：prototype_add_elf</h3><p><img src="/images/20230309182735790_27817.jpg" alt=""><br>解决：<br>修改源码，ftrace/prototype.cpp第 38 和 53 行elf&amp; 改为 hoge::elf&amp;</p><h3 id="报错：asm-user-h"><a href="#报错：asm-user-h" class="headerlink" title="报错：asm/user.h"></a>报错：asm/user.h</h3><p><img src="/images/20230309182735640_18370.jpg" alt=""><br>解决：<br>修改源码，printer.cpp将第 17 行更改#include &lt;asm/user.h&gt;为#include &lt;sys/user.h&gt;<br><img src="/images/20230309182735500_8832.jpg" alt=""><br>解决：同上，修改文件trace.cpp</p><h3 id="报错：CHAR-BIT"><a href="#报错：CHAR-BIT" class="headerlink" title="报错：CHAR_BIT"></a>报错：CHAR_BIT</h3><p><img src="/images/20230309182735360_17737.jpg" alt="">解决：trace.cpp，增加#include<climits></climits></p><h3 id="报错：print-insn-i386-att"><a href="#报错：print-insn-i386-att" class="headerlink" title="报错：print_insn_i386_att"></a>报错：print_insn_i386_att</h3><p>Compiler error on Fedora:<a href="https://github.com/ThoughtGang/opdis/issues/20">https://github.com/ThoughtGang/opdis/issues/20</a><br>尝试：低版本gcc，不好使，脚本使用编译命令是g++<br>使用低版本g++，7.x不行，6.5不行，5.5<br><img src="/images/20230309182735220_29541.jpg" alt=""></p><h4 id="g-5-5报错-uintprt-t"><a href="#g-5-5报错-uintprt-t" class="headerlink" title="g++5.5报错:uintprt_t"></a>g++5.5报错:uintprt_t</h4><p><img src="/images/20230309182735090_7287.jpg" alt=""><br>问题：uintptr_t，修改mani.c增加#include &lt;stdint.h&gt;<br>再次编译,问题依旧在。<br><img src="/images/20230309182734940_8389.jpg" alt=""><br>根据之前参考文章，这个报错主要原因是头文件应该是opcodes/disassemble.h而非当前dis-asm.h，但本机其实没有opcodes/ disassemble.h</p><h4 id="安装opcodes-disassemble-h"><a href="#安装opcodes-disassemble-h" class="headerlink" title="安装opcodes/ disassemble.h"></a>安装opcodes/ disassemble.h</h4><h5 id="尝试01-安装binutils"><a href="#尝试01-安装binutils" class="headerlink" title="尝试01:安装binutils"></a>尝试01:安装binutils</h5><p><a href="https://sourceware.org/legacy-ml/gdb-patches/2017-06/msg00303.html">https://sourceware.org/legacy-ml/gdb-patches/2017-06/msg00303.html</a></p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">As a result, these print\_insn\_XXX are not used  </span><br><span class="line">out of opcodes, so this patch also moves their declarations from  </span><br><span class="line">include&#x2F;dis-asm.h to opcodes&#x2F;disassemble.h. With this change,  </span><br><span class="line">GDB doesn&#39;t use any print\_insn\_XXX directly any more.  </span><br><span class="line">opcodes&#x2F;disassemble.h.&#x3D;》  </span><br><span class="line">https:&#x2F;&#x2F;fossies.org&#x2F;linux&#x2F;binutils&#x2F;opcodes&#x2F;disassemble.h  </span><br><span class="line"></span><br><span class="line">**binutils-2.40.tar.xz**:  </span><br><span class="line">&#x3D;&gt;  </span><br><span class="line">Linux下载安装Binutils工具集:https:&#x2F;&#x2F;blog.csdn.net&#x2F;qq_40994908&#x2F;article&#x2F;details&#x2F;123708345  </span><br><span class="line">安装后还是没有opcodes&#x2F;disassemble.h  </span><br><span class="line">此路不通。</span><br></pre></td></tr></table></figure><h5 id="尝试02：安装binutils-gdb-git"><a href="#尝试02：安装binutils-gdb-git" class="headerlink" title="尝试02：安装binutils-gdb.git"></a>尝试02：安装binutils-gdb.git</h5><p>我想制作 tracef(hogetrce)。错误：未声明 print_insn_i386_att：<a href="https://teratail.com/questions/207929">https://teratail.com/questions/207929</a><br>=》<br>显然，函数 print_insn_i386_att 已从头文件 &lt;dis-asm.h&gt; 移至另一个头文件。<br>将 print_insn_XXX 移动到操作码内部标头<br>也许在目的地读取头文件会更好，但如果不存在这样的文件，即使包含似乎是目的地的 opcodes/disassemble.h 也会出错。<br>=》<br><a href="https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;a=commit;h=88c1242dc0a1e1ab582a65ea8bd05eb5f244c59b">https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;a=commit;h=88c1242dc0a1e1ab582a65ea8bd05eb5f244c59b</a><br>make install报错了，<br>尝试搜索disassemble.h，<br><img src="/images/20230309182734810_6720.jpg" alt=""><br>依然找不到。所以说明还是不行</p><h2 id="云机器01"><a href="#云机器01" class="headerlink" title="云机器01"></a>云机器01</h2><p>sudo apt-get install libelf-dev<br>sudo apt-get install binutils-dev<br>sudo apt-get install elfutils<br>sudo apt-get install libboost-all-dev<br>sudo apt-get install libelf-dev libdwarf-dev<br>sudo apt-get install libiberty-dev<br>sudo apt-get install binutils-dev<br>下载源码：<br>wget <a href="https://i-red.info/docs/rpm/stray_rpms/tracef/tracef-0.16.org.tar.gz">https://i-red.info/docs/rpm/stray_rpms/tracef/tracef-0.16.org.tar.gz</a></p><h3 id="configure-ok"><a href="#configure-ok" class="headerlink" title="configure ok"></a>configure ok</h3><p><img src="/images/20230309182734672_23173.jpg" alt=""><br><img src="/images/20230309182734530_10831.jpg" alt=""></p><h3 id="Make"><a href="#Make" class="headerlink" title="Make"></a>Make</h3><p><img src="/images/20230309182734390_24849.jpg" alt=""><br>这个是之前遇到过的问题，解决方案同上，类似问题全部忽略，按照之前处理方式即可</p><h4 id="报错：print-insn-i386-att-1"><a href="#报错：print-insn-i386-att-1" class="headerlink" title="报错：print_insn_i386_att"></a>报错：print_insn_i386_att</h4><p><img src="/images/20230309182734250_13235.jpg" alt=""></p><h5 id="尝试01-安装binutils-1"><a href="#尝试01-安装binutils-1" class="headerlink" title="尝试01: 安装binutils"></a>尝试01: 安装binutils</h5><p>Linux下载安装Binutils工具集：<a href="https://blog.csdn.net/qq_40994908/article/details/123708345">https://blog.csdn.net/qq_40994908/article/details/123708345</a></p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">wget http:&#x2F;&#x2F;ftp.gnu.org&#x2F;gnu&#x2F;binutils&#x2F;binutils-2.40.tar.gz \# 下载  </span><br><span class="line">tar -xzvf binutils-2.40.tar.gz \# 解压  </span><br><span class="line">cd binutils-2.40&#x2F; \# 定位到Binutils的目录  </span><br><span class="line">.&#x2F;configure --prefix&#x3D;&#x2F;usr&#x2F;local&#x2F;binutils # 设置安装目录    </span><br><span class="line">make \# GNU中的工具  </span><br><span class="line">make install \# 执行安装命令</span><br></pre></td></tr></table></figure><p>执行make命令时报错：</p><h6 id="报错makeinfo"><a href="#报错makeinfo" class="headerlink" title="报错makeinfo"></a>报错makeinfo</h6><p><img src="/images/20230309182734110_12199.png" alt=""><br>解决：sudo apt-get install texinfo</p><h6 id="报错：bison"><a href="#报错：bison" class="headerlink" title="报错：bison"></a>报错：bison</h6><p><img src="/images/20230309182733970_19405.jpg" alt=""><br>解决：</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">jq configure: error: You need bison version 3.0 or greater:https:&#x2F;&#x2F;blog.cpming.top&#x2F;p&#x2F;configure-error-need-bison-version-30-or-greater  </span><br><span class="line">$ wget ftp:&#x2F;&#x2F;ftp.gnu.org&#x2F;gnu&#x2F;bison&#x2F;bison-3.6.tar.xz  </span><br><span class="line">$ tar xf bison-3.6.tar.xz  </span><br><span class="line">$ cd bison-3.6  </span><br><span class="line">$ .&#x2F;configure  </span><br><span class="line">$ make  </span><br><span class="line">$ make install</span><br></pre></td></tr></table></figure><p>成功执行，说明bison安装本身是成功的<br><img src="/images/20230309182733830_23268.jpg" alt=""></p><h6 id="继续binutil"><a href="#继续binutil" class="headerlink" title="继续binutil"></a>继续binutil</h6><p>Make<br>核实：binutils里面确实有我们需要的h头文件<br><img src="/images/20230309182733700_2936.jpg" alt=""><br>但不包含再include中，所以<br>cp –r opcodes include/ #希望make install时自动带过去<br>make成功<br><img src="/images/20230309182733560_3982.png" alt=""><br>Make install成功<br><img src="/images/20230309182733420_4729.jpg" alt=""><br>但是，安装后核实，发现好像依然没有disassemble.h文件。<br><img src="/images/20230309182733280_23970.jpg" alt=""><br>修改：xelf.h文件<br><img src="/images/20230309182733130_1320.png" alt=""><br>Make尝试编译：<br><img src="/images/20230309182733000_15264.jpg" alt=""><br>通过拷贝头文件，文件夹的方式越过这个问题，可以认为安装binutils的目的达到了。</p><h3 id="报错：-cannot-convert-‘bfd-const’-to-‘const-asection’-aka-‘const-bfd-section’"><a href="#报错：-cannot-convert-‘bfd-const’-to-‘const-asection’-aka-‘const-bfd-section’" class="headerlink" title="报错： cannot convert ‘bfd* const’ to ‘const asection’ {aka ‘const bfd_section’}"></a>报错： cannot convert ‘bfd* const’ to ‘const asection<em>’ {aka ‘const bfd_section</em>’}</h3><p><strong>tracef make操作</strong><br>xelf.cpp:248:33: error: cannot convert ‘bfd* const’ to ‘const asection<em>’ {aka ‘const bfd_section</em>’}<br><img src="/images/20230309182732860_4191.jpg" alt=""><br>通过这几个参考<br>Build failure with <a href="mailto:binutils@2.34">binutils@2.34</a> #242:<a href="https://github.com/HPCToolkit/hpctoolkit/issues/242">https://github.com/HPCToolkit/hpctoolkit/issues/242</a><br>OProfile Bugs：<a href="https://sourceforge.net/p/oprofile/bugs/292/">https://sourceforge.net/p/oprofile/bugs/292/</a></p><h4 id="binutils版本问题"><a href="#binutils版本问题" class="headerlink" title="binutils版本问题"></a>binutils版本问题</h4><p>典型版本界限:2.33，2.34，</p><h5 id="尝试2-32"><a href="#尝试2-32" class="headerlink" title="尝试2.32"></a>尝试2.32</h5><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">wget http:&#x2F;&#x2F;ftp.gnu.org&#x2F;gnu&#x2F;binutils&#x2F;binutils-2.32.tar.gz \# 下载  </span><br><span class="line">tar -xzvf binutils-2.32.tar.gz \# 解压  </span><br><span class="line">cd binutils-2.32&#x2F; \# 定位到Binutils的目录  </span><br><span class="line">.&#x2F;configure --prefix&#x3D;&#x2F;usr&#x2F;local&#x2F;binutils # 设置安装目录    </span><br><span class="line">make \# GNU中的工具  </span><br><span class="line">make install \# 执行安装命令  </span><br><span class="line">头文件覆盖：  </span><br><span class="line">cd &#x2F;usr&#x2F;include; rm -rf opcodes&#x2F;  </span><br><span class="line">cd ~&#x2F;binutils-2.32; cp -r opcodes &#x2F;usr&#x2F;include&#x2F;  </span><br><span class="line">cd &#x2F;root&#x2F;tracef-0.16;.&#x2F;configure;cd src;  </span><br><span class="line">make clean;make</span><br></pre></td></tr></table></figure><p>同样的问题<br><img src="/images/20230309182732710_28180.jpg" alt=""></p><h5 id="尝试2-34"><a href="#尝试2-34" class="headerlink" title="尝试2.34"></a>尝试2.34</h5><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">wget http:&#x2F;&#x2F;ftp.gnu.org&#x2F;gnu&#x2F;binutils&#x2F;binutils-2.34.tar.gz \# 下载  </span><br><span class="line">tar -xzvf binutils-2.34.tar.gz \# 解压  </span><br><span class="line">cd binutils-2.34&#x2F; \# 定位到Binutils的目录  </span><br><span class="line">.&#x2F;configure --prefix&#x3D;&#x2F;usr&#x2F;local&#x2F;binutils # 设置安装目录    </span><br><span class="line">make \# GNU中的工具  </span><br><span class="line">make install \# 执行安装命令  </span><br><span class="line">头文件覆盖：  </span><br><span class="line">cd &#x2F;usr&#x2F;include; rm -rf opcodes&#x2F;  </span><br><span class="line">cd ~&#x2F;binutils-2.34; cp -r opcodes &#x2F;usr&#x2F;include&#x2F;  </span><br><span class="line">cd &#x2F;root&#x2F;tracef-0.16;.&#x2F;configure;cd src;  </span><br><span class="line">make clean;make</span><br></pre></td></tr></table></figure><p>同样问题<br><img src="/images/20230309182732550_16289.jpg" alt=""></p><h3 id="V3报错-checking-size-of-void-…-configure-error-cannot-compute-sizeof-void-77"><a href="#V3报错-checking-size-of-void-…-configure-error-cannot-compute-sizeof-void-77" class="headerlink" title="V3报错:checking size of void *… configure: error: cannot compute sizeof (void *), 77"></a>V3报错:checking size of void *… configure: error: cannot compute sizeof (void *), 77</h3><p><img src="/images/20230309182732390_16231.jpg" alt=""><br>重新解压出新的tracef代码，然后编译，还是这个问题，说明底层某些东西已经不对了。<br>Gcc，G++版本都是采用较新的，一样的问题</p><h2 id="云机器02"><a href="#云机器02" class="headerlink" title="云机器02"></a>云机器02</h2><h3 id="Make-1"><a href="#Make-1" class="headerlink" title="Make"></a>Make</h3><h4 id="报错：print-insn-i386-att-2"><a href="#报错：print-insn-i386-att-2" class="headerlink" title="报错：print_insn_i386_att"></a>报错：print_insn_i386_att</h4><p>通过apt下载源码binutils-dev</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">root@iZ2ze18upen0x3frvar3bsZ:~&#x2F;binutils-2.34# find . -name disassemble.h  </span><br><span class="line">.&#x2F;opcodes&#x2F;disassemble.h  </span><br><span class="line">cp -rf opcodes &#x2F;usr&#x2F;include&#x2F;</span><br></pre></td></tr></table></figure><p>修改：xelf.h文件<br><img src="/images/20230309182732240_12685.png" alt=""><br>Make尝试编译：<br><img src="/images/20230309182732080_13286.jpg" alt=""></p><h4 id="报错-cannot-convert-‘bfd-const’-to-‘const-asection’-aka-‘const-bfd-section’"><a href="#报错-cannot-convert-‘bfd-const’-to-‘const-asection’-aka-‘const-bfd-section’" class="headerlink" title="报错: cannot convert ‘bfd* const’ to ‘const asection’ {aka ‘const bfd_section’}"></a>报错: cannot convert ‘bfd* const’ to ‘const asection<em>’ {aka ‘const bfd_section</em>’}</h4><p>更新binutil版本<br><a href="https://launchpad.net/ubuntu/+source/binutils/2.40-2ubuntu1">https://launchpad.net/ubuntu/+source/binutils/2.40-2ubuntu1</a><br>下载2.40</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">tar xvJf binutils_2.40.orig.tar.xz  </span><br><span class="line">cd binutils-2.40&#x2F;  </span><br><span class="line">apt-get install texinfo  </span><br><span class="line">sudo apt-get install bison  </span><br><span class="line">make  </span><br><span class="line">make install</span><br></pre></td></tr></table></figure><p>头文件覆盖: cp -rf opcodes /usr/include/<br>回到~/tracef-0.16/src#,依然报错<br><img src="/images/20230309182731920_30339.jpg" alt=""><br>错误更多了</p><h2 id="参考信息"><a href="#参考信息" class="headerlink" title="参考信息"></a>参考信息</h2><p>CentOS 7 へ 関数コールトレーサ tracef (hogetrace) をインストール：<a href="https://qiita.com/kanejun_x/items/455d2d5dc6cde4d8c337">https://qiita.com/kanejun_x/items/455d2d5dc6cde4d8c337</a></p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;Tracef&lt;/p&gt;
    
    </summary>
    
    
      <category term="07通用技术" scheme="https://hexo.yuanjh.cn/categories/07%E9%80%9A%E7%94%A8%E6%8A%80%E6%9C%AF/"/>
    
      <category term="w主机系统软件" scheme="https://hexo.yuanjh.cn/categories/07%E9%80%9A%E7%94%A8%E6%8A%80%E6%9C%AF/w%E4%B8%BB%E6%9C%BA%E7%B3%BB%E7%BB%9F%E8%BD%AF%E4%BB%B6/"/>
    
    
      <category term="07通用技术/w主机系统软件/性能工具" scheme="https://hexo.yuanjh.cn/tags/07%E9%80%9A%E7%94%A8%E6%8A%80%E6%9C%AF-w%E4%B8%BB%E6%9C%BA%E7%B3%BB%E7%BB%9F%E8%BD%AF%E4%BB%B6-%E6%80%A7%E8%83%BD%E5%B7%A5%E5%85%B7/"/>
    
  </entry>
  
  <entry>
    <title>性能工具02_perf使用</title>
    <link href="https://hexo.yuanjh.cn/hexo/64f379a7/"/>
    <id>https://hexo.yuanjh.cn/hexo/64f379a7/</id>
    <published>2024-04-09T22:04:26.000Z</published>
    <updated>2026-03-11T16:45:17.863Z</updated>
    
    <content type="html"><![CDATA[<h2 id="宏观资料"><a href="#宏观资料" class="headerlink" title="宏观资料"></a>宏观资料</h2><p>源码：<a href="https://cdn.kernel.org/pub/linux/kernel/tools/perf/v5.9.0/perf-5.9.0.tar.gz">https://cdn.kernel.org/pub/linux/kernel/tools/perf/v5.9.0/perf-5.9.0.tar.gz</a><br>或者：linux-tools-common,linux-tools-4.4.0-62-generic<br>在线手册：<a href="https://man7.org/linux/man-pages/man1/perf-stat.1.html">https://man7.org/linux/man-pages/man1/perf-stat.1.html</a><br>命令大全手册：Linux性能分析工具合集之——perf（一）：命令介绍：<a href="https://zhuanlan.zhihu.com/p/544496209">https://zhuanlan.zhihu.com/p/544496209</a><br>支持多线程，支持内核态，用户态</p><h2 id="基础原理"><a href="#基础原理" class="headerlink" title="基础原理"></a>基础原理</h2><p>ftrace的跟踪方法是一种总体跟踪法，换句话说，你统计了一个事件到下一个事件所有的时间长度，然后把它们放到时间轴上，你可以知道整个系统运行在时间轴上的分布（这部分可参考，参考文献，一文搞懂 | Ftrace 的实现原理）。<strong>这种方法准确度很高，但跟踪成本也很高</strong>。<br>perf提供的是一种抽样形态的跟踪方法。其原理是：<strong>每隔一个固定的时间，就在CPU上（每个核上都有）产生一个中断，在中断上看看，当前是哪个pid，哪个函数，然后给对应的pid和函数加一个统计值</strong>，这样，我们就知道CPU有百分几的时间在某个pid，或者某个函数上了。这个原理图示如下：<br><img src="/images/20230309182302017_26501.jpg" alt=""><br>perf使用更多是CPU的PMU计数器，PMU计数器是大部分CPU都有的功能，它们可以用来统计比如L1 Cache失效的次数，分支预测失败的次数等。PMU可以在这些计数器的计数超过一个特定的值的时候产生一个中断，这个中断，我们可以用和时钟一样的方法，来<strong>抽样判断系统中哪个函数发生了最多的Cache失效，分支预测失效等</strong>。<br>通过改变采样的触发条件可以获得不同的统计数据：<br>　　以时间点 ( 如 tick) 作为事件触发采样便可以获知程序运行时间的分布。<br>以 cache miss 事件触发采样便可以知道 cache miss 的分布，即 cache 失效经常发生在哪些程序代码中。如此等等。<br>perf 中能够触发采样的事件有哪些。<br>事件分为以下三种：<br>　　1）<strong>Hardware Event</strong> 是由 PMU 硬件产生的事件，比如 cache 命中，当您需要了解程序对硬件特性的使用情况时，便需要对这些事件进行采样；<br>　　2）<strong>Software Event</strong> 是内核软件产生的事件，比如进程切换，tick 数等 ;<br>　　3）<strong>Tracepoint event</strong> 是内核中的静态 tracepoint 所触发的事件，这些 tracepoint 用来判断程序运行期间内核的行为细节，比如 slab 分配器的分配次数等。<br>上述每一个事件都可以用于采样，并生成一项统计数据，时至今日，尚没有文档对每一个 event 的含义进行详细解释。</p><h2 id="命令概况"><a href="#命令概况" class="headerlink" title="命令概况"></a>命令概况</h2><p>全局性概况：<br><strong>perf list**</strong>查看当前系统支持的性能事件；**<br>perf bench对系统性能进行摸底；<br>perf test对系统进行健全性测试；<br><strong>perf stat**</strong>对全局性能进行统计；**<br>全局细节：<br>perf top可以实时查看当前系统进程函数占用率情况；<br><strong>perf probe可以自定义动态事件；</strong><br>特定功能分析：<br>perf kmem针对slab的系统性能分析；<br>perf kvm针对kvm虚拟化分析；<br>perf lock分析锁性能；<br>perf mem分析内存slab性能；<br>perf sched分析内核调度器性能；<br><strong>perf trace记录系统调用轨迹；</strong><br>最常用功能perf record，可以系统全局，也可以具体到某个进程，更可以具体到某一进程某一事件；可宏观，也可以很微观。<br><strong>pref record记录信息到perf.data；</strong><br><strong>perf report生成报告；</strong><br>perf diff对两个记录进行diff；<br>perf evlist列出记录的性能事件；<br><strong>perf annotate**</strong>显示perf.data函数代码；**<br>perf archive将相关符号打包，方便在其它机器进行分析；<br><strong>perf script将perf.data输出可读性文本；</strong><br>可视化工具perf timechart<br><strong>perf timechart record记录事件；</strong><br><strong>perf timechart生成output.svg文档；</strong><br>由于涉及命令太对，不可能依次研究测试，仅测试加粗体部分。</p><h2 id="命令详情"><a href="#命令详情" class="headerlink" title="命令详情"></a>命令详情</h2><h3 id="perf-list"><a href="#perf-list" class="headerlink" title="perf list"></a>perf list</h3><h4 id="简介"><a href="#简介" class="headerlink" title="简介"></a>简介</h4><p>列出当前系统支持的所有性能事件。包括硬件性能事件、软件性能事件以及检查点。<br>perf list不能完全显示所有支持的事件类型，需要sudo perf list。同时还可以显示特定模块支持的perf事件：hw/cache/pmu都是硬件相关的；tracepoint基于内核的ftrace；sw实际上是内核计数器。<br>参数：<br><strong>hw/hardware</strong>显示支持的硬件事件相关，如：sudo perf list hardware<br><strong>sw/software</strong>显示支持的软件事件列表：<br><strong>cache/hwcache</strong>显示硬件cache相关事件列表：<br>pmu显示支持的PMU事件列表：<br>tracepoint显示支持的所有tracepoint列表，这个列表就比较庞大：<br>常见命令：<br>sudo perf list<br>sudo perf list hardware</p><h4 id="示例"><a href="#示例" class="headerlink" title="示例"></a>示例</h4><p>sudo perf list<br><img src="/images/20230309182301892_3438.jpg" alt=""><br>sudo perf list hardware<br><img src="/images/20230309182301764_11875.png" alt=""><br>sudo perf list sw<br><img src="/images/20230309182301639_424.png" alt=""><br>page fault缺页异常<br>major page fault，这种类型的缺页可以通过 Disk IO来满足，<br>minor page fault，这种缺页可以直接利用内存中的缓存页满足。<br>为什么数据已经被加载内核中的Page Cache了，理论上说直接访问就行了，为什么还要触发一次minor fault呢？<br>这里给出答案，懂得人可以略过，主要是因为虚拟地址和物理地址的映射关系并没有建立，我们知道Linux进程访问一块内存实际上使用的是虚拟内存，必须把对应虚拟地址空间和物理页面进行了映射才能够正常访问，那么vma结构体实际仅仅表示一个虚拟地址空间，必须把内核中Page Cache中的物理地址与进程vma虚拟地址空间进行映射才能正常被进程访问到<br><strong>关于cpu-clock和taks-clock</strong></p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">PERF\_COUNT\_SW\_CPU\_CLOCK  </span><br><span class="line">This reports the CPU clock, a high-resolution per-CPU timer.  </span><br><span class="line">PERF\_COUNT\_SW\_TASK\_CLOCK  </span><br><span class="line">This reports a clock count specific to the task that is running.</span><br></pre></td></tr></table></figure><p>Stackoverflow上的解释:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">1) By default, **perf stat shows task-clock,** and does not show cpu-clock. Therefore we can tell task-clock was expected to be **much more useful.**  </span><br><span class="line">2) cpu-clock was simply **broken**, and **has not been fixed for many years. It is best to ignore it**.  </span><br><span class="line">It was intended that **cpu-clock of sleep 1 would show about 1 second. In contrast, task-clock would show close to zero**. It would have made sense to use cpu-clock to read wall clock time. You could then look at the ratio between cpu-clock and task-clock.  </span><br><span class="line">But **in the current implementation, cpu-clock is equivalent to task-clock**. It is even possible that &quot;fixing&quot; the existing counter might break some userspace program. If there is such a program, Linux might not be able to &quot;fix&quot; this counter. Linux might need to define a new counter instead.</span><br></pre></td></tr></table></figure><h3 id="perf-stat"><a href="#perf-stat" class="headerlink" title="perf stat"></a>perf stat</h3><h4 id="简介-1"><a href="#简介-1" class="headerlink" title="简介"></a>简介</h4><p>执行某个命令，收集特定进程的性能概况，包括CPI、Cache丢失率等。虽然perf top也可以指定pid，但是必须先启动应用才能查看信息。perf stat能完整统计应用整个生命周期的信息。<br>参数：</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">-e：选择性能事件  </span><br><span class="line">-i：禁止子任务继承父任务的性能计数器。  </span><br><span class="line">-r：重复执行 n 次目标程序，并给出性能指标在n 次执行中的变化范围。  </span><br><span class="line">-n：仅输出目标程序的执行时间，而不开启任何性能计数器。  </span><br><span class="line">-a：指定全部cpu  </span><br><span class="line">-C：指定某个cpu  </span><br><span class="line">-A：将给出每个处理器上相应的信息  </span><br><span class="line">-p：指定待分析的进程id  </span><br><span class="line">-t：指定待分析的线程id</span><br></pre></td></tr></table></figure><p>常用命令：</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">分析系统：sudo perf stat -a ^C  </span><br><span class="line">特定应用：sudo perf stat -a gst-launch-1.0 videotestsrc ! Autovideosink  </span><br><span class="line">采集特定进程：perf stat -p 997 #997最好是长时间运行程序</span><br></pre></td></tr></table></figure><p>测量多个事件，只需提供一个用逗号分隔的列表，其中没有空格：</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">perf stat -e cycles,instructions,cache-misses \[...\]</span><br></pre></td></tr></table></figure><h4 id="示例-1"><a href="#示例-1" class="headerlink" title="示例"></a>示例</h4><p><img src="/images/20230309182301514_6376.jpg" alt=""><br><img src="/images/20230309182301404_9830.png" alt=""></p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"> Task-clock-msecs：CPU 利用率，该值高，说明程序的多数时间花费在 CPU 计算上而非 IO。  </span><br><span class="line"> Context-switches：进程切换次数，记录了程序运行过程中发生了多少次进程切换，频繁的进程切换是应该避免的。  </span><br><span class="line"> Cache-misses：程序运行过程中总体的 cache 利用情况，如果该值过高，说明程序的 cache 利用不好  </span><br><span class="line"> CPU-migrations：表示进程 t1 运行过程中发生了多少次 CPU 迁移，即被调度器从一个 CPU 转移到另外一个 CPU 上运行。  </span><br><span class="line"> Cycles：处理器时钟，一条机器指令可能需要多个 cycles，  </span><br><span class="line">Instructions: 机器指令数目。  </span><br><span class="line"> IPC：是 Instructions&#x2F;Cycles 的比值，该值越大越好，说明程序充分利用了处理器的特性。  </span><br><span class="line">Cache-references: cache 命中的次数  </span><br><span class="line">Cache-misses: cache 失效的次数。</span><br></pre></td></tr></table></figure><p>仅测量用户级别，有增加一个修饰词<br><img src="/images/20230309182301279_20364.jpg" alt=""></p><p>所有用户态，用*:u？实测不行</p><h3 id="perf-record"><a href="#perf-record" class="headerlink" title="perf record"></a>perf record</h3><h4 id="简介-2"><a href="#简介-2" class="headerlink" title="简介"></a>简介</h4><p>收集采样信息，并将其记录在数据文件perf.data中。随后可通过perf report对数据文件进行分析。<br>perf record和perf report可以更精确的分析一个应用，perf record可以精确到函数级别。并且在函数里面混合显示汇编语言和代码。<br>参数：</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">-e：选择性能事件  </span><br><span class="line">-p：待分析进程的id  </span><br><span class="line">-t：待分析线程的id  </span><br><span class="line">-a：分析整个系统的性能  </span><br><span class="line">-C：只采集指定CPU数据  </span><br><span class="line">-c：事件的采样周期  </span><br><span class="line">-o：指定输出文件，默认为perf.data  </span><br><span class="line">-A：以append的方式写输出文件  </span><br><span class="line">-f：以OverWrite的方式写输出文件  </span><br><span class="line">-g：记录函数间的调用关系</span><br></pre></td></tr></table></figure><p>常见命令：</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">sudo perf record -a -g .&#x2F;demo6  </span><br><span class="line">sudo perf record -a -g .&#x2F;demo6：会在当前目录生成perf.data文件。  </span><br><span class="line">sudo perf report --call-graph none结果如下,后面结合perf timechart分析.  </span><br><span class="line">sudo perf report --call-graph none -c fork  </span><br><span class="line">perf record -p \&#96;pgrep -d &#39;,&#39; nginx\&#96; #记录nginx进程的性能数据</span><br></pre></td></tr></table></figure><p>特定频率采样特定进程：</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">perf record -F 999 -p 997 #采样频率设置为999Hz，每秒采样999次</span><br></pre></td></tr></table></figure><h4 id="示例-2"><a href="#示例-2" class="headerlink" title="示例"></a>示例</h4><p><img src="/images/20230309182301154_16384.png" alt=""></p><h3 id="perf-report"><a href="#perf-report" class="headerlink" title="perf report"></a>perf report</h3><h4 id="简介-3"><a href="#简介-3" class="headerlink" title="简介"></a>简介</h4><p>读取perf record创建的perf.data数据文件，并给出热点分析结果。<br>参数：</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">-i：输入的数据文件  </span><br><span class="line">-c：只显示指定cpu采样信息  </span><br><span class="line">-p, --parent &lt;regex&gt; regex filter to identify parent, see: &#39;--sort parent&#39;</span><br></pre></td></tr></table></figure><p>常用命令：</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">sudo perf report -i perf.data  </span><br><span class="line">sudo perf report -c fork-g #问题，上面的是全家桶信息分析，下面的时特定app的分析，那么report 后选Zoom into fork-g</span><br></pre></td></tr></table></figure><p>thread后界面和上面命令，当前命令区别是啥<br>或者直接annotate<br>annotate 来单独分析函数信息：sudo perf annotate func2</p><h4 id="示例-3"><a href="#示例-3" class="headerlink" title="示例"></a>示例</h4><p>sudo perf report<br><img src="/images/20230309182301030_9863.jpg" alt=""><br>字段含义：</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">Children：总时间（包含调用其他函数事件）  </span><br><span class="line">Self：单纯函数自身执行时间（调用其他函数的不算）  </span><br><span class="line">敲击Enter键，perf给出了一些选项。通过这些选项，我们可以进一步分析这个函数。  </span><br><span class="line">Annotate print --\- 分析print函数中指令或者代码的性能  </span><br><span class="line">Zoom into test thread --\- 聚焦到线程 test  </span><br><span class="line">Zoom into test DSO --\- 聚焦到动态共享对象test  </span><br><span class="line">Browse map details --\- 查看map  </span><br><span class="line">Run scripts for samples of thread \[test\]--- 针对test线程的采样运行脚本  </span><br><span class="line">Run scripts for samples of symbol \[test\] --- 针对函数的采样运行脚本    </span><br><span class="line">Run scripts for all samples --\- 针对所有采样运行脚步  </span><br><span class="line">Switch to another data file in PWD --- 切换到当前目录中另一个数据文件</span><br></pre></td></tr></table></figure><p>问题：report -c demo6 进去在出来后不同（单进程的）<br>sudo perf report -c demo6，显示左1<br>之后进到main中，再zoom into demo6 thread，则显示左二，二者应该是相同的吧。<br><img src="/images/20230309182300906_24662.jpg" alt=""></p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">sudo perf report -D  </span><br><span class="line"> -D, --dump-raw-trace dump raw trace in ASCII</span><br></pre></td></tr></table></figure><p>问题：这个和perf script结果差异较大<br><img src="/images/20230309182300789_10413.jpg" alt=""><br>根据paraent过滤：sudo perf report -g -c demo6 –parent main<br>问题：右侧和other也会混进来，而且main也不会那么多<br><img src="/images/20230309182300665_31176.jpg" alt=""><br>导出到文件：perf report -i perf.data &gt; perf.txt<br>控制显示字段</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo perf report -g -c demo6 -F sample,period,pid,symbol,parent,cpu,transaction,trace,time,local_weight,weight,trace</span><br></pre></td></tr></table></figure><p>不好理解：demo6而言libc_start_main只会执行一次，为何下面这么多？Func1，func2一样的。<br><img src="/images/20230309182300540_14733.jpg" alt=""><br>显示超过一定阈值的记录</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">sudo perf report -c demo6 --percent-limit 1.0  </span><br><span class="line">--percentage &lt;relative|absolute&gt;  </span><br><span class="line"> how to display percentage of filtered entries</span><br></pre></td></tr></table></figure><p><img src="/images/20230309182300415_8058.png" alt=""><br><img src="/images/20230309182300290_19147.jpg" alt=""><br>显示总时间，采集次数<br>sudo perf report -c demo6 –show-total-period –n<br><img src="/images/20230309182300165_3784.jpg" alt=""><br>限制采集层次<br>sudo perf report -c demo6 –percent-limit 1.0 –show-total-period -n –max-stack 4<br><img src="/images/20230309182300040_24764.jpg" alt=""><br>问题：不用-g进行编译，一样可以分析出结果，todo why<br><img src="/images/20230309182259915_24070.jpg" alt=""><br>使用-g编译，分析出结果<br><img src="/images/20230309182259790_25154.jpg" alt=""><br>想进一步切入函数内部？汇编级别解析。<br>annotate 来单独分析函数信息：sudo perf annotate func2<br><img src="/images/20230309182259665_27772.png" alt=""><br><img src="/images/20230309182259540_28649.png" alt=""></p><h3 id="perf-timechart"><a href="#perf-timechart" class="headerlink" title="perf timechart"></a>perf timechart</h3><h4 id="简介-4"><a href="#简介-4" class="headerlink" title="简介"></a>简介</h4><p>针对测试期间系统行为进行可视化的工具。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">perf timechart record &lt;option&gt; &lt;command&gt;用于记录整个系统或者一个应用的事件，还可以加option记录指定类型的事件。  </span><br><span class="line">perf timechart用于将perf.data转换成SVG格式的文件，SVG可以通过Inkscape或者浏览器打开。  </span><br><span class="line">perf timechart record可以指定特定类型的事件：  </span><br><span class="line">perf timechart用于将perf timechart record录取的perf.data转换成output.svg。</span><br></pre></td></tr></table></figure><p>-w调整输出的svg文件长度，可以查看更多细节。<br>-p可以指定只查看某些进程输出，使用方式：sudo perf timechart -p test1 -p thermald<br>当线程太多影响svg解析速度的时候，可以通过-p指定特定线程进行分析。如果需要几个线程，每个线程采用-p xxx。<br>sudo perf timechart record -T ./demo6 &amp;&amp; sudo perf timechart –p demo6</p><h4 id="示例-4"><a href="#示例-4" class="headerlink" title="示例"></a>示例</h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"># 运行测试程序  </span><br><span class="line"> root:&#x2F;# .&#x2F;test &amp;  </span><br><span class="line"># 采样  </span><br><span class="line"> root:&#x2F;# perf timechart record  </span><br><span class="line"> ^C\[ perf record: Woken up 0 times to write data \]  </span><br><span class="line"> [ perf record: Captured and wrote 3.140 MB perf.data (30458 samples) \]  </span><br><span class="line"># 生成svg文件  </span><br><span class="line"> root:&#x2F;# perf timechart  </span><br><span class="line"> Written 0.6 seconds of trace to output.svg.</span><br></pre></td></tr></table></figure><p><img src="/images/20230309182259430_28576.jpg" alt=""><br>只能做基础的缩放动作，其他动作均不响应。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">sudo perf timechart record –T  </span><br><span class="line">-P, --power-only  </span><br><span class="line"> Record only power-related events  </span><br><span class="line">-T, --tasks-only  </span><br><span class="line"> Record only tasks-related events  </span><br><span class="line">-I, --io-only  </span><br><span class="line"> Record only io-related events  </span><br><span class="line">-g, --callchain  </span><br><span class="line"> Do call-graph (stack chain&#x2F;backtrace) recording</span><br></pre></td></tr></table></figure><p><img src="/images/20230309182259305_15937.jpg" alt=""><br><img src="/images/20230309182259180_14739.jpg" alt=""><br><img src="/images/20230309182259055_12156.jpg" alt=""><br><img src="/images/20230309182258931_5344.jpg" alt=""><br><img src="/images/20230309182258806_10314.jpg" alt=""><br>问题：上面几个图和参数的关系，感觉参数含义注解和图含义对应不起来<br>sudo perf timechart –highlight demo6<br><img src="/images/20230309182258681_20850.jpg" alt=""><br>采集特定的app，命令行传入app或指定pid<br>问题：采集特定app，支持，但实际依然是全局采集，还需要结合pid过滤<br><img src="/images/20230309182258556_23539.jpg" alt=""><br>采集特定pid：可采用显示时过滤方式，<br>-p, –process<br>Select the processes to display, by name or PID<br>sudo perf timechart record ;sudo perf timechart -p 1330371<br><img src="/images/20230309182258431_24277.jpg" alt=""><br>上部的cpu部分并没有少（直观理解应该只显示demo6相关进程），但底部的app变少了。<br>sudo perf timechart -p demo6<br><img src="/images/20230309182258306_2996.jpg" alt=""><br>和上面结果还是有差异的，截图底部少了一个进程，主要是bash进程。</p><h3 id="xperf-script"><a href="#xperf-script" class="headerlink" title="xperf script"></a>xperf script</h3><h4 id="简介-5"><a href="#简介-5" class="headerlink" title="简介"></a>简介</h4><p>执行perl或python写的功能扩展脚本、生成脚本框架、读取数据文件中的数据信息等。<br>Tom Zanussi 将 perl 和 python 解析器嵌入到 perf 程序中，从而使得 perf 能够自动执行 perl 或者 python 脚本进一步进行处理，从而为 perf 提供了强大的扩展能力。因为任何人都可以编写新的脚本，对 perf 的原始输出数据进行所需要的进一步处理。这个特性所带来的好处很类似于 plug-in 之于 eclipse。<br>参数:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"> --header，实测多了无用的header信息  </span><br><span class="line"> --deltatime Show time stamps relative to previous event，多了一个时间列  </span><br><span class="line">--show-info display extended information from perf.data file ，实测无变化  </span><br><span class="line"> --list list available scripts，报错如下  </span><br><span class="line"> open(&#x2F;usr&#x2F;libexec&#x2F;perf-core&#x2F;scripts) failed.  </span><br><span class="line"> Check &quot;PERF\_EXEC\_PATH&quot; env to set scripts dir.</span><br></pre></td></tr></table></figure><h4 id="示例-5"><a href="#示例-5" class="headerlink" title="示例"></a>示例</h4><p>基础命令，解析perf.data内容<br><img src="/images/20230309182258181_4015.jpg" alt=""><br>字段含义：<br><img src="/images/20230309182258056_30046.jpg" alt=""></p><h3 id="perf-probe"><a href="#perf-probe" class="headerlink" title="perf probe"></a>perf probe</h3><p>用于定义动态检查点。<br>详情参考：暂不做重点研究，不可能每个函数手工添加检查点<br>perf probe笔记:<a href="https://blog.csdn.net/qq_38349235/article/details/126143881">https://blog.csdn.net/qq_38349235/article/details/126143881</a></p><h4 id="简介-6"><a href="#简介-6" class="headerlink" title="简介"></a>简介</h4><p>能够动态地在想查看的地方插入动态监测点<br>root@VM-0-9-ubuntu:~#perf probe schedule:12 cpu<br>上例利用 probe 命令在内核函数 schedule() 的第 12 行处加入了一个动态 probe 点，和 tracepoint 的功能一样，内核一旦运行到该 probe 点时，便会通知 perf。可以理解为动态增加了一个新的 tracepoint</p><h4 id="示例-6"><a href="#示例-6" class="headerlink" title="示例"></a>示例</h4><p>定义追踪的事件：sudo perf probe –add tcp_sendmsg –f<br>追踪1s内的系统事件：sudo perf record -e probe:tcp_sendmsg_1 -aR sleep 1<br>查看结果：perf script<br><img src="/images/20230309182257946_25216.jpg" alt=""><br>各字段含义：<br>Name pid CPU time/us group:event address<br>test 15423 [002] 12704.994176 probe_test:show_entry (555b8f07b4)</p><h3 id="xperf-sched"><a href="#xperf-sched" class="headerlink" title="xperf sched"></a>xperf sched</h3><h4 id="简介-7"><a href="#简介-7" class="headerlink" title="简介"></a>简介</h4><p>perf sched提供了许多工具来分析内核CPU调度器的行为。你可以用它来识别和量化调度器延迟的问题。<br>参数：</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">record &lt;command&gt;：记录测试过程中的调度事件  </span><br><span class="line">latency：报告线程调度延时和其他调度相关属性  </span><br><span class="line">script：查看执行过程中详细的trace信息  </span><br><span class="line">replay：回放record录制的执行过程  </span><br><span class="line">map:用字符表示打印上下文切换  </span><br><span class="line">perf sched timehist：每一次任务切换的信息都展现出来，就更能知道每一次延迟是怎样发生的。</span><br></pre></td></tr></table></figure><p>统计每轮 task switch 时，之前在 CPU 上运行的那个 “prev” 线程得到的执行时间 (run time) ，以及该线程在获得这次执行机会前的休眠态等待 (wait time) 和运行态等待 (sch delay) 时间</p><h4 id="示例-7"><a href="#示例-7" class="headerlink" title="示例"></a>示例</h4><p>perf sched latency<br><img src="/images/20230309182257821_27947.jpg" alt=""><br>Task：进程的名字和 pid<br>Runtime：实际运行时间<br>Switches：进程切换的次数<br>Average delay：平均的调度延迟<br>调度延迟：调度延迟是保证每一个可运行进程都至少运行一次的时间间隔，翻译一下，是指一个task的状态变成了TASK_RUNNING，然后从进入 CPU 的runqueue开始，到真正执行（获得 CPU 的执行权）的这段时间间隔。<br>调度周期，调度周期的含义就是所有可运行的task都在CPU上执行一遍的时间周期，而Linux CFS中这个值是不固定的，当进程数量小于8的时候，sched period就是一个固定值6ms，如果runqueue数量超过了8个，那么就保证每个task都必须运行一定的时间，这个一定的时间还叫最小粒度时间，CFS的默认最小粒度时间是0.75ms，使用sysctl_sched_min_granularity保存。<br>Maximum delay：最大延迟<br>perf sched timehist：每次任务切换的信息都展现出来<br><img src="/images/20230309182257696_27544.jpg" alt=""><br>更详细的任务切换信息<br><img src="/images/20230309182257571_24290.jpg" alt=""><br>问题：字段解析样例，没看懂<br><img src="/images/20230309182257462_15448.jpg" alt="https://pic1.zhimg.com/v2-6652d86405530880fb68d27901948498_r.jpg"><br>此处也用到了 “sched_wakeup” 和 “sched_switch” 这 2 个 tracepoint，后者的时间点（上图红框部分）和前面 “timehist” 输出的第一列完全吻合，而如果 “wakeup” 和 “switch” 是前后连在一起的，那两者的时间差正好是 “timehist” 输出中第五列 “sch delay” 的时长。<br>另外，”script” 还包括了 “sched_stat_runtime”，其统计的是每两次 task switch 之间的 “runtime”（上图蓝框部分），求和的话，就正好等于 “timehist” 输出中第六列 “run time” 的时长。<br>update_curr() –&gt; trace_sched_stat_runtime<br>事实上，在使用 “timehist” 功能时，如果加上 “-wn –state” 的参数，也能显示一个任务被 awaken 的时刻，和作为 “prev” 的线程 schedule-out 后的状态。</p><h3 id="perf-trace"><a href="#perf-trace" class="headerlink" title="perf trace"></a>perf trace</h3><h4 id="简介-8"><a href="#简介-8" class="headerlink" title="简介"></a>简介</h4><p>strace inspired tool（类似strace）。<br>参数：</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">-p, --pid &lt;pid&gt; trace events on existing process id  </span><br><span class="line">-s, --summary Show only syscall summary with statistics  </span><br><span class="line">-t, --tid &lt;tid&gt; trace events on existing thread id  </span><br><span class="line">--filter &lt;filter&gt; event filter  </span><br><span class="line">--filter-pids &lt;CSV list of pids&gt; pids to filter (by the kernel)  </span><br><span class="line">-D msecs, --delay msecs After starting the program, wait msecs before measuring. This is useful to filter out the startup phase of the program, which is often very different.  </span><br><span class="line">-o, --output&#x3D; Output file name.  </span><br><span class="line">sudo perf trace –s</span><br></pre></td></tr></table></figure><p>特定进程：perf trace -p $PID -s</p><h4 id="示例-8"><a href="#示例-8" class="headerlink" title="示例"></a>示例</h4><p>sudo perf trace –s<br><img src="/images/20230309182257337_12846.jpg" alt=""><br>sudo perf trace ls<br><img src="/images/20230309182257212_25516.jpg" alt=""><br>问题：字段含义找不到相关说明<br><img src="/images/20230309182257087_20025.jpg" alt=""><br>问题：都是系统调用，没有针对用户态函数的统计</p><h3 id="strace"><a href="#strace" class="headerlink" title="strace"></a>strace</h3><h4 id="简介-9"><a href="#简介-9" class="headerlink" title="简介"></a>简介</h4><p>strace 究竟能做什么呢？<br>它能够打开应用进程的这个黑盒，<strong>通过系统调用的线索，告诉你进程大概在干嘛</strong>。<br>strace 有两种运行模式。<br>一种是通过它启动要跟踪的进程。用法很简单，在原本的命令前加上 strace 即可。比如我们要跟踪 “ls -lh /var/log/messages” 这个命令的执行，可以这样：<br>strace ls -lh /var/log/messages<br>另外一种运行模式，是跟踪已经在运行的进程，在不中断进程执行的情况下，理解它在干嘛。 这种情况，给 strace 传递个 -p pid 选项即可。<br>Strace典型使用场景，参考：<br>strace 可以解决什么问题？ | Linux 中国:<a href="https://zhuanlan.zhihu.com/p/362348075">https://zhuanlan.zhihu.com/p/362348075</a><br>案例三：用调试工具掌握软件的工作原理：<a href="https://blog.51cto.com/ahuo/5317283">https://blog.51cto.com/ahuo/5317283</a><br>Strace的介绍与使用:<a href="https://www.cnblogs.com/skandbug/p/16264609.html">https://www.cnblogs.com/skandbug/p/16264609.html</a></p><h4 id="示例-9"><a href="#示例-9" class="headerlink" title="示例"></a>示例</h4><p>strace -c 统计系统调用分析的结果<br><img src="/images/20230309182256962_25543.png" alt=""><br>strace -T 打印每个系统调用所花的时间<br><img src="/images/20230309182256837_14478.jpg" alt=""><br>字段含义：函数，入参，返回值</p><h3 id="使用方法步骤"><a href="#使用方法步骤" class="headerlink" title="使用方法步骤"></a>使用方法步骤</h3><h3 id="其他"><a href="#其他" class="headerlink" title="其他"></a>其他</h3><p>工具的宏观理解<br>两部分：<br>第一部分：非严谨采样方法，某个特定事件，总发生再哪些地方，<br>特例：如果这个特定时间是时钟周期，那么统计就是各函数的运行时间<br>第二部分：严谨的统计方法，特定系统函数(接口)的调用次数，各次调用时间，以及基于此的相关统计量。<br>Perf是对一系列内核工具的封装的简易接口（工具），或者和其他工具的对标。<br>常见问题：<br>问题01<br>Perf report为例，实际调用链应该非常深的，实际看起来还行，主要原因是只会在对内核态的采集，只会再检查点检查，并非所有函数都显示。<br>目前测试结果看，用户态的是全部显示的，可以采用层次过滤，稍微控制下<br>问题02<br><img src="/images/20230309182256712_14623.png" alt=""><br>事件可以指定后缀，比如我想只跟踪发生在用户态时产生的分支预测失败，我可以这样：<br>sudo perf top -e branch-misses:u,cycles<br>全部事件都有这个要求，我还可以：<br>sudo perf top -e ‘{branch-misses,cycles}:u’<br>看看perf-list的手册，会找到更多的后缀，后缀我也用得比较少，读者对这个有兴趣，可以自己深入挖掘一下，如果有什么好的使用经验，希望也可以告诉我。<br>火焰图：参考，<a href="https://blog.csdn.net/xuhaitao23/article/details/124016932">https://blog.csdn.net/xuhaitao23/article/details/124016932</a><br>perf sched replay 这个工具更是专门为调度器开发人员所设计，它试图重放 perf.data 文件中所记录的调度场景。很多情况下，一般用户假如发现调度器的奇怪行为，他们也无法准确说明发生该情形的场景，或者一些测试场景不容易再次重现，或者仅仅是出于“偷懒”的目的，使用 perf replay，perf 将模拟 perf.data 中的场景，无需开发人员花费很多的时间去重现过去，这尤其利于调试过程，因为需要一而再，再而三地重复新的修改是否能改善原始的调度场景所发现的问题。<br>perf 记录的默认行为是什么？：<a href="https://qa.1r1g.com/sf/ask/4744087631/">https://qa.1r1g.com/sf/ask/4744087631/</a></p><h4 id="锁"><a href="#锁" class="headerlink" title="锁"></a>锁</h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"># perf lock record ls #记录  </span><br><span class="line"># perf lock report #报告  </span><br><span class="line"> Name acquired contended total wait (ns)  max wait (ns) min wait (ns)  </span><br><span class="line"> &amp;mm-&gt;page\_table\_... 382 0 0 0 0  </span><br><span class="line"> &amp;mm-&gt;page\_table\_... 72 0 0 0 0  </span><br><span class="line"> &amp;fs-&gt;lock 64 0 0 0 0  </span><br><span class="line"> dcache_lock 62 0 0 0 0  </span><br><span class="line"> vfsmount_lock 43 0 0  0 0  </span><br><span class="line">  &amp;newf-&gt;file_lock... 41 0 0 0 0  </span><br><span class="line">Name：内核锁的名字。  </span><br><span class="line">aquired：该锁被直接获得的次数，因为没有其它内核路径占用该锁，此时不用等待。  </span><br><span class="line">contended：该锁等待后获得的次数，此时被其它内核路径占用，需要等待。  </span><br><span class="line">total wait：为了获得该锁，总共的等待时间。  </span><br><span class="line">max wait：为了获得该锁，最大的等待时间。  </span><br><span class="line">min wait：为了获得该锁，最小的等待时间。</span><br></pre></td></tr></table></figure><h4 id="内存"><a href="#内存" class="headerlink" title="内存"></a>内存</h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"># perf kmem record ls #记录  </span><br><span class="line"># perf kmem stat --caller --alloc -l 20 #报告  </span><br><span class="line">\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-  </span><br><span class="line"> Callsite | Total\_alloc&#x2F;Per | Total\_req&#x2F;Per | Hit | Ping-pong | Frag  </span><br><span class="line">\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-  </span><br><span class="line"> perf\_event\_mmap+ec | 311296&#x2F;8192 | 155952&#x2F;4104 | 38 |    0 | 49.902%  </span><br><span class="line"> proc\_reg\_open+41 | 64&#x2F;64 | 40&#x2F;40 | 1 | 0 | 37.500%  </span><br><span class="line"> \_\_kmalloc\_node+4d | 1024&#x2F;1024 | 664&#x2F;664 | 1 | 0 | 35.156%  </span><br><span class="line"> ext3_readdir+5bd    | 64&#x2F;64 | 48&#x2F;48 | 1 | 0 | 25.000%  </span><br><span class="line"> load\_elf\_binary+8ec | 512&#x2F;512 | 392&#x2F;392 | 1 | 0 | 23.438%  </span><br><span class="line">Callsite：内核代码中调用kmalloc和kfree的地方。  </span><br><span class="line">Total_alloc&#x2F;Per：总共分配的内存大小，平均每次分配的内存大小。  </span><br><span class="line">Total_req&#x2F;Per：总共请求的内存大小，平均每次请求的内存大小。  </span><br><span class="line">Hit：调用的次数。  </span><br><span class="line">Ping-pong：kmalloc和kfree不被同一个CPU执行时的次数，这会导致cache效率降低。  </span><br><span class="line">Frag：碎片所占的百分比，碎片 &#x3D; 分配的内存 \- 请求的内存，这部分是浪费的。  </span><br><span class="line">有使用--alloc选项，还会看到Alloc Ptr，即所分配内存的地址。</span><br></pre></td></tr></table></figure><h4 id="调度"><a href="#调度" class="headerlink" title="调度"></a>调度</h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"># perf sched record sleep 10     </span><br><span class="line"># perf report latency --sort max     </span><br><span class="line">\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-  </span><br><span class="line">Task | Runtime ms | Switches | Average delay ms | Maximum delay ms | Maximum delay at |  </span><br><span class="line">\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-  </span><br><span class="line">events&#x2F;10:61 | 0.655 ms | 10 | avg: 0.045 ms | max: 0.161 ms | max at: 9804.958730 s  </span><br><span class="line">sleep:11156 | 2.263 ms | 4 | avg: 0.052 ms | max: 0.118 ms | max at: 9804.865552 s  </span><br><span class="line">edac-poller:1125 | 0.598 ms | 10 | avg: 0.042 ms | max: 0.113 ms | max at: 9804.958698 s  </span><br><span class="line">events&#x2F;2:53 | 0.676 ms | 10 | avg: 0.037 ms | max: 0.102 ms | max at: 9814.751605 s  </span><br><span class="line">perf:11155 | 2.109 ms | 1 | avg: 0.068 ms | max: 0.068 ms | max at: 9814.867918 s</span><br></pre></td></tr></table></figure><p>TASK：进程名和pid。<br>Runtime：实际的运行时间。<br>Switches：进程切换的次数。<br>Average delay：平均的调度延迟。<br>Maximum delay：最大的调度延迟。<br>Maximum delay at：最大调度延迟发生的时刻。</p><h4 id="原理：堆栈分析"><a href="#原理：堆栈分析" class="headerlink" title="原理：堆栈分析"></a>原理：堆栈分析</h4><p>在Linux下做性能分析3：perf:<a href="https://zhuanlan.zhihu.com/p/22194920">https://zhuanlan.zhihu.com/p/22194920</a><br>==堆栈跟踪==<br>perf的跟踪有一个错觉需要我们注意，假设我们有一个函数abc()，调用另一个函数def()，在perf的统计中，这两者是分开统计的，就是说，执行def的时间，是不计算abc的时间的，图示如下：<br><img src="/images/20230309182256587_2863.jpg" alt="https://pic1.zhimg.com/80/208e1c43d41ade589998e35b224b12b0_720w.webp"><br>这里，abc()被击中5次，def()被击中5次，ghi被击中1次。这会给我们不少错觉，似乎abc的计算压力不大，实际上不是，你要把def和ghi计算在内才行。<br>但这又带来另一个问题：可能def不仅仅是abc这个函数调用啊，别人也会调用它呢，这种情况，我们怎么知道是谁导致的？<br>这种情况我们可以启动堆栈跟踪，也就是每次击中的时候，向上回溯一下调用栈，让调用者也会被击中，这样就就更容易看出问题来，这个原理类似这样：<br><img src="/images/20230309182256462_20138.jpg" alt="https://pic2.zhimg.com/80/64e0c0e19caa218771cb9ac6e795dc89_720w.webp"><br>这种情况，abc击中了11次，def击中了6次，而ghi击中了1次。这样我们可以在一定程度上更容易判断瓶颈的位置。-g命令可以实现这样的跟踪，下面是一个例子：<br><img src="/images/20230309182256306_15859.jpg" alt="https://pic3.zhimg.com/54cddcb2d899c330c45526f3253fc8fa_r.jpg"><br>使用堆栈跟踪后，start_thread上升到前面去了，因为正是它调的heavy_cal。<br>使用堆栈跟踪要注意的是，堆栈跟踪受扫描深度的限制，太深的堆栈可能回溯不过去，这是有可能影响结果的。<br>另一个问题是，有些我们从源代码看来是函数调用的，其实在汇编一级并不是函数调用。比如inline函数，宏，都不是函数调用。另外，gcc在很多平台中，会自动把很短的函数变成inline函数，这也不产生函数调用。还有一种是，fastcall函数，通过寄存器传递参数，不会产生调用栈，也有可能不产生调用栈，这个通过调用栈回溯是有可能看不到的。<br>还有一种更奇葩的情况是，部分平台使用简化的堆栈回溯机制，在堆栈中看见一个地址像是代码段的地址，就认为是调用栈，这些情况都会引起堆栈跟踪上的严重错误。使用者应该对系统的ABI非常熟悉，才能很好驾驭堆栈跟踪这个功能的。<br>问题：这里的perf原理的函数嵌套和实际测试不大相符，进一步验证<br>Perf的原理、编译以及使用：<a href="https://blog.csdn.net/u013983194/article/details/112209853">https://blog.csdn.net/u013983194/article/details/112209853</a><br>每隔一个固定时间，CPU上产生一个中断，看当前是哪个进程、哪个函数，然后给对应的进程和函数加一个统计值，这样就知道CPU有多少时间在某个进程或某个函数上了。具体原作原理就是直接通过系统调用syscall/ioctl或者监听SW的event来看性能。<br>在Linux下做性能分析3：perf：<a href="https://zhuanlan.zhihu.com/p/22194920">https://zhuanlan.zhihu.com/p/22194920</a><br>读取和解析perf.data：<a href="https://qa.1r1g.com/sf/ask/834528971/">https://qa.1r1g.com/sf/ask/834528971/</a><br>读取和解析perf.data<br>我正在使用命令perf record来记录性能计数器frm linux。<br>我想将结果perf.data用作其他编程应用程序的输入。您知道如何读取和解析其中的数据perf.data吗？有没有办法将其转换为.text文件或.csv？<br>带有子命令“script”的linux工具的工具中有内置的perf.data解析器和打印机perf。<br>转换perf.data文件<br>perf script &gt; perf.data.txt<br>要在其他文件 ( perf record -o filename.data) 中转换 perf 记录的输出，请使用-i选项：<br>perf script -i filename.data &gt; filename.data.txt<br>perf script记录在man perf-script，可在<a href="http://man7.org/linux/man-pages/man1/perf-script.1.html在线获得">http://man7.org/linux/man-pages/man1/perf-script.1.html在线获得</a><br>perf-script - Read perf.data (created by perf record) and display<br>trace output<br>This command reads the input file and displays the trace recorded.<br>‘perf script’ to see a detailed trace of the workload that was<br>recorded.<br>`perf script` 的输出是文本并且是可读的，但是用 python/perl/awk/something 脚本解析它可能并不容易。 (2认同)<br>`perf script` 特别允许使用 python 和 perl 脚本处理 pref 事件。见[`man perf-script-python`](<a href="https://github.com/torvalds/linux/blob/master/tools/perf/Documentation/perf-script-python.txt">https://github.com/torvalds/linux/blob/master/tools/perf/Documentation/perf-script-python.txt</a>) (2认同)<br>问题：内核态用户态，event:u解决，全部的用户态事件？未知<br>perf list,perf evnlist关系<br>evlist事件和采样频率的联动</p><p>其他工具<br>linux 高级测试性能工具：<a href="https://www.lmlphp.com/user/12842/article/item/431835/">https://www.lmlphp.com/user/12842/article/item/431835/</a><br>无水干货-如何快速分析Linux服务器的性能问题:<a href="https://www.linuxprobe.com/performance-issues-linux-servers.html">https://www.linuxprobe.com/performance-issues-linux-servers.html</a></p><h2 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h2><p>page fault的两种区别（major、minor）：<a href="https://blog.csdn.net/rikeyone/article/details/108623187">https://blog.csdn.net/rikeyone/article/details/108623187</a><br>Linux perf events: cpu-clock and task-clock - what is the difference:<a href="https://stackoverflow.com/questions/23965363/linux-perf-events-cpu-clock-and-task-clock-what-is-the-difference">https://stackoverflow.com/questions/23965363/linux-perf-events-cpu-clock-and-task-clock-what-is-the-difference</a><br>手把手教你系统级性能分析工具perf的介绍与使用（超详细）:<a href="https://blog.csdn.net/youzhangjing_/article/details/124671286">https://blog.csdn.net/youzhangjing_/article/details/124671286</a><br>学会使用perf性能分析工具–这一篇就够了：<a href="https://qmiller.blog.csdn.net/article/details/123048333?spm=1001.2101.3001.6661.1">https://qmiller.blog.csdn.net/article/details/123048333?spm=1001.2101.3001.6661.1</a><br>用Perf寻找程序中的性能热点（perf step by step）：<a href="https://zhuanlan.zhihu.com/p/134721612">https://zhuanlan.zhihu.com/p/134721612</a><br>【开发工具】【perf】性能分析工具perf的编译和使用说明:<a href="https://blog.csdn.net/Ivan804638781/article/details/122700909">https://blog.csdn.net/Ivan804638781/article/details/122700909</a><br>一文搞懂 | Ftrace 的实现原理：<a href="https://blog.csdn.net/melody157398/article/details/120124294">https://blog.csdn.net/melody157398/article/details/120124294</a><br>简洁说明<br>perf –help之后可以看到perf的二级命令。<br>序号 命令 作用<br>1 annotate 解析perf record生成的perf.data文件，显示被注释的代码。<br>2 archive 根据数据文件记录的build-id，将所有被采样到的elf文件打包。利用此压缩包，可以再任何机器上分析数据文件中记录的采样数据。<br>3 bench perf中内置的benchmark，目前包括两套针对调度器和内存管理子系统的benchmark。<br>4 buildid-cache 管理perf的buildid缓存，每个elf文件都有一个独一无二的buildid。buildid被perf用来关联性能数据与elf文件。<br>5 buildid-list 列出数据文件中记录的所有buildid。<br>6 diff 对比两个数据文件的差异。能够给出每个符号（函数）在热点分析上的具体差异。<br>7 evlist 列出数据文件perf.data中所有性能事件。<br>8 inject 该工具读取perf record工具记录的事件流，并将其定向到标准输出。在被分析代码中的任何一点，都可以向事件流中注入其它事件。<br>9 kmem 针对内核内存（slab）子系统进行追踪测量的工具<br>10 kvm 用来追踪测试运行在KVM虚拟机上的Guest OS。<br>11 list 列出当前系统支持的所有性能事件。包括硬件性能事件、软件性能事件以及检查点。<br>12 lock 分析内核中的锁信息，包括锁的争用情况，等待延迟等。<br>13 mem 内存存取情况<br>14 record 收集采样信息，并将其记录在数据文件中。随后可通过其它工具对数据文件进行分析。<br>15 report 读取perf record创建的数据文件，并给出热点分析结果。<br>16 sched 针对调度器子系统的分析工具。<br>17 script 执行perl或python写的功能扩展脚本、生成脚本框架、读取数据文件中的数据信息等。<br>18 stat 执行某个命令，收集特定进程的性能概况，包括CPI、Cache丢失率等。<br>19 test perf对当前软硬件平台进行健全性测试，可用此工具测试当前的软硬件平台是否能支持perf的所有功能。<br>20 timechart 针对测试期间系统行为进行可视化的工具<br>21 top 类似于linux的top命令，对系统性能进行实时分析。<br>22 trace 关于syscall的工具。<br>23 probe 用于定义动态检查点。</p><h3 id="Demo6-cpp源码"><a href="#Demo6-cpp源码" class="headerlink" title="Demo6.cpp源码"></a>Demo6.cpp源码</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br></pre></td><td class="code"><pre><span class="line">#include &lt;iostream&gt;  </span><br><span class="line">using namespace std;  </span><br><span class="line">void func1() &#123;  </span><br><span class="line"> int i &#x3D; 0;  </span><br><span class="line"> while (i &lt; 10) &#123;  </span><br><span class="line"> ++i;  </span><br><span class="line"> &#125;  </span><br><span class="line">&#125;  </span><br><span class="line">void func2() &#123;  </span><br><span class="line"> int i &#x3D; 0;  </span><br><span class="line"> while (i &lt; 20) &#123;  </span><br><span class="line"> ++i;  </span><br><span class="line"> &#125;  </span><br><span class="line">&#125;  </span><br><span class="line">void func3() &#123;  </span><br><span class="line"> for (int i &#x3D; 0; i &lt; 100; ++i) &#123;  </span><br><span class="line"> func1();  </span><br><span class="line"> func2();  </span><br><span class="line"> &#125;  </span><br><span class="line">&#125;  </span><br><span class="line">void func4() &#123;  </span><br><span class="line"> for (int i &#x3D; 0; i &lt; 10; ++i) &#123;  </span><br><span class="line"> func3();  </span><br><span class="line"> &#125;  </span><br><span class="line">&#125;  </span><br><span class="line">void func5() &#123;  </span><br><span class="line"> for (int i &#x3D; 0; i &lt; 10; ++i) &#123;  </span><br><span class="line"> func4();  </span><br><span class="line"> &#125;  </span><br><span class="line">&#125;  </span><br><span class="line">void func6() &#123;  </span><br><span class="line"> for (int i &#x3D; 0; i &lt; 10; ++i) &#123;  </span><br><span class="line"> func5();  </span><br><span class="line"> &#125;  </span><br><span class="line">&#125;  </span><br><span class="line">void func7() &#123;  </span><br><span class="line"> for (int i &#x3D; 0; i &lt; 10; ++i) &#123;  </span><br><span class="line"> func6();  </span><br><span class="line"> &#125;  </span><br><span class="line">&#125;  </span><br><span class="line">int main()&#123;  </span><br><span class="line"> func7();  </span><br><span class="line"> return 0;  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="关于最大采样频率"><a href="#关于最大采样频率" class="headerlink" title="关于最大采样频率"></a>关于最大采样频率</h3><p>相关参数：</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">&#x2F;proc&#x2F;sys&#x2F;kernel&#x2F;  </span><br><span class="line">perf\_cpu\_time\_max\_percent： perf分析工具最大能够占用CPU性能的百分比0：不限制1~100：百分比值  </span><br><span class="line">perf\_event\_max\_sample\_rate：  设置perf_event的最大取样速率，默认值为100000  </span><br><span class="line">perf采样使用会占用cpu，所以默认限制最大是perf\_cpu\_time\_max\_percent&#x3D;25，超过就会触发告警，并调整采样速率，保持不要超过限制perf\_event\_max\_sample\_rate。  </span><br><span class="line">perf\_cpu\_time\_max\_percent设置为0，此时就不会在去监控cpu的占用率了。  </span><br><span class="line">参考信息: linux - perf 支持的最大采样频率：[https:&#x2F;&#x2F;www.coder.work&#x2F;article&#x2F;1509862](https:&#x2F;&#x2F;www.coder.work&#x2F;article&#x2F;1509862)  </span><br><span class="line">perf参数问题处理:https:&#x2F;&#x2F;blog.csdn.net&#x2F;megan_free&#x2F;article&#x2F;details&#x2F;84993547</span><br></pre></td></tr></table></figure>]]></content>
    
    <summary type="html">
    
      &lt;h2 id=&quot;宏观资料&quot;&gt;&lt;a href=&quot;#宏观资料&quot; class=&quot;headerlink&quot; title=&quot;宏观资料&quot;&gt;&lt;/a&gt;宏观资料&lt;/h2&gt;
    
    </summary>
    
    
      <category term="07通用技术" scheme="https://hexo.yuanjh.cn/categories/07%E9%80%9A%E7%94%A8%E6%8A%80%E6%9C%AF/"/>
    
      <category term="w主机系统软件" scheme="https://hexo.yuanjh.cn/categories/07%E9%80%9A%E7%94%A8%E6%8A%80%E6%9C%AF/w%E4%B8%BB%E6%9C%BA%E7%B3%BB%E7%BB%9F%E8%BD%AF%E4%BB%B6/"/>
    
    
      <category term="07通用技术/w主机系统软件/性能工具" scheme="https://hexo.yuanjh.cn/tags/07%E9%80%9A%E7%94%A8%E6%8A%80%E6%9C%AF-w%E4%B8%BB%E6%9C%BA%E7%B3%BB%E7%BB%9F%E8%BD%AF%E4%BB%B6-%E6%80%A7%E8%83%BD%E5%B7%A5%E5%85%B7/"/>
    
  </entry>
  
  <entry>
    <title>性能工具01_工具链</title>
    <link href="https://hexo.yuanjh.cn/hexo/ae195f51/"/>
    <id>https://hexo.yuanjh.cn/hexo/ae195f51/</id>
    <published>2024-04-09T22:03:21.000Z</published>
    <updated>2026-03-11T16:45:17.863Z</updated>
    
    <content type="html"><![CDATA[<h2 id="Cpu"><a href="#Cpu" class="headerlink" title="Cpu"></a>Cpu</h2><h3 id="概述"><a href="#概述" class="headerlink" title="概述"></a>概述</h3><p>CPU性能指标<br>  （1）CPU使用率：<br>1） 用户态CPU使用率（包括用户态 user 和低优先级用户态 nice）、<br>2） 系统CPU使用率、<br>3） 等待 I/O 的CPU使用率、<br>4） 软中断和硬中断的CPU使用率、<br>5） 虚拟机占用的CPU使用率。<br>  （2）平均负载 Load Average：过去 1 分钟、过去 5 分钟和过去 15 分钟的平均负载<br>  （3）进程上下文切换：<br>1） 无法获取资源而导致的自愿上下文切换；<br>2） 被系统强制调度导致的非自愿上下文切换。<br>  （4）CPU缓存命中率：因为CPU处理速度比内存访问速度快得多，则需要等待内存的响应。为了协调两者性能差距，出现了CPU的多级缓存。缓存命中率，衡量的是CPU缓存的复用情况，命中率越高、复用越多，性能越好。<br><img src="/images/20230309182706665_9746.jpg" alt=""><br>把提供CPU性能指标的工具做成了一个表格，方便你梳理关系和理解记忆，当然，你也可以当成一个”指标工具”指南来使用。<br><img src="/images/20230309182706529_9622.png" alt=""><br>第二个维度，从工具出发。也就是当你已经安装了某个工具后，要知道这个工具能提供哪些指标。<br><img src="/images/20230309182706389_30505.jpg" alt=""><br>注意，我在这个图中只列出了最核心的几个性能工具，并没有列出所有。这么做，一方面是不想用大量的工具列表吓到你。在学习之初就接触所有或核心或小众的工具，不见得是好事。另一方面，是希望你能先<strong>把重心放在核心工具上，毕竟熟练掌握它们，就可以解决大多数问题</strong>。<br>我相信到这一步，你对CPU的性能指标已经非常熟悉，也清楚每种性能指标分别能用什么工具来获取。<br>那是不是说，<strong>每次碰到CPU的性能问题，你都要把上面这些工具全跑一遍，然后再把所有的CPU 性能指标全分析一遍呢</strong>?<br>你估计觉得这种简单查找的方式，就像是在傻找。不过，别笑话，因为最早的时候我就是这么做的。把所有的指标都查出来再统一分析，当然是可以的，也很可能找到系统的潜在瓶颈。但是这种方法的效率真的太低了! 耗时耗力不说，在庞大的指标体系面前，你一不小心可能就忽路了某个细节，导致白干一场。我就吃过好多次这样的苦。<br>所以，在<strong>实际生产环境中，我们通常都希望尽可能快地定位系统的瓶颈，然后尽可能快地优化性能，也就是要又快又准地解决性能问题</strong>。<br>那有没有什么方法，可以又快又准找出系统瓶颈呢?答案是肯定的。<br>虽然CPU的性能指标比较多，但要知道，既然都是描述系统的CPU性能，它们就不会是完全孤立的，<strong>很多指标间都有一定的关联</strong>。想弄清楚性能指标的关联性，就要通晓每种性能指标的工作原理。这也是为什么我在介绍每个性能指标时，都要穿插讲解相关的系统原理，希望你能记住这一点。<br>举个例子，用户CPU使用率高，我们应该去排查进程的用户态而不是内核态。因为用户CPU 使用率反映的就是用户态的CPU 使用情况，而内核态的CPU使用情况只会反映到系统CPU使用率上。<br>你看，有这样的基本认识，我们就可以缩小排查的范围，省时省力。<br>所以，为了缩小排查范围，我通常会先运行几个支持指标较多的工具，如top、vmstat 和pidstat。为什么是这三个工具呢?仔细看看下面这张图，你就清楚了。<br><img src="/images/20230309182706249_29621.jpg" alt="">这张图里，我列出了 top、vmstat和pidstat 分别提供的重要的CPU指标，并用虚线表示关联关系，对应出了性能分析下一步的方向。<br>通过这张图你可以发现，这三个命令，几乎包含了所有重要的CPU性能指标比如∶<br>● 从 top的输出可以得到各种CPU使用率以及僵尸进程和平均负载等信息。<br>● 从vmstat的输出可以得到上下文切换次数、中断次数、运行状态和不可中断状态的进程数。<br>● 从 pidstat的输出可以得到进程的用户CPU使用率、系统CPU使用率、以及自愿上下文切换和非自愿上下文切换情况。</p><h3 id="CPU使用率"><a href="#CPU使用率" class="headerlink" title="CPU使用率"></a>CPU使用率</h3><p>相关命令：top，vmstat，mpstat，iostat -c<br><img src="/images/20230309182706120_16371.jpg" alt=""><br><img src="/images/20230309182705989_22804.jpg" alt=""></p><h3 id="平均负载-Load-Average"><a href="#平均负载-Load-Average" class="headerlink" title="平均负载 Load Average"></a>平均负载 Load Average</h3><p>相关命令：uptime,top<br>系统的平均活跃进程数。Uptime<br><img src="/images/20230309182705849_11728.jpg" alt=""><br>统计系统当前的运行状况，输出的信息依次为：系统现在的时间、系统从上次开机到现在运行了多长时间、系统目前有多少登陆用户、系统在一分钟内、五分钟内、十五分钟内的平均负载。<br>这里需要注意的是load average这个输出值，<strong>这三个值的大小一般不能大于系统CPU的个数</strong>，例如，本输出中系统有8个CPU,<strong>如果load average的三个值长期大于8时，说明CPU很繁忙，负载很高，可能会影响系统性能</strong>，但是偶尔大于8时，倒不用担心，一般不会影响系统性能。相反，如果load average的输出值小于CPU的个数，则表示CPU还有空闲的时间片，比如本例中的输出，CPU是非常空闲的。</p><h3 id="进程上下文切换"><a href="#进程上下文切换" class="headerlink" title="进程上下文切换"></a>进程上下文切换</h3><p>相关命令：vmstat，pidstat<br><img src="/images/20230309182705719_4319.jpg" alt=""><br><img src="/images/20230309182705580_30721.png" alt=""></p><h3 id="CPU缓存命中率（暂无）"><a href="#CPU缓存命中率（暂无）" class="headerlink" title="CPU缓存命中率（暂无）"></a>CPU缓存命中率（暂无）</h3><p>相关命令：没找到</p><h3 id="案例"><a href="#案例" class="headerlink" title="案例"></a>案例</h3><p>CPU使用率过高的总体分析步骤<br>  Step1：通过 top、pidstat 找到哪个进程CPU使用率过高；<br>  Step2：通过 perf 找到该进程中具体哪个函数使用过高。$ perf top -g -p<pid_id><br>  Step3：通过 grep 查看该函数中的具体内容。$ grep -nr “&lt;function_name&gt;” &lt;file_path&gt;<br>性能问题：<br>  （1）用户 CPU 和 Nice CPU 高，说明用户态进程占用了较多的 CPU，所以应该着重排查进程的性能问题。<br>  （2）系统 CPU 高，说明内核态占用了较多的 CPU，所以应该着重排查内核线程或者系统调用的性能问题。<br>  （3）I/O 等待 CPU 高，说明等待 I/O 的时间比较长，所以应该着重排查系统存储是不是出现了 I/O 问题。<br>  （4）软中断和硬中断高，说明软中断或硬中断的处理程序占用了较多的CPU，所以应该着重排查内核中的中断服务程序。<br>样例01，pidstat 输出的进程用户CPU使用率升高，会导致 top输出的用户 CPU使用率升高。所以，当发现 top输出的用户CPU使用率有问题时，可以跟 pidstat的输出做对比，观察是否是某个进程导致的问题。<br>而找出导致性能问题的进程后，就要用进程分析工具来分析进程的行为，比如使用 strace 分析系统调用情况，以及使用 perf分析调用链中各级函数的执行情况。<br>样例02，top输出的平均负载升高，可以跟 vmstat输出的运行状态和不可中断状态的进程数做对比，观察是哪种进程导致的负载升高。<br>● 如果是不可中断进程数增多了，那么就需要做I/O的分析，也就是用dstat或sar等工具，进一步分析I/0的情况。<br>● 如果是运行状态进程数增多了，那就需要回到 top和 pidstat，找出这些处于运行状态的到底是什么进程，然后再用进程分析工具，做进一步分析。<br>样例03，当发现 top输出的软中断 CPU使用率升高时，可以查看/proc/softirqs 文件中各种类型软中断的变化情况，确定到底是哪种软中断出的问题。比如，发现是网络接收中断导致的问题，那就可以继续用网络分析工具 sar和 tcpdump 来分析。<br>样例04，系统的CPU使用率升高的案例。我们先用 top观察到了系统CPU升高，但通过 top 和 pidstat，却找不出高CPU使用率的进程。于是，我们重新审视 top的输出，又从CPU使用率不高但处于Running状态的进程入手，找出了可疑之处，最终通过 perf record和 perf report，发现原来是短时进程在捣鬼。<br>样例05，系统的 CPU 使用率很高，却找不到高 CPU 的应用<br>  系统的 CPU 使用率，不仅包括进程用户态和内核态的运行，还包括中断处理、等待 I/O 以及内核线程等。所以，当你发现系统的 CPU 使用率很高的时候，不一定能找到相对应的高 CPU 使用率的进程。<br>  如下系统总CPU使用率80.8%，而单个进程的CPU使用率都较小。需要通过 top 、pidstat 等交叉确认系统和各进程的CPU使用率。<br>  并且仔细观察进程列表中的状态S，查看R、S等状态的进程是否正常。</pid_id></p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">$ top  </span><br><span class="line">%Cpu(s): 80.8 us, 15.1 sy, 0.0 ni, 2.8 id, 0.0 wa, 0.0 hi, 1.3 si, 0.0 st  </span><br><span class="line">PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND  </span><br><span class="line">6882 root 20 0 8456 5052 3884 S 2.7 0.1 0:04.78 docker-containe  </span><br><span class="line">6947 systemd+ 20 0 33104 3716 2340 S 2.7 0.0 0:04.92 nginx  </span><br><span class="line">7494 daemon 20 0 336696 15012 7332 S 2.0 0.2 0:03.55 php-fpm</span><br></pre></td></tr></table></figure><p>发生以上情况的原因：<br>（1）进程在不停地崩溃重启，比如因为段错误、配置错误等等，这时，进程在退出后可能又被监控系统自动重启了，而启动过程的资源初始化，很可能会占用相当多的 CPU。<br>（2）这些进程都是短时进程，也就是在其他应用内部通过 exec 调用的外面命令。这些命令一般都只运行很短的时间就会结束，你很难用 top 这种间隔时间比较长的工具发现。<br>发送上述问题的解决方法是找到父进程，从父进程入手，排查问题：<br>方法一：<br>（1）通过 top、pidstat 等找到可疑进程；<br>（2）通过 pstree 用树状形式显示该进程与其他进程的关系；<br>（3）通过 grep 找到具体调用代码<br>方法二：<br>（1）通过 perf record -g // 记录性能事件，等待大约 几秒后按 Ctrl+C 退出<br>（2）通过 perf report<br>方法三：<br>execsnoop 就是一个专为短时进程设计的工具，一般用于分析 Linux 内核的运行时行为。它通过 ftrace 实时监控进程的 exec() 行为，并输出短时进程的基本信息，包括进程 PID、父进程 PID、命令行参数以及执行的结果。<br>  <a href="https://github.com/brendangregg/perf-tools/blob/master/execsnoop">https://github.com/brendangregg/perf-tools/blob/master/execsnoop</a><br>样例06，系统中出现大量不可中断进程和僵尸进程<br> 不可中断状态，是为了保证进程数据与硬件状态一致，并且正常情况下，不可中断状态在很短时间内就会结束。所以，短时的不可中断状态进程，我们一般可以忽略。但如果系统或硬件发生了故障，进程可能会在不可中断状态保持很久，甚至导致系统中出现大量不可中断进程。这时系统可能出现了 I/O 等性能问题。<br>  僵尸进程，这是多进程应用很容易碰到的问题。正常情况下，当一个进程创建了子进程后，它应该通过系统调用 wait() 或者 waitpid() 等待子进程结束，回收子进程的资源；而子进程在结束时，会向它的父进程发送 SIGCHLD 信号，所以，父进程还可以注册 SIGCHLD 信号的处理函数，异步回收资源。如果父进程没这么做，或是子进程执行太快，父进程还没来得及处理子进程状态，子进程就已经提前退出，那这时的子进程就会变成僵尸进程。<br>  通常，僵尸进程持续的时间都比较短，在父进程回收它的资源后就会消亡；或者在父进程退出后，由 init 进程回收后也会消亡。但是一旦父进程没有处理子进程的终止，还一直保持运行状态，那么子进程就会一直处于僵尸状态。大量的僵尸进程会用尽 PID 进程号，导致新进程不能创建。<br><img src="/images/20230309182705444_32544.jpg" alt=""><br>第一点， iowait 太高了，导致系统的平均负载升高，甚至达到了系统 CPU 的个数。<br>第二点，僵尸进程在不断增多，说明有程序没能正确清理子进程的资源。<br>僵尸进程分析<br>既然僵尸进程是因为父进程没有回收子进程的资源而出现的，那么，也就是找出父进程的问题。<br>（1）通过 pstree -aps 找出当前进程的父进程。// -a 表示输出命令行选项 p 表示 PID s 表示指定进程的父进程<br>（2）查看父进程的代码，看看子进程结束的处理是否正确，比如有没有调用 wait() 或 waitpid() ，或是，有没有注册 SIGCHLD 信号的处理函数。<br>故障分析 | 大量短时进程导致 cpu 负载过高案例一则:<a href="https://cloud.tencent.com/developer/article/2010964">https://cloud.tencent.com/developer/article/2010964</a><br>性能分析（3）- 短时进程导致用户 CPU 使用率过高案例:<a href="http://www.manongjc.com/detail/57-ocypedxbsyhbphv.html">www.manongjc.com/detail/57-ocypedxbsyhbphv.html</a><br>短时进程，我还介绍了一个专门的工具 execsnoop，它可以实时监控进程调用的外部命令。</p><h2 id="内存"><a href="#内存" class="headerlink" title="内存"></a>内存</h2><h3 id="概述-1"><a href="#概述-1" class="headerlink" title="概述"></a>概述</h3><p>下面这张图，就是一个迅速定位内存瓶颈的流程。我们可以通过 free 和 vmstat 输出的性能指标，确认内存瓶颈；然后，再根据内存问题的类型，进一步分析内存的使用、分配、泄漏以及缓 存等，最后找出问题的来源。<br><img src="/images/20230309182705309_6452.png" alt="在这里插入图片描述"><br>很多内存的性能指标，也来源于 /proc 文件系统(比如 /proc/meminfo、/proc/slabinfo 等)，它们也都应该通过监控系统监控起来。这样，当收到内存告警时，就可以从监控系统中，直接得到上图中的各项性能指标，从而加快性能问题的定位过程。<br>比如说，当收到内存不足的告警时，首先可以从监控系统中。找出占用内存最多的几个进程。 然后，再根据这些进程的内存占用历史，观察是否存在内存泄漏问题。确定出最可疑的进程后， 再登录到进程所在的 Linux 服务器中，分析该进程的内存空间或者内存分配，最后弄清楚进程为什么会占用大量内存。</p><h3 id="各部分空间分布"><a href="#各部分空间分布" class="headerlink" title="各部分空间分布"></a>各部分空间分布</h3><p>相关命令：free<br><img src="/images/20230309182705169_18670.jpg" alt=""><br>Mem 行是内存的使用情况。<br>buffers/cache 行是物理内存的缓存统计情况。<br>Swap 行是交换空间的使用情况。<br>前面分别介绍过了物理内存和Swap分区。这里再介绍一下buffers和cache。<br><strong>free 与 available 的区别</strong><br>free 是真正尚未被使用的物理内存数量。<br>available 是应用程序认为可用内存数量，available = free + buffer + cache (注：只是大概的计算方法)<br>Linux 为了提升读写性能，会消耗一部分内存资源缓存磁盘数据，对于内核来说，buffer 和 cache 其实都属于已经被使用的内存。但当应用程序申请内存时，如果 free 内存不够，内核就会回收 buffer 和 cache 的内存来满足应用程序的请求。<br>当free内存接近零时，有些人会非常担心。但是接近零的free内存很酷，这实际上<strong>意味着您的内核正在将内存用于诸如缓存之类的良好用途</strong>。<br><strong>buffer与cache</strong><br>A buffer is something that has yet to be “written” to disk.<br>A cache is something that has been “read” from the disk and stored for later use.<br>简单点说：<br>buffers 就是存放要输出到disk（块设备）的数据，缓冲满了一次写，<strong>提高IO性能</strong>（内存 -&gt; 磁盘）<br>cached 就是存放从disk上读出的数据，常用的缓存起来，<strong>减少IO</strong>（磁盘 -&gt; 内存）<br>buffer 和 cache，两者都是RAM中的数据。简单来说，<strong>buffer是即将要被写入磁盘的，cache是被从磁盘中读出来的</strong>。<br>这里也有不同意见<br>结论：读文件时数据会缓存到 Cache 中，而读磁盘时数据会缓存到 Buffer 中。<br>Buffer 既可以用作“将要写入磁盘数据的缓存”，也可以用作“从磁盘读取数据的缓存”。<br>Cache 既可以用作“从文件读取数据的页缓存”，也可以用作“写文件的页缓存”。<br>  简单来说，Buffer 是对磁盘数据的缓存，而 Cache 是文件内容数据的缓存，它们既会用在读请求中，也会用在写请求中。<br>来自：Linux性能优化从入门到实战：09 内存篇：Buffer和Cache:<a href="https://blog.csdn.net/qccz123456/article/details/95369115">https://blog.csdn.net/qccz123456/article/details/95369115</a></p><h3 id="特定进程占用swap"><a href="#特定进程占用swap" class="headerlink" title="特定进程占用swap"></a>特定进程占用swap</h3><p>相关命令：Cat /proc/<pid>/smaps<br><img src="/images/20230309182705039_14677.jpg" alt=""></pid></p><h3 id="缓存的读写命中-系统"><a href="#缓存的读写命中-系统" class="headerlink" title="缓存的读写命中(系统)"></a>缓存的读写命中(系统)</h3><p>相关命令：cachestat<br><img src="/images/20230309182704910_10970.png" alt=""><br>TOTAL ，表示总的 I/O 次数；<br>MISSES ，表示缓存未命中的次数；<br>HITS ，表示缓存命中的次数；<br>DIRTIES， 表示新增到缓存中的脏页数；<br>BUFFERS_MB 表示 Buffers 的大小，以 MB 为单位；<br>CACHED_MB 表示 Cache 的大小，以 MB 为单位。</p><h3 id="进程的缓存命中（进程）"><a href="#进程的缓存命中（进程）" class="headerlink" title="进程的缓存命中（进程）"></a>进程的缓存命中（进程）</h3><p>相关命令:cachetop<br><img src="/images/20230309182704779_29586.jpg" alt=""><br>默认按照缓存的<strong>命中次数（HITS）排序</strong>，展示了每个进程的缓存命中情况。具体到每一个指标，这里的 HITS、MISSES和DIRTIES ，跟 cachestat 里的含义一样，分别代表间隔时间内的缓存命中次数、未命中次数以及新增到缓存中的脏页数。<br>而 READ_HIT 和 WRITE_HIT ，分别表示读和写的缓存命中率。</p><h3 id="特定文件的缓存大小"><a href="#特定文件的缓存大小" class="headerlink" title="特定文件的缓存大小"></a>特定文件的缓存大小</h3><p>相关命令： ​pcstat​​<br>pcstat 是一个基于 Go 语言开发的工具，所以安装它之前，你首先应该安装 Go 语言，下面就是一个 pcstat 运行的示例，它展示了 /bin/ls 这个文件的缓存情况：<br><img src="/images/20230309182704659_22934.png" alt=""><br>这个输出中，Cached 就是 /bin/ls 在缓存中的大小，而 Percent 则是缓存的百分比。你看到它们都是 0，这说明 /bin/ls 并不在缓存中。<br>接着，如果你执行一下 ls 命令，再运行相同的命令来查看的话，就会发现 /bin/ls 都在缓存中了：<br><img src="/images/20230309182704529_25775.png" alt=""></p><h3 id="进程内存占用详情"><a href="#进程内存占用详情" class="headerlink" title="进程内存占用详情"></a>进程内存占用详情</h3><p>相关命令：pmap<br>显示进程的内存映射，显示它们的大小、权限及映射对象。<br><img src="/images/20230309182704410_30949.jpg" alt=""></p><h3 id="内存带宽"><a href="#内存带宽" class="headerlink" title="内存带宽"></a>内存带宽</h3><p>相关命令: mbw -q -n 10 256<br><img src="/images/20230309182704279_11658.jpg" alt=""><br>3种method类型含义<br><img src="/images/20230309182704149_29897.jpg" alt=""></p><h2 id="Io"><a href="#Io" class="headerlink" title="Io"></a>Io</h2><h3 id="概述-2"><a href="#概述-2" class="headerlink" title="概述"></a>概述</h3><p>使用 iostat ，发现磁盘 I/O 存在性能瓶颈(比如 I/O 使用率过高、 响应时间过长或者等待队列长度突然增大等)后，可以再通过 pidstat、 vmstat 等，确认 I/O 的来源。接着，再根据来源的不同，进一步分析文件系统和磁盘的使用率、缓存以及进程的 I/O 等，从而揪出 I/O 问题的真凶。<br><img src="/images/20230309182704020_22000.png" alt="https://img-blog.csdnimg.cn/463252430eb14400a2cf88706b6a9030.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3poYW5nbHUwMzAy,size_16,color_FFFFFF,t_70#pic_center"><br>同 CPU 和内存性能类似，很多磁盘和文件系统的性能指标，也来源于 /proc 和 /sys 文件系统 (比如 /proc/diskstats、/sys/block/sda/stat 等)。自然，它们也应该通过监控系统监控起 来。这样，当收到 I/O 性能告警时，就可以从监控系统中，直接得到上图中的各项性能指标， 从而加快性能定位的过程。<br>比如，当发现某块磁盘的 I/O 使用率为 100% 时，首先可以从监控系统中。找出 I/O 最多的进程。然后，再登录到进程所在的 Linux 服务器中，借助 strace、lsof、perf 等工具，分析该进程的 I/O 行为。最后，再结合应用程序的原理，找出大量 I/O 的原因。</p><h3 id="磁盘角度的io负载"><a href="#磁盘角度的io负载" class="headerlink" title="磁盘角度的io负载"></a>磁盘角度的io负载</h3><p>相关命令: iostat<br><img src="/images/20230309182703889_18666.jpg" alt=""><br>结果解析:<br>tps 该设备每秒的传输次数，“一次传输”意思是“一次I/O请求”。多个逻辑请求可能会被合并为“一次I/O请求”，“一次传输”请求的大小是未知的<br>kB_read/s 每秒从设备（drive expressed）读取的数据量<br>kB_wrtn/s 每秒向设备（drive expressed）写入的数据量<br>kB_read 读取的总数据量<br>kB_wrtn 写入的总数据量<br><img src="/images/20230309182703759_15265.jpg" alt=""><br>结果解析：<br>rrqm/s 每秒合并读操作的次数，如果两个读操作读取相邻的数据块时，可以被合并成一个，以提高效率。合并的操作通常是I/O scheduler（也叫elevator）负责的。<br>wrqm/s 每秒合并写操作的次数<br>r/s 每秒读操作的次数<br>w/s 每秒写操作的次数<br>rkB/s 每秒读取的字节数（KB）<br>wkB/s 每秒写入的字节数（KB）<br>avgrq-sz 每个IO的平均扇区数，即所有请求的平均大小，以扇区（512字节）为单位<br>avgqu-sz 平均未完成的IO请求数量，即平均意义上的请求队列长度<br>await 平均每个IO所需要的时间，包括在队列等待的时间，也包括磁盘控制器处理本次请求的有效时间<br>r_await 每个读操作平均所需要的时间，不仅包括硬盘设备读操作的时间，也包括在内核队列中的时间<br>w_await 每个写操平均所需要的时间，不仅包括硬盘设备写操作的时间，也包括在队列中等待的时间<br>svctm 表面看是每个IO请求的服务时间，不包括等待时间，但是实际上，这个指标已经废弃。实际上，iostat工具没有任何一输出项表示的是硬盘设备平均每次IO的时间<br>%util 表示该设备有I/O（即非空闲）的时间比率，不考虑I/O有多少，只考虑有没有，由于硬盘设备有并行处理多个i/o请求的能力，<strong>所以%util即使达到100%也不意味着设备饱和</strong>了。<br>举个简化的例子：某硬盘处理单个I/O需要0.1秒，有能力同时处理10个I/O请求，那么当10个I/O请求依次顺序提交的时候，需要1秒才能全部完成，在1秒的采样周期里%util达到100%；而如果10个I/O请求一次性提交的话，0.1秒就全部完成，在1秒的采样周期里%util只有10%。可见，即使%util高达100%，硬盘也仍然有可能还有余力处理更多的I/O请求，即没有达到饱和状态。<br>不足<br>iostat 的输出结果大多数是 一段时间内的平均值，因此<strong>难以反映峰值情况</strong>；<br>iostat 仅能对 系统整体情况进行分析汇报，却<strong>不能针对某个进程</strong>进行深入分析；<br>iostat 未单独统计IO处理信息，而是 将IO处理时间 和 IO等待时间 合并统计，因此包括await在内的指标并<strong>不能非常准确地衡量磁盘性能</strong>表现。</p><h3 id="进程io"><a href="#进程io" class="headerlink" title="进程io"></a>进程io</h3><p>相关命令：iotop，pidstat，ioprofile<br><img src="/images/20230309182703640_579.jpg" alt=""><br>pidstat -p xxx -d 1 10<br><img src="/images/20230309182703510_31135.jpg" alt=""><br>进程打开文件列表: lsof -p<pid><br><img src="/images/20230309182703380_1810.jpg" alt=""></pid></p><h3 id="线程io"><a href="#线程io" class="headerlink" title="线程io"></a>线程io</h3><p>相关命令: pidstat<br>分析应用程序中哪一个线程占用的io比较高<br>shell&gt; pidstat -dt -p 73739 1 执行两三秒即可<br>Average: 1000 - 73823 0.00 233133.98 0.00 |<strong>mysqld<br>Average: 1000 - 74674 0.00 174291.26 0.00 |</strong>mysqld<br>11:56:18 PM 1000 - 74770 124928.00 74688.00 0.00 |<strong>mysqld<br>11:56:17 PM 1000 - 74770 124603.77 73358.49 0.00 |</strong>mysqld<br>Average: 1000 - 74770 124761.17 74003.88 0.00 |__mysqld<br>由上可知：74770这个线程占用的io比较高</p><h2 id="Net"><a href="#Net" class="headerlink" title="Net"></a>Net</h2><h3 id="概述-3"><a href="#概述-3" class="headerlink" title="概述"></a>概述</h3><p>网络性能，其实包含两类资源，即网络接口和内核资源。网络性能的分析，要从 Linux 网络协议栈的原理来切入。下面这张图，就是 Linux 网络协议栈的基本原理，包括应用层、套机字接口、传输层、网络层以及链路层等。<br><img src="/images/20230309182703259_29630.png" alt="在这里插入图片描述"><br>而要分析网络的性能，自然也是要从这几个协议层入手，通过使用率、饱和度以及错误数这几类 性能指标，观察是否存在性能问题。比如：<br>在链路层，可以从网络接口的吞吐量、丢包、错误以及软中断和网络功能卸载等角度分析；<br>在网络层，可以从路由、分片、叠加网络等角度进行分析；<br>在传输层，可以从 TCP、UDP 的协议原理出发，从连接数、吞吐量、延迟、重传等角度进行 分析；<br>在应用层，可以从应用层协议(如 HTTP 和 DNS)、请求数(QPS)、套接字缓存等角度进 行分析。<br>同前面几种资源类似，网络的性能指标也都来源于内核，包括 /proc 文件系统(如 /proc/net)、网络接口以及 conntrack 等内核模块。这些指标同样需要被监控系统监控。这样，当收到网络告警时，就可以从监控系统中，查询这些协议层的各项性能指标，从而更快定位出性能问题。<br>比如，当我们收到网络不通的告警时，就可以从监控系统中，查找各个协议层的丢包指标，确认丢包所在的协议层。然后，从监控系统的数据中，确认网络带宽、缓冲区、连接跟踪数等软硬件， 是否存在性能瓶颈。最后，再登录到发生问题的 Linux 服务器中，借助 netstat、tcpdump、 bcc 等工具，分析网络的收发数据，并且结合内核中的网络选项以及 TCP 等网络协议的原理，找出问题的来源。</p><h3 id="连通性测试"><a href="#连通性测试" class="headerlink" title="连通性测试"></a>连通性测试</h3><p>相关命令：ping</p><h3 id="累计流量"><a href="#累计流量" class="headerlink" title="累计流量"></a>累计流量</h3><p>相关命令：ifconfig<br><img src="/images/20230309182703130_28928.jpg" alt=""><br>RX= =receive，接收，从开启到现在接收封包的情况，是下行流量。<br>TX= =Transmit，发送，从开启到现在发送封包的情况，是上行流量。</p><h3 id="实时流量"><a href="#实时流量" class="headerlink" title="实时流量"></a>实时流量</h3><p>相关命令:nload<br><img src="/images/20230309182702999_29287.jpg" alt=""><br>Nload –m<br><img src="/images/20230309182702870_1423.jpg" alt=""></p><h3 id="网络连接分析"><a href="#网络连接分析" class="headerlink" title="网络连接分析"></a>网络连接分析</h3><p>相关命令： Iftop<br><img src="/images/20230309182702744_31406.jpg" alt=""><br>第一行，是带宽，下面带有标尺，用来标示每个连接上的实时流量占用的带宽<br>中间部分，是所有的连接，默认显示的是主机名，可以通过参数显示ip，箭头表示数据方向<br>中间右侧三列，分别是该连接2s、10s、40s的平均流量<br>底部三行，分别表示发送、接收、汇总的流量<br>底部三行第2列，为iftop启动到现在的流量汇总<br>底部三行第3列，为峰值速率<br>第4列，为平均值<br>注意，流量单位为bit，非Byte<br>可以看到，通过iftop可以很容易看到<strong>各个连接的流量使用情况</strong>。</p><h3 id="进程占用流量"><a href="#进程占用流量" class="headerlink" title="进程占用流量"></a>进程占用流量</h3><p>端口定位法：iftop(-P )+lsof(-i:xx)<br><img src="/images/20230309182702609_6338.jpg" alt=""><br><img src="/images/20230309182702489_20118.png" alt=""><br>命令：nethogs<br><img src="/images/20230309182702359_26130.jpg" alt=""></p><h3 id="网卡性能测试"><a href="#网卡性能测试" class="headerlink" title="网卡性能测试"></a>网卡性能测试</h3><p>ethtool，物理属性速度<br>dmesg|grep eno2 | grep up，物理速度属性<br>speedtest-cli：针对固定ip的测试<br>nload：实际流量测试<br>iftop,nethogs：进程流量统计<br>iperf：双网卡直连方式测试<br>两个网卡用网线连接到同一个交换机上，或者直连，交换机交换最大速率不能低于待测试网卡的标称速率。<br>在两台机器上分别运行命令：<br>服务端命令：iperf -s -P 0 -i 1 -p 5001 -w 2M -f k<br>客户端命令：iperf -c 192.168.1.3 -i 1 -w 2M -t 600(服务端IP地址：192.168.1.3)</p><h2 id="其他"><a href="#其他" class="headerlink" title="其他"></a>其他</h2><h3 id="系统资源瓶颈识别和定位"><a href="#系统资源瓶颈识别和定位" class="headerlink" title="系统资源瓶颈识别和定位"></a>系统资源瓶颈识别和定位</h3><p>在系统监控的综合思路篇中，系统资源的瓶颈，可以通过 <strong>USE 法，即使用率、饱和度以及错误数</strong>这三类指标来衡量。系统的资源，可以分为硬件资源和软件资源两类。<br>硬件资源：CPU、内存、磁盘和文件系统以及网络等<br>软件资源：文件描述符数、连接跟踪数、套接字缓冲区大小等<br>在收到监控系统的告警时，可以对照这些资源列表，再根据不同的指标来进行定位。<br>其中，<strong>硬件资源瓶颈相对容易定位</strong>，cpu占用率，内存使用率等明确且清晰。<strong>软件资源由于不同应用的差异，并没有明确的界限区别正常还是异常</strong>。一个对A程序属于正常范畴的指标，对B程序则是异常，只能具体问题具体分析。</p><h3 id="应用程序瓶颈"><a href="#应用程序瓶颈" class="headerlink" title="应用程序瓶颈"></a>应用程序瓶颈</h3><p>部分瓶颈，直接来自应用程序。比如，最典型的应用程序性能问题，就是吞吐量(并发请求数)下降、错误率升高以及响应时间增大。<br>这些应用程序性能问题虽然各种各样，但就其本质来源，实际上<strong>只有三种，也就是资源瓶颈、依赖服务瓶颈以及应用自身的瓶颈</strong>。<br>第一种资源瓶颈，其实还是指刚才提到的 CPU、内存、磁盘和文件系统 I/O、网络以及内核资源等各类软硬件资源出现了瓶颈，从而导致应用程序的运行受限。对于这种情况，我们就可以用前面系统资源瓶颈模块提到的各种方法来分析。<br>第二种依赖服务的瓶颈，也就是诸如数据库、分布式缓存、中间件等应用程序，直接或者间接调用的服务出现了性能问题，从而导致应用程序的响应变慢，或者错误率升高。这说白了就是跨应用的性能问题，使用全链路跟踪系统，就可以帮你快速定位这类问题的根源。<br>最后一种，应用程序自身的性能问题，包括了多线程处理不当、死锁、业务算法的复杂度过高等等。对于这类问题，在应用程序指标监控以及日志监控中，观察关键环节的耗时和内部执行过程中的错误，就可以帮你缩小问题的范围。<br>不过，由于这是应用程序内部的状态，外部通常不能直接获取详细的性能数据，所以就需要应用程序在设计和开发时，就提供出这些指标，以便监控系统可以了解应用程序的内部运行状态。<br>如果这些手段过后还是无法找出瓶颈，我们还可以用系统资源模块提到的各类进程分析工具，来进行分析定位。比如：<br>可以用 strace，观察系统调用；<br>使用 perf 和火焰图，分析热点函数；<br>甚至使用动态追踪技术，来分析进程的执行状态。<br>当然，系统资源和应用程序本来就是相互影响、相辅相成的一个整体。实际上，<strong>很多资源瓶颈， 也是应用程序自身运行导致的。比如，进程的内存泄漏，会导致系统内存不足；进程过多的 I/O 请求，会拖慢整个系统的 I/O 请求等</strong>。<br>所以，很多情况下，资源瓶颈和应用自身瓶颈，其实都是同一个问题导致的，并不需要我们重复分析。</p><h3 id="性能分析工具集特征"><a href="#性能分析工具集特征" class="headerlink" title="性能分析工具集特征"></a>性能分析工具集特征</h3><p>工具体系非常庞大，围绕硬件的(英伟达nsight，英特尔Vtune等)，围绕系统的（vmstat,mpstat），围绕app的(perf,gprof,strace内核态)，围绕语言的(go的gprof,java,pyton等均有特定工具)<br>不同层次工具之间，功能上存在交叉<br>没有严谨的方法论，比如：按照一个手册12345后，就得得到确定结论，大多都需要具体问题具体分析</p><h2 id="问题排查-定位进程-gt-线程-gt-gstack线程堆栈现场"><a href="#问题排查-定位进程-gt-线程-gt-gstack线程堆栈现场" class="headerlink" title="问题排查,定位进程-&gt;线程-&gt;gstack线程堆栈现场"></a>问题排查,定位进程-&gt;线程-&gt;gstack线程堆栈现场</h2><p>CPU飙高排查步骤：<a href="https://blog.csdn.net/weixin_50914566/article/details/141939462">https://blog.csdn.net/weixin_50914566/article/details/141939462</a><br>性能分析之CPU分析-从CPU调用高到具体代码行（C/C++）：<a href="https://www.cnblogs.com/GaoLou/p/14897144.html">https://www.cnblogs.com/GaoLou/p/14897144.html</a></p><h2 id="命令响应解析"><a href="#命令响应解析" class="headerlink" title="命令响应解析"></a>命令响应解析</h2><h3 id="Top"><a href="#Top" class="headerlink" title="Top"></a>Top</h3><p><img src="/images/20230309182702239_16801.jpg" alt=""><br>命令参考<br>一文辨析，性能分析top命令中进程NI和PR:<a href="https://zhuanlan.zhihu.com/p/503042646">https://zhuanlan.zhihu.com/p/503042646</a><br>理解virt、res、shr之间的关系（linux系统篇）:<a href="https://baijiahao.baidu.com/s?id=1743908545937632735&amp;wfr=spider&amp;for=pc">https://baijiahao.baidu.com/s?id=1743908545937632735&amp;wfr=spider&amp;for=pc</a></p><h3 id="mpstat"><a href="#mpstat" class="headerlink" title="mpstat"></a>mpstat</h3><p>针对多核问题，比如多线程程序任务分配不均匀，无法充分利用cpu等<br>mpstat -P ALL<br><img src="/images/20230309182702109_11151.jpg" alt=""><br>参考：<br>系统调优–mpstat命令详解：<a href="https://blog.csdn.net/weixin_44175418/article/details/124986740">https://blog.csdn.net/weixin_44175418/article/details/124986740</a></p><h3 id="Vmstat"><a href="#Vmstat" class="headerlink" title="Vmstat"></a>Vmstat</h3><p><img src="/images/20230309182701979_19869.jpg" alt=""><br>上面每项的输出解释如下：<br> <strong>procs</strong><br> r列表示运行和等待cpu时间片的进程数，这个值如果长期大于系统CPU的个数，说明CPU不足，需要增加CPU。<br> b列表示在等待资源的进程数，比如正在等待I/O、或者内存交换等。<br> <strong>memory</strong><br> swpd列表示切换到内存交换区的内存数量（以k为单位）。如果swpd的值不为0，或者比较大，只要si、so的值长期为0，这种情况下一般不用担心，不会影响系统性能。<br> free列表示当前空闲的物理内存数量（以k为单位）<br> buff列表示buffers cache的内存数量，一般对块设备的读写才需要缓冲。<br> cache列表示page cached的内存数量，一般作为文件系统cached，频繁访问的文件都会被cached，如果cache值较大，说明cached的文件数较多，如果此时IO中bi比较小，说明文件系统效率比较好。<br> <strong>swap</strong><br> si列表示由磁盘调入内存，也就是内存进入内存交换区的数量。<br> so列表示由内存调入磁盘，也就是内存交换区进入内存的数量。<br>一般情况下，si、so的值都为0，如果si、so的值长期不为0，则表示系统内存不足。需要增加系统内存。<br> <strong>IO</strong><br>磁盘读写状况<br> Bi列表示从块设备读入数据的总量（即读磁盘）（每秒kb）。<br> Bo列表示写入到块设备的数据总量（即写磁盘）（每秒kb）<br>这里我们设置的bi+bo参考值为1000，如果超过1000，而且wa值较大，则表示系统磁盘IO有问题，应该考虑提高磁盘的读写性能。<br> <strong>system</strong><br>采集间隔内发生的中断数<br> in列表示在某一时间间隔中观测到的每秒设备中断数。<br> cs列表示每秒产生的上下文切换次数。<br>上面这2个值越大，会看到由内核消耗的CPU时间会越多。<br> <strong>CPU</strong><br>CPU的使用状态，此列是我们关注的重点。<br> us列显示了用户进程消耗的CPU 时间百分比。us的值比较高时，说明用户进程消耗的cpu时间多，但是如果长期大于50%，就需要考虑优化程序或算法。<br> sy列显示了内核进程消耗的CPU时间百分比。Sy的值较高时，说明内核消耗的CPU资源很多。<br>根据经验，us+sy的参考值为80%，如果us+sy大于 80%说明可能存在CPU资源不足。<br> id 列显示了CPU处在空闲状态的时间百分比。<br> wa列显示了IO等待所占用的CPU时间百分比。wa值越高，说明IO等待越严重，根据经验，wa的参考值为20%，如果wa超过20%，说明IO等待严重，引起IO等待的原因可能是磁盘大量随机读写造成的，也可能是磁盘或者磁盘控制器的带宽瓶颈造成的（主要是块操作）。<br>综上所述，<strong>在对CPU的评估中，需要重点注意的是procs项r列的值和CPU项中us、sy和id列的值</strong>。</p><h3 id="NetData"><a href="#NetData" class="headerlink" title="NetData"></a>NetData</h3><p><strong>安装</strong><br>sudo apt-get install zlib1g-dev uuid-dev libuv1-dev liblz4-dev libjudy-dev libssl-dev libmnl-dev gcc make git autoconf autoconf-archive autogen<br>sudo apt-get install netdata<br><strong>基本操作</strong></p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"># 启动NetData服务，并设置开机启动  </span><br><span class="line">sudo systemctl enable netdata  </span><br><span class="line">sudo systemctl start netdata  </span><br><span class="line"># 重启服务  </span><br><span class="line">sudo systemctl restart netdata  </span><br><span class="line"># 停止NetData服务  </span><br><span class="line">sudo systemctl stop netdata  </span><br><span class="line"># 更新NetData服务（重新拉去，重新运行）  </span><br><span class="line">cd netdata  </span><br><span class="line">git pull  </span><br><span class="line">sudo .&#x2F;netdata-installer.sh</span><br></pre></td></tr></table></figure><p><strong>功能开关</strong><br>修改文件：/etc/netdata/netdata.conf<br>修改[plugins]中的配置。原配置文件中大部分默认开启的，如果我们不需要某些图表的话，可以将注释去掉，改为no。然后重启服务，就可以禁用相应的图表。<br><strong>降低内存占用</strong><br>修改文件：/etc/netdata/netdata.conf<br>核心配置中的数据刷新率。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"># 降低cpu占用：  </span><br><span class="line"># 编辑：vim netdata.conf  </span><br><span class="line"> \[global\]  </span><br><span class="line"> update every &#x3D; 2  </span><br><span class="line"># 或者只修改apps部分：  </span><br><span class="line"> \[plugin:apps\]  </span><br><span class="line"> update every &#x3D; 2</span><br></pre></td></tr></table></figure><p><strong>第三方扩展插件（NVIDIA-SMI）</strong></p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"># 使用官方提供的脚本，生成对应文件的配置文件  </span><br><span class="line">cd &#x2F;etc&#x2F;netdata    </span><br><span class="line">sudo .&#x2F;edit-config python.d&#x2F;nvidia_smi.conf  </span><br><span class="line">修改文档内容  </span><br><span class="line"># 官方文档提供样例  </span><br><span class="line">loop_mode : yes \# 默认为yes。 如果设置为yes，则使用-l选项在单独的线程中执行nvidia-smi。  </span><br><span class="line">poll_seconds : 1 \# 默认为1。设置循环查询nvidia-smi工具的频率（秒数）。</span><br></pre></td></tr></table></figure><p><strong>监控数据的保存</strong><br>存入mongdb后端<br>sudo ./edit-config mongodb.conf<br>设置MongoDB URI，数据库名称和集合名称</p><h3 id="Glances"><a href="#Glances" class="headerlink" title="Glances"></a>Glances</h3><p><strong>安装</strong><br>pip install glances<br><strong>本机直接运行</strong><br>Glances<br><img src="/images/20230309182701849_4947.jpg" alt="_static/screenshot-wide.png"><br>说明：这个页面的说明文档在这，官方github的docs/aoa文件夹下<br>关于字段说明，交互项，排序规则，字符颜色控制等，想了解或修改相关模块配置，到aoa文件夹下查阅。<br>比如修改：进度显示样式<br><img src="/images/20230309182701699_5037.png" alt=""><br>对应文档：aoa/quicklook.rst<br>其他类似的</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">aoa&#x2F;connections.rst，tcp连接模块，  </span><br><span class="line">aoa&#x2F;cpu.rst，cpu模块  </span><br><span class="line">aoa&#x2F;load.rst，负载模块  </span><br><span class="line">aoa&#x2F;memory.rst，内存模块  </span><br><span class="line">aoa&#x2F;folders.rst，文件夹监控  </span><br><span class="line">aoa&#x2F;hddtemp.rst，硬件传感器温度  </span><br><span class="line">aoa&#x2F;sensors.rst，传感器温度，包含psutil, hddtemp, batinfo  </span><br><span class="line">aoa&#x2F;smart.rst，磁盘信息</span><br></pre></td></tr></table></figure><p>较为常用的还有ps的过滤<br>这里需要留意的是文档中：<br><img src="/images/20230309182701569_14126.jpg" alt=""><br>第一个意思是输入:python可以匹配出python开始的进程，亲测不行，其余3个ok<br>怀疑是软件版本问题，当前04上安装软件，提示如下：<br><img src="/images/20230309182701439_13716.png" alt=""><br><strong>监控其他机器（客户端服务端模式）</strong><br>server$ glances -s #服务侧启动服务<br>glances -c @server \s#客户端连接服务端显示数据<br><strong>网页模式：</strong><br>glances -w<br>浏览器打开：<a href="http://0.0.0.0:61208/">http://0.0.0.0:61208/</a><br>本机测试时报错:<br><img src="/images/20230309182701309_19087.jpg" alt="_static/screenshot-web.png"><br><img src="/images/20230309182701159_13128.jpg" alt=""><br><strong>不同颜色的含义：</strong><br>◆绿色：正常(OK)<br>◆蓝色：小心(careful)<br>◆紫色：警告(warning)<br>◆红色：致命(critical)<br>默认设置下，Glances 的阀值设置是：careful=50，warning=70，critical=90。你可以通过 “/etc/glances/” 目录下的默认配置文件 glances.conf 来自定义这些阀值。<br><strong>常用的热键列表：</strong><br>◆m：按内存占用排序进程<br>◆p：按进程名称排序进程<br>◆c：按 CPU 占用率排序进程<br>◆i：按 I/O 频率排序进程<br>◆a：自动排序进程<br>◆d：显示/隐藏磁盘 I/O 统计信息<br>◆f：显示/隐藏文件系统统计信息<br>◆s：显示/隐藏传感器统计信息<br>◆y：显示/隐藏硬盘温度统计信息<br>◆n：显示/隐藏网络统计信息<br>◆q：退出<br><strong>还有一些特性体现再和外部平台对接上</strong><br>比如：docs/api.rst，对外暴露的restful接口<br>docs/docker.rst，docker代替原生安装，对外暴露web服务<br>aoa/actions.rst，某状态持续多久后，执行特定命令（脚本）</p>]]></content>
    
    <summary type="html">
    
      &lt;h2 id=&quot;Cpu&quot;&gt;&lt;a href=&quot;#Cpu&quot; class=&quot;headerlink&quot; title=&quot;Cpu&quot;&gt;&lt;/a&gt;Cpu&lt;/h2&gt;
    
    </summary>
    
    
      <category term="07通用技术" scheme="https://hexo.yuanjh.cn/categories/07%E9%80%9A%E7%94%A8%E6%8A%80%E6%9C%AF/"/>
    
      <category term="w主机系统软件" scheme="https://hexo.yuanjh.cn/categories/07%E9%80%9A%E7%94%A8%E6%8A%80%E6%9C%AF/w%E4%B8%BB%E6%9C%BA%E7%B3%BB%E7%BB%9F%E8%BD%AF%E4%BB%B6/"/>
    
    
      <category term="07通用技术/w主机系统软件/性能工具" scheme="https://hexo.yuanjh.cn/tags/07%E9%80%9A%E7%94%A8%E6%8A%80%E6%9C%AF-w%E4%B8%BB%E6%9C%BA%E7%B3%BB%E7%BB%9F%E8%BD%AF%E4%BB%B6-%E6%80%A7%E8%83%BD%E5%B7%A5%E5%85%B7/"/>
    
  </entry>
  
  <entry>
    <title>深度学习回顾_06tensorflow快速入门</title>
    <link href="https://hexo.yuanjh.cn/hexo/4f51f2cb/"/>
    <id>https://hexo.yuanjh.cn/hexo/4f51f2cb/</id>
    <published>2024-03-13T22:54:44.000Z</published>
    <updated>2026-03-11T16:45:17.867Z</updated>
    
    <content type="html"><![CDATA[<p>前置知识<br>01,基础Python 编程<br>02,数组相关的知识<br>03,机器学习基础，感知机，神经网络<br>学习目的：tensorflow大概做什么的（近似”极值“（可能是局部极值）靠近器）</p><h2 id="基本概念"><a href="#基本概念" class="headerlink" title="基本概念"></a>基本概念</h2><h3 id="张量（Tensor）数组or列表"><a href="#张量（Tensor）数组or列表" class="headerlink" title="张量（Tensor）数组or列表"></a>张量（Tensor）数组or列表</h3><p>TensorFlow 内部使用tf.Tensor类的实例来表示张量，每个 tf.Tensor有两个属性：</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">dtype Tensor 存储的数据的类型，可以为tf.float32、tf.int32、tf.string…</span><br><span class="line">shape Tensor 存储的多维数组中每个维度的数组中元素的个数，如上面例子中的shape</span><br></pre></td></tr></table></figure><p>可以敲几行代码看一下 Tensor 。在命令终端输入 python 或者 python3 启动一个 Python 会话，然后输入下面的代码：</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"># 引入 tensorflow 模块</span><br><span class="line">import tensorflow as tf</span><br><span class="line"></span><br><span class="line"># 创建一个浮点数的一维数组，即 1 阶 Tensor</span><br><span class="line">t1 &#x3D; tf.constant([3., 4.1, 5.2], dtype&#x3D;tf.float32)</span><br><span class="line"></span><br><span class="line">&gt;&gt;&gt; print(t1)</span><br><span class="line">Tensor(&quot;Const_1:0&quot;, shape&#x3D;(3,), dtype&#x3D;float32)</span><br></pre></td></tr></table></figure><p>print 一个 Tensor 只能打印出它的属性定义，并不能打印出它的值，要想查看一个 Tensor 中的值还需要经过Session 运行一下：</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">&gt;&gt;&gt; print(sess.run(t1))</span><br><span class="line">[ 3.          4.0999999   5.19999981]</span><br></pre></td></tr></table></figure><h3 id="数据流图-Dataflow-Graph-有向图"><a href="#数据流图-Dataflow-Graph-有向图" class="headerlink" title="数据流图(Dataflow Graph)有向图"></a>数据流图(Dataflow Graph)有向图</h3><p>数据流是一种常用的并行计算编程模型，数据流图是由节点(nodes)和线(edges)构成的有向图：</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">节点(nodes) 表示计算单元，也可以是输入的起点或者输出的终点，在 TensorFlow 中，每个节点都是用 tf.Tensor的实例来表示的，即每个节点的输入、输出都是Tensor  </span><br><span class="line">线(edges) 表示节点之间的输入&#x2F;输出关系</span><br></pre></td></tr></table></figure><p><img src="/images/20210527001920668_94501803.jpg" alt=""></p><p>TensorFlow 中的数据流图有以下几个优点：</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">可并行 计算节点之间有明确的线进行连接，系统可以很容易的判断出哪些计算操作可以并行执行</span><br><span class="line">可分发 图中的各个节点可以分布在不同的计算单元(CPU、 GPU、 TPU等)或者不同的机器中，每个节点产生的数据可以通过明确的线发送的下一个节点中</span><br><span class="line">可优化 TensorFlow 中的 XLA 编译器可以根据数据流图进行代码优化，加快运行速度</span><br><span class="line">可移植 数据流图的信息可以不依赖代码进行保存，如使用Python创建的图，经过保存后可以在C++或Java中使用</span><br></pre></td></tr></table></figure><h2 id="Sesssion"><a href="#Sesssion" class="headerlink" title="Sesssion"></a>Sesssion</h2><p>我们在Python中需要做一些计算操作时一般会使用NumPy，NumPy在做矩阵操作等复杂的计算的时候会使用其他语言(C/C++)来实现这些计算逻辑，来保证计算的高效性。但是频繁的在多个编程语言间切换也会有一定的耗时，如果只是单机操作这些耗时可能会忽略不计，但是如果在分布式并行计算中，计算操作可能分布在不同的CPU、GPU甚至不同的机器中，这些耗时可能会比较严重。<br>TensorFlow <strong>底层是使用C++实现</strong>，这样可以保证计算效率，并<strong>使用 tf.Session类来连接客户端程序与C++运行时。上层的Python、Java等代码用来设计、定义模型，构建的Graph，最后通过tf.Session.run()方法传递给底层执行。</strong></p><h2 id="构建计算图"><a href="#构建计算图" class="headerlink" title="构建计算图"></a>构建计算图</h2><p>上面介绍的是 TensorFlow 和 Graph 的概念，下面介绍怎么用 Tensor 构建 Graph。<br>Tensor 即可以表示输入、输出的端点，还可以表示计算单元，如下的代码创建了对两个 Tensor 执行 + 操作的 Tensor：</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">import tensorflow as tf</span><br><span class="line"># 创建两个常量节点</span><br><span class="line">node1 &#x3D; tf.constant(3.2)</span><br><span class="line">node2 &#x3D; tf.constant(4.8)</span><br><span class="line"># 创建一个 adder 节点，对上面两个节点执行 + 操作</span><br><span class="line">adder &#x3D; node1 + node2</span><br><span class="line"># 打印一下 adder 节点</span><br><span class="line">print(adder)</span><br><span class="line"># 打印 adder 运行后的结果</span><br><span class="line">sess &#x3D; tf.Session()</span><br><span class="line">print(sess.run(adder))</span><br></pre></td></tr></table></figure><p>上面print的输出为</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">Tensor(&quot;add:0&quot;, shape&#x3D;(), dtype&#x3D;float32)</span><br><span class="line">8.0</span><br></pre></td></tr></table></figure><p>上面使用tf.constant()创建的 Tensor 都是常量，一旦创建后其中的值就不能改变了。有时我们还会需要从外部输入数据，这时可以用tf.placeholder 创建占位 Tensor，占位 Tensor 的值可以在运行的时候输入。</p><h2 id="在TensorFlow-中建立模型"><a href="#在TensorFlow-中建立模型" class="headerlink" title="在TensorFlow 中建立模型"></a>在TensorFlow 中建立模型</h2><h3 id="TensorFlow-的2个基本组件"><a href="#TensorFlow-的2个基本组件" class="headerlink" title="TensorFlow 的2个基本组件"></a>TensorFlow 的2个基本组件</h3><p>1）占位符（Placeholder）：表示执行梯度下降时将实际数据值输入到模型中的一个入口点。例如房子面积 (x) 和房价 (y_)。<br><img src="/images/20210527002448981_1710793050.jpg" alt=""></p><p>2）变量：表示我们试图寻找的能够使成本函数降到最小的「good」值的变量，例如 W 和 b。<br><img src="/images/20210527002458835_290482348.jpg" alt=""></p><p>然后 TensorFlow 中的线性模型 (y = W.x + b) 就是：<br><img src="/images/20210527002511433_843317509.jpg" alt=""></p><h3 id="TensorFlow-中的成本函数"><a href="#TensorFlow-中的成本函数" class="headerlink" title="TensorFlow 中的成本函数"></a>TensorFlow 中的成本函数</h3><p>与将数据点的实际房价 (y_) 输入模型类似，我们创建一个占位符。<br><img src="/images/20210527002602452_1897169878.jpg" alt=""></p><p>成本函数的最小方差就是：<br><img src="/images/20210527002611447_550215999.jpg" alt=""></p><h3 id="梯度下降"><a href="#梯度下降" class="headerlink" title="梯度下降"></a>梯度下降</h3><p>有了线性模型、成本函数和数据，我们就可以开始执行梯度下降从而最小化代价函数，以获得 W、b 的「good」值。<br><img src="/images/20210527002648228_1091690217.jpg" alt=""><br>0.00001 是我们每次进行训练时在最陡的梯度方向上所采取的「步」长；它也被称作学习率（learning rate）。</p><h2 id="训练模型"><a href="#训练模型" class="headerlink" title="训练模型"></a>训练模型</h2><p>训练包含以预先确定好的次数执行梯度下降，或者是直到成本函数低于某个预先确定的临界值为止。<br>1.TensorFlow 的怪异<br>所有变量都需要在训练开始时进行初始化，否则它们可能会带有之前执行过程中的残余值。<br>2.TensorFlow 会话<br>虽然 TensorFlow 是一个 Python 库，Python 是一种解释性的语言，但是默认情况下不把 TensorFlow 运算用作解释性能的原因，因此不执行上面的 init 。相反 TensorFlow 是在一个会话中进行；创建一个会话 (sess) 然后使用 sess.run() 去执行。<br>类似地我们在一个循环中调用 withinsess.run() 来执行上面的 train_step。<br><img src="/images/20210527002846811_1653949652.jpg" alt=""><br>你需要将由 x, y_ 所组成的实际数据输入再提供给输入，因为 TensorFlow 将 train_step 分解为它的从属项：<br><img src="/images/20210527002908023_376975680.jpg" alt=""><br>从属项的底部是占位符 x，y_；而且正如我们之前提到的，tf.placeholders 是用来表示所要提供的实际数据点值房价 (y_) 和房子面积 (x) 的位置。</p><h2 id="训练变量"><a href="#训练变量" class="headerlink" title="训练变量"></a>训练变量</h2><h3 id="随机、mini-batch、batch"><a href="#随机、mini-batch、batch" class="headerlink" title="随机、mini-batch、batch"></a>随机、mini-batch、batch</h3><p>在上面的训练中，我们在每个 epoch 送入单个数据点。这被称为随机梯度下降（stochastic gradient descent）。我们也可以在每个 epoch 送入一堆数据点，这被称为 mini-batch 梯度下降，或者甚至在一个 epoch 一次性送入所有的数据点，这被称为 batch 梯度下降。<br>选择随机、mini-batch、batch 梯度下降的优缺点总结在下图中：<br><img src="/images/20210527003409958_1244288551.jpg" alt=""></p><p>计算成本和执行梯度下降所需的计算资源（减法、平方、加法）会增加<br>模型的学习和泛化的速度增加</p><h3 id="学习率变化"><a href="#学习率变化" class="headerlink" title="学习率变化"></a>学习率变化</h3><p>学习率（learn rate）是指梯度下降调整 W 和 b 递增或递减的速度。学习率较小时，处理过程会更慢，但肯定能得到更小成本；而当学习率更大时，我们可以更快地得到最小成本，但有「冲过头」的风险，导致我们没法找到最小成本。<br>为了克服这一问题，许多机器学习实践者选择开始时使用较大的学习率（假设开始时的成本离最小成本还很远），然后随每个 epoch 而逐渐降低学习率。</p><h2 id="常见的tensorflow的OP"><a href="#常见的tensorflow的OP" class="headerlink" title="常见的tensorflow的OP"></a>常见的tensorflow的OP</h2><table><thead><tr><th><strong>类型</strong></th><th><strong>实例</strong></th></tr></thead><tbody><tr><td><strong>标量运算</strong></td><td>add、sub、mul、div、exp、log、greater、less、equal</td></tr><tr><td><strong>向量运算</strong></td><td>concat、slice、splot、constant、rank、spape、shuffle、</td></tr><tr><td><strong>矩阵运算</strong></td><td>matmul、matrixinverse、matrixdateminant</td></tr><tr><td><strong>带状态的运算</strong></td><td>Variable、assgin、assginadd</td></tr><tr><td><strong>神经元组件</strong></td><td>softmax、sigmoid、relu、convolution、max_pool</td></tr><tr><td><strong>存储、恢复</strong></td><td>Save、Restroe</td></tr><tr><td><strong>队列与同步运算</strong></td><td>Equeue、Dequeue、MutexAxquire、MutexRelease</td></tr><tr><td><strong>控制流</strong></td><td>Merge、Switch、Enter、Leave、Nextiteration</td></tr></tbody></table><h2 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h2><p>TensorFlow入门：第一个机器学习Demo:<a href="https://blog.csdn.net/geyunfei_/article/details/78782804">https://blog.csdn.net/geyunfei_/article/details/78782804</a><br>机器学习与tensorflow入门教程（任何人都能看懂）：<a href="https://blog.csdn.net/ebzxw/article/details/86609997">https://blog.csdn.net/ebzxw/article/details/86609997</a><br>TensorFlow入门教程：<a href="https://www.cnblogs.com/mq0036/p/12690638.html#会话的run">https://www.cnblogs.com/mq0036/p/12690638.html#会话的run</a><br>TensorFlow是什么：<a href="http://c.biancheng.net/view/1880.html">http://c.biancheng.net/view/1880.html</a><br>简单粗暴 TensorFlow 2 | A Concise Handbook of TensorFlow 2：<a href="https://tf.wiki/zh_hans/">https://tf.wiki/zh_hans/</a></p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;前置知识&lt;br&gt;01,基础Python 编程&lt;br&gt;02,数组相关的知识&lt;br&gt;03,机器学习基础，感知机，神经网络&lt;br&gt;学习目的：tensorflow大概做什么的（近似”极值“（可能是局部极值）靠近器）&lt;/p&gt;
    
    </summary>
    
    
      <category term="08领域技术" scheme="https://hexo.yuanjh.cn/categories/08%E9%A2%86%E5%9F%9F%E6%8A%80%E6%9C%AF/"/>
    
      <category term="c机器学习" scheme="https://hexo.yuanjh.cn/categories/08%E9%A2%86%E5%9F%9F%E6%8A%80%E6%9C%AF/c%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/"/>
    
    
      <category term="08领域技术/c机器学习/深度学习回顾" scheme="https://hexo.yuanjh.cn/tags/08%E9%A2%86%E5%9F%9F%E6%8A%80%E6%9C%AF-c%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0-%E6%B7%B1%E5%BA%A6%E5%AD%A6%E4%B9%A0%E5%9B%9E%E9%A1%BE/"/>
    
  </entry>
  
  <entry>
    <title>深度学习回顾_05VGG,ResNet50,InceptionV3区别</title>
    <link href="https://hexo.yuanjh.cn/hexo/64642abd/"/>
    <id>https://hexo.yuanjh.cn/hexo/64642abd/</id>
    <published>2024-03-10T18:04:49.000Z</published>
    <updated>2026-03-11T16:45:17.867Z</updated>
    
    <content type="html"><![CDATA[<p>做应用时，会涉及到算法切换，有时会迷茫，为啥要改成这种算法？这种算法和之前有啥区别。<br>这篇文章就是自我扫盲的</p><h2 id="LeNet-5"><a href="#LeNet-5" class="headerlink" title="LeNet-5"></a>LeNet-5</h2><p>LeNet-5的特点：<br>使用了<strong>卷积</strong>来提取特征，结构单元一般为卷积 - 池化 -非线性激活<br>已经加入了<strong>非线性激活</strong>，激活函数采用了tanh和sigmoid，目前大多数情况下我们使用的是relu<br>池化层使用的是<strong>平均值池化</strong>，目前大多数情况下我们使用最大值池化<br>分类器使用了Gaussian Connections，目前已经被softmax替代</p><h2 id="AlexNet"><a href="#AlexNet" class="headerlink" title="AlexNet"></a>AlexNet</h2><p>AlexNet的特点：<br>采用<strong>relu替代了tanh和sigmoid激活函数</strong>。relu具有<strong>计算简单，不产生梯度弥散</strong>等优点，现在已经基本替代了tanh和sigmoid<br><strong>全连接层使用了dropout来防止过拟合</strong>。dropout可以理解为是一种下采样方式，可以有效降低过拟合问题。<br>卷积-激活-池化后，采用了一层LRN，也就是<strong>局部响应归一化</strong>。将一个卷积核在(x,y)空间像素点的输出，和它前后的几个卷积核上的输出做权重归一化。<br>使用了<strong>重叠的最大值池化层</strong>。3x3的池化核，步长为2，因此产生了重叠池化效应，使得一个像素点在多个池化结果中均有输出，提高了特征提取的丰富性<br><strong>数据增强</strong>。随机的从256x256的原始图片中，裁剪得到224x224的图片，从而使一张图片变为了(256-224)^2张图片。并对图片进行镜像，旋转，随机噪声等数据增强操作，大大降低了过拟合现象。</p><p>为什么Dropout有效？<br>Dropout背后理念和集成模型很相似。在Drpout层，不同的神经元组合被关闭，这代表了一种不同的结构，所有这些不同的结构使用一个的子数据集并行地带权重训练，而权重总和为1。如果Dropout层有n个神经元，那么会形成2^n个不同的子结构。在预测时，相当于集成这些模型并取均值。这种结构化的模型正则化技术有利于避免过拟合。Dropout有效的另外一个视点是：由于神经元是随机选择的，所以可以减少神经元之间的相互依赖，从而确保提取出相互独立的重要特征。<br>Dropout有效的另外一个视点是：由于神经元是随机选择的，所以可以减少神经元之间的相互依赖，从而确保提取出相互独立的重要特征。</p><h2 id="VGG16"><a href="#VGG16" class="headerlink" title="VGG16"></a>VGG16</h2><p>VGG16是牛津大学VGG组提出的。VGG16相比AlexNet的一个改进是<strong>采用连续的几个3x3的卷积核代替AlexNet中的较大卷积核</strong>（11x11，5x5）。对于给定的感受野（与输出有关的输入图片的局部大小），采用堆积的小卷积核是优于采用大的卷积核，因为多层非线性层可以增加网络深度来保证学习更复杂的模式，而且代价还比较小（参数更少）。</p><p>VGG的特点：<br>采用了<strong>较深的网络</strong>，最多达到19层，证明了网络越深，高阶特征提取越多，从而准确率得到提升。<br><strong>串联多个小卷积</strong>，相当于一个大卷积。VGG中使用两个串联的3x3卷积，达到了一个5x5卷积的效果，但参数量却只有之前的9/25。同时串联多个小卷积，也增加了使用relu非线性激活的概率，从而增加了模型的非线性特征。<br>VGG-16中使用了<strong>1x1的卷积</strong>。1x1的卷积是性价比最高的卷积，可以用来实现线性变化，输出通道变换等功能，而且还可以多一次relu非线性激活。<br>VGG有11层，13层，16层，19层等多种不同复杂度的结构。<strong>使用复杂度低的模型的训练结果，来初始化复杂度高模型的权重等参数，这样可以加快收敛速度</strong>。</p><h2 id="GoogLeNet-Inception"><a href="#GoogLeNet-Inception" class="headerlink" title="GoogLeNet/Inception"></a>GoogLeNet/Inception</h2><p>Google Inception是一个大家族，包括inceptionV1 inceptionV2 inceptionV3 inceptionV4等结构。它主要不是对网络深度的探索，而是进行了<strong>网络结构的改进</strong>。</p><h3 id="InceptionV1"><a href="#InceptionV1" class="headerlink" title="InceptionV1"></a>InceptionV1</h3><p>inceptionV1是一个设计十分精巧的网络，它有22层深，只有500万左右的参数量，模型大小仅为20M左右，但错误率却只有6.7%。它的网络结构特点如下：<br>去除了最后的全连接层，而使用<strong>全局平均池化</strong>来代替。这是模型之所以小的原因。AlexNet和VGG中全连接几乎占据了90%的参数量。而inceptionV1仅仅需要1000个参数，大大降低了参数量<br>inception module的使用。借鉴与Network in Network的思想，提出了inception module的概念，<strong>允许通道并联来组合特征</strong>。其结构如下<br><img src="/images/20201202195248957_792435310.jpg" alt=""></p><p>使用了1x1,3x3,5x5等不同尺寸的卷积，<strong>增加了提取特征面积的多样性</strong>，从而减小过拟合</p><h3 id="inceptionV2"><a href="#inceptionV2" class="headerlink" title="inceptionV2"></a>inceptionV2</h3><p>inceptionV2和V1网络结构大体相似，其模型大小为40M左右，错误率仅4.8%，低于人眼识别的错误率5.1%。主要改进如下<br>使用<strong>两个串联3x3卷积来代替5x5卷积</strong>，从而<strong>降低参数量</strong>，并增加relu非线性。这一点参考了VGG的设计<br>提出了Batch Normalization。在<strong>卷积池化后，增加了这一层正则化，将输出数据归一化到0~1之间，从而降低神经元分布的不一致性</strong>。这样训练时就可以使用<strong>相对较大的学习率</strong>，从而<strong>加快收敛速度</strong>。在达到之前的准确率之后还能继续训练，从而<strong>提高准确率</strong>。V2达到V1的准确率时，迭代次数仅为V1的1/14, 从而使训练时间大大减少。最终错误率仅4.8%</p><h3 id="inceptionV3"><a href="#inceptionV3" class="headerlink" title="inceptionV3"></a>inceptionV3</h3><p>inceptionV3的网络结构也没太大变化，其模型大小96M左右。主要改进如下<br>使用<strong>非对称卷积。用1x3+3x1的卷积来代替一个3x3的卷积</strong>，降低了参数的同时，提高了卷积的多样性<br>分支中出现了分支。如下图<br><img src="/images/20201202201215410_866643886.jpg" alt=""></p><h3 id="inceptionV4"><a href="#inceptionV4" class="headerlink" title="inceptionV4"></a>inceptionV4</h3><p>inceptionV4主要是借鉴了resNet残差网络的思想，可以看做是inceptionV3和resNet的结合。inceptionV4模型大小163M，错误率仅仅为3.08%。主要在ResNet网络中讲解</p><h2 id="ResNet"><a href="#ResNet" class="headerlink" title="ResNet"></a>ResNet</h2><h3 id="ResNetV1"><a href="#ResNetV1" class="headerlink" title="ResNetV1"></a>ResNetV1</h3><p>ResNet提出了残差思想，将输入中的一部分数据不经过神经网络，而直接进入到输出中。这样来保留一部分原始信息，防止反向传播时的梯度弥散问题，从而使得网络深度一举达到152层。当前有很多人甚至训练了1000多层的网络，当然我们实际使用中100多层的就远远足够了。残差网络如下图<br><img src="/images/20201202195641546_673769491.jpg" alt=""></p><p>深度网络的训练问题称为退化问题，残差单元可以解决退化问题的背后逻辑在于此：想象一个网络A，其训练误差为x。现在通过在A上面堆积更多的层来构建网络B，这些新增的层什么也不做，仅仅复制前面A的输出。这些新增的层称为C。这意味着网络B应该和A的训练误差一样。那么，如果训练网络B其训练误差应该不会差于A。但是实际上却是更差，唯一的原因是让增加的层C学习恒等映射并不容易。为了解决这个退化问题，残差模块在输入和输出之间建立了一个直接连接，这样新增的层C仅仅需要在原来的输入层基础上学习新的特征，即<strong>学习残差</strong>，会比较容易。<br>与GoogLeNet类似，ResNet也最后使用了<strong>全局均值池化层</strong>。利用残差模块，可以训练152层的残差网络。其准确度比VGG和GoogLeNet要高，但是计算效率也比VGG高。152层的ResNet其top-5准确度为95.51%。</p><p>ResNet的主要特点，就一个字，深！</p><h3 id="ResNetV2"><a href="#ResNetV2" class="headerlink" title="ResNetV2"></a>ResNetV2</h3><p>ResNetV2相对于V1的最大变化，就是借鉴了inceptionV2的BN归一化思想，这样来减少模型训练时间。</p><h2 id="MobileNet-略"><a href="#MobileNet-略" class="headerlink" title="MobileNet(略)"></a>MobileNet(略)</h2><p>为了能将模型部署在终端上，需要在保证准确率的前提下，<strong>减小模型体积，并降低预测时的计算时间</strong>，以提高实时性。</p><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>TensorFlow等框架的成熟和GPU等硬件性能的提升，使得网络结构的设计和验证日趋平民化。各种网络结构，百花齐放。<br>其实本质上也是在解决神经网络的几大痛点问题：</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">减少模型参数量，降低模型体积</span><br><span class="line">加快训练收敛速度，减少训练耗时</span><br><span class="line">加快模型预测计算时间，提高实时性。这主要还是通过减少参数量来达到</span><br><span class="line">减少过拟合问题</span><br><span class="line">减少网络层级过深时的梯度弥散问题</span><br></pre></td></tr></table></figure><p>学习网络模型，不应该去死记硬背，因为有源源不断的网络结构涌现。我们应该重点掌握每个模型的特点，以及他们是如何来解决上面列举的这些神经网络痛点的。</p><h2 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h2><p>VGG16 、VGG19 、ResNet50 、Inception V3 、Xception介绍:<a href="https://cloud.tencent.com/developer/article/1621045">https://cloud.tencent.com/developer/article/1621045</a><br>一文读懂物体分类AI算法：LeNet-5 AlexNet VGG Inception ResNet MobileNet:<a href="https://blog.csdn.net/maoreyou/article/details/80612467">https://blog.csdn.net/maoreyou/article/details/80612467</a></p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;做应用时，会涉及到算法切换，有时会迷茫，为啥要改成这种算法？这种算法和之前有啥区别。&lt;br&gt;这篇文章就是自我扫盲的&lt;/p&gt;
    
    </summary>
    
    
      <category term="08领域技术" scheme="https://hexo.yuanjh.cn/categories/08%E9%A2%86%E5%9F%9F%E6%8A%80%E6%9C%AF/"/>
    
      <category term="c机器学习" scheme="https://hexo.yuanjh.cn/categories/08%E9%A2%86%E5%9F%9F%E6%8A%80%E6%9C%AF/c%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/"/>
    
    
      <category term="08领域技术/c机器学习/深度学习回顾" scheme="https://hexo.yuanjh.cn/tags/08%E9%A2%86%E5%9F%9F%E6%8A%80%E6%9C%AF-c%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0-%E6%B7%B1%E5%BA%A6%E5%AD%A6%E4%B9%A0%E5%9B%9E%E9%A1%BE/"/>
    
  </entry>
  
  <entry>
    <title>深度学习回顾_04LSTM笔记</title>
    <link href="https://hexo.yuanjh.cn/hexo/b84b3216/"/>
    <id>https://hexo.yuanjh.cn/hexo/b84b3216/</id>
    <published>2024-03-10T15:16:49.000Z</published>
    <updated>2026-03-11T16:45:17.867Z</updated>
    
    <content type="html"><![CDATA[<p>本文适合有一定基础同学的复习使用，不适合小白入门，入门参考本文参考文献第一篇</p><h2 id="结构-静态综合图"><a href="#结构-静态综合图" class="headerlink" title="结构_静态综合图"></a>结构_静态综合图</h2><p><img src="/images/20200410152537276_813336082.jpg" alt=""><br><img src="/images/20200410152609812_1067224219.jpg" alt=""></p><h2 id="结构-分步动图"><a href="#结构-分步动图" class="headerlink" title="结构_分步动图"></a>结构_分步动图</h2><p><img src="/images/20200410153555044_536427309.gif" alt=""></p><p><img src="/images/20200410153706415_18713920.gif" alt=""></p><p><img src="/images/20200410153724171_945342609.gif" alt=""></p><h2 id="进一步，向量化参数和引入问题"><a href="#进一步，向量化参数和引入问题" class="headerlink" title="进一步，向量化参数和引入问题"></a>进一步，向量化参数和引入问题</h2><p><img src="/images/20200410155959328_1405969400.jpg" alt=""><br>1， cell 的状态是一个向量，是有多个值的<br>如果理解了上面结构，这个理解起来问题不大，单一数字变向量即可。<br>引出一个问题：int相加无问题，ht+xt组合时如何组合？直接相加不可能，毕竟维度不同，比如20维和5维<br>答：[x1,x2,,x20]+[y1,y2,,y5]=[x1,x2,x20,y1,y2,,,y5]，直接拼接，就这么简单.<br>2, cell 的权重是共享的，这是什么意思呢？这是指这张图片上有三个绿色的大框，代表三个 cell 对吧，但是实际上，它只是代表了一个 cell 在不同时序时候的状态，所有的数据只会通过一个 cell，然后不断更新它的权重。<br>3,cell 最上面的一条线的状态即 s(t) 代表了长时记忆，而下面的 h(t)则代表了工作记忆或短时记忆</p><h2 id="细节，参数个数-神经元分析"><a href="#细节，参数个数-神经元分析" class="headerlink" title="细节，参数个数(神经元分析)"></a>细节，参数个数(神经元分析)</h2><h3 id="忘记门层"><a href="#忘记门层" class="headerlink" title="忘记门层"></a>忘记门层</h3><p><img src="/images/20200410160421032_2142878214.jpg" alt=""><br>图中公式的是上一个状态的隐向量(已设定隐向量长度为10),为当前状态的输入(长度为5),那么的长度就是10+5=15了.和为该层的参数.<br>该层输出是中间隐向量的长度(10),经过激活前后的长度不变.只需要考虑里面的操作得到10维特征即可.<br>是(1,15)的向量,与相乘得到(1,10)的向量,根据矩阵相乘规律,得到是(15,10)的矩阵,得到(1,10)矩阵后,与该门层偏置相加,偏置也应该有相同的形状,即是(1,10)的矩阵.<br>即:该层神经元为:<br><img src="/images/20200410160459601_418841782.jpg" alt=""></p><h3 id="细胞状态"><a href="#细胞状态" class="headerlink" title="细胞状态"></a>细胞状态</h3><p>确定更新信息过程<br><img src="/images/20200410160540153_392582849.jpg" alt=""></p><p><img src="/images/20200410160522807_1134280805.jpg" alt=""></p><p>更新过程<br><img src="/images/20200410160615994_343542850.jpg" alt=""><br>公式中的四个值,均是前面计算得到的结果,因此该过程没有参数需要学习.</p><h3 id="输出层"><a href="#输出层" class="headerlink" title="输出层"></a>输出层</h3><p><img src="/images/20200410160649626_378141806.jpg" alt=""><br><img src="/images/20200410160658117_1953027734.jpg" alt=""></p><h3 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h3><p>把公式(1),(2),(3)的神经元加起来,就是该LSTM的神经元个数了.<br><img src="/images/20200410160718541_1495959375.jpg" alt=""><br>假设你一个时间步的特征长度是n,经过该LSTM得到的长度是m,这样就可以算出该LSTM层的神经元个数为:<br><img src="/images/20200410160755717_1082619173.jpg" alt=""></p><p>参考教程:<br>难以置信！LSTM和GRU的解析从未如此清晰（动图+视频:<a href="https://blog.csdn.net/dQCFKyQDXYm3F8rB0/article/details/82922386">https://blog.csdn.net/dQCFKyQDXYm3F8rB0/article/details/82922386</a><br>LSTM神经网络知识—资源整理:<a href="https://blog.csdn.net/jizhidexiaoming/article/details/80930287">https://blog.csdn.net/jizhidexiaoming/article/details/80930287</a><br>RNN与LSTM系列（二）——LSTM的参数个数:<a href="https://blog.csdn.net/manmanxiaowugun/article/details/82966879">https://blog.csdn.net/manmanxiaowugun/article/details/82966879</a></p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;本文适合有一定基础同学的复习使用，不适合小白入门，入门参考本文参考文献第一篇&lt;/p&gt;
    
    </summary>
    
    
      <category term="08领域技术" scheme="https://hexo.yuanjh.cn/categories/08%E9%A2%86%E5%9F%9F%E6%8A%80%E6%9C%AF/"/>
    
      <category term="c机器学习" scheme="https://hexo.yuanjh.cn/categories/08%E9%A2%86%E5%9F%9F%E6%8A%80%E6%9C%AF/c%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/"/>
    
    
      <category term="08领域技术/c机器学习/深度学习回顾" scheme="https://hexo.yuanjh.cn/tags/08%E9%A2%86%E5%9F%9F%E6%8A%80%E6%9C%AF-c%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0-%E6%B7%B1%E5%BA%A6%E5%AD%A6%E4%B9%A0%E5%9B%9E%E9%A1%BE/"/>
    
  </entry>
  
  <entry>
    <title>深度学习回顾_03RNN</title>
    <link href="https://hexo.yuanjh.cn/hexo/72480256/"/>
    <id>https://hexo.yuanjh.cn/hexo/72480256/</id>
    <published>2024-03-03T00:03:49.000Z</published>
    <updated>2026-03-11T16:45:17.867Z</updated>
    
    <content type="html"><![CDATA[<p>某些任务需要能够更好的处理序列的信息，即前面的输入和后面的输入是有关系的。</p><h2 id="RNN结构"><a href="#RNN结构" class="headerlink" title="RNN结构"></a>RNN结构</h2><p><img src="/images/20201128220800065_2007793890.jpg" alt=""></p><p><img src="/images/20201128222525362_684678895.jpg" alt=""></p><p>这个抽象图对应的具体图：<br><img src="/images/20201128222100048_933979996.jpg" alt=""></p><p>DNN的权重矩阵每层都不一样，而RNN每个时刻的权重矩阵都是相同的，即一个单层RNN的权重矩阵只有三个：U UU、V VV、W WW，和两个权重向量b bb、c cc。这说明RNN每个时刻做的事情是一样的，即接收输入信息和上个时刻的输出信息，输出当前时刻的信息。</p><p>可以把隐藏层节点s t s_ts<br>当成一个记忆单元，它用来捕获之前所有时刻的信息。<br>上面图中每个时刻都有输出，但是有的任务没必要这样做。比如文本分类时，我们只关心最后的输出，而不需要每个词都有输出；同理我们也可能不需要每个时刻都输入。</p><p>RNN存在问题：<br>a、梯度消失 ；梯度消失就是一定深度的梯度对模型更新没有帮助。<br>b、梯度爆炸；<br>b、长期依赖问题<br>梯度消失原因简述：<br>更新模型参数的方法是反向求导，越往前梯度越小。而激活函数是 sigmoid 和 tanh 的时候，这两个函数的导数又是在两端都是无限趋近于0的，会使得之前的梯度也朝向0，最终的结果是到达一定”深度“后，梯度就对模型的更新没有任何贡献。<br>梯度爆炸原因简述：<br>长期依赖问题：相关信息和当前预测位置之间的间隔不断增大时，RNN 会丧失学习到连接如此远的信息的能力。</p><p>解决办法：升级版的RNN——LSTM。LSTM 通过刻意的设计来避免长期依赖问题。记住长期的信息在实践中是 LSTM 的默认行为，而非需要付出很大代价才能获得的能力！</p><h2 id="CNN-vs-RNN"><a href="#CNN-vs-RNN" class="headerlink" title="CNN vs RNN"></a>CNN vs RNN</h2><p>CNN 需要固定长度的输入、输出，RNN 的输入和输出可以是不定长且不等长的<br>CNN 只有 one-to-one 一种结构，而 RNN 有多种结构，如下图：<br><img src="/images/20201128222841777_172245238.jpg" alt=""></p><h2 id="LSTM-网络"><a href="#LSTM-网络" class="headerlink" title="LSTM 网络"></a>LSTM 网络</h2><p>Long Short Term 网络—— 一般就叫做 LSTM ——是一种 RNN 特殊的类型，可以学习长期依赖信息。LSTM 由Hochreiter &amp; Schmidhuber (1997)提出，并在近期被Alex Graves进行了改良和推广。在很多问题，LSTM 都取得相当巨大的成功，并得到了广泛的使用。<br>LSTM 通过刻意的设计来避免长期依赖问题。记住长期的信息在实践中是 LSTM 的默认行为，而非需要付出很大代价才能获得的能力！</p><p>所有 RNN 都具有一种重复神经网络模块的链式的形式。在标准的 RNN 中，这个重复的模块只有一个非常简单的结构，例如一个 tanh 层。<br><img src="/images/20201128223156378_312830702.jpg" alt=""></p><h2 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h2><p>一文搞懂RNN（循环神经网络）基础篇：<a href="https://zhuanlan.zhihu.com/p/30844905">https://zhuanlan.zhihu.com/p/30844905</a><br>RNN 结构详解（Rnn的多种结构）：<a href="https://www.jiqizhixin.com/articles/2018-12-14-4">https://www.jiqizhixin.com/articles/2018-12-14-4</a><br>【转载】RNN详解:<a href="https://www.cnblogs.com/veagau/articles/11767977.html">https://www.cnblogs.com/veagau/articles/11767977.html</a><br>RNN快速入门（超赞讲解）：<a href="https://www.jianshu.com/p/1a12623f24eb">https://www.jianshu.com/p/1a12623f24eb</a></p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;某些任务需要能够更好的处理序列的信息，即前面的输入和后面的输入是有关系的。&lt;/p&gt;
    
    </summary>
    
    
      <category term="08领域技术" scheme="https://hexo.yuanjh.cn/categories/08%E9%A2%86%E5%9F%9F%E6%8A%80%E6%9C%AF/"/>
    
      <category term="c机器学习" scheme="https://hexo.yuanjh.cn/categories/08%E9%A2%86%E5%9F%9F%E6%8A%80%E6%9C%AF/c%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/"/>
    
    
      <category term="08领域技术/c机器学习/深度学习回顾" scheme="https://hexo.yuanjh.cn/tags/08%E9%A2%86%E5%9F%9F%E6%8A%80%E6%9C%AF-c%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0-%E6%B7%B1%E5%BA%A6%E5%AD%A6%E4%B9%A0%E5%9B%9E%E9%A1%BE/"/>
    
  </entry>
  
</feed>
