107 template <
typename Ntk,
typename Opt,
typename Par>
125 std::stringstream ss;
131 template <
typename Ntk,
typename Opt,
typename Par>
135 return lhs->
id > rhs->
id;
143 template <
typename Ntk,
typename Opt,
typename Par>
144 template<
typename... Args>
145 inline void Scheduler<Ntk, Opt, Par>::Print(
int nVerboseLevel, std::string prefix, Args... args) {
146 if(nVerbose <= nVerboseLevel) {
149#ifdef ABC_USE_PTHREADS
150 if(fMultiThreading) {
152 std::unique_lock<std::mutex> l(mutexPrint);
155 std::cout << std::endl;
162 std::cout << std::endl;
169 template <
typename Ntk,
typename Opt,
typename Par>
170 inline seconds Scheduler<Ntk, Opt, Par>::GetRemainingTime()
const {
175 seconds nRemainingTime = nTimeout - DurationInSeconds(timeStart, timeCurrent);
176 if(nRemainingTime == 0) {
179 return nRemainingTime;
182 template <
typename Ntk,
typename Opt,
typename Par>
183 inline double Scheduler<Ntk, Opt, Par>::GetElapsedTime()
const {
185 return Duration(timeStart, timeCurrent);
192 template <
typename Ntk,
typename Opt,
typename Par>
193 inline void Scheduler<Ntk, Opt, Par>::CallAbc(Ntk *pNtk_, std::string Command) {
194#ifdef ABC_USE_PTHREADS
195 if(fMultiThreading) {
197 std::unique_lock<std::mutex> l(mutexAbc);
210 template <
typename Ntk,
typename Opt,
typename Par>
211 void Scheduler<Ntk, Opt, Par>::RunJob(Opt &
opt, Job *pJob) {
213 opt.AssignNetwork(pJob->pNtk, !fPartitioning);
214 opt.SetPrintLine([&](std::string str) {
215 Print(-1, pJob->prefix, str);
220 opt.Run(pJob->iSeed, GetRemainingTime());
223 std::mt19937 rng(pJob->iSeed);
224 double cost = pJob->costInitial;
225 double costBest = cost;
226 Ntk best(*(pJob->pNtk));
227 for(
int i = 0; i < 10; i++) {
228 if(GetRemainingTime() < 0) {
232 CallAbc(pJob->pNtk,
"&if -K 6; &mfs; &st");
233 cost = CostFunction(pJob->pNtk);
234 Print(1, pJob->prefix,
"hop", i,
":",
"cost",
"=", cost);
236 for(
int j = 0;
true; j++) {
237 if(GetRemainingTime() < 0) {
240 opt.Run(rng(), GetRemainingTime());
241 CallAbc(pJob->pNtk,
"&dc2");
242 double costNew = CostFunction(pJob->pNtk);
243 Print(1, pJob->prefix,
"ite", j,
":",
"cost",
"=", costNew);
250 if(cost < costBest) {
252 best = *(pJob->pNtk);
256 *(pJob->pNtk) = best;
260 std::mt19937 rng(pJob->iSeed);
262 double cost = pJob->costInitial;
263 Ntk best(*(pJob->pNtk));
264 for(
int i = 0; i < 1000000; i++) {
265 if(GetRemainingTime() < 0) {
270 unsigned Rand = rng();
273 int fCom = (Rand >> 1) & 1;
274 int fFx = (Rand >> 2) & 1;
275 int KLut = fUseTwo ? 2 + (i % 5) : 3 + (i % 4);
278 pComp = std::string(
"; &put; ") + pCompress2rs +
"; " + pCompress2rs +
"; " + pCompress2rs +
"; &get";
279 else if ( fCom == 2 )
280 pComp = std::string(
"; &put; ") + pCompress2rs +
"; " + pCompress2rs +
"; &get";
281 else if ( fCom == 1 )
282 pComp = std::string(
"; &put; ") + pCompress2rs +
"; &get";
283 else if ( fCom == 0 )
285 std::string Command =
"&dch";
288 Command +=
"; &if -a -K " + std::to_string(KLut) +
"; &mfs -e -W 20 -L 20";
290 Command +=
"; &fx; &st";
292 CallAbc(pJob->pNtk, Command);
293 Print(1, pJob->prefix,
"ite", i,
":",
"cost",
"=", CostFunction(pJob->pNtk));
295 for(
int j = 0; j < n; j++) {
296 if(GetRemainingTime() < 0) {
299 opt.Run(rng(), GetRemainingTime());
301 CallAbc(pJob->pNtk,
"&dc2");
303 CallAbc(pJob->pNtk, std::string(
"&put; ") + pCompress2rs +
"; &get");
305 Print(1, pJob->prefix,
"rrr", j,
":",
"cost",
"=", CostFunction(pJob->pNtk));
308 double costNew = CostFunction(pJob->pNtk);
311 best = *(pJob->pNtk);
316 *(pJob->pNtk) = best;
320 opt.Run(pJob->iSeed, GetRemainingTime());
321 CallAbc(pJob->pNtk, std::string(
"&put; ") + pCompress2rs +
"; dc2; &get");
327 pJob->duration = Duration(timeStartLocal, timeEndLocal);
328 pJob->stats =
opt.GetStatsSummary();
329 pJob->times =
opt.GetTimesSummary();
337 template <
typename Ntk,
typename Opt,
typename Par>
339 Job *pJob =
new Job(nCreatedJobs++, pNtk_, iSeed_, cost);
340#ifdef ABC_USE_PTHREADS
341 if(fMultiThreading) {
343 std::unique_lock<std::mutex> l(mutexPendingJobs);
344 qPendingJobs.push(pJob);
345 condPendingJobs.notify_one();
350 qPendingJobs.push(pJob);
354 template <
typename Ntk,
typename Opt,
typename Par>
355 void Scheduler<Ntk, Opt, Par>::OnJobEnd(std::function<
void(Job *pJob)>
const &func) {
356#ifdef ABC_USE_PTHREADS
357 if(fMultiThreading) {
360 std::unique_lock<std::mutex> l(mutexFinishedJobs);
361 while(qFinishedJobs.empty() || (fDeterministic && qFinishedJobs.top()->id != nFinishedJobs)) {
362 condFinishedJobs.wait(l);
364 pJob = qFinishedJobs.top();
369 AddToSummary(vStatsSummaryKeys, mStatsSummary, pJob->stats);
370 AddToSummary(vTimesSummaryKeys, mTimesSummary, pJob->times);
377 assert(!qPendingJobs.empty());
378 Job *pJob = qPendingJobs.front();
382 AddToSummary(vStatsSummaryKeys, mStatsSummary, pJob->stats);
383 AddToSummary(vTimesSummaryKeys, mTimesSummary, pJob->times);
392#ifdef ABC_USE_PTHREADS
393 template <
typename Ntk,
typename Opt,
typename Par>
395 Opt
opt(pPar, CostFunction);
399 std::unique_lock<std::mutex> l(mutexPendingJobs);
400 while(!fTerminate && qPendingJobs.empty()) {
401 condPendingJobs.wait(l);
404 assert(qPendingJobs.empty());
407 pJob = qPendingJobs.front();
413 std::unique_lock<std::mutex> l(mutexFinishedJobs);
414 qFinishedJobs.push(pJob);
415 condFinishedJobs.notify_one();
425 template <
typename Ntk,
typename Opt,
typename Par>
426 template <
typename T>
427 void Scheduler<Ntk, Opt, Par>::AddToSummary(std::vector<std::string> &
keys, std::map<std::string, T> &m,
summary<T> const &result)
const {
428 std::vector<std::string>::iterator it =
keys.begin();
429 for(
auto const &entry: result) {
430 if(m.count(entry.first)) {
431 m[entry.first] += entry.second;
432 it = std::find(it,
keys.end(), entry.first);
436 m[entry.first] = entry.second;
437 it =
keys.insert(it, entry.first);
447 template <
typename Ntk,
typename Opt,
typename Par>
450 nVerbose(pPar->nSchedulerVerbose),
452 nFlow(pPar->nSchedulerFlow),
454 fMultiThreading(pPar->nThreads > 1),
455 fPartitioning(pPar->nPartitionSize > 0),
456 fDeterministic(pPar->fDeterministic),
457 nParallelPartitions(pPar->nParallelPartitions),
458 fOptOnInsert(pPar->fOptOnInsert),
459 nTimeout(pPar->nTimeout),
465 CostFunction = [](Ntk *pNtk) {
466 int nTwoInputSize = 0;
467 pNtk->ForEachInt([&](
int id) {
468 nTwoInputSize += pNtk->GetNumFanins(
id) - 1;
470 return nTwoInputSize;
472#ifdef ABC_USE_PTHREADS
474 if(fMultiThreading) {
476 for(
int i = 0; i < pPar->
nThreads; i++) {
477 vThreads.emplace_back(std::bind(&Scheduler::Thread,
this, pPar));
483 pOpt =
new Opt(pPar, CostFunction);
486 template <
typename Ntk,
typename Opt,
typename Par>
488#ifdef ABC_USE_PTHREADS
489 if(fMultiThreading) {
491 std::unique_lock<std::mutex> l(mutexPendingJobs);
493 condPendingJobs.notify_all();
495 for(std::thread &t: vThreads) {
508 template <
typename Ntk,
typename Opt,
typename Par>
510 timeStart = GetCurrentTime();
511 double costStart = CostFunction(pNtk);
513 fDeterministic =
false;
515 par.AssignNetwork(pNtk);
516 while(nCreatedJobs < nJobs) {
517 assert(nParallelPartitions > 0);
518 if(nCreatedJobs < nFinishedJobs + nParallelPartitions) {
519 Ntk *pSubNtk = par.Extract(iSeed + nCreatedJobs);
521 Job *pJob = CreateJob(pSubNtk, iSeed + nCreatedJobs, CostFunction(pSubNtk));
522 Print(1, pJob->
prefix,
"created ",
":",
"i/o",
"=", pJob->
pNtk->GetNumPis(),
"/", pJob->
pNtk->GetNumPos(),
",",
"node",
"=", pJob->
pNtk->GetNumInts(),
",",
"level",
"=", pJob->
pNtk->GetNumLevels(),
",",
"cost",
"=", pJob->
costInitial);
526 if(nCreatedJobs == nFinishedJobs) {
527 PrintWarning(
"failed to partition");
530 while(nFinishedJobs < nCreatedJobs) {
531 OnJobEnd([&](
Job *pJob) {
532 double cost = CostFunction(pJob->
pNtk);
533 Print(1, pJob->
prefix,
"finished",
":",
"i/o",
"=", pJob->
pNtk->GetNumPis(),
"/", pJob->
pNtk->GetNumPos(),
",",
"node",
"=", pJob->
pNtk->GetNumInts(),
",",
"level",
"=", pJob->
pNtk->GetNumLevels(),
",",
"cost",
"=", cost);
534 Print(0,
"",
"job", pJob->
id,
"(", nFinishedJobs + 1,
"/", nJobs,
")",
":",
"i/o",
"=", pJob->
pNtk->GetNumPis(),
"/", pJob->
pNtk->GetNumPos(),
",",
"node",
"=", pJob->
pNtk->GetNumInts(),
",",
"level",
"=", pJob->
pNtk->GetNumLevels(),
",",
"cost",
"=", cost,
"(", 100 * (cost - pJob->
costInitial) / pJob->
costInitial,
"%",
")",
",",
"duration",
"=", pJob->
duration,
"s",
",",
"elapsed",
"=", GetElapsedTime(),
"s");
535 par.Insert(pJob->
pNtk);
540 CallAbc(pNtk, std::string(
"&put; ") + pCompress2rs +
"; dc2; &get");
542 par.AssignNetwork(pNtk);
543 double cost = CostFunction(pNtk);
544 Print(0,
"",
"c2rs; dc2",
":", std::string(34,
' '),
"node",
"=", pNtk->GetNumInts(),
",",
"level",
"=", pNtk->GetNumLevels(),
",",
"cost",
"=", cost,
"(", 100 * (cost - costStart) / costStart,
"%",
")",
",",
"duration",
"=", Duration(timeStartLocal, timeEndLocal),
"s",
",",
"elapsed",
"=", GetElapsedTime(),
"s");
547 while(nFinishedJobs < nCreatedJobs) {
548 OnJobEnd([&](
Job *pJob) {
549 double cost = CostFunction(pJob->
pNtk);
550 Print(1, pJob->
prefix,
"finished",
":",
"i/o",
"=", pJob->
pNtk->GetNumPis(),
"/", pJob->
pNtk->GetNumPos(),
",",
"node",
"=", pJob->
pNtk->GetNumInts(),
",",
"level",
"=", pJob->
pNtk->GetNumLevels(),
",",
"cost",
"=", CostFunction(pJob->
pNtk));
551 Print(0,
"",
"job", pJob->
id,
"(", nFinishedJobs + 1,
"/", nJobs,
")",
":",
"i/o",
"=", pJob->
pNtk->GetNumPis(),
"/", pJob->
pNtk->GetNumPos(),
",",
"node",
"=", pJob->
pNtk->GetNumInts(),
",",
"level",
"=", pJob->
pNtk->GetNumLevels(),
",",
"cost",
"=", cost,
"(", 100 * (cost - pJob->
costInitial) / pJob->
costInitial,
"%",
")",
",",
"duration",
"=", pJob->
duration,
"s",
",",
"elapsed",
"=", GetElapsedTime(),
"s");
552 par.Insert(pJob->
pNtk);
556 CallAbc(pNtk, std::string(
"&put; ") + pCompress2rs +
"; dc2; &get");
557 par.AssignNetwork(pNtk);
559 }
else if(nJobs > 1) {
560 double costBest = costStart;
561 for(
int i = 0; i < nJobs; i++) {
562 Ntk *pCopy =
new Ntk(*pNtk);
563 CreateJob(pCopy, iSeed + i, costBest);
565 for(
int i = 0; i < nJobs; i++) {
566 OnJobEnd([&](
Job *pJob) {
567 double cost = CostFunction(pJob->
pNtk);
568 Print(0,
"",
"job", pJob->
id,
"(", nFinishedJobs + 1,
"/", nJobs,
")",
":",
"node",
"=", pJob->
pNtk->GetNumInts(),
",",
"level",
"=", pJob->
pNtk->GetNumLevels(),
",",
"cost",
"=", cost,
"(", 100 * (cost - pJob->
costInitial) / pJob->
costInitial,
"%",
")",
",",
"duration",
"=", pJob->
duration,
"s",
",",
"elapsed",
"=", GetElapsedTime(),
"s");
569 if(cost < costBest) {
571 *pNtk = *(pJob->
pNtk);
577 CreateJob(pNtk, iSeed, costStart);
578 OnJobEnd([&](
Job *pJob) {
579 double cost = CostFunction(pJob->
pNtk);
580 Print(0,
"",
"job", pJob->
id,
"(", nFinishedJobs + 1,
"/", nJobs,
")",
":",
"node",
"=", pJob->
pNtk->GetNumInts(),
",",
"level",
"=", pJob->
pNtk->GetNumLevels(),
",",
"cost",
"=", cost,
"(", 100 * (cost - pJob->
costInitial) / pJob->
costInitial,
"%",
")",
",",
"duration",
"=", pJob->
duration,
"s",
",",
"elapsed",
"=", GetElapsedTime(),
"s");
583 double cost = CostFunction(pNtk);
584 double duration = GetElapsedTime();
585 Print(0,
"\n",
"stats summary",
":");
586 for(std::string
key: vStatsSummaryKeys) {
587 Print(0,
"\t",
SW{30,
true},
key,
":",
SW{10}, mStatsSummary[
key]);
589 Print(0,
"",
"runtime summary",
":");
590 for(std::string
key: vTimesSummaryKeys) {
591 Print(0,
"\t",
SW{30,
true},
key,
":", mTimesSummary[
key],
"s",
"(", 100 * mTimesSummary[
key] / duration,
"%",
")");
593 Print(0,
"",
"end",
":",
"cost",
"=", cost,
"(", 100 * (cost - costStart) / costStart,
"%",
")",
",",
"time",
"=", duration,
"s");