Как я могу создать 3-разрядный счетчик-предсказатель ветви gshare из 2-разрядного счетчика-предсказателя ветви gshare? - PullRequest
0 голосов
/ 16 апреля 2020

Я пытался выяснить, какие части этого кода включают 2-битный счетчик, потому что я должен превратить его в 3-битный счетчик.

Для размера таблицы GSHARE_SIZE, я думаю, правильный размер для 3-битного счетчика будет 17 вместо 2-битного 18, потому что есть еще один счетчик и 18 слишком велик для выделенной памяти пробел (64k).

Кроме того, я считаю, что значение счетчика в разделе --- // предиктора обновления --- необходимо изменить с:

            // update predictor
            bool t = uop->br_taken;
            if (t && gtable[gidx] < 1)
                gtable[gidx] ++;
            else if (!t && gtable[gidx] > -2)
                gtable[gidx] --;

на

            // update predictor
            bool t = uop->br_taken;
            if (t && gtable[gidx] < 2)
                gtable[gidx] ++;
            else if (!t && gtable[gidx] > -3)
                gtable[gidx] --;

Кроме этих двух вещей, я не уверен, как преобразовать этот 2-битный счетчик в 3-битный. Ниже приведен код для 2-битного предиктора.

#include <stdio.h>
#include <cassert>
#include <string.h>
#include <inttypes.h>

using namespace std;
#include "cbp3_def.h"
#include "cbp3_framework.h"

#define GSHARE_SIZE 18 // 256K 2-bit counters = 64 KB cost

// predictor tables
int8_t   *gtable;

// cost: depending on predictor size
uint32_t brh_fetch;
uint32_t brh_retire;

// count number of runs
uint32_t runs;

void PredictorInit() {
    runs = 0;
    gtable = new int8_t[1 << GSHARE_SIZE];
    assert(gtable);
}

void PredictorReset() {
    // this function is called before EVERY run
    // it is used to reset predictors and change configurations
        printf("Predictor:gshare\nconfig: %i counters, %i KB cost\n", 1 << GSHARE_SIZE, (1 << GSHARE_SIZE) * 2 / 8 / 1024);

    for (int i = 0; i < (1 << GSHARE_SIZE); i ++)
        gtable[i] = 0;


    brh_fetch = 0;
    brh_retire = 0;
}

void PredictorRunACycle() {
    // get info about what uops are processed at each pipeline stage
    const cbp3_cycle_activity_t *cycle_info = get_cycle_info();

    // make prediction at fetch stage
    for (int i = 0; i < cycle_info->num_fetch; i++) {
        uint32_t fe_ptr = cycle_info->fetch_q[i];
        const cbp3_uop_dynamic_t *uop = &fetch_entry(fe_ptr)->uop;

        if (runs == 0 && uop->type & IS_BR_CONDITIONAL) {
            // get prediction
            uint32_t gidx = (brh_fetch ^ uop->pc) & ((1 << GSHARE_SIZE) - 1);
            bool gpred = (gtable[gidx] >= 0);

            assert(report_pred(fe_ptr, false, gpred));
        }

        // update fetch branch history
        if (uop->type & IS_BR_CONDITIONAL)
            brh_fetch = (brh_fetch << 1) | (uop->br_taken ? 1 : 0);
        else if (uop_is_branch(uop->type))
            brh_fetch = (brh_fetch << 1) | 1;
    }

    for (int i = 0; i < cycle_info->num_retire; i++) {
        uint32_t rob_ptr = cycle_info->retire_q[i];
        const cbp3_uop_dynamic_t *uop = &rob_entry(rob_ptr)->uop;

        if (runs == 0 && uop->type & IS_BR_CONDITIONAL) {
            uint32_t gidx = (brh_retire ^ uop->pc) & ((1 << GSHARE_SIZE) - 1);

            // update predictor
            bool t = uop->br_taken;
            if (t && gtable[gidx] < 1)
                gtable[gidx] ++;
            else if (!t && gtable[gidx] > -2)
                gtable[gidx] --;


        // update retire branch history
        if (uop->type & IS_BR_CONDITIONAL)
            brh_retire = (brh_retire << 1) | (uop->br_taken ? 1 : 0);
        else if (uop_is_branch(uop->type))
            brh_retire = (brh_retire << 1) | 1;
    }
}

void PredictorRunEnd() {
    runs ++;
    if (runs < 1) // set rewind_marked to indicate that we want more runs
        rewind_marked = true;
}

void PredictorExit() {
    delete [] gtable;
}

Я не уверен, какие части этого предиктора имеют отношение к компоненту "2-битного счетчика" этого предиктора.

...