diff --git a/Makefile b/Makefile
index 81c0505..df1ac74 100644
--- a/Makefile
+++ b/Makefile
@@ -87,6 +87,9 @@ libx264gtk.a: muxers.o libx264.a
 checkasm: tools/checkasm.o libx264.a
 	$(CC) -o $@ $+ $(LDFLAGS)
 
+timeasm: tools/timeasm.o libx264.a
+	$(CC) -o $@ $+ $(LDFLAGS)
+
 %.o: %.asm
 	$(AS) $(ASFLAGS) -o $@ $<
 # delete local/anonymous symbols, so they don't show up in oprofile
@@ -138,6 +141,7 @@ endif
 clean:
 	rm -f $(OBJS) $(OBJASM) $(OBJCLI) $(SONAME) *.a x264 x264.exe .depend TAGS
 	rm -f checkasm checkasm.exe tools/checkasm.o
+	rm -f timeasm timeasm.exe tools/timeasm.o
 	rm -f tools/avc2avi tools/avc2avi.exe tools/avc2avi.o
 	rm -f $(SRC2:%.c=%.gcda) $(SRC2:%.c=%.gcno)
 	- sed -e 's/ *-fprofile-\(generate\|use\)//g' config.mak > config.mak2 && mv config.mak2 config.mak
diff --git a/tools/timeasm.c b/tools/timeasm.c
new file mode 100644
index 0000000..14ad0db
--- /dev/null
+++ b/tools/timeasm.c
@@ -0,0 +1,250 @@
+#define _GNU_SOURCE
+#include <unistd.h>
+#include <sched.h>
+#include <emmintrin.h>
+#include <stdint.h>
+#include <stdio.h>
+
+#include "common/common.h"
+#include "common/cpu.h"
+
+#define ITERATION_COUNT (4*1024*1024)
+
+/* buf1, buf2: initialised to random data and shouldn't write into them */
+uint8_t * buf1, * buf2;
+/* buf3, buf4: used to store output */
+uint8_t * buf3, * buf4;
+
+static
+uint64_t read_tsc(void) __attribute__((noinline));
+
+#if defined (ARCH_X86_64)
+static
+uint64_t read_tsc(void)
+{
+    uint32_t low,high;
+    uint64_t res;
+    __asm__ __volatile__(
+	"push %%rbx\n\t"
+	"xorl %%eax,%%eax\n\t"
+	"cpuid\n\t"
+	"rdtsc\n\t"
+	"push %%rax\n\t"
+	"push %%rdx\n\t"
+	"xorl %%eax,%%eax\n\t"
+	"cpuid\n\t"
+	"pop %%rdx\n\t"
+	"pop %%rax\n\t"
+	"pop %%rbx\n\t"
+	: "=a"(low),"=d"(high)
+	:
+	: "rcx");
+
+    
+    res = high;
+    res <<= 32;
+    res |= low;
+    return res;
+}
+#elif defined (ARCH_X86)
+static
+uint64_t read_tsc(void)
+{
+    uint32_t low,high;
+    uint64_t res;
+    __asm__ __volatile__(
+	"push %%ebx\n\t"
+	"xorl %%eax,%%eax\n\t"
+	"cpuid\n\t"
+	"rdtsc\n\t"
+	"push %%eax\n\t"
+	"push %%edx\n\t"
+	"xorl %%eax,%%eax\n\t"
+	"cpuid\n\t"
+	"pop %%edx\n\t"
+	"pop %%eax\n\t"
+	"pop %%ebx\n\t"
+	: "=a"(low),"=d"(high)
+	:
+	: "ecx");
+    res = high;
+    res <<= 32;
+    res |= low;
+    return res;
+}
+#else
+#error "please define read_tsc for this architecture"
+#endif
+
+static void func_dummy() __attribute__((noinline));
+static
+void func_dummy()
+{
+}
+
+#define call_func(func,...) func(__VA_ARGS__)
+
+#define time_val(o,msg, func,...)				\
+    do {							\
+	uint64_t a,b;						\
+	uint64_t d;						\
+	dmin=~0UL;						\
+	uint64_t dmax=0;					\
+	int64_t i;						\
+	for (i=0;i<ITERATION_COUNT;++i) {			\
+	    a=read_tsc();					\
+	    func(__VA_ARGS__);					\
+	    b=read_tsc();					\
+	    d= b-a;						\
+	    if ( d< dmin )					\
+		dmin=d;						\
+	    if ( d> dmax)					\
+		dmax=d;						\
+	}							\
+	if (msg)						\
+	    fprintf(stdout,"%s: %lu clocks\n", msg, dmin -o);	\
+    } while (0)
+
+void time_zigzag(int cpu_ref, int cpu_new, int interlace)
+{
+
+    x264_zigzag_function_t zigzag_c;
+    x264_zigzag_function_t zigzag_ref;
+    x264_zigzag_function_t zigzag_new;
+
+    uint64_t dmin, offset;
+
+    fprintf(stdout, "---------------------------------------------\n");
+    fprintf(stdout, "zigzag %s\n", (interlace == 0 ? "frame" : "field"));
+    x264_zigzag_init( 0, &zigzag_c, interlace );
+    x264_zigzag_init( cpu_ref, &zigzag_ref, interlace );
+    x264_zigzag_init( cpu_new, &zigzag_new, interlace );
+
+    DECLARE_ALIGNED_16( int16_t level[64] );
+
+    time_val(0,"offset determination", func_dummy, level, buf2, buf3 );
+    offset =dmin;
+    memcpy( buf3, buf1, 16*FDEC_STRIDE );
+    time_val(offset, "c - sub_4x4", zigzag_c.sub_4x4, level, buf2, buf3 );
+    memcpy( buf3, buf1, 16*FDEC_STRIDE );
+    time_val(offset, "ref - sub_4x4", zigzag_ref.sub_4x4, level, buf2, buf3 );
+    memcpy( buf3, buf1, 16*FDEC_STRIDE );
+    time_val(offset, "new - sub_4x4", zigzag_new.sub_4x4, level, buf2, buf3 );
+
+    DECLARE_ALIGNED_16( int16_t dct4[4][4] );
+    time_val(0,"offset determination", func_dummy, level, dct4);
+    offset =dmin;
+    memcpy( dct4, buf1, 4*4*sizeof(int16_t));
+    time_val(offset, "c - scan_4x4", zigzag_c.scan_4x4, level, dct4 );
+    memcpy( dct4, buf1, 4*4*sizeof(int16_t));
+    time_val(offset, "ref - scan_4x4", zigzag_ref.scan_4x4, level, dct4 );
+    memcpy( dct4, buf1, 4*4*sizeof(int16_t));
+    time_val(offset, "new - scan_4x4", zigzag_new.scan_4x4, level, dct4);
+
+    DECLARE_ALIGNED_16( int16_t dct8[8][8] );
+    time_val(0,"offset determination", func_dummy, level, dct8);
+    offset =dmin;
+    memcpy( dct8, buf1, 8*8*sizeof(int16_t));
+    time_val(offset, "c - scan_8x8", zigzag_c.scan_8x8, level, dct8 );
+    memcpy( dct8, buf1, 8*8*sizeof(int16_t));
+    time_val(offset, "ref - scan_8x8", zigzag_ref.scan_8x8, level, dct8 );
+    memcpy( dct8, buf1, 8*8*sizeof(int16_t));
+    time_val(offset, "new - scan_8x8", zigzag_new.scan_8x8, level, dct8 );
+}
+
+void time_dct(int cpu_ref, int cpu_new)
+{
+    DECLARE_ALIGNED_16( int16_t res16[16][4][4] );
+    uint64_t dmin, offset;
+    x264_dct_function_t dct_c;
+    x264_dct_function_t dct_ref;
+    x264_dct_function_t dct_new;
+
+    fprintf(stdout, "---------------------------------------------\n");
+    fprintf(stdout, "dct\n" );
+
+    x264_dct_init(0,&dct_c);
+    x264_dct_init(cpu_ref,&dct_ref);
+    x264_dct_init(cpu_new,&dct_new);
+
+    time_val(0,"offset determination", func_dummy, res16, buf1, buf2);
+    offset = dmin;
+    time_val(offset, "c - sub8x8_dct", 
+	     dct_c.sub8x8_dct, res16, buf1, buf2);
+    time_val(offset, "ref - sub8x8_dct", 
+	     dct_ref.sub8x8_dct, res16, buf1, buf2);
+    time_val(offset, "new - sub8x8_dct", 
+	     dct_new.sub8x8_dct, res16, buf1, buf2);
+
+    time_val(0,"offset determination", func_dummy, res16, buf1, buf2);
+    offset = dmin;
+    time_val(offset, "c - sub16x16_dct", 
+	     dct_c.sub16x16_dct, res16, buf1, buf2);
+    time_val(offset, "ref - sub16x16_dct", 
+	     dct_ref.sub16x16_dct, res16, buf1, buf2);
+    time_val(offset, "new - sub16x16_dct", 
+	     dct_new.sub16x16_dct, res16, buf1, buf2);
+
+    time_val(0,"offset determination", func_dummy, buf2, res16);
+    offset = dmin;
+    time_val(offset, "c - add8x8_idct", 
+	     dct_c.add8x8_idct, buf2, res16);
+    time_val(offset, "ref - add8x8_idct", 
+	     dct_ref.add8x8_idct, buf2, res16);
+    time_val(offset, "new - add8x8_idct", 
+	     dct_new.add8x8_idct, buf2, res16);
+
+    time_val(0,"offset determination", func_dummy, buf2, res16);
+    offset = dmin;
+    time_val(offset, "c - add16x16_idct", 
+	     dct_c.add16x16_idct, buf2, res16);
+    time_val(offset, "ref - add16x16_idct", 
+	     dct_ref.add16x16_idct, buf2, res16);
+    time_val(offset, "new - add16x16_idct", 
+	     dct_new.add16x16_idct, buf2, res16);
+
+}
+
+int main(int argc, char** argv)
+{
+    int i,cpu1,cpu2;
+#ifdef ARCH_X86_64
+    fprintf(stdout, "Architecture: x86-64\n");
+#elif ARCH_X86
+    fprintf(stdout, "Architecture: x86-32\n");
+#else
+    fprintf(stdout, "Architecture: unknown\n");
+#endif
+#if defined (__linux__)
+    {
+	cpu_set_t cpus;
+	CPU_ZERO(&cpus);
+	CPU_SET(0,&cpus);
+	sched_setaffinity(getpid(),sizeof(cpus),&cpus);
+	nice(19);
+    }
+    system("cat /proc/cpuinfo | grep \"model name\" | sort -u");
+#endif
+
+    buf1 = x264_malloc( 1024 ); /* 32 x 32 */
+    buf2 = x264_malloc( 1024 );
+    buf3 = x264_malloc( 4096 );
+    buf4 = x264_malloc( 4096 );
+
+    i = ( argc > 1 ) ? atoi(argv[1]) : x264_mdate();
+    fprintf( stderr, "x264: using random seed %u\n", i );
+    srand( i );
+
+    for( i = 0; i < 1024; i++ )
+    {
+	buf1[i] = rand() & 0xFF;
+	buf2[i] = rand() & 0xFF;
+	buf3[i] = buf4[i] = 0;
+    }
+    cpu1= X264_CPU_MMX | X264_CPU_MMXEXT;
+    cpu2= cpu1 | X264_CPU_SSE2;
+    time_zigzag (cpu1, cpu2,0);
+    time_zigzag (cpu1, cpu2,1);
+    time_dct(cpu1, cpu2);
+    return 0;
+}
