<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>chinaluke</title>
  
  <subtitle>行有不得，反求诸己</subtitle>
  <link href="http://example.com/atom.xml" rel="self"/>
  
  <link href="http://example.com/"/>
  <updated>2024-11-26T01:55:20.903Z</updated>
  <id>http://example.com/</id>
  
  <author>
    <name>chinaluke</name>
    
  </author>
  
  <generator uri="https://hexo.io/">Hexo</generator>
  
  <entry>
    <title>buildroot中BR2_INSTRUMENTATION_SCRIPTS实操</title>
    <link href="http://example.com/2024/11/25/buildroot%E4%B8%ADBR2-INSTRUMENTATION-SCRIPTS%E5%AE%9E%E6%93%8D/"/>
    <id>http://example.com/2024/11/25/buildroot%E4%B8%ADBR2-INSTRUMENTATION-SCRIPTS%E5%AE%9E%E6%93%8D/</id>
    <published>2024-11-25T11:20:20.000Z</published>
    <updated>2024-11-26T01:55:20.903Z</updated>
    
    <content type="html"><![CDATA[<p>近期在看buildroot manual文档，发现有个章节“Chapter 21. Debugging Buildroot”，里面提到了可以对buildroot编译各阶段加入想要的操作。</p><p>但是网上找了下，没有发现有相关案例，打算实操下</p><span id="more"></span><h1 id="Debugging-Buildroot官方说明"><a href="#Debugging-Buildroot官方说明" class="headerlink" title="Debugging Buildroot官方说明"></a>Debugging Buildroot官方说明</h1><p><a href="http://www.buildroot.net/downloads/manual/manual.html#debugging-buildroot">Debugging Buildroot</a></p><p>It is possible to instrument the steps Buildroot does when building packages. Define the variable BR2_INSTRUMENTATION_SCRIPTS to contain the path of one or more scripts (or other executables), in a space-separated list, you want called before and after each step. The scripts are called in sequence, with three parameters:</p><ul><li>start or end to denote the start (resp. the end) of a step;</li><li>the name of the step about to be started, or which just ended;</li><li>the name of the package.</li></ul><p>For example :</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">make BR2_INSTRUMENTATION_SCRIPTS=&quot;/path/to/my/script1 /path/to/my/script2&quot;</span><br></pre></td></tr></table></figure><p>The list of steps is:</p><ul><li>extract</li><li>patch</li><li>configure</li><li>build</li><li>install-host, when a host-package is installed in $(HOST_DIR)</li><li>install-target, when a target-package is installed in $(TARGET_DIR)</li><li>install-staging, when a target-package is installed in $(STAGING_DIR)</li><li>install-image, when a target-package installs files in $(BINARIES_DIR)</li></ul><p>The script has access to the following variables:</p><ul><li>BR2_CONFIG: the path to the Buildroot .config file</li><li>HOST_DIR, STAGING_DIR, TARGET_DIR: see Section 18.6.2, “generic-package reference”</li><li>BUILD_DIR: the directory where packages are extracted and built</li><li>BINARIES_DIR: the place where all binary files (aka images) are stored</li><li>BASE_DIR: the base output directory</li></ul><p>简单来说，在执行make时，可以加入BR2_INSTRUMENTATION_SCRIPTS参数，该参数可以指定一些脚本（脚本之间用空格区分开）。在编译每个软件包的extract、patch、configure等各阶段的start、end会执行这些脚本，脚本带有3个参数：</p><ul><li>参数1，表示每个阶段的start还是end</li><li>参数2，表示该阶段的名字</li><li>参数3，表示软件包的名字</li></ul><p>另外脚本中还可以调用BR2_CONFIG、HOST_DIR、BUILD_DIR等变量。</p><p>看起来很迷糊，直接实操一下。</p><h1 id="BR2-INSTRUMENTATION-SCRIPTS实操"><a href="#BR2-INSTRUMENTATION-SCRIPTS实操" class="headerlink" title="BR2_INSTRUMENTATION_SCRIPTS实操"></a>BR2_INSTRUMENTATION_SCRIPTS实操</h1><p>编写script脚本。其中scripts1.sh如下：</p><figure class="highlight plaintext"><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">#!/bin/bash</span><br><span class="line"></span><br><span class="line">echo &quot;Debugging: ======&gt;scripts1.sh&quot;</span><br><span class="line"></span><br><span class="line">echo &quot;Debugging: para1 \$1 is: $1&quot;</span><br><span class="line">echo &quot;Debugging: para2 \$2 is: $2&quot;</span><br><span class="line">echo &quot;Debugging: para3 \$3 is: $3&quot;</span><br><span class="line"></span><br><span class="line">echo Debugging: BR2_CONFIG: $&#123;BR2_CONFIG&#125;</span><br><span class="line">echo Debugging: HOST_DIR: $&#123;HOST_DIR&#125;</span><br><span class="line">echo Debugging: BUILD_DIR: $&#123;BUILD_DIR&#125;</span><br><span class="line">echo Debugging: BINARIES_DIR: $&#123;BINARIES_DIR&#125;</span><br><span class="line">echo Debugging: BASE_DIR: $&#123;BASE_DIR&#125;</span><br></pre></td></tr></table></figure><p>scripts2.sh脚本如下：</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="meta">#!/bin/bash</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;Debugging: ======&gt;scripts2.sh&quot;</span></span><br></pre></td></tr></table></figure><p>在buildroot下执行如下命令：</p><figure class="highlight awk"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ make -C <span class="regexp">/home/u</span>ser<span class="regexp">/work/</span>buildroot/out &lt;pkg-name&gt; BR2_INSTRUMENTATION_SCRIPTS=<span class="string">&quot;scripts1.sh scripts2.sh&quot;</span></span><br></pre></td></tr></table></figure><p>输出结果如下：</p><figure class="highlight awk"><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></pre></td><td class="code"><pre><span class="line">Debugging: ======&gt;scripts1.sh</span><br><span class="line">Debugging: para1 <span class="variable">$1</span> is: start</span><br><span class="line">Debugging: para2 <span class="variable">$2</span> is: rsync</span><br><span class="line">Debugging: para3 <span class="variable">$3</span> is: &lt;pkg-name&gt;</span><br><span class="line">Debugging: BR2_CONFIG: <span class="regexp">/home/u</span>ser<span class="regexp">/work/</span>buildroot<span class="regexp">/out/</span>.config</span><br><span class="line">Debugging: HOST_DIR: <span class="regexp">/home/u</span>ser<span class="regexp">/work/</span>buildroot<span class="regexp">/out/</span>host</span><br><span class="line">Debugging: BUILD_DIR: <span class="regexp">/home/u</span>ser<span class="regexp">/work/</span>buildroot<span class="regexp">/out/</span>build</span><br><span class="line">Debugging: BINARIES_DIR: <span class="regexp">/home/u</span>ser<span class="regexp">/work/</span>buildroot<span class="regexp">/out/im</span>ages</span><br><span class="line">Debugging: BASE_DIR: <span class="regexp">/home/u</span>ser<span class="regexp">/work/</span>buildroot/out</span><br><span class="line">Debugging: ======&gt;scripts2.sh</span><br><span class="line">Debugging: ======&gt;scripts1.sh</span><br><span class="line">Debugging: para1 <span class="variable">$1</span> is: end</span><br><span class="line">Debugging: para2 <span class="variable">$2</span> is: rsync</span><br><span class="line">Debugging: para3 <span class="variable">$3</span> is: &lt;pkg-name&gt;</span><br><span class="line">Debugging: BR2_CONFIG: <span class="regexp">/home/u</span>ser<span class="regexp">/work/</span>buildroot<span class="regexp">/out/</span>.config</span><br><span class="line">Debugging: HOST_DIR: <span class="regexp">/home/u</span>ser<span class="regexp">/work/</span>buildroot<span class="regexp">/out/</span>host</span><br><span class="line">Debugging: BUILD_DIR: <span class="regexp">/home/u</span>ser<span class="regexp">/work/</span>buildroot<span class="regexp">/out/</span>build</span><br><span class="line">Debugging: BINARIES_DIR: <span class="regexp">/home/u</span>ser<span class="regexp">/work/</span>buildroot<span class="regexp">/out/im</span>ages</span><br><span class="line">Debugging: BASE_DIR: <span class="regexp">/home/u</span>ser<span class="regexp">/work/</span>buildroot/out</span><br><span class="line">Debugging: ======&gt;scripts2.sh</span><br><span class="line">Debugging: ======&gt;scripts1.sh</span><br><span class="line">Debugging: para1 <span class="variable">$1</span> is: start</span><br><span class="line">Debugging: para2 <span class="variable">$2</span> is: configure</span><br><span class="line">Debugging: para3 <span class="variable">$3</span> is: &lt;pkg-name&gt;</span><br><span class="line">Debugging: BR2_CONFIG: <span class="regexp">/home/u</span>ser<span class="regexp">/work/</span>buildroot<span class="regexp">/out/</span>.config</span><br><span class="line">Debugging: HOST_DIR: <span class="regexp">/home/u</span>ser<span class="regexp">/work/</span>buildroot<span class="regexp">/out/</span>host</span><br><span class="line">Debugging: BUILD_DIR: <span class="regexp">/home/u</span>ser<span class="regexp">/work/</span>buildroot<span class="regexp">/out/</span>build</span><br><span class="line">Debugging: BINARIES_DIR: <span class="regexp">/home/u</span>ser<span class="regexp">/work/</span>buildroot<span class="regexp">/out/im</span>ages</span><br><span class="line">Debugging: BASE_DIR: <span class="regexp">/home/u</span>ser<span class="regexp">/work/</span>buildroot/out</span><br><span class="line">Debugging: ======&gt;scripts2.sh</span><br><span class="line">Debugging: ======&gt;scripts1.sh</span><br><span class="line">Debugging: para1 <span class="variable">$1</span> is: end</span><br><span class="line">Debugging: para2 <span class="variable">$2</span> is: configure</span><br><span class="line">Debugging: para3 <span class="variable">$3</span> is: &lt;pkg-name&gt;</span><br><span class="line">Debugging: BR2_CONFIG: <span class="regexp">/home/u</span>ser<span class="regexp">/work/</span>buildroot<span class="regexp">/out/</span>.config</span><br><span class="line">Debugging: HOST_DIR: <span class="regexp">/home/u</span>ser<span class="regexp">/work/</span>buildroot<span class="regexp">/out/</span>host</span><br><span class="line">Debugging: BUILD_DIR: <span class="regexp">/home/u</span>ser<span class="regexp">/work/</span>buildroot<span class="regexp">/out/</span>build</span><br><span class="line">Debugging: BINARIES_DIR: <span class="regexp">/home/u</span>ser<span class="regexp">/work/</span>buildroot<span class="regexp">/out/im</span>ages</span><br><span class="line">Debugging: BASE_DIR: <span class="regexp">/home/u</span>ser<span class="regexp">/work/</span>buildroot/out</span><br><span class="line">Debugging: ======&gt;scripts2.sh</span><br><span class="line">Debugging: ======&gt;scripts1.sh</span><br><span class="line">Debugging: para1 <span class="variable">$1</span> is: start</span><br><span class="line">Debugging: para2 <span class="variable">$2</span> is: build</span><br><span class="line">Debugging: para3 <span class="variable">$3</span> is: &lt;pkg-name&gt;</span><br><span class="line">Debugging: BR2_CONFIG: <span class="regexp">/home/u</span>ser<span class="regexp">/work/</span>buildroot<span class="regexp">/out/</span>.config</span><br><span class="line">Debugging: HOST_DIR: <span class="regexp">/home/u</span>ser<span class="regexp">/work/</span>buildroot<span class="regexp">/out/</span>host</span><br><span class="line">Debugging: BUILD_DIR: <span class="regexp">/home/u</span>ser<span class="regexp">/work/</span>buildroot<span class="regexp">/out/</span>build</span><br><span class="line">Debugging: BINARIES_DIR: <span class="regexp">/home/u</span>ser<span class="regexp">/work/</span>buildroot<span class="regexp">/out/im</span>ages</span><br><span class="line">Debugging: BASE_DIR: <span class="regexp">/home/u</span>ser<span class="regexp">/work/</span>buildroot/out</span><br><span class="line">Debugging: ======&gt;scripts2.sh</span><br><span class="line">Debugging: ======&gt;scripts1.sh</span><br><span class="line">Debugging: para1 <span class="variable">$1</span> is: end</span><br><span class="line">Debugging: para2 <span class="variable">$2</span> is: build</span><br><span class="line">Debugging: para3 <span class="variable">$3</span> is: &lt;pkg-name&gt;</span><br><span class="line">Debugging: BR2_CONFIG: <span class="regexp">/home/u</span>ser<span class="regexp">/work/</span>buildroot<span class="regexp">/out/</span>.config</span><br><span class="line">Debugging: HOST_DIR: <span class="regexp">/home/u</span>ser<span class="regexp">/work/</span>buildroot<span class="regexp">/out/</span>host</span><br><span class="line">Debugging: BUILD_DIR: <span class="regexp">/home/u</span>ser<span class="regexp">/work/</span>buildroot<span class="regexp">/out/</span>build</span><br><span class="line">Debugging: BINARIES_DIR: <span class="regexp">/home/u</span>ser<span class="regexp">/work/</span>buildroot<span class="regexp">/out/im</span>ages</span><br><span class="line">Debugging: BASE_DIR: <span class="regexp">/home/u</span>ser<span class="regexp">/work/</span>buildroot/out</span><br><span class="line">Debugging: ======&gt;scripts2.sh</span><br><span class="line">Debugging: ======&gt;scripts1.sh</span><br><span class="line">Debugging: para1 <span class="variable">$1</span> is: start</span><br><span class="line">Debugging: para2 <span class="variable">$2</span> is: install-target</span><br><span class="line">Debugging: para3 <span class="variable">$3</span> is: &lt;pkg-name&gt;</span><br><span class="line">Debugging: BR2_CONFIG: <span class="regexp">/home/u</span>ser<span class="regexp">/work/</span>buildroot<span class="regexp">/out/</span>.config</span><br><span class="line">Debugging: HOST_DIR: <span class="regexp">/home/u</span>ser<span class="regexp">/work/</span>buildroot<span class="regexp">/out/</span>host</span><br><span class="line">Debugging: BUILD_DIR: <span class="regexp">/home/u</span>ser<span class="regexp">/work/</span>buildroot<span class="regexp">/out/</span>build</span><br><span class="line">Debugging: BINARIES_DIR: <span class="regexp">/home/u</span>ser<span class="regexp">/work/</span>buildroot<span class="regexp">/out/im</span>ages</span><br><span class="line">Debugging: BASE_DIR: <span class="regexp">/home/u</span>ser<span class="regexp">/work/</span>buildroot/out</span><br><span class="line">Debugging: ======&gt;scripts2.sh</span><br><span class="line">Debugging: ======&gt;scripts1.sh</span><br><span class="line">Debugging: para1 <span class="variable">$1</span> is: end</span><br><span class="line">Debugging: para2 <span class="variable">$2</span> is: install-target</span><br><span class="line">Debugging: para3 <span class="variable">$3</span> is: &lt;pkg-name&gt;</span><br><span class="line">Debugging: BR2_CONFIG: <span class="regexp">/home/u</span>ser<span class="regexp">/work/</span>buildroot<span class="regexp">/out/</span>.config</span><br><span class="line">Debugging: HOST_DIR: <span class="regexp">/home/u</span>ser<span class="regexp">/work/</span>buildroot<span class="regexp">/out/</span>host</span><br><span class="line">Debugging: BUILD_DIR: <span class="regexp">/home/u</span>ser<span class="regexp">/work/</span>buildroot<span class="regexp">/out/</span>build</span><br><span class="line">Debugging: BINARIES_DIR: <span class="regexp">/home/u</span>ser<span class="regexp">/work/</span>buildroot<span class="regexp">/out/im</span>ages</span><br><span class="line">Debugging: BASE_DIR: <span class="regexp">/home/u</span>ser<span class="regexp">/work/</span>buildroot/out</span><br><span class="line">Debugging: ======&gt;scripts2.sh</span><br></pre></td></tr></table></figure>]]></content>
    
    
    <summary type="html">&lt;p&gt;近期在看buildroot manual文档，发现有个章节“Chapter 21. Debugging Buildroot”，里面提到了可以对buildroot编译各阶段加入想要的操作。&lt;/p&gt;
&lt;p&gt;但是网上找了下，没有发现有相关案例，打算实操下&lt;/p&gt;</summary>
    
    
    
    <category term="技术" scheme="http://example.com/categories/%E6%8A%80%E6%9C%AF/"/>
    
    
    <category term="buildroot" scheme="http://example.com/tags/buildroot/"/>
    
  </entry>
  
  <entry>
    <title>buildroot中graph-build实操</title>
    <link href="http://example.com/2024/11/22/buildroot%E4%B8%ADgraph-build%E5%AE%9E%E6%93%8D/"/>
    <id>http://example.com/2024/11/22/buildroot%E4%B8%ADgraph-build%E5%AE%9E%E6%93%8D/</id>
    <published>2024-11-22T01:36:24.000Z</published>
    <updated>2024-11-22T02:32:37.692Z</updated>
    
    <content type="html"><![CDATA[<p>又捡起buildroot了。</p><p>近期在做buildroot编译优化，阅读buildroot manual时发现个有意思的东西graph-build，准备实操下。</p><span id="more"></span><h1 id="graph-build官方说明"><a href="#graph-build官方说明" class="headerlink" title="graph-build官方说明"></a>graph-build官方说明</h1><p><a href="http://www.buildroot.net/downloads/manual/manual.html#_graphing_the_build_duration">Graphing the build duration</a></p><p>When the build of a system takes a long time, it is sometimes useful to be able to understand which packages are the longest to build, to see if anything can be done to speed up the build. In order to help such build time analysis, Buildroot collects the build time of each step of each package, and allows to generate graphs from this data.</p><p>To generate the build time graph after a build, run:</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">make graph-build</span><br></pre></td></tr></table></figure><p>This will generate a set of files in output&#x2F;graphs :</p><p>build.hist-build.pdf, a histogram of the build time for each package, ordered in the build order.<br>build.hist-duration.pdf, a histogram of the build time for each package, ordered by duration (longest first)<br>build.hist-name.pdf, a histogram of the build time for each package, order by package name.<br>build.pie-packages.pdf, a pie chart of the build time per package<br>build.pie-steps.pdf, a pie chart of the global time spent in each step of the packages build process.<br>This graph-build target requires the Python Matplotlib and Numpy libraries to be installed (python-matplotlib and python-numpy on most distributions), and also the argparse module if you’re using a Python version older than 2.7 (python-argparse on most distributions).</p><p>By default, the output format for the graph is PDF, but a different format can be selected using the BR2_GRAPH_OUT environment variable. The only other format supported is PNG:</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">BR2_GRAPH_OUT=png make graph-build</span><br></pre></td></tr></table></figure><p>简单来说，在构建完成buildroot之后，可以运行make graph-build生成一系列的编译过程中耗时图，主要有：</p><ul><li>build.hist-build.pdf：按构建顺序排序的每个软件包构建时间的直方图。</li><li>build.hist-duration.pdf：按持续时间排序（从最长开始）的每个软件包构建时间的直方图。</li><li>build.hist-name.pdf：按软件包名称排序的每个软件包构建时间的直方图。</li><li>build.pie-packages.pdf：每个软件包构建时间的饼图。</li><li>build.pie-steps.pdf：每个软件包构建过程中各步骤所占总时间的饼图。</li></ul><p>在实际运行时，还存在timeline的图。</p><ul><li>build.timeline.pdf：按照编译时间顺序显示整个编译过程的甘特图。</li></ul><h1 id="graph-build原理"><a href="#graph-build原理" class="headerlink" title="graph-build原理"></a>graph-build原理</h1><p>查看buildroot&#x2F;Makefile文件，可以看到就是使用support&#x2F;scripts&#x2F;graph-build-time对$(O)&#x2F;build&#x2F;build-time.log文件进行解析，生成各类图片。</p><figure class="highlight make"><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"><span class="section">graph-build: <span class="variable">$(O)</span>/build/build-time.log</span></span><br><span class="line">@install -d <span class="variable">$(GRAPHS_DIR)</span></span><br><span class="line"><span class="variable">$(<span class="built_in">foreach</span> o,name build duration,./support/scripts/graph-build-time \</span></span><br><span class="line"><span class="variable">--type=histogram --order=<span class="variable">$(o)</span> --input=$(&lt;)</span> \</span><br><span class="line">--output=<span class="variable">$(GRAPHS_DIR)</span>/build.hist-<span class="variable">$(o)</span>.<span class="variable">$(BR_GRAPH_OUT)</span> \</span><br><span class="line"><span class="variable">$(<span class="built_in">if</span> <span class="variable">$(BR2_GRAPH_ALT)</span>,--alternate-colors)</span><span class="variable">$(sep)</span>)</span><br><span class="line"><span class="variable">$(<span class="built_in">foreach</span> t,packages steps,./support/scripts/graph-build-time \</span></span><br><span class="line"><span class="variable">   --type=pie-<span class="variable">$(t)</span> --input=$(&lt;)</span> \</span><br><span class="line">   --output=<span class="variable">$(GRAPHS_DIR)</span>/build.pie-<span class="variable">$(t)</span>.<span class="variable">$(BR_GRAPH_OUT)</span> \</span><br><span class="line">   <span class="variable">$(<span class="built_in">if</span> <span class="variable">$(BR2_GRAPH_ALT)</span>,--alternate-colors)</span><span class="variable">$(sep)</span>)</span><br><span class="line">./support/scripts/graph-build-time --type=timeline --input=$(&lt;) \</span><br><span class="line">--output=<span class="variable">$(GRAPHS_DIR)</span>/build.timeline.<span class="variable">$(BR_GRAPH_OUT)</span> \</span><br><span class="line"><span class="variable">$(<span class="built_in">if</span> <span class="variable">$(BR2_GRAPH_ALT)</span>,--alternate-colors)</span></span><br></pre></td></tr></table></figure><h1 id="安装python3依赖"><a href="#安装python3依赖" class="headerlink" title="安装python3依赖"></a>安装python3依赖</h1><p>使用graph-build需要python-matplotlib、python-numpy等python包。由于服务器是离线环境，这里提供一种whl的安装方式。</p><p>正常可以到python官网下载，这里使用清华源。</p><ul><li>进入<a href="https://pypi.tuna.tsinghua.edu.cn/simple/kiwisolver/">https://pypi.tuna.tsinghua.edu.cn/simple/kiwisolver/</a> ，将其中的kiwisolver换成对应的包名，并下载对应版本。</li><li>下载后whl后，使用pip3 install xxx.whl进行安装，默认安装到~&#x2F;.local&#x2F;bin下。</li><li>在<del>&#x2F;.bashrc中将</del>&#x2F;.local&#x2F;bin在加入到PATH环境变量中，执行source ~&#x2F;.bashrc生效。</li></ul><figure class="highlight elixir"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="title class_">PATH</span>=<span class="variable">$PATH</span><span class="symbol">:/home/xxx/</span>.local/bin</span><br></pre></td></tr></table></figure><h1 id="graph-build输出"><a href="#graph-build输出" class="headerlink" title="graph-build输出"></a>graph-build输出</h1><h2 id="hist"><a href="#hist" class="headerlink" title="hist"></a>hist</h2><p>hist会列出每个包各个阶段的耗时，主要用于筛选出编译耗时长的包，针对这些包进行优化。</p><h3 id="hist-build"><a href="#hist-build" class="headerlink" title="hist-build"></a>hist-build</h3><p><img data-src="/2024/11/22/buildroot%E4%B8%ADgraph-build%E5%AE%9E%E6%93%8D/%E6%9E%84%E5%BB%BA%E9%A1%BA%E5%BA%8F%E7%9B%B4%E6%96%B9%E5%9B%BE.png" alt="构建顺序直方图"></p><h3 id="hist-duration"><a href="#hist-duration" class="headerlink" title="hist-duration"></a>hist-duration</h3><p><img data-src="/2024/11/22/buildroot%E4%B8%ADgraph-build%E5%AE%9E%E6%93%8D/%E8%80%97%E6%97%B6%E9%A1%BA%E5%BA%8F%E7%9B%B4%E6%96%B9%E5%9B%BE.png" alt="耗时顺序直方图"></p><h3 id="hist-name"><a href="#hist-name" class="headerlink" title="hist-name"></a>hist-name</h3><p><img data-src="/2024/11/22/buildroot%E4%B8%ADgraph-build%E5%AE%9E%E6%93%8D/%E5%8C%85%E5%90%8D%E9%A1%BA%E5%BA%8F%E7%9B%B4%E6%96%B9%E5%9B%BE.png" alt="包名顺序直方图"></p><h2 id="pie"><a href="#pie" class="headerlink" title="pie"></a>pie</h2><p>pie主要是用于统计目的。</p><h3 id="pie-packages"><a href="#pie-packages" class="headerlink" title="pie-packages"></a>pie-packages</h3><p><img data-src="/2024/11/22/buildroot%E4%B8%ADgraph-build%E5%AE%9E%E6%93%8D/%E8%BD%AF%E4%BB%B6%E5%8C%85%E6%9E%84%E5%BB%BA%E8%80%97%E6%97%B6%E9%A5%BC%E5%9B%BE.png" alt="软件包构建耗时饼图"></p><h3 id="pie-steps"><a href="#pie-steps" class="headerlink" title="pie-steps"></a>pie-steps</h3><p><img data-src="/2024/11/22/buildroot%E4%B8%ADgraph-build%E5%AE%9E%E6%93%8D/%E6%80%BB%E6%9E%84%E5%BB%BA%E6%AD%A5%E9%AA%A4%E8%80%97%E6%97%B6%E9%A5%BC%E5%9B%BE.png" alt="总构建步骤耗时饼图"></p><h2 id="timeline"><a href="#timeline" class="headerlink" title="timeline"></a>timeline</h2><p>timeline主要是用于优化编译依赖的目的。</p><p><img data-src="/2024/11/22/buildroot%E4%B8%ADgraph-build%E5%AE%9E%E6%93%8D/%E6%9E%84%E5%BB%BA%E9%A1%BA%E5%BA%8F%E7%94%98%E7%89%B9%E5%9B%BE.png" alt="构建顺序甘特图"></p><h3 id="timeline输出优化"><a href="#timeline输出优化" class="headerlink" title="timeline输出优化"></a>timeline输出优化</h3><p>使用默认的脚本，生成的图片纵坐标label都重叠了，且很多耗时短的包都绘制了，看起来不清晰。</p><p>这里提供一个补丁，优化其输出。</p><figure class="highlight patch"><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></pre></td><td class="code"><pre><span class="line"><span class="comment">diff --git a/support/scripts/graph-build-time b/support/scripts/graph-build-time</span></span><br><span class="line"><span class="comment">index 1edc3b3c..4c61f120 100755</span></span><br><span class="line"><span class="comment">--- a/support/scripts/graph-build-time</span></span><br><span class="line"><span class="comment">+++ b/support/scripts/graph-build-time</span></span><br><span class="line"><span class="meta">@@ -270,6 +270,10 @@</span> def pkg_timeline(data, output):</span><br><span class="line">     # give the proper dependency chain, but still provides a good-enough</span><br><span class="line">     # cascade graph.</span><br><span class="line">     for p in sorted(data, reverse=True, key=lambda x: x.steps_start[&#x27;configure&#x27;]):</span><br><span class="line"><span class="addition">+        # if configure + build time &lt; 4.0s, do not show in graph, to prevent the overlap of y-axis labels</span></span><br><span class="line"><span class="addition">+        if p.steps_end[&#x27;build&#x27;] - p.steps_start[&#x27;build&#x27;] + p.steps_end[&#x27;configure&#x27;] - p.steps_start[&#x27;configure&#x27;] &lt; 4.0:</span></span><br><span class="line"><span class="addition">+            continue</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line">         durations = []</span><br><span class="line">         facecolors = []</span><br><span class="line">         for step in steps:</span><br><span class="line"><span class="meta">@@ -295,9 +299,10 @@</span> def pkg_timeline(data, output):</span><br><span class="line"> </span><br><span class="line">     plt.gcf().subplots_adjust(left=0.2)</span><br><span class="line"> </span><br><span class="line"><span class="deletion">-    plt.tick_params(axis=&#x27;y&#x27;, which=&#x27;both&#x27;, labelsize=6)</span></span><br><span class="line"><span class="addition">+    # use small labelsize, to prevent the overlap of y-axis labels</span></span><br><span class="line"><span class="addition">+    plt.tick_params(axis=&#x27;y&#x27;, which=&#x27;both&#x27;, labelsize=2)</span></span><br><span class="line">     plt.title(&#x27;Timeline&#x27;)</span><br><span class="line"><span class="deletion">-    plt.savefig(output, dpi=300)</span></span><br><span class="line"><span class="addition">+    plt.savefig(output, dpi=1024)</span></span><br><span class="line"> </span><br><span class="line"> </span><br><span class="line"> # Parses the csv file passed on standard input and returns a list of</span><br></pre></td></tr></table></figure><p><img data-src="/2024/11/22/buildroot%E4%B8%ADgraph-build%E5%AE%9E%E6%93%8D/%E6%9E%84%E5%BB%BA%E9%A1%BA%E5%BA%8F%E7%94%98%E7%89%B9%E5%9B%BE%E4%BC%98%E5%8C%96.png" alt="构建顺序甘特图优化"></p>]]></content>
    
    
    <summary type="html">&lt;p&gt;又捡起buildroot了。&lt;/p&gt;
&lt;p&gt;近期在做buildroot编译优化，阅读buildroot manual时发现个有意思的东西graph-build，准备实操下。&lt;/p&gt;</summary>
    
    
    
    <category term="技术" scheme="http://example.com/categories/%E6%8A%80%E6%9C%AF/"/>
    
    
    <category term="buildroot" scheme="http://example.com/tags/buildroot/"/>
    
    <category term="python" scheme="http://example.com/tags/python/"/>
    
    <category term="可视化" scheme="http://example.com/tags/%E5%8F%AF%E8%A7%86%E5%8C%96/"/>
    
  </entry>
  
  <entry>
    <title>Linux_log重定向添加时间戳</title>
    <link href="http://example.com/2023/08/15/Linux-log%E9%87%8D%E5%AE%9A%E5%90%91%E6%B7%BB%E5%8A%A0%E6%97%B6%E9%97%B4%E6%88%B3/"/>
    <id>http://example.com/2023/08/15/Linux-log%E9%87%8D%E5%AE%9A%E5%90%91%E6%B7%BB%E5%8A%A0%E6%97%B6%E9%97%B4%E6%88%B3/</id>
    <published>2023-08-15T00:50:13.000Z</published>
    <updated>2023-08-15T01:21:30.159Z</updated>
    
    <content type="html"><![CDATA[<p>执行Linux命令时，log重定向时在每行前面加入时间戳信息。</p><span id="more"></span><p>命令如下：</p><figure class="highlight shell"><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"><span class="meta prompt_"># </span><span class="language-bash">加入时间戳，直接输出到控制台</span></span><br><span class="line">&lt;command&gt; | ts &quot;[%d-%m-%y] %H:%M:%.S&quot;</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">加入时间戳，输出到控制台，同时重定向到指定<span class="built_in">log</span></span></span><br><span class="line">&lt;command&gt; | ts &quot;[%d-%m-%y] %H:%M:%.S&quot; 2&gt;&amp;1|tee &lt;rel.log&gt;</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash"><span class="built_in">log</span>输出到控制台，加入时间戳重定向到指定<span class="built_in">log</span></span></span><br><span class="line">&lt;command&gt; 2&gt;&amp;1|tee &gt;(ts &quot;[%d-%m-%y] %H:%M:%.S&quot; &gt; &lt;rel.log&gt;)</span><br></pre></td></tr></table></figure><p>参数说明：</p><ul><li>command: 运行的命令</li><li>rel.log: log重定向的文件</li></ul><p><strong>注：ts是timestamp的缩写，使用ts命令需要安装moreutils包。ts是一个脚本，也可以从已安装的机器中复制&#x2F;usr&#x2F;bin&#x2F;ts来使用。</strong></p><p>测试效果：</p><figure class="highlight shell"><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></pre></td><td class="code"><pre><span class="line"><span class="meta prompt_">$ </span><span class="language-bash"><span class="built_in">cat</span> test.sh</span></span><br><span class="line"><span class="meta prompt_">#</span><span class="language-bash">!/bin/bash</span></span><br><span class="line"></span><br><span class="line">count=0</span><br><span class="line"></span><br><span class="line">while true; do</span><br><span class="line">        count=$((count+1))</span><br><span class="line">        echo &quot;count: $&#123;count&#125;&quot;</span><br><span class="line">        sleep 1</span><br><span class="line">done</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_">$ </span><span class="language-bash">./test.sh | ts <span class="string">&quot;[%y-%m-%d] %H:%M:%.S&quot;</span></span></span><br><span class="line">[23-08-15] 09:10:04.574804 count: 1</span><br><span class="line">[23-08-15] 09:10:05.558411 count: 2</span><br><span class="line">[23-08-15] 09:10:06.559441 count: 3</span><br><span class="line">^C</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_">$ </span><span class="language-bash">./test.sh | ts <span class="string">&quot;[%y-%m-%d] %H:%M:%.S&quot;</span> 2&gt;&amp;1|<span class="built_in">tee</span> 1.<span class="built_in">log</span></span></span><br><span class="line">[23-08-15] 09:10:17.630634 count: 1</span><br><span class="line">[23-08-15] 09:10:18.613956 count: 2</span><br><span class="line">[23-08-15] 09:10:19.615041 count: 3</span><br><span class="line">^C</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_">$ </span><span class="language-bash"><span class="built_in">cat</span> 1.<span class="built_in">log</span></span></span><br><span class="line">[23-08-15] 09:10:17.630634 count: 1</span><br><span class="line">[23-08-15] 09:10:18.613956 count: 2</span><br><span class="line">[23-08-15] 09:10:19.615041 count: 3</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_">$ </span><span class="language-bash">./test.sh 2&gt;&amp;1|<span class="built_in">tee</span> &gt;(ts <span class="string">&quot;[%d-%m-%y] %H:%M:%.S&quot;</span> &gt; 2.<span class="built_in">log</span>)</span></span><br><span class="line">count: 1</span><br><span class="line">count: 2</span><br><span class="line">count: 3</span><br><span class="line">^C</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_">$ </span><span class="language-bash"><span class="built_in">cat</span> 2.<span class="built_in">log</span></span></span><br><span class="line">[15-08-23] 09:10:28.792188 count: 1</span><br><span class="line">[15-08-23] 09:10:29.773346 count: 2</span><br><span class="line">[15-08-23] 09:10:30.774403 count: 3</span><br></pre></td></tr></table></figure>]]></content>
    
    
    <summary type="html">&lt;p&gt;执行Linux命令时，log重定向时在每行前面加入时间戳信息。&lt;/p&gt;</summary>
    
    
    
    <category term="技术" scheme="http://example.com/categories/%E6%8A%80%E6%9C%AF/"/>
    
    
    <category term="Linux" scheme="http://example.com/tags/Linux/"/>
    
    <category term="log" scheme="http://example.com/tags/log/"/>
    
  </entry>
  
  <entry>
    <title>使用python解析CVS表格绘制燃尽图和收敛图</title>
    <link href="http://example.com/2023/08/12/%E4%BD%BF%E7%94%A8python%E8%A7%A3%E6%9E%90CVS%E8%A1%A8%E6%A0%BC%E7%BB%98%E5%88%B6%E7%87%83%E5%B0%BD%E5%9B%BE%E5%92%8C%E6%94%B6%E6%95%9B%E5%9B%BE/"/>
    <id>http://example.com/2023/08/12/%E4%BD%BF%E7%94%A8python%E8%A7%A3%E6%9E%90CVS%E8%A1%A8%E6%A0%BC%E7%BB%98%E5%88%B6%E7%87%83%E5%B0%BD%E5%9B%BE%E5%92%8C%E6%94%B6%E6%95%9B%E5%9B%BE/</id>
    <published>2023-08-12T07:59:24.000Z</published>
    <updated>2024-11-22T01:39:02.182Z</updated>
    
    <content type="html"><![CDATA[<p>近期有个任务，是让部门的项目开发变得可视化，以便老板们能快速了解项目情况。</p><p>我这边主要是提供思路，从PMS系统中提取项目的任务以及缺陷情况，绘制成两张图——任务燃尽图（TR4）以及缺陷收敛图（TR5）。</p><p>当然这个开发任务最终还是公司IT部门承接，我主要是配合。</p><p>近期恰好学习了一些python的知识，心里想着python是否也能实现，于是就有了这篇文章。</p><span id="more"></span><h1 id="任务燃尽图"><a href="#任务燃尽图" class="headerlink" title="任务燃尽图"></a>任务燃尽图</h1><h2 id="源码"><a href="#源码" class="headerlink" title="源码"></a>源码</h2><p>使用方法：</p><ul><li>task.cvs: 从pms特定项目中导出的任务cvs表格文件</li><li>task_id: 分析指定任务及其所有子任务</li></ul><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">./xxx.py &lt;task.cvs&gt; &lt;task_id&gt;</span><br></pre></td></tr></table></figure><p>代码如下：</p><figure class="highlight python"><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><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#!/usr/bin/env python3</span></span><br><span class="line"><span class="comment"># _*_ coding:utf-8 _*_</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> sys</span><br><span class="line"><span class="keyword">import</span> csv</span><br><span class="line"><span class="keyword">from</span> datetime <span class="keyword">import</span> datetime, timedelta</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> matplotlib.pyplot <span class="keyword">as</span> plt</span><br><span class="line"><span class="keyword">import</span> matplotlib.dates <span class="keyword">as</span> mdates</span><br><span class="line"><span class="keyword">import</span> numpy <span class="keyword">as</span> np</span><br><span class="line"><span class="keyword">import</span> matplotlib</span><br><span class="line"></span><br><span class="line">filename = sys.argv[<span class="number">1</span>]</span><br><span class="line">index = sys.argv[<span class="number">2</span>]</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">get_xticks</span>(<span class="params">min_date, max_date, delta_day</span>):</span><br><span class="line">    <span class="comment"># 创建日期数组</span></span><br><span class="line">    x_ticks = []</span><br><span class="line">    curr_date = min_date</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 设置日期间隔</span></span><br><span class="line">    delta = timedelta(days=delta_day)</span><br><span class="line"></span><br><span class="line">    <span class="keyword">while</span> curr_date &lt;= max_date:</span><br><span class="line">        x_ticks.append(curr_date)</span><br><span class="line">        curr_date += delta</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> x_ticks</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">find_min_max_dates</span>(<span class="params">csv_data, column_index</span>):</span><br><span class="line">    dates = []</span><br><span class="line">    <span class="keyword">for</span> row <span class="keyword">in</span> csv_data:</span><br><span class="line">        date_str = row[column_index]</span><br><span class="line">        <span class="keyword">try</span>:</span><br><span class="line">            date = datetime.strptime(date_str, <span class="string">&#x27;%Y-%m-%d&#x27;</span>).date()  <span class="comment"># 将日期字符串解析为 datetime 对象</span></span><br><span class="line">            dates.append(date)</span><br><span class="line">        <span class="keyword">except</span> ValueError:</span><br><span class="line">            <span class="keyword">pass</span></span><br><span class="line">    </span><br><span class="line">    min_date = <span class="built_in">min</span>(dates) <span class="keyword">if</span> dates <span class="keyword">else</span> <span class="literal">None</span></span><br><span class="line">    max_date = <span class="built_in">max</span>(dates) <span class="keyword">if</span> dates <span class="keyword">else</span> <span class="literal">None</span></span><br><span class="line">    </span><br><span class="line">    <span class="keyword">return</span> min_date, max_date</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">count_dates_before_3</span>(<span class="params">csv_data, column_index, min_date, max_date</span>):</span><br><span class="line">    date_counts = &#123;&#125;</span><br><span class="line">    </span><br><span class="line">    curr_date = min_date</span><br><span class="line">    <span class="keyword">while</span> curr_date &lt;= max_date:</span><br><span class="line">        date_counts[curr_date] = <span class="number">0</span></span><br><span class="line">        curr_date += timedelta(days=<span class="number">1</span>)</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">for</span> row <span class="keyword">in</span> csv_data:</span><br><span class="line">        date_str = row[column_index]</span><br><span class="line">        <span class="keyword">try</span>:</span><br><span class="line">            date_obj = datetime.strptime(date_str, <span class="string">&#x27;%Y-%m-%d&#x27;</span>).date()</span><br><span class="line">            <span class="keyword">if</span> min_date &lt;= date_obj &lt;= max_date:</span><br><span class="line">                curr_date = date_obj</span><br><span class="line">                <span class="keyword">while</span> curr_date &gt;= min_date:</span><br><span class="line">                    date_counts[curr_date] += <span class="number">1</span></span><br><span class="line">                    curr_date -= timedelta(days=<span class="number">1</span>)</span><br><span class="line">        <span class="keyword">except</span> ValueError:</span><br><span class="line">            curr_date = max_date</span><br><span class="line">            <span class="keyword">while</span> curr_date &gt;= min_date:</span><br><span class="line">                date_counts[curr_date] += <span class="number">1</span></span><br><span class="line">                curr_date -= timedelta(days=<span class="number">1</span>)</span><br><span class="line">            <span class="keyword">pass</span></span><br><span class="line">    </span><br><span class="line">    <span class="keyword">return</span> date_counts</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">find_children</span>(<span class="params">csv_data, parent_index, c_col, p_col</span>):</span><br><span class="line">    children = []</span><br><span class="line">    <span class="keyword">for</span> row <span class="keyword">in</span> csv_data:</span><br><span class="line">        <span class="keyword">if</span> row[<span class="number">2</span>] == parent_index:</span><br><span class="line">            children.append(row)  <span class="comment"># 将子任务的索引添加到列表中</span></span><br><span class="line">            children.extend(find_children(csv_data, row[<span class="number">0</span>], c_col, p_col))  <span class="comment"># 递归查找子任务的子任务</span></span><br><span class="line">    <span class="keyword">return</span> children</span><br><span class="line"></span><br><span class="line"><span class="comment"># 打开原始CSV文件和新的CSV文件</span></span><br><span class="line"><span class="keyword">with</span> <span class="built_in">open</span>(filename, <span class="string">&#x27;r&#x27;</span>) <span class="keyword">as</span> csvfile, <span class="built_in">open</span>(filename+<span class="string">&quot;.sort&quot;</span>, <span class="string">&#x27;w&#x27;</span>, newline=<span class="string">&#x27;&#x27;</span>) <span class="keyword">as</span> sorted_csvfile:</span><br><span class="line">    <span class="comment"># 创建CSV读取器和写入器对象</span></span><br><span class="line">    reader = csv.reader(csvfile)</span><br><span class="line">    writer = csv.writer(sorted_csvfile)</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 读取原始CSV文件中的数据</span></span><br><span class="line">    data = <span class="built_in">list</span>(reader)</span><br><span class="line"></span><br><span class="line">    writer.writerow(data[<span class="number">0</span>])</span><br><span class="line">  </span><br><span class="line">    <span class="comment"># 查找&quot;父任务&quot;,&quot;计划开始日期&quot;,&quot;计划完成日期&quot;所在的列索引</span></span><br><span class="line">    p_col = <span class="literal">None</span></span><br><span class="line">    s_col = <span class="literal">None</span></span><br><span class="line">    e_col = <span class="literal">None</span></span><br><span class="line">    l_col = <span class="literal">None</span></span><br><span class="line">    <span class="keyword">for</span> i, cell <span class="keyword">in</span> <span class="built_in">enumerate</span>(data[<span class="number">0</span>]):</span><br><span class="line">        <span class="keyword">if</span> cell == <span class="string">&quot;父任务&quot;</span>:</span><br><span class="line">            p_col = i</span><br><span class="line">        </span><br><span class="line">        <span class="keyword">if</span> cell == <span class="string">&quot;计划开始日期&quot;</span>:</span><br><span class="line">            s_col = i</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> cell == <span class="string">&quot;计划完成日期&quot;</span>:</span><br><span class="line">            e_col = i</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> cell == <span class="string">&quot;实际完成时间&quot;</span>:</span><br><span class="line">            l_col = i</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 根据第二列对数据进行排序</span></span><br><span class="line">    sorted_data = <span class="built_in">sorted</span>(data[<span class="number">1</span>:], key=<span class="keyword">lambda</span> row: row[<span class="number">0</span>])</span><br><span class="line"></span><br><span class="line">    <span class="keyword">for</span> row <span class="keyword">in</span> sorted_data:</span><br><span class="line">        <span class="keyword">if</span> row[<span class="number">0</span>] == index:</span><br><span class="line">            writer.writerow(row)</span><br><span class="line">            real_min_date = datetime.strptime(row[s_col], <span class="string">&#x27;%Y-%m-%d&#x27;</span>).date()</span><br><span class="line">            <span class="comment">#real_min_date = row[s_col]</span></span><br><span class="line"></span><br><span class="line">    child_data = find_children(sorted_data, index, <span class="number">0</span>, p_col)</span><br><span class="line"></span><br><span class="line">    <span class="keyword">for</span> child <span class="keyword">in</span> child_data:</span><br><span class="line">        writer.writerow(child)</span><br><span class="line"></span><br><span class="line">    min_date, max_date = find_min_max_dates(child_data, e_col)</span><br><span class="line"></span><br><span class="line">    date_now = datetime.now().date()</span><br><span class="line">    date_counts_orig = count_dates_before_3(child_data, e_col, real_min_date, max_date)</span><br><span class="line">    real_date_counts_orig = count_dates_before_3(child_data, l_col, real_min_date, max_date)</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 截止到今天</span></span><br><span class="line">    date_counts = &#123;k: v <span class="keyword">for</span> k, v <span class="keyword">in</span> date_counts_orig.items() <span class="keyword">if</span> k &lt; date_now&#125;</span><br><span class="line">    real_date_counts = &#123;k: v <span class="keyword">for</span> k, v <span class="keyword">in</span> real_date_counts_orig.items() <span class="keyword">if</span> k &lt; date_now&#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 画图</span></span><br><span class="line">    matplotlib.rcParams[<span class="string">&#x27;font.sans-serif&#x27;</span>] = [<span class="string">&#x27;SimHei&#x27;</span>]</span><br><span class="line">    matplotlib.rcParams[<span class="string">&#x27;axes.unicode_minus&#x27;</span>] = <span class="literal">False</span></span><br><span class="line"></span><br><span class="line">    plt.figure(figsize=(<span class="number">15</span>, <span class="number">6</span>))</span><br><span class="line"></span><br><span class="line">    x = <span class="built_in">list</span>(date_counts.keys())</span><br><span class="line">    y = <span class="built_in">list</span>(date_counts.values())</span><br><span class="line"></span><br><span class="line">    x1 = <span class="built_in">list</span>(real_date_counts.keys())</span><br><span class="line">    y1 = <span class="built_in">list</span>(real_date_counts.values())</span><br><span class="line"></span><br><span class="line">    plt.plot(x, y, label=<span class="string">&#x27;预期剩余&#x27;</span>)</span><br><span class="line">    plt.plot(x1, y1, label=<span class="string">&#x27;实际剩余&#x27;</span>)</span><br><span class="line">    plt.xlabel(<span class="string">&#x27;日期&#x27;</span>)</span><br><span class="line">    plt.ylabel(<span class="string">&#x27;任务个数&#x27;</span>)</span><br><span class="line"></span><br><span class="line">    plt.title(<span class="string">&#x27;任务燃尽图&#x27;</span>)</span><br><span class="line"></span><br><span class="line">    x_ticks = get_xticks(min_date, date_now, <span class="number">15</span>)</span><br><span class="line">    num_list = mdates.date2num(x_ticks)</span><br><span class="line">    plt.xticks(num_list, [date.strftime(<span class="string">&#x27;%Y-%m-%d&#x27;</span>) <span class="keyword">for</span> date <span class="keyword">in</span> x_ticks])</span><br><span class="line"></span><br><span class="line">    y_ticks = np.arange(<span class="number">0</span>, <span class="number">280</span>, <span class="number">20</span>)</span><br><span class="line">    plt.yticks(y_ticks)</span><br><span class="line"></span><br><span class="line">    plt.xticks(rotation=<span class="number">90</span>)</span><br><span class="line">    plt.legend()</span><br><span class="line">    plt.show()</span><br><span class="line"></span><br></pre></td></tr></table></figure><h2 id="效果"><a href="#效果" class="headerlink" title="效果"></a>效果</h2><p><img data-src="/2023/08/12/%E4%BD%BF%E7%94%A8python%E8%A7%A3%E6%9E%90CVS%E8%A1%A8%E6%A0%BC%E7%BB%98%E5%88%B6%E7%87%83%E5%B0%BD%E5%9B%BE%E5%92%8C%E6%94%B6%E6%95%9B%E5%9B%BE/%E4%BB%BB%E5%8A%A1%E7%87%83%E5%B0%BD%E5%9B%BE.png" alt="任务燃尽图"></p><h1 id="缺陷收敛图"><a href="#缺陷收敛图" class="headerlink" title="缺陷收敛图"></a>缺陷收敛图</h1><h2 id="源码-1"><a href="#源码-1" class="headerlink" title="源码"></a>源码</h2><p>使用方法：</p><ul><li>issues.cvs: 从pms特定项目中导出的任务cvs表格文件</li></ul><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">./xxx.py &lt;issues.cvs&gt;</span><br></pre></td></tr></table></figure><p>代码如下：</p><figure class="highlight python"><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><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#!/usr/bin/env python3</span></span><br><span class="line"><span class="comment"># _*_ coding:utf-8 _*_</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> sys</span><br><span class="line"><span class="keyword">import</span> csv</span><br><span class="line"><span class="keyword">from</span> datetime <span class="keyword">import</span> datetime, timedelta</span><br><span class="line"><span class="keyword">from</span> collections <span class="keyword">import</span> Counter</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> matplotlib.pyplot <span class="keyword">as</span> plt</span><br><span class="line"><span class="keyword">import</span> matplotlib.dates <span class="keyword">as</span> mdates</span><br><span class="line"><span class="keyword">import</span> numpy <span class="keyword">as</span> np</span><br><span class="line"><span class="keyword">import</span> matplotlib</span><br><span class="line"></span><br><span class="line">filename = sys.argv[<span class="number">1</span>]</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">get_xticks</span>(<span class="params">min_date, max_date, delta_day</span>):</span><br><span class="line">    <span class="comment"># 设置日期间隔</span></span><br><span class="line">    delta = timedelta(days=delta_day)</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 生成日期刻度</span></span><br><span class="line">    x_ticks = mdates.drange(min_date, max_date, delta)</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">return</span> x_ticks</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">find_min_max_dates</span>(<span class="params">csv_data, column_index</span>):</span><br><span class="line">    dates = []</span><br><span class="line">    <span class="keyword">for</span> row <span class="keyword">in</span> csv_data:</span><br><span class="line">        date_str_tmp = row[column_index]</span><br><span class="line">        date_str = date_str_tmp.split(<span class="string">&#x27; &#x27;</span>)[<span class="number">0</span>]</span><br><span class="line">        <span class="keyword">try</span>:</span><br><span class="line">            date = datetime.strptime(date_str, <span class="string">&#x27;%Y-%m-%d&#x27;</span>).date()  <span class="comment"># 将日期字符串解析为 datetime 对象</span></span><br><span class="line">            dates.append(date)</span><br><span class="line">        <span class="keyword">except</span> ValueError:</span><br><span class="line">            <span class="keyword">pass</span></span><br><span class="line">    </span><br><span class="line">    min_date = <span class="built_in">min</span>(dates) <span class="keyword">if</span> dates <span class="keyword">else</span> <span class="literal">None</span></span><br><span class="line">    max_date = <span class="built_in">max</span>(dates) <span class="keyword">if</span> dates <span class="keyword">else</span> <span class="literal">None</span></span><br><span class="line">    </span><br><span class="line">    <span class="keyword">return</span> min_date, max_date</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">count_columns</span>(<span class="params">cvs_data, index1, index2, min_date, max_date</span>):</span><br><span class="line">    column1_data = []</span><br><span class="line">    column2_data = []</span><br><span class="line"></span><br><span class="line">    <span class="keyword">for</span> row <span class="keyword">in</span> cvs_data:</span><br><span class="line">        createtime_str = row[index1]</span><br><span class="line">        index1_str = createtime_str.split(<span class="string">&#x27; &#x27;</span>)[<span class="number">0</span>]</span><br><span class="line">        column1_data.append(index1_str)</span><br><span class="line">        <span class="keyword">if</span> row[index2] != <span class="string">&quot;&quot;</span>:</span><br><span class="line">            column2_data.append(row[index2])</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 使用 Counter 统计不同元素的个数</span></span><br><span class="line">    column1_counts = Counter(column1_data)</span><br><span class="line">    column2_counts = Counter(column2_data)</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 按日期从旧到新进行排序</span></span><br><span class="line">    sorted_column1_counts = <span class="built_in">dict</span>(<span class="built_in">sorted</span>(column1_counts.items(), key=<span class="keyword">lambda</span> x: x[<span class="number">0</span>]))</span><br><span class="line">    sorted_column2_counts = <span class="built_in">dict</span>(<span class="built_in">sorted</span>(column2_counts.items(), key=<span class="keyword">lambda</span> x: x[<span class="number">0</span>]))</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 填充不在日期范围内的日期，并将计数设置为0</span></span><br><span class="line">    current_date = min_date</span><br><span class="line"></span><br><span class="line">    <span class="keyword">while</span> current_date &lt;= max_date:</span><br><span class="line">        date_str = current_date.strftime(<span class="string">&#x27;%Y-%m-%d&#x27;</span>)</span><br><span class="line">        <span class="keyword">if</span> date_str <span class="keyword">not</span> <span class="keyword">in</span> sorted_column1_counts:</span><br><span class="line">            sorted_column1_counts[date_str] = <span class="number">0</span></span><br><span class="line">        <span class="keyword">if</span> date_str <span class="keyword">not</span> <span class="keyword">in</span> sorted_column2_counts:</span><br><span class="line">            sorted_column2_counts[date_str] = <span class="number">0</span></span><br><span class="line">        current_date += timedelta(days=<span class="number">1</span>)</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 按日期从旧到新进行排序</span></span><br><span class="line">    sorted_c_counts = <span class="built_in">dict</span>(<span class="built_in">sorted</span>(sorted_column1_counts.items(), key=<span class="keyword">lambda</span> x: x[<span class="number">0</span>]))</span><br><span class="line">    sorted_l_counts = <span class="built_in">dict</span>(<span class="built_in">sorted</span>(sorted_column2_counts.items(), key=<span class="keyword">lambda</span> x: x[<span class="number">0</span>]))</span><br><span class="line"></span><br><span class="line">    current_date = min_date</span><br><span class="line">    sorted_c_counts_sum = &#123;&#125;</span><br><span class="line">    sorted_l_counts_sum = &#123;&#125;</span><br><span class="line">    count_c_sum = <span class="number">0</span></span><br><span class="line">    count_l_sum = <span class="number">0</span></span><br><span class="line">    <span class="keyword">while</span> current_date &lt;= max_date:</span><br><span class="line">        date_str = current_date.strftime(<span class="string">&#x27;%Y-%m-%d&#x27;</span>)</span><br><span class="line">        count_c_sum += sorted_c_counts[date_str]</span><br><span class="line">        sorted_c_counts_sum[date_str] = count_c_sum</span><br><span class="line">        count_l_sum += sorted_l_counts[date_str]</span><br><span class="line">        sorted_l_counts_sum[date_str] = count_l_sum</span><br><span class="line">        current_date += timedelta(days=<span class="number">1</span>)</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> sorted_c_counts, sorted_l_counts, sorted_c_counts_sum, sorted_l_counts_sum</span><br><span class="line"></span><br><span class="line"><span class="comment"># 打开原始CSV文件和新的CSV文件</span></span><br><span class="line"><span class="keyword">with</span> <span class="built_in">open</span>(filename, <span class="string">&#x27;r&#x27;</span>) <span class="keyword">as</span> csvfile:</span><br><span class="line">    <span class="comment"># 创建CSV读取器和写入器对象</span></span><br><span class="line">    reader = csv.reader(csvfile)</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 读取原始CSV文件中的数据</span></span><br><span class="line">    data = <span class="built_in">list</span>(reader)</span><br><span class="line">  </span><br><span class="line">    <span class="comment"># 查找&quot;#&quot;,&quot;创建时间&quot;,&quot;实际完成日期&quot;所在的列索引</span></span><br><span class="line">    i_col = <span class="literal">None</span></span><br><span class="line">    c_col = <span class="literal">None</span></span><br><span class="line">    l_col = <span class="literal">None</span></span><br><span class="line">    <span class="keyword">for</span> i, cell <span class="keyword">in</span> <span class="built_in">enumerate</span>(data[<span class="number">0</span>]):</span><br><span class="line">        <span class="keyword">if</span> cell == <span class="string">&quot;#&quot;</span>:</span><br><span class="line">            i_col = i</span><br><span class="line">        </span><br><span class="line">        <span class="keyword">if</span> cell == <span class="string">&quot;创建时间&quot;</span>:</span><br><span class="line">            c_col = i</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> cell == <span class="string">&quot;实际完成时间&quot;</span>:</span><br><span class="line">            l_col = i</span><br><span class="line"></span><br><span class="line">    min_date, fake_max_date = find_min_max_dates(data[<span class="number">1</span>:], c_col)</span><br><span class="line">    date_now = datetime.now().date()</span><br><span class="line">    max_date = date_now</span><br><span class="line"></span><br><span class="line">    c_counts, l_counts, c_counts_sum, l_counts_sum = count_columns(data[<span class="number">1</span>:], c_col, l_col, min_date, max_date)</span><br><span class="line"></span><br><span class="line">    plt.rcParams[<span class="string">&#x27;font.sans-serif&#x27;</span>]=[<span class="string">&#x27;SimHei&#x27;</span>]</span><br><span class="line">    plt.rcParams[<span class="string">&#x27;axes.unicode_minus&#x27;</span>] = <span class="literal">False</span></span><br><span class="line"></span><br><span class="line">    plt.figure(figsize=(<span class="number">15</span>, <span class="number">6</span>))</span><br><span class="line"></span><br><span class="line">    x = <span class="built_in">list</span>(c_counts.keys())</span><br><span class="line">    y = <span class="built_in">list</span>(c_counts.values())</span><br><span class="line"></span><br><span class="line">    x1 = <span class="built_in">list</span>(l_counts.keys())</span><br><span class="line">    y1 = <span class="built_in">list</span>(l_counts.values())</span><br><span class="line"></span><br><span class="line">    x2 = <span class="built_in">list</span>(c_counts_sum.keys())</span><br><span class="line">    y2 = <span class="built_in">list</span>(c_counts_sum.values())</span><br><span class="line"></span><br><span class="line">    x3 = <span class="built_in">list</span>(l_counts_sum.keys())</span><br><span class="line">    y3 = <span class="built_in">list</span>(l_counts_sum.values())</span><br><span class="line"></span><br><span class="line">    plt.plot(x, y, label=<span class="string">&#x27;每日新增&#x27;</span>)</span><br><span class="line">    plt.plot(x1, y1, label=<span class="string">&#x27;每日解决&#x27;</span>)</span><br><span class="line">    plt.plot(x2, y2, label=<span class="string">&#x27;累计新增&#x27;</span>)</span><br><span class="line">    plt.plot(x3, y3, label=<span class="string">&#x27;累计解决&#x27;</span>)</span><br><span class="line">    plt.xlabel(<span class="string">&#x27;日期&#x27;</span>)</span><br><span class="line">    plt.ylabel(<span class="string">&#x27;缺陷个数&#x27;</span>)</span><br><span class="line"></span><br><span class="line">    plt.title(<span class="string">&#x27;缺陷收敛图&#x27;</span>)</span><br><span class="line">    x_ticks = get_xticks(min_date, date_now, <span class="number">15</span>)</span><br><span class="line">    <span class="comment"># 将数值转换为日期对象</span></span><br><span class="line">    x_dates = [mdates.num2date(x) <span class="keyword">for</span> x <span class="keyword">in</span> x_ticks]</span><br><span class="line">    <span class="comment"># 将日期对象格式化为字符串</span></span><br><span class="line">    x_labels = [date.strftime(<span class="string">&#x27;%Y-%m-%d&#x27;</span>) <span class="keyword">for</span> date <span class="keyword">in</span> x_dates]</span><br><span class="line">    <span class="comment"># 设置 x 轴刻度为日期字符串</span></span><br><span class="line">    plt.xticks(x_labels, rotation=<span class="number">90</span>)</span><br><span class="line"></span><br><span class="line">    y_ticks = np.arange(<span class="number">0</span>, <span class="number">500</span>, <span class="number">20</span>)</span><br><span class="line">    plt.yticks(y_ticks)</span><br><span class="line"></span><br><span class="line">    plt.legend()</span><br><span class="line">    plt.show()</span><br><span class="line"></span><br><span class="line"></span><br></pre></td></tr></table></figure><h2 id="效果-1"><a href="#效果-1" class="headerlink" title="效果"></a>效果</h2><p><img data-src="/2023/08/12/%E4%BD%BF%E7%94%A8python%E8%A7%A3%E6%9E%90CVS%E8%A1%A8%E6%A0%BC%E7%BB%98%E5%88%B6%E7%87%83%E5%B0%BD%E5%9B%BE%E5%92%8C%E6%94%B6%E6%95%9B%E5%9B%BE/%E7%BC%BA%E9%99%B7%E6%94%B6%E6%95%9B%E5%9B%BE.png" alt="缺陷收敛图"></p>]]></content>
    
    
    <summary type="html">&lt;p&gt;近期有个任务，是让部门的项目开发变得可视化，以便老板们能快速了解项目情况。&lt;/p&gt;
&lt;p&gt;我这边主要是提供思路，从PMS系统中提取项目的任务以及缺陷情况，绘制成两张图——任务燃尽图（TR4）以及缺陷收敛图（TR5）。&lt;/p&gt;
&lt;p&gt;当然这个开发任务最终还是公司IT部门承接，我主要是配合。&lt;/p&gt;
&lt;p&gt;近期恰好学习了一些python的知识，心里想着python是否也能实现，于是就有了这篇文章。&lt;/p&gt;</summary>
    
    
    
    <category term="技术" scheme="http://example.com/categories/%E6%8A%80%E6%9C%AF/"/>
    
    
    <category term="python" scheme="http://example.com/tags/python/"/>
    
    <category term="可视化" scheme="http://example.com/tags/%E5%8F%AF%E8%A7%86%E5%8C%96/"/>
    
  </entry>
  
  <entry>
    <title>Hello World</title>
    <link href="http://example.com/2023/08/10/hello-world/"/>
    <id>http://example.com/2023/08/10/hello-world/</id>
    <published>2023-08-10T02:53:04.475Z</published>
    <updated>2023-08-10T02:53:04.475Z</updated>
    
    <content type="html"><![CDATA[<p>Welcome to <a href="https://hexo.io/">Hexo</a>! This is your very first post. Check <a href="https://hexo.io/docs/">documentation</a> for more info. If you get any problems when using Hexo, you can find the answer in <a href="https://hexo.io/docs/troubleshooting.html">troubleshooting</a> or you can ask me on <a href="https://github.com/hexojs/hexo/issues">GitHub</a>.</p><span id="more"></span><h2 id="Quick-Start"><a href="#Quick-Start" class="headerlink" title="Quick Start"></a>Quick Start</h2><h3 id="Create-a-new-post"><a href="#Create-a-new-post" class="headerlink" title="Create a new post"></a>Create a new post</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ hexo new <span class="string">&quot;My New Post&quot;</span></span><br></pre></td></tr></table></figure><p>More info: <a href="https://hexo.io/docs/writing.html">Writing</a></p><h3 id="Run-server"><a href="#Run-server" class="headerlink" title="Run server"></a>Run server</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ hexo server</span><br></pre></td></tr></table></figure><p>More info: <a href="https://hexo.io/docs/server.html">Server</a></p><h3 id="Generate-static-files"><a href="#Generate-static-files" class="headerlink" title="Generate static files"></a>Generate static files</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ hexo generate</span><br></pre></td></tr></table></figure><p>More info: <a href="https://hexo.io/docs/generating.html">Generating</a></p><h3 id="Deploy-to-remote-sites"><a href="#Deploy-to-remote-sites" class="headerlink" title="Deploy to remote sites"></a>Deploy to remote sites</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ hexo deploy</span><br></pre></td></tr></table></figure><p>More info: <a href="https://hexo.io/docs/one-command-deployment.html">Deployment</a></p>]]></content>
    
    
    <summary type="html">&lt;p&gt;Welcome to &lt;a href=&quot;https://hexo.io/&quot;&gt;Hexo&lt;/a&gt;! This is your very first post. Check &lt;a href=&quot;https://hexo.io/docs/&quot;&gt;documentation&lt;/a&gt; for more info. If you get any problems when using Hexo, you can find the answer in &lt;a href=&quot;https://hexo.io/docs/troubleshooting.html&quot;&gt;troubleshooting&lt;/a&gt; or you can ask me on &lt;a href=&quot;https://github.com/hexojs/hexo/issues&quot;&gt;GitHub&lt;/a&gt;.&lt;/p&gt;</summary>
    
    
    
    
  </entry>
  
  <entry>
    <title>todo list</title>
    <link href="http://example.com/2023/08/09/todo_list/"/>
    <id>http://example.com/2023/08/09/todo_list/</id>
    <published>2023-08-09T06:19:56.000Z</published>
    <updated>2023-08-12T09:03:09.266Z</updated>
    
    <content type="html"><![CDATA[<p>待办事项</p><span id="more"></span><h1 id="todo-list"><a href="#todo-list" class="headerlink" title="todo list"></a>todo list</h1><h2 id="hexo-next"><a href="#hexo-next" class="headerlink" title="hexo&#x2F;next"></a>hexo&#x2F;next</h2><ul><li>完成google&#x2F;baidu sitemap</li><li>完善aboutme</li><li><del>添加头像</del></li></ul><h2 id="技术"><a href="#技术" class="headerlink" title="技术"></a>技术</h2><ul><li>syslog</li><li>llvm&#x2F;clang</li><li>gn&#x2F;ninja</li><li>freertos支持模块化加载</li><li><del>使用python绘制任务燃尽图、缺陷收敛图</del></li></ul><h2 id="书籍"><a href="#书籍" class="headerlink" title="书籍"></a>书籍</h2>]]></content>
    
    
    <summary type="html">todo list</summary>
    
    
    
    <category term="todo_list" scheme="http://example.com/categories/todo-list/"/>
    
    
    <category term="todo" scheme="http://example.com/tags/todo/"/>
    
    <category term="other" scheme="http://example.com/tags/other/"/>
    
  </entry>
  
</feed>
