化学摩尔定律是什么如何为Hyper

摩尔定律会失效吗?不会的
近几十年间,摩尔定律一直推动着半导体制造能力的进步,同时也带来了高科技领域的巨大飞跃。然而,近期关于摩尔定律已走到尽头的声音开始甚嚣尘上,为此英特尔也不得不出面辟谣。
讲到摩尔定律,我们首先来回顾下它的定义。摩尔定律是由英特尔创世人之一的戈登&摩尔于1956年提出,大致概况其核心含义为芯片上的晶体管数量每隔24个月将增加一倍。其经济学意义就是:按照特定节奏推动半导体制造能力的进步,我们就可以降低任何依赖于计算的商业模式的成本。
作为摩尔定律的提出者,英特尔自然一直践行着该定律。事实也是如此,半个多世纪以来,半导体行业一直按照摩尔定律来前进。然而,特尔从22纳米到14纳米再到10纳米的推出时间间隔都已超过24个月、甚至36个月,这似乎正在背离摩尔定律。与此同时,作为半导体芯片领域的另外两个强劲对手,三星和台积电都宣传已经投产10nm工艺,7nm也将接踵而至,而此时英特尔还只是在14nm阶段,行业质疑声也不短出现。
在这样的情况下,英特尔终于坐不住了,芯片制程方面的大咖集体亮相为摩尔定律正名。9月19日在北京举办的&英特尔精尖制造日&上,英特尔公司全球副总裁兼中国区总裁杨旭,英特尔公司执行副总裁兼制造、运营与销售集团总裁Stacy
Smith,英特尔高级院士、制程架构与集成总监 Mark Bohr,英特尔公司技术与制造事业部副总裁、英特尔代工业务联合总经理 Zane
Ball等众多高管纷纷出席,正式发布了其10nm制程工艺。一方面力证摩尔定律依然有效,另一方面怒怼了三星和台积电。
摩尔定律依然有效
&摩尔定律究竟是否会失效,答案是肯定不会。&英特尔公司执行副总裁兼制造运营与销售集团总裁Stacy
Smith认为:&摩尔定律在不同层面上奠定了英特尔发展以及整个行业的进步。我们都知道,制造成本趋势是不断攀升的,如果晶体管体积不断微缩,事实上每个晶体管的成本是下降的。由下图可以看出,最后两个节点的成本下降幅度是高于历史趋势的。它证明什么?那就是摩尔定律仍然有效。虽然说14纳米到10纳米节点之间的时间已经延长,但是英特尔创新性地采用超微缩技术,创纪录地将晶片面积缩小了0.5倍以上,使得摩尔定律依然能够发挥经济效益,推动半导体产业向前发展。&
但是客观而言,物理极限终归会出现。对此,Stacy
Smith认为:&有一天我们可能会达到物理极限,但目前还看不到终点。记得在1990年,当晶圆上的晶体管大小达到用以印刷它们的光的波长(193纳米)时,物理学界明确指出:我们不能再向前推进了。但是我们突破了那个挑战:我们使用掩模图形产生的干涉光栅进行印刷,开发了计算型光刻技术和多重曝光。回想起来,193纳米甚至称不上是减速带,我们目前的制程比当时还要小20倍。这得益于我们持续的创新。比如目前在14纳米制程中使用的鳍式场效应晶体管(FinFET)和超微缩技术(hyper
scaling)。升级版的超微缩技术已应用在我们即将量产的10纳米制程,而得益于这一新的工艺突破,我们可以不断降低每百万晶体管的成本。&
对此,英特尔高级院士、制程架构与集成总监 Mark
Bohr也表示:&如果你在20年前问半导体业内专家,他们会告诉你摩尔定律还能继续十年。如果你在10年前再问行业专家,他们还会说十年。现在你问我,我还是会回答十年。我们拿海平面打一个比方,你离海平线越来越近,但它还是不断往前推进的。&
总体而言,英特尔坚信摩尔定律依然有效,至少现在还看不到终点。面对制程工艺的挑战,英特尔寄予厚望的鳍式场效应晶体管和超微缩等技术,有望使得英特尔再次渡过难关。
怒怼三星和台积电
我们都知道,在半导体制程技术方面三星和台积电正在对英特尔发起强劲挑战。2014年英特尔推出14nm工艺之后,不到一年的时间三星也推出了其14nm工艺,而台积电也推出了16nm工艺。而在2016年底,三星和台积电后来居上,相继推出了10nm工艺,整整比英特尔提前了近一年时间。
&并不是所有的10nm就是真正的10nm。&英特尔高级院士、制程架构与集成总监 Mark
Bohr表示:&对于制程节点上的乱象,更多是企业市场销售的策略。采用晶体管密度更适合准确反应制程工艺水平,从而厘清制程节点命名的混乱状况。英特尔在重要的制程创新方面领先整个行业至少三年。过去15年,英特尔在逻辑制程方面推出的所有重要创新均得到行业的广泛采纳。对于未来发展,英特尔也没有停下脚步,正在研究更多突破性技术,引领行业发展。&
对于制程节点命名方式,英特尔也提出用晶体管密度更加适合,具体公式为:
从重新定义制程节点命名,到列举10nm工艺性能和功耗对比,英特尔直接点名道姓,三星和台积电你们都不是真的10nm。可谓狠狠地怼了两大竞争对手,作为吃瓜群众正在期待三星和台积电如何回应。但是,先站出来的却是NVDIA。
NVDIA先站了出来
9月26日同样是在北京举办的GTC技术大会上,NVIDIA创办人兼执行长黄仁勋直接呛声英特尔:&摩尔定律已经终结,设计人员无法再创造出可以实现更高指令集并行的GPU架构,晶体管数量每年增长50%,但CPU的性能每年仅增长10%。&
这英特尔前脚刚宣布摩尔定律依然有效,NVIDIA就直接宣布摩尔定律已经终结,其中充满了火药味。
还是标志性黑色皮衣,黄仁勋高呼:&GPU才是全新的&超级摩尔定律&,这也是整个行业一次千载难逢的机遇。&
据黄仁勋介绍,NVIDIA V100数据中心GPU配备有210亿个晶体管,性能较早前的NVIDIA Pascal架构P100
GPU提升了5倍,同时可提供相当于100个CPU的深度学习性能。这一性能的提升相较于摩尔定律对同一时期的预测提升了4倍。
在黄仁勋看来,GPU可以弥补CPU的不足,加速处理高强度计算负载。摩尔定律太老,太慢了&&
在黄教主开启AI时代计算新纪元的雄心壮志之下,似乎看到了摩尔定律落寞的身影&&&p&2018年了,不要再看网上那些老旧的文章还在教你使用手工生成 tags 的,请使用自动代码索引生成工具,比如 &a href=&//link.zhihu.com/?target=https%3A//github.com/ludovicchabant/vim-gutentags& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&vim-gutentags&/a&,现在网上好像就没有一篇能正确讨论
Vim C/C++ 环境搭建的,都在谈些十年前的东西,所以我写了篇关于 Vim 8 和 C/C++ 相关插件的介绍:&/p&&p&假设你已经有一定 Vim 使用经验,并且折腾过 Vim 配置,能够相对舒适的在 Vim 中编写其他代码的时候,准备在 Vim 开始 C/C++ 项目开发,或者你已经用 Vim 编写了几年 C/C++ 代码,想要更进一步,让自己的工作更加顺畅的话,本文就是为你准备的:&/p&&p&&br&&/p&&p&&b&插件管理&/b&&/p&&p&为什么把插件管理放在第一个来讲呢?这是比较基本的一个东西,如今 Vim 下熟练开发的人,基本上手都有 20-50 个插件,遥想十年前,Vim里常用的插件一只手都数得过来。过去我一直使用老牌的 &a href=&//link.zhihu.com/?target=https%3A//github.com/VundleVim/Vundle.vim& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Vundle&/a& 来管理插件,但是随着插件越来越多,更新越来越频繁,Vundle 这种每次更新就要好几分钟的东西实在是不堪重负了。&/p&&p&在我逐步对 Vundle 失去耐心之后,我试用了 &a href=&//link.zhihu.com/?target=https%3A//github.com/junegunn/vim-plug& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&vim-plug&/a& ,用了两天以后就再也回不去 Vundle了,它支持全异步的插件安装,安装50个插件只需要一分钟不到的时间,这在 Vundle 下面根本不可想像的事情,插件更新也很快,不像原来每次更新都可以去喝杯茶去,最重要的是它支持插件延迟加载:&/p&&div class=&highlight&&&pre&&code class=&language-vim&&&span class=&c&&& 定义插件,默认用法,和 Vundle 的语法差不多&/span&
Plug &span class=&s1&&'junegunn/vim-easy-align'&/span&
Plug &span class=&s1&&'skywind3000/quickmenu.vim'&/span&
&span class=&c&&& 延迟按需加载,使用到命令的时候再加载或者打开对应文件类型才加载&/span&
Plug &span class=&s1&&'scrooloose/nerdtree'&/span&&span class=&p&&,&/span& { &span class=&s1&&'on'&/span&:
&span class=&s1&&'NERDTreeToggle'&/span& }
Plug &span class=&s1&&'tpope/vim-fireplace'&/span&&span class=&p&&,&/span& { &span class=&s1&&'for'&/span&: &span class=&s1&&'clojure'&/span& }
&span class=&c&&& 确定插件仓库中的分支或者 tag&/span&
Plug &span class=&s1&&'rdnetto/YCM-Generator'&/span&&span class=&p&&,&/span& { &span class=&s1&&'branch'&/span&: &span class=&s1&&'stable'&/span& }
Plug &span class=&s1&&'nsf/gocode'&/span&&span class=&p&&,&/span& { &span class=&s1&&'tag'&/span&: &span class=&s1&&'v.'&/span&&span class=&p&&,&/span& &span class=&s1&&'rtp'&/span&: &span class=&s1&&'vim'&/span& }
&/code&&/pre&&/div&&p&定义好插件以后一个 :PlugInstall 命令就并行安装所有插件了,比 Vundle 快捷不少,关键是 vim-plug 只有单个文件,正好可以放在我 github 上的 vim 配置仓库中,每次需要更新 vim-plug 时只需要 :PlugUpgrade,即可自我更新。使用时建议给插件分组,同类别插件放一个组里,vimrc 里面只需要确定下启用哪些组就行了。&/p&&p&抛弃 Vundle 切换到 vim-plug 以后,不仅插件安装和更新快了一个数量级,大量的插件我都配置成了延迟加载,Vim 启动速度比 Vundle 时候提高了不少。使用 Vundle 的时候一旦插件数量超过30个,管理是一件很痛苦的事情,而用了 vim-plug 以后,50-60个插件都轻轻松松。&/p&&p&&br&&/p&&p&&b&符号索引&/b&&/p&&p&现在有好多 ctags 的代替品,比如 gtags, etags 和 cquery。然而我并不排斥 ctags,因为他支持 50+ 种语言,没有任何一个符号索引工具有它支持的语言多。同时 Vim 和 ctags 集成的相当好,用它依赖最少,大量基础工作可以直接通过 ctags 进行,然而到现在为止,我就没见过几个人把 ctags 用对了的。&/p&&p&就连配置文件他们都没写对,正确的 ctags 配置应该是:&/p&&div class=&highlight&&&pre&&code class=&language-vim&&&span class=&k&&set&/span& &span class=&k&&tags&/span&&span class=&p&&=&/span&./.&span class=&k&&tags&/span&;&span class=&p&&,&/span&.&span class=&k&&tags&/span&
&/code&&/pre&&/div&&p&这里解释一下,首先我把 tag 文件的名字从“tags” 换成了 “.tags”,前面多加了一个点,这样即便放到项目中也不容易污染当前项目的文件,删除时也好删除,gitignore 也好写,默认忽略点开头的文件名即可。&/p&&p&前半部分 “&b&./. &/b&”代表在文件的所在目录下(不是 “:pwd”返回的 Vim 当前目录)查找名字为 “.tags”的符号文件,后面一个分号代表查找不到的话向上递归到父目录,直到找到 .tags 文件或者递归到了根目录还没找到,这样对于复杂工程很友好,源代码都是分布在不同子目录中,而只需要在项目顶层目录放一个 .tags文件即可;逗号分隔的后半部分 .tags 是指同时在 Vim 的当前目录(“:pwd”命令返回的目录,可以用 :cd ..命令改变)下面查找 .tags 文件。&/p&&p&最后请更新你的 ctags,不要再使用老旧的 Exuberant Ctags,这货停止更新快十年了,请使用最新的
&a href=&//link.zhihu.com/?target=https%3A//ctags.io/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Universal CTags&/a& 代替之,它在 Exuberant Ctags 的基础上继续更新迭代了近十年,如今任然活跃的维护着,功能更强大,语言支持更多。&/p&&p&(注意最新版 universal ctags 调用时需要加一个 --output-format=e-ctags,输出格式才和老的 exuberant ctags 兼容否则会有 windows 下路径名等小问题)。&/p&&p&&br&&/p&&p&&b&自动索引&/b&&/p&&p&过去写几行代码又需要运行一下 ctags 来生成索引,每次生成耗费不少时间。如今 Vim 8 下面自动异步生成 tags 的工具有很多,这里推荐最好的一个:&a href=&//link.zhihu.com/?target=https%3A//github.com/ludovicchabant/vim-gutentags& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&vim-gutentags&/a&,这个插件主要做两件事情:&/p&&p&- 确定文件所属的工程目录,即文件当前路径向上递归查找是否有 `.git`, `.svn`, `.project` 等标志性文件(可以自定义)来确定当前文档所属的工程目录。&/p&&p&- 检测同一个工程下面的文件改动,能会自动增量更新对应工程的 `.tags` 文件。每次改了几行不用全部重新生成,并且这个增量更新能够保证 `.tags` 文件的符号排序,方便 Vim 中用二分查找快速搜索符号。&/p&&p&vim-gutentags 需要简单配置一下:&/p&&div class=&highlight&&&pre&&code class=&language-vim&&&span class=&c&&& gutentags 搜索工程目录的标志,碰到这些文件/目录名就停止向上一级目录递归&/span&
&span class=&k&&let&/span& &span class=&k&&g&/span&:gutentags_project_root &span class=&p&&=&/span& [&span class=&s1&&'.root'&/span&&span class=&p&&,&/span& &span class=&s1&&'.svn'&/span&&span class=&p&&,&/span& &span class=&s1&&'.git'&/span&&span class=&p&&,&/span& &span class=&s1&&'.hg'&/span&&span class=&p&&,&/span& &span class=&s1&&'.project'&/span&]
&span class=&c&&& 所生成的数据文件的名称&/span&
&span class=&k&&let&/span& &span class=&k&&g&/span&:gutentags_ctags_tagfile &span class=&p&&=&/span& &span class=&s1&&'.tags'&/span&
&span class=&c&&& 将自动生成的 tags 文件全部放入 ~/.cache/tags 目录中,避免污染工程目录&/span&
&span class=&k&&let&/span& s:vim_tags &span class=&p&&=&/span& expand&span class=&p&&(&/span&&span class=&s1&&'~/.cache/tags'&/span&&span class=&p&&)&/span&
&span class=&k&&let&/span& &span class=&k&&g&/span&:gutentags_cache_dir &span class=&p&&=&/span& s:vim_tags
&span class=&c&&& 配置 ctags 的参数&/span&
&span class=&k&&let&/span& &span class=&k&&g&/span&:gutentags_ctags_extra_args &span class=&p&&=&/span& [&span class=&s1&&'--fields=+niazS'&/span&&span class=&p&&,&/span& &span class=&s1&&'--extra=+q'&/span&]
&span class=&k&&let&/span& &span class=&k&&g&/span&:gutentags_ctags_extra_args &span class=&p&&+=&/span& [&span class=&s1&&'--c++-kinds=+px'&/span&]
&span class=&k&&let&/span& &span class=&k&&g&/span&:gutentags_ctags_extra_args &span class=&p&&+=&/span& [&span class=&s1&&'--c-kinds=+px'&/span&]
&span class=&c&&& 检测 ~/.cache/tags 不存在就新建&/span&
&span class=&k&&if&/span& &span class=&p&&!&/span&isdirectory&span class=&p&&(&/span&s:vim_tags&span class=&p&&)&/span&
&span class=&k&&silent&/span&&span class=&p&&!&/span& &span class=&k&&call&/span& mkdir&span class=&p&&(&/span&s:vim_tags&span class=&p&&,&/span& &span class=&s1&&'p'&/span&&span class=&p&&)&/span&
&span class=&k&&endif&/span&
&/code&&/pre&&/div&&p&有了上面的设置,你平时基本感觉不到 tags 文件的生成过程了,只要文件修改过,gutentags 都在后台为你默默打点是否需要更新数据文件,你根本不用管,还会帮你:&b&setlocal tags+=...&/b& 添加到局部 tags 搜索列表中。&/p&&p&为当前文件添加上对应的 tags 文件的路劲而不影响其他文件。得益于 Vim 8 的异步机制,你可以任意随时使用 ctags 相关功能,并且数据库都是最新的。需要注意的是,gutentags 需要靠上面定义的 project_root 里的标志,判断文件所在的工程,如果一个文件没有托管在 .git/.svn 中,gutentags 找不到工程目录的话,就不会为该野文件生成 tags,这也很合理。想要避免的话,你可以在你的野文件目录中放一个名字为 &b&.root&/b& 的空白文件,主动告诉 gutentags 这里就是工程目录。&/p&&p&最后啰嗦两句,少用 &b&CTRL-]&/b& 直接在当前窗口里跳转到定义,多使用 &b&CTRL-W ]&/b& 用新窗口打开并查看光标下符号的定义,或者 &b&CTRL-W } &/b&使用 preview 窗口预览光标下符号的定义。&/p&&p&我自己还写过不少关于 ctags 的 vimscript,例如在最下面命令行显示函数的原型而不用急着跳转,或者重复按 `ALT+;` 在 preview 窗口中轮流查看多个定义,不切走当前窗口,不会出一个很长的列表让你选择,有兴趣可以刨我的 &a href=&//link.zhihu.com/?target=https%3A//github.com/skywind3000/vim& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&vim dotfiles&/a&。&/p&&p&&br&&/p&&p&&b&编译运行&/b&&/p&&p&再 Vim 8 以前,编译和运行程序要么就让 vim 傻等着结束,不能做其他事情,要么切到一个新的终端下面去单独运行编译命令和执行命令,要么开个 tmux 左右切换。如今新版本的异步模式可以让这个流程更加简化,这里我们使用 &a href=&//link.zhihu.com/?target=https%3A//github.com/skywind3000/asyncrun.vim& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&AsyncRun&/a& 插件,简单设置下:&/p&&div class=&highlight&&&pre&&code class=&language-vim&&Plug &span class=&s1&&'skywind3000/asyncrun.vim'&/span&
&span class=&c&&& 自动打开 quickfix window ,高度为 6&/span&
&span class=&k&&let&/span& &span class=&k&&g&/span&:asyncrun_open &span class=&p&&=&/span& &span class=&m&&6&/span&
&span class=&c&&& 任务结束时候响铃提醒&/span&
&span class=&k&&let&/span& &span class=&k&&g&/span&:asyncrun_bell &span class=&p&&=&/span& &span class=&m&&1&/span&
&span class=&c&&& 设置 F10 打开/关闭 Quickfix 窗口&/span&
&span class=&nb&&nnoremap&/span& &span class=&p&&&&/span&F10&span class=&p&&&&/span& :&span class=&k&&call&/span& asyncrun#quickfix_toggle&span class=&p&&(&/span&&span class=&m&&6&/span&&span class=&p&&)&&/span&&span class=&k&&cr&/span&&span class=&p&&&&/span&
&/code&&/pre&&/div&&p&该插件可以在后台运行 shell 命令,并且把结果输出到 quickfix 窗口:&/p&&figure&&img src=&https://pic2.zhimg.com/50/v2-b683e6b77ad4cbe2177104_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&680& data-rawheight=&460& class=&origin_image zh-lightbox-thumb& width=&680& data-original=&https://pic2.zhimg.com/50/v2-b683e6b77ad4cbe2177104_r.jpg&&&/figure&&p&最简单的编译单个文件,和 sublime 的默认 build system 差不多,我们定义 F9 为编译单文件:&/p&&div class=&highlight&&&pre&&code class=&language-vim&&&span class=&nb&&nnoremap&/span& &span class=&p&&&&/span&&span class=&k&&silent&/span&&span class=&p&&&&/span& &span class=&p&&&&/span&F9&span class=&p&&&&/span& :AsyncRun gcc &span class=&p&&-&/span&Wall &span class=&p&&-&/span&O2 &span class=&s2&&&$(VIM_FILEPATH)&&/span& &span class=&p&&-&/span&&span class=&k&&o&/span& &span class=&s2&&&$(VIM_FILEDIR)/$(VIM_FILENOEXT)&&/span& &span class=&p&&&&/span&&span class=&k&&cr&/span&&span class=&p&&&&/span&
&/code&&/pre&&/div&&p&其中 $(...) 形式的宏在执行时会被替换成实际的文件名或者文件目录,这样按 F9 就可以编译当前文件,同时按 F5 运行:&/p&&div class=&highlight&&&pre&&code class=&language-vim&&&span class=&nb&&nnoremap&/span& &span class=&p&&&&/span&&span class=&k&&silent&/span&&span class=&p&&&&/span& &span class=&p&&&&/span&F5&span class=&p&&&&/span& :AsyncRun &span class=&p&&-&/span&raw &span class=&p&&-&/span&cwd&span class=&p&&=&/span&$&span class=&p&&(&/span&VIM_FILEDIR&span class=&p&&)&/span& &span class=&s2&&&$(VIM_FILEDIR)/$(VIM_FILENOEXT)&&/span& &span class=&p&&&&/span&&span class=&k&&cr&/span&&span class=&p&&&&/span&
&/code&&/pre&&/div&&p&用双引号引起来避免文件名包含空格,“&b&-cwd=$(VIM_FILEDIR)&/b&” 的意思时在文件文件的所在目录运行可执行,后面可执行使用了全路径,避免 linux 下面当前路径加 “./” 而 windows 不需要的跨平台问题。&/p&&p&参数 `-raw` 表示输出不用匹配错误检测模板 (errorformat) ,直接原始内容输出到 quickfix 窗口。这样你可以一边编辑一边 F9 编译,出错了可以在 quickfix 窗口中按回车直接跳转到错误的位置,编译正确就接着执行。&/p&&p&接下来是项目的编译,不管你直接使用 make 还是 cmake,都是对一群文件做点什么,都需要定位到文件所属项目的目录,AsyncRun 识别当前文件的项目目录方式和 gutentags相同,从文件所在目录向上递归,直到找到名为 “.git”, “.svn”, “.hg”或者 “.root”文件或者目录,如果递归到根目录还没找到,那么文件所在目录就被当作项目目录,你重新定义项目标志:&/p&&div class=&highlight&&&pre&&code class=&language-vim&&&span class=&k&&let&/span& &span class=&k&&g&/span&:asyncrun_rootmarks &span class=&p&&=&/span& [&span class=&s1&&'.svn'&/span&&span class=&p&&,&/span& &span class=&s1&&'.git'&/span&&span class=&p&&,&/span& &span class=&s1&&'.root'&/span&&span class=&p&&,&/span& &span class=&s1&&'_darcs'&/span&&span class=&p&&,&/span& &span class=&s1&&'build.xml'&/span&]
&/code&&/pre&&/div&&p&然后在 AsyncRun 命令行中,用 “&root&” 或者 “$(VIM_ROOT)”来表示项目所在路径,于是我们可以定义按 F7 编译整个项目:&/p&&div class=&highlight&&&pre&&code class=&language-vim&&&span class=&nb&&nnoremap&/span& &span class=&p&&&&/span&&span class=&k&&silent&/span&&span class=&p&&&&/span& &span class=&p&&&&/span&F7&span class=&p&&&&/span& :AsyncRun &span class=&p&&-&/span&cwd&span class=&p&&=&&/span&root&span class=&p&&&&/span& &span class=&k&&make&/span& &span class=&p&&&&/span&&span class=&k&&cr&/span&&span class=&p&&&&/span&
&/code&&/pre&&/div&&p&那么如果你有一个项目不在 svn 也不在 git 中怎么查找 &code&&root&&/code& 呢?很简单,放一个空的 &code&.root&/code& 文件到你的项目目录下就行了,前面配置过,识别名为 .root 的文件。&/p&&p&继续配置用 F8 运行当前项目:&/p&&div class=&highlight&&&pre&&code class=&language-vim&&&span class=&nb&&nnoremap&/span& &span class=&p&&&&/span&&span class=&k&&silent&/span&&span class=&p&&&&/span& &span class=&p&&&&/span&F8&span class=&p&&&&/span& :AsyncRun &span class=&p&&-&/span&cwd&span class=&p&&=&&/span&root&span class=&p&&&&/span& &span class=&p&&-&/span&raw &span class=&k&&make&/span& run &span class=&p&&&&/span&&span class=&k&&cr&/span&&span class=&p&&&&/span&
&/code&&/pre&&/div&&p&当然,你的 makefile 中需要定义怎么 run ,接着按 F6 执行测试:&/p&&div class=&highlight&&&pre&&code class=&language-vim&&&span class=&nb&&nnoremap&/span& &span class=&p&&&&/span&&span class=&k&&silent&/span&&span class=&p&&&&/span& &span class=&p&&&&/span&F6&span class=&p&&&&/span& :AsyncRun &span class=&p&&-&/span&cwd&span class=&p&&=&&/span&root&span class=&p&&&&/span& &span class=&p&&-&/span&raw &span class=&k&&make&/span& test &span class=&p&&&&/span&&span class=&k&&cr&/span&&span class=&p&&&&/span&
&/code&&/pre&&/div&&p&如果你使用了 cmake 的话,还可以照葫芦画瓢,定义 F4 为更新 Makefile 文件,如果不用 cmake 可以忽略:&/p&&div class=&highlight&&&pre&&code class=&language-vim&&&span class=&nb&&nnoremap&/span& &span class=&p&&&&/span&&span class=&k&&silent&/span&&span class=&p&&&&/span& &span class=&p&&&&/span&F4&span class=&p&&&&/span& :AsyncRun &span class=&p&&-&/span&cwd&span class=&p&&=&&/span&root&span class=&p&&&&/span& cmake . &span class=&p&&&&/span&&span class=&k&&cr&/span&&span class=&p&&&&/span&
&/code&&/pre&&/div&&p&由于 C/C++ 标准库的实现方式是发现在后台运行时会缓存标准输出直到程序退出,你想实时看到 printf 输出的话需要 fflush(stdout) 一下,或者程序开头关闭缓存:“setbuf(stdout, NULL);” 即可。&/p&&p&同时,如果你开发 C++ 程序使用 std::cout 的话,后面直接加一个 std::endl 就强制刷新缓存了,不需要弄其他。而如果你在 Windows 下使用 GVim 的话,可以弹出新的 cmd.exe 窗口来运行刚才的程序:&/p&&div class=&highlight&&&pre&&code class=&language-vim&&&span class=&nb&&nnoremap&/span& &span class=&p&&&&/span&&span class=&k&&silent&/span&&span class=&p&&&&/span& &span class=&p&&&&/span&F5&span class=&p&&&&/span& :AsyncRun &span class=&p&&-&/span&cwd&span class=&p&&=&/span&$&span class=&p&&(&/span&VIM_FILEDIR&span class=&p&&)&/span& &span class=&p&&-&/span&&span class=&k&&mode&/span&&span class=&p&&=&/span&&span class=&m&&4&/span& &span class=&s2&&&$(VIM_FILEDIR)/$(VIM_FILENOEXT)&&/span& &span class=&p&&&&/span&&span class=&k&&cr&/span&&span class=&p&&&&/span&
&span class=&nb&&nnoremap&/span& &span class=&p&&&&/span&&span class=&k&&silent&/span&&span class=&p&&&&/span& &span class=&p&&&&/span&F8&span class=&p&&&&/span& :AsyncRun &span class=&p&&-&/span&cwd&span class=&p&&=&&/span&root&span class=&p&&&&/span& &span class=&p&&-&/span&&span class=&k&&mode&/span&&span class=&p&&=&/span&&span class=&m&&4&/span& &span class=&k&&make&/span& run &span class=&p&&&&/span&&span class=&k&&cr&/span&&span class=&p&&&&/span&
&/code&&/pre&&/div&&p&在 Windows 下使用 -mode=4 选项可以跟 Visual Studio 执行命令行工具一样,弹出一个新的 cmd.exe窗口来运行程序或者项目,于是我们有了下面的快捷键:&/p&&ul&&li&F4:使用 cmake 生成 Makefile &/li&&li&F5:单文件:运行&/li&&li&F6:项目:测试&/li&&li&F7:项目:编译&/li&&li&F8:项目:运行&/li&&li&F9:单文件:编译&/li&&li&F10:打开/关闭底部的 quickfix 窗口&/li&&/ul&&p&恩,编译和运行基本和 NotePad++ / GEdit 的体验差不多了。如果你重度使用 cmake 的话,你还可以写点小脚本,将 F4 和 F7 的功能合并,检测 CMakeLists.txt 文件改变的话先执行 cmake 更新一下 Makefile,然后再执行 make,否则直接执行 make,这样更自动化些。&/p&&p&&br&&/p&&p&&b&动态检查&/b&&/p&&p&代码检查是个好东西,让你在编辑文字的同时就帮你把潜在错误标注出来,不用等到编译或者运行了才发现。我很奇怪 2018 年了,为啥网上还在到处介绍老旧的 &a href=&//link.zhihu.com/?target=https%3A//github.com/vim-syntastic/syntastic& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&syntastic&/a&,但凡见到介绍这个插件的文章基本都可以不看了。老的 syntastic 基本没法用,不能实时检查,一保存文件就运行检查器并且等待半天,所以请用实时 linting 工具 &a href=&//link.zhihu.com/?target=https%3A//github.com/w0rp/ale& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&ALE&/a&:&/p&&figure&&img src=&https://pic3.zhimg.com/50/v2-548f3afab2e0d989ad06dc_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&718& data-rawheight=&475& class=&origin_image zh-lightbox-thumb& width=&718& data-original=&https://pic3.zhimg.com/50/v2-548f3afab2e0d989ad06dc_r.jpg&&&/figure&&p&大概长这个样子,随着你不断的编辑新代码,有语法错误的地方会实时帮你标注出来,侧边会标注本行有错,光标移动过去的时候下面会显示错误原因,而具体错误的符号下面会有红色波浪线提醒。Ale 支持多种语言的各种代码分析器,就 C/C++ 而言,就支持:gcc, clang, cppcheck 以及 clang-format 等,需要另行安装并放入 PATH下面,ALE能在你修改了文本后自动调用这些 linter 来分析最新代码,然后将各种 linter 的结果进行汇总并显示再界面上。&/p&&p&同样,我们也需要简单配置一下:&/p&&div class=&highlight&&&pre&&code class=&language-vim&&&span class=&k&&let&/span& &span class=&k&&g&/span&:ale_linters_explicit &span class=&p&&=&/span& &span class=&m&&1&/span&
&span class=&k&&let&/span& &span class=&k&&g&/span&:ale_completion_delay &span class=&p&&=&/span& &span class=&m&&500&/span&
&span class=&k&&let&/span& &span class=&k&&g&/span&:ale_echo_delay &span class=&p&&=&/span& &span class=&m&&20&/span&
&span class=&k&&let&/span& &span class=&k&&g&/span&:ale_lint_delay &span class=&p&&=&/span& &span class=&m&&500&/span&
&span class=&k&&let&/span& &span class=&k&&g&/span&:ale_echo_msg_format &span class=&p&&=&/span& &span class=&s1&&'[%linter%] %code: %%s'&/span&
&span class=&k&&let&/span& &span class=&k&&g&/span&:ale_lint_on_text_changed &span class=&p&&=&/span& &span class=&s1&&'normal'&/span&
&span class=&k&&let&/span& &span class=&k&&g&/span&:ale_lint_on_insert_leave &span class=&p&&=&/span& &span class=&m&&1&/span&
&span class=&k&&let&/span& &span class=&k&&g&/span&:airline#extensions#ale#enabled &span class=&p&&=&/span& &span class=&m&&1&/span&
&span class=&k&&let&/span& &span class=&k&&g&/span&:ale_c_gcc_options &span class=&p&&=&/span& &span class=&s1&&'-Wall -O2 -std=c99'&/span&
&span class=&k&&let&/span& &span class=&k&&g&/span&:ale_cpp_gcc_options &span class=&p&&=&/span& &span class=&s1&&'-Wall -O2 -std=c++14'&/span&
&span class=&k&&let&/span& &span class=&k&&g&/span&:ale_c_cppcheck_options &span class=&p&&=&/span& &span class=&s1&&''&/span&
&span class=&k&&let&/span& &span class=&k&&g&/span&:ale_cpp_cppcheck_options &span class=&p&&=&/span& &span class=&s1&&''&/span&
&/code&&/pre&&/div&&p&基本上就是定义了一下运行规则,信息显示格式以及几个 linter 的运行参数,其中 6,7 两行比较重要,它规定了如果 normal 模式下文字改变以及离开 insert 模式的时候运行 linter,这是相对保守的做法,如果没有的话,会导致 YouCompleteMe 的补全对话框频繁刷新。&/p&&p&记得设置一下各个 linter 的参数,忽略一些你觉得没问题的规则,不然错误太多没法看。默认错误和警告的风格都太难看了,你需要修改一下,比如我使用 GVim,就重新定义了警告和错误的样式,去除默认难看的红色背景,代码正文使用干净的波浪下划线表示:&/p&&div class=&highlight&&&pre&&code class=&language-vim&&&span class=&k&&let&/span& &span class=&k&&g&/span&:ale_sign_error &span class=&p&&=&/span& &span class=&s2&&&\ue009\ue009&&/span&
&span class=&k&&hi&/span&&span class=&p&&!&/span& clear SpellBad
&span class=&k&&hi&/span&&span class=&p&&!&/span& clear SpellCap
&span class=&k&&hi&/span&&span class=&p&&!&/span& clear SpellRare
&span class=&k&&hi&/span&&span class=&p&&!&/span& SpellBad &span class=&k&&gui&/span&&span class=&p&&=&/span&undercurl guisp&span class=&p&&=&/span&&span class=&k&&red&/span&
&span class=&k&&hi&/span&&span class=&p&&!&/span& SpellCap &span class=&k&&gui&/span&&span class=&p&&=&/span&undercurl guisp&span class=&p&&=&/span&blue
&span class=&k&&hi&/span&&span class=&p&&!&/span& SpellRare &span class=&k&&gui&/span&&span class=&p&&=&/span&undercurl guisp&span class=&p&&=&/span&magenta
&/code&&/pre&&/div&&p&不同项目之间如果评测标准不一样还可以具体单独制定 linter 的参数,具体见 ALE 帮助文档了。我基本使用两个检查器:gcc 和 cppcheck,都可以在 ALE 中进行详细配置,前者主要检查有无语法错误,后者主要会给出一些编码建议,和对危险写法的警告。&/p&&p&我之前用 syntastic 时就用了两天就彻底删除了,而开始用 ALE 后,一用上就停不下来,头两天我还一度觉得它就是个可有可无的点缀,但是第三天它帮我找出两个潜在的 bug 的时候,我开始觉得没白安装,比如:&/p&&figure&&img src=&https://pic1.zhimg.com/50/v2-479ed8beda07d042dead7a_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&718& data-rawheight=&473& data-default-watermark-src=&https://pic3.zhimg.com/50/v2-ea259f40f7e4b_b.jpg& class=&origin_image zh-lightbox-thumb& width=&718& data-original=&https://pic1.zhimg.com/50/v2-479ed8beda07d042dead7a_r.jpg&&&/figure&&p&即便你使用各类 C/C++ IDE,也只能给实时你标注一些编译错误或者警告,而使用 ALE + cppcheck/gcc,连上面类似的潜在错误都能帮你自动找出来,并且当你光标移动过去时在最下面命令行提示你错误原因。&/p&&p&用上一段时间以后,让你写 C/C++ 有一种安心和舒适的感觉。&/p&&p&&br&&/p&&p&&b&修改比较&/b&&/p&&p&这是个小功能,在侧边栏显示一个修改状态,对比当前文本和 git/svn 仓库里的版本,在侧边栏显示修改情况,以前 Vim 做不到实时显示修改状态,如今推荐使用 &a href=&//link.zhihu.com/?target=https%3A//github.com/mhinz/vim-signify& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&vim-signify&/a& 来实时显示修改状态,它比 gitgutter 强,除了 git 外还支持 svn/mercurial/cvs 等十多种主流版本管理系统。&/p&&p&没注意到它时,你可能觉得它不存在,当你有时真的看上两眼时,你会发现这个功能很贴心。最新版 signify 还有一个命令`:SignifyDiff`,可以左右分屏对比提交前后记录,比你命令行 svn/git diff 半天直观多了。并且对我这种同时工作在 subversion 和 git 环境下的情况契合的比较好。&/p&&p&Signify 和前面的 ALE 都会在侧边栏显示一些标记,默认侧边栏会自动隐藏,有内容才会显示,不喜欢侧边栏时有时无的行为可设置强制显示侧边栏:“set signcolumn=yes” 。&/p&&p&&br&&/p&&p&&b&文本对象&/b&&/p&&p&相信大家用 Vim 进行编辑时都很喜欢文本对象这个概念,diw 删除光标所在单词,ciw 改写单词,vip 选中段落等,ci&/ci( 改写引号/括号中的内容。而编写 C/C++ 代码时我推荐大家补充几个十分有用的文本对象,可以使用 textobj-user 全家桶:&/p&&div class=&highlight&&&pre&&code class=&language-vim&&Plug &span class=&s1&&'kana/vim-textobj-user'&/span&
Plug &span class=&s1&&'kana/vim-textobj-indent'&/span&
Plug &span class=&s1&&'kana/vim-textobj-syntax'&/span&
Plug &span class=&s1&&'kana/vim-textobj-function'&/span&&span class=&p&&,&/span& { &span class=&s1&&'for'&/span&:[&span class=&s1&&'c'&/span&&span class=&p&&,&/span& &span class=&s1&&'cpp'&/span&&span class=&p&&,&/span& &span class=&s1&&'vim'&/span&&span class=&p&&,&/span& &span class=&s1&&'java'&/span&] }
Plug &span class=&s1&&'sgur/vim-textobj-parameter'&/span&
&/code&&/pre&&/div&&p&它新定义的文本对象主要有:&/p&&ul&&li&i, 和 a, :参数对象,写代码一半在修改,现在可以用 di, 或 ci, 一次性删除/改写当前参数&/li&&li&ii 和 ai :缩进对象,同一个缩进层次的代码,可以用 vii 选中,dii / cii 删除或改写&/li&&li&if 和 af :函数对象,可以用 vif / dif / cif 来选中/删除/改写函数的内容&/li&&/ul&&p&最开始我不太想用额外的文本对象,一直在坚持 Vim 固有的几个默认对象,生怕手练习惯了肌肉形成记忆到远端没有环境的 vim 下形成依赖改不过来,后来我慢慢发现挺有用的,比如改写参数,以前是比较麻烦的事情,这下流畅了很多,当我发现自己编码效率得到比较大的提升时,才发现习惯依赖不重要,行云流水才是真重要。以前看到过无数次都选择性忽略的东西,有时候试试可能会有新的发现。&/p&&p&&br&&/p&&p&&b&编辑辅助&/b&&/p&&p&大家都知道 color 文件定义了众多不同语法元素的色彩,还有一个关键因素就是语法文件本身能否识别并标记得出众多不同的内容来?语法文件对某些东西没标注,你 color 文件确定了颜色也没用。因此 Vim 下面写 C/C++ 代码,语法高亮准确丰富的话能让你编码的心情好很多,这里推荐 &a href=&//link.zhihu.com/?target=https%3A//github.com/octol/vim-cpp-enhanced-highlight& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&vim-cpp-enhanced-highlight&/a& 插件,提供比 Vim 自带语法文件更好的 C/C++ 语法标注,支持 标准 11/14/17。&/p&&p&前面编译运行时需要频繁的操作 quickfix 窗口,ale查错时也需要快速再错误间跳转(location list),就连文件比较也会用到快速跳转到上/下一个差异处,&a href=&//link.zhihu.com/?target=https%3A//github.com/tpope/vim-unimpaired& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&unimpaired&/a& 插件帮你定义了一系列方括号开头的快捷键,被称为官方 Vim 中丢失的快捷键。&/p&&p&我们好些地方用到了 quickfix / location 窗口,你在 quickfix 中回车选中一条错误的话,默认会把你当前窗口给切走,变成新文件,虽然按 CTRL+O 可以返回,但是如果不太喜欢这样切走当前文件的做法,可以设置 switchbuf,发现文件已在 Vim 中打开就跳过去,没打开过就新建窗口/标签打开,具体见帮助。&/p&&p&Vim最爽的地方是把所有 ALT 键映射全部留给用户了,尽量使用 Vim 的 ALT键映射,可以让冗长的快捷键缩短很多,请参考:《&a href=&//link.zhihu.com/?target=http%3A//www.skywind.me/blog/archives/2021& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Vim和终端软件中支持ALT映射&/a&》。&/p&&p&&br&&/p&&p&&b&代码补全&/b&&/p&&p&传统的 Vim 代码补全基本以 omni 系列补全和符号补全为主,omni 补全系统是 Vim 自带的针对不同文件类型编写不同的补全函数的基础语义补全系统,搭配 neocomplete 可以很方便的对所有补全结果(omni补全/符号补全/字典补全)进行一个合成并且自动弹出补全框,虽然赶不上 IDE 的补全,但是已经比大部分编辑器补全好用很多了。然而传统 Vim 补全还是有两个迈不过去的坎:语义补全太弱,其次是补全分析无法再后台运行,对大项目而言,某些复杂符号的补全会拖慢你的打字速度。&/p&&p&新一代的 Vim 补全系统,&a href=&//link.zhihu.com/?target=https%3A//github.com/Valloric/YouCompleteMe& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&YouCompleteMe&/a& 和 &a href=&//link.zhihu.com/?target=https%3A//github.com/Shougo/deoplete.nvim& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Deoplete&/a&,都支持异步补全和基于 clang 的语义补全,前者集成度高,后者扩展方便。对于 C/C++ 的话,我推荐 YCM,因为 deoplete 的 clang 补全插件不够稳定,太吃内存,并且反应比较慢,它的代码量和代码质量和 YCM完全不是一个量级的。所以 C/C++ 的补全的话,请直接使用 YCM,没有之一,而使用 YCM的话,需要进行一些简单的调教:&/p&&div class=&highlight&&&pre&&code class=&language-vim&&&span class=&k&&let&/span& &span class=&k&&g&/span&:ycm_add_preview_to_completeopt &span class=&p&&=&/span& &span class=&m&&0&/span&
&span class=&k&&let&/span& &span class=&k&&g&/span&:ycm_show_diagnostics_ui &span class=&p&&=&/span& &span class=&m&&0&/span&
&span class=&k&&let&/span& &span class=&k&&g&/span&:ycm_server_log_level &span class=&p&&=&/span& &span class=&s1&&'info'&/span&
&span class=&k&&let&/span& &span class=&k&&g&/span&:ycm_min_num_identifier_candidate_chars &span class=&p&&=&/span& &span class=&m&&2&/span&
&span class=&k&&let&/span& &span class=&k&&g&/span&:ycm_collect_identifiers_from_comments_and_strings &span class=&p&&=&/span& &span class=&m&&1&/span&
&span class=&k&&let&/span& &span class=&k&&g&/span&:ycm_complete_in_strings&span class=&p&&=&/span&&span class=&m&&1&/span&
&span class=&k&&let&/span& &span class=&k&&g&/span&:ycm_key_invoke_completion &span class=&p&&=&/span& &span class=&s1&&'&c-z&'&/span&
&span class=&k&&set&/span& &span class=&nb&&completeopt&/span&&span class=&p&&=&/span&menu&span class=&p&&,&/span&menuone
&span class=&nb&&noremap&/span& &span class=&p&&&&/span&&span class=&k&&c&/span&&span class=&p&&-&/span&z&span class=&p&&&&/span& &span class=&p&&&&/span&NOP&span class=&p&&&&/span&
&span class=&k&&let&/span& &span class=&k&&g&/span&:ycm_semantic_triggers &span class=&p&&=&/span&
\ &span class=&s1&&'c,cpp,python,java,go,erlang,perl'&/span&: [&span class=&s1&&'re!\w{2}'&/span&]&span class=&p&&,&/span&
\ &span class=&s1&&'cs,lua,javascript'&/span&: [&span class=&s1&&'re!\w{2}'&/span&]&span class=&p&&,&/span&
&/code&&/pre&&/div&&p&这样可以输入两个字符就自动弹出语义补全,不用等到输入句号 . 或者 -& 才触发,同时关闭了预览窗口和代码诊断这些 YCM 花边功能,保持清静,对于原型预览和诊断我们后面有更好的解决方法,YCM这两项功能干扰太大。&/p&&p&上面这几行配置具体每行的含义,可以见:《&a href=&https://zhuanlan.zhihu.com/p/& class=&internal&&YouCompleteMe 中容易忽略的配置&/a&》。另外我在 Windows 下编译了一个版本,你用 Windows 的话无需下载VS编译,点击 [&a href=&https://www.zhihu.com/question//answer/& class=&internal&&这里&/a&]。我日常开发使用 YCM 辅助编写 C/C++, Python 和 Go 代码,基本能提供 IDE 级别的补全。&/p&&p&&br&&/p&&p&&b&函数列表&/b&&/p&&p&不再建议使用 &a href=&//link.zhihu.com/?target=https%3A//github.com/majutsushi/tagbar& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&tagbar&/a&, 它会在你保存文件的时候以同步等待的方式运行 ctags (即便你没有打开 tagbar),导致vim操作变卡,特别是 windows下开了反病毒软件扫描的话,有时候保存文件卡5-6秒。2018年了,我们有更好的选择,比如使用 &a class=&member_mention& href=&//www.zhihu.com/people/d9bf12c9f42ee30f8aa9242cece83053& data-hash=&d9bf12c9f42ee30f8aa9242cece83053& data-hovercard=&p$b$d9bf12c9f42ee30f8aa9242cece83053&&@Yggdroot&/a& 开发的 &a href=&//link.zhihu.com/?target=https%3A//github.com/Yggdroot/LeaderF& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&LeaderF&/a& 来显示函数列表:&/p&&figure&&img src=&https://pic3.zhimg.com/50/v2-98b21c2d3eeffd3c_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&1034& data-rawheight=&664& class=&origin_image zh-lightbox-thumb& width=&1034& data-original=&https://pic3.zhimg.com/50/v2-98b21c2d3eeffd3c_r.jpg&&&/figure&&p&全异步显示文件函数列表,不用的时候不会占用你任何屏幕空间,将 ALT+P 绑定到 `:LeaderfFunction!` 这个命令上,按 ALT+P 就弹出当前文件的函数列表,然后可以进行模糊匹配搜索,除了上下键移动选择外,各种vim的跳转和搜索命令都可以始用,回车跳转然后关闭函数列表,除此之外按 i 进入模糊匹配,按TAB切换回列表选择。&/p&&p&Leaderf 的函数功能属于你想要它的时候它才会出来,不想要它的时候不会给你捣乱。&/p&&p&&br&&/p&&p&&b&文件切换&/b&&/p&&p&文件/buffer模糊匹配快速切换的方式,比你打开一个对话框选择文件便捷不少,过去我们常用的 CtrlP 可以光荣下岗了,如今有更多速度更快,匹配更精准以及完美支持后台运行方式的文件模糊匹配工具。我自己用的是上面提到的 &a href=&//link.zhihu.com/?target=https%3A//github.com/Yggdroot/LeaderF& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&LeaderF&/a&,除了提供函数列表外,还支持文件,MRU,Buffer名称搜索,完美代替 CtrlP,使用时需要简单调教下:&/p&&div class=&highlight&&&pre&&code class=&language-vim&&&span class=&k&&let&/span& &span class=&k&&g&/span&:Lf_ShortcutF &span class=&p&&=&/span& &span class=&s1&&'&c-p&'&/span&
&span class=&k&&let&/span& &span class=&k&&g&/span&:Lf_ShortcutB &span class=&p&&=&/span& &span class=&s1&&'&m-n&'&/span&
&span class=&nb&&noremap&/span& &span class=&p&&&&/span&&span class=&k&&c&/span&&span class=&p&&-&/span&&span class=&k&&n&/span&&span class=&p&&&&/span& :LeaderfMru&span class=&p&&&&/span&&span class=&k&&cr&/span&&span class=&p&&&&/span&
&span class=&nb&&noremap&/span& &span class=&p&&&&/span&&span class=&k&&m&/span&&span class=&p&&-&/span&&span class=&k&&p&/span&&span class=&p&&&&/span& :LeaderfFunction&span class=&p&&!&&/span&&span class=&k&&cr&/span&&span class=&p&&&&/span&
&span class=&nb&&noremap&/span& &span class=&p&&&&/span&&span class=&k&&m&/span&&span class=&p&&-&/span&&span class=&k&&n&/span&&span class=&p&&&&/span& :LeaderfBuffer&span class=&p&&&&/span&&span class=&k&&cr&/span&&span class=&p&&&&/span&
&span class=&nb&&noremap&/span& &span class=&p&&&&/span&&span class=&k&&m&/span&&span class=&p&&-&/span&&span class=&k&&m&/span&&span class=&p&&&&/span& :LeaderfTag&span class=&p&&&&/span&&span class=&k&&cr&/span&&span class=&p&&&&/span&
&span class=&k&&let&/span& &span class=&k&&g&/span&:Lf_StlSeparator &span class=&p&&=&/span& { &span class=&s1&&'left'&/span&: &span class=&s1&&''&/span&&span class=&p&&,&/span& &span class=&s1&&'right'&/span&: &span class=&s1&&''&/span&&span class=&p&&,&/span& &span class=&s1&&'font'&/span&: &span class=&s1&&''&/span& }
&span class=&k&&let&/span& &span class=&k&&g&/span&:Lf_RootMarkers &span class=&p&&=&/span& [&span class=&s1&&'.project'&/span&&span class=&p&&,&/span& &span class=&s1&&'.root'&/span&&span class=&p&&,&/span& &span class=&s1&&'.svn'&/span&&span class=&p&&,&/span& &span class=&s1&&'.git'&/span&]
&span class=&k&&let&/span& &span class=&k&&g&/span&:Lf_WorkingDirectoryMode &span class=&p&&=&/span& &span class=&s1&&'Ac'&/span&
&span class=&k&&let&/span& &span class=&k&&g&/span&:Lf_WindowHeight &span class=&p&&=&/span& &span class=&m&&0&/span&.&span class=&m&&30&/span&
&span class=&k&&let&/span& &span class=&k&&g&/span&:Lf_CacheDirectory &span class=&p&&=&/span& expand&span class=&p&&(&/span&&span class=&s1&&'~/.vim/cache'&/span&&span class=&p&&)&/span&
&span class=&k&&let&/span& &span class=&k&&g&/span&:Lf_ShowRelativePath &span class=&p&&=&/span& &span class=&m&&0&/span&
&span class=&k&&let&/span& &span class=&k&&g&/span&:Lf_HideHelp &span class=&p&&=&/span& &span class=&m&&1&/span&
&span class=&k&&let&/span& &span class=&k&&g&/span&:Lf_StlColorscheme &span class=&p&&=&/span& &span class=&s1&&'powerline'&/span&
&span class=&k&&let&/span& &span class=&k&&g&/span&:Lf_PreviewResult &span class=&p&&=&/span& {&span class=&s1&&'Function'&/span&:&span class=&m&&0&/span&&span class=&p&&,&/span& &span class=&s1&&'BufTag'&/span&:&span class=&m&&0&/span&}
&/code&&/pre&&/div&&p&这里定义了 CTRL+P 在当前项目目录打开文件搜索,CTRL+N 打开 MRU搜索,搜索你最近打开的文件,这两项是我用的最频繁的功能。接着 ALT+P 打开函数搜索,ALT+N 打开 Buffer 搜索:&/p&&figure&&img src=&https://pic1.zhimg.com/50/v2-f47e003ab026a7de6dffded_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&1006& data-rawheight=&625& class=&origin_image zh-lightbox-thumb& width=&1006& data-original=&https://pic1.zhimg.com/50/v2-f47e003ab026a7de6dffded_r.jpg&&&/figure&&p&LeaderF 是目前匹配效率最高的,高过 CtrlP/Fzf 不少,敲更少的字母就能把文件找出来,同时搜索很迅速,使用 Python 后台线程进行搜索匹配,还有一个 C模块可以加速匹配性能,需要手工编译下。LeaderF在模糊匹配模式下按 TAB 可以切换到匹配结果窗口用光标或者 Vim 搜索命令进一步筛选,这是 CtrlP/Fzf 不具备的,更多方便的功能见它的官方文档。&/p&&p&文件/MRU 模糊匹配对于熟悉的项目效率是最高的,但对于一个新的项目,通常我们都不知道它有些什么文件,那就谈不上根据文件名匹配什么了,我们需要文件浏览功能。如果你喜欢把 Vim 伪装成 NotePad++ 之类的,那你该继续使用 &a href=&//link.zhihu.com/?target=https%3A//github.com/scrooloose/nerdtree& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&NERDTree&/a& 进行文件浏览,但你想按照 Vim 的方式来,推荐阅读这篇文章:&/p&&p&&a href=&//link.zhihu.com/?target=http%3A//vimcasts.org/blog/2013/01/oil-and-vinegar-split-windows-and-project-drawer/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Oil and vinegar - split windows and project drawer&/a&&/p&&p&然后像我一样开始使用 &a href=&//link.zhihu.com/?target=https%3A//github.com/justinmk/vim-dirvish& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&vim-dirvish&/a&,进行一些配置,比如当前文档按“-”号就能不切窗口的情况下在当前窗口直接返回当前文档所在的目录,再按一次减号就返回上一级目录,按回车进入下一级目录或者再当前窗口打开光标下的文件。进一步映射 “&tab&7” , “&tab&8” 和 “&tab&9” 分别用于在新的 split, vsplit 和新标签打开当前文件所在目录,这样从一个文件如手,很容易找到和该文件相关的其他项目文件。&/p&&p&最后一个是 C/C++ 的头文件/源文件快速切换功能,有现成的插件做这事情,比如 &a href=&//link.zhihu.com/?target=https%3A//github.com/vim-scripts/a.vim& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&a.vim&/a&,我自己没用,因为这事情太简单,再我发现 a.vim 前我就觉得需要这个功能,然后自己两行 vim 脚本就搞定了。&/p&&p&&br&&/p&&p&&b&参数提示&/b&&/p&&p&这个功能应人而异,有人觉得不需要,有人觉得管用。写 C/C++ 时函数忘了可以用上面的 YCM 补全,但很多时候是参数忘记了怎么办?YCM的参数提示很蛋疼,要打开个 Preview 窗口,实在是太影响我的视线了,我自己写过一些参数提醒功能,可以在最下面的命令行显示当前函数的参数,不过这是基于 tags 的,搭配前面的 gutentags,对其他语言很管用,但对 C/C++ 我们还可以使用更好的 &a href=&//link.zhihu.com/?target=https%3A//github.com/Shougo/echodoc.vim& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&echodoc&/a& 插件:&/p&&figure&&img src=&https://pic4.zhimg.com/50/v2-18ba5ec85e3762_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&619& data-rawheight=&109& class=&origin_image zh-lightbox-thumb& width=&619& data-original=&https://pic4.zhimg.com/50/v2-18ba5ec85e3762_r.jpg&&&/figure&&p&它可以无缝的和前面的 YCM 搭配,用 libclang 给你生成参数提示,当你用 YCM 的 tab 补全了一个函数名后,只要输入左括号,下面命令行就会里面显示出该函数的参数信息,随着光标移动,下面还会高亮出来你正在处于哪个参数位置。&/p&&p&唯一需要设置的是使用 “set noshowmode”关闭模式提示,就是底部 ---INSERT--- 那个,我们一般都用 airline / lightline 之类的显示当前模式了,所以默认模式提示可以关闭,INSERT 模式下的命令行,完全留给 echodoc 显示参数使用。&/p&&p&&br&&/p&&p&-------------&/p&&p&2018年了,用点新方法,网上那些 Vim 开发 C/C++ 的文章真的都可以淘汰了。&/p&&p&更多参考:《&a href=&//link.zhihu.com/?target=https%3A//github.com/wsdjeg/vim-galore-zh_cn& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Vim 中文版入门到精通&/a&》和《&a href=&//link.zhihu.com/?target=https%3A//github.com/skywind3000/awesome-cheatsheets/blob/master/editors/vim.txt& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Vim 中文速查表&/a&》&/p&&p&本文主要是针对 C/C++ 环境搭建的插件介绍,关于基本使用,欢迎参考上面这些链接。篇幅有限,这里只能谈一部分内容,对大多数人已经够了,如果你想继续深入的话,还能继续折腾诸如 git 集成,调试,gtags 和 lsp 这些,可关注 &a href=&https://zhuanlan.zhihu.com/vimrc& class=&internal&&Vim专栏&/a&。&/p&
2018年了,不要再看网上那些老旧的文章还在教你使用手工生成 tags 的,请使用自动代码索引生成工具,比如 ,现在网上好像就没有一篇能正确讨论 Vim C/C++ 环境搭建的,都在谈些十年前的东西,所以我写了篇关于 Vim 8 和 C/C++ 相关插件的介绍…
&figure&&img src=&https://pic3.zhimg.com/v2-bb3b7e3a812dc8690becdc1e_b.jpg& data-rawwidth=&761& data-rawheight=&485& class=&origin_image zh-lightbox-thumb& width=&761& data-original=&https://pic3.zhimg.com/v2-bb3b7e3a812dc8690becdc1e_r.jpg&&&/figure&&p&&/p&&figure&&img src=&https://pic3.zhimg.com/v2-f8df8a14d403c778f9f7c4c863ecf393_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&1080& data-rawheight=&608& class=&origin_image zh-lightbox-thumb& width=&1080& data-original=&https://pic3.zhimg.com/v2-f8df8a14d403c778f9f7c4c863ecf393_r.jpg&&&/figure&&p&本文由 「AI前线」原创,原文链接:&a href=&https://link.zhihu.com/?target=http%3A//t.cn/REFfp31& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&JeffDean又用深度学习搞事情:这次要颠覆整个计算机系统结构设计&/a&&/p&&blockquote&策划编辑 | Natalie&br&作者 | Milad Hashemi 等&br&编译 | Rays&br&编辑 | Emily&/blockquote&&p&&b&AI 前线导读:&/b&上个月,Jeff Dean、Michael I.Jordan、李飞飞、LeCun 等大牛发起的系统机器学习会议 SysML 2018 在斯坦福闭幕。这是一个专门针对系统和机器学习交叉研究领域的会议,目的是弥补当前关于 AI/ML 的讨论大多偏向算法和应用而关于底层的基础设施却少有讨论造成的缺口。&/p&&p&在会议主题演讲中,Jeff Dean提到了去年谷歌发布的研究论文《用 ML 模型替代数据库索引结构》(The Case for Learned Index Structures,去年在技术圈引起轰动,&b&&a href=&https://link.zhihu.com/?target=https%3A//mp.weixin.qq.com/s%3F__biz%3DMzU1NDA4NjU2MA%3D%3D%26mid%3D%26idx%3D1%26sn%3D5ee1e2d7352aae9b4ab65105d8fce455%26chksm%3Dfbe9b707cc9e3ec7b14c93d175bf8d334cc5a0a0a565dd1f91019%26scene%3D21%23wechat_redirect& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&详见 AI 前线首发报道&/a&&/b&),其关键点就是用计算换内存。未来基于摩尔定律的 CPU 在本质上将不复存在,利用神经网络取代分支重索引结构,数据库就可以从硬件发展趋势中受益。Jeff Dean 认为,这代表了一个非常有前景且十分有趣的方向:&b&传统系统开发中,使用 ML 的视角,就能发现很多新的应用。&/b&除了数据库,ML 还能使用在系统的哪些方面?Jeff Dean 表示,一个很大的机会是启发式方法,计算机系统里大量应用启发式方法,因此,ML 在用到启发式方法的地方都有机会带来改变。&/p&&p&今天 AI 前线为大家带来的是《用 ML 模型替代数据库索引结构》研究的续篇,这一次谷歌研究人员尝试用深度学习解决冯·诺依曼结构内存性能瓶颈,并取得了一定成果。Jeff Dean 在推特评论表示,未来在计算机系统的众多领域,类似研究工作将不断增多。&/p&&p&&b&该论文是将神经网络应用于计算机结构设计中的一项开创性工作。&/b&如何将机器学习应用于计算机硬件结构领域,目前依然鲜有研究。这篇论文展示了深度学习在解决冯·诺依曼架构计算机内存性能瓶颈问题中的应用。论文关注的是学习内存访问模式这一关键问题,意在构建一种准确高效的内存预期器。研究提出将预期策略视为 NLP 中的 n-gram 模型,并使用 RNN 模型完全替代基于表的传统预取。在基准测试集上的实验表明,基于神经网络的模型在预测内存访问模式上可稳定地给出更优的准确率和召回率。&/p&&p&&b&更多干货内容请关注微信公众号“AI 前线”,(ID:ai-front)&/b&&/p&&p&&br&&/p&&figure&&img src=&https://pic3.zhimg.com/v2-1eb92f0d64eb3f26d282fd960b8e17bf_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&800& data-rawheight=&390& class=&origin_image zh-lightbox-thumb& width=&800& data-original=&https://pic3.zhimg.com/v2-1eb92f0d64eb3f26d282fd960b8e17bf_r.jpg&&&/figure&&p&&br&&/p&&p&&br&&/p&&figure&&img src=&https://pic2.zhimg.com/v2-efeddf91b2251_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&800& data-rawheight=&689& class=&origin_image zh-lightbox-thumb& width=&800& data-original=&https://pic2.zhimg.com/v2-efeddf91b2251_r.jpg&&&/figure&&p&&br&&/p&&p&以下内容为AI前线根据论文编译整理而成:&/p&&p&在计算机结构的设计中,很多问题涉及使用预测和启发式规则,内存预取就是其中的一个经典问题。内存预取将指令和数据在被微处理器实际使用前,预先置于存取速度更快的内存中。因为在冯·诺伊曼结构计算机中,微处理器的运算速度要比内存访问速度高出数个数量级,因此内存预取是一个关键的瓶颈问题,也被称为“内存墙”(Memory Wall)。有统计表明,计算机中 50% 的计算周期是在等待数据加载到内存中。为解决内存墙的问题,微处理器使用了层次结构的内存,即在结构上采用多级缓存设计,让规模更小但是访问速度更快的缓存更接近于处理器。为降低内存读取的延迟,需要预测何时以及哪些数据应预取到缓存中。因此,提高性能的一个关键问题,是如何给出有效的内存访问模式预测。&/p&&p&在现代处理器中,使用了一些预测方法。很多预测器是基于记录表实现的。记录表是一种内存数组结构,记录了未来事件与以往历史信息的关联性。但是相比起传统的单机工作负载,现代数据中心的工作负载规模呈现指数级的增长,这对内存访问模式预测提出了严峻挑战。预测的准确性会随预测表规模的增大而显著下降。简单地扩展预测表的规模,需在硬件实现上付出很大的代价。&/p&&p&神经网络技术已在 NLP 和文本理解取得了很好的效果,它为解决序列预测问题提供了一种强大的技术。例如,在 SPARC T4 处理器中,已经部署了一种简单的感知机,实现对分支处理指令的预测。但是,对于微处理器架构设计而言,如何有效地引入序列学习算法依然是一个开放的问题。&/p&&p&本文的研究考虑在微处理架构中引入基于序列的神经网络模型,意在解决内存墙所提出挑战,将序列学习应用到内存预取这一难题上。内存预取问题,在本质上可以看成是一种回归问题。但是该问题的输出空间很大,并且非常稀疏,使用标准的回归模型难以给出好的效果。本文作者们考虑使用一些图像和语言生成上的最新研究成果,例如 PixelRNN 和 Wavenet。这些研究成果对搜索空间做离散化,使得内存预取模型更近似于神经语言模型,并依此作为构建神经网络内存预取器的出发点。本文研究所提出的神经网络模型,可以成功地建模问题的输出空间,实现一种神经网络内存预取,并给出了显著优于现有传统硬件预取器的性能。此外,论文中使用的 RNN 可以根据应用的内存访问轨迹辨别应用的底层语义信息,给出的结果更具可解释性。&/p&&h2&&b&背景知识&/b&&/h2&&p&&b&内存预取器(Prefetcher)&/b&&/p&&p&内存预取器是一种计算机硬件结构,它使用历史内存访问记录预测将来的内存访问模式。现有的内存预取器大体上可分为两类。一类称为“步长预取器”(stride prefetcher),另一类称为“关联预取器”(correlation prefetcher)。现代处理器中通常使用的是步长预取器,序列中固定采用稳定的、可重复的地址差值(即序列中相邻两个内存地址间的差值)。例如,给定一个内存访问模式(0,4,8,12),每次访问的地址差值为 4,那么预取器可以由此预测此后的地址访问模式为(16,20,24)。&/p&&p&关联预取器可预测地址差值不固定的重复模式。它使用了一个大的记录表,保持过往的内存访问历史信息。相比于步长预取器,关联预取器可以更好地预测非规则变化的模式。典型的管理预取器包括 Markov 预取器、GHB 预取器,以及一些使用大规模内存中结构的最新研究预取器。关联预取器需要具备一张大规模的记录表,该表的实现代价大,因此通常并未实现在多核处理器中。&/p&&p&&b&递归神经网络(RNN)&/b&&/p&&p&深度学习适用于很多的序列预测问题,例如语言识别和自然语言处理。其中,RNN 可对长距离依赖建模。LSTM 作为一种广为使用的 RNN 变体,通过以加法方式而非乘法方式传播内部状态,解决了标准 RNN 的训练问题。LSTM 由隐含状态、元胞状态、输入门、输出门和记忆门组成,分别表示了需要存储的信息,以及在下一个时间步(timestep)中传播的信息。给定时间步和输入,LSTN 的状态可以使用如下过程计算:&/p&&ol&&li&计算输入门、输出门和记忆门&/li&&li&更新胞元状态&/li&&li&计算 LSTM 隐含状态(输出)&/li&&/ol&&p&其中,表示当前的输入和前一个隐含状态的级联(concatenation),表示点乘操作(element-wise multiplication),是 Sigmoid 非线性函数。上面给出的过程表示了单个 LSTM 层的处理形式,是该层的权重,是偏差。LSTM 层可以进行堆叠,在时间步 N 的 LSTM 层的输出,可以作为另一个 LSTM 层的输入,这类似于前向回馈神经网络中的多层结构。这使得模型在使用相对较少额外参数的情况下,增大了灵活性。&/p&&h2&问题定义&/h2&&p&&b&将预取作为预测问题&/b&&/p&&p&预取可以看成是对未来内存访问模式的预测过程。如果数据并不在缓存中(即缓存未命中),预期器需要根据历史访问情况,到主存中去获取数据。每条内存地址由内存操作指令(load/store)生成。内存操作指令是计算机指令集中的一个子集,实现对计算机系统中具有地址内存的操作。&/p&&p&很多硬件厂商建议在做出预期决策时使用两个特征。一个是截至目前缓存未命中的地址序列,另一个是指令地址序列,也称为程序计数器(Program counter,PC),即关联到生成每条缓存未命中地址的指令。&/p&&p&每条 PC 可以唯一标识一条指令,指令是对给定代码文件中的特定函数编译生成的。PC 序列可告知模型应用代码的控制流模式,而缓存未命中地址序列可告知模型需要下一步预期的地址情况。在现代计算机系统中,上述特性均使用 64 位整数表示。&/p&&p&初始模型可以在每个时间步使用两个输入特征,即在步生成的缓存未命中地址,以及由 PC 预测的 N+1 步缓存未命中情况。但是其中存在一个问题,应用的地址空间是非常稀疏的。对于此问题的训练数据而言,缓存未命中的空间复杂度为量级,其中只有的缓存未命中地址出现在的物理地址空间中。图 1 显示了使用标准 SPEC CPU2006 基准测试集 omnetpp 时的缓存情况,红色点表示了缓存未命中地址。这一空间范围宽泛,具有重度多模态本质,这对传统的时序回归模型提出了挑战。例如,虽然神经网络非常适用于正则化输入,但是对这样的数据做正则化时,有限精度的浮点数表示将导致显著的信息丢失。该问题影响了对输入层和输出层的建模。在本文中,作者对此给出了解决方法。&/p&&figure&&img src=&https://pic1.zhimg.com/v2-4d4a26e9aba5b9a6731e05_b.jpg& data-size=&normal& data-rawwidth=&800& data-rawheight=&421& class=&origin_image zh-lightbox-thumb& width=&800& data-original=&https://pic1.zhimg.com/v2-4d4a26e9aba5b9a6731e05_r.jpg&&&figcaption&图 1 数据集 omnetpp 上的缓存未命中情况。图中多尺度地展示了稀疏访问模式。&/figcaption&&/figure&&p&&b&将预取作为分类问题&/b&&/p&&p&在本文作者提出的解决方法中,考虑将整个地址空间视为一个离散的大规模词汇表,并对词汇表执行分类操作。这类似于 NLP 中对随后出现的字符或单词的预测问题。但是,该空间是极度稀疏的,并且其中部分地址比其它地址更频繁地访问。对于 RNN 模型,是可以管理这样规模的有效词汇表的。此外,相比于单模态回归技术,通过生成多模态输出,模型处理可以变得更加灵活。在图像处理和语音生成领域中,已有一些研究成功地将输出输出作为预测问题而非回归问题。&/p&&p&但是,预期问题存在着种可能的 softmax 目标,因此需要给出一种量化(quantization)模式。更重要的是,预取必须完全准确才能发挥作用。对于通常的 64 个字节情况应该如此,对于通常是 4096 个字节的页面也应如此。在页面层级上的预测,将会给出中可能的目标。为避免对超过个值应用 softmax,一些研究提出应用非线性量化模式将空间降维到 256 类。但是这些解决方法这并不适用于本文中的问题。因为这些方法降低了地址的分辨率,使得预取无法获得所需的高精度。&/p&&p&由于动态边界效应,例如地址空间布局随机化(ASLR)问题,同一程序的多轮运行可能会访问不同的原始地址。但是,同一程序对于一个给定的布局将给出一致的行为。由此,一种可行的策略是预测地址差值,而非直接预测地址本身。如表 1 所示,地址差值的可能出现情况,要比地址的可能出现情况呈空间指数级别降低。&/p&&p&表 1 程序追踪数据集统计情况,“M”表示“百万”&/p&&p&&br&&/p&&figure&&img src=&https://pic4.zhimg.com/v2-42a918eb8b7e352c460ea9_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&800& data-rawheight=&313& class=&origin_image zh-lightbox-thumb& width=&800& data-original=&https://pic4.zhimg.com/v2-42a918eb8b7e352c460ea9_r.jpg&&&/figure&&p&&br&&/p&&h2&模型描述&/h2&&p&论文给出了两种基于 LSTM 的预取模型。第一种模型称为“嵌入 LSTM”模型,它类似于标准的语言模型。第二种模型利用内存访问空间的结构去降低词汇表的规模,降低了模型占用的内存量。&/p&&p&&b&嵌入 LSTM 模型&/b&&/p&&p&该模型限制输出词汇表的规模,仅建模最频繁出现的地址间隔。根据表 1,要获得最优 50% 的准确性,所需的词汇表规模仅为量级乃至更小。这样规模的词汇表完全处于标准语言模型可解决的能力范围内。基于此,论文提出的第一种模型对输出词汇表规模做了限制,选用了其中 50000 个最频繁出现的唯一地址差值。对于输入词汇表,模型考虑在词汇表中出现了至少 10 次的所有地址差值。要进一步扩展词汇表,无论在统计学还是计数上都是有挑战的。这些挑战可以采用层次 softmax 类方法解决,有待进一步研究。&/p&&p&嵌入 LSTM 的结构如图 2 所示。模型将输入和输出地址差值以分类表示(即独热编码)。在时间步,分别嵌入输入和,并将嵌入词汇级联起来,构成两层 LSTM 的输入。进而,LSTM 对地址差值词汇做分类,并且选取个最高概率地址差值,用于预取。分类方法可直接给出预测概率,这对传统硬件是另一个优点。&/p&&figure&&img src=&https://pic2.zhimg.com/v2-5d4ddadcceda4c_b.jpg& data-size=&normal& data-rawwidth=&718& data-rawheight=&576& class=&origin_image zh-lightbox-thumb& width=&718& data-original=&https://pic2.zhimg.com/v2-5d4ddadcceda4c_r.jpg&&&figcaption&图 2 嵌入 LSTM 模型结构。其中和分别表示嵌入函数&/figcaption&&/figure&&p&实际实现中,预取器会返回多个预测值,因此需要从中做出权衡。虽然更多的预测值增加了缓存命中下一个时间步的可能性,但是有可能会从缓存中移除其它一些有用的项。论文选取在每个时间步预取 LSTM 的头部 10 个预测值。这里还有其它一些可能的做法,例如使用使用 beam-search 预测之后个时间步,或是通过直接学习先于 LSTM 的一次前向操作给出对到时间步的预测。&/p&&p&嵌入 LSTM 模型存在一些局限性。首先,大型的词汇表增加了模型的计算复杂度和存储量。其次,截取部分词汇表无疑为模型准确性设置了一个上限。最后,不易处理一下罕见发生的地址差值,因为这些差值很少在训练集中出现。该问题在 NLP 领域称为“罕见词汇问题”。&/p&&p&&b&聚类与 LSTM 的组合模型&/b&&/p&&p&假定大多数地址间感兴趣操作发生在本地地址空间中。例如,结构体和数组的数据结构通常使用持续的数据块存储,并会被指令重复访问。论文在模型设计中引入了上述理念,对本地上下文做细致建模。与之不同的是,在嵌入 LSTM 模型中不仅考虑了本地上下文,而且引入了全局上下文。&/p&&p&通过查看更窄区域的地址空间,可以发现其中的确存在着丰富的本地上下文。为此,论文从 omnetpp 中取出了部分地址集,并使用 K-Means 聚类为 6 个不同的区域。图 3 中展示了其中的两个聚类。&/p&&figure&&img src=&https://pic3.zhimg.com/v2-f1664fea33e4bf248aa94a_b.jpg& data-size=&normal& data-rawwidth=&725& data-rawheight=&548& class=&origin_image zh-lightbox-thumb& width=&725& data-original=&https://pic3.zhimg.com/v2-f1664fea33e4bf248aa94a_r.jpg&&&figcaption&图 3 展示了基准测试数据集 omnetpp 的六个 K-Means 聚类中的两个聚类。内存访问按照生成访问的 PC 分别标记颜色。&/figcaption&&/figure&&p&为达到对本地地址空间区域建模的相对准确性,论文对原始地址空间进行 K-Means 聚类,将数据分区为多个聚类,并对计算每个聚类内的地址差值。图 4a 是对上例的可视化。该方法具有一个显著的优点,就是聚类内的地址差值集要显著地小于全局词汇表中的差值,这缓解了嵌入 LSTM 模型中存在的一些问题。&/p&&p&为进一步降低模型的规模,论文使用了多任务 LSTM 对所有距离建模,即对每个聚类独立使用一个 LSTM 建模。聚类 ID 也添加为模型的特性,这为每个 LSTM 提供了一组不同的偏差。&/p&&p&将地址空间分区为更小的区域,意味着每个聚类内地址组使用的幅度量级大体上相同。因此,所生成的地址差值可以有效地正则化为适用于 LSTM 的真实输入值,不再需要维护一个大型的嵌入矩阵,进而进一步降低了模型的规模。更重要的是,下一个地址差值预测的问题可作为一个分类问题,而回归模型在现实中通常不够精确。&/p&&p&该模型解决了一些嵌入 LSTM 中存在的问题。预处理步骤(即对地址空间的聚类)是模型中需要权衡考虑的一个因素。此外,该模型只对本地上下文建模,也可以对程序访问的不同地址空间区域进行动态建模。&/p&&figure&&img src=&https://pic3.zhimg.com/v2-ffa24a76bd5ecc61d79f324ba551c8be_b.jpg& data-size=&normal& data-rawwidth=&800& data-rawheight=&288& class=&origin_image zh-lightbox-thumb& width=&800& data-original=&https://pic3.zhimg.com/v2-ffa24a76bd5ecc61d79f324ba551c8be_r.jpg&&&figcaption&图 4 组合聚类和 LSTM 模型的结构,以及数据处理&/figcaption&&/figure&&h2&实验&/h2&&p&一个有效的内存预取器,应该具备对缓存未命中情况的准确预测能力。因此,论文的实验主要针对如何测定预取器的有效性。&/p&&p&&b&实验数据的收集&/b&&/p&&p&实验中所使用的数据主要是程序的动态追踪数据,其中包含程序计算的一个内存地址序列。追踪数据使用动态工具 Pin 捕获。该工具附着在进程上,并以文件形式给出被测量应用访问内存的“PC,虚地址”元组。原始访问追踪数据主要包含了堆栈访问等命中内存的方法。对于研究中关注的预测缓存未命中情况,实验中使用了一个模拟 Intel Broadwell 微处理器的模拟器,获取缓存未命中情况。&/p&&p&实验程序使用的是对内存做密集访问的 SPEC CPU2006 应用。该基准测试集用于算机系统的性能做完全评估。但是,与现代数据中心工作负载相比,SPEC CPU2006 依然是一个小规模的工作集。因此在论文的实验中,还添加了 Google 的 Web 搜索工作负载。&/p&&p&实验中将内存访问数据集分为训练集和测试集,其中 70% 用于训练,30% 用于测试。在每个数据集上独立训练每个 LSTM。嵌入 LSTM 使用 ADAM 训练,聚类 LSTM 使用 Adagrad 训练。使用的超参数参见原文附录。&/p&&p&实验测试的度量包括准确率和召回率。在实验中,对每个模型做出 10 次预测。如果在头部 10 次预测中给出了完全正确的地址差值,就认为生成了一次准确预测。&/p&&p&&b&模型对比情况&/b&&/p&&p&实验将基于 LSTM 的预取器与两种硬件预取器进行了对比。第一种是标准流预取器。为保持机器学习预取器与传统预取器的一致性,实验中模拟了支持多至 10 个并发流的硬件结构。第二种是 GHB PC/DC 预期器。这是一种关联预取器,它使用了两个表。一个表用于存储 PC,并将所存储的 PC 作为执行第二个表的指针。第二个表存储了地址差值的历史信息。在每次访问时,GHB 预取器跳转到第二个表,预取历史记录的地址差值。关联预取器对于复杂内存访问模式表现很好,具有比流预取器更低的召回率。&/p&&p&图 5 给出了不同预取器在各种基准测试数据集上的对比情况。尽管流预取器由于其动态词汇表特性可以获得最高的召回率,但是 LSTM 模型整体表现更好,尤其是准确率。&/p&&figure&&img src=&https://pic2.zhimg.com/v2-bb0b601e389b44dc1de04fa3e968c097_b.jpg& data-size=&normal& data-rawwidth=&555& data-rawheight=&570& class=&origin_image zh-lightbox-thumb& width=&555& data-original=&https://pic2.zhimg.com/v2-bb0b601e389b44dc1de04fa3e968c097_r.jpg&&&figcaption&图 5 传统预取器和 LSTM 预取器的准确率和召回率对比图。其中,“Geomean”表示几何平均值&/figcaption&&/figure&&p&通过对比嵌入 LSTM 模型和聚类与 LSTM 的组合模型,可以看到两种模型间的准确率不相上下。后者趋向于给出更好的召回率。当然,组合更多的模型将会给出更好的结果,这有待未来的工作去探索。&/p&&p&&b&对比 PC 的预测情况&/b&&/p&&p&该实验从嵌入 LSTM 模型的输入中分别移除或 PC。实验设计意在确定在不同输入模组中所包含的相对信息内容。&/p&&p&实验结果如图 6 所示。从图中可以看出,PC 和地址差值中包含有大量预测信息。地址差值序列中的预测信息可以提高准确率,而 PC 序列有助于提高召回率。&/p&&figure&&img src=&https://pic4.zhimg.com/v2-fe4b07f7ce9fe_b.jpg& data-size=&normal& data-rawwidth=&563& data-rawheight=&576& class=&origin_image zh-lightbox-thumb& width=&563& data-original=&https://pic4.zhimg.com/v2-fe4b07f7ce9fe_r.jpg&&&figcaption&图 6 不同输入模组的嵌入 LSTM 模型,准确率和召回率的对比图&/figcaption&&/figure&&h2&解释程序的语义&/h2&&p&相比于基于查找表的预期器,模式学习模型的一个主要优点是可以通过审视模型获取数据的内涵。图 7 展示了级联串在 mcf 上嵌入情况的 t-SNE 可视化。&/p&&figure&&img src=&https://pic4.zhimg.com/v2-0ee5835ade32f00e285a51661f32edbe_b.jpg& data-size=&normal& data-rawwidth=&540& data-rawheight=&538& class=&origin_image zh-lightbox-thumb& width=&540& data-original=&https://pic4.zhimg.com/v2-0ee5835ade32f00e285a51661f32edbe_r.jpg&&&figcaption&图 7 级联串在 mcf 上嵌入情况的 t-SNE 可视化,图中按指令展示为不同的颜色&/figcaption&&/figure&&p&图中的一个聚类是由一组具有统一代码的重复指令组成,这是由于编译器对循环体展开所导致。还有一个聚类仅由指针解除引用(pointer dereference)组成,这是由于程序遍历链接列表所导致的。在 omnetpp 中,对数据结构的插入和移除操作映射为同一个聚类,而数据比较操作则映射在不同聚类中。例子所使用的代码参见原文附录。&/p&&h2&结论及进一步工作&/h2&&p&对应用程序行为的学习和预测,可在解决计算机架构中的控制和数据并发问题中发挥重要作用。传统方法是使用基于表的预测器,但是当扩展到数据密集不规则工作负载时,实现此类方法的代价过大。&/p&&p&本文介绍了两者基于神经网络的预取模型,它们给出了比基于表的传统方法显著高的准确率和召回率。在实验中,论文对模型做离线训练并在线测试,使用准确率和召回率评估了模型。实验表明,论文提出的预取器模型可以改进缓存未命中的分布。当然,还有其它一些在不增加预取器的计算和内存负担条件下改进预期器的方法。在进一步的研究中,可以考虑基于内存命中和未命中数据训练模型,但是这将显著改变数据集的分布和规模。&/p&&p&时效性也是研究预期其中一个考虑的重要因素。对于 RNN 预取器而言,预期过早会导致处理器未使用缓存数据,预取过迟会则对性能影响甚微,因为延迟访问内存的代价已经付出。一个简单的启发式规则是采用类似于流预期器的行为,预先对多个时间步做出预测,而非仅是下一个时间步。&/p&&p&最后一点,对应用性能的影响可以评估 RNN 预取器的有效性。在理想情况下,RNN 将会直接优化应用性能。一个考虑是,使用强化学习技术作为动态环境中 RNN 的训练方法。&/p&&p&当然,内存预取并非计算机系统中唯一需要给出预测执行的领域。只要涉及分支行为,就需要做出预测。分支算法用于重定向控制流的地址,高速缓存替换算法在需要做出替换决定时预测从高速缓存的最佳替换处。如果采用机器学习系统代替传统微体系结构中的启发式规则,可以通过对此类系统审视,更好地理解系统的行为。论文中的 t-SNE 实验仅给出了一些表面上的观察,展示了内存访问模式是程序行为的一种表示。这表明,利用最新研究的 RNN 系统,为计算机系统结构研究提供了大量的机会。&/p&&p&查看论文原文:&/p&&p&&a href=&https://link.zhihu.com/?target=https%3A//arxiv.org/pdf/.pdf& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&https://&/span&&span class=&visible&&arxiv.org/pdf/&/span&&span class=&invisible&&9.pdf&/span&&span class=&ellipsis&&&/span&&/a&&/p&&p&更多干货内容,可关注AI前线,ID:&b&ai-front&/b&,后台回复「&b&AI&/b&」、「&b&TF&/b&」、「&b&大数据&/b&」可获得《AI前线》系列PDF迷你书和技能图谱。&/p&
本文由 「AI前线」原创,原文链接:策划编辑 | Natalie 作者 | Milad Hashemi 等 编译 | Rays 编辑 | EmilyAI 前线导读:上个月,Jeff Dean、Michael I.Jordan、李飞飞、LeCun 等大牛发起的系…
&figure&&img src=&https://pic4.zhimg.com/v2-cc37c61ebf9adacbc2437f0_b.jpg& data-rawwidth=&1020& data-rawheight=&510& class=&origin_image zh-lightbox-thumb& width=&1020& data-original=&https://pic4.zhimg.com/v2-cc37c61ebf9adacbc2437f0_r.jpg&&&/figure&&p&【编者按】机器学习开发者&a href=&https://link.zhihu.com/?target=http%3A//otoro.net/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&hardmaru&/a&撰写博客,介绍了他在年度Google Brain Residency期间和同事合作发表的论文&a href=&https://link.zhihu.com/?target=https%3A//arxiv.org/abs/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&HyperNetworks&/a&(超网络)。&/p&&figure&&img src=&https://pic1.zhimg.com/v2-82cebb121_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&707& data-rawheight=&270& class=&origin_image zh-lightbox-thumb& width=&707& data-original=&https://pic1.zhimg.com/v2-82cebb121_r.jpg&&&/figure&&h2&介绍&/h2&&figure&&img src=&https://pic2.zhimg.com/v2-c74ddcdceafa_b.jpg& data-size=&normal& data-rawwidth=&1178& data-rawheight=&457& class=&origin_image zh-lightbox-thumb& width=&1178& data-original=&https://pic2.zhimg.com/v2-c74ddcdceafa_r.jpg&&&figcaption&用于手写生成的超网络,LSTM的权重矩阵随时间而改变&/figcaption&&/figure&&p&大部分现代的神经网络架构或者是一个深度卷积网络

我要回帖

更多关于 什么是摩尔定律 的文章

 

随机推荐