00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include <Basics.H>
00022 #include <FP.H>
00023 #include <Model.H>
00024 #include <FV.H>
00025 #include <CacheIndex.H>
00026 #include <CacheC.H>
00027 #include "ApplyCache.H"
00028 #include "Expr.H"
00029 #include "Val.H"
00030 #include "Pickle.H"
00031 #include "Err.H"
00032 #include "PrimRunTool.H"
00033 #include "Debug.H"
00034 #include "ThreadData.H"
00035 #include <Table.H>
00036
00037 using std::ostream;
00038 using std::cerr;
00039 using std::endl;
00040 using Basics::OBufStream;
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066 const char *evaluatorRunToolVersion = "Fri Feb 11 13:30:46 2005";
00067 const FP::Tag evaluatorRunToolVersionTag(evaluatorRunToolVersion);
00068
00069
00070 const char *evaluatorFunctionVersion = "Fri Feb 11 13:30:46 2005";
00071 const FP::Tag evaluatorFunctionVersionTag(evaluatorFunctionVersion);
00072
00073
00074 static int addEntryCount = 0;
00075
00076
00077
00078 static Basics::mutex frontierMu;
00079
00080
00081
00082 static Basics::mutex leaseMu;
00083 static time_t lastRenewed;
00084 static bool renewLease_failure = false;
00085
00086
00087
00088
00089 static Basics::mutex runToolTableMu;
00090 class rtt_cond {
00091 Basics::cond cond;
00092 int count;
00093
00094 bool dec_and_del() {
00095 assert(count > 0);
00096 if(--count == 0) {
00097 delete this;
00098 return false;
00099 } else {
00100 return true;
00101 }
00102 };
00103 public:
00104 rtt_cond() { count = 1; };
00105 void wait() {
00106 count++;
00107 cond.wait(runToolTableMu);
00108 (void) dec_and_del();
00109 };
00110 void wake() {
00111 if(dec_and_del()) {
00112 cond.broadcast();
00113 }
00114 };
00115
00116 };
00117 static Table<FP::Tag, rtt_cond *>::Default runToolTable;
00118
00119
00120 void Tags(const CompactFV::List& names, const Context& c,
00121 FP::List& tags) {
00122
00123 int len = names.num;
00124 if (len > 0) {
00125 tags.len = len;
00126 tags.fp = NEW_PTRFREE_ARRAY(FP::Tag, len);
00127 int size = names.tbl.NumArcs();
00128 Val *vals = NEW_ARRAY(Val, size);
00129 int i;
00130 for (i = 0; i < size; i++) { vals[i] = NULL; }
00131 for (i = 0; i < len; i++) {
00132 short int idx = names.idx[i];
00133 PathKind pkind = (PathKind)names.types[i];
00134 tags.fp[i] = LookupPath(idx, pkind, names.tbl, c, vals)->FingerPrint();
00135 }
00136 } else {
00137 tags.len = 0;
00138 tags.fp = NULL;
00139 }
00140 return;
00141 }
00142
00143 bool NamesTagsPickle(Val val, bool cutoff, const Context& inPKArgs,
00144 char*& types, FV2::List& names,
00145 FP::List& tags, VestaVal::T& vval) {
00146
00147
00148
00149
00150
00151 DPaths *sk = NEW_CONSTR(DPaths, (val->SizeOfDPS()));
00152 sk->Merge(val->dps);
00153 ValueDpnd(val, sk);
00154 DepPathTbl::TIter iter(sk);
00155 DepPathTbl::KVPairPtr ptr;
00156 Context work = inPKArgs;
00157 Text id;
00158 while (!work.Null()) {
00159 id = work.Pop()->name;
00160 iter.Reset();
00161 while (iter.Next(ptr)) {
00162 if (ptr->key.content->path->getlo() == id)
00163 sk->Delete(ptr->key, ptr, false);
00164 }
00165 }
00166 sk->Resize();
00167
00168 int len = sk->Size();
00169 names.len = len;
00170 tags.len = len;
00171 if (len > 0) {
00172 types = NEW_PTRFREE_ARRAY(char, len);
00173 names.name = NEW_ARRAY(FV2::TPtr, len);
00174 tags.fp = NEW_PTRFREE_ARRAY(FP::Tag, len);
00175 iter.Reset();
00176 int index = 0;
00177 while (iter.Next(ptr)) {
00178 types[index] = (char)ptr->key.content->pKind;
00179 names.name[index] = ptr->key.content->path;
00180 if (ptr->val->vKind != FpVK && ptr->key.content->pKind == ExprPK) {
00181 if (ptr->val->vKind == ClosureVK)
00182 tags.fp[index++] = ((ClosureVC*)ptr->val)->FingerPrintExpr();
00183 else {
00184 assert(ptr->val->vKind == ModelVK);
00185 tags.fp[index++] = ((ModelVC*)ptr->val)->FingerPrintFile();
00186 }
00187 }
00188 else
00189 tags.fp[index++] = ptr->val->FingerPrint();
00190 }
00191 }
00192
00193 if (cutoff) ModelCutOff(val);
00194 return Pickle(val, vval);
00195 }
00196
00197 static void CheckLeases() {
00198 leaseMu.lock();
00199 bool expired = (time(NULL) - lastRenewed) > leaseDuration;
00200 bool failed = renewLease_failure;
00201 leaseMu.unlock();
00202 if (expired) {
00203 throw(Evaluator::failure("Leases timed out. Start over.", true));
00204 } else if(failed) {
00205 throw(Evaluator::failure("Lease renewal failed.", true));
00206 }
00207 }
00208
00209 void CollectKids(CacheEntry::IndicesApp* orphanCIs, int kidsIndex,
00210 CacheEntry::Indices& kids) {
00211 CheckLeases();
00212 kids.len = orphanCIs->len - kidsIndex;
00213 kids.index = orphanCIs->index + kidsIndex;
00214 }
00215
00216 void UpdateOrphans(CacheEntry::IndicesApp* orphanCIs, int kidsIndex,
00217 CacheEntry::Index ci) {
00218 frontierMu.lock();
00219 orphanCIs->len = kidsIndex;
00220 orphanCIs->Append(ci);
00221 frontierMu.unlock();
00222 }
00223
00224 void Checkpoint() {
00225 CheckLeases();
00226 frontierMu.lock();
00227 addEntryCount++;
00228 if ((addEntryCount & 0x3f) == 0) {
00229 CacheEntry::IndicesApp orphanCIs;
00230 ThreadData::mu.lock();
00231 ThreadData* cur = ThreadData::head;
00232 while (cur) {
00233 assert(cur->orphanCIs != 0);
00234 for (int i = 0; i < cur->orphanCIs->len; i++) {
00235 orphanCIs.Append(cur->orphanCIs->index[i]);
00236 }
00237 cur = cur->next;
00238 }
00239 ThreadData::mu.unlock();
00240 theCache->Checkpoint(topModelRoot->fptag, topModelSid, orphanCIs, false);
00241 }
00242 frontierMu.unlock();
00243 }
00244
00245 void FreeNamesTags(CompactFV::List& names, FP::List& tags) {
00246
00247 names.tbl = PrefixTbl();
00248 tags.len = 0;
00249 tags.fp = NULL;
00250 }
00251
00252
00253 Context BindApplicationArgs(ClosureVC *clos, ArgList actuals, const Context& c) {
00254 Context result, closCon = clos->con;
00255 Exprs forms = clos->func->args->elems;
00256 Exprs acts = actuals->elems;
00257 int fSize = forms.size();
00258 int aSize = acts.size();
00259 Expr fe;
00260 AssignEC *formal;
00261 Text name;
00262 int i;
00263
00264 if (aSize > fSize + 1) {
00265 outputMu.lock();
00266 actuals->EError("Too many actual parameters:");
00267 outputMu.unlock();
00268 return conEmpty;
00269 }
00270 for (i = 0; i < aSize; i++) {
00271 if (i == fSize)
00272 name = nameDot;
00273 else {
00274 fe = forms.get(i);
00275 if (fe->kind == NameEK)
00276 name = ((Name)fe)->id;
00277 else if (fe->kind == AssignEK)
00278 name = ((AssignEC*)fe)->lhs->id;
00279 else {
00280 outputMu.lock();
00281 actuals->EError("Bad parameter list. It is neither actual nor default: `");
00282 ErrorExpr(fe);
00283 ErrorDetail("'.");
00284 outputMu.unlock();
00285 return conEmpty;
00286 }
00287 }
00288 PushToContext(name, acts.get(i), c, result);
00289 }
00290 for (i = aSize; i < fSize; i++) {
00291 fe = forms.get(i);
00292 if (fe->kind == AssignEK) {
00293 formal = (AssignEC*)fe;
00294 PushToContext(formal->lhs->id, formal->rhs, closCon, result);
00295 }
00296 else {
00297 outputMu.lock();
00298 actuals->EError("Bad parameter list. Must have default: `");
00299 ErrorExpr(fe);
00300 ErrorDetail("'.");
00301 outputMu.unlock();
00302 return conEmpty;
00303 }
00304 }
00305 if (aSize <= fSize) {
00306 Name eDot = NEW_CONSTR(NameEC, (nameDot, actuals->loc));
00307 PushToContext(nameDot, eDot, c, result);
00308 }
00309 return result;
00310 }
00311
00312 Val ApplicationFromCache(ClosureVC* clos, const Context& argsCon, SrcLoc *loc) {
00313 FP::Tag pk(evaluatorFunctionVersionTag);
00314 CompactFV::List fvNames;
00315 FV2::List entryNames;
00316 FP::List tags;
00317 CacheEntry::Index cIndex;
00318 VestaVal::T cVal;
00319 CacheIntf::LookupRes cResult = CacheIntf::Miss;
00320 Model::T model = clos->func->body->loc->shortId;
00321 Val result;
00322
00323 IncCounter(&appCallCounter);
00324 Context evalCon = argsCon.Append(clos->con);
00325
00326 ostream *traceRes = ThreadDataGet()->traceRes;
00327
00328 if (cacheOption != 3 || clos->func->noCache) {
00329
00330 if (traceRes) *traceRes << ": disabled\n";
00331 result = clos->func->body->Eval(evalCon);
00332 if (cacheOption < 2) return result;
00333 return FuncDpnd(result, clos, argsCon);
00334 }
00335
00336
00337
00338
00339 pk.Extend(clos->FingerPrintExpr());
00340 Context work = argsCon;
00341 (void)work.Pop();
00342 int last = clos->func->args->elems.size();
00343 Bit64 inPKs = clos->func->args->inPKs;
00344 Context inPKArgs;
00345 while (!work.Null()) {
00346 Assoc elem = work.Pop();
00347 if (inPKs & ((Bit64)1 << --last)) {
00348
00349 pk.Extend(elem->FingerPrint());
00350 inPKArgs.Push(elem);
00351 }
00352 else {
00353 switch (elem->val->vKind) {
00354 case BooleanVK: case IntegerVK: case PrimitiveVK:
00355 case TextVK: case ErrorVK:
00356 pk.Extend(elem->FingerPrint());
00357 inPKArgs.Push(elem);
00358 break;
00359 case ClosureVK:
00360 {
00361 FP::Tag tag(elem->name);
00362 tag.Extend(((ClosureVC*)elem->val)->FingerPrintExpr());
00363 pk.Extend(tag);
00364 break;
00365 }
00366 case ModelVK:
00367 {
00368 FP::Tag tag(elem->name);
00369 tag.Extend(((ModelVC*)elem->val)->FingerPrintFile());
00370 pk.Extend(tag);
00371 break;
00372 }
00373 case FpVK:
00374 assert(false);
00375 default:
00376 break;
00377 }
00378 }
00379 }
00380
00381 ThreadData *thdata = ThreadDataGet();
00382 CacheEntry::IndicesApp* orphanCIs = thdata->orphanCIs;
00383 try {
00384 while (true) {
00385 bool noEntry;
00386 FV::Epoch epoch = theCache->FreeVariables(pk, fvNames, noEntry);
00387 if (noEntry)
00388 cResult = CacheIntf::Miss;
00389 else {
00390 Tags(fvNames, evalCon, tags);
00391 cResult = theCache->Lookup(pk, epoch, tags, cIndex, cVal);
00392 }
00393 FreeNamesTags(fvNames, tags);
00394 if (cResult == CacheIntf::Hit) {
00395 if (Unpickle(cVal, evalCon, result)) {
00396 if (traceRes) {
00397 *traceRes << ": hit (ci=" << cIndex << ")\n";
00398 }
00399 IncCounter(&appHitCounter);
00400 UpdateOrphans(orphanCIs, orphanCIs->len, cIndex);
00401
00402
00403
00404
00405
00406
00407
00408 return FuncDpnd(result, clos, argsCon);
00409 }
00410 outputMu.lock();
00411 OBufStream l_msg;
00412 l_msg << "ApplicationFromCache: Cache hit but bad cache data." << endl << endl
00413 << "\tpk = " << pk << endl
00414 << "\tci = " << cIndex << endl << endl
00415 << "Evaluate as cache miss." << endl;
00416 Error(Text(l_msg.str()), loc);
00417 outputMu.unlock();
00418 cResult = CacheIntf::Miss;
00419 }
00420 if (cResult == CacheIntf::Miss) {
00421 if (traceRes) *traceRes << ": miss\n";
00422 int kidsIndex = orphanCIs->len;
00423 result = clos->func->body->Eval(evalCon);
00424 if (!noAddEntry) {
00425
00426 char *types;
00427 if (NamesTagsPickle(result, false, inPKArgs, types, entryNames,
00428 tags, cVal)) {
00429 CacheEntry::Indices kids;
00430 CollectKids(orphanCIs, kidsIndex, kids);
00431 Text pksource(clos->func->loc->file);
00432 pksource += "/" + clos->func->name;
00433 pksource += "(), line " + IntToText(clos->func->loc->line);
00434 pksource += ", col " + IntToText(clos->func->loc->character);
00435
00436 CacheIntf::AddEntryRes ae_res =
00437 theCache->AddEntry(pk, types, entryNames, tags, cVal, model,
00438 kids, pksource, cIndex);
00439
00440 if(ae_res != CacheIntf::EntryAdded)
00441 {
00442 outputMu.lock();
00443 Error(Text("AddEntry failed: ")+
00444 CacheIntf::AddEntryResName(ae_res)+"\n"
00445 "This may be an evaluator bug. "
00446 "Please report it.\n",
00447 loc);
00448 outputMu.unlock();
00449 if (traceRes) *traceRes << endl;
00450 throw(Evaluator::failure(Text("AddEntry failed (may be an "
00451 "evaluator bug)"),
00452 false));
00453 }
00454 UpdateOrphans(orphanCIs, kidsIndex, cIndex);
00455 Checkpoint();
00456 if (traceRes) {
00457 *traceRes << " " << thdata->funcCallDepth << ". "
00458 << clos->func->args->loc->file << ": "
00459 << clos->func->name << "(): add (ci=" << cIndex << ")\n";
00460 }
00461 }
00462 }
00463 return FuncDpnd(result, clos, argsCon);
00464 }
00465 if (cResult != CacheIntf::FVMismatch) {
00466 if (traceRes) *traceRes << ": mismatch\n";
00467 OBufStream err_msg;
00468 err_msg << "ApplicationFromCache got bad result: "
00469 << CacheIntf::LookupResName(cResult) << endl
00470 << "\tpk = " << pk << endl
00471 << "\tFV epoch = " << epoch << endl
00472 << "\ttags.len = " << tags.len << endl
00473 << "This may be an evaluator bug. Please report it." << endl;
00474 outputMu.lock();
00475 Error(Text(err_msg.str()), loc);
00476 outputMu.unlock();
00477 result = NEW(ErrorVC);
00478 return result;
00479 }
00480 }
00481 } catch (PrefixTbl::Overflow) {
00482 outputMu.lock();
00483 Error(Text("Internal limits exceeded: PrefixTbl overflow\n"),
00484 loc);
00485 cerr << "Caching function \"" << clos->func->name
00486 << "\" defined at:" << endl << endl
00487 << " " << clos->func->loc->file
00488 << ", line " << clos->func->loc->line
00489 << ", char " << clos->func->loc->character
00490 << endl << endl
00491 << Text("This usually means that there are too many free variables "
00492 "in the secondary key of the function being cached. This "
00493 "can often be alleviated by marking more arguments with "
00494 "the /**pk**/ pragma. (Fixing this will also reduce the CPU "
00495 "load of your evaluator and cache server, and improve "
00496 "build performance.)").WordWrap()
00497 << endl << endl;
00498
00499 abort();
00500 outputMu.unlock();
00501 } catch (SRPC::failure f) {
00502 outputMu.lock();
00503 Error(Text("ApplicationFromCache: SRPC failure (")
00504 + IntToText(f.r) + "): " + f.msg + ".\n",
00505 loc);
00506 outputMu.unlock();
00507 if (traceRes) *traceRes << endl;
00508 throw(Evaluator::failure(Text("Cache server is possibly down"), false));
00509 }
00510
00511 }
00512
00513 Val ApplyFunction(ClosureVC* clos, ApplyEC *ae, const Context& c) {
00514 ArgList args = ae->args;
00515 Context argsCon;
00516
00517 argsCon = BindApplicationArgs(clos, args, c);
00518
00519 ThreadData *thdata = ThreadDataGet();
00520 ostream *traceRes = thdata->traceRes;
00521 thdata->funcCallDepth++;
00522 if (traceRes) {
00523 *traceRes << " " << thdata->funcCallDepth << ". "
00524 << clos->func->args->loc->file << ": "
00525 << clos->func->name << "()";
00526 }
00527 if (argsCon == conEmpty) {
00528
00529
00530 outputMu.lock();
00531 ErrorDetail("\n Formal list is ");
00532 ErrorExpr(clos->func->args);
00533 ErrorDetail("\n Actual list is ");
00534 ErrorExpr(args);
00535 ErrorDetail("\n");
00536 outputMu.unlock();
00537 if (traceRes) *traceRes << ": badargs\n";
00538 return NEW(ErrorVC);
00539 }
00540
00541
00542 Val result = ApplicationFromCache(clos, argsCon, ae->loc);
00543 thdata->funcCallDepth--;
00544 return result;
00545 }
00546
00547
00548 Val NormalModelFromCache(ModelVC *fun, const Context& evalCon, SrcLoc *loc) {
00549 Model::T model = fun->content->sid;
00550 FP::Tag pk(evaluatorFunctionVersionTag);
00551 CompactFV::List fvNames;
00552 FV2::List entryNames;
00553 FP::List tags;
00554 CacheEntry::Index cIndex;
00555 VestaVal::T cVal;
00556 CacheIntf::LookupRes cResult = CacheIntf::Miss;
00557 Val result;
00558
00559 ThreadData *thdata = ThreadDataGet();
00560 ostream *traceRes = thdata->traceRes;
00561
00562
00563 if (((ModelEC*)fun->content->model)->ImportLocalModel()) {
00564 result = ((ModelEC*)fun->content->model)->block->Eval(evalCon);
00565 ModelCutOff(result);
00566 return result;
00567 }
00568
00569 IncCounter(&nModelCallCounter);
00570
00571 if (traceRes) {
00572 *traceRes << " " << thdata->funcCallDepth << ". " << fun->content->name;
00573 }
00574
00575
00576 pk.Extend(fun->FingerPrintFile());
00577
00578
00579 CacheEntry::IndicesApp* orphanCIs = ThreadDataGet()->orphanCIs;
00580 try {
00581 while (true) {
00582 bool noEntry;
00583 FV::Epoch epoch = theCache->FreeVariables(pk, fvNames, noEntry);
00584 if (noEntry)
00585 cResult = CacheIntf::Miss;
00586 else {
00587 Tags(fvNames, evalCon, tags);
00588 cResult = theCache->Lookup(pk, epoch, tags, cIndex, cVal);
00589 }
00590 FreeNamesTags(fvNames, tags);
00591 if (cResult == CacheIntf::Hit) {
00592 if (Unpickle(cVal, evalCon, result)) {
00593 if (traceRes) {
00594 *traceRes << ": hit (ci=" << cIndex << ")\n";
00595 }
00596 IncCounter(&nModelHitCounter);
00597 UpdateOrphans(orphanCIs, orphanCIs->len, cIndex);
00598 return result;
00599 }
00600 outputMu.lock();
00601 OBufStream l_msg;
00602 l_msg << "NormalModelFromCache: Cache hit but bad cache data." << endl << endl
00603 << "\tpk = " << pk << endl
00604 << "\tci = " << cIndex << endl << endl
00605 << "Evaluate as cache miss." << endl;
00606 Error(Text(l_msg.str()), loc);
00607 outputMu.unlock();
00608 throw(Evaluator::failure(Text("Bad cache data"), false));
00609 }
00610 if (cResult == CacheIntf::Miss) {
00611 if (traceRes) *traceRes << ": miss\n";
00612 int kidsIndex = orphanCIs->len;
00613 result = ((ModelEC*)fun->content->model)->block->Eval(evalCon);
00614 if (!noAddEntry) {
00615
00616 char *types;
00617 if (NamesTagsPickle(result, true, conEmpty, types, entryNames,
00618 tags, cVal)) {
00619 CacheEntry::Indices kids;
00620 CollectKids(orphanCIs, kidsIndex, kids);
00621 Text pksource(fun->content->name);
00622 pksource += "() (normal)";
00623
00624 CacheIntf::AddEntryRes ae_res =
00625 theCache->AddEntry(pk, types, entryNames, tags, cVal, model,
00626 kids, pksource, cIndex);
00627
00628 if(ae_res != CacheIntf::EntryAdded)
00629 {
00630 outputMu.lock();
00631 Error(Text("AddEntry failed: ")+
00632 CacheIntf::AddEntryResName(ae_res)+"\n"
00633 "This may be an evaluator bug. "
00634 "Please report it.\n",
00635 loc);
00636 outputMu.unlock();
00637 if (traceRes) *traceRes << endl;
00638 throw(Evaluator::failure(Text("AddEntry failed (may be an "
00639 "evaluator bug)"),
00640 false));
00641 }
00642 UpdateOrphans(orphanCIs, kidsIndex, cIndex);
00643 Checkpoint();
00644 if (traceRes) {
00645 *traceRes << " " << thdata->funcCallDepth << ". " << fun->content->name
00646 << ": add (ci=" << cIndex << ")\n";
00647 }
00648 }
00649 }
00650 return result;
00651 }
00652 if (cResult != CacheIntf::FVMismatch) {
00653 if (traceRes) *traceRes << ": mismatch\n";
00654 OBufStream err_msg;
00655 err_msg << "NormalModelFromCache got bad result: "
00656 << CacheIntf::LookupResName(cResult) << endl
00657 << "\tpk = " << pk << endl
00658 << "\tFV epoch = " << epoch << endl
00659 << "\ttags.len = " << tags.len << endl
00660 << "This may be an evaluator bug. Please report it." << endl;
00661 outputMu.lock();
00662 Error(Text(err_msg.str()), loc);
00663 outputMu.unlock();
00664 result = NEW(ErrorVC);
00665 return result;
00666 }
00667 }
00668 } catch (PrefixTbl::Overflow) {
00669 outputMu.lock();
00670 Error(Text("Internal limits exceeded: PrefixTbl overflow\n"),
00671 loc);
00672 cerr << "Caching model (normal):" << endl << endl
00673 << " " << fun->content->name
00674 << endl << endl
00675 << Text("This usually means that there are too many free variables "
00676 "in the secondary key of the function being cached. For "
00677 "models, this may mean too much work is being done in a "
00678 "single model file. Try splitting up the work of this "
00679 "model file into several separate model files each doing "
00680 "a smaller amount of work. (Fixing this will also reduce "
00681 "the CPU load of your evaluator and cache server, and "
00682 "improve build performance.)").WordWrap()
00683 << endl << endl;
00684
00685 abort();
00686 outputMu.unlock();
00687 } catch (SRPC::failure f) {
00688 outputMu.lock();
00689 fun->VError(Text("NormalModelFromCache: SRPC failure (")
00690 + IntToText(f.r) + "): " + f.msg + ".\n");
00691 outputMu.unlock();
00692 if (traceRes) *traceRes << endl;
00693 throw(Evaluator::failure(Text("Cache server is possibly down"), false));
00694 }
00695 }
00696
00697 Val ModelFromCache(ModelVC* fun, const Context& argsCon, SrcLoc *loc) {
00698 Context evalCon;
00699 Model::T model = fun->content->sid;
00700 FP::Tag pk(evaluatorFunctionVersionTag);
00701 CompactFV::List fvNames;
00702 FV2::List entryNames;
00703 FP::List tags;
00704 CacheEntry::Index cIndex;
00705 VestaVal::T cVal;
00706 CacheIntf::LookupRes cResult = CacheIntf::Miss;
00707 Val result;
00708
00709 IncCounter(&sModelCallCounter);
00710 ThreadData *thdata = ThreadDataGet();
00711 ostream *traceRes = thdata->traceRes;
00712
00713
00714 if (cacheOption < 2) {
00715 if (traceRes) *traceRes << ": disabled\n";
00716 Val fun1 = ((ModelVC*)fun)->Force();
00717 if (fun1->vKind == ModelVK) {
00718 ModelEC *modelExpr = (ModelEC*)((ModelVC*)fun1)->content->model;
00719 evalCon = argsCon.Append(((ModelVC*)fun1)->content->c);
00720 return modelExpr->block->Eval(evalCon);
00721 }
00722 outputMu.lock();
00723 Error("Trying to apply a model that failed to parse: `", loc);
00724 ErrorVal(fun1);
00725 ErrorDetail("'.\n");
00726 outputMu.unlock();
00727 result = NEW(ErrorVC);
00728 return result;
00729 }
00730
00731
00732 pk.Extend(fun->FingerPrint());
00733
00734
00735 CacheEntry::IndicesApp* orphanCIs = ThreadDataGet()->orphanCIs;
00736 try {
00737 while (true) {
00738 bool noEntry;
00739 FV::Epoch epoch = theCache->FreeVariables(pk, fvNames, noEntry);
00740 if (noEntry)
00741 cResult = CacheIntf::Miss;
00742 else {
00743 Tags(fvNames, argsCon, tags);
00744 cResult = theCache->Lookup(pk, epoch, tags, cIndex, cVal);
00745 }
00746 FreeNamesTags(fvNames, tags);
00747 if (cResult == CacheIntf::Hit) {
00748 if (Unpickle(cVal, argsCon, result)) {
00749 if (traceRes) {
00750 *traceRes << ": hit (ci=" << cIndex << ")\n";
00751 }
00752 IncCounter(&sModelHitCounter);
00753 UpdateOrphans(orphanCIs, orphanCIs->len, cIndex);
00754 return ModelDpnd(result, fun, argsCon);
00755 }
00756 outputMu.lock();
00757 OBufStream l_msg;
00758 l_msg << "ModelFromCache: Cache hit but bad cache data." << endl << endl
00759 << "\tpk = " << pk << endl
00760 << "\tci = " << cIndex << endl << endl
00761 << "Evaluate as cache miss." << endl;
00762 Error(Text(l_msg.str()), loc);
00763 outputMu.unlock();
00764 throw(Evaluator::failure(Text("Bad cache data"), false));
00765 }
00766 if (cResult == CacheIntf::Miss) {
00767 if (traceRes) *traceRes << ": miss\n";
00768 int kidsIndex = orphanCIs->len;
00769 Val fun1 = ((ModelVC*)fun)->Force();
00770 if (fun1->vKind == ModelVK) {
00771 evalCon = argsCon.Append(((ModelVC*)fun1)->content->c);
00772 result = NormalModelFromCache(fun, evalCon, loc);
00773 if (noAddEntry) {
00774 ModelCutOff(result);
00775 }
00776 else {
00777
00778 char *types;
00779 if (NamesTagsPickle(result, false, conEmpty, types, entryNames,
00780 tags, cVal)) {
00781 CacheEntry::Indices kids;
00782 CollectKids(orphanCIs, kidsIndex, kids);
00783 Text pksource(fun->content->name);
00784 pksource += "() (special)";
00785
00786 CacheIntf::AddEntryRes ae_res =
00787 theCache->AddEntry(pk, types, entryNames, tags, cVal, model,
00788 kids, pksource, cIndex);
00789
00790 if(ae_res != CacheIntf::EntryAdded)
00791 {
00792 outputMu.lock();
00793 Error(Text("AddEntry failed: ")+
00794 CacheIntf::AddEntryResName(ae_res)+"\n"
00795 "This may be an evaluator bug. "
00796 "Please report it.\n",
00797 loc);
00798 outputMu.unlock();
00799 if (traceRes) *traceRes << endl;
00800 throw(Evaluator::failure(Text("AddEntry failed (may be an "
00801 "evaluator bug)"),
00802 false));
00803 }
00804 UpdateOrphans(orphanCIs, kidsIndex, cIndex);
00805 Checkpoint();
00806 if (traceRes) {
00807 *traceRes << " " << thdata->funcCallDepth << ". " << fun->content->name
00808 << ": add (ci=" << cIndex << ")\n";
00809 }
00810 }
00811 }
00812 return ModelDpnd(result, fun, argsCon);
00813 }
00814 outputMu.lock();
00815 Error("Trying to apply a model that failed to parse: `", loc);
00816 ErrorVal(fun1);
00817 ErrorDetail("'.\n");
00818 outputMu.unlock();
00819 result = NEW(ErrorVC);
00820 return result->Merge(fun);
00821 }
00822 if (cResult != CacheIntf::FVMismatch) {
00823 if (traceRes) *traceRes << ": mismatch\n";
00824 OBufStream err_msg;
00825 err_msg << "ModelFromCache got bad result: "
00826 << CacheIntf::LookupResName(cResult) << endl
00827 << "\tpk = " << pk << endl
00828 << "\tFV epoch = " << epoch << endl
00829 << "\ttags.len = " << tags.len << endl
00830 << "This may be an evaluator bug. Please report it." << endl;
00831 outputMu.lock();
00832 Error(Text(err_msg.str()), loc);
00833 outputMu.unlock();
00834 result = NEW(ErrorVC);
00835 return result;
00836 }
00837 }
00838 } catch (PrefixTbl::Overflow) {
00839 outputMu.lock();
00840 Error(Text("Internal limits exceeded: PrefixTbl overflow\n"),
00841 loc);
00842 cerr << "Caching model (special):" << endl << endl
00843 << " " << fun->content->name
00844 << endl << endl
00845 << Text("This usually means that there are too many free variables "
00846 "in the secondary key of the function being cached. For "
00847 "models, this may mean too much work is being done in a "
00848 "single model file. Try splitting up the work of this "
00849 "model file into several separate model files each doing "
00850 "a smaller amount of work. (Fixing this will also reduce "
00851 "the CPU load of your evaluator and cache server, and "
00852 "improve build performance.)").WordWrap()
00853 << endl << endl;
00854
00855 abort();
00856 outputMu.unlock();
00857 } catch (SRPC::failure f) {
00858 outputMu.lock();
00859 Error(Text("ModelFromCache: SRPC failure (") + IntToText(f.r) + "): " + f.msg + ".\n",
00860 loc);
00861 outputMu.unlock();
00862 if (traceRes) *traceRes << endl;
00863 throw(Evaluator::failure(Text("Cache server is possibly down"), false));
00864 }
00865
00866 }
00867
00868 Val ApplyModel(ModelVC* fun, ApplyEC *ae, const Context& c) {
00869
00870
00871
00872
00873
00874 ArgList args = ae->args;
00875 Exprs acts = args->elems;
00876 Context argsCon;
00877
00878 ThreadData *thdata = ThreadDataGet();
00879 ostream *traceRes = thdata->traceRes;
00880
00881
00882 int aSize = acts.size();
00883 if (aSize == 0) {
00884 Name eDot = NEW_CONSTR(NameEC, (nameDot, args->loc));
00885 PushToContext(nameDot, eDot, c, argsCon);
00886 }
00887 else if (aSize == 1)
00888 PushToContext(nameDot, acts.getlo(), c, argsCon);
00889 else {
00890 outputMu.lock();
00891 args->EError("Too many actual parameters:");
00892 outputMu.unlock();
00893 thdata->funcCallDepth++;
00894 if (traceRes) {
00895 *traceRes << " " << thdata->funcCallDepth << ". " << fun->content->name;
00896 *traceRes << ": badargs\n";
00897 }
00898 thdata->funcCallDepth--;
00899 return NEW(ErrorVC);
00900 }
00901
00902 thdata->funcCallDepth++;
00903
00904 if (traceRes) {
00905 *traceRes << " " << thdata->funcCallDepth << ". " << fun->content->name;
00906 }
00907
00908
00909 Val result = ModelFromCache(fun, argsCon, ae->loc);
00910 thdata->funcCallDepth--;
00911 return result;
00912 }
00913
00914
00915 bool CheckTreatment(TextVC *tr) {
00916 Text txt(tr->NDS());
00917 return (txt == "ignore" ||
00918 txt == "report" ||
00919 txt == "report_nocache" ||
00920 txt == "value" ||
00921 txt == "report_value");
00922 }
00923
00924 bool AllTexts(BindingVC *b) {
00925 Context work = b->elems;
00926 while (!work.Null()) {
00927 Assoc a = work.Pop();
00928 if (a->val->vKind != TextVK) return false;
00929 }
00930 return true;
00931 }
00932
00933 bool BindRunToolArgs(ArgList args, const Context& c,
00934 RunToolArgs& runToolArgs) {
00935
00936 int nArgs = args->Length();
00937 Exprs elems = args->elems;
00938 Val val;
00939
00940 if (nArgs < 2) {
00941 outputMu.lock();
00942 args->EError("Too few actual parameters:");
00943 outputMu.unlock();
00944 return false;
00945 }
00946 if (nArgs > 11) {
00947 outputMu.lock();
00948 args->EError("Too many actual parameters:");
00949 outputMu.unlock();
00950 return false;
00951 }
00952
00953
00954 val = elems.get(0)->Eval(c);
00955 if (val->vKind != TextVK) {
00956 outputMu.lock();
00957 args->EError("The `platform' argument to _run_tool must be a text:");
00958 outputMu.unlock();
00959 return false;
00960 }
00961 runToolArgs.platform = (TextVC*)val;
00962
00963
00964 val = elems.get(1)->Eval(c);
00965 bool ok = false;
00966 if (val->vKind == ListVK) {
00967 Vals vs = ((ListVC*)val)->elems;
00968 ok = true;
00969 while (!vs.Null())
00970 if (vs.Pop()->vKind != TextVK) { ok = false; break; }
00971 }
00972 if (!ok) {
00973 outputMu.lock();
00974 args->EError("The `command' argument to _run_tool must be a list of texts:");
00975 outputMu.unlock();
00976 return false;
00977 }
00978 runToolArgs.command_line = (ListVC*)val;
00979
00980
00981 if (nArgs <= 2) {
00982 Text stdin_default(emptyText);
00983 val = NEW_CONSTR(TextVC, (stdin_default));
00984 }
00985 else {
00986 val = elems.get(2)->Eval(c);
00987 if (val->vKind != TextVK) {
00988 outputMu.lock();
00989 args->EError("The `stdin' argument to _run_tool must be a text:");
00990 outputMu.unlock();
00991 return false;
00992 }
00993 }
00994 runToolArgs.stdin_data = (TextVC*)val;
00995
00996
00997 if (nArgs <= 3) {
00998 Text stdout_treatment_default("report");
00999 val = NEW_CONSTR(TextVC, (stdout_treatment_default));
01000 }
01001 else {
01002 val = elems.get(3)->Eval(c);
01003 if (val->vKind != TextVK || !CheckTreatment((TextVC*)val)) {
01004 outputMu.lock();
01005 args->EError("The `stdout_treatment' argument to _run_tool is not a suitable text:");
01006 outputMu.unlock();
01007 return false;
01008 }
01009 }
01010 runToolArgs.stdout_treatment = (TextVC*)val;
01011
01012
01013 if (nArgs <= 4) {
01014 Text stderr_treatment_default("report");
01015 val = NEW_CONSTR(TextVC, (stderr_treatment_default));
01016 }
01017 else {
01018 val = elems.get(4)->Eval(c);
01019 if (val->vKind != TextVK || !CheckTreatment((TextVC *)val)) {
01020 outputMu.lock();
01021 args->EError("The `stderr_treatment' argument to _run_tool is not a suitable text:");
01022 outputMu.unlock();
01023 return false;
01024 }
01025 }
01026 runToolArgs.stderr_treatment = (TextVC*)val;
01027
01028
01029 if (nArgs <= 5) {
01030 Text status_treatment_default("report_nocache");
01031 val = NEW_CONSTR(TextVC, (status_treatment_default));
01032 }
01033 else {
01034 val = elems.get(5)->Eval(c);
01035 if (val->vKind != TextVK || !CheckTreatment((TextVC *)val)) {
01036 outputMu.lock();
01037 args->EError("The `status_treatment' argument to _run_tool is not a suitable text:");
01038 outputMu.unlock();
01039 return false;
01040 }
01041 }
01042 runToolArgs.status_treatment = (TextVC*)val;
01043
01044
01045 if (nArgs <= 6) {
01046 Text signal_treatment_default("report_nocache");
01047 val = NEW_CONSTR(TextVC, (signal_treatment_default));
01048 }
01049 else {
01050 val = elems.get(6)->Eval(c);
01051 if (val->vKind != TextVK || !CheckTreatment((TextVC *)val)) {
01052 outputMu.lock();
01053 args->EError("The `signal_treatment' argument to _run_tool is not a suitable text:");
01054 outputMu.unlock();
01055 return false;
01056 }
01057 }
01058 runToolArgs.signal_treatment = (TextVC*)val;
01059
01060
01061 if (nArgs <= 7) {
01062 val = fpContent;
01063 }
01064 else {
01065 val = elems.get(7)->Eval(c);
01066 if (val->vKind == BooleanVK) {
01067 val = NEW_CONSTR(IntegerVC, (((BooleanVC*)val)->b ? -1 : 0));
01068 }
01069 else if (val->vKind != IntegerVK) {
01070 outputMu.lock();
01071 args->EError("The `fp_content' argument to _run_tool must be an integer or boolean:");
01072 outputMu.unlock();
01073 return false;
01074 }
01075 else if (((IntegerVC*)val)->num == -2) {
01076 val = fpContent;
01077 }
01078 }
01079 runToolArgs.fp_content = (IntegerVC*)val;
01080
01081
01082 if (nArgs <= 8) {
01083 Text wd_name(".WD");
01084 val = NEW_CONSTR(TextVC, (wd_name));
01085 }
01086 else {
01087 val = elems.get(8)->Eval(c);
01088 if (val->vKind != TextVK) {
01089 outputMu.lock();
01090 args->EError("The `wd' argument to _run_tool must be a text:");
01091 outputMu.unlock();
01092 return false;
01093 }
01094 }
01095 runToolArgs.wd_name = (TextVC*)val;
01096
01097
01098 if (nArgs <= 9) {
01099 val = NEW_CONSTR(BooleanVC, (false));
01100 }
01101 else {
01102 val = elems.get(9)->Eval(c);
01103 if (val->vKind != BooleanVK) {
01104 outputMu.lock();
01105 args->EError("The `existing_writable' argument to _run_tool must be a boolean:");
01106 outputMu.unlock();
01107 return false;
01108 }
01109 }
01110 runToolArgs.existing_writable = (BooleanVC*)val;
01111
01112
01113 if (nArgs <= 10) {
01114 val = LookupInContext(nameDot, c);
01115 if (val->vKind != BindingVK) {
01116 outputMu.lock();
01117 args->EError("The `.' argument to _run_tool must be a binding:");
01118 outputMu.unlock();
01119 return false;
01120 }
01121 }
01122 else {
01123 val = elems.get(10)->Eval(c);
01124 if (val->vKind != BindingVK) {
01125 outputMu.lock();
01126 args->EError("The `.' argument to _run_tool must be a binding:");
01127 outputMu.unlock();
01128 return false;
01129 }
01130 }
01131 runToolArgs.dot = (BindingVC *)val;
01132 Val envVars = runToolArgs.dot->Lookup("envVars");
01133 if (envVars->vKind != BindingVK || !AllTexts((BindingVC*)envVars)) {
01134 outputMu.lock();
01135 args->EError("./envVars isn't a binding of texts:");
01136 outputMu.unlock();
01137 return false;
01138 }
01139 Val root = runToolArgs.dot->Lookup("root");
01140 if (root->vKind != BindingVK) {
01141 outputMu.lock();
01142 args->EError("./root isn't a binding:");
01143 outputMu.unlock();
01144 return false;
01145 }
01146
01147
01148 runToolArgs.loc = args->loc;
01149 return true;
01150 }
01151
01152 void RunToolPK(const RunToolArgs& runToolArgs, FP::Tag &pk) {
01153
01154
01155
01156 pk.Extend("_run_tool");
01157 pk.Extend(runToolArgs.platform->FingerPrint());
01158 pk.Extend(runToolArgs.command_line->FingerPrint());
01159 pk.Extend(runToolArgs.stdin_data->FingerPrint());
01160 pk.Extend(runToolArgs.stdout_treatment->FingerPrint());
01161 pk.Extend(runToolArgs.stderr_treatment->FingerPrint());
01162 pk.Extend(runToolArgs.status_treatment->FingerPrint());
01163 pk.Extend(runToolArgs.signal_treatment->FingerPrint());
01164 pk.Extend(runToolArgs.fp_content->FingerPrint());
01165 pk.Extend(runToolArgs.wd_name->FingerPrint());
01166 if (runToolArgs.existing_writable->b)
01167 pk.Extend(runToolArgs.existing_writable->FingerPrint());
01168 Val envVars = runToolArgs.dot->Lookup("envVars");
01169 pk.Extend(envVars->FingerPrint());
01170 }
01171
01172 Val MergeArgsDpnd(Val result, const RunToolArgs& args) {
01173
01174 result->Merge(args.platform);
01175
01176 ListVC *command = args.command_line;
01177 result->Merge(command);
01178 if (!command->path) {
01179 if (command->lenDps != NULL &&
01180 command->lenDps->Size() != 0) {
01181 DPaths psTemp;
01182 ValueDpnd(command, &psTemp);
01183 result->MergeDPS(&psTemp);
01184 }
01185 else {
01186 Vals vs = command->elems;
01187 while (!vs.Null())
01188 result->Merge(vs.Pop());
01189 }
01190 }
01191 result->Merge(args.stdin_data);
01192 result->Merge(args.stdout_treatment);
01193 result->Merge(args.stderr_treatment);
01194 result->Merge(args.wd_name);
01195 return result;
01196 }
01197
01198 static Basics::thread renewLeaseThread;
01199
01200 static void* RenewLeases(void *arg) throw () {
01201 time_t tsStart;
01202
01203 time_t sleepDuration = 10;
01204
01205
01206 unsigned int server_busy_count = 0;
01207
01208 while (true) {
01209 int left = sleepDuration;
01210 do {
01211 left = sleep(left);
01212 } while (left > 0);
01213
01214
01215 leaseMu.lock();
01216 if (time(&tsStart) - lastRenewed > leaseDuration) {
01217 leaseMu.unlock();
01218
01219
01220 if(server_busy_count > 0)
01221 {
01222 outputMu.lock();
01223 Error(Text("RenewLeases thread got \"connection refused: server busy\" ") +
01224 IntToText(server_busy_count) + " times, and now leases have expired!\n");
01225 outputMu.unlock();
01226 }
01227 return NULL;
01228 }
01229 leaseMu.unlock();
01230
01231
01232 CacheEntry::IndicesApp orphanCIs;
01233 frontierMu.lock();
01234 ThreadData::mu.lock();
01235 ThreadData* cur = ThreadData::head;
01236 while (cur) {
01237 assert(cur->orphanCIs != 0);
01238 for (int i = 0; i < cur->orphanCIs->len; i++) {
01239 orphanCIs.Append(cur->orphanCIs->index[i]);
01240 }
01241 cur = cur->next;
01242 }
01243 ThreadData::mu.unlock();
01244 frontierMu.unlock();
01245
01246 bool renewed = false;
01247 try
01248 {
01249
01250 renewed = theCache->RenewLeases(orphanCIs);
01251
01252
01253 server_busy_count = 0;
01254
01255
01256
01257 if(!renewed)
01258 {
01259 outputMu.lock();
01260 Error(Text("RenewLeases returned failure!\n") +
01261 "This may be a bug. Please reposrt it.\n");
01262 outputMu.unlock();
01263
01264 leaseMu.lock();
01265 renewLease_failure = true;
01266 leaseMu.unlock();
01267
01268 return NULL;
01269 }
01270 }
01271
01272 catch (SRPC::failure f)
01273 {
01274
01275
01276
01277 if((f.r == 1) && (f.msg.FindText("connection refused: server busy") != -1))
01278 {
01279 server_busy_count++;
01280 }
01281
01282 else
01283 {
01284
01285
01286
01287 outputMu.lock();
01288 Error(Text("RenewLeases thread: SRPC failure (")
01289 + IntToText(f.r) + "): " + f.msg + ".\n");
01290 outputMu.unlock();
01291
01292 leaseMu.lock();
01293 renewLease_failure = true;
01294 leaseMu.unlock();
01295
01296 return NULL;
01297 }
01298 }
01299
01300
01301 leaseMu.lock();
01302 if (time(NULL) - lastRenewed > leaseDuration) {
01303 leaseMu.unlock();
01304
01305
01306 if(server_busy_count > 0)
01307 {
01308 outputMu.lock();
01309 Error(Text("RenewLeases thread got \"connection refused: server busy\" ") +
01310 IntToText(server_busy_count) + " times, and now leases have expired!\n");
01311 outputMu.unlock();
01312 }
01313 return NULL;
01314 }
01315
01316 if(renewed)
01317 {
01318
01319 lastRenewed = tsStart;
01320 }
01321 leaseMu.unlock();
01322 }
01323 }
01324
01325 void StartRenewLeaseThread() {
01326 if (cacheOption != 0) {
01327 time(&lastRenewed);
01328 renewLeaseThread.fork_and_detach(RenewLeases, (void*)NULL);
01329 }
01330 }
01331
01332 Val RunToolFromCache(const RunToolArgs& runToolArgs, const Context& c, SrcLoc *loc) {
01333 FP::Tag pk(evaluatorRunToolVersionTag);
01334 CompactFV::List fvNames;
01335 FV2::List entryNames;
01336 FP::List tags;
01337 CacheEntry::Index cIndex;
01338 VestaVal::T cVal;
01339 CacheIntf::LookupRes cResult = CacheIntf::Miss;
01340 Model::T model = NullShortId;
01341 Val result;
01342 VestaSource* rootForTool;
01343
01344 ThreadData *thdata = ThreadDataGet();
01345 ostream *traceRes = thdata->traceRes;
01346
01347
01348 if (cacheOption == 0) {
01349 if (traceRes) *traceRes << ": disabled\n";
01350 result = RunTool(runToolArgs, rootForTool);
01351 DeleteRootForTool(rootForTool);
01352 return result;
01353 }
01354
01355
01356 RunToolPK(runToolArgs, pk);
01357
01358
01359 CacheEntry::IndicesApp* orphanCIs = ThreadDataGet()->orphanCIs;
01360 try {
01361 while (true) {
01362 bool noEntry;
01363 FV::Epoch epoch = theCache->FreeVariables(pk, fvNames, noEntry);
01364 if (noEntry)
01365 cResult = CacheIntf::Miss;
01366 else {
01367 Tags(fvNames, c, tags);
01368 cResult = theCache->Lookup(pk, epoch, tags, cIndex, cVal);
01369 }
01370 FreeNamesTags(fvNames, tags);
01371 if (cResult == CacheIntf::Hit) {
01372 if (Unpickle(cVal, c, result)) {
01373 if (traceRes) *traceRes << ": hit(ci=" << cIndex << ")\n";
01374 IncCounter(&toolHitCounter);
01375 if (cacheOption == 1) {
01376 result->dps = NULL;
01377 return result;
01378 }
01379 UpdateOrphans(orphanCIs, orphanCIs->len, cIndex);
01380 return MergeArgsDpnd(result, runToolArgs);
01381 }
01382 outputMu.lock();
01383 OBufStream l_msg;
01384 l_msg << "RunToolFromCache: Cache hit but bad cache data." << endl << endl
01385 << "\tpk = " << pk << endl
01386 << "\tci = " << cIndex << endl << endl
01387 << "Evaluate as cache miss." << endl;
01388 Error(Text(l_msg.str()), loc);
01389 outputMu.unlock();
01390 cResult = CacheIntf::Miss;
01391 }
01392 if (cResult == CacheIntf::Miss) {
01393 if (traceRes) *traceRes << ": miss\n";
01394 int kidsIndex = orphanCIs->len;
01395
01396
01397 rtt_cond *rttCond;
01398 runToolTableMu.lock();
01399 bool found = runToolTable.Get(pk, rttCond);
01400 if(!found) {
01401 rttCond = NEW(rtt_cond);
01402 runToolTable.Put(pk, rttCond);
01403 runToolTableMu.unlock();
01404 } else {
01405
01406
01407 outputMu.lock();
01408 cerr << ThreadLabel() << "Waiting on possbily identical tool run" << endl;
01409 outputMu.unlock();
01410 rttCond->wait();
01411
01412
01413 runToolTableMu.unlock();
01414 continue;
01415 }
01416
01417 try {
01418 result = RunTool(runToolArgs, rootForTool);
01419 char *types;
01420 if (!noAddEntry &&
01421 NamesTagsPickle(result, false, conEmpty, types, entryNames,
01422 tags, cVal)) {
01423 CacheEntry::Indices kids;
01424 CollectKids(orphanCIs, kidsIndex, kids);
01425
01426
01427 Text pksource("_run_tool, command line: ");
01428 pksource += ToolCommandLineAsText(runToolArgs);
01429
01430
01431 CacheIntf::AddEntryRes ae_res =
01432 theCache->AddEntry(pk, types, entryNames, tags, cVal, model,
01433 kids, pksource, cIndex);
01434
01435 if(ae_res != CacheIntf::EntryAdded)
01436 {
01437 outputMu.lock();
01438 Error(Text("AddEntry failed: ")+
01439 CacheIntf::AddEntryResName(ae_res)+"\n"
01440 "This may be an evaluator bug. "
01441 "Please report it.\n",
01442 loc);
01443 outputMu.unlock();
01444 if (traceRes) *traceRes << endl;
01445 throw(Evaluator::failure(Text("AddEntry failed (may be an "
01446 "evaluator bug)"),
01447 false));
01448 }
01449
01450 UpdateOrphans(orphanCIs, kidsIndex, cIndex);
01451 Checkpoint();
01452 if (traceRes) {
01453 *traceRes << " " << thdata->funcCallDepth << ". " << loc->file << ": "
01454 << "_run_tool(): add (ci=" << cIndex << ")\n";
01455 }
01456 }
01457
01458 runToolTableMu.lock();
01459 runToolTable.Delete(pk, rttCond);
01460 rttCond->wake();
01461 runToolTableMu.unlock();
01462 } catch(...) {
01463 runToolTableMu.lock();
01464 runToolTable.Delete(pk, rttCond);
01465 rttCond->wake();
01466 runToolTableMu.unlock();
01467 throw;
01468 }
01469
01470
01471
01472 DeleteRootForTool(rootForTool);
01473 if (cacheOption == 1) {
01474 result->dps = NULL;
01475 return result;
01476 }
01477 return MergeArgsDpnd(result, runToolArgs);
01478 }
01479 if (cResult != CacheIntf::FVMismatch) {
01480 if (traceRes) *traceRes << ": mismatch\n";
01481 OBufStream err_msg;
01482 err_msg << "RunToolFromCache got bad result: "
01483 << CacheIntf::LookupResName(cResult) << endl
01484 << "\tpk = " << pk << endl
01485 << "\tFV epoch = " << epoch << endl
01486 << "\ttags.len = " << tags.len << endl
01487 << "This may be an evaluator bug. Please report it." << endl;
01488 outputMu.lock();
01489 Error(Text(err_msg.str()), loc);
01490 outputMu.unlock();
01491 result = NEW(ErrorVC);
01492 return result;
01493 }
01494 }
01495 } catch (PrefixTbl::Overflow) {
01496 outputMu.lock();
01497 Error(Text("Internal limits exceeded: PrefixTbl overflow\n"),
01498 loc);
01499 cerr << "Caching _run_tool with command line:" << endl << endl
01500 << " " << ToolCommandLineAsText(runToolArgs) << endl << endl
01501 << Text("This usually means that there are too many free variables "
01502 "in the secondary key of the function being cached. For "
01503 "_run_tool calls, this may mean you're trying to do too "
01504 "much work in a single tool invocation. Try splitting the "
01505 "work of this tool invocation into several separate tool "
01506 "invocations each doing a smaller amount of work and using "
01507 "a smaller number of source files. (Fixing this will also "
01508 "reduce the CPU load of your evaluator and cache server, and "
01509 "improve build performance.)").WordWrap()
01510 << endl << endl;
01511
01512 abort();
01513 outputMu.unlock();
01514 } catch (SRPC::failure f) {
01515 outputMu.lock();
01516 Error(Text("RunToolFromCache: SRPC failure (")
01517 + IntToText(f.r) + "): " + f.msg + ".\n",
01518 loc);
01519 outputMu.unlock();
01520 if (traceRes) *traceRes << endl;
01521 throw(Evaluator::failure(Text("Cache server is possibly down"), false));
01522 }
01523
01524 }
01525
01526 Val ApplyRunTool(ArgList args, const Context& c) {
01527 RunToolArgs runToolArgs;
01528
01529 ThreadData *thdata = ThreadDataGet();
01530 ostream *traceRes = thdata->traceRes;
01531
01532 IncCounter(&toolCallCounter);
01533 if (!BindRunToolArgs(args, c, runToolArgs)) {
01534 thdata->funcCallDepth++;
01535 if (traceRes) {
01536 *traceRes << " " << thdata->funcCallDepth << ". " << args->loc->file << ": ";
01537 *traceRes << "_run_tool()";
01538 *traceRes << ": badargs\n";
01539 }
01540 thdata->funcCallDepth--;
01541 return NEW(ErrorVC);
01542 }
01543 thdata->funcCallDepth++;
01544 if (traceRes) {
01545 *traceRes << " " << thdata->funcCallDepth << ". " << args->loc->file << ": ";
01546 *traceRes << "_run_tool()";
01547 }
01548
01549
01550 Val result = RunToolFromCache(runToolArgs, c, args->loc);
01551 thdata->funcCallDepth--;
01552 return result;
01553 }