作者注:

限于能力和时间,文中定有不少错误,欢迎指出,邮箱yixiangrong@hotmail.com, 期待讨论。由于绝大部分是原创,即使拷贝也指明了出处(如有遗漏请指出),所以转载请表明出处http://www.cnblogs.com/e-shannon/

http://www.cnblogs.com/e-shannon/p/7495618.html

2   CAPI overview

2.1         背景

2.1.1          行业背景

2013年8月由IBM、Google 、NVIDIA等公司联合成立成立了OpenPower 基金会, 其目的是通过建立开源Power生态系统,在warehouse data center(仓储式数据中心)、HPC(高性能计算)等服务器领域与intel展开竞争[dream1] 。4年里,先后有150多家企业加入,涉及从芯片到I/O、固件、系统、软件等各个产业链。OpenPower成立后IBM于2014年推出的第一款CPU是Power8,而CAPI1.0(一致性加速处理器接口)是Power8 系统所支持的重要特性之一,用于减轻CPU负担,实现CPU加速的功能。

2017年IBM推出Power9,Power9 基于14nm FineFET工艺,8billion个晶体管(注:Power9将是检验IBM的openPower策略的重要筹码,希望能抢回HPC和超大规模数据中心市场份额的10%-20%)。同时作为Power9所支持的重要特性CAPI2.0已经公布,相比于1.0,支持PCIE Gen4(到底是4GB/s还是2GB/s的速率?Power9似乎指的是4GB/s),以及在AFU接口添加了DMA通道,支持PCIE的native 操作,便于AFU直接通过PCIE访问。值的一提的是其提供了NVlink接口可以直接对接nVIDIA的GPU,也可以复用为OpenCAPI的phy(bluelink)。(yxr注:OpenCAPI在后续会介绍)

2.1.2          技术背景以及开放式总线接口

由于在大数据/云计算/HPC(超算)/人工智能(深度学习)等大计算大存储领域,单靠CPU性能提升无法胜任越来越复杂的高运算量的需求。最近的趋势显示[dream2] ,CPU创造的价值越来越小,而加速器以及更多的依附于CPU的疯狂创新则创造了更大的价值,所以高速、低延迟、协同操作(coherent)的(CPU)高性能总线(或称为互联加速接口)成为了业界急迫的需求。CAPI则是在这种背景下出现(yxr注:对应于intel,则是QPI通道),但其依附于OpenPower的CPU体系。业界为了满足业务需求,更希望能出现一套开放式总线,独立于不同的ISA和CPU体系,并且不仅仅为了对接accelerator,而且也面向未来高速的memory,网络存储以及高速network,实现计算机集群的互联和高速运算。所以2016年共出现了3个开放标准,分别是CCIX,Gen-Z,OpenCAPI[dream3] 。

三个标准的目的相似,侧重点有些差异,成员也互相交叉,甚至有成员在三个组里(比如AMD、IBM、Xilinx、Micron等,而Google和nVIDIA仅仅在OpenCAPI,当然intel不在这三个组里)。

CCIX物理介质基于PCIE,实现处理器和加速器全cache一致性。而Gen-Z则侧重于机框之间的互联一致性加速。OpenCAPI则获得了IBM的Power9支持。(yxr猜测:相信最后这三个标准将会统一,因为其共同的敌人应该是intel吧,也许intel加入后又不同了)

<?xml:namespace prefix = o />

2.2         Cache

CAPI里的coherent是指cache coherency。而理解cache coherency,需要从cache的认识入手,对于cache熟悉的读者可以略过本节,以下均是自己不专业地从网上搜罗整理。

2.2.1          浅析Cache

由于CPU运算速度要比内存读写速度快很多,这样会使CPU花费更多时间等待数据到来或把数据写入内存。内存一般由高密度的动态内存DRAM组成,所以其访问速度相对慢于CPU速度(需要行地址和列地址,以及刷新操作,等待周期等,并且功耗大)。

