Modeling Deep Learning Accelerator Enabled GPUs

news2024/11/19 13:20:37

Modeling Deep Learning Accelerator Enabled GPUs 发表在 ISPASS 2019 上。文章研究了 NVIDIA 的 Volta 和 Turing 架构中张量核的设计,并提出了 Volta 中张量核的架构模型。 基于 GPGPU-Sim 实现该模型,并且支持 CUTLASS 运行。发现其性能与硬件非常吻合,与 Titan V GPU 相比,获得了99.6%的 IPC 相关性。文中还展示了 Turing 架构中张量核的操作数矩阵元素到线程的映射,并发现它们与 Volta 张量核的行为不同。

Related Work

论文的相关工作:

  • Demystifying GPU Microarchitecture through Microbenchmarking 使用广泛的微基准对 NVIDIA GT200进行了透彻的分析。他们探索了处理核和内存层次结构的架构细节。描述了先前未公开的屏障同步和内存层次结构的细节,包括 GPU 中的 TLB 组织。

  • Dissecting the NVIDIA Volta GPU Architecture via Microbenchmarking 详细研究了张量核。他们在混合精度模式下解码了 Volta 张量核的集合和步骤。

  • NVIDIA Tensor Core Programmability, Performance & Precision 研究了 Tensor Core 的精度损失和可编程性方面对 HPC 应用的影响。

  • Exploring Modern GPU Memory System Design Challenges through Accurate Modeling 研究了包括 Volta 在内的现代 GPU 的内存系统,并发现了内存系统中许多重要的设计决策。他们在 GPGPU-Sim 中对其进行建模,并在广泛的 GPGPU 工作负载上实现了非常高的相关性。

Background

Volta Microarchitecture

Volta 是 NVIDIA 第一代包含机器学习加速器的 GPU 架构。NVIDIA GPU 通常由多个流式多处理器 (Streaming Multiprocessor, SM) 组成,这些处理器通过片上网络连接到多个内存分区。 每个内存分区都包含最后一级缓存的一部分,并将 GPU 连接到片外 DRAM。 正如 NVIDIA 所描述的,每个 SM 内包含多个张量核。Volta 中的 SM 设计分为四个处理块,NVIDIA 将其称为 Sub-Core。如图 1所示,Volta 中的每个子核都有两个张量核、一个 Warp 调度器、一个调度单元和一个64KB 的寄存器文件。
在这里插入图片描述
除了新增张量核之外,Volta 还包括与机器学习工作负载性能相关的其他增强功能:

  • 每个流式多处理器 (SM) 的调度单元数量是上一代 Pascal 架构的两倍;
  • 拥有独立的整数和 32 位浮点 (FP32) 核;
  • 对发散线程,分支后面的两条路径都可以由单个 warp 内的线程以交错的方式执行。

Tensor Core

每个张量核都是一个可编程计算单元,专门用于加速机器学习工作负载。Tesla Titan V GPU 包含分布在80个 SM 中的640个张量核,每个 SM 有8个张量核,在1530 MHz 的工作频率下提供125 TFLOPS 的理论性能。根据 NVIDIA TESLA V100 GPU ARCHITECTURE,每个张量核可以在每个时钟周期完成一次 4 × 4 4\times 4 4×4 矩阵乘法累加 (MACC),即 D = A × B + C D=A\times B+C D=A×B+C,其中 A , B , C A ,B,C A,B,C 4 × 4 4\times 4 4×4 矩阵,如图 3 所示。
在这里插入图片描述

虽然单个张量核在任何时候都对 4 × 4 4 \times 4 4×4 矩阵进行操作,但 WMMA API 在更大的图块大小上公开张量核。自然地,两个 16 × 16 16 \times 16 16×16 矩阵的乘法分解为一个分块矩阵乘法,结果矩阵由十六个 4 × 4 4 \times 4 4×4 子矩阵构成,每个涉及四个 4 × 4 4 \times 4 4×4 矩阵相乘累加。因此,CUDA C++ WMMA 级别的每个mma_sync或 PTX 级别的每个 wmma.mma操作可以用64个独立的张量核操作来实现。

