📄 gpsprof
字号:
#!/usr/bin/env python## Collect and plot latency-profiling data from a running gpsd.# Requires gnuplot.#import sys, os, time, getopt, tempfile, time, socket, math, copyimport gpsclass Baton: "Ship progress indication to stderr." def __init__(self, prompt, endmsg=None): self.stream = sys.stderr self.stream.write(prompt + "...") if os.isatty(self.stream.fileno()): self.stream.write(" \010") self.stream.flush() self.count = 0 self.endmsg = endmsg self.time = time.time() return def twirl(self, ch=None): if self.stream is None: return if ch: self.stream.write(ch) elif os.isatty(self.stream.fileno()): self.stream.write("-/|\\"[self.count % 4]) self.stream.write("\010") self.count = self.count + 1 self.stream.flush() return def end(self, msg=None): if msg == None: msg = self.endmsg if self.stream: self.stream.write("...(%2.2f sec) %s.\n" % (time.time() - self.time, msg)) returnclass spaceplot: "Total times without instrumentation." name = "space" def __init__(self): self.fixes = [] def d(self, a, b): return math.sqrt((a[0] - b[0])**2 + (a[1] - b[1])**2) def gather(self, session): # Include altitude, not used here, for 3D plot experiments. # Watch out for the NaN value from gps.py. self.fixes.append((session.fix.latitude, session.fix.longitude, session.fix.altitude)) return True def header(self, session): res = "# Position uncertainty, %s, %s, %ds cycle\n" % \ (title, session.gps_id, session.cycle) return res def data(self, session): res = "" for i in range(len(self.recentered)): (lat, lon) = self.recentered[i][:2] (raw1, raw2, alt) = self.fixes[i] res += "%f\t%f\t%f\t%f\t%f\n" % (lat, lon, raw1, raw2, alt) return res def plot(self, title, session): if len(self.fixes) == 0: sys.stderr.write("No fixes collected, can't estimate accuracy.") sys.exit(1) else: self.centroid = (sum(map(lambda x:x[0], self.fixes))/len(self.fixes), sum(map(lambda x:x[1], self.fixes))/len(self.fixes)) # Sort fixes by distance from centroid self.fixes.sort(lambda x, y: cmp(self.d(self.centroid, x), self.d(self.centroid, y))) # Convert fixes to offsets from centroid in meters self.recentered = map(lambda fix: gps.MeterOffset(self.centroid, fix[:2]), self.fixes) # Compute CEP(50%) cep_meters = gps.EarthDistance(self.centroid[:2], self.fixes[len(self.fixes)/2][:2]) alt_sum = 0 alt_num = 0 lon_max = -9999 for i in range(len(self.recentered)): (lat, lon) = self.recentered[i][:2] (raw1, raw2, alt) = self.fixes[i] if not gps.isnan(alt): alt_sum += alt alt_num += 1 if lon > lon_max : lon_max = lon if alt_num == 0: alt_avg = gps.NaN else: alt_avg = alt_sum / alt_num if self.centroid[0] < 0: latstring = "%fS" % -self.centroid[0] elif self.centroid[0] == 0: latstring = "0" else: latstring = "%fN" % self.centroid[0] if self.centroid[1] < 0: lonstring = "%fW" % -self.centroid[1] elif self.centroid[1] == 0: lonstring = "0" else: lonstring = "%fE" % self.centroid[1] fmt = "set autoscale\n" fmt += 'set key below\n' fmt += 'set key title "%s"\n' % time.asctime() fmt += 'set size ratio -1\n' fmt += 'set style line 2 pt 1\n' fmt += 'set style line 3 pt 2\n' fmt += 'set xlabel "Meters east from %s"\n' % lonstring fmt += 'set ylabel "Meters north from %s"\n' % latstring fmt += 'set border 15\n' if not gps.isnan(alt_avg): fmt += 'set y2label "Meters Altitude from %f"\n' % alt_avg fmt += 'set ytics nomirror\n' fmt += 'set y2tics\n' fmt += 'cep=%f\n' % self.d((0,0), self.recentered[len(self.fixes)/2]) fmt += 'set parametric\n' fmt += 'set trange [0:2*pi]\n' fmt += 'cx(t, r) = sin(t)*r\n' fmt += 'cy(t, r) = cos(t)*r\n' fmt += 'chlen = cep/20\n' fmt += "set arrow from -chlen,0 to chlen,0 nohead\n" fmt += "set arrow from 0,-chlen to 0,chlen nohead\n" fmt += 'plot cx(t, cep),cy(t, cep) title "CEP (50%%) = %f meters", ' % (cep_meters) fmt += ' "-" using 1:2 with points ls 3 title "%d GPS fixes" ' % (len(self.fixes)) if not gps.isnan(alt_avg): fmt += ', "-" using ( %f ):($5 < 100000 ? $5 - %f : 1/0) axes x1y2 with points ls 2 title " %d Altitude fixes, Average = %f" \n' % (lon_max +1, alt_avg, alt_num, alt_avg) else: fmt += "\n" fmt += self.header(session) fmt += self.data(session) if not gps.isnan(alt_avg): fmt += "e\n" + self.data(session) return fmtclass uninstrumented: "Total times without instrumentation." name = "uninstrumented" def __init__(self): self.stats = [] def gather(self, session): if session.fix.time: seconds = time.time() - session.fix.time self.stats.append(seconds) return True else: return False def header(self, session): return "# Uninstrumented total latency, %s, %s, %dN%d, cycle %ds\n" % \ (title, session.gps_id, session.baudrate, session.stopbits, session.cycle) def data(self, session): res = "" for seconds in self.stats: res += "%2.6lf\n" % seconds return res def plot(self, title, session): fmt = '''set autoscaleset key belowset key title "Uninstrumented total latency, %s, %s, %dN%d, cycle %ds"plot "-" using 0:1 title "Total time" with impulses''' res = fmt % (title, session.gps_id, session.baudrate, session.stopbits, session.cycle) res += self.header(session) return res + self.data(session)class rawplot: "All measurement, no deductions." name = "raw" def __init__(self): self.stats = [] def gather(self, session): self.stats.append(copy.copy(session.timings)) return True def header(self, session): res = "# Raw latency data, %s, %s, %dN%d, cycle %ds\n" % \ (title, session.gps_id, session.baudrate, session.stopbits, session.cycle) res += "#" for hn in ("tag", "T1", "E1", "D1", "W", "E2", "T2", "D2"): res += "%8s\t" % hn res += "\n#" for i in range(0, 7): res += "--------\t" return res + "--------\n" def data(self, session): res = "" for timings in self.stats: if timings.sentence_time: e1 = timings.d_xmit_time else: e1 = 0 res += "%s\t%2d\t%2.6f\t%2.6f\t%2.6f\t%2.6f\t%2.6f\t%2.6f\t%2.6f\n" \ % (timings.sentence_tag, timings.sentence_length, e1, timings.d_recv_time, timings.d_decode_time, timings.poll_time, timings.emit_time, timings.c_recv_time, timings.c_decode_time) return res def plot(self, file, session): fmt = '''set autoscaleset key belowset key title "Raw latency data, %s, %s, %dN%d, cycle %ds"plot \ "-" using 0:9 title "D2 = Client decode time" with impulses, \ "-" using 0:8 title "T2 = TCP/IP latency" with impulses, \ "-" using 0:7 title "E2 = Daemon encode time" with impulses, \ "-" using 0:6 title "W = Poll wait time" with impulses, \ "-" using 0:5 title "D1 = Daemon decode time" with impulses, \ "-" using 0:4 title "T1 = RS232 time" with impulses, \ "-" using 0:3 title "E1 = GPS latency" with impulses''' res = fmt % (title, session.gps_id, session.baudrate, session.stopbits, session.cycle) res += self.header(session) for dummy in range(0, 7): res += self.data(session) + "e\n" return resclass splitplot: "Discard base time, use color to indicate different tags." name = "split" sentences = []
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -