简介

TableGen 是一种领域特定语言(DSL),TableGen 的设计目标是允许编写灵活的描述,并将记录的通用特性提取出来,从而减少重复代码并提高代码的可维护性。

TableGen的工作流程:

前端解析

  • TableGen 的前端解析 .td 文件,这些文件包含了用 TableGen 语言编写的声明和定义。

  • 前端将这些声明和定义实例化,生成一个中间表示(IR),这个 IR 包含了所有定义的记录(records)和类(classes)。

后端处理

  • 生成的中间表示(IR)会被传递给特定领域的后端进行处理。

  • 后端根据 IR 生成目标代码,通常是 C++ 代码。不同的后端可以生成不同类型的代码,例如 LLVM 的指令集描述、MLIR 的操作定义等。

TableGen DSL当前主要的应用:

  • LLVM Target-Independent Code Generator
  • Clang diagnostics and attributes

  • MLIR Dialects Code Generator

由于本文是Triton源码解析的系列文章,后续重点分析在MLIR Dialects Code Generator中的应用。在MLIR中,TableGen主要用于代码生成,减少新增Dialect/Pass等需要手写的代码。

TableGen 基本概念

TableGen 的语法基于 C++ 模板,包含built-in types和specification。此外,TableGen 的语法引入了一些自动化概念,multiclass、foreach、let 等。

TableGen文件包含2个关键部分:classe和definition,这两者都是record。

TableGen record组成:

  • 唯一的名字
  • values列表
  • superclasses列表

TableGen definition

TableGen definition是concrete record,通常不包含未定义的值,使用def关键字标记。

示例:Triton IR中float类型:

// Floating-point Type
def TT_Float : AnyTypeOf<[F8E4M3FN, F8E4M3FNUZ, F8E5M2, 
F8E5M2FNUZ, F16, BF16, F32, F64], "floating-point">;

TableGen class

TableGen class是abstract record,用于构建和描述其他record。允许用户构建领域抽象。class可以通过def关键字实例化,生成一个definition。

示例:Triton IR中的TritonTypeDef:

class TritonTypeDef<string name, string _mnemonic, list<Trait> traits = []>: TypeDef<Triton_Dialect, name, traits> {// Used by printer/parserlet mnemonic = _mnemonic;
}// Pointer Type in C++ (corresponding to `TT_PtrOf`)
def TT_PtrType : TritonTypeDef<"Pointer", "ptr"> {let summary = "Pointer type (`::mlir::triton::PointerType`) in Triton IR type system";let description = [{Pointer type in Triton IR type system, which could be pointing to scalars or tensors.}];let parameters = (ins "Type":$pointeeType, "int":$addressSpace);let builders = [TypeBuilderWithInferredContext<(ins"Type":$pointeeType,"int":$addressSpace), [{return $_get(pointeeType.getContext(), pointeeType, addressSpace);}]>];let hasCustomAssemblyFormat = 1;let skipDefaultBuilders = 1;
}

TableGen multiclass

multiclass是一种特殊的class,表示一组相关的abstract records,通过def实例化,生成一组definitions。

示例(Triton和MLIR中未使用):

