544 eff.c 1761 优化设计文档

1:性能分析

1.1性能对比

oneapi 与hygonGcc性能对比发现,544课题中的eff.c 1761循环处,oneapi 进行了循环向量化, gcc使用标量,循环源码前加 #pragma clang loop vectorize(disable) 找出oneapi在该循环处关闭和开启loop vect 的性能差距,在15%左右。

  mme34.0.svg(图中的svml_log4_mask)

1.2源代码

1761           for (k = 0; k < lpears[i] + upears[i]; k++) {
1762
1763             if (pearlist[i] == NULL) {
1764                fprintf(nabout,
1765                        "NULL pair list entry in egb loop 1, taskid = %d\n",
1766                        mytaskid);
1767                fflush(nabout);
1768             }
1769             j = pearlist[i][k];
1770
1771             xij = xi - x[dim * j];
1772             yij = yi - x[dim * j + 1];
1773             zij = zi - x[dim * j + 2];
1774             r2 = xij * xij + yij * yij + zij * zij;
1775
1776             if (dim == 4) {                     // delete
1777                wij = wi - x[dim * j + 3];
1778                r2 += wij * wij;
1779             }
1780
1781             if (r2 > rgbmaxpsmax2)      //  %hir.cmp.4310 ule
1782                continue;
1783             dij1i = 1.0 / sqrt(r2);
1784             dij = r2 * dij1i;
1785             sj = fs[j] * (rborn[j] - BOFFSET);   //   select fast
1786             sj2 = sj * sj;
1787
1788             /*
1789              * ---following are from the Appendix of Schaefer and Froemmel,
1790              * JMB 216:1045-1066, 1990;  Taylor series expansion for d>>s
1791              * is by Andreas Svrcek-Seiler; smooth rgbmax idea is from
1792              * Andreas Svrcek-Seiler and Alexey Onufriev.
1793              */
1794
1795             if (dij > rgbmax + sj)      // rgbmax = 20;   %hir.cmp.4333 ule
1796                continue;
1797
1798             if ((dij > rgbmax - sj)) {      //    %hir.cmp.4349  ogt
1799                uij = 1. / (dij - sj);
1800                sumi -= 0.125 * dij1i * (1.0 + 2.0 * dij * uij +
1801                                         rgbmax2i * (r2 -
1802                                                     4.0 * rgbmax *
1803                                                     dij - sj2) +
1804                                         2.0 * log((dij - sj) * rgbmax1i));
1805
1806             } else if (dij > 4.0 * sj) {
1807                dij2i = dij1i * dij1i;
1808                tmpsd = sj2 * dij2i;
1809                dumbo =
1810                    TA + tmpsd * (TB +
1811                                  tmpsd * (TC +
1812                                           tmpsd * (TD + tmpsd * TDD)));
1813                sumi -= sj * tmpsd * dij2i * dumbo;
1814
1815             } else if (dij > ri + sj) {
1816                sumi -= 0.5 * (sj / (r2 - sj2) +
1817                               0.5 * dij1i * log((dij - sj) / (dij + sj)));
1818
1819             } else if (dij > fabs(ri - sj)) {
1820                theta = 0.5 * ri1i * dij1i * (r2 + ri * ri - sj2);
1821                uij = 1. / (dij + sj);
1822                sumi -= 0.25 * (ri1i * (2. - theta) - uij +
1823                                dij1i * log(ri * uij));
1824
1825             } else if (ri < sj) {
1826                sumi -= 0.5 * (sj / (r2 - sj2) + 2. * ri1i +
1827                               0.5 * dij1i * log((sj - dij) / (sj + dij)));
1828
1829             }
1830
1831          }

2 向量化 遇到的问题

2.1 if printf

               if (pearlist[i] == NULL) {
1764                fprintf(nabout,
1765                        "NULL pair list entry in egb loop 1, taskid = %d\n",
1766                        mytaskid);
1767                fflush(nabout);
1768             }j = pearlist[i][k];

问题:分析不出内存关系,无法ifcvt。引入了控制流,否则control flow in loop。

eff.c:2072:16: missed: statement clobbers memory: fprintf (nabout.934_2047, "NULL pair list entry in egb loop 1, taskid = %d\n", 0);