现代计算机中一般在CPU和内存之间插入了一个SRAM,作为cache,用于解决CPU速度运行速度快和内存访问速度相对慢的矛盾。CPU不再能直接访问内存[dream4] ,而是访问cache,见下面示意图

SRAM的访问速度远快于DRAM,克服了CPU访问内存的瓶颈,其缺点是无法做成大容量。引入 Cache(SRAM)的理论基础是程序局部性原理,包括时间局部性和空间局部性。即最近被CPU访问的数据,短期内 CPU还要访问(时间);被 CPU 访问的数据附近的数据,CPU 短期内还要访问(空间)。因此如果将刚刚访问过的数据缓存在 Cache中,那下次访问时,可以直接从Cache中取,其速度可以得到数量级的提高[dream5] 。

在高级的CPU中,存在二级缓存,服务器等CPU则达到三级缓存[dream6] 。Power9含有12个SMT8 core,每个core有三级缓存[dream7] ,10 MB Capacity L3+  512k L2(SRAM),而一级缓存则由32kB instruction cache(I-cache)和32kB data cache(D-cache)组成。三级缓存工12x10MB=120 MB 其实是Shared Capacity NUCA Cache由eDRAM组成,目的是为了[dream8] 大容量并行计算以及异种互动。

如下是以intel core2 双核处理器为例,其为双核,使用二级缓存。1级缓存是每个core对应有32KB L1 数据和32KB L1 指令。而二级缓存为6MB[dream9] 为双核共享,其cache line均为64byte。(Yxr注:Power9与其相比,似乎是插入了一级SRAM作为2级缓存。)

http://www.cnblogs.com/xkfz007/archive/2012/10/08/2715163.html

2.2.2          Cache访问方式

如上图所示,CPU无法直接访问内存,只能沿着Register —> L1 Cache —> L2 Cache —> L3 Cache —> Memory —> Mass storage的层次结构进行访问。CPU访问内存则存在4种方式,

读写各两种,读有 look through 和 look aside方式,写有 write through 和write back

Look through:指的是CPU读请求只能发给cache,如果命中则cache回内容给CPU,结束本次访问。如果没有命中(hit),则cache将读请求发给内存。

Look aside: 则是CPU的读请求同时给cache和内存[dream10]  ,如果cache命中,则cache回数据并且中断内存读。如果没有命中,则不中断内存读操作,继续内存访问,好处是减少了延迟,缺点是每次都将发起内存总线读操作,占用了内存访问总线[dream11] 。

Write through:透过本级缓存,直接把数据写到下一级缓存(或直接到内存)中,如果对应的段被缓存了,我们同时更新缓存中的内容(甚至直接丢弃)。优点是操作简单,保证缓存和内存一致,缺点是降低了系统写速度,占用了内存的访问总线。

Write back:(yxr注:有两种说法,回写时机不一样,不清楚哪种正确!!!)

1种说法.缓存不会立即把写操作传递到下一级,而是仅修改本级缓存中的数据,并且把对应的缓存段标记为“脏”段。脏段会触发回写,也就是把里面的内容写到对应的内存或下一级缓存中。回写后,脏段又变“干净”了。当一个脏段被丢弃的时候,总是先要进行一次回写[dream12] 。

2种说法. 数据一般只写到Cache,这样有可能出现Cache中的数据得到更新而主存(Main Storage)中的数据不变(数据陈旧)的情况。但此时可在Cache 中设一标志地址及数据陈旧的信息,只有当Cache中的数据被再次更改时,才将原更新的数据写入主存相应的单元中,然后再接受再次更新的数据。这样保证了 Cache和主存中的数据不致产生冲突。

有些(大多数是比较老的)CPU只使用直写模式,有些只使用回写模式,还有一些,一级缓存使用直写而二级缓存使用回写。这样做虽然在一级和二级缓存之间产生了不必要的数据流量,但二级缓存和更低级缓存或内存之间依然保留了回写的优势。

2.2.3          缓存映射方式和cache line

Cache的内部结构含有内存地址和cache内部地址映射关系,以及存储内存数据的单元。

Cache line是cache加载内存的基本操作单位,每次加载一个cache line而不是一个字节。大小是32(较早的ARM、90年代/2000年代早期的x86和PowerPC)、64(较新的ARM和x86)或128(较新的Power ISA机器)字节,(yxr注:cache line大小可能和DRAM内存的内部结构有关,一个基本内存访问的基本操作可能是8个时钟的数据,而数据线宽度为32,64,128bit (注意不要跨DRAM的bank[dream13] ))

每个cache line,都有如下类似的结构,tag是数据块在内存中的地址,data block则是数据内容,flag bits则是valid和脏等标志,甚至一些算法信息

而相对于内存的物理地址,则可理解为如下结构,其原因是缓存与内存的映射关系造成。

这里的 page 不是分页机制的page概念,而是cache 内部的page,line则是cache line所在的位置,offset则是具体数据所在字节(?理解正确吗),具体理解需要从cache的映射关系来看。

Cache与主存有三种映射关系,可参考如下资料(高速缓存与主存的三种映射方式[dream14]

http://blog.csdn.net/hs794502825/article/details/37937949 (ok)讲的比较好,这里直接搬过来),  https://en.wikipedia.org/wiki/CPU_cache,http://blog.sina.com.cn/s/blog_5ccec1e30100yte3.html)

1、全相联映射方式    (full-associative)

2、直接相联映射方式  (direct map,相当于1-way associative) http://www.cs.umd.edu/class/sum2003/cmsc311/Notes/Memory/direct.html

3、组相联映射方式    (2-way,8-way  N-Way Set-Associative) 这个是现在CPU中用的较多的方式,算是前面两种的组合折中[dream15]

http://blog.csdn.net/leoufung/article/details/48804627 http://blog.csdn.net/zdl1016/article/details/8882092

http://www.mouseos.com/arch/cache.html

1、全相联映射是指主存中任意一个块都可以映射到cache中任意一个块的方式,也就是说,当主存中的某一块需调入cache时,可根据当时cache的块占用或分配情况,选择一个块给主存块存储,所选的cache块可以是cache中的任意一个块。所以需要一个表存放cache和内存之间的关系,如下图

(Yxr注:这个就有点像CAM了,输入主存地址,输出index是cache的地址,然后找到对应的数据。在文中(1)Cache的组成结构_云中鸿雁_新浪博客提到,组相联映射方式中,在同一个Set中,Real Address Tag阵列多使用CAM(Content Addressable Memory)存放,以利于并行查找PS(Parallel Search)方式的实现)

优点是cache利用率高,命中率高。缺点是存储相联关系的存储器(相联存储器)庞大,查找整个cache,比较电路复杂,速度慢,无法做大。

2、直接相联映射方式

直接相联映射方式是指主存的某块j只能映射到满足如下特定关系的cache块i中:

i=j mod 2^C

主存的第0、2^C、2^(C+1)、…块只能映射到cache的第0块,主存的第1、2^C+1、2^(C+1)+1、…块只能映射到cache的第1块,……,主存的第2^C-1、2^(C+1)-1、…2^M-1块只能映射到cache的第2^C-1块。即:对2^C求余后余数相同的主存块对应cache中同一个块。如下图所示:

优点:比较电路最简单,地址映射方式简单,数据访问时,只需检查区号是否相等即可,因而可以得到比较快的访问速度,硬件设备简单。

缺点:cache块冲突率较高,余数相同的主存块无法同时进入cache,从而降低了cache的利用率。

3、组相联映射方式

结合了上面两种方法,这样主存的某一块不会限制在cache的某一块中,而是限制在某一组中。

组相联映射方式下,将cache分成2^u组,每组包含2^v块。主存的块与cache的组之间采用直接相联映射,而与组内的各块则采用全相联映射。也就是说,主存的某块只能映射到cache的特定组中的任意一块。主存的某块j与cache的组k之间满足如下关系:k=j mod 2^u

设主存共有2^s×2^u块(即M=s+u),则它们的映射关系如下图所示:

Yxr注:这里的组应该就是way[dream16] ,文章适合更进一步理解cache(http://www.mouseos.com/arch/cache.html)。在理解cache中的8-way set或者AMD 的2-way set,就是8组或者2组。Power8的L2 也是512 KB 8 way per core。

优点:块的冲突概率比较低,块的利用率大幅度提高,块失效率明显降低。

缺点:实现难度和造价要比直接映射方式高。

延伸阅读

1)现代CPU中,更多采用组相联映射方法。在Cache的组成结构一文(Cache的组成结构_云中鸿雁_新浪博客)中,有着更进一步讲述这几种方法的演进和优劣,以及组的个数和效率之间关系。值得进一步阅读。

2)在《理解 Cache》(mik@mouseos.com)中则举例了AMD和intel的CPU,如下是AMD的2-way cache

