bool Task::isEqualTo(Task another){ if (another.getDone() != _done){ return false; } switch(another.getType()){ case FLOATING_TASK: return another.getTitle() == _title && another.getType() == _type; break; case DEADLINE_TASK: return another.getTitle() == _title && another.getEnd().compareTo(_end) == 0 && another.getType() == _type; break; case TIMED_TASK: return another.getTitle() == _title && another.getStart().compareTo(_start) == 0 && another.getEnd().compareTo(_end) == 0 && another.getType() == _type; break; default: return false; break; } return false; }
bool Task::operator<(Task& a){ if(a.getType() == TIMED_TASK) return (_start.compareTo(a.getStart()) < 0); else if(a.getType() == DEADLINE_TASK) return (_end.compareTo(a.getEnd()) < 0); else return false; }
void *Task::workerLoop(void *aux){ ThreadData *data = (ThreadData *)aux; while (1){ pthread_mutex_lock(&(data->mutex)); while (data->t == NULL){ pthread_cond_wait(&(data->todo), &(data->mutex)); } Task* task = data->t; pthread_mutex_unlock(&(data->mutex)); pthread_mutex_lock(&(task->lock)); task->started = true; pthread_mutex_unlock(&(task->lock)); if (task->getType() == TASK_EXITER){ data->status = THREAD_KILLED; } task->run(); pthread_mutex_lock(&(task->lock)); task->finished = true; pthread_cond_broadcast(&(task->wait)); pthread_mutex_unlock(&(task->lock)); data->status = THREAD_WAITING; data->parent->notifyDone(data); } return NULL; }
// // Debug routine // // This routine has no call, instead it is invoked in the debugger to display // the tasks currently queued at a context. And to display the details of the // oldest task. // void displayContextTasks(map<ContextId, Context> &context, int id) { Context tgt = context[id]; Task* last; for (Task* t : tgt.tasks) { last = t; printf("%llx ", t->getTaskId()); } if (last != NULL) { cout << last->toString() << endl; if (last->getType() == task_type_join) { auto jc = tgt.joinCountMap.find(last->getTaskId()); if (jc == tgt.joinCountMap.end()) { cout << "Join is not waiting on any tasks, should be queued.\n"; } else { cout << "Waiting on: " << jc->second << " tasks to join" << endl; for (TaskId s : last->getSuccessorTasks()) { if (tgt.joinMap.find(s.getContextId()) != tgt.joinMap.end()) { cout << "\tWaiting on: " << s.toString() << endl; } } } } } }
// // Support routine to determine what is the blocking task // // Provided for being invoked by the debugger. It scans the // blocked tasks in the background writing thread and finds // the oldest task. And then reports what tasks have not been // sent to the background, such that this task cannot yet be written. // void debugBackground(map<TaskId, pair<Task*, int> > &tasks) { Task* minT = NULL; ct_tsc_t minTsc = ~0; int predWait = 0; for (auto it = tasks.begin(), et = tasks.end(); it != et; ++it) { if (it->second.first->getStartTime() < minTsc) { minTsc = it->second.first->getStartTime(); minT = it->second.first; predWait = it->second.second; } } if (minT != NULL) { cout << "Minimum Task is: "; cout << minT->getTaskId().toString() << " of type - "; cout << minT->getType() << endl; printf("Waiting on: %d tasks\n", predWait); for (TaskId p : minT->getPredecessorTasks()) { if (tasks.find(p) == tasks.end()) { printf("Predecessor: %s - Not Present\n", p.toString().c_str()); } else { printf("Predecessor: %s - Present\n", p.toString().c_str()); } } } }
// populateQueue // Populates the memory request queue with additional requests int TraceWrapper::populateQueue() { int addedMemOps = 0; Task* nextTask = NULL; // foreach task in graph // Update running tasks based on the advancement in time represented by // the new task while (pauseTask != NULL || (nextTask = tg->getNextTask())) { Task* currentTask = nextTask; if (pauseTask != NULL) { currentTask = pauseTask; pauseTask = NULL; } TaskId ctui = currentTask->getTaskId(); ContextId ctci = currentTask->getContextId(); ct_timestamp start = currentTask->getStartTime(); ct_timestamp req = currentTask->getEndTime(); if (priorStart + 1000 > start) { ;// only advance to start } else { start = priorStart + 1000; // advance by 1000 cycles } priorStart = start; // Iterate through every basic block, older than start for (auto hs_b = contechState.begin(), hs_e = contechState.end(); hs_b != hs_e; ++hs_b) { ctid_current_state* tempState = (hs_b->second); if (tempState->terminated == true) continue; Task* t = tempState->currentTask; ct_timestamp tempCurrent = tempState->taskCurrTime; ct_timestamp tempRate = tempState->taskRate; auto f = tempState->currentBB; string s = t->getTaskId().toString(); // // tempRate = 0 -> no basic blocks or currentTask->time == nextTask->time // Still, process the basic blocks // for (auto e = tempState->currentBBCol.end(); (tempCurrent <= start) && (f != e); ++f) { BasicBlockAction tbb = *f; // Push MemOps onto queue auto memOps = f.getMemoryActions(); MemReqContainer tReq; tReq.mav.clear(); tReq.bbid = tbb.basic_block_id; tReq.ctid = (unsigned int) t->getContextId(); uint32_t pushedOps = 0; for (auto iReq = memOps.begin(), eReq = memOps.end(); iReq != eReq; ++iReq) { MemoryAction ma = *iReq; if (ma.type == action_type_mem_read || action_type_mem_write) { // Nothing special } else if (ma.type == action_type_memcpy) { tReq.mav.push_back(ma); ++iReq; pushedOps++; ma = *iReq; if (ma.type == action_type_memcpy) { tReq.mav.push_back(ma); ++iReq; pushedOps++; ma = *iReq; } } else if (ma.type == action_type_malloc) { tReq.mav.push_back(ma); ++iReq; pushedOps++; ma = *iReq; } pushedOps++; tReq.mav.push_back(ma); } assert(pushedOps == tReq.mav.size()); if (pushedOps != 0) { memReqQ.push(tReq); addedMemOps += pushedOps; } tempCurrent += tempRate; } // Should the task switch always be from currentTask == next? // o.w. The last basic block "spans" start if (ctui == tempState->nextTaskId) { bool tBlock = tempState->blocked; if (start < currentTask->getStartTime()) { pauseTask = currentTask; } // // Termination condition if the contech IDs change // Or 0 is the successor task // if (t->getContextId() != tempState->nextTaskId.getContextId() || tempState->nextTaskId == 0) { delete t; tempState->terminated = true; continue; } // Is the new task running or doing something synchronizing? if (ctui == tempState->nextTaskId) { tempState->currentTask = currentTask; } else { tempState->currentTask = tg->getTaskById((tempState->nextTaskId)); } assert(tempState->currentTask != NULL); if (tempState->currentTask->getType() == task_type_basic_blocks) tempState->blocked = false; else tempState->blocked = true; // If there is no continuation, then this task has terminated tempState->nextTaskId = getSequenceTask(tempState->currentTask->getSuccessorTasks(), tempState->currentTask->getContextId()); tempState->taskCurrTime = tempState->currentTask->getStartTime(); tempState->currentBBCol = tempState->currentTask->getBasicBlockActions(); tempState->currentBB = tempState->currentBBCol.begin(); // If the task is blocked, then it is not running. // o.w. compute the task rate for this next task if (tempState->blocked == true) { tempState->taskRate = 0; } else { int bbc = tempState->currentTask->getBBCount(); if (bbc == 0) bbc = 1; tempState->taskRate = (tempState->currentTask->getEndTime() - tempState->taskCurrTime/* + bbc - 1*/) / (bbc); } delete t; } else if (tempCurrent < start) { tempState->blocked = true; } else { tempState->currentBB = f; tempState->taskCurrTime = tempCurrent; } } // end of foreach task in contechState // // If ctci is not in contechState, then it is a new contech // TODO: Due to barriers, it is possible that we'll need to "unterminate" some states // if (contechState.find(ctci) == contechState.end()) { ctid_current_state* tempState = new ctid_current_state; tempState->terminated = false; tempState->taskCurrTime = start; tempState->currentBBCol = currentTask->getBasicBlockActions(); tempState->currentBB = tempState->currentBBCol.begin(); tempState->currentTask = currentTask; tempState->nextTaskId = getSequenceTask(tempState->currentTask->getSuccessorTasks(), tempState->currentTask->getContextId()); if (currentTask->getType() == task_type_basic_blocks) { tempState->blocked = false; tempState->taskRate = (tempState->currentTask->getEndTime() - start) / (currentTask->getBBCount()); } else { tempState->blocked = true; tempState->taskRate = 0; } contechState[ctci] = tempState; } if (addedMemOps > 0) break; } return addedMemOps; }
void* backgroundTaskWriter(void* v) { ct_file* out = *(ct_file**)v; deque<Task*> writeTaskQueue; map<TaskId, TaskWrapper> writeTaskMap; uint64 taskCount = 0, taskWriteCount = 0; uint64 bytesWritten = ct_tell(out); long pos; bool firstTime = true; unsigned int sec = 0, msec = 0, taskLastWriteCount = 0; // // noMoreTasks is a flag from the foreground thread // And if there are no more, then there is the worklist of ready tasks // And finally, there could still be tasks queued from the foreground // When all of those are clear, everything has been written. // while (!noMoreTasks || (!writeTaskQueue.empty() || (taskQueue != NULL && !taskQueue->empty()))) { deque<Task*>* taskChunk = NULL; // // Get tasks from the foreground // pthread_mutex_lock(&taskQueueLock); while (!noMoreTasks && taskQueue->empty()) { pthread_cond_wait(&taskQueueCond, &taskQueueLock); } if (!noMoreTasks) { taskChunk = taskQueue; taskQueue = new deque<Task*>; } else { taskChunk = taskQueue; taskQueue = NULL; { struct timeb tp; ftime(&tp); printf("MIDDLE_DEQUE: %d.%03d\t%u\n", (unsigned int)tp.time, tp.millitm, taskWriteCount); } } pthread_mutex_unlock(&taskQueueLock); // Have a chunk of tasks from the foreground if (taskChunk != NULL) { writeTaskQueue.insert(writeTaskQueue.end(), taskChunk->begin(), taskChunk->end()); taskCount += taskChunk->size(); delete taskChunk; } while (!writeTaskQueue.empty()) { Task* t = writeTaskQueue.front(); TaskId id = t->getTaskId(); writeTaskQueue.pop_front(); // Task will be null if it has already been handled assert(t != NULL); // Write out the task pos = ct_tell(out); // TaskIndex is a graph, then use the graph to // determine the bfs order, this way tasks can be written out // immediately { TaskWrapper tw; tw.self = id; tw.start = t->getStartTime(); tw.p = t->getPredecessorTasks().size(); tw.s = t->getSuccessorTasks(); tw.t = t->getType(); tw.writePos = pos; assert(writeTaskMap.find(id) == writeTaskMap.end()); writeTaskMap[id] = tw; /* Debugging code for bug where TaskId(x:0) had multiple predecessors if (id.getSeqId() == 0) { printf("%u:%u -- ", id.getContextId(), id.getSeqId()); auto pr = t->getPredecessorTasks(); for (auto it = pr.begin(), et = pr.end(); it != et; ++it) { printf("%s\t", it->toString().c_str()); } printf("\n"); }*/ //printf("%s", t->toSummaryString().c_str()); } bytesWritten += Task::writeContechTask(*t, out); taskWriteCount += 1; // Delete the task delete t; } taskLastWriteCount = taskWriteCount; } // Write how many entries are in the index // The write each index entry pair pos = ct_tell(out); if (pos == -1) { //int esav = errno; perror("Cannot identify index position"); } { struct timeb tp; ftime(&tp); printf("MIDDLE_TASK: %d.%03d\n", (unsigned int)tp.time, tp.millitm); } printf("Writing index for %d at %lld\n", taskWriteCount, pos); size_t t = ct_write(&taskWriteCount, sizeof(taskWriteCount), out); priority_queue<pair<ct_tsc_t, pair<TaskId, uint64> >, vector<pair<ct_tsc_t, pair<TaskId, uint64> > >, first_compare > taskSort; { TaskWrapper tw = writeTaskMap.find(0)->second; taskSort.push(make_pair(tw.start, make_pair(tw.self, tw.writePos))); } // // This reproduces the BFS algorithm that had been used for writing tasks // It is much faster to sort the tasks on just the graph information than // to indefinitely delay writing a task until the entire graph is available. // // taskSort is a priority queue, the top element is the oldest task that has all // its prior tasks in the index. // unsigned int indexWriteCount = 0; TaskId lastTid = 0; while (!taskSort.empty()) { TaskId tid = taskSort.top().second.first; uint64 offset = taskSort.top().second.second; lastTid = tid; ct_write(&tid, sizeof(TaskId), out); ct_write(&offset, sizeof(uint64), out); //printf("%d:%d @ %llx\t", tid.getContextId(), tid.getSeqId(), offset); taskSort.pop(); auto twit = writeTaskMap.find(tid); assert(twit != writeTaskMap.end()); TaskWrapper tw = twit->second; assert(twit->first == tw.self); for (TaskId succ : tw.s) { TaskWrapper &suTW = writeTaskMap.find(succ)->second; //printf("%d:%d (%d)\t", succ.getContextId(), succ.getSeqId(), suTW.p); suTW.p--; if (suTW.p == 0) { taskSort.push(make_pair(suTW.start, make_pair(suTW.self, suTW.writePos))); } } //printf("\n"); // Can erase tid, but we don't need the memory, will it speed up? writeTaskMap.erase(twit); indexWriteCount ++; } printf("Wrote %u tasks to index\n", indexWriteCount); if (indexWriteCount != taskWriteCount) { for (auto it = writeTaskMap.begin(), et = writeTaskMap.end(); it != et; ++it) { printf("%s (type:%d) (pred:%d)\t", it->first.toString().c_str(), it->second.t, it->second.p); for (TaskId succ : it->second.s) { printf("%s\t", succ.toString().c_str()); } printf("\n"); } } // Failing this assert indicates that the graph either has cycles or is disjoint // Both case are bad assert(indexWriteCount == taskWriteCount); // Now write the position of the index ct_seek(out, 4); // With ftell, we use long, rather than the uint64 type which we track positions ct_write(&pos, sizeof(pos), out); // Write the ROI start and end after index ct_write(&roiStart, sizeof(TaskId), out); if (roiEnd == 0) { roiEnd = lastTid; } ct_write(&roiEnd, sizeof(TaskId), out); // // Stats for the background thread. // TaskCount should equal taskWriteCount // And there should be no tasks remaining. // printf("Tasks Received: %ld\n", taskCount); printf("Tasks Written: %ld\n", taskWriteCount); if (taskQueue != NULL) printf("Tasks Left: %ld\n", taskQueue->size()); printf("Tasks Remaining: %u\n", writeTaskQueue.size()); return NULL; }
void updateContextTaskList(Context &c) { // Non basic block tasks are handled by their creation logic // basic block tasks can be queued, if they are not the newest task // and they have a predecessor (i.e., have been created by another context). // Task(0:0) has no predecessor and is a special case here. // // Creates must be complete when they are not the active task. The child is // known at creation time, so no update is required of this task. bool exited = (c.endTime != 0); // TODO: Should we 'cache' getType() or can the compiler do this? // task_type tType ... if (exited == false) { for (auto it = c.tasks.begin(), et = c.tasks.end(); it != et; ++it) { Task* t = *it; if (t == c.activeTask()) continue; if (( t->getType() == task_type_basic_blocks && (t->getPredecessorTasks().size() > 0 || t->getTaskId() == TaskId(0))) || (t->getType() == task_type_create) || (t->getType() == task_type_join && c.isCompleteJoin(t->getTaskId()))) { // This is not guaranteed to remove every task in one pass; // however, the routine will be invoked many times and it // will correctly remove tasks. it = c.tasks.erase(it); backgroundQueueTask(t); } } /*while (t != c.activeTask() && (( t->getType() == task_type_basic_blocks && (t->getPredecessorTasks().size() > 0 || t->getTaskId() == TaskId(0))) || (t->getType() == task_type_create) || (t->getType() == task_type_join && c.isCompleteJoin(t->getTaskId())))) { c.tasks.pop_back(); backgroundQueueTask(t); t = c.tasks.back(); }*/ } else { // If the context has exited, then even the active task can go if (c.tasks.empty()) return; Task* t = c.tasks.back(); while (( t->getType() == task_type_basic_blocks && (t->getPredecessorTasks().size() > 0 || t->getTaskId() == TaskId(0)) && (t->getSuccessorTasks().size() > 0)) || t->getType() == task_type_create) { c.tasks.pop_back(); backgroundQueueTask(t); if (c.tasks.empty()) return; t = c.tasks.back(); } } }
void ZerglingMicro::micro(BWAPI::Unit* unit) { Task task = this->hc->ta->getTaskOfUnit(unit); UnitGroup allies = allEigenUnits().inRadius(dist(12), unit->getPosition()); UnitGroup enemiesground = allEnemyUnits().inRadius(dist(10), unit->getPosition()).not(isFlyer); UnitGroup enemiesair = allEnemyUnits().inRadius(dist(7), unit->getPosition())(isFlyer); if(amountCanAttackGround(enemiesair) > 0 && amountCanAttackAir(allies) == 0) { unit->move(moveAway(unit)); } else { if(task.getType() == ScoutTask) { if(allEnemyUnits().not(isBuilding).inRadius(dist(4), unit->getPosition()).size() > 0) { unit->move(moveAway(unit)); } else { if(unit->getDistance(task.getPosition()) < dist(4) && BWAPI::Broodwar->isVisible(BWAPI::TilePosition(task.getPosition()))) { if(!unit->isMoving()) { int x = unit->getPosition().x(); int y = unit->getPosition().y(); int factor = dist(10); int newx = x + (((rand() % 30)-15)*factor); int newy = y + (((rand() % 30)-15)*factor); unit->move(BWAPI::Position(newx, newy).makeValid()); } } else { unit->move(task.getPosition()); } } } else { UnitGroup swarms = allUnits()(Dark_Swarm); BWAPI::Unit* swarm = getNearestUnit(unit->getPosition(), swarms); if(swarm != NULL && swarm->getPosition().getDistance(unit->getPosition()) < dist(9)) { if(!isUnderDarkSwarm(unit) && !unit->isAttacking()) { unit->attack(swarm->getPosition()); } else { UnitGroup enemiesunderswarm = allEnemyUnits().inRadius(dist(6), unit->getPosition()).not(isFlyer); if(!unit->isAttacking() && enemiesunderswarm.size() > 0) { unit->attack(getNearestUnit(unit->getPosition(), enemiesunderswarm)); } } } else { if(allies.size() < amountCanAttackGround(enemiesground)) { unit->move(moveAway(unit)); } else { if(enemiesground.inRadius(dist(3), unit->getPosition()).size() > 0) { // game AI } else { if(enemiesground.size() > 0) { BWAPI::Unit* nearest = getNearestUnit(unit->getPosition(), enemiesground); unit->attack(nearest); } else { UnitGroup* ug = this->hc->eiugm->getGroupOfUnit(unit); if(ug != NULL && tooSplitUp(dist(7), *ug)) { BWAPI::Unit* nearest = getNearestUnit(ug->getCenter(), *ug); unit->attack(nearest); } else { unit->move(task.getPosition()); } } } } } } } }
void SchemeMachine::performTask(){ Task * task = tasks.pop(last_line); int n; switch(task->getType()){ case Task::EVALUATE : { EvalTask * evtask; SchObjectRef * ref; int step; evtask = static_cast<EvalTask *>(task); ref = new SchObjectRef(*evtask->ref); last_line = (*ref)->getLine(); step = evtask->step; delete task; (*ref)->evaluate(*this, step); delete ref; } break; case Task::CALL : { // tail recursion optimisation. if CALL and argument haz been evaluated --> del CallTask * ctask; ctask = static_cast<CallTask *>(task); int step = ctask->step; if(!tasks.isEmpty() && tasks.data[tasks.size-1]->getType() == Task::DEL_NAMES && ((*ctask->ref)->getType() != SchObject::SPECIAL || static_cast<SchSpecial *>(&**ctask->ref)->prepareArgs())) { // swap tasks Task * tmp = tasks.data[tasks.size-1]; // DEL_NAMES tasks.push(task); tasks.data[tasks.size-2] = tasks.data[tasks.size-1]; // DEL <- CALL tasks.data[tasks.size-1] = tmp; // CALL <- tmp } else { SchObjectRef * ref; ref = new SchObjectRef(*ctask->ref); last_line = (*ref)->getLine(); n = ctask->n; delete task; (*ref)->call(*this, n, step); delete ref; } } break; case Task::EXECUTE : { ExecTask * extask; int step; bool must_swap = false; extask = static_cast<ExecTask *>(task); if(!tasks.isEmpty() && tasks.data[tasks.size-1]->getType() == Task::DEL_NAMES){ if((*extask->ref)->getType() == SchObject::LIST){ // TODO must_swap = false; } else if((*extask->ref)->getType() != SchObject::SPECIAL){ must_swap = true; } else if(static_cast<SchSpecial *>(&**extask->ref)->prepareArgs()){ must_swap = true; } } if(must_swap) { // swap tasks Task * tmp = tasks.data[tasks.size-1]; // DEL_NAMES tasks.push(task); tasks.data[tasks.size-2] = tasks.data[tasks.size-1]; // DEL <- CALL tasks.data[tasks.size-1] = tmp; // CALL <- tmp } else { SchObjectRef * ref; ref = new SchObjectRef(*extask->ref); last_line = (*ref)->getLine(); step = extask->step; n = extask->n; delete task; (*ref)->execute(*this, n, step); delete ref; } } break; case Task::ALIAS : { AliasTask * altask; altask = static_cast<AliasTask *>(task); global_names.push(altask->id, *(altask->ref)); delete task; } break; case Task::ADD_NAMES : { AddNamesTask * atask; local_names_t * tmp; atask = static_cast<AddNamesTask *>(task); tmp = (typeof(tmp)) malloc (sizeof(*tmp)); tmp->current = atask->map; tmp->prev = local_names; local_names = tmp; delete task; } break; case Task::DEL_NAMES : { delete task; if(local_names == NULL){ throw LocalNamespaceUnderflowError(last_line); } else { local_names_t * tmp = local_names->prev; delete local_names->current; delete local_names; local_names = tmp; } } break; case Task::PRINT : { int N; SchObjectRef ** refs; N = static_cast<PrintTask *>(task)->N; refs = results.pop(N, last_line); for(int i = N-1; i >= 0; --i){ (*refs[i])->print(); } printf("\n"); delete task; } break; case Task::PUSH_RESULT : { SchObjectRef * ref; ref = new SchObjectRef( * static_cast<PushResultTask *>(task)->ref ); delete task; pushResult(*ref); delete ref; } break; case Task::NETWORK : { NetworkTask * ntask = static_cast<NetworkTask *>(task); int quantity = ntask->quantity, price = ntask->price, pid=ntask->player_id; if(ntask->gtype == NetworkTask::PERFORM){ client->perform(ntask->subtype, quantity, price); } else { int res = client->getInfo(ntask->gtype, ntask->subtype, pid, quantity, price); pushResult(SchObjectRef(new SchInteger(last_line, res))); } delete task; break; } default: throw RuntimeError(last_line); break; } }