静态测试---基于WorkList的活跃变量分析

本文主要用于记录在活跃变量分析实验中的报错及解决,涉及静态测试的详细原理内容较少,编译运行底层逻辑偏多。

一、实验要求

1)使用llvm基于框架实现一个基于WorkList的活跃变量分析demo。变量在某个程序点有两种状态,live 或 dead。对于变量 x 和程序点 p,判断 x 在点 p 上的值是否会在 CFG 中的某条从点 p 出发的路径中使用。如果是,就说 x 在 p 上 live;否则就说x在p上是 dead。

目前本实验假设的输入程序当中只有整型变量(即,没有浮点、指针、结构、枚举、数组等)。

即实现LivenessAnalysis中的如下函数:

  • void LivenessPass::flowIn(Instruction *Inst, BitVector InVec)
  • void LivenessPass::flowOut(Instruction *Inst, BitVector Pre, BitVector Post)
  • BitVector LivenessPass::transfer(Instruction *Inst)
  • void LivenessPass::InstAnalysis()

这些函数对应如下Worklist算法当中的如下四个部分:

活跃变量分析为后向的数据流分析,本实验实现的demo将通过一个Worklist的大循环对LLVM IR当中的每条指令进行活跃变量的计算,其中计算的结果将以llvm::BitVector的形式存储在std::map<Value *, BitVector> INSet\OUTSet当中。

上述输出为最终预期的输出结果,其中右侧为每个指令对应的活跃变量分析结果,以 [ INSet[inst] --> OUTSet[inst] ]形式表现,且由于是后向分析,所以最后右侧的输出结果是从下到上的形式表现的。

二、实验内容:

2.1实验环境:

2.1.1环境配置:

安装LLVM 10.0.1:

  1. ##llvm10.0.1安装
  2. wget https://github.com/llvm/llvm-project/archive/llvmorg-10.0.1.tar.gz
  3. tar -zxvf llvmorg-10.0.1.tar.gz
  4. cd llvm-project
  5. mkdir build
  6. cd build
  7. cmake -DCMAKE_BUILD_TYPE=Release  -DLLVM_ENABLE_PROJECTS="clang" -G "Unix Makefiles" -DCMAKE_INSTALL_PREFIX=llvm_install_dir ../llvm
  8. make -j 4 ##4为编译运行时的线程数
  9. sudo make install
  10. ##若未安装到默认目录当中,需要在~/.bashrc当中添加路径:
  11. sudo gedit ~/.bashrc
  12. ##在文本末尾添加:
  13. export PATH="$PATH:llvm_install_dir/bin"
  14. ##更新shell:
  15. source ~/.bashrc

安装完环境后,在实验框架目录下执行以下指令编译运行:

  1. mkdir build
  2. cd build
  3. cmake ..
  4. make

若能够编译成功,你将在build目录下见到LivenessPass.so。 之后在test目录下运行./auto.sh test01得到以下输出:

  1. Running Liveness on main
  2. BitVec map:
  3. Liveness Analysis Result:
  4.   %retval = alloca i32, align 4:                        [  -->  ]
  5.   %a = alloca i32, align 4:                             [  -->  ]
  6.   %b = alloca i32, align 4:                             [  -->  ]
  7.   %c = alloca i32, align 4:                             [  -->  ]
  8.   %d = alloca i32, align 4:                             [  -->  ]
  9.   store i32 0, i32* %retval, align 4:                   [  -->  ]
  10.   %0 = load i32, i32* %a, align 4:                      [  -->  ]
  11.   %1 = load i32, i32* %b, align 4:                      [  -->  ]
  12.   %add = add nsw i32 %0, %1:                            [  -->  ]
  13.   store i32 %add, i32* %d, align 4:                     [  -->  ]
  14.   %2 = load i32, i32* %d, align 4:                      [  -->  ]
  15.   store i32 %2, i32* %b, align 4:                       [  -->  ]
  16.   %3 = load i32, i32* %a, align 4:                      [  -->  ]
  17.   store i32 %3, i32* %c, align 4:                       [  -->  ]
  18.   ret i32 0:                                            [  -->  ]

2.1.2环境情况:

Ubuntu:

Linux:

Llvm:

2.2 flowIn实现:

2.2.1文件框架:

// Inst:当前处理的Inst; InVec:当前处理的Inst的前一轮分析的Input Bitvectorvoid LivenessPass::flowIn(Instruction *Inst, BitVector InVec) {///TODO 将所有上一个Inst(由于是后向分析,所以是当前Inst的后继Inst)的Output Bitvector进行join操作作为当前Inst的Input Bitvectorauto  successors = getSuccessors(Inst);BitVector InputVec = InVec;// 遍历后继指令,并进行合并操作for (auto successor : successors) {BitVector OutputVec = OUTSet[successor];InputVec |= OutputVec;}INSet[Inst] = InputVec;// 将合并后的结果设置为当前指令的输入位向量
}
  • LivenessPass::flowIn(Instruction *Inst, BitVector InVec):

这是一个成员函数,用于计算指定指令 Inst 的输入位向量 InVec。输入位向量 InVec 表示在 Inst 执行之前活跃的变量集合。函数的目标是将所有 Inst 的后继指令的输出位向量进行合并(join操作),得到 Inst 的输入位向量。

  • auto successors = getSuccessors(Inst);:

获取 Inst 的所有后继指令。在控制流图中,后继指令是指在控制流中直接跟随 Inst 的指令。

  • BitVector InputVec = InVec;:

创建了一个新的位向量 InputVec,它是 InVec 的副本,用于存储 Inst 的最终输入位向量。

  • for (auto successor : successors) { ... }:

这个循环遍历 Inst 的所有后继指令。对于每个后继指令,它获取其输出位向量 OutputVec,这是在 successor 执行之后活跃的变量集合。

  • InputVec |= OutputVec;:

执行位向量的逻辑或操作,将 OutputVec 合并到 InputVec 中。合并操作是将所有后继指令的输出位向量合并到当前指令的输入位向量中,表示这些变量在 Inst 执行之前也是活跃的。

  • INSet[Inst] = InputVec;:

计算得到的输入位向量 InputVec 存储在 INSet 映射中,INSet 用于存储每个指令的输入位向量。

  • bool bitVectorsEqual(const BitVector& vec1, const BitVector& vec2):

用于比较两个位向量是否相等。它首先检查两个位向量的长度是否相同,如果不同,则它们不相等。然后,它遍历位向量的每个位,如果发现任何不匹配的位,则返回 false。如果所有位都匹配,则返回 true

2.3 flowOut实现 :

void LivenessPass::flowOut(Instruction *Inst, BitVector Pre, BitVector Post){
///TODO
//判断当前输出的Output Bitvector和上一轮迭代的Output Bitvector是否一致,
//如果不一致就将当前Inst的所有下一个Inst(由于是后向分析,所以是当前Inst的前继Inst)加入InstVector当中if(bitVectorsEqual(Pre,Post) ){//Pass;}else{auto nextnodes = getPredecessors(Inst);for(auto eachnodes : nextnodes)InstVector.push_back(eachnodes);}OUTSet[Inst] = Post;//?
}
  • void LivenessPass::flowOut(Instruction *Inst, BitVector Pre, BitVector Post):

这个成员函数接受三个参数:Inst 是当前正在处理的指令,Pre 是指令执行前的位向量(即输入位向量),Post 是指令执行后的位向量(即输出位向量)。

  • if(bitVectorsEqual(Pre, Post)):

用于检查当前指令的输出位向量 Post 是否与上一轮迭代的输出位向量 Pre 相同。如果它们相同,说明对于当前指令的输出位向量没有新的信息,因此不需要进行任何操作。

  • else:

如果输出位向量发生了变化,即 Pre 和 Post 不相同,那么需要更新依赖于当前指令的其他指令的活性信息。

    1. auto nextnodes = getPredecessors(Inst); 获取当前指令的所有前继指令。
    2. for(auto eachnodes : nextnodes) InstVector.push_back(eachnodes); 将这些前继指令加入到 InstVector 中,这是一个待处理的指令列表,用于后续的迭代。
  • OUTSet[Inst] = Post;:

更新当前指令 Inst 的输出位向量 OUTSet 为新的值 Post。OUTSet 是一个映射,用于存储每个指令的输出位向量。

2.4 transfer实现:

BitVector LivenessPass::transfer(Instruction *Inst) {// 实现活跃变量分析的转移函数// 初始化Use和Def集合BitVector Use = BitVector(InstCounter, false);BitVector Def = BitVector(InstCounter, false);// 根据指令类型进行分类处理if (auto *BinOp = dyn_cast<BinaryOperator>(Inst)) {Value *Operand0 = BinOp;Value *Operand1 = BinOp->getOperand(0);Value *Operand2 = BinOp->getOperand(1);Def[InstBitMap[Operand0]] = true;if (!isImmutable(Operand1))Use[InstBitMap[Operand1]] = true;if (!isImmutable(Operand2))Use[InstBitMap[Operand2]] = true;} else if (auto *Load = dyn_cast<LoadInst>(Inst)) {Value *Operand0 = Load;Value *Operand1 = Load->getOperand(0);Def[InstBitMap[Operand0]] = true;if (!isImmutable(Operand1))Use[InstBitMap[Operand1]] = true;} else if (auto *Store = dyn_cast<StoreInst>(Inst)) {Value *Operand0 = Store->getOperand(0);Value *Operand1 = Store->getOperand(1);Def[InstBitMap[Operand1]] = true;if (!isImmutable(Operand0))Use[InstBitMap[Operand0]] = true;} else if (auto *Alloc = dyn_cast<AllocaInst>(Inst)) {Value *Operand0 = Alloc;Def[InstBitMap[Operand0]] = true;} else if (auto *Cmp = dyn_cast<ICmpInst>(Inst)) {Value *Operand0 = Cmp;Value *Operand1 = Cmp->getOperand(0);Value *Operand2 = Cmp->getOperand(1);Def[InstBitMap[Operand0]] = true;if (!isImmutable(Operand1))Use[InstBitMap[Operand1]] = true;if (!isImmutable(Operand2))Use[InstBitMap[Operand2]] = true;}// 计算输出活跃变量集合BitVector Out = BitVector(InstCounter, false);BitVector Temp = INSet[Inst];for (int i = 0; i < Temp.size(); ++i) {if (Def[i])Temp[i] = false;}for (int i = 0; i < Use.size(); ++i) {if (Use[i] || Temp[i])Out[i] = true;}return Out;
}

这段代码是一个活跃变量分析(Liveness Analysis)的迁移函数transfer的实现。迁移函数用于计算在执行当前指令后,哪些变量是活跃的。活跃变量是指在指令执行后仍然有效的变量,它们可能是使用(Use)或定义(Def)的变量。

代码的主要部分是针对不同类型的指令(二元运算符、加载指令、存储指令、内存分配指令、比较指令)的分支处理。对于每种类型的指令,代码会更新Use和Def集合,然后使用这些集合来计算输出活跃变量集合。

  • BitVector Use = BitVector(InstCounter, false); 和 BitVector Def = BitVector(InstCounter, false);:

这两行代码初始化了两个位向量 Use 和 Def,它们分别用于表示指令的“使用”集合和“定义”集合。InstCounter 是指令的数量,用于确定位向量的长度。初始化时,位向量的所有位都设置为 false。

  • if (auto *BinOp = dyn_cast<BinaryOperator>(Inst)) { ... }:

这段代码处理二元运算符指令。dyn_cast 是一个类型转换函数,用于安全地将指令转换为 BinaryOperator 类型。如果转换成功,说明当前指令是一条二元运算符指令。

对于二元运算符,它的结果(Operand0)被加入到 Def 集合中,表示这个指令定义了结果值。如果操作数(Operand1 和 Operand2)不是不可变的(isImmutable 返回 false),则它们被加入到 Use 集合中,表示这些操作数被使用了。

  • else if (auto *Load = dyn_cast<LoadInst>(Inst)) { ... }:

这段代码处理加载指令(Load)。加载指令的结果被加入到 Def 集合中,表示这个指令定义了加载的值。加载指令的源操作数(Operand1)如果是可变的,则被加入到 Use 集合中。

  • else if (auto *Store = dyn_cast<StoreInst>(Inst)) { ... }:

处理存储指令(Store)。存储指令的目标操作数(Operand1)被加入到 Def 集合中,表示这个指令定义了存储的目标。存储指令的源操作数(Operand0)如果是可变的,则被加入到 Use 集合中。

  • else if (auto *Alloc = dyn_cast<AllocaInst>(Inst)) { ... }:

处理分配指令(Alloca)。

分配指令的结果被加入到 Def 集合中,表示这个指令定义了分配的内存。

  • else if (auto *Cmp = dyn_cast<ICmpInst>(Inst)) { ... }:

处理比较指令(ICmp)。

比较指令的结果被加入到 Def 集合中,表示这个指令定义了比较的结果。

比较指令的操作数(Operand1 和 Operand2)如果是可变的,则被加入到 Use 集合中。

  • BitVector Out = BitVector(InstCounter, false);:

初始化了输出位向量 Out,它将用于存储当前指令执行后的活跃变量集合。

  • BitVector Temp = INSet[Inst];:

获取了当前指令的输入位向量 INSet[Inst],并将其存储在临时位向量 Temp 中。

  • for (int i = 0; i < Temp.size(); ++i) { ... }:

遍历临时位向量 Temp,如果某个位在 Def 集合中为 true,则将该位在 Temp 中设置为 false。

这是因为如果一个变量在当前指令中被定义,那么它之前的活跃状态就不重要了。

  • for (int i = 0; i < Use.size(); ++i) { ... }:

遍历 Use 集合,如果某个位在 Use 集合中为 true 或者该位在 Temp 中为 true,则将该位在 Out 中设置为 true。

这表示这个变量在当前指令执行后仍然是活跃的。

  • return Out;:

最后,返回输出位向量 Out,它表示当前指令执行后的活跃变量集合。

2.5 InstAnalysis实现:

初次尝试:

结果:

更新后,成功!:

