Skip to content

Commit

Permalink
debug view flame-graph
Browse files Browse the repository at this point in the history
  • Loading branch information
quinchs committed Mar 9, 2024
1 parent 8cc1ebb commit e035d58
Show file tree
Hide file tree
Showing 10 changed files with 208 additions and 97 deletions.
11 changes: 7 additions & 4 deletions src/EdgeDB.Net.QueryBuilder/Builders/ShapeBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,17 @@ internal class SelectShape
{
private readonly SelectedProperty[] _shape;

public SelectShape(IEnumerable<SelectedProperty> shape)
private readonly Type _type;

public SelectShape(IEnumerable<SelectedProperty> shape, Type type)
{
_shape = shape.ToArray();
_type = type;
}

public void Compile(QueryWriter writer, SelectShapeExpressionTranslatorCallback translator)
{
writer.Shape($"shape_{_shape.GetHashCode()}", _shape, (writer, x) =>
writer.Shape($"{_type.GetEdgeDBTypeName()}_shape", _shape, (writer, x) =>
{
x.Compile(writer, translator);
});
Expand Down Expand Up @@ -163,7 +166,7 @@ internal static MemberInfo GetSelectedProperty(LambdaExpression expression)

internal SelectShape GetShape()
{
return new(SelectedProperties.Select(x => x.Value));
return new(SelectedProperties.Select(x => x.Value), SelectedType);
}

SelectShape IShapeBuilder.GetShape() => GetShape();
Expand Down Expand Up @@ -266,7 +269,7 @@ private SelectedProperty ParseShape(MemberInfo info, ShapeElementExpression elem
var flattened = FlattenNewExpression(info.GetMemberType(), newExpression, element.Root)
.Select(x => ParseShape(x.Key, x.Value));

return new SelectedProperty(info, new SelectShape(flattened));
return new SelectedProperty(info, new SelectShape(flattened, info.GetMemberType()));
}

// computed
Expand Down
118 changes: 83 additions & 35 deletions src/EdgeDB.Net.QueryBuilder/Compiled/DebugCompiledQuery.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,87 +14,129 @@ internal DebugCompiledQuery(string query, Dictionary<string, object?> variables,
DebugView = CreateDebugText(query, variables, markers);
}

private static string NumberCircle(int i)
{
if (i <= 50)
{
return i == 0 ? "\u24ea" : ((char)('\u2460' + i - 1)).ToString();
}

return i.ToString();
}

private static string CreateDebugText(string query, Dictionary<string, object?> variables,
LinkedList<QuerySpan> markers)
{
var sb = new StringBuilder();

sb.AppendLine(query);

if (markers.Count > 0)
{
StringBuilder? topRow = null;

var view = CreateMarkerView(markers);
var markerTexts = new Dictionary<string, string>();
var markerTexts = new Dictionary<string, QuerySpan>();
var rows = new List<StringBuilder>();

foreach (var row in view)
{
var rowText = new StringBuilder($"{"".PadLeft(query.Length)}\n{"".PadLeft(query.Length)}");


foreach (var column in row)
{
var size = column.Range.End.Value - column.Range.Start.Value;

if (size <= 2)
{
topRow ??= new StringBuilder("".PadLeft(query.Length));

var indicator = (markerTexts.Count + 1).ToString();

topRow.Remove(column.Range.Start.Value, indicator.Length);
topRow.Insert(column.Range.Start.Value, indicator);

markerTexts.Add(indicator, column);
continue;
}

// bar
rowText.Remove(column.Range.Start.Value, size);
var barText = new StringBuilder($"\u2550".PadLeft(size - 3, '\u2550'));

barText.Insert(barText.Length / 2, "\u2566"); // T
barText.Insert(0, "\u255a"); // corner UR
barText.Insert(size - 1, "\u255d"); // corner UL
rowText.Insert(column.Range.Start.Value, barText);

foreach (var prevRowText in rows)
{
prevRowText.Remove(column.Range.Start.Value, 1);
prevRowText.Insert(column.Range.Start.Value, '\u2551');
prevRowText.Remove(query.Length + 1 + column.Range.Start.Value, 1);
prevRowText.Insert(query.Length + 1 + column.Range.Start.Value, '\u2551');

prevRowText.Remove(column.Range.End.Value - 1, 1);
prevRowText.Insert(column.Range.End.Value - 1, '\u2551');
prevRowText.Remove(query.Length + column.Range.End.Value, 1);
prevRowText.Insert(query.Length + column.Range.End.Value, '\u2551');
var prevStart = prevRowText[column.Range.Start.Value];

if (prevStart is ' ' or '\u255a')
{
prevRowText.Remove(column.Range.Start.Value, 1);
prevRowText.Insert(column.Range.Start.Value, prevStart == '\u255a' ? '\u2560' : '\u2551');
}

prevStart = prevRowText[query.Length + 1 + column.Range.Start.Value];

if (prevStart is ' ' or '\u255a')
{
prevRowText.Remove(query.Length + 1 + column.Range.Start.Value, 1);
prevRowText.Insert(query.Length + 1 + column.Range.Start.Value, prevStart == '\u255a' ? '\u2560' : '\u2551');
}

var prevEnd = prevRowText[column.Range.End.Value - 1];

if (prevEnd is ' ' or '\u255d')
{
prevRowText.Remove(column.Range.End.Value - 1, 1);
prevRowText.Insert(column.Range.End.Value - 1, prevEnd == '\u255d' ? '\u2563' : '\u2551');
}

prevEnd = prevRowText[query.Length + column.Range.End.Value];

if (prevEnd is ' ' or '\u255d')
{
prevRowText.Remove(query.Length + column.Range.End.Value, 1);
prevRowText.Insert(query.Length + column.Range.End.Value, prevEnd == '\u255d' ? '\u2563' : '\u2551');
}
}

// desc
var desc = $"{column.Marker.Type}: {column.Name}";
string descriptionText;
var icon = (markerTexts.Count + 1).ToString();
var desc = $"{icon} [{column.Marker.Type}] {column.Name}";

if (column.Marker.DebugText is not null)
desc += $": {column.Marker.DebugText.Get()}";


if (desc.Length > size)
if (desc.Length - 3 > size)
{
var icon = NumberCircle(markerTexts.Count + 1);
markerTexts.Add(icon, desc);
descriptionText = icon;
desc = $"{icon} [{column.Marker.Type}] {column.Name}";
}
else

if (desc.Length - 3 > size)
{
desc = $"{icon} {column.Name}";
}

if (desc.Length - 3 >= size)
{
descriptionText = desc;
desc = icon;
}

markerTexts.Add(icon, column);

var position = query.Length + 1 // line 2
+ column.Range.Start.Value // start of the slice
+ size / 2 // half of the slices' length : center of the slice
- (descriptionText.Length == 1 ? 1 : descriptionText.Length / 2); // half of the contents length : centers it
- (desc.Length == 1
? size % 2 == 0 ? 1 : 0 // don't ask
: desc.Length / 2); // half of the contents length : centers it

rowText.Remove(position, descriptionText.Length);
rowText.Insert(position, descriptionText);
rowText.Remove(position, desc.Length);
rowText.Insert(position, desc);
}

rows.Add(rowText);

}

if (topRow is not null)
sb.AppendLine(topRow.ToString());

sb.AppendLine(query);

foreach (var row in rows)
{
sb.AppendLine(row.ToString());
Expand All @@ -104,14 +146,20 @@ private static string CreateDebugText(string query, Dictionary<string, object?>
{
sb.AppendLine("Markers:");

var markerTypePadding = Enum.GetValues<MarkerType>().Max(x => Enum.GetName(x)!.Length) + 2;
foreach (var (name, value) in markerTexts)
{
sb.AppendLine($" - {name}: {value}");
var desc = $"{$"[{value.Marker.Type}]".PadRight(markerTypePadding)} {value.Name}";
if (value.Marker.DebugText is not null)
desc += $": {value.Marker.DebugText.Get()}";

sb.AppendLine($" - {name.PadRight(markerTexts.Count.ToString().Length)} {$"({value.Range})".PadRight(query.Length.ToString().Length*2+4)} {desc}");
}
}
}
else
{
sb.AppendLine(query);
sb.AppendLine();
}

Expand Down
54 changes: 36 additions & 18 deletions src/EdgeDB.Net.QueryBuilder/Grammar/Terms.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
internal static class Terms
{
#region Markers
public static QueryWriter LabelVariable(this QueryWriter writer, string name, params Value[] values)
=> writer.Marker(MarkerType.Variable, name, values);
public static QueryWriter LabelVerbose(this QueryWriter writer, string name, params Value[] values)
=> writer.Marker(MarkerType.Verbose, name, values);
public static QueryWriter LabelVariable(this QueryWriter writer, string name, Deferrable<string>? debug = null, params Value[] values)
=> writer.Marker(MarkerType.Variable, name, debug, values);
public static QueryWriter LabelVerbose(this QueryWriter writer, string name, Deferrable<string>? debug = null, params Value[] values)
=> writer.Marker(MarkerType.Verbose, name, debug, values);
#endregion

public static QueryWriter Wrapped(this QueryWriter writer, Value value, string separator = "()")
Expand All @@ -20,7 +20,7 @@ public static QueryWriter Wrapped(this QueryWriter writer, Value value, string s
public static QueryWriter Wrapped(this QueryWriter writer, WriterProxy value, string separator = "()")
{
if (separator.Length != 2)
throw new ArgumentOutOfRangeException(nameof(separator));
throw new ArgumentOutOfRangeException(nameof(separator));

return writer.Append(separator[0], value, separator[1]);
}
Expand All @@ -38,19 +38,19 @@ public static QueryWriter WrappedValues(this QueryWriter writer, string separato
return writer.Append(value);
}

public static QueryWriter Shape(this QueryWriter writer, string name, params Value[] values)
public static QueryWriter Shape(this QueryWriter writer, string name, Deferrable<string>? debug, params Value[] values)
{
var value = new Value[values.Length + 2];
value[0] = "{ ";
value[^1] = " }";

values.CopyTo(value[1..^1].AsSpan());

return writer.Marker(MarkerType.Shape, name, value);
return writer.Marker(MarkerType.Shape, name, debug, value);
}

public static QueryWriter Shape<T>(this QueryWriter writer, string name, T[] elements,
Action<QueryWriter, T> func, string parentheses = "{}")
Action<QueryWriter, T> func, string parentheses = "{}", Deferrable<string>? debug = null)
{
if (parentheses.Length != 2)
throw new ArgumentException("Parentheses must contain 2 characters", nameof(parentheses));
Expand All @@ -69,7 +69,8 @@ public static QueryWriter Shape<T>(this QueryWriter writer, string name, T[] ele
}

writer.Append(' ', parentheses[1]);
})
}),
debug
);
}

Expand Down Expand Up @@ -119,22 +120,39 @@ public FunctionArg(Value value, string? named = null)

public static QueryWriter Function(this QueryWriter writer, string name, params FunctionArg[] args)
{
return writer.Marker(MarkerType.Function, $"func_{name}_{args.GetHashCode()}", Value.Of(
return writer.Marker(MarkerType.Function, $"func_{name}", Value.Of(
writer =>
{
writer.Append(name, '(');

for (var i = 0; i < args.Length;)
{
var arg = args[i++];

if(writer.AppendIsEmpty(arg.Value, out _, out var node))
bool isEmpty = false;

writer.Marker(
MarkerType.FunctionArg,
$"func_{name}_arg_{i}",
null,
Value.Of(
writer =>
{
if (writer.AppendIsEmpty(arg.Value, out _, out var node))
{
isEmpty = true;
return;
}

// append the named part if its specified
if (arg.Named is not null)
writer.Prepend(node, Value.Of(writer => writer.Append(arg.Named, " := ")));
}
)
);

if(isEmpty)
continue;

// append the named part if its specified
if (arg.Named is not null)
writer.Prepend(node, Value.Of(writer => writer.Append(arg.Named, " := ")));

if (i != args.Length)
writer.Append(", ");
}
Expand All @@ -147,8 +165,8 @@ public static QueryWriter Function(this QueryWriter writer, string name, params
public static QueryWriter SingleQuoted(this QueryWriter writer, Value value)
=> writer.Append('\'', value, '\'');

public static QueryWriter QueryArgument(this QueryWriter writer, Value type, string name)
=> writer.Marker(MarkerType.Variable, name, '<', type, ">$", name);
public static QueryWriter QueryArgument(this QueryWriter writer, Value type, string name, Deferrable<string>? debug = null)
=> writer.Marker(MarkerType.Variable, name, debug, '<', type, ">$", name);

public static Value[] Span(this QueryWriter writer, WriterProxy proxy)
{
Expand Down
4 changes: 3 additions & 1 deletion src/EdgeDB.Net.QueryBuilder/Lexical/Marker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ internal sealed class Marker
public MarkerType Type { get; }
public int Position { get; private set; }
public int Size { get; }
public Deferrable<string>? DebugText { get; }

public LooseLinkedList<Value>.Node Start { get; set; }

Expand Down Expand Up @@ -51,13 +52,14 @@ public IOrderedEnumerable<Marker> Parents

private readonly QueryWriter _writer;

internal Marker(MarkerType type, QueryWriter writer, int size, int position, LooseLinkedList<Value>.Node start)
internal Marker(MarkerType type, QueryWriter writer, int size, int position, LooseLinkedList<Value>.Node start, Deferrable<string>? debugText)
{
Type = type;
_writer = writer;
Size = size;
Position = position;
Start = start;
DebugText = debugText;
}

internal void Update(int delta)
Expand Down
1 change: 1 addition & 0 deletions src/EdgeDB.Net.QueryBuilder/Lexical/MarkerType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ public enum MarkerType
{
Global,
Function,
FunctionArg,
Shape,
Variable,
Verbose
Expand Down
Loading

0 comments on commit e035d58

Please sign in to comment.