I want to count the total number of instructions executed when running /bin/ls. I used 3 methods whose results differ heavily and i dont have a clue why.
1. Instruction counting with ptrace
I wrote a piece of code that invokes an instance of ls and singlesteps through it with ptrace:
#include <stdio.h>
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <sys/user.h>
#include <sys/reg.h>
#include <sys/syscall.h>
int main()
{
pid_t child;
child = fork(); //create child
if(child == 0) {
ptrace(PTRACE_TRACEME, 0, NULL, NULL);
char* child_argv[] = {"/bin/ls", NULL};
execv("/bin/ls", child_argv);
}
else {
int status;
long long ins_count = 0;
while(1)
{
//stop tracing if child terminated successfully
wait(&status);
if(WIFEXITED(status))
break;
ins_count++;
ptrace(PTRACE_SINGLESTEP, child, NULL, NULL);
}
printf("\n%lld Instructions executed.\n", ins_count);
}
return 0;
}
Running this code gives me 516.678 Instructions executed.
2. QEMU singlestepping
I simulated ls using qemu in singlestep mode and logged all incoming instructions into a log file using the following command: qemu-x86_64 -singlestep -D logfile -d in_asm /bin/ls
According to qemu ls executes 16.836 instructions.
3. perf
sudo perf stat ls
This command gave me 8.162.180 instructions executed.
I know that most of these instructions come from the dynamic linker and it is fine that they get counted. But why do these numbers differ so much? Shouldn't they all be the same?