解决办法:循环无关的判断,若 pearlist[i] == NULL 则求j = pearlist[i][k]为非法,按照逻辑在if判断里面插入abort()(AOCC 插入了),符合逻辑同时 loop unswitch 可以将其提到循环外

2.2 ifcvt pass 

ifcvt pass 是loop vect pass 的必须经过的前置pass, 二者绑定,中间一般不能插入其他pass , 目的为了对if else 分支做conversion , 将分支跳转转化为条件选择,以便于做 loop vect.

对于if else 的结构,ifcvt pass可以将其转化为由原来 多个控制流和bb块的形式,消除控制流合并到到同一个bb块,通过条件运算符?或者 mask_load的方式,使其满足loop vect  pass 的 loop form analysis。最内层的loop只能由两个bb块组成的要求,进而进行下一步的loop vect。

ifcvt 消除if中的control flow。

/* Predicate each write to memory in LOOP.
2401
2402    This function transforms control flow constructs containing memory
2403    writes of the form:
2404
2405    | for (i = 0; i < N; i++)
2406    |   if (cond)
2407    |     A[i] = expr;
2408
2409    into the following form that does not contain control flow:
2410
2411    | for (i = 0; i < N; i++)
2412    |   A[i] = cond ? expr : A[i];

2.3 dim =3 常量传播

1776             if (dim == 4) {
1777                wij = wi - x[dim * j + 3];
1778                r2 += wij * wij;
1779             }

问题:wij的计算会向量化遇到问题。

解决办法:由于dim 是静态全局变量,尝试过inline 做常量传播,发现并未能实现。调整loop unswitch 参数--param=max-unswitch-insns=150,将其提到循环外面。

2.4   phi 节点的参数超过限制

问题:sumi 的结果的phi节点参数过多,无法进行ifcvt

BB 90 has complicated PHI with more than 4 args.

解决:aggressive_if_conv = true; 让ifcvt 做激进的优化,不受phi节点参数个数限制。

3300   /* Apply more aggressive if-conversion when loop or its outer loop were
3301      marked with simd pragma.  When that's the case, we try to if-convert
3302      loop containing PHIs with more than MAX_PHI_ARG_NUM arguments.  */
3303  // aggressive_if_conv = loop->force_vectorize;
3304   aggressive_if_conv = true;
3305   if (!aggressive_if_conv)
3306     {
3307       class loop *outer_loop = loop_outer (loop);
3308       if (outer_loop && outer_loop->force_vectorize)
3309   aggressive_if_conv = true;
3310     }

2.5  gcc在zen架构下,不支持mask gather

1769             j = pearlist[i][k];
1781             if (r2 > rgbmaxpsmax2)      
1782                continue;
1783             dij1i = 1.0 / sqrt(r2);
1784             dij = r2 * dij1i;
1785             sj = fs[j] * (rborn[j] - BOFFSET); 
1786             sj2 = sj * sj;

问题:对于每一轮的j 的值 是不连续的,因此fs[j] 也不连续, 并且在if continue 之后需要进行mask, 不支持使用mask从不连续的内存向量化的取数据。

467 /* X86_TUNE_USE_GATHER_4PARTS: Use gather instructions for vectors with 4
468    elements.  */
469 /*DEF_TUNE (X86_TUNE_USE_GATHER_4PARTS, "use_gather_4parts",
470     ~(m_ZNVER1 | m_ZNVER2 | m_ZNVER3 | m_ZNVER4 | m_ALDERLAKE | m_GENERIC))*/

解决方法:可以使用-mtune-ctrl=use_gather_4parts 使其支持builtin 形式的mask gather操作。

2.6 多分支下的同一个reduction var 问题

问题:nphi_def_loop_uses > 1 一个reduction 变量在loop 中使用次数超过一个,被认为不是simple reduction 。loop vect pass 不会对其向量化。

69628 eff.c:1761:24: note:   Analyze phi: sumi_1654 = PHI <sumi_1557(320), 0.0(402)>69629 eff.c:1761:24: missed:   reduction used in loop.

