Main Page | Namespace List | Class Hierarchy | Class List | Directories | File List | Namespace Members | Class Members | File Members

TestCacheRandom.C

Go to the documentation of this file.
00001 // Copyright (C) 2001, Compaq Computer Corporation
00002 // 
00003 // This file is part of Vesta.
00004 // 
00005 // Vesta is free software; you can redistribute it and/or
00006 // modify it under the terms of the GNU Lesser General Public
00007 // License as published by the Free Software Foundation; either
00008 // version 2.1 of the License, or (at your option) any later version.
00009 // 
00010 // Vesta is distributed in the hope that it will be useful,
00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013 // Lesser General Public License for more details.
00014 // 
00015 // You should have received a copy of the GNU Lesser General Public
00016 // License along with Vesta; if not, write to the Free Software
00017 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00018 
00019 // Last modified on Mon May 23 22:09:07 EDT 2005 by ken@xorian.net 
00020 //      modified on Fri Jul 27 19:02:36 PDT 2001 by mann 
00021 //      modified on Thu Feb 10 12:14:02 PST 2000 by heydon 
00022 //      modified on Sat Jan 29 14:24:12 PST 2000 by heydon
00023 
00024 /* TestCacheRandom -- make random calls on the Vesta-2 cache server */
00025 
00026 #include <sstream>
00027 
00028 #include <Basics.H>
00029 #include <SRPC.H>
00030 #include <FP.H>
00031 #include <VestaConfig.H>
00032 
00033 // cache-common
00034 #include <CacheArgs.H>
00035 #include <CacheIntf.H>
00036 #include <Model.H>
00037 #include <CacheIndex.H>
00038 #include <FV.H>
00039 #include <CompactFV.H>
00040 #include <VestaVal.H>
00041 #include <NewVal.H>
00042 #include <Debug.H>
00043 
00044 #include "CacheC.H"
00045 
00046 using std::ostringstream;
00047 using std::cout;
00048 using std::cerr;
00049 using std::endl;
00050 
00051 // fatal programmer error
00052 class FatalError {
00053   public: FatalError() { /*EMPTY*/ }
00054 };
00055 
00056 struct ClientArgs {
00057     int id;                     // thread id
00058     int numReqs;                // number of requests; -1 -> infinity
00059     int numAddOps;              // number of AddEntry ops; -1 -> infinity
00060     int numPKs;                 // number of distinct PKs
00061     int minNames;               // min number of free vars / entry
00062     int maxNames;               // max number of free vars / entry
00063     int commonNames;            // number of common names per PK
00064     bool kids;                  // generate non-empty "kids" to AddEntry?
00065     bool verbose;               // print call/return values?
00066 };
00067 
00068 static void ExitClient() throw ()
00069 {
00070     cerr << "SYNTAX: TestCacheRandom ";
00071     cerr << "[-threads n] [-reqs numReqs] [-pks numPKs ] [-kids] [-quiet]";
00072     cerr << endl;
00073     exit(1);
00074 }
00075 
00076 static FV::Epoch ClientFreeVarsCall(CacheC *client,
00077   int id, const FP::Tag& pk, /*OUT*/ int &numNames,
00078   /*OUT*/ bool &isEmpty) throw (SRPC::failure)
00079 {
00080     CompactFV::List names;
00081     FV::Epoch epoch;
00082 
00083     epoch = client->FreeVariables(pk, /*OUT*/ names, /*OUT*/ isEmpty);
00084     numNames = names.num;
00085     return epoch;
00086 }
00087 
00088 static CacheIntf::LookupRes
00089 ClientLookupCall(CacheC *client, int id, const FP::Tag& pk,
00090   FV::Epoch epoch, int numNames) throw (SRPC::failure)
00091 {
00092     // initialize arguments
00093     FP::List fps;
00094     if (numNames > 0) {
00095         NewVal::NewFPs(fps, numNames);
00096     }
00097 
00098     // make call
00099     CacheEntry::Index ci;
00100     VestaVal::T value;
00101     CacheIntf::LookupRes res;
00102     res = client->Lookup(pk, epoch, fps, /*OUT*/ ci, /*OUT*/ value);
00103     return res;
00104 }
00105 
00106 static void NewNames2(/*OUT*/ char* &types, /*OUT*/ FV2::List &names,
00107   int numCommon, unsigned int num) throw ()
00108 {
00109     // pick random number of names if needed
00110     if (num < 1) num = Debug::MyRand(1, 5);
00111 
00112     // pick random types
00113     num = max(num, numCommon);
00114     types = NEW_PTRFREE_ARRAY(char, num+1);
00115     int i;
00116     for (i = 0; i < numCommon; i++) {
00117         types[i] = 'A';
00118     }
00119     for (/*SKIP*/; i < num; i++) {
00120         types[i] = 'A' + Debug::MyRand(0,25);
00121     }
00122     // terminate string to make debugging easier
00123     types[num] = '\0';
00124 
00125     // pick random names
00126     names.len = num;
00127     names.name = NEW_ARRAY(FV2::TPtr, num);
00128     Text prefix("name");
00129     for (i=0; i < num; i++) {
00130       names.name[i] = NEW(FV2::T);
00131       names.name[i]->addhi(prefix);
00132       ostringstream oss; oss << i;
00133       names.name[i]->addhi(Text(oss.str()));
00134     }
00135 }
00136 
00137 static const Text SourceFunc("TestCacheRandom source function location");
00138 
00139 static void ClientAddEntry(CacheC *client, int id, const FP::Tag& pk,
00140   int minNames, int maxNames, int commonNames, bool genKids)
00141   throw (SRPC::failure)
00142 {
00143     int numNames;
00144     FV2::List names;
00145     char *types;
00146     FP::List fps;
00147     VestaVal::T value;
00148     Model::T model;
00149     CacheEntry::Indices kids;
00150     CacheEntry::Index ci;
00151     CacheIntf::AddEntryRes res;
00152 
00153     // initialize arguments
00154     numNames = Debug::MyRand(minNames, maxNames);
00155     NewNames2(/*OUT*/ types, /*OUT*/ names, commonNames, numNames);
00156     NewVal::NewFPs(/*OUT*/ fps, numNames);
00157     NewVal::NewValue(/*OUT*/ value);
00158     NewVal::NewModel(/*OUT*/ model);
00159     if (genKids) NewVal::NewCIs(/*OUT*/ kids);
00160 
00161     // make call
00162     res = client->AddEntry(pk, types, names, fps, value, model,
00163       kids, SourceFunc, /*OUT*/ ci);
00164 }
00165 
00166 void *MainClientProc(void *ptr) throw ()
00167 /* This is the procedure invoked for each thread forked by "main". "ptr" is
00168    actually a pointer to a "ClientArgs" structure, which encodes the thread
00169    id, the number of requests this thread should make on the cache, and
00170    whether or not it should generate a non-empty "kids" list on calls to the
00171    cache's AddEntry method. */
00172 {
00173     ClientArgs *args = (ClientArgs *)ptr;
00174     FP::Tag pk;
00175     FV::Epoch epoch;
00176     int numNames;
00177     CacheIntf::LookupRes res;
00178 
00179     Debug::Lock();
00180     cout << Debug::Timestamp() << "Starting client thread " << args->id <<endl;
00181     cout << endl;
00182     Debug::Unlock();
00183 
00184     try {
00185       CacheC client(/*debug=*/ args->verbose
00186                     ? CacheIntf::All
00187                     : CacheIntf::None);
00188 
00189       int addOps = 0;
00190       for (int i = 0; 
00191            (args->numReqs < 0 || i < args->numReqs) &&
00192            (args->numAddOps < 0 || addOps < args->numAddOps);
00193            i++) {
00194         if (args->verbose) {
00195           Debug::Lock();
00196           cout << Debug::Timestamp() << "Client thread " << args->id;
00197           cout << " **** Round " << i << " ****" << endl;
00198           cout << endl;
00199           Debug::Unlock();
00200         }
00201         NewVal::NewFP(/*OUT*/ pk, /*vals=*/ args->numPKs);
00202         do {
00203           bool isEmpty;
00204           epoch = ClientFreeVarsCall(&client, args->id, pk,
00205                                      /*OUT*/ numNames, /*OUT*/ isEmpty);
00206           if (isEmpty) {
00207             res = CacheIntf::Miss;
00208           } else {
00209             res = ClientLookupCall(&client, args->id,
00210                                    pk, epoch, numNames);
00211           }
00212         } while (res == CacheIntf::FVMismatch);
00213         if (res == CacheIntf::Miss) {
00214           ClientAddEntry(&client, args->id, pk,
00215                          args->minNames, args->maxNames, args->commonNames,
00216                          args->kids);
00217           addOps++;
00218         }
00219       }
00220     } catch (SRPC::failure f) {
00221       Debug::Lock();
00222       cerr << "SRPC Failure: " << f.msg
00223            << " (code " << f.r << ")" << endl;
00224       cerr << endl;
00225       Debug::Unlock();
00226     }
00227 
00228     Debug::Lock();
00229     cout << Debug::Timestamp() << "Exiting client thread " << args->id << endl;
00230     cout << endl;
00231     Debug::Unlock();
00232     return (void *)NULL;
00233 }
00234 
00235 int main(int argc, char *argv[]) 
00236 {
00237     int numThreads = 1, numReqs = -1, numAddOps = -1, numPKs = 10;
00238     int minNames = 1, maxNames = 5, commonNames = 1;
00239     bool verbose = true;
00240     bool kids = false;
00241     int arg;
00242 
00243     // parse arguments
00244     if (argc < 1 || argc > 17) {
00245         cerr << "Error: Incorrect number of arguments" << endl;
00246         ExitClient();
00247     }
00248     for (arg = 1; arg < argc; arg++) {
00249         if (CacheArgs::StartsWith(argv[arg], "-threads")) {
00250             if (sscanf(argv[++arg], "%d", &numThreads) < 1 || numThreads < 1) {
00251                 cerr <<"Error: -threads argument not a positive integer"<<endl;
00252                 ExitClient();
00253             }
00254         } else if (CacheArgs::StartsWith(argv[arg], "-reqs")) {
00255             if (sscanf(argv[++arg], "%d", &numReqs) < 1) {
00256                 cerr << "Error: -reqs argument must be an integer" << endl;
00257                 ExitClient();
00258             }
00259         } else if (CacheArgs::StartsWith(argv[arg], "-addops")) {
00260             if (sscanf(argv[++arg], "%d", &numAddOps) < 1) {
00261                 cerr << "Error: -addops argument must be an integer" << endl;
00262                 ExitClient();
00263             }
00264         } else if (CacheArgs::StartsWith(argv[arg], "-commonNames")) {
00265             if (sscanf(argv[++arg], "%d", &commonNames) < 1) {
00266                 cerr << "Error: -commonNames argument must be an integer"
00267                      << endl;
00268                 ExitClient();
00269             }
00270         } else if (CacheArgs::StartsWith(argv[arg], "-minNames", 3)) {
00271             if (sscanf(argv[++arg], "%d", &minNames) < 1) {
00272                 cerr << "Error: -minNames argument must be an integer" << endl;
00273                 ExitClient();
00274             }
00275             if (maxNames < minNames) maxNames = minNames;
00276         } else if (CacheArgs::StartsWith(argv[arg], "-maxNames", 3)) {
00277             if (sscanf(argv[++arg], "%d", &maxNames) < 1) {
00278                 cerr << "Error: -maxNames argument must be an integer" << endl;
00279                 ExitClient();
00280             }
00281             if (maxNames < minNames) minNames = maxNames;
00282         } else if (CacheArgs::StartsWith(argv[arg], "-pks")) {
00283             if (sscanf(argv[++arg], "%d", &numPKs) < 1) {
00284                 cerr << "Error: -numPKs argument must be an integer" << endl;
00285                 ExitClient();
00286             }
00287         } else if (CacheArgs::StartsWith(argv[arg], "-seed")) {
00288             int seed;
00289             if (sscanf(argv[++arg], "%d", &seed) < 1) {
00290                 cerr << "Error: -seed argument must be an integer" << endl;
00291                 ExitClient();
00292             }
00293             srand((unsigned int) seed);
00294         } else if (CacheArgs::StartsWith(argv[arg], "-kids")) {
00295             kids = true;
00296         } else if (CacheArgs::StartsWith(argv[arg], "-quiet")) {
00297             verbose = false;
00298         } else {
00299             cerr << "Error: argument " << arg << " is bad" << endl;
00300             ExitClient();
00301         }
00302     }
00303     
00304     // start client
00305     Debug::Lock();
00306     cout << "Starting client:" << endl;
00307     cout << "  Config: " << VestaConfig::get_location() << endl;
00308     cout << endl;
00309     Debug::Unlock();
00310 
00311     // fork threads
00312     Debug::Lock();
00313     cout << Debug::Timestamp() <<"Forking "<< numThreads <<" thread(s)"<< endl;
00314     cout << endl;
00315     Debug::Unlock();
00316     Basics::thread *th = NEW_PTRFREE_ARRAY(Basics::thread, numThreads);
00317     int i;
00318     for (i = 0; i < numThreads; i++) {
00319       ClientArgs *args = NEW(ClientArgs);
00320       args->id = i + 1;
00321       args->numReqs = numReqs;
00322       args->numAddOps = numAddOps;
00323       args->numPKs = numPKs;
00324       args->minNames = minNames;
00325       args->maxNames = maxNames;
00326       args->commonNames = commonNames;
00327       args->kids = kids;
00328       args->verbose = verbose;
00329       th[i].fork(MainClientProc, (void *)args);
00330     }
00331 
00332     // join with forked threads
00333     Debug::Lock();
00334     cout << Debug::Timestamp()
00335       << "Main client thread now waiting for threads to complete..." << endl;
00336     cout << endl;
00337     Debug::Unlock();
00338     for (i = 0; i < numThreads; i++) {
00339         (void) th[i].join();
00340     }
00341 }

Generated on Mon May 8 00:48:31 2006 for Vesta by  doxygen 1.4.2