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 #include <algorithm>
00037
00038 using std::ostream;
00039 using std::endl;
00040 using Basics::OBufStream;
00041 using OS::cio;
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
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094 extern int currentPickleVersion;
00095 static const Basics::int32 currentPickleVersion_net = Basics::hton32(currentPickleVersion);
00096
00097
00098 const char *evaluatorRunToolVersion = "Wed Aug 16 13:07:11 EDT 2006";
00099 const FP::Tag evaluatorRunToolVersionTag(evaluatorRunToolVersion);
00100
00101
00102 const char *evaluatorFunctionVersion = "Thu Oct 26 01:44:45 2006";
00103 const FP::Tag evaluatorFunctionVersionTag(evaluatorFunctionVersion);
00104
00105
00106 static int addEntryCount = 0;
00107
00108
00109
00110 static Basics::mutex leaseMu;
00111 static time_t lastRenewed;
00112 static bool renewLease_failure = false;
00113
00114
00115
00116
00117 static Basics::mutex runningPkTableMu;
00118 class rpt_cond {
00119 Basics::cond cond;
00120 int count;
00121 bool dec_and_del() {
00122 assert(count > 0);
00123 if(--count == 0) {
00124 delete this;
00125 return false;
00126 } else {
00127 return true;
00128 }
00129 };
00130 public:
00131 rpt_cond() { count = 1; };
00132 void wait() {
00133 count++;
00134 cond.wait(runningPkTableMu);
00135 (void) dec_and_del();
00136 };
00137 void wake() {
00138 if(dec_and_del()) {
00139 cond.broadcast();
00140 }
00141 };
00142
00143 };
00144 static Table<FP::Tag, rpt_cond *>::Default runningPkTable;
00145
00146
00147
00148
00149
00150 bool WaitForDuplicateEval(FP::Tag pk, const char *thing) {
00151 rpt_cond *rptCond = 0;
00152 runningPkTableMu.lock();
00153 bool found = runningPkTable.Get(pk, rptCond);
00154 if(!found) {
00155 rptCond = NEW_PTRFREE(rpt_cond);
00156 runningPkTable.Put(pk, rptCond);
00157 runningPkTableMu.unlock();
00158 return false;
00159 } else {
00160
00161 cio().start_err() << ThreadLabel()
00162 << "Waiting on possibly identical "
00163 << thing << endl;
00164 cio().end_err();
00165 assert(rptCond != 0);
00166 rptCond->wait();
00167
00168 runningPkTableMu.unlock();
00169 return true;
00170 }
00171 }
00172
00173
00174 void WakeWaitingEvals(FP::Tag pk) {
00175 rpt_cond *rptCond = 0;
00176 runningPkTableMu.lock();
00177 bool found = runningPkTable.Delete(pk, rptCond);
00178 assert(found);
00179 assert(rptCond != 0);
00180 rptCond->wake();
00181 runningPkTableMu.unlock();
00182
00183 }
00184
00185
00186 void Tags(const CompactFV::List& names, const Context& c,
00187 FP::List& tags) {
00188
00189 int len = names.num;
00190 if (len > 0) {
00191 tags.len = len;
00192 tags.fp = NEW_PTRFREE_ARRAY(FP::Tag, len);
00193 int size = names.tbl.NumArcs();
00194 Val *vals = NEW_ARRAY(Val, size);
00195 int i;
00196 for (i = 0; i < size; i++) { vals[i] = NULL; }
00197 for (i = 0; i < len; i++) {
00198 short int idx = names.idx[i];
00199 PathKind pkind = (PathKind)names.types[i];
00200 tags.fp[i] = LookupPath(idx, pkind, names.tbl, c, vals)->FingerPrint();
00201 }
00202 } else {
00203 tags.len = 0;
00204 tags.fp = NULL;
00205 }
00206 return;
00207 }
00208
00209 bool NamesTagsPickle(Val val, bool cutoff, const Context& inPKArgs,
00210 char*& types, FV2::List& names,
00211 FP::List& tags, VestaVal::T& vval,
00212 DPaths *fv_exclude = 0) {
00213
00214
00215
00216
00217
00218 DPaths *sk = NEW_CONSTR(DPaths, (val->dps));
00219 ValueDpnd(val, sk);
00220 DepPathTbl::TIter iter(sk);
00221 DepPathTbl::KVPairPtr ptr;
00222 Text id;
00223 if(!inPKArgs.Null() || (fv_exclude != 0))
00224 {
00225 while (iter.Next(ptr)) {
00226 bool deleted = false;
00227 Context work = inPKArgs;
00228 while (!work.Null() && !deleted) {
00229 id = work.Pop()->name;
00230 if (ptr->key.content->path->getlo() == id)
00231 {
00232 sk->Delete(ptr->key, ptr, false);
00233 deleted = true;
00234 }
00235 }
00236
00237 if((fv_exclude != 0) && !deleted)
00238 {
00239
00240
00241 DepPathTbl::TIter exclude_iter(fv_exclude);
00242 DepPathTbl::KVPairPtr exclude_ptr;
00243 while(exclude_iter.Next(exclude_ptr) && !deleted)
00244 {
00245
00246
00247
00248
00249
00250 bool match = (ptr->key.content->path->size() >=
00251 exclude_ptr->key.content->path->size());
00252
00253
00254
00255 for(unsigned int i = 0;
00256 match && (i < exclude_ptr->key.content->path->size());
00257 i++)
00258 {
00259 match = (ptr->key.content->path->get(i) ==
00260 exclude_ptr->key.content->path->get(i));
00261 }
00262
00263
00264
00265 if(match)
00266 {
00267 sk->Delete(ptr->key, ptr, false);
00268 deleted = true;
00269 }
00270 }
00271 }
00272 }
00273 }
00274 sk->Resize();
00275
00276 int len = sk->Size();
00277 names.len = len;
00278 tags.len = len;
00279 if (len > 0) {
00280 types = NEW_PTRFREE_ARRAY(char, len);
00281 names.name = NEW_ARRAY(FV2::TPtr, len);
00282 tags.fp = NEW_PTRFREE_ARRAY(FP::Tag, len);
00283 iter.Reset();
00284 int index = 0;
00285 while (iter.Next(ptr)) {
00286 types[index] = (char)ptr->key.content->pKind;
00287 names.name[index] = ptr->key.content->path;
00288 if (ptr->val->vKind != FpVK && ptr->key.content->pKind == ExprPK) {
00289 if (ptr->val->vKind == ClosureVK)
00290 tags.fp[index++] = ((ClosureVC*)ptr->val)->FingerPrintExpr();
00291 else {
00292 assert(ptr->val->vKind == ModelVK);
00293 tags.fp[index++] = ((ModelVC*)ptr->val)->FingerPrintFile();
00294 }
00295 }
00296 else
00297 tags.fp[index++] = ptr->val->FingerPrint();
00298 }
00299 }
00300
00301 if (cutoff) ModelCutOff(val);
00302 return Pickle(val, vval);
00303 }
00304
00305 static void CheckLeases() {
00306 leaseMu.lock();
00307 bool expired = (time(NULL) - lastRenewed) > leaseDuration;
00308 bool failed = renewLease_failure;
00309 leaseMu.unlock();
00310 if (expired) {
00311 throw(Evaluator::failure("Leases timed out. Start over.", true));
00312 } else if(failed) {
00313 throw(Evaluator::failure("Lease renewal failed.", true));
00314 }
00315 }
00316
00317 void CollectKids(CacheEntry::IndicesApp* orphanCIs, int kidsIndex,
00318 CacheEntry::Indices& kids) {
00319 CheckLeases();
00320 kids.len = orphanCIs->len - kidsIndex;
00321 kids.index = orphanCIs->index + kidsIndex;
00322 }
00323
00324 void UpdateOrphans(CacheEntry::IndicesApp* orphanCIs, int kidsIndex,
00325 CacheEntry::Index ci) {
00326 frontierMu.lock();
00327 assert(kidsIndex <= orphanCIs->len);
00328 orphanCIs->len = kidsIndex;
00329 orphanCIs->Append(ci);
00330 frontierMu.unlock();
00331 }
00332
00333 void Checkpoint() {
00334 CheckLeases();
00335 frontierMu.lock();
00336 addEntryCount++;
00337 if ((addEntryCount & 0x3f) == 0) {
00338 CacheEntry::IndicesApp orphanCIs;
00339 ThreadData::mu.lock();
00340 ThreadData* cur = ThreadData::head;
00341 while (cur) {
00342 assert(cur->orphanCIs != 0);
00343 for (int i = 0; i < cur->orphanCIs->len; i++) {
00344 orphanCIs.Append(cur->orphanCIs->index[i]);
00345 }
00346 cur = cur->next;
00347 }
00348 ThreadData::mu.unlock();
00349 theCache->Checkpoint(topModelRoot->fptag, topModelSid, orphanCIs, false);
00350 }
00351 frontierMu.unlock();
00352 }
00353
00354 void FreeNamesTags(CompactFV::List& names, FP::List& tags) {
00355
00356 names.tbl = PrefixTbl();
00357 tags.len = 0;
00358 tags.fp = NULL;
00359 }
00360
00361
00362 Context BindApplicationArgs(ClosureVC *clos, ArgList actuals, const Context& c) {
00363 Context result, closCon = clos->con;
00364 Exprs forms = clos->func->args->elems;
00365 Exprs acts = actuals->elems;
00366 int fSize = forms.size();
00367 int aSize = acts.size();
00368 Expr fe;
00369 AssignEC *formal;
00370 Text name;
00371 int i;
00372
00373 if (aSize > fSize + 1) {
00374 actuals->EError(cio().start_err(), "Too many actual parameters:");
00375 cio().end_err();
00376 return conEmpty;
00377 }
00378 for (i = 0; i < aSize; i++) {
00379 if (i == fSize)
00380 name = nameDot;
00381 else {
00382 fe = forms.get(i);
00383 if (fe->kind == NameEK)
00384 name = ((Name)fe)->id;
00385 else if (fe->kind == AssignEK)
00386 name = ((AssignEC*)fe)->lhs->id;
00387 else {
00388 ostream& err_stream = cio().start_err();
00389 actuals->EError(err_stream,
00390 "Bad parameter list. It is neither actual nor default: `");
00391 ErrorExpr(err_stream, fe);
00392 ErrorDetail(err_stream, "'.");
00393 cio().end_err();
00394 return conEmpty;
00395 }
00396 }
00397 PushToContext(name, acts.get(i), c, result);
00398 }
00399 for (i = aSize; i < fSize; i++) {
00400 fe = forms.get(i);
00401 if (fe->kind == AssignEK) {
00402 formal = (AssignEC*)fe;
00403 PushToContext(formal->lhs->id, formal->rhs, closCon, result);
00404 }
00405 else {
00406 ostream& err_stream = cio().start_err();
00407 actuals->EError(err_stream, "Bad parameter list. Must have default: `");
00408 ErrorExpr(err_stream, fe);
00409 ErrorDetail(err_stream, "'.");
00410 cio().end_err();
00411 return conEmpty;
00412 }
00413 }
00414 if (aSize <= fSize) {
00415 Name eDot = NEW_CONSTR(NameEC, (nameDot, actuals->loc));
00416 PushToContext(nameDot, eDot, c, result);
00417 }
00418 return result;
00419 }
00420
00421
00422
00423
00424 static bool shouldDependencyCheck(CacheEntry::Index cIndex)
00425 {
00426 static Basics::mutex mu;
00427 static BitVector *doneCIs = 0;
00428
00429 mu.lock();
00430 if(!doneCIs)
00431 doneCIs = NEW(BitVector);
00432 bool not_yet = !doneCIs->Set(cIndex);
00433 mu.unlock();
00434 return not_yet;
00435 }
00436
00437 Val ApplicationFromCache(ClosureVC* clos, const Context& argsCon, SrcLoc *loc) {
00438 FP::Tag pk(evaluatorFunctionVersionTag);
00439 pk.Extend((char*)(¤tPickleVersion_net), sizeof_assert(currentPickleVersion_net, 4));
00440 CompactFV::List fvNames;
00441 FV2::List entryNames;
00442 FP::List tags;
00443 CacheEntry::Index cIndex;
00444 VestaVal::T cVal;
00445 CacheIntf::LookupRes cResult = CacheIntf::Miss;
00446 Model::T model = clos->func->body->loc->shortId;
00447 Val result = 0;
00448
00449 Val old_result = 0;
00450
00451 IncCounter(&appCallCounter);
00452 Context evalCon = argsCon.Append(clos->con);
00453
00454 ostream *traceRes = ThreadDataGet()->traceRes;
00455
00456 if (cacheOption != 3 || clos->func->noCache) {
00457
00458 if (traceRes) *traceRes << ": disabled\n";
00459 result = clos->func->body->Eval(evalCon);
00460 if (cacheOption < 2) return result;
00461 return FuncDpnd(result, clos, argsCon);
00462 }
00463
00464
00465
00466
00467 pk.Extend(clos->FingerPrintExpr());
00468 Context work = argsCon;
00469 (void)work.Pop();
00470 int last = clos->func->args->elems.size();
00471 Bit64 inPKs = clos->func->args->inPKs;
00472 Context inPKArgs;
00473 while (!work.Null()) {
00474 Assoc elem = work.Pop();
00475 if (inPKs & ((Bit64)1 << --last)) {
00476
00477 pk.Extend(elem->FingerPrint());
00478 inPKArgs.Push(elem);
00479 }
00480 else {
00481 switch (elem->val->vKind) {
00482 case BooleanVK: case IntegerVK: case PrimitiveVK:
00483 case TextVK: case ErrorVK:
00484 pk.Extend(elem->FingerPrint());
00485 inPKArgs.Push(elem);
00486 break;
00487 case ClosureVK:
00488 {
00489 FP::Tag tag(elem->name);
00490 tag.Extend(((ClosureVC*)elem->val)->FingerPrintExpr());
00491 pk.Extend(tag);
00492 break;
00493 }
00494 case ModelVK:
00495 {
00496 FP::Tag tag(elem->name);
00497 tag.Extend(((ModelVC*)elem->val)->FingerPrintFile());
00498 pk.Extend(tag);
00499 break;
00500 }
00501 case FpVK:
00502 assert(false);
00503 default:
00504 break;
00505 }
00506 }
00507 }
00508
00509 ThreadData *thdata = ThreadDataGet();
00510 CacheEntry::IndicesApp* orphanCIs = thdata->orphanCIs;
00511 try {
00512 while (true) {
00513 bool noEntry;
00514 FV::Epoch epoch = theCache->FreeVariables(pk, fvNames, noEntry);
00515 if (noEntry)
00516 cResult = CacheIntf::Miss;
00517 else {
00518 Tags(fvNames, evalCon, tags);
00519 cResult = theCache->Lookup(pk, epoch, tags, cIndex, cVal);
00520 }
00521 FreeNamesTags(fvNames, tags);
00522 if (cResult == CacheIntf::Hit) {
00523 if (Unpickle(cVal, evalCon, result)) {
00524 assert(result != 0);
00525
00526
00527 if(dependencyCheck && shouldDependencyCheck(cIndex))
00528 {
00529 old_result = result;
00530 cResult = CacheIntf::Miss;
00531 }
00532 else
00533 {
00534 if (traceRes) {
00535 *traceRes << ": hit (ci=" << cIndex << ")\n";
00536 }
00537 IncCounter(&appHitCounter);
00538 UpdateOrphans(orphanCIs, orphanCIs->len, cIndex);
00539 return FuncDpnd(result, clos, argsCon);
00540 }
00541 }
00542 else {
00543 OBufStream l_msg;
00544 l_msg << "ApplicationFromCache: Cache hit but bad cache data."
00545 << endl << endl
00546 << "\tpk = " << pk << endl
00547 << "\tci = " << cIndex << endl << endl
00548 << "Evaluate as cache miss." << endl;
00549 Error(cio().start_err(), Text(l_msg.str()), loc);
00550 cio().end_err();
00551 cResult = CacheIntf::Miss;
00552 }
00553 }
00554 if (cResult == CacheIntf::Miss) {
00555 if (traceRes) *traceRes << ": miss\n";
00556 int kidsIndex = orphanCIs->len;
00557
00558
00559 if(clos->func->noDup && WaitForDuplicateEval(pk, "function")) {
00560
00561 continue;
00562 }
00563 try {
00564 result = clos->func->body->Eval(evalCon);
00565 if (!noAddEntry) {
00566
00567 char *types;
00568 if (NamesTagsPickle(result, false, inPKArgs, types,
00569 entryNames, tags, cVal)) {
00570 Text pksource(clos->func->loc->file);
00571 pksource += "/" + clos->func->name;
00572 pksource += "(), line " + IntToText(clos->func->loc->line);
00573 pksource += ", col " + IntToText(clos->func->loc->character);
00574 if(dependencyCheck) {
00575
00576
00577
00578 if(old_result)
00579 {
00580 Val new_val = NULL;
00581 if(Unpickle(cVal, evalCon, new_val)) {
00582 assert(new_val != 0);
00583 PrintDepsDiffs(pksource, pk, cIndex, old_result, new_val);
00584 PrintDepsDiffs(pksource, pk, cIndex, result, new_val, "pickle");
00585 if (traceRes) {
00586 *traceRes << " " << thdata->funcCallDepth << ". "
00587 << clos->func->args->loc->file << ": "
00588 << clos->func->name
00589 << "(): dependencies comapred (with ci="
00590 << cIndex << ")\n";
00591 }
00592 }
00593 else
00594 {
00595 ostream &err = cio().start_err();
00596 Error(err, "(Impl) Trying to compare dependencies, failed to unpickle new value");
00597 InternalError(err, cio().helper(true), "ApplicationFromCache");
00598
00599 cio().end_err();
00600 }
00601 }
00602 }
00603 else {
00604 CacheEntry::Indices kids;
00605 CollectKids(orphanCIs, kidsIndex, kids);
00606
00607 CacheIntf::AddEntryRes ae_res =
00608 theCache->AddEntry(pk, types, entryNames, tags, cVal, model,
00609 kids, pksource, cIndex);
00610
00611 if(ae_res != CacheIntf::EntryAdded)
00612 {
00613 Error(cio().start_err(), Text("AddEntry failed: ")+
00614 CacheIntf::AddEntryResName(ae_res)+"\n"
00615 "This may be an evaluator bug. "
00616 "Please report it.\n",
00617 loc);
00618 cio().end_err();
00619 if (traceRes) *traceRes << endl;
00620 throw(Evaluator::failure(Text("AddEntry failed (may be an "
00621 "evaluator bug)"),
00622 false));
00623 }
00624 UpdateOrphans(orphanCIs, kidsIndex, cIndex);
00625 Checkpoint();
00626 if (traceRes) {
00627 *traceRes << " " << thdata->funcCallDepth << ". "
00628 << clos->func->args->loc->file << ": "
00629 << clos->func->name << "(): add (ci="
00630 << cIndex << ")\n";
00631 }
00632 }
00633 }
00634 }
00635 if(clos->func->noDup) {
00636 WakeWaitingEvals(pk);
00637 }
00638 } catch (...) {
00639 if(clos->func->noDup) {
00640 WakeWaitingEvals(pk);
00641 }
00642 throw;
00643 }
00644 return FuncDpnd(result, clos, argsCon);
00645 }
00646 if (cResult != CacheIntf::FVMismatch) {
00647 if (traceRes) *traceRes << ": mismatch\n";
00648 OBufStream err_msg;
00649 err_msg << "ApplicationFromCache got bad result: "
00650 << CacheIntf::LookupResName(cResult) << endl
00651 << "\tpk = " << pk << endl
00652 << "\tFV epoch = " << epoch << endl
00653 << "\ttags.len = " << tags.len << endl
00654 << "This may be an evaluator bug. Please report it." << endl;
00655 Error(cio().start_err(), Text(err_msg.str()), loc);
00656 cio().end_err();
00657 result = NEW(ErrorVC);
00658 return result;
00659 }
00660 }
00661 } catch (PrefixTbl::Overflow) {
00662 ostream& err_stream = cio().start_err();
00663 Error(err_stream,
00664 Text("Internal limits exceeded: PrefixTbl overflow\n"), loc);
00665 err_stream << "Caching function \"" << clos->func->name
00666 << "\" defined at:" << endl << endl
00667 << " " << clos->func->loc->file
00668 << ", line " << clos->func->loc->line
00669 << ", char " << clos->func->loc->character
00670 << endl << endl
00671 << Text("This usually means that there are too many free variables "
00672 "in the secondary key of the function being cached. This "
00673 "can often be alleviated by marking more arguments with "
00674 "the /**pk**/ pragma. (Fixing this will also reduce the CPU "
00675 "load of your evaluator and cache server, and improve "
00676 "build performance.)").WordWrap()
00677 << endl << endl;
00678 cio().end_err(true);
00679
00680 abort();
00681 }
00682 catch (SRPC::failure f) {
00683 Error(cio().start_err(), Text("ApplicationFromCache: SRPC failure (")
00684 + IntToText(f.r) + "): " + f.msg + ".\n", loc);
00685 cio().end_err();
00686 if (traceRes) *traceRes << endl;
00687 throw(Evaluator::failure(Text("Cache server is possibly down"), false));
00688 }
00689
00690 }
00691
00692 Val ApplyFunction(ClosureVC* clos, ApplyEC *ae, const Context& c) {
00693 ArgList args = ae->args;
00694 Context argsCon;
00695
00696 argsCon = BindApplicationArgs(clos, args, c);
00697
00698 ThreadData *thdata = ThreadDataGet();
00699 ostream *traceRes = thdata->traceRes;
00700 thdata->funcCallDepth++;
00701 if (traceRes) {
00702 *traceRes << " " << thdata->funcCallDepth << ". "
00703 << clos->func->args->loc->file << ": "
00704 << clos->func->name << "()";
00705 }
00706 if (argsCon == conEmpty) {
00707
00708
00709 ostream& err_stream = cio().start_err();
00710 ErrorDetail(err_stream, "\n Formal list is ");
00711 ErrorExpr(err_stream, clos->func->args);
00712 ErrorDetail(err_stream, "\n Actual list is ");
00713 ErrorExpr(err_stream, args);
00714 ErrorDetail(err_stream, "\n");
00715 cio().end_err();
00716 if (traceRes) *traceRes << ": badargs\n";
00717 return NEW(ErrorVC);
00718 }
00719
00720
00721 Val result = ApplicationFromCache(clos, argsCon, ae->loc);
00722 thdata->funcCallDepth--;
00723 return result;
00724 }
00725
00726
00727 Val NormalModelFromCache(ModelVC *fun, const Context& evalCon, SrcLoc *loc) {
00728 Model::T model = fun->content->sid;
00729 FP::Tag pk(evaluatorFunctionVersionTag);
00730 pk.Extend((char*)(¤tPickleVersion_net), sizeof_assert(currentPickleVersion_net, 4));
00731 CompactFV::List fvNames;
00732 FV2::List entryNames;
00733 FP::List tags;
00734 CacheEntry::Index cIndex;
00735 VestaVal::T cVal;
00736 CacheIntf::LookupRes cResult = CacheIntf::Miss;
00737 Val result = 0;
00738
00739 Val old_result = 0;
00740
00741 ThreadData *thdata = ThreadDataGet();
00742 ostream *traceRes = thdata->traceRes;
00743
00744
00745 if (((ModelEC*)fun->content->model)->ImportLocalModel()) {
00746 result = ((ModelEC*)fun->content->model)->block->Eval(evalCon);
00747 ModelCutOff(result);
00748 return result;
00749 }
00750
00751 IncCounter(&nModelCallCounter);
00752
00753 if (traceRes) {
00754 *traceRes << " " << thdata->funcCallDepth << ". " << fun->content->name;
00755 }
00756
00757
00758 pk.Extend(fun->FingerPrintFile());
00759
00760
00761 CacheEntry::IndicesApp* orphanCIs = ThreadDataGet()->orphanCIs;
00762 try {
00763 while (true) {
00764 bool noEntry;
00765 FV::Epoch epoch = theCache->FreeVariables(pk, fvNames, noEntry);
00766 if (noEntry)
00767 cResult = CacheIntf::Miss;
00768 else {
00769 Tags(fvNames, evalCon, tags);
00770 cResult = theCache->Lookup(pk, epoch, tags, cIndex, cVal);
00771 }
00772 FreeNamesTags(fvNames, tags);
00773 if (cResult == CacheIntf::Hit) {
00774 if (Unpickle(cVal, evalCon, result)) {
00775 assert(result != 0);
00776
00777
00778 if(dependencyCheck && shouldDependencyCheck(cIndex))
00779 {
00780 old_result = result;
00781 cResult = CacheIntf::Miss;
00782 }
00783 else
00784 {
00785 if (traceRes) {
00786 *traceRes << ": hit (ci=" << cIndex << ")\n";
00787 }
00788 IncCounter(&nModelHitCounter);
00789 UpdateOrphans(orphanCIs, orphanCIs->len, cIndex);
00790 return result;
00791 }
00792 }
00793 else {
00794 OBufStream l_msg;
00795 l_msg << "NormalModelFromCache: Cache hit but bad cache data."
00796 << endl << endl
00797 << "\tpk = " << pk << endl
00798 << "\tci = " << cIndex << endl << endl
00799 << "Evaluate as cache miss." << endl;
00800 Error(cio().start_err(), Text(l_msg.str()), loc);
00801 cio().end_err();
00802 throw(Evaluator::failure(Text("Bad cache data"), false));
00803 }
00804 }
00805 if (cResult == CacheIntf::Miss) {
00806 if (traceRes) *traceRes << ": miss\n";
00807 int kidsIndex = orphanCIs->len;
00808 result = ((ModelEC*)fun->content->model)->block->Eval(evalCon);
00809 if (!noAddEntry) {
00810
00811 char *types;
00812 if (NamesTagsPickle(result, true, conEmpty, types,
00813 entryNames, tags, cVal)) {
00814 Text pksource(fun->content->name);
00815 pksource += "() (normal)";
00816 if(dependencyCheck) {
00817
00818
00819
00820 if(old_result)
00821 {
00822 Val new_val = NULL;
00823 if(Unpickle(cVal, evalCon, new_val)) {
00824 assert(new_val != 0);
00825 PrintDepsDiffs(pksource, pk, cIndex, old_result, new_val);
00826 PrintDepsDiffs(pksource, pk, cIndex, result, new_val, "pickle");
00827 if (traceRes) {
00828 *traceRes << " " << thdata->funcCallDepth << ". "
00829 << fun->content->name
00830 << ": dependencies comapred (with ci="
00831 << cIndex << ")\n";
00832 }
00833 }
00834 else
00835 {
00836 ostream &err = cio().start_err();
00837 Error(err, "(Impl) Trying to compare dependencies, failed to unpickle new value");
00838 InternalError(err, cio().helper(true), "NormalModelFromCache");
00839
00840 cio().end_err();
00841 }
00842 }
00843 }
00844 else {
00845 CacheEntry::Indices kids;
00846 CollectKids(orphanCIs, kidsIndex, kids);
00847
00848 CacheIntf::AddEntryRes ae_res =
00849 theCache->AddEntry(pk, types, entryNames, tags, cVal, model,
00850 kids, pksource, cIndex);
00851
00852 if(ae_res != CacheIntf::EntryAdded)
00853 {
00854 Error(cio().start_err(), Text("AddEntry failed: ")+
00855 CacheIntf::AddEntryResName(ae_res)+"\n"
00856 "This may be an evaluator bug. "
00857 "Please report it.\n", loc);
00858 cio().end_err();
00859 if (traceRes) *traceRes << endl;
00860 throw(Evaluator::failure(Text("AddEntry failed (may be an "
00861 "evaluator bug)"),
00862 false));
00863 }
00864 UpdateOrphans(orphanCIs, kidsIndex, cIndex);
00865 Checkpoint();
00866 if (traceRes) {
00867 *traceRes << " " << thdata->funcCallDepth << ". "
00868 << fun->content->name
00869 << ": add (ci=" << cIndex << ")\n";
00870 }
00871 }
00872 }
00873 }
00874 return result;
00875 }
00876 if (cResult != CacheIntf::FVMismatch) {
00877 if (traceRes) *traceRes << ": mismatch\n";
00878 OBufStream err_msg;
00879 err_msg << "NormalModelFromCache got bad result: "
00880 << CacheIntf::LookupResName(cResult) << endl
00881 << "\tpk = " << pk << endl
00882 << "\tFV epoch = " << epoch << endl
00883 << "\ttags.len = " << tags.len << endl
00884 << "This may be an evaluator bug. Please report it." << endl;
00885 Error(cio().start_err(), Text(err_msg.str()), loc);
00886 cio().end_err();
00887 result = NEW(ErrorVC);
00888 return result;
00889 }
00890 }
00891 } catch (PrefixTbl::Overflow) {
00892 ostream& err_stream = cio().start_err();
00893 Error(err_stream,
00894 Text("Internal limits exceeded: PrefixTbl overflow\n"), loc);
00895 err_stream << "Caching model (normal):" << endl << endl
00896 << " " << fun->content->name
00897 << endl << endl
00898 << Text("This usually means that there are too many free variables "
00899 "in the secondary key of the function being cached. For "
00900 "models, this may mean too much work is being done in a "
00901 "single model file. Try splitting up the work of this "
00902 "model file into several separate model files each doing "
00903 "a smaller amount of work. (Fixing this will also reduce "
00904 "the CPU load of your evaluator and cache server, and "
00905 "improve build performance.)").WordWrap()
00906 << endl << endl;
00907 cio().end_err(true);
00908
00909 abort();
00910 }
00911 catch (SRPC::failure f) {
00912 fun->VError(cio().start_err(), Text("NormalModelFromCache: SRPC failure (")
00913 + IntToText(f.r) + "): " + f.msg + ".\n");
00914 cio().end_err();
00915 if (traceRes) *traceRes << endl;
00916 throw(Evaluator::failure(Text("Cache server is possibly down"), false));
00917 }
00918 }
00919
00920 Val ModelFromCache(ModelVC* fun, const Context& argsCon, SrcLoc *loc) {
00921 Context evalCon;
00922 Model::T model = fun->content->sid;
00923 FP::Tag pk(evaluatorFunctionVersionTag);
00924 pk.Extend((char*)(¤tPickleVersion_net), sizeof_assert(currentPickleVersion_net, 4));
00925 CompactFV::List fvNames;
00926 FV2::List entryNames;
00927 FP::List tags;
00928 CacheEntry::Index cIndex;
00929 VestaVal::T cVal;
00930 CacheIntf::LookupRes cResult = CacheIntf::Miss;
00931 Val result = 0;
00932
00933 Val old_result = 0;
00934
00935 IncCounter(&sModelCallCounter);
00936 ThreadData *thdata = ThreadDataGet();
00937 ostream *traceRes = thdata->traceRes;
00938
00939
00940 if (cacheOption < 2) {
00941 if (traceRes) *traceRes << ": disabled\n";
00942 Val fun1 = ((ModelVC*)fun)->Force();
00943 if (fun1->vKind == ModelVK) {
00944 ModelEC *modelExpr = (ModelEC*)((ModelVC*)fun1)->content->model;
00945 evalCon = argsCon.Append(((ModelVC*)fun1)->content->c);
00946 return modelExpr->block->Eval(evalCon);
00947 }
00948 ostream& err_stream = cio().start_err();
00949 Error(err_stream, "Trying to apply a model that failed to parse: `", loc);
00950 ErrorVal(err_stream, fun1);
00951 ErrorDetail(err_stream, "'.\n");
00952 cio().end_err();
00953 result = NEW(ErrorVC);
00954 return result;
00955 }
00956
00957
00958 pk.Extend(fun->FingerPrint());
00959
00960
00961 CacheEntry::IndicesApp* orphanCIs = ThreadDataGet()->orphanCIs;
00962 try {
00963 while (true) {
00964 bool noEntry;
00965 FV::Epoch epoch = theCache->FreeVariables(pk, fvNames, noEntry);
00966 if (noEntry)
00967 cResult = CacheIntf::Miss;
00968 else {
00969 Tags(fvNames, argsCon, tags);
00970 cResult = theCache->Lookup(pk, epoch, tags, cIndex, cVal);
00971 }
00972 FreeNamesTags(fvNames, tags);
00973 if (cResult == CacheIntf::Hit) {
00974 if (Unpickle(cVal, argsCon, result)) {
00975 assert(result != 0);
00976
00977
00978 if(dependencyCheck && shouldDependencyCheck(cIndex))
00979 {
00980 old_result = result;
00981 cResult = CacheIntf::Miss;
00982 }
00983 else
00984 {
00985 if (traceRes) {
00986 *traceRes << ": hit (ci=" << cIndex << ")\n";
00987 }
00988 IncCounter(&sModelHitCounter);
00989 UpdateOrphans(orphanCIs, orphanCIs->len, cIndex);
00990 return ModelDpnd(result, fun, argsCon);
00991 }
00992 }
00993 else {
00994 OBufStream l_msg;
00995 l_msg << "ModelFromCache: Cache hit but bad cache data." << endl << endl
00996 << "\tpk = " << pk << endl
00997 << "\tci = " << cIndex << endl << endl
00998 << "Evaluate as cache miss." << endl;
00999 Error(cio().start_err(), Text(l_msg.str()), loc);
01000 cio().end_err();
01001 throw(Evaluator::failure(Text("Bad cache data"), false));
01002 }
01003 }
01004 if (cResult == CacheIntf::Miss) {
01005 if (traceRes) *traceRes << ": miss\n";
01006 int kidsIndex = orphanCIs->len;
01007 Val fun1 = ((ModelVC*)fun)->Force();
01008 if (fun1->vKind == ModelVK) {
01009 evalCon = argsCon.Append(((ModelVC*)fun1)->content->c);
01010 if(((ModelEC*)fun->content->model)->noDup && WaitForDuplicateEval(pk, "model")) {
01011 continue;
01012 }
01013 try {
01014 result = NormalModelFromCache(fun, evalCon, loc);
01015 if(((ModelEC*)fun->content->model)->noDup) {
01016 WakeWaitingEvals(pk);
01017 }
01018 } catch (...) {
01019 if(((ModelEC*)fun->content->model)->noDup) {
01020 WakeWaitingEvals(pk);
01021 }
01022 throw;
01023 }
01024 if (noAddEntry) {
01025 ModelCutOff(result);
01026 }
01027 else {
01028
01029 char *types;
01030 if (NamesTagsPickle(result, false, conEmpty, types,
01031 entryNames, tags, cVal)) {
01032 Text pksource(fun->content->name);
01033 pksource += "() (special)";
01034 if(dependencyCheck) {
01035
01036
01037
01038 if(old_result)
01039 {
01040 Val new_val = NULL;
01041 if(Unpickle(cVal, evalCon, new_val)) {
01042 assert(new_val != 0);
01043 PrintDepsDiffs(pksource, pk, cIndex, old_result, new_val);
01044 PrintDepsDiffs(pksource, pk, cIndex, result, new_val, "pickle");
01045 if (traceRes) {
01046 *traceRes << " " << thdata->funcCallDepth << ". "
01047 << fun->content->name
01048 << ": dependencies comapred (with ci="
01049 << cIndex << ")\n";
01050 }
01051 }
01052 else
01053 {
01054 ostream &err = cio().start_err();
01055 Error(err, "(Impl) Trying to compare dependencies, failed to unpickle new value");
01056 InternalError(err, cio().helper(true), "ModelFromCache");
01057
01058 cio().end_err();
01059 }
01060 }
01061 }
01062 else {
01063 CacheEntry::Indices kids;
01064 CollectKids(orphanCIs, kidsIndex, kids);
01065
01066 CacheIntf::AddEntryRes ae_res =
01067 theCache->AddEntry(pk, types, entryNames, tags, cVal, model,
01068 kids, pksource, cIndex);
01069
01070 if(ae_res != CacheIntf::EntryAdded)
01071 {
01072 Error(cio().start_err(), Text("AddEntry failed: ")+
01073 CacheIntf::AddEntryResName(ae_res)+"\n"
01074 "This may be an evaluator bug. "
01075 "Please report it.\n", loc);
01076 cio().end_err();
01077 if (traceRes) *traceRes << endl;
01078 throw(Evaluator::failure(Text("AddEntry failed (may be an "
01079 "evaluator bug)"),
01080 false));
01081 }
01082 UpdateOrphans(orphanCIs, kidsIndex, cIndex);
01083 Checkpoint();
01084 if (traceRes) {
01085 *traceRes << " " << thdata->funcCallDepth << ". "
01086 << fun->content->name
01087 << ": add (ci=" << cIndex << ")\n";
01088 }
01089 }
01090 }
01091 }
01092 return ModelDpnd(result, fun, argsCon);
01093 }
01094 ostream& err_stream = cio().start_err();
01095 Error(err_stream, "Trying to apply a model that failed to parse: `", loc);
01096 ErrorVal(err_stream, fun1);
01097 ErrorDetail(err_stream, "'.\n");
01098 cio().end_err();
01099 result = NEW(ErrorVC);
01100 return result->Merge(fun);
01101 }
01102 if (cResult != CacheIntf::FVMismatch) {
01103 if (traceRes) *traceRes << ": mismatch\n";
01104 OBufStream err_msg;
01105 err_msg << "ModelFromCache got bad result: "
01106 << CacheIntf::LookupResName(cResult) << endl
01107 << "\tpk = " << pk << endl
01108 << "\tFV epoch = " << epoch << endl
01109 << "\ttags.len = " << tags.len << endl
01110 << "This may be an evaluator bug. Please report it." << endl;
01111
01112 Error(cio().start_err(), Text(err_msg.str()), loc);
01113 cio().end_err();
01114 result = NEW(ErrorVC);
01115 return result;
01116 }
01117 }
01118 } catch (PrefixTbl::Overflow) {
01119 ostream& err_stream = cio().start_err();
01120 Error(err_stream, Text("Internal limits exceeded: PrefixTbl overflow\n"), loc);
01121 err_stream << "Caching model (special):" << endl << endl
01122 << " " << fun->content->name
01123 << endl << endl
01124 << Text("This usually means that there are too many free variables "
01125 "in the secondary key of the function being cached. For "
01126 "models, this may mean too much work is being done in a "
01127 "single model file. Try splitting up the work of this "
01128 "model file into several separate model files each doing "
01129 "a smaller amount of work. (Fixing this will also reduce "
01130 "the CPU load of your evaluator and cache server, and "
01131 "improve build performance.)").WordWrap()
01132 << endl << endl;
01133 cio().end_err(true);
01134
01135 abort();
01136 } catch (SRPC::failure f) {
01137 Error(cio().start_err(),
01138 Text("ModelFromCache: SRPC failure (") + IntToText(f.r) + "): "
01139 + f.msg + ".\n", loc);
01140 cio().end_err();
01141 if (traceRes) *traceRes << endl;
01142 throw(Evaluator::failure(Text("Cache server is possibly down"), false));
01143 }
01144
01145 }
01146
01147 Val ApplyModel(ModelVC* fun, ApplyEC *ae, const Context& c) {
01148
01149
01150
01151
01152
01153 ArgList args = ae->args;
01154 Exprs acts = args->elems;
01155 Context argsCon;
01156
01157 ThreadData *thdata = ThreadDataGet();
01158 ostream *traceRes = thdata->traceRes;
01159
01160
01161 int aSize = acts.size();
01162 if (aSize == 0) {
01163 Name eDot = NEW_CONSTR(NameEC, (nameDot, args->loc));
01164 PushToContext(nameDot, eDot, c, argsCon);
01165 }
01166 else if (aSize == 1)
01167 PushToContext(nameDot, acts.getlo(), c, argsCon);
01168 else {
01169 args->EError(cio().start_err(), "Too many actual parameters:");
01170 cio().end_err();
01171 thdata->funcCallDepth++;
01172 if (traceRes) {
01173 *traceRes << " " << thdata->funcCallDepth << ". " << fun->content->name;
01174 *traceRes << ": badargs\n";
01175 }
01176 thdata->funcCallDepth--;
01177 return NEW(ErrorVC);
01178 }
01179
01180 thdata->funcCallDepth++;
01181
01182 if (traceRes) {
01183 *traceRes << " " << thdata->funcCallDepth << ". " << fun->content->name;
01184 }
01185
01186
01187 Val result = ModelFromCache(fun, argsCon, ae->loc);
01188 thdata->funcCallDepth--;
01189 return result;
01190 }
01191
01192
01193 bool CheckTreatment(TextVC *tr) {
01194 Text txt(tr->NDS());
01195 return (txt == "ignore" ||
01196 txt == "report" ||
01197 txt == "report_nocache" ||
01198 txt == "value" ||
01199 txt == "report_value");
01200 }
01201
01202 bool AllTexts(BindingVC *b) {
01203 Context work = b->elems;
01204 while (!work.Null()) {
01205 Assoc a = work.Pop();
01206 if (a->val->vKind != TextVK) return false;
01207 }
01208 return true;
01209 }
01210
01211 bool BindRunToolArgs(ArgList args, const Context& c,
01212 RunToolArgs& runToolArgs) {
01213
01214 int nArgs = args->Length();
01215 Exprs elems = args->elems;
01216 Val val;
01217
01218 if (nArgs < 2) {
01219 args->EError(cio().start_err(), "Too few actual parameters:");
01220 cio().end_err();
01221 return false;
01222 }
01223 if (nArgs > 10) {
01224 args->EError(cio().start_err(), "Too many actual parameters:");
01225 cio().end_err();
01226 return false;
01227 }
01228
01229 runToolArgs.loc = args->loc;
01230
01231
01232 val = elems.get(0)->Eval(c);
01233 if (val->vKind != TextVK) {
01234 args->EError(cio().start_err(),
01235 "The `platform' argument to _run_tool must be a text:");
01236 cio().end_err();
01237 return false;
01238 }
01239 runToolArgs.platform = (TextVC*)val;
01240
01241
01242 val = elems.get(1)->Eval(c);
01243 bool ok = false;
01244 if (val->vKind == ListVK) {
01245 Vals vs = ((ListVC*)val)->elems;
01246 ok = true;
01247 while (!vs.Null())
01248 if (vs.Pop()->vKind != TextVK) { ok = false; break; }
01249 }
01250 if (!ok) {
01251 args->EError(cio().start_err(),
01252 "The `command' argument to _run_tool must be a list of texts:");
01253 cio().end_err();
01254 return false;
01255 }
01256 runToolArgs.command_line = (ListVC*)val;
01257
01258
01259 if (nArgs <= 2) {
01260 Text stdin_default(emptyText);
01261 val = NEW_CONSTR(TextVC, (stdin_default));
01262 }
01263 else {
01264 val = elems.get(2)->Eval(c);
01265 if (val->vKind != TextVK) {
01266 args->EError(cio().start_err(),
01267 "The `stdin' argument to _run_tool must be a text:");
01268 cio().end_err();
01269 return false;
01270 }
01271 }
01272 runToolArgs.stdin_data = (TextVC*)val;
01273
01274
01275 if (nArgs <= 3) {
01276 Text stdout_treatment_default("report");
01277 val = NEW_CONSTR(TextVC, (stdout_treatment_default));
01278 }
01279 else {
01280 val = elems.get(3)->Eval(c);
01281 if (val->vKind != TextVK || !CheckTreatment((TextVC*)val)) {
01282 args->EError(cio().start_err(),
01283 "The `stdout_treatment' argument to _run_tool is not a suitable text:");
01284 cio().end_err();
01285 return false;
01286 }
01287 }
01288 runToolArgs.stdout_treatment = (TextVC*)val;
01289
01290
01291 if (nArgs <= 4) {
01292 Text stderr_treatment_default("report");
01293 val = NEW_CONSTR(TextVC, (stderr_treatment_default));
01294 }
01295 else {
01296 val = elems.get(4)->Eval(c);
01297 if (val->vKind != TextVK || !CheckTreatment((TextVC *)val)) {
01298 args->EError(cio().start_err(),
01299 "The `stderr_treatment' argument to _run_tool is not a suitable text:");
01300 cio().end_err();
01301 return false;
01302 }
01303 }
01304 runToolArgs.stderr_treatment = (TextVC*)val;
01305
01306
01307 if (nArgs <= 5) {
01308 Text status_treatment_default("report_nocache");
01309 val = NEW_CONSTR(TextVC, (status_treatment_default));
01310 }
01311 else {
01312 val = elems.get(5)->Eval(c);
01313 if (val->vKind != TextVK || !CheckTreatment((TextVC *)val)) {
01314 args->EError(cio().start_err(),
01315 "The `status_treatment' argument to _run_tool is not a suitable text:");
01316 cio().end_err();
01317 return false;
01318 }
01319 }
01320 runToolArgs.status_treatment = (TextVC*)val;
01321
01322
01323 if (nArgs <= 6) {
01324 Text signal_treatment_default("report_nocache");
01325 val = NEW_CONSTR(TextVC, (signal_treatment_default));
01326 }
01327 else {
01328 val = elems.get(6)->Eval(c);
01329 if (val->vKind != TextVK || !CheckTreatment((TextVC *)val)) {
01330 args->EError(cio().start_err(),
01331 "The `signal_treatment' argument to _run_tool is not a suitable text:");
01332 cio().end_err();
01333 return false;
01334 }
01335 }
01336 runToolArgs.signal_treatment = (TextVC*)val;
01337
01338
01339 if (nArgs <= 7) {
01340 val = fpContent;
01341 }
01342 else {
01343 val = elems.get(7)->Eval(c);
01344 if (val->vKind == BooleanVK) {
01345 val = NEW_CONSTR(IntegerVC, (((BooleanVC*)val)->b ? -1 : 0));
01346 }
01347 else if (val->vKind != IntegerVK) {
01348 args->EError(cio().start_err(),
01349 "The `fp_content' argument to _run_tool must be an integer or boolean:");
01350 cio().end_err();
01351 return false;
01352 }
01353 else if (((IntegerVC*)val)->num == -2) {
01354 val = fpContent;
01355 }
01356 }
01357 runToolArgs.fp_content = (IntegerVC*)val;
01358
01359
01360 if (nArgs <= 8) {
01361 Text wd_name(".WD");
01362 val = NEW_CONSTR(TextVC, (wd_name));
01363 }
01364 else {
01365 val = elems.get(8)->Eval(c);
01366 if (val->vKind != TextVK) {
01367 args->EError(cio().start_err(),
01368 "The `wd' argument to _run_tool must be a text:");
01369 cio().end_err();
01370 return false;
01371 }
01372 }
01373 runToolArgs.wd_name = (TextVC*)val;
01374
01375
01376 if (nArgs <= 9) {
01377 val = NEW_CONSTR(BooleanVC, (false));
01378 }
01379 else {
01380 val = elems.get(9)->Eval(c);
01381 if (val->vKind != BooleanVK) {
01382 args->EError(cio().start_err(),
01383 "The `existing_writable' argument to _run_tool must be a boolean:");
01384 cio().end_err();
01385 return false;
01386 }
01387 }
01388 runToolArgs.existing_writable = (BooleanVC*)val;
01389
01390
01391 val = LookupInContext(nameDot, c);
01392 if (val->vKind != BindingVK) {
01393 args->EError(cio().start_err(),
01394 "The `.' argument to _run_tool must be a binding:");
01395 cio().end_err();
01396 return false;
01397 }
01398 runToolArgs.dot = (BindingVC *)val->Copy();
01399 runToolArgs.dot->path = NEW_CONSTR(DepPath, (nameDot));
01400 Val envVars = runToolArgs.dot->Lookup("envVars");
01401 if (envVars->vKind != BindingVK || !AllTexts((BindingVC*)envVars)) {
01402 args->EError(cio().start_err(),
01403 "./envVars isn't a binding of texts:");
01404 cio().end_err();
01405 return false;
01406 }
01407 Val root = runToolArgs.dot->Lookup("root");
01408 if (root->vKind != BindingVK) {
01409 args->EError(cio().start_err(), "./root isn't a binding:");
01410 cio().end_err();
01411 return false;
01412 }
01413
01414
01415 val = runToolArgs.dot->LookupNoDpnd("tool_dep_control");
01416 if ((val == valUnbnd) || (val == 0)) {
01417 val = default_dep_control;
01418 }
01419 else {
01420 if (val->vKind != BindingVK) {
01421 args->EError(cio().start_err(),
01422 "./tool_dep_control must be a binding");
01423 cio().end_err();
01424 return false;
01425 }
01426
01427
01428 {
01429 TextSeq unrecognized_names;
01430 Context work = ((BindingVC *) val)->elems;
01431 while (!work.Null()) {
01432 Assoc a = work.Pop();
01433
01434
01435 if((a->name != "pk") &&
01436 (a->name != "coarse") &&
01437 (a->name != "coarse_names"))
01438 unrecognized_names.addhi(a->name);
01439 }
01440
01441
01442 if(unrecognized_names.size() > 0)
01443 {
01444 ostream& err_stream = cio().start_err();
01445 Warning(err_stream,
01446 "ignoring unrecognized names in ./tool_dep_control:",
01447 runToolArgs.loc);
01448 err_stream << endl;
01449 for(unsigned int i = 0; i < unrecognized_names.size(); i++)
01450 {
01451 err_stream << "\t" << unrecognized_names.get_ref(i) << endl;
01452 }
01453 err_stream << endl;
01454 cio().end_err();
01455 }
01456 }
01457 }
01458 assert(val->vKind == BindingVK);
01459 runToolArgs.dep_control = (BindingVC *) val;
01460
01461
01462 return true;
01463 }
01464
01465
01466
01467 static bool AssocNameLessThan(const Assoc &a, const Assoc &b)
01468 {
01469 assert(a != 0);
01470 assert(b != 0);
01471 return a->name < b->name;
01472 }
01473
01474 static void print_ignored_path(ostream &out, const char *reason,
01475 const ArcSeq &path)
01476 {
01477 out << "\t";
01478
01479
01480 for(unsigned int i = 2; i < path.size(); i++)
01481 {
01482 if(i > 2) out << "/";
01483 out << path.get_ref(i);
01484 }
01485 out << " : " << reason << endl;
01486 }
01487
01488 void RunToolPKFromRoot(BindingVC *control, BindingVC *dir, FP::Tag &pk,
01489 const ArcSeq &partial_path, DPaths &fv_exclude,
01490 ostream &ignore_msgs)
01491 {
01492
01493
01494
01495 Context work_con = control->elems;
01496 Sequence<Assoc> work;
01497 while(!work_con.Null())
01498 {
01499 work.addhi(work_con.Pop());
01500 }
01501 std::sort(work.begin(), work.end(), AssocNameLessThan);
01502
01503
01504 while(work.size() > 0)
01505 {
01506 Assoc a = work.remlo();
01507 ArcSeq path_seq(partial_path);
01508 path_seq.addhi(a->name);
01509 Val v = dir->LookupNoDpnd(a->name);
01510
01511 if((v != 0) && (v != valUnbnd))
01512 {
01513
01514
01515 if(((a->val->vKind == IntegerVK) &&
01516 ((IntegerVC *) a->val)->num) ||
01517 ((a->val->vKind == BooleanVK) &&
01518 ((BooleanVC *)a->val)->b))
01519 {
01520
01521
01522
01523
01524
01525
01526 DepPath path(NEW_CONSTR(ArcSeq, (path_seq)), DummyPK);
01527
01528 pk.Extend(path.content->pathFP);
01529 pk.Extend(v->FingerPrint());
01530
01531
01532
01533
01534 fv_exclude.Add(&path, a->val);
01535 }
01536
01537 else if((a->val->vKind == BindingVK) &&
01538 (v != 0) &&
01539 (v->vKind == BindingVK))
01540 {
01541 RunToolPKFromRoot((BindingVC *) a->val, (BindingVC *) v,
01542 pk, path_seq, fv_exclude, ignore_msgs);
01543 }
01544
01545
01546 else
01547 {
01548 print_ignored_path(ignore_msgs,
01549 ((a->val->vKind == BindingVK)
01550 ? "control binding for non-directory"
01551 : "invalid control type"),
01552 path_seq);
01553 }
01554 }
01555
01556
01557 else
01558 {
01559 print_ignored_path(ignore_msgs, "not in ./root", path_seq);
01560 }
01561 }
01562 }
01563
01564 DPaths *RunToolPK(const RunToolArgs& runToolArgs, FP::Tag &pk) {
01565
01566
01567
01568 pk.Extend("_run_tool");
01569 pk.Extend(runToolArgs.platform->FingerPrint());
01570 pk.Extend(runToolArgs.command_line->FingerPrint());
01571 pk.Extend(runToolArgs.stdin_data->FingerPrint());
01572 pk.Extend(runToolArgs.stdout_treatment->FingerPrint());
01573 pk.Extend(runToolArgs.stderr_treatment->FingerPrint());
01574 pk.Extend(runToolArgs.status_treatment->FingerPrint());
01575 pk.Extend(runToolArgs.signal_treatment->FingerPrint());
01576 pk.Extend(runToolArgs.fp_content->FingerPrint());
01577 pk.Extend(runToolArgs.wd_name->FingerPrint());
01578 if (runToolArgs.existing_writable->b)
01579 pk.Extend(runToolArgs.existing_writable->FingerPrint());
01580 Val envVars = runToolArgs.dot->Lookup("envVars");
01581 pk.Extend(envVars->FingerPrint());
01582
01583 DPaths *fv_exclude = 0;
01584 if(runToolArgs.dep_control != 0)
01585 {
01586 Val pk_control = runToolArgs.dep_control->LookupNoDpnd("pk");
01587
01588 if((pk_control != 0) &&
01589 (pk_control != valUnbnd))
01590 {
01591 if(pk_control->vKind == BindingVK)
01592 {
01593 ArcSeq path_seq;
01594 path_seq.addhi(".");
01595 path_seq.addhi("root");
01596
01597 fv_exclude = NEW(DPaths);
01598 Val root = runToolArgs.dot->LookupNoDpnd("root");
01599 assert(root->vKind == BindingVK);
01600 OBufStream ignore_msgs;
01601 RunToolPKFromRoot((BindingVC *) pk_control, (BindingVC *) root,
01602 pk, path_seq, *fv_exclude, ignore_msgs);
01603
01604
01605 if(!ignore_msgs.empty())
01606 {
01607 ostream& err_stream = cio().start_err();
01608 Warning(err_stream,
01609 ("ignoring some values in 'pk' sub-binding"
01610 " of ./tool_dep_control:"),
01611 runToolArgs.loc);
01612 err_stream << endl
01613 << ignore_msgs.str()
01614 << endl;
01615 cio().end_err();
01616 }
01617 }
01618 else
01619 {
01620
01621
01622 Warning(cio().start_err(),
01623 "ignoring non-binding for 'pk' in ./tool_dep_control",
01624 runToolArgs.loc);
01625 cio().end_err();
01626 }
01627 }
01628
01629 }
01630 return fv_exclude;
01631 }
01632
01633 Val MergeArgsDpnd(Val result, const RunToolArgs& args) {
01634
01635 result->Merge(args.platform);
01636
01637 ListVC *command = args.command_line;
01638 result->Merge(command);
01639 if (!command->path) {
01640 if (command->lenDps != NULL &&
01641 command->lenDps->Size() != 0) {
01642 DPaths psTemp;
01643 ValueDpnd(command, &psTemp);
01644 result->MergeDPS(&psTemp);
01645 }
01646 else {
01647 Vals vs = command->elems;
01648 while (!vs.Null())
01649 result->Merge(vs.Pop());
01650 }
01651 }
01652 result->Merge(args.stdin_data);
01653 result->Merge(args.stdout_treatment);
01654 result->Merge(args.stderr_treatment);
01655 result->Merge(args.wd_name);
01656 result->Merge(args.existing_writable);
01657
01658 Val envVars = args.dot->Lookup("envVars");
01659 assert(envVars->vKind == BindingVK);
01660 result->Merge((BindingVC*)envVars);
01661 assert(envVars->path);
01662 return result;
01663 }
01664
01665 static Basics::thread renewLeaseThread;
01666
01667 static void* RenewLeases(void *arg) throw () {
01668 time_t tsStart;
01669
01670 time_t sleepDuration = 10;
01671
01672
01673 unsigned int server_busy_count = 0;
01674
01675 while (true) {
01676 int left = sleepDuration;
01677 do {
01678 left = sleep(left);
01679 } while (left > 0);
01680
01681
01682 leaseMu.lock();
01683 if (time(&tsStart) - lastRenewed > leaseDuration) {
01684 leaseMu.unlock();
01685
01686
01687 if(server_busy_count > 0)
01688 {
01689 Error(cio().start_err(),
01690 Text("RenewLeases thread got \"connection refused: server busy\" ") +
01691 IntToText(server_busy_count) + " times, and now leases have expired!\n");
01692 cio().end_err();
01693 }
01694 return NULL;
01695 }
01696 leaseMu.unlock();
01697
01698
01699 CacheEntry::IndicesApp orphanCIs;
01700 frontierMu.lock();
01701 ThreadData::mu.lock();
01702 ThreadData* cur = ThreadData::head;
01703 while (cur) {
01704 assert(cur->orphanCIs != 0);
01705 for (int i = 0; i < cur->orphanCIs->len; i++) {
01706 orphanCIs.Append(cur->orphanCIs->index[i]);
01707 }
01708 for(ThreadData::orphanCI_set::iterator it =
01709 cur->unclaimed_child_orphanCIs.begin();
01710 it != cur->unclaimed_child_orphanCIs.end();
01711 it++)
01712 {
01713 orphanCIs.Append(*it);
01714 }
01715 cur = cur->next;
01716 }
01717 ThreadData::mu.unlock();
01718 frontierMu.unlock();
01719
01720 bool renewed = false;
01721 try
01722 {
01723
01724 renewed = theCache->RenewLeases(orphanCIs);
01725
01726
01727 server_busy_count = 0;
01728
01729
01730
01731 if(!renewed)
01732 {
01733 Error(cio().start_err(),
01734 Text("RenewLeases returned failure!\n") +
01735 "This may be a bug. Please reposrt it.\n");
01736 cio().end_err();
01737
01738 leaseMu.lock();
01739 renewLease_failure = true;
01740 leaseMu.unlock();
01741
01742 return NULL;
01743 }
01744 }
01745
01746 catch (SRPC::failure f)
01747 {
01748
01749
01750
01751 if((f.r == 1) && (f.msg.FindText("connection refused: server busy") != -1))
01752 {
01753 server_busy_count++;
01754 }
01755
01756 else
01757 {
01758
01759
01760
01761 Error(cio().start_err(), Text("RenewLeases thread: SRPC failure (")
01762 + IntToText(f.r) + "): " + f.msg + ".\n");
01763 cio().end_err();
01764
01765 leaseMu.lock();
01766 renewLease_failure = true;
01767 leaseMu.unlock();
01768
01769 return NULL;
01770 }
01771 }
01772
01773
01774 leaseMu.lock();
01775 if (time(NULL) - lastRenewed > leaseDuration) {
01776 leaseMu.unlock();
01777
01778
01779 if(server_busy_count > 0)
01780 {
01781 Error(cio().start_err(),
01782 Text("RenewLeases thread got \"connection refused: server busy\" ") +
01783 IntToText(server_busy_count) + " times, and now leases have expired!\n");
01784 cio().end_err();
01785 }
01786 return NULL;
01787 }
01788
01789 if(renewed)
01790 {
01791
01792 lastRenewed = tsStart;
01793 }
01794 leaseMu.unlock();
01795 }
01796 }
01797
01798 extern "C" void StartRenewLeaseThread_inner() {
01799 if (cacheOption != 0) {
01800 time(&lastRenewed);
01801 renewLeaseThread.fork_and_detach(RenewLeases, (void*)NULL);
01802 }
01803 }
01804
01805 void StartRenewLeaseThread()
01806 {
01807 static pthread_once_t init_once = PTHREAD_ONCE_INIT;
01808 pthread_once(&init_once, StartRenewLeaseThread_inner);
01809 }
01810
01811 Val RunToolFromCache(const RunToolArgs& runToolArgs, const Context& c, SrcLoc *loc) {
01812 FP::Tag pk(evaluatorRunToolVersionTag);
01813 pk.Extend((char*)(¤tPickleVersion_net), sizeof_assert(currentPickleVersion_net, 4));
01814 CompactFV::List fvNames;
01815 FV2::List entryNames;
01816 FP::List tags;
01817 CacheEntry::Index cIndex;
01818 VestaVal::T cVal;
01819 CacheIntf::LookupRes cResult = CacheIntf::Miss;
01820 Model::T model = NullShortId;
01821 Val result = 0;
01822 VestaSource* rootForTool;
01823
01824 Val old_result = 0;
01825
01826 ThreadData *thdata = ThreadDataGet();
01827 ostream *traceRes = thdata->traceRes;
01828
01829
01830 if (cacheOption == 0) {
01831 if (traceRes) *traceRes << ": disabled\n";
01832 result = RunTool(runToolArgs, rootForTool);
01833 DeleteRootForTool(rootForTool);
01834 return result;
01835 }
01836
01837
01838
01839 DPaths *fv_exclude = RunToolPK(runToolArgs, pk);
01840
01841
01842 CacheEntry::IndicesApp* orphanCIs = ThreadDataGet()->orphanCIs;
01843 try {
01844 while (true) {
01845 bool noEntry;
01846 FV::Epoch epoch = theCache->FreeVariables(pk, fvNames, noEntry);
01847 if (noEntry)
01848 cResult = CacheIntf::Miss;
01849 else {
01850 Tags(fvNames, c, tags);
01851 cResult = theCache->Lookup(pk, epoch, tags, cIndex, cVal);
01852 }
01853 FreeNamesTags(fvNames, tags);
01854 if (cResult == CacheIntf::Hit) {
01855 if (Unpickle(cVal, c, result)) {
01856 assert(result != 0);
01857
01858
01859 if(dependencyCheck && shouldDependencyCheck(cIndex))
01860 {
01861 old_result = result;
01862 cResult = CacheIntf::Miss;
01863 }
01864 else
01865 {
01866 if (traceRes) *traceRes << ": hit(ci=" << cIndex << ")\n";
01867 IncCounter(&toolHitCounter);
01868 if (cacheOption == 1) {
01869 result->dps = NULL;
01870 return result;
01871 }
01872 UpdateOrphans(orphanCIs, orphanCIs->len, cIndex);
01873 return MergeArgsDpnd(result, runToolArgs);
01874 }
01875 }
01876 else {
01877 OBufStream l_msg;
01878 l_msg << "RunToolFromCache: Cache hit but bad cache data." << endl << endl
01879 << "\tpk = " << pk << endl
01880 << "\tci = " << cIndex << endl << endl
01881 << "Evaluate as cache miss." << endl;
01882 Error(cio().start_err(), Text(l_msg.str()), loc);
01883 cio().end_err();
01884 cResult = CacheIntf::Miss;
01885 }
01886 }
01887 if (cResult == CacheIntf::Miss) {
01888 if (traceRes) *traceRes << ": miss\n";
01889 int kidsIndex = orphanCIs->len;
01890
01891
01892 if(WaitForDuplicateEval(pk, "tool")) {
01893
01894 continue;
01895 }
01896
01897
01898 try {
01899 result = RunTool(runToolArgs, rootForTool);
01900 char *types;
01901 if (!noAddEntry &&
01902 NamesTagsPickle(result, false, conEmpty, types, entryNames,
01903 tags, cVal, fv_exclude)) {
01904 Text pksource("_run_tool, command line: ");
01905 pksource += ToolCommandLineAsText(runToolArgs);
01906
01907 if(dependencyCheck) {
01908
01909
01910
01911 if(old_result) {
01912 Val new_val = NULL;
01913 if(Unpickle(cVal, c, new_val)) {
01914 assert(new_val != 0);
01915 PrintDepsDiffs(pksource, pk, cIndex, old_result, new_val);
01916 PrintDepsDiffs(pksource, pk, cIndex, result, new_val, "pickle");
01917
01918 if (traceRes) {
01919 *traceRes << " " << thdata->funcCallDepth << ". " << loc->file
01920 << ": " << "_run_tool(): dependencies comapred (with ci="
01921 << cIndex << ")\n";
01922 }
01923
01924 } else {
01925 ostream &err = cio().start_err();
01926 Error(err, "(Impl) Trying to compare dependencies, failed to unpickle new value");
01927 InternalError(err, cio().helper(true), "RunToolFromCache");
01928
01929 cio().end_err();
01930 }
01931 }
01932 } else {
01933 CacheEntry::Indices kids;
01934 CollectKids(orphanCIs, kidsIndex, kids);
01935
01936
01937
01938 CacheIntf::AddEntryRes ae_res =
01939 theCache->AddEntry(pk, types, entryNames, tags, cVal, model,
01940 kids, pksource, cIndex);
01941
01942 if(ae_res != CacheIntf::EntryAdded) {
01943 Error(cio().start_err(),
01944 Text("AddEntry failed: ")+
01945 CacheIntf::AddEntryResName(ae_res)+"\n"
01946 "This may be an evaluator bug. "
01947 "Please report it.\n",
01948 loc);
01949 cio().end_err();
01950 if (traceRes) *traceRes << endl;
01951 throw(Evaluator::failure(Text("AddEntry failed (may be an "
01952 "evaluator bug)"),
01953 false));
01954 }
01955
01956 UpdateOrphans(orphanCIs, kidsIndex, cIndex);
01957 Checkpoint();
01958 if (traceRes) {
01959 *traceRes << " " << thdata->funcCallDepth << ". " << loc->file << ": "
01960 << "_run_tool(): add (ci=" << cIndex << ")\n";
01961 }
01962 }
01963 }
01964
01965 WakeWaitingEvals(pk);
01966 } catch(...) {
01967 WakeWaitingEvals(pk);
01968 throw;
01969 }
01970
01971
01972
01973 DeleteRootForTool(rootForTool);
01974 if (cacheOption == 1) {
01975 result->dps = NULL;
01976 return result;
01977 }
01978 return MergeArgsDpnd(result, runToolArgs);
01979 }
01980 if (cResult != CacheIntf::FVMismatch) {
01981 if (traceRes) *traceRes << ": mismatch\n";
01982 OBufStream err_msg;
01983 err_msg << "RunToolFromCache got bad result: "
01984 << CacheIntf::LookupResName(cResult) << endl
01985 << "\tpk = " << pk << endl
01986 << "\tFV epoch = " << epoch << endl
01987 << "\ttags.len = " << tags.len << endl
01988 << "This may be an evaluator bug. Please report it." << endl;
01989 Error(cio().start_err(), Text(err_msg.str()), loc);
01990 cio().end_err();
01991 result = NEW(ErrorVC);
01992 return result;
01993 }
01994 }
01995 } catch (PrefixTbl::Overflow) {
01996 Text cmd_line = ToolCommandLineAsText(runToolArgs);
01997 ostream& err_stream = cio().start_err();
01998 Error(err_stream, Text("Internal limits exceeded: PrefixTbl overflow\n"), loc);
01999 err_stream << "Caching _run_tool with command line:" << endl << endl
02000 << " " << cmd_line << endl << endl
02001 << Text("This usually means that there are too many free variables "
02002 "in the secondary key of the function being cached. For "
02003 "_run_tool calls, this may mean you're trying to do too "
02004 "much work in a single tool invocation. Try splitting the "
02005 "work of this tool invocation into several separate tool "
02006 "invocations each doing a smaller amount of work and using "
02007 "a smaller number of source files. (Fixing this will also "
02008 "reduce the CPU load of your evaluator and cache server, and "
02009 "improve build performance.)").WordWrap()
02010 << endl << endl;
02011 cio().end_err(true);
02012
02013 abort();
02014 } catch (SRPC::failure f) {
02015 Error(cio().start_err(),
02016 Text("RunToolFromCache: SRPC failure (")
02017 + IntToText(f.r) + "): " + f.msg + ".\n",
02018 loc);
02019 cio().end_err();
02020 if (traceRes) *traceRes << endl;
02021 throw(Evaluator::failure(Text("Cache server is possibly down"), false));
02022 }
02023
02024 }
02025
02026 Val ApplyRunTool(ArgList args, const Context& c) {
02027 RunToolArgs runToolArgs;
02028
02029 ThreadData *thdata = ThreadDataGet();
02030 ostream *traceRes = thdata->traceRes;
02031
02032 IncCounter(&toolCallCounter);
02033 if (!BindRunToolArgs(args, c, runToolArgs)) {
02034 thdata->funcCallDepth++;
02035 if (traceRes) {
02036 *traceRes << " " << thdata->funcCallDepth << ". " << args->loc->file << ": ";
02037 *traceRes << "_run_tool()";
02038 *traceRes << ": badargs\n";
02039 }
02040 thdata->funcCallDepth--;
02041 return NEW(ErrorVC);
02042 }
02043 thdata->funcCallDepth++;
02044 if (traceRes) {
02045 *traceRes << " " << thdata->funcCallDepth << ". " << args->loc->file << ": ";
02046 *traceRes << "_run_tool()";
02047 }
02048
02049
02050 Val result = RunToolFromCache(runToolArgs, c, args->loc);
02051 thdata->funcCallDepth--;
02052 return result;
02053 }