导言
遇到的DNS相关的问题

sudo passwd root只要在安装系统时分出一个/home分区。你可以把Ubuntu的“/”分区看为Windows的C盘,重装Ubuntu时只格式化“/”分区,不格式化“/home”,这样就可以保留“/home”中的数据了。使用的时候就挂载就行
但是假如一开始没分区:
xfs类型不可以直接缩减,只扩不减。如果是ext2,ext3,ext4可以在线缩减,如果xfs盘要缩小就要删除后重新添加
1 | umount /lv/ #取消挂载目录 |
1 | e2fsck -f /dev/vg0/lv0 |
df -h查看的空间1 | resize2fs /dev/vg0/lv0 10G |
1 | lvreduce -L 10G /dev/vg0/lv0 |
1 | mount -a |
正常启动系统进入救援模式 :启动按shift键,出现选择系统界面,按e。找到以单词 linux 开头的行,并在该行的末尾添加以下内容(要到达末尾,只需按下 CTRL+e 或使用 END 键或左右箭头键):
1 | systemd.unit=rescue.target |
添加完成后,只需按下 CTRL+x 或 F10 即可继续启动救援模式。几秒钟后,你将以 root 用户身份进入救援模式(单用户模式)
暂无
https://blog.csdn.net/weixin_40018873/article/details/109537532


暂无
暂无
https://developer.qiniu.com/fusion/kb/3725/how-to-apply-for-and-use-free-certificate
1 | shaojiemike @ node5 in ~ [7:20:31] |
1 | source /opt/intel/oneapi/setvars.sh |
1 | ipcc22_0029@ln121 ~/github/IPCC2022-preliminary/run (float_trick*) [10:49:48] |
For MPICH, according to the mpicc man pages, mpicc -compile_info shows the flags for compiling a program, and mpicc -link_info shows the flags for linking a program.
-showme (Open MPI) or -show (Open MPI, MPICH and derivates) use -showme:compile and -showme:link to obtain the options automatically
1 | > mpirun -info |
1 | ipcc22_0029@ln121 ~ [11:55:08] |
1 | ## 安装了IB支持 |
暂无
暂无
https://stackoverflow.com/questions/11312719/how-to-compile-mpi-with-gcc
1 | MPI_Init(&argc, &argv); |
StackOverflow的回答是,Init在调用过程中初始化MPI库,并且在进程间建立通讯和编号。
知乎的回答: OpenMPI会在调用MPI_Init时按照你传递给mpirun的指令新建进程,而你传递给MPI_Init的参数,会被传递给新建的进程。
这似乎在暗示,两个进程不是同时产生和运行的。
有顺序的观点是不成立的
即使有顺序 malloc的时间也没这么长。
难道是malloc的数据需要MPI_Init复制一遍?
简单将MPI_Init提前到最开始,时间也基本没变,也不对。

如果单独写一个只有MPI_Init的程序,IntelMPI还是要耗时800ms
1 | ipcc22_0029@ln121 ~/slurm/MPIInit [11:42:32] |
以IPCC2022初赛的北京超算云 AMD机器举例
| mpirun的选择 | mpi版本 | GCC或者ICC的选择版本 | 超算运行 | MPI_Init时间(ms) |
|---|---|---|---|---|
| IntelMPI | mpi/intel/2022.1 | gcc/10.2.0 | 只能sbatch,不能srun | 1282.24 ~ 1678.59 |
| OpenMPI | mpi/openmpi/4.1.1-gcc7.3.0 | 2706ms~3235ms | ||
| MPICH | mpich/3.1.4-gcc8.1.0 | 17ms | ||
| mpich/3.4.2 | gcc/10.2.0 | 107ms |
需要export I_MPI_PMI_LIBRARY=libpmi2.so
设置这个Intel mpi 1200 -> 1100
1 | export PMI_TIME=1 |
实在是弄不懂,为什么不同的实现,时间差别这么大。可能慢是因为额外的通路设置,是为了之后的快速传输??
3.1.4的安装选项也看不到
1 | > mpiexec --version |
暂无
必须先安装base,可以看到默认安装的内容


这个GDB好像可以分析多进程

