maria-discuss team mailing list archive
-
maria-discuss team
-
Mailing list archive
-
Message #05685
Re: Some questions about the Aarch64 CI
On Tue, 26 Nov 2019 10:56:41 +0200
Marko Mäkelä <marko.makela@xxxxxxxxxxx> wrote:
> Hi Daniel,
>
> On Tue, Nov 26, 2019 at 2:02 AM Daniel Black <daniel@xxxxxxxxxxxxx> wrote:
> >
> > On Mon, 25 Nov 2019 11:32:07 +0200
> > Marko Mäkelä <marko.makela@xxxxxxxxxxx> wrote:
> >
> >
> > > I also found a claim that POWER8 supports unaligned access,
> >
> > This is correct (for the normal cacheable memory (i.e. not device IO mapped - so not applicable to mariadb))
> >
> > > and I seem
> > > to remember that the latest version of the SPARC introduced support
> > > for that as well. (IA-32 and AMD64 have always supported unaligned
> > > access, except for some SIMD operations.)
> > >
> > > Last, I believe that we could get some performance benefits if
> > > include/byte_order_generic.h was rewritten in a suitable way. Ideally,
> > > include/byte_order_generic_x86_64.h would be replaced with a portable
> > > version of both, and compilers could simply perform the optimizations.
> > > I have been told that replacing the + in the macros with | could
> > > already be a good start. I would welcome patches in this area.
> >
> > I've never managed to get the time to look at these however a non-aligned version for non-common arches seems a better way to model this.
>
> I pushed my micro-optimization to 10.5:
> https://github.com/MariaDB/server/commit/25e2a556de2e125784d52a0c7ccda4fa6595df50
>
> If there really is no compiler flag that would allow any memcpy(),
> memset(),
> memcmp()
Well, actually:
-fno-builtin-mem{cmp,set,cpy}
-mmem{set,cpy}-strategy= (seems x86 only)
> of 2,4,8 bytes to be translated into simple
> (possibly unaligned) multi-byte instructions,
Actually gcc has put an effort into getting the optimum implementation here already. It doesn't look like a thing an end application should be trying to optimise.
$ rm -f memset_opt.o && gcc -O1 -fomit-frame-pointer -c memset_opt.c -o memset_opt.o && objdump -d memset_opt.o | grep -A 10 vmem
0000000000000000 <vmemset>:
0: c7 07 00 00 00 00 movl $0x0,(%rdi)
6: c3 retq
0000000000000007 <vmemcmp>:
7: 48 83 ec 18 sub $0x18,%rsp
b: 89 7c 24 0c mov %edi,0xc(%rsp)
f: ba 04 00 00 00 mov $0x4,%edx
14: 48 8d 74 24 0c lea 0xc(%rsp),%rsi
19: bf 00 00 00 00 mov $0x0,%edi
1e: e8 00 00 00 00 callq 23 <vmemcmp+0x1c>
23: 48 83 c4 18 add $0x18,%rsp
27: c3 retq
0000000000000028 <vmemstatic>:
28: b8 ff ff ff ff mov $0xffffffff,%eax
2d: c3 retq
000000000000002e <vmemcpy>:
2e: 8b 05 00 00 00 00 mov 0x0(%rip),%eax # 34 <vmemcpy+0x6>
34: 89 07 mov %eax,(%rdi)
36: c3 retq
[dan@volution junk]$ cat memset_opt.c
#include <string.h>
static int comp = 7;
char r[30];
void vmemset(char v[30])
{
memset(v, 0, 4);
}
int vmemcmp(int c)
{
return memcmp(&comp, &c, sizeof(c));
}
int vmemstatic()
{
return memcmp("cat", "dog", 3);
}
void vmemcpy(int *c)
{
memcpy(c, r, sizeof(*c));
}
Not sure why vmemcmp still has a memcpy call, but by vmemstatic some understanding is there.
script to test:
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=43052#c12
Intel(R) Core(TM) i7-6820HQ CPU @ 2.70GHz (laptop)
glibc-2.29-22.fc30
gcc (GCC) 9.2.1 20190827 (Red Hat 9.2.1-1)
$ sh test_stringop 64 640000000 gcc -march=native
memcpy mode:64 size:640000000
libcall rep1 noalg rep4 noalg rep8 noalg loop noalg unrl noalg byte profiled dynamic
block size 8192000 0:00.12 0:00.12 0:00.12 0:00.13 0:00.12 0:00.12 0:00.13 0:00.13 0:00.13 0:00.13 0:00.13 0:00.50 0:00.12 0:00.12 best: 0:00.12 libcall
block size 819200 0:00.08 0:00.10 0:00.10 0:00.10 0:00.10 0:00.10 0:00.10 0:00.09 0:00.09 0:00.09 0:00.09 0:00.48 0:00.08 0:00.08 best: 0:00.08 libcall
block size 81920 0:00.04 0:00.05 0:00.05 0:00.05 0:00.04 0:00.04 0:00.05 0:00.09 0:00.08 0:00.07 0:00.08 0:00.51 0:00.04 0:00.04 best: 0:00.04 libcall
block size 20480 0:00.04 0:00.04 0:00.04 0:00.04 0:00.04 0:00.04 0:00.04 0:00.07 0:00.11 0:00.08 0:00.08 0:00.86 0:00.03 0:00.04 best: 0:00.04 libcall
block size 8192 0:00.03 0:00.03 0:00.04 0:00.04 0:00.03 0:00.03 0:00.03 0:00.06 0:00.10 0:00.06 0:00.07 0:00.48 0:00.03 0:00.03 best: 0:00.03 libcall
block size 4096 0:00.03 0:00.03 0:00.03 0:00.03 0:00.03 0:00.03 0:00.03 0:00.06 0:00.10 0:00.06 0:00.07 0:00.47 0:00.03 0:00.03 best: 0:00.03 libcall
block size 2048 0:00.03 0:00.03 0:00.03 0:00.04 0:00.03 0:00.04 0:00.03 0:00.07 0:00.10 0:00.06 0:00.07 0:00.48 0:00.03 0:00.03 best: 0:00.03 libcall
block size 1024 0:00.04 0:00.04 0:00.04 0:00.05 0:00.04 0:00.05 0:00.04 0:00.08 0:00.11 0:00.07 0:00.07 0:00.49 0:00.03 0:00.04 best: 0:00.04 libcall
block size 512 0:00.05 0:00.06 0:00.06 0:00.06 0:00.05 0:00.06 0:00.05 0:00.09 0:00.12 0:00.07 0:00.07 0:00.50 0:00.09 0:00.06 best: 0:00.05 libcall
block size 256 0:00.07 0:00.08 0:00.08 0:00.09 0:00.08 0:00.09 0:00.08 0:00.10 0:00.12 0:00.09 0:00.09 0:00.52 0:00.10 0:00.09 best: 0:00.07 libcall
block size 128 0:00.11 0:00.13 0:00.13 0:00.15 0:00.13 0:00.15 0:00.13 0:00.14 0:00.14 0:00.12 0:00.11 0:00.56 0:00.12 0:00.12 best: 0:00.11 libcall
block size 64 0:00.20 0:00.20 0:00.20 0:00.24 0:00.22 0:00.24 0:00.22 0:00.19 0:00.20 0:00.18 0:00.19 0:00.75 0:00.18 0:00.18 best: 0:00.18 unrl
block size 48 0:00.25 0:00.28 0:00.28 0:00.31 0:00.31 0:00.31 0:00.29 0:00.23 0:00.22 0:00.22 0:00.23 0:00.66 0:00.22 0:00.22 best: 0:00.22 loopnoalign
block size 32 0:00.38 0:00.40 0:00.38 0:00.44 0:00.39 0:00.45 0:00.38 0:00.30 0:00.32 0:00.30 0:00.31 0:00.93 0:00.31 0:00.31 best: 0:00.30 loop
block size 24 0:00.51 0:00.57 0:00.56 0:00.63 0:00.58 0:00.64 0:00.56 0:00.42 0:00.40 0:00.36 0:00.37 0:00.78 0:00.37 0:00.36 best: 0:00.36 unrl
block size 16 0:00.75 0:00.74 0:00.74 0:00.84 0:00.74 0:00.85 0:00.70 0:00.48 0:00.47 0:00.40 0:00.40 0:00.87 0:00.48 0:00.47 best: 0:00.40 unrl
block size 14 0:00.76 0:00.95 0:00.97 0:01.01 0:00.99 0:01.01 0:00.89 0:00.52 0:00.51 0:00.49 0:00.49 0:00.88 0:00.54 0:00.53 best: 0:00.49 unrl
block size 12 0:00.93 0:01.10 0:01.10 0:01.14 0:01.05 0:01.19 0:00.98 0:00.64 0:00.61 0:00.56 0:00.57 0:00.79 0:00.64 0:00.59 best: 0:00.56 unrl
block size 10 0:01.04 0:01.31 0:01.31 0:01.37 0:01.23 0:01.41 0:01.14 0:00.75 0:00.74 0:00.68 0:00.65 0:00.86 0:00.68 0:00.69 best: 0:00.65 unrlnoalign
block size 8 0:01.36 0:01.59 0:01.55 0:01.68 0:01.37 0:01.64 0:01.18 0:00.79 0:00.79 0:00.73 0:00.73 0:00.89 0:00.81 0:00.78 best: 0:00.73 unrl
block size 6 0:01.66 0:02.25 0:02.23 0:02.31 0:02.01 0:02.31 0:01.57 0:01.01 0:00.96 0:00.99 0:01.01 0:01.02 0:01.00 0:01.01 best: 0:00.96 loopnoalign
block size 4 0:02.68 0:03.24 0:03.47 0:03.21 0:02.65 0:01.38 0:01.36 0:01.41 0:01.34 0:01.38 0:01.35 0:01.47 0:01.26 0:01.32 best: 0:01.34 loopnoalign
block size 1 0:05.41 0:17.59 0:17.41 0:01.52 0:01.51 0:01.46 0:01.50 0:01.59 0:01.49 0:01.56 0:01.52 0:02.43 0:02.39 0:02.42 best: 0:01.46 rep8
memset
libcall rep1 noalg rep4 noalg rep8 noalg loop noalg unrl noalg byte profiled dynamic
block size 8192000 0:00.05 0:00.05 0:00.06 0:00.05 0:00.05 0:00.05 0:00.05 0:00.11 0:00.09 0:00.09 0:00.11 0:00.47 0:00.05 0:00.05 best: 0:00.05 libcall
block size 819200 0:00.05 0:00.05 0:00.05 0:00.05 0:00.05 0:00.05 0:00.05 0:00.10 0:00.08 0:00.07 0:00.08 0:00.45 0:00.06 0:00.05 best: 0:00.05 libcall
block size 81920 0:00.03 0:00.03 0:00.03 0:00.04 0:00.04 0:00.03 0:00.03 0:00.10 0:00.07 0:00.06 0:00.07 0:00.47 0:00.04 0:00.03 best: 0:00.03 libcall
block size 20480 0:00.03 0:00.03 0:00.03 0:00.03 0:00.03 0:00.03 0:00.03 0:00.08 0:00.11 0:00.07 0:00.08 0:00.51 0:00.03 0:00.03 best: 0:00.03 libcall
block size 8192 0:00.03 0:00.03 0:00.03 0:00.03 0:00.03 0:00.03 0:00.03 0:00.09 0:00.06 0:00.06 0:00.06 0:00.45 0:00.03 0:00.03 best: 0:00.03 libcall
block size 4096 0:00.03 0:00.03 0:00.03 0:00.03 0:00.03 0:00.03 0:00.04 0:00.10 0:00.06 0:00.06 0:00.06 0:00.41 0:00.03 0:00.03 best: 0:00.03 libcall
block size 2048 0:00.04 0:00.03 0:00.04 0:00.04 0:00.03 0:00.04 0:00.03 0:00.10 0:00.06 0:00.06 0:00.06 0:00.41 0:00.04 0:00.04 best: 0:00.03 rep1
block size 1024 0:00.05 0:00.04 0:00.05 0:00.05 0:00.04 0:00.05 0:00.04 0:00.10 0:00.07 0:00.07 0:00.07 0:00.41 0:00.05 0:00.05 best: 0:00.04 rep1
block size 512 0:00.07 0:00.06 0:00.06 0:00.07 0:00.06 0:00.07 0:00.06 0:00.11 0:00.07 0:00.08 0:00.07 0:00.42 0:00.07 0:00.07 best: 0:00.06 rep1
block size 256 0:00.11 0:00.08 0:00.08 0:00.10 0:00.08 0:00.10 0:00.08 0:00.12 0:00.09 0:00.09 0:00.09 0:00.44 0:00.10 0:00.11 best: 0:00.08 rep1
block size 128 0:00.15 0:00.13 0:00.13 0:00.15 0:00.13 0:00.15 0:00.12 0:00.15 0:00.12 0:00.13 0:00.13 0:00.50 0:00.14 0:00.14 best: 0:00.12 loopnoalign
block size 64 0:00.28 0:00.21 0:00.22 0:00.25 0:00.23 0:00.23 0:00.22 0:00.20 0:00.20 0:00.20 0:00.21 0:00.50 0:00.20 0:00.20 best: 0:00.20 loop
block size 48 0:00.31 0:00.27 0:00.27 0:00.30 0:00.30 0:00.29 0:00.28 0:00.24 0:00.23 0:00.24 0:00.25 0:00.59 0:00.24 0:00.24 best: 0:00.23 loopnoalign
block size 32 0:00.47 0:00.36 0:00.36 0:00.40 0:00.37 0:00.40 0:00.37 0:00.30 0:00.31 0:00.31 0:00.30 0:00.58 0:00.31 0:00.31 best: 0:00.30 loop
block size 24 0:00.62 0:00.55 0:00.55 0:00.59 0:00.56 0:00.55 0:00.52 0:00.35 0:00.35 0:00.35 0:00.36 0:00.66 0:00.35 0:00.34 best: 0:00.35 loop
block size 16 0:00.92 0:00.78 0:00.72 0:00.76 0:00.70 0:00.71 0:00.63 0:00.40 0:00.40 0:00.33 0:00.34 0:00.67 0:00.39 0:00.40 best: 0:00.33 unrl
block size 14 0:00.98 0:00.94 0:00.95 0:00.95 0:00.91 0:00.90 0:00.85 0:00.43 0:00.43 0:00.39 0:00.39 0:00.68 0:00.43 0:00.43 best: 0:00.39 unrl
block size 12 0:01.16 0:01.11 0:01.10 0:01.09 0:01.03 0:01.01 0:00.87 0:00.43 0:00.46 0:00.44 0:00.43 0:00.72 0:00.46 0:00.45 best: 0:00.43 loop
block size 10 0:01.39 0:01.33 0:01.33 0:01.29 0:01.21 0:01.17 0:00.99 0:00.49 0:00.51 0:00.50 0:00.55 0:00.84 0:00.58 0:00.57 best: 0:00.49 loop
block size 8 0:01.87 0:01.51 0:01.47 0:01.43 0:01.26 0:01.27 0:00.96 0:00.57 0:00.56 0:00.52 0:00.51 0:00.83 0:00.56 0:00.55 best: 0:00.51 unrlnoalign
block size 6 0:02.17 0:02.26 0:02.29 0:01.99 0:01.80 0:01.56 0:01.27 0:00.70 0:00.70 0:00.74 0:00.72 0:00.92 0:00.74 0:00.71 best: 0:00.70 loop
block size 4 0:03.16 0:03.16 0:03.11 0:02.47 0:02.04 0:01.02 0:00.95 0:00.92 0:00.93 0:00.91 0:00.93 0:01.09 0:00.93 0:01.08 best: 0:00.91 unrl
block size 1 0:04.64 0:17.11 0:18.85 0:01.78 0:01.79 0:01.77 0:01.76 0:01.74 0:01.79 0:01.70 0:01.68 0:02.05 0:01.27 0:02.27 best: 0:01.68 unrlnoalign
For non-x86 I modified the above script (at attached) to run the memX and compare to it with {-fno-builtin-X}
root@ozrom2:~# sh test_stringop 64 640000000 gcc -mcpu=power9 | tee out.txt
root@ozrom2:~# gcc --version
gcc (Ubuntu 7.4.0-1ubuntu1~18.04.1) 7.4.0
memcpy mode:64 size:640000000
libcall nobuiltin byte profiled
block size 8192000 0:00.04 0:00.04 0:00.04 best: 0:00.04 libcall
block size 819200 0:00.04 0:00.03 0:00.04 best: 0:00.03 nobuiltin
block size 81920 0:00.03 0:00.03 0:00.03 best: 0:00.03 libcall
block size 20480 0:00.03 0:00.03 0:00.04 best: 0:00.03 libcall
block size 8192 0:00.03 0:00.04 0:00.04 best: 0:00.03 libcall
block size 4096 0:00.04 0:00.04 0:00.04 best: 0:00.04 libcall
block size 2048 0:00.05 0:00.05 0:00.05 best: 0:00.05 libcall
block size 1024 0:00.07 0:00.07 0:00.06 best: 0:00.07 libcall
block size 512 0:00.09 0:00.09 0:00.10 best: 0:00.09 libcall
block size 256 0:00.12 0:00.12 0:00.11 best: 0:00.12 libcall
block size 128 0:00.19 0:00.20 0:00.19 best: 0:00.19 libcall
block size 64 0:00.32 0:00.32 0:00.31 best: 0:00.32 libcall
block size 48 0:00.45 0:00.44 0:00.46 best: 0:00.44 nobuiltin
block size 32 0:00.58 0:00.59 0:00.58 best: 0:00.58 libcall
block size 24 0:00.82 0:00.83 0:00.81 best: 0:00.82 libcall
block size 16 0:01.09 0:01.10 0:01.05 best: 0:01.09 libcall
block size 14 0:01.36 0:01.36 0:01.32 best: 0:01.36 libcall
block size 12 0:01.58 0:01.57 0:01.56 best: 0:01.57 nobuiltin
block size 10 0:01.88 0:01.88 0:01.84 best: 0:01.88 libcall
block size 8 0:02.14 0:02.14 0:02.03 best: 0:02.14 libcall
block size 6 0:03.24 0:03.24 0:03.01 best: 0:03.24 libcall
block size 4 0:04.27 0:04.26 0:03.90 best: 0:04.26 nobuiltin
block size 1 0:18.42 0:18.45 0:15.29 best: 0:18.42 libcall
memset
libcall nobuiltin byte profiled
block size 8192000 0:00.04 0:00.04 0:00.04 best: 0:00.04 libcall
block size 819200 0:00.04 0:00.03 0:00.04 best: 0:00.03 nobuiltin
block size 81920 0:00.04 0:00.03 0:00.03 best: 0:00.03 nobuiltin
block size 20480 0:00.04 0:00.04 0:00.03 best: 0:00.04 libcall
block size 8192 0:00.03 0:00.04 0:00.03 best: 0:00.03 libcall
block size 4096 0:00.04 0:00.04 0:00.04 best: 0:00.04 libcall
block size 2048 0:00.05 0:00.05 0:00.05 best: 0:00.05 libcall
block size 1024 0:00.07 0:00.07 0:00.06 best: 0:00.07 libcall
block size 512 0:00.09 0:00.09 0:00.10 best: 0:00.09 libcall
block size 256 0:00.13 0:00.12 0:00.11 best: 0:00.12 nobuiltin
block size 128 0:00.19 0:00.18 0:00.19 best: 0:00.18 nobuiltin
block size 64 0:00.31 0:00.32 0:00.31 best: 0:00.31 libcall
block size 48 0:00.44 0:00.45 0:00.45 best: 0:00.44 libcall
block size 32 0:00.58 0:00.58 0:00.58 best: 0:00.58 libcall
block size 24 0:00.82 0:00.82 0:00.81 best: 0:00.82 libcall
block size 16 0:01.09 0:01.09 0:01.05 best: 0:01.09 libcall
block size 14 0:01.36 0:01.36 0:01.32 best: 0:01.36 libcall
block size 12 0:01.57 0:01.58 0:01.55 best: 0:01.57 libcall
block size 10 0:01.90 0:01.90 0:01.83 best: 0:01.90 libcall
block size 8 0:02.14 0:02.15 0:02.05 best: 0:02.14 libcall
block size 6 0:03.20 0:03.20 0:03.03 best: 0:03.20 libcall
block size 4 0:04.26 0:04.27 0:03.91 best: 0:04.26 libcall
block size 1 0:18.43 0:18.44 0:15.30 best: 0:18.43 libcall
So its pretty much better or identical to use memset/cmp in all cases the ones showing up as nobuiltin are pretty much in the noise of measurement.
> then we might add
> further MY_ASSUME_ALIGNED() assertions here and there, to allow gcc
> and clang to generate better code for POWER and ARM.
>
> If the compiler is smart enough, it might suffice to implement an
> accessor for buf_block_t or buf_block_t::frame that would
> MY_ASSUME_ALIGNED(frame, 4096). Then the compiler might correctly
> infer the alignment of (block->frame + some_compile_time_constant) and
> enable the optimization. I would be unwilling to pepper such hints all
> over the code.
>
> Marko
Attachment:
test_stringop
Description: Binary data
Follow ups
References