Ver Fonte

Kernel+SystemMonitor: Log amounts of I/O per thread

This patch adds these I/O counters to each thread:

- (Inode) file read bytes
- (Inode) file write bytes
- Unix socket read bytes
- Unix socket write bytes
- IPv4 socket read bytes
- IPv4 socket write bytes

These are then exposed in /proc/all and seen in SystemMonitor.
Andreas Kling há 5 anos atrás
pai
commit
5a45376180

+ 54 - 0
Applications/SystemMonitor/ProcessModel.cpp

@@ -71,6 +71,18 @@ String ProcessModel::column_name(int column) const
         return "F:Zero";
     case Column::CowFaults:
         return "F:CoW";
+    case Column::IPv4SocketReadBytes:
+        return "IPv4 In";
+    case Column::IPv4SocketWriteBytes:
+        return "IPv4 Out";
+    case Column::UnixSocketReadBytes:
+        return "Unix In";
+    case Column::UnixSocketWriteBytes:
+        return "Unix Out";
+    case Column::FileReadBytes:
+        return "File In";
+    case Column::FileWriteBytes:
+        return "File Out";
     default:
         ASSERT_NOT_REACHED();
     }
@@ -107,6 +119,18 @@ GModel::ColumnMetadata ProcessModel::column_metadata(int column) const
         return { 60, TextAlignment::CenterRight };
     case Column::CowFaults:
         return { 60, TextAlignment::CenterRight };
+    case Column::FileReadBytes:
+        return { 60, TextAlignment::CenterRight };
+    case Column::FileWriteBytes:
+        return { 60, TextAlignment::CenterRight };
+    case Column::UnixSocketReadBytes:
+        return { 60, TextAlignment::CenterRight };
+    case Column::UnixSocketWriteBytes:
+        return { 60, TextAlignment::CenterRight };
+    case Column::IPv4SocketReadBytes:
+        return { 60, TextAlignment::CenterRight };
+    case Column::IPv4SocketWriteBytes:
+        return { 60, TextAlignment::CenterRight };
     default:
         ASSERT_NOT_REACHED();
     }
@@ -164,6 +188,18 @@ GVariant ProcessModel::data(const GModelIndex& index, Role role) const
             return (int)thread.current_state.zero_faults;
         case Column::CowFaults:
             return (int)thread.current_state.cow_faults;
+        case Column::IPv4SocketReadBytes:
+            return (int)thread.current_state.ipv4_socket_read_bytes;
+        case Column::IPv4SocketWriteBytes:
+            return (int)thread.current_state.ipv4_socket_write_bytes;
+        case Column::UnixSocketReadBytes:
+            return (int)thread.current_state.unix_socket_read_bytes;
+        case Column::UnixSocketWriteBytes:
+            return (int)thread.current_state.unix_socket_write_bytes;
+        case Column::FileReadBytes:
+            return (int)thread.current_state.file_read_bytes;
+        case Column::FileWriteBytes:
+            return (int)thread.current_state.file_write_bytes;
         }
         ASSERT_NOT_REACHED();
         return {};
@@ -216,6 +252,18 @@ GVariant ProcessModel::data(const GModelIndex& index, Role role) const
             return (int)thread.current_state.zero_faults;
         case Column::CowFaults:
             return (int)thread.current_state.cow_faults;
+        case Column::IPv4SocketReadBytes:
+            return (int)thread.current_state.ipv4_socket_read_bytes;
+        case Column::IPv4SocketWriteBytes:
+            return (int)thread.current_state.ipv4_socket_write_bytes;
+        case Column::UnixSocketReadBytes:
+            return (int)thread.current_state.unix_socket_read_bytes;
+        case Column::UnixSocketWriteBytes:
+            return (int)thread.current_state.unix_socket_write_bytes;
+        case Column::FileReadBytes:
+            return (int)thread.current_state.file_read_bytes;
+        case Column::FileWriteBytes:
+            return (int)thread.current_state.file_write_bytes;
         }
     }
 
