GPU编程和流式多处理器(三)

3. Floating-Point Support

快速的本机浮点硬件是GPU的存在理由,并且在许多方面,它们在浮点实现方面都等于或优于CPU。全速支持异常可以根据每条指令指定直接舍入,特殊功能单元可为六种流行的单精度先验函数,提供高性能的近似函数。相比之下,x86 CPU在微代码中实现异常,其运行速度可能比在规范化浮点算子上运行的速度慢100倍。舍入方向是由一个控制字指定的,该控制字需要数十个时钟周期来更改,并且SSE指令集中唯一的超越逼近函数是用于倒数和倒数平方根的,给出必须用牛顿-微分精确的12位近似值。使用Raphson迭代之前。

由于GPU的核心数量较多,但其较低的时钟频率会有所抵消,开发人员可以期望在公平竞争的环境下最多提高10倍(或大约10倍)的速度。如果一篇论文报告了从将优化的CPU实现移植到CUDA所实现的100倍或更高的速度,则可能是上述“指令集不匹配”之一。

3.1. Formats

图2描述了CUDA支持的三(3)个IEEE标准浮点格式:双精度(64位),单精度(32位)和半精度(16位)。值分为三个字段:正负号,指数和尾数。对于doublesinglehalf,指数字段的大小分别为11位,8位和5位。相应的尾数字段为52、23和10位。

Figure 2 Floating-point formats.

指数字段更改浮点值的解释。最常见的(“正常”)表示形式将一个隐式1位编码为尾数,然后将该值乘以2个e-bias,其中bias是在编码为浮点表示形式之前添加到实际指数的值。例如,单精度的偏差为127。

表7总结了如何对浮点值进行编码。对于大多数指数值(所谓的“正常”浮点值),尾数假定为隐式1,并将其乘以指数的偏置值。最大指数值保留用于无穷大和非数字值。除以零(或除以除法)会产生无穷大;执行无效运算(例如取平方根或负数的对数)会产生NaN。最小指数值保留给太小而无法用隐式前导1表示的值。随着所谓的正规数接近零,它们失去有效精度的位,这种现象称为逐渐下溢。表8给出了三种格式的某些极值的编码和值。

Table 7 Floating-Point Representations

Table 8 Floating-Point Extreme Values

Rounding舍入取整法

IEEE标准提供了四(4)个回合模式。

  • 四舍五入到最近(也称为“四舍五入”)
  • 向零舍入(也称为“截断”或“斩”)
  • 向下舍入(或“朝负无穷大舍入”)
  • 向上舍入(或“朝正无穷大舍入”)

舍入取整法是迄今为止最常用的舍入模式,在每次操作后将中间值舍入为最接近的可表示浮点值。向上舍入和向下舍入(“定向舍入模式”)用于间隔算术,其中一对浮点值用于括住计算的中间结果。为了正确地将结果括起来,该间隔的下限值和上限值必须分别四舍五入为负无穷大(“向下”)和正无穷大(“ up”)。

C语言不提供任何方式来按指令指定舍入模式,并且CUDA硬件不提供用于隐式指定舍入模式的控制字。因此,CUDA提供了一组内部函数来指定操作的舍入模式,如表9所示。

Table 9 Intrinsics for Rounding

Conversion

通常,开发人员可以使用标准C结构,在不同的浮点表示形式和/或整数之间进行转换:隐式转换或显式类型转换。但是,如有必要,开发人员可以使用表10中列出的内在函数,执行C语言规范中不包含的转换,例如,使用定向舍入的转换。

由于一半未在C编程语言中标准化,因此CUDA在__half2float()__float2half()的接口中使用unsigned short__float2half()仅支持舍入到最近舍入模式。

float __half2float( unsigned short );

unsigned short __float2half( float );

3.2. Single Precision (32-Bit)

单精度浮点支持是GPU计算的主力军。GPU已经过优化,可以在此数据类型上原生提供高性能,11不仅适用于核心标准IEEE操作(例如加法和乘法),还适用于非标准操作(例如对先验的近似例如sin()log()))。32位值与整数保存在同一寄存器文件中,因此单精度浮点值和32位整数(使用__float_as_int()__int_as_float())之间的强制转换是免费的。

加法,乘法和乘加

编译器自动将浮点值的+,–和*运算符转换为加,乘和乘加指令。__fadd_rn()__fmul_rn()内部函数,可以被用于加入抑制融合和乘法操作进入乘加指令。

