1 module profiled;
2 
3 import core.sync.mutex;
4 import std;
5 
6 private:
7 
8 public __gshared Profiler theProfiler;
9 
10 abstract class Event
11 {
12     public abstract string toJson();
13 }
14 
15 // TODO
16 string tid2string(Tid id)
17 {
18     import std.conv : text;
19 
20     // dfmt off
21     return id
22         .text
23         .replace("Tid(", "")
24         .replace(")", "")[5 .. $ - 1]
25         .to!(long)(16)
26         .to!string;
27     // dfmt on
28 }
29 
30 class CompleteEvent : Event
31 {
32     string name;
33     Tid threadId;
34     MonoTime start;
35     Duration duration;
36     this(string name, Tid threadId, MonoTime start, Duration duration)
37     {
38         this.name = name;
39         this.threadId = threadId;
40         this.start = start;
41         this.duration = duration;
42     }
43 
44     override public string toJson()
45     {
46         // dfmt off
47         return `{"name":"%s","cat":"category","ph":"X","ts":%s,"dur":%s, "pid":1, "tid":%s}`
48             .format(name,
49                     convClockFreq(start.ticks,
50                                   MonoTime.ticksPerSecond, 1_000_000).to!string,
51                     duration.total!("usecs"),
52                     tid2string(threadId));
53         // dfmt on
54     }
55 }
56 
57 class CompleteEventProcess
58 {
59     Profiler profiler;
60     string name;
61     Tid tid;
62     MonoTime start;
63     this(Profiler profiler, string name, Tid tid, MonoTime start)
64     {
65         this.profiler = profiler;
66         this.name = name;
67         this.tid = tid;
68         this.start = start;
69     }
70 
71     ~this()
72     {
73         profiler.add(new CompleteEvent(name, tid, start, MonoTime.currTime - start));
74     }
75 }
76 
77 public class Profiler
78 {
79     Mutex eventsMutex;
80     Appender!(Event[]) events = appender!(Event[]);
81     this()
82     {
83         eventsMutex = new Mutex();
84     }
85 
86     public Unique!CompleteEventProcess start(string name)
87     {
88         Unique!CompleteEventProcess result = new CompleteEventProcess(this,
89                 name, thisTid, MonoTime.currTime);
90         return result;
91     }
92 
93     public void add(Event e)
94     {
95         eventsMutex.lock;
96         scope (exit)
97             eventsMutex.unlock;
98         events ~= e;
99     }
100 
101     public void dumpJson(string filename)
102     {
103         auto f = File(filename, "w");
104         f.writeln("[");
105         bool first = true;
106         eventsMutex.lock;
107         scope(exit)
108             eventsMutex.unlock;
109         foreach (e; events[])
110         {
111             if (first)
112             {
113                 first = false;
114             }
115             else
116             {
117                 f.writeln(",");
118             }
119             f.write(e.toJson());
120         }
121     }
122 }
123 
124 public class NoopProfiler : Profiler
125 {
126     override public void add(Event e)
127     {
128     }
129 
130     override public void dumpJson(string filename)
131     {
132     }
133 }