def setUp(self): """Set up data and create a temporary directory to save data and stats.""" self.tempdir = tempfile.mkdtemp() self.data = StatsManager() self.data.AddValue('A', 99999.5) self.data.AddValue('A', 100000.5) self.data.AddValue('A', 'ERROR') self.data.AddValue('B', 1.5) self.data.AddValue('B', 2.5) self.data.AddValue('B', 3.5) self.data.CalculateStats()
def launch_aux_processes(): # Close any open server connections before forking and... app.data_engine._reset_pool() app.cache_engine._reset_pool() # ...spawn the remaining services StatsManager.run_server( app.config['STATS_SERVER'], app.config['STATS_SERVER_PORT'], app.config['DEBUG'] ) TaskManager.run_server( app.config['TASK_SERVER'], app.config['TASK_SERVER_PORT'], app.config['DEBUG'] )
def main_setup(output_name): ''' This should be called at the beginning of main if you're running unit tests or simulations. We need to set |globals_.event_manager| for most class definitions and helper functions to make sense. ''' globals_.event_manager = EventManager(output_name) globals_.stats_manager = StatsManager(output_name)
def __init__(self, brdfile, cfgfile, serial_a=None, serial_b=None, sync_date=False, use_ms=False, use_mW=False, print_stats=False, stats_dir=None, stats_json_dir=None, print_raw_data=True, raw_data_dir=None): """Init the powerlog class and set the variables. Args: brdfile: string name of json file containing board layout. cfgfile: string name of json containing list of rails to read. serial_a: serial number of sweetberry A. serial_b: serial number of sweetberry B. sync_date: report timestamps synced with host datetime. use_ms: report timestamps in ms rather than us. use_mW: report power as milliwatts, otherwise default to microwatts. print_stats: print statistics for sweetberry readings at the end. stats_dir: directory to save sweetberry readings statistics; if None then do not save the statistics. stats_json_dir: directory to save means of sweetberry readings in json format; if None then do not save the statistics. print_raw_data: print sweetberry readings raw data in real time, default is to print. raw_data_dir: directory to save sweetberry readings raw data; if None then do not save the raw data. """ self._data = StatsManager() self._pwr = {} self._use_ms = use_ms self._use_mW = use_mW self._print_stats = print_stats self._stats_dir = stats_dir self._stats_json_dir = stats_json_dir self._print_raw_data = print_raw_data self._raw_data_dir = raw_data_dir if not serial_a and not serial_b: self._pwr['A'] = Spower('A') if serial_a: self._pwr['A'] = Spower('A', serialname=serial_a) if serial_b: self._pwr['B'] = Spower('B', serialname=serial_b) with open(process_filename(cfgfile)) as data_file: names = json.load(data_file) self._names = self.process_scenario(names) for key in self._pwr: self._pwr[key].load_board(brdfile) self._pwr[key].reset() # Allocate the rails to the appropriate boards. used_boards = [] for name in self._names: success = False for key in self._pwr.keys(): if self._pwr[key].add_ina_name(name): success = True if key not in used_boards: used_boards.append(key) if not success: raise Exception("Failed to add %s (maybe missing " "sweetberry, or bad board file?)" % name) # Evict unused boards. for key in self._pwr.keys(): if key not in used_boards: self._pwr.pop(key) for key in self._pwr.keys(): if sync_date: self._pwr[key].set_time(time.time() * 1000000) else: self._pwr[key].set_time(0)
class powerlog(object): """Power class to log aggregated power. Usage: obj = powerlog() Instance Variables: _data: a StatsManager object that records sweetberry readings and calculates statistics. _pwr[]: Spower objects for individual sweetberries. """ def __init__(self, brdfile, cfgfile, serial_a=None, serial_b=None, sync_date=False, use_ms=False, use_mW=False, print_stats=False, stats_dir=None, stats_json_dir=None, print_raw_data=True, raw_data_dir=None): """Init the powerlog class and set the variables. Args: brdfile: string name of json file containing board layout. cfgfile: string name of json containing list of rails to read. serial_a: serial number of sweetberry A. serial_b: serial number of sweetberry B. sync_date: report timestamps synced with host datetime. use_ms: report timestamps in ms rather than us. use_mW: report power as milliwatts, otherwise default to microwatts. print_stats: print statistics for sweetberry readings at the end. stats_dir: directory to save sweetberry readings statistics; if None then do not save the statistics. stats_json_dir: directory to save means of sweetberry readings in json format; if None then do not save the statistics. print_raw_data: print sweetberry readings raw data in real time, default is to print. raw_data_dir: directory to save sweetberry readings raw data; if None then do not save the raw data. """ self._data = StatsManager() self._pwr = {} self._use_ms = use_ms self._use_mW = use_mW self._print_stats = print_stats self._stats_dir = stats_dir self._stats_json_dir = stats_json_dir self._print_raw_data = print_raw_data self._raw_data_dir = raw_data_dir if not serial_a and not serial_b: self._pwr['A'] = Spower('A') if serial_a: self._pwr['A'] = Spower('A', serialname=serial_a) if serial_b: self._pwr['B'] = Spower('B', serialname=serial_b) with open(process_filename(cfgfile)) as data_file: names = json.load(data_file) self._names = self.process_scenario(names) for key in self._pwr: self._pwr[key].load_board(brdfile) self._pwr[key].reset() # Allocate the rails to the appropriate boards. used_boards = [] for name in self._names: success = False for key in self._pwr.keys(): if self._pwr[key].add_ina_name(name): success = True if key not in used_boards: used_boards.append(key) if not success: raise Exception("Failed to add %s (maybe missing " "sweetberry, or bad board file?)" % name) # Evict unused boards. for key in self._pwr.keys(): if key not in used_boards: self._pwr.pop(key) for key in self._pwr.keys(): if sync_date: self._pwr[key].set_time(time.time() * 1000000) else: self._pwr[key].set_time(0) def process_scenario(self, name_list): """Return list of tuples indicating name and type. Args: json originated list of names, or [name, type] Returns: list of tuples of (name, type) defaulting to type "POWER" Raises: exception, invalid INA type. """ names = [] for entry in name_list: if isinstance(entry, list): name = entry[0] if entry[1] == "POWER": type = Spower.INA_POWER elif entry[1] == "BUSV": type = Spower.INA_BUSV elif entry[1] == "CURRENT": type = Spower.INA_CURRENT elif entry[1] == "SHUNTV": type = Spower.INA_SHUNTV else: raise Exception( "Invalid INA type", "Type of %s [%s] not recognized," " try one of POWER, BUSV, CURRENT" % (entry[0], entry[1])) else: name = entry type = Spower.INA_POWER names.append((name, type)) return names def start(self, integration_us_request, seconds, sync_speed=.8): """Starts sampling. Args: integration_us_request: requested interval between sample values. seconds: time until exit, or None to run until cancel. sync_speed: A usb request is sent every [.8] * integration_us. """ # We will get back the actual integration us. # It should be the same for all devices. integration_us = None for key in self._pwr: integration_us_new = self._pwr[key].start(integration_us_request) if integration_us: if integration_us != integration_us_new: raise Exception( "FAIL", "Integration on A: %dus != integration on B %dus" % (integration_us, integration_us_new)) integration_us = integration_us_new # CSV header title = "ts:%dus" % integration_us for name_tuple in self._names: name, ina_type = name_tuple if ina_type == Spower.INA_POWER: unit = "mW" if self._use_mW else "uW" elif ina_type == Spower.INA_BUSV: unit = "mV" elif ina_type == Spower.INA_CURRENT: unit = "uA" elif ina_type == Spower.INA_SHUNTV: unit = "uV" title += ", %s %s" % (name, unit) name_type = name + Spower.INA_SUFFIX[ina_type] self._data.SetUnit(name_type, unit) title += ", status" if self._print_raw_data: logoutput(title) forever = False if not seconds: forever = True end_time = time.time() + seconds try: pending_records = [] while forever or end_time > time.time(): if (integration_us > 5000): time.sleep((integration_us / 1000000.) * sync_speed) for key in self._pwr: records = self._pwr[key].read_line() if not records: continue for record in records: pending_records.append(record) pending_records.sort(key=lambda r: r['ts']) aggregate_record = {"boards": set()} for record in pending_records: if record["berry"] not in aggregate_record["boards"]: for rkey in record.keys(): aggregate_record[rkey] = record[rkey] aggregate_record["boards"].add(record["berry"]) else: print("break %s, %s" % (record["berry"], aggregate_record["boards"])) break if aggregate_record["boards"] == set(self._pwr.keys()): csv = "%f" % aggregate_record["ts"] for name in self._names: if name in aggregate_record: multiplier = 0.001 if ( self._use_mW and name[1] == Spower.INA_POWER) else 1 value = aggregate_record[name] * multiplier csv += ", %.2f" % value name_type = name[0] + Spower.INA_SUFFIX[ name[1]] self._data.AddValue(name_type, value) else: csv += ", " csv += ", %d" % aggregate_record["status"] if self._print_raw_data: logoutput(csv) aggregate_record = {"boards": set()} for r in range(0, len(self._pwr)): pending_records.pop(0) except KeyboardInterrupt: print('\nCTRL+C caught.') finally: for key in self._pwr: self._pwr[key].stop() self._data.CalculateStats() if self._print_stats: self._data.PrintSummary() save_dir = 'sweetberry%s' % time.time() if self._stats_dir: stats_dir = os.path.join(self._stats_dir, save_dir) self._data.SaveSummary(stats_dir) if self._stats_json_dir: stats_json_dir = os.path.join(self._stats_json_dir, save_dir) self._data.SaveSummaryJSON(stats_json_dir) if self._raw_data_dir: raw_data_dir = os.path.join(self._raw_data_dir, save_dir) self._data.SaveRawData(raw_data_dir)
class TestStatsManager(unittest.TestCase): """Test to verify StatsManager methods work as expected. StatsManager should collect raw data, calculate their statistics, and save them in expected format. """ def setUp(self): """Set up data and create a temporary directory to save data and stats.""" self.tempdir = tempfile.mkdtemp() self.data = StatsManager() self.data.AddValue('A', 99999.5) self.data.AddValue('A', 100000.5) self.data.AddValue('A', 'ERROR') self.data.SetUnit('A', 'uW') self.data.SetUnit('A', 'mW') self.data.AddValue('B', 1.5) self.data.AddValue('B', 2.5) self.data.AddValue('B', 3.5) self.data.SetUnit('B', 'mV') self.data.CalculateStats() def tearDown(self): """Delete the temporary directory and its content.""" shutil.rmtree(self.tempdir) def test_GetRawData(self): raw_data = self.data.GetRawData() self.assertListEqual([99999.5, 100000.5], raw_data['A']) self.assertListEqual([1.5, 2.5, 3.5], raw_data['B']) def test_GetSummary(self): summary = self.data.GetSummary() self.assertEqual(2, summary['A']['count']) self.assertAlmostEqual(100000.5, summary['A']['max']) self.assertAlmostEqual(99999.5, summary['A']['min']) self.assertAlmostEqual(0.5, summary['A']['stddev']) self.assertAlmostEqual(100000.0, summary['A']['mean']) self.assertEqual(3, summary['B']['count']) self.assertAlmostEqual(3.5, summary['B']['max']) self.assertAlmostEqual(1.5, summary['B']['min']) self.assertAlmostEqual(0.81649658092773, summary['B']['stddev']) self.assertAlmostEqual(2.5, summary['B']['mean']) def test_SaveRawData(self): dirname = 'unittest_raw_data' self.data.SaveRawData(self.tempdir, dirname) dirname = os.path.join(self.tempdir, dirname) fileA = os.path.join(dirname, 'A_mW.txt') fileB = os.path.join(dirname, 'B_mV.txt') with open(fileA, 'r') as fA: self.assertEqual('99999.50', fA.readline().strip()) self.assertEqual('100000.50', fA.readline().strip()) with open(fileB, 'r') as fB: self.assertEqual('1.50', fB.readline().strip()) self.assertEqual('2.50', fB.readline().strip()) self.assertEqual('3.50', fB.readline().strip()) def test_SaveSummary(self): fname = 'unittest_summary.txt' self.data.SaveSummary(self.tempdir, fname) fname = os.path.join(self.tempdir, fname) with open(fname, 'r') as f: self.assertEqual( '@@ NAME COUNT MEAN STDDEV MAX MIN\n', f.readline()) self.assertEqual( '@@ A_mW 2 100000.00 0.50 100000.50 99999.50\n', f.readline()) self.assertEqual( '@@ B_mV 3 2.50 0.82 3.50 1.50\n', f.readline()) def test_SaveSummaryJSON(self): fname = 'unittest_summary.json' self.data.SaveSummaryJSON(self.tempdir, fname) fname = os.path.join(self.tempdir, fname) with open(fname, 'r') as f: summary = json.load(f) self.assertAlmostEqual(100000.0, summary['A']['mean']) self.assertEqual('milliwatt', summary['A']['unit']) self.assertAlmostEqual(2.5, summary['B']['mean']) self.assertEqual('millivolt', summary['B']['unit'])
def __init__(self, config, cred, specs, factory, notifier=None): """Create a new instance of chain runner. Create dependent components A new instance is created everytime the nfvbench config may have changed. config: the new nfvbench config to use for this run cred: openstack credentials (or None if no openstack) specs: TBD factory: notifier: """ self.config = config self.cred = cred self.specs = specs self.factory = factory self.notifier = notifier self.chain_name = self.config.service_chain # get an instance of traffic client self.traffic_client = TrafficClient(config, notifier) if self.config.no_traffic: LOG.info('Dry run: traffic generation is disabled') else: # Start the traffic generator server self.traffic_client.start_traffic_generator() # get an instance of a chain manager self.chain_manager = ChainManager(self) # at this point all resources are setup/discovered # we need to program the traffic dest MAC and VLANs gen_config = self.traffic_client.generator_config if config.vlan_tagging: # VLAN is discovered from the networks gen_config.set_vlans(0, self.chain_manager.get_chain_vlans(0)) gen_config.set_vlans(1, self.chain_manager.get_chain_vlans(1)) # the only case we do not need to set the dest MAC is in the case of # l2-loopback (because the traffic gen will default to use the peer MAC) # or EXT+ARP+VLAN (because dest MAC will be discovered by TRex ARP) # Note that in the case of EXT+ARP+VxLAN, the dest MACs need to be loaded # because ARP only operates on the dest VTEP IP not on the VM dest MAC if not config.l2_loopback and \ (config.service_chain != ChainType.EXT or config.no_arp or config.vxlan): gen_config.set_dest_macs(0, self.chain_manager.get_dest_macs(0)) gen_config.set_dest_macs(1, self.chain_manager.get_dest_macs(1)) if config.vxlan: # VXLAN is discovered from the networks vtep_vlan = gen_config.gen_config.vtep_vlan src_vteps = gen_config.gen_config.src_vteps dst_vtep = gen_config.gen_config.dst_vtep gen_config.set_vxlans(0, self.chain_manager.get_chain_vxlans(0)) gen_config.set_vxlans(1, self.chain_manager.get_chain_vxlans(1)) gen_config.set_vtep_vlan(0, vtep_vlan) gen_config.set_vtep_vlan(1, vtep_vlan) # Configuring source an remote VTEPs on TREx interfaces gen_config.set_vxlan_endpoints(0, src_vteps[0], dst_vtep) gen_config.set_vxlan_endpoints(1, src_vteps[1], dst_vtep) self.config['vxlan_gen_config'] = gen_config # get an instance of the stats manager self.stats_manager = StatsManager(self) LOG.info('ChainRunner initialized')
class ChainRunner(object): """Run selected chain, collect results and analyse them.""" def __init__(self, config, cred, specs, factory, notifier=None): """Create a new instance of chain runner. Create dependent components A new instance is created everytime the nfvbench config may have changed. config: the new nfvbench config to use for this run cred: openstack credentials (or None if no openstack) specs: TBD factory: notifier: """ self.config = config self.cred = cred self.specs = specs self.factory = factory self.notifier = notifier self.chain_name = self.config.service_chain # get an instance of traffic client self.traffic_client = TrafficClient(config, notifier) if self.config.no_traffic: LOG.info('Dry run: traffic generation is disabled') else: # Start the traffic generator server self.traffic_client.start_traffic_generator() # get an instance of a chain manager self.chain_manager = ChainManager(self) # at this point all resources are setup/discovered # we need to program the traffic dest MAC and VLANs gen_config = self.traffic_client.generator_config if config.vlan_tagging: # VLAN is discovered from the networks gen_config.set_vlans(0, self.chain_manager.get_chain_vlans(0)) gen_config.set_vlans(1, self.chain_manager.get_chain_vlans(1)) # the only case we do not need to set the dest MAC is in the case of # l2-loopback (because the traffic gen will default to use the peer MAC) # or EXT+ARP+VLAN (because dest MAC will be discovered by TRex ARP) # Note that in the case of EXT+ARP+VxLAN, the dest MACs need to be loaded # because ARP only operates on the dest VTEP IP not on the VM dest MAC if not config.l2_loopback and \ (config.service_chain != ChainType.EXT or config.no_arp or config.vxlan): gen_config.set_dest_macs(0, self.chain_manager.get_dest_macs(0)) gen_config.set_dest_macs(1, self.chain_manager.get_dest_macs(1)) if config.vxlan: # VXLAN is discovered from the networks vtep_vlan = gen_config.gen_config.vtep_vlan src_vteps = gen_config.gen_config.src_vteps dst_vtep = gen_config.gen_config.dst_vtep gen_config.set_vxlans(0, self.chain_manager.get_chain_vxlans(0)) gen_config.set_vxlans(1, self.chain_manager.get_chain_vxlans(1)) gen_config.set_vtep_vlan(0, vtep_vlan) gen_config.set_vtep_vlan(1, vtep_vlan) # Configuring source an remote VTEPs on TREx interfaces gen_config.set_vxlan_endpoints(0, src_vteps[0], dst_vtep) gen_config.set_vxlan_endpoints(1, src_vteps[1], dst_vtep) self.config['vxlan_gen_config'] = gen_config # get an instance of the stats manager self.stats_manager = StatsManager(self) LOG.info('ChainRunner initialized') def __setup_traffic(self): self.traffic_client.setup() if not self.config.no_traffic: # ARP is needed for EXT chain or VxLAN overlay unless disabled explicitly if (self.config.service_chain == ChainType.EXT or self.config.vxlan or self.config.l3_router) and not self.config.no_arp: self.traffic_client.ensure_arp_successful() self.traffic_client.ensure_end_to_end() def __get_result_per_frame_size(self, frame_size, bidirectional): traffic_result = {frame_size: {}} result = {} if not self.config.no_traffic: self.traffic_client.set_traffic(frame_size, bidirectional) if self.config.single_run: result = self.stats_manager.run_fixed_rate() else: results = self.traffic_client.get_ndr_and_pdr() for dr in ['pdr', 'ndr']: if dr in results: traffic_result[frame_size][dr] = results[dr] if 'warning' in results[dr]['stats'] and results[dr][ 'stats']['warning']: traffic_result['warning'] = results[dr]['stats'][ 'warning'] traffic_result[frame_size]['iteration_stats'] = results[ 'iteration_stats'] if self.config.single_run: result['run_config'] = self.traffic_client.get_run_config( result) required = result['run_config']['direction-total']['orig'][ 'rate_pps'] actual = result['stats']['total_tx_rate'] warning = self.traffic_client.compare_tx_rates( required, actual) if warning is not None: result['run_config']['warning'] = warning traffic_result[frame_size].update(result) return traffic_result def __get_chain_result(self): result = OrderedDict() for fs in self.config.frame_sizes: result.update( self.__get_result_per_frame_size( fs, self.config.traffic.bidirectional)) chain_result = { 'flow_count': self.config.flow_count, 'service_chain_count': self.config.service_chain_count, 'bidirectional': self.config.traffic.bidirectional, 'profile': self.config.traffic.profile, 'compute_nodes': self.stats_manager.get_compute_nodes_bios(), 'result': result } return chain_result def run(self): """Run the requested benchmark. return: the results of the benchmark as a dict """ results = {} if self.config.no_traffic: return results LOG.info('Starting %dx%s benchmark...', self.config.service_chain_count, self.chain_name) self.stats_manager.create_worker() if self.config.vxlan: # Configure vxlan tunnels self.stats_manager.worker.config_interfaces() self.__setup_traffic() results[self.chain_name] = {'result': self.__get_chain_result()} LOG.info("Service chain '%s' run completed.", self.chain_name) return results def close(self): """Close this instance of chain runner and delete resources if applicable.""" try: if not self.config.no_cleanup: LOG.info('Cleaning up...') if self.chain_manager: self.chain_manager.delete() else: LOG.info('Clean up skipped.') try: self.traffic_client.close() except Exception: LOG.exception() if self.stats_manager: self.stats_manager.close() except Exception: LOG.exception('Cleanup not finished') def get_version(self): """Retrieve the version of dependent components.""" versions = {} if self.traffic_client: versions['Traffic_Generator'] = self.traffic_client.get_version() versions.update(self.stats_manager.get_version()) return versions
APIs = {"wiki_data": WikiDataAPI, "osm_xapi": OSMXAPI} EXTRACTORS = { "wiki_data": WikiDataCitiesExtractor, "osm_xapi": OSMXAPICitiesExtractor } api, extractor = APIs[API_NAME], EXTRACTORS[API_NAME] if __name__ == "__main__": arguments = docopt(help) if arguments["extract"] is True: if API_NAME == "osm_xapi": params = dict(area=int(arguments["--area"]), types=arguments["--type"].split(","), write_hard=int(arguments["--overwrite"]) == 1) elif API_NAME == "wiki_data": params = dict(write_hard=int(arguments["--overwrite"]) == 1) else: params = {} extractor.extract_cities(**params) _format = arguments["--merge"] if _format is not None: api.merge_cities_file(_format=_format) elif arguments["merge"] is True: _format = arguments["--output-format"] print "merging cities files" api.merge_cities_file(_format=_format) elif arguments['stats'] is True: print "computing stats" print StatsManager.get_extracted_cities_stats()
from functools import wraps import settings.flask_settings as local_settings import settings.global_settings as global_settings import logging from assets.streamer import Streamer from assets.twitchapi import TwitchAPI from assets.jwtworker import JWTworker from stats_manager import StatsManager from assets.profanity_filter import ProfanityFilter application = Flask(__name__, template_folder='frontend', static_url_path="") socketio = SocketIO(application) logger = logging.getLogger('flask_app') TwitchAPI.generate_oauth() bubble = Bubble(read_data=True) stats = StatsManager() def log_setup(app, logger): log_f = logging.FileHandler(local_settings.FLASK_LOG_FILE) log_s = logging.StreamHandler() if (global_settings.DEBUG): logger.setLevel(logging.DEBUG) log_f.setLevel(logging.DEBUG) log_s.setLevel(logging.DEBUG) else: logger.setLevel(logging.INFO) # Set formatter for requests formatter = local_settings.RequestFormatter(local_settings.REQUEST_FORMAT)
def main_setup(): random.seed(0) globals_.event_manager = EventManager(None) globals_.stats_manager = StatsManager('output')
class powerlog(object): """Power class to log aggregated power. Usage: obj = powerlog() Instance Variables: _data: records sweetberries readings and calculates statistics. _pwr[]: Spower objects for individual sweetberries. """ def __init__(self, brdfile, cfgfile, serial_a=None, serial_b=None, sync_date=False, use_ms=False, use_mW=False, print_stats=False, stats_dir=None, stats_json_dir=None, print_raw_data=True, raw_data_dir=None): """Init the powerlog class and set the variables. Args: brdfile: string name of json file containing board layout. cfgfile: string name of json containing list of rails to read. serial_a: serial number of sweetberry A. serial_b: serial number of sweetberry B. sync_date: report timestamps synced with host datetime. use_ms: report timestamps in ms rather than us. use_mW: report power as milliwatts, otherwise default to microwatts. print_stats: print statistics for sweetberry readings at the end. stats_dir: directory to save sweetberry readings statistics; if None then do not save the statistics. stats_json_dir: directory to save means of sweetberry readings in json format; if None then do not save the statistics. print_raw_data: print sweetberry readings raw data in real time, default is to print. raw_data_dir: directory to save sweetberry readings raw data; if None then do not save the raw data. """ self._data = StatsManager() self._pwr = {} self._use_ms = use_ms self._use_mW = use_mW self._print_stats = print_stats self._stats_dir = stats_dir self._stats_json_dir = stats_json_dir self._print_raw_data = print_raw_data self._raw_data_dir = raw_data_dir if not serial_a and not serial_b: self._pwr['A'] = Spower('A') if serial_a: self._pwr['A'] = Spower('A', serialname=serial_a) if serial_b: self._pwr['B'] = Spower('B', serialname=serial_b) with open(cfgfile) as data_file: names = json.load(data_file) self._names = names for key in self._pwr: self._pwr[key].load_board(brdfile) self._pwr[key].reset() # Allocate the rails to the appropriate boards. used_boards = [] for name in self._names: success = False for key in self._pwr.keys(): if self._pwr[key].add_ina_name(name): success = True if key not in used_boards: used_boards.append(key) if not success: raise Exception("Failed to add %s (maybe missing " "sweetberry, or bad board file?)" % name) # Evict unused boards. for key in self._pwr.keys(): if key not in used_boards: self._pwr.pop(key) for key in self._pwr.keys(): if sync_date: self._pwr[key].set_time(time.time() * 1000000) else: self._pwr[key].set_time(0) def start(self, integration_us_request, seconds, sync_speed=.8): """Starts sampling. Args: integration_us_request: requested interval between sample values. seconds: time until exit, or None to run until cancel. sync_speed: A usb request is sent every [.8] * integration_us. """ # We will get back the actual integration us. # It should be the same for all devices. integration_us = None for key in self._pwr: integration_us_new = self._pwr[key].start(integration_us_request) if integration_us: if integration_us != integration_us_new: raise Exception( "FAIL", "Integration on A: %dus != integration on B %dus" % (integration_us, integration_us_new)) integration_us = integration_us_new # CSV header if self._print_raw_data: title = "ts:%dus" % integration_us for name in self._names: unit = "mW" if self._use_mW else "uW" title += ", %s %s" % (name, unit) title += ", status" logoutput(title) forever = False if not seconds: forever = True end_time = time.time() + seconds try: pending_records = [] while forever or end_time > time.time(): if (integration_us > 5000): time.sleep((integration_us / 1000000.) * sync_speed) for key in self._pwr: records = self._pwr[key].read_line() if not records: continue for record in records: pending_records.append(record) pending_records.sort(key=lambda r: r['ts']) aggregate_record = {"boards": set()} for record in pending_records: if record["berry"] not in aggregate_record["boards"]: for rkey in record.keys(): aggregate_record[rkey] = record[rkey] aggregate_record["boards"].add(record["berry"]) else: print("break %s, %s" % (record["berry"], aggregate_record["boards"])) break if aggregate_record["boards"] == set(self._pwr.keys()): csv = "%f" % aggregate_record["ts"] for name in self._names: if name in aggregate_record: multiplier = 0.001 if self._use_mW else 1 power = aggregate_record[name] * multiplier csv += ", %.2f" % power self._data.AddValue(name, power) else: csv += ", " csv += ", %d" % aggregate_record["status"] if self._print_raw_data: logoutput(csv) aggregate_record = {"boards": set()} for r in range(0, len(self._pwr)): pending_records.pop(0) except KeyboardInterrupt: print('\nCTRL+C caught.') finally: for key in self._pwr: self._pwr[key].stop() self._data.CalculateStats() if self._print_stats: self._data.PrintSummary() save_dir = datetime.datetime.now().strftime( 'sweetberry%Y%m%d%H%M%S.%f') if self._stats_dir: stats_dir = os.path.join(self._stats_dir, save_dir) self._data.SaveSummary(stats_dir) if self._stats_json_dir: stats_json_dir = os.path.join(self._stats_json_dir, save_dir) self._data.SaveSummaryJSON(stats_json_dir) if self._raw_data_dir: raw_data_dir = os.path.join(self._raw_data_dir, save_dir) self._data.SaveRawData(raw_data_dir)