对等与除法

对于具有2.x或更高版本的计算能力的设备,使用--prec-div = true编译代码时,除法运算符符合IEEE规定。对于具有计算能力1.x的设备或对于具有计算能力2.x的设备,当使用--prec-div = false编译代码时,除法运算符和__fdividef(x,y)具有相同的精度,

SM中的特殊功能单元(SFU)实现了六个常见超越功能的快速版本。

  • 正弦和余弦
  • 对数和指数
  • 倒数和倒数平方根

表11(摘自有关Tesla架构的论文)摘录了受支持的操作和相应的精度。SFU并不能完全实现精度,可以很好地近似于这些功能,并且速度很快。对于比优化的CPU等效端口(例如25倍或更多)快得多的CUDA端口,代码很可能依赖SFU。

Table 11 SFU Accuracy

使用表12中给出的内在函数访问SFU。指定--fast-math编译器选项,将使编译器将常规C运行时runtime,调用替换为上面列出的相应SFU内部函数。

Table 12 SFU Intrinsics

Miscellaneous

__saturate(x) returns 0 if x<0, 1 if x>1, and x otherwise.

3.3. Double Precision (64-Bit)

带有SM 1.3的CUDA中添加了双精度浮点支持(最早在GeForce GTX 280中实现),而SM 2.0则提供了大大改进的双精度支持(功能和性能)。CUDA对双精度的硬件支持具有全速异常功能,并且从SM 2.x开始,符合IEEE 754 c的本机融合乘法加法指令(FMAD)。2008年,仅执行一个舍入步骤。FMAD除了是本质上有用的操作之外,还可以使某些功能(与Newton-Raphson迭代收敛)完全准确。

与单精度运算一样,编译器会自动将标准C运算符转换为乘法,加法和乘加指令。__dadd_rn()和__dmul_rn()内部函数可以被用于加入抑制融合和乘法操作进入乘加指令。

3.4. Half Precision (16-Bit)

对于5位指数和10位有效数,值具有足够的精度以用于HDR(高动态范围)图像,并可用于保存其它不需要浮点精度的值,例如角度。半精度值仅用于存储,而不用于计算,硬件仅提供指令以转换为32位或从32位转换。这些指令以__halftofloat()__floattohalf()内部函数公开

float __halftofloat( unsigned short );

unsigned short __floattohalf( float );

这些内部函数使用unsigned short因为C语言尚未标准化浮点类型。

3.5. Case Study: float→half Conversion

研究float → half转换操作,了解浮点编码和舍入细节的有用方法。这是一个简单的一元运算,可以专注于编码和舍入,而不会被浮点运算的细节和中间表示的精度所分散。

当从float转换为half时,对于任何太大而无法表示的float的正确输出是half infinity。任何太小而不能代表一半(甚至是反常的一半)的浮点数都必须固定为0.0。舍入为0.0的一半的最大浮点数为0x32FFFFFF或2.98,而舍入为无穷大的一半的最小浮点数为65520.0。此范围内的float值可以通过传播符号位转换为一半,重新偏置指数(因为float的8位指数偏差为127,一半的5位指数偏差为15),然后将float的尾数四舍五入到最接近的一半尾数。在所有情况下,舍入都是简单的,除非输入值恰好落在两个可能的输出值之间。在这种情况下,IEEE标准指定四舍五入到“最近的偶数”值。在十进制算术中,这意味着四舍五入为1.5到2.0,但也四舍五入为2.5到2.0,以及(例如)四舍五入到0.5到0.0。

清单3显示了一个C例程,该例程完全复制了CUDA硬件实现的浮点到一半转换操作。变量exp和mag包含输入指数和“幅值”,尾数和指数以及被屏蔽的符号位。可以对幅度执行许多操作,例如比较和舍入操作,而无需分离指数和尾数。

清单3中使用的宏LG_MAKE_MASK创建具有给定位数的掩码:#define LG_MAKE_MASK(bits)((1 << bits)-1)。联合用于治疗相同的32位值作为浮子和无符号整型; 诸如*((float *)(&u))之类的习惯用法不是可移植的。该例程首先传播输入符号位并将其屏蔽掉。

提取幅度和指数后,该函数处理输入浮点为INF或NaN的特殊情况,并尽早退出。注意,INF是带符号的,但NaN具有规范的无符号值。将输入浮点值钳位到与可表示的半值相对应的最小值或最大值,然后重新计算钳位值的大小。不要被构造f32MinRInfin和f32MaxRf16_zero的复杂代码所迷惑;它们是分别具有值0x477ff000和0x32ffffff的常量。