cache 中的 other 部分还包括了 cache 的状态信息,LRU(least Recently Used)算法等,还包括一些预解码,分支预测等一些信息

2.3         Cache Coherency

以上介绍了单CPU核的单个Cache的内部组成,当多个CPU的多组cache在一起工作时,就牵涉到cache的一致性。CAPI里的Coherent指的是cache Coherency[dream17] ,即缓存一致性。多核CPU中,均有各自的cache,如何保证各个cache的内容一致性以及和内存的一致性,是一致性协议需要解决的问题。

这里推荐一篇介绍cache coherency的文章。《Cache coherency primer》《缓存一致性入门》

http://www.infoq.com/cn/articles/cache-coherency-primer

文中介绍cache的来源、cache line(yxr注:有意思的是作者认为cache line应该是指一段内存内容,并不一定在cache中)的含义和cache访问所遵循的定理。指出一致性问题来源是由于多组cache造成的,而不是多核造成,如果多核共用一个cache,则不存在此问题。在解决一致性问题中提到了最普遍的方法,snoop协议,其物理基础是在多核系统里,每个CPU都有自己的cache系统,但同时和唯一的一个memroy控制器交互,所以均能够窥探(snoop)到memory 的访问,知道其他cache访问内存的动作,从而更新和操作自己的cache。在write-through模式中,各组cache知道其他cache的动作,可以马上更新,但是对于write-back模式,就存在问题,可能出现多个CPU核的cache同时更新一块内存。所以在修改本地缓存之前,就要告知其他处理器。处理回写模式这个问题的最简单方案,我们通常叫做MESI协议(梅西我最喜欢的球员啊,MESI是Modified、Exclusive、Shared、Invalid的首字母缩写,代表四种缓存状态[dream18] ).

原生的MESI协议

MESI是四种缓存段状态的首字母缩写,任何多核系统中的缓存段cache line都处于这四种状态之一,各个cache之间需要相互通信,完成各个状态的装换,保证cache的一致性。出于合理性,文中以相反的顺序逐个讲解MESI:

失效(Invalid)缓存段,要么已经不在缓存中,要么它的内容已经过时。为了达到缓存的目的,这种状态的段将会被忽略。一旦缓存段被标记为失效,那效果就等同于它从来没被加载到缓存中。

共享(Shared)缓存段,它是和主内存内容保持一致的一份拷贝,在这种状态下的缓存段只能被读取,不能被写入。多组缓存可以同时拥有针对同一内存地址的共享缓存段,这就是名称的由来。

独占(Exclusive)缓存段,和S状态一样,也是和主内存内容保持一致的一份拷贝。区别在于,如果一个处理器持有了某个E状态的缓存段,那其他处理器就不能同时持有它,所以叫“独占”。这意味着,如果其他处理器原本也持有同一缓存段,那么它会马上变成“失效”状态。

