void resourceOffers(const vector<Offer>& offers) { foreach (const Offer& offer, offers) { cout << "Received offer " << offer.id() << " with " << Resources(offer.resources()) << endl; static const Resources TASK_RESOURCES = Resources::parse( "cpus:" + stringify(CPUS_PER_TASK) + ";mem:" + stringify(MEM_PER_TASK)).get(); Resources remaining = offer.resources(); // Launch tasks. vector<TaskInfo> tasks; while (tasksLaunched < totalTasks && remaining.flatten().contains(TASK_RESOURCES)) { int taskId = tasksLaunched++; cout << "Launching task " << taskId << " using offer " << offer.id() << endl; TaskInfo task; task.set_name("Task " + lexical_cast<string>(taskId)); task.mutable_task_id()->set_value( lexical_cast<string>(taskId)); task.mutable_agent_id()->MergeFrom(offer.agent_id()); task.mutable_executor()->MergeFrom(executor); Option<Resources> resources = remaining.find(TASK_RESOURCES.flatten(framework.role())); CHECK_SOME(resources); task.mutable_resources()->CopyFrom(resources.get()); remaining -= resources.get(); tasks.push_back(task); } Call call; CHECK(framework.has_id()); call.mutable_framework_id()->CopyFrom(framework.id()); call.set_type(Call::ACCEPT); Call::Accept* accept = call.mutable_accept(); accept->add_offer_ids()->CopyFrom(offer.id()); Offer::Operation* operation = accept->add_operations(); operation->set_type(Offer::Operation::LAUNCH); foreach (const TaskInfo& taskInfo, tasks) { operation->mutable_launch()->add_task_infos()->CopyFrom(taskInfo); }
virtual void resourceOffers(SchedulerDriver* driver, const vector<Offer>& offers) { foreach (const Offer& offer, offers) { cout << "Received offer " << offer.id() << " with " << offer.resources() << endl; static const Resources TASK_RESOURCES = Resources::parse( "cpus:" + stringify(CPUS_PER_TASK) + ";mem:" + stringify(MEM_PER_TASK)).get(); Resources remaining = offer.resources(); // Launch tasks. vector<TaskInfo> tasks; while (tasksLaunched < totalTasks && remaining.flatten().contains(TASK_RESOURCES)) { int taskId = tasksLaunched++; cout << "Launching task " << taskId << " using offer " << offer.id() << endl; TaskInfo task; task.set_name("Task " + lexical_cast<string>(taskId)); task.mutable_task_id()->set_value(lexical_cast<string>(taskId)); task.mutable_slave_id()->MergeFrom(offer.slave_id()); task.mutable_executor()->MergeFrom(executor); Try<Resources> flattened = TASK_RESOURCES.flatten(role); CHECK_SOME(flattened); Option<Resources> resources = remaining.find(flattened.get()); CHECK_SOME(resources); task.mutable_resources()->MergeFrom(resources.get()); remaining -= resources.get(); tasks.push_back(task); } driver->launchTasks(offer.id(), tasks); }
virtual void resourceOffers(SchedulerDriver* driver, const vector<Offer>& offers) { for (size_t i = 0; i < offers.size(); i++) { const Offer& offer = offers[i]; Resources remaining = offer.resources(); static Resources TASK_RESOURCES = Resources::parse( "cpus:" + stringify<float>(CPUS_PER_TASK) + ";mem:" + stringify<size_t>(MEM_PER_TASK)).get(); size_t maxTasks = 0; while (remaining.flatten().contains(TASK_RESOURCES)) { maxTasks++; remaining -= TASK_RESOURCES; } // Launch tasks. vector<TaskInfo> tasks; for (size_t i = 0; i < maxTasks / 2 && crawlQueue.size() > 0; i++) { string url = crawlQueue.front(); crawlQueue.pop(); string urlId = "C" + stringify<size_t>(processed[url]); TaskInfo task; task.set_name("Crawler " + urlId); task.mutable_task_id()->set_value(urlId); task.mutable_slave_id()->MergeFrom(offer.slave_id()); task.mutable_executor()->MergeFrom(crawler); task.mutable_resources()->MergeFrom(TASK_RESOURCES); task.set_data(url); tasks.push_back(task); tasksLaunched++; cout << "Crawler " << urlId << " " << url << endl; } for (size_t i = maxTasks/2; i < maxTasks && renderQueue.size() > 0; i++) { string url = renderQueue.front(); renderQueue.pop(); string urlId = "R" + stringify<size_t>(processed[url]); TaskInfo task; task.set_name("Renderer " + urlId); task.mutable_task_id()->set_value(urlId); task.mutable_slave_id()->MergeFrom(offer.slave_id()); task.mutable_executor()->MergeFrom(renderer); task.mutable_resources()->MergeFrom(TASK_RESOURCES); task.set_data(url); tasks.push_back(task); tasksLaunched++; cout << "Renderer " << urlId << " " << url << endl; } driver->launchTasks(offer.id(), tasks); } }
TEST(ResourcesTest, FlattenRoles) { Resource cpus1 = Resources::parse("cpus", "1", "role1").get(); Resource cpus2 = Resources::parse("cpus", "2", "role2").get(); Resource mem1 = Resources::parse("mem", "5", "role1").get(); Resources r; r += cpus1; r += cpus2; r += mem1; EXPECT_EQ(r.flatten(), Resources::parse("cpus:3;mem:5").get()); }
// For use with a MockScheduler, for example: // EXPECT_CALL(sched, resourceOffers(_, _)) // .WillOnce(LaunchTasks(TASKS, CPUS, MEM)); // Launches up to TASKS no-op tasks, if possible, // each with CPUS cpus and MEM memory. ACTION_P4(LaunchTasks, tasks, cpus, mem, role) { SchedulerDriver* driver = arg0; std::vector<Offer> offers = arg1; int numTasks = tasks; int launched = 0; for (size_t i = 0; i < offers.size(); i++) { const Offer& offer = offers[i]; const Resources TASK_RESOURCES = Resources::parse( "cpus:" + stringify(cpus) + ";mem:" + stringify(mem)).get(); int nextTaskId = 0; std::vector<TaskInfo> tasks; Resources remaining = offer.resources(); while (TASK_RESOURCES <= remaining.flatten() && launched < numTasks) { TaskInfo task; task.set_name("TestTask"); task.mutable_task_id()->set_value(stringify(nextTaskId++)); task.mutable_slave_id()->MergeFrom(offer.slave_id()); ExecutorInfo executor; executor.mutable_executor_id()->set_value("default"); executor.mutable_command()->set_value(":"); task.mutable_executor()->MergeFrom(executor); Option<Resources> resources = remaining.find(TASK_RESOURCES, role); CHECK_SOME(resources); task.mutable_resources()->MergeFrom(resources.get()); remaining -= resources.get(); tasks.push_back(task); launched++; } driver->launchTasks(offer.id(), tasks); } }
virtual void resourceOffers(SchedulerDriver* driver, const vector<Offer>& offers) { cout << "." << flush; for (size_t i = 0; i < offers.size(); i++) { const Offer& offer = offers[i]; static const Resources TASK_RESOURCES = Resources::parse( "cpus:" + stringify(CPUS_PER_TASK) + ";mem:" + stringify(MEM_PER_TASK)).get(); Resources remaining = offer.resources(); // Launch tasks. vector<TaskInfo> tasks; while (tasksLaunched < totalTasks && TASK_RESOURCES <= remaining.flatten()) { int taskId = tasksLaunched++; cout << "Starting task " << taskId << " on " << offer.hostname() << endl; TaskInfo task; task.set_name("Task " + lexical_cast<string>(taskId)); task.mutable_task_id()->set_value(lexical_cast<string>(taskId)); task.mutable_slave_id()->MergeFrom(offer.slave_id()); task.mutable_executor()->MergeFrom(executor); Option<Resources> resources = remaining.find(TASK_RESOURCES, role); CHECK_SOME(resources); task.mutable_resources()->MergeFrom(resources.get()); remaining -= resources.get(); tasks.push_back(task); } driver->launchTasks(offer.id(), tasks); } }
void ChapelScheduler::resourceOffers(SchedulerDriver* driver, const vector<Offer>& offers) { // offers only contain resources describing a single node -> for more details read include/mesos/mesos.proto // cout << "***\tProcessing Offers!" << endl; const int remainingCpusReq = cpusReq - launchedTsks.size(); if(remainingCpusReq == 0) { for(size_t k = 0; k < offers.size(); k++) { const Offer& offer = offers[k]; driver->declineOffer(offer.id()); } cout << "\t\tChapelScheduler declined offer because resource requirements satisfied" << endl; } // cycle through all the offers and resource a task // each offer corresponds to a single compute node // const static Resources TASK_RESOURCES = Resources::parse(mesosReq).get(); vector<TaskInfo> tsks; for(size_t i = 0; i < offers.size(); i++) { const Offer& offer = offers[i]; if(tsks.size() == remainingCpusReq) { driver->declineOffer(offer.id()); continue; // need to cycle through the remaining offers and decline them } Resources remaining = offer.resources(); /* attempting to exercise multi-tenancy capabilities in mesos * given an offer from a node, try to maximize the number of jobs * that can be allocated to that node given the job's resource * requirements * * if the desired number of nodes and jobs are met, then launch * all the jobs on that node's offer * * this means some nodes will get multiple tasks assigned for * execution */ vector<TaskInfo> tol; while(remaining.flatten().contains(TASK_RESOUCES) && ((remainingCpusReq-tsks.size()) > 0)) { const string tid = stringify<size_t>(tsks.size()); TaskInfo task; task.set_name("Chapel Remote Program Task\t" + tid); task.mutable_task_id()->set_value(tid); task.mutable_slave_id()->MergeFrom(offer.slave_id()); task.mutable_command()->MergeFrom(chplCmdInfo); task.mutable_resources()->MergeFrom(TASK_RESOURCES); task.set_data(remoteCmd); tol.push_back(task); // tol means "to launch" tsks.push_back(task); // tsks tracks tasks launched for framework termination purposes remaining-=TASK_RESOURCES; tasksLaunched+=1; cout << "\t\t+++\tLaunching # of Tasks!\t" << tol.size() << " of " << tasksLaunched << endl; } // after all the tasks for this offer have been "resourced" // launch the tasks using this offer.id // driver->launchTasks(offer.id(), tol); } const size_t pendingTsksSize = tsks.size(); cout << endl << "\tAcquired # tasks " << pendingTsksSize << " required # of tasks " << cpusReq << " remaining required # tasks " << remainingCpusReq << endl << endl; if(pendingTsksSize > 0) { for(vector<TaskInfo>::iterator i = tsks.begin(); i != tsks.end(); i++) { launchedTsks.insert(make_pair(i->task_id().value(), *i)); } } }