Untuk mendapatkan CPU Usage atau CPU Utilization atau bisa juga Kita bilang penggunaan CPU di Linux, Kita biasanya menggunakan command top seperti berikut:

pi@raspberrypi:~ $ top
top - 11:32:10 up 23:07,  1 user,  load average: 0.06, 0.04, 0.00
Tasks: 175 total,   1 running, 117 sleeping,   0 stopped,  57 zombie
%Cpu(s):  0.2 us,  0.8 sy,  0.0 ni, 99.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
MiB Mem :    923.1 total,    690.7 free,     77.2 used,    155.2 buff/cache
MiB Swap:    100.0 total,    100.0 free,      0.0 used.    790.8 avail Mem 

  PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND                                                                                                                                       
  339 root      20   0  235708  17172   3368 S   2.6   1.8  33:05.23 kinanti                                                                                                                                       
 4042 pi        20   0   11244   2984   2556 R   1.3   0.3   0:00.10 top                                                                                                                                           
  342 avahi     20   0    6916   2760   2496 S   0.7   0.3   0:29.04 avahi-daemon                                                                                                                                  
   12 root      20   0       0      0      0 I   0.3   0.0   1:50.55 rcu_sched                                                                                                                                     
   65 root       0 -20       0      0      0 I   0.3   0.0   1:39.99 kworker/u9:0-brcmf_wq/mmc1:0001:1                                                                                                             
 3980 root      20   0       0      0      0 I   0.3   0.0   0:01.17 kworker/0:1-events                                                                                                                            
    1 root      20   0   33696   8612   6872 S   0.0   0.9   0:10.63 systemd                                                                                                                                       
    2 root      20   0       0      0      0 S   0.0   0.0   0:00.17 kthreadd                                                                                                                                      
    3 root       0 -20       0      0      0 I   0.0   0.0   0:00.00 rcu_gp                                                                                                                                        
    4 root       0 -20       0      0      0 I   0.0   0.0   0:00.00 rcu_par_gp

Yang kadang jadi pertanyaan, kenapa proses top ini malah menjadi proses yang memakan resource cpu yang cukup banyak. Tapi untuk informasi administratif/sysadmin command top ini sudah lebih dari cukup untuk melihat penggunaan cpu, tapi bila hendak mengambilnya secara programming, menjalankan command top dan mengambil stdout nya bukan cara yang efisien dan efektif, tapi ada cara lain yang lebih mudah dan lebih ramah lingkungan.

Cara terbaik adalah dengan membaca dan melakukan parsing isi file /proc/stat (bukan regular file, tapi file yang digenerate kernel untuk keperluan informasi dan komunikasi). Berikut adalah contoh isi dari /proc/stat dengan menggunakan command cat

pi@raspberrypi:~ $ cat /proc/stat
cpu  69150 52 114041 33106096 898 0 33193 0 0 0
cpu0 11635 2 37813 7867817 203 0 31169 0 0 0
cpu1 11385 9 22150 8429079 302 0 546 0 0 0
cpu2 35559 35 33561 8381312 239 0 847 0 0 0
cpu3 10571 6 20517 8427886 152 0 631 0 0 0
intr 572709450 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7877 37573987 0 844170 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1221112 71 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2946 0 7560 409 0 0 0 0 0 0 0 0 0 0 502578152 85748 0 0 0 0 0 0 0 0 170839 0 0 0 0 0 0 0 0 0 0 78 0 0 3979 7459 0 0 0 0 8047862 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22157195 0 0 0 6
ctxt 113213475
btime 1652268271
processes 4082
procs_running 1
procs_blocked 0
softirq 35775033 5208493 3626654 16991 2715306 7586 0 7928996 9168855 0 7102152
pi@raspberrypi:~ $

Di dalamnya terdapat banyak informasi tentang penggunaan cpu, baik secara keseluruhan atau masing-masing cpu (core), informasi interrupt, jumlah process dan sebagainya.

Yang paling berguna untuk menghitung total penggunaan CPU adalah baris pertama dengan nama penanda cpu, dimana pada sebelah kanan kolomnya terdapat 10 nilai yang dapat dimanfaatkan berdasarkan jenis valuenya:

usernicesystemidleiowaitirqsoftirqstealguestguest_nice
cpu691505211404133106096898033193000
Jenis value pada /proc/stat

Pada tabel di atas, kolom yang ditandai sebagai bold merupakan total non-idle atau bila disebut total proses yang dilakukan CPU, sedangkan untuk idle dan iowait merupakan jumlah CPU melakukan idle (tidak melakukan proses). Untuk guest dan guest_nice tidak digunakan sebagai parameter untuk dihitung.

Dengan itu Kita memiliki 2 kategori parameter utama yaitu idle dan non-idle, yang bila Kita jumlahkan keduanya akan mendapatkan hasil berupa jumlah kapasitas CPU.

Nilai idle dan non-idle dapat dengan mudah didapatkan dengan fungsi berikut ini:

