This commit is contained in:
benbierens 2024-12-20 11:32:14 +01:00
parent 596011c962
commit 89193fdfde
No known key found for this signature in database
GPG Key ID: 877D2C2E09A22F3A
3 changed files with 301 additions and 172 deletions

195
SeeTimeline/LogToEvents.cs Normal file
View File

@ -0,0 +1,195 @@
using CodexPlugin;
using System.IO;
using System.Windows.Media;
namespace SeeTimeline
{
public class CodexEvent
{
public string Name { get; }
public Color Color { get; }
public DateTime Dt { get; private set; }
public CodexEvent(string name, Color color, DateTime dt)
{
Name = name;
Color = color;
Dt = dt;
}
public void Move(TimeSpan timeSpan)
{
Dt = Dt + timeSpan;
}
public void Scale(DateTime from, double factor)
{
var span = Dt - from;
Dt = from + (span * factor);
}
public override string ToString()
{
return Name;
}
}
public class EventSet
{
private readonly Dictionary<string, List<CodexEvent>> events = new Dictionary<string, List<CodexEvent>>();
private readonly LogLineAdder adder = new LogLineAdder();
public void Add(string address, CodexEvent e)
{
if (address != "-" && (!address.Contains("treeCid:") || !address.Contains("index:"))) return;
if (!events.ContainsKey(address)) events.Add(address, new List<CodexEvent>());
events[address].Add(e);
if (e.Dt > Latest) Latest = e.Dt;
if (e.Dt < Earliest) Earliest = e.Dt;
}
public DateTime Earliest { get; private set; } = DateTime.MaxValue;
public DateTime Latest { get; private set; } = DateTime.MinValue;
public void Iterate(int max, Action<string, CodexEvent[]> action)
{
var i = 0;
foreach (var pair in events)
{
action(pair.Key, pair.Value.ToArray());
i++;
if (i >= max) return;
}
}
public void AddLine(string line)
{
var cline = CodexLogLine.Parse(line);
if (cline == null) return;
adder.Add(cline, this);
}
public void AddFile(string path)
{
var lines = File.ReadAllLines(path);
foreach (var line in lines) AddLine(line);
}
public void Scale(DateTime from, double factor)
{
foreach (var pair in events)
{
foreach (var e in pair.Value) e.Scale(from, factor);
}
}
public void Move(TimeSpan timeSpan)
{
foreach (var pair in events)
{
foreach (var e in pair.Value) e.Move(timeSpan);
}
}
}
public class LogLineAdder
{
public void Add(CodexLogLine line, EventSet set)
{
var context = new SetLineContext(line, set);
context.Parse();
}
public class SetLineContext
{
private readonly CodexLogLine line;
private readonly EventSet set;
public SetLineContext(CodexLogLine line, EventSet set)
{
this.line = line;
this.set = set;
}
public void Parse()
{
//AddJobs(result, "Created", Colors.Red, req.Created);
// trace "BlockRequest created", address
if (line.Message == "BlockRequest created") AddEvent(line.Attributes["address"], "ReqCreated", Colors.Red);
//AddJobs(result, "TaskScheduled", Colors.Purple, req.TaskScheduled);
// trace "Task scheduled", peerId = task.id
else if (line.Message == "Task scheduled") AddEvent("-", "TaskScheduled", Colors.White);
//trace "Sending wantHave request", toAsk, peer = p.id
//AddJobs(result, "WantHaveSent", Colors.Orange, req.WantHaveSent);
else if (line.Message == "Sending wantHave request") AddMultiple(line.Attributes["toAsk"], "SentWantHave", Colors.Orange);
//trace "Sending wantBlock request to", addresses, peer = blockPeer.id
//AddJobs(result, "WantBlkSent", Colors.Green, req.WantBlkSent);
else if (line.Message == "Sending wantBlock request to") AddMultiple(line.Attributes["addresses"], "SentWantBlk", Colors.Green);
//trace "Handling blockPresences", addrs = blocks.mapIt(it.address)
//AddJobs(result, "PresenceRecv", Colors.Yellow, req.PresenceRecv);
else if (line.Message == "Handling blockPresences") AddMultiple(line.Attributes["addrs"], "PresenceRecv", Colors.Yellow);
//trace "Sending block request cancellations to peers", addrs, peers = b.peers.mapIt($it.id)
//AddJobs(result, "CancelSent", Colors.Purple, req.CancelSent);
else if (line.Message == "Sending block request cancellations to peers") AddMultiple(line.Attributes["addrs"], "CancelSent", Colors.Purple);
//trace "Resolving blocks", addrs = blocksDelivery.mapIt(it.address)
//AddJobs(result, "Resolve", Colors.Pink, req.Resolve);
else if (line.Message == "Resolving blocks") AddMultiple(line.Attributes["addrs"], "Resolve", Colors.Pink);
//trace "Received blocks from peer", peer, blocks = (blocksDelivery.mapIt(it.address))
//AddJobs(result, "BlkRecv", Colors.Blue, req.BlkRecv);
else if (line.Message == "Received blocks from peer") AddMultiple(line.Attributes["blocks"], "BlkRecv", Colors.Blue);
//logScope:
// peer = peerCtx.id
// address = e.address
// wantType = $e.wantType
// isCancel = $e.cancel
//trace "Received wantHave".
//AddJobs(result, "WantHaveRecv", Colors.Red, req.WantHaveRecv);
else if (line.Message == "Received wantHave") AddEvent(line.Attributes["address"], "WantHaveRecv", Colors.Red);
//trace "Received wantBlock"
//AddJobs(result, "WantBlkRecv", Colors.Yellow, req.WantBlkRecv);
else if (line.Message == "Received wantBlock") AddEvent(line.Attributes["address"], "WantBlkRecv", Colors.Yellow);
//trace "Sending presence to remote", addrs = presence.mapIt(it.address)
//AddJobs(result, "PresenceSent", Colors.Orange, req.PresenceSent);
else if (line.Message == "Sending presence") AddMultiple(line.Attributes["addrs"], "PresenceSent", Colors.Orange);
//trace "Begin sending blocks", addrs = wantAddresses
//AddJobs(result, "BlkSendStart", Colors.Green, req.BlkSendStart);
else if (line.Message == "Begin sending blocks") AddMultiple(line.Attributes["addrs"], "BlkSendStart", Colors.Green);
//trace "Finished sending blocks", addrs = wantAddresses
//AddJobs(result, "BlkSendEnd", Colors.Blue, req.BlkSendEnd);
else if (line.Message == "Finished sending blocks") AddMultiple(line.Attributes["addrs"], "BlkSendEnd", Colors.Blue);
}
private void AddMultiple(string addresses, string name, Color color)
{
var addressToken = addresses
.Replace("@[", "")
.Replace("]", "");
//foreach (var adddress in addressTokens)
//{
// AddEvent(adddress, name, color);
//}
AddEvent(addressToken, name, color);
}
private void AddEvent(string address, string name, Color color)
{
set.Add(address, new CodexEvent(name, color, line.TimestampUtc));
}
}
}
}

