ProcessModel.cpp 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. #include "ProcessModel.h"
  2. #include "GraphWidget.h"
  3. #include <AK/JsonArray.h>
  4. #include <AK/JsonObject.h>
  5. #include <AK/JsonValue.h>
  6. #include <LibCore/CProcessStatisticsReader.h>
  7. #include <fcntl.h>
  8. #include <stdio.h>
  9. ProcessModel::ProcessModel(GraphWidget& graph)
  10. : m_graph(graph)
  11. {
  12. m_generic_process_icon = GraphicsBitmap::load_from_file("/res/icons/gear16.png");
  13. m_high_priority_icon = GraphicsBitmap::load_from_file("/res/icons/highpriority16.png");
  14. m_low_priority_icon = GraphicsBitmap::load_from_file("/res/icons/lowpriority16.png");
  15. m_normal_priority_icon = GraphicsBitmap::load_from_file("/res/icons/normalpriority16.png");
  16. }
  17. ProcessModel::~ProcessModel()
  18. {
  19. }
  20. int ProcessModel::row_count(const GModelIndex&) const
  21. {
  22. return m_pids.size();
  23. }
  24. int ProcessModel::column_count(const GModelIndex&) const
  25. {
  26. return Column::__Count;
  27. }
  28. String ProcessModel::column_name(int column) const
  29. {
  30. switch (column) {
  31. case Column::Icon:
  32. return "";
  33. case Column::PID:
  34. return "PID";
  35. case Column::State:
  36. return "State";
  37. case Column::User:
  38. return "User";
  39. case Column::Priority:
  40. return "Pr";
  41. case Column::Virtual:
  42. return "Virtual";
  43. case Column::Physical:
  44. return "Physical";
  45. case Column::CPU:
  46. return "CPU";
  47. case Column::Name:
  48. return "Name";
  49. case Column::Syscalls:
  50. return "Syscalls";
  51. default:
  52. ASSERT_NOT_REACHED();
  53. }
  54. }
  55. GModel::ColumnMetadata ProcessModel::column_metadata(int column) const
  56. {
  57. switch (column) {
  58. case Column::Icon:
  59. return { 16, TextAlignment::CenterLeft };
  60. case Column::PID:
  61. return { 32, TextAlignment::CenterRight };
  62. case Column::State:
  63. return { 75, TextAlignment::CenterLeft };
  64. case Column::Priority:
  65. return { 16, TextAlignment::CenterLeft };
  66. case Column::User:
  67. return { 50, TextAlignment::CenterLeft };
  68. case Column::Virtual:
  69. return { 65, TextAlignment::CenterRight };
  70. case Column::Physical:
  71. return { 65, TextAlignment::CenterRight };
  72. case Column::CPU:
  73. return { 32, TextAlignment::CenterRight };
  74. case Column::Name:
  75. return { 140, TextAlignment::CenterLeft };
  76. case Column::Syscalls:
  77. return { 60, TextAlignment::CenterRight };
  78. default:
  79. ASSERT_NOT_REACHED();
  80. }
  81. }
  82. static String pretty_byte_size(size_t size)
  83. {
  84. return String::format("%uK", size / 1024);
  85. }
  86. GVariant ProcessModel::data(const GModelIndex& index, Role role) const
  87. {
  88. ASSERT(is_valid(index));
  89. auto it = m_processes.find(m_pids[index.row()]);
  90. auto& process = *(*it).value;
  91. if (role == Role::Sort) {
  92. switch (index.column()) {
  93. case Column::Icon:
  94. return 0;
  95. case Column::PID:
  96. return process.current_state.pid;
  97. case Column::State:
  98. return process.current_state.state;
  99. case Column::User:
  100. return process.current_state.user;
  101. case Column::Priority:
  102. if (process.current_state.priority == "Idle")
  103. return 0;
  104. if (process.current_state.priority == "Low")
  105. return 1;
  106. if (process.current_state.priority == "Normal")
  107. return 2;
  108. if (process.current_state.priority == "High")
  109. return 3;
  110. ASSERT_NOT_REACHED();
  111. return 3;
  112. case Column::Virtual:
  113. return (int)process.current_state.virtual_size;
  114. case Column::Physical:
  115. return (int)process.current_state.physical_size;
  116. case Column::CPU:
  117. return process.current_state.cpu_percent;
  118. case Column::Name:
  119. return process.current_state.name;
  120. // FIXME: GVariant with unsigned?
  121. case Column::Syscalls:
  122. return (int)process.current_state.syscalls;
  123. }
  124. ASSERT_NOT_REACHED();
  125. return {};
  126. }
  127. if (role == Role::Display) {
  128. switch (index.column()) {
  129. case Column::Icon:
  130. return *m_generic_process_icon;
  131. case Column::PID:
  132. return process.current_state.pid;
  133. case Column::State:
  134. return process.current_state.state;
  135. case Column::User:
  136. return process.current_state.user;
  137. case Column::Priority:
  138. if (process.current_state.priority == "Idle")
  139. return String::empty();
  140. if (process.current_state.priority == "High")
  141. return *m_high_priority_icon;
  142. if (process.current_state.priority == "Low")
  143. return *m_low_priority_icon;
  144. if (process.current_state.priority == "Normal")
  145. return *m_normal_priority_icon;
  146. return process.current_state.priority;
  147. case Column::Virtual:
  148. return pretty_byte_size(process.current_state.virtual_size);
  149. case Column::Physical:
  150. return pretty_byte_size(process.current_state.physical_size);
  151. case Column::CPU:
  152. return process.current_state.cpu_percent;
  153. case Column::Name:
  154. return process.current_state.name;
  155. // FIXME: It's weird that GVariant doesn't support unsigned ints. Should it?
  156. case Column::Syscalls:
  157. return (int)process.current_state.syscalls;
  158. }
  159. }
  160. return {};
  161. }
  162. void ProcessModel::update()
  163. {
  164. auto all_processes = CProcessStatisticsReader::get_all();
  165. unsigned last_sum_nsched = 0;
  166. for (auto& it : m_processes)
  167. last_sum_nsched += it.value->current_state.nsched;
  168. HashTable<pid_t> live_pids;
  169. unsigned sum_nsched = 0;
  170. for (auto& it : all_processes) {
  171. ProcessState state;
  172. state.pid = it.value.pid;
  173. state.nsched = it.value.nsched;
  174. state.user = it.value.username;
  175. state.priority = it.value.priority;
  176. state.syscalls = it.value.syscalls;
  177. state.state = it.value.state;
  178. state.name = it.value.name;
  179. state.virtual_size = it.value.virtual_size;
  180. state.physical_size = it.value.physical_size;
  181. sum_nsched += it.value.nsched;
  182. {
  183. auto pit = m_processes.find(it.value.pid);
  184. if (pit == m_processes.end())
  185. m_processes.set(it.value.pid, make<Process>());
  186. }
  187. auto pit = m_processes.find(it.value.pid);
  188. ASSERT(pit != m_processes.end());
  189. (*pit).value->previous_state = (*pit).value->current_state;
  190. (*pit).value->current_state = state;
  191. live_pids.set(it.value.pid);
  192. }
  193. m_pids.clear();
  194. float total_cpu_percent = 0;
  195. Vector<pid_t, 16> pids_to_remove;
  196. for (auto& it : m_processes) {
  197. if (!live_pids.contains(it.key)) {
  198. pids_to_remove.append(it.key);
  199. continue;
  200. }
  201. auto& process = *it.value;
  202. u32 nsched_diff = process.current_state.nsched - process.previous_state.nsched;
  203. process.current_state.cpu_percent = ((float)nsched_diff * 100) / (float)(sum_nsched - last_sum_nsched);
  204. if (it.key != 0) {
  205. total_cpu_percent += process.current_state.cpu_percent;
  206. m_pids.append(it.key);
  207. }
  208. }
  209. for (auto pid : pids_to_remove)
  210. m_processes.remove(pid);
  211. m_graph.add_value(total_cpu_percent);
  212. did_update();
  213. }