void get_procstat(uint32_t *nonidle, uint32_t *idle) {
  FILE *fp = fopen("/proc/stat", "r");
  char cpun[255];
  uint32_t t_user, t_nice, t_system, t_idle, t_iowait, t_irq, t_softirq,
      t_steal, t_guest;
  fscanf(fp, "%s  %u %u %u %u %u %u %u %u %u", cpun, &t_user, &t_nice,
         &t_system, &t_idle, &t_iowait, &t_irq, &t_softirq, &t_steal, &t_guest);

  *nonidle = t_user + t_system + t_nice + t_irq + t_softirq + t_steal;
  *idle = t_idle + t_iowait;
  fclose(fp);
}

Tapi nilai dari /proc/stat ini merupakan akumulasi total idle dan non-idle, jadi tidak dapat menentukan penggunaan CPU pada waktu yang sedang berjalan. Untuk menentukan penggunaan CPU pada waktu yang sedang berjalan caranya dengan mengambil parameter di atas sebagai patokan awal, lalu lakukan sleep/menunggu beberapa saat, kemudian ambil lagi parameter yang sama kemudian lakukan kalkulasi kembali seperti pada contoh program berikut ini:

float get_cpu_usage() {
  uint32_t start_nonidle, start_idle, end_nonidle, end_idle;
  uint32_t start_total, end_total, dif_total, dif_nonidle;

  // Ambil parameter awal
  get_procstat(&start_nonidle, &start_idle);

  // Sleep selama 1 detik
  sleep(1);

  // Ambil parameter terbaru
  get_procstat(&end_nonidle, &end_idle);

  // Lakukan penghitungan total cpu
  start_total = start_nonidle + start_idle;
  end_total = end_nonidle + end_idle;

  // Hitung perbedaan awal dan akhir
  dif_total = end_total - start_total;
  dif_nonidle = end_nonidle - start_nonidle;

  // Return Persentase CPU Usage
  return (float)(((double)dif_nonidle / (double)dif_total) * 100.0);
}

Fungsi get_cpu_usage akan memberikan return berupa float persentase penggunaan CPU yang dapat digunakan selanjutnya.

Fungsi di atas akan memerlukan waktu setidaknya 1 detik sampai dia memberikan return, dan kadang bukan solusi terbaik bila yang diinginkan adalah monitoring disertai mengerjakan proses lainnya di dalam program, jadi ada baiknya dibuatkan thread khusus yang melakukan pencatatan cpu Usage dan menyimpannya pada suatu variabel yang di update setiap detiknya, dimana variabel tersebut dapat diakses oleh thread lainnya untuk kegunaan lain.

Pada Java Android, Kita juga dapat melakukan monitoring penggunaan CPU dengan contoh fungsi berikut ini:

// Ini harus di dalam class ya
private static float current_cpu_usage = 0;
private static long last_act = 0;
private static long last_idle = 0;
private static boolean cpu_usage_active=false;
private static void cpuUsageStart(){
	if (cpu_usage_active) return;
	new Thread(()->{
		cpu_usage_active = true;
		while (cpu_usage_active) {
			String p = FS.fileReadLine("/proc/stat");
			if (p != null) {
				String[] u = p.replace("  ", " ")
						.replace("  ", " ").split(" ");
				if (u.length == 11) {
					long[] v = new long[10];
					for (int i = 0; i < 10; i++) {
						try {
							v[i] = Long.parseLong(u[i + 1]);
						} catch (Exception e) {
							v[i] = 0;
						}
					}
					long act = v[0] + v[1] + v[2] + v[5] + v[6] + v[7];
					long idle = v[3] + v[4];
					long last_tot = last_act + last_idle;
					long tot = act + idle;
					long totald = tot - last_tot;
					long idled = idle - last_idle;
					if (totald!=0){
						current_cpu_usage=(float) ((((double) (totald - idled)) /
								((double) totald)) * 100.0);
					}

					last_act = act;
					last_idle = idle;
				}
			}
			try{
				// Tunggu 2 detik
				Thread.sleep(2000);
			}catch(Exception ex){
				break;
			}
		}
	}).start();
}
private static void cpuUsageStop(){
	cpu_usage_active = false;
}
private static float getCpuUsage(){
	return current_cpu_usage;
}

Kode program di atas adalah contoh bagaimana implementasi thread sederhana untuk fetch data cpu usage per 2 detik, dan hasil dari kalkukasi disimpan pada variable, dan dapat digunakan kapanpun dengan memanggil getCpuUsage() oleh thread manapun tanpa harus menunggu selama beberapa detik. Dengan syarat thread sudah berjalan dengan memanggil terlebih dahulu cpuUsageStart() pada awal program dan memberhentikannya dengan cpuUsageStop() pada akhir program.

Penutup

Seperti biasanya, kode program di atas merupakan ilustrasi, yang walaupun dapat berjalan dengan baik dan digunakan apa adanya, tapi disarankan untuk mengimplementasikannya sesuai dengan kebutuhan.

Terima Kasih, dan sampai berjumpa lagi pada pembahasan menarik lainnya.