#include #include #include /* Definicoes de "combine" para calcular soma de inteiros */ #define IDENT 0 #define OPER + #define OPER_NAME "Sum" #define DATA_NAME "Integer" typedef int data_t; /* $begin adt */ /* Criar um "abstract data type" para vector */ typedef struct { int len; data_t *data; } vec_rec, *vec_ptr; /* $end adt */ /* Declaracoes das funcoes necessarias */ /* Criar vector de comprimento "len" */ vec_ptr new_vec(int len) { /* allocate header structure */ vec_ptr result = (vec_ptr) malloc(sizeof(vec_rec)); if (!result) return NULL; /* Couldn't allocate storage */ result->len = len; /* Allocate array */ if (len > 0) { data_t *data = (data_t *)calloc(len, sizeof(data_t)); if (!data) { free((void *) result); return NULL; /* Couldn't allocate storage */ } result->data = data; } else result->data = NULL; return result; } /* $begin get_vec_start */ data_t *get_vec_start(vec_ptr v) { return v->data; } /* $end get_vec_start */ /* * Copiar um elemento do vector para "dest" e * devolver 0 (indice fora de limites) ou 1 (sucesso) */ int get_vec_element(vec_ptr v, int index, data_t *dest) { if (index < 0 || index >= v->len) return 0; *dest = v->data[index]; return 1; } /* Calcular o comprimento do vector */ int vec_length(vec_ptr v) { return v->len; } /* * Rotinas para usar o cycle counter */ /* Initializar as variaveis do cycle counter */ static unsigned cyc_hi = 0; static unsigned cyc_lo = 0; /* Colocar em *hi e *lo os bits mais e menos significativos do cycle counter. * Requer codigo assembly para usar a instrucao "rdtsc". */ void access_counter(unsigned *hi, unsigned *lo) { asm("rdtsc; movl %%edx,%0; movl %%eax,%1" /* Ler o cycle counter */ : "=r" (*hi), "=r" (*lo) /* e mover resultados para */ : /* No input */ /* os dois outputs */ : "%edx", "%eax"); } /* Registar o valor actual do cycle counter. */ void start_counter() { access_counter(&cyc_hi, &cyc_lo); } /* Devolver o numero de ciclos desde a ultima chamada a start_counter. */ double get_counter() { unsigned ncyc_hi, ncyc_lo; unsigned hi, lo, borrow; double result; /* Obter o valor do cycle counter */ access_counter(&ncyc_hi, &ncyc_lo); /* Efectuar subtraccao de precisao dupla */ lo = ncyc_lo - cyc_lo; borrow = lo > ncyc_lo; hi = ncyc_hi - cyc_hi - borrow; result = (double) hi * (1 << 30) * 4 + lo; if (result < 0) { fprintf(stderr, "Erro: contador devolve valor negativo: %.0f\n", result); } return result; } /* * Calcular o "combine1" */ void combine1(vec_ptr v, data_t *dest) { int i; *dest = IDENT; for (i = 0; i < vec_length(v); i++) { data_t val; get_vec_element(v, i, &val); *dest = *dest OPER val; } } /* Programa para medir o CPE (simplificado) da função combine1 * e produzir apenas um resultado - soma inteiros - com a cache a quente */ int main() { int dimensao = 1000; vec_ptr vector = new_vec(dimensao); data_t resultado; double cpe; combine1(vector, &resultado); /* Aquecimento da cache */ start_counter(); combine1(vector, &resultado); cpe = get_counter(); cpe = cpe / dimensao; printf("CPE a quente (%s, %s, %d elem): %.2f\n", OPER_NAME, DATA_NAME, dimensao,cpe); }