张量核有 FP16 和混合精度两种工作模式:

  • 在 FP16模式下,张量核读取三个 4 × 4 4 \times 4 4×4 16位浮点矩阵作为源操作数;
  • 而在混合精度模式下,它读取两个 4 × 4 4 \times 4 4×4 16位浮点矩阵以及第三个 4 × 4 4 \times 4 4×4 32位浮点累加矩阵。

Demystifying NVIDIA’s Tensor Cores

Dissecting the NVIDIA Volta GPU Architecture via Microbenchmarking 研究了列主布局中混合精度模式的矩阵操作数元素到寄存器的分布情况。文中将线程束内的一组四个连续线程称为“线程组”。

为了描述方便,论文余下部分中将其缩写为 threadgroup。由于一个 warp 中有32个线程,因此一个线程束中有 8 8 8threadgroup。给定线程的 threadgroup id(类似于 Dissecting the NVIDIA Volta GPU Architecture via Microbenchmarking 中的“group id”)根据 ⌊ t h r e a d I d x 4 ⌋ \lfloor\frac{threadIdx}{4}\rfloor 4threadIdx 得到。

Microbenchmarks

本节讨论了用于分析张量核实现的微基准测试。其包含两种类型的微基准测试:

  • 一种旨在确定数据如何移入和移出张量核;
  • 另一种用于确定张量核执行操作所需的时间。
Fragment to thread mapping

图 4包含 III-B 节中使用的 CUDA 代码的一部分,用于确定操作数矩阵元素和线程之间的映射。此代码是在 16 × 16 16\times16 16×16 矩阵上运行的更大的通用矩阵乘法 (GEMM) 内核的一部分。每个线程加载输入矩阵的一个段并将其打印到输出控制台。通过使用不同的值初始化输入矩阵的每个元素,可以直接揭示从操作数矩阵元素到线程束内线程的映射。
在这里插入图片描述

Analyzing machine instructions

正如在 III-C. Machine ISA interface 节中详细描述的那样,PTX 指令被映射为多个HMMA SASS 指令。图 5 在高层次上说明了用微基准测试分析HMMA指令如何访问数据时的操作。作者使用 radare2 将HMMA操作替换为“无操作” ( NOP) 指令的操作,仅保留一个HMMA操作。
在这里插入图片描述

图 6 概括地说明了微基准测试用于分析张量核心上低级操作的时序的方法。为了开发这些微基准测试,作者使用 radare2 添加了在 1 s t 1^{st} 1st 之前和 n t h n^{th} nth HMMA指令之后读取时钟寄存器的代码。
在这里插入图片描述

Operand matrix element mapping

本节总结了矩阵元素到线程的分布的分析结果。

Volta Tensor Cores

图 7a 和 7b 总结了矩阵操作数的元素如何映射到线程束内各个线程的寄存器。

  • 大矩形 ( 1 ◯ \textcircled{1} 1) 表示 FP16和混合精度操作模式的 16 × 16 16\times16 16×16 操作数矩阵 A 或 B。
  • 较小的方块是操作数矩阵中的各个元素,同一行中的元素在内存中连续存储。
  • 每个 threadgroup 加载一个不同的 4 × 16 4\times16 4×16 子矩阵,文中将其称为一个段。组成操作数矩阵的四个段用不同的着色突出显示。

在这里插入图片描述
图 7a 的右上部分 ( 2 ◯ , 3 ◯ \textcircled{2},\textcircled{3} 2,3) 显示了段内的元素如何分布在一个线程组的线程中。在 Volta 上,每个段都由两个不同的 threadgroup 加载。因此,A 和 B 操作数矩阵的每个元素 由 Volta 上的线程束中的两个不同线程加载。图 7a 的底部部分 ( 4 ◯ \textcircled{4} 4) 与左上角部分 ( 1 ◯ \textcircled{1} 1) 相结合,总结了确切的映射。例如,实验发现操作数矩阵 A 的连续前四行由 threadgroup 0和2加载。