解决办法:在ifcvt pass 中加上一个函数,实现如下述源码中的,将同一个reduction 变为多个不同的reduction ,实现向量化。

    
1763          double temp0 = 0;
1764          double temp1 = 0;
1765          double temp2 = 0;
1766          double temp3 = 0;
1767          double temp4 = 0;
1805 
1806             if ((dij > rgbmax - sj)) {
1807                uij = 1. / (dij - sj);
1808             
1813             /*   sumi -= 0.125 * dij1i * (1.0 + 2.0 * dij * uij +
1814                                         rgbmax2i * (r2 -
1815                                                     4.0 * rgbmax *
1816                                                     dij - sj2) +
1817                                         2.0 * log((dij - sj) * rgbmax1i));*/
1818            
1823                temp0 -= 0.125 * dij1i * (1.0 + 2.0 * dij * uij +
1824                                         rgbmax2i * (r2 -
1825                                                     4.0 * rgbmax *
1826                                                     dij - sj2) +
1827                                         2.0 * log((dij - sj) * rgbmax1i));
1828 
1829             } else if (dij > 4.0 * sj) {
1830                dij2i = dij1i * dij1i;
1831                tmpsd = sj2 * dij2i;
1832                dumbo =
1833                    TA + tmpsd * (TB +
1834                                  tmpsd * (TC +
1835                                           tmpsd * (TD + tmpsd * TDD)));
1836           
1837           //     sumi -= sj * tmpsd * dij2i * dumbo;
1839                temp1 -= sj * tmpsd * dij2i * dumbo;
1840 
1841             } 
1879          sumi = temp0 + temp1 + temp2+ temp3+temp4;
1880 

能够实现向量化,但是性能相对与标量下降了

544base向量化加上分块
32 copies10092107

 向量化的代价太大,临时变量,mask gather load带来的性能下降太显著。(性能下降的loop vect 为什么能通过,cost的计算,没有把mask gather 算进去)。

3. 向量化后优化

3.1:循环分块

问题:gcc 向量化后所有分支的代码在一个bb块里面,所以所有的分支都会走一遍,对最后运算的结果根据分支条件进行选择,带来冗余运算。

解决方法:发现gcc loop pass 上有对optimize_mask_stores,向量化后进行分块的函数。在此基础上拓展添加了对 VEC_COND_EXPR的分块。

添加对于每个分支判断变量全为0,也就是所有元素都不满足该分支,则不需要进入该分支计算,省去了以部分冗余运算。

3.2:向量化因子

使用该选择  -mtune-ctrl=^avx256_split_regs,^avx128_optimal,256_unaligned_store_optimal 打开256非对其存储优化,可以使VF 由 4 变为8, 提高性能。

544baseVF4VF8
32 copies100101107

4:优化详细说明

4.1 添加的编译选项

--param=max-unswitch-insns=150 -ftree-insert-abort
-mtune-ctrl=^avx256_split_regs,^avx128_optimal,256_unaligned_store_optimal,use_gather_4parts

1:loop unswitch  insns 参数调整,默认是50,调整到150

2:插入一个新的pass 来插入abort()

3: 使能256bit的非对齐存储优化,VF为8.(^avx256_split_regs 不加这个也可)

4:使能256bit 的 mask gather 指令。

4.2:添加的优化代码

4.2.1 激进的ifcvt优化 (找到选项来控制)?

将 aggressive_if_conv 标志位修改为true。(能否通过某些选项来控制)

3303  // aggressive_if_conv = loop->force_vectorize;
3304   aggressive_if_conv = true;

4.2.2  插入abort() 优化

新建一个gimple pass,  放在adjust_alignment pass 后。(107 pass)

199   NEXT_PASS (pass_adjust_alignment);
200   NEXT_PASS (pass_insert_abort);
201   NEXT_PASS (pass_all_optimizations);

设计思路:识别对0进行判断gimple_cond,并且判断为true的bb 以及其single suc,有对该gimple cond lhs 定义的stmt进行解引用,则认为是对空指针解引用回出现问题,插入abort()

识别的pattern:

(1) :识别一个gimple_cond 语句,并且是和0进行相等判断

(2) :找到判断为true的bb块以及其后继bb块中,是否有对该判断条件lhs的def的stmt进行解引用使用。

transform:

(1):找到后在gimple cond条件为true的bb 末尾插入abort()。

14044   <bb 148> [local count: 919275880]:
14045   _2044 = _127 + _2039;
14046   _2045 = *_2044;
14047   if (_2045 == 0B)
14048     goto <bb 149>; [17.43%]
14049   else
14050     goto <bb 150>; [82.57%]
14051
14052   <bb 149> [local count: 160229786]:
14053   _2046 = 0;
14054   _2047 = nabout;
14055   fprintf (_2047, "NULL pair list entry in egb loop 1, taskid = %d\n", _2046);
14056   _2048 = nabout;
14057   fflush (_2048);
14058
14059   <bb 150> [local count: 919275880]:
14060   _2049 = *_2044;
14061   _2051 = (long unsigned int) k_2050;
14062   _2052 = _2051 * 4;
14063   _2053 = _2049 + _2052;
14064   j_2054 = *_2053;

4.2.3 消除reduction use in loop (改变一种方式,消除reduction,重新修改代码),如果是sumi的加减混合运算?

使用其他方法修改reduction 后性能没有原方法好,因为原方法都是在循环外面,新方法需要在循环里面。

在ifcvt pass 中添加函数,(尝试在loop vect pass 中当出现reduction use in loop  后transform , 新建的reduction 会错过 loop vect 中对reduction 的分析)

思路:识别reduction  在 loop 中的使用次数超过1次的情况,找到该reduction 的phi 节点,在每次使用的地方进行替换成为不同的reduction,需要对是否进行ifcvt的两个版本都进行转化。标量和向量版本都会走到(如何识别是reduction?)       复用发现reduction 的接口,在一个新的pass 里面加上这部分代码。

(该优化是根据先修改源码后,产生的IR,进行对照修改,涉及到的修改较多,目前想仅仅针对该课题pattern,其他情况比较难以覆盖)

1761           for (k = 0; k < lpears[i] + upears[i]; k++) {
1762
1763             if (pearlist[i] == NULL) {
1764                fprintf(nabout,
1765                        "NULL pair list entry in egb loop 1, taskid = %d\n",
1766                        mytaskid);
1767                fflush(nabout);
1768             }
1769             j = pearlist[i][k];
1770
1771             xij = xi - x[dim * j];
1772             yij = yi - x[dim * j + 1];
1773             zij = zi - x[dim * j + 2];
1774             r2 = xij * xij + yij * yij + zij * zij;
1775
1776             if (dim == 4) {                     // delete
1777                wij = wi - x[dim * j + 3];
1778                r2 += wij * wij;
1779             }
1780
1781             if (r2 > rgbmaxpsmax2)      //  %hir.cmp.4310 ule
1782                continue;
1783             dij1i = 1.0 / sqrt(r2);
1784             dij = r2 * dij1i;
1785             sj = fs[j] * (rborn[j] - BOFFSET);   //   select fast
1786             sj2 = sj * sj;
1787
1788             /*
1789              * ---following are from the Appendix of Schaefer and Froemmel,
1790              * JMB 216:1045-1066, 1990;  Taylor series expansion for d>>s
1791              * is by Andreas Svrcek-Seiler; smooth rgbmax idea is from
1792              * Andreas Svrcek-Seiler and Alexey Onufriev.
1793              */
1794
1795             if (dij > rgbmax + sj)      // rgbmax = 20;   %hir.cmp.4333 ule
1796                continue;
1797             double temp = 0;
1798             if ((dij > rgbmax - sj)) {      //    %hir.cmp.4349  ogt
1799                uij = 1. / (dij - sj);
1800                temp -= 0.125 * dij1i * (1.0 + 2.0 * dij * uij +
1801                                         rgbmax2i * (r2 -
1802                                                     4.0 * rgbmax *
1803                                                     dij - sj2) +
1804                                         2.0 * log((dij - sj) * rgbmax1i));
1805
1806             } else if (dij > 4.0 * sj) {
1807                dij2i = dij1i * dij1i;
1808                tmpsd = sj2 * dij2i;
1809                dumbo =
1810                    TA + tmpsd * (TB +
1811                                  tmpsd * (TC +
1812                                           tmpsd * (TD + tmpsd * TDD)));
1813                temp -= sj * tmpsd * dij2i * dumbo;
1814
1815             } else if (dij > ri + sj) {
1816                temp -= 0.5 * (sj / (r2 - sj2) +
1817                               0.5 * dij1i * log((dij - sj) / (dij + sj)));
1818
1819             } else if (dij > fabs(ri - sj)) {
1820                theta = 0.5 * ri1i * dij1i * (r2 + ri * ri - sj2);
1821                uij = 1. / (dij + sj);
1822                temp -= 0.25 * (ri1i * (2. - theta) - uij +
1823                                dij1i * log(ri * uij));
1824
1825             } else if (ri < sj) {
1826                temp -= 0.5 * (sj / (r2 - sj2) + 2. * ri1i +
1827                               0.5 * dij1i * log((sj - dij) / (sj + dij)));
1828
1829             }sumi+=temp;
1830
1831          }
进行ifcvt后的部分(向量)(初始化为0,不为0 的情况 应该直接将其初始化结果加入到新建的reduction 变量中)

