No código colado abaixo, estou executando duas funções f1
and f2
que realizam exatamente o mesmo trabalho. Pegue um T
array de números e inteiros arr
(que foi inicializado para 0
everywhere) e então incremente T
vezes cada elemento de arr
Assim, no final de ambos f1
e f2
, a entrada 0,0...0
deve se tornar T,T...T
.
O que eu não entendo é por que f1
roda muito mais devagar do que f2
(cerca de 1,76 vezes mais lento quando T
é, digamos, 1 bilhão). Aqui está minha saída
➜ Diferença de tempo do gcc para desktop.c && ./a.out 1000000000 16
-----> Executando f1 <------- Tempo gasto: 15,511 segundos
-----> Executando f2 <------- Tempo gasto: 8,887 segundos%
Aqui T
é fornecido ao programa como argv[1]
e o comprimento do array como argv[2]
. O timing-difference.c
arquivo é colado abaixo no final deste post.
Basicamente, f1
é incrementar diretamente cada arr[i]
, enquanto f2
usa uma variável temporária tmp
para o incremento e, em seguida, atribui-la a arr[i] quando terminar.
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<time.h>
/*Directly increment arr[i] for each i*/
void f1(int T, int* arr, int arrlength){
printf("\n-----> Running f1 <-------\n");
clock_t end, start;
double cpu_time_used;
// For each element of arr, increment it T times.
start = clock();
for(int i = 0 ; i<arrlength ;++i){
for (int j=0 ; j<T ; ++j){
arr[i] += 1;
}
}
end = clock();
cpu_time_used = ((double) (end - start)) / CLOCKS_PER_SEC;
printf("Time taken: %.3f seconds", cpu_time_used);
}
/*increment arr[i] using temporary variable tmp*/
void f2(int T, int* arr, int arrlength){
printf("\n-----> Running f2 <-------\n");
clock_t end, start;
double cpu_time_used;
// For each element of arr, increment it T times.
start = clock();
for(int i = 0 ; i<arrlength ;++i){
int tmp=arr[i];
for (int j=0 ; j<T ; ++j){
tmp += 1;
}
arr[i] = tmp;
}
end = clock();
cpu_time_used = ((double) (end - start)) / CLOCKS_PER_SEC;
printf("Time taken: %.3f seconds", cpu_time_used);
}
void print_arr(int* arr, int arrlength){
for(int i = 0 ; i<arrlength ; ++i){
printf("%d ", arr[i]);
}
printf("\n\n");
}
/*Zero initialize array*/
void initialize_array(int* arr, int arrlength){
for (int i=0 ; i<arrlength ; ++i){
arr[i] = 0;
}
}
int main(int argc, char** argv){
int T = atoi(argv[1]);
int arrlength = atoi(argv[2]);
int arr[arrlength];
initialize_array(arr, arrlength);
f1(T,arr,arrlength); // --> why does this run slower than f2?
//print_arr(arr, arrlength);
printf("\n\n");
initialize_array(arr, arrlength);
f2(T,arr,arrlength);
//print_arr(arr, arrlength);
return 0;
}
EDIT : Eu obtenho as mesmas medições de tempo quando chamof2
primeiro ef1
depois ou mesmo se eu executo várias vezes.
Com -O2 habilitado, obtenho os timings como 0,000 em ambos. Fiquei curioso sobre as configurações padrão que o gcc estava usando para compilar e por que havia uma diferença tão grande no desempenho. A resposta, como wohlstad sugere, deve estar no assembly, mas, infelizmente, não consigo ler o assembly x86 bem :-( para um entendimento informado
Acontece que há muita coisa acontecendo no nível de montagem
f1
para esta instrução:Isso compila para:
Que é executado em cada iteração do loop interno.
Enquanto esta linha em
f2
:Cumpre com isso:
E a tarefa de volta:
Compila para isto:
Que só roda no loop externo. Isso explica a diferença no tempo de execução.