View File

@ -1,23 +1,10 @@
using CodexPlugin;
using Microsoft.Win32;
using System.IO;
using System.Text;
using System.IO;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using TimelinerNet;
namespace SeeTimeline
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
@ -33,167 +20,104 @@ namespace SeeTimeline
Timeliner2.RightEdge = Timeliner1.RightEdge;
}
private TimelinerData CreateTimelineData(string logfile, DateTime now)
{
var lines = File.ReadAllLines(logfile);
var handler = new LogLineHandler(now);
foreach (var line in lines)
{
var cline = CodexLogLine.Parse(line);
if (cline != null)
{
handler.Handle(cline);
if (handler.Size > 20) break;
}
}
return handler.GetTimeline();
}
public class LogLineHandler
{
public class BlockReq
{
public string Address { get; set; } = string.Empty;
public DateTime Created { get; set; }
public DateTime[] WantHaveSent { get; set; } = Array.Empty<DateTime>();
public DateTime[] PresenceRecv{ get; set; } = Array.Empty<DateTime>();
public DateTime[] WantBlkSent { get; set; } = Array.Empty<DateTime>();
public DateTime[] BlkRecv { get; set; } = Array.Empty<DateTime>();
public DateTime[] CancelSent { get; set; } = Array.Empty<DateTime>();
public DateTime[] Resolve { get; set; } = Array.Empty<DateTime>();
}
private readonly List<BlockReq> requests = new List<BlockReq>();
private readonly DateTime now;
private long? zero;
public int Size => requests.Count;
public LogLineHandler(DateTime now)
{
this.now = now;
}
public void Handle(CodexLogLine line)
{
if (line.Message != "times for") return;
var addr = line.Attributes["addrs"];
if (!addr.Contains("index")) return;
// addrs="treeCid: zDz*qNvVWp, index: 0"
// reqCreatedTime=4784825696831
// wantHaveSentTimes=@[4784825884225]
// presenceRecvTimes=@[4784826770921]
// wantBlkSentTimes=@[4784826954293]
// blkRecvTimes=@[4784829724756]
// cancelSentTimes=@[4784830399255]
// resolveTimes=@[4784830322141]
var req = new BlockReq
{
Address = line.Attributes["addrs"],
Created = ToUtc(line.Attributes["reqCreatedTime"]),
WantHaveSent = ToUtcs(line.Attributes["wantHaveSentTimes"]),
PresenceRecv = ToUtcs(line.Attributes["presenceRecvTimes"]),
WantBlkSent = ToUtcs(line.Attributes["wantBlkSentTimes"]),
BlkRecv = ToUtcs(line.Attributes["blkRecvTimes"]),
CancelSent = ToUtcs(line.Attributes["cancelSentTimes"]),
Resolve = ToUtcs(line.Attributes["resolveTimes"])
};
requests.Add(req);
}
private DateTime[] ToUtcs(string str)
{
var tokens = str.Split(",");
return tokens
.Select(t => t
.Replace(" ", "")
.Replace("@[", "")
.Replace("]", "")
).Select(t => ToUtc(t)).ToArray();
}
private DateTime ToUtc(string str)
{
// is nanoseconds from arbitrary time point.
var monotime = Convert.ToInt64(str);
if (!zero.HasValue) zero = monotime;
double deltaNanoseconds = (monotime - zero.Value);
var delta = deltaNanoseconds / (1000 * 1000);
return now + TimeSpan.FromSeconds(delta * 5.0);
}
public TimelinerData GetTimeline()
{
return new TimelinerData
{
Items = requests.Select(ToTimelineItem).ToList()
};
}
private TimelinerItem ToTimelineItem(BlockReq req)
{
return new TimelinerItem
{
Name = req.Address,
Jobs = CreateTimelineJobs(req)
};
}
private List<TimelinerJob> CreateTimelineJobs(BlockReq req)
{
var result = new List<TimelinerJob>();
AddJobs(result, "Created", Colors.Red, req.Created);
AddJobs(result, "WantHaveSent", Colors.Orange, req.WantHaveSent);
AddJobs(result, "PresenceRecv", Colors.Yellow, req.PresenceRecv);
AddJobs(result, "WantBlkSent", Colors.Green, req.WantBlkSent);
AddJobs(result, "BlkRecv", Colors.Blue, req.BlkRecv);
AddJobs(result, "CancelSent", Colors.Purple, req.CancelSent);
AddJobs(result, "Resolve", Colors.Pink, req.Resolve);
return result;
}
private void AddJobs(List<TimelinerJob> result, string name, Color color, params DateTime[] moments)
{
var i = 0;
foreach (var dt in moments)
{
result.Add(new TimelinerJob
{
Name = name + i.ToString(),
Begin = dt,
End = dt,
Color = new SolidColorBrush(color),
});
i++;
}
}
}
private void Button_Click(object sender, RoutedEventArgs e)
{
var now = DateTime.Now;
var dlg = new OpenFileDialog();
if (dlg.ShowDialog() != true) return;
var file1 = dlg.FileName;
Line1Name.Text = file1;
if (dlg.ShowDialog() != true) return;
var file2 = dlg.FileName;
Line2Name.Text = file2;
Post-holiday todo:
// TODO: way to line up upload and download events for same blockaddress
// currently: group by address => mixed together = not very handy.
// also: check resolution for log lines is correctly preserved, some events appear at exact same moment.
var data1 = CreateTimelineData(file1, now);
var data2 = CreateTimelineData(file2, now);
//var dlg = new OpenFileDialog();
var path = "d:\\Projects\\cs-codex-dist-tests\\Tests\\CodexReleaseTests\\bin\\Debug\\net8.0\\CodexTestLogs\\2024-12\\20\\09-57-01Z_TwoClientTests\\";
var file1 = Path.Combine(path, "TwoClientTest[thatbenbierens_nim-codex_blkex-cancelpresence-14]_FAST_Downloader1.log");
var file2 = Path.Combine(path, "TwoClientTest[thatbenbierens_nim-codex_blkex-cancelpresence-14]_FAST_Uploader0.log");
var file3 = Path.Combine(path, "TwoClientTest[thatbenbierens_nim-codex_blkex-cancelpresence-15]_000000_Uploader0.log");
var file4 = Path.Combine(path, "TwoClientTest[thatbenbierens_nim-codex_blkex-cancelpresence-15]_000001_Downloader1.log");
Timeliner1.Data = data1;
Timeliner2.Data = data2;
//MessageBox.Show("Select fast-run upload and download logs.");
//if (dlg.ShowDialog() != true) return;
//var file1 = dlg.FileName;
//if (dlg.ShowDialog() != true) return;
//var file2 = dlg.FileName;
Line1Name.Text = file1 + " / " + file2;
//MessageBox.Show("Select slow-run upload and download logs.");
//if (dlg.ShowDialog() != true) return;
//var file3 = dlg.FileName;
//if (dlg.ShowDialog() != true) return;
//var file4 = dlg.FileName;
Line2Name.Text = file3 + " / " + file4;
var set1 = new EventSet();
set1.AddFile(file1);
set1.AddFile(file2);
var set2 = new EventSet();
set2.AddFile(file3);
set2.AddFile(file4);
set2.Move(-(set2.Earliest - set1.Earliest));
var now = set1.Earliest;
set1.Scale(from: now, factor: 5000.0);
set2.Scale(from: now, factor: 5000.0);
DisplaySet(set1, Timeliner1, max: 5);
DisplaySet(set2, Timeliner2, max: 5);
var end = set2.Latest;
Timeliner1.Now = now;
Timeliner2.Now = now;
Timeliner1.LeftEdge = now;
Timeliner1.RightEdge = end;
Timeliner2.LeftEdge = now;
Timeliner2.RightEdge = end;
}
private void DisplaySet(EventSet set, Timeliner timeliner, int max)
{
timeliner.Data = new TimelinerData()
{
Items = CreateItems(set, max)
};
}
private List<TimelinerItem> CreateItems(EventSet set, int max)
{
var result = new List<TimelinerItem>();
set.Iterate(max, (addr, events) =>
{
result.Add(CreateItem(addr, events));
});
return result;
}
private TimelinerItem CreateItem(string addr, CodexEvent[] events)
{
return new TimelinerItem
{
Name = addr,
Jobs = CreateJobs(events)
};
}
private List<TimelinerJob> CreateJobs(CodexEvent[] events)
{
return events.Select(CreateJob).ToList();
}
private TimelinerJob CreateJob(CodexEvent e)
{
return new TimelinerJob
{
Name = e.Name,
Color = new SolidColorBrush(e.Color),
Begin = e.Dt,
End = e.Dt
};
}
}
}

View File

@ -30,7 +30,17 @@ namespace CodexReleaseTests.DataTests
"thatbenbierens/nim-codex:blkex-cancelpresence-9", // crashes S? eventtimelogging + no cancel-presence-msg (should be slow)
"thatbenbierens/nim-codex:blkex-cancelpresence-10", // F eventtimelogging (should be fast)
"thatbenbierens/nim-codex:blkex-cancelpresence-11" // S eventtimelogging + no cancel-presence-msg (should be slow)
"thatbenbierens/nim-codex:blkex-cancelpresence-11", // S eventtimelogging + no cancel-presence-msg (should be slow)
"thatbenbierens/nim-codex:blkex-cancelpresence-12", // F upload and download event logging (should be fast)
"thatbenbierens/nim-codex:blkex-cancelpresence-13", // S same but with no cancel-presence-msg (should be slow)
"thatbenbierens/nim-codex:peerselecta-1", // F PR update (yes cancel-presence-msg)
"thatbenbierens/nim-codex:peerselecta-2", // S PR update (no cancel-presence-msg)
"thatbenbierens/nim-codex:blkex-cancelpresence-14", // F new logging
"thatbenbierens/nim-codex:blkex-cancelpresence-15" // S new logging
)] string img
)
{