* configure.ac: New switch for disabling -O2 (--disable-optimizations).
[cacao.git] / contrib / vmlog / vmlogdiff.c
1 /* vmlog - high-speed logging for free VMs                  */
2 /* Copyright (C) 2006 Edwin Steiner <edwin.steiner@gmx.net> */
3
4 /* This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17  */
18
19 #include "vmlog.h"
20 #include <string.h>
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include <stdarg.h>
24 #include <assert.h>
25 #include <errno.h>
26 #include <fcntl.h>
27 #include <unistd.h>
28 #include <getopt.h>
29 #include <sys/stat.h>
30 #include <sys/mman.h>
31
32 #define VMLOGDIFF_RINGBUF_SIZE 1024*1024
33 #define VMLOGDIFF_PREFETCH 256
34
35
36 #if 0
37 #define LOG(args) printf args
38 #else
39 #define LOG(args)
40 #endif
41
42 typedef struct vmlogdiff_removed vmlogdiff_removed;
43
44 struct vmlogdiff_removed {
45         vmlog_seq_t start;
46         vmlog_seq_t len;
47 };
48
49 char *opt_prefix;
50 char *opt_fname[2];
51 int opt_verbose = 0;
52 int opt_context = 10;
53
54 char *g_idxfname;
55 char *g_strfname;
56 char *g_cleanedfname[2] = { "vmlogdiff.A.clean", "vmlogdiff.B.clean" };
57 char *g_removedfname[2] = { "vmlogdiff.A.removed", "vmlogdiff.B.removed" };
58 int g_idxlen;
59 int g_strlen;
60 int g_nstrings;
61 char *g_indentation = "    ";
62 vmlog_seq_t g_context_available = 0;
63 vmlog_seq_t g_context_requested = 0;
64
65 vmlog_string_entry *g_idxmap;
66 char *g_strmap;
67 vmlogdiff_removed *g_removedmap[2];
68 vmlogdiff_removed *g_removedptr[2];
69 vmlogdiff_removed *g_removedend[2];
70 int g_removedlen[2];
71 int g_nremoved[2];
72 vmlog_seq_t g_showseq[2] = { 0 };
73
74 int g_level = 0;
75
76 vmlog_ringbuf *g_ringbuf[2] = { NULL };
77 vmlog_ringbuf *g_ringbuf_back[2] = { NULL };
78 vmlog_ringbuf *g_ringbuf_show[2] = { NULL };
79 vmlog_ringbuf *g_ringbuf_orig[2] = { NULL };
80
81 const char *usage = 
82 "Usage: vmlogdiff [options] prefix fileA fileB\n"
83 "\n"
84 "    Options:\n"
85 "        -h      display this help message\n"
86 "        -v      verbose messages to stderr\n"
87 "\n";
88
89 /* global variables for diff algorithm */
90
91 vmlog_seq_t g_n[2];
92 vmlog_seq_t *g_Vforw_buf = NULL;
93 vmlog_seq_t *g_Vback_buf = NULL;
94 vmlog_seq_t *g_Vforw = NULL;
95 vmlog_seq_t *g_Vback = NULL;
96 int g_maxD;
97 int g_Vsize = 0;
98
99 char *g_index_used = NULL;
100
101 static void compare(vmlog_seq_t xstart,vmlog_seq_t ystart,vmlog_seq_t xend,vmlog_seq_t yend);
102         
103 static void diff_alloc(int maxD)
104 {
105         assert(maxD >= 0);
106
107         if (g_Vsize) {
108                 VMLOG_FREE_ARRAY(vmlog_seq_t,g_Vsize,g_Vforw_buf);
109                 VMLOG_FREE_ARRAY(vmlog_seq_t,g_Vsize,g_Vback_buf);
110         }
111
112         g_maxD = maxD;
113         g_Vsize = 2 * g_maxD + 1;
114
115         g_Vforw_buf = VMLOG_NEW_ARRAY(vmlog_seq_t,g_Vsize);
116         g_Vback_buf = VMLOG_NEW_ARRAY(vmlog_seq_t,g_Vsize);
117
118         g_Vforw = g_Vforw_buf + g_maxD;
119         g_Vback = g_Vback_buf + g_maxD;
120 }
121
122 void parse_command_line(int argc,char **argv)
123 {
124         int r;
125
126         while (1) {
127                 r = getopt(argc,argv,"hv");
128                 if (r == -1)
129                         break;
130                 switch (r) {
131                         case 'h':
132                                 vmlog_die_usage(usage,0);
133
134                         case 'v':
135                                 opt_verbose++;
136                                 break;
137
138                         case '?':
139                                 vmlog_die_usage(usage,1);
140                 }
141         }
142
143         if (argc - optind < 3)
144                 vmlog_die_usage(usage,1);
145         
146         opt_prefix = argv[optind++];
147         opt_fname[0] = argv[optind++];
148         opt_fname[1] = argv[optind++];
149 }
150
151 static void fprint_string(FILE *file,int index)
152 {
153         char *str;
154         vmlog_string_entry *strent;
155         char *buf;
156
157         strent = g_idxmap + index;
158         str = g_strmap + strent->ofs;
159
160         buf = VMLOG_NEW_ARRAY(char,strent->len+1);
161
162         memcpy(buf,str,strent->len);
163         buf[strent->len] = 0;
164
165         fputs(buf,file);
166         
167         VMLOG_FREE_ARRAY(char,strent->len+1,buf);
168 }
169
170 static void dump_log_entry(vmlog_log_entry *logent,int depth)
171 {
172 #if 0
173         fprintf(stdout,"%d",depth);
174         fputc(':',stdout);
175         if (depth < 100) {
176                 fputc(' ',stdout);
177                 if (depth < 10)
178                         fputc(' ',stdout);
179         }
180         for (i=0; i<depth; ++i)
181                 fputs(g_indentation,stdout);
182 #endif
183         switch(logent->tag) {
184                 case VMLOG_TAG_ENTER: fputs("enter ",stdout); break;
185                 case VMLOG_TAG_LEAVE: fputs("leave ",stdout); break;
186                 case VMLOG_TAG_THROW: fputs("throw ",stdout); break;
187                 case VMLOG_TAG_CATCH: fputs("catch ",stdout); break;
188                 case VMLOG_TAG_UNWND: fputs("unwnd ",stdout); break;
189         }
190         fprint_string(stdout,logent->index);
191         fputs("\n",stdout);
192 }
193
194 static void show_context(void)
195 {
196         int len;
197         vmlog_log_entry *logent;
198         vmlog_seq_t skipped;
199
200         if (g_context_available > 2*opt_context) {
201                 skipped = g_context_available - 2*opt_context;
202                 printf("@@ " VMLOG_SEQ_FMT " common entr%s skipped @@\n",skipped,(skipped > 1) ? "ies" : "y");
203                 g_context_available = opt_context;
204         }
205         
206         len = opt_context;
207         if (len > g_context_available) {
208                 len = g_context_available;
209         }
210
211         if (len <= 0)
212                 return;
213
214         vmlog_ringbuf_seek(g_ringbuf_show[0],g_ringbuf_show[0]->seq - len);
215         while (len-- && (logent = vmlog_ringbuf_next(g_ringbuf_show[0],VMLOGDIFF_PREFETCH))) {
216                 fputc(' ',stdout);
217                 dump_log_entry(logent,0);
218                 g_context_available--;
219         }
220 }
221
222 static void handle_unmatchable(int which,vmlogdiff_removed *rm)
223 {
224         int i;
225         vmlog_log_entry *logent;
226         
227         LOG(("unmatchable, only in %d: ofs=%lld len=%lld\n",which,rm->start,rm->len));
228
229         assert(rm->len);
230
231         show_context();
232
233         vmlog_ringbuf_seek(g_ringbuf_orig[which],rm->start);
234         for (i=0; i<rm->len; ++i) {
235                 logent = vmlog_ringbuf_next(g_ringbuf_orig[which],1 /* XXX */);
236                 fputc((which) ? '+' : '-',stdout);
237                 dump_log_entry(logent,0);
238         }
239
240         g_context_requested = opt_context;
241         g_context_available = 0;
242 }
243
244 static void handle_common(vmlog_seq_t xstart,vmlog_seq_t ystart,vmlog_seq_t len)
245 {
246         int i;
247         int j;
248         vmlog_log_entry *logent;
249         
250         LOG(("common: x=%lld y=%lld len=%lld\n",xstart,ystart,len));
251
252         vmlog_ringbuf_seek(g_ringbuf_show[0],xstart);
253         for (i=0; i<len; ++i) {
254                 for (j=0; j<2; ++j) {
255                         if (g_removedptr[j] < g_removedend[j] && g_showseq[j] == g_removedptr[j]->start) {
256                                 handle_unmatchable(j,g_removedptr[j]);
257                                 g_showseq[j] += g_removedptr[j]->len;
258                                 g_removedptr[j]++;
259                         }
260                 }
261                 
262                 logent = vmlog_ringbuf_next(g_ringbuf_show[0],VMLOGDIFF_PREFETCH);
263                 if (g_context_requested) {
264                         fputc(' ',stdout);
265                         dump_log_entry(logent,0);
266                         g_context_requested--;
267                         assert(!g_context_available);
268                 }
269                 else {
270                         g_context_available++;
271                 }
272
273                 g_showseq[0]++;
274                 g_showseq[1]++;
275         }
276 }
277
278 static void handle_only_in(int which,vmlog_seq_t start,vmlog_seq_t len)
279 {
280         int i;
281         vmlog_log_entry *logent;
282         
283         LOG(("only in %d: ofs=%lld len=%lld\n",which,start,len));
284
285         assert(len);
286
287         show_context();
288
289         vmlog_ringbuf_seek(g_ringbuf_show[which],start);
290         for (i=0; i<len; ++i) {
291                 if (g_removedptr[which] < g_removedend[which] && g_showseq[which] == g_removedptr[which]->start) {
292                         handle_unmatchable(which,g_removedptr[which]);
293                         g_showseq[which] += g_removedptr[which]->len;
294                         g_removedptr[which]++;
295                 }
296                 logent = vmlog_ringbuf_next(g_ringbuf_show[which],1 /* XXX */);
297                 fputc((which) ? '+' : '-',stdout);
298                 dump_log_entry(logent,0);
299
300                 g_showseq[which]++;
301         }
302
303         g_context_requested = opt_context;
304         g_context_available = 0;
305 }
306
307 static vmlog_seq_t match_forward(vmlog_seq_t x,vmlog_seq_t y,vmlog_seq_t xend,vmlog_seq_t yend)
308 {
309         vmlog_log_entry *enta;
310         vmlog_log_entry *entb;
311         vmlog_seq_t xorigin;
312
313         if (x >= xend || y >= yend)
314                 return 0;
315
316         xorigin = x;
317         vmlog_ringbuf_seek(g_ringbuf[0],x);
318         vmlog_ringbuf_seek(g_ringbuf[1],y);
319
320         do {
321                 enta = vmlog_ringbuf_next(g_ringbuf[0],VMLOGDIFF_PREFETCH);
322                 entb = vmlog_ringbuf_next(g_ringbuf[1],VMLOGDIFF_PREFETCH);
323                 assert(enta && entb);
324
325                 if (enta->index != entb->index || enta->tag != entb->tag)
326                         break;
327
328                 /* a diagonal edge in the edit graph */
329                 x++;
330                 y++;
331         } while (x < xend && y < yend);
332
333         return x - xorigin;
334 }
335
336 static vmlog_seq_t match_backward(vmlog_seq_t xstart,vmlog_seq_t ystart,vmlog_seq_t x,vmlog_seq_t y)
337 {
338         vmlog_log_entry *enta;
339         vmlog_log_entry *entb;
340         vmlog_seq_t xorigin;
341
342         if (x <= xstart || y <= ystart)
343                 return 0;
344
345         xorigin = x;
346         vmlog_ringbuf_seek(g_ringbuf_back[0],x);
347         vmlog_ringbuf_seek(g_ringbuf_back[1],y);
348
349         do {
350                 enta = vmlog_ringbuf_prev(g_ringbuf_back[0],VMLOGDIFF_PREFETCH);
351                 entb = vmlog_ringbuf_prev(g_ringbuf_back[1],VMLOGDIFF_PREFETCH);
352                 assert(enta && entb);
353
354                 if (enta->index != entb->index || enta->tag != entb->tag)
355                         break;
356
357                 /* a diagonal edge in the edit graph */
358                 x--;
359                 y--;
360         } while (x > xstart && y > ystart);
361
362         return xorigin - x;
363 }
364
365 /* pre-condition: X and Y differ at both ends */
366
367 static void find_middle_snake(vmlog_seq_t xstart,vmlog_seq_t ystart,vmlog_seq_t xend,vmlog_seq_t yend)
368 {
369         int D;
370         int k;
371         int resultD;
372         vmlog_seq_t diagofs;
373         vmlog_seq_t rdiagofs;
374         vmlog_seq_t Delta;
375         vmlog_seq_t x,y;
376         vmlog_seq_t snakex,snakey;
377         vmlog_seq_t snakestartx = 0;
378         vmlog_seq_t snakestarty = 0;
379         vmlog_seq_t snakelen = 0;
380         vmlog_seq_t match;
381         vmlog_seq_t best_forward;
382         vmlog_seq_t best_backward;
383
384         LOG(("find_middle_snake(%lld,%lld,%lld,%lld)\n",
385                         xstart,ystart,xend,yend));
386
387         diagofs = ystart - xstart;
388         rdiagofs = yend - xend;
389
390         Delta = diagofs - rdiagofs;
391         
392         /* fake vertical edge (0,-1) -> (0,0) ending on 0-diagonal */
393         g_Vforw[1] = xstart;
394
395         /* fake vertical edge (N,M+1) -> (N,M) ending on 0-reverse-diagonal */
396         g_Vback[-1] = xend;
397
398         best_forward = 0;
399         best_backward = xend;
400         
401         for (D=0; D <= g_maxD; ++D) {
402                 LOG(("D = %d\n",D));
403
404                 if (opt_verbose && D && (D % 1000 == 0))
405                         fprintf(stderr,"%d. (" VMLOG_SEQ_FMT_W ":" VMLOG_SEQ_FMT_W " entries, " VMLOG_SEQ_FMT_W " left) D = %d\n",
406                                         g_level,xend-xstart,yend-ystart,best_backward - best_forward,D);
407
408                 for (k = -D; k <= D; k += 2) {
409                         LOG(("    k = %d, forward\n",k));
410
411                         /* we take a (D-1)-path that ends on a          */
412                         /* neighbouring diagonal and extend it with a   */
413                         /* vertical or horizontal edge (whichever takes */
414                         /* us further)                                  */
415
416                         if (k == -D || (k != +D && g_Vforw[k-1] < g_Vforw[k+1])) {
417                                 /* vertical edge from diagonal k+1 down to k */
418                                 x = g_Vforw[k+1];
419                         }
420                         else {
421                                 /* horizontal edge from diagonal k-1 right to k */
422                                 x = g_Vforw[k-1] + 1;
423                         }
424
425                         /* calculate y using the k-diagonal equation */
426                         
427                         y = x - k + diagofs;
428
429                         /* append the trailing snake to the D-path */
430
431                         snakex = x;
432                         snakey = y;
433
434                         match = match_forward(x,y,xend,yend);
435                         x += match;
436                         y += match;
437
438                         if (match) {
439                                 LOG(("match from (%lld,%lld) to (%lld,%lld)\n",
440                                                 snakex,snakey,x-1,y-1));
441                         }
442
443                         if (D > 4000) {
444                                 resultD = 2*D - 1;
445                                 snakestartx = (xstart + xend) / 2;;
446                                 snakestarty = snakestartx;
447                                 if (snakestarty < ystart)
448                                         snakestarty = ystart;
449                                 else if (snakestarty > yend)
450                                         snakestarty = yend;
451                                 snakelen = 0;
452                                 goto found_middle_snake;
453                         }
454
455                         /* this is the furthest reaching D-path on the k-diagonal */
456
457                         g_Vforw[k] = x;
458                         if (x > best_forward)
459                                 best_forward = x;
460
461                         LOG(("\tlongest %d-path on %d-diagonal ends at x=%lld\n",
462                                         D,k,x));
463
464                         /* check overlap with furthest reaching reverse D-1 path */
465
466                         if ((Delta & 1) && k - Delta >= -(D-1) && k - Delta <= +(D-1)) {
467                                 if (x >= g_Vback[k - Delta]) {
468                                         LOG(("length of SES is %d\n",2*D - 1));
469
470                                         resultD = 2*D - 1;
471                                         snakestartx = snakex;
472                                         snakestarty = snakey;
473                                         snakelen = x - snakex;
474                                         goto found_middle_snake;
475                                 }
476                         }
477                 }
478
479                 for (k = -D; k <= +D; k += 2) {
480
481                         LOG(("    k = %d, backward\n",k));
482
483                         /* we take a reverse (D-1)-path that ends on a  */
484                         /* neighbouring diagonal and extend it with a   */
485                         /* vertical or horizontal edge (whichever takes */
486                         /* us further)                                  */
487
488                         if (k == +D || (k != -D && g_Vback[k-1] < g_Vback[k+1])) {
489                                 /* vertical edge from reverse diagonal k-1 up to k */
490                                 x = g_Vback[k-1];
491                         }
492                         else {
493                                 /* horizontal edge from reverse diagonal k+1 left to k */
494                                 x = g_Vback[k+1] - 1;
495                         }
496
497                         /* calculate y using the k-reverse-diagonal equation */
498                         
499                         y = x - k + rdiagofs;
500
501                         /* append the trailing snake to the D-path */
502
503                         snakex = x;
504                         snakey = y;
505                         match = match_backward(xstart,ystart,x,y);
506                         x -= match;
507                         y -= match;
508
509                         if (match)
510                                 LOG(("match from (%lld,%lld) to (%lld,%lld)\n",
511                                                 x,y,snakex-1,snakey-1));
512
513                         /* this is the furthest reaching reverse D-path on the k-diagonal */
514
515                         g_Vback[k] = x;
516                         if (x < best_backward)
517                                 best_backward = x;
518
519                         LOG(("\tlongest reverse %d-path on %d-diagonal ends at x=%lld\n",
520                                         D,k,x));
521
522                         /* check overlap with forward reaching D path */
523
524                         if (!(Delta & 1) && k + Delta >= -D && k + Delta <= +D) {
525                                 if (x <= g_Vforw[k + Delta]) {
526                                         LOG(("length of SES is %d\n",2*D));
527
528                                         resultD = 2*D;
529                                         snakestartx = x;
530                                         snakestarty = y;
531                                         snakelen = snakex - x;
532                                         goto found_middle_snake;
533                                 }
534                         }
535                 }
536         }
537
538         vmlog_die("length of shortest editing script is > %d\n",g_maxD);
539
540 found_middle_snake:
541         if (opt_verbose && g_level == 0) {
542                 fprintf(stderr,"shortest editing script D = %d\n",resultD);
543         }
544         
545         if (resultD > 1) {
546                 g_level++;
547                 compare(xstart,ystart,snakestartx,snakestarty);
548         
549                 LOG(("middle snake: x=%lld y=%lld len=%lld\n",
550                                 snakestartx,snakestarty,snakelen));
551
552                 if (snakelen) {
553                         handle_common(snakestartx,snakestarty,snakelen);
554                 }
555
556                 compare(snakestartx + snakelen,snakestarty + snakelen,xend,yend);
557                 g_level--;
558         }
559         else {
560                 vmlog_seq_t lendiff = (yend - ystart) - (xend - xstart);
561                 
562                 LOG(("snakestartx=%lld snakestarty=%lld snakelen=%lld\n",
563                                 snakestartx,snakestarty,snakelen));
564                 assert(snakelen == 0);
565                 assert(lendiff);
566
567                 if (lendiff > 0) {
568                         handle_only_in(1,ystart,lendiff);
569                 }
570                 else {
571                         handle_only_in(0,xstart,-lendiff);
572                 }
573         }
574 }
575
576 static void compare(vmlog_seq_t xstart,vmlog_seq_t ystart,vmlog_seq_t xend,vmlog_seq_t yend)
577 {
578         vmlog_seq_t prefix;
579         vmlog_seq_t suffix;
580         vmlog_seq_t xdiffend;
581         vmlog_seq_t ydiffend;
582
583         LOG(("compare(%lld,%lld,%lld,%lld)\n",
584                         xstart,ystart,xend,yend));
585
586         /* process and strip common prefix */
587
588         prefix = match_forward(xstart,ystart,xend,yend);
589         if (opt_verbose && g_level == 0) {
590                 fprintf(stderr,"common prefix = " VMLOG_SEQ_FMT "\n",prefix);
591         }
592         if (prefix) {
593                 handle_common(xstart,ystart,prefix);
594                 xstart += prefix;
595                 ystart += prefix;
596         }
597
598         /* strip common suffix */
599
600         suffix = match_backward(xstart,ystart,xend,yend);
601         if (opt_verbose && g_level == 0) {
602                 fprintf(stderr,"common suffix = " VMLOG_SEQ_FMT "\n",suffix);
603         }
604         xdiffend = xend - suffix;
605         ydiffend = yend - suffix;
606         
607
608         /* handle differences */
609
610         if (xstart < xdiffend || ystart < ydiffend) {
611                 if (xstart == xdiffend) {
612                         handle_only_in(1,ystart,ydiffend - ystart);
613                 }
614                 else if (ystart == ydiffend) {
615                         handle_only_in(0,xstart,xdiffend - xstart);
616                 }
617                 else {
618                         find_middle_snake(xstart,ystart,xdiffend,ydiffend);
619                 }
620         }
621
622         /* process common suffix */
623
624         if (suffix) {
625                 handle_common(xdiffend,ydiffend,suffix);
626         }
627 }
628
629 static void unmatchable_entries(void)
630 {
631         vmlog_log_entry *logent;
632         int i;
633         int mark;
634         vmlog_file cleaned;
635         vmlog_file seqs;
636         vmlog_seq_t count;
637         vmlog_seq_t seq;
638         vmlogdiff_removed removed;
639         
640         VMLOG_XZNEW_ARRAY(g_index_used,char,g_nstrings);
641
642         for (i=0; i<2; ++i) {
643                 mark = 1<<i;
644                 
645                 vmlog_ringbuf_seek(g_ringbuf[i],0);
646                 while ((logent = vmlog_ringbuf_next(g_ringbuf[i],VMLOGDIFF_PREFETCH))) {
647                         g_index_used[logent->index] |= mark;
648                 }
649         }
650
651         for (i=0; i<2; ++i) {
652                 vmlog_file_open(&cleaned,g_cleanedfname[i],vmlogTruncateAppend);
653                 vmlog_file_open(&seqs,g_removedfname[i],vmlogTruncateAppend);
654                 
655                 vmlog_ringbuf_seek(g_ringbuf[i],0);
656                 count = 0;
657                 seq = 0;
658                 removed.start = 0;
659                 removed.len = 0;
660                 while ((logent = vmlog_ringbuf_next(g_ringbuf[i],VMLOGDIFF_PREFETCH))) {
661                         if (g_index_used[logent->index] == 3) {
662                                 vmlog_file_append(&cleaned,logent,sizeof(vmlog_log_entry));
663                                 if (removed.len)
664                                         vmlog_file_append(&seqs,&removed,sizeof(vmlogdiff_removed));
665                                 removed.len = 0;
666                                 removed.start = seq + 1;
667                         }
668                         else {
669                                 count++;
670                                 removed.len++;
671                         }
672                         seq++;
673                 }
674                 if (removed.len)
675                         vmlog_file_append(&seqs,&removed,sizeof(vmlogdiff_removed));
676
677                 vmlog_file_close(&seqs);
678                 vmlog_file_close(&cleaned);
679
680                 if (opt_verbose)
681                         fprintf(stderr,"removed " VMLOG_SEQ_FMT " unmatchable entries from %s\n",
682                                         count,g_ringbuf[i]->file.fname);
683
684                 g_removedmap[i] = vmlog_file_mmap(g_removedfname[i],&(g_removedlen[i]));
685                 g_nremoved[i] = g_removedlen[i] / sizeof(vmlogdiff_removed);
686                 g_removedptr[i] = g_removedmap[i];
687                 g_removedend[i] = g_removedmap[i] + g_nremoved[i];
688         }
689 }
690
691 static void diff_logs(void)
692 {
693         int i;
694
695         for (i=0; i<2; ++i) {
696                 g_ringbuf[i] = vmlog_ringbuf_new(opt_fname[i],VMLOGDIFF_RINGBUF_SIZE);
697         }
698
699         unmatchable_entries();
700         diff_alloc(200000);
701
702         for (i=0; i<2; ++i) {
703                 g_ringbuf_orig[i] = g_ringbuf[i];
704                 g_ringbuf[i] = vmlog_ringbuf_new(g_cleanedfname[i],VMLOGDIFF_RINGBUF_SIZE);
705                 g_ringbuf_back[i] = vmlog_ringbuf_new(g_cleanedfname[i],VMLOGDIFF_RINGBUF_SIZE);
706                 g_ringbuf_show[i] = vmlog_ringbuf_new(g_cleanedfname[i],VMLOGDIFF_RINGBUF_SIZE);
707         }
708
709         g_n[0] = g_ringbuf[0]->file.size / sizeof(vmlog_log_entry);
710         g_n[1] = g_ringbuf[1]->file.size / sizeof(vmlog_log_entry);
711
712         compare(0,0,g_n[0],g_n[1]);
713 }
714
715 int main(int argc,char **argv)
716 {
717         if (argc)
718                 vmlog_set_progname(argv[0]);
719         parse_command_line(argc,argv);
720
721         g_idxfname = vmlog_concat3(opt_prefix,"",".idx",NULL);
722         g_strfname = vmlog_concat3(opt_prefix,"",".str",NULL);
723
724         g_idxmap = (vmlog_string_entry *) vmlog_file_mmap(g_idxfname,&g_idxlen);
725         g_nstrings = g_idxlen / sizeof(vmlog_string_entry);
726         g_strmap = (char *) vmlog_file_mmap(g_strfname,&g_strlen);
727
728         diff_logs();
729         
730         vmlog_ringbuf_free(g_ringbuf[0]);
731         vmlog_ringbuf_free(g_ringbuf[1]);
732         g_ringbuf[0] = NULL;
733         g_ringbuf[1] = NULL;
734         vmlog_file_munmap(g_strmap,g_strlen);
735         vmlog_file_munmap(g_idxmap,g_idxlen);
736         vmlog_file_munmap(g_removedmap[0],g_removedlen[0]);
737         vmlog_file_munmap(g_removedmap[1],g_removedlen[1]);
738
739         return 0;
740 }
741
742 /* vim: noet ts=8 sw=8
743  */
744