multiclass ro_signed_pats<string T, string Rm, dag Base, dag Offset, dag Extend,dag address, ValueType sty> {
def : Pat<(i32 (!cast<SDNode>("sextload" # sty) address)),(!cast<Instruction>("LDRS" # T # "w_" # Rm # "_RegOffset")Base, Offset, Extend)>;def : Pat<(i64 (!cast<SDNode>("sextload" # sty) address)),(!cast<Instruction>("LDRS" # T # "x_" # Rm # "_RegOffset")Base, Offset, Extend)>;
}defm : ro_signed_pats<"B", Rm, Base, Offset, Extend,!foreach(decls.pattern, address,!subst(SHIFT, imm_eq0, decls.pattern)),i8>;

TableGen 语法

Literals

支持Numeric Literals和String Literals。

Identifirs

和C++类似,但支持数字开头,保留关键字有:

assert     bit           bits          class         code
dag        def           dump          else          false
foreach    defm          defset        defvar        field
if         in            include       int           let
list       multiclass    string        then          true

Bang Operators

支持算术运算,逻辑运算,类型转换和检查,列表和集合操作,DAG 操作,字符串操作等。

BangOperator ::=  one of!add         !and         !cast         !con         !dag!div         !empty       !eq           !exists      !filter!find        !foldl       !foreach      !ge          !getdagarg!getdagname  !getdagop    !getdagopname !gt          !head!if          !initialized !instances    !interleave  !isa!le          !listconcat  !listflatten  !listremove  !listsplat!logtwo      !lt          !match        !mul         !ne!not         !or          !range        !repr        !setdagarg!setdagname  !setdagop    !setdagopname !shl         !size!sra         !srl         !strconcat    !sub         !subst!substr      !tail        !tolower      !toupper     !xor

Include

和C++类似:

​IncludeDirective ::= "include" TokString

Preprocess

和C++类似:

PreprocessorDirective ::=  "#define" | "#ifdef" | "#ifndef"

Types

静态类型,支持的类型:

Type    ::=  "bit" | "int" | "string" | "dag" | "code"| "bits" "<" TokInteger ">"| "list" "<" Type ">"| ClassID
ClassID ::=  TokIdentifier

Value & Expression

SimpleValue  ::=  SimpleValue1| SimpleValue2| SimpleValue3| SimpleValue4| SimpleValue5| SimpleValue6| SimpleValue7| SimpleValue8| SimpleValue9
SimpleValue1 ::=  TokInteger | TokString+ | TokCode

Statement

语句:

TableGenFile ::=  (Statement | IncludeDirective| PreprocessorDirective)*
Statement    ::=  Assert | Class | Def | Defm | Defset | Deftype| Defvar | Dump  | Foreach | If | Let | MultiClass

class

定义了一个抽象的,可以被其他record继承的record。

Class           ::=  "class" ClassID [TemplateArgList] RecordBody
TemplateArgList ::=  "<" TemplateArgDecl ("," TemplateArgDecl)* ">"
TemplateArgDecl ::=  Type TokIdentifier ["=" Value]

Record bodies

跟在class和definition后面:

RecordBody            ::=  ParentClassList Body
ParentClassList       ::=  [":" ParentClassListNE]
ParentClassListNE     ::=  ClassRef ("," ClassRef)*
ClassRef              ::=  (ClassID | MultiClassID) ["<" [ArgValueList] ">"]
ArgValueList          ::=  PostionalArgValueList [","] NamedArgValueList
PostionalArgValueList ::=  [Value {"," Value}*]
NamedArgValueList     ::=  [NameValue "=" Value {"," NameValue "=" Value}*]
Body     ::=  ";" | "{" BodyItem* "}"
BodyItem ::=  Type TokIdentifier ["=" Value] ";"| "let" TokIdentifier ["{" RangeList "}"] "=" Value ";"| "defvar" TokIdentifier "=" Value ";"| Assert

def

定义一个新的concrete record:

Def       ::=  "def" [NameValue] RecordBody
NameValue ::=  Value (parsed in a special mode)

let

let 语句收集一组字段值,并将这些值应用于 let 语句作用域内定义的所有class和record:

Let     ::=   "let" LetList "in" "{" Statement* "}"| "let" LetList "in" Statement
LetList ::=  LetItem ("," LetItem)*
LetItem ::=  TokIdentifier ["<" RangeList ">"] "=" Value

 let的语义是设置默认值或者覆盖继承的值(override),但不能覆盖template参数的值。

当record中只有少数字段需要覆盖(override)的时候,可以使用top-level的let来减少重复代码,并且let还可以嵌套,在如下示例中,isCall和Defs会分别覆盖里面3个record(CALLpcrel32/CALL32r/CALL32m)的字段值isCall和Defs:

let isCall = true in// All calls clobber the non-callee saved registers...let Defs = [EAX, ECX, EDX, FP0, FP1, FP2, FP3, FP4, FP5, FP6, ST0,MM0, MM1, MM2, MM3, MM4, MM5, MM6, MM7, XMM0, XMM1, XMM2,XMM3, XMM4, XMM5, XMM6, XMM7, EFLAGS] in {def CALLpcrel32 : Ii32<0xE8, RawFrm, (outs), (ins i32imm:$dst, variable_ops),"call\t${dst:call}", []>;def CALL32r     : I<0xFF, MRM2r, (outs), (ins GR32:$dst, variable_ops),"call\t{*}$dst", [(X86call GR32:$dst)]>;def CALL32m     : I<0xFF, MRM2m, (outs), (ins i32mem:$dst, variable_ops),"call\t{*}$dst", []>;}

multiclasses

方便一次实例化多个definition。

MultiClass          ::=  "multiclass" TokIdentifier [TemplateArgList]ParentClassList"{" MultiClassStatement+ "}"
MultiClassID        ::=  TokIdentifier
MultiClassStatement ::=  Assert | Def | Defm | Defvar | Foreach | If | Let

defm 

和multiclasses配套使用,一次实例化多个definition。

示例:

假设ISA中,对所有具体的指令,都存在两种instruction形式:

reg = reg op reg 
reg = reg op imm 

这样就可以用multiclass来同时定义两种形式,然后用defm来定义具体的instrution:

def ops;
def GPR;
def Imm;
class inst <int opc, string asmstr, dag operandlist>;multiclass ri_inst <int opc, string asmstr> {def _rr : inst<opc, !strconcat(asmstr, " $dst, $src1, $src2"),(ops GPR:$dst, GPR:$src1, GPR:$src2)>;def _ri : inst<opc, !strconcat(asmstr, " $dst, $src1, $src2"),(ops GPR:$dst, GPR:$src1, Imm:$src2)>;
}// Define records for each instruction in the RR and RI formats.
defm ADD : ri_inst<0b111, "add">;
defm SUB : ri_inst<0b101, "sub">;
defm MUL : ri_inst<0b100, "mul">;

defset 

将一组record收集到一个全局list中:

Defset ::=  "defset" Type TokIdentifier "=" "{" Statement* "}"

示例:

class MyRecord<string Name, int Value> {string name = Name;int value = Value;
}defset list<MyRecord> MyRecords = {def R1 : MyRecord<"Record1", 10>;def R2 : MyRecord<"Record2", 20>;def R3 : MyRecord<"Record3", 30>;
};

deftype

定义一个类型,类似c++的using,右边只能是primitive types和type aliases:

Deftype ::=  "deftype" TokIdentifier "=" Type ";"

defvar 

定义一个变量:

Defvar ::=  "defvar" TokIdentifier "=" Value ";"

示例:

defvar i = !add(i, 1);

foreach 

for循环:

Foreach         ::=  "foreach" ForeachIterator "in" "{" Statement* "}"| "foreach" ForeachIterator "in" Statement
ForeachIterator ::=  TokIdentifier "=" ("{" RangeList "}" | RangePiece | Value)

示例:

foreach i = [0, 1, 2, 3] in {def R#i : Register<...>;def F#i : Register<...>;
}

dump 

打印输出到stderr,用作调试:

Dump ::=  "dump" Value ";"

如果在顶层,会直接打印;如果在record中,会在该record每次实例化时打印。

示例:

multiclass MC<dag s> {dump "s = " # !repr(s);
}

if 

根据条件从2个statement中选1个:

If     ::=  "if" Value "then" IfBody| "if" Value "then" IfBody "else" IfBody
IfBody ::=  "{" Statement* "}" | Statement

assert 

断言:

Assert ::=  "assert" Value "," Value ";"

mlir-tblgen工具

在MLIR编译过程中,会使用mlir-tblgen工具将Dialect或Pass的td文件,编译为对应的C++代码:

set(LLVM_TARGET_DEFINITIONS TritonDialect.td)
mlir_tablegen(Dialect.h.inc -gen-dialect-decls) # 生成声明
mlir_tablegen(Dialect.cpp.inc -gen-dialect-defs) # 生成定义
add_mlir_doc(TritonDialect TritonDialect dialects/ -gen-dialect-doc) # 生成文档

Triton Dialect的td文件内容如下:

#ifndef TRITON_DIALECT
#define TRITON_DIALECTinclude "mlir/IR/OpBase.td"def Triton_Dialect : Dialect {let name = "tt";let cppNamespace = "::mlir::triton";let summary = "The Triton IR in MLIR";let description = [{Triton Dialect.Dependent Dialects:* Arith:* addf, addi, andi, cmpf, cmpi, divf, fptosi, ...* Math:* exp, sin, cos, log, ...* StructuredControlFlow:* for, if, while, yield, condition* ControlFlow:* br, cond_br}];let dependentDialects = ["arith::ArithDialect","math::MathDialect","scf::SCFDialect","cf::ControlFlowDialect","ub::UBDialect"];let extraClassDeclaration = [{void registerTypes();static TritonDialect *getLoaded(MLIRContext *ctx) {return ctx->getLoadedDialect<TritonDialect>();}static TritonDialect *getLoaded(Operation *op) {return getLoaded(op->getContext());}}];let discardableAttrs = (ins"::mlir::IntegerAttr":$num_stages,"::mlir::IntegerAttr":$latency,"::mlir::IntegerAttr":$self_latency);let hasConstantMaterializer = 1;let useDefaultTypePrinterParser = 1;let usePropertiesForAttributes = 1;
}include "triton/Dialect/Triton/IR/TritonTypes.td"#endif // TRITON_DIALECT

生成的声明文件如下:

/*===- TableGen'erated file -------------------------------------*- C++ -*-===*\
|*                                                                            *|
|* Dialect Declarations                                                       *|
|*                                                                            *|
|* Automatically generated file, do not edit!                                 *|
|* From: TritonDialect.td                                                     *|
|*                                                                            *|
\*===----------------------------------------------------------------------===*/namespace mlir {
namespace triton {/// The Triton IR in MLIR
/// Triton Dialect.
/// 
///     Dependent Dialects:
///       * Arith:
///         * addf, addi, andi, cmpf, cmpi, divf, fptosi, ...
///       * Math:
///         * exp, sin, cos, log, ...
///       * StructuredControlFlow:
///         * for, if, while, yield, condition
///       * ControlFlow:
///         * br, cond_br
class TritonDialect : public ::mlir::Dialect {explicit TritonDialect(::mlir::MLIRContext *context);void initialize();friend class ::mlir::MLIRContext;
public:~TritonDialect() override;static constexpr ::llvm::StringLiteral getDialectNamespace() {return ::llvm::StringLiteral("tt");}/// Parse a type registered to this dialect.::mlir::Type parseType(::mlir::DialectAsmParser &parser) const override;/// Print a type registered to this dialect.void printType(::mlir::Type type,::mlir::DialectAsmPrinter &os) const override;/// Materialize a single constant operation from a given attribute value with/// the desired resultant type.::mlir::Operation *materializeConstant(::mlir::OpBuilder &builder,::mlir::Attribute value,::mlir::Type type,::mlir::Location loc) override;/// Helper to manage the discardable attribute `num_stages`.class NumStagesAttrHelper {::mlir::StringAttr name;public:static constexpr ::llvm::StringLiteral getNameStr() {return "tt.num_stages";}constexpr ::mlir::StringAttr getName() {return name;}NumStagesAttrHelper(::mlir::MLIRContext *ctx): name(::mlir::StringAttr::get(ctx, getNameStr())) {}::mlir::IntegerAttr getAttr(::mlir::Operation *op) {return op->getAttrOfType<::mlir::IntegerAttr>(name);}void setAttr(::mlir::Operation *op, ::mlir::IntegerAttr val) {op->setAttr(name, val);}bool isAttrPresent(::mlir::Operation *op) {return op->hasAttrOfType<::mlir::IntegerAttr>(name);}void removeAttr(::mlir::Operation *op) {assert(op->hasAttrOfType<::mlir::IntegerAttr>(name));op->removeAttr(name);}};NumStagesAttrHelper getNumStagesAttrHelper() {return numStagesAttrName;}private:NumStagesAttrHelper numStagesAttrName;public:/// Helper to manage the discardable attribute `latency`.class LatencyAttrHelper {::mlir::StringAttr name;public:static constexpr ::llvm::StringLiteral getNameStr() {return "tt.latency";}constexpr ::mlir::StringAttr getName() {return name;}LatencyAttrHelper(::mlir::MLIRContext *ctx): name(::mlir::StringAttr::get(ctx, getNameStr())) {}::mlir::IntegerAttr getAttr(::mlir::Operation *op) {return op->getAttrOfType<::mlir::IntegerAttr>(name);}void setAttr(::mlir::Operation *op, ::mlir::IntegerAttr val) {op->setAttr(name, val);}bool isAttrPresent(::mlir::Operation *op) {return op->hasAttrOfType<::mlir::IntegerAttr>(name);}void removeAttr(::mlir::Operation *op) {assert(op->hasAttrOfType<::mlir::IntegerAttr>(name));op->removeAttr(name);}};LatencyAttrHelper getLatencyAttrHelper() {return latencyAttrName;}private:LatencyAttrHelper latencyAttrName;public:/// Helper to manage the discardable attribute `self_latency`.class SelfLatencyAttrHelper {::mlir::StringAttr name;public:static constexpr ::llvm::StringLiteral getNameStr() {return "tt.self_latency";}constexpr ::mlir::StringAttr getName() {return name;}SelfLatencyAttrHelper(::mlir::MLIRContext *ctx): name(::mlir::StringAttr::get(ctx, getNameStr())) {}::mlir::IntegerAttr getAttr(::mlir::Operation *op) {return op->getAttrOfType<::mlir::IntegerAttr>(name);}void setAttr(::mlir::Operation *op, ::mlir::IntegerAttr val) {op->setAttr(name, val);}bool isAttrPresent(::mlir::Operation *op) {return op->hasAttrOfType<::mlir::IntegerAttr>(name);}void removeAttr(::mlir::Operation *op) {assert(op->hasAttrOfType<::mlir::IntegerAttr>(name));op->removeAttr(name);}};SelfLatencyAttrHelper getSelfLatencyAttrHelper() {return selfLatencyAttrName;}private:SelfLatencyAttrHelper selfLatencyAttrName;public:void registerTypes();static TritonDialect *getLoaded(MLIRContext *ctx) {return ctx->getLoadedDialect<TritonDialect>();}static TritonDialect *getLoaded(Operation *op) {return getLoaded(op->getContext());}};
} // namespace triton
} // namespace mlir
MLIR_DECLARE_EXPLICIT_TYPE_ID(::mlir::triton::TritonDialect)

该文件被Triton IR的Dialect.h包含:

生成的定义如下:

#include "triton/Dialect/Triton/IR/Dialect.h"
#include "triton/Dialect/Triton/IR/Interfaces.h"
#include "triton/Dialect/Triton/IR/Types.h"#include "mlir/Dialect/ControlFlow/IR/ControlFlowOps.h"
#include "mlir/Dialect/UB/IR/UBOps.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/TypeSwitch.h"#include "triton/Dialect/Triton/IR/AttrInterfaces.cpp.inc"
#include "triton/Dialect/Triton/IR/Dialect.cpp.inc"
#include "triton/Dialect/Triton/IR/OpInterfaces.cpp.inc"using namespace mlir;
using namespace mlir::triton;//===----------------------------------------------------------------------===//
// TritonDialect Dialect Interfaces
//===----------------------------------------------------------------------===//bool TritonInlinerInterface::isLegalToInline(Operation *call,Operation *callable,bool wouldBeCloned) const {auto funcOp = dyn_cast<triton::FuncOp>(callable);if (!funcOp)return true;if (funcOp->hasAttr("noinline"))return !funcOp->getAttrOfType<BoolAttr>("noinline").getValue();return true;
}/// Handle the given inlined terminator by replacing it with a new operation
/// as necessary.
void TritonInlinerInterface::handleTerminator(Operation *op,Block *newDest) const {// Only return needs to be handled here.auto returnOp = dyn_cast<triton::ReturnOp>(op);if (!returnOp)return;// Replace the return with a branch to the dest.OpBuilder builder(op);builder.create<mlir::cf::BranchOp>(op->getLoc(), newDest,returnOp.getOperands());op->erase();
}/// Handle the given inlined terminator by replacing it with a new operation
/// as necessary.
void TritonInlinerInterface::handleTerminator(Operation *op,ValueRange valuesToRepl) const {// Only return needs to be handled here.auto returnOp = cast<triton::ReturnOp>(op);// Replace the values directly with the return operands.assert(returnOp.getNumOperands() == valuesToRepl.size());for (const auto &it : llvm::enumerate(returnOp.getOperands()))valuesToRepl[it.index()].replaceAllUsesWith(it.value());
}void TritonDialect::initialize() {registerTypes();addOperations<
#define GET_OP_LIST
#include "triton/Dialect/Triton/IR/Ops.cpp.inc">();// We can also add interface here.addInterfaces<TritonInlinerInterface>();
}Operation *TritonDialect::materializeConstant(OpBuilder &builder,Attribute value, Type type,Location loc) {return arith::ConstantOp::materialize(builder, value, type, loc);
}

该文件被Triton IR的Dialect.cpp包含:

参考资料:

TableGen Overview — LLVM 22.0.0git documentation

1 TableGen Programmer’s Reference — LLVM 22.0.0git documentation

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

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

相关文章

2、docker容器命令 | 信息查看

1、命令总览命令作用docker ps查看运行中的容器&#xff08;-a查看所有容器&#xff09;docker logs [CONTAINER]查看容器日志&#xff08;-f实时追踪日志&#xff09;docker inspect [CONTAINER]查看容器详细信息&#xff08;JSON格式&#xff09;docker stats [CONTAINER]实时…

【MySQL】MySQL中锁有哪些?

一、按照粒度分类&#xff1a; 粒度越小&#xff0c;并发度越高&#xff0c;锁开销越大。 1.全局锁&#xff1a; 作用&#xff1a; 锁定整个MySQL实例(所有数据库)。适用场景&#xff1a; 全库逻辑部分。(确保备份期间数据的一致性。)实现方式&#xff1a; 通过 FLUSH TABLES W…

语义分割--deeplabV3+

根据论文网络结构图讲一下&#xff1a;网络分为两部分&#xff1a;encoder和decoder部分。 Encoder&#xff1a;DCNN就是主干网络&#xff0c;例如resnet&#xff0c;Xception&#xff0c;MobileNet这些&#xff08;主干网络也要使用空洞卷积&#xff09;&#xff0c;对dcnn的结…

Azure DevOps 中的代理

必知词汇 深入研究 Azure DevOps 中的代理之前需要掌握的基本概念: 代理:Azure DevOps 中的代理是一个软件组件,负责执行流水线中的任务和作业。这可能包括数据中心内的物理服务器、本地或云端托管的虚拟机,甚至是容器化环境。这些代理可以在各种操作系统和环境中运行,例如…

AUTOSAR进阶图解==>AUTOSAR_SRS_ADCDriver

AUTOSAR ADC驱动详解 基于AUTOSAR标准的ADC驱动模块需求规范分析目录 ADC驱动模块概述 关键概念定义 ADC驱动架构 ADC驱动在AUTOSAR分层架构中的位置ADC驱动的主要职责 ADC驱动配置结构 通用配置(AdcGeneral)硬件单元配置(AdcHwUnit)通道配置(AdcChannel)通道组配置(AdcChanne…

宝马集团与SAP联合打造生产物流数字化新标杆

在德国雷根斯堡的宝马工厂&#xff0c;每57秒就有一辆新车下线。这座工厂不仅是汽车制造的基地&#xff0c;更是宝马集团向SAP S/4HANA云平台转型的先锋项目。通过“RISE with SAP”计划&#xff0c;宝马将该工厂的运营系统全面迁移至SAP S/4HANA Cloud Private Edition&#x…

Go 语言实战:构建一个高性能的 MySQL + Redis 应用

引言&#xff1a;为什么是 Go MySQL Redis&#xff1f;在现代后端技术栈中&#xff0c;Go MySQL Redis 的组合堪称“黄金搭档”&#xff0c;被广泛应用于各种高并发业务场景。Go 语言&#xff1a;以其卓越的并发性能、简洁的语法和高效的执行效率&#xff0c;成为构建高性能…

Excel超级处理器,多个word表格模板中内容提取到Excel表格中

在职场中&#xff0c;很多人习惯在word里插入表格&#xff0c;设计模板&#xff0c;填写内容&#xff0c;一旦有多个word文件需要整理在excel表格中&#xff0c;最常见的工作方式就是每个word文件打开&#xff0c;复制&#xff0c;粘贴到excel表格里&#xff0c;这样的工作方式…

前端工程化:ES6特性

本文为个人学习笔记整理&#xff0c;仅供交流参考&#xff0c;非专业教学资料&#xff0c;内容请自行甄别 文章目录一、let与var1.1、越狱问题1.2、变量的重复声明1.3、变量提升问题二、解构2.1、数组解构2.2、对象解构2.3、方法解构三、链判断四、参数默认值五、箭头函数六、模…

大屏项目展示

一、项目克隆与基础操作 我们参考的项目 互联网设备可视化平台---IofTV-Screen: 🔥一个基于 vue、datav、Echart 框架的物联网可视化(大屏展示)模板,提供数据动态刷新渲染、屏幕适应、数据滚动配置,内部图表自由替换、Mixins注入等功能,持续更新.... 将次项目克隆到本…

基于R语言地理加权回归、主成份分析、判别分析等空间异质性数据分析实践技术应用

在自然和社会科学领域有大量与地理或空间有关的数据&#xff0c;这一类数据一般具有严重的空间异质性&#xff0c;而通常的统计学方法并不能处理空间异质性&#xff0c;因而对此类型的数据无能为力。以地理加权回归为基础的一系列方法&#xff1a;经典地理加权回归&#xff0c;…

【Flask 基础 ①】 | 路由、参数与模板渲染

0 序言 Flask 是 Python 生态中一款轻量级 Web 框架&#xff0c;以简洁、灵活著称。 学习 Flask 的意义在于&#xff1a; 快速开发&#xff1a;通过少量代码即可搭建功能完整的 Web 应用&#xff1b;理解原理&#xff1a;其设计清晰体现了 Web 框架的核心逻辑&#xff0c;如路由…

wordpress登陆前登陆后显示不同的顶部菜单

在WordPress中让“未登录”和“已登录”用户看到不同的顶部菜单&#xff0c;最干净、最安全、最可维护的做法是&#xff1a; 在同一个菜单位置(themelocation)里&#xff0c;根据is_user_logged_in()动态切换菜单。 下面给出三种常见实现方式&#xff0c;按推荐程度排序。任选…

【昇腾推理PaddleOCR】生产级部署方式

已知的在昇腾上推理Paddle OCR有三种方法&#xff1a; 概要&#xff1a; PyTorch官方提供了昇腾插件包&#xff0c;安装后虽然可以支持PytorchOCR和PaddlePaddle的推理任务&#xff0c;但性能较低。换句话说&#xff0c;PaddlePaddle框架层面支持了昇腾&#xff0c;但具体到某个…

LangChain摘要记忆组件的使用与解析

01. 摘要记忆组件的类型 在 LangChain 中使用缓冲记忆组件要不就保存所有信息&#xff08;占用过多容量&#xff09;&#xff0c;要不就保留最近的记忆信息&#xff08;丢失太多重要信息&#xff09;&#xff0c;那么有没有一种情况是既要又要呢&#xff1f; 所以折中方案就出…

NAT与智能选路

1、NAT 基础概念核心作用&#xff1a;私网地址无法在 Internet 上直接使用和分配&#xff0c;NAT 通过将私有地址与公有地址及端口进行转换&#xff0c;实现私网与公网的通信。转换示例&#xff1a;内网用户&#xff08;10.1.1.1&#xff09;访问外网 FTP Server&#xff08;12…

【05】VisionMaster入门到精通——圆查找

文章目录1 运行参数先检测出多个边缘点然后拟合成圆形&#xff0c;可用于圆的定位与测量 1 运行参数 先检测出多个边缘点然后拟合成圆形&#xff0c;可用于圆的定位与测量——运行参数 扇环半径——圆环ROI的内外圆半经&#xff1b; 边绿类型 最强——只检测扫描范围内梯度最…

p5.js 用 beginGeometry () 和 endGeometry () 打造自定义 3D 模型

点赞 关注 收藏 学会了 在 p5.js 的 3D 绘图中&#xff0c;这两个函数是一对 “黄金搭档”&#xff1a; beginGeometry()&#xff1a;像一个 “3D 模型的开关”&#xff0c;调用它之后&#xff0c;你画的所有简单 3D 形状&#xff08;比如球体、圆锥&#xff09;都会被 “…

(9)NMPC非线性模型预测控制及机械臂ROS控制器实现

前言 本篇介绍Nonlinear Model Predictive Control&#xff0c;非线性模型预测控制&#xff0c;MPC是一种现代先进的控制方法&#xff0c;而NMPC特指对非线性模型的控制&#xff0c;其核心思想是在每个控制周期内利用系统的非线性模型及损失函数&#xff0c;预测未来一段时间内…

达梦数据库备份与还原终极指南:从基础到增量策略实战

第一部分&#xff1a;备份与还原核心原理 一、备份还原本质解析数据存储机制 数据存储在物理文件页中&#xff08;最小单位4K-32K&#xff09;有效数据页 文件描述页 已分配使用页日志优先原则&#xff1a;操作先写REDO日志再更新数据文件三大核心操作操作作用关键特性备份复…