/* mergecompletely offset reads size Purpose: Test caching and tlb-limitations Try to merge an area of size bytes completely. Then, perform bytereads/size many reads on it. This example shows that m_merge can be used independently of the two other calls, if we know what we want. */ #include #include #include #include #include #include /* mergetwo pid1 pid2 */ #define ERROREXIT(msg) ( fprintf(stderr,"%s:%d: %s\n",__FILE__,__LINE__,msg), exit(1) ) static time_t lastusertimems, lastsystemtimems; static time_t rep(void) { struct tms buf; time_t udiffms, sdiffms; times(&buf); udiffms = buf.tms_utime-lastusertimems; sdiffms = buf.tms_stime-lastsystemtimems; printf("delta s=%ldms, u=%ldms: ",sdiffms,udiffms); lastusertimems = buf.tms_utime; lastsystemtimems = buf.tms_stime; return udiffms; } #define vtalloc(nel, type) ((type*)valloc(nel*sizeof(type))) #define talloc(nel, type) ((type*)calloc(nel,sizeof(type))) size_t readthrough ( unsigned char * area, size_t offset, size_t reads, size_t size ) { size_t sum = 0, i, j = 0; for (i = 0; i < reads; i++) { sum += area[j]; j+= offset; if ( j > size ) j = 0; } return sum; } void dosimpleioctl(void); /* semiexported */ int main(const int argc, const char * const argv[]) { pid_t pid; int retval; size_t offset, reads, size, i, nel, suma, sumb; unsigned char *area; const unsigned char *page; MEQUALPAIR *eps; MPAGEINFO *is; time_t ta, tb; if (argc != 4) ERROREXIT("mergecompletely "); offset = atol(argv[1]); reads = atol(argv[2]); size = atol(argv[3]); rep(),printf("This is mergecompletely testing %.2fMb of memory\n", ((float)size)/(1024*1024)); area = vtalloc(size,unsigned char); if (area == NULL) ERROREXIT("no more memory"); rep(),printf("initializing memory...\n"); for (i = 0; i < size; i++) area[i] = 77; rep(),printf("now reading tru...\n"); suma = readthrough(area, offset, reads, size); ta = rep(),printf("read\n"); eps = talloc(size/offset+1, MEQUALPAIR); is = talloc(size/offset+1, MPAGEINFO); if (eps == NULL) ERROREXIT("no more memory"); pid = getpid(); /* now merge the pages, assuming that offset is the size to merge */ i = 0; { const void * lastdest = area; for ( page = area+offset; page < area+size; page+=offset ) { const int goodmerge = (1==1); eps[i].spid = eps[i].dpid = pid; is[i].v_addr = page; if (goodmerge) { eps[i].sv_addr = page; eps[i].dv_addr = lastdest; lastdest = page; /* as long as all merges are succesfully completed, this last assignment is not strictly needed. But it is more robust, in the case some pages are not equal! */ } else { /* This will merge a single page only! Moving it from mapping to mapping */ eps[i].sv_addr = lastdest; eps[i].dv_addr = page; } i++; } } nel = i; rep(),printf("now built in hashing ...\n"); retval = m_hashpages(pid, is,nel, NULL); if ( retval == - 1 ) ERROREXIT(strerror(errno)); rep(),printf("and now library hashing ...\n"); retval = m_hashpages(pid, is,nel, m_libhash_addrothalf); if ( retval == -1 ) ERROREXIT(strerror(errno)); rep(),printf("again built in hashing ...\n"); retval = m_hashpages(pid, is,nel, NULL); if ( retval == - 1 ) ERROREXIT(strerror(errno)); rep(),printf("now issuing m_merge...\n"); retval = m_merge(eps, nel); if (retval == -1) ERROREXIT(strerror(errno)); rep();printf("m_merge merged %d pages from %d requests...\n",retval,nel); if (retval != nel) { for (i = 0 ; i < nel; i++) if (eps[i].status != 0) { printf("eps[%d] == { %d, %p, %d, %p, %d }\n", i, eps[i].spid, eps[i].sv_addr, eps[i].dpid, eps[i].dv_addr, eps[i].status ); if ( i == nel -1) printf("The last page was not merged, but that's ok\n"); } } rep(),printf("now reading tru...\n"); sumb = readthrough(area, offset, reads, size); tb = rep(),printf("read\n"); if (suma != sumb) ERROREXIT("the sums are not equal!"); if (1==2) { rep(),printf("now sleeping so you can check my memory\n"); sleep(10); } rep(),printf("now built in hashing ...\n"); retval = m_hashpages(pid, is,nel, NULL); if ( retval == - 1 ) ERROREXIT(strerror(errno)); rep(),printf("and now library hashing ...\n"); retval = m_hashpages(pid, is,nel, m_libhash_addrothalf); if ( retval == -1 ) ERROREXIT(strerror(errno)); rep(),printf("and now stupid library hashing ...\n"); retval = m_hashpages(pid, is,nel, m_libhash_const); if ( retval == -1 ) ERROREXIT(strerror(errno)); rep(),printf("again built in hashing ...\n"); retval = m_hashpages(pid, is,nel, NULL); if ( retval == - 1 ) ERROREXIT(strerror(errno)); rep(),printf("now issuing m_merge a second time...\n"); retval = m_merge(eps, nel); if (retval == -1) ERROREXIT(strerror(errno)); rep();printf("m_merge merged %d pages from %d requests...\n",retval,nel); nel *= 10; rep(),printf("now issuing %d ioctls\n", nel); for (i = 0; i < nel; i++) dosimpleioctl(); rep(),printf("now issuing %d getpids\n", nel); for (i = 0; i < nel; i++) getpid(); rep(),printf("finished\n"); { float speedup = (float)ta/(float)tb; printf("speedup = %ldms/%ldms = %.2f, ", ta, tb, speedup); if ( speedup < 1.02 ) printf("naa - this wasn't fine, maybe better sequence for m_merge or tlb problems\n"); else if ( speedup > 1.20 ) printf("yeah! That's what mmlib is for!\n"); else printf("could be better, maybe we are in this tlb trashing\n"); } return 0; }