From mboxrd@z Thu Jan 1 00:00:00 1970 From: Dor Laor Subject: Re: [KVM-AUTOTEST PATCH 1/2] Add KSM test Date: Mon, 07 Sep 2009 15:03:52 +0300 Message-ID: <4AA4F6A8.5010609@redhat.com> References: <4A9B97E5.3000109@redhat.com> <4A9B9956.9000209@redhat.com> Reply-To: dlaor@redhat.com Mime-Version: 1.0 Content-Type: text/plain; charset=ISO-8859-2; format=flowed Content-Transfer-Encoding: QUOTED-PRINTABLE Cc: KVM list , Autotest mailing list To: =?ISO-8859-2?Q?Luk=E1=B9_Doktor?= Return-path: Received: from mx1.redhat.com ([209.132.183.28]:37552 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753054AbZIGMDs (ORCPT ); Mon, 7 Sep 2009 08:03:48 -0400 In-Reply-To: <4A9B9956.9000209@redhat.com> Sender: kvm-owner@vger.kernel.org List-ID: On 08/31/2009 12:35 PM, Luk=E1=B9 Doktor wrote: > allocator.c is a program, which allocates pages in the memory and all= ow > us to fill or test those pages. It's controlled using sockets. After a quick review I have the following questions: 1. Why did you implement the guest tool in 'c' and not in python? Python is much simpler and you can share some code with the server. This 'test protocol' would also be easier to understand this way. 2. IMHO there is no need to use select, you can do blocking read. 3. Also you can use plain malloc without the more complex ( a bit) mmap= =2E > > Signed-off-by: Luk=E1=B9 Doktor > Signed-off-by: Ji=F8=ED =AEupka > --- > 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/allocato= r.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 > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +//socket linux > +#include > +#include > +#include > +#include > +//TODO: socket windows > + > + > + > +#define PS (4096) > +long PAGE_SIZE =3D PS; > +long intInPage =3D 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 =3D -1; > +int base_fd =3D -1; > +int checkvalue =3D 0; > + > + > +//Socket > +struct sockaddr_in sockName; > +struct sockaddr_in clientInfo; > +int mainSocket,clientSocket; > +int port; > + > +socklen_t addrlen; > + > + > + > + > +const uint32_t random_mask =3D UINT32_MAX>>1; > +uint32_t random_x =3D 0; > +const uint32_t random_a =3D 1103515245; > +const uint32_t random_m =3D 2^32; > +const uint32_t random_c =3D 12345; > + > +int statickey =3D 0; > +int dynamickey =3D 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 =3D 0; > + while (sz< size) > + sz +=3D write(socket, data+sz, size-sz); > + return sz; > +} > + > + > +int write_message(int s,char * message){ > + size_t len =3D strlen(message); > + char buf[10]; > + sprintf(buf,"%d:",(unsigned int)len); > + size_t size =3D 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 =3D 0; > + tv.tv_usec =3D 100; > + int max =3D s+1; > + tv.tv_sec =3D 10; > + tv.tv_usec =3D 0; > + int ret =3D select(max, NULL,&writeset, NULL,&tv); > + if (ret =3D=3D -1) > + { > + return -1; > + } > + if (ret =3D=3D 0) > + { > + return -1; > + } > + if (FD_ISSET(s,&writeset)) > + { > + if (writefull(s, buf, size) !=3D size){ > + return -1; > + } > + if (writefull(s, message, len) !=3D len){ > + return -1; > + } > + } > + return 0; > +} > + > +void log_info(char *str) > +{ > + if (write_message(clientSocket, str) !=3D 0){ > + fprintf(stderr,"write error\n"); > + } > +} > + > +/* fill pages with zero */ > +void zero_pages(void **page_array,int npages) > +{ > + int n =3D 0; > + for(n=3D0;n + memset(page_array[n],0,intInPage); > +} > + > +/* fill pages with zero */ > +void value_to_pages(void **page_array,int npages,char value) > +{ > + int n =3D 0; > + for(n=3D0;n + memset(page_array[n],value,PAGE_SIZE/sizeof(char)); > +} > + > +/* initialise page_array */ > +void **map_zero_page(unsigned long npages) > +{ > + void **page_array=3D(void **)malloc(sizeof(void *)*npages); > + long n =3D 0; > + > + if ( page_array =3D=3D 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=3D0 ; n< npages; n++){ > + int i; > + void *addr=3D(void *)mmap(0,PAGE_SIZE,PROT_FLAGS,MAP_FLAGS,0,0); > + if ( addr =3D=3D MAP_FAILED ){ > + log_info("map failed!\n"); > + for (i=3D0;i + munmap( page_array[i], 0); > + free(page_array); > + return NULL; > + } > + > + page_array[n] =3D addr; > + } > +#endif > + > + void *addr =3D (void *)mmap(0,PAGE_SIZE*npages,PROT_FLAGS,MAP_FLAGS= ,0,0); > + if (addr =3D=3D MAP_FAILED){ > + log_info("FAIL: map failed!\n"); > + free(page_array); > + return NULL; > + } > + > + for (n=3D0;n + page_array[n] =3D 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 =3D 0; > + int value =3D 0; > + int offset =3D 0; > + void *addr =3D NULL; > + > + for( n =3D 0; n< npages; n++){ > + offset =3D rand() % (intInPage); > + value =3D rand(); > + addr =3D page_array[n] + offset; > + *((int *)addr) =3D value; > + } > +} > + > + > +/*set random series seed*/ > +void mrseed(int seed){ > + random_x =3D seed; > +} > + > +/*Generate random number*/ > +int mrand(){ > + random_x =3D random_a*random_x+random_c; > + return random_x& random_mask; > +} > + > +/* Generate randomcode array*/ > +int* random_code_array(int nblock) > +{ > + int * randArray =3D malloc(PAGE_SIZE*nblock); > + int n =3D 0; > + for (;n< nblock;n++){ > + int i =3D 0; > + for (;i< intInPage;i++){ > + randArray[n*intInPage+i]=3Dmrand(); > + } > + } > + 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 =3D random_code_array(nblock); > + int n =3D 0; > + int q =3D -1; > + int blocksize =3D npages/nblock; > + int offset =3D 0; > + void *addr =3D NULL; > + > + mrseed(randomArray[0]); > + for (;n< npages;n++){ > + if (n%(blocksize) =3D=3D 0) q++; > + memcpy(page_array[n],&randomArray[q*intInPage],PAGE_SIZE); > + offset =3D mrand() % (intInPage); > + addr =3D ((int *)page_array[n]) + offset; > + *((int *)addr) =3D 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 =3D malloc(PAGE_SIZE); > + mrseed(dynamickey); > + int* randomArray =3D random_code_array(nblock); > + int n =3D 0; > + int q =3D -1; > + int blocksize =3D npages/nblock; > + int offset =3D 0; > + void *addr =3D NULL; > + char buf[128]; > + > + int ret =3D 1; > + > + mrseed(randomArray[0]); > + for (;n< npages;n++){ > + if (n%(blocksize) =3D=3D 0) q++; > + memcpy(p,&randomArray[q*intInPage],PAGE_SIZE); > + offset =3D mrand() % (intInPage); > + p[offset] =3D n; > + addr =3D ((int*)page_array[n]) + offset; > + int r =3D memcmp(p,page_array[n],PAGE_SIZE); > + if (r !=3D 0){ > + for (r =3D 0;r< intInPage;r++){ > + addr =3D ((int *)page_array[n]) + r; > + if (*((int *)addr) !=3D p[r]){ > + sprintf(buf,"verify failed [0x%p] %d instead of > %d\n",addr,*((int *)addr),n); > + log_info(buf); > + ret =3D 0; > + } > + } > + } > + } > + free(randomArray); > + free(p); > + return ret; > +} > + > + > +/* verify value */ > +int verify_address_space(void **page_array, unsigned long npages, in= t > checkvalue) > +{ > + int m,n; > + char buf[128]; > + sprintf(buf,"verify value =3D %d\n",checkvalue); > + log_info(buf); > + if ( checkvalue =3D=3D -1 ){ > + return 1; > + } > + for( n =3D 0; n< npages; n++ ){ > + for ( m =3D 0; m< PAGE_SIZE ; m++ ){ > + char *address =3D (char *)(page_array[n]+m); > + if (*address !=3D 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** startO= fData) > +{ > + char command[MAX_COMMANDSIZE]; > + memset(command,0,MAX_COMMANDSIZE); > + COMMANDS retc; > + int i=3D0; > + for(;i< MAX_COMMANDSIZE&& data[i] !=3D ':';i++){ > + command[i] =3D data[i]; > + } > + *startOfData =3D&data[i+1]; > + > + if (strcmp(command,"init") =3D=3D 0){ > + if ((size-i-1) =3D=3D 7){ > + retc =3D ninit; > + } > + }else if(strcmp(command,"random") =3D=3D 0){ > + retc =3D nrandom; > + }else if(strcmp(command,"srandom") =3D=3D 0){ > + retc =3D nsrandom; > + }else if(strcmp(command,"srverify") =3D=3D 0){ > + retc =3D nsrverify; > + }else if(strcmp(command,"fillzero") =3D=3D 0){ > + retc =3D nfillzero; > + }else if(strcmp(command,"fillvalue") =3D=3D 0){ > + retc =3D nfillvalue; > + }else if(strcmp(command,"verify") =3D=3D 0){ > + retc =3D nverify; > + }else if(strcmp(command,"exit") =3D=3D 0){ > + retc =3D nexit; > + } > + return retc; > +} > + > +void daemon_loop(void **page_array, unsigned long npages, int socket= ) > +{ > + COMMANDS com =3D wrongcommad; > + char csize[MAX_SIZESIZE+1]; //size max > + memset(csize,0,MAX_SIZESIZE+1); > + int end =3D 0; > + while(!end){ > + > + /*Data > + size:xxx:xxx; > + */ > + > + //Read data size > + char * data; > + const char * startOfData =3D NULL; > + > + int i =3D 0; > + for (;(i<=3D MAX_SIZESIZE)&& (csize[i-1] !=3D ':');i++){ > + recv(socket,&csize[i],1,0); > + } > + if (i<=3D MAX_SIZESIZE) { //data is good > + int size =3D atoi(csize)-1; > + data =3D malloc(size*sizeof(char)+1); > + int sz =3D 0; > + while (sz< size) > + sz +=3D recv(socket,data+sz,size-sz,0); > + if (data[size-1] =3D=3D ';'){//Decode data > + com =3D 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 =3D 0; > + log_info("PASS: zero mapped mode\n"); > + break; > + case nfillvalue: /* Zero all pages */ > + log_info("fill value statickey\n"); > + checkvalue =3D 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 =3D -1; > + log_info("PASS: filled by random value\n"); > + break; > + case nexit: /* Do exit */ > + log_info("PASS: exit\n"); > + end =3D 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 =3D %x\n", checkval= ue); > + log_info(buf); > + }else{ > + sprintf(buf,"PASS: verification with checkvalue =3D %x\n", > checkvalue); > + log_info(buf); > + } > + break; > + case nsrandom:/*Generate static random series*/ > + log_info("fill static random series\n"); > + clock_t starttime =3D clock(); > + static_random_fill(page_array, npages,BLOCK_COUNT); > + clock_t endtime =3D clock(); > + sprintf(buf,"PASS: filling duration =3D %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 =3D atoi(buf); > + strncpy(buf,&startOfData[3],3); > + dynamickey =3D 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 =3D 0; > + unsigned long npages =3D 0; > + int ret; > + void **page_array =3D NULL; > + > + > + void (*prev_fn)(int); > + > + prev_fn =3D signal (SIGPIPE,sigpipe); > + > + > + if (argc !=3D 3){ > + fprintf(stderr,"Usage %s size(MB) port\n",argv[0]); > + return -1; > + } > + > + port =3D atoi(argv[2]); > + // Vytvo=F8=EDme soket - viz minul=FD d=EDl > + if ((mainSocket =3D socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) =3D= =3D -1) > + { > + fprintf(stderr,"Could not create socket!\n"); > + return -1; > + } > + > + sockName.sin_family =3D AF_INET; > + sockName.sin_port =3D htons(port); > + sockName.sin_addr.s_addr =3D INADDR_ANY; > + > + > + if (bind(mainSocket, (struct sockaddr *)&sockName, sizeof(sockName= )) > =3D=3D -1) > + { > + fprintf(stderr,"Could not bind socket!\n"); > + return -1; > + } > + > + if (listen(mainSocket, 1) =3D=3D -1) > + { > + fprintf(stderr,"Could not listen socket!\n"); > + return -1; > + } > + > + unlink(FIFO_FILE); > + unlink(LOG_FILE); > + PAGE_SIZE =3D getpagesize(); > + intInPage =3D PAGE_SIZE/sizeof(int); > + long page =3D atoi(argv[1]); > + npages =3D (page * 1024 * 1024)/PAGE_SIZE; > + > + ret =3D daemon(0,0); > + if(ret =3D=3D -1){ > + log_info("FAIL: failed to run in daemon mode\n"); > + return -1; > + } > + > + addrlen =3D sizeof(clientInfo); > + > + clientSocket =3D accept(mainSocket, (struct sockaddr*)&clientInfo, > &addrlen); > + int set =3D 1; > + setsockopt(clientSocket, SOL_SOCKET, SO_KEEPALIVE, (void *)&set, > sizeof(int)); > + if (clientSocket =3D=3D -1) > + { > + fprintf(stderr,"Could not connect client\n"); > + return -1; > + } > + > + log_info("Initialising zero mapped pages!\n"); > + page_array =3D map_zero_page(npages); > + if (page_array =3D=3D 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=3D0;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=3D=3DSIG_IGN) signal (SIGTERM,SIG_IGN); > + > + return 0; > +} > + > +