已修改(Modified)缓存段,属于脏段,它们已经被所属的处理器修改了。如果一个段处于已修改状态,那么它在其他处理器缓存中的拷贝马上会变成失效状态,这个规律和E状态一样。此外,已修改缓存段如果被丢弃或标记为失效,那么先要把它的内容回写到内存中——这和回写模式下常规的脏段处理方式一样。

MESI协议是一个合适的状态机,既能处理来自本地处理器的请求,也能把信息广播到总线上[dream19] 。E状态解决了“在我们开始修改某块内存之前,我们需要告诉其他处理器”这一问题:只有当缓存段处于E或M状态时,处理器才能去写它,也就是说只有这两种状态下,处理器是独占这个缓存段的。当处理器想写某个缓存段时,如果它没有独占权,它必须先发送一条“我要独占权”的请求给总线,这会通知其他处理器,把它们拥有的同一缓存段的拷贝失效(如果它们有的话)。只有在获得独占权后,处理器才能开始修改数据——并且此时,这个处理器知道,这个缓存段只有一份拷贝,在我自己的缓存里,所以不会有任何冲突。

反之,如果有其他处理器想读取这个缓存段(我们马上能知道,因为我们一直在窥探总线),独占或已修改的缓存段必须先回到“共享”状态。如果是已修改的缓存段,那么还要先把内容回写到内存中。

MESI定律:在所有的脏缓存段(M状态)被回写后,任意缓存级别的所有缓存段中的内容,和它们对应的内存中的内容一致。此外,在任意时刻,当某个位置的内存被一个处理器加载入独占缓存段时(E状态),那它就不会再出现在其他任何处理器的缓存中。

除了基于窥探(snoop)协议来完成cache coherency,文中同时指出还有一种基于目录的cache coherency协议,虽然延迟大,但更适用于大规模的多核系统,在《cache的理解》一文中,可以看到在 Intel 中,使用 Directory 结构来匹配查找数据

上面这个图显示了使用 Direcotry 结构进行查找,同样是需要匹配 page 值。这些 status 值和 AMD的other 异曲同工的作用,记录着每条 cache line 的状态值。

2.4         Power CPU的cache coherency系统

在Power多[dream20] CPU的体系下,多核cache的关系如下图所示

摘自http://www.csdn.net/article/2015-06-17/2824990

ccA就是cache coherency agent,猜测就是cache 一致性处理机构,完成了cache 一致性协议比如snooping(图中的probe应为此功能),MESI协议,或基于directory的更新。MC是memory controller,控制RAM的访问。而CAPI 则是基于PCIE的物理介质,通过CPU上的RC(PCIE root complex)访问MC。为达到cache一致性,在CAPI接口上应该有个类似ccA的模块,这里就是CAPP和PSL的一部分(见下图),其中PSL含有cache约256KB(为L2cache的一半)。