例程的其余部分处理输出正常和异常的情况(输入异常在前面的代码中被钳位,因此mag对应于正常float)。与钳位代码一样,f32Minf16Normal是一个常量,其值为0x38ffffff。

要构建法线,必须计算新的指数(第92和93行),正确舍入的10位尾数将移入输出。要构造非正规数,必须将隐式1与输出尾数进行“或”运算,然后将所得尾数偏移与输入指数对应的量。对于正向和非正向,输出尾数的舍入分两步完成。舍入是通过添加一个1的掩码来实现的,该掩码的末尾刚好等于输出的LSB,如图3所示。

Figure 3 Rounding mask (half).

如果输入的位12置1,则此操作将增加输出尾数;否则,将增加输出尾数。如果输入尾数全为1,则溢出会导致输出指数正确递增。如果向此调整的最高有效位再加1,将获得小学风格的四舍五入,其中平局决胜数更大。反之,即使设置了舍入到最接近值,如果设置了10位输出的LSB,则有条件地增加输出尾数(图8.4)。注意,这些步骤可以按任何顺序执行,也可以以许多不同的方式重新制定。

Figure 4 Round-to-nearest-even (half).

Listing 3. ConvertToHalf().

/*

* exponent shift and mantissa bit count are the same.

*    When we are shifting, we use [f16|f32]ExpShift

*    When referencing the number of bits in the mantissa,

*        we use [f16|f32]MantissaBits

*/

const int f16ExpShift = 10;

const int f16MantissaBits = 10;

const int f16ExpBias = 15;

const int f16MinExp = -14;

const int f16MaxExp = 15;

const int f16SignMask = 0x8000;

const int f32ExpShift = 23;

const int f32MantissaBits = 23;

const int f32ExpBias = 127;

const int f32SignMask = 0x80000000;

unsigned short

ConvertFloatToHalf( float f )

{

/*

* Use a volatile union to portably coerce

* 32-bit float into 32-bit integer

*/

volatile union {

float f;

unsigned int u;

} uf;

uf.f = f;

// return value: start by propagating the sign bit.

unsigned short w = (uf.u >> 16) & f16SignMask;

// Extract input magnitude and exponent

unsigned int mag = uf.u & ~f32SignMask;

int exp = (int) (mag >> f32ExpShift) - f32ExpBias;

// Handle float32 Inf or NaN

if ( exp == f32ExpBias+1 ) {    // INF or NaN

if ( mag & LG_MAKE_MASK(f32MantissaBits) )

return 0x7fff; // NaN

// INF - propagate sign

return w|0x7c00;

}

/*

* clamp float32 values that are not representable by float16

*/

{

// min float32 magnitude that rounds to float16 infinity

unsigned int f32MinRInfin = (f16MaxExp+f32ExpBias) <<

f32ExpShift;

f32MinRInfin |= LG_MAKE_MASK( f16MantissaBits+1 ) <<

(f32MantissaBits-f16MantissaBits-1);

if (mag > f32MinRInfin)

mag = f32MinRInfin;

}

{

// max float32 magnitude that rounds to float16 0.0

unsigned int f32MaxRf16_zero = f16MinExp+f32ExpBias

(f32MantissaBits-f16MantissaBits-1);

f32MaxRf16_zero <<= f32ExpShift;

f32MaxRf16_zero |= LG_MAKE_MASK( f32MantissaBits );

if (mag < f32MaxRf16_zero)

mag = f32MaxRf16_zero;

}

/*

* compute exp again, in case mag was clamped above

*/

exp = (mag >> f32ExpShift) - f32ExpBias;

// min float32 magnitude that converts to float16 normal

unsigned int f32Minf16Normal = ((f16MinExp+f32ExpBias)<<

f32ExpShift);

f32Minf16Normal |= LG_MAKE_MASK( f32MantissaBits );

if ( mag >= f32Minf16Normal ) {

//

// Case 1: float16 normal

//

// Modify exponent to be biased for float16, not float32

mag += (unsigned int) ((f16ExpBias-f32ExpBias)<<

f32ExpShift);

int RelativeShift = f32ExpShift-f16ExpShift;

// add rounding bias

mag += LG_MAKE_MASK(RelativeShift-1);

// round-to-nearest even

mag += (mag >> RelativeShift) & 1;

w |= mag >> RelativeShift;

}

else {

/*

* Case 2: float16 denormal

*/

// mask off exponent bits - now fraction only

mag &= LG_MAKE_MASK(f32MantissaBits);

// make implicit 1 explicit

mag |= (1<<f32ExpShift);

int RelativeShift = f32ExpShift-f16ExpShift+f16MinExp-exp;

// add rounding bias

mag += LG_MAKE_MASK(RelativeShift-1);

// round-to-nearest even

mag += (mag >> RelativeShift) & 1;

w |= mag >> RelativeShift;

}

return w;

}