Intel OneAPI HPC toolkit包括了icc,icpc,ifort和OpenMP,IntelMPI还有MKL(Intel® oneAPI Math Kernel Library (oneMKL))
在Download界面选择版本, 选择online或者offline会有推荐指令,如下
1 | wget https://registrationcenter-download.intel.com/akdlm/irc_nas/18679/l_HPCKit_p_2022.2.0.191.sh |
1 | > icx -v |
暂无
暂无
1 | __asm__ __volatile__("Instruction List" : Output : Input : Clobber/Modify); |
__asm__或asm 用来声明一个内联汇编表达式,所以任何一个内联汇编表达式都是以它开头的,是必不可少的。__volatile__或volatile 是可选的。如果用了它,则是向GCC 声明不允许对该内联汇编优化,否则当 使用了优化选项(-O)进行编译时,GCC 将会根据自己的判断决定是否将这个内联汇编表达式中的指令优化掉。__asm__ __volatile__(""); 或 __asm__ ("");都是完全合法的内联汇编表达式,只不过这两条语句没有什么意义。__asm__ ("":::"memory");就非常有意义,它向GCC 声明:“内存作了改动”,GCC 在编译的时候,会将此因素考虑进去。%0,%1,…,%9。指令中使用占位符表示的操作数,总被视为long型(4个字节),%h1。"constraint"(variable)的列表(逗号分隔)。按照出现的顺序分别与指令操作数”%0”,”%1”对应"=r" (value)__asm__ ("mov R0, #0x34" : : : "R0");寄存器R0出现在”Instruction List中”,并且被mov指令修改,但却未被任何Input/Output操作表达式指定,所以你需要在Clobber/Modify域指定”R0”,以让GCC知道这一点。每一个Input和Output表达式都必须指定自己的操作约束Operation Constraint,这里将讨论在80386平台上所可能使用的操作约束。
当前的输入或输出需要借助一个寄存器时,需要为其指定一个寄存器约束,可以直接指定一个寄存器的名字。
常用的寄存器约束的缩写
| 约束 | 意义 |
|---|---|
| r | 表示使用一个通用寄存器,由 GCC 在%eax/%ax/%al,%ebx/%bx/%bl,%ecx/%cx/%cl,%edx/%dx/%dl中选取一个GCC认为合适的。 |
| g | 表示使用任意一个寄存器,由GCC在所有的可以使用的寄存器中选取一个GCC认为合适的。 |
| q | 表示使用一个通用寄存器,和约束r的意义相同。 |
| a | 表示使用%eax/%ax/%al |
| b | 表示使用%ebx/%bx/%bl |
| c | 表示使用%ecx/%cx/%cl |
| d | 表示使用%edx/%dx/%dl |
| D | 表示使用%edi/%di |
| S | 表示使用%esi/%si |
| f | 表示使用浮点寄存器 |
| t | 表示使用第一个浮点寄存器 |
| u | 表示使用第二个浮点寄存器 |
| 分类 | 限定符 | 描述 |
|---|---|---|
| 通用寄存器 | “a” | 将输入变量放入eax 这里有一个问题:假设eax已经被使用,那怎么办?其实很简单:因为GCC 知道eax 已经被使用,它在这段汇编代码的起始处插入一条语句pushl %eax,将eax 内容保存到堆栈,然 后在这段代码结束处再增加一条语句popl %eax,恢复eax的内容 |
| “b” | 将输入变量放入ebx | |
| “c” | 将输入变量放入ecx | |
| “d” | 将输入变量放入edx | |
| “s” | 将输入变量放入esi | |
| “d” | 将输入变量放入edi | |
| “q” | 将输入变量放入eax,ebx,ecx,edx中的一个 | |
| “r” | 将输入变量放入通用寄存器,也就是eax,ebx,ecx,edx,esi,edi中的一个 | |
| “A” | 把eax和edx合成一个64 位的寄存器(use long longs) | |
| 内存 | “m” | 内存变量 |
| “o” | 操作数为内存变量,但是其寻址方式是偏移量类型, 也即是基址寻址,或者是基址加变址寻址 | |
| “V” | 操作数为内存变量,但寻址方式不是偏移量类型 | |
| “ “ | 操作数为内存变量,但寻址方式为自动增量 | |
| “p” | 操作数是一个合法的内存地址(指针) | |
| 寄存器或内存 | “g” | 将输入变量放入eax,ebx,ecx,edx中的一个 或者作为内存变量 |
| “X” | 操作数可以是任何类型 | |
| 立即数 | “I” | 0-31之间的立即数(用于32位移位指令) |
| “J” | 0-63之间的立即数(用于64位移位指令) | |
| “N” | 0-255之间的立即数(用于out指令) | |
| “i” | 立即数 | |
| “n” | 立即数,有些系统不支持除字以外的立即数, 这些系统应该使用”n”而不是”i” | |
| 匹配 | “ 0 “,“1” …“9” | , 表示用它限制的操作数与某个指定的操作数匹配,也即该操作数就是指定的那个操作数,例如”0”去描述”%1”操作数,那么”%1”引用的其实就是”%0”操作数,注意作为限定符字母的0-9 与 指令中的”%0”-“%9”的区别,前者描述操作数,后者代表操作数。 |
| &; | 该输出操作数不能使用过和输入操作数相同的寄存器 | |
| 操作数类型 | “=” | 操作数在指令中是只写的(输出操作数) |
| “+” | 操作数在指令中是读写类型的(输入输出操作数) | |
| 浮点数 | “f” | 浮点寄存器 |
| “t” | 第一个浮点寄存器 | |
| “u” | 第二个浮点寄存器 | |
| “G” | 标准的80387浮点常数 | |
| % | 该操作数可以和下一个操作数交换位置.例如addl的两个操作数可以交换顺序 (当然两个操作数都不能是立即数) | |
| # | 部分注释,从该字符到其后的逗号之间所有字母被忽略 | |
| * | 表示如果选用寄存器,则其后的字母被忽略 |
如果一个Input/Output 操作表达式的C/C++表达式表现为一个内存地址,不想借助于任何寄存器,则可以使用内存约束。比如:
1 | __asm__("lidt%0":"=m"(__idt_addr)); |
| 修饰符 | 输入/输出 | 意义 |
|---|---|---|
| = | O | 表示此Output操作表达式是Write-Only的。 |
| O |表示此Output操作表达式是Read-Write的。
& | O |表示此Output操作表达式独占为其指定的寄存器。
% | I |表示此Input 操作表达式中的C/C++表达式可以和下一 个Input操作表达式中的C/C++表达式互换
1 | Static __inline__ void __set_bit(int nr, volatile void * addr) |
第一个占位符%0与C 语言变量ADDR对应,第二个占位符%1与C语言变量nr对应。因此上面的汇编语句代码与下面的伪代码等价:btsl nr, ADDR
使用”memory”是向GCC声明内存发生了变化,而内存发生变化带来的影响并不止这一点。
例如:
1 | int main(int __argc, char* __argv[]) |
本例中,如果没有那条内联汇编语句,那个if语句的判断条件就完全是一句废话。GCC在优化时会意识到这一点,而直接只生成return 5的汇编代码,而不会再生成if语句的相关代码,而不会生成return (*__p)的相关代码。
但你加上了这条内联汇编语句,它除了声明内存变化之外,什么都没有做。
但GCC此时就不能简单的认为它不需要判断都知道 (*__p)一定与9999相等,它只有老老实实生成这条if语句的汇编代码,一起相关的两个return语句相关代码。
另外在linux内核中内存屏障也是基于它实现的include/asm/system.h中
1 | # define barrier() _asm__volatile_("": : :"memory") |
主要是保证程序的执行遵循顺序一致性。呵呵,有的时候你写代码的顺序,不一定是终执行的顺序,这个是处理器有关的。
1 | static inline char * strcpy(char * dest, const char *src) |
暂无
暂无
| 命令 | 压缩空间效果 | 压缩时间效果 | 解压时间 | 说明 |
|---|---|---|---|---|
| tar -cf | 2.9G | 13.8s | 3.3s | tar -cf archive.tar foo归档文件,没有压缩功能 |
| tar -zcf | 823M | 1:44 | 19s | tar -zcf archive.tar.gz foo归档并使用gzip压缩文件,gzip是zip的GNU实现,是最老的公开压缩方法 |
| zip -1r | 856M | 48.6s | 23.3s | zip -1qr intel.zip intel, -1 compress faster,unzip解压 |
| zip -9r | 824M | 11:19 | 24s | 压缩这也太慢了吧 |
| rar a | 683M | 2:02 | 46s | unrar x解压 |
上述测试基于大小3GB的文件夹
虽然说好像有专利的软件,但是sudo apt install rar貌似就可以安装。但是空间效果确实还行多压1/3,但是时间要多两倍。
首先找到vtune程序
1 | > module load intel/2022.1 |
vtune-gui获取可执行命令
1 | /opt/intel/oneapi/vtune/2021.1.1/bin64/vtune -collect hotspots -knob enable-stack-collection=true -knob stack-size=4096 -data-limit=1024000 -app-working-dir /home/shaojiemike/github/IPCC2022first/build/bin -- /home/shaojiemike/github/IPCC2022first/build/bin/pivot /home/shaojiemike/github/IPCC2022first/src/uniformvector-2dim-5h.txt |
编写sbatch_vtune.sh
1 |
|
log文件如下,但是将生成的trace文件r000hs导入识别不了AMD
1 | > cat log/vtune |

1 | objdump -Sd ../build/bin/pivot > pivot1.s |
https://blog.csdn.net/thisinnocence/article/details/80767776


(没有开O3,默认值)

偏移 -64 是k
-50 是ki

CDQE复制EAX寄存器双字的符号位(bit 31)到RAX的高32位。

这里的movsdq的q在intel里的64位,相当于使用了128位的寄存器,做了64位的事情,并没有自动向量化。

如果想把 C 语言变量的名称作为汇编语言语句中的注释,可以加上 -fverbose-asm 选项:
1 | gcc -S -O3 -fverbose-asm ../src/pivot.c -o pivot_O1.s |
1 | .L15: |
原本以为O3是看不了原代码与汇编的对应关系的,但实际可以-g -O3 是不冲突的。

r9 mov到 rax里,leaq (%r12,%r8,8), %r9。其中r12是rebuiltCoord,所以r8原本存储的是[i*k]的值rax是rebuiltCoord+[i*k]的地址,由于和i有关,index的计算在外层就计算好了。rdx的值减去r8存储在rdx里rdx原本存储的是[j*k]的地址r8原本存储的是[i*k]的值rdx之后存储的是[(j-i)*k]的地址data16 nop是为了对齐插入的nop
maxsdxmm0是缓存值xmm1是chebyshevxmm2是fabs的掩码xmm4是chebyshevSum
r14d存储k的值,所以edi存储j*k值rdx原本存储的是[j*k]的地址
r14d存储k的值,r8和r11d存储了i*k的值从汇编看不出有该操作,需要开启编译选项
从汇编看不出有该操作,需要开启编译选项
从汇编看不出有该操作,需要开启编译选项
为什么求和耗时这么多
gcc


