diff options
Diffstat (limited to 'src/xine-utils')
-rw-r--r-- | src/xine-utils/Makefile.am | 82 | ||||
-rw-r--r-- | src/xine-utils/attributes.h | 27 | ||||
-rw-r--r-- | src/xine-utils/cpu_accel.c | 124 | ||||
-rw-r--r-- | src/xine-utils/cpu_accel.h | 531 | ||||
-rw-r--r-- | src/xine-utils/memcpy.c | 439 | ||||
-rw-r--r-- | src/xine-utils/memcpy.h | 33 | ||||
-rw-r--r-- | src/xine-utils/monitor.c | 138 | ||||
-rw-r--r-- | src/xine-utils/monitor.h | 114 | ||||
-rw-r--r-- | src/xine-utils/utils.c | 146 | ||||
-rw-r--r-- | src/xine-utils/utils.h | 52 |
10 files changed, 1686 insertions, 0 deletions
diff --git a/src/xine-utils/Makefile.am b/src/xine-utils/Makefile.am new file mode 100644 index 000000000..29ef6eef0 --- /dev/null +++ b/src/xine-utils/Makefile.am @@ -0,0 +1,82 @@ +## +## Process this file with automake to produce Makefile.in +## + +CFLAGS = @GLOBAL_CFLAGS@ @THREAD_CFLAGS@ + + +EXTRA_DIST = cpu_accel.c + +lib_LTLIBRARIES = libxineutils.la + +libxineutils_la_SOURCES = utils.c memcpy.c monitor.c +libxineutils_la_LIBADD = cpu_accel.lo \ + $(THREAD_LIBS) \ + $(DYNAMIC_LD_LIBS) \ + -lm + +libxineutils_la_LDFLAGS = \ + -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) \ + -release $(LT_RELEASE) + +include_HEADERS = attributes.h cpu_accel.h memcpy.h utils.h monitor.h + +### +# Hardcoded rule: +# gcc failed to compile this with -fPIC flag +# hackish: [X] yes [ ] no +# +LIBTOOLNOFPIC = $(SHELL) $(top_builddir)/libtool-nofpic +LTCOMPILENOFPIC = $(LIBTOOLNOFPIC) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +cpu_accel.lo: cpu_accel.c + @mkdir -p .deps; touch .deps/cpu_accel.pp; \ + echo '$(LTCOMPILENOFPIC) -c $<'; \ + $(LTCOMPILENOFPIC) -Wp,-MD,.deps/$(*F).pp -c $< + @-sed -e 's/^\([^:]*\)\.o[ ]*:/\1.lo \1.o :/' \ + < .deps/$(*F).pp > .deps/$(*F).P; \ + tr ' ' '\012' < .deps/$(*F).pp \ + | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \ + >> .deps/$(*F).P; \ + rm -f .deps/$(*F).pp + + +debug: + @$(MAKE) CFLAGS="$(DEBUG_CFLAGS)" + +install-debug: debug + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + + + +### +# Install header files (default=$includedir/xine) +# +install-includeHEADERS: $(include_HEADERS) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(includedir)/xine + @list='$(include_HEADERS)'; for p in $$list; do \ + if test -f "$$p"; then d= ; else d="$(srcdir)/"; fi; \ + echo " $(INSTALL_DATA) $$d$$p $(DESTDIR)$(includedir)/xine/$$p"; \ + $(INSTALL_DATA) $$d$$p $(DESTDIR)$(includedir)/xine/$$p; \ + done + + +### +# Remove them +# +uninstall-includeHEADERS: + @$(NORMAL_UNINSTALL) + list='$(include_HEADERS)'; for p in $$list; do \ + rm -f $(DESTDIR)$(includedir)/xine/$$p; \ + done + + +mostlyclean-generic: + -rm -f *~ \#* .*~ .\#* + + +maintainer-clean-generic: + -@echo "This command is intended for maintainers to use;" + -@echo "it deletes files that may require special tools to rebuild." + -rm -f Makefile.in + diff --git a/src/xine-utils/attributes.h b/src/xine-utils/attributes.h new file mode 100644 index 000000000..8ed7aef9e --- /dev/null +++ b/src/xine-utils/attributes.h @@ -0,0 +1,27 @@ +/* + * attributes.h + * Copyright (C) 1999-2000 Aaron Holtzman <aholtzma@ess.engr.uvic.ca> + * + * This file is part of mpeg2dec, a free MPEG-2 video stream decoder. + * + * mpeg2dec is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * mpeg2dec is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +//use gcc attribs to align critical data structures +#ifdef ATTRIBUTE_ALIGNED_MAX +#define ATTR_ALIGN(align) __attribute__ ((__aligned__ ((ATTRIBUTE_ALIGNED_MAX < align) ? ATTRIBUTE_ALIGNED_MAX : align))) +#else +#define ATTR_ALIGN(align) +#endif diff --git a/src/xine-utils/cpu_accel.c b/src/xine-utils/cpu_accel.c new file mode 100644 index 000000000..8c28d950a --- /dev/null +++ b/src/xine-utils/cpu_accel.c @@ -0,0 +1,124 @@ +/* + * cpu_accel.c + * Copyright (C) 1999-2001 Aaron Holtzman <aholtzma@ess.engr.uvic.ca> + * + * This file is part of mpeg2dec, a free MPEG-2 video stream decoder. + * + * mpeg2dec is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * mpeg2dec is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "config.h" + +#include <inttypes.h> + +#include "attributes.h" +#include "cpu_accel.h" + +#ifdef ARCH_X86 +static uint32_t x86_accel (void) +{ + uint32_t eax, ebx, ecx, edx; + int AMD; + uint32_t caps; + +#define cpuid(op,eax,ebx,ecx,edx) \ + asm ("cpuid" \ + : "=a" (eax), \ + "=b" (ebx), \ + "=c" (ecx), \ + "=d" (edx) \ + : "a" (op) \ + : "cc") + + + asm ("pushfl\n\t" + "pushfl\n\t" + "popl %0\n\t" + "movl %0,%1\n\t" + "xorl $0x200000,%0\n\t" + "pushl %0\n\t" + "popfl\n\t" + "pushfl\n\t" + "popl %0\n\t" + "popfl" + : "=a" (eax), + "=b" (ebx) + : + : "cc"); + + if (eax == ebx) /* no cpuid */ + return 0; + + cpuid (0x00000000, eax, ebx, ecx, edx); + if (!eax) /* vendor string only */ + return 0; + + AMD = (ebx == 0x68747541) && (ecx == 0x444d4163) && (edx == 0x69746e65); + + cpuid (0x00000001, eax, ebx, ecx, edx); + if (! (edx & 0x00800000)) /* no MMX */ + return 0; + caps = MM_ACCEL_X86_MMX; + + if (edx & 0x02000000) /* SSE - identical to AMD MMX extensions */ + caps |= MM_ACCEL_X86_SSE | MM_ACCEL_X86_MMXEXT; + + if (edx & 0x04000000) /* SSE2 */ + caps |= MM_ACCEL_X86_SSE2; + + cpuid (0x80000000, eax, ebx, ecx, edx); + if (eax < 0x80000001) /* no extended capabilities */ + return caps; + + cpuid (0x80000001, eax, ebx, ecx, edx); + + if (edx & 0x80000000) /* 3DNOW */ + caps |= MM_ACCEL_X86_3DNOW; + + if (edx & 0x40000000) /* 3DNOWEXT */ + /*caps |= MM_ACCEL_X86_???*/ ; + + if (AMD && (edx & 0x00400000)) /* AMD MMX extensions */ + caps |= MM_ACCEL_X86_MMXEXT; + + return caps; +} +#endif + +uint32_t mm_accel (void) +{ +#ifdef ARCH_X86 + static int got_accel = 0; + static uint32_t accel; + + if (!got_accel) { + got_accel = 1; + accel = x86_accel (); + } + + return accel; +#else +#ifdef HAVE_MLIB + return MM_ACCEL_MLIB; +#else + return 0; +#endif +#endif +} + +uint32_t mm_support (void) +{ + return mm_accel(); +} diff --git a/src/xine-utils/cpu_accel.h b/src/xine-utils/cpu_accel.h new file mode 100644 index 000000000..053c142f6 --- /dev/null +++ b/src/xine-utils/cpu_accel.h @@ -0,0 +1,531 @@ +/* + * cpu_accel.h - based on mmx.h, sse.h + * Copyright (C) 1997-1999 H. Dietz and R. Fisher + * + * This file is part of mpeg2dec, a free MPEG-2 video stream decoder. + * + * mpeg2dec is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * mpeg2dec is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * xine specific modifications 2001 by G. Bartsch + * + */ + +/* + * The type of an value that fits in an MMX register (note that long + * long constant values MUST be suffixed by LL and unsigned long long + * values by ULL, lest they be truncated by the compiler) + */ + +#ifndef _CPU_ACCEL_H +#define _CPU_ACCEL_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "attributes.h" + +/* generic accelerations */ +#define MM_ACCEL_MLIB 0x00000001 + +/* x86 accelerations */ +#define MM_ACCEL_X86_MMX 0x80000000 +#define MM_ACCEL_X86_3DNOW 0x40000000 +#define MM_ACCEL_X86_MMXEXT 0x20000000 +#define MM_ACCEL_X86_SSE 0x10000000 +#define MM_ACCEL_X86_SSE2 0x08000000 +/* x86 compat defines */ +#define MM_MMX MM_ACCEL_X86_MMX +#define MM_3DNOW MM_ACCEL_X86_3DNOW +#define MM_MMXEXT MM_ACCEL_X86_MMXEXT +#define MM_SSE MM_ACCEL_X86_SSE +#define MM_SSE2 MM_ACCEL_X86_SSE2 + +uint32_t mm_accel (void) ; +/* uint32_t mm_support (void) ; */ + +#ifdef ARCH_X86 + +typedef union { + long long q; /* Quadword (64-bit) value */ + unsigned long long uq; /* Unsigned Quadword */ + int d[2]; /* 2 Doubleword (32-bit) values */ + unsigned int ud[2]; /* 2 Unsigned Doubleword */ + short w[4]; /* 4 Word (16-bit) values */ + unsigned short uw[4]; /* 4 Unsigned Word */ + char b[8]; /* 8 Byte (8-bit) values */ + unsigned char ub[8]; /* 8 Unsigned Byte */ + float s[2]; /* Single-precision (32-bit) value */ +} ATTR_ALIGN(8) mmx_t; /* On an 8-byte (64-bit) boundary */ + + + +#define mmx_i2r(op,imm,reg) \ + __asm__ __volatile__ (#op " %0, %%" #reg \ + : /* nothing */ \ + : "X" (imm) ) + +#define mmx_m2r(op,mem,reg) \ + __asm__ __volatile__ (#op " %0, %%" #reg \ + : /* nothing */ \ + : "X" (mem)) + +#define mmx_r2m(op,reg,mem) \ + __asm__ __volatile__ (#op " %%" #reg ", %0" \ + : "=X" (mem) \ + : /* nothing */ ) + +#define mmx_r2r(op,regs,regd) \ + __asm__ __volatile__ (#op " %" #regs ", %" #regd) + + +#define emms() __asm__ __volatile__ ("emms") + +#define movd_m2r(var,reg) mmx_m2r (movd, var, reg) +#define movd_r2m(reg,var) mmx_r2m (movd, reg, var) +#define movd_r2r(regs,regd) mmx_r2r (movd, regs, regd) + +#define movq_m2r(var,reg) mmx_m2r (movq, var, reg) +#define movq_r2m(reg,var) mmx_r2m (movq, reg, var) +#define movq_r2r(regs,regd) mmx_r2r (movq, regs, regd) + +#define packssdw_m2r(var,reg) mmx_m2r (packssdw, var, reg) +#define packssdw_r2r(regs,regd) mmx_r2r (packssdw, regs, regd) +#define packsswb_m2r(var,reg) mmx_m2r (packsswb, var, reg) +#define packsswb_r2r(regs,regd) mmx_r2r (packsswb, regs, regd) + +#define packuswb_m2r(var,reg) mmx_m2r (packuswb, var, reg) +#define packuswb_r2r(regs,regd) mmx_r2r (packuswb, regs, regd) + +#define paddb_m2r(var,reg) mmx_m2r (paddb, var, reg) +#define paddb_r2r(regs,regd) mmx_r2r (paddb, regs, regd) +#define paddd_m2r(var,reg) mmx_m2r (paddd, var, reg) +#define paddd_r2r(regs,regd) mmx_r2r (paddd, regs, regd) +#define paddw_m2r(var,reg) mmx_m2r (paddw, var, reg) +#define paddw_r2r(regs,regd) mmx_r2r (paddw, regs, regd) + +#define paddsb_m2r(var,reg) mmx_m2r (paddsb, var, reg) +#define paddsb_r2r(regs,regd) mmx_r2r (paddsb, regs, regd) +#define paddsw_m2r(var,reg) mmx_m2r (paddsw, var, reg) +#define paddsw_r2r(regs,regd) mmx_r2r (paddsw, regs, regd) + +#define paddusb_m2r(var,reg) mmx_m2r (paddusb, var, reg) +#define paddusb_r2r(regs,regd) mmx_r2r (paddusb, regs, regd) +#define paddusw_m2r(var,reg) mmx_m2r (paddusw, var, reg) +#define paddusw_r2r(regs,regd) mmx_r2r (paddusw, regs, regd) + +#define pand_m2r(var,reg) mmx_m2r (pand, var, reg) +#define pand_r2r(regs,regd) mmx_r2r (pand, regs, regd) + +#define pandn_m2r(var,reg) mmx_m2r (pandn, var, reg) +#define pandn_r2r(regs,regd) mmx_r2r (pandn, regs, regd) + +#define pcmpeqb_m2r(var,reg) mmx_m2r (pcmpeqb, var, reg) +#define pcmpeqb_r2r(regs,regd) mmx_r2r (pcmpeqb, regs, regd) +#define pcmpeqd_m2r(var,reg) mmx_m2r (pcmpeqd, var, reg) +#define pcmpeqd_r2r(regs,regd) mmx_r2r (pcmpeqd, regs, regd) +#define pcmpeqw_m2r(var,reg) mmx_m2r (pcmpeqw, var, reg) +#define pcmpeqw_r2r(regs,regd) mmx_r2r (pcmpeqw, regs, regd) + +#define pcmpgtb_m2r(var,reg) mmx_m2r (pcmpgtb, var, reg) +#define pcmpgtb_r2r(regs,regd) mmx_r2r (pcmpgtb, regs, regd) +#define pcmpgtd_m2r(var,reg) mmx_m2r (pcmpgtd, var, reg) +#define pcmpgtd_r2r(regs,regd) mmx_r2r (pcmpgtd, regs, regd) +#define pcmpgtw_m2r(var,reg) mmx_m2r (pcmpgtw, var, reg) +#define pcmpgtw_r2r(regs,regd) mmx_r2r (pcmpgtw, regs, regd) + +#define pmaddwd_m2r(var,reg) mmx_m2r (pmaddwd, var, reg) +#define pmaddwd_r2r(regs,regd) mmx_r2r (pmaddwd, regs, regd) + +#define pmulhw_m2r(var,reg) mmx_m2r (pmulhw, var, reg) +#define pmulhw_r2r(regs,regd) mmx_r2r (pmulhw, regs, regd) + +#define pmullw_m2r(var,reg) mmx_m2r (pmullw, var, reg) +#define pmullw_r2r(regs,regd) mmx_r2r (pmullw, regs, regd) + +#define por_m2r(var,reg) mmx_m2r (por, var, reg) +#define por_r2r(regs,regd) mmx_r2r (por, regs, regd) + +#define pslld_i2r(imm,reg) mmx_i2r (pslld, imm, reg) +#define pslld_m2r(var,reg) mmx_m2r (pslld, var, reg) +#define pslld_r2r(regs,regd) mmx_r2r (pslld, regs, regd) +#define psllq_i2r(imm,reg) mmx_i2r (psllq, imm, reg) +#define psllq_m2r(var,reg) mmx_m2r (psllq, var, reg) +#define psllq_r2r(regs,regd) mmx_r2r (psllq, regs, regd) +#define psllw_i2r(imm,reg) mmx_i2r (psllw, imm, reg) +#define psllw_m2r(var,reg) mmx_m2r (psllw, var, reg) +#define psllw_r2r(regs,regd) mmx_r2r (psllw, regs, regd) + +#define psrad_i2r(imm,reg) mmx_i2r (psrad, imm, reg) +#define psrad_m2r(var,reg) mmx_m2r (psrad, var, reg) +#define psrad_r2r(regs,regd) mmx_r2r (psrad, regs, regd) +#define psraw_i2r(imm,reg) mmx_i2r (psraw, imm, reg) +#define psraw_m2r(var,reg) mmx_m2r (psraw, var, reg) +#define psraw_r2r(regs,regd) mmx_r2r (psraw, regs, regd) + +#define psrld_i2r(imm,reg) mmx_i2r (psrld, imm, reg) +#define psrld_m2r(var,reg) mmx_m2r (psrld, var, reg) +#define psrld_r2r(regs,regd) mmx_r2r (psrld, regs, regd) +#define psrlq_i2r(imm,reg) mmx_i2r (psrlq, imm, reg) +#define psrlq_m2r(var,reg) mmx_m2r (psrlq, var, reg) +#define psrlq_r2r(regs,regd) mmx_r2r (psrlq, regs, regd) +#define psrlw_i2r(imm,reg) mmx_i2r (psrlw, imm, reg) +#define psrlw_m2r(var,reg) mmx_m2r (psrlw, var, reg) +#define psrlw_r2r(regs,regd) mmx_r2r (psrlw, regs, regd) + +#define psubb_m2r(var,reg) mmx_m2r (psubb, var, reg) +#define psubb_r2r(regs,regd) mmx_r2r (psubb, regs, regd) +#define psubd_m2r(var,reg) mmx_m2r (psubd, var, reg) +#define psubd_r2r(regs,regd) mmx_r2r (psubd, regs, regd) +#define psubw_m2r(var,reg) mmx_m2r (psubw, var, reg) +#define psubw_r2r(regs,regd) mmx_r2r (psubw, regs, regd) + +#define psubsb_m2r(var,reg) mmx_m2r (psubsb, var, reg) +#define psubsb_r2r(regs,regd) mmx_r2r (psubsb, regs, regd) +#define psubsw_m2r(var,reg) mmx_m2r (psubsw, var, reg) +#define psubsw_r2r(regs,regd) mmx_r2r (psubsw, regs, regd) + +#define psubusb_m2r(var,reg) mmx_m2r (psubusb, var, reg) +#define psubusb_r2r(regs,regd) mmx_r2r (psubusb, regs, regd) +#define psubusw_m2r(var,reg) mmx_m2r (psubusw, var, reg) +#define psubusw_r2r(regs,regd) mmx_r2r (psubusw, regs, regd) + +#define punpckhbw_m2r(var,reg) mmx_m2r (punpckhbw, var, reg) +#define punpckhbw_r2r(regs,regd) mmx_r2r (punpckhbw, regs, regd) +#define punpckhdq_m2r(var,reg) mmx_m2r (punpckhdq, var, reg) +#define punpckhdq_r2r(regs,regd) mmx_r2r (punpckhdq, regs, regd) +#define punpckhwd_m2r(var,reg) mmx_m2r (punpckhwd, var, reg) +#define punpckhwd_r2r(regs,regd) mmx_r2r (punpckhwd, regs, regd) + +#define punpcklbw_m2r(var,reg) mmx_m2r (punpcklbw, var, reg) +#define punpcklbw_r2r(regs,regd) mmx_r2r (punpcklbw, regs, regd) +#define punpckldq_m2r(var,reg) mmx_m2r (punpckldq, var, reg) +#define punpckldq_r2r(regs,regd) mmx_r2r (punpckldq, regs, regd) +#define punpcklwd_m2r(var,reg) mmx_m2r (punpcklwd, var, reg) +#define punpcklwd_r2r(regs,regd) mmx_r2r (punpcklwd, regs, regd) + +#define pxor_m2r(var,reg) mmx_m2r (pxor, var, reg) +#define pxor_r2r(regs,regd) mmx_r2r (pxor, regs, regd) + + +/* 3DNOW extensions */ + +#define pavgusb_m2r(var,reg) mmx_m2r (pavgusb, var, reg) +#define pavgusb_r2r(regs,regd) mmx_r2r (pavgusb, regs, regd) + + +/* AMD MMX extensions - also available in intel SSE */ + + +#define mmx_m2ri(op,mem,reg,imm) \ + __asm__ __volatile__ (#op " %1, %0, %%" #reg \ + : /* nothing */ \ + : "X" (mem), "X" (imm)) +#define mmx_r2ri(op,regs,regd,imm) \ + __asm__ __volatile__ (#op " %0, %%" #regs ", %%" #regd \ + : /* nothing */ \ + : "X" (imm) ) + +#define mmx_fetch(mem,hint) \ + __asm__ __volatile__ ("prefetch" #hint " %0" \ + : /* nothing */ \ + : "X" (mem)) + + +#define maskmovq(regs,maskreg) mmx_r2ri (maskmovq, regs, maskreg) + +#define movntq_r2m(mmreg,var) mmx_r2m (movntq, mmreg, var) + +#define pavgb_m2r(var,reg) mmx_m2r (pavgb, var, reg) +#define pavgb_r2r(regs,regd) mmx_r2r (pavgb, regs, regd) +#define pavgw_m2r(var,reg) mmx_m2r (pavgw, var, reg) +#define pavgw_r2r(regs,regd) mmx_r2r (pavgw, regs, regd) + +#define pextrw_r2r(mmreg,reg,imm) mmx_r2ri (pextrw, mmreg, reg, imm) + +#define pinsrw_r2r(reg,mmreg,imm) mmx_r2ri (pinsrw, reg, mmreg, imm) + +#define pmaxsw_m2r(var,reg) mmx_m2r (pmaxsw, var, reg) +#define pmaxsw_r2r(regs,regd) mmx_r2r (pmaxsw, regs, regd) + +#define pmaxub_m2r(var,reg) mmx_m2r (pmaxub, var, reg) +#define pmaxub_r2r(regs,regd) mmx_r2r (pmaxub, regs, regd) + +#define pminsw_m2r(var,reg) mmx_m2r (pminsw, var, reg) +#define pminsw_r2r(regs,regd) mmx_r2r (pminsw, regs, regd) + +#define pminub_m2r(var,reg) mmx_m2r (pminub, var, reg) +#define pminub_r2r(regs,regd) mmx_r2r (pminub, regs, regd) + +#define pmovmskb(mmreg,reg) \ + __asm__ __volatile__ ("movmskps %" #mmreg ", %" #reg) + +#define pmulhuw_m2r(var,reg) mmx_m2r (pmulhuw, var, reg) +#define pmulhuw_r2r(regs,regd) mmx_r2r (pmulhuw, regs, regd) + +#define prefetcht0(mem) mmx_fetch (mem, t0) +#define prefetcht1(mem) mmx_fetch (mem, t1) +#define prefetcht2(mem) mmx_fetch (mem, t2) +#define prefetchnta(mem) mmx_fetch (mem, nta) + +#define psadbw_m2r(var,reg) mmx_m2r (psadbw, var, reg) +#define psadbw_r2r(regs,regd) mmx_r2r (psadbw, regs, regd) + +#define pshufw_m2r(var,reg,imm) mmx_m2ri(pshufw, var, reg, imm) +#define pshufw_r2r(regs,regd,imm) mmx_r2ri(pshufw, regs, regd, imm) + +#define sfence() __asm__ __volatile__ ("sfence\n\t") + +typedef union { + float sf[4]; /* Single-precision (32-bit) value */ +} ATTR_ALIGN(16) sse_t; /* On a 16 byte (128-bit) boundary */ + + +#define sse_i2r(op, imm, reg) \ + __asm__ __volatile__ (#op " %0, %%" #reg \ + : /* nothing */ \ + : "X" (imm) ) + +#define sse_m2r(op, mem, reg) \ + __asm__ __volatile__ (#op " %0, %%" #reg \ + : /* nothing */ \ + : "X" (mem)) + +#define sse_r2m(op, reg, mem) \ + __asm__ __volatile__ (#op " %%" #reg ", %0" \ + : "=X" (mem) \ + : /* nothing */ ) + +#define sse_r2r(op, regs, regd) \ + __asm__ __volatile__ (#op " %" #regs ", %" #regd) + +#define sse_r2ri(op, regs, regd, imm) \ + __asm__ __volatile__ (#op " %0, %%" #regs ", %%" #regd \ + : /* nothing */ \ + : "X" (imm) ) + +#define sse_m2ri(op, mem, reg, subop) \ + __asm__ __volatile__ (#op " %0, %%" #reg ", " #subop \ + : /* nothing */ \ + : "X" (mem)) + + +#define movaps_m2r(var, reg) sse_m2r(movaps, var, reg) +#define movaps_r2m(reg, var) sse_r2m(movaps, reg, var) +#define movaps_r2r(regs, regd) sse_r2r(movaps, regs, regd) + +#define movntps_r2m(xmmreg, var) sse_r2m(movntps, xmmreg, var) + +#define movups_m2r(var, reg) sse_m2r(movups, var, reg) +#define movups_r2m(reg, var) sse_r2m(movups, reg, var) +#define movups_r2r(regs, regd) sse_r2r(movups, regs, regd) + +#define movhlps_r2r(regs, regd) sse_r2r(movhlps, regs, regd) + +#define movlhps_r2r(regs, regd) sse_r2r(movlhps, regs, regd) + +#define movhps_m2r(var, reg) sse_m2r(movhps, var, reg) +#define movhps_r2m(reg, var) sse_r2m(movhps, reg, var) + +#define movlps_m2r(var, reg) sse_m2r(movlps, var, reg) +#define movlps_r2m(reg, var) sse_r2m(movlps, reg, var) + +#define movss_m2r(var, reg) sse_m2r(movss, var, reg) +#define movss_r2m(reg, var) sse_r2m(movss, reg, var) +#define movss_r2r(regs, regd) sse_r2r(movss, regs, regd) + +#define shufps_m2r(var, reg, index) sse_m2ri(shufps, var, reg, index) +#define shufps_r2r(regs, regd, index) sse_r2ri(shufps, regs, regd, index) + +#define cvtpi2ps_m2r(var, xmmreg) sse_m2r(cvtpi2ps, var, xmmreg) +#define cvtpi2ps_r2r(mmreg, xmmreg) sse_r2r(cvtpi2ps, mmreg, xmmreg) + +#define cvtps2pi_m2r(var, mmreg) sse_m2r(cvtps2pi, var, mmreg) +#define cvtps2pi_r2r(xmmreg, mmreg) sse_r2r(cvtps2pi, mmreg, xmmreg) + +#define cvttps2pi_m2r(var, mmreg) sse_m2r(cvttps2pi, var, mmreg) +#define cvttps2pi_r2r(xmmreg, mmreg) sse_r2r(cvttps2pi, mmreg, xmmreg) + +#define cvtsi2ss_m2r(var, xmmreg) sse_m2r(cvtsi2ss, var, xmmreg) +#define cvtsi2ss_r2r(reg, xmmreg) sse_r2r(cvtsi2ss, reg, xmmreg) + +#define cvtss2si_m2r(var, reg) sse_m2r(cvtss2si, var, reg) +#define cvtss2si_r2r(xmmreg, reg) sse_r2r(cvtss2si, xmmreg, reg) + +#define cvttss2si_m2r(var, reg) sse_m2r(cvtss2si, var, reg) +#define cvttss2si_r2r(xmmreg, reg) sse_r2r(cvtss2si, xmmreg, reg) + +#define movmskps(xmmreg, reg) \ + __asm__ __volatile__ ("movmskps %" #xmmreg ", %" #reg) + +#define addps_m2r(var, reg) sse_m2r(addps, var, reg) +#define addps_r2r(regs, regd) sse_r2r(addps, regs, regd) + +#define addss_m2r(var, reg) sse_m2r(addss, var, reg) +#define addss_r2r(regs, regd) sse_r2r(addss, regs, regd) + +#define subps_m2r(var, reg) sse_m2r(subps, var, reg) +#define subps_r2r(regs, regd) sse_r2r(subps, regs, regd) + +#define subss_m2r(var, reg) sse_m2r(subss, var, reg) +#define subss_r2r(regs, regd) sse_r2r(subss, regs, regd) + +#define mulps_m2r(var, reg) sse_m2r(mulps, var, reg) +#define mulps_r2r(regs, regd) sse_r2r(mulps, regs, regd) + +#define mulss_m2r(var, reg) sse_m2r(mulss, var, reg) +#define mulss_r2r(regs, regd) sse_r2r(mulss, regs, regd) + +#define divps_m2r(var, reg) sse_m2r(divps, var, reg) +#define divps_r2r(regs, regd) sse_r2r(divps, regs, regd) + +#define divss_m2r(var, reg) sse_m2r(divss, var, reg) +#define divss_r2r(regs, regd) sse_r2r(divss, regs, regd) + +#define rcpps_m2r(var, reg) sse_m2r(rcpps, var, reg) +#define rcpps_r2r(regs, regd) sse_r2r(rcpps, regs, regd) + +#define rcpss_m2r(var, reg) sse_m2r(rcpss, var, reg) +#define rcpss_r2r(regs, regd) sse_r2r(rcpss, regs, regd) + +#define rsqrtps_m2r(var, reg) sse_m2r(rsqrtps, var, reg) +#define rsqrtps_r2r(regs, regd) sse_r2r(rsqrtps, regs, regd) + +#define rsqrtss_m2r(var, reg) sse_m2r(rsqrtss, var, reg) +#define rsqrtss_r2r(regs, regd) sse_r2r(rsqrtss, regs, regd) + +#define sqrtps_m2r(var, reg) sse_m2r(sqrtps, var, reg) +#define sqrtps_r2r(regs, regd) sse_r2r(sqrtps, regs, regd) + +#define sqrtss_m2r(var, reg) sse_m2r(sqrtss, var, reg) +#define sqrtss_r2r(regs, regd) sse_r2r(sqrtss, regs, regd) + +#define andps_m2r(var, reg) sse_m2r(andps, var, reg) +#define andps_r2r(regs, regd) sse_r2r(andps, regs, regd) + +#define andnps_m2r(var, reg) sse_m2r(andnps, var, reg) +#define andnps_r2r(regs, regd) sse_r2r(andnps, regs, regd) + +#define orps_m2r(var, reg) sse_m2r(orps, var, reg) +#define orps_r2r(regs, regd) sse_r2r(orps, regs, regd) + +#define xorps_m2r(var, reg) sse_m2r(xorps, var, reg) +#define xorps_r2r(regs, regd) sse_r2r(xorps, regs, regd) + +#define maxps_m2r(var, reg) sse_m2r(maxps, var, reg) +#define maxps_r2r(regs, regd) sse_r2r(maxps, regs, regd) + +#define maxss_m2r(var, reg) sse_m2r(maxss, var, reg) +#define maxss_r2r(regs, regd) sse_r2r(maxss, regs, regd) + +#define minps_m2r(var, reg) sse_m2r(minps, var, reg) +#define minps_r2r(regs, regd) sse_r2r(minps, regs, regd) + +#define minss_m2r(var, reg) sse_m2r(minss, var, reg) +#define minss_r2r(regs, regd) sse_r2r(minss, regs, regd) + +#define cmpps_m2r(var, reg, op) sse_m2ri(cmpps, var, reg, op) +#define cmpps_r2r(regs, regd, op) sse_r2ri(cmpps, regs, regd, op) + +#define cmpeqps_m2r(var, reg) sse_m2ri(cmpps, var, reg, 0) +#define cmpeqps_r2r(regs, regd) sse_r2ri(cmpps, regs, regd, 0) + +#define cmpltps_m2r(var, reg) sse_m2ri(cmpps, var, reg, 1) +#define cmpltps_r2r(regs, regd) sse_r2ri(cmpps, regs, regd, 1) + +#define cmpleps_m2r(var, reg) sse_m2ri(cmpps, var, reg, 2) +#define cmpleps_r2r(regs, regd) sse_r2ri(cmpps, regs, regd, 2) + +#define cmpunordps_m2r(var, reg) sse_m2ri(cmpps, var, reg, 3) +#define cmpunordps_r2r(regs, regd) sse_r2ri(cmpps, regs, regd, 3) + +#define cmpneqps_m2r(var, reg) sse_m2ri(cmpps, var, reg, 4) +#define cmpneqps_r2r(regs, regd) sse_r2ri(cmpps, regs, regd, 4) + +#define cmpnltps_m2r(var, reg) sse_m2ri(cmpps, var, reg, 5) +#define cmpnltps_r2r(regs, regd) sse_r2ri(cmpps, regs, regd, 5) + +#define cmpnleps_m2r(var, reg) sse_m2ri(cmpps, var, reg, 6) +#define cmpnleps_r2r(regs, regd) sse_r2ri(cmpps, regs, regd, 6) + +#define cmpordps_m2r(var, reg) sse_m2ri(cmpps, var, reg, 7) +#define cmpordps_r2r(regs, regd) sse_r2ri(cmpps, regs, regd, 7) + +#define cmpss_m2r(var, reg, op) sse_m2ri(cmpss, var, reg, op) +#define cmpss_r2r(regs, regd, op) sse_r2ri(cmpss, regs, regd, op) + +#define cmpeqss_m2r(var, reg) sse_m2ri(cmpss, var, reg, 0) +#define cmpeqss_r2r(regs, regd) sse_r2ri(cmpss, regs, regd, 0) + +#define cmpltss_m2r(var, reg) sse_m2ri(cmpss, var, reg, 1) +#define cmpltss_r2r(regs, regd) sse_r2ri(cmpss, regs, regd, 1) + +#define cmpless_m2r(var, reg) sse_m2ri(cmpss, var, reg, 2) +#define cmpless_r2r(regs, regd) sse_r2ri(cmpss, regs, regd, 2) + +#define cmpunordss_m2r(var, reg) sse_m2ri(cmpss, var, reg, 3) +#define cmpunordss_r2r(regs, regd) sse_r2ri(cmpss, regs, regd, 3) + +#define cmpneqss_m2r(var, reg) sse_m2ri(cmpss, var, reg, 4) +#define cmpneqss_r2r(regs, regd) sse_r2ri(cmpss, regs, regd, 4) + +#define cmpnltss_m2r(var, reg) sse_m2ri(cmpss, var, reg, 5) +#define cmpnltss_r2r(regs, regd) sse_r2ri(cmpss, regs, regd, 5) + +#define cmpnless_m2r(var, reg) sse_m2ri(cmpss, var, reg, 6) +#define cmpnless_r2r(regs, regd) sse_r2ri(cmpss, regs, regd, 6) + +#define cmpordss_m2r(var, reg) sse_m2ri(cmpss, var, reg, 7) +#define cmpordss_r2r(regs, regd) sse_r2ri(cmpss, regs, regd, 7) + +#define comiss_m2r(var, reg) sse_m2r(comiss, var, reg) +#define comiss_r2r(regs, regd) sse_r2r(comiss, regs, regd) + +#define ucomiss_m2r(var, reg) sse_m2r(ucomiss, var, reg) +#define ucomiss_r2r(regs, regd) sse_r2r(ucomiss, regs, regd) + +#define unpcklps_m2r(var, reg) sse_m2r(unpcklps, var, reg) +#define unpcklps_r2r(regs, regd) sse_r2r(unpcklps, regs, regd) + +#define unpckhps_m2r(var, reg) sse_m2r(unpckhps, var, reg) +#define unpckhps_r2r(regs, regd) sse_r2r(unpckhps, regs, regd) + +#define fxrstor(mem) \ + __asm__ __volatile__ ("fxrstor %0" \ + : /* nothing */ \ + : "X" (mem)) + +#define fxsave(mem) \ + __asm__ __volatile__ ("fxsave %0" \ + : /* nothing */ \ + : "X" (mem)) + +#define stmxcsr(mem) \ + __asm__ __volatile__ ("stmxcsr %0" \ + : /* nothing */ \ + : "X" (mem)) + +#define ldmxcsr(mem) \ + __asm__ __volatile__ ("ldmxcsr %0" \ + : /* nothing */ \ + : "X" (mem)) +#endif /*ARCH_X86 */ + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/src/xine-utils/memcpy.c b/src/xine-utils/memcpy.c new file mode 100644 index 000000000..23a17059c --- /dev/null +++ b/src/xine-utils/memcpy.c @@ -0,0 +1,439 @@ +/* + * Copyright (C) 2001 the xine project + * + * This file is part of xine, a unix video player. + * + * xine is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * xine is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * These are the MMX/MMX2/SSE optimized versions of memcpy + * + * This code was adapted from Linux Kernel sources by Nick Kurshev to + * the mplayer program. (http://mplayer.sourceforge.net) + * + * Miguel Freitas split the #ifdefs into several specialized functions that + * are benchmarked at runtime by xine. Some original comments from Nick + * have been preserved documenting some MMX/SSE oddities. + * Also added kernel memcpy function that seems faster than glibc one. + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdlib.h> +#include <string.h> +#include "xine_internal.h" +#include "cpu_accel.h" + +void *(* fast_memcpy)(void *to, const void *from, size_t len); + +/* Original comments from mplayer (file: aclib.c) + This part of code was taken by me from Linux-2.4.3 and slightly modified +for MMX, MMX2, SSE instruction set. I have done it since linux uses page aligned +blocks but mplayer uses weakly ordered data and original sources can not +speedup them. Only using PREFETCHNTA and MOVNTQ together have effect! + +>From IA-32 Intel Architecture Software Developer's Manual Volume 1, + +Order Number 245470: +"10.4.6. Cacheability Control, Prefetch, and Memory Ordering Instructions" + +Data referenced by a program can be temporal (data will be used again) or +non-temporal (data will be referenced once and not reused in the immediate +future). To make efficient use of the processor's caches, it is generally +desirable to cache temporal data and not cache non-temporal data. Overloading +the processor's caches with non-temporal data is sometimes referred to as +"polluting the caches". +The non-temporal data is written to memory with Write-Combining semantics. + +The PREFETCHh instructions permits a program to load data into the processor +at a suggested cache level, so that it is closer to the processors load and +store unit when it is needed. If the data is already present in a level of +the cache hierarchy that is closer to the processor, the PREFETCHh instruction +will not result in any data movement. +But we should you PREFETCHNTA: Non-temporal data fetch data into location +close to the processor, minimizing cache pollution. + +The MOVNTQ (store quadword using non-temporal hint) instruction stores +packed integer data from an MMX register to memory, using a non-temporal hint. +The MOVNTPS (store packed single-precision floating-point values using +non-temporal hint) instruction stores packed floating-point data from an +XMM register to memory, using a non-temporal hint. + +The SFENCE (Store Fence) instruction controls write ordering by creating a +fence for memory store operations. This instruction guarantees that the results +of every store instruction that precedes the store fence in program order is +globally visible before any store instruction that follows the fence. The +SFENCE instruction provides an efficient way of ensuring ordering between +procedures that produce weakly-ordered data and procedures that consume that +data. + +If you have questions please contact with me: Nick Kurshev: nickols_k@mail.ru. +*/ + +/* mmx v.1 Note: Since we added alignment of destinition it speedups + of memory copying on PentMMX, Celeron-1 and P2 upto 12% versus + standard (non MMX-optimized) version. + Note: on K6-2+ it speedups memory copying upto 25% and + on K7 and P3 about 500% (5 times). +*/ + +#ifdef ARCH_X86 + +/* for small memory blocks (<256 bytes) this version is faster */ +#define small_memcpy(to,from,n)\ +{\ +register unsigned long int dummy;\ +__asm__ __volatile__(\ + "rep; movsb"\ + :"=&D"(to), "=&S"(from), "=&c"(dummy)\ + :"0" (to), "1" (from),"2" (n)\ + : "memory");\ +} + +/* linux kernel __memcpy (from: /include/asm/string.h) */ +static inline void * __memcpy(void * to, const void * from, size_t n) +{ +int d0, d1, d2; + + if( n < 4 ) { + small_memcpy(to,from,n); + } + else + __asm__ __volatile__( + "rep ; movsl\n\t" + "testb $2,%b4\n\t" + "je 1f\n\t" + "movsw\n" + "1:\ttestb $1,%b4\n\t" + "je 2f\n\t" + "movsb\n" + "2:" + : "=&c" (d0), "=&D" (d1), "=&S" (d2) + :"0" (n/4), "q" (n),"1" ((long) to),"2" ((long) from) + : "memory"); + + return (to); +} + +#define SSE_MMREG_SIZE 16 +#define MMX_MMREG_SIZE 8 + +#define MMX1_MIN_LEN 0x800 /* 2K blocks */ +#define MIN_LEN 0x40 /* 64-byte blocks */ + +/* SSE note: i tried to move 128 bytes a time instead of 64 but it +didn't make any measureable difference. i'm using 64 for the sake of +simplicity. [MF] */ +static void * sse_memcpy(void * to, const void * from, size_t len) +{ + void *retval; + size_t i; + retval = to; + + if(len >= MIN_LEN) + { + register unsigned long int delta; + /* Align destinition to MMREG_SIZE -boundary */ + delta = ((unsigned long int)to)&(SSE_MMREG_SIZE-1); + if(delta) + { + delta=SSE_MMREG_SIZE-delta; + len -= delta; + small_memcpy(to, from, delta); + } + i = len >> 6; /* len/64 */ + len&=63; + if(((unsigned long)from) & 15) + /* if SRC is misaligned */ + for(; i>0; i--) + { + __asm__ __volatile__ ( + "prefetchnta 320(%0)\n" + "movups (%0), %%xmm0\n" + "movups 16(%0), %%xmm1\n" + "movups 32(%0), %%xmm2\n" + "movups 48(%0), %%xmm3\n" + "movntps %%xmm0, (%1)\n" + "movntps %%xmm1, 16(%1)\n" + "movntps %%xmm2, 32(%1)\n" + "movntps %%xmm3, 48(%1)\n" + :: "r" (from), "r" (to) : "memory"); + ((const unsigned char *)from)+=64; + ((unsigned char *)to)+=64; + } + else + /* + Only if SRC is aligned on 16-byte boundary. + It allows to use movaps instead of movups, which required data + to be aligned or a general-protection exception (#GP) is generated. + */ + for(; i>0; i--) + { + __asm__ __volatile__ ( + "prefetchnta 320(%0)\n" + "movaps (%0), %%xmm0\n" + "movaps 16(%0), %%xmm1\n" + "movaps 32(%0), %%xmm2\n" + "movaps 48(%0), %%xmm3\n" + "movntps %%xmm0, (%1)\n" + "movntps %%xmm1, 16(%1)\n" + "movntps %%xmm2, 32(%1)\n" + "movntps %%xmm3, 48(%1)\n" + :: "r" (from), "r" (to) : "memory"); + ((const unsigned char *)from)+=64; + ((unsigned char *)to)+=64; + } + /* since movntq is weakly-ordered, a "sfence" + * is needed to become ordered again. */ + __asm__ __volatile__ ("sfence":::"memory"); + /* enables to use FPU */ + __asm__ __volatile__ ("emms":::"memory"); + } + /* + * Now do the tail of the block + */ + if(len) __memcpy(to, from, len); + return retval; +} + +static void * mmx_memcpy(void * to, const void * from, size_t len) +{ + void *retval; + size_t i; + retval = to; + + /* PREFETCH has effect even for MOVSB instruction ;) */ + __asm__ __volatile__ ( + " prefetchnta (%0)\n" + " prefetchnta 64(%0)\n" + " prefetchnta 128(%0)\n" + " prefetchnta 192(%0)\n" + " prefetchnta 256(%0)\n" + : : "r" (from) ); + + if(len >= MMX1_MIN_LEN) + { + register unsigned long int delta; + /* Align destinition to MMREG_SIZE -boundary */ + delta = ((unsigned long int)to)&(MMX_MMREG_SIZE-1); + if(delta) + { + delta=MMX_MMREG_SIZE-delta; + len -= delta; + small_memcpy(to, from, delta); + } + i = len >> 6; /* len/64 */ + len&=63; + for(; i>0; i--) + { + __asm__ __volatile__ ( + "prefetchnta 320(%0)\n" + "movq (%0), %%mm0\n" + "movq 8(%0), %%mm1\n" + "movq 16(%0), %%mm2\n" + "movq 24(%0), %%mm3\n" + "movq 32(%0), %%mm4\n" + "movq 40(%0), %%mm5\n" + "movq 48(%0), %%mm6\n" + "movq 56(%0), %%mm7\n" + "movq %%mm0, (%1)\n" + "movq %%mm1, 8(%1)\n" + "movq %%mm2, 16(%1)\n" + "movq %%mm3, 24(%1)\n" + "movq %%mm4, 32(%1)\n" + "movq %%mm5, 40(%1)\n" + "movq %%mm6, 48(%1)\n" + "movq %%mm7, 56(%1)\n" + :: "r" (from), "r" (to) : "memory"); + ((const unsigned char *)from)+=64; + ((unsigned char *)to)+=64; + } + __asm__ __volatile__ ("emms":::"memory"); + } + /* + * Now do the tail of the block + */ + if(len) __memcpy(to, from, len); + return retval; +} + +void * mmx2_memcpy(void * to, const void * from, size_t len) +{ + void *retval; + size_t i; + retval = to; + + /* PREFETCH has effect even for MOVSB instruction ;) */ + __asm__ __volatile__ ( + " prefetchnta (%0)\n" + " prefetchnta 64(%0)\n" + " prefetchnta 128(%0)\n" + " prefetchnta 192(%0)\n" + " prefetchnta 256(%0)\n" + : : "r" (from) ); + + if(len >= MIN_LEN) + { + register unsigned long int delta; + /* Align destinition to MMREG_SIZE -boundary */ + delta = ((unsigned long int)to)&(MMX_MMREG_SIZE-1); + if(delta) + { + delta=MMX_MMREG_SIZE-delta; + len -= delta; + small_memcpy(to, from, delta); + } + i = len >> 6; /* len/64 */ + len&=63; + for(; i>0; i--) + { + __asm__ __volatile__ ( + "prefetchnta 320(%0)\n" + "movq (%0), %%mm0\n" + "movq 8(%0), %%mm1\n" + "movq 16(%0), %%mm2\n" + "movq 24(%0), %%mm3\n" + "movq 32(%0), %%mm4\n" + "movq 40(%0), %%mm5\n" + "movq 48(%0), %%mm6\n" + "movq 56(%0), %%mm7\n" + "movntq %%mm0, (%1)\n" + "movntq %%mm1, 8(%1)\n" + "movntq %%mm2, 16(%1)\n" + "movntq %%mm3, 24(%1)\n" + "movntq %%mm4, 32(%1)\n" + "movntq %%mm5, 40(%1)\n" + "movntq %%mm6, 48(%1)\n" + "movntq %%mm7, 56(%1)\n" + :: "r" (from), "r" (to) : "memory"); + ((const unsigned char *)from)+=64; + ((unsigned char *)to)+=64; + } + /* since movntq is weakly-ordered, a "sfence" + * is needed to become ordered again. */ + __asm__ __volatile__ ("sfence":::"memory"); + __asm__ __volatile__ ("emms":::"memory"); + } + /* + * Now do the tail of the block + */ + if(len) __memcpy(to, from, len); + return retval; +} + +static void *linux_kernel_memcpy(void *to, const void *from, size_t len) { + return __memcpy(to,from,len); +} + +#endif /* ARCH_X86 */ + +static struct { + char *name; + void *(* function)(void *to, const void *from, size_t len); + unsigned long long time; + uint32_t cpu_require; +} memcpy_method[] = +{ + { "glibc memcpy()", memcpy, 0, 0 }, +#ifdef ARCH_X86 + { "linux kernel memcpy()", linux_kernel_memcpy, 0, 0 }, + { "MMX optimized memcpy()", mmx_memcpy, 0, MM_MMX }, + { "MMXEXT optimized memcpy()", mmx2_memcpy, 0, MM_MMXEXT }, + { "SSE optimized memcpy()", sse_memcpy, 0, MM_MMXEXT|MM_SSE }, +#endif /* ARCH_X86 */ + { NULL, NULL, 0, 0 } +}; + +#ifdef ARCH_X86 +static unsigned long long int rdtsc() +{ + unsigned long long int x; + __asm__ volatile (".byte 0x0f, 0x31" : "=A" (x)); + return x; +} +#else +static unsigned long long int rdtsc() +{ + /* FIXME: implement an equivalent for using optimized memcpy on other + architectures */ + return 0; +} +#endif + + +#define BUFSIZE 1024*1024 +void probe_fast_memcpy(config_values_t *config) +{ +unsigned long long t; +char *buf1, *buf2; +int i, j, best; +static int config_flags = -1; + +#ifdef ARCH_X86 + config_flags = mm_accel(); +#else + config_flags = 0; +#endif + + best = config->lookup_int (config, "fast_memcpy", -1); + /* check if function is configured and valid for this machine */ + if( best != -1 && + (config_flags & memcpy_method[best].cpu_require) == + memcpy_method[best].cpu_require ) { + printf("xine: using %s\n", memcpy_method[best].name ); + fast_memcpy = memcpy_method[best].function; + return; + } + + fast_memcpy = memcpy; + + if( (buf1 = malloc(BUFSIZE)) == NULL ) + return; + + if( (buf2 = malloc(BUFSIZE)) == NULL ) { + free(buf1); + return; + } + + printf("Benchmarking memcpy methods (smaller is better):\n"); + /* make sure buffers are present on physical memory */ + memcpy(buf1,buf2,BUFSIZE); + + for(i=0; memcpy_method[i].name; i++) + { + if( (config_flags & memcpy_method[i].cpu_require) != + memcpy_method[i].cpu_require ) + continue; + + t = rdtsc(); + for(j=0;j<100;j++) + memcpy_method[i].function(buf1,buf2,BUFSIZE); + t = rdtsc() - t; + memcpy_method[i].time = t; + + printf("\t%s : %lld\n",memcpy_method[i].name, t); + + if( best == -1 || t < memcpy_method[best].time ) + best = i; + } + printf("xine: using %s\n", memcpy_method[best].name ); + fast_memcpy = memcpy_method[best].function; + config->set_int (config, "fast_memcpy", best ); + + free(buf1); + free(buf2); +} diff --git a/src/xine-utils/memcpy.h b/src/xine-utils/memcpy.h new file mode 100644 index 000000000..a693f37fe --- /dev/null +++ b/src/xine-utils/memcpy.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2000-2001 the xine project + * + * This file is part of xine, a unix video player. + * + * xine is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * xine is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + */ + +#ifndef HAVE_MEMCPY_H +#define HAVE_MEMCPY_H + +/* optimized/fast memcpy */ +extern void *(* fast_memcpy)(void *to, const void *from, size_t len); + +#ifdef HAVE_XINE_INTERNAL_H +/* benchmark available memcpy methods */ +void probe_fast_memcpy(config_values_t *config); +#endif + +#endif diff --git a/src/xine-utils/monitor.c b/src/xine-utils/monitor.c new file mode 100644 index 000000000..9250ee2c4 --- /dev/null +++ b/src/xine-utils/monitor.c @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2000-2001 the xine project + * + * This file is part of xine, a unix video player. + * + * xine is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * xine is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * $Id: monitor.c,v 1.1 2001/10/22 00:52:10 guenter Exp $ + * + * debug print and profiling functions - implementation + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdio.h> +#include <sys/time.h> +#include "utils.h" +#include "monitor.h" + +#define MAX_ID 10 + +#ifdef DEBUG + +long long int profiler_times[MAX_ID] ; +long long int profiler_start[MAX_ID] ; +long profiler_calls[MAX_ID] ; +char * profiler_label[MAX_ID] ; + +void profiler_init () { + int i; + for (i=0; i<MAX_ID; i++) { + profiler_times[i] = 0; + profiler_start[i] = 0; + profiler_calls[i] = 0; + profiler_label[i] = NULL; + } +} + +int profiler_allocate_slot (char *label) { + int id; + + for (id = 0; id < MAX_ID && profiler_label[id] != NULL; id++) + ; + + if (id >= MAX_ID) + return -1; + + profiler_label[id] = label; + return id; +} + + +#ifdef ARCH_X86 +__inline__ unsigned long long int rdtsc() +{ + unsigned long long int x; + __asm__ volatile (".byte 0x0f, 0x31" : "=A" (x)); + return x; +} +#endif + +void profiler_start_count (int id) { + + if ((unsigned)id >= MAX_ID) return; + +#ifdef ARCH_X86 + profiler_start[id] = rdtsc(); +#endif +} + +void profiler_stop_count (int id) { + + if ((unsigned)id >= MAX_ID) return; + +#ifdef ARCH_X86 + profiler_times[id] += rdtsc() - profiler_start[id]; +#endif + profiler_calls[id]++; +} + +void profiler_print_results () { + int i; + +#ifdef ARCH_X86 + static long long int cpu_speed; /* cpu cyles/usec */ + if (!cpu_speed) { + long long int tsc_start, tsc_end; + struct timeval tv_start, tv_end; + + tsc_start = rdtsc(); + gettimeofday(&tv_start, NULL); + + xine_usec_sleep(100000); + + tsc_end = rdtsc(); + gettimeofday(&tv_end, NULL); + + cpu_speed = (tsc_end - tsc_start) / + ((tv_end.tv_sec - tv_start.tv_sec) * 1e6 + + tv_end.tv_usec - tv_start.tv_usec); + } +#endif + + printf ("\n\nPerformance analysis:\n\n" + "%-3s %-24.24s %12s %9s %12s %9s\n" + "----------------------------------------------------------------------------\n", + "ID", "name", "cpu cycles", "calls", "cycles/call", "usec/call"); + for (i=0; i<MAX_ID; i++) { + if (profiler_label[i]) { + printf ("%2d: %-24.24s %12lld %9ld", + i, profiler_label[i], profiler_times[i], profiler_calls[i]); + if (profiler_calls[i]) { + printf(" %12lld", profiler_times[i] / profiler_calls[i]); +#ifdef ARCH_X86 + printf(" %9lld", profiler_times[i] / (cpu_speed * profiler_calls[i])); +#endif + } + printf ("\n"); + } + } +} + +#endif diff --git a/src/xine-utils/monitor.h b/src/xine-utils/monitor.h new file mode 100644 index 000000000..6f899aaf4 --- /dev/null +++ b/src/xine-utils/monitor.h @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2000-2001 the xine project + * + * This file is part of xine, a unix video player. + * + * xine is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * xine is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * $Id: monitor.h,v 1.1 2001/10/22 00:52:10 guenter Exp $ + * + * debug print and profiling functions + * + */ + +#ifndef HAVE_MONITOR_H +#define HAVE_MONITOR_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <inttypes.h> + +extern uint32_t xine_debug; + +#define VERBOSE (xine_debug & 0x8000>>1) // 16384 +#define METRONOM (xine_debug & 0x8000>>2) // 8192 +#define AUDIO (xine_debug & 0x8000>>3) // 4096 +#define DEMUX (xine_debug & 0x8000>>4) // 2048 +#define INPUT (xine_debug & 0x8000>>5) // 1024 +#define VIDEO (xine_debug & 0x8000>>6) // 512 +#define VPTS (xine_debug & 0x8000>>7) // 256 +#define MPEG (xine_debug & 0x8000>>8) // 128 +#define VAVI (xine_debug & 0x8000>>9) // 64 +#define AC3 (xine_debug & 0x8000>>10) // 32 +#define LOOP (xine_debug & 0x8000>>11) // 16 +#define GUI (xine_debug & 0x8000>>12) // 8 + +#ifdef __GNUC__ +#define perr(FMT,ARGS...) {fprintf(stderr, FMT, ##ARGS);fflush(stderr);} +#else /* C99 version: */ +#define perr(...) {fprintf(stderr, __VA_ARGS__);fflush(stderr);} +#endif + +#ifdef DEBUG + +/* + * Debug stuff + */ + +//#define perr(FMT,ARGS...) {fprintf(stderr, FMT, ##ARGS);fflush(stderr);} + +#ifdef __GNUC__ +#define xprintf(LVL, FMT, ARGS...) { \ + if(LVL) { \ + printf(FMT, ##ARGS); \ + } \ + } +#else /* C99 version: */ +#define xprintf(LVL, ...) { \ + if(LVL) { \ + printf(__VA_ARGS__); \ + } \ + } +#endif + +/* + * profiling + */ + +void profiler_init (); + +int profiler_allocate_slot (char *label); + +void profiler_start_count (int id); + +void profiler_stop_count (int id); + +void profiler_print_results (); + +#else /* no DEBUG, release version */ + +//#define perr(FMT,ARGS...) + +#ifdef __GNUC__ +#define xprintf(LVL, FMT, ARGS...) +#else /* C99 version: */ +#define xprintf(LVL, ...) +#endif + +#define profiler_init() +#define profiler_allocate_slot(label) (-1) +#define profiler_start_count(id) +#define profiler_stop_count(id) +#define profiler_print_results() + +#endif /* DEBUG*/ + +#ifdef __cplusplus +} +#endif + +#endif /* HAVE_MONITOR_H */ diff --git a/src/xine-utils/utils.c b/src/xine-utils/utils.c new file mode 100644 index 000000000..d3435ea84 --- /dev/null +++ b/src/xine-utils/utils.c @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2000-2001 the xine project + * + * This file is part of xine, a unix video player. + * + * xine is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * xine is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * $Id: utils.c,v 1.1 2001/10/22 00:52:10 guenter Exp $ + * + */ +#define _POSIX_PTHREAD_SEMANTICS 1 /* for 5-arg getpwuid_r on solaris */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <string.h> +#include <unistd.h> +#include <pwd.h> +#include <time.h> +#include <sys/types.h> + +#ifndef __GNUC__ +#define __FUNCTION__ __func__ +#endif + + +/* + * + */ +void *xmalloc(size_t size) { + void *ptr; + + if((ptr = malloc(size)) == NULL) { + fprintf(stderr, "%s: malloc() failed: %s.\n", + __FUNCTION__, strerror(errno)); + return NULL; + } + + memset(ptr, 0, size); + + return ptr; +} + +/* + * + */ +void *xmalloc_aligned (size_t alignment, size_t size) { + char *pMem; + + pMem = xmalloc (size+alignment); + + while ((int) pMem % alignment) + pMem++; + + return pMem; +} + +/* + * + */ +const char *get_homedir(void) { + struct passwd *pw = NULL; + char *homedir = NULL; +#ifdef HAVE_GETPWUID_R + int ret; + struct passwd pwd; + char *buffer = NULL; + int bufsize = 128; + + buffer = (char *) xmalloc(bufsize); + + if((ret = getpwuid_r(getuid(), &pwd, buffer, bufsize, &pw)) < 0) { +#else + if((pw = getpwuid(getuid())) == NULL) { +#endif + if((homedir = getenv("HOME")) == NULL) { + fprintf(stderr, "Unable to get home directory, set it to /tmp.\n"); + homedir = strdup("/tmp"); + } + } + else { + if(pw) + homedir = strdup(pw->pw_dir); + } + + +#ifdef HAVE_GETPWUID_R + if(buffer) + free(buffer); +#endif + + return homedir; +} + +/* + * + */ +char *chomp(char *str) { + char *pbuf; + + pbuf = str; + + while(*pbuf != '\0') pbuf++; + + while(pbuf > str) { + if(*pbuf == '\r' || *pbuf == '\n' || *pbuf == '"') pbuf = '\0'; + pbuf--; + } + + while(*pbuf == '=' || *pbuf == '"') pbuf++; + + return pbuf; +} + + +/* + * A thread-safe usecond sleep + */ +void xine_usec_sleep(unsigned usec) { +#if HAVE_NANOSLEEP + /* nanosleep is prefered on solaris, because it's mt-safe */ + struct timespec ts; + + ts.tv_sec = usec / 1000000; + ts.tv_nsec = (usec % 1000000) * 1000; + nanosleep(&ts, NULL); +#else + usleep(usec); +#endif +} diff --git a/src/xine-utils/utils.h b/src/xine-utils/utils.h new file mode 100644 index 000000000..2c35d52db --- /dev/null +++ b/src/xine-utils/utils.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2000-2001 the xine project + * + * This file is part of xine, a unix video player. + * + * xine is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * xine is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * $Id: utils.h,v 1.1 2001/10/22 00:52:10 guenter Exp $ + * + */ +#ifndef HAVE_UTILS_H +#define HAVE_UTILS_H + +#ifdef __cplusplus +extern "C" { +#endif + +void *xmalloc(size_t size); + +void *xmalloc_aligned(size_t alignment, size_t size); + +const char *get_homedir(void); + +/* + * Clean a string (remove spaces and '=' at the begin, + * and '\n', '\r' and spaces at the end. + */ + +char *chomp (char *str); + +/* + * A thread-safe usecond sleep + */ +void xine_usec_sleep(unsigned usec); + +#ifdef __cplusplus +} +#endif + +#endif |