sperf.c
C Source File · 183 lines
#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <sys/types.h>#include <sys/wait.h>#include <sys/poll.h>#include <sys/time.h>#include <time.h>
// Feel free to change the data structures generated by AI.
#define MAX_SYSCALLS 1024#define TOP_N 5extern char **environ;
typedef struct { char name[64]; double time;} syscall_stat;
typedef struct { syscall_stat stats[MAX_SYSCALLS]; int count; double total_time;} syscall_stats;
int parse_strace_line(char *line, char *syscall_name, double *time) { if (!('a' <= line[0] && line[0] <= 'z')) return -1; int n = strlen(line); int flag1 = 0, flag2 = 0, flag3 = 0; int name_ptr = 0; *time = 0; double base = 1.0; for (int i = 0; i < n; i++) { if (!flag1) syscall_name[name_ptr++] = line[i]; if (i != n - 1 && !flag1 && line[i + 1] == '(') flag1 = 1; if (line[i] == '<') flag2 = 1; else if (flag2 && line[i] == '>') flag2 = 0; else if (flag2) { if (line[i] == '.') flag3 = 1; else if (!flag3) { *time = (*time) * 10 + (line[i] - '0'); }else { base /= 10; *time += base * (line[i] - '0'); } } } syscall_name[name_ptr] = '\0'; return 0;}
void add_syscall(syscall_stats *stats, const char *name, double time) { (*stats).total_time += time; int n = (*stats).count; for (int i = 0; i < n; i++) { if (strcmp((*stats).stats[i].name, name) == 0) { (*stats).stats[i].time += time; return; } } int _len = strlen(name); memcpy((*stats).stats[n].name, name, sizeof(char) * (_len + 1)); (*stats).stats[n].time = time; (*stats).count++;}
void swap(syscall_stat *a, syscall_stat *b) { syscall_stat c = *a; *a = *b; *b = c;}
void print_top_syscalls(syscall_stats *stats, int k) { int n = (*stats).count; while (1) { int flag = 0; for (int i = 0; i + 1 < n; i++) { if ((*stats).stats[i].time < (*stats).stats[i + 1].time) { swap(((*stats).stats + i), ((*stats).stats + i + 1)); flag = 1; } } if (!flag) break; } k = k > n ? n : k; for (int i = 0; i < k; i++) { printf("%s (%d%%)\n", (*stats).stats[i].name, (int)((*stats).stats[i].time / (*stats).total_time * 100.0)); } for (int i = 0; i < 80; i++) { fputc('\0', stdout); } fflush(stdout);}
char buffer[1 << 16];int buffer_ptr;syscall_stats ss;
int handle_buffer() { int pos = 0, retval = 0; for (int i = 0; i < buffer_ptr; i++) { if (buffer[i] == '\n') { int len = i - pos + 1; char *line = (char *)malloc(sizeof(char) * (len + 1)); memcpy(line, buffer + pos, sizeof(char) * len); line[len] = '\0'; char *syscall_name = (char *)malloc(sizeof(char) * 64); double time; int ret = parse_strace_line(line, syscall_name, &time); pos = i + 1; if (ret == -1) { retval = -1; free(line); free(syscall_name); continue; } add_syscall(&ss, syscall_name, time); free(line); free(syscall_name); } } int _buffer_ptr = buffer_ptr - pos; for (int i = 0; i < _buffer_ptr; i++) { buffer[i] = buffer[pos++]; } buffer_ptr = _buffer_ptr; buffer[buffer_ptr] = '\0'; return retval;}
int main(int argc, char *argv[]) { int pipefd[2]; if (pipe(pipefd) == -1) { perror("pipe error\n"); return 1; } int pid = fork(); if (pid == 0) { //child close(pipefd[0]); dup2(pipefd[1], STDERR_FILENO); close(pipefd[1]); char ** my_argv = (char**)malloc(sizeof (char*) * (argc + 2)); my_argv[0] = "strace"; my_argv[1] = "-T"; for (int i = 1; i < argc; i++) { my_argv[i + 1] = argv[i]; } my_argv[argc + 1] = NULL; execve("/bin/strace", my_argv, environ); } else { //parent close(pipefd[1]); dup2(pipefd[0], STDIN_FILENO); close(pipefd[0]); struct pollfd fds[2]; fds[0].fd = STDIN_FILENO; fds[0].events = POLLIN | POLLHUP; int timeout = 100000; while (1) { struct timeval now, _now; gettimeofday(&now, NULL); int r = poll(fds, 1, timeout / 1000 + 5); gettimeofday(&_now, NULL); int dif = (_now.tv_sec - now.tv_sec) * 1000000 + (_now.tv_usec - now.tv_usec); timeout -= dif; if (r > 0) { if (fds[0].revents & POLLIN) { int len; if ((len = read(STDIN_FILENO, buffer + buffer_ptr, sizeof(buffer) - buffer_ptr)) > 0) buffer_ptr += len; handle_buffer(); } if (fds[0].revents & POLLHUP) { while (read(STDIN_FILENO, buffer, sizeof(buffer)) > 0); break; } } if (r == 0 || timeout < 0) { print_top_syscalls(&ss, 5); timeout = 100000; } if (r < 0) break; } }
return 0;}