[dream1](服务器市场现在几乎是intel的天下?是这样吗,据说IBM的小型机性能远超intel x86,且高端市场主要用IBM小型机,其稳定性和性能扩展性远超intel。但是由于采用计算机群技术,通过分布式计算解决了稳定性和性能提升,所以基于intel的处理器的服务器反而处于优势地位。而IBM小型机非常贵,包括CPU也很贵,所以现在IBM推出OpenPower,估计也是针对这个问题,仿效arm,基于IP,降低CPU价格,其他厂家也能生产PowerCPU

[dream2]https://www.nextplatform.com/2016/10/17/opening-server-bus-coherent-acceleration/

What is going on here is that we are re-architecting the system,” Brad McCredie, the former president of the OpenPower Foundation and an IBM Fellow and vice president of development in IBM’s Power Systems division, tells The Next Platform. “No matter how you slice it, the processor is not improving cost/performance at the incredible rate and pace that it had in the past. And yet there is still this ever-growing demand for more and more compute capability, driven by these new workloads of artificial intelligence as well as simulation and analytics, there is this huge appetite to still produce more advanced systems. Less and less value is being driven by CPUs and more and more is being generated by accelerators, new memory technologies, and lots of crazy innovations that are attaching to processors. The value is shifting around, and in order to have the ability to mix and match technologies, we are going to need standards and Google, Hewlett Packard Enterprise, and Dell EMC see this very plainly.”

[dream3](213_CCIXGen-Z_BBenton.pdf,CCIX,Gen-Z,OpenCAPI_Overview&Comparison.pdf)

[dream4]但是也有的CPU可以旁路cache,直接访问内存,这个应该和CPU有关,引出了更多的信号同时给cache和内存

[dream5]具体多少,不清楚yxr..如下一段话虽然是硬盘,也能说明些问题。

硬盘的cache也有助于改进性能。虽然16MB的cache只能覆盖整个磁盘容量的0.002%,可别看cache只有这么一点大,其效果十分明显。它可以把一组零散的写入操作合成一个,也就是使磁盘能够控制写入操作的顺序,从而减少寻道的次数。同样的,为了提高效率,一系列读取操作也可以被重组,而且操作系统和驱动器固件(firmware)都会参与到这类优化中来。

[dream6]没有听说四级缓存

[dream7]三级缓存的作用明显吗?提高效能呢

[dream8]Big Caches for Massively Parallel Compute

and Heterogeneous Interaction

[dream9]是SRAM吗?

[dream10]1)有这种应用吗 2)物理上芯片实现上是否单独引CPU信号给内存?还是在cache中透传信号给了内存

[dream11]其实这个叫look through似乎更好,和write through一致嘛

[dream12]怎么有的网站werghryp,所遵循的一次回写。回写所遵循的规律有点不同

[dream13]我们已经知道,一个cache line对应的是主存中连续的几个字,那么这些字的低位对于映射一个cache line是没用的,比如说在一个32位系统中,一个cache line的大小是16个字,也就是64个字节,cache读取memory的数据时按照,cache line的尺寸读入,所以编程时组织数据结构,按照cache line的方式能够提升效率

[dream14]这里自己理解的并无信心,

[dream15]理解正确否?

[dream16]正确否?

[dream17]是这样吗?为啥在openCAPI中,还提到V3.30的openCAPI仅仅支持memory coherent,而不支持cache coherent(见CCIX,Gen-Z,penCAPI_Overview&Comparison.pdf 的page9)

[dream18]  为达到cache conherency,cache访问引入了MESI状态(梅西,四个字母代表四种状态),各个core之间需要相互通信,完成各个状态的装换,保证cache的一致性。

[dream19]这让我想起在TCP/IP offload中自己设计的的如何将TCP的访问无阻塞被各个模块使用,也是窥探也是采用总线通知收发模块以及Timer模块。蛮佩服自己的,^_^。可以多学习些控制协议!计算机专业的书记

