Как я могу повлиять на Graphviz / dot, чтобы сделать более приятные графы управления потоками, удаляя змею и улучшая пересечение ребер? - PullRequest
0 голосов
/ 25 ноября 2018

Я рисую графы потоков управления для программ на Python и хотел бы повлиять на то, какие грани не следует пересекать.Есть ли способ сделать это?

Рассмотрим эту простую программу на Python:

try:
    a += 1
except:
    a += 2
else:
    a = 3

И точечную программу для представления потока управления, сгенерированного с помощью https://github.com/rocky/python-control-flow/

digraph G {
  mclimit=1.5;
  rankdir=TD; ordering=out;
  graph[fontsize=10 fontname="Verdana"];
  color="#efefef";
  node[shape=box style=filled fontsize=8 fontname="Verdana" fillcolor="#efefef"];
  edge[fontsize=8 fontname="Verdana"];

  node_0 [shape = "oval"][label="Basic Block 0\loffsets: 0..12\lflags=entry, block, unconditional, try\ljumps=[34]\l"];
  node_1 [label="Basic Block 1\loffsets: 14..30\lflags=except, unconditional\ljumps=[38]\l"];
  node_2 [label="Basic Block 2\loffsets: 32..32\lflags=end finally\l"];
  node_3 [label="Basic Block 3\loffsets: 34..36\l"];
  node_4 [label="Basic Block 4\loffsets: 38..40\lflags=no fallthrough\l"];

  node_0 -> node_2 [weight=1][color="red"];
  node_3 -> node_4 [weight=10];
  node_0 -> node_1 [weight=1][color="red"];
  node_2 -> node_3 [weight=10];
  node_0 -> node_1 [weight=10][style="invis"];
  node_1 -> node_2 [weight=10][style="invis"];
  node_1 -> node_4 [weight=1];
  node_0 -> node_3 [weight=1];
}

Изображение, которое ставит точкуПроизводительность для вышеупомянутого равна enter image description here

Обратите внимание на то, как одна линия огибает и пересекает прямую стрелку вниз.Вместо этого я бы предпочел, чтобы ни одна из прямых стрелок вниз не была пересечена.Сплайновые края помогут лучше пересечь места.

Если вы посмотрите на точку, у меня есть два невидимых нисходящих края, которые я использую для выравнивания.(В байт-коде они следуют линейной последовательности инструкций).

Так что, если необходимо пересечь прямую линию вниз (а здесь нет), невидимые края предпочтительнее, чем видимые.

Мысли?

Редактировать

Один отличный ответ до сих пор предлагает изменить порядок определения краев и указать в определенных ситуациях, где должны быть выполнены присоединения краев.

В этом приложении у меня есть иерархическая информация о вложенности из дерева доминант, и я могу классифицировать ребра: те, которые зацикливаются, те, которые переходят к концу составной структуры, те, которые выходят из цикла,и т. д.

Так что теперь проблема становится точно как использует эту информацию, чтобы избежать этих змеиных стрелок, и гарантирует, что разрывы циклов предпочтительнее, если они пересекают края, скажем, «если"/" еще "прыжки по краям.

Это похоже на дизайн VLSI: придумать набор шаблонов, которые работают для каждого типа структуры (потока управления), и они будут затем правильно вкладываться и упорядочиваться.

Я экспериментировал супорядочение и размещение краев, и у меня просто нет интуитивного ощущения, когда нужно что-то ставить раньше или позже.

Руководство или, что лучше, правило проектирования для структурированных границ потока управления будет весьма полезным.

1 Ответ

0 голосов
/ 26 ноября 2018

Вам нужно сделать две вещи, чтобы улучшить ситуацию:

  • нарисовать (один из) ребер, которыми вы хотите управлять раньше других,
  • сообщить графу, где выхочу, чтобы они были присоединены (Север, Восток ...)

Я отредактировал ваш код соответственно

digraph G {
  mclimit=1.5;
  rankdir=TD; ordering=out;
  graph[fontsize=10 fontname="Verdana"];
  color="#efefef";
  node[shape=box style=filled fontsize=8 fontname="Verdana" fillcolor="#efefef"];
  edge[fontsize=8 fontname="Verdana"];

  node_0 [shape = "oval"][label="Basic Block 0\loffsets: 0..12\lflags=entry, block, unconditional, try\ljumps=[34]\l"];
  node_1 [label="Basic Block 1\loffsets: 14..30\lflags=except, unconditional\ljumps=[38]\l"];
  node_2 [label="Basic Block 2\loffsets: 32..32\lflags=end finally\l"];
  node_3 [label="Basic Block 3\loffsets: 34..36\l"];
  node_4 [label="Basic Block 4\loffsets: 38..40\lflags=no fallthrough\l"];

  node_0 -> node_3:nw [weight=1];           /* moved up and added directions*/
  node_0 -> node_2 [weight=1][color="red"];
  node_3 -> node_4 [weight=10];
  node_0 -> node_1 [weight=1][color="red"];
  node_2 -> node_3 [weight=10];
  node_0 -> node_1 [weight=10][style="invis"];
  node_1 -> node_2 [weight=10][style="invis"];
  node_1:se -> node_4:ne [weight=1];            /* added directions */
}

, что дает вам

enter image description here

Здесь есть немного проб и ошибок, но я уверен, что это должно помочь.

...