Пример #1
0
    def _ddmin(self,
               dag,
               carryover_inputs,
               precompute_cache=None,
               recursion_level=0,
               label_prefix=(),
               total_inputs_pruned=0):
        ''' carryover_inputs is the variable "r" from the paper. '''
        # Hack: superclass calls _ddmin with an integer, which doesn't match our
        # API. Translate that to an empty sequence. (we also don't use precompute_cache)
        if type(carryover_inputs) == int:
            carryover_inputs = []

        local_label = lambda i: "%s/%d" % ("l"
                                           if i == 0 else "r", recursion_level)
        subset_label = lambda label: ".".join(
            map(str, label_prefix + (label, )))
        print_subset = lambda label, s: subset_label(label) + ": " + " ".join(
            map(lambda e: e.label, s))

        # Base case. Note that atomic_inputs are grouped-together failure/recovery
        # pairs, or normal inputs otherwise.
        if len(dag.atomic_input_events) == 1:
            self.log("Base case %s" % str(dag.input_events))
            return (dag, total_inputs_pruned)

        (left, right) = split_list(dag.atomic_input_events, 2)
        self.log("Subsets:\n" + "\n".join(
            print_subset(local_label(i), s)
            for i, s in enumerate([left, right])))
        # This is: [dag.input_subset(left), dag.input_subset(right)]
        left_right_dag = []

        for i, subsequence in enumerate([left, right]):
            label = local_label(i)
            prefix = label_prefix + (label, )
            new_dag = dag.atomic_input_subset(subsequence)
            self.log("Current subset: %s" %
                     print_subset(label, new_dag.atomic_input_events))
            left_right_dag.append(new_dag)
            # We test on subsequence U carryover_inputs
            test_dag = new_dag.insert_atomic_inputs(carryover_inputs)
            self._track_iteration_size(total_inputs_pruned)
            violation = self._check_violation(test_dag, i, label)
            if violation:
                self.log("Violation found in %dth half. Recursing" % i)
                total_inputs_pruned += len(dag.input_events) - len(
                    new_dag.input_events)
                self.mcs_log_tracker.maybe_dump_intermediate_mcs(
                    new_dag, "", self)
                return self._ddmin(new_dag,
                                   carryover_inputs,
                                   recursion_level=recursion_level + 1,
                                   label_prefix=prefix,
                                   total_inputs_pruned=total_inputs_pruned)

        self.log("Interference")
        (left_dag, right_dag) = left_right_dag
        self.log("Recursing on left half")
        prefix = label_prefix + ("il/%d" % recursion_level, )
        (left_result, total_inputs_pruned) = self._ddmin(
            left_dag,
            right_dag.insert_atomic_inputs(
                carryover_inputs).atomic_input_events,
            recursion_level=recursion_level + 1,
            label_prefix=prefix,
            total_inputs_pruned=total_inputs_pruned)
        self.log("Recursing on right half")
        prefix = label_prefix + ("ir/%d" % recursion_level, )
        (right_result, total_inputs_pruned) = self._ddmin(
            right_dag,
            left_dag.insert_atomic_inputs(
                carryover_inputs).atomic_input_events,
            recursion_level=recursion_level + 1,
            label_prefix=prefix,
            total_inputs_pruned=total_inputs_pruned)

        return (left_result.insert_atomic_inputs(
            right_result.atomic_input_events), total_inputs_pruned)