实际上,开发人员应使用__floattohalf()内在函数将float转换为一半,编译器会将其转换为单个F2F机器指令。提供此示例例程的目的纯粹,为了帮助理解浮点布局和舍入。同样,检查所有INF / NAN和非标准值的特殊情况代码,有助于说明IEEE规范的这些功能,自诞生以来就一直引起争议:使硬件变慢,成本更高,或者由于增加的硅片面积和工程设计而使硬件变慢验证工作。

清单3中的ConvertFloatToHalf()例程被合并到名为float_to_float16.cu的程序中,该程序针对每个32位浮点值测试其输出。

3.6. Math Library

CUDA包括一个以C运行时库为模型的内置数学库,但有一些小区别:CUDA硬件不包括舍入模式寄存器(取而代之的是,舍入模式是按指令编码的),作为引用当前舍入模式的rint(),始终舍入为最接近值。此外,硬件不会引发浮点异常。异常运算的结果(例如,取负数的平方根)将编码为NaN。

表13列出了数学库函数以及每个函数的最大误差(单位为ulps)。在float上操作的大多数函数的函数名称后均带有“ f”,例如,计算正弦函数的函数如下。

double sin( double angle );

float sinf( float angle );

Table 13 Math Library

     

ULP ERROR

FUNCTION

OPERATION

EXPRESSION

32

64

x+y

Addition

x+y

01

0

x/y

Multiplication

x*y

01

0

x/y

Division

x/y

22

0

1/x

Reciprocal

1/x

12

0

acos[f](x)

Inverse cosine

cos–1 x

3

2

acosh[f](x)

Inverse hyperbolic cosine

 

4

2

asin[f](x)

Inverse sine

sin–1x

4

2

asinh[f](x)

Inverse hyperbolic sine

 

3

2

atan[f](x)

Inverse tangent

tan–1x

2

2

atan2[f](y,x)

Inverse tangent of y/x

 

3

2

atanh[f](x)

Inverse hyperbolic tangent

tanh–1

3

2

cbrt[f](x)

Cube root

 

1

1

ceil[f](x)

“Ceiling,” nearest integer greater than or equal to x

⌊x⌋

0

 

copysign[f](x,y)

Sign of y, magnitude of x

 

n/a

 

cos[f](x)

Cosine

cos x

2

1

cosh[f](x)

Hyperbolic cosine

 

2

 

cospi[f](x)

Cosine, scaled byΠ

cosΠx

2

 

erf[f](x)

Error function

 

3

2

erfc[f](x)

Complementary error function

 

6

4

erfcinv[f](y)

Inverse complementary error function

Return x for which y=1-erff(x)

7

8

erfcx[f](x)

Scaled error function

ex2[erff(x))

6

3

erfinv[f](y)

Inverse error function

Return x for which y=erff(x)

3

5

exp[f](x)

Natural exponent

ex

2

1

exp10[f](x)

Exponent (base 10)

10x

2

1

exp2[f](x)

Exponent (base 2)

2x

2

1

expm1[f](x)

Natural exponent, minus one

ex–1

1

1

fabs[f](x)

Absolute value

|x|

0

0

fdim[f](x,y)

Positive difference

x–1,x>y+0,x≤NAN,X or y NAN

0

0

floor[f](x)

“Floor,” nearest integer less than or equal to x

⌊x⌋

0

0

fma[f](x,y,z)

Multiply-add

xy + z

0

0

fmax[f](x,y)

Maximum

x, x y or isNaN(y)y, otherwise

0

0

fmin[f](x,y)

Minimum

x, x y or isNaN(y)y, otherwise

0

0

fmod[f](x,y)

Floating-point remainder

 

0

0

frexp[f](x,exp)

Fractional component

 

0

0

hypot[f](x,y)

Length of hypotenuse

 

3

2

ilogb[f](x)

Get exponent

 

0

