initial commit

This commit is contained in:
klein panic
2024-09-29 02:34:44 -04:00
commit 84e64f6ad1
3 changed files with 234 additions and 0 deletions

26
Makefile Normal file
View File

@@ -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

8
analyze.sh Executable file
View File

@@ -0,0 +1,8 @@
#!/bin/bash
if [ $# -lt 2 ]; then
echo "Usage: $0 <command> [args] <duration>"
exit 1
fi
/usr/local/bin/code_analyzer "$@"

200
code_analyzer.c Normal file
View File

@@ -0,0 +1,200 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <time.h>
#include <errno.h>
#include <sys/statvfs.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/hdreg.h>
#include <net/if.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
// 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 <command> [args] <duration>\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;
}