예제 #1
0
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
예제 #2
0
    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()
예제 #3
0
                        '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)
예제 #4
0
    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
예제 #5
0
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 ===")