00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include <Basics.H>
00026 #include <CacheArgs.H>
00027 #include <CacheConfig.H>
00028 #include "StatError.H"
00029 #include "StatNames.H"
00030 #include "StatCount.H"
00031 #include "StatCollection.H"
00032 #include "StatDirEntry.H"
00033 #include "StatMPKFile.H"
00034
00035 using std::ostream;
00036 using std::cerr;
00037 using std::cout;
00038 using std::endl;
00039
00040 void PrintSyntax(const char *msg, const char *arg = NULL) throw ()
00041 {
00042 cerr << "Error: " << msg;
00043 if (arg != NULL) cerr << ": " << arg;
00044 cerr << endl;
00045 cerr << "Syntax: VCacheStats "
00046 << "[ -histo ] [ -min ] [ -max ] [ -v | -V ] [ path ]" << endl;
00047 exit(1);
00048 }
00049
00050 static void Banner(ostream &os) throw ()
00051 {
00052 os << endl;
00053 for (int i = 0; i < 75; i++) os << '*';
00054 os << endl << endl;
00055 }
00056
00057 void Process(const char *path, int verbose,
00058 bool histo, bool minName, bool maxName,
00059 Stat::Collection &stats) throw ()
00060 {
00061 Text fullpath(path);
00062 if (path[0] != '/') {
00063
00064 if (fullpath.Length() > 0) {
00065 fullpath = Config_SCachePath + ('/' + fullpath);
00066 } else {
00067 fullpath = Config_SCachePath;
00068 }
00069 }
00070 cout << "STATISTICS FOR:" << endl << " " << fullpath << endl;
00071
00072 try {
00073
00074 DirEntry *entry = DirEntry::Open(fullpath);
00075 if (verbose > 0) cout << endl << "SEARCHING:" << endl;
00076 entry->Search(verbose, stats);
00077
00078
00079 cout << endl << "*** FANOUT STATISTICS ***" << endl;
00080 int i;
00081 for (i = stats.fanout.size() - 1; i >= 0; i--) {
00082 cout << endl;
00083 cout << Stat::LevelName(i) << " (level " << i << "):" << endl;
00084 StatCount *sc = stats.fanout.get(i);
00085 sc->Print(cout, 2, histo,
00086 minName, maxName, (i>0));
00087 }
00088
00089
00090 cout << endl;
00091 cout << "*** MULTIPKFILE, PKFILE, AND CACHE ENTRY STATISTICS ***";
00092 cout << endl;
00093 for (i = 0; i < Stat::NumAttributes; i++) {
00094
00095
00096 if(!stats.redundant &&
00097 ((i == Stat::NumRedundantNames) ||
00098 (i == Stat::PcntRedundantNames)))
00099 {
00100 continue;
00101 }
00102
00103 cout << endl << Stat::AttrName((Stat::Attribute)i) << ":" << endl;
00104 stats.entryStats[i].Print(cout, 2,
00105 histo, minName, maxName);
00106 }
00107 }
00108 catch (const StatError::UnevenLevels &dirName) {
00109 Banner(cerr);
00110 cerr << "Error: the following directory "
00111 << "contains MPKFiles at different depths:" << endl;
00112 cerr << " " << dirName << endl;
00113 Banner(cerr);
00114 }
00115 catch (const StatError::BadMPKFile &fname) {
00116 Banner(cerr);
00117 cerr << "Error: found illegal MultiPKFile:" << endl;
00118 cerr << " " << fname << endl;
00119 Banner(cerr);
00120 }
00121 catch (const StatError::EndOfFile &fname) {
00122 Banner(cerr);
00123 cerr << "Fatal error: premature end-of-file" << endl;
00124 cerr << " " << fname << endl;
00125 Banner(cerr);
00126 }
00127 catch (const FS::Failure &f) {
00128 Banner(cerr);
00129 cerr << "Error: " << f << endl;
00130 Banner(cerr);
00131 }
00132 catch (FS::DoesNotExist) {
00133 Banner(cerr);
00134 cerr << "Error: file '" << fullpath << "' does not exist" << endl;
00135 Banner(cerr);
00136 }
00137 }
00138
00139
00140 static StatCount *parseStatName(Stat::Collection &stats, const char *stat)
00141 {
00142 #define ATTRIB_CASE(name) \
00143 if(strcmp(#name, stat) == 0) return &(stats.entryStats[Stat::name])
00144
00145 ATTRIB_CASE(MPKFileSize);
00146
00147 ATTRIB_CASE(PKFileSize);
00148 ATTRIB_CASE(NumNames);
00149 ATTRIB_CASE(NameSize);
00150 ATTRIB_CASE(NumEntries);
00151 ATTRIB_CASE(NumCommonNames);
00152 ATTRIB_CASE(PcntCommonNames);
00153
00154 ATTRIB_CASE(NumEntryNames);
00155 ATTRIB_CASE(NumUncommonNames);
00156 ATTRIB_CASE(PcntUncommonNames);
00157 ATTRIB_CASE(ValueSize);
00158 ATTRIB_CASE(NumDIs);
00159 ATTRIB_CASE(NumKids);
00160 ATTRIB_CASE(NameMapSize);
00161
00162
00163
00164
00165 ATTRIB_CASE(ValPfxTblSize);
00166 ATTRIB_CASE(NumRedundantNames);
00167 ATTRIB_CASE(PcntRedundantNames);
00168
00169 #define FANOUT_CASE(name, level) \
00170 if(strcmp(name, stat)) return stats.getFanout(level);
00171
00172 FANOUT_CASE("PKFileFanout", 2);
00173 FANOUT_CASE("CFPFanout", 1);
00174
00175
00176 PrintSyntax("unrecognized statistic name", stat);
00177
00178
00179 return 0;
00180 }
00181
00182 int main(int argc, char *argv[])
00183 {
00184
00185 int verbose = 0;
00186 bool printHisto = false, printMinName = false, printMaxName = false;
00187
00188
00189 Stat::Collection stats;
00190
00191 int arg;
00192 for (arg = 1; arg < argc && *argv[arg] == '-'; arg++) {
00193 if (CacheArgs::StartsWith(argv[arg], "-histo")) {
00194 printHisto = true;
00195 } else if (CacheArgs::StartsWith(argv[arg], "-min", 3)) {
00196 printMinName = true;
00197 } else if (CacheArgs::StartsWith(argv[arg], "-max", 3)) {
00198 printMaxName = true;
00199 } else if (CacheArgs::StartsWith(argv[arg], "-verbose")) {
00200 verbose = max(verbose, 1);
00201 } else if (CacheArgs::StartsWith(argv[arg], "-Verbose")) {
00202 verbose = max(verbose, 2);
00203 } else if (CacheArgs::StartsWith(argv[arg], "-report")) {
00204
00205 if(++arg >= argc)
00206 PrintSyntax("-report expects stat name");
00207 StatCount *stat = parseStatName(stats, argv[arg]);
00208
00209 if(++arg >= argc)
00210 PrintSyntax("-report expects count");
00211 unsigned int report_count = atoi(argv[arg]);
00212
00213 stat->SetReportCount(report_count);
00214 } else if (CacheArgs::StartsWith(argv[arg], "-mask")) {
00215
00216 if(++arg >= argc)
00217 PrintSyntax("-mask expects stat name");
00218 StatCount *stat = parseStatName(stats, argv[arg]);
00219
00220
00221 if(++arg >= argc)
00222 PrintSyntax("-mask expects regular expression");
00223 Basics::RegExp *mask = NEW_CONSTR(Basics::RegExp, (argv[arg]));
00224
00225 stat->AddReportMask(mask);
00226 } else if (CacheArgs::StartsWith(argv[arg], "-redundant")) {
00227
00228 stats.redundant = true;
00229 } else {
00230 PrintSyntax("unrecognized command-line option", argv[arg]);
00231 }
00232 }
00233
00234
00235 const char *path = (arg == argc) ? "" : argv[arg];
00236 Process(path, verbose, printHisto, printMinName, printMaxName, stats);
00237 }