以行优先布局存储的操作数矩阵 A 的矩阵元素到线程的分布与以列优先布局存储的操作数矩阵 B 的分布相同,反之亦然。

  • 对于行主布局中的操作数矩阵 A,threadgroup 内的每个线程使用两个合并的 128 位宽加载指令,加载一行中的 16 16 16 个连续元素 ( 2 ◯ \textcircled{2} 2);
  • 而在列主布局中为了加载4行, threadgroup 内的每个线程通过四个合并的 64 位宽加载指令加载四个块,每个块内四个连续元素,每个加载指令的跨距为 64 个元素 ( 3 ◯ \textcircled{3} 3)。

如图 7b 所示,对于操作数矩阵 C,矩阵元素到线程的分布是不同的。具体来说,

  • 对于操作数矩阵 C,每个 threadgroup 加载矩阵 C 的一个 8 × 4 8\times 4 8×4 段。
  • threadgroup 内的具体分布取决于矩阵 C 是 FP16还是 FP32,并且与布局无关。

在两种工作模式下,均使用32位宽(部分合并)的加载指令访问矩阵 C 的元素。

Turing Tensor Cores

图 8 总结了 NVIDIA Turing 架构中张量核的操作数矩阵元素到线程的分布。Turing 的张量核心支持三种新的精度模式:1位、4位和8位,以及三种新的图块大小:8位和16位模式的 32 × 8 × 16 32\times 8\times 16 32×8×16 8 × 32 × 16 8\times 32\times 16 8×32×16,4位模式为 8 × 8 × 32 8\times 8\times 32 8×8×32
figure 8Figure 8: Distribution of operand matrix elements to threads for tensor cores in the RTX 2080 (Turing).

在撰写本文时,对1位模式的支持才启用,并且似乎不适用于文中的系统。因此,本文其余部分不提供1位模式的分析。

Turing 的元素到线程的分布比 Volta 更简单。具体而言,

  • 每个操作数矩阵元素仅加载一次。
  • 两种图块尺寸 32 × 8 × 16 32\times 8\times 16 32×8×16 8 × 32 × 16 8\times 32\times 16 8×32×16 都采用相同的分布。
  • 对于所有模式和配置,每行或列(取决于模式和操作数矩阵)由 threadgroup 加载,并且连续的 threadgroup 加载连续的行或列。

Machine ISA interface

本节总结了作者所了解的有关如何在机器指令集架构级别访问 Tensor Core 的知识。 对于 NVIDIA GPU,这个层次通常称为 SASS。这里的分析基于使用 NVIDIA 的 cuobjdump 工具检查 SASS 反汇编。

论文发现wmma.loadwmma.store PTX 指令是通过分解为一组普通的 SASS 加载(LD.E.64LD.E.64LD.E.SYS) 和存储 (ST.E.SYS) 指令来实现的。这表明 Tensor Core 直接从普通 GPU 寄存器文件中访问操作数矩阵片段。更详细地说,发现wmma.load.c PTX 指令被分解为一组LD.E.SYS指令。

对于操作数矩阵 A 和 B,根据操作数矩阵布局是行优先还是列优先,将wmma.load PTX 指令拆分为四个 64 位加载 (LD.E.64) 或两个 128 位负载 (LD.E.128)。

图 9 说明了单个wmma.mma PTX 指令所对应的 Volta 的 SASS 代码。
在这里插入图片描述
从图中可以看出,

  • 矩阵乘法累加运算是通过新的 SASS 指令HMMA实现的。
  • 每个HMMA指令有四个操作数,每个操作数使用一对寄存器。
  • 由不同内存操作访问的一对相邻寄存器使用单个寄存器标识符编码在HMMA指令中(通过比较HMMA以及加载和存储使用的寄存器可以推断出)。例如,论文分析图 9 中第一条HMMA指令中的R8表示寄存器对<R8,R7>
  • 寄存器对中较高位的寄存器标识符是指令中编码的寄存器标识符。例如,对于图 9 第一行的HMMA指令,目标寄存器R8实际上代表<R8,R7>对。 类似地,剩余的寄存器标识符实际上代表三对源操作数寄存器(<R24,R23><R22,R21><R8, R7>)。
  • 一些寄存器在图 9 中用“reuse”注释。 SGEMM Implementation 分析了 NVIDIA 针对早期 Maxwell 架构的 SASS 指令集,其中经常出现类似的注释。根据他的分析和 NVIDIA 关于 GPU 寄存器文件缓存的相关论文[43],作者认为“reuse”符号表示相关操作数在下一步中被重用,因此缓存在操作数重用缓存以避免寄存器读取并可能减少 bank冲突。
