llvm.org GIT mirror llvm / 337481a
Okay, spiff is completely incapable of handling files of nontrivial size. Here is a simple minimal program that does what we want. Instead of taking minutes to compare mesa's output, and crashing on binary files (like spiff does), this take < .02s in the common case and doesn't crash. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@12926 91177308-0d34-0410-b5e6-96231b3b80d8 Chris Lattner 15 years ago
2 changed file(s) with 171 addition(s) and 0 deletion(s). Raw diff Collapse all Expand all
0 ##===- utils/fpcmp/Makefile --------------------------------*- Makefile -*-===##
1 #
2 # The LLVM Compiler Infrastructure
3 #
4 # This file was developed by the LLVM research group and is distributed under
5 # the University of Illinois Open Source License. See LICENSE.TXT for details.
6 #
7 ##===----------------------------------------------------------------------===##
8
9 LEVEL = ../..
10 TOOLNAME = fpcmp
11 USEDLIBS = support.a
12
13 include $(LEVEL)/Makefile.common
14
0 //===- fpcmp.cpp - A fuzzy "cmp" that permits floating point noise --------===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file was developed by the LLVM research group and is distributed under
5 // the University of Illinois Open Source License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // fpcmp is a tool that basically works like the 'cmp' tool, except that it can
10 // tolerate errors due to floating point noise, with the -r option.
11 //
12 //===----------------------------------------------------------------------===//
13
14 #include "Support/CommandLine.h"
15 #include "Support/FileUtilities.h"
16 #include "Config/fcntl.h"
17 #include "Config/sys/mman.h"
18 #include
19 #include
20
21 using namespace llvm;
22
23 namespace {
24 cl::opt
25 File1(cl::Positional, cl::desc(""), cl::Required);
26 cl::opt
27 File2(cl::Positional, cl::desc(""), cl::Required);
28
29 cl::opt
30 RelTolerance("r", cl::desc("Relative error tolerated"), cl::init(0));
31 cl::opt
32 AbsTolerance("a", cl::desc("Absolute error tolerated"), cl::init(0));
33 }
34
35
36 /// OpenFile - mmap the specified file into the address space for reading, and
37 /// return the length and address of the buffer.
38 static void OpenFile(const std::string &Filename, unsigned &Len, char* &BufPtr){
39 int FD = open(Filename.c_str(), O_RDONLY);
40 if (FD == -1 || (Len = getFileSize(Filename)) == ~0U) {
41 std::cerr << "Error: cannot open file '" << Filename << "'\n";
42 exit(2);
43 }
44
45 // mmap in the file all at once...
46 BufPtr = (char*)mmap(0, Len, PROT_READ, MAP_PRIVATE, FD, 0);
47
48 if (BufPtr == (char*)MAP_FAILED) {
49 std::cerr << "Error: cannot open file '" << Filename << "'\n";
50 exit(2);
51 }
52 }
53
54 static bool isNumberChar(char C) {
55 switch (C) {
56 case '0': case '1': case '2': case '3': case '4':
57 case '5': case '6': case '7': case '8': case '9':
58 case '.':
59 case 'e':
60 case 'E': return true;
61 default: return false;
62 }
63 }
64
65 static char *BackupNumber(char *Pos, char *FirstChar) {
66 while (Pos < FirstChar && isNumberChar(Pos[-1]))
67 --Pos;
68 return Pos;
69 }
70
71 static void CompareNumbers(char *&F1P, char *&F2P, char *F1End, char *F2End) {
72 char *F1NumEnd, *F2NumEnd;
73 double V1 = strtod(F1P, &F1NumEnd);
74 double V2 = strtod(F2P, &F2NumEnd);
75
76 if (F1NumEnd == F1P || F2NumEnd == F2P) {
77 std::cerr << "Comparison failed, not a numeric difference.\n";
78 exit(1);
79 }
80
81 // Check to see if these are inside the absolute tolerance
82 if (AbsTolerance < std::abs(V1-V2)) {
83 // Nope, check the relative tolerance...
84 double Diff;
85 if (V2)
86 Diff = std::abs(V1/V2 - 1.0);
87 else if (V1)
88 Diff = std::abs(V2/V1 - 1.0);
89 else
90 Diff = 0; // Both zero.
91 if (Diff > RelTolerance) {
92 std::cerr << "Compared: " << V1 << " and " << V2 << ": diff = "
93 << Diff << "\n";
94 std::cerr << "Out of tolerence: rel/abs: " << RelTolerance
95 << "/" << AbsTolerance << "\n";
96 exit(1);
97 }
98 }
99
100 // Otherwise, advance our read pointers to the end of the numbers.
101 F1P = F1NumEnd; F2P = F2NumEnd;
102 }
103
104
105 int main(int argc, char **argv) {
106 cl::ParseCommandLineOptions(argc, argv);
107
108 // mmap in the files.
109 unsigned File1Len, File2Len;
110 char *File1Start, *File2Start;
111 OpenFile(File1, File1Len, File1Start);
112 OpenFile(File2, File2Len, File2Start);
113
114 // Okay, now that we opened the files, scan them for the first difference.
115 char *File1End = File1Start+File1Len;
116 char *File2End = File2Start+File2Len;
117 char *F1P = File1Start;
118 char *F2P = File2Start;
119
120 while (1) {
121 // Scan for the end of file or first difference.
122 while (F1P < File1End && F2P < File2End && *F1P == *F2P)
123 ++F1P, ++F2P;
124
125 if (F1P >= File1End || F2P >= File2End) break;
126
127 // Okay, we must have found a difference. Backup to the start of the
128 // current number each stream is at so that we can compare from the
129 // beginning.
130 F1P = BackupNumber(F1P, File1Start);
131 F2P = BackupNumber(F2P, File2Start);
132
133 // Now that we are at the start of the numbers, compare them, exiting if
134 // they don't match.
135 CompareNumbers(F1P, F2P, File1End, File2End);
136 }
137
138 // Okay, we reached the end of file. If both files are at the end, we
139 // succeeded.
140 if (F1P >= File1End && F2P >= File2End) return 0;
141
142 // Otherwise, we might have run off the end due to a number, backup and retry.
143 F1P = BackupNumber(F1P, File1Start);
144 F2P = BackupNumber(F2P, File2Start);
145
146 // Now that we are at the start of the numbers, compare them, exiting if
147 // they don't match.
148 CompareNumbers(F1P, F2P, File1End, File2End);
149
150 // If we found the end, we succeeded.
151 if (F1P >= File1End && F2P >= File2End) return 0;
152
153 return 1;
154 }
155