David's final changes: more profiler features, fixes.
[ipdf/code.git] / tools / stream_plot.py
1 #!/usr/bin/python -u
2
3 # Script to plot data in real(ish) time
4 # Naive approach is to just read from stdin and plot each point as it arrives
5 # This isn't so great if you have a fast data rate, the plot window flashes and gets out of sync
6 # Improvement is to use a thread to read from stdin, and a thread (main thread) that periodically plots the data (set the time interval to be sufficiently slow)
7
8 import os
9 import sys
10 import select
11 import threading
12 import time
13 import Gnuplot, Gnuplot.funcutils
14
15 plt = Gnuplot.Gnuplot(persist=1)
16 data = []
17 semaphore = threading.Semaphore()
18 running = True
19
20 def ProcessData(points):
21         #TODO: Alter to change data as it is read
22         global data
23         if len(data) > 0:
24                 # Store finite differences
25                 points += [points[i]-data[-1][i] for i in xrange(len(points))]
26         else:
27                 points += [0 for _ in xrange(len(points))]
28         return points
29
30 def PlotData():
31         #TODO: Alter to change plotting of data
32         global data
33         data = data[-100:]
34
35         plt.plot(Gnuplot.Data(data, with_="lp",using="2:($8/$9)", title="[Real] clock_gettime()"))
36         plt.replot(Gnuplot.Data(data, with_="lp",using="2:($8/$10)", title="[CPU] SDL_GetPerformanceCounter()"))
37         plt.replot(Gnuplot.Data(data, with_="lp",using="2:($8/$11)", title="[GPU] OpenGL Query (GL_TIME_ELAPSED)"))
38
39 # Produces data points by reading from stdin
40 def Producer():
41         global data
42         global running
43         while running:
44                 line = sys.stdin.readline()
45                 line = line.strip(" \t\r\n")
46                 if line == "":
47                         continue
48                 semaphore.acquire()
49                 try:
50                         data.append(ProcessData(map(float, line.split())))
51                 except:
52                         pass
53                 semaphore.release()
54
55 # "Consumes" data points by plotting them. Not really a consumer because it doesn't actually clear any but whatever
56 def Consumer():
57         global data
58         global running
59         data_size = len(data)
60         while running:
61                 prev_size = data_size
62                 data_size = len(data)
63                 if data_size != prev_size and data_size >= 2:
64                         semaphore.acquire()
65                         PlotData()
66                         data_size = len(data)
67                         semaphore.release()
68                         
69                 time.sleep(1)
70         
71 # Setup plot and start threads
72 def main(argv):
73         global running
74         plt.title("Performance Graph")
75         plt.xlabel("Real Time (s)")
76         plt.ylabel("Average FPS (since last data point)")
77         producer = threading.Thread(target=Producer)
78         producer.start()
79         try:
80                 Consumer() # Can run plot in main thread, easier that way
81         except KeyboardInterrupt:
82                 sys.stderr.write("Press enter to exit.\n")
83                 pass
84         running = False
85         producer.join()
86
87 if __name__ == "__main__":
88         main(sys.argv)
89         

UCC git Repository :: git.ucc.asn.au