Runs dot for all given jobs.
For each unique format, a single dot invocation is made with -O and all input files for that format.
279{
280 if (dotJobs.empty())
return TRUE;
281
282
283 std::map<std::string, std::map<std::string, std::vector<const DotJob*>>> byFormatAndDir;
284 for (const auto &job : dotJobs)
285 {
286 byFormatAndDir[job.format.str()][job.absPath.str()].push_back(&job);
287 }
288
289 std::mt19937 rng(std::random_device{}());
290 bool ok = true;
291 size_t prev=0;
292 for (const auto &[fmtStr, byDir] : byFormatAndDir)
293 {
294 QCString format = QCString(fmtStr);
295
296 for (const auto &[dirStr, jobs] : byDir)
297 {
300
301
302 const size_t numThreads =
static_cast<size_t>(
Config_getInt(DOT_NUM_THREADS));
303 const size_t batchSize =
static_cast<size_t>(
Config_getInt(DOT_BATCH_SIZE));
304 const size_t exeLen =
m_dotExe.length() + 1;
305 const size_t maxArgLen = 32000-exeLen;
306
307
308 std::vector<size_t> indices(jobs.size());
309 std::iota(indices.begin(), indices.end(), 0);
310 std::shuffle(indices.begin(), indices.end(), rng);
311
312
313 struct CommandArgument
314 {
315 CommandArgument(const QCString &args) : arguments(args) {}
316 QCString arguments;
317 size_t numDotFiles = 0;
318 const DotJob *firstJob = nullptr;
319 };
320
321 std::vector<CommandArgument> partialCommands;
322 std::vector<CommandArgument> finalCommands;
323
324 bool hasImageMap = std::any_of(jobs.begin(),jobs.end(),[](const auto &j) { return j->generateImageMap; });
325
326
327 QCString baseArgs = QCString("-T") + format;
328 if (hasImageMap)
329 {
330 baseArgs += " -Tcmapx";
331 }
332 baseArgs += " -O";
333
334
335 for (size_t i=0; i<numThreads; i++)
336 {
337 partialCommands.emplace_back(baseArgs);
338 }
339
340
341 size_t index=0;
342 for (size_t i : indices)
343 {
344 const auto &job = jobs[i];
345 QCString fileArg = QCString(" ") + job->relDotName;
346 auto &cmd = partialCommands[index];
347 if (cmd.numDotFiles<batchSize && cmd.arguments.length()+fileArg.
length()<maxArgLen)
348 {
349 cmd.arguments+=fileArg;
350 cmd.numDotFiles++;
351 }
352 else
353 {
354 finalCommands.push_back(cmd);
355 cmd.arguments=baseArgs+fileArg;
356 cmd.numDotFiles=1;
357 }
358 if (cmd.firstJob==nullptr) cmd.firstJob=job;
359 index = (index+1)%numThreads;
360 }
361
362
363 finalCommands.insert(finalCommands.end(),partialCommands.begin(),partialCommands.end());
364
365
367 {
368 for (const auto &cmd : finalCommands)
369 {
370 if (cmd.numDotFiles>0)
371 {
372 if (cmd.numDotFiles>1)
373 {
374 msg(
"Running dot for graphs {}-{}/{}\n",prev+1,prev+cmd.numDotFiles,dotJobs.size());
375 }
376 else
377 {
378 msg(
"Running dot for graph {}/{}\n",prev+1,dotJobs.size());
379 }
380 prev+=cmd.numDotFiles;
381 int exitCode;
383 {
385 "Problems running dot: exit code={}, command='{}', dir='{}', arguments='{}'",
386 exitCode,
m_dotExe, dirStr, cmd.arguments);
387 ok = false;
388 }
389 }
390 }
391 }
392 else
393 {
394 ThreadPool workers(numThreads);
395 std::vector< std::future<size_t> > results;
396 for (auto & cmd: finalCommands)
397 {
398 if (cmd.numDotFiles>0)
399 {
400 auto locDirStr = dirStr;
401 auto process = [this,cmd,locDirStr]() -> size_t
402 {
403 int exitCode;
405 {
407 "Problems running dot: exit code={}, command='{}', dir='{}', arguments='{}'",
408 exitCode,
m_dotExe, locDirStr, cmd.arguments);
409 }
410 return cmd.numDotFiles;
411 };
412 results.emplace_back(workers.queue(process));
413 }
414 }
415 for (auto &f : results)
416 {
417 size_t numDotFiles = f.get();
418 if (numDotFiles>1)
419 {
420 msg(
"Finished running dot for graphs {}-{}/{}\n",prev+1,prev+numDotFiles,dotJobs.size());
421 }
422 else
423 {
424 msg(
"Finished running dot for graph {}/{}\n",prev+1,dotJobs.size());
425 }
426 prev+=numDotFiles;
427 }
428 }
429
430
431
432
433 for (const auto *job : jobs)
434 {
436 QCString dotOutput = job->absPath + job->relDotName + "." + format;
437 QCString output = base + "." + format;
438 Dir d;
440 {
441 err(
"Failed to rename {} to {}!\n", dotOutput, output);
442 ok = false;
443 continue;
444 }
445 if (job->generateImageMap)
446 {
447 QCString dotMapOutput = job->absPath + job->relDotName + ".cmapx";
448 QCString mapOutput = base + ".map";
450 {
451 err(
"Failed to rename {} to {}!\n", dotMapOutput, mapOutput);
452 ok = false;
453 continue;
454 }
455 }
456
457 if (format.startsWith("pdf"))
458 {
459 int width=0, height=0;
461 {
462 ok = false;
463 continue;
464 }
466 {
468 {
469 ok = false;
470 continue;
471 }
472
473 QCString rerunArgs = QCString("-T") + format + " -O \"" + job->relDotName + "\"";
474 int exitCode;
476 {
478 "Problems running dot: exit code={}, command='{}', dir='{}', arguments='{}'",
479 exitCode,
m_dotExe, dirStr, rerunArgs);
480 ok = false;
481 }
482 else
483 {
484 Dir d2;
486 {
487 err(
"Failed to rename {} to {}!\n", dotOutput, output);
488 ok = false;
489 }
490 }
491 }
492 }
493 else if (format.startsWith("png"))
494 {
496 }
497 }
499 }
500 }
501
502
503 std::set<std::string> processed;
504 for (const auto &job : dotJobs)
505 {
506 if (!processed.insert((job.absPath + job.relDotName).str()).second) continue;
507
508 if (!job.md5Hash.isEmpty())
509 {
512 if (f)
513 {
514 fwrite(job.md5Hash.data(), 1, 32, f);
516 }
517 }
518
520 {
522 }
523 }
524
525 return ok;
526}
static std::string currentDirPath()
bool rename(const std::string &orgName, const std::string &newName, bool acceptsAbsPath=true) const
static bool setCurrent(const std::string &path)
static bool readBoundingBox(const QCString &fileName, int *width, int *height, bool isEps)
size_t length() const
Returns the length of the string, not counting the 0-terminator.
const std::string & str() const
#define Config_getInt(name)
#define Config_getBool(name)
static QCString getBaseNameOfOutput(const QCString &output)
static void checkPngResult(const QCString &imgName)
#define MAX_LATEX_GRAPH_SIZE
static bool resetPDFSize(const int width, const int height, const QCString &base)
#define err_full(file, line, fmt,...)
void unlink(const QCString &fileName)
FILE * fopen(const QCString &fileName, const QCString &mode)
int system(const QCString &command, const QCString &args, bool commandHasConsole=true)