diff options
-rw-r--r-- | Applications/SystemMonitor/ProcessModel.cpp | 144 | ||||
-rw-r--r-- | Applications/SystemMonitor/ProcessModel.h | 32 | ||||
-rw-r--r-- | DevTools/HackStudio/ProcessStateWidget.cpp | 4 | ||||
-rw-r--r-- | Kernel/FileSystem/ProcFS.cpp | 14 | ||||
-rw-r--r-- | Libraries/LibCore/CProcessStatisticsReader.cpp | 16 | ||||
-rw-r--r-- | Libraries/LibCore/CProcessStatisticsReader.h | 17 | ||||
-rw-r--r-- | Servers/WindowServer/WSCPUMonitor.cpp | 10 | ||||
-rw-r--r-- | Userland/ps.cpp | 4 | ||||
-rw-r--r-- | Userland/top.cpp | 125 |
9 files changed, 243 insertions, 123 deletions
diff --git a/Applications/SystemMonitor/ProcessModel.cpp b/Applications/SystemMonitor/ProcessModel.cpp index ec79fa0c99..2445976ade 100644 --- a/Applications/SystemMonitor/ProcessModel.cpp +++ b/Applications/SystemMonitor/ProcessModel.cpp @@ -47,6 +47,8 @@ String ProcessModel::column_name(int column) const return ""; case Column::PID: return "PID"; + case Column::TID: + return "TID"; case Column::State: return "State"; case Column::User: @@ -81,6 +83,8 @@ GModel::ColumnMetadata ProcessModel::column_metadata(int column) const return { 16, TextAlignment::CenterLeft }; case Column::PID: return { 32, TextAlignment::CenterRight }; + case Column::TID: + return { 32, TextAlignment::CenterRight }; case Column::State: return { 75, TextAlignment::CenterLeft }; case Column::Priority: @@ -117,47 +121,49 @@ GVariant ProcessModel::data(const GModelIndex& index, Role role) const { ASSERT(is_valid(index)); - auto it = m_processes.find(m_pids[index.row()]); - auto& process = *(*it).value; + auto it = m_threads.find(m_pids[index.row()]); + auto& thread = *(*it).value; if (role == Role::Sort) { switch (index.column()) { case Column::Icon: return 0; case Column::PID: - return process.current_state.pid; + return thread.current_state.pid; + case Column::TID: + return thread.current_state.tid; case Column::State: - return process.current_state.state; + return thread.current_state.state; case Column::User: - return process.current_state.user; + return thread.current_state.user; case Column::Priority: - if (process.current_state.priority == "Idle") + if (thread.current_state.priority == "Idle") return 0; - if (process.current_state.priority == "Low") + if (thread.current_state.priority == "Low") return 1; - if (process.current_state.priority == "Normal") + if (thread.current_state.priority == "Normal") return 2; - if (process.current_state.priority == "High") + if (thread.current_state.priority == "High") return 3; ASSERT_NOT_REACHED(); return 3; case Column::Virtual: - return (int)process.current_state.amount_virtual; + return (int)thread.current_state.amount_virtual; case Column::Physical: - return (int)process.current_state.amount_resident; + return (int)thread.current_state.amount_resident; case Column::CPU: - return process.current_state.cpu_percent; + return thread.current_state.cpu_percent; case Column::Name: - return process.current_state.name; + return thread.current_state.name; // FIXME: GVariant with unsigned? case Column::Syscalls: - return (int)process.current_state.syscall_count; + return (int)thread.current_state.syscall_count; case Column::InodeFaults: - return (int)process.current_state.inode_faults; + return (int)thread.current_state.inode_faults; case Column::ZeroFaults: - return (int)process.current_state.zero_faults; + return (int)thread.current_state.zero_faults; case Column::CowFaults: - return (int)process.current_state.cow_faults; + return (int)thread.current_state.cow_faults; } ASSERT_NOT_REACHED(); return {}; @@ -166,8 +172,8 @@ GVariant ProcessModel::data(const GModelIndex& index, Role role) const if (role == Role::Display) { switch (index.column()) { case Column::Icon: - if (process.current_state.icon_id != -1) { - auto icon_buffer = SharedBuffer::create_from_shared_buffer_id(process.current_state.icon_id); + if (thread.current_state.icon_id != -1) { + auto icon_buffer = SharedBuffer::create_from_shared_buffer_id(thread.current_state.icon_id); if (icon_buffer) { auto icon_bitmap = GraphicsBitmap::create_with_shared_buffer(GraphicsBitmap::Format::RGBA32, *icon_buffer, { 16, 16 }); if (icon_bitmap) @@ -176,38 +182,40 @@ GVariant ProcessModel::data(const GModelIndex& index, Role role) const } return *m_generic_process_icon; case Column::PID: - return process.current_state.pid; + return thread.current_state.pid; + case Column::TID: + return thread.current_state.tid; case Column::State: - return process.current_state.state; + return thread.current_state.state; case Column::User: - return process.current_state.user; + return thread.current_state.user; case Column::Priority: - if (process.current_state.priority == "Idle") + if (thread.current_state.priority == "Idle") return String::empty(); - if (process.current_state.priority == "High") + if (thread.current_state.priority == "High") return *m_high_priority_icon; - if (process.current_state.priority == "Low") + if (thread.current_state.priority == "Low") return *m_low_priority_icon; - if (process.current_state.priority == "Normal") + if (thread.current_state.priority == "Normal") return *m_normal_priority_icon; - return process.current_state.priority; + return thread.current_state.priority; case Column::Virtual: - return pretty_byte_size(process.current_state.amount_virtual); + return pretty_byte_size(thread.current_state.amount_virtual); case Column::Physical: - return pretty_byte_size(process.current_state.amount_resident); + return pretty_byte_size(thread.current_state.amount_resident); case Column::CPU: - return process.current_state.cpu_percent; + return thread.current_state.cpu_percent; case Column::Name: - return process.current_state.name; + return thread.current_state.name; // FIXME: It's weird that GVariant doesn't support unsigned ints. Should it? case Column::Syscalls: - return (int)process.current_state.syscall_count; + return (int)thread.current_state.syscall_count; case Column::InodeFaults: - return (int)process.current_state.inode_faults; + return (int)thread.current_state.inode_faults; case Column::ZeroFaults: - return (int)process.current_state.zero_faults; + return (int)thread.current_state.zero_faults; case Column::CowFaults: - return (int)process.current_state.cow_faults; + return (int)thread.current_state.cow_faults; } } @@ -219,44 +227,48 @@ void ProcessModel::update() auto all_processes = CProcessStatisticsReader::get_all(); unsigned last_sum_times_scheduled = 0; - for (auto& it : m_processes) + for (auto& it : m_threads) last_sum_times_scheduled += it.value->current_state.times_scheduled; - HashTable<pid_t> live_pids; + HashTable<PidAndTid> live_pids; unsigned sum_times_scheduled = 0; for (auto& it : all_processes) { - ProcessState state; - state.pid = it.value.pid; - state.times_scheduled = it.value.times_scheduled; - state.user = it.value.username; - state.priority = it.value.priority; - state.syscall_count = it.value.syscall_count; - state.inode_faults = it.value.inode_faults; - state.zero_faults = it.value.zero_faults; - state.cow_faults = it.value.cow_faults; - state.state = it.value.state; - state.name = it.value.name; - state.amount_virtual = it.value.amount_virtual; - state.amount_resident = it.value.amount_resident; - state.icon_id = it.value.icon_id; - sum_times_scheduled += it.value.times_scheduled; - { - auto pit = m_processes.find(it.value.pid); - if (pit == m_processes.end()) - m_processes.set(it.value.pid, make<Process>()); - } - auto pit = m_processes.find(it.value.pid); - ASSERT(pit != m_processes.end()); - (*pit).value->previous_state = (*pit).value->current_state; - (*pit).value->current_state = state; + for (auto& thread : it.value.threads) { + ThreadState state; + state.pid = it.value.pid; + state.user = it.value.username; + state.syscall_count = it.value.syscall_count; + state.inode_faults = it.value.inode_faults; + state.zero_faults = it.value.zero_faults; + state.cow_faults = it.value.cow_faults; + state.name = it.value.name; + state.amount_virtual = it.value.amount_virtual; + state.amount_resident = it.value.amount_resident; + state.icon_id = it.value.icon_id; - live_pids.set(it.value.pid); + state.tid = thread.tid; + state.times_scheduled = thread.times_scheduled; + state.priority = thread.priority; + state.state = thread.state; + sum_times_scheduled += thread.times_scheduled; + { + auto pit = m_threads.find({ it.value.pid, thread.tid }); + if (pit == m_threads.end()) + m_threads.set({ it.value.pid, thread.tid }, make<Thread>()); + } + auto pit = m_threads.find({ it.value.pid, thread.tid }); + ASSERT(pit != m_threads.end()); + (*pit).value->previous_state = (*pit).value->current_state; + (*pit).value->current_state = state; + + live_pids.set({ it.value.pid, thread.tid }); + } } m_pids.clear(); float total_cpu_percent = 0; - Vector<pid_t, 16> pids_to_remove; - for (auto& it : m_processes) { + Vector<PidAndTid, 16> pids_to_remove; + for (auto& it : m_threads) { if (!live_pids.contains(it.key)) { pids_to_remove.append(it.key); continue; @@ -264,13 +276,13 @@ void ProcessModel::update() auto& process = *it.value; u32 times_scheduled_diff = process.current_state.times_scheduled - process.previous_state.times_scheduled; process.current_state.cpu_percent = ((float)times_scheduled_diff * 100) / (float)(sum_times_scheduled - last_sum_times_scheduled); - if (it.key != 0) { + if (it.key.pid != 0) { total_cpu_percent += process.current_state.cpu_percent; m_pids.append(it.key); } } for (auto pid : pids_to_remove) - m_processes.remove(pid); + m_threads.remove(pid); if (on_new_cpu_data_point) on_new_cpu_data_point(total_cpu_percent); diff --git a/Applications/SystemMonitor/ProcessModel.h b/Applications/SystemMonitor/ProcessModel.h index fc54488583..c6365d109f 100644 --- a/Applications/SystemMonitor/ProcessModel.h +++ b/Applications/SystemMonitor/ProcessModel.h @@ -1,13 +1,22 @@ #pragma once -#include <AK/String.h> #include <AK/HashMap.h> +#include <AK/String.h> #include <AK/Vector.h> #include <LibGUI/GModel.h> #include <unistd.h> class GraphWidget; +struct PidAndTid { + bool operator==(const PidAndTid& other) const + { + return pid == other.pid && tid == other.tid; + } + pid_t pid; + int tid; +}; + class ProcessModel final : public GModel { public: enum Column { @@ -18,6 +27,7 @@ public: Priority, User, PID, + TID, Virtual, Physical, Syscalls, @@ -44,7 +54,8 @@ public: private: ProcessModel(); - struct ProcessState { + struct ThreadState { + int tid; pid_t pid; unsigned times_scheduled; String name; @@ -61,16 +72,23 @@ private: int icon_id; }; - struct Process { - ProcessState current_state; - ProcessState previous_state; + struct Thread { + ThreadState current_state; + ThreadState previous_state; }; HashMap<uid_t, String> m_usernames; - HashMap<pid_t, NonnullOwnPtr<Process>> m_processes; - Vector<pid_t> m_pids; + HashMap<PidAndTid, NonnullOwnPtr<Thread>> m_threads; + Vector<PidAndTid> m_pids; RefPtr<GraphicsBitmap> m_generic_process_icon; RefPtr<GraphicsBitmap> m_high_priority_icon; RefPtr<GraphicsBitmap> m_low_priority_icon; RefPtr<GraphicsBitmap> m_normal_priority_icon; }; + +namespace AK { +template<> +struct Traits<PidAndTid> : public GenericTraits<PidAndTid> { + static unsigned hash(const PidAndTid& value) { return pair_int_hash(value.pid, value.tid); } +}; +} diff --git a/DevTools/HackStudio/ProcessStateWidget.cpp b/DevTools/HackStudio/ProcessStateWidget.cpp index 2509f0944e..f195c91cd8 100644 --- a/DevTools/HackStudio/ProcessStateWidget.cpp +++ b/DevTools/HackStudio/ProcessStateWidget.cpp @@ -55,8 +55,8 @@ void ProcessStateWidget::refresh() auto& data = active_process_data.value(); m_pid_label->set_text(String::format("%s(%d)", data.name.characters(), pid)); - m_state_label->set_text(data.state); - m_cpu_label->set_text(String::format("%d", data.times_scheduled)); + m_state_label->set_text(data.threads.first().state); + m_cpu_label->set_text(String::format("%d", data.threads.first().times_scheduled)); m_memory_label->set_text(String::format("%d", data.amount_resident)); } diff --git a/Kernel/FileSystem/ProcFS.cpp b/Kernel/FileSystem/ProcFS.cpp index bb7a86d7bc..928719b4fe 100644 --- a/Kernel/FileSystem/ProcFS.cpp +++ b/Kernel/FileSystem/ProcFS.cpp @@ -677,13 +677,11 @@ Optional<KBuffer> procfs$all(InodeIdentifier) auto build_process = [&](const Process& process) { auto process_object = array.add_object(); process_object.add("pid", process.pid()); - process_object.add("times_scheduled", process.main_thread().times_scheduled()); process_object.add("pgid", process.tty() ? process.tty()->pgid() : 0); process_object.add("pgp", process.pgid()); process_object.add("sid", process.sid()); process_object.add("uid", process.uid()); process_object.add("gid", process.gid()); - process_object.add("state", process.main_thread().state_string()); process_object.add("ppid", process.ppid()); process_object.add("nfds", process.number_of_open_file_descriptors()); process_object.add("name", process.name()); @@ -691,13 +689,21 @@ Optional<KBuffer> procfs$all(InodeIdentifier) process_object.add("amount_virtual", (u32)process.amount_virtual()); process_object.add("amount_resident", (u32)process.amount_resident()); process_object.add("amount_shared", (u32)process.amount_shared()); - process_object.add("ticks", process.main_thread().ticks()); - process_object.add("priority", to_string(process.main_thread().priority())); process_object.add("syscall_count", process.syscall_count()); process_object.add("inode_faults", process.inode_faults()); process_object.add("zero_faults", process.zero_faults()); process_object.add("cow_faults", process.cow_faults()); process_object.add("icon_id", process.icon_id()); + auto thread_array = process_object.add_array("threads"); + process.for_each_thread([&](const Thread& thread) { + auto thread_object = thread_array.add_object(); + thread_object.add("tid", thread.tid()); + thread_object.add("times_scheduled", thread.times_scheduled()); + thread_object.add("ticks", thread.ticks()); + thread_object.add("state", thread.state_string()); + thread_object.add("priority", to_string(thread.priority())); + return IterationDecision::Continue; + }); }; build_process(*Scheduler::colonel()); for (auto* process : processes) diff --git a/Libraries/LibCore/CProcessStatisticsReader.cpp b/Libraries/LibCore/CProcessStatisticsReader.cpp index 1ccb72a9e3..c9e2becbe2 100644 --- a/Libraries/LibCore/CProcessStatisticsReader.cpp +++ b/Libraries/LibCore/CProcessStatisticsReader.cpp @@ -26,13 +26,11 @@ HashMap<pid_t, CProcessStatistics> CProcessStatisticsReader::get_all() // kernel data first process.pid = process_object.get("pid").to_u32(); - process.times_scheduled = process_object.get("times_scheduled").to_u32(); process.pgid = process_object.get("pgid").to_u32(); process.pgp = process_object.get("pgp").to_u32(); process.sid = process_object.get("sid").to_u32(); process.uid = process_object.get("uid").to_u32(); process.gid = process_object.get("gid").to_u32(); - process.state = process_object.get("state").to_string(); process.ppid = process_object.get("ppid").to_u32(); process.nfds = process_object.get("nfds").to_u32(); process.name = process_object.get("name").to_string(); @@ -40,14 +38,24 @@ HashMap<pid_t, CProcessStatistics> CProcessStatisticsReader::get_all() process.amount_virtual = process_object.get("amount_virtual").to_u32(); process.amount_resident = process_object.get("amount_resident").to_u32(); process.amount_shared = process_object.get("amount_shared").to_u32(); - process.ticks = process_object.get("ticks").to_u32(); - process.priority = process_object.get("priority").to_string(); process.syscall_count = process_object.get("syscall_count").to_u32(); process.inode_faults = process_object.get("inode_faults").to_u32(); process.zero_faults = process_object.get("zero_faults").to_u32(); process.cow_faults = process_object.get("cow_faults").to_u32(); process.icon_id = process_object.get("icon_id").to_int(); + auto thread_array = process_object.get("threads").as_array(); + thread_array.for_each([&](auto& value) { + auto& thread_object = value.as_object(); + CThreadStatistics thread; + thread.tid = thread_object.get("tid").to_u32(); + thread.times_scheduled = thread_object.get("times_scheduled").to_u32(); + thread.state = thread_object.get("state").to_string(); + thread.ticks = thread_object.get("ticks").to_u32(); + thread.priority = thread_object.get("priority").to_string(); + process.threads.append(move(thread)); + }); + // and synthetic data last process.username = username_from_uid(process.uid); map.set(process.pid, process); diff --git a/Libraries/LibCore/CProcessStatisticsReader.h b/Libraries/LibCore/CProcessStatisticsReader.h index c793d1f8f4..848821cb26 100644 --- a/Libraries/LibCore/CProcessStatisticsReader.h +++ b/Libraries/LibCore/CProcessStatisticsReader.h @@ -1,19 +1,26 @@ #pragma once -#include <AK/String.h> #include <AK/HashMap.h> +#include <AK/String.h> +#include <unistd.h> + +struct CThreadStatistics { + int tid; + unsigned times_scheduled; + unsigned ticks; + String state; + String priority; +}; struct CProcessStatistics { // Keep this in sync with /proc/all. // From the kernel side: pid_t pid; - unsigned times_scheduled; unsigned pgid; unsigned pgp; unsigned sid; uid_t uid; gid_t gid; - String state; pid_t ppid; unsigned nfds; String name; @@ -21,14 +28,14 @@ struct CProcessStatistics { size_t amount_virtual; size_t amount_resident; size_t amount_shared; - unsigned ticks; - String priority; unsigned syscall_count; unsigned inode_faults; unsigned zero_faults; unsigned cow_faults; int icon_id; + Vector<CThreadStatistics> threads; + // synthetic String username; }; diff --git a/Servers/WindowServer/WSCPUMonitor.cpp b/Servers/WindowServer/WSCPUMonitor.cpp index d1fb2d8653..175c5d2672 100644 --- a/Servers/WindowServer/WSCPUMonitor.cpp +++ b/Servers/WindowServer/WSCPUMonitor.cpp @@ -44,10 +44,12 @@ void WSCPUMonitor::get_cpu_usage(unsigned& busy, unsigned& idle) auto all_processes = CProcessStatisticsReader::get_all(); for (auto& it : all_processes) { - if (it.value.pid == 0) - idle += it.value.times_scheduled; - else - busy += it.value.times_scheduled; + for (auto& jt : it.value.threads) { + if (it.value.pid == 0) + idle += jt.times_scheduled; + else + busy += jt.times_scheduled; + } } } diff --git a/Userland/ps.cpp b/Userland/ps.cpp index a56da0c12d..1cadff536b 100644 --- a/Userland/ps.cpp +++ b/Userland/ps.cpp @@ -28,9 +28,9 @@ int main(int argc, char** argv) proc.pgp, proc.sid, proc.uid, - proc.state.characters(), + proc.threads.first().state.characters(), proc.ppid, - proc.times_scheduled, + proc.threads.first().times_scheduled, proc.nfds, tty.characters(), proc.name.characters()); diff --git a/Userland/top.cpp b/Userland/top.cpp index 9654493a2b..de987d7055 100644 --- a/Userland/top.cpp +++ b/Userland/top.cpp @@ -1,9 +1,9 @@ -#include <AK/String.h> #include <AK/HashMap.h> #include <AK/JsonArray.h> #include <AK/JsonObject.h> #include <AK/JsonValue.h> #include <AK/QuickSort.h> +#include <AK/String.h> #include <AK/Vector.h> #include <LibCore/CProcessStatisticsReader.h> #include <fcntl.h> @@ -11,15 +11,55 @@ #include <stdlib.h> #include <unistd.h> -struct ProcessData { - CProcessStatistics stats; +struct ThreadData { + int tid; + pid_t pid; + unsigned pgid; + unsigned pgp; + unsigned sid; + uid_t uid; + gid_t gid; + pid_t ppid; + unsigned nfds; + String name; + String tty; + size_t amount_virtual; + size_t amount_resident; + size_t amount_shared; + unsigned syscall_count; + unsigned inode_faults; + unsigned zero_faults; + unsigned cow_faults; + int icon_id; + unsigned times_scheduled; + unsigned times_scheduled_since_prev { 0 }; unsigned cpu_percent { 0 }; unsigned cpu_percent_decimal { 0 }; + + String priority; + String username; + String state; +}; + +struct PidAndTid { + bool operator==(const PidAndTid& other) const + { + return pid == other.pid && tid == other.tid; + } + pid_t pid; + int tid; +}; + +namespace AK { +template<> +struct Traits<PidAndTid> : public GenericTraits<PidAndTid> { + static unsigned hash(const PidAndTid& value) { return pair_int_hash(value.pid, value.tid); } }; +} struct Snapshot { - HashMap<unsigned, ProcessData> map; + HashMap<PidAndTid, ThreadData> map; u32 sum_times_scheduled { 0 }; }; @@ -31,10 +71,35 @@ static Snapshot get_snapshot() for (auto& it : all_processes) { auto& stats = it.value; - snapshot.sum_times_scheduled += stats.times_scheduled; - ProcessData process_data; - process_data.stats = stats; - snapshot.map.set(stats.pid, move(process_data)); + for (auto& thread : stats.threads) { + snapshot.sum_times_scheduled += thread.times_scheduled; + ThreadData thread_data; + thread_data.tid = thread.tid; + thread_data.pid = stats.pid; + thread_data.pgid = stats.pgid; + thread_data.pgp = stats.pgp; + thread_data.sid = stats.sid; + thread_data.uid = stats.uid; + thread_data.gid = stats.gid; + thread_data.ppid = stats.ppid; + thread_data.nfds = stats.nfds; + thread_data.name = stats.name; + thread_data.tty = stats.tty; + thread_data.amount_virtual = stats.amount_virtual; + thread_data.amount_resident = stats.amount_resident; + thread_data.amount_shared = stats.amount_shared; + thread_data.syscall_count = stats.syscall_count; + thread_data.inode_faults = stats.inode_faults; + thread_data.zero_faults = stats.zero_faults; + thread_data.cow_faults = stats.cow_faults; + thread_data.icon_id = stats.icon_id; + thread_data.times_scheduled = thread.times_scheduled; + thread_data.priority = thread.priority; + thread_data.state = thread.state; + thread_data.username = stats.username; + + snapshot.map.set({ stats.pid, thread.tid }, move(thread_data)); + } } return snapshot; @@ -42,7 +107,7 @@ static Snapshot get_snapshot() int main(int, char**) { - Vector<ProcessData*> processes; + Vector<ThreadData*> threads; auto prev = get_snapshot(); usleep(10000); for (;;) { @@ -50,8 +115,9 @@ int main(int, char**) auto sum_diff = current.sum_times_scheduled - prev.sum_times_scheduled; printf("\033[3J\033[H\033[2J"); - printf("\033[47;30m%6s %3s %-8s %-8s %6s %6s %4s %s\033[K\033[0m\n", + printf("\033[47;30m%6s %3s %3s %-8s %-10s %6s %6s %4s %s\033[K\033[0m\n", "PID", + "TID", "PRI", "USER", "STATE", @@ -60,38 +126,39 @@ int main(int, char**) "%CPU", "NAME"); for (auto& it : current.map) { - pid_t pid = it.key; - if (pid == 0) + auto pid_and_tid = it.key; + if (pid_and_tid.pid == 0) continue; - u32 times_scheduled_now = it.value.stats.times_scheduled; - auto jt = prev.map.find(pid); + u32 times_scheduled_now = it.value.times_scheduled; + auto jt = prev.map.find(pid_and_tid); if (jt == prev.map.end()) continue; - u32 times_scheduled_before = (*jt).value.stats.times_scheduled; + u32 times_scheduled_before = (*jt).value.times_scheduled; u32 times_scheduled_diff = times_scheduled_now - times_scheduled_before; it.value.times_scheduled_since_prev = times_scheduled_diff; it.value.cpu_percent = ((times_scheduled_diff * 100) / sum_diff); it.value.cpu_percent_decimal = (((times_scheduled_diff * 1000) / sum_diff) % 10); - processes.append(&it.value); + threads.append(&it.value); } - quick_sort(processes.begin(), processes.end(), [](auto* p1, auto* p2) { + quick_sort(threads.begin(), threads.end(), [](auto* p1, auto* p2) { return p2->times_scheduled_since_prev < p1->times_scheduled_since_prev; }); - for (auto* process : processes) { - printf("%6d %c %-8s %-10s %6zu %6zu %2u.%1u %s\n", - process->stats.pid, - process->stats.priority[0], - process->stats.username.characters(), - process->stats.state.characters(), - process->stats.amount_virtual / 1024, - process->stats.amount_resident / 1024, - process->cpu_percent, - process->cpu_percent_decimal, - process->stats.name.characters()); + for (auto* thread : threads) { + printf("%6d %3d %c %-8s %-10s %6zu %6zu %2u.%1u %s\n", + thread->pid, + thread->tid, + thread->priority[0], + thread->username.characters(), + thread->state.characters(), + thread->amount_virtual / 1024, + thread->amount_resident / 1024, + thread->cpu_percent, + thread->cpu_percent_decimal, + thread->name.characters()); } - processes.clear_with_capacity(); + threads.clear_with_capacity(); prev = move(current); sleep(1); } |