Volta Tensor Cores

每个wmma.mma PTX 指令被分解为一组HMMA指令:

  • 图 9a 说明了混合精度模式的 SASS 代码。在该模式下,
    • 每条 PTX wmma.mma指令被分解成16条HMMA指令。
    • 16条HMMA指令被组织为4条HMMA指令的4个集合
    • 每条HMMA指令用" STEP<n>"标注,其中<n>的取值范围从0到3。因此,每个集合包括四个步骤。
  • 图 9b 说明了 FP16 模式的 SASS 代码,其中,
    • 单条 PTX wmma.mma指令分为四组;
    • 仅包含 2 个步骤。

图 9 还显示了 Volta Tensor Core 的累积时钟周期。wmma.mma API 在混合精度模式下的延迟比 FP16模式下低十个周期。

Turing Tensor Cores

对于 Turing,每条 PTX wmma.mma指令

  • 在4位模式下转换为单条HMMA指令;
  • 其他模式下均都分为一组四个HMMA指令。

表 I 显示了 Turing 架构上HMMA指令的累积时钟周期。 对于 16 × 16 × 16 16\times 16\times 16 16×16×16 图块大小,Turing 上混合精度模式下 wmma.mma的延迟为99个周期(表 I), 多于 Volta 的54个周期(图 9a)。混合精度模式的延迟大于 FP16模式。8位模式速度最快。4位模式的延迟最高,这可能是因为它是2080 RTX 上的一个实验特性。
在这里插入图片描述

HMMA Instruction Analysis

本节将更详细地探讨HMMA执行。

Volta

作者考察了图 9 中HMMA指令的每个"集合"的操作。如图 10a 所示,无论模式如何,当执行集合中的HMMA指令时,每个 threadgroup 将操作数矩阵 A 的 4 × 4 4\times4 4×4 图块与操作数矩阵 B 的 4 × 8 4\times 8 4×8 图块相乘,并将结果与操作数矩阵 C 相加。例如,当 threadgroup 0 执行第一组HMMA指令 (Set 1) 时,它将由操作数矩阵 A 的前四行和前四列组成的子图块与由操作数矩阵 B 的前四行和前八列组成的子图块相乘。结果通过操作数矩阵 C 的 4 × 8 4\times8 4×8 子图块进行累加,并存储在操作数矩阵 D 的 4 × 8 4\times8 4×8 子图块中。串联4个集合,threadgroup 0 完成操作数矩阵 A 的 4 × 16 4 \times 16 4×16 图块与操作数矩阵 B 的 16 × 8 16 \times 8 16×8 图块的乘法。
在这里插入图片描述

图 10b 显示了混合精度模式下 threadgroup 0 的“集合”中每个HMMA “步骤”的详细操作。HMMA指令的每个“集合”包含四个“步骤”。在每个步骤中,操作数矩阵 A 的 2 × 4 2\times4 2×4 子图块与操作数矩阵 B 的 4 × 4 4\times4 4×4 子图块相乘,并与操作数矩阵 C 的 2 × 4 2\times4 2×4 子图块累加。

类似地,图 10c 显示了 FP16模式下 threadgroup 0 的“集合”中每个HMMA“步骤”的详细操作。每组HMMA指令包含两个“步骤”。在每个步骤中,每个线程组将操作数矩阵 A 的 4 × 4 4\times4 4×4 子图块与操作数矩阵 B 的 4 × 4 4\times4 4×4 子图块相乘,并将结果与矩阵 C 累加。

经过以上步骤,threadgroup 0 完成操作数矩阵 A 的 8 × 4 8\times4 8×4 子图块与操作数矩阵 B 的 4 × 8 4\times8 4×8 子图块的乘法。

Turing

