kvm.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: "Lukáš Doktor" <ldoktor@redhat.com>
To: KVM list <kvm@vger.kernel.org>,
	Autotest mailing list <autotest@test.kernel.org>
Subject: Re: [KVM-AUTOTEST PATCH 1/2] Add KSM test
Date: Mon, 31 Aug 2009 11:35:18 +0200	[thread overview]
Message-ID: <4A9B9956.9000209@redhat.com> (raw)
In-Reply-To: <4A9B97E5.3000109@redhat.com>

allocator.c is a program, which allocates pages in the memory and allow 
us to fill or test those pages. It's controlled using sockets.

Signed-off-by: Lukáš Doktor <ldoktor@redhat.com>
Signed-off-by: Jiří Župka <jzupka@redhat.com>
---
  client/tests/kvm/allocator.c |  571 
++++++++++++++++++++++++++++++++++++++++++
  1 files changed, 571 insertions(+), 0 deletions(-)
  create mode 100644 client/tests/kvm/allocator.c

diff --git a/client/tests/kvm/allocator.c b/client/tests/kvm/allocator.c
new file mode 100644
index 0000000..89e8ce4
--- /dev/null
+++ b/client/tests/kvm/allocator.c
@@ -0,0 +1,571 @@
+/*
+ * KSM test program.
+ * Copyright(C) 2009 Redhat
+ * Jason Wang (jasowang@redhat.com)
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+#include <syscall.h>
+#include <time.h>
+#include <stdint.h>
+//socket linux
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <signal.h>
+//TODO: socket windows
+
+
+
+#define PS (4096)
+long PAGE_SIZE = PS;
+long intInPage = PS/sizeof(int);
+#define MAP_FLAGS ( MAP_ANON | MAP_SHARED )
+#define PROT_FLAGS ( PROT_WRITE )
+#define FILE_MODE ( O_RDWR | O_CREAT )
+#define LOG_FILE "/var/log/vksmd"
+#define FIFO_FILE "/tmp/vksmd"
+#define MODE 0666
+#define FILE_BASE "/tmp/ksm_file"
+#define MAX_SIZESIZE 6
+#define MAX_COMMANDSIZE 50
+#define BLOCK_COUNT 8
+
+int log_fd = -1;
+int base_fd = -1;
+int checkvalue = 0;
+
+
+//Socket
+struct sockaddr_in sockName;
+struct sockaddr_in clientInfo;
+int mainSocket,clientSocket;
+int port;
+
+socklen_t addrlen;
+
+
+
+
+const uint32_t random_mask = UINT32_MAX>>1;
+uint32_t random_x = 0;
+const uint32_t random_a = 1103515245;
+const uint32_t random_m = 2^32;
+const uint32_t random_c = 12345;
+
+int statickey = 0;
+int dynamickey = 0;
+
+typedef enum _COMMANDS
+{
+  wrongcommad,
+  ninit,
+  nrandom,
+  nexit,
+  nsrandom,
+  nsrverify,
+  nfillzero,
+  nfillvalue,
+  ndfill,
+  nverify
+} COMMANDS;
+
+void sigpipe (int param)
+{
+  fprintf(stderr,"write error\n");
+  //exit(-1); //uncomment end if network connetion is down
+}
+
+int writefull(int socket,char * data,int size){
+  int sz = 0;
+  while (sz < size)
+    sz += write(socket, data+sz, size-sz);
+  return sz;
+}
+
+
+int write_message(int s,char * message){
+  size_t len = strlen(message);
+  char buf[10];
+  sprintf(buf,"%d:",(unsigned int)len);
+  size_t size = strlen(buf);
+
+  struct timeval tv;
+  fd_set writeset;
+  fd_set errorset;
+  FD_ZERO(&writeset);
+  FD_ZERO(&errorset);
+  FD_SET(clientSocket, &writeset);
+  FD_SET(clientSocket, &errorset);
+  tv.tv_sec = 0;
+  tv.tv_usec = 100;
+  int max = s+1;
+  tv.tv_sec = 10;
+  tv.tv_usec = 0;
+  int ret = select(max, NULL, &writeset, NULL, &tv);
+  if (ret == -1)
+  {
+    return -1;
+  }
+  if (ret == 0)
+  {
+    return -1;
+  }
+  if (FD_ISSET(s, &writeset))
+  {
+    if (writefull(s, buf, size) != size){
+      return -1;
+    }
+    if (writefull(s, message, len) != len){
+      return -1;
+    }
+  }
+  return 0;
+}
+
+void log_info(char *str)
+{
+  if (write_message(clientSocket, str) != 0){
+    fprintf(stderr,"write error\n");
+  }
+}
+
+/* fill pages with zero */
+void zero_pages(void **page_array,int npages)
+{
+  int n = 0;
+  for(n=0;n<npages;n++)
+    memset(page_array[n],0,intInPage);
+}
+
+/* fill pages with zero */
+void value_to_pages(void **page_array,int npages,char value)
+{
+  int n = 0;
+  for(n=0;n<npages;n++)
+    memset(page_array[n],value,PAGE_SIZE/sizeof(char));
+}
+
+/* initialise page_array */
+void **map_zero_page(unsigned long npages)
+{
+  void **page_array=(void **)malloc(sizeof(void *)*npages);
+  long n = 0;
+
+  if ( page_array == NULL ) {
+    log_info("page array allocated failed\n");
+    return NULL;
+  }
+
+#if 0
+  /* Map the /dev/zero in order to be detected by KSM */
+  for( n=0 ; n < npages; n++){
+    int i;
+    void *addr=(void *)mmap(0,PAGE_SIZE,PROT_FLAGS,MAP_FLAGS,0,0);
+    if ( addr == MAP_FAILED ){
+      log_info("map failed!\n");
+      for (i=0;i<n;i++)
+	munmap( page_array[i], 0);
+      free(page_array);
+      return NULL;
+    }
+
+    page_array[n] = addr;
+  }
+#endif
+
+ void *addr = (void *)mmap(0,PAGE_SIZE*npages,PROT_FLAGS,MAP_FLAGS,0,0);
+  if (addr == MAP_FAILED){
+    log_info("FAIL: map failed!\n");
+    free(page_array);
+    return NULL;
+  }
+
+  for (n=0;n<npages;n++)
+    page_array[n] = addr+PAGE_SIZE*n;
+
+  zero_pages(page_array,npages);
+
+  return page_array;
+}
+
+/* fill page with random data */
+void random_fill(void **page_array, unsigned long npages)
+{
+  int n = 0;
+  int value = 0;
+  int offset = 0;
+  void *addr = NULL;
+
+  for( n = 0; n < npages; n++){
+    offset = rand() % (intInPage);
+    value = rand();
+    addr = page_array[n] + offset;
+    *((int *)addr) = value;
+  }
+}
+
+
+/*set random series seed*/
+void mrseed(int seed){
+  random_x = seed;
+}
+
+/*Generate random number*/
+int mrand(){
+  random_x  = random_a*random_x+random_c;
+  return random_x & random_mask;
+}
+
+/* Generate randomcode array*/
+int* random_code_array(int nblock)
+{
+  int * randArray = malloc(PAGE_SIZE*nblock);
+  int n = 0;
+  for (;n < nblock;n++){
+    int i = 0;
+    for (;i < intInPage;i++){
+      randArray[n*intInPage+i]=mrand();
+    }
+  }
+  return randArray;
+}
+
+/* fill page with static random series data*/
+void static_random_fill(void **page_array, unsigned long npages,int nblock)
+{
+  mrseed(dynamickey);
+  int* randomArray = random_code_array(nblock);
+  int n = 0;
+  int q = -1;
+  int blocksize = npages/nblock;
+  int offset = 0;
+  void *addr = NULL;
+
+  mrseed(randomArray[0]);
+  for (;n < npages;n++){
+    if (n%(blocksize) == 0) q++;
+    memcpy(page_array[n],&randomArray[q*intInPage],PAGE_SIZE);
+    offset = mrand() % (intInPage);
+    addr = ((int *)page_array[n]) + offset;
+    *((int *)addr) = n;
+  }
+  free(randomArray);
+  return;
+}
+
+/* fill page with static random series data*/
+int static_random_verify(void **page_array, unsigned long npages,int 
nblock)
+{
+  int* p = malloc(PAGE_SIZE);
+  mrseed(dynamickey);
+  int* randomArray = random_code_array(nblock);
+  int n = 0;
+  int q = -1;
+  int blocksize = npages/nblock;
+  int offset = 0;
+  void *addr = NULL;
+  char buf[128];
+
+  int ret = 1;
+
+  mrseed(randomArray[0]);
+  for (;n < npages;n++){
+    if (n%(blocksize) == 0) q++;
+    memcpy(p,&randomArray[q*intInPage],PAGE_SIZE);
+    offset = mrand() % (intInPage);
+    p[offset] = n;
+    addr = ((int*)page_array[n]) + offset;
+    int r = memcmp(p,page_array[n],PAGE_SIZE);
+    if (r != 0){
+      for (r = 0;r < intInPage;r++){
+        addr = ((int *)page_array[n]) + r;
+        if (*((int *)addr) != p[r]){
+          sprintf(buf,"verify failed [0x%p] %d instead of 
%d\n",addr,*((int *)addr),n);
+          log_info(buf);
+          ret = 0;
+        }
+      }
+    }
+  }
+  free(randomArray);
+  free(p);
+  return ret;
+}
+
+
+/* verify value */
+int verify_address_space(void **page_array, unsigned long npages, int 
checkvalue)
+{
+  int m,n;
+  char buf[128];
+  sprintf(buf,"verify value = %d\n",checkvalue);
+  log_info(buf);
+  if ( checkvalue == -1 ){
+    return 1;
+  }
+  for( n = 0; n < npages; n++ ){
+    for ( m = 0; m < PAGE_SIZE ; m++ ){
+      char *address = (char *)(page_array[n]+m);
+      if (*address != checkvalue) {
+	sprintf(buf,"verify failed [0x%p] %d instead of %d\n", address, 
*address, checkvalue);
+	log_info(buf);
+	return 0;
+      }
+    }
+  }
+  return 1;
+}
+
+
+/* Parse command from message*/
+COMMANDS parse_command(const char* data,int size,const char** startOfData)
+{
+  char command[MAX_COMMANDSIZE];
+  memset(command,0,MAX_COMMANDSIZE);
+  COMMANDS retc;
+  int i=0;
+  for(;i < MAX_COMMANDSIZE && data[i] != ':';i++){
+    command[i] = data[i];
+  }
+  *startOfData = &data[i+1];
+
+  if (strcmp(command,"init") == 0){
+    if ((size-i-1) == 7){
+      retc = ninit;
+    }
+  }else if(strcmp(command,"random") == 0){
+    retc = nrandom;
+  }else if(strcmp(command,"srandom") == 0){
+    retc = nsrandom;
+  }else if(strcmp(command,"srverify") == 0){
+    retc = nsrverify;
+  }else if(strcmp(command,"fillzero") == 0){
+    retc = nfillzero;
+  }else if(strcmp(command,"fillvalue") == 0){
+    retc = nfillvalue;
+  }else if(strcmp(command,"verify") == 0){
+      retc = nverify;
+  }else if(strcmp(command,"exit") == 0){
+    retc = nexit;
+  }
+  return retc;
+}
+
+void daemon_loop(void **page_array, unsigned long npages, int socket)
+{
+  COMMANDS com = wrongcommad;
+  char csize[MAX_SIZESIZE+1];  //size max
+  memset(csize,0,MAX_SIZESIZE+1);
+  int end = 0;
+  while(!end){
+
+    /*Data
+    size:xxx:xxx;
+    */
+
+    //Read data size
+    char * data;
+    const char * startOfData = NULL;
+
+    int i = 0;
+    for (;(i <= MAX_SIZESIZE) && (csize[i-1] != ':');i++){
+      recv(socket,&csize[i],1,0);
+    }
+    if (i <= MAX_SIZESIZE) { //data is good
+      int size = atoi(csize)-1;
+      data = malloc(size*sizeof(char)+1);
+      int sz = 0;
+      while (sz < size)
+        sz += recv(socket,data+sz,size-sz,0);
+      if (data[size-1] == ';'){//Decode data
+        com = parse_command(data,size,&startOfData);
+      }
+    }
+
+    char buf[128];
+    switch(com){
+    case nfillzero: /* Zero all pages */
+      log_info("into zero mapped mode\n");
+      zero_pages(page_array, npages);
+      checkvalue = 0;
+      log_info("PASS: zero mapped mode\n");
+      break;
+    case nfillvalue: /* Zero all pages */
+      log_info("fill value statickey\n");
+      checkvalue = statickey;
+      value_to_pages(page_array, npages, checkvalue);
+      sprintf(buf,"PASS: filled by %c\n", statickey);
+      log_info(buf);
+      break;
+    case nrandom: /* Fill all pages with random number */
+      log_info("into random fill mode\n");
+      random_fill(page_array, npages);
+      checkvalue = -1;
+      log_info("PASS: filled by random value\n");
+      break;
+    case nexit: /* Do exit */
+      log_info("PASS: exit\n");
+      end = 1;
+      break;
+    case nverify: /* verify */
+      log_info("veriy value\n");
+
+      if (!verify_address_space(page_array,npages,checkvalue)){
+	sprintf(buf,"value %d verify error\n",checkvalue);
+	log_info(buf);
+	sprintf(buf,"FAIL: verification with checkvalue = %x\n", checkvalue);
+	log_info(buf);
+      }else{
+        sprintf(buf,"PASS: verification with checkvalue = %x\n", 
checkvalue);
+        log_info(buf);
+      }
+      break;
+    case nsrandom:/*Generate static random series*/
+      log_info("fill static random series\n");
+      clock_t starttime = clock();
+      static_random_fill(page_array, npages,BLOCK_COUNT);
+      clock_t endtime = clock();
+      sprintf(buf,"PASS: filling duration = %ld 
ms\n",(long)(1.0*(endtime-starttime))/(CLOCKS_PER_SEC/1000));
+      log_info(buf);
+      break;
+    case nsrverify: /* verify */
+      log_info("veriy value\n");
+
+      if (!static_random_verify(page_array,npages,BLOCK_COUNT)){
+        sprintf(buf,"value %d verify error\n",checkvalue);
+        log_info(buf);
+        log_info("FAIL: random series verification\n");
+      }else{
+        log_info("PASS: random series verification\n");
+      }
+      break;
+    case ninit:/*Parametrs*/
+      memset(buf,0,5);
+      log_info("Init daemon\n");
+      strncpy(buf,&startOfData[0],3);
+      statickey = atoi(buf);
+      strncpy(buf,&startOfData[3],3);
+      dynamickey = atoi(buf);
+      sprintf(buf,"PASS: Static key %d; Dynamic key 
%d\n",statickey,dynamickey);
+      log_info(buf);
+      break;
+    default:
+      log_info("FAIL: Wrong command!\n");
+      exit(EBADMSG);
+      break;
+    }
+    free(data);
+  }
+}
+
+int main(int argc,char *argv[])
+{
+  int n = 0;
+  unsigned long npages = 0;
+  int ret;
+  void **page_array = NULL;
+
+
+  void (*prev_fn)(int);
+
+  prev_fn = signal (SIGPIPE,sigpipe);
+
+
+  if (argc != 3){
+    fprintf(stderr,"Usage %s size(MB) port\n",argv[0]);
+    return -1;
+  }
+
+  port = atoi(argv[2]);
+  // Vytvoříme soket - viz minulý díl
+  if ((mainSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1)
+  {
+    fprintf(stderr,"Could not create socket!\n");
+    return -1;
+  }
+
+  sockName.sin_family = AF_INET;
+  sockName.sin_port = htons(port);
+  sockName.sin_addr.s_addr = INADDR_ANY;
+
+
+  if (bind(mainSocket, (struct sockaddr *)&sockName, sizeof(sockName)) 
== -1)
+  {
+    fprintf(stderr,"Could not bind socket!\n");
+    return -1;
+  }
+
+  if (listen(mainSocket, 1) == -1)
+  {
+    fprintf(stderr,"Could not listen socket!\n");
+    return -1;
+  }
+
+  unlink(FIFO_FILE);
+  unlink(LOG_FILE);
+  PAGE_SIZE = getpagesize();
+  intInPage = PAGE_SIZE/sizeof(int);
+  long page = atoi(argv[1]);
+  npages = (page * 1024 * 1024)/PAGE_SIZE;
+
+  ret = daemon(0,0);
+  if(ret == -1){
+    log_info("FAIL: failed to run in daemon mode\n");
+    return -1;
+  }
+
+  addrlen = sizeof(clientInfo);
+
+  clientSocket = accept(mainSocket, (struct sockaddr*)&clientInfo, 
&addrlen);
+  int set = 1;
+  setsockopt(clientSocket, SOL_SOCKET, SO_KEEPALIVE, (void *)&set, 
sizeof(int));
+  if (clientSocket == -1)
+  {
+    fprintf(stderr,"Could not connect client\n");
+    return -1;
+  }
+
+  log_info("Initialising zero mapped pages!\n");
+  page_array = map_zero_page(npages);
+  if (page_array == NULL){
+    log_info("FAIL: could not initialise maps\n");
+    return -1;
+  }
+  log_info("PASS: first start\n");
+
+  srand(getpid());
+  daemon_loop(page_array, npages, clientSocket);
+
+
+  log_info("Free page array\n");
+  for(n=0;n<npages;n++){
+    munmap(page_array[n],0);
+  }
+  free(page_array);
+
+  log_info("exit");
+
+  sleep(5);
+
+
+  char ch;
+  while (recv(clientSocket,&ch,1,0) > 0);
+
+  close(clientSocket);
+  close(mainSocket);
+
+  if (prev_fn==SIG_IGN) signal (SIGTERM,SIG_IGN);
+
+  return 0;
+}
+
+
-- 
1.6.2.5


  reply	other threads:[~2009-08-31  9:35 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-08-31  9:29 [KVM-AUTOTEST PATCH 0/2] Add KSM test Lukáš Doktor
2009-08-31  9:35 ` Lukáš Doktor [this message]
2009-09-01  8:49   ` [KVM-AUTOTEST PATCH 1/2] " Lukáš Doktor
2009-09-07 12:03   ` Dor Laor
2009-08-31  9:48 ` [KVM-AUTOTEST PATCH 2/2] " Lukáš Doktor
2009-09-01  8:50   ` Lukáš Doktor
2009-09-07 13:00   ` Dor Laor
2009-09-07 12:37 ` [KVM-AUTOTEST PATCH 0/2] " Uri Lublin
     [not found] <1785968988.186531253041095308.JavaMail.root@zmail05.collab.prod.int.phx2.redhat.com>
2009-09-15 18:58 ` [KVM-AUTOTEST PATCH 1/2] " Jiri Zupka
2009-09-16  8:56   ` Dor Laor
     [not found] <83259492.232221253106465155.JavaMail.root@zmail05.collab.prod.int.phx2.redhat.com>
2009-09-16 13:09 ` Jiri Zupka
2009-09-16 13:21   ` Dor Laor
     [not found] <830286859.775301253870289468.JavaMail.root@zmail05.collab.prod.int.phx2.redhat.com>
2009-09-25  9:22 ` Jiri Zupka
2009-09-29 15:50   ` Lucas Meneghel Rodrigues
2009-09-30 12:23     ` Dor Laor

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4A9B9956.9000209@redhat.com \
    --to=ldoktor@redhat.com \
    --cc=autotest@test.kernel.org \
    --cc=kvm@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).