void LivenessPass::InstAnalysis() {///TODO///基于实现基本的WorkList循环,使用你刚刚实现的flowIn, flowOut, transfer函数实现活跃变量分析while (!InstVector.empty()){auto instruction = *InstVector.begin(); // 获取指向 Value* 的指针,注意*号,否则返回的是迭代器Instruction *Inst = dyn_cast<Instruction>(instruction);InstVector.erase(InstVector.begin());if (Inst) // 确保转换成功{BitVector Pre = OUTSet[instruction];flowIn(Inst, INSet[instruction]);OUTSet[instruction] = transfer(Inst); //transfer函数导致段错误flowOut(Inst, Pre, OUTSet[instruction]);}

代码解释如下:

  • void LivenessPass::InstAnalysis():

成员函数,用于执行活跃变量分析。

  • for (auto instIterator = InstVector.begin(); instIterator != InstVector.end(); ):

遍历指令集合 InstVector。

InstVector 是一个待处理的指令列表,包含了在活跃变量分析中需要考虑的指令。

  • Instruction *Inst = dyn_cast<Instruction>(*instIterator);:

尝试将迭代器指向的元素转换为 Instruction 类型的指针。

dyn_cast 是一个类型转换函数,用于安全地将迭代器指向的元素转换为 Instruction 类型。

  • instIterator = InstVector.erase(instIterator);:

如果转换成功,这行代码从 InstVector 中移除当前指令。

移除操作通常发生在指令被处理后,以确保在后续迭代中不会重复处理同一个指令。

  • if (Inst) // 确保转换成功:

用于确保转换成功,即当前迭代器指向的元素确实是一个指令。

  • BitVector &preOut = OUTSet[Inst];:

获取当前指令的输出位向量 preOut。

OUTSet 是一个映射,用于存储每个指令的输出位向量。

  • flowIn(Inst, INSet[Inst]);:

调用 flowIn 函数,计算当前指令的输入位向量。

INSet 是一个映射,用于存储每个指令的输入位向量。

  • OUTSet[Inst] = transfer(Inst);:

更新当前指令的输出位向量。

transfer 函数用于计算指令的输出位向量,即在该指令执行后活跃的变量集合。

  • flowOut(Inst, preOut, OUTSet[Inst]);:

调用 flowOut 函数,计算当前指令的前继指令的输出位向量。

preOut 是当前指令在执行前的输出位向量,OUTSet[Inst] 是当前指令在执行后的输出位向量。

2.6 测试结果:

三、补充内容:

报错1:no LivevessPass.so

.SO文件是共享对象文件(Shared Object File)的缩写,它是一种用于链接的文件格式,其中包含了可执行代码和数据,这些代码和数据可以被多个程序共享。.SO文件通常用于Unix-like操作系统,如Linux,它们用于动态链接,允许应用程序在运行时链接到这些文件,而不是在编译时链接。

这让我想起来之前学习时用的.a静态库,查阅资料发现:

  1. .SO文件
    • 文件扩展名:.so(共享对象)
    • 适用平台:Unix-like操作系统,如Linux
    • 文件内容:.so文件包含动态链接库(Dynamic Link Library)的代码和数据,它们可以在程序运行时被加载到内存中。.so文件通常用于提供扩展功能,如图形库、网络库等。
  2. .a文件
    • 文件扩展名:.a(静态链接库)
    • 适用平台:Unix-like操作系统,如Linux
    • 文件内容:.a文件包含静态链接库的代码和数据,它们在编译时被链接到程序中,而不是在运行时。.a文件通常用于提供基础功能,如标准库。
  3. .dll文件
    • 文件扩展名:.dll(动态链接库)
    • 适用平台:Windows操作系统
    • 文件内容:.dll文件包含动态链接库的代码和数据,它们可以在程序运行时被加载到内存中。.dll文件通常用于提供扩展功能,如图形库、网络库等。
  • 在功能上,.SO.dll文件都是用于动态链接的库文件,而.a文件是用于静态链接的库文件。静态链接和动态链接的主要区别在于,静态链接将库文件的内容直接合并到可执行文件中,而动态链接则将库文件作为外部依赖,在运行时加载。
  • 相关性方面,.SO.dll文件都是为了在运行时提供扩展功能,而.a文件则提供了基础功能。在实际应用中,.SO.dll文件可以被看作是.a文件的动态版本,它们提供了相同的库功能,但以不同的方式集成到应用程序中。

解决1:

原因是没有camke .. 和make编译…..

相关资料学习:

  1. CMake:
    • 用途: CMake是一个跨平台的构建系统生成器,它用于生成可执行的构建系统,如Makefile。
    • 生成: CMake不直接构建项目,而是生成一个构建系统,如Makefile或Ninja构建文件,然后使用Make或Ninja来构建项目。
    • 平台: CMake支持多种平台,包括Windows、macOS和Linux。
    • 配置: CMake通过一个名为CMakeLists.txt的配置文件来定义项目配置,包括依赖关系、编译选项等。
    • 构建系统: CMake生成的构建系统(如Makefile)可以由Make或Ninja使用来构建项目。
  2. Make:
    • 用途: Make是一个构建工具,用于自动化编译过程。
    • 直接构建: Make直接构建项目,根据Makefile中的规则和依赖关系来编译源代码。
    • 平台: Make在Unix-like操作系统中广泛使用,但在其他平台上也有替代品。
    • 构建系统: Makefile是由Make使用来构建项目的文件,它定义了项目的依赖关系和编译规则。

成功解决。

报错2: make报错(代码内变量未定义):

尝试2.1:改头文件(and make文件里的include)

看到众多未定义,我以为是头文件库的包含有误;

改动为:

但无效,查看cmake发现:

已经包含了include:

include_directories(${LLVM_INCLUDE_DIRS} include):将LLVM的头文件目录和项目中的include目录添加到编译器的头文件搜索路径中。

解决2:

实际是我的代码编写有误,确实没定义该内容;应该是livenesspass;

报错3: ./auto.sh 脚本内对输入处理有误

解决3:先输入一个符号避免报错,随后输入测试文件名;

Cat查看内容,如下:

同样需要换行后才能输入(为什么?)

报错4:./auto.sh执行完没有输出:

尝试4.1:print函数是否修改

教辅表示查看print,但是我并没有改动过其他print函数的文件.

解决4: 恢复原auto.sh

恢复原auto.sh.查看区别:

3,4行的cd原因见【报错5】,测试路径是在/myshixun下;

5,6行是把正确和错误输出都重定向到null;

第9行是问题关键:   没有-Liveness是没有正确输出的;

opt 是 LLVM 优化器的一个命令行工具,它用于对 LLVM IR(中间表示)进行各种优化。LivenessPass.so 是一个共享库,它包含了一个自定义的 LLVM pass(优化过程),这个 pass 被命名为 Liveness。

寻找Liveness,两个文件下找到:

加入Liveness后,成功得到输出:

报错5:头哥平台评测错误:

报错显示没有LivenessPass.so这个共享库(类似动态库);

根据之前的试错中得知这个是make后生成的----定位错误到make环节;

解决5:

pwd先看本地路径是什么:

发现是make失败,即代码有误(见报错2)

细看,发现报错是中括号中的变量处理有误:

对比成功代码,发现是:

我使用迭代器instIterator来访问InstVector中元素,并使用它作为OUTSetINSet的索引。而std::map不支持使用迭代器作为索引。

应该使用Inst作为索引,因为Inst是一个指向Instruction指针,这是OUTSetINSet中键的类型:

且这里的代码也同样出错【InstVector是向量vector,erase操作没有返回值;】:

 

探索6:命令行输出不一:

发现: 此处make时只有2个cpp.o:

而之前都是4个:

尝试在更改一个cpp文件后,直接make:---发现只有一个cpp.o---说明只会重新make更改过的文件【除非make clean 了 会重新make所有】

报错7:段错误【代码导致的】

是指针处的问题;(具体细节见前面【报错 4】)

        

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/18433.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

利用 Scapy 库编写源路由攻击脚本

一、介绍 源路由攻击是一种网络攻击方法&#xff0c;攻击者通过利用IP数据包中的源路由选项来控制数据包的传输路径&#xff0c;从而绕过安全设备或防火墙&#xff0c;直接访问目标系统。源路由功能允许数据包的发送方指定数据包通过的路径&#xff0c;而不是由路由器根据路由…

Xshell 5(xmanager5)报错

总结 所有的错误都是因为Xshell版本太低&#xff0c;与新的Linux系统不兼容导致的。 所以解决办法都是使用Xshell7 XShell 7 &#xff08;解压、运行绿化.bat&#xff09; https://pan.baidu.com/s/151W_MeLrrceUZQIFiNlMdg?pwd8888错误1&#xff1a;找不到匹配的host key算…

【LeetCode刷题】滑动窗口解决问题:串联所有单词的子串(困难)、最小覆盖子串(困难)

【LeetCode刷题】Day 10 题目1&#xff1a;30. 串联所有单词的子串&#xff08;困难&#xff09;思路分析&#xff1a;思路1&#xff1a;滑动窗口哈希map 题目2&#xff1a;LCR 017.最小覆盖子串思路分析思路1&#xff1a;滑动窗口哈希表 题目1&#xff1a;30. 串联所有单词的子…

基于51单片机的直流电机调速设计

一.硬件方案 本系统采用STC89C51控制输出数据&#xff0c;由单片机IO口产生PWM信号&#xff0c;送到直流电机&#xff0c;直流电机通过测速电路将实时转速送回单片机&#xff0c;进行转速显示&#xff0c;从而实现对电机速度和转向的控制&#xff0c;达到直流电机调速的目的。…

qt把虚拟键盘部署到arm开发板上(imx6ull)

分为了qt官方配置的虚拟键盘以及各路大神自己开源的第三方键盘&#xff0c;我本来想尝试利用官方键盘结果一直失败&#xff0c;最后放弃了&#xff0c;后面我用的第三方键盘参考了如下文章&#xff1a; https://blog.csdn.net/2301_76250105/article/details/136441243 https…

git 学习随笔

git 学习随笔 基本概念 git 对待数据类似快照流的形式而不是类似 cvs 那样的纪录文件随时间逐步积累的差异 git 中所有数据在存储钱都会计算校验和&#xff08;hash) 三种状态&#xff1a;已提交(committed)&#xff0c;已修改(modified)&#xff0c;已暂存(staged)。 add…

二叉树习题精讲-单值二叉树

单值二叉树 965. 单值二叉树 - 力扣&#xff08;LeetCode&#xff09;https://leetcode.cn/problems/univalued-binary-tree/description/ 判断这里面的所有数值是不是一样 方案1&#xff1a;遍历 方案2&#xff1a;拆分子问题 /*** Definition for a binary tree node.* struc…

k8s群集调度之 pod亲和 node亲和 标签指定

目录 一 调度约束 1.1K8S的 List-Watch 机制 ⭐⭐⭐⭐⭐ 1.1.1Pod 启动典型创建过程 二、调度过程 2.1Predicate&#xff08;预选策略&#xff09; 常见的算法 2.2priorities&#xff08;优选策略&#xff09;常见的算法 三、k8s将pod调度到指定node的方法 3.1指…

最强端侧多模态模型MiniCPM-V 2.5,8B 参数,性能超越 GPT-4V 和 Gemini Pro

前言 近年来&#xff0c;人工智能领域掀起了一股大模型热潮&#xff0c;然而大模型的巨大参数量级和高昂的算力需求&#xff0c;限制了其在端侧设备上的应用。为了打破这一局限&#xff0c;面壁智能推出了 MiniCPM 模型家族&#xff0c;致力于打造高性能、低参数量的端侧模型。…

【深度学习】xformers与pytorch的版本对应关系

https://github.com/facebookresearch/xformers/tree/v0.0.23 找tag&#xff1a; tag下面写了对应关系&#xff1a; 安装指令就是&#xff1a; pip install xformers0.0.23 --no-deps -i https://download.pytorch.org/whl/cu118

react ant 表格实现 拖拽排序和多选

项目背景 : react ant 要实现 : 有多选功能(实现批量删除 , 也可以全选) 可以拖拽(可以复制 , 方便顶部的搜索功能) 要实现效果如下 1 这是最初的拖拽功能实现 , 不能复制表格里的内容 , 不符合要求 2 更改了ROW的内容 , 实现了可以复制表格内容 代码 //控制是否可以选中表格…

基于粒子群算法的网络最优节点部署优化matlab仿真

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.本算法原理 5.完整程序 1.程序功能描述 基于粒子群算法的网络最优节点部署优化,实现WSN网络的节点覆盖最大化。 2.测试软件版本以及运行结果展示 MATLAB2022A版本运行 3.核心程序 .................…

Golang | Leetcode Golang题解之第118题杨辉三角

题目&#xff1a; 题解&#xff1a; func generate(numRows int) [][]int {ans : make([][]int, numRows)for i : range ans {ans[i] make([]int, i1)ans[i][0] 1ans[i][i] 1for j : 1; j < i; j {ans[i][j] ans[i-1][j] ans[i-1][j-1]}}return ans }

Notes for video: EDC-Con 2022/01 - EDC Conceptual Overview and Architecture

Eclipse Dataspace Connector 中文概念 Eclipse Dataspace Connector (EDC) 是一个开源项目&#xff0c;旨在提供一种标准化的方法来连接和共享数据空间中的数据。它是 Eclipse Foundation 下的一个项目&#xff0c;目标是促进数据共享和数据交换的互操作性。以下是 EDC 的一些…

【STL库源码剖析】list 简单实现

从此音尘各悄然 春山如黛草如烟 目录 list 的结点设计 list 的迭代器 list 的部分框架 迭代器的实现 容量相关相关函数 实现 insert 在指定位置插入 val 实现 push_back 在尾部进行插入 实现 erase 在指定位置删除 实现 pop_back 在尾部进行删除 实现 list 的头插、头删 实现…

Leetcode3161. 物块放置查询(Go语言的红黑树 + 线段树)

题目截图 题目分析 每次1操作将会分裂成两块区间长度&#xff0c;以最近右端点记录左侧区间的长度即可 因此涉及到单点更新和区间查询 然后左右侧最近端点则使用redBlackTree&#xff0c;也就是python中的sortedlist ac code type seg []int// 把 i 处的值改成 val func (t …

【小呆的力学笔记】连续介质力学的知识点回顾二:应变度量

文章目录 3. 格林应变与阿尔曼西应变 3. 格林应变与阿尔曼西应变 变形体在变形前的线元 O A → \overrightarrow{OA} OA &#xff0c;在变形后变成 o a → \overrightarrow{oa} oa &#xff0c;那么应变应该度量这种线元变形前后的差别。 ∣ o a → ∣ 2 − ∣ O A → ∣ 2 …

OrangePi AIpro开箱评测

开箱评测 有幸受邀参与了CSDN与OrangePi组织的评测活动&#xff0c;今天刚收到快递。拆开快递能看到保护盒、电源、双头typec线这三样&#xff08;充电器和线有保护膜的我先拆掉了&#xff09; 打开保护盒&#xff0c;能看到上下两块黑色海棉包裹的开发板&#xff08;保护得不…

cs61B-sp21 | lab6

cs61B-sp21 | lab6 TODO 1 在 CapersRepository.java 中 static final File CAPERS_FOLDER null; // TODO Hint: look at the join // function in Utils在 Utils.java 我们找到 join 函数&#xff0c;第一个 join 的作用是将 first 和 others 连接起来形成一个路径…

IDEA2024创建maven项目

1、new->project 2、创建后展示 3、生成resources文件夹 4、测试--编写一个hello文件