Пример #2
0
    def _ddmin(self,
               dag,
               split_ways,
               precompute_cache=None,
               label_prefix=(),
               total_inputs_pruned=0):
        # This is the delta-debugging algorithm from:
        #   http://www.st.cs.uni-saarland.de/papers/tse2002/tse2002.pdf,
        # Section 3.2
        # TODO(cs): we could do much better if we leverage domain knowledge (e.g.,
        # start by pruning all LinkFailures, or splitting by nodes rather than
        # time)
        if split_ways > len(dag.input_events):
            self.log("Done")
            return (dag, total_inputs_pruned)

        local_label = lambda i, inv=False: "%s%d/%d" % ("~" if inv else "", i,
                                                        split_ways)
        subset_label = lambda label: ".".join(
            map(str, label_prefix + (label, )))
        print_subset = lambda label, s: subset_label(label) + ": " + " ".join(
            map(lambda e: e.label, s))

        subsets = split_list(dag.input_events, split_ways)
        self.log("Subsets:\n" + "\n".join(
            print_subset(local_label(i), s) for i, s in enumerate(subsets)))
        for i, subset in enumerate(subsets):
            label = local_label(i)
            new_dag = dag.input_subset(subset)
            input_sequence = tuple(new_dag.input_events)
            self.log("Current subset: %s" %
                     print_subset(label, input_sequence))
            if precompute_cache.already_done(input_sequence):
                self.log("Already computed. Skipping")
                continue
            precompute_cache.update(input_sequence)
            if input_sequence == ():
                self.log(
                    "Subset after pruning dependencies was empty. Skipping")
                continue

            self._track_iteration_size(total_inputs_pruned)
            violation = self._check_violation(new_dag, i, label)
            if violation:
                self.log_violation(
                    "Subset %s reproduced violation. Subselecting." %
                    subset_label(label))
                self.mcs_log_tracker.maybe_dump_intermediate_mcs(
                    new_dag, subset_label(label), self)

                total_inputs_pruned += len(dag.input_events) - len(
                    new_dag.input_events)
                return self._ddmin(new_dag,
                                   2,
                                   precompute_cache=precompute_cache,
                                   label_prefix=label_prefix + (label, ),
                                   total_inputs_pruned=total_inputs_pruned)

        self.log_no_violation(
            "No subsets with violations. Checking complements")
        for i, subset in enumerate(subsets):
            label = local_label(i, True)
            prefix = label_prefix + (label, )
            new_dag = dag.input_complement(subset)
            input_sequence = tuple(new_dag.input_events)
            self.log("Current complement: %s" %
                     print_subset(label, input_sequence))
            if precompute_cache.already_done(input_sequence):
                self.log("Already computed. Skipping")
                continue
            precompute_cache.update(input_sequence)

            if input_sequence == ():
                self.log(
                    "Subset %s after pruning dependencies was empty. Skipping",
                    subset_label(label))
                continue

            self._track_iteration_size(total_inputs_pruned)
            violation = self._check_violation(new_dag, i, label)
            if violation:
                self.log_violation(
                    "Subset %s reproduced violation. Subselecting." %
                    subset_label(label))
                self.mcs_log_tracker.maybe_dump_intermediate_mcs(
                    new_dag, subset_label(label), self)
                total_inputs_pruned += len(dag.input_events) - len(
                    new_dag.input_events)
                return self._ddmin(new_dag,
                                   max(split_ways - 1, 2),
                                   precompute_cache=precompute_cache,
                                   label_prefix=prefix,
                                   total_inputs_pruned=total_inputs_pruned)

        self.log_no_violation("No complements with violations.")
        if split_ways < len(dag.input_events):
            self.log("Increasing granularity.")
            return self._ddmin(dag,
                               min(len(dag.input_events), split_ways * 2),
                               precompute_cache=precompute_cache,
                               label_prefix=label_prefix,
                               total_inputs_pruned=total_inputs_pruned)
        return (dag, total_inputs_pruned)
