Selaa lähdekoodia

Add a /bin/top program for process table monitoring.

It automagically computes %CPU usage based on the number of times a process
has been scheduled between samples. The colonel task is used as idle timer.
This is pretty cool. :^)
Andreas Kling 6 vuotta sitten
vanhempi
commit
c0cffe1134
8 muutettua tiedostoa jossa 156 lisäystä ja 4 poistoa
  1. 8 4
      Kernel/ProcFS.cpp
  2. 5 0
      Kernel/Scheduler.cpp
  3. 1 0
      Kernel/Scheduler.h
  4. 1 0
      Kernel/sync.sh
  5. 1 0
      LibC/inttypes.h
  6. 1 0
      Userland/.gitignore
  7. 5 0
      Userland/Makefile
  8. 134 0
      Userland/top.cpp

+ 8 - 4
Kernel/ProcFS.cpp

@@ -7,6 +7,7 @@
 #include "i386.h"
 #include "i386.h"
 #include "KSyms.h"
 #include "KSyms.h"
 #include "Console.h"
 #include "Console.h"
+#include "Scheduler.h"
 #include <AK/StringBuilder.h>
 #include <AK/StringBuilder.h>
 #include <LibC/errno_numbers.h>
 #include <LibC/errno_numbers.h>
 
 
@@ -486,9 +487,10 @@ ByteBuffer procfs$all(InodeIdentifier)
     InterruptDisabler disabler;
     InterruptDisabler disabler;
     auto processes = Process::all_processes();
     auto processes = Process::all_processes();
     StringBuilder builder;
     StringBuilder builder;
-    for (auto* process : processes) {
-        builder.appendf("%u,%u,%u,%u,%u,%u,%s,%u,%u,%u,%s,%s,%u,%u,%u\n",
+    auto build_process_line = [&builder] (Process* process) {
+        builder.appendf("%u,%u,%u,%u,%u,%u,%u,%s,%u,%u,%s,%s,%u,%u,%u\n",
             process->pid(),
             process->pid(),
+            process->times_scheduled(),
             process->tty() ? process->tty()->pgid() : 0,
             process->tty() ? process->tty()->pgid() : 0,
             process->pgid(),
             process->pgid(),
             process->sid(),
             process->sid(),
@@ -496,7 +498,6 @@ ByteBuffer procfs$all(InodeIdentifier)
             process->gid(),
             process->gid(),
             to_string(process->state()),
             to_string(process->state()),
             process->ppid(),
             process->ppid(),
-            process->times_scheduled(),
             process->number_of_open_file_descriptors(),
             process->number_of_open_file_descriptors(),
             process->tty() ? process->tty()->tty_name().characters() : "notty",
             process->tty() ? process->tty()->tty_name().characters() : "notty",
             process->name().characters(),
             process->name().characters(),
@@ -504,7 +505,10 @@ ByteBuffer procfs$all(InodeIdentifier)
             process->amount_resident(),
             process->amount_resident(),
             process->amount_shared()
             process->amount_shared()
         );
         );
-    }
+    };
+    build_process_line(Scheduler::colonel());
+    for (auto* process : processes)
+        build_process_line(process);
     return builder.to_byte_buffer();
     return builder.to_byte_buffer();
 }
 }
 
 

+ 5 - 0
Kernel/Scheduler.cpp

@@ -303,6 +303,11 @@ void Scheduler::prepare_to_modify_tss(Process& process)
         load_task_register(s_redirection.selector);
         load_task_register(s_redirection.selector);
 }
 }
 
 
+Process* Scheduler::colonel()
+{
+    return s_colonel_process;
+}
+
 void Scheduler::initialize()
 void Scheduler::initialize()
 {
 {
     memset(&s_redirection, 0, sizeof(s_redirection));
     memset(&s_redirection, 0, sizeof(s_redirection));

+ 1 - 0
Kernel/Scheduler.h

@@ -18,6 +18,7 @@ public:
     static bool yield();
     static bool yield();
     static bool context_switch(Process&);
     static bool context_switch(Process&);
     static void prepare_to_modify_tss(Process&);
     static void prepare_to_modify_tss(Process&);
+    static Process* colonel();
 private:
 private:
     static void prepare_for_iret_to_new_process();
     static void prepare_for_iret_to_new_process();
 };
 };

+ 1 - 0
Kernel/sync.sh

@@ -50,6 +50,7 @@ cp -v ../FontEditor/FontEditor mnt/bin/FontEditor
 ln -s FontEditor mnt/bin/ff
 ln -s FontEditor mnt/bin/ff
 cp -v ../Userland/dmesg mnt/bin/dmesg
 cp -v ../Userland/dmesg mnt/bin/dmesg
 cp -v ../Userland/chmod mnt/bin/chmod
 cp -v ../Userland/chmod mnt/bin/chmod
+cp -v ../Userland/top mnt/bin/top
 sh sync-local.sh
 sh sync-local.sh
 cp -v kernel.map mnt/
 cp -v kernel.map mnt/
 ln -s dir_a mnt/dir_cur
 ln -s dir_a mnt/dir_cur

+ 1 - 0
LibC/inttypes.h

@@ -0,0 +1 @@
+#include <stdint.h>

+ 1 - 0
Userland/.gitignore

@@ -29,4 +29,5 @@ rm
 cp
 cp
 rmdir
 rmdir
 dmesg
 dmesg
+top
 chmod
 chmod

+ 5 - 0
Userland/Makefile