0

isfinite(x)

Nonzero if x is not ±INF

   

n/a

isinf(x)

Nonzero if x is ±INF

   

n/a

isnan(x)

Nonzero if x is a NaN

   

n/a

j0[f](x)

Bessel function of the first kind (n=0)

J0(x)

93

73

j1[f](x)

Bessel function of the first kind (n=1)

J1(x)

93

73

jn[f](n,x)

Bessel function of the first kind

Jn(x)

 

*

ldexp[f](x,exp)

Scale by power of 2

x2exp

0

0

lgamma[f](x)

Logarithm of gamma function

ln(Γ(x))

64

44

llrint[f](x)

Round to long long

 

0

0

llround[f](x)

Round to long long

 

0

0

lrint[f](x)

Round to long

 

0

*

lround[f](x)

Round to long

 

0

0

log[f](x)

Natural logarithm

ln(x)

1

1

log10[f](x)

Logarithm (base 10)

log10 x

3

1

log1p[f](x)

Natural logarithm of x+1

ln(x + 1)

2

1

log2[f](x)

Logarithm (base 2)

log2 x

3

1

logb[f](x)

Get exponent

 

0

0

modff(x,iptr)

Split fractional and integer parts

 

0

0

nan[f](cptr)

Returns NaN

NaN

 

n/a

nearbyint[f](x)

Round to integer

 

0

0

nextafter[f](x,y)

Returns the FP value closest to x in the direction of y

   

n/a

normcdf[f](x)

Normal cumulative distribution

 

6

5

normcdinv[f](x)

Inverse normal cumulative distribution

 

5

8

pow[f](x,y)

Power function

xy

8

2

rcbrt[f](x)

Inverse cube root

 

2

1

remainder[f](x,y)

Remainder

 

0

0

remquo[f](x,y,iptr)

Remainder (also returns quotient)

 

0

0

rsqrt[f](x)

rsqrt[f](x) Reciprocal

 

2

1

rint[f](x)

Round to nearest int

 

0

0

round[f](x)

Round to nearest int

 

0

0

scalbln[f](x,n)

Scale x by 2n (n is long int)

x2n

0

0

scalbn[f](x,n)

Scale x by 2n (n is int)

x2n

0

0

signbit(x)

Nonzero if x is negative

 

n/a

0

sin[f](x)

Sine

sin x

2

1

sincos[f](x,s,c)

Sine and cosine

*s=sin(x);*c=cos(x);

2

1

sincospi[f](x,s,c)

Sine and cosine

*s=sin(Πx);*c=cos(Πx);

2

1

sinh[f](x)

Hyperbolic sine

 

3

1

Sine, scaled by Π

sin Πx

 

2

1

sqrt[f](x)

Square root

 

36

0

tan[f](x)

Tangent

tan x

4

2

tanh[f](x)

Hyperbolic tangent

 

2

1

tgamma[f](x)

True gamma function

γ(x)

11

8

trunc[f](x)

Truncate (round to integer toward zero)

 

0

0

y0[f](x)

Bessel function of the second kind (n=0)

Y0(x)

93

73

y1[f](x)

Bessel function of the second kind (n=1)

Y1(x)

93

73

yn[f](n,x)

Bessel function of the second kind

Yn(x)

 

..

这些在表13中表示为例如sin [f]