[dream20]从(http://www.csdn.net/article/2015-06-17/2824990 介绍中似乎power系统采用directory方法,

转载于:https://www.cnblogs.com/e-shannon/p/7496068.html

CAPI 初探及使用小结(2)相关推荐

  1. CAPI 初探及使用小结(4)

    4 开放的coherent 加速接口 正如第一节所说的,为了满足加速需求,业界为CPU高性能一致性接口(high performance coherence interface)定义开放的标准,201 ...

  2. CAPI 初探及使用小结(1)

    作者注: 限于能力和时间,文中定有不少错误,欢迎指出,邮箱yixiangrong@hotmail.com, 期待讨论.由于绝大部分是原创,即使拷贝也指明了出处(如有遗漏请指出),所以转载请表明出处ht ...

  3. CAPI 初探及使用小结(3)

    作者注: 限于能力和时间,文中定有不少错误,欢迎指出,邮箱yixiangrong@hotmail.com, 期待讨论.由于绝大部分是原创,即使拷贝也指明了出处(如有遗漏请指出),所以转载请表明出处ht ...

  4. 我的ELK搭建笔记(阿里云上部署)

    文章转载:http://www.jianshu.com/p/797073c1913f 仅用作个人学习,收藏 我的 ELK 搭建笔记(基于阿里云) "不是最好的,但一定是有良心的操作记录.&q ...

  5. 寓教于乐——PyGame游戏编程,Python小游戏制作实战教学

    Python非常受欢迎的一个原因是它的应用领域非常广泛,其中就包括游戏开发.而是用Python进行游戏开发的首选模块就是PyGame. 1. 初识Pygame PyGame是跨平台Python模块,专 ...

  6. 佩奇(社会人)大学初探——联迪商用实习小结(2018-4至2018-6)

    今天结束了为期将近3个月的实习,从4月12到6月30,除去周末,也算有始有终了.虽然决定考研二战了,不过感受还是颇多的. 联迪是一家做pos机的公司,在国内市场算是份额比较大的,在一些餐饮店都能看到我 ...

  7. python argparse_Python 命令行之旅:初探 argparse

    本文首发于 HelloGitHub 公众号,并发表于 Prodesire 博客. 前言 你是否好奇过在命令行中敲入一段命令后,它是如何被解析执行的?是否考虑过由自己实现一个命令行工具,帮你执行和处理任 ...

  8. 把《c++ primer》读薄(4-2 c和c++的数组 和 指针初探)

    督促读书,总结精华,提炼笔记,抛砖引玉,有不合适的地方,欢迎留言指正. 问题1.我们知道,将一个数组赋给另一个数组,就是将一个数组的元素逐个赋值给另一数组的对应元素,相应的,将一个vector 赋给另 ...

  9. 初探领域驱动设计(1)为复杂业务而生

    概述 领域驱动设计也就是3D(Domain-Driven Design)已经有了10年的历史,我相信很多人或多或少都听说过这个名词,但是有多少人真正懂得如何去运用它,或者把它运用好呢?于是有人说,DD ...

最新文章

  1. python-pptx
  2. 他89岁,拿下人生第3个博士学位,横跨医学物理学,只为“实现儿时梦想”
  3. 专属于Java程序员的学习福音
  4. word2013 blog test
  5. JQuery仿最新淘宝网首页带箭头幻灯片,JQuery轮播图
  6. Python语言学习:python语言的特点、入门、基础用法之详细攻略
  7. hdu 5434(状态压缩+矩阵优化)
  8. 前端学习(3312):redux的正确构建
  9. python正则匹配_Python正则表达式只匹配一次
  10. 2017.9.10 连续攻击游戏 思考记录
  11. mysql redis geo_利用Redis的Geo功能实现查找附近的位置
  12. [转载] 老友记——潘石屹 任志强《天台论道》(下)
  13. php中字符串与数组的相互转化explode(separator,$str)与implode(separator,$arr)
  14. window11在注册表修改用户名后登陆不了账户
  15. hdu2553解题报告
  16. Modown V1.9 WordPress资源素材付费下载Erphpdown主题模板原版
  17. 自己写的网页放在github里面
  18. 买的鱼丸怎么做好吃 鱼丸的家常做法介绍
  19. Android 仿美拍,秒拍 ,视频封面选择.有图有真相.
  20. 基于java学生签到考勤系统

热门文章

  1. CSS常见样式的介绍和使用(附加案例)
  2. [MISC]USB键鼠流量
  3. uni-app中一些写法
  4. python int转datetime_python – 将日期从int64转换为datetime
  5. leetcode332.重新安排行程(困难,欧拉通路)
  6. 优化采购流程——浅谈ERP采购询价管理的优势
  7. JAVA实现二维码扫码登录
  8. 阿里云提货券使用方法图文教程
  9. 用MATLAB拟合曲线怎么调参数,Matlab – 使用约束参数拟合曲线
  10. Linux里startup.sh 和 shutdown.sh