@@ -26,6 +26,7 @@ OBJS = \
        rmdir.o \
        rmdir.o \
        dmesg.o \
        dmesg.o \
        chmod.o \
        chmod.o \
+       top.o \
        rm.o
        rm.o
 
 
 APPS = \
 APPS = \
@@ -57,6 +58,7 @@ APPS = \
        rmdir \
        rmdir \
        dmesg \
        dmesg \
        chmod \
        chmod \
+       top \
        rm
        rm
 
 
 ARCH_FLAGS =
 ARCH_FLAGS =
@@ -164,6 +166,9 @@ rmdir: rmdir.o
 chmod: chmod.o
 chmod: chmod.o
 	$(LD) -o $@ $(LDFLAGS) $< ../LibC/LibC.a
 	$(LD) -o $@ $(LDFLAGS) $< ../LibC/LibC.a
 
 
+top: top.o
+	$(LD) -o $@ $(LDFLAGS) $< ../LibC/LibC.a
+
 .cpp.o:
 .cpp.o:
 	@echo "CXX $<"; $(CXX) $(CXXFLAGS) -o $@ -c $<
 	@echo "CXX $<"; $(CXX) $(CXXFLAGS) -o $@ -c $<
 
 

+ 134 - 0
Userland/top.cpp

@@ -0,0 +1,134 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <pwd.h>
+#include <stdlib.h>
+#include <AK/HashMap.h>
+#include <AK/AKString.h>
+#include <AK/Vector.h>
+
+static HashMap<unsigned, String>* s_usernames;
+
+struct Process {
+    pid_t pid;
+    unsigned nsched;
+    String name;
+    String state;
+    String user;
+    unsigned virt;
+    unsigned res;
+    unsigned nsched_since_prev;
+    unsigned cpu_percent;
+    unsigned cpu_percent_decimal;
+};
+
+struct Snapshot {
+    HashMap<unsigned, Process> map;
+    dword sum_nsched { 0 };
+};
+
+static Snapshot get_snapshot()
+{
+    Snapshot snapshot;
+
+    FILE* fp = fopen("/proc/all", "r");
+    if (!fp) {
+        perror("failed to open /proc/all");
+        exit(1);
+    }
+    for (;;) {
+        char buf[4096];
+        char* ptr = fgets(buf, sizeof(buf), fp);
+        if (!ptr)
+            break;
+        auto parts = String(buf, Chomp).split(',');
+        if (parts.size() < 14)
+            break;
+        bool ok;
+        pid_t pid = parts[0].to_uint(ok);
+        ASSERT(ok);
+        unsigned nsched = parts[1].to_uint(ok);
+        ASSERT(ok);
+        snapshot.sum_nsched += nsched;
+        Process process;
+        process.pid = pid;
+        process.nsched = nsched;
+        unsigned uid = parts[5].to_uint(ok);
+        ASSERT(ok);
+        process.user = s_usernames->get(uid);
+        process.state = parts[7];
+        process.name = parts[11];
+        process.virt = parts[12].to_uint(ok);
+        ASSERT(ok);
+        process.res = parts[13].to_uint(ok);
+        ASSERT(ok);
+        snapshot.map.set(pid, move(process));
+    }
+    int rc = fclose(fp);
+    ASSERT(rc == 0);
+    return snapshot;
+}
+
+int main(int, char**)
+{
+    s_usernames = new HashMap<unsigned, String>();
+    setpwent();
+    while (auto* passwd = getpwent())
+        s_usernames->set(passwd->pw_uid, passwd->pw_name);
+    endpwent();
+
+    Vector<Process*> processes;
+    auto prev = get_snapshot();
+    for (;;) {
+        auto current = get_snapshot();
+        auto sum_diff = current.sum_nsched - prev.sum_nsched;
+
+        printf("\033[3J\033[H\033[2J");
+        printf("\033[47;30m%6s  % 8s  %8s  %8s  %8s  %4s  %s\033[K\033[0m\n",
+               "PID",
+               "USER",
+               "STATE",
+               "VIRTUAL",
+               "RESIDENT",
+               "%CPU",
+               "NAME");
+        for (auto& it : current.map) {
+            pid_t pid = it.key;
+            if (pid == 0)
+                continue;
+            dword nsched_now = it.value.nsched;
+            auto jt = prev.map.find(pid);
+            if (jt == prev.map.end())
+                continue;
+            dword nsched_before = (*jt).value.nsched;
+            dword nsched_diff = nsched_now - nsched_before;
+            it.value.nsched_since_prev = nsched_diff;
+            it.value.cpu_percent = ((nsched_diff * 100)/ sum_diff);
+            it.value.cpu_percent_decimal = (((nsched_diff * 1000)/ sum_diff) % 10);
+            processes.append(&it.value);
+        }
+
+        qsort(processes.data(), processes.size(), sizeof(Process*), [] (const void* a, const void* b) -> int {
+            auto* p1 = *(const Process* const*)(a);
+            auto* p2 = *(const Process* const*)(b);
+            return p2->nsched_since_prev - p1->nsched_since_prev;
+        });
+
+        for (auto* process : processes) {
+            printf("%6d  % 8s  %8s  %8u  %8u  %2u.%1u  %s\n",
+                process->pid,
+                process->user.characters(),
+                process->state.characters(),
+                process->virt / 1024,
+                process->res / 1024,
+                process->cpu_percent,
+                process->cpu_percent_decimal,
+                process->name.characters()
+            );
+        }
+        processes.clear_with_capacity();
+        prev = move(current);
+        sleep(1);
+    }
+    return 0;
+}