跳转至

笔记

IPCC2022final

学到的一些亮点

总结反思

由于决赛是黑盒制度,没有排行榜,也不知道最终算分的例子是多大。我们优化着眼于自己找的清华的大例子,并行的占比在这部分很小。忽略了小例子里,占比比较高的部分的优化。结果最终赛题例子很小。

如果提前知道元素个数,并行对同一个数组的末尾添加元素可以并行,添加到指定位置之后再统一排序就行。比如山东大学,就是这里快了大约10ms,加上第一次排序快5ms。

比如信息中心(应该是第一名)的排序,用的是归并的基数排序

比如青海大学的优化:

还有高效的排序,怎么实现。类似

需要进一步的研究学习

CSR (压缩稀疏行存储) 矩阵和邻接表在表示图数据结构时,计算和访问性能有些差异:

  • CSR通过压缩行存储机制,可以大幅减少空间占用,节省内存。但索引算术运算负担重一些
  • 邻接表使用链表指针连接相邻节点,追踪任意一条边的开销很低。但总体占用内存空间更大。
  • CSR访问任意一个元素通过索引计算直接可以定位,兼具稠密和稀疏矩阵的特点。
  • 邻接表的边访问性能更好,通过指针直接遍历一个节点的所有相邻节点。
  • CSR的预处理时间较短,更易于向量化实现提高效率。
  • 邻接表更灵活,可表示加权图或处理动态变化的图。
  • CSR矩阵更易进行压缩和剪枝来优化存储,节省内存带宽。

所以简单来说,如果图更稠密,数据访问模式更随机,CSR可能会有些优势。如果需要频繁遍历边,图结构变化大,邻接表访问效率可能会更高一些。需要根据具体情况选择合适的表示。

遇到的问题

暂无

开题缘由、总结、反思、吐槽~~

哎呀,你干嘛! 今年又~西巴了~,惜败了,应该是第三名左右。

参考文献

NUMA perf

简介

NUMA使用的目的是为了每个进程能使用local内存来实现高性能。但是假如某进程的local内存提前用完了,会导致无法使用其他进程的内存,反而需要SWAP的问题。(一般小例子遇不到)

https://blog.51cto.com/quantfabric/2594323

https://www.cnblogs.com/machangwei-8/p/10402644.html

NUMA的内存分配策略

  1. 缺省(default):总是在本地节点分配(分配在当前进程运行的节点上);
  2. 绑定(bind):强制分配到指定节点上;
  3. 交叉(interleave):在所有节点或者指定的节点上交织分配;
  4. 优先(preferred):在指定节点上分配,失败则在其他节点上分配。

因为NUMA默认的内存分配策略是优先在进程所在CPU的本地内存中分配,会导致CPU节点之间内存分配不均衡,当某个CPU节点的内存不足时,会导致swap产生,而不是从远程节点分配内存。这就是所谓的swap insanity 现象。

$ numactl --hardware
available: 2 nodes (0-1)
node 0 cpus: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
node 0 size: 64076 MB
node 0 free: 23497 MB
node 1 cpus: 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
node 1 size: 64503 MB
node 1 free: 37897 MB
node distances:
node   0   1
  0:  10  21
  1:  21  10

# shaojiemike @ node5 in ~/github/IPCC2022-preliminary/run on git:main o [10:41:54]
$ numactl --show
policy: default
preferred node: current
physcpubind: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
cpubind: 0 1
nodebind: 0 1
membind: 0 1

常见命令

# 遇到内存不够时
numactl –interleave=all ./exe

# 使用local内存(默认的)
numactl --localalloc ./exe

查看程序的内存的 NUMA情况

在Linux系统上,可以通过以下常用方法来查看和分析程序的NUMA(非统一内存访问)情况:

numastat:查看进程和每个NUMA节点的内存分配和访问统计。
numactl: 查看进程NUMA policy和分配策略,可以手动设置策略。
numa_maps:查看进程在每个NUMA节点上的内存映射情况。
mpstat -P ALL:查看每个CPU核心的统计信息。
pidstat -t:查看进程在每个CPU上的执行时间。
perf stat:统计程序在不同CPU上周期数,检查是否均衡。
likwid-perfctr: 细粒度检测程序在不同内存节点的带宽和延迟。
VTune: Intel的性能分析工具,可以检测NUMA的影响。
代码插桩:统计程序对不同节点内存的访问。
numactl --hardware :查看系统NUMA拓扑结构。

通过综合使用这些工具,可以全面分析程序的NUMA性能,例如内存分布不均,访问模式导致的不均衡等,然后进行针对优化。

c++ malloc时能手动设置 内存位置

  1. libnuma: 直接调用libnuma提供的numa_alloc_onnode()numa_free()等API,在指定节点上分配释放内存。
  2. mmap

需要进一步的研究学习

暂无

遇到的问题

暂无

开题缘由、总结、反思、吐槽~~

参考文献

VtuneOptimize

vtune的安装和profile

使用

由于snode0有sudo

source /opt/intel/oneapi/setvars.sh
sudo vtune-gui

sudo后图形化界面 MobaXterm打不开的原因参考这个

Step1 : Performance Snapshot 参数说明

以IPCC2022 初赛 支撑点计算的baseline为例

Logical Core Utilization

Effective Logical Core Utilization: 3.8% (2.436 out of 64)
    Effective Physical Core Utilization: 6.4% (2.053 out of 32)

CPU利用率主要是指计算有效占比。为100%意味着所有逻辑CPU都是由应用程序的计算占用。

Microarchitecture Usage

微架构使用指标是一个关键指标,可以帮助评估(以%为单位)你的代码在当前微架构上运行的效率。

微架构的使用可能会受到

  1. long-latency memory长延迟访存、
  2. floating-point, or SIMD operations浮点或SIMD操作的影响;
  3. non-retired instructions due to branch mispredictions;由于分支错误预测导致的未退役指令;
  4. instruction starvation in the front-end.前端指令不足。

vtune的建议

Microarchitecture Usage: 37.7% of Pipeline Slots
    Retiring: 37.7%
    Front-End Bound: 16.9%
    Back-End Bound: 23.8%
    Memory Bound: 11.9%
    Core Bound: 11.9%
    Bad Speculation: 21.5%

针对Back-End Bound: 23.8%的建议如下:

A significant portion of pipeline slots are remaining empty. (??? 他是指有23.8% empty还是被使用了呢)

When operations take too long in the back-end, they introduce bubbles in the pipeline that ultimately cause fewer pipeline slots containing useful work to be retired per cycle than the machine is capable to support.

This opportunity cost results in slower execution.

  1. Long-latency operations like divides and memory operations can cause this,
  2. as can too many operations being directed to a single execution port (for example, more multiply operations arriving in the back-end per cycle than the execution unit can support).

针对Bad Speculation: 21.5%的建议如下:

A significant proportion of pipeline slots containing 21.5% useful work are being cancelled.

This can be caused by mispredicting branches or by machine clears. Note that this metric value may be highlighted due to Branch Resteers issue.

Retiring metric

Retiring metric represents a Pipeline Slots fraction utilized by useful work, meaning the issued uOps that eventually get retired. Retiring metric 表示有用工作所使用的Pipeline slot流水线管道的比例,所有发射的uOps最终都会retired。

Ideally, all Pipeline Slots would be attributed to the Retiring category. 理想情况下,所有的管道槽都应该归于退休类别。

Retiring of 100% would indicate the maximum possible number of uOps retired per cycle has been achieved. 100%的退役表明每个周期内退役的uop数量达到了可能的最大值。

Maximizing Retiring typically increases the Instruction-Per-Cycle metric. 最大化Retiring通常会增加IPC。

Note that a high Retiring value does not necessary mean no more room for performance improvement. For example, Microcode assists are categorized under Retiring. They hurt performance and can often be avoided.

Microcode assists根据Intel的解释是

当遇到特殊的计算(比如处理非常小的浮点值(所谓的逆法线)时),浮点单元并没有被设置为本机执行这些操作。为此需要在指令流中插入可能有数百个指令长的小程序,对性能会造成很大的影响。

Front-End Bound

Front-End Bound metric represents a slots fraction where the processor's Front-End undersupplies its Back-End. 该指标表示前端产生的指令是否足以支持后端处理。

Front-End denotes the first part of the processor core responsible for fetching operations that are executed later on by the Back-End part. 前端将指令分解成uops供后端处理。

