2015-07-12 18:47:43 +00:00
/*
htop - darwin / Platform . c
( C ) 2014 Hisham H . Muhammad
( C ) 2015 David C . Hunt
Released under the GNU GPL , see the COPYING file
in the source distribution for its full text .
*/
# include "Platform.h"
# include "CPUMeter.h"
# include "MemoryMeter.h"
# include "SwapMeter.h"
# include "TasksMeter.h"
# include "LoadAverageMeter.h"
# include "ClockMeter.h"
# include "HostnameMeter.h"
# include "UptimeMeter.h"
2015-07-13 21:53:46 +00:00
# include "DarwinProcessList.h"
2015-07-12 18:47:43 +00:00
2015-07-13 06:17:14 +00:00
# include <stdlib.h>
2015-07-12 18:47:43 +00:00
/*{
# include "Action.h"
2015-11-02 15:46:04 +00:00
# include "SignalsPanel.h"
2015-10-23 15:46:21 +00:00
# include "CPUMeter.h"
2015-07-12 18:47:43 +00:00
# include "BatteryMeter.h"
# include "DarwinProcess.h"
} */
Introduce CLAMP macro. Unify all MIN(MAX(a,b),c) uses.
With the CLAMP macro replacing the combination of MIN and MAX, we will
have at least two advantages:
1. It's more obvious semantically.
2. There are no more mixes of confusing uses like MIN(MAX(a,b),c) and
MAX(MIN(a,b),c) and MIN(a,MAX(b,c)) appearing everywhere. We unify
the 'clamping' with a single macro.
Note that the behavior of this CLAMP macro is different from
the combination `MAX(low,MIN(x,high))`.
* This CLAMP macro expands to two comparisons instead of three from
MAX and MIN combination. In theory, this makes the code slightly
smaller, in case that (low) or (high) or both are computed at
runtime, so that compilers cannot optimize them. (The third
comparison will matter if (low)>(high); see below.)
* CLAMP has a side effect, that if (low)>(high) it will produce weird
results. Unlike MIN & MAX which will force either (low) or (high) to
win. No assertion of ((low)<=(high)) is done in this macro, for now.
This CLAMP macro is implemented like described in glib
<http://developer.gnome.org/glib/stable/glib-Standard-Macros.html>
and does not handle weird uses like CLAMP(a++, low++, high--) .
2016-01-15 12:26:01 +00:00
# ifndef CLAMP
# define CLAMP(x,low,high) (((x)>(high))?(high):(((x)<(low))?(low):(x)))
# endif
2015-07-12 18:47:43 +00:00
ProcessField Platform_defaultFields [ ] = { PID , USER , PRIORITY , NICE , M_SIZE , M_RESIDENT , STATE , PERCENT_CPU , PERCENT_MEM , TIME , COMM , 0 } ;
2016-08-30 12:41:17 +00:00
const SignalItem Platform_signals [ ] = {
2015-10-06 16:03:47 +00:00
{ . name = " 0 Cancel " , . number = 0 } ,
{ . name = " 1 SIGHUP " , . number = 1 } ,
{ . name = " 2 SIGINT " , . number = 2 } ,
{ . name = " 3 SIGQUIT " , . number = 3 } ,
{ . name = " 4 SIGILL " , . number = 4 } ,
{ . name = " 5 SIGTRAP " , . number = 5 } ,
{ . name = " 6 SIGABRT " , . number = 6 } ,
{ . name = " 6 SIGIOT " , . number = 6 } ,
{ . name = " 7 SIGEMT " , . number = 7 } ,
{ . name = " 8 SIGFPE " , . number = 8 } ,
{ . name = " 9 SIGKILL " , . number = 9 } ,
{ . name = " 10 SIGBUS " , . number = 10 } ,
{ . name = " 11 SIGSEGV " , . number = 11 } ,
{ . name = " 12 SIGSYS " , . number = 12 } ,
{ . name = " 13 SIGPIPE " , . number = 13 } ,
{ . name = " 14 SIGALRM " , . number = 14 } ,
{ . name = " 15 SIGTERM " , . number = 15 } ,
{ . name = " 16 SIGURG " , . number = 16 } ,
{ . name = " 17 SIGSTOP " , . number = 17 } ,
{ . name = " 18 SIGTSTP " , . number = 18 } ,
{ . name = " 19 SIGCONT " , . number = 19 } ,
{ . name = " 20 SIGCHLD " , . number = 20 } ,
{ . name = " 21 SIGTTIN " , . number = 21 } ,
{ . name = " 22 SIGTTOU " , . number = 22 } ,
{ . name = " 23 SIGIO " , . number = 23 } ,
{ . name = " 24 SIGXCPU " , . number = 24 } ,
{ . name = " 25 SIGXFSZ " , . number = 25 } ,
{ . name = " 26 SIGVTALRM " , . number = 26 } ,
{ . name = " 27 SIGPROF " , . number = 27 } ,
{ . name = " 28 SIGWINCH " , . number = 28 } ,
{ . name = " 29 SIGINFO " , . number = 29 } ,
{ . name = " 30 SIGUSR1 " , . number = 30 } ,
{ . name = " 31 SIGUSR2 " , . number = 31 } ,
} ;
2016-08-30 12:41:17 +00:00
const unsigned int Platform_numberOfSignals = sizeof ( Platform_signals ) / sizeof ( SignalItem ) ;
2015-10-06 16:03:47 +00:00
2015-07-12 18:47:43 +00:00
ProcessFieldData Process_fields [ ] = {
[ 0 ] = { . name = " " , . title = NULL , . description = NULL , . flags = 0 , } ,
[ PID ] = { . name = " PID " , . title = " PID " , . description = " Process/thread ID " , . flags = 0 , } ,
[ COMM ] = { . name = " Command " , . title = " Command " , . description = " Command line " , . flags = 0 , } ,
[ STATE ] = { . name = " STATE " , . title = " S " , . description = " Process state (S sleeping, R running, D disk, Z zombie, T traced, W paging) " , . flags = 0 , } ,
[ PPID ] = { . name = " PPID " , . title = " PPID " , . description = " Parent process ID " , . flags = 0 , } ,
[ PGRP ] = { . name = " PGRP " , . title = " PGRP " , . description = " Process group ID " , . flags = 0 , } ,
[ SESSION ] = { . name = " SESSION " , . title = " SESN " , . description = " Process's session ID " , . flags = 0 , } ,
[ TTY_NR ] = { . name = " TTY_NR " , . title = " TTY " , . description = " Controlling terminal " , . flags = 0 , } ,
[ TPGID ] = { . name = " TPGID " , . title = " TPGID " , . description = " Process ID of the fg process group of the controlling terminal " , . flags = 0 , } ,
[ MINFLT ] = { . name = " MINFLT " , . title = " MINFLT " , . description = " Number of minor faults which have not required loading a memory page from disk " , . flags = 0 , } ,
[ MAJFLT ] = { . name = " MAJFLT " , . title = " MAJFLT " , . description = " Number of major faults which have required loading a memory page from disk " , . flags = 0 , } ,
[ PRIORITY ] = { . name = " PRIORITY " , . title = " PRI " , . description = " Kernel's internal priority for the process " , . flags = 0 , } ,
[ NICE ] = { . name = " NICE " , . title = " NI " , . description = " Nice value (the higher the value, the more it lets other processes take priority) " , . flags = 0 , } ,
[ STARTTIME ] = { . name = " STARTTIME " , . title = " START " , . description = " Time the process was started " , . flags = 0 , } ,
[ PROCESSOR ] = { . name = " PROCESSOR " , . title = " CPU " , . description = " Id of the CPU the process last executed on " , . flags = 0 , } ,
[ M_SIZE ] = { . name = " M_SIZE " , . title = " VIRT " , . description = " Total program size in virtual memory " , . flags = 0 , } ,
[ M_RESIDENT ] = { . name = " M_RESIDENT " , . title = " RES " , . description = " Resident set size, size of the text and data sections, plus stack usage " , . flags = 0 , } ,
[ ST_UID ] = { . name = " ST_UID " , . title = " UID " , . description = " User ID of the process owner " , . flags = 0 , } ,
[ PERCENT_CPU ] = { . name = " PERCENT_CPU " , . title = " CPU% " , . description = " Percentage of the CPU time the process used in the last sampling " , . flags = 0 , } ,
[ PERCENT_MEM ] = { . name = " PERCENT_MEM " , . title = " MEM% " , . description = " Percentage of the memory the process is using, based on resident memory size " , . flags = 0 , } ,
[ USER ] = { . name = " USER " , . title = " USER " , . description = " Username of the process owner (or user ID if name cannot be determined) " , . flags = 0 , } ,
[ TIME ] = { . name = " TIME " , . title = " TIME+ " , . description = " Total time the process has spent in user and system time " , . flags = 0 , } ,
[ NLWP ] = { . name = " NLWP " , . title = " NLWP " , . description = " Number of threads in the process " , . flags = 0 , } ,
[ TGID ] = { . name = " TGID " , . title = " TGID " , . description = " Thread group ID (i.e. process ID) " , . flags = 0 , } ,
[ 100 ] = { . name = " *** report bug! *** " , . title = NULL , . description = NULL , . flags = 0 , } ,
} ;
MeterClass * Platform_meterTypes [ ] = {
& CPUMeter_class ,
& ClockMeter_class ,
& LoadAverageMeter_class ,
& LoadMeter_class ,
& MemoryMeter_class ,
2015-11-16 17:32:22 +00:00
& SwapMeter_class ,
2015-07-12 18:47:43 +00:00
& TasksMeter_class ,
& BatteryMeter_class ,
& HostnameMeter_class ,
& UptimeMeter_class ,
& AllCPUsMeter_class ,
& AllCPUs2Meter_class ,
& LeftCPUsMeter_class ,
& RightCPUsMeter_class ,
& LeftCPUs2Meter_class ,
& RightCPUs2Meter_class ,
& BlankMeter_class ,
NULL
} ;
void Platform_setBindings ( Htop_Action * keys ) {
( void ) keys ;
}
int Platform_numberOfFields = 100 ;
int Platform_getUptime ( ) {
2015-08-19 16:56:46 +00:00
struct timeval bootTime , currTime ;
int mib [ 2 ] = { CTL_KERN , KERN_BOOTTIME } ;
size_t size = sizeof ( bootTime ) ;
2015-07-14 02:02:40 +00:00
2015-08-19 16:56:46 +00:00
int err = sysctl ( mib , 2 , & bootTime , & size , NULL , 0 ) ;
if ( err ) {
return - 1 ;
}
gettimeofday ( & currTime , NULL ) ;
2015-07-14 02:02:40 +00:00
2015-08-19 16:56:46 +00:00
return ( int ) difftime ( currTime . tv_sec , bootTime . tv_sec ) ;
2015-07-12 18:47:43 +00:00
}
void Platform_getLoadAverage ( double * one , double * five , double * fifteen ) {
2015-07-13 06:17:14 +00:00
double results [ 3 ] ;
if ( 3 = = getloadavg ( results , 3 ) ) {
* one = results [ 0 ] ;
* five = results [ 1 ] ;
* fifteen = results [ 2 ] ;
} else {
* one = 0 ;
* five = 0 ;
* fifteen = 0 ;
}
2015-07-12 18:47:43 +00:00
}
int Platform_getMaxPid ( ) {
2015-07-13 06:17:14 +00:00
/* http://opensource.apple.com/source/xnu/xnu-2782.1.97/bsd/sys/proc_internal.hh */
return 99999 ;
2015-07-12 18:47:43 +00:00
}
2015-08-20 03:32:47 +00:00
ProcessPidColumn Process_pidColumns [ ] = {
{ . id = PID , . label = " PID " } ,
{ . id = PPID , . label = " PPID " } ,
{ . id = TPGID , . label = " TPGID " } ,
{ . id = TGID , . label = " TGID " } ,
{ . id = PGRP , . label = " PGRP " } ,
{ . id = SESSION , . label = " SESN " } ,
{ . id = 0 , . label = NULL } ,
} ;
2015-07-12 18:47:43 +00:00
2015-10-23 15:46:21 +00:00
static double Platform_setCPUAverageValues ( Meter * mtr ) {
DarwinProcessList * dpl = ( DarwinProcessList * ) mtr - > pl ;
int cpus = dpl - > super . cpuCount ;
2015-10-25 03:28:29 +00:00
double sumNice = 0.0 ;
double sumNormal = 0.0 ;
double sumKernel = 0.0 ;
double sumPercent = 0.0 ;
2015-10-23 15:46:21 +00:00
for ( int i = 1 ; i < = cpus ; i + + ) {
sumPercent + = Platform_setCPUValues ( mtr , i ) ;
sumNice + = mtr - > values [ CPU_METER_NICE ] ;
sumNormal + = mtr - > values [ CPU_METER_NORMAL ] ;
sumKernel + = mtr - > values [ CPU_METER_KERNEL ] ;
}
mtr - > values [ CPU_METER_NICE ] = sumNice / cpus ;
mtr - > values [ CPU_METER_NORMAL ] = sumNormal / cpus ;
mtr - > values [ CPU_METER_KERNEL ] = sumKernel / cpus ;
return sumPercent / cpus ;
}
2015-07-13 21:53:46 +00:00
double Platform_setCPUValues ( Meter * mtr , int cpu ) {
2015-10-23 15:46:21 +00:00
if ( cpu = = 0 ) {
return Platform_setCPUAverageValues ( mtr ) ;
}
2015-08-19 16:56:46 +00:00
DarwinProcessList * dpl = ( DarwinProcessList * ) mtr - > pl ;
processor_cpu_load_info_t prev = & dpl - > prev_load [ cpu - 1 ] ;
processor_cpu_load_info_t curr = & dpl - > curr_load [ cpu - 1 ] ;
double total = 0 ;
/* Take the sums */
for ( size_t i = 0 ; i < CPU_STATE_MAX ; + + i ) {
total + = ( double ) curr - > cpu_ticks [ i ] - ( double ) prev - > cpu_ticks [ i ] ;
}
2015-07-12 18:47:43 +00:00
2015-08-19 16:56:46 +00:00
mtr - > values [ CPU_METER_NICE ]
= ( ( double ) curr - > cpu_ticks [ CPU_STATE_NICE ] - ( double ) prev - > cpu_ticks [ CPU_STATE_NICE ] ) * 100.0 / total ;
mtr - > values [ CPU_METER_NORMAL ]
= ( ( double ) curr - > cpu_ticks [ CPU_STATE_USER ] - ( double ) prev - > cpu_ticks [ CPU_STATE_USER ] ) * 100.0 / total ;
mtr - > values [ CPU_METER_KERNEL ]
= ( ( double ) curr - > cpu_ticks [ CPU_STATE_SYSTEM ] - ( double ) prev - > cpu_ticks [ CPU_STATE_SYSTEM ] ) * 100.0 / total ;
2015-07-14 02:02:40 +00:00
2015-08-19 16:56:46 +00:00
Meter_setItems ( mtr , 3 ) ;
2015-07-14 02:02:40 +00:00
2015-08-19 16:56:46 +00:00
/* Convert to percent and return */
total = mtr - > values [ CPU_METER_NICE ] + mtr - > values [ CPU_METER_NORMAL ] + mtr - > values [ CPU_METER_KERNEL ] ;
Introduce CLAMP macro. Unify all MIN(MAX(a,b),c) uses.
With the CLAMP macro replacing the combination of MIN and MAX, we will
have at least two advantages:
1. It's more obvious semantically.
2. There are no more mixes of confusing uses like MIN(MAX(a,b),c) and
MAX(MIN(a,b),c) and MIN(a,MAX(b,c)) appearing everywhere. We unify
the 'clamping' with a single macro.
Note that the behavior of this CLAMP macro is different from
the combination `MAX(low,MIN(x,high))`.
* This CLAMP macro expands to two comparisons instead of three from
MAX and MIN combination. In theory, this makes the code slightly
smaller, in case that (low) or (high) or both are computed at
runtime, so that compilers cannot optimize them. (The third
comparison will matter if (low)>(high); see below.)
* CLAMP has a side effect, that if (low)>(high) it will produce weird
results. Unlike MIN & MAX which will force either (low) or (high) to
win. No assertion of ((low)<=(high)) is done in this macro, for now.
This CLAMP macro is implemented like described in glib
<http://developer.gnome.org/glib/stable/glib-Standard-Macros.html>
and does not handle weird uses like CLAMP(a++, low++, high--) .
2016-01-15 12:26:01 +00:00
return CLAMP ( total , 0.0 , 100.0 ) ;
2015-08-19 16:56:46 +00:00
}
void Platform_setMemoryValues ( Meter * mtr ) {
DarwinProcessList * dpl = ( DarwinProcessList * ) mtr - > pl ;
2016-01-13 19:57:29 +00:00
vm_statistics_t vm = & dpl - > vm_stats ;
2015-08-19 16:56:46 +00:00
double page_K = ( double ) vm_page_size / ( double ) 1024 ;
mtr - > total = dpl - > host_info . max_mem / 1024 ;
mtr - > values [ 0 ] = ( double ) ( vm - > active_count + vm - > wire_count ) * page_K ;
mtr - > values [ 1 ] = ( double ) vm - > purgeable_count * page_K ;
mtr - > values [ 2 ] = ( double ) vm - > inactive_count * page_K ;
2015-07-12 18:47:43 +00:00
}
2015-11-16 17:32:22 +00:00
void Platform_setSwapValues ( Meter * mtr ) {
int mib [ 2 ] = { CTL_VM , VM_SWAPUSAGE } ;
struct xsw_usage swapused ;
size_t swlen = sizeof ( swapused ) ;
sysctl ( mib , 2 , & swapused , & swlen , NULL , 0 ) ;
2015-07-12 18:47:43 +00:00
2015-11-16 17:32:22 +00:00
mtr - > total = swapused . xsu_total / 1024 ;
mtr - > values [ 0 ] = swapused . xsu_used / 1024 ;
}
2015-12-03 21:16:10 +00:00
char * Platform_getProcessEnv ( pid_t pid ) {
char * env = NULL ;
int argmax ;
size_t bufsz = sizeof ( argmax ) ;
int mib [ 3 ] ;
mib [ 0 ] = CTL_KERN ;
mib [ 1 ] = KERN_ARGMAX ;
if ( sysctl ( mib , 2 , & argmax , & bufsz , 0 , 0 ) = = 0 ) {
2016-02-02 14:53:02 +00:00
char * buf = xMalloc ( argmax ) ;
2015-12-03 21:16:10 +00:00
if ( buf ) {
mib [ 0 ] = CTL_KERN ;
mib [ 1 ] = KERN_PROCARGS2 ;
mib [ 2 ] = pid ;
size_t bufsz = argmax ;
if ( sysctl ( mib , 3 , buf , & bufsz , 0 , 0 ) = = 0 ) {
if ( bufsz > sizeof ( int ) ) {
char * p = buf , * endp = buf + bufsz ;
int argc = * ( int * ) p ;
p + = sizeof ( int ) ;
// skip exe
p = strchr ( p , 0 ) + 1 ;
// skip padding
while ( ! * p & & p < endp )
+ + p ;
// skip argv
for ( ; argc - - & & p < endp ; p = strrchr ( p , 0 ) + 1 )
;
// skip padding
while ( ! * p & & p < endp )
+ + p ;
size_t size = endp - p ;
2016-02-02 14:53:02 +00:00
env = xMalloc ( size + 2 ) ;
2016-04-30 01:10:05 +00:00
memcpy ( env , p , size ) ;
env [ size ] = 0 ;
env [ size + 1 ] = 0 ;
2015-12-03 21:16:10 +00:00
}
}
free ( buf ) ;
}
}
return env ;
}