Пример #3
0
  def _ddmin(self, dag, split_ways, precompute_cache=None, label_prefix=(),
             total_inputs_pruned=0):
    # This is the delta-debugging algorithm from:
    #   http://www.st.cs.uni-saarland.de/papers/tse2002/tse2002.pdf,
    # Section 3.2
    # TODO(cs): we could do much better if we leverage domain knowledge (e.g.,
    # start by pruning all LinkFailures, or splitting by nodes rather than
    # time)
    if split_ways > len(dag.input_events):
      self.log("Done")
      return (dag, total_inputs_pruned)

    local_label = lambda i, inv=False: "%s%d/%d" % ("~" if inv else "", i, split_ways)
    subset_label = lambda label: ".".join(map(str, label_prefix + ( label, )))
    print_subset = lambda label, s: subset_label(label) + ": "+" ".join(map(lambda e: e.label, s))

    subsets = split_list(dag.input_events, split_ways)
    self.log("Subsets:\n"+"\n".join(print_subset(local_label(i), s) for i, s in enumerate(subsets)))
    for i, subset in enumerate(subsets):
      label = local_label(i)
      new_dag = dag.input_subset(subset)
      input_sequence = tuple(new_dag.input_events)
      self.log("Current subset: %s" % print_subset(label, input_sequence))
      if precompute_cache.already_done(input_sequence):
        self.log("Already computed. Skipping")
        continue
      precompute_cache.update(input_sequence)
      if input_sequence == ():
        self.log("Subset after pruning dependencies was empty. Skipping")
        continue

      self._track_iteration_size(total_inputs_pruned)
      violation = self._check_violation(new_dag, i, label)
      if violation:
        self.log_violation("Subset %s reproduced violation. Subselecting." % subset_label(label))
        self.mcs_log_tracker.maybe_dump_intermediate_mcs(new_dag,
                                                         subset_label(label), self)

        total_inputs_pruned += len(dag.input_events) - len(new_dag.input_events)
        return self._ddmin(new_dag, 2, precompute_cache=precompute_cache,
                           label_prefix = label_prefix + (label, ),
                           total_inputs_pruned=total_inputs_pruned)

    self.log_no_violation("No subsets with violations. Checking complements")
    for i, subset in enumerate(subsets):
      label = local_label(i, True)
      prefix = label_prefix + (label, )
      new_dag = dag.input_complement(subset)
      input_sequence = tuple(new_dag.input_events)
      self.log("Current complement: %s" % print_subset(label, input_sequence))
      if precompute_cache.already_done(input_sequence):
        self.log("Already computed. Skipping")
        continue
      precompute_cache.update(input_sequence)

      if input_sequence == ():
        self.log("Subset %s after pruning dependencies was empty. Skipping", subset_label(label))
        continue

      self._track_iteration_size(total_inputs_pruned)
      violation = self._check_violation(new_dag, i, label)
      if violation:
        self.log_violation("Subset %s reproduced violation. Subselecting." % subset_label(label))
        self.mcs_log_tracker.maybe_dump_intermediate_mcs(new_dag,
                                                         subset_label(label), self)
        total_inputs_pruned += len(dag.input_events) - len(new_dag.input_events)
        return self._ddmin(new_dag, max(split_ways - 1, 2),
                           precompute_cache=precompute_cache,
                           label_prefix=prefix,
                           total_inputs_pruned=total_inputs_pruned)

    self.log_no_violation("No complements with violations.")
    if split_ways < len(dag.input_events):
      self.log("Increasing granularity.")
      return self._ddmin(dag, min(len(dag.input_events), split_ways*2),
                         precompute_cache=precompute_cache,
                         label_prefix=label_prefix,
                         total_inputs_pruned=total_inputs_pruned)
    return (dag, total_inputs_pruned)
Пример #4
0
  def _ddmin(self, dag, carryover_inputs, precompute_cache=None,
             recursion_level=0, label_prefix=(), total_inputs_pruned=0):
    ''' carryover_inputs is the variable "r" from the paper. '''
    # Hack: superclass calls _ddmin with an integer, which doesn't match our
    # API. Translate that to an empty sequence. (we also don't use precompute_cache)
    if type(carryover_inputs) == int:
      carryover_inputs = []

    local_label = lambda i: "%s/%d" % ("l" if i == 0 else "r", recursion_level)
    subset_label = lambda label: ".".join(map(str, label_prefix + ( label, )))
    print_subset = lambda label, s: subset_label(label) + ": "+" ".join(map(lambda e: e.label, s))

    # Base case. Note that atomic_inputs are grouped-together failure/recovery
    # pairs, or normal inputs otherwise.
    if len(dag.atomic_input_events) == 1:
      self.log("Base case %s" % str(dag.input_events))
      return (dag, total_inputs_pruned)

    (left, right) = split_list(dag.atomic_input_events, 2)
    self.log("Subsets:\n"+"\n".join(print_subset(local_label(i), s)
                                    for i, s in enumerate([left,right])))
    # This is: [dag.input_subset(left), dag.input_subset(right)]
    left_right_dag = []

    for i, subsequence in enumerate([left, right]):
      label = local_label(i)
      prefix = label_prefix + (label, )
      new_dag = dag.atomic_input_subset(subsequence)
      self.log("Current subset: %s" % print_subset(label,
                                                   new_dag.atomic_input_events))
      left_right_dag.append(new_dag)
      # We test on subsequence U carryover_inputs
      test_dag = new_dag.insert_atomic_inputs(carryover_inputs)
      self._track_iteration_size(total_inputs_pruned)
      violation = self._check_violation(test_dag, i, label)
      if violation:
        self.log("Violation found in %dth half. Recursing" % i)
        total_inputs_pruned += len(dag.input_events) - len(new_dag.input_events)
        self.mcs_log_tracker.maybe_dump_intermediate_mcs(new_dag, "", self)
        return self._ddmin(new_dag, carryover_inputs,
                           recursion_level=recursion_level+1,
                           label_prefix=prefix,
                           total_inputs_pruned=total_inputs_pruned)

    self.log("Interference")
    (left_dag, right_dag) = left_right_dag
    self.log("Recursing on left half")
    prefix = label_prefix + ("il/%d" % recursion_level,)
    (left_result,
     total_inputs_pruned) = self._ddmin(left_dag,
                                        right_dag.insert_atomic_inputs(carryover_inputs).atomic_input_events,
                                        recursion_level=recursion_level+1,
                                        label_prefix=prefix,
                                        total_inputs_pruned=total_inputs_pruned)
    self.log("Recursing on right half")
    prefix = label_prefix + ("ir/%d" % recursion_level,)
    (right_result,
     total_inputs_pruned) = self._ddmin(right_dag,
                                        left_dag.insert_atomic_inputs(carryover_inputs).atomic_input_events,
                                        recursion_level=recursion_level+1,
                                        label_prefix=prefix,
                                        total_inputs_pruned=total_inputs_pruned)

    return (left_result.insert_atomic_inputs(right_result.atomic_input_events),
            total_inputs_pruned)