Within the Front-End, a branch predictor predicts the next address to fetch, cache-lines are fetched from the memory subsystem, parsed into instructions, and lastly decoded into micro-ops (uOps). 在前端中,分支预测器预测下一个要获取的地址,缓存行从内存子系统中获取,解析为指令,最后解码为微操作(uOps)。

Front-End Bound metric denotes unutilized issue-slots when there is no Back-End stall (bubbles where Front-End delivered no uOps while Back-End could have accepted them). For example, stalls due to instruction-cache misses would be categorized as Front-End Bound

Front-End Bound指标表示当后端没有停顿时未使用的发射槽(bubbles: 前端没有交付uOps,而发射给后端的)。例如,由于指令缓存未命中而导致的暂停将被归类为Front-End Bound

Back-End Bound

metric represents a Pipeline Slots fraction where no uOps are being delivered due to a lack of required resources for accepting new uOps in the Back-End. 该指标表示后端uops是否出现了因为硬件资源紧张而无法处理的问题。

Back-End is the portion of the processor core where an out-of-order scheduler dispatches ready uOps into their respective execution units, and, once completed, these uOps get retired according to the program order. 后端的乱序执行,顺序Reire模型。

For example, stalls due to data-cache misses or stalls due to the divider unit(除法器?) being overloaded are both categorized as Back-End Bound. Back-End Bound is further divided into two main categories: Memory Bound and Core Bound.

Memory Bound

This metric shows how memory subsystem issues affect the performance. Memory Bound measures a fraction of slots where pipeline could be stalled due to demand load or store instructions. This accounts mainly for incomplete in-flight memory demand loads that coincide with execution starvation in addition to less common cases where stores could imply back-pressure on the pipeline.

Core Bound

This metric represents how much Core non-memory issues were of a bottleneck. 表明核心的非内存原因成为了瓶颈

  1. Shortage in hardware compute resources, 硬件资源的短缺
  2. or dependencies software's instructions are both categorized under Core Bound. 指令间的依赖

Hence it may indicate

  1. the machine ran out of an OOO resources,
  2. certain execution units are overloaded
  3. or dependencies in program's data- or instruction- flow are limiting the performance (e.g. FP-chained long-latency arithmetic operations).

Bad Speculation(分支预测错误)

represents a Pipeline Slots fraction wasted due to incorrect speculations.

This includes slots used to issue uOps that do not eventually get retired and slots for which the issue-pipeline was blocked due to recovery from an earlier incorrect speculation.

For example, wasted work due to mispredicted branches is categorized as a Bad Speculation category. Incorrect data speculation followed by Memory Ordering Nukes is another example.

这里的Nukes, 猜测是数据预取预测错误,带来的访存影响像核爆一样大吧.

Memory Bound

Memory Bound: 11.9% of Pipeline Slots
    L1 Bound: 7.9%
    L2 Bound: 0.2%
    L3 Bound: 2.5%
    DRAM Bound: 2.0%
    Store Bound: 0.3%
    NUMA: % of Remote Accesses: 13.2%

This metric shows how memory subsystem issues affect the performance. Memory Bound measures a fraction of slots where pipeline could be stalled due to demand load or store instructions. 该项表明了有多少流水线的slots因为load或者store指令的需求而被迫等待

This accounts mainly for incomplete in-flight memory demand loads that coincide with execution starvation 这是指不连续访存吗?

in addition to less common cases where stores could imply back-pressure on the pipeline.

L1 Bound

This metric shows how often machine was stalled without missing the L1 data cache. 在不发生L1 miss的情况下,指令stall的频率。(因为其他原因导致stall?)

The L1 cache typically has the shortest latency. However, in certain cases like loads blocked on older stores, a load might suffer a high latency even though it is being satisfied by the L1. 假设load了一个刚store的值,load指令也会遇到很大的延迟。

L2 Bound

This metric shows how often machine was stalled on L2 cache. Avoiding cache misses (L1 misses/L2 hits) will improve the latency and increase performance.

L3 Bound

This metric shows how often CPU was stalled on L3 cache, or contended with a sibling Core(与兄弟姐妹核竞争). Avoiding cache misses (L2 misses/L3 hits) improves the latency and increases performance.

DRAM Bound

This metric shows how often CPU was stalled on the main memory (DRAM). Caching typically improves the latency and increases performance.

DRAM Bandwidth Bound

This metric represents percentage of elapsed time the system spent with high DRAM bandwidth utilization. Since this metric relies on the accurate peak system DRAM bandwidth measurement, explore the Bandwidth Utilization Histogram and make sure the Low/Medium/High utilization thresholds are correct for your system. You can manually adjust them, if required.

Store Bound

This metric shows how often CPU was stalled on store operations. Even though memory store accesses do not typically stall out-of-order CPUs; there are few cases where stores can lead to actual stalls.

NUMA: % of Remote Accesses

In NUMA (non-uniform memory architecture) machines, memory requests missing LLC may be serviced either by local or remote DRAM. Memory requests to remote DRAM incur much greater latencies than those to local DRAM. It is recommended to keep as much frequently accessed data local as possible. This metric shows percent of remote accesses, the lower the better.

可以用之前的

Vectorization

This metric represents the percentage of packed (vectorized) floating point operations. 0% means that the code is fully scalar. The metric does not take into account the actual vector length that was used by the code for vector instructions. So if the code is fully vectorized and uses a legacy instruction set that loaded only half a vector length, the Vectorization metric shows 100%.

Vectorization: 23.7% of Packed FP Operations
    Instruction Mix: 
    SP FLOPs: 0.9%
    Packed: 99.9%
    128-bit: 0.1%
    256-bit: 99.8%
    512-bit: 0.0%
    Scalar: 0.1%
    DP FLOPs: 2.9%
    Packed: 0.0%
    Scalar: 100.0%
    x87 FLOPs: 0.0%
    Non-FP: 96.2%
    FP Arith/Mem Rd Instr. Ratio: 0.091
    FP Arith/Mem Wr Instr. Ratio: 0.308

针对Vectorization: 23.7%的建议

A significant fraction of floating point arithmetic instructions are scalar. Use Intel Advisor to see possible reasons why the code was not vectorized.

SP FLOPs

The metric represents the percentage of single precision floating point operations from all operations executed by the applications. Use the metric for rough estimation of a SP FLOP fraction. If FMA vector instructions are used the metric may overcount.

X87 FLOPs

The metric represents the percentage of x87 floating point operations from all operations executed by the applications. Use the metric for rough estimation of an x87 fraction. If FMA vector instructions are used the metric may overcount.

X87是X86体系结构指令集的浮点相关子集。 它起源于8086指令的扩展,以可选的浮点协处理器的形式与相应的x86 cpus配合使用。 这些微芯片的名称在“ 87”中结尾。

FP Arith/Mem Rd Instr. Ratio

This metric represents the ratio between arithmetic floating point instructions and memory write instructions. A value less than 0.5 indicates unaligned data access for vector operations, which can negatively impact the performance of vector instruction execution.

小于0.5的值表示向量操作的未对齐数据访问,这可能会对矢量指令执行的性能产生负面影响。

Step2 : Hotspots

User-Mode Sampling只能采集单核的数据,来分析算法的优化。

Hardware Event-Based Sampling硬件时间采集能采集全部核心,但是要少于几秒钟?

这个硬件采集慢,而且到一半报错了,发生什么事了?

网上说是root权限的原因,但是我是用root运行的

反而用普通用户能正常跑Hardware Event-Based Sampling和微架构分析

example

手动向量化该区域。

核心时间是 \(k*n^2\) 次绝对值和,取最大值

优化思路:

  1. 手动向量化(假设一次处理p个)

    第一个n层取出 k个 rebuilt[i*k+ki] 重复读取到向量寄存器里,

    第二个n层取出k 个 连续的p个,到向量寄存器里。最后不足补0特殊处理,但是一般n都是4的倍数,可能可以不处理。8就要处理了。

    做向量fabs的结果缓存在k个向量寄存器里。

    再对这个k个向量寄存器做横向的向量最大值操作到一个向量寄存器。不足的补0(取最大值不影响)

    最后这一个向量寄存器做寄存器内求和,再加到 chebyshevSum 里.

    这样就实现了p个元素的向量操作。这样一趟共需要3*k个向量寄存器。

  2. 手动数据预取

  3. __builtin_prefetch()
  4. 手动循环展开形成计算访存流水
  5. 怎么根据输入来规模来展开?
  6. 分块