(1):在loop header bb 中识别phi stmt,找到其lhs中使用次数等于该分支数量,并且初始化为0的phi stmt。

transfrom: 

(1):新建与分支数量相等的phi stmt ,初始值为0和该循环计算后的结果,作为一个新的reduction.

  (2)  :   新建该reduction 和 每个分支运算结果的gimple assign。

(3):对最后结果累加运算。

48399   # k_1747 = PHI <k_2147(234), 0(279)>                                                      
48400   # sumi_1470 = PHI <sumi_2753(234), 0.0(279)>                                                
48401   # RANGE [0, 2147483647] NONZERO 2147483647  48488   sumi_2087 = sumi_1470 + _2085;
48489   _3187 = dij_2056 <= _2068;48507   sumi_2102 = sumi_1470 - _2101;
48508   _3169 = dij_2056 <= _2088;
48509   _3168 = _3169 & _3184;

转化为:

 51162   # temp_value.1035_2087 = PHI <tmp_var.1036_2090(320), 0.0(402)>
51164   # temp_value.1043_2073 = PHI <tmp_var.1044_2063(320), 0.0(402)>51320   _ifc__2108 = _1303 ? _1605 : 0.0;51321   tmp_var.1036_2090 = _ifc__2108 + temp_value.1035_2087;
51324   _ifc__2064 = _1315 ? _1586 : 0.0;51325   tmp_var.1044_2063 = _ifc__2064 + temp_value.1043_2073;52177   # tmp_sumi.1045_2075 = PHI <tmp_var.1044_2063(304), tmp_sumi_2.1060_2061(399)>52175   # tmp_sumi.1037_2076 = PHI <tmp_var.1036_2090(304), tmp_sumi_2.1056_2057(399)>52190   # sumi_suc.1046_2042 = PHI <tmp_sumi.1045_2075(351), 0.0(74), tmp_sumi.1074_644(352)>52188   # sumi_suc.1038_2775 = PHI <tmp_sumi.1037_2076(351), 0.0(74), tmp_sumi.1068_704(352)>
52193   _2052 = sumi_suc.1038_2775 + sumi_suc.1046_2042;
不进行ifcvt的部分(标量)

transform: 

(1):新建phi stmt 初始化为0,与分支数量相同。

(2):修改每个分支的中间运算结果。

(3):对每个分支的结果用phi节点来控制。

 # sumi_3078 = PHI <0.0(280), sumi_2855(277)>sumi_2872 = sumi_3078 + _2911;sumi_2973 = sumi_3078 - _2974;sumi_2855 = PHI <sumi_3078(261), sumi_3078(263), sumi_3078(269), sumi_3016(271), sumi_2999(272), sumi_2988(273), sumi_2973(274), sumi_2872(275)>

