On Tue, 26 Nov 2019 10:56:41 +0200 Marko Mäkelä <marko.mak...@mariadb.com> wrote:
> Hi Daniel, > > On Tue, Nov 26, 2019 at 2:02 AM Daniel Black <dan...@linux.ibm.com> wrote: > > > > On Mon, 25 Nov 2019 11:32:07 +0200 > > Marko Mäkelä <marko.mak...@mariadb.com> 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
test_stringop
Description: Binary data
_______________________________________________ Mailing list: https://launchpad.net/~maria-discuss Post to : maria-discuss@lists.launchpad.net Unsubscribe : https://launchpad.net/~maria-discuss More help : https://help.launchpad.net/ListHelp