{
  "version": "https://jsonfeed.org/version/1",
  "title": "王很水的笔记",
  "description": "majar buzz kill",
  "home_page_url": "https://wanghenshui.github.io",
  "feed_url": "https://wanghenshui.github.io/feed.json",
  "favicon": "https://wanghenshui.github.io/favicon.png",
  
  "author": {
    "name": "王很水"
  },
  
  "items": [
    
    
    {
      "id": "https://wanghenshui.github.io/2024/12/06/best-free-is-exit.html",
      "url": "https://wanghenshui.github.io/2024/12/06/best-free-is-exit.html",
      "title": "best free is exit",
      "content_html": "<p>省流 不析构，直接退出进程</p>\n\n<!-- more -->\n\n<p><a href=\"https://groups.google.com/g/rocksdb/c/xQ_o9jWoFqg\">rocksdb 论坛看到的帖子，发现进程关闭很慢</a></p>\n\n<p>他们的配置</p>\n\n<pre><code class=\"language-cpps\">rocksdb::LRUCacheOptions lru_block_cache_opts;\nlru_block_cache_opts.capacity = 1024*1024*1024*256; // 256 GiB\nlru_block_cache_opts.strict_capacity_limit = false;\nlru_block_cache_opts.high_pri_pool_ratio = 0.5;\nblock_cache_ = rocksdb::NewLRUCache(lru_block_cache_opts)\n</code></pre>\n\n<p>内存256G 主要都卡在析构函数上了</p>\n\n<p>我一开始给的点子是WAL或者主动停compaction之类的</p>\n\n<p>blockcache析构一时没有好的点子</p>\n\n<p>Mark Callaghan给了个点子，直接跳过析构就好了</p>\n\n<p>我怎么就没想到呢，脑子思维卡住了</p>\n\n<p>rocksdb提供了跳过析构的接口</p>\n\n<div class=\"language-cpp highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\">// Call this on shutdown if you want to speed it up. Cache will disown</span>\n<span class=\"c1\">// any underlying data and will not free it on delete. This call will leak</span>\n<span class=\"c1\">// memory - call this only if you're shutting down the process.</span>\n<span class=\"c1\">// Any attempts of using cache after this call will fail terribly.</span>\n<span class=\"c1\">// Always delete the DB object before calling this method!</span>\n<span class=\"k\">virtual</span> <span class=\"kt\">void</span> <span class=\"nf\">DisownData</span><span class=\"p\">()</span> <span class=\"p\">{</span>\n<span class=\"c1\">// default implementation is noop</span>\n<span class=\"p\">}</span>\n</code></pre></div></div>\n\n<p>主动停止的时候主动调用一下就好了</p>\n\n<p>我顺便蹭了一个PR https://github.com/apache/kvrocks/pull/2683</p>\n\n",
      "date_published": "Fri, 06 Dec 2024 00:00:00 +0000"
      },
    
    {
      "id": "https://wanghenshui.github.io/2024/10/17/german-string.html",
      "url": "https://wanghenshui.github.io/2024/10/17/german-string.html",
      "title": "german string",
      "content_html": "<p>prefix计算，空间换时间</p>\n\n<p>https://cedardb.com/blog/german_strings/</p>\n\n<p>https://cedardb.com/blog/strings_deep_dive/</p>\n\n<p>这里有来源介绍</p>\n\n<p>umbra论文的来的，主要是为了小字符串 12B 做优化</p>\n\n<!-- more -->\n\n<h2 id=\"arrow\">arrow</h2>\n\n<p>arrow</p>\n\n<div class=\"language-text highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>* Short strings, length &lt;= 12\n  | Bytes 0-3  | Bytes 4-15                            |\n  |------------|---------------------------------------|\n  | length     | data (padded with 0)                  |\n\n* Long strings, length &gt; 12\n  | Bytes 0-3  | Bytes 4-7  | Bytes 8-11 | Bytes 12-15 |\n  |------------|------------|------------|-------------|\n  | length     | prefix     | buf. index | offset      |\n</code></pre></div></div>\n\n<p>buf index表示第几个buffer \nbuf内的[offset,offset+length) 表示字符串</p>\n\n<p>https://pola.rs/posts/polars-string-type/</p>\n\n<p>https://arrow.apache.org/docs/format/Columnar.html#variable-size-binary-view-layout</p>\n\n<h2 id=\"常规\">常规</h2>\n\n<p>还有一种常规设计</p>\n\n<div class=\"language-text highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>* Short strings, length &lt;= 12\n  | Bytes 0-3  | Bytes 4-15                            |\n  |------------|---------------------------------------|\n  | length     | data (padded with 0)                  |\n\n* Long strings, length &gt; 12\n  | Bytes 0-3  | Bytes 4-7  | Bytes 8-15 |\n  |------------|------------|------------|\n  | length     | prefix     |  ptr     |\n</code></pre></div></div>\n\n<p>比较直观</p>\n<div class=\"language-c++ highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kt\">bool</span> <span class=\"nf\">isEqual</span><span class=\"p\">(</span><span class=\"n\">data128_t</span> <span class=\"n\">a</span><span class=\"p\">,</span> <span class=\"n\">data128_t</span> <span class=\"n\">b</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n    <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">a</span><span class=\"p\">.</span><span class=\"n\">v</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">!=</span> <span class=\"n\">b</span><span class=\"p\">.</span><span class=\"n\">v</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">])</span> <span class=\"k\">return</span> <span class=\"nb\">false</span><span class=\"p\">;</span>\n    <span class=\"k\">auto</span> <span class=\"n\">len</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"kt\">uint32_t</span><span class=\"p\">)</span> <span class=\"n\">a</span><span class=\"p\">.</span><span class=\"n\">v</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">];</span>\n    <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">len</span> <span class=\"o\">&lt;=</span> <span class=\"mi\">12</span><span class=\"p\">)</span> <span class=\"k\">return</span> <span class=\"n\">a</span><span class=\"p\">.</span><span class=\"n\">v</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span> <span class=\"o\">==</span> <span class=\"n\">b</span><span class=\"p\">.</span><span class=\"n\">v</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">];</span>\n    <span class=\"k\">return</span> <span class=\"n\">memcmp</span><span class=\"p\">((</span><span class=\"kt\">char</span><span class=\"o\">*</span><span class=\"p\">)</span> <span class=\"n\">a</span><span class=\"p\">.</span><span class=\"n\">v</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">],</span> <span class=\"p\">(</span><span class=\"kt\">char</span><span class=\"o\">*</span><span class=\"p\">)</span> <span class=\"n\">b</span><span class=\"p\">.</span><span class=\"n\">v</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">],</span> <span class=\"n\">len</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">;</span>\n<span class=\"p\">}</span>\n</code></pre></div></div>\n\n<p>对于小字符串 能省非常多</p>\n\n<p>不过std::string也有sso，对于小字符串，但是没有prefix优势/16B传参优势</p>\n\n<p>duckdb实现 duckdb/blob/main/src/include/duckdb/common/types/string_type.hpp</p>\n",
      "date_published": "Thu, 17 Oct 2024 00:00:00 +0000"
      },
    
    {
      "id": "https://wanghenshui.github.io/2024/10/16/gen-memtier-csv.html",
      "url": "https://wanghenshui.github.io/2024/10/16/gen-memtier-csv.html",
      "title": "生成memtier 验证数据",
      "content_html": "<p>用chatgpt生成的代码改的，chatgpt太强了</p>\n\n<!-- more -->\n\n<p><a href=\"https://github.com/RedisLabs/memtier_benchmark/blob/master/README.import\">生成的格式在这里</a></p>\n\n<pre><code class=\"language-txt\">Note: \n  To avoid unnecessary error while passing file.\n    1. Add extra 4 bytes in nbytes\n    2. Add extra 2 bytes in nkey\n    \n  Example:\n    dumpflags, time, exptime, nbytes, nsuffix, it_flags, clsid, nkey, key, data\n    0, 0, 60, 19, 200, 0, 1, 11, 'doxrpshny', 'asdfghjklqwerty'\n</code></pre>\n\n<p>主要是格式，以及多特殊预留位，以及引号</p>\n\n<p>直接贴代码了</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n<span class=\"kn\">import</span> <span class=\"nn\">csv</span>\n<span class=\"kn\">import</span> <span class=\"nn\">time</span>\n<span class=\"kn\">import</span> <span class=\"nn\">random</span>\n<span class=\"kn\">import</span> <span class=\"nn\">string</span>\n<span class=\"kn\">import</span> <span class=\"nn\">argparse</span>\n<span class=\"kn\">from</span> <span class=\"nn\">typing</span> <span class=\"kn\">import</span> <span class=\"n\">Generator</span><span class=\"p\">,</span> <span class=\"n\">Dict</span>\n\n<span class=\"k\">class</span> <span class=\"nc\">RecordGenerator</span><span class=\"p\">:</span>\n    <span class=\"s\">\"\"\"记录生成器类\"\"\"</span>\n    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">current_time</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">())</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">generate_random_string</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">min_length</span><span class=\"p\">:</span> <span class=\"nb\">int</span> <span class=\"o\">=</span> <span class=\"mi\">5</span><span class=\"p\">,</span> <span class=\"n\">max_length</span><span class=\"p\">:</span> <span class=\"nb\">int</span> <span class=\"o\">=</span> <span class=\"mi\">20</span><span class=\"p\">)</span> <span class=\"o\">-&gt;</span> <span class=\"nb\">str</span><span class=\"p\">:</span>\n        <span class=\"s\">\"\"\"\n        生成随机字符串\n        \"\"\"</span>\n        <span class=\"n\">length</span> <span class=\"o\">=</span> <span class=\"n\">random</span><span class=\"p\">.</span><span class=\"n\">randint</span><span class=\"p\">(</span><span class=\"n\">min_length</span><span class=\"p\">,</span> <span class=\"n\">max_length</span><span class=\"p\">)</span>\n        <span class=\"n\">res</span> <span class=\"o\">=</span> <span class=\"s\">''</span><span class=\"p\">.</span><span class=\"n\">join</span><span class=\"p\">(</span><span class=\"n\">random</span><span class=\"p\">.</span><span class=\"n\">choices</span><span class=\"p\">(</span><span class=\"n\">string</span><span class=\"p\">.</span><span class=\"n\">ascii_lowercase</span><span class=\"p\">,</span> <span class=\"n\">k</span><span class=\"o\">=</span><span class=\"n\">length</span><span class=\"p\">))</span>\n        <span class=\"k\">return</span> <span class=\"s\">\"'\"</span> <span class=\"o\">+</span> <span class=\"n\">res</span> <span class=\"o\">+</span> <span class=\"s\">\"'\"</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">generate_record</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">)</span> <span class=\"o\">-&gt;</span> <span class=\"n\">Dict</span><span class=\"p\">:</span>\n        <span class=\"s\">\"\"\"\n        生成单条记录\n        \"\"\"</span>\n        <span class=\"c1\"># 生成随机key和data\n</span>        <span class=\"n\">key</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">generate_random_string</span><span class=\"p\">(</span><span class=\"mi\">20</span><span class=\"p\">,</span> <span class=\"mi\">50</span><span class=\"p\">)</span>\n        <span class=\"n\">data</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">generate_random_string</span><span class=\"p\">(</span><span class=\"mi\">60</span><span class=\"p\">,</span> <span class=\"mi\">200</span><span class=\"p\">)</span>\n        \n        <span class=\"c1\"># 计算实际长度\n</span>        <span class=\"n\">actual_key_length</span> <span class=\"o\">=</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">key</span><span class=\"p\">)</span>\n        <span class=\"n\">actual_data_length</span> <span class=\"o\">=</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">data</span><span class=\"p\">)</span>\n        <span class=\"c1\">#   To avoid unnecessary error while passing file \n</span>        <span class=\"c1\">#     1. Add extra 4 bytes in nbytes\n</span>        <span class=\"c1\">#     2. Add extra 2 bytes in nkey\n</span>        <span class=\"c1\"># 我们生成的数据是多引号的，已经+2了\n</span>        <span class=\"k\">return</span> <span class=\"p\">{</span>\n            <span class=\"s\">'dumpflags'</span><span class=\"p\">:</span> <span class=\"s\">'0'</span><span class=\"p\">,</span>\n            <span class=\"s\">' time'</span><span class=\"p\">:</span> <span class=\"s\">' 0'</span><span class=\"p\">,</span> <span class=\"c1\">#self.current_time,\n</span>            <span class=\"s\">' exptime'</span><span class=\"p\">:</span> <span class=\"s\">' 60'</span><span class=\"p\">,</span> <span class=\"c1\">#self.current_time + random.randint(60, 3600),\n</span>            <span class=\"s\">' nbytes'</span><span class=\"p\">:</span> <span class=\"sa\">f</span><span class=\"s\">' </span><span class=\"si\">{</span><span class=\"n\">actual_data_length</span> <span class=\"o\">+</span><span class=\"mi\">2</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">,</span>\n            <span class=\"s\">' nsuffix'</span><span class=\"p\">:</span> <span class=\"sa\">f</span><span class=\"s\">' </span><span class=\"si\">{</span><span class=\"n\">random</span><span class=\"p\">.</span><span class=\"n\">randint</span><span class=\"p\">(</span><span class=\"mi\">100</span><span class=\"p\">,</span> <span class=\"mi\">300</span><span class=\"p\">)</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">,</span>\n            <span class=\"s\">' it_flags'</span><span class=\"p\">:</span> <span class=\"s\">' 0'</span><span class=\"p\">,</span>\n            <span class=\"s\">' clsid'</span><span class=\"p\">:</span> <span class=\"s\">' 1'</span><span class=\"p\">,</span>\n            <span class=\"s\">' nkey'</span><span class=\"p\">:</span> <span class=\"sa\">f</span><span class=\"s\">' </span><span class=\"si\">{</span><span class=\"n\">actual_key_length</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">,</span> <span class=\"c1\">## 已经加2了\n</span>            <span class=\"s\">' key'</span><span class=\"p\">:</span> <span class=\"sa\">f</span><span class=\"s\">' </span><span class=\"si\">{</span><span class=\"n\">key</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">,</span> \n            <span class=\"s\">' data'</span><span class=\"p\">:</span> <span class=\"sa\">f</span><span class=\"s\">' </span><span class=\"si\">{</span><span class=\"n\">data</span><span class=\"si\">}</span><span class=\"s\">'</span>  \n        <span class=\"p\">}</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">records</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">num_records</span><span class=\"p\">:</span> <span class=\"nb\">int</span><span class=\"p\">)</span> <span class=\"o\">-&gt;</span> <span class=\"n\">Generator</span><span class=\"p\">[</span><span class=\"n\">Dict</span><span class=\"p\">,</span> <span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"bp\">None</span><span class=\"p\">]:</span>\n        <span class=\"s\">\"\"\"\n        生成记录的生成器\n        \"\"\"</span>\n        <span class=\"k\">for</span> <span class=\"n\">_</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">num_records</span><span class=\"p\">):</span>\n            <span class=\"k\">yield</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">generate_record</span><span class=\"p\">()</span>\n\n<span class=\"k\">class</span> <span class=\"nc\">CSVWriter</span><span class=\"p\">:</span>\n    <span class=\"s\">\"\"\"CSV文件写入器类\"\"\"</span>\n    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">filename</span><span class=\"p\">:</span> <span class=\"nb\">str</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">filename</span> <span class=\"o\">=</span> <span class=\"n\">filename</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">fieldnames</span> <span class=\"o\">=</span> <span class=\"p\">[</span>\n            <span class=\"s\">'dumpflags'</span><span class=\"p\">,</span> <span class=\"s\">' time'</span><span class=\"p\">,</span> <span class=\"s\">' exptime'</span><span class=\"p\">,</span> <span class=\"s\">' nbytes'</span><span class=\"p\">,</span> <span class=\"s\">' nsuffix'</span><span class=\"p\">,</span>\n            <span class=\"s\">' it_flags'</span><span class=\"p\">,</span> <span class=\"s\">' clsid'</span><span class=\"p\">,</span> <span class=\"s\">' nkey'</span><span class=\"p\">,</span> <span class=\"s\">' key'</span><span class=\"p\">,</span> <span class=\"s\">' data'</span>\n        <span class=\"p\">]</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">write_records</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">records_generator</span><span class=\"p\">:</span> <span class=\"n\">Generator</span><span class=\"p\">[</span><span class=\"n\">Dict</span><span class=\"p\">,</span> <span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"bp\">None</span><span class=\"p\">])</span> <span class=\"o\">-&gt;</span> <span class=\"nb\">int</span><span class=\"p\">:</span>\n        <span class=\"s\">\"\"\"\n        将记录写入CSV文件\n        返回写入的记录数量\n        \"\"\"</span>\n        <span class=\"n\">count</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n        <span class=\"k\">try</span><span class=\"p\">:</span>\n            <span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">filename</span><span class=\"p\">,</span> <span class=\"s\">'w'</span><span class=\"p\">,</span> <span class=\"n\">newline</span><span class=\"o\">=</span><span class=\"s\">''</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">csvfile</span><span class=\"p\">:</span>\n                <span class=\"n\">writer</span> <span class=\"o\">=</span> <span class=\"n\">csv</span><span class=\"p\">.</span><span class=\"n\">DictWriter</span><span class=\"p\">(</span><span class=\"n\">csvfile</span><span class=\"p\">,</span> <span class=\"n\">fieldnames</span><span class=\"o\">=</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">fieldnames</span><span class=\"p\">)</span>\n                <span class=\"n\">writer</span><span class=\"p\">.</span><span class=\"n\">writeheader</span><span class=\"p\">()</span>\n                \n                <span class=\"k\">for</span> <span class=\"n\">record</span> <span class=\"ow\">in</span> <span class=\"n\">records_generator</span><span class=\"p\">:</span>\n                    <span class=\"n\">writer</span><span class=\"p\">.</span><span class=\"n\">writerow</span><span class=\"p\">(</span><span class=\"n\">record</span><span class=\"p\">)</span>\n                    <span class=\"n\">count</span> <span class=\"o\">+=</span> <span class=\"mi\">1</span>\n                    <span class=\"c1\"># 每1000条记录显示一次进度\n</span>                    <span class=\"k\">if</span> <span class=\"n\">count</span> <span class=\"o\">%</span> <span class=\"mi\">1000</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n                        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">\"已生成 </span><span class=\"si\">{</span><span class=\"n\">count</span><span class=\"si\">}</span><span class=\"s\"> 条记录...\"</span><span class=\"p\">)</span>\n            \n            <span class=\"k\">return</span> <span class=\"n\">count</span>\n        <span class=\"k\">except</span> <span class=\"nb\">Exception</span> <span class=\"k\">as</span> <span class=\"n\">e</span><span class=\"p\">:</span>\n            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">\"写入文件时发生错误：</span><span class=\"si\">{</span><span class=\"n\">e</span><span class=\"si\">}</span><span class=\"s\">\"</span><span class=\"p\">)</span>\n            <span class=\"k\">return</span> <span class=\"n\">count</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">parse_arguments</span><span class=\"p\">()</span> <span class=\"o\">-&gt;</span> <span class=\"n\">argparse</span><span class=\"p\">.</span><span class=\"n\">Namespace</span><span class=\"p\">:</span>\n    <span class=\"s\">\"\"\"解析命令行参数\"\"\"</span>\n    <span class=\"n\">parser</span> <span class=\"o\">=</span> <span class=\"n\">argparse</span><span class=\"p\">.</span><span class=\"n\">ArgumentParser</span><span class=\"p\">(</span><span class=\"n\">description</span><span class=\"o\">=</span><span class=\"s\">'memtierbenchmark data load CSV文件'</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'-n'</span><span class=\"p\">,</span> <span class=\"s\">'--number'</span><span class=\"p\">,</span> \n                       <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">int</span><span class=\"p\">,</span> \n                       <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mi\">10</span><span class=\"p\">,</span>\n                       <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">'要生成的记录数量（默认：10）'</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'-o'</span><span class=\"p\">,</span> <span class=\"s\">'--output'</span><span class=\"p\">,</span>\n                       <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">,</span>\n                       <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"s\">'output.csv'</span><span class=\"p\">,</span>\n                       <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">'output.csv）'</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">parse_args</span><span class=\"p\">()</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">main</span><span class=\"p\">():</span>\n    <span class=\"c1\"># 解析命令行参数\n</span>    <span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">parse_arguments</span><span class=\"p\">()</span>\n    \n    <span class=\"k\">try</span><span class=\"p\">:</span>\n        <span class=\"c1\"># 验证输入参数\n</span>        <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">number</span> <span class=\"o\">&lt;=</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n            <span class=\"k\">raise</span> <span class=\"nb\">ValueError</span><span class=\"p\">(</span><span class=\"s\">\"记录数量必须大于0\"</span><span class=\"p\">)</span>\n        \n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">\"开始生成 </span><span class=\"si\">{</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">number</span><span class=\"si\">}</span><span class=\"s\"> 条记录...\"</span><span class=\"p\">)</span>\n        <span class=\"n\">start_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n\n        <span class=\"c1\"># 创建生成器和写入器\n</span>        <span class=\"n\">generator</span> <span class=\"o\">=</span> <span class=\"n\">RecordGenerator</span><span class=\"p\">()</span>\n        <span class=\"n\">writer</span> <span class=\"o\">=</span> <span class=\"n\">CSVWriter</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">output</span><span class=\"p\">)</span>\n        \n        <span class=\"c1\"># 生成并写入记录\n</span>        <span class=\"n\">records_count</span> <span class=\"o\">=</span> <span class=\"n\">writer</span><span class=\"p\">.</span><span class=\"n\">write_records</span><span class=\"p\">(</span><span class=\"n\">generator</span><span class=\"p\">.</span><span class=\"n\">records</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">number</span><span class=\"p\">))</span>\n        \n        <span class=\"n\">end_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">duration</span> <span class=\"o\">=</span> <span class=\"n\">end_time</span> <span class=\"o\">-</span> <span class=\"n\">start_time</span>\n        \n        <span class=\"c1\"># 输出统计信息\n</span>        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">\"</span><span class=\"se\">\\n</span><span class=\"s\">完成！\"</span><span class=\"p\">)</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">\"生成文件：</span><span class=\"si\">{</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">output</span><span class=\"si\">}</span><span class=\"s\">\"</span><span class=\"p\">)</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">\"记录数量：</span><span class=\"si\">{</span><span class=\"n\">records_count</span><span class=\"si\">}</span><span class=\"s\">\"</span><span class=\"p\">)</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">\"耗时：</span><span class=\"si\">{</span><span class=\"n\">duration</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">2</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\"> 秒\"</span><span class=\"p\">)</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">\"平均速度：</span><span class=\"si\">{</span><span class=\"n\">records_count</span><span class=\"o\">/</span><span class=\"n\">duration</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">2</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\"> 记录/秒\"</span><span class=\"p\">)</span>\n        \n    <span class=\"k\">except</span> <span class=\"nb\">ValueError</span> <span class=\"k\">as</span> <span class=\"n\">ve</span><span class=\"p\">:</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">\"参数错误：</span><span class=\"si\">{</span><span class=\"n\">ve</span><span class=\"si\">}</span><span class=\"s\">\"</span><span class=\"p\">)</span>\n    <span class=\"k\">except</span> <span class=\"nb\">Exception</span> <span class=\"k\">as</span> <span class=\"n\">e</span><span class=\"p\">:</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">\"程序执行出错：</span><span class=\"si\">{</span><span class=\"n\">e</span><span class=\"si\">}</span><span class=\"s\">\"</span><span class=\"p\">)</span>\n\n<span class=\"k\">if</span> <span class=\"n\">__name__</span> <span class=\"o\">==</span> <span class=\"s\">\"__main__\"</span><span class=\"p\">:</span>\n    <span class=\"n\">main</span><span class=\"p\">()</span>\n\n<span class=\"c1\"># python3 gen.py -n 10000000 -o output.csv\n</span></code></pre></div></div>\n",
      "date_published": "Wed, 16 Oct 2024 00:00:00 +0000"
      },
    
    {
      "id": "https://wanghenshui.github.io/2024/08/06/spdlog-macro.html",
      "url": "https://wanghenshui.github.io/2024/08/06/spdlog-macro.html",
      "title": "给spdlog增加打印宏",
      "content_html": "<p>抄自trpc</p>\n\n<!-- more -->\n\n<div class=\"language-c++ highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kr\">inline</span> <span class=\"kt\">void</span> <span class=\"nf\">InitSpdLog</span><span class=\"p\">()</span> <span class=\"p\">{</span>\n  <span class=\"kt\">bool</span> <span class=\"n\">truncate</span> <span class=\"o\">=</span> <span class=\"nb\">true</span><span class=\"p\">;</span>\n  <span class=\"k\">auto</span> <span class=\"n\">max_files</span> <span class=\"o\">=</span> <span class=\"mi\">5</span><span class=\"p\">;</span>\n  <span class=\"k\">auto</span> <span class=\"n\">log_name</span> <span class=\"o\">=</span> <span class=\"s\">\"xxxlog_dir\"</span> <span class=\"o\">+</span> <span class=\"s\">\"/\"</span> <span class=\"o\">+</span> <span class=\"s\">\"INFO.%Y-%m-%d.log\"</span><span class=\"p\">;</span>\n  <span class=\"k\">auto</span> <span class=\"n\">default_logger</span> <span class=\"o\">=</span>\n      <span class=\"n\">spdlog</span><span class=\"o\">::</span><span class=\"n\">daily_logger_format_mt</span><span class=\"p\">(</span><span class=\"s\">\"xxxlog\"</span><span class=\"p\">,</span> <span class=\"n\">log_name</span><span class=\"p\">,</span> <span class=\"mi\">12</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"n\">truncate</span><span class=\"p\">,</span> <span class=\"n\">max_files</span><span class=\"p\">);</span>\n  <span class=\"n\">default_logger</span><span class=\"o\">-&gt;</span><span class=\"n\">set_level</span><span class=\"p\">(</span><span class=\"n\">spdlog</span><span class=\"o\">::</span><span class=\"n\">level</span><span class=\"o\">::</span><span class=\"n\">info</span><span class=\"p\">);</span>\n<span class=\"p\">}</span>\n\n\n<span class=\"cp\">#define MODULE_NAME_FMT(instance, level, formats, ...)            \\\n  do {                                                          \\\n    spdlog::get(instance)-&gt;level(formats, ##__VA_ARGS__); \\\n  } while (0)\n</span>\n<span class=\"cp\">#define MODULE_NAME_IF(instance, condition, level, formats, ...) \\\n  if (condition) {                                             \\\n    LOG_FMT(instance, level, formats, ##__VA_ARGS__);               \\\n  }\n</span>\n<span class=\"cp\">#define LOGGER_FMT_TRACE(instance, format, args...) MODULE_NAME_FMT(instance, trace, format, ##args)\n#define LOGGER_FMT_DEBUG(instance, format, args...) MODULE_NAME_FMT(instance, debug, format, ##args)\n#define LOGGER_FMT_INFO(instance, format, args...) MODULE_NAME_FMT(instance, info, format, ##args)\n#define LOGGER_FMT_WARN(instance, format, args...) MODULE_NAME_FMT(instance, warn, format, ##args)\n#define LOGGER_FMT_ERROR(instance, format, args...) MODULE_NAME_FMT(instance, error, format, ##args)\n#define LOGGER_FMT_CRITICAL(instance, format, args...) MODULE_NAME_FMT(instance, critical, format, ##args)\n</span>\n<span class=\"cp\">#define MODULE_NAME_TRACE(format, args...) LOGGER_FMT_TRACE(FLAGS_default_logger, format, ##args)\n#define MODULE_NAME_DEBUG(format, args...) LOGGER_FMT_DEBUG(FLAGS_default_logger, format, ##args)\n#define MODULE_NAME_INFO(format, args...) LOGGER_FMT_INFO(FLAGS_default_logger, format, ##args)\n#define MODULE_NAME_WARN(format, args...) LOGGER_FMT_WARN(FLAGS_default_logger, format, ##args)\n#define MODULE_NAME_ERROR(format, args...) LOGGER_FMT_ERROR(FLAGS_default_logger, format, ##args)\n#define MODULE_NAME_CRITICAL(format, args...) LOGGER_FMT_CRITICAL(FLAGS_default_logger, format, ##args)\n</span>\n<span class=\"cp\">#define LOGGER_FMT_TRACE_IF(instance, condition, format, args...) \\\n  MODULE_NAME_IF(instance, condition, trace, format, ##args)\n#define LOGGER_FMT_DEBUG_IF(instance, condition, format, args...) \\\n  MODULE_NAME_IF(instance, condition, debug, format, ##args)\n#define LOGGER_FMT_INFO_IF(instance, condition, format, args...) \\\n  MODULE_NAME_IF(instance, condition, info, format, ##args)\n#define LOGGER_FMT_WARN_IF(instance, condition, format, args...) \\\n  MODULE_NAME_IF(instance, condition, warn, format, ##args)\n#define LOGGER_FMT_ERROR_IF(instance, condition, format, args...) \\\n  MODULE_NAME_IF(instance, condition, error, format, ##args)\n#define LOGGER_FMT_CRITICAL_IF(instance, condition, format, args...) \\\n  MODULE_NAME_IF(instance, condition, critical, format, ##args)\n</span>\n<span class=\"cp\">#define MODULE_NAME_TRACE_IF(condition, format, args...) \\\n  LOGGER_FMT_TRACE_IF(FLAGS_default_logger, condition, format, ##args)\n#define MODULE_NAME_DEBUG_IF(condition, format, args...) \\\n  LOGGER_FMT_DEBUG_IF(FLAGS_default_logger, condition, format, ##args)\n#define MODULE_NAME_INFO_IF(condition, format, args...) \\\n  LOGGER_FMT_INFO_IF(FLAGS_default_logger, condition, format, ##args)\n#define MODULE_NAME_WARN_IF(condition, format, args...) \\\n  LOGGER_FMT_WARN_IF(FLAGS_default_logger, condition, format, ##args)\n#define MODULE_NAME_ERROR_IF(condition, format, args...) \\\n  LOGGER_FMT_ERROR_IF(FLAGS_default_logger, condition, format, ##args)\n#define MODULE_NAME_CRITICAL_IF(condition, format, args...) \\\n  LOGGER_FMT_CRITICAL_IF(FLAGS_default_logger, condition, format, ##args)\n</span>\n<span class=\"cp\">#define MODULE_NAME_ASSERT(x)                             \\\n  do {                                              \\\n    if (__builtin_expect(!(x), 0)) {                \\\n      [&amp;]() __attribute__((noinline, cold)) {       \\\n        MODULE_NAME_CRITICAL(\"assertion failed: {}\", #x); \\\n        std::abort();                               \\\n      }                                             \\\n      ();                                           \\\n      __builtin_unreachable();                      \\\n    }                                               \\\n  } while (0)\n</span>\n<span class=\"cp\">#define MODULE_NAME_ONCE()                                               \\\n  ({                                                               \\\n    static std::atomic_flag __MODULE_NAME_LOG_FLAG__ = ATOMIC_FLAG_INIT; \\\n    (!__MODULE_NAME_LOG_FLAG__.test_and_set(std::memory_order_relaxed)); \\\n  })\n</span>\n<span class=\"cp\">#define MODULE_NAME_EVERY_N(n)                                                            \\\n  ({                                                                                \\\n    MODULE_NAME_ASSERT((n) &gt; 0 &amp;&amp; \"should not be less than 1\");                           \\\n    static std::atomic&lt;uint64_t&gt; __MODULE_NAME_LOG_OCCURENCE_N__{(n)};                    \\\n    (__MODULE_NAME_LOG_OCCURENCE_N__.fetch_add(1, std::memory_order_relaxed) % (n) == 0); \\\n  })\n</span>\n<span class=\"cp\">#define MODULE_NAME_WITHIN_N(ms)                                                              \\\n  ({                                                                                    \\\n    MODULE_NAME_ASSERT((ms) &gt; 0 &amp;&amp; \"should not be less than 1\");                              \\\n    bool __MODULE_NAME_LOG_WRITEABLE__ = false;                                               \\\n    static std::chrono::time_point&lt;std::chrono::steady_clock&gt; __MODULE_NAME_TIME_POINT__;     \\\n    static std::atomic_flag __MODULE_NAME_LOG_CONDITION_FLAG__ = ATOMIC_FLAG_INIT;            \\\n    if (!__MODULE_NAME_LOG_CONDITION_FLAG__.test_and_set(std::memory_order_acquire)) {        \\\n      auto __MODULE_NAME_NOWS__ = std::chrono::steady_clock::now();                           \\\n      int64_t __MODULE_NAME_DIFF_N__ = std::chrono::duration_cast&lt;std::chrono::milliseconds&gt;( \\\n                                     __MODULE_NAME_NOWS__ - __MODULE_NAME_TIME_POINT__)             \\\n                                     .count();                                          \\\n      if (__MODULE_NAME_DIFF_N__ &gt; ms) {                                                      \\\n        __MODULE_NAME_TIME_POINT__ = __MODULE_NAME_NOWS__;                                          \\\n        __MODULE_NAME_LOG_WRITEABLE__ = true;                                                 \\\n      }                                                                                 \\\n      __MODULE_NAME_LOG_CONDITION_FLAG__.clear(std::memory_order_release);                    \\\n    }                                                                                   \\\n    __MODULE_NAME_LOG_WRITEABLE__;                                                            \\\n  })\n</span>\n<span class=\"cp\">#define MODULE_NAME_INFO_ONCE(format, args...) MODULE_NAME_INFO_IF(MODULE_NAME_ONCE(), format, ##args)\n#define MODULE_NAME_WARN_ONCE(format, args...) MODULE_NAME_WARN_IF(MODULE_NAME_ONCE(), format, ##args)\n#define MODULE_NAME_ERROR_ONCE(format, args...) MODULE_NAME_ERROR_IF(MODULE_NAME_ONCE(), format, ##args)\n#define MODULE_NAME_CRITICAL_ONCE(format, args...) MODULE_NAME_CRITICAL_IF(MODULE_NAME_ONCE(), format, ##args)\n</span>\n<span class=\"cp\">#define MODULE_NAME_INFO_EVERY_N(N, format, args...) MODULE_NAME_INFO_IF(MODULE_NAME_EVERY_N(N), format, ##args)\n#define MODULE_NAME_WARN_EVERY_N(N, format, args...) MODULE_NAME_WARN_IF(MODULE_NAME_EVERY_N(N), format, ##args)\n#define MODULE_NAME_ERROR_EVERY_N(N, format, args...) MODULE_NAME_ERROR_IF(MODULE_NAME_EVERY_N(N), format, ##args)\n#define MODULE_NAME_CRITICAL_EVERY_N(N, format, args...) \\\n  MODULE_NAME_CRITICAL_IF(MODULE_NAME_EVERY_N(N), format, ##args)\n</span>\n<span class=\"cp\">#define MODULE_NAME_INFO_EVERY_SECOND(format, args...) MODULE_NAME_INFO_IF(MODULE_NAME_WITHIN_N(1000), format, ##args)\n#define MODULE_NAME_WARN_EVERY_SECOND(format, args...) MODULE_NAME_WARN_IF(MODULE_NAME_WITHIN_N(1000), format, ##args)\n#define MODULE_NAME_ERROR_EVERY_SECOND(format, args...) \\\n  MODULE_NAME_ERROR_IF(MODULE_NAME_WITHIN_N(1000), format, ##args)\n#define MODULE_NAME_CRITICAL_EVERY_SECOND(format, args...) \\\n  MODULE_NAME_CRITICAL_IF(MODULE_NAME_WITHIN_N(1000), format, ##args)\n</span></code></pre></div></div>\n",
      "date_published": "Tue, 06 Aug 2024 00:00:00 +0000"
      },
    
    {
      "id": "https://wanghenshui.github.io/2024/07/19/arch-summit2023-sh.html",
      "url": "https://wanghenshui.github.io/2024/07/19/arch-summit2023-sh.html",
      "title": "ArchSummit上海2023 PPT速览",
      "content_html": "<p>ppt在这里 https://www.modb.pro/topic/640976</p>\n\n<!-- more -->\n\n<h3 id=\"云原生存储cubefs在大数据和机器学习的探索和实践\">云原生存储CubeFS在大数据和机器学习的探索和实践</h3>\n\n<p>主要是提了个缓存加速</p>\n\n<ul>\n  <li>元数据缓存：缓存inode和dentry信息，可以大量减少fuse客户端的lookup和open读文件的开销。</li>\n  <li>数据缓存：数据缓存可以利用GPU本地云盘，无需申请额外存储资源，在保证数据安全同时提升效率。</li>\n</ul>\n\n<p>其他的就是常规的东西，raft和分布式文件系统相关优化(raft,存储纠删码，NWR，攒批写（小文件聚集写）等等)</p>\n\n<h3 id=\"字节跳动时序存储引擎的探索和实践\">字节跳动时序存储引擎的探索和实践</h3>\n\n<p>Workload分析和对应的挑战</p>\n\n<ul>\n  <li>写远大于读，写入量非常大\n    <ul>\n      <li>线性扩展</li>\n    </ul>\n  </li>\n  <li>查询以分析为主，点查为辅\n    <ul>\n      <li>面向分析查询优化的同时兼顾点查性能</li>\n    </ul>\n  </li>\n  <li>超高维度\n    <ul>\n      <li>在单机亿级活跃维度情况下依然保证写入和查询性能</li>\n    </ul>\n  </li>\n  <li>Noisy Neighbours\n    <ul>\n      <li>租户间的隔离</li>\n      <li>防止个别超大metric影响整体可用性</li>\n    </ul>\n  </li>\n</ul>\n\n<p><img src=\"https://wanghenshui.github.io/assets/bytedance-tsdb1.png\" alt=\"\" width=\"80%\" /></p>\n\n<p>如何线性扩展</p>\n\n<ul>\n  <li>二级一致性Hash分区\n    <ul>\n      <li>先按照Metric做一次Hash分区</li>\n      <li>再按照序列做第二次Hash分区</li>\n    </ul>\n  </li>\n  <li>Metrics级别的动态分区\n    <ul>\n      <li>不同维度的Metric可以拥有不同的二级Hash分片数</li>\n    </ul>\n  </li>\n</ul>\n\n<p><img src=\"https://wanghenshui.github.io/assets/bytedance-tsdc.png\" alt=\"\" width=\"80%\" /></p>\n\n<p>编码优化</p>\n\n<p>观察数据特征</p>\n\n<ul>\n  <li>大部分序列拥有相同的TagKeys 每个序列的所有TagKeys称为TagKeySet\n    <ul>\n      <li>直接编码整个TagKeySet\n        <ul>\n          <li>TagSet中只存储一个id</li>\n          <li>Encode时只做一次Hash</li>\n        </ul>\n      </li>\n    </ul>\n  </li>\n</ul>\n\n<p>Datapoint Set</p>\n\n<ul>\n  <li>RingBuffer用于处理乱序写入，存储原始数据点\n    <ul>\n      <li>数据点划出RingBuffer后，写入TimeBuffer和ValueBuffer</li>\n      <li>TimeBuffer使用delta of delta压缩</li>\n      <li>ValueBuffer使用Gorilla压缩</li>\n    </ul>\n  </li>\n  <li>乱序写入优化\n    <ul>\n      <li>Question：\n        <ul>\n          <li>RingBuffer容量有限</li>\n          <li>Gorilla压缩算法只能append</li>\n        </ul>\n      </li>\n      <li>Answer：\n        <ul>\n          <li>反向Gorilla压缩，能够Popback</li>\n          <li>乱序很久的点不写入ValueBuffer，查询时合并</li>\n        </ul>\n      </li>\n    </ul>\n  </li>\n</ul>\n\n<p>查询优化</p>\n\n<ul>\n  <li>支持所有Filter下推，减少数据传输量\n    <ul>\n      <li>包括wildcard和regex，利用索引加速</li>\n    </ul>\n  </li>\n  <li>自适应执行\n    <ul>\n      <li>根据结果集大小动态选择查询索引或者Scan</li>\n    </ul>\n  </li>\n  <li>并行Scan</li>\n  <li>轻重查询隔离\n    <ul>\n      <li>轻重查询使用不同的线程池</li>\n      <li>根据维度和查询时长预估查询代价</li>\n    </ul>\n  </li>\n</ul>\n\n<p>Khronos存储引擎</p>\n\n<ul>\n  <li>降低内存使用，更低成本地支持单实例高维度数据</li>\n  <li>数据全部持久化，提升数据可靠性</li>\n  <li>保持高写入吞吐、低查询时延，提供高效的扫描，同时支持较好的点查性能</li>\n  <li>能够以较低的成本支持较长时间的存储，提供较高的压缩率以及对机械盘友好的存储格式</li>\n  <li>兼容Tsdc，最低成本接入现有集群</li>\n</ul>\n\n<p><img src=\"https://wanghenshui.github.io/assets/bytedance-khronos1.png\" alt=\"\" width=\"80%\" /></p>\n\n<ul>\n  <li>每个Shard内部都是一棵独立的LSMT\n    <ul>\n      <li>一共分为三层</li>\n      <li>每一层都有一个虚拟的时间分区</li>\n    </ul>\n  </li>\n  <li>sstable文件不会跨时间分区</li>\n  <li>Compaction在分区内调度</li>\n  <li>乱序写入的场景减少写放大</li>\n</ul>\n\n<p>Memtable</p>\n\n<ul>\n  <li>基本延用了Tsdc的内存结构</li>\n  <li>SeriesMap采用有序结构，Compaction依赖Series有序</li>\n  <li>SeriesKey = SeriesHashCode + TagSet\n    <ul>\n      <li>节省比较开销</li>\n      <li>快速拆分range，方便做分区内并行查询</li>\n    </ul>\n  </li>\n</ul>\n\n<p>SST</p>\n\n<ul>\n  <li>由于Metric数量非常多，所以将多个Metric数据混合存储在一个文件中</li>\n  <li>文件尾部有Metric Index指向Metric的位置\n    <ul>\n      <li>MetricIndex是一个Btree</li>\n      <li>Page内部使用前缀压缩</li>\n    </ul>\n  </li>\n</ul>\n\n<p>Metric格式</p>\n\n<ul>\n  <li>类Parquet格式，行列混存</li>\n  <li>每行一个序列</li>\n  <li>大Metric会划分为多个SeriesGroup，减少内存占用</li>\n  <li>字典/Raw/Bitshuffle encoding</li>\n  <li>Page索引加速查询</li>\n</ul>\n\n<p>Flush优化</p>\n\n<ul>\n  <li>大量小Metric\n    <ul>\n      <li>存储格式Overhead大</li>\n      <li>write次数太多，性能差</li>\n    </ul>\n  </li>\n  <li>BufferWrite\n    <ul>\n      <li>预先Fallocate一段空间然后mmap</li>\n      <li>数据通过mmap写入，减少syscall</li>\n    </ul>\n  </li>\n  <li>PaxLayout\n    <ul>\n      <li>所有Column写在一个Page</li>\n      <li>减少IO次数，减少元数据开销</li>\n    </ul>\n  </li>\n</ul>\n\n<p>SSTable查询优化</p>\n\n<ul>\n  <li>延迟投影\n    <ul>\n      <li>先读取带过滤条件的列</li>\n      <li>每过滤一个列都缩小下一个列的读取范围</li>\n      <li>最后投影非过滤列</li>\n      <li>数量级性能提升</li>\n    </ul>\n  </li>\n  <li>PageCache\n    <ul>\n      <li>Cache中缓存解压后的Page，避免重复的解压和CRC校验</li>\n      <li>更进一步，直接Cache PageReader对象，节省构造开销</li>\n    </ul>\n  </li>\n</ul>\n\n<p>他们的工作做的确实挺多</p>\n\n<h3 id=\"云原生数据库的架构演进\">云原生数据库的架构演进</h3>\n\n<p>就是回顾架构设计</p>\n\n<p><strong>主从</strong></p>\n\n<ul>\n  <li>架构痛点\n    <ul>\n      <li>弹性升降配困难 确实。规格钉死</li>\n      <li>只读扩展效率低延迟高 -&gt; 这个可能就要根据一致性放松一点了</li>\n      <li>存储瓶颈  -&gt; 路由分裂啊</li>\n    </ul>\n  </li>\n  <li>业务痛点\n    <ul>\n      <li>提前评估规格资源浪费 -&gt; 那就从最小集群慢慢扩容呗？</li>\n      <li>临时峰值稳定性问题 -&gt; 确实，只好限流熔断/backup request</li>\n      <li>读扩展提前拆库  路由分裂确实存在运营压力</li>\n      <li>容量拆库 这个也是要结合路由分裂，存在运营压力/资源浪费</li>\n    </ul>\n  </li>\n</ul>\n\n<p><strong>存算分离一写多读</strong></p>\n\n<ul>\n  <li>架构痛点\n    <ul>\n      <li>弹性升降配 要断链</li>\n      <li>无法无感知跨机弹性？</li>\n      <li>只读节点延迟问题</li>\n    </ul>\n  </li>\n  <li>业务痛点\n    <ul>\n      <li>业务不接受闪断</li>\n      <li>容量规划/突发流量处理？和主从一样没有解决</li>\n      <li>电商/微服务不接受读延迟</li>\n      <li>预留水位 资源浪费</li>\n    </ul>\n  </li>\n</ul>\n\n<p><strong>阿里第二代serverless设计</strong></p>\n\n<ul>\n  <li>无感弹性变更规格/跨机迁移</li>\n  <li>高性能全局一致性</li>\n  <li>跨机serverless</li>\n  <li>动态扩缩RO</li>\n  <li>存储资源降低80%，计算资源降低45%，TCO降低 40%</li>\n  <li>共享存储，RO无延迟</li>\n  <li>秒级扩缩容RW/RO，异常恢复速度快</li>\n  <li>运维工作量低</li>\n  <li>实现了一站式聚合查询和分析，提升数据向下游传送效率</li>\n  <li>秒级增删节点</li>\n  <li>透明智能代理实现智能读写分流</li>\n  <li>全局binlog向下游提供增量数据的抽取</li>\n  <li>全局RO支持汇聚业务，ePQ有效提高业务查询性能</li>\n  <li>用户通过多节点进行有效的资源隔离</li>\n</ul>\n\n<p>其实阿里这么玩的前提是有一个资源池管理</p>\n",
      "date_published": "Fri, 19 Jul 2024 00:00:00 +0000"
      },
    
    {
      "id": "https://wanghenshui.github.io/2024/07/19/2023-qcon-gz.html",
      "url": "https://wanghenshui.github.io/2024/07/19/2023-qcon-gz.html",
      "title": "qcon2023广州PPT速览",
      "content_html": "<p>ppt在这里 https://www.modb.pro/topic/640977</p>\n\n<p>只有两个感兴趣</p>\n\n<p>https://wanghenshui.github.io/pdf/byconity.pdf</p>\n\n<p>https://wanghenshui.github.io/pdf/antkv.pdf</p>\n\n<!-- more -->\n\n<h3 id=\"antkv-蚂蚁实时计算-kv-分离5x性能提升实践\">AntKV: 蚂蚁实时计算 KV 分离5x性能提升实践</h3>\n\n<p>WiscKey的rocksdb改造工作</p>\n\n<p>AntKV 核心功能</p>\n<ul>\n  <li>KV分离\n    <ul>\n      <li>元数据管理</li>\n    </ul>\n  </li>\n  <li>空间回收\n    <ul>\n      <li>GC</li>\n      <li>TTL</li>\n    </ul>\n  </li>\n  <li>数据版本\n    <ul>\n      <li>Checkpoint</li>\n      <li>Ingest Value Log Files</li>\n    </ul>\n  </li>\n  <li>特性支持\n    <ul>\n      <li>异步恢复Checkpoint</li>\n      <li>Table API</li>\n    </ul>\n  </li>\n  <li>性能优化\n    <ul>\n      <li><strong>Scan 优化</strong></li>\n      <li>流控优化</li>\n      <li><strong>Learned Index</strong></li>\n    </ul>\n  </li>\n</ul>\n\n<p><strong>Scan优化</strong></p>\n\n<p>kv分离现状</p>\n<ul>\n  <li>value 是vlog追加模式</li>\n  <li>访问value多一跳</li>\n  <li>导致scan局部性差</li>\n</ul>\n\n<p>优化策略，并发prefetch</p>\n<ul>\n  <li>根据用户访问 Pattern 或者 Range Hint 发起异步预取</li>\n  <li>发挥 NVMe SSD 能力并行预取</li>\n  <li>利用 Block Cache 实现数据同步</li>\n</ul>\n\n<p><img src=\"https://wanghenshui.github.io/assets/antkv1.png\" alt=\"\" width=\"80%\" /></p>\n\n<p>新的问题</p>\n<ul>\n  <li>中等大小（如256B）Value 情况下，Scan 仍然比 RocksDB 差很多</li>\n</ul>\n\n<p>原因</p>\n<ul>\n  <li>Block 中数据不连续，磁盘带宽即便打满，大多内容都是无效数据</li>\n</ul>\n\n<p>优化策略 Diffkv ATC 21: Differentiated Key-Value Storage Management for Balanced I/O Performance</p>\n\n<p>核心思路</p>\n<ul>\n  <li>对于中等大小的 KV pairs，对 Value Log Files也进行分层处理，增强局部连续性\n    <ul>\n      <li>Level N-2 及以下的层级不做重写</li>\n      <li>Level N-1 及以上的层级在 Compaction 时重写Value Log Files</li>\n    </ul>\n  </li>\n</ul>\n\n<p><img src=\"https://wanghenshui.github.io/assets/antkv2.png\" alt=\"\" width=\"80%\" /></p>\n\n<ul>\n  <li>针对 Scan 优化的重写：\n    <ul>\n      <li>Compaction 过程中，对本轮参与的 Value Log Files 进行重叠记数</li>\n      <li>当发现某文件重叠记数超过阈值，则标记相关文件后续进行重写</li>\n    </ul>\n  </li>\n</ul>\n\n<p><img src=\"https://wanghenshui.github.io/assets/antkv3.png\" alt=\"\" width=\"80%\" /></p>\n\n<p>收益 写入降低30% 但scan提升巨大</p>\n\n<p>这种还是要考虑业务来使用，但是这个工作是很亮眼的</p>\n\n<p><strong>借助 Learned Index 优化查询</strong></p>\n\n<p>Learned Index主要是要设计构建算法，这里需要展开一下</p>\n\n<p><img src=\"https://wanghenshui.github.io/assets/antkv-li1.png\" alt=\"\" width=\"80%\" /></p>\n\n<p><img src=\"https://wanghenshui.github.io/assets/antkv-li2.png\" alt=\"\" width=\"80%\" /></p>\n\n<p>因为实际 SST 保存的 key 为 string 类型，非 integer，因此需要进行转换</p>\n<ul>\n  <li>要求\n    <ul>\n      <li>唯一性：不同的 key，转换出来的 key_digest 不能相同</li>\n      <li>保序性：如果 key1 &lt; key2，那么转换后的 key_digest_1 &lt; key_digest_2</li>\n    </ul>\n  </li>\n  <li>问题\n    <ul>\n      <li>字符串长度是随机的，并且可能很长</li>\n    </ul>\n  </li>\n</ul>\n\n<p><img src=\"https://wanghenshui.github.io/assets/antkv-li3.png\" alt=\"\" width=\"80%\" /></p>\n\n<p>Learned Index非常小，读效率非常高</p>\n\n<p>Learned Index: 生成过程</p>\n\n<ul>\n  <li>在构建新的SST过程中，会缓存待写入的所有KV数据，在Finish时进行建模并持久化相关参数。\n    <ul>\n      <li>不会在L0构建Learned Index</li>\n      <li>不会对大小在阈值以下的SST进行构建</li>\n      <li>当不满足构建条件时，退化为默认的Binary Index</li>\n    </ul>\n  </li>\n</ul>\n\n<h3 id=\"byconity基于云原架构的开源实时数仓系\">ByConity：基于云原⽣架构的开源实时数仓系</h3>\n\n<p>clickhouse痛点</p>\n<ul>\n  <li>Shared Nothing架构\n    <ul>\n      <li>运维困难：扩缩容、读写分离、资源隔离困难</li>\n      <li>资源浪费：存储和计算⽆法独⽴扩容、弹性伸缩</li>\n    </ul>\n  </li>\n  <li>事务⽀持缺失\n    <ul>\n      <li>不满⾜对数据⼀致性要求⾼的场景</li>\n      <li>提⾼了使⽤和运维成本</li>\n      <li>复杂查询性能差（如多表Join)</li>\n    </ul>\n  </li>\n</ul>\n\n<p>架构</p>\n\n<p>设计考虑</p>\n\n<ul>\n  <li>需要统⼀的元信息管理系统</li>\n  <li>分布式⽂件系统⼤多数存在元信息管理压⼒问题</li>\n  <li>分布式统⼀存储系统⼤多不⽀持rewrite，⼀些对象存储系统甚⾄不⽀持append</li>\n  <li>分布式对象存储系统⼤多move代价都⽐较⾼</li>\n  <li>io latency通常情况对⽐本地⽂件系统下都存在增加的情况</li>\n</ul>\n\n<p>数据缓存</p>\n\n<ul>\n  <li>⼀致性hash分配parts</li>\n  <li>热数据worker节点⾃动缓存</li>\n  <li>改进bucket-lru算法</li>\n  <li>避免数据reshuffling</li>\n</ul>\n\n<p>ByConity事务</p>\n<ul>\n  <li>隐式（开源）和显示事务（待开源）</li>\n  <li>Read Committed 隔离级别，写不阻塞读</li>\n  <li>两阶段提交实现，⽀持海量数据的原⼦写⼊</li>\n  <li>具备灵活可控的并发控制的功能</li>\n</ul>\n\n<p>中⼼授时服务TSO(TimeStamp Oracle)</p>\n<ul>\n  <li>Timestamp ordering</li>\n  <li>创建事务：为事务分配开始时间t_s</li>\n  <li>提交事务：为事务分配提交时间t_c</li>\n  <li>可⻅性判断：对t_s为TS的事务，能读到所有已提交且t_c &lt; TS的事务数据</li>\n</ul>\n\n<p>说的东西还是非常多的，直接看pdf比我复述直观</p>\n\n<p>https://wanghenshui.github.io/pdf/byconity.pdf</p>\n",
      "date_published": "Fri, 19 Jul 2024 00:00:00 +0000"
      },
    
    {
      "id": "https://wanghenshui.github.io/2024/07/15/rocksdb-invalidation-cache.html",
      "url": "https://wanghenshui.github.io/2024/07/15/rocksdb-invalidation-cache.html",
      "title": "rocksdb的cache过期问题讨论",
      "content_html": "<p>如果blockcache被compaction搞失效了，有没有一种逻辑自动重填blockcache，降低cache miss？</p>\n\n<p>毕竟在blockcache中属于热数据</p>\n\n<p>另外ingest文件能不能同时预热 blockcache？</p>\n\n<p>结论:上层加row cache绕过</p>\n\n<p>rocksdb本身不好解决这个问题，太业务了</p>\n\n<p>另外 rocksdb rowcache有兼容性问题(deleterange breaking ,v9)，不能用</p>\n\n<!-- more -->\n\n<h3 id=\"lsbm-tree-re-enabling-buffer-caching-in-data-management-for-mixed-reads-and-writes\">LSbM-tree: Re-enabling Buffer Caching in Data Management for Mixed Reads and Writes</h3>\n\n<p>维护一个compaction buffer https://nan01ab.github.io/2018/07/FD-tree-and-LSbM-tree.html</p>\n\n<h3 id=\"x-engine-an-optimized-storage-engine-for-large-scale-e-commerce-transaction-processing\">X-Engine: An Optimized Storage Engine for Large-scale E-commerce Transaction Processing</h3>\n\n<p>改进LSM Row Cache缓存热点行</p>\n\n<p>减少Compaction的粒度；减少Compaction过程中改动的数据；Compaction过程中针对已有的缓存数据做定点更新（增量替换）</p>\n\n<h3 id=\"leaper-a-learned-prefetcher-for-cache-invalidation-in-lsm-tree-based-storage-engines\">Leaper: a learned prefetcher for cache invalidation in LSM-tree based storage engines</h3>\n\n<p>北京大学，vldb‘20 [18]，采用机器学习方法解决X-Engine中cache miss问题</p>\n\n<p>在X-Engine实际运行中，由于后台异步数据合并任务造成的大面积缓存失效问题。之前也有论文提出这种问题，具体解决是多增一个buffer cache，空间换效率。</p>\n\n<p>Leaper采用机器学习算法，预测一个 compaction 任务在执行过程中和刚刚结束执行时，数据库上层 SQL 负载可能会访问到数据记录并提前将其加载进 cache 中，从而实现降低 cache miss，提高 QPS 稳定性的目的</p>\n\n<p>rocksdb本身没有这种信息输入接口，只能根据blockcache存在过这个信息来来加载</p>\n\n<p>可以提供一个predict_op, 给上层判定是否回填</p>\n\n<p>显然是业务驱动</p>\n\n<h3 id=\"ac-key-adaptive-caching-for-lsm-based-key-value-stores\">AC-Key: Adaptive Caching for LSM-based Key-Value Stores</h3>\n\n<p>blockcache改成cache key/cache adderss并且2Q策略维护</p>\n\n<p>有个公式判定，较复杂 https://linqy71.github.io/2020/12/22/AC-Key/</p>\n\n<p>实现难度也比较大</p>\n\n<p>如果考虑单独做一个2Q cache放在业务上层，外部数据导入就扫一遍 cache上，实现更简单</p>\n\n<h2 id=\"特殊的cache设计\">特殊的cache设计</h2>\n\n<h3 id=\"frozenhot-cache-rethinking-cache-management-for-modern-hardware\">FrozenHot Cache: Rethinking Cache Management for Modern Hardware</h3>\n\n<p>我之前有个类似想法 FastCHD + 动态hashmap 定期重构</p>\n\n<p>感觉内存不可控</p>\n\n<p>另外cache的其他问题就不展开了，另一个话题</p>\n\n<h2 id=\"加兜底\">加兜底</h2>\n\n<h3 id=\"sas-cache-a-semantic-aware-secondary-cache-for-lsm-based-key-value-stores\">SAS-Cache: A Semantic-Aware Secondary Cache for LSM-based Key-Value Stores</h3>\n\n<p>blockcache miss了，磁盘swap再撑一下，最后查FS/S3</p>\n",
      "date_published": "Mon, 15 Jul 2024 00:00:00 +0000"
      },
    
    {
      "id": "https://wanghenshui.github.io/2024/07/07/user-group-001.html",
      "url": "https://wanghenshui.github.io/2024/07/07/user-group-001.html",
      "title": "这段代码能这段代码有办法做simd加速吗",
      "content_html": "<p>群友讨论第一期, 这个栏目要多谢群友交流</p>\n\n<p>本期鸣谢群友 <code class=\"language-plaintext highlighter-rouge\">@核聚变引擎</code> <code class=\"language-plaintext highlighter-rouge\">@mwish</code></p>\n\n<!-- more -->\n\n<p><strong>群友核聚变引擎</strong> 提问</p>\n\n<p>这段代码有办法做simd加速吗，感觉无解\nhttps://gcc.godbolt.org/z/GjjEfz1e8</p>\n\n<p>代码如下</p>\n\n<div class=\"language-c++ highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"cp\">#include</span> <span class=\"cpf\">&lt;cstdint&gt;</span><span class=\"cp\">\n</span>\n<span class=\"k\">const</span> <span class=\"kt\">int</span> <span class=\"n\">M</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">1</span> <span class=\"o\">&lt;&lt;</span> <span class=\"mi\">14</span><span class=\"p\">);</span>\n<span class=\"kt\">uint16_t</span> <span class=\"n\">bins</span><span class=\"p\">[</span><span class=\"mi\">64</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"p\">{</span><span class=\"mi\">0</span><span class=\"p\">};</span>\n<span class=\"kt\">uint8_t</span> <span class=\"n\">data</span><span class=\"p\">[</span><span class=\"n\">M</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"p\">{</span><span class=\"mi\">0</span><span class=\"p\">};</span>\n\n<span class=\"c1\">// 统计 data 中 0~63 的频数，不考虑高 2 位</span>\n<span class=\"kt\">void</span> <span class=\"n\">histgram</span><span class=\"p\">(</span><span class=\"kt\">uint16_t</span> <span class=\"o\">*</span><span class=\"n\">bins</span><span class=\"p\">,</span> <span class=\"kt\">uint8_t</span> <span class=\"o\">*</span><span class=\"n\">data</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n    <span class=\"k\">for</span> <span class=\"p\">(</span><span class=\"kt\">int</span> <span class=\"n\">i</span> <span class=\"o\">=</span> <span class=\"mi\">0</span><span class=\"p\">;</span> <span class=\"n\">i</span> <span class=\"o\">&lt;</span> <span class=\"n\">M</span><span class=\"p\">;</span> <span class=\"n\">i</span><span class=\"o\">++</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n        <span class=\"kt\">uint8_t</span> <span class=\"n\">x</span> <span class=\"o\">=</span> <span class=\"n\">data</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]</span> <span class=\"o\">&amp;</span> <span class=\"mh\">0x3f</span><span class=\"p\">;</span>\n        <span class=\"n\">bins</span><span class=\"p\">[</span><span class=\"n\">x</span><span class=\"p\">]</span><span class=\"o\">++</span><span class=\"p\">;</span>\n    <span class=\"p\">}</span>\n<span class=\"p\">}</span>\n\n</code></pre></div></div>\n\n<p>这种计算是统计型，关键是统计M输入到64，不是多对1类型的计算，比如popcnt</p>\n\n<p>优化角度无非是攒批/分片</p>\n\n<p>使用chatgpt帮咱写了一个版本</p>\n\n<div class=\"language-cpp highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kt\">void</span> <span class=\"nf\">histgram_avx</span><span class=\"p\">(</span><span class=\"kt\">uint16_t</span> <span class=\"o\">*</span><span class=\"n\">bins</span><span class=\"p\">,</span> <span class=\"kt\">uint8_t</span> <span class=\"o\">*</span><span class=\"n\">data</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n    <span class=\"n\">__m256i</span> <span class=\"n\">mask</span> <span class=\"o\">=</span> <span class=\"n\">_mm256_set1_epi8</span><span class=\"p\">(</span><span class=\"mh\">0x3F</span><span class=\"p\">);</span>\n    <span class=\"k\">for</span> <span class=\"p\">(</span><span class=\"kt\">int</span> <span class=\"n\">i</span> <span class=\"o\">=</span> <span class=\"mi\">0</span><span class=\"p\">;</span> <span class=\"n\">i</span> <span class=\"o\">&lt;</span> <span class=\"n\">M</span><span class=\"p\">;</span> <span class=\"n\">i</span> <span class=\"o\">+=</span> <span class=\"mi\">32</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n        <span class=\"n\">__m256i</span> <span class=\"n\">chunk</span> <span class=\"o\">=</span> <span class=\"n\">_mm256_loadu_si256</span><span class=\"p\">(</span><span class=\"k\">reinterpret_cast</span><span class=\"o\">&lt;</span><span class=\"k\">const</span> <span class=\"n\">__m256i</span><span class=\"o\">*&gt;</span><span class=\"p\">(</span><span class=\"n\">data</span> <span class=\"o\">+</span> <span class=\"n\">i</span><span class=\"p\">));</span>\n        <span class=\"n\">chunk</span> <span class=\"o\">=</span> <span class=\"n\">_mm256_and_si256</span><span class=\"p\">(</span><span class=\"n\">chunk</span><span class=\"p\">,</span> <span class=\"n\">mask</span><span class=\"p\">);</span>\n\n        <span class=\"kt\">uint8_t</span> <span class=\"n\">tmp</span><span class=\"p\">[</span><span class=\"mi\">32</span><span class=\"p\">];</span>\n        <span class=\"n\">_mm256_storeu_si256</span><span class=\"p\">(</span><span class=\"k\">reinterpret_cast</span><span class=\"o\">&lt;</span><span class=\"n\">__m256i</span><span class=\"o\">*&gt;</span><span class=\"p\">(</span><span class=\"n\">tmp</span><span class=\"p\">),</span> <span class=\"n\">chunk</span><span class=\"p\">);</span>\n\n        <span class=\"k\">for</span> <span class=\"p\">(</span><span class=\"kt\">int</span> <span class=\"n\">j</span> <span class=\"o\">=</span> <span class=\"mi\">0</span><span class=\"p\">;</span> <span class=\"n\">j</span> <span class=\"o\">&lt;</span> <span class=\"mi\">32</span><span class=\"p\">;</span> <span class=\"o\">++</span><span class=\"n\">j</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n            <span class=\"n\">bins</span><span class=\"p\">[</span><span class=\"n\">tmp</span><span class=\"p\">[</span><span class=\"n\">j</span><span class=\"p\">]]</span><span class=\"o\">++</span><span class=\"p\">;</span>\n        <span class=\"p\">}</span>\n    <span class=\"p\">}</span>\n<span class=\"p\">}</span>\n</code></pre></div></div>\n\n<p>这种加速其实效果非常有限，M也不大，性能提升并不明显</p>\n\n<p>群友mwish提供了一个分片的版本</p>\n\n<div class=\"language-cpp highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">using</span> <span class=\"n\">Bucket</span> <span class=\"o\">=</span> <span class=\"n\">std</span><span class=\"o\">::</span><span class=\"n\">array</span><span class=\"o\">&lt;</span><span class=\"kt\">uint16_t</span><span class=\"p\">,</span> <span class=\"mi\">64</span><span class=\"o\">&gt;</span><span class=\"p\">;</span>\n\n<span class=\"c1\">// 统计 data 中 0~63 的频数，不考虑高 2 位</span>\n<span class=\"n\">std</span><span class=\"o\">::</span><span class=\"n\">array</span><span class=\"o\">&lt;</span><span class=\"n\">Bucket</span><span class=\"p\">,</span> <span class=\"mi\">8</span><span class=\"o\">&gt;</span> <span class=\"n\">histgram_mwish</span><span class=\"p\">(</span><span class=\"kt\">uint16_t</span> <span class=\"o\">*</span><span class=\"n\">bins</span><span class=\"p\">,</span> <span class=\"kt\">uint8_t</span> <span class=\"o\">*</span><span class=\"n\">data</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n    <span class=\"n\">std</span><span class=\"o\">::</span><span class=\"n\">array</span><span class=\"o\">&lt;</span><span class=\"n\">Bucket</span><span class=\"p\">,</span> <span class=\"mi\">8</span><span class=\"o\">&gt;</span> <span class=\"n\">temp_bins</span><span class=\"p\">;</span>\n    <span class=\"k\">for</span> <span class=\"p\">(</span><span class=\"kt\">int</span> <span class=\"n\">i</span> <span class=\"o\">=</span> <span class=\"mi\">0</span><span class=\"p\">;</span> <span class=\"n\">i</span> <span class=\"o\">&lt;</span> <span class=\"n\">M</span> <span class=\"o\">/</span> <span class=\"mi\">8</span><span class=\"p\">;</span> <span class=\"n\">i</span><span class=\"o\">++</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n        <span class=\"k\">for</span> <span class=\"p\">(</span><span class=\"kt\">int</span> <span class=\"n\">idx</span> <span class=\"o\">=</span> <span class=\"mi\">0</span><span class=\"p\">;</span> <span class=\"n\">idx</span> <span class=\"o\">&lt;</span> <span class=\"mi\">8</span><span class=\"p\">;</span> <span class=\"o\">++</span><span class=\"n\">idx</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n            <span class=\"kt\">uint8_t</span> <span class=\"n\">x</span> <span class=\"o\">=</span> <span class=\"n\">data</span><span class=\"p\">[</span><span class=\"n\">i</span> <span class=\"o\">*</span> <span class=\"mi\">8</span> <span class=\"o\">+</span> <span class=\"n\">idx</span><span class=\"p\">]</span> <span class=\"o\">%</span> <span class=\"mi\">64</span><span class=\"p\">;</span>\n            <span class=\"n\">temp_bins</span><span class=\"p\">[</span><span class=\"n\">idx</span><span class=\"p\">][</span><span class=\"n\">x</span><span class=\"p\">]</span><span class=\"o\">++</span><span class=\"p\">;</span>\n        <span class=\"p\">}</span>\n    <span class=\"p\">}</span>\n    <span class=\"k\">return</span> <span class=\"n\">temp_bins</span><span class=\"p\">;</span>\n<span class=\"p\">}</span>\n</code></pre></div></div>\n\n<p>我压测了一版数据，机器是2019 mbp 性能一般，结果如下</p>\n\n<pre><code class=\"language-txt\">2024-07-07T18:16:00+08:00\nRunning ./build/bm_histgram\nRun on (12 X 2600 MHz CPU s)\nCPU Caches:\n  L1 Data 32 KiB\n  L1 Instruction 32 KiB\n  L2 Unified 256 KiB (x6)\n  L3 Unified 12288 KiB\nLoad Average: 2.84, 3.07, 2.77\n--------------------------------------------------------------------------------\nBenchmark                                      Time             CPU   Iterations\n--------------------------------------------------------------------------------\nBM_histgram_mwish/iterations:10000000       7065 ns         7019 ns     10000000\nBM_histgram_base/iterations:10000000        6836 ns         6769 ns     10000000\nBM_histgram_avx/iterations:10000000         7228 ns         7179 ns     10000000\n</code></pre>\n\n<p>能看到性能差异基本可以无视，优化反而还慢了</p>\n\n<p><a href=\"https://github.com/wanghenshui/little_bm/blob/dev/histgram/histgram.cc\">压测代码在这里</a></p>\n\n<p>有什么错误或者有什么改善的思路，欢迎提出</p>\n",
      "date_published": "Sun, 07 Jul 2024 00:00:00 +0000"
      },
    
    {
      "id": "https://wanghenshui.github.io/2024/06/30/mm-latency.html",
      "url": "https://wanghenshui.github.io/2024/06/30/mm-latency.html",
      "title": "内存管理机制针对延迟的优化",
      "content_html": "<p>原文</p>\n\n<p>https://johnnysswlab.com/latency-sensitive-application-and-the-memory-subsystem-part-2-memory-management-mechanisms</p>\n\n<p>https://www.jabperf.com/how-to-deter-or-disarm-tlb-shootdowns/</p>\n\n<!-- more -->\n\n<p>这篇文章的视角比较奇怪，可能和已知的信息不同，目标是低延迟避免内存机制影响</p>\n\n<p>page fault会引入延迟，所以要破坏page fault的生成条件 怎么做？</p>\n\n<p>尽可能分配好，而不是用到在分配，有概率触发page fault</p>\n\n<ul>\n  <li>mmap使用MAP_POPULATE</li>\n  <li>使用calloc不用malloc，用malloc/new 强制0填充</li>\n  <li>零初始化数组，立马使用上</li>\n  <li>vector 创造时直接构造好大小，不用reserve reserve不一定内存预分配，可能还会造成page fault()\n    <ul>\n      <li>或者重载allocator，预先分配内存</li>\n      <li>其他容器也是有类似的问题</li>\n    </ul>\n  </li>\n  <li>使用内存大页</li>\n  <li>禁用 5-Level Page Walk</li>\n  <li>关闭swap</li>\n  <li>TLB shotdown规避 这个一时半会讲不完</li>\n</ul>\n\n<p>这里展开讲讲，内容来自  <a href=\"https://www.jabperf.com/how-to-deter-or-disarm-tlb-shootdowns/\">这里</a></p>\n\n<p>cat /proc/interrupts</p>\n\n<p>观察tlb shutdown</p>\n\n<pre><code class=\"language-txt\">       CPU0       CPU1       CPU2       CPU3       CPU4       CPU5       CPU6       CPU7       \n\n45:          0          0          0          0          0          0          0          0   PCI-MSI-edge      eth0\n46:     192342          0          0          0          0          0          0          0   PCI-MSI-edge      ahci\n47:         14          0          0          0          0          0          0          0   PCI-MSI-edge      mei\n\nNMI:          0          0          0          0          0          0          0          0   Non-maskable interrupts\nLOC:     552219    1010298    2272333    3179890    1445484    1226202    1800191    1894825   Local timer interrupts\nSPU:          0          0          0          0          0          0          0          0   Spurious interrupts\n\nIWI:          0          0          0          0          0          0          0          0   IRQ work interrupts\nRTR:          7          0          0          0          0          0          0          0   APIC ICR read retries\nRES:      18708       9550        771        528        129        170        151        139   Rescheduling interrupts\nCAL:        711        934       1312       1261       1446       1411       1433       1432   Function call interrupts\nTLB:       4493       6108      73789       5014       1788       2327       1967        914   TLB shootdowns\n\n</code></pre>\n\n<p>抓堆栈 native_flush_tlb_others很多 numa自平衡开了 关闭<code class=\"language-plaintext highlighter-rouge\">sysctl -w numa_balancing=0</code></p>\n\n<p>TLB失效的原理 IPI触发</p>\n\n<ul>\n  <li>内核调用native_flush_tlb_others()</li>\n  <li>它填充一个flush_tlb_info结构体，其中包含必须刷新的地址空间部分的信息，将此结构体作为flush_tlb_func()回调函数的参数，然后调用smp_call_function_many()，其中包含一个cpu掩码、上述回调函数和该结构体作为函数参数</li>\n  <li>smp_call_function_many()使用llist_add_batch()将该回调函数和结构体附加到提供的cpumask中每个核心的每cpu“call_single_function”链表</li>\n  <li>然后，内核在__x2apic_send_IPI_mask()中的“for循环”中向上述cpumask中的每个核心发送IPI</li>\n  <li>每个接收到IPI的核心在中断模式下在其“call_single_function”队列中执行flush_tlb_func()回调，清除其中指定的TLB条目</li>\n  <li>向每个核心发送IPI的发起核心在另一个“for循环”中等待每个核心完成其回调程序</li>\n  <li>一旦所有核心完成其flush_tlb_func()回调，发起核心最终可以返回用户模式执行</li>\n</ul>\n\n<p>几个关键点</p>\n\n<ul>\n  <li>flush_tlb_info数量？</li>\n  <li>cpumask决定 __x2apic_send_IPI_mask循环次数</li>\n</ul>\n\n<p>核心越多影响越大</p>\n\n<p>怎么解决？</p>\n\n<p>预先分配内存，然后从不释放内存。分配器优化/使用mallopt()和mlockall()</p>\n\n<p>内核优化，不走IPI？</p>\n\n<p>测试numa 代码 madvise</p>\n\n<div class=\"language-c highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">pthread_barrier_t</span> <span class=\"n\">barrier</span><span class=\"p\">;</span>\n\n<span class=\"kt\">void</span><span class=\"o\">*</span> <span class=\"nf\">madv</span><span class=\"p\">(</span><span class=\"kt\">void</span><span class=\"o\">*</span> <span class=\"n\">mem</span><span class=\"p\">)</span>\n<span class=\"p\">{</span>\n  <span class=\"n\">pthread_barrier_wait</span><span class=\"p\">(</span><span class=\"o\">&amp;</span><span class=\"n\">barrier</span><span class=\"p\">);</span>\n\n  <span class=\"n\">std</span><span class=\"o\">::</span><span class=\"n\">chrono</span><span class=\"o\">::</span><span class=\"n\">steady_clock</span><span class=\"o\">::</span><span class=\"n\">time_point</span> <span class=\"n\">begin</span> <span class=\"o\">=</span> <span class=\"n\">std</span><span class=\"o\">::</span><span class=\"n\">chrono</span><span class=\"o\">::</span><span class=\"n\">steady_clock</span><span class=\"o\">::</span><span class=\"n\">now</span><span class=\"p\">();</span>\n  <span class=\"k\">for</span> <span class=\"p\">(</span><span class=\"kt\">int</span> <span class=\"n\">i</span> <span class=\"o\">=</span> <span class=\"mi\">0</span><span class=\"p\">;</span><span class=\"n\">i</span> <span class=\"o\">&lt;</span> <span class=\"mi\">1</span><span class=\"err\">'</span><span class=\"mo\">000</span><span class=\"err\">'</span><span class=\"mo\">000</span><span class=\"p\">;</span> <span class=\"n\">i</span><span class=\"o\">++</span><span class=\"p\">)</span>\n  <span class=\"p\">{</span>\n    <span class=\"n\">madvise</span><span class=\"p\">(</span><span class=\"o\">*</span><span class=\"p\">((</span><span class=\"kt\">char</span><span class=\"o\">**</span><span class=\"p\">)</span> <span class=\"n\">mem</span><span class=\"p\">),</span> <span class=\"mi\">4096</span><span class=\"p\">,</span> <span class=\"n\">MADV_DONTNEED</span><span class=\"p\">);</span>\n  <span class=\"p\">}</span>\n  <span class=\"n\">std</span><span class=\"o\">::</span><span class=\"n\">chrono</span><span class=\"o\">::</span><span class=\"n\">steady_clock</span><span class=\"o\">::</span><span class=\"n\">time_point</span> <span class=\"n\">end</span> <span class=\"o\">=</span> <span class=\"n\">std</span><span class=\"o\">::</span><span class=\"n\">chrono</span><span class=\"o\">::</span><span class=\"n\">steady_clock</span><span class=\"o\">::</span><span class=\"n\">now</span><span class=\"p\">();</span>\n  <span class=\"n\">std</span><span class=\"o\">::</span><span class=\"n\">cout</span> <span class=\"o\">&lt;&lt;</span> <span class=\"s\">\"Time difference = \"</span> <span class=\"o\">&lt;&lt;</span> <span class=\"n\">std</span><span class=\"o\">::</span><span class=\"n\">chrono</span><span class=\"o\">::</span><span class=\"n\">duration_cast</span><span class=\"o\">&lt;</span><span class=\"n\">std</span><span class=\"o\">::</span><span class=\"n\">chrono</span><span class=\"o\">::</span><span class=\"n\">milliseconds</span><span class=\"o\">&gt;</span><span class=\"p\">(</span><span class=\"n\">end</span> <span class=\"o\">-</span> <span class=\"n\">begin</span><span class=\"p\">).</span><span class=\"n\">count</span><span class=\"p\">()</span> <span class=\"o\">&lt;&lt;</span> <span class=\"s\">\"[ms]\"</span> <span class=\"o\">&lt;&lt;</span> <span class=\"n\">std</span><span class=\"o\">::</span><span class=\"n\">endl</span><span class=\"p\">;</span>\n  <span class=\"k\">return</span> <span class=\"mi\">0</span><span class=\"p\">;</span>\n<span class=\"p\">}</span>\n\n<span class=\"kt\">int</span> <span class=\"nf\">main</span><span class=\"p\">(</span><span class=\"kt\">int</span> <span class=\"n\">argc</span><span class=\"p\">,</span> <span class=\"kt\">char</span><span class=\"o\">**</span> <span class=\"n\">argv</span><span class=\"p\">)</span>\n<span class=\"p\">{</span>\n  <span class=\"kt\">void</span> <span class=\"o\">*</span><span class=\"n\">mem</span><span class=\"p\">;</span>\n  <span class=\"n\">posix_memalign</span><span class=\"p\">(</span><span class=\"o\">&amp;</span><span class=\"n\">mem</span><span class=\"p\">,</span> <span class=\"mi\">4096</span><span class=\"p\">,</span> <span class=\"mi\">8192</span><span class=\"p\">);</span>\n\n  <span class=\"k\">auto</span> <span class=\"n\">thread_count</span> <span class=\"o\">=</span> <span class=\"n\">atoi</span><span class=\"p\">(</span><span class=\"n\">argv</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]);</span>\n  <span class=\"k\">auto</span> <span class=\"n\">barrier_count</span> <span class=\"o\">=</span> <span class=\"n\">thread_count</span> <span class=\"o\">+</span> <span class=\"mi\">1</span><span class=\"p\">;</span>\n  <span class=\"n\">pthread_barrier_init</span><span class=\"p\">(</span><span class=\"o\">&amp;</span><span class=\"n\">barrier</span><span class=\"p\">,</span> <span class=\"n\">nullptr</span><span class=\"p\">,</span> <span class=\"n\">barrier_count</span><span class=\"p\">);</span>\n\n  <span class=\"n\">pthread_t</span> <span class=\"n\">threads</span><span class=\"p\">[</span><span class=\"n\">thread_count</span><span class=\"p\">];</span>\n  <span class=\"n\">pthread_attr_t</span> <span class=\"n\">attr</span><span class=\"p\">;</span>\n  <span class=\"n\">pthread_attr_init</span><span class=\"p\">(</span><span class=\"o\">&amp;</span><span class=\"n\">attr</span><span class=\"p\">);</span>\n  <span class=\"n\">pthread_attr_setscope</span><span class=\"p\">(</span><span class=\"o\">&amp;</span><span class=\"n\">attr</span><span class=\"p\">,</span> <span class=\"n\">PTHREAD_SCOPE_SYSTEM</span><span class=\"p\">);</span>\n  <span class=\"n\">cpu_set_t</span> <span class=\"n\">cpus</span><span class=\"p\">;</span>\n\n  <span class=\"k\">for</span> <span class=\"p\">(</span><span class=\"kt\">int</span> <span class=\"n\">i</span> <span class=\"o\">=</span> <span class=\"mi\">0</span><span class=\"p\">;</span> <span class=\"n\">i</span> <span class=\"o\">&lt;</span> <span class=\"n\">thread_count</span><span class=\"p\">;</span> <span class=\"n\">i</span><span class=\"o\">++</span><span class=\"p\">)</span>\n  <span class=\"p\">{</span>\n    <span class=\"n\">CPU_ZERO</span><span class=\"p\">(</span><span class=\"o\">&amp;</span><span class=\"n\">cpus</span><span class=\"p\">);</span>\n    <span class=\"n\">CPU_SET</span><span class=\"p\">(</span><span class=\"n\">i</span><span class=\"p\">,</span> <span class=\"o\">&amp;</span><span class=\"n\">cpus</span><span class=\"p\">);</span>\n    <span class=\"n\">pthread_attr_setaffinity_np</span><span class=\"p\">(</span><span class=\"o\">&amp;</span><span class=\"n\">attr</span><span class=\"p\">,</span> <span class=\"k\">sizeof</span><span class=\"p\">(</span><span class=\"n\">cpu_set_t</span><span class=\"p\">),</span> <span class=\"o\">&amp;</span><span class=\"n\">cpus</span><span class=\"p\">);</span>\n    <span class=\"n\">pthread_create</span><span class=\"p\">(</span><span class=\"o\">&amp;</span><span class=\"n\">threads</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">],</span> <span class=\"o\">&amp;</span><span class=\"n\">attr</span><span class=\"p\">,</span> <span class=\"n\">madv</span><span class=\"p\">,</span> <span class=\"o\">&amp;</span><span class=\"n\">mem</span><span class=\"p\">);</span>\n  <span class=\"p\">}</span>\n\n  <span class=\"n\">sleep</span><span class=\"p\">(</span><span class=\"mi\">2</span><span class=\"p\">);</span> <span class=\"n\">pthread_barrier_wait</span><span class=\"p\">(</span><span class=\"o\">&amp;</span><span class=\"n\">barrier</span><span class=\"p\">);</span>\n\n  <span class=\"k\">for</span> <span class=\"p\">(</span><span class=\"kt\">int</span> <span class=\"n\">i</span> <span class=\"o\">=</span> <span class=\"mi\">0</span><span class=\"p\">;</span> <span class=\"n\">i</span> <span class=\"o\">&lt;</span> <span class=\"n\">thread_count</span><span class=\"p\">;</span> <span class=\"n\">i</span><span class=\"o\">++</span><span class=\"p\">)</span>\n  <span class=\"p\">{</span>\n    <span class=\"n\">pthread_join</span><span class=\"p\">(</span><span class=\"n\">threads</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">],</span> <span class=\"n\">nullptr</span><span class=\"p\">);</span>\n  <span class=\"p\">}</span>\n  <span class=\"k\">return</span> <span class=\"mi\">0</span><span class=\"p\">;</span>\n<span class=\"p\">}</span>\n</code></pre></div></div>\n\n<p>perf抓 TLB shootdown</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>root@eltoro]# perf <span class=\"nb\">stat</span> <span class=\"nt\">-r</span> 3 <span class=\"nt\">-e</span> probe:native_flush_tlb_others,tlb_flush.stlb_any chrt <span class=\"nt\">-f</span> 90 ./madv 2\n\n Performance counter stats <span class=\"k\">for</span> <span class=\"s1\">'chrt -f 90 ./madv 2'</span> <span class=\"o\">(</span>3 runs<span class=\"o\">)</span>:\n\n         3,958,266      probe:native_flush_tlb_others                        <span class=\"o\">(</span> +-  0.28% <span class=\"o\">)</span>\n         7,928,801      tlb_flush.stlb_any                                   <span class=\"o\">(</span> +-  0.24% <span class=\"o\">)</span>\n         \n<span class=\"o\">[</span>root@eltoro]# perf <span class=\"nb\">stat</span> <span class=\"nt\">-r</span> 3 <span class=\"nt\">-e</span> probe:native_flush_tlb_others,tlb_flush.stlb_any chrt <span class=\"nt\">-f</span> 90 ./madv 8\n\n Performance counter stats <span class=\"k\">for</span> <span class=\"s1\">'chrt -f 90 ./madv 8'</span> <span class=\"o\">(</span>3 runs<span class=\"o\">)</span>:\n\n        15,946,430      probe:native_flush_tlb_others                        <span class=\"o\">(</span> +-  0.03% <span class=\"o\">)</span>\n       123,288,313      tlb_flush.stlb_any                                   <span class=\"o\">(</span> +-  0.05% <span class=\"o\">)</span>\n       \n<span class=\"o\">[</span>root@eltoro]# perf <span class=\"nb\">stat</span> <span class=\"nt\">-r</span> 3 <span class=\"nt\">-e</span> probe:native_flush_tlb_others,tlb_flush.stlb_any chrt <span class=\"nt\">-f</span> 90 ./madv 14\n\n Performance counter stats <span class=\"k\">for</span> <span class=\"s1\">'chrt -f 90 ./madv 14'</span> <span class=\"o\">(</span>3 runs<span class=\"o\">)</span>:\n\n        27,986,605      probe:native_flush_tlb_others                        <span class=\"o\">(</span> +-  0.01% <span class=\"o\">)</span>\n       376,502,522      tlb_flush.stlb_any                                   <span class=\"o\">(</span> +-  0.01% <span class=\"o\">)</span>\n</code></pre></div></div>\n\n<p>抓一下调用频次</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>root@eltoro]# funclatency.py <span class=\"nt\">-p</span> 37344 native_flush_tlb_others\nTracing 1 functions <span class=\"k\">for</span> <span class=\"s2\">\"native_flush_tlb_others\"</span>... Hit Ctrl-C to end.\n^C\n     nsecs               : count     distribution\n         0 -&gt; 1          : 0        |                                        |\n         2 -&gt; 3          : 0        |                                        |\n         4 -&gt; 7          : 0        |                                        |\n         8 -&gt; 15         : 0        |                                        |\n        16 -&gt; 31         : 0        |                                        |\n        32 -&gt; 63         : 0        |                                        |\n        64 -&gt; 127        : 0        |                                        |\n       128 -&gt; 255        : 0        |                                        |\n       256 -&gt; 511        : 0        |                                        |\n       512 -&gt; 1023       : 87926    |                                        |\n      1024 -&gt; 2047       : 3861380  |<span class=\"k\">****************************************</span>|\n      2048 -&gt; 4095       : 32924    |                                        |\n      4096 -&gt; 8191       : 3628     |                                        |\n      8192 -&gt; 16383      : 543      |                                        |\n     16384 -&gt; 32767      : 526      |                                        |\n     32768 -&gt; 65535      : 7        |                                        |\n     65536 -&gt; 131071     : 0        |                                        |\n    131072 -&gt; 262143     : 0        |                                        |\n    262144 -&gt; 524287     : 0        |                                        |\n    524288 -&gt; 1048575    : 0        |                                        |\n   1048576 -&gt; 2097151    : 0        |                                        |\n   2097152 -&gt; 4194303    : 11       |                                        |\n\navg <span class=\"o\">=</span> 1398 nsecs, total: 5582920090 nsecs, count: 3991212\n\n<span class=\"o\">[</span>root@eltoro]# funclatency.py <span class=\"nt\">-p</span> 37600 native_flush_tlb_others\nTracing 1 functions <span class=\"k\">for</span> <span class=\"s2\">\"native_flush_tlb_others\"</span>... Hit Ctrl-C to end.\n^C\n     nsecs               : count     distribution\n         0 -&gt; 1          : 0        |                                        |\n         2 -&gt; 3          : 0        |                                        |\n         4 -&gt; 7          : 0        |                                        |\n         8 -&gt; 15         : 0        |                                        |\n        16 -&gt; 31         : 0        |                                        |\n        32 -&gt; 63         : 0        |                                        |\n        64 -&gt; 127        : 0        |                                        |\n       128 -&gt; 255        : 0        |                                        |\n       256 -&gt; 511        : 0        |                                        |\n       512 -&gt; 1023       : 24       |                                        |\n      1024 -&gt; 2047       : 224605   |                                        |\n      2048 -&gt; 4095       : 9608508  |<span class=\"k\">****************************************</span>|\n      4096 -&gt; 8191       : 6012919  |<span class=\"k\">*************************</span>               |\n      8192 -&gt; 16383      : 18881    |                                        |\n     16384 -&gt; 32767      : 2468     |                                        |\n     32768 -&gt; 65535      : 66       |                                        |\n     65536 -&gt; 131071     : 41       |                                        |\n    131072 -&gt; 262143     : 39       |                                        |\n    262144 -&gt; 524287     : 16       |                                        |\n    524288 -&gt; 1048575    : 72       |                                        |\n   1048576 -&gt; 2097151    : 0        |                                        |\n   2097152 -&gt; 4194303    : 86       |                                        |\n   4194304 -&gt; 8388607    : 3        |                                        |\n\navg <span class=\"o\">=</span> 3891 nsecs, total: 62126896400 nsecs, count: 15963897\n\n<span class=\"o\">[</span>root@eltoro]# funclatency.py <span class=\"nt\">-p</span> 37786 native_flush_tlb_others\nTracing 1 functions <span class=\"k\">for</span> <span class=\"s2\">\"native_flush_tlb_others\"</span>... Hit Ctrl-C to end.\n^C\n     nsecs               : count     distribution\n         0 -&gt; 1          : 0        |                                        |\n         2 -&gt; 3          : 0        |                                        |\n         4 -&gt; 7          : 0        |                                        |\n         8 -&gt; 15         : 0        |                                        |\n        16 -&gt; 31         : 0        |                                        |\n        32 -&gt; 63         : 0        |                                        |\n        64 -&gt; 127        : 0        |                                        |\n       128 -&gt; 255        : 0        |                                        |\n       256 -&gt; 511        : 0        |                                        |\n       512 -&gt; 1023       : 23       |                                        |\n      1024 -&gt; 2047       : 158263   |                                        |\n      2048 -&gt; 4095       : 990737   |<span class=\"k\">*</span>                                       |\n      4096 -&gt; 8191       : 22814615 |<span class=\"k\">****************************************</span>|\n      8192 -&gt; 16383      : 3699448  |<span class=\"k\">******</span>                                  |\n     16384 -&gt; 32767      : 15401    |                                        |\n     32768 -&gt; 65535      : 676      |                                        |\n     65536 -&gt; 131071     : 53       |                                        |\n    131072 -&gt; 262143     : 83       |                                        |\n    262144 -&gt; 524287     : 28       |                                        |\n    524288 -&gt; 1048575    : 169      |                                        |\n   1048576 -&gt; 2097151    : 179      |                                        |\n   2097152 -&gt; 4194303    : 131      |                                        |\n\navg <span class=\"o\">=</span> 6610 nsecs, total: 184948768204 nsecs, count: 27976588\n</code></pre></div></div>\n\n",
      "date_published": "Sun, 30 Jun 2024 00:00:00 +0000"
      },
    
    {
      "id": "https://wanghenshui.github.io/2024/06/30/cache-warm.html",
      "url": "https://wanghenshui.github.io/2024/06/30/cache-warm.html",
      "title": "cache warm一例",
      "content_html": "<p>原文</p>\n\n<p>https://johnnysswlab.com/latency-sensitive-applications-and-the-memory-subsystem-keeping-the-data-in-the-cache/</p>\n\n<!-- more -->\n\n<p>while循环，没干活，干活逻辑是数据访问，那没干活分支应该可以热数据</p>\n\n<p>比如原来的逻辑</p>\n\n<div class=\"language-cpp highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">td</span><span class=\"o\">::</span><span class=\"n\">unordered_map</span><span class=\"o\">&lt;</span><span class=\"kt\">int32_t</span><span class=\"p\">,</span> <span class=\"n\">order</span><span class=\"o\">&gt;</span> <span class=\"n\">my_orders</span><span class=\"p\">;</span>\n<span class=\"p\">...</span>\n<span class=\"n\">packet_t</span><span class=\"o\">*</span> <span class=\"n\">p</span><span class=\"p\">;</span>\n<span class=\"k\">while</span><span class=\"p\">(</span><span class=\"o\">!</span><span class=\"n\">exit</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n    <span class=\"n\">p</span> <span class=\"o\">=</span> <span class=\"n\">get_packet</span><span class=\"p\">();</span>\n    <span class=\"c1\">// If packet arrived</span>\n    <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">p</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n        <span class=\"c1\">// Check if the identifier is known to us</span>\n        <span class=\"k\">auto</span> <span class=\"n\">it</span> <span class=\"o\">=</span> <span class=\"n\">my_orders</span><span class=\"p\">.</span><span class=\"n\">find</span><span class=\"p\">(</span><span class=\"n\">p</span><span class=\"o\">-&gt;</span><span class=\"n\">id</span><span class=\"p\">);</span>\n        <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">it</span> <span class=\"o\">!=</span> <span class=\"n\">my_orders</span><span class=\"p\">.</span><span class=\"n\">end</span><span class=\"p\">())</span> <span class=\"p\">{</span>\n            <span class=\"n\">send_answer</span><span class=\"p\">(</span><span class=\"n\">p</span><span class=\"o\">-&gt;</span><span class=\"n\">origin</span><span class=\"p\">,</span> <span class=\"n\">it</span><span class=\"o\">-&gt;</span><span class=\"n\">second</span><span class=\"p\">);</span>\n        <span class=\"p\">}</span>\n    <span class=\"p\">}</span>\n<span class=\"p\">}</span>\n</code></pre></div></div>\n\n<p>while里是个干活逻辑，但是有个大的if，我们可以把这个if拆出来分成干活不干活两个逻辑</p>\n\n<div class=\"language-cpp highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">std</span><span class=\"o\">::</span><span class=\"n\">unordered_map</span><span class=\"o\">&lt;</span><span class=\"kt\">int32_t</span><span class=\"p\">,</span> <span class=\"n\">order</span><span class=\"o\">&gt;</span> <span class=\"n\">my_orders</span><span class=\"p\">;</span>\n<span class=\"p\">...</span>\n<span class=\"n\">packet_t</span><span class=\"o\">*</span> <span class=\"n\">p</span><span class=\"p\">;</span>\n<span class=\"kt\">int64_t</span> <span class=\"n\">total_random_found</span> <span class=\"o\">=</span> <span class=\"mi\">0</span><span class=\"p\">;</span>\n<span class=\"k\">while</span><span class=\"p\">(</span><span class=\"o\">!</span><span class=\"n\">exit</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n    <span class=\"c1\">// 增加个检查header 然后再判断packet，不满足就去warm</span>\n    <span class=\"c1\">// 如果header没满足，packet必不满足</span>\n    <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">packet_header_arrived</span><span class=\"p\">())</span> <span class=\"p\">{</span>\n        <span class=\"n\">p</span> <span class=\"o\">=</span> <span class=\"n\">get_packet</span><span class=\"p\">();</span>\n        <span class=\"c1\">// If packet arrived</span>\n        <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">p</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n            <span class=\"c1\">// Check if the identifier is known to us</span>\n            <span class=\"k\">auto</span> <span class=\"n\">it</span> <span class=\"o\">=</span> <span class=\"n\">my_orders</span><span class=\"p\">.</span><span class=\"n\">find</span><span class=\"p\">(</span><span class=\"n\">p</span><span class=\"o\">-&gt;</span><span class=\"n\">id</span><span class=\"p\">);</span>\n            <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">it</span> <span class=\"o\">!=</span> <span class=\"n\">my_orders</span><span class=\"p\">.</span><span class=\"n\">end</span><span class=\"p\">())</span> <span class=\"p\">{</span>\n                <span class=\"n\">send_answer</span><span class=\"p\">(</span><span class=\"n\">p</span><span class=\"o\">-&gt;</span><span class=\"n\">origin</span><span class=\"p\">,</span> <span class=\"n\">it</span><span class=\"o\">-&gt;</span><span class=\"n\">second</span><span class=\"p\">);</span>\n            <span class=\"p\">}</span>\n        <span class=\"p\">}</span>\n    <span class=\"p\">}</span> <span class=\"k\">else</span> <span class=\"p\">{</span>\n        <span class=\"c1\">// 不干活就Cache warming </span>\n        <span class=\"k\">auto</span> <span class=\"n\">random_id</span> <span class=\"o\">=</span> <span class=\"n\">get_random_id</span><span class=\"p\">();</span>\n        <span class=\"k\">auto</span> <span class=\"n\">it</span> <span class=\"o\">=</span> <span class=\"n\">my_orders</span><span class=\"p\">.</span><span class=\"n\">find</span><span class=\"p\">(</span><span class=\"n\">random_id</span><span class=\"p\">);</span>\n        <span class=\"c1\">// 随便干点啥避免被编译器优化掉</span>\n        <span class=\"n\">total_random_found</span> <span class=\"o\">+=</span> <span class=\"p\">(</span><span class=\"n\">it</span> <span class=\"o\">!=</span> <span class=\"n\">my_orders</span><span class=\"p\">.</span><span class=\"n\">end</span><span class=\"p\">());</span>\n    <span class=\"p\">}</span>\n<span class=\"p\">}</span>\n<span class=\"n\">std</span><span class=\"o\">::</span><span class=\"n\">cout</span> <span class=\"o\">&lt;&lt;</span> <span class=\"s\">\"Total random found \"</span> <span class=\"o\">&lt;&lt;</span> <span class=\"n\">total_random_found</span> <span class=\"o\">&lt;&lt;</span> <span class=\"s\">\"</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">;</span>\n</code></pre></div></div>\n\n<p>当然这种cache warm不一定非得随机，有可能副作用</p>\n\n<p>可以从历史值来用，有个词怎么说来着，启发式</p>\n\n<p>硬件层也有cache warm 比如 <a href=\"https://johnnysswlab.com/wp-content/uploads/Introducing-Cache-Pseudo-Locking-to-Reduce-Memory-Access-Latency-Reinette-Chatre-Intel.pdf\">intel</a></p>\n\n<p>其实就是prefetch clflush那套，如果你知道具体访问哪个，那prefetch确实是比较高效的</p>\n\n<p>amd也有 L3 Cache Range Reservation 不过没例子</p>\n\n<p>作者测试了软件模拟cache warm，随机访问</p>\n\n<p>数据，迭代多次的延迟，越小越好</p>\n\n<table>\n  <thead>\n    <tr>\n      <th>hashmap数据量</th>\n      <th>正常访问hashmap</th>\n      <th>没有访问的时候只warm 0</th>\n      <th>没有访问的时候随机warm</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <td>1 K</td>\n      <td>226.1 (219.0)</td>\n      <td>213.3 (205.1)</td>\n      <td>132.5 (67.3)</td>\n    </tr>\n    <tr>\n      <td>4 K</td>\n      <td>324.7 (296.3)</td>\n      <td>350.7 (331.3)</td>\n      <td>140.1 (95.4)</td>\n    </tr>\n    <tr>\n      <td>16 K</td>\n      <td>396.8 (341.1)</td>\n      <td>389.1 (354.5)</td>\n      <td>208.7 (134.5)</td>\n    </tr>\n    <tr>\n      <td>64 K</td>\n      <td>425.5 (376.1)</td>\n      <td>416.0 (360.6)</td>\n      <td>232.1 (152.6)</td>\n    </tr>\n    <tr>\n      <td>256 K</td>\n      <td>514.2 (451.5)</td>\n      <td>473.3 (480.6)</td>\n      <td>338.8 (317.6)</td>\n    </tr>\n    <tr>\n      <td>1 M</td>\n      <td>599.8 (550.2)</td>\n      <td>615.1 (573.6)</td>\n      <td>466.3 (429.8)</td>\n    </tr>\n    <tr>\n      <td>4 M</td>\n      <td>702.1 (647.0)</td>\n      <td>619.7 (649.2)</td>\n      <td>531.3 (508.3)</td>\n    </tr>\n    <tr>\n      <td>16 M</td>\n      <td>756.7 (677.6)</td>\n      <td>668.8 (707.4)</td>\n      <td>543.2 (499.9)</td>\n    </tr>\n    <tr>\n      <td>64 M</td>\n      <td>769.1 (702.3)</td>\n      <td>735.9 (734.2)</td>\n      <td>641.0 (774.4)</td>\n    </tr>\n  </tbody>\n</table>\n\n<p>能看到随机访问 随机warm效果显著</p>\n\n<p>和群友讨论</p>\n\n<p>yangbowen认为没用，prefetch有用，手动warm当cpu傻逼(我感觉他没看懂这个例子)</p>\n\n<p>mwish给了一些prefetch的资料 https://www.cs.cmu.edu/~chensm/papers/hashjoin_tods_preliminary.pdf</p>\n\n<p>大家接触的多的例子就是prefetch，这种模拟cache warm还是比较少见的</p>\n",
      "date_published": "Sun, 30 Jun 2024 00:00:00 +0000"
      }
    
  ]
}