diff mbox

[KVM-AUTOTEST,1/2] Add KSM test

Message ID 4A9CE027.9050701@redhat.com (mailing list archive)
State New, archived
Headers show

Commit Message

Lukáš Doktor Sept. 1, 2009, 8:49 a.m. UTC
I'm sorry but thunderbird apparently crippled the path. Resending as the 
attachment.
diff mbox

Patch

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;
+}
+
+