图 11 说明了 Turing GPU 架构上HMMA指令访问的元素。 Volta 中HMMA SASS 指令上发现的“step”注释在 Turing 中不存在。
在这里插入图片描述考虑到表 I 中的延迟结果并不表明并行性增加,一种可能性是类似的“步骤”由微体系结构使用状态机排序。作者认为:

  • 对于不同的图块配置,特定模式访问的元素是相似的。
  • 在 FP16 和混合精度模式下,计算模式是两个子图块之间的乘积,其中一个子图块是 8 × 8 8\times 8 8×8,另一个子图块是 16 × 8 16\times 8 16×8 8 × 16 8\times 16 8×16。 例如,对于图块大小 16 × 16 × 16 16\times 16\times 16 16×16×16 32 × 8 × 16 32\times 8\times 16 32×8×16,SET 1 中的计算是矩阵 A 的 16 × 8 16\times 8 16×8 子图块与矩阵 B 的 8 × 8 8\times 8 8×8 子图块之间的乘积,而对于图块大小 8 × 32 × 16 8\times 32\times 16 8×32×16,乘积在矩阵 A 的 8 × 8 8\times 8 8×8 子图块与矩阵 B 的 8 × 16 8\times 16 8×16 子图块之间。
  • 对于8位模式,计算模式为矩阵 A 的 8 × 16 8\times16 8×16 子图块与矩阵 B 的 16 × 8 16\times8 16×8 子图块之间的乘积。

在4位模式下,每个 wmma.mma PTX 指令都是用单个HMMA SASS 指令实现的,因此在图 11 中省略了4位模式。

Discussion

本节对上面给出的 Volta 结果进行分析,并推断出将执行分解为“集合”和“步骤”的可能理由。

回想一下,输入矩阵的每个元素都由两个不同的 threadgroup 加载。作者编写了一个微基准测试来帮助确定HMMA指令如何使用不同线程加载的片段。例如,为了确定如何使用由 thread 0 加载的操作数矩阵元素,作者更改了这些值并观察结果如何受到影响。论文发现 threadgroup 成对工作以计算结果的 8 × 8 8\times8 8×8 子图块,并将每对这样的线程组称为 octet。一个线程束中有四个 octet

表 II 显示了构成每个 octetthreadgroup 对,一般可以表示为 o c t e t   X = t h r e a d g r o u p   X ⋃ t h r e a d g r o u p   X + 4 \mathrm{octet}\, X = \mathrm{threadgroup}\, X \bigcup\mathrm{threadgroup}\, X+4 octetX=threadgroupXthreadgroupX+4,其中 X X X 介于 0 到 3 之间。表 II 还使用符号[Row_Start: Row_End, Col_Start: Col_End]来表示每个 threadgroup 内的线程访问的操作数矩阵 A 和 B 的子图块。无论操作数矩阵的存储布局如何,threadgroup 加载的元素都保持不变。
在这里插入图片描述

表 II 显示操作数矩阵 A 和 B 的每个元素被不同 threadgroup 中的线程加载两次。这使得每个 octet 能够独立工作。具体来说,每个 octet 读取操作数矩阵 A 的 8 × 16 8\times 16 8×16 子图块、操作数矩阵 B 的 16 × 8 16\times 8 16×8 子图块和操作数矩阵 C 的 8 × 8 8\times 8 8×8 子图块,如图 12a 所示。
在这里插入图片描述

为了更好地理解 octet 中线程的组织,作者分析了 octet 在不同“集合”和“步骤”中执行的计算。如图 12b 所示,在每个集合中,每个 octet 执行输入子图块之间的外积。例如,在 Set 1 中,完成输入子图块 [ a ] , [ e ] [a],[e] [a],[e] [ A ] , [ E ] [A],[E] [A],[E] 之间外积,生成部分结果 [ a A ] , [ a E ] , [ e A ] [aA], [aE], [eA ] [aA],[aE],[eA] [ e E ] [eE] [eE]。这里每个 [ a ] , [ e ] , [ A ] , [ E ] [a],[e],[A],[E] [a],[e],[A],[E] 代表一个 4 × 4 4 \times 4 4×4 子图块。为了计算 [ a E ] [aE] [aE]threadgroup 0 需要操作数矩阵 B 子图块 [ E ] [E] [E],它仅由 threadgroup 4 加载。类似地,要计算 [ e A ] [eA] [eA]threadgroup 4 需要操作数矩阵 B 子图块 [ A ] [A] [A],它仅由 threadgroup 0 加载。因此,虽然 threadgroup 不能,但 octet 可以独立工作。表 III 在图 12b 的基础上进行了扩展,将在不同集合和步骤中执行的所有外积计算制成表格。
在这里插入图片描述