转化为:

 51867   # temp_value_2.1081_596 = PHI <0.0(426), tmp_sumi_2.1082_597(423)>51868   # temp_value_2.1083_598 = PHI <0.0(426), tmp_sumi_2.1084_575(423)>sumi_1004 = temp_value_2.1081_596 + _1003;sumi_866 = temp_value_2.1083_598 - _865;# tmp_sumi_2.1082_597 = PHI <temp_value_2.1081_596(407),temp_value_2.1081_596(409),temp_value_2.1081_596(412),temp_value_2.1081_596(414), temp_value_2.1081_596(416),temp_value_2.1081_596(418),temp_value_2.1081_596(419), sumi_1004(421)># tmp_sumi_2.1084_575 = PHI <temp_value_2.1083_598(407), temp_value_2.1083_598(409), temp_value_2.1083_598(412), temp_value_2.1083_598(414), temp_value_2.1083_598(416), temp_value_2.1083_598(418), sumi_866(419), temp_value_2.1083_598(421)>

4.2.4 if else / if continue 向量化后分块优化   (添加cost计算?)

targetm.vectorize.empty_mask_is_expensive

aarch64_empty_mask_is_expensive  这里不做mask_store 的

default_empty_mask_is_expensive  其他情况都会进行

26378 /* Implement TARGET_VECTORIZE_EMPTY_MASK_IS_EXPENSIVE.  Assume for now that
26379    it isn't worth branching around empty masked ops (including masked
26380    stores).  */
26381
26382 static bool
26383 aarch64_empty_mask_is_expensive (unsigned)
26384 {
26385   return false;
26386 }

仿照loop vect pass 中的optimize_mask_stores,在loop vect pass 中 加上基于vec_cond_expr分块的函数

思路:(1)识别loop 中在同一个bb 中的 VEC_COND_EXPR,

(2)根据第二个参数找到每个分支最后计算的结果,从此处开始拆分bb。

(3)根据第一个参数mask,找到每个分支条件,将这两个mask相或,在此后新建一个该或结果与0进行比较的gimple_cond,插入到分支条件后,同时新建该结果判断为ture 和 false的edge,分别指向新建的bb和其下一个bb。

(4)在拆分bb 块后面新建一个空 bb ,并且gimple_cond 之后的stmt 移动到新建的bb 中,维护其edge,指向下一个bb.

 98615   vect__ifc__2106.1217_795 = VEC_COND_EXPR <mask__1612.1193_854, vect__1541.1206_870, { 0.0, 0.0, 0.0, 0.0 }>;98616   vect__ifc__2106.1217_796 = VEC_COND_EXPR <mask__1612.1193_821, vect__1541.1206_871, { 0.0, 0.0, 0.0, 0.0 }>; 98621   vect__ifc__2706.1220_803 = VEC_COND_EXPR <mask__1617.1210_879, vect__1555.1216_792, { 0.0, 0.0, 0.0, 0.0 }>;98622   vect__ifc__2706.1220_804 = VEC_COND_EXPR <mask__1617.1210_880, vect__1555.1216_793, { 0.0, 0.0, 0.0, 0.0 }>; 

       

         

5.其他优化探索

5.1带有mask的向量数学函数

在loop vect pass 后新建一个pass ,替换原有的数学函数调用带有mask的svml函数。

 98615   vect__ifc__2106.1217_795 = VEC_COND_EXPR <mask__1612.1193_854, vect__1541.1206_870, { 0.0, 0.0, 0.0, 0.0 }>; 

设计方案:找到一个VEC_COND_EXPR,在同一个基本块中,根据参数中的分支运算的结果,顺着运算的关系一步步往上找(SSA_NAME_DEF_STMT),进行深度优先遍历,直到找到了需要进行mask的数学函数。VEC_COND_EXPR中的参数mask就是数学函数需要进行mask的值。将数学函数和mask一起生成带有mask的数学函数的IR,替换掉原来的不带mask的。

 

由于次优化的性能和循环分块重叠,因此不需要加入。

5.2 与oneapi性能差距的探索:

image-2024-8-30_17-6-5.png

对分支条件进行两次判断,一次判断全为false,则不进入分支里面的运算。一次判断全为true,如果正确,则只需要进入该分支的计算,其他分支不需要进入。相比于上述方案还省了分支条件全为true的时候的其他分支条件的运算。

由于涉及到的控制流和bb块的修改较多,且不好验证性能,暂且不做。

最终结果:性能在544 上提升7%。

544baseoptimize
32 copies100107

targetm.vectorize.empty_mask_is_expensive

或者看ifcvt IR 里面有没有temp_value,loop vect里面有没有combined_mask

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

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

相关文章

LeetCode.3396.使数组元素互不相同所需的最少操作次数

3396. 使数组元素互不相同所需的最少操作次数 给你一个整数数组 nums&#xff0c;你需要确保数组中的元素 互不相同 。为此&#xff0c;你可以执行以下操作任意次&#xff1a; 从数组的开头移除 3 个元素。如果数组中元素少于 3 个&#xff0c;则移除所有剩余元素。 注意&…

【已完结STM32】--自学江协科技笔记汇总

以下学习笔记代码均来自b站江协科技视频 笔记汇总完结 文章笔记对应江科大视频新建工程【2-2】新建工程江科大STM32-GPIO输出 点亮LED&#xff0c;LED闪烁&#xff0c;LED流水灯&#xff0c;蜂鸣器&#xff08;学习笔记&#xff09;_unit32-t rcc-apb2periph-CSDN博客 【3-1】…

QML Loader:加载组件与状态监控

目录 引言相关阅读工程结构示例一&#xff1a;从文件加载组件 (LoaderFile.qml)代码实现被加载的组件&#xff1a;MyComponent.qml代码解析运行效果 示例二&#xff1a;直接加载Component对象 (LoaderComponent.qml)代码实现代码解析运行效果 示例三&#xff1a;监控加载状态 (…

K8S核心技术点

Pod&#xff0c;Service和Deployment的关系 Pod&#xff1a;Kubernetes 中最小的部署单元&#xff0c;用于运行容器化应用。 Service&#xff1a;提供服务发现和负载均衡&#xff0c;为 Pod 提供稳定的网络端点&#xff0c;ClusterIP&#xff0c;NodePort&#xff0c;LoadBala…

Spring 核心注解深度解析:@Autowired、@Repository 与它们的协作关系

引言 在 Spring 框架中&#xff0c;​依赖注入&#xff08;DI&#xff09;​​ 是实现松耦合架构的核心机制。Autowired 和 Repository 作为两个高频使用的注解&#xff0c;分别承担着 ​依赖装配​ 和 ​数据访问层标识​ 的关键职责。本文将深入探讨它们的功能特性、协作模式…

[Linux]从零开始的ARM Linux交叉编译与.so文件链接教程

一、前言 最近在项目需要将C版本的opencv集成到原本的代码中从而进行一些简单的图像处理。但是在这其中遇到了一些问题&#xff0c;首先就是原本的opencv我们需要在x86的架构上进行编译然后将其集成到我们的项目中&#xff0c;这里我们到底应该将opencv编译为x86架构的还是编译…

svelte+vite+ts+melt-ui从0到1完整框架搭建

框架太“重”了&#xff1a;通常一个小型项目只由少数几个简单页面构成&#xff0c;如果使用 Vue 或者 React 这些框架来研发的话&#xff0c;有点“大材小用”了。构建的产物中包含了不少框架运行时代码(虚拟 DOM、响应式、状态管理等)&#xff0c;这些代码对于小型项目而言是…

无法看到新安装的 JDK 17

在 Linux 系统中使用 update-alternatives --config java 无法看到新安装的 JDK 17&#xff0c;可能是由于 JDK 未正确注册到系统备选列表中。 一、原因分析 JDK 未注册到 update-alternatives update-alternatives 工具需要手动注册 JDK 路径后才能识别新版本。如果仅安装 JDK…

鼎讯信通 便携式雷达信号干扰模拟器:打造实战化电磁环境的新利器

在现代战争中&#xff0c;电磁环境的复杂性直接影响着雷达装备的性能和作战效果。面对敌方日益精进的电子战手段&#xff0c;如何提升雷达设备的抗干扰能力&#xff0c;确保其在实战环境中的稳定性和可靠性&#xff0c;已成为各国军队和科研机构的重要课题。 为此&#xff0c;…

【AI提示词】决策专家

提示说明 决策专家可以帮助你进行科学决策&#xff0c;尽可能避免错误&#xff0c;提升决策成功的概率。 提示词 # Role : 决策专家决策&#xff0c;是面对不容易判断优劣的几个选项&#xff0c;做出正确的选择。说白了&#xff0c;决策就是拿个主意。决策专家是基于科学决策…