@@ -241,6 +289,12 @@ void ProcessModel::update()
             state.inode_faults = thread.inode_faults;
             state.zero_faults = thread.zero_faults;
             state.cow_faults = thread.cow_faults;
+            state.unix_socket_read_bytes = thread.unix_socket_read_bytes;
+            state.unix_socket_write_bytes = thread.unix_socket_write_bytes;
+            state.ipv4_socket_read_bytes = thread.ipv4_socket_read_bytes;
+            state.ipv4_socket_write_bytes = thread.ipv4_socket_write_bytes;
+            state.file_read_bytes = thread.file_read_bytes;
+            state.file_write_bytes = thread.file_write_bytes;
             state.name = it.value.name;
             state.amount_virtual = it.value.amount_virtual;
             state.amount_resident = it.value.amount_resident;

+ 12 - 0
Applications/SystemMonitor/ProcessModel.h

@@ -34,6 +34,12 @@ public:
         InodeFaults,
         ZeroFaults,
         CowFaults,
+        FileReadBytes,
+        FileWriteBytes,
+        UnixSocketReadBytes,
+        UnixSocketWriteBytes,
+        IPv4SocketReadBytes,
+        IPv4SocketWriteBytes,
         __Count
     };
 
@@ -68,6 +74,12 @@ private:
         unsigned inode_faults;
         unsigned zero_faults;
         unsigned cow_faults;
+        unsigned unix_socket_read_bytes;
+        unsigned unix_socket_write_bytes;
+        unsigned ipv4_socket_read_bytes;
+        unsigned ipv4_socket_write_bytes;
+        unsigned file_read_bytes;
+        unsigned file_write_bytes;
         float cpu_percent;
         int icon_id;
     };

+ 9 - 4
Kernel/FileSystem/InodeFile.cpp

@@ -15,15 +15,20 @@ InodeFile::~InodeFile()
 
 ssize_t InodeFile::read(FileDescription& description, u8* buffer, ssize_t count)
 {
-    return m_inode->read_bytes(description.offset(), count, buffer, &description);
+    ssize_t nread = m_inode->read_bytes(description.offset(), count, buffer, &description);
+    if (nread > 0)
+        current->did_file_read(nread);
+    return nread;
 }
 
 ssize_t InodeFile::write(FileDescription& description, const u8* data, ssize_t count)
 {
-    ssize_t ret = m_inode->write_bytes(description.offset(), count, data, &description);
-    if (ret > 0)
+    ssize_t nwritten = m_inode->write_bytes(description.offset(), count, data, &description);
+    if (nwritten > 0) {
         m_inode->set_mtime(kgettimeofday().tv_sec);
-    return ret;
+        current->did_file_write(nwritten);
+    }
+    return nwritten;
 }
 
 KResultOr<Region*> InodeFile::mmap(Process& process, FileDescription& description, VirtualAddress preferred_vaddr, size_t offset, size_t size, int prot)

+ 6 - 0
Kernel/FileSystem/ProcFS.cpp

@@ -725,6 +725,12 @@ Optional<KBuffer> procfs$all(InodeIdentifier)
             thread_object.add("inode_faults", thread.inode_faults());
             thread_object.add("zero_faults", thread.zero_faults());
             thread_object.add("cow_faults", thread.cow_faults());
+            thread_object.add("file_read_bytes", thread.file_read_bytes());
+            thread_object.add("file_write_bytes", thread.file_write_bytes());
+            thread_object.add("unix_socket_read_bytes", thread.unix_socket_read_bytes());
+            thread_object.add("unix_socket_write_bytes", thread.unix_socket_write_bytes());
+            thread_object.add("ipv4_socket_read_bytes", thread.ipv4_socket_read_bytes());
+            thread_object.add("ipv4_socket_write_bytes", thread.ipv4_socket_write_bytes());
             return IterationDecision::Continue;
         });
     };

+ 8 - 2
Kernel/Net/IPv4Socket.cpp

@@ -206,7 +206,10 @@ ssize_t IPv4Socket::sendto(FileDescription&, const void* data, size_t data_lengt
         return data_length;
     }
 
