cmparenas.c 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  1. /*
  2. * This file is part of the UCB release of Plan 9. It is subject to the license
  3. * terms in the LICENSE file found in the top-level directory of this
  4. * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
  5. * part of the UCB release of Plan 9, including this file, may be copied,
  6. * modified, propagated, or distributed except according to the terms contained
  7. * in the LICENSE file.
  8. */
  9. #include "stdinc.h"
  10. #include "dat.h"
  11. #include "fns.h"
  12. static int verbose;
  13. static int fd;
  14. static int fd1;
  15. static uint8_t *data;
  16. static uint8_t *data1;
  17. static int blocksize;
  18. static int sleepms;
  19. void
  20. usage(void)
  21. {
  22. fprint(2, "usage: cmparenas [-b blocksize] [-s ms] [-v] arenapart1 arenapart2 [name...]]\n");
  23. threadexitsall(0);
  24. }
  25. static int
  26. preadblock(int fd, uint8_t *buf, int n, int64_t off)
  27. {
  28. int nr, m;
  29. for(nr = 0; nr < n; nr += m){
  30. m = n - nr;
  31. m = pread(fd, &buf[nr], m, off+nr);
  32. if(m <= 0){
  33. if(m == 0)
  34. werrstr("early eof");
  35. return -1;
  36. }
  37. }
  38. return 0;
  39. }
  40. static int
  41. readblock(int fd, uint8_t *buf, int n)
  42. {
  43. int nr, m;
  44. for(nr = 0; nr < n; nr += m){
  45. m = n - nr;
  46. m = read(fd, &buf[nr], m);
  47. if(m <= 0){
  48. if(m == 0)
  49. werrstr("early eof");
  50. return -1;
  51. }
  52. }
  53. return 0;
  54. }
  55. static int
  56. printheader(char *name, ArenaHead *head, int fd)
  57. {
  58. Arena arena;
  59. int64_t baseoff, lo, hi, off;
  60. int clumpmax;
  61. off = seek(fd, 0, 1);
  62. seek(fd, off + head->size - head->blocksize, 0);
  63. if(readblock(fd, data, head->blocksize) < 0){
  64. fprint(2, "%s: reading arena tail: %r\n", name);
  65. return -1;
  66. }
  67. seek(fd, off, 0);
  68. memset(&arena, 0, sizeof arena);
  69. if(unpackarena(&arena, data) < 0){
  70. fprint(2, "%s: unpack arena tail: %r\n", name);
  71. return -1;
  72. }
  73. arena.blocksize = head->blocksize;
  74. arena.base = off + head->blocksize;
  75. arena.clumpmax = arena.blocksize / ClumpInfoSize;
  76. arena.size = head->size - 2*head->blocksize;
  77. fprint(2, "%s: base=%llx size=%llx blocksize=%x\n", name, off, head->size, head->blocksize);
  78. baseoff = head->blocksize;
  79. fprint(2, "\t%llx-%llx: head\n", (int64_t)0, baseoff);
  80. lo = baseoff;
  81. hi = baseoff + arena.diskstats.used;
  82. fprint(2, "\t%llx-%llx: data (%llx)\n", lo, hi, hi - lo);
  83. hi = head->size - head->blocksize;
  84. clumpmax = head->blocksize / ClumpInfoSize;
  85. if(clumpmax > 0)
  86. lo = hi - (uint64_t)arena.diskstats.clumps/clumpmax * head->blocksize;
  87. else
  88. lo = hi;
  89. fprint(2, "\t%llx-%llx: clumps (%llx)\n", lo, hi, hi - lo);
  90. fprint(2, "\t%llx-%llx: tail\n", hi, hi + head->blocksize);
  91. fprint(2, "arena:\n");
  92. printarena(2, &arena);
  93. return 0;
  94. }
  95. static void
  96. cmparena(char *name, int64_t len)
  97. {
  98. ArenaHead head;
  99. DigestState s;
  100. uint64_t n, e;
  101. uint32_t bs;
  102. int i, j;
  103. char buf[20];
  104. fprint(2, "cmp %s\n", name);
  105. memset(&s, 0, sizeof s);
  106. /*
  107. * read a little bit, which will include the header
  108. */
  109. if(readblock(fd, data, HeadSize) < 0){
  110. fprint(2, "%s: reading header: %r\n", name);
  111. return;
  112. }
  113. if(unpackarenahead(&head, data) < 0){
  114. fprint(2, "%s: corrupt arena header: %r\n", name);
  115. return;
  116. }
  117. if(head.version != ArenaVersion4 && head.version != ArenaVersion5)
  118. fprint(2, "%s: warning: unknown arena version %d\n", name, head.version);
  119. if(len != 0 && len != head.size)
  120. fprint(2, "%s: warning: unexpected length %lld != %lld\n", name, head.size, len);
  121. if(strcmp(name, "<stdin>") != 0 && strcmp(head.name, name) != 0)
  122. fprint(2, "%s: warning: unexpected name %s\n", name, head.name);
  123. if(readblock(fd1, data1, HeadSize) < 0){
  124. fprint(2, "%s: reading header: %r\n", name);
  125. return;
  126. }
  127. if(unpackarenahead(&head, data) < 0){
  128. fprint(2, "%s: corrupt arena header: %r\n", name);
  129. return;
  130. }
  131. if(head.version != ArenaVersion4 && head.version != ArenaVersion5)
  132. fprint(2, "%s: warning: unknown arena version %d\n", name, head.version);
  133. if(len != 0 && len != head.size)
  134. fprint(2, "%s: warning: unexpected length %lld != %lld\n", name, head.size, len);
  135. if(strcmp(name, "<stdin>") != 0 && strcmp(head.name, name) != 0)
  136. fprint(2, "%s: warning: unexpected name %s\n", name, head.name);
  137. seek(fd, -HeadSize, 1);
  138. seek(fd1, -HeadSize, 1);
  139. if(printheader(name, &head, fd) < 0)
  140. return;
  141. /*
  142. * now we know how much to read
  143. * read everything but the last block, which is special
  144. */
  145. e = head.size;
  146. bs = blocksize;
  147. for(n = 0; n < e; n += bs){
  148. if(n + bs > e)
  149. bs = e - n;
  150. if(readblock(fd, data, bs) < 0){
  151. fprint(2, "%s: read data: %r\n", name);
  152. return;
  153. }
  154. if(readblock(fd1, data1, bs) < 0){
  155. fprint(2, "%s: read data: %r\n", name);
  156. return;
  157. }
  158. if(memcmp(data, data1, bs) != 0){
  159. print("mismatch at %llx\n", n);
  160. for(i=0; i<bs; i+=16){
  161. if(memcmp(data+i, data1+i, 16) != 0){
  162. snprint(buf, sizeof buf, "%llx", n+i);
  163. print("%s ", buf);
  164. for(j=0; j<16; j++){
  165. print(" %.2ux", data[i+j]);
  166. if(j == 7)
  167. print(" -");
  168. }
  169. print("\n");
  170. print("%*s ", (int)strlen(buf), "");
  171. for(j=0; j<16; j++){
  172. print(" %.2ux", data1[i+j]);
  173. if(j == 7)
  174. print(" -");
  175. }
  176. print("\n");
  177. }
  178. }
  179. }
  180. }
  181. }
  182. static int
  183. shouldcheck(char *name, char **s, int n)
  184. {
  185. int i;
  186. if(n == 0)
  187. return 1;
  188. for(i=0; i<n; i++){
  189. if(s[i] && strcmp(name, s[i]) == 0){
  190. s[i] = nil;
  191. return 1;
  192. }
  193. }
  194. return 0;
  195. }
  196. char *
  197. readap(int fd, ArenaPart *ap)
  198. {
  199. char *table;
  200. if(preadblock(fd, data, 8192, PartBlank) < 0)
  201. sysfatal("read arena part header: %r");
  202. if(unpackarenapart(ap, data) < 0)
  203. sysfatal("corrupted arena part header: %r");
  204. fprint(2, "# arena part version=%d blocksize=%d arenabase=%d\n",
  205. ap->version, ap->blocksize, ap->arenabase);
  206. ap->tabbase = (PartBlank+HeadSize+ap->blocksize-1)&~(ap->blocksize-1);
  207. ap->tabsize = ap->arenabase - ap->tabbase;
  208. table = malloc(ap->tabsize+1);
  209. if(preadblock(fd, (uint8_t*)table, ap->tabsize, ap->tabbase) < 0)
  210. sysfatal("reading arena part directory: %r");
  211. table[ap->tabsize] = 0;
  212. return table;
  213. }
  214. void
  215. threadmain(int argc, char *argv[])
  216. {
  217. int i, nline;
  218. char *p, *q, *table, *table1, *f[10], line[256];
  219. vlong start, stop;
  220. ArenaPart ap;
  221. ArenaPart ap1;
  222. ventifmtinstall();
  223. blocksize = MaxIoSize;
  224. ARGBEGIN{
  225. case 'b':
  226. blocksize = unittoull(EARGF(usage()));
  227. break;
  228. case 's':
  229. sleepms = atoi(EARGF(usage()));
  230. break;
  231. case 'v':
  232. verbose++;
  233. break;
  234. default:
  235. usage();
  236. break;
  237. }ARGEND
  238. if(argc < 2)
  239. usage();
  240. data = vtmalloc(blocksize);
  241. data1 = vtmalloc(blocksize);
  242. if((fd = open(argv[0], OREAD)) < 0)
  243. sysfatal("open %s: %r", argv[0]);
  244. if((fd1 = open(argv[1], OREAD)) < 0)
  245. sysfatal("open %s: %r", argv[0]);
  246. table = readap(fd, &ap);
  247. table1 = readap(fd1, &ap1);
  248. if(strcmp(table, table1) != 0)
  249. sysfatal("arena partitions do not have identical tables");
  250. nline = atoi(table);
  251. p = strchr(table, '\n');
  252. if(p)
  253. p++;
  254. for(i=0; i<nline; i++){
  255. if(p == nil){
  256. fprint(2, "warning: unexpected arena table end\n");
  257. break;
  258. }
  259. q = strchr(p, '\n');
  260. if(q)
  261. *q++ = 0;
  262. if(strlen(p) >= sizeof line){
  263. fprint(2, "warning: long arena table line: %s\n", p);
  264. p = q;
  265. continue;
  266. }
  267. strcpy(line, p);
  268. memset(f, 0, sizeof f);
  269. if(tokenize(line, f, nelem(f)) < 3){
  270. fprint(2, "warning: bad arena table line: %s\n", p);
  271. p = q;
  272. continue;
  273. }
  274. p = q;
  275. if(shouldcheck(f[0], argv+1, argc-1)){
  276. start = strtoull(f[1], 0, 0);
  277. stop = strtoull(f[2], 0, 0);
  278. if(stop <= start){
  279. fprint(2, "%s: bad start,stop %lld,%lld\n", f[0], stop, start);
  280. continue;
  281. }
  282. if(seek(fd, start, 0) < 0)
  283. fprint(2, "%s: seek to start: %r\n", f[0]);
  284. if(seek(fd1, start, 0) < 0)
  285. fprint(2, "%s: seek to start: %r\n", f[0]);
  286. cmparena(f[0], stop - start);
  287. }
  288. }
  289. for(i=2; i<argc; i++)
  290. if(argv[i] != 0)
  291. fprint(2, "%s: did not find arena\n", argv[i]);
  292. threadexitsall(nil);
  293. }