力扣Hot100题,刷题

力扣HOT100 - 1. 两数之和 解题思路&#xff1a; 解法一&#xff1a;暴力 class Solution {public int[] twoSum(int[] nums, int target) {int n nums.length;for (int i 0; i < n; i)for (int j i 1; j < n; j) {if (target nums[i] nums[j])return new int[]…

uni-app ucharts自定义换行tooltips

实现效果&#xff1a; 第一步&#xff1a;在uni_modules文件夹下找到config-ucharts.js和u-charts.js文件 第二步&#xff1a;在config-ucharts.js文件中配置换行格式 // 换行格式"wrapTooltip":function(item, category, index, opts){return item.name&#xff1a;…

国标GB28181视频平台EasyCVR顺应智慧农业自动化趋势,打造大棚实时视频监控防线

一、方案背景 近年来&#xff0c;温室大棚种植技术凭借其显著的优势&#xff0c;在提升农作物产量和质量、丰富农产品供应方面发挥了重要的作用&#xff0c;极大改善了人们的生活水平&#xff0c;得到了广泛的推广和应用。大棚内的温度、湿度、光照度和二氧化碳浓度等环境因素…

InternVideo2.5:Empowering Video MLLMs with Long and Rich Context Modeling

一、TL&#xff1b;DR InternVideo2.5通过LRC建模来提升MLLM的性能。层次化token压缩和任务偏好优化&#xff08;mask时空 head&#xff09;整合到一个框架中&#xff0c;并通过自适应层次化token压缩来开发紧凑的时空表征MVBench/Perception Test/EgoSchema/MLVU数据benchmar…

【时时三省】(C语言基础)条件运算符和条件表达式

山不在高&#xff0c;有仙则名。水不在深&#xff0c;有龙则灵。 ----CSDN 时时三省 有一种if语句&#xff0c;当被判别的表达式的值为“真”或“假”时&#xff0c;都执行一个赋值语句且向一个变量赋值。 如&#xff1a; if ( a > b ) max a&#xff1b; else max …

KWDB创作者计划—边缘计算:从概念到落地的技术解读

引言 随着物联网&#xff08;IoT&#xff09;和人工智能&#xff08;AI&#xff09;的快速发展&#xff0c;数据量呈爆炸式增长&#xff0c;传统的云计算架构逐渐暴露出延迟高、带宽占用大等问题。边缘计算作为一种新兴的分布式计算范式&#xff0c;正在改变数据处理的方式。本…

蓝桥杯基础算法-递归

代码简洁&#xff0c;但涉及到的运算&#xff0c;会随着递归层数的增加成指数级增长 路分析&#xff1a;第20行20列位于45度这条线上 这条线上的数字是1 5 13 25 41...两数之差:4 8 12 16 --->每一个都是在前面的基础上4&#xff0c;可以用递归或者循环 public class dem…

通过学习opencv图像库编程借助第三方库函数完成一个综合程序设计

通过学习opencv图像库编程借助第三方库函数完成一个综合程序设计 1) 编译命令解释&#xff1a; 编译命令&#xff1a; gcc test1.cpp -o test1 pkg-config --cflags --libs opencv这条命令包含了以下部分&#xff1a; gcc test1.cpp -o test1: gcc 是 GNU 编译器集合&#…

第十四届蓝桥杯大赛软件赛国赛C/C++研究生组

研究生C国赛软件大赛 题一&#xff1a;混乘数字题二&#xff1a;钉板上的正方形题三&#xff1a;整数变换题四&#xff1a;躲炮弹题五&#xff1a;最大区间 题一&#xff1a;混乘数字 有一点像哈希表&#xff1a; 首先定义两个数组&#xff0c;拆分ab和n 然后令n a*b 查看两个…

系统与网络安全------网络通信原理(2)

资料整理于网络资料、书本资料、AI&#xff0c;仅供个人学习参考。 物理层解析 物理层概述 物理层是TCP/IP模型的最底层物理层数据传输提供稳定的物理连接 物理层功能 定义设备的物理连接的标准和特性&#xff0c;比如接口形状&#xff0c;大小定义电气特性&#xff0c;高低…