| 
						
						
						
					 | 
					 | 
					@ -1,5 +1,4 @@ | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					#!/usr/bin/env python3 | 
					 | 
					 | 
					 | 
					#!/usr/bin/env python3 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					import numpy as np | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					import os | 
					 | 
					 | 
					 | 
					import os | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					import unittest | 
					 | 
					 | 
					 | 
					import unittest | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					import requests | 
					 | 
					 | 
					 | 
					import requests | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					 | 
					@ -10,7 +9,6 @@ import cereal.messaging as messaging | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					from typing import Any | 
					 | 
					 | 
					 | 
					from typing import Any | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					from cereal.visionipc import VisionIpcClient, VisionStreamType | 
					 | 
					 | 
					 | 
					from cereal.visionipc import VisionIpcClient, VisionStreamType | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					from openpilot.selfdrive.manager.process_config import managed_processes | 
					 | 
					 | 
					 | 
					from openpilot.selfdrive.manager.process_config import managed_processes | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					from openpilot.system.hardware import TICI | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					LLK_DECIMATION = 10 | 
					 | 
					 | 
					 | 
					LLK_DECIMATION = 10 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					CACHE_PATH = "/data/mbgl-cache-navd.db" | 
					 | 
					 | 
					 | 
					CACHE_PATH = "/data/mbgl-cache-navd.db" | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					 | 
					@ -18,11 +16,6 @@ CACHE_PATH = "/data/mbgl-cache-navd.db" | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					LOCATION1 = (32.7174, -117.16277) | 
					 | 
					 | 
					 | 
					LOCATION1 = (32.7174, -117.16277) | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					LOCATION2 = (32.7558, -117.2037) | 
					 | 
					 | 
					 | 
					LOCATION2 = (32.7558, -117.2037) | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					DEFAULT_ITERATIONS = 30 * LLK_DECIMATION | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					LOCATION1_REPEATED = [LOCATION1] * DEFAULT_ITERATIONS | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					LOCATION2_REPEATED = [LOCATION2] * DEFAULT_ITERATIONS | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					def gen_llk(location=LOCATION1): | 
					 | 
					 | 
					 | 
					def gen_llk(location=LOCATION1): | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  msg = messaging.new_message('liveLocationKalman') | 
					 | 
					 | 
					 | 
					  msg = messaging.new_message('liveLocationKalman') | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  msg.liveLocationKalman.positionGeodetic = {'value': [*location, 0], 'std': [0., 0., 0.], 'valid': True} | 
					 | 
					 | 
					 | 
					  msg.liveLocationKalman.positionGeodetic = {'value': [*location, 0], 'std': [0., 0., 0.], 'valid': True} | 
				
			
			
		
	
	
		
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
					 | 
					@ -117,14 +110,15 @@ class TestMapRenderer(unittest.TestCase): | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    assert self.vipc.connect(False) | 
					 | 
					 | 
					 | 
					    assert self.vipc.connect(False) | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    self.vipc.recv() | 
					 | 
					 | 
					 | 
					    self.vipc.recv() | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  def _run_test(self, expect_valid, locations=LOCATION1_REPEATED): | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					  def _run_test(self, expect_valid, location=LOCATION1): | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    starting_frame_id = None | 
					 | 
					 | 
					 | 
					    starting_frame_id = None | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    render_times = [] | 
					 | 
					 | 
					 | 
					    self.location = location | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    # run test | 
					 | 
					 | 
					 | 
					    # run test | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    prev_frame_id = -1 | 
					 | 
					 | 
					 | 
					    prev_frame_id = -1 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    for i, location in enumerate(locations): | 
					 | 
					 | 
					 | 
					    for i in range(30*LLK_DECIMATION): | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      frame_expected = (i+1) % LLK_DECIMATION == 0 | 
					 | 
					 | 
					 | 
					      frame_expected = (i+1) % LLK_DECIMATION == 0 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      if self.sm.logMonoTime['mapRenderState'] == 0: | 
					 | 
					 | 
					 | 
					      if self.sm.logMonoTime['mapRenderState'] == 0: | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					 | 
					@ -137,7 +131,7 @@ class TestMapRenderer(unittest.TestCase): | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      if starting_frame_id is None: | 
					 | 
					 | 
					 | 
					      if starting_frame_id is None: | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        starting_frame_id = prev_frame_id | 
					 | 
					 | 
					 | 
					        starting_frame_id = prev_frame_id | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      llk = gen_llk(location) | 
					 | 
					 | 
					 | 
					      llk = gen_llk(self.location) | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      self.pm.send("liveLocationKalman", llk) | 
					 | 
					 | 
					 | 
					      self.pm.send("liveLocationKalman", llk) | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      self.pm.wait_for_readers_to_update("liveLocationKalman", 10) | 
					 | 
					 | 
					 | 
					      self.pm.wait_for_readers_to_update("liveLocationKalman", 10) | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      self.sm.update(1000 if frame_expected else 0) | 
					 | 
					 | 
					 | 
					      self.sm.update(1000 if frame_expected else 0) | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					 | 
					@ -163,7 +157,6 @@ class TestMapRenderer(unittest.TestCase): | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        assert self.sm['mapRenderState'].renderTime == 0. | 
					 | 
					 | 
					 | 
					        assert self.sm['mapRenderState'].renderTime == 0. | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      else: | 
					 | 
					 | 
					 | 
					      else: | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        assert 0. < self.sm['mapRenderState'].renderTime < 0.1 | 
					 | 
					 | 
					 | 
					        assert 0. < self.sm['mapRenderState'].renderTime < 0.1 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        render_times.append(self.sm['mapRenderState'].renderTime) | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      # check vision ipc output | 
					 | 
					 | 
					 | 
					      # check vision ipc output | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      assert self.vipc.recv() is not None | 
					 | 
					 | 
					 | 
					      assert self.vipc.recv() is not None | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					 | 
					@ -171,8 +164,6 @@ class TestMapRenderer(unittest.TestCase): | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      assert self.vipc.timestamp_sof == llk.logMonoTime | 
					 | 
					 | 
					 | 
					      assert self.vipc.timestamp_sof == llk.logMonoTime | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      assert self.vipc.frame_id == self.sm['mapRenderState'].frameId | 
					 | 
					 | 
					 | 
					      assert self.vipc.frame_id == self.sm['mapRenderState'].frameId | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    return render_times | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  def test_with_internet(self): | 
					 | 
					 | 
					 | 
					  def test_with_internet(self): | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    self._setup_test() | 
					 | 
					 | 
					 | 
					    self._setup_test() | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    self._run_test(True) | 
					 | 
					 | 
					 | 
					    self._run_test(True) | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					 | 
					@ -189,42 +180,13 @@ class TestMapRenderer(unittest.TestCase): | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    self.server.disable_internet() | 
					 | 
					 | 
					 | 
					    self.server.disable_internet() | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    # change locations to force mapsd to refetch | 
					 | 
					 | 
					 | 
					    # change locations to force mapsd to refetch | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    self._run_test(False, LOCATION2_REPEATED) | 
					 | 
					 | 
					 | 
					    self._run_test(False, LOCATION2) | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    self.server.enable_internet() | 
					 | 
					 | 
					 | 
					    self.server.enable_internet() | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    self._run_test(True, LOCATION2_REPEATED) | 
					 | 
					 | 
					 | 
					    self._run_test(True, LOCATION2) | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    self._run_test(True, LOCATION2_REPEATED) | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  def test_render_time_distribution(self): | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    if not TICI: | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      raise unittest.SkipTest | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    self._setup_test() | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    # from location1 -> location2 and back | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    locations = np.array([*np.linspace(LOCATION1, LOCATION2, 500), *np.linspace(LOCATION2, LOCATION1, 500)]).tolist() | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    render_times = self._run_test(True, locations) | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    _min = np.min(render_times) | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    _max = np.max(render_times) | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    _mean = np.mean(render_times) | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    _median = np.median(render_times) | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    _stddev = np.std(render_times) | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    print(f"Stats: min: {_min}, max: {_max}, mean: {_mean}, median: {_median}, stddev: {_stddev}, count: {len(render_times)}") | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    def assert_stat(stat, nominal, tol=0.2): | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      tol = (nominal / (1+tol)), (nominal * (1+tol)) | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      self.assertTrue(tol[0] < stat < tol[1], f"{stat} not in tolerance {tol}") | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    assert_stat(_mean,   0.0035) | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    assert_stat(_median, 0.0034) | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    assert_stat(_stddev, 0.00093) | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    self.assertLess(_max, 0.2) | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    self.assertGreater(_min, 0.0010) | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					    self.location = LOCATION1 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					    self._run_test(True, LOCATION2) | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					if __name__ == "__main__": | 
					 | 
					 | 
					 | 
					if __name__ == "__main__": | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  unittest.main() | 
					 | 
					 | 
					 | 
					  unittest.main() | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
					 | 
					 | 
					
  |