vmov,vadd的操作,但是实际还是64位的工作。add rax, 0x8没有变成add rax, 0x16可以体现1 | VADDSD (VEX.128 encoded version) |
汇编代码表面没变,但是快了10s(49s - 39s)
下图是avx2的
下图是avx512的
猜测注意原因是
1 | lscpu|grep pref |
应该是支持的
虽然时间基本没变,主要是对主体循环没有进行预取操作,对其余循环(热点占比少的)有重新调整。如下图增加了预取指令
变慢很多(39s -> 55s)
汇编实现,在最内层循环根据k的值直接跳转到对应的展开块,这里k是2。
默认是展开了8层,这应该和xmm寄存器总数有关

由于数据L1能全部存储下,没有提升
并没有形成想象中预取的流水。每512位取,还有重复。

每次预取一个Cache Line,后面两条指令预取的数据还有重复部分(导致时间增加 39s->61s)

想预取全部,循环每次预取了512位=64字节
(能便于编译器自动展开来使用所有的向量寄存器,avx2
39s -> 10s -> 8.4s 编译器
1 | for(i=0; i<n-blockSize; i+=blockSize){ |
明明展开了一次,但是编译器继续展开了,总共8次。用满了YMM 16个向量寄存器。
下图是avx512,都出现寄存器ymm26了。
vhaddpd是水平的向量内加法指令
当在avx512的情况下展开4次,形成了相当工整的代码。
ymm18,估计只能展开到6次了。
最后求和的处理,编译器首先识别出了,不需要实际store。还是在寄存器层面完成了计算。并且通过三次add和两次数据 移动指令自动实现了二叉树型求和。
avx2 寄存器不够会出现下面的情况。
假如硬件存在四个一起归约的就好了,但是对于底层元件可能过于复杂了。


1 | __m256d _mm256_hadd_pd (__m256d a, __m256d b); |

如果可以实现会节约一次数据移动和一次数据add。没有分析两种情况的寄存器依赖。可能依赖长度是一样的,导致优化后时间反而增加一点。

对于int还有这种实现

并且将j的循环展开变成i的循环展开

支持的理由:打破了循环间的壁垒,编译器会识别出无效中间变量,在for的jump指令划出的基本块内指令会乱序执行,并通过寄存器重命名来形成最密集的计算访存流水。
不支持的理由:如果编译器为了形成某一指令的流水,占用了太多资源。导致需要缓存其他结果(比如,向量寄存器不够,反而需要额外的指令来写回,和产生延迟。
理想的平衡: 在不会达到资源瓶颈的情况下展开。
手动展开后,识别出来了连续的访存应该在一起进行,并自动调度。将+1的偏移编译器提前计算了。
如果写成macro define,可以发现编译器自动重排了汇编。
avx2可以看出有写回的操作,把值从内存读出来压入栈中。
寄存器足够时没有这种问题
由于不同代码对向量寄存器的使用次数不同,不同机器的向量寄存器个数和其他资源数不同。汇编也难以分析。在写好单次循环之后,最佳的展开次数需要手动测量。如下图,6次应该是在不会达到资源瓶颈的情况下展开来获得最大流水。
1 | for(j=beginJ; j<n-jBlockSize; j+=jBlockSize){ / |
由于基本块内乱序执行,代码的顺序也不重要。
加上寄存器重命名来形成流水的存在,寄存器名也不重要。当然数据依赖还是要正确。
思路: 外层多load数据到寄存器,但是运行的任何时候也不要超过寄存器数量的上限(特别注意在内层循环运行一遍到末尾时)。
左图外层load了8个寄存器,但是右边只有2个。
特别注意在内层循环运行一遍到末尾时:
如图,黄框就有16个了。
所以内层调用次数多,尽量用快的
1 | _mm256_loadu_ps >> _mm256_broadcast_ss > _mm256_set_epi16 |
1 | vsub vmax ps 0.02 Latency 4 |
|指令|精度|时间(吞吐延迟和实际依赖导致)|Latency|Throughput
|-|-|-|-|-|-|
|_mm256_loadu_ps /_mm256_broadcast_ss|||7|0.5
|vsub vmax | ps| 0.02 | 4|0.5
vand ||0.02| 1|0.33
vadd |ps |0.80 |4| 0.5
vhadd ||0.8| 7|2
vcvtps2pd || 2.00 | 7|1
vextractf128 || 0.50 | 3|1

17条avx计算 5load 2cvt 2extract

| 单位时间 | avx计算 | load | cvt | extract |
|---|---|---|---|---|
| 2.33 | 3.68 | 12.875 | 4.1 |
可见类型转换相当耗费时间,最好在循环外,精度不够,每几次循环做一次转换。
-march=skylake-avx512是一条指令
-mavx2 是两条指令
1 | vmovupd xmm7, xmmword ptr [rdx+rsi*8] |
将IPCC初赛的代码去掉O3发现还是慢了10倍。

为什么连汇编函数调用也慢这么多呢?
这个不开O3的编译器所属有点弱智了,一条指令的两个操作数竟然在rbp的栈里存来存去的。
暂无
暂无
一块铁 10^22个原子
高性能计算每年翻一倍 = 超算规模 + Chip摩尔定律
但是由于分子动力学的方法是O^3, 问题规模增大,每一步迭代反而变慢了(2011年GB是3天一步)。
一百万内规模6次方内的专用机器 anton? ,比一般超算快100倍。
compute is cheap,memory and bandwidth are expansive, latency is physics.
18GB: AI图片处理大气模拟问题
AI : 高纬度函数的逼近(解空间相对于输入维度)



将epoch从几百变几个
基于薛定谔方程和经典电子结构
digist + analog
量子计算的a killer app
当前问题:
量子计算缺乏复杂度分析?
UCC Ansatz
暂无
暂无