-    return protocol_send(data, data_length);
+    int nsent = protocol_send(data, data_length);
+    if (nsent > 0)
+        current->did_ipv4_socket_write(nsent);
+    return nsent;
 }
 
 ssize_t IPv4Socket::recvfrom(FileDescription& description, void* buffer, size_t buffer_length, int flags, sockaddr* addr, socklen_t* addr_length)
@@ -285,7 +288,10 @@ ssize_t IPv4Socket::recvfrom(FileDescription& description, void* buffer, size_t
         return ipv4_packet.payload_size();
     }
 
-    return protocol_receive(packet.data.value(), buffer, buffer_length, flags);
+    int nreceived = protocol_receive(packet.data.value(), buffer, buffer_length, flags);
+    if (nreceived > 0)
+        current->did_ipv4_socket_read(nreceived);
+    return nreceived;
 }
 
 bool IPv4Socket::did_receive(const IPv4Address& source_address, u16 source_port, KBuffer&& packet)

+ 18 - 7
Kernel/Net/LocalSocket.cpp

@@ -222,27 +222,35 @@ ssize_t LocalSocket::sendto(FileDescription& description, const void* data, size
 {
     if (!has_attached_peer(description))
         return -EPIPE;
+    ssize_t nwritten = send_buffer_for(description).write((const u8*)data, data_size);
+    if (nwritten > 0)
+        current->did_unix_socket_write(nwritten);
+    return nwritten;
+}
+
+DoubleBuffer& LocalSocket::receive_buffer_for(FileDescription& description)
+{
     auto role = this->role(description);
     if (role == Role::Accepted)
-        return m_for_client.write((const u8*)data, data_size);
+        return m_for_server;
     if (role == Role::Connected)
-        return m_for_server.write((const u8*)data, data_size);
+        return m_for_client;
     ASSERT_NOT_REACHED();
 }
 
-DoubleBuffer& LocalSocket::buffer_for(FileDescription& description)
+DoubleBuffer& LocalSocket::send_buffer_for(FileDescription& description)
 {
     auto role = this->role(description);
-    if (role == Role::Accepted)
-        return m_for_server;
     if (role == Role::Connected)
+        return m_for_server;
+    if (role == Role::Accepted)
         return m_for_client;
     ASSERT_NOT_REACHED();
 }
 
 ssize_t LocalSocket::recvfrom(FileDescription& description, void* buffer, size_t buffer_size, int, sockaddr*, socklen_t*)
 {
-    auto& buffer_for_me = buffer_for(description);
+    auto& buffer_for_me = receive_buffer_for(description);
     if (!description.is_blocking()) {
         if (buffer_for_me.is_empty()) {
             if (!has_attached_peer(description))
@@ -257,7 +265,10 @@ ssize_t LocalSocket::recvfrom(FileDescription& description, void* buffer, size_t
     if (!has_attached_peer(description) && buffer_for_me.is_empty())
         return 0;
     ASSERT(!buffer_for_me.is_empty());
-    return buffer_for_me.read((u8*)buffer, buffer_size);
+    int nread = buffer_for_me.read((u8*)buffer, buffer_size);
+    if (nread > 0)
+        current->did_unix_socket_read(nread);
+    return nread;
 }
 
 StringView LocalSocket::socket_path() const

+ 2 - 1
Kernel/Net/LocalSocket.h

@@ -36,7 +36,8 @@ private:
     virtual bool is_local() const override { return true; }
     bool has_attached_peer(const FileDescription&) const;
     static Lockable<InlineLinkedList<LocalSocket>>& all_sockets();
-    DoubleBuffer& buffer_for(FileDescription&);
+    DoubleBuffer& receive_buffer_for(FileDescription&);
+    DoubleBuffer& send_buffer_for(FileDescription&);
 
     // An open socket file on the filesystem.
     RefPtr<FileDescription> m_file;

+ 48 - 0
Kernel/Thread.h

@@ -363,6 +363,45 @@ public:
     unsigned cow_faults() const { return m_cow_faults; }
     void did_cow_fault() { ++m_cow_faults; }
 
+    unsigned file_read_bytes() const { return m_file_read_bytes; }
+    unsigned file_write_bytes() const { return m_file_write_bytes; }
+
+    void did_file_read(unsigned bytes)
+    {
+        m_file_read_bytes += bytes;
+    }
+
+    void did_file_write(unsigned bytes)
+    {
+        m_file_write_bytes += bytes;
+    }
+
+    unsigned unix_socket_read_bytes() const { return m_unix_socket_read_bytes; }
+    unsigned unix_socket_write_bytes() const { return m_unix_socket_write_bytes; }
+
+    void did_unix_socket_read(unsigned bytes)
+    {
+        m_unix_socket_read_bytes += bytes;
+    }
+
+    void did_unix_socket_write(unsigned bytes)
+    {
+        m_unix_socket_write_bytes += bytes;
+    }
+
+    unsigned ipv4_socket_read_bytes() const { return m_ipv4_socket_read_bytes; }
+    unsigned ipv4_socket_write_bytes() const { return m_ipv4_socket_write_bytes; }
+
+    void did_ipv4_socket_read(unsigned bytes)
+    {
+        m_ipv4_socket_read_bytes += bytes;
+    }
+
+    void did_ipv4_socket_write(unsigned bytes)
+    {
+        m_ipv4_socket_write_bytes += bytes;
+    }
+
     Thread* clone(Process&);
 
     template<typename Callback>
@@ -416,6 +455,15 @@ private:
     unsigned m_zero_faults { 0 };
     unsigned m_cow_faults { 0 };
 
+    unsigned m_file_read_bytes { 0 };
+    unsigned m_file_write_bytes { 0 };
+
+    unsigned m_unix_socket_read_bytes { 0 };
+    unsigned m_unix_socket_write_bytes { 0 };
+
+    unsigned m_ipv4_socket_read_bytes { 0 };
+    unsigned m_ipv4_socket_write_bytes { 0 };
+
     FPUState* m_fpu_state { nullptr };
     State m_state { Invalid };
     ThreadPriority m_priority { ThreadPriority::Normal };

+ 6 - 1
Libraries/LibCore/CProcessStatisticsReader.cpp

@@ -53,6 +53,12 @@ HashMap<pid_t, CProcessStatistics> CProcessStatisticsReader::get_all()
             thread.inode_faults = thread_object.get("inode_faults").to_u32();
             thread.zero_faults = thread_object.get("zero_faults").to_u32();
             thread.cow_faults = thread_object.get("cow_faults").to_u32();
+            thread.unix_socket_read_bytes = thread_object.get("unix_socket_read_bytes").to_u32();
+            thread.unix_socket_write_bytes = thread_object.get("unix_socket_write_bytes").to_u32();
+            thread.ipv4_socket_read_bytes = thread_object.get("ipv4_socket_read_bytes").to_u32();
+            thread.ipv4_socket_write_bytes = thread_object.get("ipv4_socket_write_bytes").to_u32();
+            thread.file_read_bytes = thread_object.get("file_read_bytes").to_u32();
+            thread.file_write_bytes = thread_object.get("file_write_bytes").to_u32();
             process.threads.append(move(thread));
         });
 
@@ -78,4 +84,3 @@ String CProcessStatisticsReader::username_from_uid(uid_t uid)
         return (*it).value;
     return String::number(uid);
 }
-

+ 6 - 0
Libraries/LibCore/CProcessStatisticsReader.h

@@ -12,6 +12,12 @@ struct CThreadStatistics {
     unsigned inode_faults;
     unsigned zero_faults;
     unsigned cow_faults;
+    unsigned unix_socket_read_bytes;
+    unsigned unix_socket_write_bytes;
+    unsigned ipv4_socket_read_bytes;
+    unsigned ipv4_socket_write_bytes;
+    unsigned file_read_bytes;
+    unsigned file_write_bytes;
     String state;
     String priority;
 };