Hello,
 I've run some tests with memxor on a x86-64 machine. My results are:
* C implementation (compiled with gcc 4.4):
        Xoring in chunks of 32768 bytes: done. 50.09 Gb in 5.00 secs:
10.02 Gb/sec
        Xoring (unaligned) in chunks of 32768 bytes: done. 39.90 Gb in
5.00 secs: 7.98 Gb/sec

* ASM implementation:
        Xoring in chunks of 32768 bytes: done. 38.32 Gb in 5.00 secs:
7.66 Gb/sec
        Xoring (unaligned) in chunks of 32768 bytes: done. 30.16 Gb in
5.00 secs: 6.03 Gb/sec

It seems that in x86-64 the ASM version is slower than the C one.
Moreover I noticed that the loop unrolling techniques used in the C
code have no visible performance benefit.

However, an SSE2 version of memxor (attached) increases performance by
30% or more in the same CPU.

* SSE2:
        Xoring in chunks of 32768 bytes: done. 69.94 Gb in 5.00 secs:
13.98 Gb/sec
        Xoring (unaligned) in chunks of 32768 bytes: done. 65.96 Gb in
5.00 secs: 13.19 Gb/sec

regards,
Nikos
/* memxor.c
 *
 */

/* nettle, low-level cryptographics library
 *
 * Copyright (C) 1991, 1993, 1995 Free Software Foundation, Inc.
 * Copyright (C) 2010 Niels Möller
 *  
 * The nettle library is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or (at your
 * option) any later version.
 * 
 * The nettle library 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 Lesser General Public
 * License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with the nettle library; see the file COPYING.LIB.  If not, write to
 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
 * MA 02111-1307, USA.
 */

/* Implementation inspired by memcmp in glibc, contributed to the FSF
   by Torbjorn Granlund.
 */

#if HAVE_CONFIG_H
# include "config.h"
#endif

#include <limits.h>
#include <emmintrin.h>

#include "memxor.h"

typedef __m128i word_t;

#if SIZEOF_LONG & (SIZEOF_LONG - 1)
#error Word size must be a power of two
#endif

#define ALIGN_OFFSET(p) ((uintptr_t) (p) % sizeof(word_t))

#define WORD_T_THRESH 16

/* XOR word-aligned areas. n is the number of words, not bytes. */
static void
memxor_common_alignment (word_t *dst, const word_t *src, size_t n)
{
  __m128i xmm1,xmm2;
  
  for (; n > 0; dst += 1, src += 1, n--) 
    {
      xmm1 = _mm_load_si128(dst);
      xmm2 = _mm_load_si128(src);

      xmm1 = _mm_xor_si128(xmm1, xmm2);
      _mm_store_si128(dst, xmm1);
    }
}

/* XOR *un-aligned* src-area onto aligned dst area. n is number of
   words, not bytes. Assumes we can read complete words at the start
   and end of the src operand. */
static void
memxor_different_alignment (word_t *dst, const word_t *src, size_t n)
{
  __m128i xmm1,xmm2;
  
  for (; n > 0; dst += 1, src += 1, n--) 
    {
      xmm1 = _mm_loadu_si128(dst);
      xmm2 = _mm_loadu_si128(src);

      xmm1 = _mm_xor_si128(xmm1, xmm2);
      _mm_storeu_si128(dst, xmm1);
    }
}

/* Performance, Intel SU1400 (x86_64): 0.25 cycles/byte aligned, 0.45
   cycles/byte unaligned. */

/* XOR LEN bytes starting at SRCADDR onto DESTADDR. Result undefined
   if the source overlaps with the destination. Return DESTADDR. */
uint8_t *
memxor(uint8_t *dst, const uint8_t *src, size_t n)
{
  uint8_t *orig_dst = dst;

  if (n >= WORD_T_THRESH)
    {
      /* There are at least some bytes to compare.  No need to test
	 for N == 0 in this alignment loop.  */
      while (ALIGN_OFFSET (dst))
	{
	  *dst++ ^= *src++;
	  n--;
	}
      if (ALIGN_OFFSET (src))
	memxor_different_alignment ((word_t *) dst, (const word_t*)src, n / sizeof(word_t));
      else
	memxor_common_alignment ((word_t *) dst, (const word_t *) src, n / sizeof(word_t));

      dst += n & -SIZEOF_LONG;
      src += n & -SIZEOF_LONG;
      n = n & (SIZEOF_LONG - 1);
    }
  for (; n > 0; n--)
    *dst++ ^= *src++;

  return orig_dst;
}


