Exemplo n.º 1
0
def measure_cache_hit_rate(memtrace_path,
                           cache_config,
                           eviction_model,
                           model_prob_schedule,
                           get_step,
                           eviction_trace_path,
                           max_examples=None,
                           use_oracle_scores=True,
                           k=5):
    """Measures the hit rate on the memtrace, returning the eviction entries.

  Passes through the entire memory trace and returns eviction entries
  obtained by following the model prediction model_prob of the time, and
  following the oracle eviction policy 1 - model_prob of the time.
  Passes through the memory trace in max_examples chunks at a time.

  Args:
    memtrace_path (str): path to the memory trace to simulate through.
    cache_config (Config): configures the cache to simulate with.
    eviction_model (EvictionPolicyModel): the model whose predictions to follow
      model_prob of the time
    model_prob_schedule (Schedule): returns the portion of the time to follow
      model predictions.
    get_step (Callable): called with no arguments produces the current step
      number.
    eviction_trace_path (str): all simulated eviction entries are written to
      eviction_trace_path.format(get_step()).
    max_examples (int | None): collects at most this many examples, if provided.
      Otherwise, collects the entire memory trace.
    use_oracle_scores (bool): If True, all returned eviction entries are labeled
      with oracle scores, even when the model is followed.
    k (int): see return value.

  Yields:
    entries (dict): maps set id (int) to sequence of consecutive eviction
      entries of that set id (list[EvictionEntry]).
    cache_hit_rates (list[float]): the cache hit rates on the first 1 / k,
      2 / k, ..., k / k portions of the current chunk of max_examples from the
      memtrace.
  """
    if max_examples is None:
        max_examples = np.inf

    line_size = cache_config.get("cache_line_size")
    with memtrace.MemoryTrace(memtrace_path,
                              cache_line_size=line_size) as trace:

        def create_eviction_policy(model_prob):
            """Creates the appropriate eviction policy for collecting data.

      Args:
        model_prob (float): the returned policy is a mixture of the learned
        eviction policy and the oracle policy, where the learned eviction policy
        is played model_prob of the time.

      Returns:
        EvictionPolicy
      """
            # Need to update the eviction policy and keep the cache state around
            oracle_scorer = {
                "lru": eviction_policy.LRUScorer(),
                "belady": eviction_policy.BeladyScorer(trace),
            }[FLAGS.oracle_eviction_policy]
            learned_scorer = model_eviction_policy.LearnedScorer(
                eviction_model)

            # Use scoring_policy_index = 0 to always get scores from the oracle scorer
            scoring_policy_index = 0 if use_oracle_scores else None
            return eviction_policy.MixturePolicy(
                [
                    eviction_policy.GreedyEvictionPolicy(oracle_scorer),
                    eviction_policy.GreedyEvictionPolicy(learned_scorer)
                ],
                [1 - model_prob, model_prob],
                scoring_policy_index=scoring_policy_index,
            )

        # This eviction policy isn't actually used (immediately overwritten
        # below), but we need to pass something that is not None.
        policy = create_eviction_policy(model_prob_schedule.value(get_step()))
        cache = cache_mod.Cache.from_config(cache_config,
                                            eviction_policy=policy,
                                            trace=trace)

        addresses = set()
        pcs = set()
        desc = "Collecting data from {} with mixture parameter: {}".format(
            memtrace_path, model_prob_schedule.value(get_step()))
        with tqdm.tqdm(desc=desc) as pbar:
            while not trace.done():
                data = []
                hit_rates = []
                model_prob = model_prob_schedule.value(get_step())
                cache.set_eviction_policy(create_eviction_policy(model_prob))
                # discard stats from previous iterations
                cache.hit_rate_statistic.reset()
                eviction_trace_path = eviction_trace_path.format(get_step())
                with evict_trace.EvictionTrace(eviction_trace_path,
                                               False) as etrace:

                    def add_to_data(cache_access, eviction_decision):
                        entry = evict_trace.EvictionEntry(
                            cache_access, eviction_decision)
                        data.append(entry)
                        # Add here for cache line aligned address
                        addresses.add(cache_access.address)
                        entry = evict_trace.EvictionEntry(
                            cache_access, eviction_decision)
                        etrace.write(entry)

                    while len(data) < max_examples and not trace.done():
                        pc, address = trace.next()
                        pcs.add(pc)
                        cache.read(pc, address, [add_to_data])
                        hit_rates.append(
                            cache.hit_rate_statistic.success_rate())
                        pbar.update(1)

                # Post-filter here, since length is unknown if max_examples is not
                # provided (or trace terminates earlier than max_examples).
                skip_len = len(hit_rates) // k
                hit_rates = (hit_rates[skip_len:skip_len *
                                       (k - 1) + 1:skip_len] + [hit_rates[-1]])
                yield data, hit_rates

        logging.info("Number of unique addresses: %d", len(addresses))
        logging.info("Number of unique pcs: %d", len(pcs))