A Tensor Core Microarchitecture

本节提出了一个张量核微架构,其与本文前面对 Volta 的观察结果一致。

回想一下,每个张量核每个周期完成 4 × 4 4\times4 4×4 矩阵乘法并累加。 为了实现这一目标,每个张量核必须能够在每个周期执行16个四元素点积(four-element dot-products,FEDP)。如图 9 和 图 10b 所示,在稳定状态下, threadgroup 需要两个周期来生成输出矩阵的 2 × 4 2\times 4 2×4 子图块。 因此,在 warp 内的所有线程中,HMMA指令每个周期执行32个 FEDP。由于每个张量核每个周期只能完成16个 FEDP,因此 SM 中每个子核需要两个张量核才能达到满吞吐量。为了证实这一点,作者编写了一个微基准测试,它重复执行HMMA操作,改变每个线程块内的 warp 数量,并保持并发执行的线程块数量不变。如图 12c 所示,该微基准测试显示单个 SM 上只能同时执行 4 个 warp,但 Titan V SM 每个 SM 有 8 个张量核。 因此,每个 warp 似乎都利用了两个张量核。

接下来,考虑寄存器访问带宽。图 9a 中的数据表明HMMA指令的最小启动间隔是两个周期。有三个源操作数,并且如第 III-C 节中所述,对于每个源操作数,读取一对32位寄存器。综合考虑这些因素,总寄存器读取带宽为每个线程束每两个周期 32 × 2 × 3 × 32 = 6 k b 32\times2\times3\times32 = 6\mathrm{kb} 32×2×3×32=6kb。 此带宽足以让线程束每两个周期获取以下值:

  • 操作数 A 的八个 2 × 4 2\times4 2×4 FP16子图,
  • 操作数 B 的八个 4 × 4 4\times4 4×4 FP16子图,
  • 以及操作数 C 的八个 2 × 4 2\times4 2×4 FP32子图或八个 4 × 4 4\times4 4×4 FP16子图。

假设每个线程束访问两个张量核,每个张量核的寄存器带宽为每个时钟周期每个线程束1.5kb。

NVIDIA 指出在 Volta 中 INT 和 FP32指令可以共同下发[26]。另一方面,Dissecting the NVIDIA Volta GPU Architecture via Microbenchmarking 报告张量核运算不能与整数和浮点算术指令共同发出。 论文认为原因是张量核可能正在使用与 INT 和 FP32核关联的寄存器文件访问端口。Titan V SM 内部有64个 INT 和64个 FP32 ALU,共计128个 ALU。由于一个 SM 中的8个张量核共享对寄存器文件的访问权限,每个张量核每个周期应该能够访问每个源操作的 128 8 × 32 = 16 × 32 = 512 \frac{128}{8}\times32=16\times32=512 8128×32=16×32=512 比特。假设每个 ALU 有3个源操作数(以支持乘法累加运算),这意味着每个张量核可以访问1.5kb/cycle。

图 13 展示了论文提出的张量核微架构。每个线程束使用两个张量核。假设线程束内每个张量核经由两个不同的 octet 访问。每个张量核有16个专用 SIMD 通道,每个 octet 有8个通道,每个 threadgroup 有 4 个通道。每个 threadgroup 通道将操作数送入内部缓冲区。

在这里插入图片描述

对于操作数矩阵 A 和 C,每个 threadgroup 将操作数提取到其单独的缓冲区,而对于操作数矩阵 B,两个 threadgroup 都将操作数提取到共享缓冲区。操作模式和步骤决定了从中获取每个操作数的 threadgroup 通道。缓冲器为16个 FP16 FEDP 单元提供数据。在每个 FEDP 单元内部,乘法在第一阶段并行执行,累加发生在三个阶段,总共四个流水线阶段。由于每个张量核由16个 FP16 FEDP 单元组成,因此每个周期能够完成一个 4 × 4 4\times4 4×4 矩阵乘法。

