diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 00000000..34811c65 Binary files /dev/null and b/.DS_Store differ diff --git a/CMakeLists.txt b/CMakeLists.txt index 2702e965..ba05830e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,9 +1,14 @@ -cmake_minimum_required(VERSION 2.6) +cmake_minimum_required(VERSION 2.8.12) project(monitor) -set(CURSES_NEED_NCURSES TRUE) -find_package(Curses REQUIRED) -include_directories(${CURSES_INCLUDE_DIRS}) +# set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -W -Wextra -Wall -Werror -ansi -pedantic -pthread --std=c++11") +include_directories(includes libs/c++ /opt/homebrew/opt/ncurses/include) +link_directories(/opt/homebrew/opt/ncurses/lib) +link_libraries(ncurses) + +# set(CURSES_NEED_NCURSES TRUE) +# find_package(ncurses REQUIRED) +# include_directories(${CURSES_INCLUDE_DIRS}) include_directories(include) file(GLOB SOURCES "src/*.cpp") diff --git a/Makefile b/Makefile index 340d4230..ffa2d86b 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,11 @@ +CXXFLAGS += -W -Wextra -Wall -Werror -ansi -pedantic +CXXFLAGS += -pthread --std=c++11 -Iincludes -Ilibs/c++ -I/usr/local/opt/ncurses/include +LDFLAGS += -lncurses -L/usr/local/opt/ncurses/lib + +# existing Makefile targets go here + .PHONY: all -all: format test build +all: format build .PHONY: format format: @@ -22,3 +28,4 @@ debug: .PHONY: clean clean: rm -rf build + diff --git a/include/linux_parser.h b/include/linux_parser.h index 988ac069..58569c0e 100644 --- a/include/linux_parser.h +++ b/include/linux_parser.h @@ -41,6 +41,7 @@ enum CPUStates { kGuestNice_ }; std::vector CpuUtilization(); +float cpuProcessUtilization(int pid); long Jiffies(); long ActiveJiffies(); long ActiveJiffies(int pid); diff --git a/include/process.h b/include/process.h index 6b7d1c22..14ceeffb 100644 --- a/include/process.h +++ b/include/process.h @@ -8,6 +8,7 @@ It contains relevant attributes as shown below */ class Process { public: + Process(int pid) : pid_(pid){}; int Pid(); // TODO: See src/process.cpp std::string User(); // TODO: See src/process.cpp std::string Command(); // TODO: See src/process.cpp @@ -18,6 +19,12 @@ class Process { // TODO: Declare any necessary private members private: + int pid_; + std::string user_; + std::string command_; + float cpuUtilization_; + std::string ram_; + long int upTime_; }; #endif \ No newline at end of file diff --git a/include/processor.h b/include/processor.h index 6951a659..80956d40 100644 --- a/include/processor.h +++ b/include/processor.h @@ -3,10 +3,13 @@ class Processor { public: + Processor() : prevTotal_(0), prevIdle_(0){}; float Utilization(); // TODO: See src/processor.cpp // TODO: Declare any necessary private members private: + float prevTotal_; + float prevIdle_; }; -#endif \ No newline at end of file +#endif diff --git a/src/format.cpp b/src/format.cpp index 8f8f854b..34c37d69 100644 --- a/src/format.cpp +++ b/src/format.cpp @@ -1,11 +1,19 @@ -#include - #include "format.h" +#include + using std::string; -// TODO: Complete this helper function +// DONE: Complete this helper function // INPUT: Long int measuring seconds // OUTPUT: HH:MM:SS -// REMOVE: [[maybe_unused]] once you define the function -string Format::ElapsedTime(long seconds[[maybe_unused]]) { return string(); } \ No newline at end of file +string Format::ElapsedTime(long seconds) { + string timeFormat; + int hours = seconds / 3600; + int minutes = (seconds % 3600) / 60; + int sec = seconds % 60; + timeFormat = std::to_string(hours) + ":" + std::to_string(minutes) + ":" + + std::to_string(sec); + + return timeFormat; +} \ No newline at end of file diff --git a/src/linux_parser.cpp b/src/linux_parser.cpp index 75cfa5d7..35e9b861 100644 --- a/src/linux_parser.cpp +++ b/src/linux_parser.cpp @@ -1,10 +1,13 @@ +#include "linux_parser.h" + #include #include + +#include +#include +#include #include #include - -#include "linux_parser.h" - using std::stof; using std::string; using std::to_string; @@ -57,8 +60,13 @@ vector LinuxParser::Pids() { // Is every character of the name a digit? string filename(file->d_name); if (std::all_of(filename.begin(), filename.end(), isdigit)) { - int pid = stoi(filename); - pids.push_back(pid); + long long int pid0; + try { + pid0 = stoi(filename); + } catch (std::out_of_range& e) { + std::cerr << "Number is out of range: " << e.what() << '\n'; + } + pids.push_back(pid0); } } } @@ -66,50 +74,308 @@ vector LinuxParser::Pids() { return pids; } -// TODO: Read and return the system memory utilization -float LinuxParser::MemoryUtilization() { return 0.0; } +// DONE: Read and return the system memory utilization +// Memory Utilization = (Total Memory - Available Memory) / Total Memory +// Available Memory = Free Memory + Buffers + Cached +float LinuxParser::MemoryUtilization() { + std::ifstream filestream(kProcDirectory + kMeminfoFilename); + std::string line; + if (!filestream.is_open()) { + std::cerr << "Failed to open file MemoryUtilization: " + << kProcDirectory + kMeminfoFilename << std::endl; + } + std::string currentKey; + std::string currentValue; + float MemUtilization; + float MemAvailable; + std::vector memInfo; + while (getline(filestream, line)) { + std::istringstream iss(line); + iss >> currentKey >> currentValue; + if (currentKey == "MemTotal:") { + float val = stof(currentValue) / 1024 / 1024; + memInfo.push_back(val); + } + if (currentKey == "MemFree:") { + float val = stof(currentValue) / 1024 / 1024; + memInfo.push_back(val); + } + if (currentKey == "Buffers:") { + float val = stof(currentValue) / 1024 / 1024; + memInfo.push_back(val); + } + if (currentKey == "Cached:") { + float val = stof(currentValue) / 1024 / 1024; + memInfo.push_back(val); + } + } + MemAvailable = memInfo[1] + memInfo[2] + memInfo[3]; + MemUtilization = (((memInfo[0]) - (MemAvailable)) / (memInfo[0])); + + return MemUtilization; +} -// TODO: Read and return the system uptime -long LinuxParser::UpTime() { return 0; } +// DONE: Read and return the system uptime +long LinuxParser::UpTime() { + std::ifstream filestream(kProcDirectory + kUptimeFilename); + std::string line; + long uptime = 0; + if (!filestream.is_open()) { + std::cerr << "Failed to open file UpTime: " + << kProcDirectory + kUptimeFilename << std::endl; + } else { + + while (getline(filestream, line)) { + std::istringstream iss(line); + // read info + std::string currentValue; + iss >> currentValue; + // uptime = std::stoi(currentValue); + try { + uptime = std::stoi(currentValue); + } catch (std::out_of_range& e) { + std::cerr << "Number is out of range: " << e.what() << '\n'; + } + break; + } + filestream.close();} + return uptime; +} // TODO: Read and return the number of jiffies for the system -long LinuxParser::Jiffies() { return 0; } +long LinuxParser::Jiffies() { return 0.0; } -// TODO: Read and return the number of active jiffies for a PID -// REMOVE: [[maybe_unused]] once you define the function -long LinuxParser::ActiveJiffies(int pid[[maybe_unused]]) { return 0; } +// DONE: Read and return the number of active jiffies for a PID +long LinuxParser::ActiveJiffies(int pid) { + long activeJiffies = 0; + std::ifstream filestream(kProcDirectory + std::to_string(pid) + + kStatFilename); + if (filestream.is_open()) { + string line; + if (std::getline(filestream, line)) { + std::istringstream linestream(line); + std::istream_iterator streamIterator(linestream); + std::istream_iterator endIterator; + // Skip the fields until the utime field + std::advance(streamIterator, 12); + // Read the utime field + long utime = std::stol(*streamIterator++); + // Read the stime field + long stime = std::stol(*streamIterator++); + activeJiffies = utime + stime; + } + } + filestream.close(); + return activeJiffies; +} + +float LinuxParser::cpuProcessUtilization(int pid) { + long total_time; + long seconds; + float cpuUsage; + long uptime = LinuxParser::UpTime(); + long starttimePerHz = LinuxParser::UpTime(pid); + // Next we get the total elapsed time in seconds since the process started: + total_time = LinuxParser::ActiveJiffies(pid); + seconds = uptime - starttimePerHz; + // Next we get the total elapsed time in seconds since the process started: + cpuUsage = (float)100 * (total_time / sysconf(_SC_CLK_TCK)) / seconds; + return cpuUsage; +} // TODO: Read and return the number of active jiffies for the system -long LinuxParser::ActiveJiffies() { return 0; } +long LinuxParser::ActiveJiffies() { return 0.0; } // TODO: Read and return the number of idle jiffies for the system -long LinuxParser::IdleJiffies() { return 0; } +long LinuxParser::IdleJiffies() { return 0.0; } -// TODO: Read and return CPU utilization -vector LinuxParser::CpuUtilization() { return {}; } +// DONE: Read and return CPU utilization +vector LinuxParser::CpuUtilization() { + vector cpuUtilization; -// TODO: Read and return the total number of processes -int LinuxParser::TotalProcesses() { return 0; } + std::ifstream filestream(kProcDirectory + kStatFilename); + if (filestream.is_open()) { + string line; + if (std::getline(filestream, line)) { + std::istringstream linestream(line); + string value; + while (linestream >> value) { + cpuUtilization.push_back(value); + } + } + } -// TODO: Read and return the number of running processes -int LinuxParser::RunningProcesses() { return 0; } + filestream.close(); + return cpuUtilization; +} -// TODO: Read and return the command associated with a process -// REMOVE: [[maybe_unused]] once you define the function -string LinuxParser::Command(int pid[[maybe_unused]]) { return string(); } +// DONE: Read and return the total number of processes +int LinuxParser::TotalProcesses() { + std::ifstream filestream(kProcDirectory + kStatFilename); + std::string line; + if (!filestream.is_open()) { + std::cerr << "Failed to open file TotalProcesses: " + << kProcDirectory + kStatFilename << std::endl; + } + std::string currentKey; + std::string currentValue; + long long int totalProcesses = 0; + while (getline(filestream, line)) { + std::istringstream iss(line); + // read info + iss >> currentKey >> currentValue; + if (currentKey == "processes") { + // totalProcesses = std::stoi(currentValue); + try { + totalProcesses = std::stoi(currentValue); + } catch (std::out_of_range& e) { + std::cerr << "Number is out of range: " << e.what() << '\n'; + } + break; + } + } -// TODO: Read and return the memory used by a process -// REMOVE: [[maybe_unused]] once you define the function -string LinuxParser::Ram(int pid[[maybe_unused]]) { return string(); } + return totalProcesses; +} + +// DONE: Read and return the number of running processes +int LinuxParser::RunningProcesses() { + std::ifstream filestream(kProcDirectory + kStatFilename); + std::string line; + if (!filestream.is_open()) { + std::cerr << "Failed to open file RunningProcesses: " + << kProcDirectory + kStatFilename << std::endl; + } + std::string currentKey; + std::string currentValue; + long long int runningProcesses; + while (getline(filestream, line)) { + std::istringstream iss(line); + // read info + iss >> currentKey >> currentValue; + if (currentKey == "procs_running") { + // runningProcesses = std::stoi(currentValue); + try { + runningProcesses = std::stoi(currentValue); + } catch (std::out_of_range& e) { + std::cerr << "Number is out of range: " << e.what() << '\n'; + } + } + } + + return runningProcesses; +} + +// DONE: Read and return the command associated with a process +string LinuxParser::Command(int pid) { + std::string command; + std::ifstream filestream(kProcDirectory + std::to_string(pid) + + kCmdlineFilename); + if (filestream.is_open()) { + std::getline(filestream, command); + filestream.close(); + } + + return command; +} + +// DONE: Read and return the memory used by a process +string LinuxParser::Ram(int pid) { + std::string line; + std::ifstream filestream(kProcDirectory + std::to_string(pid) + + kStatusFilename); + if (!filestream.is_open()) { + std::cerr << "Failed to open file Ram: " + << kProcDirectory + std::to_string(pid) + kStatusFilename + << std::endl; + } + std::string currentKey; + std::string currentValue; + std::string ram; + while (std::getline(filestream, line)) { + std::istringstream iss(line); + while (iss >> currentKey >> currentValue) { + if (currentKey == "VmSize:") { + ram = to_string((int)std::floor(stof(currentValue) / 1024)); + } + break; + } + } -// TODO: Read and return the user ID associated with a process -// REMOVE: [[maybe_unused]] once you define the function -string LinuxParser::Uid(int pid[[maybe_unused]]) { return string(); } + return ram; +} -// TODO: Read and return the user associated with a process -// REMOVE: [[maybe_unused]] once you define the function -string LinuxParser::User(int pid[[maybe_unused]]) { return string(); } +// DONE: Read and return the user ID associated with a process +string LinuxParser::Uid(int pid) { + std::string line; + std::ifstream filestream(kProcDirectory + std::to_string(pid) + + kStatusFilename); + if (!filestream.is_open()) { + std::cerr << "Failed to open file Uid: " + << kProcDirectory + std::to_string(pid) + kStatusFilename + << std::endl; + } + std::string currentKey; + std::string currentValue; + std::string uid; + while (std::getline(filestream, line)) { + std::istringstream iss(line); + iss >> currentKey; + if (currentKey == "Uid:") { + iss >> currentValue; + uid = currentValue; + break; + } + } + + return uid; +} + +// DONE: Read and return the user associated with a process +string LinuxParser::User(int pid) { + std::string uid = Uid(pid); + std::string name; + std::ifstream filestream(kPasswordPath); + if (!filestream.is_open()) { + std::cerr << "Failed to open file User: " << kPasswordPath << std::endl; + } + std::string temp; + std::string user; + std::string x; + std::string line; + std::string id; -// TODO: Read and return the uptime of a process -// REMOVE: [[maybe_unused]] once you define the function -long LinuxParser::UpTime(int pid[[maybe_unused]]) { return 0; } + while (std::getline(filestream, line)) { + std::replace(line.begin(), line.end(), ':', ' '); + std::istringstream iss(line); + iss >> user >> x >> id; + if (id == uid) { + name = user; + break; + } + } + + return name; +} + +// DONE: Read and return the uptime of a process +long LinuxParser::UpTime(int pid) { + long starttime = 0; + std::ifstream filestream(kProcDirectory + std::to_string(pid) + + kStatFilename); + if (!filestream.is_open()) { + std::cerr << "Failed to open file UpTime: " + << kProcDirectory + std::to_string(pid) + kStatFilename + << std::endl; + } + std::string line; + std::string cuurentValue; + vector values; + std::getline(filestream, line); + std::istringstream iss(line); + while (iss >> cuurentValue) { + values.push_back(cuurentValue); + } + starttime = stol(values[21]) / sysconf(_SC_CLK_TCK); + return starttime; +} diff --git a/src/ncurses_display.cpp b/src/ncurses_display.cpp index fdff8893..6ffc7535 100644 --- a/src/ncurses_display.cpp +++ b/src/ncurses_display.cpp @@ -1,11 +1,13 @@ +#include "ncurses_display.h" + #include +#include #include #include #include #include #include "format.h" -#include "ncurses_display.h" #include "system.h" using std::string; diff --git a/src/process.cpp b/src/process.cpp index 82119905..5d23e90c 100644 --- a/src/process.cpp +++ b/src/process.cpp @@ -1,33 +1,40 @@ +#include "process.h" + #include + #include #include #include #include -#include "process.h" +#include "linux_parser.h" using std::string; using std::to_string; using std::vector; // TODO: Return this process's ID -int Process::Pid() { return 0; } +int Process::Pid() { return pid_; } // TODO: Return this process's CPU utilization -float Process::CpuUtilization() { return 0; } +float Process::CpuUtilization() { + return cpuUtilization_ = LinuxParser::cpuProcessUtilization(pid_); +} // TODO: Return the command that generated this process -string Process::Command() { return string(); } +string Process::Command() { return command_ = LinuxParser::Command(pid_); } // TODO: Return this process's memory utilization -string Process::Ram() { return string(); } +string Process::Ram() { return ram_ = LinuxParser::Ram(pid_); } // TODO: Return the user (name) that generated this process -string Process::User() { return string(); } +string Process::User() { return user_ = LinuxParser::User(pid_); } // TODO: Return the age of this process (in seconds) -long int Process::UpTime() { return 0; } +long int Process::UpTime() { return upTime_ = LinuxParser::UpTime(pid_); } // TODO: Overload the "less than" comparison operator for Process objects // REMOVE: [[maybe_unused]] once you define the function -bool Process::operator<(Process const& a[[maybe_unused]]) const { return true; } \ No newline at end of file +bool Process::operator<(Process const& a [[maybe_unused]]) const { + return true; +} \ No newline at end of file diff --git a/src/processor.cpp b/src/processor.cpp index 91662895..d7fecd55 100644 --- a/src/processor.cpp +++ b/src/processor.cpp @@ -1,4 +1,41 @@ #include "processor.h" -// TODO: Return the aggregate CPU utilization -float Processor::Utilization() { return 0.0; } \ No newline at end of file +#include "linux_parser.h" + +float Processor::Utilization() { + std::vector currentUtilization = LinuxParser::CpuUtilization(); + if (currentUtilization.size() < 10) { + return 0.0; + } + std::string user = currentUtilization[0]; + float nice = std::stoi(currentUtilization[1]); + float system = std::stoi(currentUtilization[2]); + float idle = std::stoi(currentUtilization[3]); + float iowait = 0.0; // std::stoi(currentUtilization[4]); + float irq = std::stoi(currentUtilization[5]); + float softirq = std::stoi(currentUtilization[6]); + float steal = std::stoi(currentUtilization[7]); + + // try { + // int num = std::stoi(iowait); + // } catch (std::out_of_range& e) { + // std::cerr << "Number is out of range: " << e.what() << '\n'; + // } + + float totalTime = nice + system + idle + iowait + irq + softirq + steal; + float idleTime = idle + iowait; + + float deltaTimeTotal = totalTime - prevTotal_; + float deltaTimeIdle = idleTime - prevIdle_; + + float cpuUtilization; + if (deltaTimeTotal != 0) { + cpuUtilization = (float)(deltaTimeTotal - deltaTimeIdle) / deltaTimeTotal; + } else { + cpuUtilization = 0.0; + } + prevTotal_ = totalTime; + prevIdle_ = idleTime; + + return cpuUtilization; +} \ No newline at end of file diff --git a/src/system.cpp b/src/system.cpp index b15d0116..5e40c524 100644 --- a/src/system.cpp +++ b/src/system.cpp @@ -1,38 +1,49 @@ +#include "system.h" + #include + #include #include #include #include +#include "linux_parser.h" #include "process.h" #include "processor.h" -#include "system.h" using std::set; using std::size_t; using std::string; using std::vector; -// TODO: Return the system's CPU +// DONE: Return the system's CPU Processor& System::Cpu() { return cpu_; } -// TODO: Return a container composed of the system's processes -vector& System::Processes() { return processes_; } +// DONE: Return a container composed of the system's processes +vector& System::Processes() { + processes_.clear(); + vector pids = LinuxParser::Pids(); + for (std::vector::iterator it = pids.begin(); it != pids.end(); it++) { + int pidIndex = *it; + processes_.push_back(Process(pidIndex)); + }; + return processes_; +} -// TODO: Return the system's kernel identifier (string) -std::string System::Kernel() { return string(); } +// DONE: Return the system's kernel identifier (string) +std::string System::Kernel() { return LinuxParser::Kernel(); } -// TODO: Return the system's memory utilization -float System::MemoryUtilization() { return 0.0; } +// DONE: Return the system's memory utilization +float System::MemoryUtilization() { return LinuxParser::MemoryUtilization(); } -// TODO: Return the operating system name -std::string System::OperatingSystem() { return string(); } +// DONE: Return the operating system name +std::string System::OperatingSystem() { return LinuxParser::OperatingSystem(); } -// TODO: Return the number of processes actively running on the system -int System::RunningProcesses() { return 0; } +// DONE: Return the number of processes actively running on the system +int System::RunningProcesses() { return LinuxParser::RunningProcesses(); } -// TODO: Return the total number of processes on the system -int System::TotalProcesses() { return 0; } +// DONE: Return the total number of processes on the system +int System::TotalProcesses() { return LinuxParser::TotalProcesses(); } -// TODO: Return the number of seconds since the system started running -long int System::UpTime() { return 0; } \ No newline at end of file +// DONE: Return the number of seconds since the system started running +long int System::UpTime() { return LinuxParser::UpTime(); } \ No newline at end of file