From 84e64f6ad1a0bb66032fb2700060ccab5c295f3b Mon Sep 17 00:00:00 2001 From: klein panic Date: Sun, 29 Sep 2024 02:34:44 -0400 Subject: [PATCH] initial commit --- Makefile | 26 +++++++ analyze.sh | 8 ++ code_analyzer.c | 200 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 234 insertions(+) create mode 100644 Makefile create mode 100755 analyze.sh create mode 100644 code_analyzer.c diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..62f8606 --- /dev/null +++ b/Makefile @@ -0,0 +1,26 @@ +# Variables +CC = gcc +CFLAGS = -Wall -Wextra -Werror +TARGET = code_analyzer +SCRIPT = analyze.sh +INSTALL_DIR = /usr/local/bin + +# Default target +all: $(TARGET) + +# Compile the C program +$(TARGET): code_analyzer.c + $(CC) $(CFLAGS) -o $(TARGET) code_analyzer.c + +# Install the script and binary +install: $(TARGET) $(SCRIPT) + sudo cp $(TARGET) $(INSTALL_DIR)/$(TARGET) + sudo cp $(SCRIPT) $(INSTALL_DIR)/$(SCRIPT) + sudo chmod +x $(INSTALL_DIR)/$(SCRIPT) + +# Clean up the binary +clean: + rm -f $(TARGET) + +# Phony targets +.PHONY: all install clean diff --git a/analyze.sh b/analyze.sh new file mode 100755 index 0000000..03c2430 --- /dev/null +++ b/analyze.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +if [ $# -lt 2 ]; then + echo "Usage: $0 [args] " + exit 1 +fi + +/usr/local/bin/code_analyzer "$@" diff --git a/code_analyzer.c b/code_analyzer.c new file mode 100644 index 0000000..30416bd --- /dev/null +++ b/code_analyzer.c @@ -0,0 +1,200 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Function to get the CPU usage of a process +double get_cpu_usage(int pid) { + char path[40]; + FILE *file; + sprintf(path, "/proc/%d/stat", pid); + file = fopen(path, "r"); + if (!file) return -1; + + long unsigned int utime, stime, cutime, cstime; + double total_time; + long unsigned int starttime; + unsigned long int total_jiffies; + + fscanf(file, "%*d %*s %*c %*d %*d %*d %*d %*d %*u %*u %*u %*u %*u %*u %*u %lu %lu %lu %lu %*d %*d %*d %*d %lu", + &utime, &stime, &cutime, &cstime, &starttime); + fclose(file); + + total_time = (double) (utime + stime + cutime + cstime); + total_jiffies = sysconf(_SC_CLK_TCK); + return total_time / total_jiffies; +} + +// Function to get the memory usage of a process +long get_memory_usage(int pid) { + char path[40], line[100]; + FILE *file; + sprintf(path, "/proc/%d/status", pid); + file = fopen(path, "r"); + if (!file) return -1; + + long memory = -1; + while (fgets(line, 100, file)) { + if (strncmp(line, "VmRSS:", 6) == 0) { + sscanf(line + 6, "%ld", &memory); + break; + } + } + fclose(file); + return memory; +} + +// Function to get disk usage +void get_disk_usage(const char *path, long *total, long *free) { + struct statvfs stat; + if (statvfs(path, &stat) != 0) { + *total = -1; + *free = -1; + return; + } + *total = stat.f_blocks * stat.f_frsize; + *free = stat.f_bfree * stat.f_frsize; +} + +// Function to get disk I/O usage +void get_disk_io_usage(int pid, long *read_bytes, long *write_bytes) { + char path[40], line[100]; + FILE *file; + sprintf(path, "/proc/%d/io", pid); + file = fopen(path, "r"); + if (!file) { + *read_bytes = -1; + *write_bytes = -1; + return; + } + + while (fgets(line, 100, file)) { + if (strncmp(line, "read_bytes:", 11) == 0) { + sscanf(line + 11, "%ld", read_bytes); + } else if (strncmp(line, "write_bytes:", 12) == 0) { + sscanf(line + 12, "%ld", write_bytes); + } + } + fclose(file); +} + +// Function to get network usage +void get_network_usage(long *rx_bytes, long *tx_bytes) { + FILE *file; + char line[256]; + *rx_bytes = 0; + *tx_bytes = 0; + + file = fopen("/proc/net/dev", "r"); + if (!file) return; + + // Skip the first two lines + fgets(line, sizeof(line), file); + fgets(line, sizeof(line), file); + + while (fgets(line, sizeof(line), file)) { + char iface[32]; + long rx, tx; + sscanf(line, "%s %ld %*d %*d %*d %*d %*d %*d %*d %ld", iface, &rx, &tx); + *rx_bytes += rx; + *tx_bytes += tx; + } + fclose(file); +} + +// Function to run a command and analyze its usage for a given duration +void analyze_command(char *command[], int duration) { + pid_t pid = fork(); + if (pid == 0) { + // Child process: Execute the command + execvp(command[0], command); + perror("execvp"); + exit(1); + } else if (pid > 0) { + // Parent process: Monitor the child process + double start_cpu_time = get_cpu_usage(pid); + long start_rx_bytes, start_tx_bytes; + get_network_usage(&start_rx_bytes, &start_tx_bytes); + + long total_memory_usage = 0; + long total_read_bytes = 0, total_write_bytes = 0; + int sample_count = 0; + + time_t start = time(NULL); + while (time(NULL) - start < duration) { + long memory_usage = get_memory_usage(pid); + long read_bytes, write_bytes; + get_disk_io_usage(pid, &read_bytes, &write_bytes); + + if (memory_usage < 0 || read_bytes < 0 || write_bytes < 0) { + fprintf(stderr, "Error: Could not retrieve information for PID %d\n", pid); + break; + } + + total_memory_usage += memory_usage; + total_read_bytes = read_bytes; // Update to reflect actual read bytes + total_write_bytes = write_bytes; // Update to reflect actual write bytes + sample_count++; + + sleep(1); + } + + double end_cpu_time = get_cpu_usage(pid); + long end_rx_bytes, end_tx_bytes; + get_network_usage(&end_rx_bytes, &end_tx_bytes); + + kill(pid, SIGKILL); // Terminate the process after the duration + waitpid(pid, NULL, 0); // Wait for the child process to finish + + double cpu_time_diff = end_cpu_time - start_cpu_time; + long avg_memory_usage = total_memory_usage / sample_count; + long total_rx_bytes = end_rx_bytes - start_rx_bytes; + long total_tx_bytes = end_tx_bytes - start_tx_bytes; + + int num_cores = sysconf(_SC_NPROCESSORS_ONLN); + double elapsed_time = duration; + double cpu_usage_percentage = (cpu_time_diff / elapsed_time) * 100.0 * num_cores; + + long disk_total, disk_free; + get_disk_usage("/", &disk_total, &disk_free); + + printf("Command: %s\n", command[0]); + printf("CPU Usage: %.2f%%\n", cpu_usage_percentage); + printf("Average Memory Usage: %ld kB\n", avg_memory_usage); + printf("Disk Read Bytes: %ld\n", total_read_bytes); + printf("Disk Write Bytes: %ld\n", total_write_bytes); + printf("Network Received Bytes: %ld\n", total_rx_bytes); + printf("Network Transmitted Bytes: %ld\n", total_tx_bytes); + printf("Disk Total: %ld bytes\n", disk_total); + printf("Disk Free: %ld bytes\n", disk_free); + } else { + perror("fork"); + exit(1); + } +} + +int main(int argc, char *argv[]) { + if (argc < 3) { + fprintf(stderr, "Usage: %s [args] \n", argv[0]); + return 1; + } + + int duration = atoi(argv[argc - 1]); // The last argument is the duration + argv[argc - 1] = NULL; // Remove the duration from the command arguments + + analyze_command(argv + 1, duration); + + return 0; +}