ProcessTableModel.cpp 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. #include "ProcessTableModel.h"
  2. #include <fcntl.h>
  3. #include <stdio.h>
  4. #include <pwd.h>
  5. enum Column {
  6. PID = 0,
  7. State,
  8. User,
  9. Priority,
  10. Linear,
  11. Physical,
  12. CPU,
  13. Name,
  14. __Count
  15. };
  16. ProcessTableModel::ProcessTableModel()
  17. {
  18. setpwent();
  19. while (auto* passwd = getpwent())
  20. m_usernames.set(passwd->pw_uid, passwd->pw_name);
  21. endpwent();
  22. }
  23. ProcessTableModel::~ProcessTableModel()
  24. {
  25. }
  26. int ProcessTableModel::row_count() const
  27. {
  28. return m_processes.size();
  29. }
  30. int ProcessTableModel::column_count() const
  31. {
  32. return Column::__Count;
  33. }
  34. String ProcessTableModel::column_name(int column) const
  35. {
  36. switch (column) {
  37. case Column::PID: return "PID";
  38. case Column::State: return "State";
  39. case Column::User: return "User";
  40. case Column::Priority: return "Priority";
  41. case Column::Linear: return "Linear";
  42. case Column::Physical: return "Physical";
  43. case Column::CPU: return "CPU";
  44. case Column::Name: return "Name";
  45. default: ASSERT_NOT_REACHED();
  46. }
  47. }
  48. GTableModel::ColumnMetadata ProcessTableModel::column_metadata(int column) const
  49. {
  50. switch (column) {
  51. case Column::PID: return { 30, TextAlignment::CenterRight };
  52. case Column::State: return { 80, TextAlignment::CenterLeft };
  53. case Column::Priority: return { 75, TextAlignment::CenterLeft };
  54. case Column::User: return { 60, TextAlignment::CenterLeft };
  55. case Column::Linear: return { 70, TextAlignment::CenterRight };
  56. case Column::Physical: return { 70, TextAlignment::CenterRight };
  57. case Column::CPU: return { 30, TextAlignment::CenterRight };
  58. case Column::Name: return { 200, TextAlignment::CenterLeft };
  59. default: ASSERT_NOT_REACHED();
  60. }
  61. }
  62. GModelIndex ProcessTableModel::selected_index() const
  63. {
  64. return { m_selected_row, 0 };
  65. }
  66. void ProcessTableModel::set_selected_index(GModelIndex index)
  67. {
  68. if (!index.is_valid()) {
  69. m_selected_row = -1;
  70. return;
  71. }
  72. if (index.row() >= 0 && index.row() < m_pids.size())
  73. m_selected_row = index.row();
  74. }
  75. static String pretty_byte_size(size_t size)
  76. {
  77. return String::format("%uK", size / 1024);
  78. }
  79. String ProcessTableModel::data(int row, int column) const
  80. {
  81. ASSERT(is_valid({ row, column }));
  82. auto it = m_processes.find(m_pids[row]);
  83. auto& process = *(*it).value;
  84. switch (column) {
  85. case Column::PID: return String::format("%d", process.current_state.pid);
  86. case Column::State: return process.current_state.state;
  87. case Column::User: return process.current_state.user;
  88. case Column::Priority: return process.current_state.priority;
  89. case Column::Linear: return pretty_byte_size(process.current_state.linear);
  90. case Column::Physical: return pretty_byte_size(process.current_state.physical);
  91. case Column::CPU: return String::format("%d", (int)process.current_state.cpu_percent);
  92. case Column::Name: return process.current_state.name;
  93. }
  94. ASSERT_NOT_REACHED();
  95. }
  96. void ProcessTableModel::update()
  97. {
  98. FILE* fp = fopen("/proc/all", "r");
  99. if (!fp) {
  100. perror("failed to open /proc/all");
  101. exit(1);
  102. }
  103. unsigned last_sum_nsched = 0;
  104. for (auto& it : m_processes)
  105. last_sum_nsched += it.value->current_state.nsched;
  106. HashTable<pid_t> live_pids;
  107. unsigned sum_nsched = 0;
  108. for (;;) {
  109. char buf[BUFSIZ];
  110. char* ptr = fgets(buf, sizeof(buf), fp);
  111. if (!ptr)
  112. break;
  113. auto parts = String(buf, Chomp).split(',');
  114. if (parts.size() < 17)
  115. break;
  116. bool ok;
  117. pid_t pid = parts[0].to_uint(ok);
  118. ASSERT(ok);
  119. unsigned nsched = parts[1].to_uint(ok);
  120. ASSERT(ok);
  121. ProcessState state;
  122. state.pid = pid;
  123. state.nsched = nsched;
  124. unsigned uid = parts[5].to_uint(ok);
  125. ASSERT(ok);
  126. {
  127. auto it = m_usernames.find((uid_t)uid);
  128. if (it != m_usernames.end())
  129. state.user = String::format("%s", (*it).value.characters());
  130. else
  131. state.user = String::format("%u", uid);
  132. }
  133. state.priority = parts[16];
  134. state.state = parts[7];
  135. state.name = parts[11];
  136. state.linear = parts[12].to_uint(ok);
  137. ASSERT(ok);
  138. state.physical = parts[13].to_uint(ok);
  139. ASSERT(ok);
  140. {
  141. auto it = m_processes.find(pid);
  142. if (it == m_processes.end())
  143. m_processes.set(pid, make<Process>());
  144. }
  145. auto it = m_processes.find(pid);
  146. ASSERT(it != m_processes.end());
  147. (*it).value->previous_state = (*it).value->current_state;
  148. (*it).value->current_state = state;
  149. live_pids.set(pid);
  150. sum_nsched += nsched;
  151. }
  152. int rc = fclose(fp);
  153. ASSERT(rc == 0);
  154. m_pids.clear();
  155. Vector<pid_t> pids_to_remove;
  156. for (auto& it : m_processes) {
  157. if (!live_pids.contains(it.key)) {
  158. pids_to_remove.append(it.key);
  159. continue;
  160. }
  161. auto& process = *it.value;
  162. dword nsched_diff = process.current_state.nsched - process.previous_state.nsched;
  163. process.current_state.cpu_percent = ((float)nsched_diff * 100) / (float)(sum_nsched - last_sum_nsched);
  164. m_pids.append(it.key);
  165. }
  166. for (auto pid : pids_to_remove)
  167. m_processes.remove(pid);
  168. did_update();
  169. }
  170. pid_t ProcessTableModel::selected_pid() const
  171. {
  172. if (m_selected_row == -1)
  173. return -1;
  174. return m_pids[m_selected_row];
  175. }