def _shutdown_workers( workers: List[Tuple[multiprocessing.Process, multiprocessing.Queue, multiprocessing.Queue]] ) -> Tuple[int, int]: logger = logutils.get_logger() for worker, in_q, report_q in workers: in_q.put(None) total_errors = total_executions = 0 still_alive = [] for worker, _, report_q in workers: try: while True: execs, errors = report_q.get_nowait() total_executions += execs total_errors += errors except queue.Empty: pass worker.join(timeout=.1) if worker.is_alive(): still_alive.append((worker, report_q)) still_alive2 = [] if still_alive: logger.info( "{} workers still running. Waiting a little longer ...".format( len(still_alive))) for worker, report_q in still_alive: try: while True: execs, errors = report_q.get_nowait() total_executions += execs total_errors += errors except queue.Empty: pass worker.join(timeout=.1) if worker.is_alive(): still_alive2.append((worker, report_q)) if still_alive2: logger.info("{} workers still running. Terminating ...".format( len(still_alive2))) for worker, report_q in still_alive2: try: while True: execs, errors = report_q.get_nowait() total_executions += execs total_errors += errors except queue.Empty: pass worker.terminate() return total_errors, total_executions
def generate(self): if not self._start_time: self._start_time = time.time() if self._next_adjustment_index < len(self._adjustments): next_adjustment_time = self._adjustments[ self._next_adjustment_index][0] passed_time = time.time() - self._start_time if passed_time >= next_adjustment_time: update_tpl = self._adjustments[self._next_adjustment_index] self._max_seq_len = update_tpl[1] self._alloc_free_ratio = update_tpl[2] logger = logutils.get_logger() logger.info(("Updating interaction generator parameters: " "max_seq_len: {}, alloc_free_ratio: {}").format( self._max_seq_len, self._alloc_free_ratio)) self._next_adjustment_index += 1 return super(AdjustingFSNN, self).generate()
'tcmalloc-2.6.1', 'default' ], help="The allocator to use") args = parser.parse_args() if not args.output_dir: result_path = pathlib.Path('/tmp') / pathlib.Path( 'expres-' + time.strftime('%Y-%m-%d-%H-%M-%S')) os.mkdir(result_path.as_posix()) else: result_path = pathlib.Path(args.output_dir) os.mkdir(result_path.as_posix()) logutils.configure_logger(result_path, args.debug) logger = logutils.get_logger() logger.info("Testing the {} allocator".format(args.allocator)) if args.allocator == 'jemalloc-5.0.1': driver = drivers.get_jemalloc_5_0_1() elif args.allocator == 'dlmalloc-2.8.6': driver = drivers.get_dlmalloc_2_8_6() elif args.allocator == 'tcmalloc-2.6.1': driver = drivers.get_tcmalloc_2_6_1() elif args.allocator == 'avrlibc-r2537': driver = drivers.get_avrlibc_r2537() elif args.allocator == 'default': driver = drivers.get_default() else: logger.error("Unhandled allocator {}".format(args.allocator)) sys.exit(1)
def generate(self, starting_id: int): logger = get_logger() alloc_re = re.compile('vtx alloc (\d+) 0x([0-9a-f]+)') free_re = re.compile('vtx free 0x([0-9a-f]+)') realloc_re = re.compile( 'vtx realloc (\d+) 0x([0-9a-f]+) 0x([0-9a-f]+)') calloc_re = re.compile('vtx calloc (\d+) (\d+) 0x([0-9a-f]+)') res = [] next_alloc_id = starting_id addresses_to_ids = {} with open(self._data_path) as fd: for line in fd: line = line.strip() # Alloc m = re.fullmatch(alloc_re, line) if m: sz = int(m.group(1)) addr = int(m.group(2), 16) res.append(Alloc(next_alloc_id, sz)) addresses_to_ids[addr] = next_alloc_id next_alloc_id += 1 continue # Calloc m = re.fullmatch(calloc_re, line) if m: nmemb = int(m.group(1)) sz = int(m.group(2)) addr = int(m.group(3), 16) res.append(Calloc(next_alloc_id, nmemb, sz)) addresses_to_ids[addr] = next_alloc_id next_alloc_id += 1 continue # Free m = re.fullmatch(free_re, line) if m: addr = int(m.group(1), 16) if addr not in addresses_to_ids: logger.error( "Free of {} which was not allocated".format(addr)) continue res.append(Free(addresses_to_ids[addr])) del addresses_to_ids[addr] continue # Realloc m = re.fullmatch(realloc_re, line) if m: sz = int(m.group(1)) old_addr = int(m.group(2), 16) new_addr = int(m.group(3), 16) if old_addr != 0 and old_addr not in addresses_to_ids: logger.error( "Realloc of {} which was not allocated".format( old_addr)) continue if old_addr != 0: realloc = Realloc(addresses_to_ids[old_addr], next_alloc_id, sz) del addresses_to_ids[old_addr] else: realloc = Realloc(0, next_alloc_id, sz) res.append(realloc) addresses_to_ids[new_addr] = next_alloc_id next_alloc_id += 1 continue raise StartingConfigError( "Unknown event type '{}'".format(line)) self._sequence = stringify_sequence(res) self._generate_called = True
def run_experiment(exp_res: ExpResult, driver: pathlib.Path, interaction_generator: interactiongen.InteractionGenerator, starting_config: List[str], output_dir: pathlib.Path, jobs: int, time_limit: int, execution_limit: int, cutoff: int): logger = logutils.get_logger() # All workers will share this queue and write their results to it worker_result_q = multiprocessing.Queue() starting_config_path = _write_starting_config(starting_config) workers = [] for _ in range(jobs): in_q = multiprocessing.Queue() report_q = multiprocessing.Queue() workers.append((multiprocessing.Process( target=_minimise_distance_worker, args=(driver, interaction_generator, starting_config_path, in_q, report_q, worker_result_q)), in_q, report_q)) workers[-1][0].start() neg_trigger_path = output_dir / "neg_trigger.txt" pos_trigger_path = output_dir / "pos_trigger.txt" total_executions = total_errors = 0 min_pos_dist = min_neg_dist = None start_time = time.time() progress_report = [] while True: if ((time_limit and time.time() - start_time > time_limit) or (execution_limit and total_executions > execution_limit)): break report_change = False for _, _, report_q in workers: try: execs, errors = report_q.get_nowait() total_executions += execs total_errors += errors report_change = True except queue.Empty: pass if report_change: run_time = time.time() - start_time logger.info( ("Min. pos: {}. Min. neg: {}. Run time {:.2f}s. " "{:.2f} executions per second. {} successful executions. " "{} errors.").format(min_pos_dist, min_neg_dist, run_time, (total_executions + total_errors) / run_time, total_executions, total_errors)) try: new_seq, new_dist, execs, errors = worker_result_q.get(timeout=5) total_executions += execs total_errors += errors if new_dist < 0: # The first was allocated before the second so add the size of # the first adj_dist = new_dist + interaction_generator.first_named_alloc assert adj_dist <= 0 if min_neg_dist is None or adj_dist > min_neg_dist: # Handle a new minimum negative distance min_neg_dist = adj_dist exp_res.record_neg_result(min_neg_dist, time.time() - start_time, total_executions) with open(neg_trigger_path, 'w') as fd: for x in starting_config: fd.write(x + "\n") fd.write("\n") fd.write(new_seq[0] + "\n") fd.write("vtx gamestart\n") for x in new_seq[1:]: fd.write(x + "\n") logger.info("Min. neg. distance is now {} ({})".format( min_neg_dist, neg_trigger_path)) run_time = int(time.time() - start_time) progress_report.append((run_time, total_executions, min_pos_dist, min_neg_dist)) # Distribute the new shortest distance to the other workers for _, worker_in_q, _ in workers: worker_in_q.put(new_dist) elif new_dist > 0: # The first was allocated after the second so subtract the # size of the second adj_dist = new_dist - interaction_generator.second_named_alloc assert adj_dist >= 0 if min_pos_dist is None or adj_dist < min_pos_dist: # Handle a new minimum positive distance min_pos_dist = adj_dist exp_res.record_pos_result(min_pos_dist, time.time() - start_time, total_executions) with open(pos_trigger_path, 'w') as fd: for x in starting_config: fd.write(x + "\n") fd.write("\n") fd.write(new_seq[0] + "\n") fd.write("vtx gamestart\n") for x in new_seq[1:]: fd.write(x + "\n") logger.info("Min. pos. distance is now {} ({})".format( min_pos_dist, pos_trigger_path)) run_time = int(time.time() - start_time) progress_report.append((run_time, total_executions, min_pos_dist, min_neg_dist)) # Distribute the new shortest distance to the other workers for _, worker_in_q, _ in workers: worker_in_q.put(new_dist) except queue.Empty: pass if (cutoff is not None and min_neg_dist is not None and min_pos_dist is not None and abs(min_neg_dist) <= cutoff and min_pos_dist <= cutoff): break exp_res.total_time = time.time() - start_time if (cutoff is not None and min_neg_dist is not None and min_pos_dist and abs(min_neg_dist) <= cutoff and min_pos_dist <= cutoff): logger.info(("Discovered distances <= the cut off. " "Shutting down workers ...")) elif execution_limit and total_executions > execution_limit: logger.info("Execution limit exceeded. Shutting down workers ...") else: logger.info("Time limit expired. Shutting down workers ...") errors, execs = _shutdown_workers(workers) total_executions += execs total_errors += errors exp_res.total_execs = total_executions logger.info("{} successful executions. {} errors.".format( total_executions, total_errors)) logger.info("=== Progress Report ===") for t, e, pos, neg in progress_report: logger.info("Time: {}, execs: {}, pos: {}, neg: {}".format( t, e, pos, neg)) logger.info("=== End Progress Report ===")