/*  cryptodev_test - simple benchmark tool for cryptodev
 *
 *    Copyright (C) 2010 by Phil Sutter <[email protected]>
 *
 *  This program 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.
 *
 *  This program 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */
#include <fcntl.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <signal.h>
#include <unistd.h>

static double udifftimeval(struct timeval start, struct timeval end)
{
	return (double)(end.tv_usec - start.tv_usec) +
	       (double)(end.tv_sec - start.tv_sec) * 1000 * 1000;
}

static int must_finish = 0;

static void alarm_handler(int signo)
{
        must_finish = 1;
}

static void value2human(double bytes, double time, double* data, double* speed,char* metric)
{
        if (bytes > 1000 && bytes < 1000*1000) {
                *data = ((double)bytes)/1000;
                *speed = *data/time;
                strcpy(metric, "Kb");
                return;
        } else if (bytes >= 1000*1000 && bytes < 1000*1000*1000) {
                *data = ((double)bytes)/(1000*1000);
                *speed = *data/time;
                strcpy(metric, "Mb");
                return;
        } else if (bytes >= 1000*1000*1000) {
                *data = ((double)bytes)/(1000*1000*1000);
                *speed = *data/time;
                strcpy(metric, "Gb");
                return;
        } else {
                *data = (double)bytes;
                *speed = *data/time;
                strcpy(metric, "bytes");
                return;
        }
}


void xor(void)
{
	unsigned char *buffer1, *buffer2, *buffer3;
	static int val = 23;
	struct timeval start, end;
	double total = 0;
	double secs, ddata, dspeed;
	char metric[16];
	int i = 23;
	int chunksize = 32*1024;

	buffer1 = malloc(chunksize+1);
	buffer3 = malloc(chunksize+1);

	memset(buffer1, i, chunksize+1);
	memset(buffer3, i, chunksize+1);

	buffer2 = malloc(chunksize);
	memset(buffer2, 0x78, chunksize);

	/* sanity check first */
	memxor(buffer3, buffer2, chunksize);
	for (i=0;i<chunksize;i++)
	  if (buffer3[i] != (buffer1[i] ^ buffer2[i])) {
	    fprintf(stderr, "memxor is broken! %x found, expected %x ^ %x = %x\n", buffer3[i], buffer1[i], buffer2[i], buffer1[i]^buffer2[i]);
	    abort();
	  }

	memcpy(buffer3, buffer1, chunksize+1);
	memxor(buffer3+1, buffer2, chunksize);
	for (i=0;i<chunksize;i++)
	  if (buffer3[i+1] != (buffer1[i+1] ^ buffer2[i])) {
	    fprintf(stderr, "memxor (unaligned) is broken! in pos %d, found %x, expected %x ^ %x = %x\n", i, buffer3[i+1], buffer1[i+1], buffer2[i], buffer1[i+1]^buffer2[i]);
	    abort();
	  }

	printf("\tXoring in chunks of %d bytes: ", chunksize);
	fflush(stdout);
	
	must_finish = 0;
	alarm(5);

	gettimeofday(&start, NULL);
	do {
		size_t output_size;

		memxor(buffer1, buffer2, chunksize);

		total+=chunksize;
	} while(must_finish==0);
	gettimeofday(&end, NULL);

	secs = udifftimeval(start, end)/ 1000000.0;
	
	value2human(total, secs, &ddata, &dspeed, metric);
	printf ("done. %.2f %s in %.2f secs: ", ddata, metric, secs);
	printf ("%.2f %s/sec\n", dspeed, metric);



	printf("\tXoring (unaligned) in chunks of %d bytes: ", chunksize);
	fflush(stdout);
	
	must_finish = 0;
	total = 0;
	alarm(5);

	gettimeofday(&start, NULL);
	do {
		size_t output_size;

		memxor(buffer1+1, buffer2, chunksize);

		total+=chunksize;
	} while(must_finish==0);
	gettimeofday(&end, NULL);

	secs = udifftimeval(start, end)/ 1000000.0;
	
	value2human(total, secs, &ddata, &dspeed, metric);
	printf ("done. %.2f %s in %.2f secs: ", ddata, metric, secs);
	printf ("%.2f %s/sec\n", dspeed, metric);

	return;
}

int main(void)
{
	int fd, i;

	signal(SIGALRM, alarm_handler);
	
	xor();

	return 0;
}
_______________________________________________
nettle-bugs mailing list
[email protected]
http://lists.lysator.liu.se/mailman/listinfo/nettle-bugs

Reply via email to