GPU编程和流式多处理器(三)的更多相关文章

  1. GPU编程和流式多处理器

    GPU编程和流式多处理器 流式多处理器(SM)是运行CUDA内核的GPU的一部分.本章重点介绍SM的指令集功能. 流式多处理器(SM)是运行我们的CUDA内核的GPU的一部分.每个SM包含以下内容. ...

  2. GPU编程和流式多处理器(六)

    GPU编程和流式多处理器(六) 5. 纹理和表面 读取和写入纹理和表面的指令,所引用的隐式状态,比其他指令要多得多.header中包含诸如基地址,尺寸,格式和纹理内容的解释之类的参数,该header是 ...

  3. GPU编程和流式多处理器(五)

    GPU编程和流式多处理器(五) 4. 条件代码 硬件实现了"条件代码"或CC寄存器,其中包含用于整数比较的常用4位状态向量(符号,进位,零,溢出).可以使用比较指令(例如ISET) ...

  4. GPU编程和流式多处理器(四)

    GPU编程和流式多处理器(四) 3.2. 单精度(32位) 单精度浮点支持是GPU计算的主力军.GPU已经过优化,可以在此数据类型上原生提供高性能,不仅适用于核心标准IEEE操作(例如加法和乘法),还 ...

  5. GPU编程和流式多处理器(二)

    GPU编程和流式多处理器(二) 2. 整数支持 SM具有32位整数运算的完整补充. 加法运算符的可选否定加法 乘法与乘法加法 整数除法 逻辑运算 条件码操作 to/from浮点转换 其它操作(例如,S ...

  6. GPU编程和流式多处理器(七)

    6. 杂项说明 6.1. warp级原语 warp作为执行的原始单元(自然位于线程和块之间),重要性对CUDA程序员显而易见.从SM 1.x开始,NVIDIA开始添加专门针对thread的指令. Vo ...

  7. GPU 编程入门到精通(三)之 第一个 GPU 程序

    博主因为工作其中的须要.開始学习 GPU 上面的编程,主要涉及到的是基于 GPU 的深度学习方面的知识,鉴于之前没有接触过 GPU 编程,因此在这里特地学习一下 GPU 上面的编程.有志同道合的小伙伴 ...

  8. Java8新特性 Stream流式思想(三)

    Stream接口中的常用方法 forEach()方法package cn.com.cqucc.demo02.StreamMethods.Test02.StreamMethods; import jav ...

  9. GPU 编程入门到精通(五)之 GPU 程序优化进阶

    博主因为工作其中的须要,開始学习 GPU 上面的编程,主要涉及到的是基于 GPU 的深度学习方面的知识.鉴于之前没有接触过 GPU 编程.因此在这里特地学习一下 GPU 上面的编程. 有志同道合的小伙 ...

随机推荐

  1. 攻防世界Web刷题记录(进阶区)

    攻防世界Web刷题记录(进阶区) 1.baby_web 发现去掉URLhttp://111.200.241.244:51461/1.php后面的1.php,还是会跳转到http://111.200.2 ...

  2. MBG:mybatis逆向工程使用

    一:如果是Maven工程可在pom.xml文件中添加插件 <build> <plugins> <plugin> <groupId>org.mybatis ...

  3. 支付宝手机端网页支付 PHP(基于官方提供的demo)

    1.支付宝开放平台添加应用并且签约快捷手机wap支付(应用添加不做详细说明) 2.下载demo,文档中心SDK&Demo, 3.个人中心秘钥管理,查看商户appID,商户私钥,支付宝公钥,商户 ...

  4. [PowerShell] 快速入门, 基本语法, 常用类型, 函数, .NET 互操作

    PowerShell 快速入门 开始之前, 我们认定你已经有一定的编程基础, 熟悉 .NET 中的类型与对象. 此文章对于 .NET 开发者来说更简单哦! 在 PowerShell 中, 几乎一切都是 ...

  5. 浅入浅出 MySQL 索引

    简单了解索引 首先,索引(Index)是什么?如果我直接告诉你索引是数据库管理系统中的一个有序的数据结构,你可能会有点懵逼. 为了避免这种情况,我打算举几个例子来帮助你更容易的认识索引. 我们查询字典 ...

  6. 03.28,周六,12:00-17:00,ICPC训练联盟周赛,选用试题:UCF Local Programming Contest 2016正式赛。

    A. Majestic 10 题意:三个数均大于10则输出"triple-double",如果两个数大于10则输出"double-double",如果一个大于1 ...

  7. 面试遇到的坑JS深拷贝和浅拷贝

    首先要搞明白深拷贝和钱拷贝的区别要先搞明白 栈和堆的区别 一.栈 栈存储基础数据类型,如: String.Number.Boolean.Null.Underined,这些简单的基础数据类型能够直接存储 ...

  8. 交互-通过axios拦截器添加token认证

    通过axios拦截器添加token认证 一.通过axios请求拦截器添加token,保证拥有获取数据的权限 通常访问接口需要相关权限,通常是需要携带token如下所示 那如何在请求头中添加token? ...

  9. 解决 Ubuntu 无法使用 root 用户进行 ssh 远程登陆

    解决 Ubuntu 无法使用 root 用户进行 ssh 远程登陆 操作系统 Ubuntu 20.04.2 LTS 一.修改sshd配置文件 //打开 /etc/ssh/sshd_config 配置文 ...

  10. Zabbix5.0服务端部署

    Zabbix5.0服务端部署 基础环境配置 [root@localhost ~]# systemctl disable --now firewalld Removed symlink /etc/sys ...