ProcessModel.cpp 7.8 KB

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