- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我想通过AVX2指令来加快以下操作的速度,但是我找不到解决方法。
我得到了uint64_t的大数组uint64_t data[100000]
和字节的数组unsigned char indices[100000]
。我想输出一个数组uint64_t Out[256]
,其中第i个值是所有data[j]
的异或,例如index[j]=i
。
我想要的一个简单的实现是:
uint64_t Out[256] = {0}; // initialize output array
for (i = 0; i < 100000 ; i++) {
Out[Indices[i]] ^= data[i];
}
uint64_t Out[256][4] = {0}; // initialize output array
for (i = 0; i < 100000 ; i+=4) {
Out[Indices[i ]][0] ^= data[i];
Out[Indices[i+1]][1] ^= data[i+1];
Out[Indices[i+2]][2] ^= data[i+2];
Out[Indices[i+3]][3] ^= data[i+3];
}
最佳答案
基于对Haswell / Skylake的静态分析,我想出了一个版本,它由gcc编译时,每4个i
值大约运行5个周期,而不是8个周期。大尺寸的平均值,不包括组合多个Out[]
副本的时间,并假定索引的随机分布不会导致任何存储/重载dep链运行足够长的时间。
如果您关心Ryzen或Excavator(其他2种主流AVX2微结构),则为IDK。
我没有进行手工仔细的分析,但是IACA对于HSW / SKL是错误的,并且认为某些指令实际上确实是微熔丝的(在具有perf计数器的i7-6700k上进行了测试),所以它认为前端瓶颈比实际更严重。例如movhps
加载+合并微熔断器,但是IACA认为它甚至没有简单的寻址模式。
我们应该忽略任何缓存丢失,因为uint64_t Out[4][256]
仅为8kiB。因此,在最近的CPU上,我们的缓存占用空间仅为L1d大小的1/4,即使在两个逻辑线程之间共享L1d的超线程共享中,我们的缓存占用也应该足够好。循环遍历data[]
和Indices[]
应该很好地预取,并且希望不会过多地退出Out[]
。因此,静态分析很有可能会有些准确,并且比仔细进行微基准测试要快,而且更重要的是,它可以准确告诉您瓶颈所在。
但是当然,我们严重依赖乱序执行,不完善的计划安排或其他意外瓶颈很容易发生。但是,如果我没有得到报酬,我实际上并不想进行微基准测试。
我们可以使用AVX2指令更有效地实现这一点吗?
这基本上是一个直方图问题。通常使用使用多个表并在最后合并的直方图优化。 SIMD XOR对于末端组合非常有用(只要您使用Out[4][256]
,而不是Out[256][4]
。后者还会通过要求使用8*4
而不是8
进行缩放来使索引变慢(这可以可以在缩放索引寻址模式下使用单个LEA完成))。
但是与普通的直方图不同,您要对内存中的某些数据进行XOR运算,而不是对常量1进行加法运算。因此,除了直接的1
之外,代码还必须将data[i]
加载到寄存器中作为xor
的源。 (或加载,然后xor reg, data[i]
/存储)。这比直方图要多得多。
我们从“手动”收集/分散到SIMD向量(使用movq
/ movhps
加载/存储)中脱颖而出,从而允许我们将SIMD用于data[i]
加载和XOR。这减少了负载操作的总数,从而减少了负载端口压力,而无需花费额外的前端带宽。
手动收集到256位向量中可能不值得进行额外的改组(额外的vinserti128 / vextracti128,以便我们可以将2个内存源vpxor
组合为一个256位之一)。 128位向量应该很好。前端吞吐量也是一个主要问题,因为(在Intel SnB系列CPU上)您要避免存储的索引寻址模式。 gcc使用lea
指令来计算寄存器中的地址,而不是使用索引加载/存储。带有-march=skylake
的clang / LLVM决定不这样做,因为在端口2 /端口3上存在环路瓶颈,并且花费额外的ALU指令以允许存储地址指令使用端口7是成功的,所以这是一个错误的决定。但是,如果您没有遇到p23的瓶颈,那么花额外的钱来避免建立索引存储就不好了。 (还有in cases where the can stay micro-fused,绝对不仅仅是避免索引负载;愚蠢的gcc)。也许gcc和LLVM的寻址模式成本模型不是很准确,或者它们没有对流水线进行足够详细的建模以找出何时前端和特定端口上的环路出现瓶颈。
寻址模式的选择以及其他asm代码生成的选择对于使SnB系列达到最佳性能至关重要。但是用C编写使您无法控制它。除非您可以调整源代码以做出其他选择,否则您通常会受到编译器的摆布。例如gcc与clang在这里有很大的不同。
在SnB系列上,movhps
负载需要端口5进行混洗/混合(尽管它确实将微熔丝装入一个uop中),但是movhps
存储是没有ALU uop的纯存储。因此,它在那里达到了收支平衡,让我们对两个数据元素使用一个SIMD加载/ XOR。
使用AVX,ALU uops允许使用未对齐的内存源操作数,因此我们不需要为data[]
对齐。但是,英特尔HSW / SKL可以使索引寻址模式与pxor
而不是vpxor
微融合。因此,在未启用AVX的情况下进行编译会更好,允许编译器使用索引寻址模式,而不是增加单独的指针。 (或者,如果编译器不知道并且仍使用索引寻址模式,则可以使其更快。)TL:DR:可能最好要求16字节对齐的data[]
并在禁用AVX的情况下编译该功能,以实现更好的宏融合。 (但随后,我们错过了在末尾组合Out
切片的256位SIMD,除非我们将其放入使用AVX或AVX2编译的其他函数中)
避免未对齐的负载也将避免任何高速缓存行拆分,这不会花费额外的成本,但是我们很可能接近L1d吞吐量限制的瓶颈,而不仅仅是加载/存储执行单元吞吐量限制。
我还查看了一次加载4个索引并使用ALU指令解压缩的情况。例如用memcpy
转换为struct { uint8_t idx[4]; } idx;
。但是gcc生成了许多浪费的指令来解压缩该指令。太糟糕的x86没有很好的位域指令,例如ARM ubfx
或特别是PowerPC rlwinm
(这可能会使结果免费左移,因此,如果x86拥有该位,则静态Out
可以使用base +非PIC代码中的disp32寻址模式。)
如果我们使用标量XOR,则用shift / movzx从AL / AH中解压缩双字是一个胜利,但是当我们在data[]
中使用SIMD并将lea
指令的前端吞吐量用于允许存储地址uops在端口7上运行。这使我们成为前端瓶颈,而不是port2 / 3瓶颈,因此根据静态分析,使用4x movzx
内存加载看起来最好。如果您花时间手动编辑组件,则值得对两种方法进行基准测试。 (由gcc生成的具有额外uos的asm太糟糕了,包括在右移24之后完全冗余的movzx
,而高位已经为零。)
代码
(在the Godbolt compiler explorer上查看它,以及标量版本):
#include <immintrin.h>
#include <stdint.h>
#include <string.h>
#include <stdalign.h>
#ifdef IACA_MARKS
#include "/opt/iaca-3.0/iacaMarks.h"
#else
#define IACA_START
#define IACA_END
#endif
void hist_gatherscatter(unsigned idx0, unsigned idx1,
uint64_t Out0[256], uint64_t Out1[256],
__m128i vdata) {
// gather load from Out[0][?] and Out[1][?] with movq / movhps
__m128i hist = _mm_loadl_epi64((__m128i*)&Out0[idx0]);
hist = _mm_castps_si128( // movhps into the high half
_mm_loadh_pi(_mm_castsi128_ps(hist), (__m64*)&Out1[idx1]));
// xorps could bottleneck on port5.
// Actually probably not, using __m128 the whole time would be simpler and maybe not confuse clang
hist = _mm_xor_si128(hist, vdata);
// scatter store with movq / movhps
_mm_storel_epi64((__m128i*)&Out0[idx0], hist);
_mm_storeh_pi((__m64*)&Out1[idx1], _mm_castsi128_ps(hist));
}
void ext(uint64_t*);
void xor_histo_avx(uint8_t *Indices, const uint64_t *data, size_t len)
{
alignas(32) uint64_t Out[4][256] = {{0}};
// optional: peel the first iteration and optimize away loading the old known-zero values from Out[0..3][Indices[0..3]].
if (len<3) // not shown: cleanup for last up-to-3 elements.
return;
for (size_t i = 0 ; i<len ; i+=4) {
IACA_START
// attempt to hand-hold compiler into a dword load + shifts to extract indices
// to reduce load-port pressure
struct { uint8_t idx[4]; } idx;
#if 0
memcpy(&idx, Indices+i, sizeof(idx)); // safe with strict-aliasing and possibly-unaligned
//gcc makes stupid asm for this, same as for memcpy into a struct,
// using a dword load into EAX (good),
// then AL/AH for the first 2 (good)
// but then redundant mov and movzx instructions for the high 2
// clang turns it into 4 loads
/*
//Attempt to hand-hold gcc into less-stupid asm
//doesn't work: same asm as the struct
uint32_t tmp;
memcpy(&tmp, Indices+i, sizeof(tmp)); // mov eax,[mem]
idx.idx[0] = tmp; //movzx reg, AL
idx.idx[1] = tmp>>8; //movzx reg, AH
tmp >>= 16; //shr eax, 16
idx.idx[2] = tmp; //movzx reg, AL
idx.idx[3] = tmp>>8; //movzx reg, AH
*/
#else
// compiles to separate loads with gcc and clang
idx.idx[0] = Indices[i+0];
idx.idx[1] = Indices[i+1];
idx.idx[2] = Indices[i+2];
idx.idx[3] = Indices[i+3];
#endif
__m128i vd = _mm_load_si128((const __m128i*)&data[i]);
hist_gatherscatter(idx.idx[0], idx.idx[1], Out[0], Out[1], vd);
vd = _mm_load_si128((const __m128i*)&data[i+2]);
hist_gatherscatter(idx.idx[2], idx.idx[3], Out[2], Out[3], vd);
}
IACA_END
// hand-hold compilers into a pointer-increment loop
// to avoid indexed addressing modes. (4/5 speedup on HSW/SKL if all the stores use port7)
__m256i *outp = (__m256i*)&Out[0];
__m256i *endp = (__m256i*)&Out[3][256];
for (; outp < endp ; outp++) {
outp[0] ^= outp[256/4*1];
outp[0] ^= outp[256/4*2];
outp[0] ^= outp[256/4*3];
}
// This part compiles horribly with -mno-avx, but does compile
// because I used GNU C native vector operators on __m256i instead of intrinsics.
/*
for (int i=0 ; i<256 ; i+=4) {
// use loadu / storeu if Out isn't aligned
__m256i out0 = _mm256_load_si256(&Out[0][i]);
__m256i out1 = _mm256_load_si256(&Out[1][i]);
__m256i out2 = _mm256_load_si256(&Out[2][i]);
__m256i out3 = _mm256_load_si256(&Out[3][i]);
out0 = _mm256_xor_si256(out0, out1);
out0 = _mm256_xor_si256(out0, out2);
out0 = _mm256_xor_si256(out0, out3);
_mm256_store_si256(&Out[0][i], out0);
}
*/
//ext(Out[0]); // prevent optimizing away the work
asm("" :: "r"(Out) : "memory");
}
-std=gnu11 -DIACA_MARKS -O3 -march=skylake -mno-avx
编译,并用IACA-3.0分析:
$ /opt/iaca-3.0/iaca xor-histo.iaca.o Intel(R) Architecture Code Analyzer Version - v3.0-28-g1ba2cbb build date: 2017-10-23;16:42:45
Analyzed File - xor-histo.iaca.o
Binary Format - 64Bit
Architecture - SKL
Analysis Type - Throughput
Throughput Analysis Report
--------------------------
Block Throughput: 5.79 Cycles Throughput Bottleneck: FrontEnd
Loop Count: 22 (this is fused-domain uops. It's actually 20, so a 5 cycle front-end bottleneck)
Port Binding In Cycles Per Iteration:
--------------------------------------------------------------------------------------------------
| Port | 0 - DV | 1 | 2 - D | 3 - D | 4 | 5 | 6 | 7 |
--------------------------------------------------------------------------------------------------
| Cycles | 2.0 0.0 | 3.0 | 5.5 5.1 | 5.5 4.9 | 4.0 | 3.0 | 2.0 | 3.0 |
--------------------------------------------------------------------------------------------------
DV - Divider pipe (on port 0)
D - Data fetch pipe (on ports 2 and 3)
F - Macro Fusion with the previous instruction occurred
* - instruction micro-ops not bound to a port
^ - Micro Fusion occurred
# - ESP Tracking sync uop was issued
@ - SSE instruction followed an AVX256/AVX512 instruction, dozens of cycles penalty is expected
X - instruction not supported, was not accounted in Analysis
| Num Of | Ports pressure in cycles | |
| Uops | 0 - DV | 1 | 2 - D | 3 - D | 4 | 5 | 6 | 7 |
-----------------------------------------------------------------------------------------
| 1 | | | 0.5 0.5 | 0.5 0.5 | | | | | movzx r8d, byte ptr [rdi]
| 1 | | | 0.5 0.5 | 0.5 0.5 | | | | | movzx edx, byte ptr [rdi+0x2]
| 1 | | | | | | | 1.0 | | add rdi, 0x4
| 1 | | | | | | | 1.0 | | add rsi, 0x20
| 1 | | | 0.5 0.5 | 0.5 0.5 | | | | | movzx eax, byte ptr [rdi-0x1]
| 1 | | 1.0 | | | | | | | lea r12, ptr [rcx+r8*8]
| 1 | | | 0.5 0.5 | 0.5 0.5 | | | | | movzx r8d, byte ptr [rdi-0x3]
| 1 | | 1.0 | | | | | | | lea rdx, ptr [r10+rdx*8]
| 1 | | | 0.5 0.5 | 0.5 0.5 | | | | | movq xmm0, qword ptr [r12]
| 1 | | | | | | 1.0 | | | lea rax, ptr [r9+rax*8]
| 1 | | 1.0 | | | | | | | lea r8, ptr [r11+r8*8]
| 2 | | | 0.5 0.5 | 0.5 0.5 | | 1.0 | | | movhps xmm0, qword ptr [r8] # Wrong, 1 micro-fused uop on SKL
| 2^ | 1.0 | | 0.5 0.5 | 0.5 0.5 | | | | | pxor xmm0, xmmword ptr [rsi-0x20]
| 2^ | | | 0.5 | 0.5 | 1.0 | | | | movq qword ptr [r12], xmm0 # can run on port 7, IDK why IACA chooses not to model it there
| 2^ | | | | | 1.0 | | | 1.0 | movhps qword ptr [r8], xmm0
| 1 | | | 0.5 0.5 | 0.5 0.5 | | | | | movq xmm0, qword ptr [rdx]
| 2 | | | 0.5 0.5 | 0.5 0.5 | | 1.0 | | | movhps xmm0, qword ptr [rax] # Wrong, 1 micro-fused uop on SKL
| 2^ | 1.0 | | 0.5 0.5 | 0.5 0.5 | | | | | pxor xmm0, xmmword ptr [rsi-0x10]
| 2^ | | | | | 1.0 | | | 1.0 | movq qword ptr [rdx], xmm0
| 2^ | | | | | 1.0 | | | 1.0 | movhps qword ptr [rax], xmm0
| 1* | | | | | | | | | cmp rbx, rdi
| 0*F | | | | | | | | | jnz 0xffffffffffffffa0
Total Num Of Uops: 29 (This is unfused-domain, and a weird thing to total up).
pxor
使用缩放索引寻址模式,对索引和
data[]
使用相同的计数器,这样可以节省
add
。
i
,因为没有任何存储uops可以在端口7上运行。
Out[4][256]
切片):
$ iaca.sh -mark 2 xor-histo.iaca.o
Intel(R) Architecture Code Analyzer Version - 2.3 build:246dfea (Thu, 6 Jul 2017 13:38:05 +0300)
Analyzed File - xor-histo.iaca.o
Binary Format - 64Bit
Architecture - SKL
Analysis Type - Throughput
*******************************************************************
Intel(R) Architecture Code Analyzer Mark Number 2
*******************************************************************
Throughput Analysis Report
--------------------------
Block Throughput: 7.24 Cycles Throughput Bottleneck: FrontEnd
Port Binding In Cycles Per Iteration:
---------------------------------------------------------------------------------------
| Port | 0 - DV | 1 | 2 - D | 3 - D | 4 | 5 | 6 | 7 |
---------------------------------------------------------------------------------------
| Cycles | 3.0 0.0 | 3.0 | 6.2 4.5 | 6.8 4.5 | 4.0 | 3.0 | 3.0 | 0.0 |
---------------------------------------------------------------------------------------
N - port number or number of cycles resource conflict caused delay, DV - Divider pipe (on port 0)
D - Data fetch pipe (on ports 2 and 3), CP - on a critical path
F - Macro Fusion with the previous instruction occurred
* - instruction micro-ops not bound to a port
^ - Micro Fusion happened
# - ESP Tracking sync uop was issued
@ - SSE instruction followed an AVX256/AVX512 instruction, dozens of cycles penalty is expected
X - instruction not supported, was not accounted in Analysis
| Num Of | Ports pressure in cycles | |
| Uops | 0 - DV | 1 | 2 - D | 3 - D | 4 | 5 | 6 | 7 | |
---------------------------------------------------------------------------------
| 1 | | | 0.5 0.5 | 0.5 0.5 | | | | | | mov eax, dword ptr [rdi]
| 1 | 0.4 | 0.5 | | | | 0.1 | | | | add rdi, 0x4
| 1 | | 0.7 | | | | 0.3 | | | | add rsi, 0x20
| 1* | | | | | | | | | | movzx r9d, al
| 1 | | | 0.5 0.5 | 0.5 0.5 | | | | | | mov rdx, qword ptr [rbp+r9*8-0x2040]
| 2^ | | 0.3 | 0.5 0.5 | 0.5 0.5 | | 0.3 | 0.4 | | | xor rdx, qword ptr [rsi-0x20]
| 2 | | | 0.5 | 0.5 | 1.0 | | | | | mov qword ptr [rbp+r9*8-0x2040], rdx # wrong, HSW/SKL can keep indexed stores fused
| 1* | | | | | | | | | | movzx edx, ah
| 1 | | | | | | 0.4 | 0.6 | | | add rdx, 0x100
| 1 | | | 0.5 0.5 | 0.5 0.5 | | | | | | mov r9, qword ptr [rbp+rdx*8-0x2040]
| 2^ | 0.6 | 0.2 | 0.5 0.5 | 0.5 0.5 | | 0.2 | 0.1 | | | xor r9, qword ptr [rsi-0x18]
| 2 | | | 0.2 | 0.8 | 1.0 | | | | | mov qword ptr [rbp+rdx*8-0x2040], r9 # wrong, HSW/SKL can keep indexed stores fused
| 1* | | | | | | | | | | mov edx, eax # gcc code-gen isn't great, but not as bad as in the SIMD loop. No extra movzx, but not taking advantage of AL/AH
| 1 | 0.4 | | | | | | 0.6 | | | shr eax, 0x18
| 1 | 0.8 | | | | | | 0.2 | | | shr edx, 0x10
| 1 | | 0.6 | | | | 0.3 | | | | add rax, 0x300
| 1* | | | | | | | | | | movzx edx, dl
| 1 | 0.2 | 0.1 | | | | 0.5 | 0.2 | | | add rdx, 0x200
| 1 | | | 0.5 0.5 | 0.5 0.5 | | | | | | mov r9, qword ptr [rbp+rdx*8-0x2040]
| 2^ | | 0.6 | 0.5 0.5 | 0.5 0.5 | | 0.3 | 0.1 | | | xor r9, qword ptr [rsi-0x10]
| 2 | | | 0.5 | 0.5 | 1.0 | | | | | mov qword ptr [rbp+rdx*8-0x2040], r9 # wrong, HSW/SKL can keep indexed stores fused
| 1 | | | 0.5 0.5 | 0.5 0.5 | | | | | | mov rdx, qword ptr [rbp+rax*8-0x2040]
| 2^ | | | 0.5 0.5 | 0.5 0.5 | | 0.6 | 0.4 | | | xor rdx, qword ptr [rsi-0x8]
| 2 | | | 0.5 | 0.5 | 1.0 | | | | | mov qword ptr [rbp+rax*8-0x2040], rdx # wrong, HSW/SKL can keep indexed stores fused
| 1 | 0.6 | | | | | | 0.4 | | | cmp r8, rdi
| 0F | | | | | | | | | | jnz 0xffffffffffffff75
Total Num Of Uops: 33
.L7:
vmovdqa ymm2, YMMWORD PTR [rax+4096]
vpxor ymm0, ymm2, YMMWORD PTR [rax+6144]
vmovdqa ymm3, YMMWORD PTR [rax]
vpxor ymm1, ymm3, YMMWORD PTR [rax+2048]
vpxor ymm0, ymm0, ymm1
vmovdqa YMMWORD PTR [rax], ymm0
add rax, 32
cmp rax, rdx
jne .L7
vmovdqa
加载,并且必须在没有内存操作数的情况下执行一个
vpxor
。 (OoO执行人员将隐藏VPXOR的这个微小链/树的延迟,因此没有关系。)
out[8][256]
,以便每个向量元素都可以使用不同的表。 (否则,如果
Indices[i+0]
和
Indices[i+4]
相等,则会遇到问题,因为分散存储将只存储具有该索引的最高矢量元素。
_mm256_setr_epi64(0, 256, 256*2, ...);
零扩展加载后简单地添加
vpmovzxbq
。
-mark
选项来选择要分析的循环。在这种情况下,IACA3.0并未解决IACA2.3对SKL管道错误的任何方式。
关于optimization - 使用AVX2指令选择性地对列表元素进行异或,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50583718/
我正在尝试在现有指令的基础上构建一个新指令,但我在我的过程中停止了。加载页面时,我面临以下错误: Multiple directives [directive#1, directive#2] aski
我是 angularjs 世界的新手,我只需要在数字类型的输入中输入从 1 到 10 的数字。不使用 HTML5 的 min 和 max 属性 我在 Jquery 中找到了一个示例,能否帮我将其转换为
我想使用 ionic与 Material 设计。我被困在使用带有自定义 CSS 的 ionic 指令和 angular-material 之间。 我读过使用 ionic 指令我们得到了很多高效的特性,
我创建了以下代码: var node = document.getElementById('TreeList'); var keys = Object.keys(model[0]); var trac
在 AngularJs 中没有提供 ng-enabled 指令。是否有任何适当的理由不在框架中提供该指令,因为当您可以使用 ng- 时,我们同时拥有 ng-show 和 ng-hide隐藏来实现我们的
我最近制作的程序有问题。基本上,它是 John Conway 人生游戏的简单版本,但它运行不正常。问题出在读取单元格及其邻居的状态并决定该单元格的 future 状态的代码中。这是代码的一部分(有点长
Dockerfile reference关于 FROM 指令的内容如下: FROM can appear multiple times within a single Dockerfile in or
我一直在尝试理解指令中孤立作用域和继承作用域之间的区别。这是我准备让自己理解的一个例子: HTML Inside isolated scope directive: {{m
知道如何从指令内部访问属性值吗? angular.module('portal.directives', []) .directive('languageFlag', ['$r
我正在通过将 c 程序与其等价的汇编程序进行比较来学习汇编。 这是代码。 .file "ex3.c" .section .rodata .LC0: .string "I am %d
我正在尝试写一个 Jenkinsfile并行执行一系列步骤。目标是拥有两个 agents (又名。 nodes )。一个应该进行 Windows 构建,另一个应该进行 linux 构建。但是,我不希望
我想知道为什么指令 FYL2XP1在 x86 架构上精确计算数学公式 y · log2(x + 1)。 这个公式有什么特别之处? 最佳答案 y操作数通常是编译时常量,暂时忘记 x + 1 . 自 lo
这个问题已经有答案了: Parameterize an SQL IN clause (41 个回答) 已关闭 8 年前。 第一个声明: Select GroupMember FROM Group 结果
我从 this question fork 并编辑了一个 plunker 我想做的是在数据加载后更新/填充 SELECT 元素(组合框),但有些事情不对劲。我检索数据,它位于 SELECT 元素的范围
我想创建一个简单的 markdown 指令,它接受元素中的一些内容,解析它并用 html 替换它。 所以这样: #Heading 或这个(其中 $scope.heading = '#Heading';
我对 Ansible 还很陌生,对于我对 local_action 指令的理解有一个简单的问题。 这是否意味着该命令完全在本地执行?假设你有这样的东西: local_action: command w
我有以下 HTML: ... ... 以及以下指令: myApp.directive('specialInput', ['$timeout', function($timeout)
如何在 .htaccess 中创建 Apache 指令强制文件 .mp4和 .pdf去下载?目前它们出现在浏览器窗口中。相反,我希望出现一个下载文件对话框。 最佳答案 将以下内容添加到 .htacce
我的问题是关于 C 中的 fork() 指令。我有以下程序: void main(){ int result, status; result = fork(); if(result=
我想要一个类似于 ng-model 的属性指令。我只想另外将一个输入字段值绑定(bind)到一个范围变量(只是在一个方向输入字段 ->范围变量)。所以我刚刚尝试了这个指令,但无论如何我都无法调用该指令
我是一名优秀的程序员,十分优秀!