参考资料:

  • # [DOC] Where does cutlass’ detailed GEMM kernel? #526
  • Dissecting the NVIDIA Volta GPU Architecture via Microbenchmarking
  • Modeling Deep Learning Accelerator Enabled GPUs
  • NVIDIA Tensor Core微架构解析

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

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

相关文章

git log 命令详解

测试仓库 asdf 常用参数 查询指定目录 git -C /Users/yanlp/workspace/asdf log 限制显示提交数量 git log -n 3 限制提交人|邮箱 git log --authorEdwin Kofler | git log --authoredwinkofler.dev 限制一个月内的提交git log --since1.month.ago | git log --since2023-0…

1024程序员狂欢节特辑 | ELK+ 协同过滤算法构建个性化推荐引擎,智能实现“千人千面”

专栏集锦&#xff0c;大佬们可以收藏以备不时之需 Spring Cloud实战专栏&#xff1a;https://blog.csdn.net/superdangbo/category_9270827.html Python 实战专栏&#xff1a;https://blog.csdn.net/superdangbo/category_9271194.html Logback 详解专栏&#xff1a;https:/…

推荐一款支持异步批量下载图片的chrome插件——图片助手(ImageAssistant) 批量图片下载器

https://chrome.google.com/webstore/detail/imageassistant-batch-imag/dbjbempljhcmhlfpfacalomonjpalpko/related?hlzh-CNhttps://chrome.google.com/webstore/detail/imageassistant-batch-imag/dbjbempljhcmhlfpfacalomonjpalpko/related?hlzh-CN 安装后直接点击 会根据…

第五章Maven依赖的特性-进阶篇

文章目录 第一节 重新认识MavenMaven 的完整功能项目管理功能的具体体现 POM 的四个层次超级 POM父 POM有效 POM概念查看有效 POM 小结 属性的声明与引用help 插件的各个目标使用 help:evaluate 查看属性值通过 Maven 访问系统属性Java 系统属性一览使用 Maven 访问系统属性 访…

Django 注册及创建订单商品

注册功能的实现 user/views from rest_framework.generics import GenericAPIView from rest_framework.views import APIViewfrom apps.user.models import User from apps.user.serializers import UserSerializer from utils import ResponseMessage from utils.jwt_auth …

Unity OnGUI调试工具

背景 在产品开发过程中调试数据是必不可少的过程之一&#xff0c;那么涉及到频繁的设置数据、运行unity等一系列繁琐的操作&#xff0c;有没有更好的办法呢&#xff1f;答案是肯定有更好的办法。这里我所用到的是unity自带的OnGUI相关的工具可以实时的更改数据调试。 代码 usi…

有没有人声和背景音乐分离的神器?

做视频剪辑&#xff0c;二次创作的朋友&#xff0c;需要去除视频中的背景音乐&#xff0c;保留人声&#xff1b;或者去除人声&#xff0c;保留背景音乐。随着用户需求的增多&#xff0c;科技的发展&#xff0c;让我们能通过智能的人声分离软件来实现&#xff0c;下面就来看看如…

基于AT89C51+DS1302+LCD1602的实时时钟proteus仿真设计

一、DS1302简介&#xff1a; DS1302 可慢速充电实时时钟芯片包含实时时钟/日历和 31 字节的非易失性静态 RAM。它经过一个简 单的串行接口与微处理器通信。实时时钟/日历可对秒&#xff0c;分&#xff0c;时&#xff0c;日&#xff0c;周&#xff0c;月&#xff0c;和年进行计数…

无人驾驶智能改造机场“人货场”

机场作为国家的门户&#xff0c;承载着众多旅客与货物的流动&#xff0c;其运行效率直接关系到整个国家的发展和繁荣。随着科技的进步&#xff0c;无人驾驶技术日益成熟&#xff0c;智能交通革新将成为现实&#xff0c;将其应用于机场会为我们带来更加便捷、高效的出行体验&…

【Javascript】数组练习(在排好序的数组⾥,按照⼤⼩顺序插⼊数据)

var array[1,4,5,7,9,17]; console.log(array);比如要插入一个数16 var array[1,4,5,7,9,17];var num16; var indexnull; var i; for(i0;i<array.length;i){if(array[i]<num){indexi;} } console.log(index);首先通过循环找出最后一个比自定义的num小的值&#xff0c;并…

Vue.js中的高级概念:渲染函数和渲染无内容组件的深度探讨

文章目录 前言渲染函数&#xff08;Render Functions&#xff09;示例使用场景渲染无内容组件&#xff08;Renderless Components&#xff09;示例使用场景总结 ✍创作者&#xff1a;全栈弄潮儿 &#x1f3e1; 个人主页&#xff1a; 全栈弄潮儿的个人主页 &#x1f3d9;️ 个人…

基于springboot实现地方废物回收机构平台管理系统【项目源码+论文说明】计算机毕业设计

基于springboot实现地方废物回收机构平台管理系统演示 摘要 网络的广泛应用给生活带来了十分的便利。所以把地方废物回收机构管理与现在网络相结合&#xff0c;利用java技术建设地方废物回收机构管理系统&#xff0c;实现地方废物回收机构的信息化。则对于进一步提高地方废物回…

腾讯云优惠券免费领取入口整理分享

腾讯云作为国内领先的云服务提供商&#xff0c;为了回馈用户的支持和信任&#xff0c;经常推出各种优惠活动&#xff0c;并提供优惠券供用户使用。本文将整理和分享腾讯云优惠券的免费领取入口&#xff0c;帮助用户在购买腾讯云产品时享受更多的优惠和福利。 一、腾讯云优惠券介…

VPN(虚拟专用网)攻略大全,你一定会用到!

你们好&#xff0c;我的网工朋友。 今天想和你聊聊VPN。 在VPN出现之前&#xff0c;企业分支之间的数据传输只能依靠现有物理网络&#xff08;例如Internet&#xff09;。 但由于Internet中存在多种不安全因素&#xff0c;报文容易被网络中的黑客窃取或篡改&#xff0c;最终…

wordpress搬家后,更改固定链接404文章无法打开,找不到网页与解决办法

出现这个问题的原因可能是服务没有设置伪静态设置&#xff0c;需要配置nginx服务器或者apach服务器 1.问题描述 WordPress中修改固定链接&#xff0c;如下。 保存后再打开网页出现类似于如下404错误。 2.解决办法 打开Nginx的配置文件(如果你没有自己写过那就是默认的nginx.…

JAVA毕业设计101—基于Java+Springboot的电影购票微信小程序带后台管理(源码+数据库)

基于JavaSpringboot的电影购票微信小程序带后台管理(源码数据库)101 一、系统介绍 本系统是小程序前台&#xff0c;带后台管理 本系统分为管理员、用户两种角色 管理员功能&#xff1a; 登录、统计分析、密码修改、用户管理、广告管理、影院管理、分类管理、电影管理、场次…

找不到vcruntime140.dll,无法继续执行代码的详细解决方案

找不到vcruntime140.dll,无法继续执行代码&#xff1f;遇到这种问题&#xff0c;你知道要怎么去解决么&#xff1f;其实在我们开始讨论解决方案之前&#xff0c;需要首先了解什么是vcruntime140.dll文件。它是由Microsoft公司开发的一种DLL&#xff08;动态链接库&#xff09;文…

ExoPlayer架构详解与源码分析(6)——MediaPeriod

系列文章目录 ExoPlayer架构详解与源码分析&#xff08;1&#xff09;——前言 ExoPlayer架构详解与源码分析&#xff08;2&#xff09;——Player ExoPlayer架构详解与源码分析&#xff08;3&#xff09;——Timeline ExoPlayer架构详解与源码分析&#xff08;4&#xff09;—…

Dynamic DataSource 多数据源配置【 Springboot + DataSource + MyBatis Plus + Druid】

一、前言 MybatisPlus多数据源配置主要解决的是多数据库连接和切换的问题。在一些大型应用中&#xff0c;由于数据量的增长或者业务模块的增多&#xff0c;可能需要访问多个数据库。这时&#xff0c;就需要配置多个数据源。 二、Springboot MyBatis Plus 数据源配置 2.1、单数…

K8S集群实践之九: Ceph

Rook is an open source cloud-native storage orchestrator, providing the platform, framework, and support for Ceph storage to natively integrate with cloud-native environments.1. 说明 因香橙派和树莓派资源所限&#xff0c;转移到基于VirtualBox建立的VMs继续实践…