Exemplo n.º 2
0
def main(_):
  # Set up experiment directory
  exp_dir = os.path.join(FLAGS.experiment_base_dir, FLAGS.experiment_name)
  utils.create_experiment_directory(exp_dir, FLAGS.force_overwrite)
  tensorboard_dir = os.path.join(exp_dir, "tensorboard")
  tf.disable_eager_execution()
  tb_writer = tf.summary.FileWriter(tensorboard_dir)
  miss_trace_path = os.path.join(exp_dir, "misses.csv")
  evict_trace_path = os.path.join(exp_dir, "evictions.txt")

  cache_config = cfg.Config.from_files_and_bindings(
      FLAGS.cache_configs, FLAGS.config_bindings)
  with open(os.path.join(exp_dir, "cache_config.json"), "w") as f:
    cache_config.to_file(f)

  flags_config = cfg.Config({
      "memtrace_file": FLAGS.memtrace_file,
      "tb_freq": FLAGS.tb_freq,
      "warmup_period": FLAGS.warmup_period,
  })
  with open(os.path.join(exp_dir, "flags.json"), "w") as f:
    flags_config.to_file(f)

  logging.info("Config: %s", str(cache_config))
  logging.info("Flags: %s", str(flags_config))

  cache_line_size = cache_config.get("cache_line_size")
  with memtrace.MemoryTrace(
      FLAGS.memtrace_file, cache_line_size=cache_line_size) as trace:
    with memtrace.MemoryTraceWriter(miss_trace_path) as write_trace:
      with evict.EvictionTrace(evict_trace_path, False) as evict_trace:
        def write_to_eviction_trace(cache_access, eviction_decision):
          evict_trace.write(
              evict.EvictionEntry(cache_access, eviction_decision))

        cache = cache_mod.Cache.from_config(cache_config, trace=trace)

        # Warm up cache
        for _ in tqdm.tqdm(range(FLAGS.warmup_period), desc="Warming up cache"):
          pc, address = trace.next()
          hit = cache.read(pc, address, [write_to_eviction_trace])

          if not hit:
            write_trace.write(pc, address)

          if trace.done():
            raise ValueError()

        # Discard warm-up cache statistics
        cache.hit_rate_statistic.reset()

        num_reads = 0
        with tqdm.tqdm(desc="Simulating cache on MemoryTrace") as pbar:
          while not trace.done():
            pc, address = trace.next()
            hit = cache.read(pc, address, [write_to_eviction_trace])

            if not hit:
              write_trace.write(pc, address)

            num_reads += 1
            if num_reads % FLAGS.tb_freq == 0:
              log_scalar(tb_writer, "cache_hit_rate",
                         cache.hit_rate_statistic.success_rate(), num_reads)

            pbar.update(1)

          log_scalar(tb_writer, "cache_hit_rate",
                     cache.hit_rate_statistic.success_rate(), num_reads)

  # Force flush, otherwise last writes will be lost.
  tb_writer.flush()