Пример #5
0
  def _ddmin(self, split_ways, precomputed_subsets=None, iteration=0):
    ''' - iteration is the # of times we've replayed (not the number of times
    we've invoked _ddmin)'''
    # This is the delta-debugging algorithm from:
    #   http://www.st.cs.uni-saarland.de/papers/tse2002/tse2002.pdf,
    # Section 3.2
    # TODO(cs): we could do much better if we leverage domain knowledge (e.g.,
    # start by pruning all LinkFailures)
    if split_ways > len(self.dag.input_events):
      self._track_iteration_size(iteration + 1, split_ways)
      self.log("Done")
      return

    if precomputed_subsets is None:
      precomputed_subsets = set()

    self.log("Checking %d subsets" % split_ways)
    subsets = split_list(self.dag.input_events, split_ways)
    self.log("Subsets: %s" % str(subsets))
    for i, subset in enumerate(subsets):
      new_dag = self.dag.input_subset(subset)
      input_sequence = tuple(new_dag.input_events)
      self.log("Current subset: %s" % str(input_sequence))
      if input_sequence in precomputed_subsets:
        self.log("Already computed. Skipping")
        continue
      precomputed_subsets.add(input_sequence)
      if input_sequence == ():
        self.log("Subset after pruning dependencies was empty. Skipping")
        continue

      iteration += 1
      violation = self._check_violation(new_dag, i, iteration, split_ways)
      if violation:
        self.dag = new_dag
        return self._ddmin(2, precomputed_subsets=precomputed_subsets,
                           iteration=iteration)

    self.log("No subsets with violations. Checking complements")
    for i, subset in enumerate(subsets):
      new_dag = self.dag.input_complement(subset)
      input_sequence = tuple(new_dag.input_events)
      self.log("Current complement: %s" % str(input_sequence))
      if input_sequence in precomputed_subsets:
        self.log("Already computed. Skipping")
        continue
      precomputed_subsets.add(input_sequence)
      if input_sequence == ():
        self.log("Subset after pruning dependencies was empty. Skipping")
        continue

      iteration += 1
      violation = self._check_violation(new_dag, i, iteration, split_ways)
      if violation:
        self.dag = new_dag
        return self._ddmin(max(split_ways - 1, 2),
                           precomputed_subsets=precomputed_subsets,
                           iteration=iteration)

    self.log("No complements with violations.")
    if split_ways < len(self.dag.input_events):
      self.log("Increasing granularity.")
      return self._ddmin(min(len(self.dag.input_events), split_ways*2),
                         precomputed_subsets=precomputed_subsets,
                         iteration=iteration)
    self._track_iteration_size(iteration + 1, split_ways)