blob: 5efad97981f198a6b4dce7b25f53e55cd45949e1 [file] [log] [blame] [raw]
/*
htop - vmkernel/VMKernelProcessList.c
(C) 2014 Hisham H. Muhammad
Copyright 2015-2026 Rivoreo
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
/*{
#include "ProcessList.h"
typedef struct {
ProcessList super;
uint32_t vsi_world_id;
uint32_t vsi_world_info_id;
uint32_t vsi_world_name_id;
uint32_t vsi_sched_id;
uint32_t vsi_sched_memclients_id;
uint32_t vsi_sched_memclients_memstats_id;
uint32_t vsi_sched_memclients_memstats_common_id;
uint32_t vsi_sched_memclients_memstats_uw_id;
uint32_t vsi_sched_cpuclients_id;
uint32_t vsi_sched_cpuclients_numvcpus_id;
uint32_t vsi_sched_vcpus_id;
uint32_t vsi_sched_vcpus_stats_id;
uint32_t vsi_sched_vcpus_stats_summarystats_id;
uint32_t vsi_sched_vcpus_stats_statetimes_id;
uint32_t vsi_userworld_id;
uint32_t vsi_userworld_cartel_id;
uint32_t vsi_userworld_cartel_cmdline_id;
uint32_t vsi_memory_id;
uint32_t vsi_memory_comprehensive_id;
uint64_t vsi_world_cksum;
uint64_t vsi_world_info_cksum;
uint64_t vsi_world_name_cksum;
uint64_t vsi_sched_cksum;
uint64_t vsi_sched_memclients_cksum;
uint64_t vsi_sched_memclients_memstats_cksum;
uint64_t vsi_sched_memclients_memstats_common_cksum;
uint64_t vsi_sched_memclients_memstats_uw_cksum;
uint64_t vsi_sched_cpuclients_cksum;
uint64_t vsi_sched_cpuclients_numvcpus_cksum;
uint64_t vsi_sched_vcpus_cksum;
uint64_t vsi_sched_vcpus_stats_cksum;
uint64_t vsi_sched_vcpus_stats_summarystats_cksum;
uint64_t vsi_sched_vcpus_stats_statetimes_cksum;
uint64_t vsi_userworld_cksum;
uint64_t vsi_userworld_cartel_cksum;
uint64_t vsi_userworld_cartel_cmdline_cksum;
uint64_t vsi_memory_cksum;
uint64_t vsi_memory_comprehensive_cksum;
size_t world_info_size;
struct timeval last_updated;
} VMKernelProcessList;
}*/
#include "VMKernelProcessList.h"
#include "VMKernelProcess.h"
#include "StringUtils.h"
#include "Settings.h"
#include "Platform.h"
#include "CRT.h"
#include <sys/time.h>
#include <sys/resource.h>
#include <limits.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <assert.h>
struct world_info {
uint32_t world_id;
uint32_t group_id;
uint32_t userspace_id;
uint32_t cartel_id;
uint32_t parent_cartel_id;
uint32_t cartel_group_id;
uint32_t session_id;
uint32_t flags;
uint32_t ref_count;
uint32_t reap_calls;
uint8_t scsi_active;
uint8_t security_domain;
#if 0
uint8_t _unknown[26];
#else
uint8_t _unknown[30];
#endif
};
// Size values are in kibibyte
struct memstats_common_32 {
uint32_t reservation;
uint32_t limit;
uint32_t reservation_limit;
int32_t shares;
uint32_t max_mem_size;
uint32_t size;
uint32_t touched;
uint32_t written;
uint32_t current_size;
uint32_t target_size;
uint32_t overhead;
uint32_t overhead_touched;
uint32_t overhead_max;
uint32_t zero;
uint32_t poison;
uint32_t swapped;
uint32_t zipped;
uint32_t llswapped;
uint32_t llswap_used;
uint32_t mapped;
uint32_t copy_on_write_mapped;
uint32_t shared_saved;
uint32_t zip_saved;
uint32_t commit_target;
uint32_t swap_target;
uint64_t pages_per_share;
uint32_t swap_scope;
uint32_t _reserved_1;
uint8_t use_reliable_mem;
uint32_t min_commit_target;
uint32_t commit_charged;
union {
struct {
uint8_t client_responsive;
} __attribute__((__packed__)) v5;
struct {
uint32_t _reserved_2;
uint8_t client_responsive;
uint8_t _reserved_3[2];
} __attribute__((__packed__)) v6;
};
} __attribute__((__packed__));
// Size values are in kibibyte
struct memstats_common_64 {
uint64_t reservation;
uint64_t limit;
uint64_t reservation_limit;
int32_t shares;
uint64_t max_mem_size;
uint64_t size;
uint64_t touched;
uint64_t written;
uint64_t current_size;
uint64_t target_size;
uint64_t overhead;
uint64_t overhead_touched;
uint64_t overhead_max;
uint64_t zero;
uint64_t poison;
uint64_t swapped;
uint64_t zipped;
uint64_t llswapped;
uint64_t ro_vpmem;
uint64_t rw_vpmem;
uint64_t uncached_vpmem;
uint64_t llswap_used;
uint64_t mapped;
uint64_t copy_on_write_mapped;
uint64_t shared_saved;
uint64_t zip_saved;
uint64_t commit_target;
uint64_t swap_target;
uint64_t pages_per_share;
uint32_t swap_scope;
uint32_t _reserved_1;
uint8_t use_reliable_mem;
uint64_t consumed;
uint64_t min_commit_target;
uint64_t commit_charged;
uint8_t client_responsive;
uint8_t _reserved_2[2];
} __attribute__((__packed__));
#if 0
struct memstats_uw_64 {
struct memstats_common64 common;
uint64_t total_reserve;
uint64_t pinned_reserve;
uint64_t mem_bstore;
uint64_t swap_bstore;
uint64_t swappable;
uint64_t shm;
uint64_t cow;
uint64_t pageable;
uint64_t pageable_unacct;
uint64_t swapped;
uint64_t pinned;
uint64_t prealloced;
} __attribute__((__packed__));
#endif
// All values are in kibibyte
struct comprehensive_memory_statistics {
uint64_t physical_memory_estimate;
uint64_t given_to_vmkernel;
uint64_t reliable_memory;
uint64_t discarded_by_vmkernel;
uint64_t mmap_critical_space;
uint64_t mmap_buddy_overhead;
uint64_t kernel_code;
uint64_t kernel_data_and_heap;
uint64_t kernel_other;
uint64_t non_kernel;
uint64_t reserved_low;
uint64_t free;
};
// All values are in kibibyte
struct comprehensive_memory_statistics_6_7 {
uint64_t physical_memory_estimate;
uint64_t given_to_vmkernel;
uint64_t reliable_memory;
uint64_t discarded_by_vmkernel;
uint64_t mmap_buddy_overhead;
uint64_t kernel_code;
uint64_t kernel_data_and_heap;
uint64_t kernel_other;
uint64_t non_kernel;
uint64_t reserved_low;
uint64_t free;
};
struct sched_allocation {
uint32_t min;
uint32_t max;
uint32_t shares;
uint32_t min_limits;
uint32_t units;
};
struct vcpu_load_metrics {
uint64_t inter_wait_run_avg;
uint64_t sleep_avg;
uint32_t cache_miss_rate;
} __attribute__((__packed__));
struct vcpu_stats_5_5 {
uint32_t world_flags;
uint32_t run_state;
uint32_t wait_state;
uint8_t paused;
uint32_t vmm_world_id;
uint32_t active_world_id;
uint32_t ht_sharing;
struct sched_allocation normalized_allocated;
struct sched_allocation internal_allocated;
uint32_t pcpu;
uint32_t effective_min;
uint8_t ht_quarantine;
uint8_t group_max_enforced;
uint64_t ht_stolen_time;
uint64_t vtime_main;
uint64_t vtime_extra;
uint64_t vtime_limit;
uint64_t vtime_ahead;
struct vcpu_load_metrics load_information;
uint64_t cpu_latency;
uint64_t mem_swap_fault_time;
uint32_t mem_swap_fault_count;
uint64_t mem_compress_fault_time;
uint32_t mem_compress_fault_count;
uint8_t _reserved[53];
} __attribute__((__packed__));
struct vcpu_stats_6_5 {
uint32_t world_flags;
uint32_t run_state;
uint32_t wait_state;
uint32_t vmm_world_id;
uint32_t active_world_id;
struct sched_allocation normalized_allocated;
struct sched_allocation internal_allocated;
uint32_t pcpu;
uint64_t _reserved[24];
} __attribute__((__packed__));
struct vcpu_state_times_5_0 {
uint64_t up_time;
uint64_t used_time;
uint64_t system_time;
uint64_t system_overlap_time;
uint64_t run_time;
uint64_t wait_time;
uint64_t co_stop_time;
uint64_t idle_time;
uint64_t ready_time;
uint64_t max_limited_time;
uint64_t paused_time;
uint64_t vmkernel_call_time;
uint64_t guest_progress_time;
uint64_t sticky_time;
uint64_t active_sticky_time;
};
struct vcpu_state_times_6_0 {
uint64_t up_time;
uint64_t used_time;
uint64_t system_time;
uint64_t system_overlap_time;
uint64_t system_distributed_time;
uint64_t run_time;
uint64_t wait_time;
uint64_t co_stop_time;
uint64_t idle_time;
uint64_t ready_time;
uint64_t max_limited_time;
uint64_t paused_time;
uint64_t vmkernel_call_time;
uint64_t guest_progress_time;
uint64_t sticky_time;
uint64_t active_sticky_time;
};
struct vcpu_state_times_6_5 {
uint64_t up_time;
uint64_t used_time;
uint64_t system_time;
uint64_t system_overlap_time;
uint64_t system_distributed_time;
uint64_t run_time;
uint64_t wait_time;
uint64_t co_stop_time;
uint64_t idle_time;
uint64_t ready_time;
uint64_t max_limited_time;
uint64_t vmkernel_call_time;
uint64_t guest_progress_time;
uint64_t sticky_time;
uint64_t active_sticky_time;
};
static const char vcpu_run_state_map_5_0[] = { 'N', 'Z', 'O', 'R', 'R', 'W' };
static const char vcpu_run_state_map_6_5[] = { 'O', 'R', 'W', 'R', 'N', 'Z' };
ProcessList* ProcessList_new(UsersTable* usersTable, const Hashtable *pidWhiteList, uid_t userId) {
VMKernelProcessList *this = xCalloc(1, sizeof(VMKernelProcessList));
ProcessList_init(&this->super, Class(VMKernelProcess), usersTable, pidWhiteList, userId);
int e = Platform_vsiGetNodeIdAndChecksum(0, "world", &this->vsi_world_id, &this->vsi_world_cksum);
if(e) CRT_fatalError("VSI_GetNodeInfo world", e);
e = Platform_vsiGetNodeIdAndChecksum(this->vsi_world_id, "info",
&this->vsi_world_info_id, &this->vsi_world_info_cksum);
if(e) CRT_fatalError("VSI_GetNodeInfo world.info", e);
e = Platform_vsiGetNodeIdAndChecksum(this->vsi_world_id, "name",
&this->vsi_world_name_id, &this->vsi_world_name_cksum);
if(e) CRT_fatalError("VSI_GetNodeInfo world.name", e);
e = Platform_vsiGetNodeIdAndChecksum(0, "sched", &this->vsi_sched_id, &this->vsi_sched_cksum);
if(e) CRT_fatalError("VSI_GetNodeInfo sched", e);
e = Platform_vsiGetNodeIdAndChecksum(this->vsi_sched_id, "memClients",
&this->vsi_sched_memclients_id, &this->vsi_sched_memclients_cksum);
if(e) CRT_fatalError("VSI_GetNodeInfo sched.memClients", e);
e = Platform_vsiGetNodeIdAndChecksum(this->vsi_sched_memclients_id, "memStats",
&this->vsi_sched_memclients_memstats_id, &this->vsi_sched_memclients_memstats_cksum);
if(e) CRT_fatalError("VSI_GetNodeInfo sched.memClients.memStats", e);
e = Platform_vsiGetNodeIdAndChecksum(this->vsi_sched_memclients_memstats_id, "totalCommon",
&this->vsi_sched_memclients_memstats_common_id, &this->vsi_sched_memclients_memstats_common_cksum);
if(e) CRT_fatalError("VSI_GetNodeInfo sched.memClients.memStats.totalCommon", e);
e = Platform_vsiGetNodeIdAndChecksum(this->vsi_sched_memclients_memstats_id, "uw",
&this->vsi_sched_memclients_memstats_uw_id, &this->vsi_sched_memclients_memstats_uw_cksum);
if(e) CRT_fatalError("VSI_GetNodeInfo sched.memClients.memStats.uw", e);
e = Platform_vsiGetNodeIdAndChecksum(this->vsi_sched_id, "cpuClients",
&this->vsi_sched_cpuclients_id, &this->vsi_sched_cpuclients_cksum);
if(e) CRT_fatalError("VSI_GetNodeInfo sched.cpuClients", e);
e = Platform_vsiGetNodeIdAndChecksum(this->vsi_sched_cpuclients_id, "numVcpus",
&this->vsi_sched_cpuclients_numvcpus_id, &this->vsi_sched_cpuclients_numvcpus_cksum);
if(e) CRT_fatalError("VSI_GetNodeInfo sched.cpuClients.numVcpus", e);
e = Platform_vsiGetNodeIdAndChecksum(this->vsi_sched_id, "Vcpus",
&this->vsi_sched_vcpus_id, &this->vsi_sched_vcpus_cksum);
if(e) CRT_fatalError("VSI_GetNodeInfo sched.Vcpus", e);
e = Platform_vsiGetNodeIdAndChecksum(this->vsi_sched_vcpus_id, "stats",
&this->vsi_sched_vcpus_stats_id, &this->vsi_sched_vcpus_stats_cksum);
if(e) CRT_fatalError("VSI_GetNodeInfo sched.Vcpus.stats", e);
e = Platform_vsiGetNodeIdAndChecksum(this->vsi_sched_vcpus_stats_id, "summaryStats",
&this->vsi_sched_vcpus_stats_summarystats_id, &this->vsi_sched_vcpus_stats_summarystats_cksum);
if(e) CRT_fatalError("VSI_GetNodeInfo sched.Vcpus.stats.summaryStats", e);
e = Platform_vsiGetNodeIdAndChecksum(this->vsi_sched_vcpus_stats_id, "stateTimes",
&this->vsi_sched_vcpus_stats_statetimes_id, &this->vsi_sched_vcpus_stats_statetimes_cksum);
if(e) CRT_fatalError("VSI_GetNodeInfo sched.Vcpus.stats.stateTimes", e);
e = Platform_vsiGetNodeIdAndChecksum(0, "userworld",
&this->vsi_userworld_id, &this->vsi_userworld_cksum);
if(e) CRT_fatalError("VSI_GetNodeInfo userworld", e);
e = Platform_vsiGetNodeIdAndChecksum(this->vsi_userworld_id, "cartel",
&this->vsi_userworld_cartel_id, &this->vsi_userworld_cartel_cksum);
if(e) CRT_fatalError("VSI_GetNodeInfo userworld.cartel", e);
e = Platform_vsiGetNodeIdAndChecksum(this->vsi_userworld_cartel_id, "cmdline",
&this->vsi_userworld_cartel_cmdline_id, &this->vsi_userworld_cartel_cmdline_cksum);
if(e) CRT_fatalError("VSI_GetNodeInfo userworld.cartel.cmdline", e);
e = Platform_vsiGetNodeIdAndChecksum(0, "memory", &this->vsi_memory_id, &this->vsi_memory_cksum);
if(e) CRT_fatalError("VSI_GetNodeInfo memory", e);
e = Platform_vsiGetNodeIdAndChecksum(this->vsi_memory_id, "comprehensive",
&this->vsi_memory_comprehensive_id, &this->vsi_memory_comprehensive_cksum);
if(e) CRT_fatalError("VSI_GetNodeInfo memory.comprehensive", e);
Platform_checkVMkernelVersion();
switch(Platform_running_vmkernel_version) {
case VMKERNEL_VERSION_5_5:
case VMKERNEL_VERSION_6_7:
this->world_info_size = 68;
break;
case VMKERNEL_VERSION_6_0:
case VMKERNEL_VERSION_6_5:
this->world_info_size = 72;
break;
}
return &this->super;
}
void ProcessList_delete(ProcessList* this) {
ProcessList_done(this);
free(this);
}
static struct vsi_list *allocate_vsi_list(uint32_t count, uint32_t string_size) {
size_t list_size = sizeof(struct vsi_list) + sizeof(struct vsi_param) * count + string_size;
struct vsi_list *list = xMalloc(list_size);
memset(list, 0, list_size);
list->type_or_version = 1;
list->allocated_count = count;
list->param_size = sizeof(struct vsi_list) + sizeof(struct vsi_param) * count;
list->string_size = string_size;
if(string_size) list->string_offset = list->param_size;
list->self_ptr = (uintptr_t)list;
return list;
}
static void get_global_memory_stats(VMKernelProcessList *this) {
struct vsi_list list = {
.type_or_version = 1, .param_size = sizeof(struct vsi_list), .self_ptr = (uintptr_t)&list
};
switch(Platform_running_vmkernel_version) {
struct comprehensive_memory_statistics stats;
struct comprehensive_memory_statistics_6_7 stats_6_7;
int e;
case VMKERNEL_VERSION_5_5:
case VMKERNEL_VERSION_6_0:
case VMKERNEL_VERSION_6_5:
e = Platform_vsiGet(this->vsi_memory_comprehensive_id, this->vsi_memory_comprehensive_cksum,
&list, &stats, sizeof stats);
if(e) goto failure;
this->super.totalMem = stats.physical_memory_estimate;
this->super.freeMem = stats.free;
this->super.usedMem = stats.physical_memory_estimate - stats.free;
break;
case VMKERNEL_VERSION_6_7:
e = Platform_vsiGet(this->vsi_memory_comprehensive_id, this->vsi_memory_comprehensive_cksum,
&list, &stats_6_7, sizeof stats_6_7);
if(e) goto failure;
this->super.totalMem = stats_6_7.physical_memory_estimate;
this->super.freeMem = stats_6_7.free;
this->super.usedMem = stats_6_7.physical_memory_estimate - stats_6_7.free;
break;
failure:
this->super.totalMem = 0;
this->super.freeMem = 0;
this->super.usedMem = 0;
break;
default:
abort();
}
}
static bool get_world_info(const VMKernelProcessList *this, Process *proc) {
struct vsi_list *list = allocate_vsi_list(1, 0);
Platform_vsiListAddInt(list, proc->pid);
struct world_info info;
assert(this->world_info_size <= sizeof info);
int e = Platform_vsiGet(this->vsi_world_info_id, this->vsi_world_info_cksum,
list, &info, this->world_info_size);
free(list);
if(e) return false;
VMKernelProcess *vmk_proc = (VMKernelProcess *)proc;
vmk_proc->group_id = info.group_id;
vmk_proc->userspace_id = info.userspace_id;
proc->tgid = info.cartel_id;
proc->ppid = info.parent_cartel_id;
vmk_proc->cartel_group_id = info.cartel_group_id;
proc->session = info.session_id;
vmk_proc->is_kernel_process = info.flags & WORLD_SYSTEM;
return true;
}
static void get_world_name(const VMKernelProcessList *this, Process *proc) {
struct vsi_list *list = allocate_vsi_list(1, 0);
Platform_vsiListAddInt(list, proc->pid);
char buffer[128];
int e = Platform_vsiGet(this->vsi_world_name_id, this->vsi_world_name_cksum,
list, buffer, sizeof buffer);
free(list);
proc->name = xStrdup(e ? "" : buffer);
}
static bool get_cartel_command(const VMKernelProcessList *this, Process *proc) {
if(proc->tgid <= 0) return false;
struct vsi_list *list = allocate_vsi_list(1, 0);
Platform_vsiListAddInt(list, proc->tgid);
char buffer[1024];
int e = Platform_vsiGet(this->vsi_userworld_cartel_cmdline_id,
this->vsi_userworld_cartel_cmdline_cksum, list, buffer, sizeof buffer);
free(list);
if(e) return false;
proc->comm = xStrdup(buffer);
return true;
}
static void get_memory_stats(const VMKernelProcessList *this, Process *proc) {
struct vsi_list *list = allocate_vsi_list(1, 0);
Platform_vsiListAddInt(list, proc->pid);
switch(Platform_running_vmkernel_version) {
struct memstats_common_32 common32;
struct memstats_common_64 common64;
int e;
case VMKERNEL_VERSION_5_5:
assert(128 < sizeof common32);
e = Platform_vsiGet(this->vsi_sched_memclients_memstats_common_id,
this->vsi_sched_memclients_memstats_common_cksum, list,
&common32, 128);
goto copy_common32_values;
case VMKERNEL_VERSION_6_0:
assert(132 == sizeof common32);
e = Platform_vsiGet(this->vsi_sched_memclients_memstats_common_id,
this->vsi_sched_memclients_memstats_common_cksum, list,
&common32, 132);
copy_common32_values:
if(e) goto failure;
proc->m_size = common32.size / CRT_page_size_kibibyte;
proc->m_resident = common32.mapped / CRT_page_size_kibibyte;
break;
case VMKERNEL_VERSION_6_5:
case VMKERNEL_VERSION_6_7:
e = Platform_vsiGet(this->vsi_sched_memclients_memstats_common_id,
this->vsi_sched_memclients_memstats_common_cksum, list,
&common64, sizeof common64);
if(e) goto failure;
proc->m_size = common64.size / CRT_page_size_kibibyte;
proc->m_resident = common64.mapped / CRT_page_size_kibibyte;
break;
failure:
proc->m_size = 0;
proc->m_resident = 0;
break;
default:
abort();
}
free(list);
}
static void get_vcpu_stats(const VMKernelProcessList *this, uint64_t interval, VMKernelProcess *proc) {
struct vsi_list *list = allocate_vsi_list(1, 0);
Platform_vsiListAddInt(list, proc->super.pid);
switch(Platform_running_vmkernel_version) {
struct vcpu_stats_5_5 stats_5_5;
struct vcpu_stats_6_5 stats_6_5;
int e;
case VMKERNEL_VERSION_5_5:
e = Platform_vsiGet(this->vsi_sched_vcpus_stats_summarystats_id,
this->vsi_sched_vcpus_stats_summarystats_cksum, list,
&stats_5_5, 204);
if(e) goto stats_failure;
goto read_5_5_stats;
case VMKERNEL_VERSION_6_0:
e = Platform_vsiGet(this->vsi_sched_vcpus_stats_summarystats_id,
this->vsi_sched_vcpus_stats_summarystats_cksum, list,
&stats_5_5, 220);
if(e) goto stats_failure;
read_5_5_stats:
proc->super.state = stats_5_5.run_state < sizeof vcpu_run_state_map_5_0 ?
vcpu_run_state_map_5_0[stats_5_5.run_state] : '?';
if(proc->super.state == 'W') {
proc->super.state = stats_5_5.wait_state ? stats_5_5.wait_state << 8 : '?';
}
proc->super.processor = stats_5_5.pcpu;
break;
case VMKERNEL_VERSION_6_5:
e = Platform_vsiGet(this->vsi_sched_vcpus_stats_summarystats_id,
this->vsi_sched_vcpus_stats_summarystats_cksum, list,
&stats_6_5, 248);
if(e) goto stats_failure;
goto read_6_5_stats;
case VMKERNEL_VERSION_6_7:
e = Platform_vsiGet(this->vsi_sched_vcpus_stats_summarystats_id,
this->vsi_sched_vcpus_stats_summarystats_cksum, list,
&stats_6_5, 256);
if(e) goto stats_failure;
read_6_5_stats:
proc->super.state = stats_6_5.run_state < sizeof vcpu_run_state_map_6_5 ?
vcpu_run_state_map_6_5[stats_6_5.run_state] : '?';
if(proc->super.state == 'W') {
proc->super.state = stats_6_5.wait_state ? stats_6_5.wait_state << 8 : '?';
}
proc->super.processor = stats_6_5.pcpu;
break;
stats_failure:
proc->super.state = '?';
proc->super.processor = -1;
break;
default:
abort();
}
free(list);
if(proc->super.state > 255) switch(Platform_running_vmkernel_version) {
case VMKERNEL_VERSION_5_5:
switch(proc->super.state >> 8) {
case 1:
case 3 ... 5:
case 53:
proc->super.state = 'L';
break;
case 2:
case 10 ... 24:
case 26:
case 28:
case 50:
case 54 ... 71:
case 73 ... 75:
case 77:
case 84:
case 88 ... 91:
case 93 ... 102:
case 106:
case 113 ... 116:
case 119:
case 125:
case 126:
proc->super.state = 'D';
break;
case 6:
case 7:
case 32 ... 47:
case 52:
proc->super.state = 'S';
break;
case 8:
case 9:
case 72:
case 76:
case 92:
case 112:
case 121:
proc->super.state = 'I';
break;
case 25:
case 27:
proc->super.state = 'V';
break;
case 29:
case 30:
case 104:
case 105:
case 110:
case 117:
case 118:
proc->super.state = 'C';
break;
case 31:
proc->super.state = 'T';
break;
case 49:
proc->super.state = 't';
break;
case 78 ... 83:
proc->super.state = 'H';
break;
default:
proc->super.state = 'W';
break;
}
break;
case VMKERNEL_VERSION_6_0:
switch(proc->super.state >> 8) {
case 1:
case 3 ... 5:
case 58:
proc->super.state = 'L';
break;
case 2:
case 11:
case 12:
case 15 ... 22:
case 24 ... 26:
case 28:
case 30:
case 35:
case 55:
case 59 ... 67:
case 69:
case 70:
case 72:
case 74 ... 82:
case 84 ... 86:
case 88 ... 90:
case 97:
case 101 ... 104:
case 106:
case 108 ... 116:
case 120:
case 143:
case 144:
case 146:
proc->super.state = 'D';
break;
case 7:
case 39:
case 45:
case 50:
case 51:
case 52:
case 57:
proc->super.state = 'S';
break;
case 8:
case 10:
case 13:
case 14:
case 23:
case 27:
case 32:
case 68:
case 71:
case 73:
case 83:
case 87:
case 105:
case 107:
case 126:
case 131 ... 133:
case 136:
proc->super.state = 'I';
break;
case 29:
proc->super.state = 'V';
break;
case 31:
case 33:
case 34:
case 118:
case 119:
case 124:
proc->super.state = 'C';
break;
case 36:
proc->super.state = 'T';
break;
case 54:
case 142:
proc->super.state = 't';
break;
case 91 ... 96:
case 137:
proc->super.state = 'H';
break;
default:
proc->super.state = 'W';
break;
}
break;
case VMKERNEL_VERSION_6_5:
switch(proc->super.state >> 8) {
case 1 ... 5:
case 57:
proc->super.state = 'L';
break;
case 6:
case 37 ... 52:
case 56:
proc->super.state = 'S';
break;
case 7:
case 8:
case 11:
case 13:
case 33:
case 65:
case 68:
case 70:
case 71:
case 90:
case 107 ... 109:
case 113:
case 130:
case 135 ... 137:
case 140:
proc->super.state = 'I';
break;
case 9:
case 10:
case 12:
case 14:
case 19 ... 32:
case 34:
case 35:
case 55:
case 58 ... 64:
case 66:
case 67:
case 69:
case 72 ... 89:
case 91 ... 95:
case 101:
case 104 ... 106:
case 110 ... 112:
case 114 ... 122:
case 149:
case 151 ... 153:
proc->super.state = 'D';
break;
case 15:
proc->super.state = 'V';
break;
case 16 ... 18:
case 102:
case 124:
case 128:
proc->super.state = 'C';
break;
case 36:
proc->super.state = 'T';
break;
case 54:
case 139:
case 145:
proc->super.state = 't';
break;
case 96 ... 100:
case 141:
proc->super.state = 'H';
break;
default:
proc->super.state = 'W';
break;
}
break;
case VMKERNEL_VERSION_6_7:
switch(proc->super.state >> 8) {
case 1 ... 5:
case 59:
case 82:
proc->super.state = 'L';
break;
case 6:
case 39 ... 54:
case 58:
case 62:
proc->super.state = 'S';
break;
case 7:
case 8:
case 12:
case 14:
case 35:
case 69:
case 72:
case 74:
case 75:
case 98:
case 115 ... 117:
case 121:
case 139:
case 144 ... 146:
case 149:
proc->super.state = 'I';
break;
case 9 ... 11:
case 13:
case 15:
case 20 ... 34:
case 36:
case 37:
case 57:
case 60:
case 61:
case 64 ... 68:
case 70:
case 71:
case 73:
case 76 ... 81:
case 83 ... 97:
case 99 ... 103:
case 109:
case 112 ... 114:
case 118 ... 120:
case 122 ... 131:
case 159:
case 161:
case 162:
case 165:
proc->super.state = 'D';
break;
case 16:
proc->super.state = 'V';
break;
case 17 ... 19:
case 110:
case 133:
case 137:
proc->super.state = 'C';
break;
case 38:
proc->super.state = 'T';
break;
case 56:
case 63:
case 155:
proc->super.state = 't';
break;
case 104 ... 108:
case 150:
proc->super.state = 'H';
break;
default:
proc->super.state = 'W';
break;
}
break;
}
uint64_t diff = proc->time_usec;
list = allocate_vsi_list(1, 0);
Platform_vsiListAddInt(list, proc->super.pid);
switch(Platform_running_vmkernel_version) {
struct vcpu_state_times_5_0 state_times_5_0;
struct vcpu_state_times_6_0 state_times_6_0;
struct vcpu_state_times_6_5 state_times_6_5;
int e;
case VMKERNEL_VERSION_5_5:
e = Platform_vsiGet(this->vsi_sched_vcpus_stats_statetimes_id,
this->vsi_sched_vcpus_stats_statetimes_cksum, list,
&state_times_5_0, sizeof state_times_5_0);
if(e) break;
if(proc->super.starttime_ctime == (time_t)-1) {
proc->super.starttime_ctime = this->last_updated.tv_sec - state_times_5_0.up_time / 1000000;
}
proc->time_usec = state_times_5_0.run_time;
break;
case VMKERNEL_VERSION_6_0:
e = Platform_vsiGet(this->vsi_sched_vcpus_stats_statetimes_id,
this->vsi_sched_vcpus_stats_statetimes_cksum, list,
&state_times_6_0, sizeof state_times_6_0);
if(e) break;
if(proc->super.starttime_ctime == (time_t)-1) {
proc->super.starttime_ctime = this->last_updated.tv_sec - state_times_6_0.up_time / 1000000;
}
proc->time_usec = state_times_6_0.run_time;
break;
case VMKERNEL_VERSION_6_5:
case VMKERNEL_VERSION_6_7:
e = Platform_vsiGet(this->vsi_sched_vcpus_stats_statetimes_id,
this->vsi_sched_vcpus_stats_statetimes_cksum, list,
&state_times_6_5, sizeof state_times_6_5);
if(e) break;
if(proc->super.starttime_ctime == (time_t)-1) {
proc->super.starttime_ctime = this->last_updated.tv_sec - state_times_6_5.up_time / 1000000;
}
proc->time_usec = state_times_6_5.run_time;
break;
default:
abort();
}
free(list);
// Just use last value if VSI_Get failed
diff = proc->time_usec < diff ? 0 : proc->time_usec - diff;
proc->super.time = proc->time_usec / 10000;
if(interval) proc->super.percent_cpu = (double)diff / (double)interval * 100;
if(this->super.settings->flags & PROCESS_FLAG_VMKERNEL_VCPU_COUNT) {
list = allocate_vsi_list(1, 0);
Platform_vsiListAddInt(list, proc->super.pid);
int e = Platform_vsiGet(this->vsi_sched_cpuclients_numvcpus_id,
this->vsi_sched_cpuclients_numvcpus_cksum, list,
&proc->vcpu_count, sizeof proc->vcpu_count);
free(list);
if(e) proc->vcpu_count = 0;
}
}
void ProcessList_goThroughEntries(ProcessList *super, bool skip_processes) {
VMKernelProcessList *this = (VMKernelProcessList *)super;
struct timeval now;
gettimeofday(&now, NULL);
uint64_t interval_usec = now.tv_sec < this->last_updated.tv_sec ?
0 : (uint64_t)(now.tv_sec - this->last_updated.tv_sec) * 1000000 +
(now.tv_usec - this->last_updated.tv_usec);
this->last_updated = now;
get_global_memory_stats(this);
struct vsi_list *worlds_list = xMalloc(sizeof(struct vsi_list));
memset(worlds_list, 0, sizeof(struct vsi_list));
worlds_list->type_or_version = 1;
worlds_list->param_size = sizeof(struct vsi_list);
worlds_list->self_ptr = (uintptr_t)worlds_list;
int e = Platform_vsiGetList(this->vsi_world_id, this->vsi_world_cksum,
worlds_list, sizeof(struct vsi_list));
if(e) CRT_fatalError("VSI_GetList", e);
size_t count = worlds_list->instance_count;
worlds_list->instance_count = 0;
size_t param_size = sizeof(struct vsi_list) + sizeof(struct vsi_param) * count;
size_t string_size = 128 * count;
size_t list_size = param_size + string_size;
worlds_list = xRealloc(worlds_list, list_size);
worlds_list->allocated_count = count;
worlds_list->param_size = param_size;
worlds_list->string_size = string_size;
worlds_list->string_offset = param_size;
worlds_list->self_ptr = (uintptr_t)worlds_list;
e = Platform_vsiGetList(this->vsi_world_id, this->vsi_world_cksum, worlds_list, list_size);
if(e) CRT_fatalError("VSI_GetList", e);
for(size_t i = 0; i < worlds_list->instance_count; i++) {
pid_t pid = Platform_vsiListGetValue(worlds_list, i);
bool is_existing;
Process *proc = ProcessList_getProcess(super, pid, &is_existing, (Process_New)VMKernelProcess_new);
if(!get_world_info(this, proc)) {
if(!is_existing) Process_delete((Object *)proc);
continue;
}
if(!is_existing) {
proc->state = '?';
ProcessList_add(super, proc);
}
get_memory_stats(this, proc);
get_vcpu_stats(this, interval_usec, (VMKernelProcess *)proc);
if(super->settings->flags & PROCESS_FLAG_VMKERNEL_PRIORITY) {
errno = 0;
proc->nice = getpriority(PRIO_PROCESS, pid);
if(proc->nice == -1 && errno) proc->nice = INT_MAX;
}
if(!is_existing || ProcessList_shouldUpdateProcessNames(super)) {
free(proc->name);
free(proc->comm);
get_world_name(this, proc);
if(!get_cartel_command(this, proc)) proc->comm = xStrdup(proc->name);
}
if(Process_isKernelProcess(proc)) {
super->kernel_process_count++;
super->kernel_thread_count++;
if(proc->tgid == 0) proc->tgid = pid;
}
super->totalTasks++;
if(proc->state == 'O') {
super->running_thread_count++;
super->running_process_count++;
}
proc->updated = true;
}
free(worlds_list);
}