访存分析

github对应项目与赛题

HPL-PL

复现机器

$ lscpu
Architecture:                    x86_64
CPU op-mode(s):                  32-bit, 64-bit
Byte Order:                      Little Endian
Address sizes:                   46 bits physical, 48 bits virtual
CPU(s):                          36
On-line CPU(s) list:             0-35
Thread(s) per core:              1
Core(s) per socket:              18
Socket(s):                       2
NUMA node(s):                    2
Vendor ID:                       GenuineIntel
CPU family:                      6
Model:                           79
Model name:                      Intel(R) Xeon(R) CPU E5-2695 v4 @ 2.10GHz
Stepping:                        1
CPU MHz:                         1296.157
CPU max MHz:                     3300.0000
CPU min MHz:                     1200.0000
BogoMIPS:                        4199.98
Virtualization:                  VT-x
L1d cache:                       1.1 MiB
L1i cache:                       1.1 MiB
L2 cache:                        9 MiB
L3 cache:                        90 MiB

baseline

$ gcc --version
gcc (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0
$ gcc -std=c11 conway.c -o Conway
$ ./Conway
……
Iter 997...
Iter 998...
Iter 999...
136527.433000 ms

优化步骤

由于O3和并行会导致热点代码不可读

在可迭代优化的例子下,根据vtune最大化单核性能。

很明显不是计算密集的应用,怎么形成流水最大化带宽利用,划分重复利用元素提高Cache命中率是重点(向量化对计算加速明显)

  1. 替换if tmp[i][j] = (!(cnt^3))||((a[i][j]&1)&&(!(cnt^4)));
  2. 去除中间不必要的拷贝
  3. int 变 char
  4. OMP_PROC_BIND=true 绑定线程到对应local处理器和对应local内存

需要进一步的研究学习

暂无

遇到的问题

暂无

开题缘由、总结、反思、吐槽~~

  1. 实验室同学黄业琦参加了HPC-PL全明星。想复现一下效果
  2. 之前Nvidia Nsight用得很爽, 想到vtune的访存优化部分和汇编对应的分析,使用的很少。想从提高计算流水和访存连续流水的角度结合vtune优化。

参考文献

Nas Disk Speed Test

导言

电脑直接传输特别慢平均10M

群晖DS220j文件传输速度、外网访问速度、moment套件使用情况以及耗电情况。 最高写入速度为105MB/S,最高读取速度为110MB/S。

西数红盘 2T。 145MB/s。

知乎评测: 局域网实际拷贝速度还不错,基本能达到千兆水平。下图是拷贝GB级文件(如电影)的截图,拷贝照片和音乐之类的小文件会慢不少,10MB大小的文件写入速度有60MB/s左右,更小的文件就只有30MB/s了。

排查配置

网口

路由器是Redmi AX3000wifi6 WAN口和LAN口都是千兆口 2000Mbit 3000Mbit

电脑的网口是B450 迫击炮的主板 千兆口

网线

电脑连路由器的的网线是cat.6A的

电脑连墙壁接口的是cat.5e的

网线,DS220J 送的是cat.5e

只要网线够短,cat.5e至少有5Gb/s,一般都不是瓶颈。1

额外测试

网线直连电脑和群晖的机器,用这根CAT.6A,速度也很慢。

(结果第二天就好多了,路由器平均50M,直连能跑满,感觉原因在于路由器缓存转发的问题,端口都是千兆的)

其余测试

检测硬盘

diskgenius

命令行硬盘测速

控制面板 开启ssh

ssh -p 2333 [email protected]
sudo -s

sh-4.4# df -h
Filesystem         Size  Used Avail Use% Mounted on
/dev/md0           2.3G  1.1G  1.2G  50% /
devtmpfs           225M     0  225M   0% /dev
tmpfs              243M   24K  243M   1% /dev/shm
tmpfs              243M   15M  228M   7% /run
tmpfs              243M     0  243M   0% /sys/fs/cgroup
tmpfs              243M  1.5M  241M   1% /tmp
/dev/vg1/volume_1  1.8T  1.5T  289G  85% /volume1
/dev/vg3/volume_3  4.0T  2.0G  4.0T   1% /volume3
/dev/vg3/volume_4  4.0T   89M  4.0T   1% /volume4

# 磁盘读性能
sh-4.4# hdparm -Tt /dev/vg1/volume_1

/dev/vg1/volume_1:
 Timing cached reads:   1092 MB in  2.00 seconds = 545.67 MB/sec
 Timing buffered disk reads: 456 MB in  3.03 seconds = 150.28 MB/sec
sh-4.4# hdparm -Tt /dev/md4

/dev/md4:
 Timing cached reads:   1086 MB in  2.00 seconds = 542.89 MB/sec
 Timing buffered disk reads: 838 MB in  3.00 seconds = 279.23 MB/sec
sh-4.4# hdparm -Tt /dev/mapper/vg3-volume_4

/dev/mapper/vg3-volume_4:
 Timing cached reads:   1076 MB in  2.00 seconds = 537.13 MB/sec
 Timing buffered disk reads: 592 MB in  3.01 seconds = 196.89 MB/sec

 # 磁盘写性能
sh-4.4# dd if=/dev/vg3/volume_3 bs=1024 count=1000000 of=/1Gb.file
1000000+0 records in
1000000+0 records out
1024000000 bytes (1.0 GB, 977 MiB) copied, 13.0458 s, 78.5 MB/s
sh-4.4# dd if=/dev/vg1/volume_1 bs=1024 count=1000000 of=/1Gb.file
1000000+0 records in
1000000+0 records out
1024000000 bytes (1.0 GB, 977 MiB) copied, 18.837 s, 54.4 MB/s

群晖测网速

群晖的docker里也有speedtest

参考文献

Synology NAS Configuration

Nas 购买的考虑点

https://post.smzdm.com/p/a5d23w98/

  1. 处理器:建议至少是Intel的双核,ARM的还是不好使。单核性能太弱了。虚拟机,docker什么的就别想了。
  2. 群晖官方套件不支持DS220j,十分不建议尝试。
  3. 内存:尽量8GB组双通道
  4. 网口:群晖的都是1Gb的老千兆(虽然我电脑,路由器网口也是),但是威联通是2.5Gb的。
  5. M2.SSD加速:是否支持SSD加速
  6. USB口是不是3.2Gen2

群晖 DS220J (本体1200)

控制台与数据访问

  1. PC公用路由器控制:http://find.synology.com或者http://synologynas:5000
  2. QuickConnect:https://QuickConnect.to/shaojiemike or http://222.195.90.2/ (能ping通,就能访问)
  3. 电脑SMB直接访问
    1. \\192.168.31.247 (双斜杠,右键home有选项:映射网络驱动器)
    2. \\tsjNas (需要在局域网下)
    3. \\222.195.90.2/ (需要开启路由器的SMB(137-139,445)端口转发,否则能ping通,但是不能访问)

wireguard 网络配置脚本

使用开机wireguard脚本连接上网

  • 任意盘位置 /volume1/xxx编辑脚本,赋予权限
  • 群晖添加计划:点击任务计划。点击新增 -> 触发的任务 -> 用户定义的脚本(注意选择root用户权限)
  • 也可以选择写入启动文件中 vi /etc/rc
# 设置本地ssh eth0的222.195.90.2的高优先级,不至于开启wg断开ssh
ip ro add default via 222.195.90.254 dev eth0 table eth0-table
# 为了使得除开本地ssh网络走wg,需要删除屏蔽default的wg的DHCP
ip ro d default via 222.195.90.254 dev eth0  src 222.195.90.2 table main
# 防止服务端重启,Nas的wg客户端失联
ip ro a 114.214.233.0/24 via 222.195.90.254 dev eth0  src 222.195.90.2 table main 
# 启动wg
wg-quick up wg1

常见问题与解决方案

删除失效网络硬盘

Win10 无法直接取消,会报错"此连接不存在",参考文章1

需要删除两项 regedit注册表 计算机\HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\MountPoints2\##10.0.0.12#homes计算机\HKEY_CURRENT_USER\Network 下对应的盘符即可。

十分不建议组RAID

如果要利用空间不要组RAID,通过添加存储池来使用每个盘。

RAID0也不要组,文件是打散的,虽然读和写块,但是是一个整体。坏一个就全坏了。

先配置存储池和存储空间

然后设置文件夹

再重新映射盘符即可

停用与启用硬盘

若要激活硬盘: 已停用硬盘的分配状态会更改为未初始化,这表示此硬盘未安装 DSM,可以分配给存储池。请执行以下任何操作以激活硬盘:

  1. 从硬盘插槽中移除硬盘,然后将其重新插入硬盘插槽。
  2. 重启系统。
图形化界面控制台很卡顿

原因内存和性能不行,建议升级DS220j+ 额外拓展内存

电脑直接传输特别慢平均10M

群晖DS220j文件传输速度、外网访问速度、moment套件使用情况以及耗电情况。 最高写入速度为105MB/S,最高读取速度为110MB/S。

西数红盘 2T。 145MB/s。

知乎评测: 局域网实际拷贝速度还不错,基本能达到千兆水平。下图是拷贝GB级文件(如电影)的截图,拷贝照片和音乐之类的小文件会慢不少,10MB大小的文件写入速度有60MB/s左右,更小的文件就只有30MB/s了。

正常插在路由器LAN口下,无法找到群晖的IP

很有可能之前设置了静态IP,然后换了网络环境,网络掩码变了自然完全找不到。唯一的办法就是一定要保存和记录下之前的静态IP。

参考文档

Wireguard

简介

  • WireGuard 是由 Jason Donenfeld 等人用 C 语言编写的一个开源 VPN 协议,被视为下一代 VPN 协议,旨在解决许多困扰 IPSec/IKEv2、OpenVPN 或 L2TP 等其他 VPN 协议的问题。它与 Tinc 和 MeshBird 等现代 VPN 产品有一些相似之处,即加密技术先进、配置简单。
  • 从 2020 年 1 月开始,它已经并入了 Linux 内核的 5.6 版本,这意味着大多数 Linux 发行版的用户将拥有一个开箱即用的 WireGuard。
  • WireGuard 作为一个更先进、更现代的 VPN 协议,比起传统的 IPSec、OpenVPN 等实现,效率更高,配置更简单,并且已经合并入 Linux 内核,使用起来更加方便。

常见VPN方法比较

  • wireguard 精簡、速度極快:
  • 只有 4000 行程式碼,是最精簡的 VPN 協議。对比下 OpenVPN,大约有 10 万行代码。
  • WireGuard 利用内核空间处理来提升性能(更高吞吐和更低延迟),同时避免了不必要的内核和用户空间频繁上下文切换开销。

Wireguard客户端连接Debug

  • 首先,服务端的ip或者域名能ping通
  • 其次端口确定开放> nc -z -v -u 4.shaojiemike.top 51822,wg是udp
  • 修改wg客户端配置文件,限制ip为wg设置的内网段,AllowedIPs = 192.168.31.0/24,10.0.233.1/24.然后ping 192.168.31.1测试
  • 如果还不行,判断为wg的VPN包被中间网关识别并丢弃

配置文件

配置详解参考中文文档

PersistentKeepalive

  • 一端位于 NAT 后面,另一端直接通过公网暴露
  • 这种情况下,最简单的方案是:通过公网暴露的一端作为服务端,另一端指定服务端的公网地址和端口,然后通过 persistent-keepalive 选项维持长连接,让 NAT 记得对应的映射关系。
  • [peer]里设定字段 PersistentKeepalive = 25,表示每隔 25 秒发送一次 ping 来检查连接。

AllowedIPs

虽然AllowedIPs = 0.0.0.0/0AllowedIPs = 0.0.0.0/1, 128.0.0.0/1包含的都是全部的ip。

但是前者在iptable里为default dev wg1,后者为两条0.0.0.0/1 dev wg1128.0.0.0/1 dev wg1

由于路由的ip匹配遵循最长前缀匹配规则,如果路由表里原本有一条efault dev eth0。使用前者会导致混乱。但是使用后者,由于两条的优先级会更高,会屏蔽掉原本的default规则。

前者的iptable修改如下:(macbook上)

> ip route
default via link#18 dev utun3
default via 192.168.233.1 dev en0
10.0.233.5/32 via 10.0.233.5 dev utun3
224.0.0.0/4 dev utun3  scope link
224.0.0.0/4 dev en0  scope link
255.255.255.255/32 dev utun3  scope link
255.255.255.255/32 dev en0  scope link

后者的iptable修改如下

> ip route
0.0.0.0/1 dev utun3  scope link
default via 192.168.233.1 dev en0
default via link#18 dev utun3
10.0.233.5/32 via 10.0.233.5 dev utun3
128.0.0.0/1 dev utun3  scope link
224.0.0.0/4 dev en0  scope link
224.0.0.0/4 dev utun3  scope link
255.255.255.255/32 dev en0  scope link
255.255.255.255/32 dev utun3  scope link

原理

建议看WireGuard 教程:WireGuard 的工作原理WireGuard 基础教程:wg-quick 路由策略解读,详细解释了wg是如何修改路由表规则的。

wireguard 运行原理以及配置文件

默认会产生51840的路由table,ip rule优先级较高。可以通过配置文件中添加PostUp来修改最后一个default的路由规则。

root@snode6:/etc/wireguard# cat wg0.conf
[Interface]
Address = 192.168.253.5/32,fd00::aaaa:5/128
PrivateKey = eGj5skRAGJu8d………………1PVfu0lY=
# PublicKey = VWe0wBVztgX………………xd7/kZ2CVJlEvS51c=

#Table必须有,不然默认的还是会修改ip rule
Table = 51820
#DNS = 1.1.1.1 #指定DNS服务器

#启动时运行: %i 是指wg的路由, 默认修改default, metric 一般不用指定
PostUp   = /sbin/ip -4 route replace default dev %i table default metric 1
PostUp   = /sbin/ip -6 route replace default dev %i table default metric 1
#down后运行
PostDown = /sbin/ip -4 route delete  default dev %i table default metric 1
PostDown = /sbin/ip -6 route delete  default dev %i table default metric 1

PostUp会产生下面的规则

root@snode6:/staff/shaojiemike# ip ro show table default
default dev wg0 scope link metric 1

OpenVPN原理

OpenVPN原理通过在main添加all规则来实现

# shaojiemike @ node5 in ~ [22:29:05]
$ ip route show table main
0.0.0.0/1 via 192.168.255.5 dev tun1

clash TUN模式

Macbook上的应用上的ClashX Pro的增强模式类似, 会添加如下配置,将基本所有流量代理(除开0.0.0.0/8

> ip route
1.0.0.0/8 via 198.18.0.1 dev utun3
2.0.0.0/7 via 198.18.0.1 dev utun3
4.0.0.0/6 via 198.18.0.1 dev utun3
8.0.0.0/5 via 198.18.0.1 dev utun3
16.0.0.0/4 via 198.18.0.1 dev utun3
32.0.0.0/3 via 198.18.0.1 dev utun3
64.0.0.0/2 via 198.18.0.1 dev utun3
128.0.0.0/1 via 198.18.0.1 dev utun3 #前面接受所有的ip,然后转换成198.18.0.1
198.18.0.1/32 via 198.18.0.1 dev utun3 #接受转换后的198.18.0.1,由于最长前缀匹配

明显有代理死循环问题,如何解决???

shaojiemike@shaojiemikedeMacBook-Air ~/github/hugoMinos (main*) [10:59:32]
> ip route get 198.18.0.42
198.18.0.42 via 198.18.0.1 dev utun3  src 198.18.0.1
shaojiemike@shaojiemikedeMacBook-Air ~/github/hugoMinos (main*) [10:59:38]
> ip route get 198.18.0.1
198.18.0.1 dev utun3  src 198.18.0.1

Wireguard 环境配置

wireguard-go: 安装客户端 wg-quick up config wireguard-tools: 安装服务端 wg

Wireguard 常见命令

  • 启动wg-quick up wg1
  • 关闭wg-quick down wg1
  • 查看状态 wg显示全部,或者wg show wg1显示wg1

wireguard开机启动

systemctl enable wg-quick@wg1 --now

使用wireguard 代理ipv6请求

  • WireGuard 也支持 IPv6。OpenWRT 服务端,当然要allowed ip fd00::aaaa:5/128
  • 注意:这是伪需求,为什么ipv6的流量需要走ipv6,不走wg,每个机器可以获得独立的公网ipv6,对于PT做种是很好的。
brainiac1# cat wg-tsj.conf
[Interface]
PrivateKey = xxx
ListenPort = 51828
Address = 10.0.233.7/32, fd00::aaaa:5/128
Table = 51820
#DNS = 1.1.1.1

# 使用iptable修改ipv6的路由规则
PostUp   = /sbin/ip -4 route replace default dev %i table default metric 1
PostUp   = /sbin/ip -6 route replace default dev %i table default metric 1
PostDown = /sbin/ip -4 route delete  default dev %i table default metric 1
PostDown = /sbin/ip -6 route delete  default dev %i table default metric 1

[Peer]
#AllowedIPs = 0.0.0.0/0,::/0
PublicKey = xxx
AllowedIPs = 0.0.0.0/1, 128.0.0.0/1
Endpoint = 4.shaojiemike.top:51822
PersistentKeepalive = 30

两次wireguard上网

修改sysctl.conf文件的net.ipv4.ip_forward参数。其值为0,说明禁止进行IP转发;如果是1,则说明IP转发功能已经打开。

需要执行指令sysctl -p 后新的配置才会生效。

两台机器的wireguard配置

注意中间需要NAT转换, 相当于把kunpeng机器的请求,隐藏成snode6的请求。在后一次wireguard转发时,就不会被过滤掉。

PostUp   = iptables -t nat -A POSTROUTING -s 10.1.0.0/24 ! -o %i -j MASQUERADE
PostDown = iptables -t nat -D POSTROUTING -s 10.1.0.0/24 ! -o %i -j MASQUERADE || true

机器(Nas)使用Wireguard上网

问题场景

由于换了wg服务端,导致nas变成闭环的网络了。最后是通过群晖助手(Synology Assistant / Web Assistant)的设置静态ip才连接上机器,但是iptable被设置乱了。

Synology Assistant can not find nas

静态连接上机器,首先在网页管理页面切换成DHCP(静态ip的DNS解析有误),iptable变成如下

sh-4.4# ip ro
default via 222.195.90.254 dev eth0  src 222.195.90.2
10.0.233.0/24 dev wg1  proto kernel  scope link  src 10.0.233.3
222.195.90.0/24 dev eth0  proto kernel  scope link  src 222.195.90.2

sh-4.4# ip ro s t eth0-table
222.195.90.0/24 via 222.195.90.2 dev eth0

注意iptable的修改是实时生效的。

思路

为了让nas上网我们需要满足两点

  1. 本地ssh eth0的222.195.90.2能访问机器(优先级更高)
  2. 其余网络走wg
# 重要项如下
sh-4.4# ip rule
3:      from 222.195.90.2 lookup eth0-table (ping  ssh ip 222.195.90.2的会使用这个规则)
32766:  from all lookup main (ping  ssh 其余ip 比如wg的10.0.233.3的会使用这个规则)

# 1. 设置本地ssh eth0的222.195.90.2的高优先级,不至于开启wg断开ssh
# 使用命令添加: ip ro add default via 222.195.90.254 dev eth0 table eth0-table
sh-4.4# ip route show table eth0-table
default via 222.195.90.254 dev eth0
222.195.90.0/24 via 222.195.90.2 dev eth0

# 2. 为了使得除开本地ssh网络走wg,需要删除屏蔽default的wg的DHCP(如果提前删,导致机器ssh连接不上了,重新插拔网线,让DHCP重新配置):
# 使用命令添加:ip ro d default via 222.195.90.254 dev eth0  src 222.195.90.2 table main,
# 3. 防止服务端重启,Nas的wg客户端失联
# 使用命令添加:ip ro a 114.214.233.0/24 via 222.195.90.254 dev eth0  src 222.195.90.2 table main 
# 4. 测试: ping域名能正常运行

# 其余方法:为了使得除开本地ssh网络走wg,也可以不删除,在DHCP的前面添加wg的网络通路
# 使用命令添加: ip ro add default dev wg1  proto kernel  scope link  src 10.0.233.3 table main
sh-4.4# ip r s t main
default dev wg1  proto kernel  scope link  src 10.0.233.3

使用wg1配置如下:

sh-4.4# cat /etc/wireguard/wg1.conf
[Interface]
PrivateKey = xxx
ListenPort = xxx
Address = 10.0.xxx.xxx/24

Table = 51820
PostUp   = /sbin/ip -4 route replace default dev %i table default metric 1
PostDown = /sbin/ip -4 route delete  default dev %i table default metric 1

[Peer]
PublicKey = xxx
AllowedIPs = 0.0.0.0/1, 128.0.0.0/1
Endpoint = 114.xxx.xxx.xxx:xxx
PersistentKeepalive = 25

问题:服务端重启,Nas的wg客户端失联

要保留没有wg的时候访问服务端的eth0(114.214.233.xxx)的通路

sh-4.4# ip ro s t main
···
114.214.233.0/24 via 222.195.90.254 dev eth0  src 222.195.90.2
···

来自eth0的ssh与ping请求原路返回

源地址为自身IP的包走学校的路由器

目的:需要ssh和ping ipv4成功

修改netplan的配置文件

# shaojiemike @ node5 in ~ [22:29:11]
$ cat /etc/netplan/acsa.yaml
network:
  version: 2
  renderer: networkd
  ethernets:
    eno0:
      dhcp4: false
      dhcp6: false
      accept-ra: false
      addresses:
        - 202.38.73.217/24
        - 2001:da8:d800:730::217/64
      gateway4: 202.38.73.254
      gateway6: 2001:da8:d800:730::1
      nameservers:
        addresses:
          - 202.38.64.1
      routing-policy:
        - from: 202.38.73.217
          table: 1
          priority: 2
      routes:
        - to: 0.0.0.0/0
          via: 202.38.73.254
          table: 1

$netplan apply

routing-policy会产生

# shaojiemike @ node5 in ~ [22:30:33]
$ ip rule
0:      from all lookup local
2:      from 202.38.73.217 lookup 1
32766:  from all lookup main
32767:  from all lookup default
# 也可以手动添加
ip rule add from 202.38.73.217 table 1 pref 2
或者
ip rule add from 202.38.73.217 lookup 1 pref 2

由于2优先级高,使得ping和ssh的返回信包(源地址为自身机器IP的包)走table1 规则,而不是走

routes使得所有的table1都会走学校的路由器(202.38.73.254)

$ ip route show table 1
default via 202.38.73.254 dev eno0 proto static
# 也可以通过`ip route add`
$ ip route add default via 202.38.73.254 dev eno0 proto static table 1

衍生问题:网络请求的源地址不是自己吗?怎么确定的

开启wg后,网络请求源地址变成了10.0.33.2。不是202.38.73.217

root@node5:/home/shaojiemike# ip ro
10.0.33.0/24 dev wg2 proto kernel scope link src 10.0.33.2

但是外界ping的是202.38.73.217。返回包交换所以会产生源地址为202.38.73.217的包

wireguard 实现翻墙

  • WireGuard 在国内网络环境下会遇到一个致命的问题:UDP 封锁/限速。虽然通过 WireGuard 可以在隧道内传输任何基于 IP 的协议(TCP、UDP、ICMP、SCTP、IPIP、GRE 等),但 WireGuard 隧道本身是通过 UDP 协议进行通信的,而国内运营商根本没有能力和精力根据 TCP 和 UDP 的不同去深度定制不同的 QoS 策略,几乎全部采取一刀切的手段:对 UDP 进行限速甚至封锁。
  • 虽然对 UDP 不友好,但却无力深度检测 TCP 连接的真实性。
  • 将 UDP 连接伪装成 TCP 连接不就蒙混过关了。目前支持将 UDP 流量伪装成 TCP 流量的主流工具是 udp2raw,但是有一款更强大的新工具: Phantun

需要进一步的研究学习

暂无

遇到的问题

暂无

开题缘由、总结、反思、吐槽~~

参考文献

WireGuard 基础教程:使用 Phantun 将 WireGuard 的 UDP 流量伪装成 TCP

https://nordvpn.com/zh-tw/blog/vpn-xieyi/

https://blog.mozcp.com/wireguard-usage/

Assembly X86

关于X86 与 arm的寄存器的区别写在了arm那篇下

IDA analysis

word/ dword/ qword

In x86 terminology/documentation, a "word" is 16 bits

x86 word = 2 bytes

x86 dword = 4 bytes (double word)

x86 qword = 8 bytes (quad word)

x86 double-quad or xmmword = 16 bytes, e.g. movdqa xmm0, [rdi].

常见X86汇编

https://en.wikipedia.org/wiki/X86_instruction_listings

https://www.felixcloutier.com/x86/

https://officedaytime.com/simd512e/

官方手册第一个4800页

SHR     # Shift right (unsigned shift right)
SAL       # Shift Arithmetically left (signed shift left)
lea       # Load Effective Address, like mov but not change Flags, can store in any register, three opts
imul      # Signed multiply
movslq    # Move doubleword to quadword with sign-extension.
movl $0x46dd0bfe, 0x804a1dc #将数值0x46dd0bfe放入0x804a1dc的地址中
movl 0x46dd0bfe, 0x804a1dc #将0x46dd0bfe地址里的内容放入0x804a1dc地址中

lea & leaq

lea    -0xc(%ebp),%eax
mov    %eax,0x8(%esp) #常见于scanf第三个参数,lea传结果写入地址
// x is %rdi, result is %rax 就是计算地址,没有寻址操作
lea    0x0(,%rdi,8),%rax //result = x * 8;
lea    0x4b(,%rdi),%rax //result = x + 0x4b;

call & ret

  • Call 地址:返回地址入栈(等价于“Push %eip,mov 地址,%eip”;注意eip指向下一条尚未执行的指令)
  • ret:从栈中弹出地址,并跳到那个地址(pop %eip

leave

leave:使栈做好返回准备,等价于

mov %ebp,%esp
pop %ebp

compare order

cmpl   $0x5,$0x1
jle    8048bc5 # Jump if Less or Equal 会触发,前面的 1<=5

X86 load store

X86 不像 ARM有专门的ldrstr指令。是通过mov实现的

movswl (%rdi), %eax sign-extending load from word (w) to dword (l). Intel movsx eax, word [rdi]

AVX

https://docs.oracle.com/cd/E36784_01/html/E36859/gntbd.html

vxorpd   XORPD
Bitwise Logical XOR for Double-Precision Floating-Point Values

vxorps   XORPS
Bitwise Logical XOR for Single-Precision Floating-Point Values

vmovaps  MOVAPS
Move Aligned Packed Single-Precision Floating-Point Values

test & jump

test    al, al
jne     0x1000bffcc

The test instruction performs a logical and of the two operands and sets the CPU flags register according to the result (which is not stored anywhere). If al is zero, the anded result is zero and that sets the Z flag. If al is nonzero, it clears the Z flag. (Other flags, such as Carry, oVerflow, Sign, Parity, etc. are affected too, but this code has no instruction testing them.)

The jne instruction alters EIP if the Z flag is not set. There is another mnemonic for the same operation called jnz.

test   %eax,%eax
jg     <phase_4+0x35> # eax & eax > 0 jump

注意 cmp不等于 test

The TEST operation sets the flags CF and OF to zero.

The SF is set to the MSB(most significant bit) of the result of the AND.

If the result of the AND is 0, the ZF is set to 1, otherwise set to 0.

kinds of jump

AT&T syntax jmpq *0x402390(,%rax,8) into INTEL-syntax: jmp [RAX*8 + 0x402390].

ja VS jg

JUMP IF ABOVE AND JUMP IF GREATER

ja jumps if CF = 0 and ZF = 0 (unsigned Above: no carry and not equal)

jg jumps if SF = OF and ZF = 0 (signed Greater, excluding equal)

FLAGS

cmp performs a sub (but does not keep the result).

cmp eax, ebx

Let's do the same by hand:

 reg     hex value   binary value  

 eax = 0xdeadc0de    ‭11011110101011011100000011011110‬
 ebx = 0x1337ca5e    ‭00010011001101111100101001011110‬
  -    ----------
 res   0xCB75F680    11001011011101011111011010000000 

The flags are set as follows:

OF (overflow) : did bit 31 change      -> no
SF (sign)     : is bit 31 set          -> yes
CF (carry)    : is abs(ebx) < abs(eax) -> no  
ZF (zero)     : is result zero         -> no
PF (parity)   : is parity of LSB even  -> no (archaic)
AF (Adjust)   : overflow in bits 0123  -> archaic, for BCD only.

Carry Flag

Carry Flag is a flag set when:

a) two unsigned numbers were added and the result is larger than "capacity" of register where it is saved.

Ex: we wanna add two 8 bit numbers and save result in 8 bit register. In your example: 255 + 9 = 264 which is more that 8 bit register can store. So the value "8" will be saved there (264 & 255 = 8) and CF flag will be set.

b) two unsigned numbers were subtracted and we subtracted the bigger one from the smaller one.

Ex: 1-2 will give you 255 in result and CF flag will be set.

Auxiliary Flag is used as CF but when working with BCD. So AF will be set when we have overflow or underflow on in BCD calculations. For example: considering 8 bit ALU unit, Auxiliary flag is set when there is carry from 3rd bit to 4th bit i.e. carry from lower nibble to higher nibble. (Wiki link)

Overflow Flag is used as CF but when we work on signed numbers.

Ex we wanna add two 8 bit signed numbers: 127 + 2. the result is 129 but it is too much for 8bit signed number, so OF will be set.

Similar when the result is too small like -128 - 1 = -129 which is out of scope for 8 bit signed numbers.

register signed & unsigned

Positive or negative The CPU does not know (or care) whether a number is positive or negative. The only person who knows is you. If you test SF and OF, then you treat the number as signed. If you only test CF then you treat the number as unsigned. In order to help you the processor keeps track of all flags at once. You decide which flags to test and by doing so, you decide how to interpret the numbers.

register multiply

The computer makes use of binary multiplication(AND), followed by bit shift (in the direction in which the multiplication proceeds), followed by binary addition(OR).

1100100
0110111
=======
0000000
-1100100
--1100100
---0000000
----1100100
-----1100100
------1100100
==============
1010101111100

100 = 1.1001 * 2^6
55  = 1.10111* 2^5
100 * 55 -> 1.1001 * 1.10111 * 2^(6+5)

for more:

How computer multiplies 2 numbers? And: Binary multiplier - Wikipedia

Memory and Addressing Modes

声明静态代码区域

DB, DW, and DD can be used to declare one, two, and four byte data locations,

# 基本例子
.DATA       
var DB 64   ; Declare a byte, referred to as location var, containing the value 64.
var2    DB ?    ; Declare an uninitialized byte, referred to as location var2.
DB 10   ; Declare a byte with no label, containing the value 10. Its location is var2 + 1.
X   DW ?    ; Declare a 2-byte uninitialized value, referred to as location X.
Y   DD 30000        ; Declare a 4-byte value, referred to as location Y, initialized to 30000.

数组的声明,The DUP directive tells the assembler to duplicate an expression a given number of times. For example, 4 DUP(2) is equivalent to 2, 2, 2, 2.

Z   DD 1, 2, 3  ; Declare three 4-byte values, initialized to 1, 2, and 3. The value of location Z + 8 will be 3.
bytes   DB 10 DUP(?)    ; Declare 10 uninitialized bytes starting at location bytes.
arr DD 100 DUP(0)       ; Declare 100 4-byte words starting at location arr, all initialized to 0
str DB 'hello',0    ; Declare 6 bytes starting at the address str, initialized to the ASCII character values for hello and the null (0) byte.

寻址

32位X86机器寻址支持

  1. 最多支持32位寄存器和32位有符号常数相加
  2. 其中一个寄存器可以再乘上 2,4,8
# right
mov eax, [ebx]  ; Move the 4 bytes in memory at the address contained in EBX into EAX
mov [var], ebx  ; Move the contents of EBX into the 4 bytes at memory address var. (Note, var is a 32-bit constant).
mov eax, [esi-4]    ; Move 4 bytes at memory address ESI + (-4) into EAX
mov [esi+eax], cl   ; Move the contents of CL into the byte at address ESI+EAX
mov edx, [esi+4*ebx]        ; Move the 4 bytes of data at address ESI+4*EBX into EDX

# wrong and reason
mov eax, [ebx-ecx]  ; Can only add register values
mov [eax+esi+edi], ebx      ; At most 2 registers in address computation

指定存储在地址的数据大小

mov BYTE PTR [ebx], 2   ; Move 2 into the single byte at the address stored in EBX.
mov WORD PTR [ebx], 2   ; Move the 16-bit integer representation of 2 into the 2 bytes starting at the address in EBX.
mov DWORD PTR [ebx], 2      ; Move the 32-bit integer representation of 2 into the 4 bytes starting at the address in EBX.

汇编寄存器顺序,作用方向

这和汇编器语法有关:

X86 instructions

For instructions with two operands, the first (lefthand) operand is the source operand, and the second (righthand) operand is the destination operand (that is, source->destination).

mov eax, ebx — copy the value in ebx into eax
add eax, 10 — EAX ← EAX + 10

AT&T syntax

AT&T Syntax is an assembly syntax used in UNIX environments, that originates from AT&T Bell Labs. It is descended from the MIPS assembly syntax. (AT&T, American Telephone & Telegraph)

AT&T Syntax is an assembly syntax used mostly in UNIX environments or by tools like gcc that originated in that environment.

语法特点:https://stackoverflow.com/tags/att/info

需要注意的:

  1. Operands are in destination-last order
  2. Register names are prefixed with %, and immediates are prefixed with $
  3. sub $24, %rsp reserves 24 bytes on the stack.
  4. Operand-size is indicated with a b/w/l/q suffix on the mnemonic
  5. addb $1, byte_table(%rdi) increment a byte in a static table.
  6. The mov suffix (b, w, l, or q) indicates how many bytes are being copied (1, 2, 4, or 8 respectively)
  7. imul $13, 16(%rdi, %rcx, 4), %eax 32-bit load from rdi + rcx<<2 + 16, multiply that by 13, put the result in %eax. Intel imul eax, [16 + rdi + rcx*4], 13.
  8. movswl (%rdi), %eax sign-extending load from word (w) to dword (l). Intel movsx eax, word [rdi].

Intel syntax (used in Intel/AMD manuals).

The Intel assembler(icc,icpc我猜) uses the opposite order (destination<-source) for operands.

语法特点: https://stackoverflow.com/tags/intel-syntax/info

RISC-V

beq rs1, rs2, Label #RISC-V
SW rs2, imm(rs1)  # Mem[rs1+imm]=rs2 ,汇编将访存放在最后
add rd, rs1, rs2  # rd = rs1 + rs2

反汇编器

但是这个语法不是很重要,因为decompiler有选项控制语法

objdump has -Mintel flag, gdb has set disassembly-flavor intel option.

gcc -masm=intel -S or objdump -drwC -Mintel.

需要进一步的研究学习

暂无

遇到的问题

暂无

开题缘由、总结、反思、吐槽~~

参考文献

https://www.cs.virginia.edu/~evans/cs216/guides/x86.html

Localhost

环回地址

  • 环回地址,是指不离开主机的数据包(也就是说,这些数据包不会通过外部网络接口)。
  • 任何发往环回地址的数据包,其处理都在 TCP/IP 协议叠的链路层中实现的。这些数据包不会向下交由网卡(NIC)或者设备驱动程序处理,既不应在电脑系统以外出现,也不可经路由器转发。
  • 环回地址是主机用于向自身发送通信的一个特殊地址,帮助我们在同一台主机上实现client和server的功能。
  • 运用本地环回机制,便可在主机上运行网络服务,期间不须安装实体网络接口卡,也无须将该服务开放予主机所在网络。

localhost

  • localhost 是一个别名,用于指代为环回保留的 IP 地址(环回地址)。
  • IPv4使用 A 类地址的最后一个块(从 127.0.0.1 到 127.255.255)
    • 发送到这些地址(127.0.0.1 到 127.255.255.255)的所有数据包都会返回本机。
  • 而IPv6保留第一个(0:0:0:0:0:0:0:1 - 或 : :1)作为其环回地址。

0.0.0.0 任意ip

  • 0.0.0.0并不是一个真实的的IP地址,它表示本机中所有的IPV4地址。
  • 监听0.0.0.0的端口,就是监听本机中所有IP的端口。
  • 0.0.0.0是不能被ping通的。

localhost 与 127.0.0.1区别

  • localhost(本地主机)不是专门指 127.0.0.1,而是指为环回保留的整个 IP 地址范围。
    • 注意你不能总是使用127.0.0.1进行环回。
    • 仅限 IPv6 的系统不会响应此类请求,因为它们的 localhost 链接到地址::1。
    • 修改/etc/hosts文件即可修改环回的地址。但是十分不建议这样做,很可能导致本地服务崩溃
  • 请求的发送方式不同???
    • 127.0.0.1是通过网卡传输,依赖网卡,并受到网络防火墙和网卡相关的限制。
    • localhost不会解析成ip,也不会占用网卡、网络资源。一般设置程序时本地服务用localhost是最好的。

如何将环回地址某端口上的服务映射到外部网络接口

  • 可以使用ssh转发ssh -L 1313:localhost:8020 [email protected]将服务器localhost:1313上的内容转发到本地8020端口
  • hugo server -D -d ~/test/public默认会部署在localhost上
  • 解决办法hugo server --bind=202.38.72.23 --baseURL=http://202.38.72.23:1313 -D -d ~/test/public

需要进一步的研究学习

暂无

遇到的问题

暂无

开题缘由、总结、反思、吐槽~~

参考文献

https://blog.nnwk.net/article/107

UnimportantView: Game

关于偏好的循环

轮回与回旋镖:小别胜新婚

我发现我陷入了一种循环:

正向:

  1. 美术音乐和玩法的新鲜感:一开始游戏新鲜内容好奇,然后在新鲜内容耗尽时。
  2. 成就感
  3. 史诗故事感(真实代入感),和领悟
  4. 刺激感?(不适用我这里

反向:

  1. 日常的枯燥的刷任务积累,实在令人厌烦。
  2. PVP的队友的争吵和失败的挫败感也会大幅降低游玩意愿

关于PVP 和 PVE

如果在游玩的时候,如果没有对面是电脑的想法,任务的难度就是合适的,有趣的,或者有挑战的。

如果意识到了NPC反应的模板化,枯燥化,简单化的PVE就不行。 PVP可以避免这三点,但是组队的门槛、队内的矛盾、和失利会带来反向效果。

比如GTA5 online通关之后,上线之后所有东西都尝试过后,就没有留恋的意思了。除非将NPC接入AI并且动态调节难度,就可以避免这点。

如何筛选适合的游戏

现状:游玩时间少,时间碎片化,无规律

  • 游玩体验一定要舒适
    • 体验的主线内容:真实的幻想世界
      • 轻松快乐的主线剧情体验,(-20 ~ 35)
        • 一起提供代入感和沉浸式的游玩体验
        • 无剧情该项为0
        • 扣分:枯燥拖沓的演出(-10)
        • 加分:刺激有趣的剧情表演(+10)、诙谐的台本(+5),令人有所感悟的主线故事(+15)、动容的NPC故事(+5)
      • 有趣新颖的玩法(30)
        • 新鲜玩法(15)
        • 眼前一亮的细节(5)
        • 足够深的游戏内容,来随意探索;(10)
          • 或者足够精致宏大的单机主线内容(FF,大镖客2)
      • 精致华丽的美术(30)
        • 交互界面UI(3)
        • 开放世界风景(7) 震撼华丽的大场景可以弥补角色喜爱塑造的缺失
        • 令人喜爱的角色(15)
        • 动听的音乐(5)
    • 日常周常体验(40)
      • 耗时/门槛(20):
        • 无需投入大量前期时间才能正常体验
          • 经验训练技巧
          • 前置任务过多
        • 没有强制的任务指标来限制/延长在线时长
      • 收获感(10):投入有回报(货币)、提升(数值)
      • 新鲜感(10):有Rougelike元素,避免无聊
    • 手游根据逼氪程度减分
      • 200以上减5;1000以上减10

适合的类型:

  • 合家欢小游戏(主玩法,轻竞技):
    • 蛋仔、任系游戏(惊奇)
  • 主剧情的单机RPG游戏
    • 王国之泪,星际争霸(金手指)
  • 主美术的二次元轻度手游
    • 铁道
  • 网状叙事的电影史
    • 博德之门3

不适合的类型:

  • 有紧迫任务目标的游戏(大量限时任务的网游)
  • 快乐建立在胜负上的竞技类游戏(PVP游戏)

举例

231221 少女前线2 追放

首先,我没有玩过少前1,和战棋类游戏,和偏写实的剧情。

  1. 剧情与主线:
    1. 沉浸感低:谜语人,各种看不到的名词。我不知道是为了装逼还是少前1的基本概念。好的游戏,都不会在玩家理解上制造问题。
    2. 个人感觉写实的剧情立意不足,和目的性,意义行解释不清楚,导致游玩时,感觉动力不足。 由于本人并不喜欢打杀。我玩游戏也是认真玩的,如果剧情感觉不够恢弘,写实的枪战细节剧情感觉不是很动人。(可能是玄幻和幻想游戏玩多了,写实类剧情完全没接触过),需要平衡好真实感与现实的繁琐程度
  2. 美术
    1. UI简洁好看
    2. 好但可以更好,人物, 闪电姐的脸总感觉怪怪的胖胖的。黑丝等拟真质感确实不错。但是人物服饰什么的都是冷淡风,只能说之后的潜力很大。(比如像 尘白禁区泳装一样。
  3. 玩法
    1. 好但可以更好,利用地形杀,和道具之类的。(有潜力

需要进一步的研究学习

暂无

遇到的问题

暂无

开题缘由、总结、反思、吐槽~~

参考文献

Optimization Outline

Sun's 常见超线性加速的情况

http://www.cs.iit.edu/%7Esun/cs546.html#materials

https://annals-csis.org/Volume_8/pliks/498.pdf

Superlinear Speedup in HPC Systems: why and when?

  1. Cache size increased 多核的cache总size增加
  2. 在大多数的并行计算系统中,每个处理器都有少量的高速缓存,当某一问题执行在大量的处理器上,而所需要的数据都放在高速缓存中时,由于数据的复用,总的计算时间趋于减少,如果由于这种高速缓存效应补偿了由于通信造成的额外开销,就有可能造成超线性加速比。
  3. Overhead reduced 锁减少,粒度变小
  4. Latency hidden 数据预取更多了
  5. Randomized algorithms
  6. 在某些并行搜索算法中,允许不同的处理器在不同的分支方向上同时搜索,当某一处理器一旦迅速的找到了解,它就向其余的处理器发出中止搜索的信号,这就会提前取消那些在串行算法中所做的无谓的搜索分枝,从而出现超线性加速比现象
  7. Mathematical inefficiency of the serial algorithm 改并行算法
  8. Higher memory consumption access cost for in sequantial processing

应用优化前提

  1. 迭代进行 :分析程序最大热点(perf,vtune工具)->优化该热点—>分析程序最大热点->……
  2. 自顶向下分析优化程序热点的思路

    1. 全局算法的调研、理解、总体设计改进
    2. 程序任务划分,并行各部分模块
    3. 仔细分析热点的kernel循环
  3. 基本了解物理数学背景公式

  4. 阅读代码,明白实现
  5. 从main函数开始看的都是大撒比,没错,说的就是我
  6. 带着问题看,才能快速抓住重点
  7. 建议串行直接用vtune判断算法热点和时间
  8. 粗略判断热点
  9. 加入各部分热点的时间输出 (必需的:积极的正向反馈,会提高积极性和理清思路)
  10. 寻找合适的大例子
#include <omp.h>
itime = omp_get_wtime();
printf("\nTime taken is %f",omp_get_wtime()-itime);
  1. 运行n次求得平均值; 或者对不同大小的例子在不同参数下的效果拉图对比
  2. 单机不同数量多核,同机器的不同编译器,不同核心kernel/CPU
  3. warmup=10 loop=50 先热身10次,然后循环10次
./SLIC_0805_3 |tee 3.log && ./SLIC_0805_3 |tee 3.log && ./SLIC_0805_3 |tee 3.log

7. 每次优化基给予正确性的评价,并对负优化进行解释。

  1. 查看汇编
  2. 基本并行加速实现后,vtune检查访存,或者用Intel advisor的Roofline Model来分析。
  3. 新函数用 utils.cpputils.h

应用类型及其常见优化

  1. 计算密集
  2. 采用适合并行平台的算法
  3. CPU核数利用率
    1. 多进程
      1. 进程池动态调度
    2. 多线程(对于特别小的例子,一个cpu的核就够用了)
      1. 线程亲和性
      2. 线程动态调度
  4. 向量化率(提高单次计算量)SIMD
    1. 自动向量化提升有限吗?怎么写出好让编译器自动向量化的代码
      1. https://blog.csdn.net/zyl910/?type=blog SIMD测试比较
    2. pragma omp parallel for simd
    3. 循环展开,凑够无依赖计算,填满流水线avx512的宽度(8个float)
    4. intrins接口手动向量化
    5. 注意边界,不足8个单独计算
    6. 手动向量化avx2一般会快一些
  5. 降低计算量技巧
    1. 其他各种小技巧
    2. 使用掩码代替分支判断
      1. 增A:|A 删A:&(~A)判断:&A!=0
      2. https://blog.csdn.net/zyl910/article/details/7345655
    3. 替换if tmp[i][j] = (!(cnt^3))||((a[i][j]&1)&&(!(cnt^4)));
    4. 使用乘法代替除法
    5. 位运算实现整数绝对值
      1. 位运算实现浮点数绝对值
    6. 位运算实现整数MaxMin
    7. 位运算求二进制内1的个数
    8. 位运算代替乘除2运算
    9. 重新划分去除乘除,小代价是归约一下sigma
  6. 混合精度(降低部分精度,降低计算量)
  7. 数据重用(不重复计算,降低计算量)
  8. 访存密集
  9. vtune memory access分析,提高cpu访存带宽,优化2CPU通信
    1. store与load比stream慢很多
      1. 原因store是将要写的数据load到缓存里,然后修改。而stream是直接写内存。
  10. 计算分块
    1. 根据L1的大小设置块大小
      MiB = Mebibyte = 1024 KB,
      KiB = Kibibyte = 1024 Bytes,
      MB = Megabyte = 1,000 KB,
      KB = Kilobyte = 1,000 Bytes
      
    2. double 8 bytes
  11. 改变数据结构优化访存(提高cache命中率)
    1. 不合理的数据结构定义,导致数据存储不连续。通过改变数据结构,通过内存指针访问连续地址
  12. 强制使用静态链接库glibc
  13. 访存局部性原理(提高cache命中率)
    1. c语言先行后列
    2. 循环拆分、循环重组
  14. 根据cache空间,以及cache策略,进行cache数据预取,
  15. 计算融合(减少访存次数)
    1. 计算结果及时使用,去除中间结果的存储访问时间
    2. 将多个循环整合为一个
  16. 对于对同一个地址的连续读写依赖,采取pingpong-buffer来两个分治
  17. 申请空间
  18. 负载均衡(并行划分)
  19. 对不同的数据量进行不同的策略,比如数据特别少,单cpu反而最快。
  20. 二维的图,无脑按照y划分就行。
    1. 合并的时候,按照并查集(1.维护顺序 2.有代表性)
  21. 针对数据规模,是否要并行。
  22. IO密集
  23. 并行读取
  24. 内存硬盘化
  25. 通讯密集
  26. IB网通信
  27. 改变通信结构
  28. 打包发送
  29. 希尔伯特划分(一维二维)
  30. 编译选项
  31. O3优化,ipo过程优化,fp-model fast=2加速浮点计算
  32. 其他未分类

还没来得及看的优化

Software optimization resources :https://www.agner.org/optimize/

AMD 罗马米兰平台优化

https://www.bilibili.com/video/BV19q4y197uX?spm_id_from=333.999.0.0 https://www.bilibili.com/video/BV1vU4y1u7nL?spm_id_from=333.999.0.0

常见的参数

2 sockets cpu latency : 50/60

core memory bandwidth :20GB/s

样例图片

  1. 不合理数据结构,和合理的数据结构
  2. 编译选项

性能 功耗 与容错

陈子忠 教授( 美国加州大学河滨分校 ) 230616报告

  1. 多核的出现,单核能耗与频率三次方成正比,难以压住散热
  2. 在已知调度时间复杂度估计的情况下,降低频率DVFS延长执行能大幅度节约功耗。同理提升频率也行。
  3. 纠错:检查点机制,中间验证算法复杂度比计算算法复杂度低。

需要进一步的研究学习

https://johnysswlab.com/

遇到的问题

太糊了

开题缘由、总结、反思、吐槽~~

因为参加2021 IPCC,观看B站视频,学到很多特地总结一下

参考文献

https://www.bilibili.com/video/BV1Dv411p7ay