mirror of https://github.com/xzeldon/htop.git
Merge branch 'cpu_count' of cgzones/htop
This commit is contained in:
commit
ed82ce6456
|
@ -17,7 +17,7 @@ jobs:
|
||||||
- name: Bootstrap
|
- name: Bootstrap
|
||||||
run: ./autogen.sh
|
run: ./autogen.sh
|
||||||
- name: Configure
|
- name: Configure
|
||||||
run: ./configure --enable-werror --enable-linux-affinity --disable-unicode --disable-sensors
|
run: ./configure --enable-werror --enable-affinity --disable-unicode --disable-sensors
|
||||||
- name: Enable compatibility modes
|
- name: Enable compatibility modes
|
||||||
run: |
|
run: |
|
||||||
sed -i 's/#define HAVE_FSTATAT 1/#undef HAVE_FSTATAT/g' config.h
|
sed -i 's/#define HAVE_FSTATAT 1/#undef HAVE_FSTATAT/g' config.h
|
||||||
|
@ -26,7 +26,7 @@ jobs:
|
||||||
- name: Build
|
- name: Build
|
||||||
run: make -k
|
run: make -k
|
||||||
- name: Distcheck
|
- name: Distcheck
|
||||||
run: make distcheck DISTCHECK_CONFIGURE_FLAGS="--enable-werror --enable-linux-affinity --disable-unicode --disable-sensors"
|
run: make distcheck DISTCHECK_CONFIGURE_FLAGS="--enable-werror --enable-affinity --disable-unicode --disable-sensors"
|
||||||
|
|
||||||
build-ubuntu-latest-minimal-clang:
|
build-ubuntu-latest-minimal-clang:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
@ -44,11 +44,11 @@ jobs:
|
||||||
- name: Bootstrap
|
- name: Bootstrap
|
||||||
run: ./autogen.sh
|
run: ./autogen.sh
|
||||||
- name: Configure
|
- name: Configure
|
||||||
run: ./configure --enable-werror --enable-linux-affinity --disable-unicode --disable-sensors
|
run: ./configure --enable-werror --enable-affinity --disable-unicode --disable-sensors
|
||||||
- name: Build
|
- name: Build
|
||||||
run: make -k
|
run: make -k
|
||||||
- name: Distcheck
|
- name: Distcheck
|
||||||
run: make distcheck DISTCHECK_CONFIGURE_FLAGS="--enable-werror --enable-linux-affinity --disable-unicode --disable-sensors"
|
run: make distcheck DISTCHECK_CONFIGURE_FLAGS="--enable-werror --enable-affinity --disable-unicode --disable-sensors"
|
||||||
|
|
||||||
build-ubuntu-latest-full-featured-gcc:
|
build-ubuntu-latest-full-featured-gcc:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
13
Action.c
13
Action.c
|
@ -34,7 +34,7 @@ in the source distribution for its full text.
|
||||||
#include "Vector.h"
|
#include "Vector.h"
|
||||||
#include "XUtils.h"
|
#include "XUtils.h"
|
||||||
|
|
||||||
#if (defined(HAVE_LIBHWLOC) || defined(HAVE_LINUX_AFFINITY))
|
#if (defined(HAVE_LIBHWLOC) || defined(HAVE_AFFINITY))
|
||||||
#include "Affinity.h"
|
#include "Affinity.h"
|
||||||
#include "AffinityPanel.h"
|
#include "AffinityPanel.h"
|
||||||
#endif
|
#endif
|
||||||
|
@ -302,10 +302,10 @@ static Htop_Reaction actionSetAffinity(State* st) {
|
||||||
if (Settings_isReadonly())
|
if (Settings_isReadonly())
|
||||||
return HTOP_OK;
|
return HTOP_OK;
|
||||||
|
|
||||||
if (st->pl->cpuCount == 1)
|
if (st->pl->activeCPUs == 1)
|
||||||
return HTOP_OK;
|
return HTOP_OK;
|
||||||
|
|
||||||
#if (defined(HAVE_LIBHWLOC) || defined(HAVE_LINUX_AFFINITY))
|
#if (defined(HAVE_LIBHWLOC) || defined(HAVE_AFFINITY))
|
||||||
const Process* p = (const Process*) Panel_getSelected((Panel*)st->mainPanel);
|
const Process* p = (const Process*) Panel_getSelected((Panel*)st->mainPanel);
|
||||||
if (!p)
|
if (!p)
|
||||||
return HTOP_OK;
|
return HTOP_OK;
|
||||||
|
@ -328,8 +328,11 @@ static Htop_Reaction actionSetAffinity(State* st) {
|
||||||
Affinity_delete(affinity2);
|
Affinity_delete(affinity2);
|
||||||
}
|
}
|
||||||
Object_delete(affinityPanel);
|
Object_delete(affinityPanel);
|
||||||
#endif
|
|
||||||
return HTOP_REFRESH | HTOP_REDRAW_BAR | HTOP_UPDATE_PANELHDR;
|
return HTOP_REFRESH | HTOP_REDRAW_BAR | HTOP_UPDATE_PANELHDR;
|
||||||
|
#else
|
||||||
|
return HTOP_OK;
|
||||||
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static Htop_Reaction actionKill(State* st) {
|
static Htop_Reaction actionKill(State* st) {
|
||||||
|
@ -484,7 +487,7 @@ static const struct {
|
||||||
{ .key = " F9 k: ", .roInactive = true, .info = "kill process/tagged processes" },
|
{ .key = " F9 k: ", .roInactive = true, .info = "kill process/tagged processes" },
|
||||||
{ .key = " F7 ]: ", .roInactive = true, .info = "higher priority (root only)" },
|
{ .key = " F7 ]: ", .roInactive = true, .info = "higher priority (root only)" },
|
||||||
{ .key = " F8 [: ", .roInactive = false, .info = "lower priority (+ nice)" },
|
{ .key = " F8 [: ", .roInactive = false, .info = "lower priority (+ nice)" },
|
||||||
#if (defined(HAVE_LIBHWLOC) || defined(HAVE_LINUX_AFFINITY))
|
#if (defined(HAVE_LIBHWLOC) || defined(HAVE_AFFINITY))
|
||||||
{ .key = " a: ", .roInactive = true, .info = "set CPU affinity" },
|
{ .key = " a: ", .roInactive = true, .info = "set CPU affinity" },
|
||||||
#endif
|
#endif
|
||||||
{ .key = " e: ", .roInactive = false, .info = "show process environment" },
|
{ .key = " e: ", .roInactive = false, .info = "show process environment" },
|
||||||
|
|
|
@ -22,7 +22,7 @@ in the source distribution for its full text.
|
||||||
#else
|
#else
|
||||||
#define HTOP_HWLOC_CPUBIND_FLAG HWLOC_CPUBIND_PROCESS
|
#define HTOP_HWLOC_CPUBIND_FLAG HWLOC_CPUBIND_PROCESS
|
||||||
#endif
|
#endif
|
||||||
#elif defined(HAVE_LINUX_AFFINITY)
|
#elif defined(HAVE_AFFINITY)
|
||||||
#include <sched.h>
|
#include <sched.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -59,7 +59,7 @@ Affinity* Affinity_get(const Process* proc, ProcessList* pl) {
|
||||||
if (ok) {
|
if (ok) {
|
||||||
affinity = Affinity_new(pl);
|
affinity = Affinity_new(pl);
|
||||||
if (hwloc_bitmap_last(cpuset) == -1) {
|
if (hwloc_bitmap_last(cpuset) == -1) {
|
||||||
for (unsigned int i = 0; i < pl->cpuCount; i++) {
|
for (unsigned int i = 0; i < pl->existingCPUs; i++) {
|
||||||
Affinity_add(affinity, i);
|
Affinity_add(affinity, i);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -84,7 +84,7 @@ bool Affinity_set(Process* proc, Arg arg) {
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
#elif defined(HAVE_LINUX_AFFINITY)
|
#elif defined(HAVE_AFFINITY)
|
||||||
|
|
||||||
Affinity* Affinity_get(const Process* proc, ProcessList* pl) {
|
Affinity* Affinity_get(const Process* proc, ProcessList* pl) {
|
||||||
cpu_set_t cpuset;
|
cpu_set_t cpuset;
|
||||||
|
@ -93,7 +93,7 @@ Affinity* Affinity_get(const Process* proc, ProcessList* pl) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
Affinity* affinity = Affinity_new(pl);
|
Affinity* affinity = Affinity_new(pl);
|
||||||
for (unsigned int i = 0; i < pl->cpuCount; i++) {
|
for (unsigned int i = 0; i < pl->existingCPUs; i++) {
|
||||||
if (CPU_ISSET(i, &cpuset)) {
|
if (CPU_ISSET(i, &cpuset)) {
|
||||||
Affinity_add(affinity, i);
|
Affinity_add(affinity, i);
|
||||||
}
|
}
|
||||||
|
|
10
Affinity.h
10
Affinity.h
|
@ -12,7 +12,7 @@ in the source distribution for its full text.
|
||||||
|
|
||||||
#include "ProcessList.h"
|
#include "ProcessList.h"
|
||||||
|
|
||||||
#if defined(HAVE_LIBHWLOC) || defined(HAVE_LINUX_AFFINITY)
|
#if defined(HAVE_LIBHWLOC) || defined(HAVE_AFFINITY)
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
#include "Object.h"
|
#include "Object.h"
|
||||||
|
@ -20,8 +20,8 @@ in the source distribution for its full text.
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#if defined(HAVE_LIBHWLOC) && defined(HAVE_LINUX_AFFINITY)
|
#if defined(HAVE_LIBHWLOC) && defined(HAVE_AFFINITY)
|
||||||
#error hwloc and linux affinity are mutual exclusive.
|
#error hwloc and affinity support are mutual exclusive.
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
@ -38,12 +38,12 @@ void Affinity_delete(Affinity* this);
|
||||||
|
|
||||||
void Affinity_add(Affinity* this, unsigned int id);
|
void Affinity_add(Affinity* this, unsigned int id);
|
||||||
|
|
||||||
#if defined(HAVE_LIBHWLOC) || defined(HAVE_LINUX_AFFINITY)
|
#if defined(HAVE_LIBHWLOC) || defined(HAVE_AFFINITY)
|
||||||
|
|
||||||
Affinity* Affinity_get(const Process* proc, ProcessList* pl);
|
Affinity* Affinity_get(const Process* proc, ProcessList* pl);
|
||||||
|
|
||||||
bool Affinity_set(Process* proc, Arg arg);
|
bool Affinity_set(Process* proc, Arg arg);
|
||||||
|
|
||||||
#endif /* HAVE_LIBHWLOC || HAVE_LINUX_AFFINITY */
|
#endif /* HAVE_LIBHWLOC || HAVE_AFFINITY */
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -383,7 +383,10 @@ Panel* AffinityPanel_new(ProcessList* pl, const Affinity* affinity, int* width)
|
||||||
Panel_setHeader(super, "Use CPUs:");
|
Panel_setHeader(super, "Use CPUs:");
|
||||||
|
|
||||||
unsigned int curCpu = 0;
|
unsigned int curCpu = 0;
|
||||||
for (unsigned int i = 0; i < pl->cpuCount; i++) {
|
for (unsigned int i = 0; i < pl->existingCPUs; i++) {
|
||||||
|
if (!ProcessList_isCPUonline(this->pl, i))
|
||||||
|
continue;
|
||||||
|
|
||||||
char number[16];
|
char number[16];
|
||||||
xSnprintf(number, 9, "CPU %d", Settings_cpuId(pl->settings, i));
|
xSnprintf(number, 9, "CPU %d", Settings_cpuId(pl->settings, i));
|
||||||
unsigned cpu_width = 4 + strlen(number);
|
unsigned cpu_width = 4 + strlen(number);
|
||||||
|
@ -427,7 +430,7 @@ Affinity* AffinityPanel_getAffinity(Panel* super, ProcessList* pl) {
|
||||||
Affinity_add(affinity, i);
|
Affinity_add(affinity, i);
|
||||||
hwloc_bitmap_foreach_end();
|
hwloc_bitmap_foreach_end();
|
||||||
#else
|
#else
|
||||||
for (unsigned int i = 0; i < this->pl->cpuCount; i++) {
|
for (int i = 0; i < Vector_size(this->cpuids); i++) {
|
||||||
const MaskItem* item = (const MaskItem*)Vector_get(this->cpuids, i);
|
const MaskItem* item = (const MaskItem*)Vector_get(this->cpuids, i);
|
||||||
if (item->value) {
|
if (item->value) {
|
||||||
Affinity_add(affinity, item->cpu);
|
Affinity_add(affinity, item->cpu);
|
||||||
|
|
|
@ -94,9 +94,9 @@ const PanelClass AvailableMetersPanel_class = {
|
||||||
|
|
||||||
// Handle (&CPUMeter_class) entries in the AvailableMetersPanel
|
// Handle (&CPUMeter_class) entries in the AvailableMetersPanel
|
||||||
static void AvailableMetersPanel_addCPUMeters(Panel* super, const MeterClass* type, const ProcessList* pl) {
|
static void AvailableMetersPanel_addCPUMeters(Panel* super, const MeterClass* type, const ProcessList* pl) {
|
||||||
if (pl->cpuCount > 1) {
|
if (pl->existingCPUs > 1) {
|
||||||
Panel_add(super, (Object*) ListItem_new("CPU average", 0));
|
Panel_add(super, (Object*) ListItem_new("CPU average", 0));
|
||||||
for (unsigned int i = 1; i <= pl->cpuCount; i++) {
|
for (unsigned int i = 1; i <= pl->existingCPUs; i++) {
|
||||||
char buffer[50];
|
char buffer[50];
|
||||||
xSnprintf(buffer, sizeof(buffer), "%s %d", type->uiName, Settings_cpuId(pl->settings, i - 1));
|
xSnprintf(buffer, sizeof(buffer), "%s %d", type->uiName, Settings_cpuId(pl->settings, i - 1));
|
||||||
Panel_add(super, (Object*) ListItem_new(buffer, i));
|
Panel_add(super, (Object*) ListItem_new(buffer, i));
|
||||||
|
|
21
CPUMeter.c
21
CPUMeter.c
|
@ -43,7 +43,7 @@ static void CPUMeter_init(Meter* this) {
|
||||||
unsigned int cpu = this->param;
|
unsigned int cpu = this->param;
|
||||||
if (cpu == 0) {
|
if (cpu == 0) {
|
||||||
Meter_setCaption(this, "Avg");
|
Meter_setCaption(this, "Avg");
|
||||||
} else if (this->pl->cpuCount > 1) {
|
} else if (this->pl->activeCPUs > 1) {
|
||||||
char caption[10];
|
char caption[10];
|
||||||
xSnprintf(caption, sizeof(caption), "%3u", Settings_cpuId(this->pl->settings, cpu - 1));
|
xSnprintf(caption, sizeof(caption), "%3u", Settings_cpuId(this->pl->settings, cpu - 1));
|
||||||
Meter_setCaption(this, caption);
|
Meter_setCaption(this, caption);
|
||||||
|
@ -59,21 +59,24 @@ static void CPUMeter_getUiName(const Meter* this, char* buffer, size_t length) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void CPUMeter_updateValues(Meter* this) {
|
static void CPUMeter_updateValues(Meter* this) {
|
||||||
|
memset(this->values, 0, sizeof(double) * CPU_METER_ITEMCOUNT);
|
||||||
|
|
||||||
unsigned int cpu = this->param;
|
unsigned int cpu = this->param;
|
||||||
if (cpu > this->pl->cpuCount) {
|
if (cpu > this->pl->existingCPUs) {
|
||||||
xSnprintf(this->txtBuffer, sizeof(this->txtBuffer), "absent");
|
xSnprintf(this->txtBuffer, sizeof(this->txtBuffer), "absent");
|
||||||
for (uint8_t i = 0; i < this->curItems; i++)
|
|
||||||
this->values[i] = 0;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
memset(this->values, 0, sizeof(double) * CPU_METER_ITEMCOUNT);
|
|
||||||
|
double percent = Platform_setCPUValues(this, cpu);
|
||||||
|
if (isnan(percent)) {
|
||||||
|
xSnprintf(this->txtBuffer, sizeof(this->txtBuffer), "offline");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
char cpuUsageBuffer[8] = { 0 };
|
char cpuUsageBuffer[8] = { 0 };
|
||||||
char cpuFrequencyBuffer[16] = { 0 };
|
char cpuFrequencyBuffer[16] = { 0 };
|
||||||
char cpuTemperatureBuffer[16] = { 0 };
|
char cpuTemperatureBuffer[16] = { 0 };
|
||||||
|
|
||||||
double percent = Platform_setCPUValues(this, cpu);
|
|
||||||
|
|
||||||
if (this->pl->settings->showCPUUsage) {
|
if (this->pl->settings->showCPUUsage) {
|
||||||
xSnprintf(cpuUsageBuffer, sizeof(cpuUsageBuffer), "%.1f%%", percent);
|
xSnprintf(cpuUsageBuffer, sizeof(cpuUsageBuffer), "%.1f%%", percent);
|
||||||
}
|
}
|
||||||
|
@ -112,7 +115,7 @@ static void CPUMeter_display(const Object* cast, RichString* out) {
|
||||||
int len;
|
int len;
|
||||||
const Meter* this = (const Meter*)cast;
|
const Meter* this = (const Meter*)cast;
|
||||||
|
|
||||||
if (this->param > this->pl->cpuCount) {
|
if (this->param > this->pl->existingCPUs) {
|
||||||
RichString_appendAscii(out, CRT_colors[METER_TEXT], "absent");
|
RichString_appendAscii(out, CRT_colors[METER_TEXT], "absent");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -206,7 +209,7 @@ static void AllCPUsMeter_updateValues(Meter* this) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void CPUMeterCommonInit(Meter* this, int ncol) {
|
static void CPUMeterCommonInit(Meter* this, int ncol) {
|
||||||
unsigned int cpus = this->pl->cpuCount;
|
unsigned int cpus = this->pl->existingCPUs;
|
||||||
CPUMeterData* data = this->meterData;
|
CPUMeterData* data = this->meterData;
|
||||||
if (!data) {
|
if (!data) {
|
||||||
data = this->meterData = xMalloc(sizeof(CPUMeterData));
|
data = this->meterData = xMalloc(sizeof(CPUMeterData));
|
||||||
|
|
|
@ -295,7 +295,7 @@ int CommandLine_run(const char* name, int argc, char** argv) {
|
||||||
Hashtable* dm = DynamicMeters_new();
|
Hashtable* dm = DynamicMeters_new();
|
||||||
ProcessList* pl = ProcessList_new(ut, dm, flags.pidMatchList, flags.userId);
|
ProcessList* pl = ProcessList_new(ut, dm, flags.pidMatchList, flags.userId);
|
||||||
|
|
||||||
Settings* settings = Settings_new(pl->cpuCount);
|
Settings* settings = Settings_new(pl->activeCPUs);
|
||||||
pl->settings = settings;
|
pl->settings = settings;
|
||||||
|
|
||||||
Header* header = Header_new(pl, settings, 2);
|
Header* header = Header_new(pl, settings, 2);
|
||||||
|
|
|
@ -47,12 +47,12 @@ static void LoadAverageMeter_updateValues(Meter* this) {
|
||||||
if (this->values[0] < 1.0) {
|
if (this->values[0] < 1.0) {
|
||||||
this->curAttributes = OK_attributes;
|
this->curAttributes = OK_attributes;
|
||||||
this->total = 1.0;
|
this->total = 1.0;
|
||||||
} else if (this->values[0] < this->pl->cpuCount) {
|
} else if (this->values[0] < this->pl->activeCPUs) {
|
||||||
this->curAttributes = Medium_attributes;
|
this->curAttributes = Medium_attributes;
|
||||||
this->total = this->pl->cpuCount;
|
this->total = this->pl->activeCPUs;
|
||||||
} else {
|
} else {
|
||||||
this->curAttributes = High_attributes;
|
this->curAttributes = High_attributes;
|
||||||
this->total = 2 * this->pl->cpuCount;
|
this->total = 2 * this->pl->activeCPUs;
|
||||||
}
|
}
|
||||||
|
|
||||||
xSnprintf(this->txtBuffer, sizeof(this->txtBuffer), "%.2f/%.2f/%.2f", this->values[0], this->values[1], this->values[2]);
|
xSnprintf(this->txtBuffer, sizeof(this->txtBuffer), "%.2f/%.2f/%.2f", this->values[0], this->values[1], this->values[2]);
|
||||||
|
@ -79,12 +79,12 @@ static void LoadMeter_updateValues(Meter* this) {
|
||||||
if (this->values[0] < 1.0) {
|
if (this->values[0] < 1.0) {
|
||||||
this->curAttributes = OK_attributes;
|
this->curAttributes = OK_attributes;
|
||||||
this->total = 1.0;
|
this->total = 1.0;
|
||||||
} else if (this->values[0] < this->pl->cpuCount) {
|
} else if (this->values[0] < this->pl->activeCPUs) {
|
||||||
this->curAttributes = Medium_attributes;
|
this->curAttributes = Medium_attributes;
|
||||||
this->total = this->pl->cpuCount;
|
this->total = this->pl->activeCPUs;
|
||||||
} else {
|
} else {
|
||||||
this->curAttributes = High_attributes;
|
this->curAttributes = High_attributes;
|
||||||
this->total = 2 * this->pl->cpuCount;
|
this->total = 2 * this->pl->activeCPUs;
|
||||||
}
|
}
|
||||||
|
|
||||||
xSnprintf(this->txtBuffer, sizeof(this->txtBuffer), "%.2f", this->values[0]);
|
xSnprintf(this->txtBuffer, sizeof(this->txtBuffer), "%.2f", this->values[0]);
|
||||||
|
|
|
@ -824,7 +824,7 @@ void Process_writeField(const Process* this, RichString* str, ProcessField field
|
||||||
case PERCENT_NORM_CPU: {
|
case PERCENT_NORM_CPU: {
|
||||||
float cpuPercentage = this->percent_cpu;
|
float cpuPercentage = this->percent_cpu;
|
||||||
if (field == PERCENT_NORM_CPU) {
|
if (field == PERCENT_NORM_CPU) {
|
||||||
cpuPercentage /= this->processList->cpuCount;
|
cpuPercentage /= this->processList->activeCPUs;
|
||||||
}
|
}
|
||||||
if (cpuPercentage > 999.9F) {
|
if (cpuPercentage > 999.9F) {
|
||||||
xSnprintf(buffer, n, "%4u ", (unsigned int)cpuPercentage);
|
xSnprintf(buffer, n, "%4u ", (unsigned int)cpuPercentage);
|
||||||
|
|
|
@ -34,7 +34,8 @@ ProcessList* ProcessList_init(ProcessList* this, const ObjectClass* klass, Users
|
||||||
this->userId = userId;
|
this->userId = userId;
|
||||||
|
|
||||||
// set later by platform-specific code
|
// set later by platform-specific code
|
||||||
this->cpuCount = 0;
|
this->activeCPUs = 0;
|
||||||
|
this->existingCPUs = 0;
|
||||||
this->monotonicMs = 0;
|
this->monotonicMs = 0;
|
||||||
|
|
||||||
// always maintain valid realtime timestamps
|
// always maintain valid realtime timestamps
|
||||||
|
|
|
@ -83,12 +83,15 @@ typedef struct ProcessList_ {
|
||||||
memory_t usedSwap;
|
memory_t usedSwap;
|
||||||
memory_t cachedSwap;
|
memory_t cachedSwap;
|
||||||
|
|
||||||
unsigned int cpuCount;
|
unsigned int activeCPUs;
|
||||||
|
unsigned int existingCPUs;
|
||||||
} ProcessList;
|
} ProcessList;
|
||||||
|
|
||||||
|
/* Implemented by platforms */
|
||||||
ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* dynamicMeters, Hashtable* pidMatchList, uid_t userId);
|
ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* dynamicMeters, Hashtable* pidMatchList, uid_t userId);
|
||||||
void ProcessList_delete(ProcessList* pl);
|
void ProcessList_delete(ProcessList* pl);
|
||||||
void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate);
|
void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate);
|
||||||
|
bool ProcessList_isCPUonline(const ProcessList* super, unsigned int id);
|
||||||
|
|
||||||
|
|
||||||
ProcessList* ProcessList_init(ProcessList* this, const ObjectClass* klass, UsersTable* usersTable, Hashtable* dynamicMeters, Hashtable* pidMatchList, uid_t userId);
|
ProcessList* ProcessList_init(ProcessList* this, const ObjectClass* klass, UsersTable* usersTable, Hashtable* dynamicMeters, Hashtable* pidMatchList, uid_t userId);
|
||||||
|
|
8
README
8
README
|
@ -80,8 +80,11 @@ To install on the local system run `make install`. By default `make install` ins
|
||||||
enable Performance Co-Pilot support via a new pcp-htop utility
|
enable Performance Co-Pilot support via a new pcp-htop utility
|
||||||
dependency: *libpcp*
|
dependency: *libpcp*
|
||||||
default: *no*
|
default: *no*
|
||||||
|
* `--enable-affinity`:
|
||||||
|
enable `sched_setaffinity(2)` and `sched_getaffinity(2)` for affinity support; conflicts with hwloc
|
||||||
|
default: *check*
|
||||||
* `--enable-hwloc`:
|
* `--enable-hwloc`:
|
||||||
enable hwloc support for CPU affinity; disables Linux affinity
|
enable hwloc support for CPU affinity; disables affinity support
|
||||||
dependency: *libhwloc*
|
dependency: *libhwloc*
|
||||||
default: *no*
|
default: *no*
|
||||||
* `--enable-static`:
|
* `--enable-static`:
|
||||||
|
@ -113,9 +116,6 @@ To install on the local system run `make install`. By default `make install` ins
|
||||||
* `--enable-ancient-vserver`:
|
* `--enable-ancient-vserver`:
|
||||||
enable ancient VServer support (implies `--enable-vserver`)
|
enable ancient VServer support (implies `--enable-vserver`)
|
||||||
default: *no*
|
default: *no*
|
||||||
* `--enable-linux-affinity`:
|
|
||||||
enable Linux `sched_setaffinity(2)` and `sched_getaffinity(2)` for affinity support; conflicts with hwloc
|
|
||||||
default: *check*
|
|
||||||
* `--enable-delayacct`:
|
* `--enable-delayacct`:
|
||||||
enable Linux delay accounting support
|
enable Linux delay accounting support
|
||||||
dependencies: *pkg-config*(build-time), *libnl-3* and *libnl-genl-3*
|
dependencies: *pkg-config*(build-time), *libnl-3* and *libnl-genl-3*
|
||||||
|
|
|
@ -28,7 +28,7 @@ static void TasksMeter_updateValues(Meter* this) {
|
||||||
this->values[0] = pl->kernelThreads;
|
this->values[0] = pl->kernelThreads;
|
||||||
this->values[1] = pl->userlandThreads;
|
this->values[1] = pl->userlandThreads;
|
||||||
this->values[2] = pl->totalTasks - pl->kernelThreads - pl->userlandThreads;
|
this->values[2] = pl->totalTasks - pl->kernelThreads - pl->userlandThreads;
|
||||||
this->values[3] = MINIMUM(pl->runningTasks, pl->cpuCount);
|
this->values[3] = MINIMUM(pl->runningTasks, pl->activeCPUs);
|
||||||
this->total = pl->totalTasks;
|
this->total = pl->totalTasks;
|
||||||
|
|
||||||
xSnprintf(this->txtBuffer, sizeof(this->txtBuffer), "%d/%d", (int) this->values[3], (int) this->total);
|
xSnprintf(this->txtBuffer, sizeof(this->txtBuffer), "%d/%d", (int) this->values[3], (int) this->total);
|
||||||
|
|
|
@ -19,7 +19,7 @@ static const int UptimeMeter_attributes[] = {
|
||||||
|
|
||||||
static void UptimeMeter_updateValues(Meter* this) {
|
static void UptimeMeter_updateValues(Meter* this) {
|
||||||
int totalseconds = Platform_getUptime();
|
int totalseconds = Platform_getUptime();
|
||||||
if (totalseconds == -1) {
|
if (totalseconds <= 0) {
|
||||||
xSnprintf(this->txtBuffer, sizeof(this->txtBuffer), "(unknown)");
|
xSnprintf(this->txtBuffer, sizeof(this->txtBuffer), "(unknown)");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
74
configure.ac
74
configure.ac
|
@ -355,9 +355,44 @@ AC_CHECK_FUNCS( [set_escdelay] )
|
||||||
AC_CHECK_FUNCS( [getmouse] )
|
AC_CHECK_FUNCS( [getmouse] )
|
||||||
|
|
||||||
|
|
||||||
|
AC_ARG_ENABLE([affinity],
|
||||||
|
[AS_HELP_STRING([--enable-affinity],
|
||||||
|
[enable sched_setaffinity and sched_getaffinity for affinity support, conflicts with hwloc @<:@default=check@:>@])],
|
||||||
|
[],
|
||||||
|
[enable_affinity=check])
|
||||||
|
if test "x$enable_affinity" = xcheck; then
|
||||||
|
if test "x$enable_hwloc" = xyes; then
|
||||||
|
enable_affinity=no
|
||||||
|
else
|
||||||
|
AC_MSG_CHECKING([for usable sched_setaffinity])
|
||||||
|
AC_RUN_IFELSE([
|
||||||
|
AC_LANG_PROGRAM([[
|
||||||
|
#include <sched.h>
|
||||||
|
#include <errno.h>
|
||||||
|
static cpu_set_t cpuset;
|
||||||
|
]], [[
|
||||||
|
CPU_ZERO(&cpuset);
|
||||||
|
sched_setaffinity(0, sizeof(cpu_set_t), &cpuset);
|
||||||
|
if (errno == ENOSYS) return 1;
|
||||||
|
]])],
|
||||||
|
[enable_affinity=yes
|
||||||
|
AC_MSG_RESULT([yes])],
|
||||||
|
[enable_affinity=no
|
||||||
|
AC_MSG_RESULT([no])],
|
||||||
|
[AC_MSG_RESULT([yes (assumed while cross compiling)])])
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
if test "x$enable_affinity" = xyes; then
|
||||||
|
if test "x$enable_hwloc" = xyes; then
|
||||||
|
AC_MSG_ERROR([--enable-hwloc and --enable-affinity are mutual exclusive. Specify at most one of them.])
|
||||||
|
fi
|
||||||
|
AC_DEFINE([HAVE_AFFINITY], [1], [Define if sched_setaffinity and sched_getaffinity are to be used.])
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
AC_ARG_ENABLE([hwloc],
|
AC_ARG_ENABLE([hwloc],
|
||||||
[AS_HELP_STRING([--enable-hwloc],
|
[AS_HELP_STRING([--enable-hwloc],
|
||||||
[enable hwloc support for CPU affinity; disables Linux affinity; requires libhwloc @<:@default=no@:>@])],
|
[enable hwloc support for CPU affinity; disables affinity support; requires libhwloc @<:@default=no@:>@])],
|
||||||
[],
|
[],
|
||||||
[enable_hwloc=no])
|
[enable_hwloc=no])
|
||||||
case "$enable_hwloc" in
|
case "$enable_hwloc" in
|
||||||
|
@ -433,41 +468,6 @@ if test "x$enable_ancient_vserver" = xyes; then
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
AC_ARG_ENABLE([linux_affinity],
|
|
||||||
[AS_HELP_STRING([--enable-linux-affinity],
|
|
||||||
[enable Linux sched_setaffinity and sched_getaffinity for affinity support, conflicts with hwloc @<:@default=check@:>@])],
|
|
||||||
[],
|
|
||||||
[enable_linux_affinity=check])
|
|
||||||
if test "x$enable_linux_affinity" = xcheck; then
|
|
||||||
if test "x$enable_hwloc" = xyes; then
|
|
||||||
enable_linux_affinity=no
|
|
||||||
else
|
|
||||||
AC_MSG_CHECKING([for usable sched_setaffinity])
|
|
||||||
AC_RUN_IFELSE([
|
|
||||||
AC_LANG_PROGRAM([[
|
|
||||||
#include <sched.h>
|
|
||||||
#include <errno.h>
|
|
||||||
static cpu_set_t cpuset;
|
|
||||||
]], [[
|
|
||||||
CPU_ZERO(&cpuset);
|
|
||||||
sched_setaffinity(0, sizeof(cpu_set_t), &cpuset);
|
|
||||||
if (errno == ENOSYS) return 1;
|
|
||||||
]])],
|
|
||||||
[enable_linux_affinity=yes
|
|
||||||
AC_MSG_RESULT([yes])],
|
|
||||||
[enable_linux_affinity=no
|
|
||||||
AC_MSG_RESULT([no])],
|
|
||||||
[AC_MSG_RESULT([yes (assumed while cross compiling)])])
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
if test "x$enable_linux_affinity" = xyes; then
|
|
||||||
if test "x$enable_hwloc" = xyes; then
|
|
||||||
AC_MSG_ERROR([--enable-hwloc and --enable-linux-affinity are mutual exclusive. Specify at most one of them.])
|
|
||||||
fi
|
|
||||||
AC_DEFINE([HAVE_LINUX_AFFINITY], [1], [Define if Linux sched_setaffinity and sched_getaffinity are to be used.])
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
AC_ARG_ENABLE([capabilities],
|
AC_ARG_ENABLE([capabilities],
|
||||||
[AS_HELP_STRING([--enable-capabilities],
|
[AS_HELP_STRING([--enable-capabilities],
|
||||||
[enable Linux capabilities support; requires libcap @<:@default=check@:>@])],
|
[enable Linux capabilities support; requires libcap @<:@default=check@:>@])],
|
||||||
|
@ -688,11 +688,11 @@ AC_MSG_RESULT([
|
||||||
(Linux) openvz: $enable_openvz
|
(Linux) openvz: $enable_openvz
|
||||||
(Linux) vserver: $enable_vserver
|
(Linux) vserver: $enable_vserver
|
||||||
(Linux) ancient vserver: $enable_ancient_vserver
|
(Linux) ancient vserver: $enable_ancient_vserver
|
||||||
(Linux) affinity: $enable_linux_affinity
|
|
||||||
(Linux) delay accounting: $enable_delayacct
|
(Linux) delay accounting: $enable_delayacct
|
||||||
(Linux) sensors: $enable_sensors
|
(Linux) sensors: $enable_sensors
|
||||||
(Linux) capabilities: $enable_capabilities
|
(Linux) capabilities: $enable_capabilities
|
||||||
unicode: $enable_unicode
|
unicode: $enable_unicode
|
||||||
|
affinity: $enable_affinity
|
||||||
hwloc: $enable_hwloc
|
hwloc: $enable_hwloc
|
||||||
debug: $enable_debug
|
debug: $enable_debug
|
||||||
static: $enable_static
|
static: $enable_static
|
||||||
|
|
|
@ -134,7 +134,9 @@ ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* dynamicMeters, H
|
||||||
ProcessList_init(&this->super, Class(DarwinProcess), usersTable, dynamicMeters, pidMatchList, userId);
|
ProcessList_init(&this->super, Class(DarwinProcess), usersTable, dynamicMeters, pidMatchList, userId);
|
||||||
|
|
||||||
/* Initialize the CPU information */
|
/* Initialize the CPU information */
|
||||||
this->super.cpuCount = ProcessList_allocateCPULoadInfo(&this->prev_load);
|
this->super.activeCPUs = ProcessList_allocateCPULoadInfo(&this->prev_load);
|
||||||
|
// TODO: support offline CPUs and hot swapping
|
||||||
|
this->super.existingCPUs = this->super.activeCPUs;
|
||||||
ProcessList_getHostInfo(&this->host_info);
|
ProcessList_getHostInfo(&this->host_info);
|
||||||
ProcessList_allocateCPULoadInfo(&this->curr_load);
|
ProcessList_allocateCPULoadInfo(&this->curr_load);
|
||||||
|
|
||||||
|
@ -184,13 +186,13 @@ void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate) {
|
||||||
|
|
||||||
/* Get the time difference */
|
/* Get the time difference */
|
||||||
dpl->global_diff = 0;
|
dpl->global_diff = 0;
|
||||||
for (unsigned int i = 0; i < dpl->super.cpuCount; ++i) {
|
for (unsigned int i = 0; i < dpl->super.existingCPUs; ++i) {
|
||||||
for (size_t j = 0; j < CPU_STATE_MAX; ++j) {
|
for (size_t j = 0; j < CPU_STATE_MAX; ++j) {
|
||||||
dpl->global_diff += dpl->curr_load[i].cpu_ticks[j] - dpl->prev_load[i].cpu_ticks[j];
|
dpl->global_diff += dpl->curr_load[i].cpu_ticks[j] - dpl->prev_load[i].cpu_ticks[j];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const double time_interval = ticksToNanoseconds(dpl->global_diff) / (double) dpl->super.cpuCount;
|
const double time_interval = ticksToNanoseconds(dpl->global_diff) / (double) dpl->super.activeCPUs;
|
||||||
|
|
||||||
/* Clear the thread counts */
|
/* Clear the thread counts */
|
||||||
super->kernelThreads = 0;
|
super->kernelThreads = 0;
|
||||||
|
@ -234,3 +236,12 @@ void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate) {
|
||||||
|
|
||||||
free(ps);
|
free(ps);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ProcessList_isCPUonline(const ProcessList* super, unsigned int id) {
|
||||||
|
assert(id < super->existingCPUs);
|
||||||
|
|
||||||
|
// TODO: support offline CPUs and hot swapping
|
||||||
|
(void) super; (void) id;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
|
@ -34,4 +34,6 @@ void ProcessList_delete(ProcessList* this);
|
||||||
|
|
||||||
void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate);
|
void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate);
|
||||||
|
|
||||||
|
bool ProcessList_isCPUonline(const ProcessList* super, unsigned int id);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -186,21 +186,21 @@ int Platform_getMaxPid() {
|
||||||
|
|
||||||
static double Platform_setCPUAverageValues(Meter* mtr) {
|
static double Platform_setCPUAverageValues(Meter* mtr) {
|
||||||
const ProcessList* dpl = mtr->pl;
|
const ProcessList* dpl = mtr->pl;
|
||||||
unsigned int cpus = dpl->cpuCount;
|
unsigned int activeCPUs = dpl->activeCPUs;
|
||||||
double sumNice = 0.0;
|
double sumNice = 0.0;
|
||||||
double sumNormal = 0.0;
|
double sumNormal = 0.0;
|
||||||
double sumKernel = 0.0;
|
double sumKernel = 0.0;
|
||||||
double sumPercent = 0.0;
|
double sumPercent = 0.0;
|
||||||
for (unsigned int i = 1; i <= cpus; i++) {
|
for (unsigned int i = 1; i <= dpl->existingCPUs; i++) {
|
||||||
sumPercent += Platform_setCPUValues(mtr, i);
|
sumPercent += Platform_setCPUValues(mtr, i);
|
||||||
sumNice += mtr->values[CPU_METER_NICE];
|
sumNice += mtr->values[CPU_METER_NICE];
|
||||||
sumNormal += mtr->values[CPU_METER_NORMAL];
|
sumNormal += mtr->values[CPU_METER_NORMAL];
|
||||||
sumKernel += mtr->values[CPU_METER_KERNEL];
|
sumKernel += mtr->values[CPU_METER_KERNEL];
|
||||||
}
|
}
|
||||||
mtr->values[CPU_METER_NICE] = sumNice / cpus;
|
mtr->values[CPU_METER_NICE] = sumNice / activeCPUs;
|
||||||
mtr->values[CPU_METER_NORMAL] = sumNormal / cpus;
|
mtr->values[CPU_METER_NORMAL] = sumNormal / activeCPUs;
|
||||||
mtr->values[CPU_METER_KERNEL] = sumKernel / cpus;
|
mtr->values[CPU_METER_KERNEL] = sumKernel / activeCPUs;
|
||||||
return sumPercent / cpus;
|
return sumPercent / activeCPUs;
|
||||||
}
|
}
|
||||||
|
|
||||||
double Platform_setCPUValues(Meter* mtr, unsigned int cpu) {
|
double Platform_setCPUValues(Meter* mtr, unsigned int cpu) {
|
||||||
|
|
|
@ -95,13 +95,15 @@ ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* dynamicMeters, H
|
||||||
sysctl(MIB_kern_cp_times, 2, dfpl->cp_times_o, &len, NULL, 0);
|
sysctl(MIB_kern_cp_times, 2, dfpl->cp_times_o, &len, NULL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
pl->cpuCount = MAXIMUM(cpus, 1);
|
pl->existingCPUs = MAXIMUM(cpus, 1);
|
||||||
|
// TODO: support offline CPUs and hot swapping
|
||||||
|
pl->activeCPUs = pl->existingCPUs;
|
||||||
|
|
||||||
if (cpus == 1 ) {
|
if (cpus == 1 ) {
|
||||||
dfpl->cpus = xRealloc(dfpl->cpus, sizeof(CPUData));
|
dfpl->cpus = xRealloc(dfpl->cpus, sizeof(CPUData));
|
||||||
} else {
|
} else {
|
||||||
// on smp we need CPUs + 1 to store averages too (as kernel kindly provides that as well)
|
// on smp we need CPUs + 1 to store averages too (as kernel kindly provides that as well)
|
||||||
dfpl->cpus = xRealloc(dfpl->cpus, (pl->cpuCount + 1) * sizeof(CPUData));
|
dfpl->cpus = xRealloc(dfpl->cpus, (pl->existingCPUs + 1) * sizeof(CPUData));
|
||||||
}
|
}
|
||||||
|
|
||||||
len = sizeof(kernelFScale);
|
len = sizeof(kernelFScale);
|
||||||
|
@ -140,8 +142,8 @@ void ProcessList_delete(ProcessList* this) {
|
||||||
static inline void DragonFlyBSDProcessList_scanCPUTime(ProcessList* pl) {
|
static inline void DragonFlyBSDProcessList_scanCPUTime(ProcessList* pl) {
|
||||||
const DragonFlyBSDProcessList* dfpl = (DragonFlyBSDProcessList*) pl;
|
const DragonFlyBSDProcessList* dfpl = (DragonFlyBSDProcessList*) pl;
|
||||||
|
|
||||||
unsigned int cpus = pl->cpuCount; // actual CPU count
|
unsigned int cpus = pl->existingCPUs; // actual CPU count
|
||||||
unsigned int maxcpu = cpus; // max iteration (in case we have average + smp)
|
unsigned int maxcpu = cpus; // max iteration (in case we have average + smp)
|
||||||
int cp_times_offset;
|
int cp_times_offset;
|
||||||
|
|
||||||
assert(cpus > 0);
|
assert(cpus > 0);
|
||||||
|
@ -430,7 +432,6 @@ void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate) {
|
||||||
|
|
||||||
int count = 0;
|
int count = 0;
|
||||||
|
|
||||||
// TODO Kernel Threads seem to be skipped, need to figure out the correct flag
|
|
||||||
const struct kinfo_proc* kprocs = kvm_getprocs(dfpl->kd, KERN_PROC_ALL | (!hideUserlandThreads ? KERN_PROC_FLAG_LWP : 0), 0, &count);
|
const struct kinfo_proc* kprocs = kvm_getprocs(dfpl->kd, KERN_PROC_ALL | (!hideUserlandThreads ? KERN_PROC_FLAG_LWP : 0), 0, &count);
|
||||||
|
|
||||||
for (int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
|
@ -442,8 +443,6 @@ void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate) {
|
||||||
Process* proc = ProcessList_getProcess(super, kproc->kp_ktaddr ? (pid_t)kproc->kp_ktaddr : kproc->kp_pid, &preExisting, DragonFlyBSDProcess_new);
|
Process* proc = ProcessList_getProcess(super, kproc->kp_ktaddr ? (pid_t)kproc->kp_ktaddr : kproc->kp_pid, &preExisting, DragonFlyBSDProcess_new);
|
||||||
DragonFlyBSDProcess* dfp = (DragonFlyBSDProcess*) proc;
|
DragonFlyBSDProcess* dfp = (DragonFlyBSDProcess*) proc;
|
||||||
|
|
||||||
proc->show = ! ((hideKernelThreads && Process_isKernelThread(proc)) || (hideUserlandThreads && Process_isUserlandThread(proc)));
|
|
||||||
|
|
||||||
if (!preExisting) {
|
if (!preExisting) {
|
||||||
dfp->jid = kproc->kp_jailid;
|
dfp->jid = kproc->kp_jailid;
|
||||||
if (kproc->kp_ktaddr && kproc->kp_flags & P_SYSTEM) {
|
if (kproc->kp_ktaddr && kproc->kp_flags & P_SYSTEM) {
|
||||||
|
@ -596,6 +595,16 @@ void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate) {
|
||||||
if (proc->state == 'R')
|
if (proc->state == 'R')
|
||||||
super->runningTasks++;
|
super->runningTasks++;
|
||||||
|
|
||||||
|
proc->show = ! ((hideKernelThreads && Process_isKernelThread(proc)) || (hideUserlandThreads && Process_isUserlandThread(proc)));
|
||||||
proc->updated = true;
|
proc->updated = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ProcessList_isCPUonline(const ProcessList* super, unsigned int id) {
|
||||||
|
assert(id < super->existingCPUs);
|
||||||
|
|
||||||
|
// TODO: support offline CPUs and hot swapping
|
||||||
|
(void) super; (void) id;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
|
@ -59,4 +59,6 @@ void ProcessList_delete(ProcessList* this);
|
||||||
|
|
||||||
void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate);
|
void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate);
|
||||||
|
|
||||||
|
bool ProcessList_isCPUonline(const ProcessList* super, unsigned int id);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -159,7 +159,7 @@ int Platform_getMaxPid() {
|
||||||
|
|
||||||
double Platform_setCPUValues(Meter* this, unsigned int cpu) {
|
double Platform_setCPUValues(Meter* this, unsigned int cpu) {
|
||||||
const DragonFlyBSDProcessList* fpl = (const DragonFlyBSDProcessList*) this->pl;
|
const DragonFlyBSDProcessList* fpl = (const DragonFlyBSDProcessList*) this->pl;
|
||||||
unsigned int cpus = this->pl->cpuCount;
|
unsigned int cpus = this->pl->activeCPUs;
|
||||||
const CPUData* cpuData;
|
const CPUData* cpuData;
|
||||||
|
|
||||||
if (cpus == 1) {
|
if (cpus == 1) {
|
||||||
|
|
|
@ -125,13 +125,15 @@ ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* dynamicMeters, H
|
||||||
sysctl(MIB_kern_cp_times, 2, fpl->cp_times_o, &len, NULL, 0);
|
sysctl(MIB_kern_cp_times, 2, fpl->cp_times_o, &len, NULL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
pl->cpuCount = MAXIMUM(cpus, 1);
|
pl->existingCPUs = MAXIMUM(cpus, 1);
|
||||||
|
// TODO: support offline CPUs and hot swapping
|
||||||
|
pl->activeCPUs = pl->existingCPUs;
|
||||||
|
|
||||||
if (cpus == 1 ) {
|
if (cpus == 1 ) {
|
||||||
fpl->cpus = xRealloc(fpl->cpus, sizeof(CPUData));
|
fpl->cpus = xRealloc(fpl->cpus, sizeof(CPUData));
|
||||||
} else {
|
} else {
|
||||||
// on smp we need CPUs + 1 to store averages too (as kernel kindly provides that as well)
|
// on smp we need CPUs + 1 to store averages too (as kernel kindly provides that as well)
|
||||||
fpl->cpus = xRealloc(fpl->cpus, (pl->cpuCount + 1) * sizeof(CPUData));
|
fpl->cpus = xRealloc(fpl->cpus, (pl->existingCPUs + 1) * sizeof(CPUData));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -169,8 +171,8 @@ void ProcessList_delete(ProcessList* this) {
|
||||||
static inline void FreeBSDProcessList_scanCPU(ProcessList* pl) {
|
static inline void FreeBSDProcessList_scanCPU(ProcessList* pl) {
|
||||||
const FreeBSDProcessList* fpl = (FreeBSDProcessList*) pl;
|
const FreeBSDProcessList* fpl = (FreeBSDProcessList*) pl;
|
||||||
|
|
||||||
unsigned int cpus = pl->cpuCount; // actual CPU count
|
unsigned int cpus = pl->existingCPUs; // actual CPU count
|
||||||
unsigned int maxcpu = cpus; // max iteration (in case we have average + smp)
|
unsigned int maxcpu = cpus; // max iteration (in case we have average + smp)
|
||||||
int cp_times_offset;
|
int cp_times_offset;
|
||||||
|
|
||||||
assert(cpus > 0);
|
assert(cpus > 0);
|
||||||
|
@ -378,16 +380,15 @@ static inline void FreeBSDProcessList_scanMemoryInfo(ProcessList* pl) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void FreeBSDProcessList_updateExe(const struct kinfo_proc* kproc, Process* proc) {
|
static void FreeBSDProcessList_updateExe(const struct kinfo_proc* kproc, Process* proc) {
|
||||||
const int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, kproc->ki_pid };
|
if (Process_isKernelThread(proc)) {
|
||||||
char buffer[2048];
|
|
||||||
size_t size = sizeof(buffer);
|
|
||||||
if (sysctl(mib, 4, buffer, &size, NULL, 0) != 0) {
|
|
||||||
Process_updateExe(proc, NULL);
|
Process_updateExe(proc, NULL);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Kernel threads return an empty buffer */
|
const int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, kproc->ki_pid };
|
||||||
if (buffer[0] == '\0') {
|
char buffer[2048];
|
||||||
|
size_t size = sizeof(buffer);
|
||||||
|
if (sysctl(mib, 4, buffer, &size, NULL, 0) != 0) {
|
||||||
Process_updateExe(proc, NULL);
|
Process_updateExe(proc, NULL);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -494,12 +495,10 @@ void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate) {
|
||||||
Process* proc = ProcessList_getProcess(super, kproc->ki_pid, &preExisting, FreeBSDProcess_new);
|
Process* proc = ProcessList_getProcess(super, kproc->ki_pid, &preExisting, FreeBSDProcess_new);
|
||||||
FreeBSDProcess* fp = (FreeBSDProcess*) proc;
|
FreeBSDProcess* fp = (FreeBSDProcess*) proc;
|
||||||
|
|
||||||
proc->show = ! ((hideKernelThreads && Process_isKernelThread(proc)) || (hideUserlandThreads && Process_isUserlandThread(proc)));
|
|
||||||
|
|
||||||
if (!preExisting) {
|
if (!preExisting) {
|
||||||
fp->jid = kproc->ki_jid;
|
fp->jid = kproc->ki_jid;
|
||||||
proc->pid = kproc->ki_pid;
|
proc->pid = kproc->ki_pid;
|
||||||
proc->isKernelThread = kproc->ki_pid != 0 && kproc->ki_pid != 1 && (kproc->ki_flag & P_SYSTEM);
|
proc->isKernelThread = kproc->ki_pid != 1 && (kproc->ki_flag & P_SYSTEM);
|
||||||
proc->isUserlandThread = false;
|
proc->isUserlandThread = false;
|
||||||
proc->ppid = kproc->ki_ppid;
|
proc->ppid = kproc->ki_ppid;
|
||||||
proc->tpgid = kproc->ki_tpgid;
|
proc->tpgid = kproc->ki_tpgid;
|
||||||
|
@ -591,9 +590,20 @@ void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate) {
|
||||||
if (Process_isKernelThread(proc))
|
if (Process_isKernelThread(proc))
|
||||||
super->kernelThreads++;
|
super->kernelThreads++;
|
||||||
|
|
||||||
|
proc->show = ! ((hideKernelThreads && Process_isKernelThread(proc)) || (hideUserlandThreads && Process_isUserlandThread(proc)));
|
||||||
|
|
||||||
super->totalTasks++;
|
super->totalTasks++;
|
||||||
if (proc->state == 'R')
|
if (proc->state == 'R')
|
||||||
super->runningTasks++;
|
super->runningTasks++;
|
||||||
proc->updated = true;
|
proc->updated = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ProcessList_isCPUonline(const ProcessList* super, unsigned int id) {
|
||||||
|
assert(id < super->existingCPUs);
|
||||||
|
|
||||||
|
// TODO: support offline CPUs and hot swapping
|
||||||
|
(void) super; (void) id;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
|
@ -53,4 +53,6 @@ void ProcessList_delete(ProcessList* this);
|
||||||
|
|
||||||
void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate);
|
void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate);
|
||||||
|
|
||||||
|
bool ProcessList_isCPUonline(const ProcessList* super, unsigned int id);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -181,7 +181,7 @@ int Platform_getMaxPid() {
|
||||||
|
|
||||||
double Platform_setCPUValues(Meter* this, unsigned int cpu) {
|
double Platform_setCPUValues(Meter* this, unsigned int cpu) {
|
||||||
const FreeBSDProcessList* fpl = (const FreeBSDProcessList*) this->pl;
|
const FreeBSDProcessList* fpl = (const FreeBSDProcessList*) this->pl;
|
||||||
unsigned int cpus = this->pl->cpuCount;
|
unsigned int cpus = this->pl->activeCPUs;
|
||||||
const CPUData* cpuData;
|
const CPUData* cpuData;
|
||||||
|
|
||||||
if (cpus == 1) {
|
if (cpus == 1) {
|
||||||
|
|
|
@ -32,10 +32,10 @@ static void* dlopenHandle = NULL;
|
||||||
|
|
||||||
#endif /* BUILD_STATIC */
|
#endif /* BUILD_STATIC */
|
||||||
|
|
||||||
int LibSensors_init(FILE* input) {
|
int LibSensors_init(void) {
|
||||||
#ifdef BUILD_STATIC
|
#ifdef BUILD_STATIC
|
||||||
|
|
||||||
return sym_sensors_init(input);
|
return sym_sensors_init(NULL);
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
|
@ -69,7 +69,7 @@ int LibSensors_init(FILE* input) {
|
||||||
#undef resolve
|
#undef resolve
|
||||||
}
|
}
|
||||||
|
|
||||||
return sym_sensors_init(input);
|
return sym_sensors_init(NULL);
|
||||||
|
|
||||||
|
|
||||||
dlfailure:
|
dlfailure:
|
||||||
|
@ -99,6 +99,18 @@ void LibSensors_cleanup(void) {
|
||||||
#endif /* BUILD_STATIC */
|
#endif /* BUILD_STATIC */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int LibSensors_reload(void) {
|
||||||
|
#ifndef BUILD_STATIC
|
||||||
|
if (!dlopenHandle) {
|
||||||
|
errno = ENOTSUP;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#endif /* !BUILD_STATIC */
|
||||||
|
|
||||||
|
sym_sensors_cleanup();
|
||||||
|
return sym_sensors_init(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
static int tempDriverPriority(const sensors_chip_name* chip) {
|
static int tempDriverPriority(const sensors_chip_name* chip) {
|
||||||
static const struct TempDriverDefs {
|
static const struct TempDriverDefs {
|
||||||
const char* prefix;
|
const char* prefix;
|
||||||
|
@ -120,10 +132,10 @@ static int tempDriverPriority(const sensors_chip_name* chip) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LibSensors_getCPUTemperatures(CPUData* cpus, unsigned int cpuCount) {
|
void LibSensors_getCPUTemperatures(CPUData* cpus, unsigned int existingCPUs, unsigned int activeCPUs) {
|
||||||
assert(cpuCount > 0 && cpuCount < 16384);
|
assert(existingCPUs > 0 && existingCPUs < 16384);
|
||||||
double data[cpuCount + 1];
|
double data[existingCPUs + 1];
|
||||||
for (size_t i = 0; i < cpuCount + 1; i++)
|
for (size_t i = 0; i < existingCPUs + 1; i++)
|
||||||
data[i] = NAN;
|
data[i] = NAN;
|
||||||
|
|
||||||
#ifndef BUILD_STATIC
|
#ifndef BUILD_STATIC
|
||||||
|
@ -145,7 +157,7 @@ void LibSensors_getCPUTemperatures(CPUData* cpus, unsigned int cpuCount) {
|
||||||
|
|
||||||
if (priority < topPriority) {
|
if (priority < topPriority) {
|
||||||
/* Clear data from lower priority sensor */
|
/* Clear data from lower priority sensor */
|
||||||
for (size_t i = 0; i < cpuCount + 1; i++)
|
for (size_t i = 0; i < existingCPUs + 1; i++)
|
||||||
data[i] = NAN;
|
data[i] = NAN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -166,7 +178,7 @@ void LibSensors_getCPUTemperatures(CPUData* cpus, unsigned int cpuCount) {
|
||||||
/* Feature name IDs start at 1, adjust to start at 0 to match data indices */
|
/* Feature name IDs start at 1, adjust to start at 0 to match data indices */
|
||||||
tempID--;
|
tempID--;
|
||||||
|
|
||||||
if (tempID > cpuCount)
|
if (tempID > existingCPUs)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
const sensors_subfeature* subFeature = sym_sensors_get_subfeature(chip, feature, SENSORS_SUBFEATURE_TEMP_INPUT);
|
const sensors_subfeature* subFeature = sym_sensors_get_subfeature(chip, feature, SENSORS_SUBFEATURE_TEMP_INPUT);
|
||||||
|
@ -190,8 +202,8 @@ void LibSensors_getCPUTemperatures(CPUData* cpus, unsigned int cpuCount) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Adjust data for chips not providing a platform temperature */
|
/* Adjust data for chips not providing a platform temperature */
|
||||||
if (coreTempCount + 1 == cpuCount || coreTempCount + 1 == cpuCount / 2) {
|
if (coreTempCount + 1 == activeCPUs || coreTempCount + 1 == activeCPUs / 2) {
|
||||||
memmove(&data[1], &data[0], cpuCount * sizeof(*data));
|
memmove(&data[1], &data[0], existingCPUs * sizeof(*data));
|
||||||
data[0] = NAN;
|
data[0] = NAN;
|
||||||
coreTempCount++;
|
coreTempCount++;
|
||||||
|
|
||||||
|
@ -200,7 +212,7 @@ void LibSensors_getCPUTemperatures(CPUData* cpus, unsigned int cpuCount) {
|
||||||
|
|
||||||
/* Only package temperature - copy to all cores */
|
/* Only package temperature - copy to all cores */
|
||||||
if (coreTempCount == 0 && !isnan(data[0])) {
|
if (coreTempCount == 0 && !isnan(data[0])) {
|
||||||
for (unsigned int i = 1; i <= cpuCount; i++)
|
for (unsigned int i = 1; i <= existingCPUs; i++)
|
||||||
data[i] = data[0];
|
data[i] = data[0];
|
||||||
|
|
||||||
/* No further adjustments */
|
/* No further adjustments */
|
||||||
|
@ -210,7 +222,7 @@ void LibSensors_getCPUTemperatures(CPUData* cpus, unsigned int cpuCount) {
|
||||||
/* No package temperature - set to max core temperature */
|
/* No package temperature - set to max core temperature */
|
||||||
if (isnan(data[0]) && coreTempCount != 0) {
|
if (isnan(data[0]) && coreTempCount != 0) {
|
||||||
double maxTemp = NAN;
|
double maxTemp = NAN;
|
||||||
for (unsigned int i = 1; i <= cpuCount; i++) {
|
for (unsigned int i = 1; i <= existingCPUs; i++) {
|
||||||
if (isnan(data[i]))
|
if (isnan(data[i]))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -224,7 +236,7 @@ void LibSensors_getCPUTemperatures(CPUData* cpus, unsigned int cpuCount) {
|
||||||
|
|
||||||
/* Only temperature for core 0, maybe Ryzen - copy to all other cores */
|
/* Only temperature for core 0, maybe Ryzen - copy to all other cores */
|
||||||
if (coreTempCount == 1 && !isnan(data[1])) {
|
if (coreTempCount == 1 && !isnan(data[1])) {
|
||||||
for (unsigned int i = 2; i <= cpuCount; i++)
|
for (unsigned int i = 2; i <= existingCPUs; i++)
|
||||||
data[i] = data[1];
|
data[i] = data[1];
|
||||||
|
|
||||||
/* No further adjustments */
|
/* No further adjustments */
|
||||||
|
@ -232,7 +244,7 @@ void LibSensors_getCPUTemperatures(CPUData* cpus, unsigned int cpuCount) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Half the temperatures, probably HT/SMT - copy to second half */
|
/* Half the temperatures, probably HT/SMT - copy to second half */
|
||||||
const unsigned int delta = cpuCount / 2;
|
const unsigned int delta = activeCPUs / 2;
|
||||||
if (coreTempCount == delta) {
|
if (coreTempCount == delta) {
|
||||||
memcpy(&data[delta + 1], &data[1], delta * sizeof(*data));
|
memcpy(&data[delta + 1], &data[1], delta * sizeof(*data));
|
||||||
|
|
||||||
|
@ -241,7 +253,7 @@ void LibSensors_getCPUTemperatures(CPUData* cpus, unsigned int cpuCount) {
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
for (unsigned int i = 0; i <= cpuCount; i++)
|
for (unsigned int i = 0; i <= existingCPUs; i++)
|
||||||
cpus[i].temperature = data[i];
|
cpus[i].temperature = data[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,9 +8,10 @@
|
||||||
#include "linux/LinuxProcessList.h"
|
#include "linux/LinuxProcessList.h"
|
||||||
|
|
||||||
|
|
||||||
int LibSensors_init(FILE* input);
|
int LibSensors_init(void);
|
||||||
void LibSensors_cleanup(void);
|
void LibSensors_cleanup(void);
|
||||||
|
int LibSensors_reload(void);
|
||||||
|
|
||||||
void LibSensors_getCPUTemperatures(CPUData* cpus, unsigned int cpuCount);
|
void LibSensors_getCPUTemperatures(CPUData* cpus, unsigned int existingCPUs, unsigned int activeCPUs);
|
||||||
|
|
||||||
#endif /* HEADER_LibSensors */
|
#endif /* HEADER_LibSensors */
|
||||||
|
|
|
@ -158,30 +158,85 @@ static void LinuxProcessList_initNetlinkSocket(LinuxProcessList* this) {
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void LinuxProcessList_updateCPUcount(ProcessList* super, FILE* stream) {
|
static void LinuxProcessList_updateCPUcount(ProcessList* super) {
|
||||||
|
/* Similiar to get_nprocs_conf(3) / _SC_NPROCESSORS_CONF
|
||||||
|
* https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/linux/getsysstats.c;hb=HEAD
|
||||||
|
*/
|
||||||
|
|
||||||
LinuxProcessList* this = (LinuxProcessList*) super;
|
LinuxProcessList* this = (LinuxProcessList*) super;
|
||||||
|
unsigned int existing = 0, active = 0;
|
||||||
|
|
||||||
unsigned int cpus = 0;
|
DIR* dir = opendir("/sys/devices/system/cpu");
|
||||||
char buffer[PROC_LINE_LENGTH + 1];
|
if (!dir) {
|
||||||
while (fgets(buffer, sizeof(buffer), stream)) {
|
super->activeCPUs = 1;
|
||||||
if (String_startsWith(buffer, "cpu")) {
|
super->existingCPUs = 1;
|
||||||
cpus++;
|
this->cpuData = xReallocArray(this->cpuData, 2, sizeof(CPUData));
|
||||||
|
this->cpuData[0].online = true;
|
||||||
|
this->cpuData[1].online = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int currExisting = super->existingCPUs;
|
||||||
|
|
||||||
|
const struct dirent* entry;
|
||||||
|
while ((entry = readdir(dir)) != NULL) {
|
||||||
|
if (entry->d_type != DT_DIR)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!String_startsWith(entry->d_name, "cpu"))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
char *endp;
|
||||||
|
unsigned long int id = strtoul(entry->d_name + 3, &endp, 10);
|
||||||
|
if (id == ULONG_MAX || endp == entry->d_name + 3 || *endp != '\0')
|
||||||
|
continue;
|
||||||
|
|
||||||
|
#ifdef HAVE_OPENAT
|
||||||
|
int cpuDirFd = openat(dirfd(dir), entry->d_name, O_DIRECTORY | O_PATH | O_NOFOLLOW);
|
||||||
|
if (cpuDirFd < 0)
|
||||||
|
continue;
|
||||||
|
#else
|
||||||
|
char cpuDirFd[4096];
|
||||||
|
xSnprintf(cpuDirFd, sizeof(cpuDirFd), "/sys/devices/system/cpu/%s", entry->d_name);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
existing++;
|
||||||
|
|
||||||
|
/* readdir() iterates with no specific order */
|
||||||
|
unsigned int max = MAXIMUM(existing, id + 1);
|
||||||
|
if (max > currExisting) {
|
||||||
|
this->cpuData = xReallocArray(this->cpuData, max + /* aggregate */ 1, sizeof(CPUData));
|
||||||
|
for (unsigned int j = currExisting; j < max; j++) {
|
||||||
|
this->cpuData[j].online = false;
|
||||||
|
}
|
||||||
|
currExisting = max;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char buffer[8];
|
||||||
|
ssize_t res = xReadfileat(cpuDirFd, "online", buffer, sizeof(buffer));
|
||||||
|
/* If the file "online" does not exist or on failure count as active */
|
||||||
|
if (res < 1 || buffer[0] != '0') {
|
||||||
|
active++;
|
||||||
|
this->cpuData[id + 1].online = true;
|
||||||
|
} else {
|
||||||
|
this->cpuData[id + 1].online = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Compat_openatArgClose(cpuDirFd);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cpus == 0)
|
closedir(dir);
|
||||||
CRT_fatalError("No cpu entry in " PROCSTATFILE);
|
|
||||||
if (cpus == 1)
|
|
||||||
CRT_fatalError("No cpu aggregate or cpuN entry in " PROCSTATFILE);
|
|
||||||
|
|
||||||
/* Subtract aggregate cpu entry */
|
#ifdef HAVE_SENSORS_SENSORS_H
|
||||||
cpus--;
|
/* When started with offline CPUs, libsensors does not monitor those,
|
||||||
|
* even when they become online. */
|
||||||
|
if (super->existingCPUs != 0 && (active > super->activeCPUs || currExisting > super->existingCPUs))
|
||||||
|
LibSensors_reload();
|
||||||
|
#endif
|
||||||
|
|
||||||
if (cpus != super->cpuCount || !this->cpus) {
|
super->activeCPUs = active;
|
||||||
super->cpuCount = MAXIMUM(cpus, 1);
|
assert(existing == currExisting);
|
||||||
free(this->cpus);
|
super->existingCPUs = currExisting;
|
||||||
this->cpus = xCalloc(cpus + 1, sizeof(CPUData));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* dynamicMeters, Hashtable* pidMatchList, uid_t userId) {
|
ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* dynamicMeters, Hashtable* pidMatchList, uid_t userId) {
|
||||||
|
@ -220,15 +275,13 @@ ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* dynamicMeters, H
|
||||||
CRT_fatalError("Failed to parse btime from " PROCSTATFILE);
|
CRT_fatalError("Failed to parse btime from " PROCSTATFILE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fclose(statfile);
|
||||||
|
|
||||||
if (btime == -1)
|
if (btime == -1)
|
||||||
CRT_fatalError("No btime in " PROCSTATFILE);
|
CRT_fatalError("No btime in " PROCSTATFILE);
|
||||||
|
|
||||||
rewind(statfile);
|
|
||||||
|
|
||||||
// Initialize CPU count
|
// Initialize CPU count
|
||||||
LinuxProcessList_updateCPUcount(pl, statfile);
|
LinuxProcessList_updateCPUcount(pl);
|
||||||
|
|
||||||
fclose(statfile);
|
|
||||||
|
|
||||||
return pl;
|
return pl;
|
||||||
}
|
}
|
||||||
|
@ -236,7 +289,7 @@ ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* dynamicMeters, H
|
||||||
void ProcessList_delete(ProcessList* pl) {
|
void ProcessList_delete(ProcessList* pl) {
|
||||||
LinuxProcessList* this = (LinuxProcessList*) pl;
|
LinuxProcessList* this = (LinuxProcessList*) pl;
|
||||||
ProcessList_done(pl);
|
ProcessList_done(pl);
|
||||||
free(this->cpus);
|
free(this->cpuData);
|
||||||
if (this->ttyDrivers) {
|
if (this->ttyDrivers) {
|
||||||
for (int i = 0; this->ttyDrivers[i].path; i++) {
|
for (int i = 0; this->ttyDrivers[i].path; i++) {
|
||||||
free(this->ttyDrivers[i].path);
|
free(this->ttyDrivers[i].path);
|
||||||
|
@ -1270,9 +1323,9 @@ static bool LinuxProcessList_recurseProcTree(LinuxProcessList* this, openat_arg_
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int cpus = pl->cpuCount;
|
const unsigned int activeCPUs = pl->activeCPUs;
|
||||||
bool hideKernelThreads = settings->hideKernelThreads;
|
const bool hideKernelThreads = settings->hideKernelThreads;
|
||||||
bool hideUserlandThreads = settings->hideUserlandThreads;
|
const bool hideUserlandThreads = settings->hideUserlandThreads;
|
||||||
while ((entry = readdir(dir)) != NULL) {
|
while ((entry = readdir(dir)) != NULL) {
|
||||||
const char* name = entry->d_name;
|
const char* name = entry->d_name;
|
||||||
|
|
||||||
|
@ -1407,7 +1460,7 @@ static bool LinuxProcessList_recurseProcTree(LinuxProcessList* this, openat_arg_
|
||||||
|
|
||||||
/* period might be 0 after system sleep */
|
/* period might be 0 after system sleep */
|
||||||
float percent_cpu = (period < 1E-6) ? 0.0F : ((lp->utime + lp->stime - lasttimes) / period * 100.0);
|
float percent_cpu = (period < 1E-6) ? 0.0F : ((lp->utime + lp->stime - lasttimes) / period * 100.0);
|
||||||
proc->percent_cpu = CLAMP(percent_cpu, 0.0F, cpus * 100.0F);
|
proc->percent_cpu = CLAMP(percent_cpu, 0.0F, activeCPUs * 100.0F);
|
||||||
proc->percent_mem = proc->m_resident / (double)(pl->totalMem) * 100.0;
|
proc->percent_mem = proc->m_resident / (double)(pl->totalMem) * 100.0;
|
||||||
|
|
||||||
if (! LinuxProcessList_updateUser(pl, proc, procFd))
|
if (! LinuxProcessList_updateUser(pl, proc, procFd))
|
||||||
|
@ -1771,33 +1824,50 @@ static inline void LinuxProcessList_scanZfsArcstats(LinuxProcessList* lpl) {
|
||||||
static inline double LinuxProcessList_scanCPUTime(ProcessList* super) {
|
static inline double LinuxProcessList_scanCPUTime(ProcessList* super) {
|
||||||
LinuxProcessList* this = (LinuxProcessList*) super;
|
LinuxProcessList* this = (LinuxProcessList*) super;
|
||||||
|
|
||||||
|
LinuxProcessList_updateCPUcount(super);
|
||||||
|
|
||||||
FILE* file = fopen(PROCSTATFILE, "r");
|
FILE* file = fopen(PROCSTATFILE, "r");
|
||||||
if (!file)
|
if (!file)
|
||||||
CRT_fatalError("Cannot open " PROCSTATFILE);
|
CRT_fatalError("Cannot open " PROCSTATFILE);
|
||||||
|
|
||||||
LinuxProcessList_updateCPUcount(super, file);
|
unsigned int existingCPUs = super->existingCPUs;
|
||||||
|
unsigned int lastAdjCpuId = 0;
|
||||||
|
|
||||||
rewind(file);
|
for (unsigned int i = 0; i <= existingCPUs; i++) {
|
||||||
|
|
||||||
unsigned int cpus = super->cpuCount;
|
|
||||||
for (unsigned int i = 0; i <= cpus; i++) {
|
|
||||||
char buffer[PROC_LINE_LENGTH + 1];
|
char buffer[PROC_LINE_LENGTH + 1];
|
||||||
unsigned long long int usertime, nicetime, systemtime, idletime;
|
unsigned long long int usertime, nicetime, systemtime, idletime;
|
||||||
unsigned long long int ioWait = 0, irq = 0, softIrq = 0, steal = 0, guest = 0, guestnice = 0;
|
unsigned long long int ioWait = 0, irq = 0, softIrq = 0, steal = 0, guest = 0, guestnice = 0;
|
||||||
// Depending on your kernel version,
|
|
||||||
// 5, 7, 8 or 9 of these fields will be set.
|
|
||||||
// The rest will remain at zero.
|
|
||||||
const char* ok = fgets(buffer, sizeof(buffer), file);
|
const char* ok = fgets(buffer, sizeof(buffer), file);
|
||||||
if (!ok)
|
if (!ok)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
// cpu fields are sorted first
|
||||||
|
if (!String_startsWith(buffer, "cpu"))
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Depending on your kernel version,
|
||||||
|
// 5, 7, 8 or 9 of these fields will be set.
|
||||||
|
// The rest will remain at zero.
|
||||||
|
unsigned int adjCpuId;
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
(void) sscanf(buffer, "cpu %16llu %16llu %16llu %16llu %16llu %16llu %16llu %16llu %16llu %16llu", &usertime, &nicetime, &systemtime, &idletime, &ioWait, &irq, &softIrq, &steal, &guest, &guestnice);
|
(void) sscanf(buffer, "cpu %16llu %16llu %16llu %16llu %16llu %16llu %16llu %16llu %16llu %16llu", &usertime, &nicetime, &systemtime, &idletime, &ioWait, &irq, &softIrq, &steal, &guest, &guestnice);
|
||||||
|
adjCpuId = 0;
|
||||||
} else {
|
} else {
|
||||||
unsigned int cpuid;
|
unsigned int cpuid;
|
||||||
(void) sscanf(buffer, "cpu%4u %16llu %16llu %16llu %16llu %16llu %16llu %16llu %16llu %16llu %16llu", &cpuid, &usertime, &nicetime, &systemtime, &idletime, &ioWait, &irq, &softIrq, &steal, &guest, &guestnice);
|
(void) sscanf(buffer, "cpu%4u %16llu %16llu %16llu %16llu %16llu %16llu %16llu %16llu %16llu %16llu", &cpuid, &usertime, &nicetime, &systemtime, &idletime, &ioWait, &irq, &softIrq, &steal, &guest, &guestnice);
|
||||||
assert(cpuid == i - 1);
|
adjCpuId = cpuid + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (adjCpuId > super->existingCPUs)
|
||||||
|
break;
|
||||||
|
|
||||||
|
for (unsigned int j = lastAdjCpuId + 1; j < adjCpuId; j++) {
|
||||||
|
// Skipped an ID, but /proc/stat is ordered => got offline CPU
|
||||||
|
memset(&(this->cpuData[j]), '\0', sizeof(CPUData));
|
||||||
|
}
|
||||||
|
lastAdjCpuId = adjCpuId;
|
||||||
|
|
||||||
// Guest time is already accounted in usertime
|
// Guest time is already accounted in usertime
|
||||||
usertime -= guest;
|
usertime -= guest;
|
||||||
nicetime -= guestnice;
|
nicetime -= guestnice;
|
||||||
|
@ -1807,7 +1877,7 @@ static inline double LinuxProcessList_scanCPUTime(ProcessList* super) {
|
||||||
unsigned long long int systemalltime = systemtime + irq + softIrq;
|
unsigned long long int systemalltime = systemtime + irq + softIrq;
|
||||||
unsigned long long int virtalltime = guest + guestnice;
|
unsigned long long int virtalltime = guest + guestnice;
|
||||||
unsigned long long int totaltime = usertime + nicetime + systemalltime + idlealltime + steal + virtalltime;
|
unsigned long long int totaltime = usertime + nicetime + systemalltime + idlealltime + steal + virtalltime;
|
||||||
CPUData* cpuData = &(this->cpus[i]);
|
CPUData* cpuData = &(this->cpuData[adjCpuId]);
|
||||||
// Since we do a subtraction (usertime - guest) and cputime64_to_clock_t()
|
// Since we do a subtraction (usertime - guest) and cputime64_to_clock_t()
|
||||||
// used in /proc/stat rounds down numbers, it can lead to a case where the
|
// used in /proc/stat rounds down numbers, it can lead to a case where the
|
||||||
// integer overflow.
|
// integer overflow.
|
||||||
|
@ -1837,7 +1907,7 @@ static inline double LinuxProcessList_scanCPUTime(ProcessList* super) {
|
||||||
cpuData->totalTime = totaltime;
|
cpuData->totalTime = totaltime;
|
||||||
}
|
}
|
||||||
|
|
||||||
double period = (double)this->cpus[0].totalPeriod / cpus;
|
double period = (double)this->cpuData[0].totalPeriod / super->activeCPUs;
|
||||||
|
|
||||||
char buffer[PROC_LINE_LENGTH + 1];
|
char buffer[PROC_LINE_LENGTH + 1];
|
||||||
while (fgets(buffer, sizeof(buffer), file)) {
|
while (fgets(buffer, sizeof(buffer), file)) {
|
||||||
|
@ -1853,7 +1923,7 @@ static inline double LinuxProcessList_scanCPUTime(ProcessList* super) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static int scanCPUFreqencyFromSysCPUFreq(LinuxProcessList* this) {
|
static int scanCPUFreqencyFromSysCPUFreq(LinuxProcessList* this) {
|
||||||
unsigned int cpus = this->super.cpuCount;
|
unsigned int existingCPUs = this->super.existingCPUs;
|
||||||
int numCPUsWithFrequency = 0;
|
int numCPUsWithFrequency = 0;
|
||||||
unsigned long totalFrequency = 0;
|
unsigned long totalFrequency = 0;
|
||||||
|
|
||||||
|
@ -1871,7 +1941,7 @@ static int scanCPUFreqencyFromSysCPUFreq(LinuxProcessList* this) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (unsigned int i = 0; i < cpus; ++i) {
|
for (unsigned int i = 0; i < existingCPUs; ++i) {
|
||||||
char pathBuffer[64];
|
char pathBuffer[64];
|
||||||
xSnprintf(pathBuffer, sizeof(pathBuffer), "/sys/devices/system/cpu/cpu%u/cpufreq/scaling_cur_freq", i);
|
xSnprintf(pathBuffer, sizeof(pathBuffer), "/sys/devices/system/cpu/cpu%u/cpufreq/scaling_cur_freq", i);
|
||||||
|
|
||||||
|
@ -1887,7 +1957,7 @@ static int scanCPUFreqencyFromSysCPUFreq(LinuxProcessList* this) {
|
||||||
if (fscanf(file, "%lu", &frequency) == 1) {
|
if (fscanf(file, "%lu", &frequency) == 1) {
|
||||||
/* convert kHz to MHz */
|
/* convert kHz to MHz */
|
||||||
frequency = frequency / 1000;
|
frequency = frequency / 1000;
|
||||||
this->cpus[i + 1].frequency = frequency;
|
this->cpuData[i + 1].frequency = frequency;
|
||||||
numCPUsWithFrequency++;
|
numCPUsWithFrequency++;
|
||||||
totalFrequency += frequency;
|
totalFrequency += frequency;
|
||||||
}
|
}
|
||||||
|
@ -1907,7 +1977,7 @@ static int scanCPUFreqencyFromSysCPUFreq(LinuxProcessList* this) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (numCPUsWithFrequency > 0)
|
if (numCPUsWithFrequency > 0)
|
||||||
this->cpus[0].frequency = (double)totalFrequency / numCPUsWithFrequency;
|
this->cpuData[0].frequency = (double)totalFrequency / numCPUsWithFrequency;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1917,7 +1987,7 @@ static void scanCPUFreqencyFromCPUinfo(LinuxProcessList* this) {
|
||||||
if (file == NULL)
|
if (file == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
unsigned int cpus = this->super.cpuCount;
|
unsigned int existingCPUs = this->super.existingCPUs;
|
||||||
int numCPUsWithFrequency = 0;
|
int numCPUsWithFrequency = 0;
|
||||||
double totalFrequency = 0;
|
double totalFrequency = 0;
|
||||||
int cpuid = -1;
|
int cpuid = -1;
|
||||||
|
@ -1940,11 +2010,11 @@ static void scanCPUFreqencyFromCPUinfo(LinuxProcessList* this) {
|
||||||
(sscanf(buffer, "clock : %lfMHz", &frequency) == 1) ||
|
(sscanf(buffer, "clock : %lfMHz", &frequency) == 1) ||
|
||||||
(sscanf(buffer, "clock: %lfMHz", &frequency) == 1)
|
(sscanf(buffer, "clock: %lfMHz", &frequency) == 1)
|
||||||
) {
|
) {
|
||||||
if (cpuid < 0 || (unsigned int)cpuid > (cpus - 1)) {
|
if (cpuid < 0 || (unsigned int)cpuid > (existingCPUs - 1)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
CPUData* cpuData = &(this->cpus[cpuid + 1]);
|
CPUData* cpuData = &(this->cpuData[cpuid + 1]);
|
||||||
/* do not override sysfs data */
|
/* do not override sysfs data */
|
||||||
if (isnan(cpuData->frequency)) {
|
if (isnan(cpuData->frequency)) {
|
||||||
cpuData->frequency = frequency;
|
cpuData->frequency = frequency;
|
||||||
|
@ -1958,15 +2028,15 @@ static void scanCPUFreqencyFromCPUinfo(LinuxProcessList* this) {
|
||||||
fclose(file);
|
fclose(file);
|
||||||
|
|
||||||
if (numCPUsWithFrequency > 0) {
|
if (numCPUsWithFrequency > 0) {
|
||||||
this->cpus[0].frequency = totalFrequency / numCPUsWithFrequency;
|
this->cpuData[0].frequency = totalFrequency / numCPUsWithFrequency;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void LinuxProcessList_scanCPUFrequency(LinuxProcessList* this) {
|
static void LinuxProcessList_scanCPUFrequency(LinuxProcessList* this) {
|
||||||
unsigned int cpus = this->super.cpuCount;
|
unsigned int existingCPUs = this->super.existingCPUs;
|
||||||
|
|
||||||
for (unsigned int i = 0; i <= cpus; i++) {
|
for (unsigned int i = 0; i <= existingCPUs; i++) {
|
||||||
this->cpus[i].frequency = NAN;
|
this->cpuData[i].frequency = NAN;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (scanCPUFreqencyFromSysCPUFreq(this) == 0) {
|
if (scanCPUFreqencyFromSysCPUFreq(this) == 0) {
|
||||||
|
@ -1993,7 +2063,7 @@ void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate) {
|
||||||
|
|
||||||
#ifdef HAVE_SENSORS_SENSORS_H
|
#ifdef HAVE_SENSORS_SENSORS_H
|
||||||
if (settings->showCPUTemperature)
|
if (settings->showCPUTemperature)
|
||||||
LibSensors_getCPUTemperatures(this->cpus, this->super.cpuCount);
|
LibSensors_getCPUTemperatures(this->cpuData, this->super.existingCPUs, this->super.activeCPUs);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// in pause mode only gather global data for meters (CPU/memory/...)
|
// in pause mode only gather global data for meters (CPU/memory/...)
|
||||||
|
@ -2011,3 +2081,10 @@ void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate) {
|
||||||
|
|
||||||
LinuxProcessList_recurseProcTree(this, rootFd, PROCDIR, NULL, period);
|
LinuxProcessList_recurseProcTree(this, rootFd, PROCDIR, NULL, period);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ProcessList_isCPUonline(const ProcessList* super, unsigned int id) {
|
||||||
|
assert(id < super->existingCPUs);
|
||||||
|
|
||||||
|
const LinuxProcessList* this = (const LinuxProcessList*) super;
|
||||||
|
return this->cpuData[id + 1].online;
|
||||||
|
}
|
||||||
|
|
|
@ -53,6 +53,8 @@ typedef struct CPUData_ {
|
||||||
#ifdef HAVE_SENSORS_SENSORS_H
|
#ifdef HAVE_SENSORS_SENSORS_H
|
||||||
double temperature;
|
double temperature;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
bool online;
|
||||||
} CPUData;
|
} CPUData;
|
||||||
|
|
||||||
typedef struct TtyDriver_ {
|
typedef struct TtyDriver_ {
|
||||||
|
@ -65,7 +67,8 @@ typedef struct TtyDriver_ {
|
||||||
typedef struct LinuxProcessList_ {
|
typedef struct LinuxProcessList_ {
|
||||||
ProcessList super;
|
ProcessList super;
|
||||||
|
|
||||||
CPUData* cpus;
|
CPUData* cpuData;
|
||||||
|
|
||||||
TtyDriver* ttyDrivers;
|
TtyDriver* ttyDrivers;
|
||||||
bool haveSmapsRollup;
|
bool haveSmapsRollup;
|
||||||
|
|
||||||
|
@ -117,4 +120,6 @@ void ProcessList_delete(ProcessList* pl);
|
||||||
|
|
||||||
void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate);
|
void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate);
|
||||||
|
|
||||||
|
bool ProcessList_isCPUonline(const ProcessList* super, unsigned int id);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -246,10 +246,16 @@ int Platform_getMaxPid() {
|
||||||
|
|
||||||
double Platform_setCPUValues(Meter* this, unsigned int cpu) {
|
double Platform_setCPUValues(Meter* this, unsigned int cpu) {
|
||||||
const LinuxProcessList* pl = (const LinuxProcessList*) this->pl;
|
const LinuxProcessList* pl = (const LinuxProcessList*) this->pl;
|
||||||
const CPUData* cpuData = &(pl->cpus[cpu]);
|
const CPUData* cpuData = &(pl->cpuData[cpu]);
|
||||||
double total = (double) ( cpuData->totalPeriod == 0 ? 1 : cpuData->totalPeriod);
|
double total = (double) ( cpuData->totalPeriod == 0 ? 1 : cpuData->totalPeriod);
|
||||||
double percent;
|
double percent;
|
||||||
double* v = this->values;
|
double* v = this->values;
|
||||||
|
|
||||||
|
if (!cpuData->online) {
|
||||||
|
this->curItems = 0;
|
||||||
|
return NAN;
|
||||||
|
}
|
||||||
|
|
||||||
v[CPU_METER_NICE] = cpuData->nicePeriod / total * 100.0;
|
v[CPU_METER_NICE] = cpuData->nicePeriod / total * 100.0;
|
||||||
v[CPU_METER_NORMAL] = cpuData->userPeriod / total * 100.0;
|
v[CPU_METER_NORMAL] = cpuData->userPeriod / total * 100.0;
|
||||||
if (this->pl->settings->detailedCPUTime) {
|
if (this->pl->settings->detailedCPUTime) {
|
||||||
|
@ -1000,7 +1006,7 @@ void Platform_init(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_SENSORS_SENSORS_H
|
#ifdef HAVE_SENSORS_SENSORS_H
|
||||||
LibSensors_init(NULL);
|
LibSensors_init();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,13 +36,66 @@ static long fscale;
|
||||||
static int pageSize;
|
static int pageSize;
|
||||||
static int pageSizeKB;
|
static int pageSizeKB;
|
||||||
|
|
||||||
ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* dynamicMeters, Hashtable* pidMatchList, uid_t userId) {
|
static void OpenBSDProcessList_updateCPUcount(ProcessList* super) {
|
||||||
|
OpenBSDProcessList* opl = (OpenBSDProcessList*) super;
|
||||||
const int nmib[] = { CTL_HW, HW_NCPU };
|
const int nmib[] = { CTL_HW, HW_NCPU };
|
||||||
const int mib[] = { CTL_HW, HW_NCPUONLINE };
|
const int mib[] = { CTL_HW, HW_NCPUONLINE };
|
||||||
const int fmib[] = { CTL_KERN, KERN_FSCALE };
|
|
||||||
int r;
|
int r;
|
||||||
unsigned int cpu_index_c = 0;
|
unsigned int value;
|
||||||
unsigned int ncpu;
|
size_t size;
|
||||||
|
bool change = false;
|
||||||
|
|
||||||
|
size = sizeof(value);
|
||||||
|
r = sysctl(mib, 2, &value, &size, NULL, 0);
|
||||||
|
if (r < 0 || value < 1) {
|
||||||
|
value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value != super->activeCPUs) {
|
||||||
|
super->activeCPUs = value;
|
||||||
|
change = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
size = sizeof(value);
|
||||||
|
r = sysctl(nmib, 2, &value, &size, NULL, 0);
|
||||||
|
if (r < 0 || value < 1) {
|
||||||
|
value = super->activeCPUs;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value != super->existingCPUs) {
|
||||||
|
opl->cpuData = xReallocArray(opl->cpuData, value + 1, sizeof(CPUData));
|
||||||
|
super->existingCPUs = value;
|
||||||
|
change = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (change) {
|
||||||
|
CPUData* dAvg = &opl->cpuData[0];
|
||||||
|
memset(dAvg, '\0', sizeof(CPUData));
|
||||||
|
dAvg->totalTime = 1;
|
||||||
|
dAvg->totalPeriod = 1;
|
||||||
|
dAvg->online = true;
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < super->existingCPUs; i++) {
|
||||||
|
CPUData* d = &opl->cpuData[i + 1];
|
||||||
|
memset(d, '\0', sizeof(CPUData));
|
||||||
|
d->totalTime = 1;
|
||||||
|
d->totalPeriod = 1;
|
||||||
|
|
||||||
|
const int ncmib[] = { CTL_KERN, KERN_CPUSTATS, i };
|
||||||
|
struct cpustats cpu_stats;
|
||||||
|
|
||||||
|
size = sizeof(cpu_stats);
|
||||||
|
if (sysctl(ncmib, 3, &cpu_stats, &size, NULL, 0) < 0) {
|
||||||
|
CRT_fatalError("ncmib sysctl call failed");
|
||||||
|
}
|
||||||
|
d->online = (cpu_stats.cs_flags & CPUSTATS_ONLINE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* dynamicMeters, Hashtable* pidMatchList, uid_t userId) {
|
||||||
|
const int fmib[] = { CTL_KERN, KERN_FSCALE };
|
||||||
size_t size;
|
size_t size;
|
||||||
char errbuf[_POSIX2_LINE_MAX];
|
char errbuf[_POSIX2_LINE_MAX];
|
||||||
|
|
||||||
|
@ -50,18 +103,7 @@ ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* dynamicMeters, H
|
||||||
ProcessList* pl = (ProcessList*) opl;
|
ProcessList* pl = (ProcessList*) opl;
|
||||||
ProcessList_init(pl, Class(OpenBSDProcess), usersTable, dynamicMeters, pidMatchList, userId);
|
ProcessList_init(pl, Class(OpenBSDProcess), usersTable, dynamicMeters, pidMatchList, userId);
|
||||||
|
|
||||||
size = sizeof(pl->cpuCount);
|
OpenBSDProcessList_updateCPUcount(pl);
|
||||||
r = sysctl(mib, 2, &pl->cpuCount, &size, NULL, 0);
|
|
||||||
if (r < 0 || pl->cpuCount < 1) {
|
|
||||||
pl->cpuCount = 1;
|
|
||||||
}
|
|
||||||
opl->cpus = xCalloc(pl->cpuCount + 1, sizeof(CPUData));
|
|
||||||
|
|
||||||
size = sizeof(int);
|
|
||||||
r = sysctl(nmib, 2, &ncpu, &size, NULL, 0);
|
|
||||||
if (r < 0) {
|
|
||||||
ncpu = pl->cpuCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
size = sizeof(fscale);
|
size = sizeof(fscale);
|
||||||
if (sysctl(fmib, 2, &fscale, &size, NULL, 0) < 0) {
|
if (sysctl(fmib, 2, &fscale, &size, NULL, 0) < 0) {
|
||||||
|
@ -72,12 +114,6 @@ ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* dynamicMeters, H
|
||||||
CRT_fatalError("pagesize sysconf call failed");
|
CRT_fatalError("pagesize sysconf call failed");
|
||||||
pageSizeKB = pageSize / ONE_K;
|
pageSizeKB = pageSize / ONE_K;
|
||||||
|
|
||||||
for (unsigned int i = 0; i <= pl->cpuCount; i++) {
|
|
||||||
CPUData* d = opl->cpus + i;
|
|
||||||
d->totalTime = 1;
|
|
||||||
d->totalPeriod = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
opl->kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, errbuf);
|
opl->kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, errbuf);
|
||||||
if (opl->kd == NULL) {
|
if (opl->kd == NULL) {
|
||||||
CRT_fatalError("kvm_openfiles() failed");
|
CRT_fatalError("kvm_openfiles() failed");
|
||||||
|
@ -85,23 +121,6 @@ ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* dynamicMeters, H
|
||||||
|
|
||||||
opl->cpuSpeed = -1;
|
opl->cpuSpeed = -1;
|
||||||
|
|
||||||
for (unsigned int i = 0; i < ncpu; i++) {
|
|
||||||
const int ncmib[] = { CTL_KERN, KERN_CPUSTATS, i };
|
|
||||||
struct cpustats cpu_stats;
|
|
||||||
|
|
||||||
size = sizeof(cpu_stats);
|
|
||||||
if (sysctl(ncmib, 3, &cpu_stats, &size, NULL, 0) < 0) {
|
|
||||||
CRT_fatalError("ncmib sysctl call failed");
|
|
||||||
}
|
|
||||||
if (cpu_stats.cs_flags & CPUSTATS_ONLINE) {
|
|
||||||
opl->cpus[cpu_index_c].cpuIndex = i;
|
|
||||||
cpu_index_c++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cpu_index_c == pl->cpuCount)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return pl;
|
return pl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,7 +131,7 @@ void ProcessList_delete(ProcessList* this) {
|
||||||
kvm_close(opl->kd);
|
kvm_close(opl->kd);
|
||||||
}
|
}
|
||||||
|
|
||||||
free(opl->cpus);
|
free(opl->cpuData);
|
||||||
|
|
||||||
ProcessList_done(this);
|
ProcessList_done(this);
|
||||||
free(this);
|
free(this);
|
||||||
|
@ -172,7 +191,7 @@ static void OpenBSDProcessList_scanMemoryInfo(ProcessList* pl) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void OpenBSDProcessList_updateCwd(const struct kinfo_proc* kproc, Process* proc) {
|
static void OpenBSDProcessList_updateCwd(const struct kinfo_proc* kproc, Process* proc) {
|
||||||
const int mib[] = { CTL_KERN, KERN_PROC_CWD, kproc->ki_pid };
|
const int mib[] = { CTL_KERN, KERN_PROC_CWD, kproc->p_pid };
|
||||||
char buffer[2048];
|
char buffer[2048];
|
||||||
size_t size = sizeof(buffer);
|
size_t size = sizeof(buffer);
|
||||||
if (sysctl(mib, 3, buffer, &size, NULL, 0) != 0) {
|
if (sysctl(mib, 3, buffer, &size, NULL, 0) != 0) {
|
||||||
|
@ -274,8 +293,6 @@ static void OpenBSDProcessList_scanProcs(OpenBSDProcessList* this) {
|
||||||
Process* proc = ProcessList_getProcess(&this->super, (kproc->p_tid == -1) ? kproc->p_pid : kproc->p_tid, &preExisting, OpenBSDProcess_new);
|
Process* proc = ProcessList_getProcess(&this->super, (kproc->p_tid == -1) ? kproc->p_pid : kproc->p_tid, &preExisting, OpenBSDProcess_new);
|
||||||
OpenBSDProcess* fp = (OpenBSDProcess*) proc;
|
OpenBSDProcess* fp = (OpenBSDProcess*) proc;
|
||||||
|
|
||||||
proc->show = ! ((hideKernelThreads && Process_isKernelThread(proc)) || (hideUserlandThreads && Process_isUserlandThread(proc)));
|
|
||||||
|
|
||||||
if (!preExisting) {
|
if (!preExisting) {
|
||||||
proc->ppid = kproc->p_ppid;
|
proc->ppid = kproc->p_ppid;
|
||||||
proc->tpgid = kproc->p_tpgid;
|
proc->tpgid = kproc->p_tpgid;
|
||||||
|
@ -312,7 +329,7 @@ static void OpenBSDProcessList_scanProcs(OpenBSDProcessList* this) {
|
||||||
proc->m_virt = kproc->p_vm_dsize * pageSizeKB;
|
proc->m_virt = kproc->p_vm_dsize * pageSizeKB;
|
||||||
proc->m_resident = kproc->p_vm_rssize * pageSizeKB;
|
proc->m_resident = kproc->p_vm_rssize * pageSizeKB;
|
||||||
proc->percent_mem = proc->m_resident / (float)this->super.totalMem * 100.0F;
|
proc->percent_mem = proc->m_resident / (float)this->super.totalMem * 100.0F;
|
||||||
proc->percent_cpu = CLAMP(getpcpu(kproc), 0.0F, this->super.cpuCount * 100.0F);
|
proc->percent_cpu = CLAMP(getpcpu(kproc), 0.0F, this->super.activeCPUs * 100.0F);
|
||||||
proc->nice = kproc->p_nice - 20;
|
proc->nice = kproc->p_nice - 20;
|
||||||
proc->time = 100 * (kproc->p_rtime_sec + ((kproc->p_rtime_usec + 500000) / 1000000));
|
proc->time = 100 * (kproc->p_rtime_sec + ((kproc->p_rtime_usec + 500000) / 1000000));
|
||||||
proc->priority = kproc->p_priority - PZERO;
|
proc->priority = kproc->p_priority - PZERO;
|
||||||
|
@ -347,11 +364,13 @@ static void OpenBSDProcessList_scanProcs(OpenBSDProcessList* this) {
|
||||||
if (proc->state == 'R') {
|
if (proc->state == 'R') {
|
||||||
this->super.runningTasks++;
|
this->super.runningTasks++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
proc->show = ! ((hideKernelThreads && Process_isKernelThread(proc)) || (hideUserlandThreads && Process_isUserlandThread(proc)));
|
||||||
proc->updated = true;
|
proc->updated = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void getKernelCPUTimes(int cpuId, u_int64_t* times) {
|
static void getKernelCPUTimes(unsigned int cpuId, u_int64_t* times) {
|
||||||
const int mib[] = { CTL_KERN, KERN_CPTIME2, cpuId };
|
const int mib[] = { CTL_KERN, KERN_CPTIME2, cpuId };
|
||||||
size_t length = sizeof(*times) * CPUSTATES;
|
size_t length = sizeof(*times) * CPUSTATES;
|
||||||
if (sysctl(mib, 3, times, &length, NULL, 0) == -1 || length != sizeof(*times) * CPUSTATES) {
|
if (sysctl(mib, 3, times, &length, NULL, 0) == -1 || length != sizeof(*times) * CPUSTATES) {
|
||||||
|
@ -400,9 +419,14 @@ static void OpenBSDProcessList_scanCPUTime(OpenBSDProcessList* this) {
|
||||||
u_int64_t kernelTimes[CPUSTATES] = {0};
|
u_int64_t kernelTimes[CPUSTATES] = {0};
|
||||||
u_int64_t avg[CPUSTATES] = {0};
|
u_int64_t avg[CPUSTATES] = {0};
|
||||||
|
|
||||||
for (unsigned int i = 0; i < this->super.cpuCount; i++) {
|
for (unsigned int i = 0; i < this->super.existingCPUs; i++) {
|
||||||
getKernelCPUTimes(this->cpus[i].cpuIndex, kernelTimes);
|
CPUData* cpu = &this->cpuData[i + 1];
|
||||||
CPUData* cpu = this->cpus + i + 1;
|
|
||||||
|
if (!cpu->online) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
getKernelCPUTimes(i, kernelTimes);
|
||||||
kernelCPUTimesToHtop(kernelTimes, cpu);
|
kernelCPUTimesToHtop(kernelTimes, cpu);
|
||||||
|
|
||||||
avg[CP_USER] += cpu->userTime;
|
avg[CP_USER] += cpu->userTime;
|
||||||
|
@ -416,10 +440,10 @@ static void OpenBSDProcessList_scanCPUTime(OpenBSDProcessList* this) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < CPUSTATES; i++) {
|
for (int i = 0; i < CPUSTATES; i++) {
|
||||||
avg[i] /= this->super.cpuCount;
|
avg[i] /= this->super.activeCPUs;
|
||||||
}
|
}
|
||||||
|
|
||||||
kernelCPUTimesToHtop(avg, this->cpus);
|
kernelCPUTimesToHtop(avg, &this->cpuData[0]);
|
||||||
|
|
||||||
{
|
{
|
||||||
const int mib[] = { CTL_HW, HW_CPUSPEED };
|
const int mib[] = { CTL_HW, HW_CPUSPEED };
|
||||||
|
@ -436,6 +460,7 @@ static void OpenBSDProcessList_scanCPUTime(OpenBSDProcessList* this) {
|
||||||
void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate) {
|
void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate) {
|
||||||
OpenBSDProcessList* opl = (OpenBSDProcessList*) super;
|
OpenBSDProcessList* opl = (OpenBSDProcessList*) super;
|
||||||
|
|
||||||
|
OpenBSDProcessList_updateCPUcount(super);
|
||||||
OpenBSDProcessList_scanMemoryInfo(super);
|
OpenBSDProcessList_scanMemoryInfo(super);
|
||||||
OpenBSDProcessList_scanCPUTime(opl);
|
OpenBSDProcessList_scanCPUTime(opl);
|
||||||
|
|
||||||
|
@ -446,3 +471,10 @@ void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate) {
|
||||||
|
|
||||||
OpenBSDProcessList_scanProcs(opl);
|
OpenBSDProcessList_scanProcs(opl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ProcessList_isCPUonline(const ProcessList* super, unsigned int id) {
|
||||||
|
assert(id < super->existingCPUs);
|
||||||
|
|
||||||
|
const OpenBSDProcessList* opl = (const OpenBSDProcessList*) super;
|
||||||
|
return opl->cpuData[id + 1].online;
|
||||||
|
}
|
||||||
|
|
|
@ -36,14 +36,14 @@ typedef struct CPUData_ {
|
||||||
unsigned long long int intrPeriod;
|
unsigned long long int intrPeriod;
|
||||||
unsigned long long int idlePeriod;
|
unsigned long long int idlePeriod;
|
||||||
|
|
||||||
int cpuIndex;
|
bool online;
|
||||||
} CPUData;
|
} CPUData;
|
||||||
|
|
||||||
typedef struct OpenBSDProcessList_ {
|
typedef struct OpenBSDProcessList_ {
|
||||||
ProcessList super;
|
ProcessList super;
|
||||||
kvm_t* kd;
|
kvm_t* kd;
|
||||||
|
|
||||||
CPUData* cpus;
|
CPUData* cpuData;
|
||||||
int cpuSpeed;
|
int cpuSpeed;
|
||||||
|
|
||||||
} OpenBSDProcessList;
|
} OpenBSDProcessList;
|
||||||
|
@ -55,4 +55,6 @@ void ProcessList_delete(ProcessList* this);
|
||||||
|
|
||||||
void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate);
|
void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate);
|
||||||
|
|
||||||
|
bool ProcessList_isCPUonline(const ProcessList* super, unsigned int id);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -169,11 +169,18 @@ int Platform_getMaxPid() {
|
||||||
|
|
||||||
double Platform_setCPUValues(Meter* this, unsigned int cpu) {
|
double Platform_setCPUValues(Meter* this, unsigned int cpu) {
|
||||||
const OpenBSDProcessList* pl = (const OpenBSDProcessList*) this->pl;
|
const OpenBSDProcessList* pl = (const OpenBSDProcessList*) this->pl;
|
||||||
const CPUData* cpuData = &(pl->cpus[cpu]);
|
const CPUData* cpuData = &(pl->cpuData[cpu]);
|
||||||
double total = cpuData->totalPeriod == 0 ? 1 : cpuData->totalPeriod;
|
double total;
|
||||||
double totalPercent;
|
double totalPercent;
|
||||||
double* v = this->values;
|
double* v = this->values;
|
||||||
|
|
||||||
|
if (!cpuData->online) {
|
||||||
|
this->curItems = 0;
|
||||||
|
return NAN;
|
||||||
|
}
|
||||||
|
|
||||||
|
total = cpuData->totalPeriod == 0 ? 1 : cpuData->totalPeriod;
|
||||||
|
|
||||||
v[CPU_METER_NICE] = cpuData->nicePeriod / total * 100.0;
|
v[CPU_METER_NICE] = cpuData->nicePeriod / total * 100.0;
|
||||||
v[CPU_METER_NORMAL] = cpuData->userPeriod / total * 100.0;
|
v[CPU_METER_NORMAL] = cpuData->userPeriod / total * 100.0;
|
||||||
if (this->pl->settings->detailedCPUTime) {
|
if (this->pl->settings->detailedCPUTime) {
|
||||||
|
|
|
@ -33,10 +33,13 @@ static int PCPProcessList_computeCPUcount(void) {
|
||||||
static void PCPProcessList_updateCPUcount(PCPProcessList* this) {
|
static void PCPProcessList_updateCPUcount(PCPProcessList* this) {
|
||||||
ProcessList* pl = &(this->super);
|
ProcessList* pl = &(this->super);
|
||||||
unsigned int cpus = PCPProcessList_computeCPUcount();
|
unsigned int cpus = PCPProcessList_computeCPUcount();
|
||||||
if (cpus == pl->cpuCount)
|
if (cpus == pl->existingCPUs)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
pl->cpuCount = cpus;
|
pl->existingCPUs = cpus;
|
||||||
|
// TODO: support offline CPUs and hot swapping
|
||||||
|
pl->activeCPUs = pl->existingCPUs;
|
||||||
|
|
||||||
free(this->percpu);
|
free(this->percpu);
|
||||||
free(this->values);
|
free(this->values);
|
||||||
|
|
||||||
|
@ -79,7 +82,7 @@ void ProcessList_delete(ProcessList* pl) {
|
||||||
PCPProcessList* this = (PCPProcessList*) pl;
|
PCPProcessList* this = (PCPProcessList*) pl;
|
||||||
ProcessList_done(pl);
|
ProcessList_done(pl);
|
||||||
free(this->values);
|
free(this->values);
|
||||||
for (unsigned int i = 0; i < pl->cpuCount; i++)
|
for (unsigned int i = 0; i < pl->existingCPUs; i++)
|
||||||
free(this->percpu[i]);
|
free(this->percpu[i]);
|
||||||
free(this->percpu);
|
free(this->percpu);
|
||||||
free(this->cpu);
|
free(this->cpu);
|
||||||
|
@ -372,7 +375,7 @@ static bool PCPProcessList_updateProcesses(PCPProcessList* this, double period,
|
||||||
|
|
||||||
float percent_cpu = (pp->utime + pp->stime - lasttimes) / period * 100.0;
|
float percent_cpu = (pp->utime + pp->stime - lasttimes) / period * 100.0;
|
||||||
proc->percent_cpu = isnan(percent_cpu) ?
|
proc->percent_cpu = isnan(percent_cpu) ?
|
||||||
0.0 : CLAMP(percent_cpu, 0.0, pl->cpuCount * 100.0);
|
0.0 : CLAMP(percent_cpu, 0.0, pl->activeCPUs * 100.0);
|
||||||
proc->percent_mem = proc->m_resident / (double)pl->totalMem * 100.0;
|
proc->percent_mem = proc->m_resident / (double)pl->totalMem * 100.0;
|
||||||
|
|
||||||
PCPProcessList_updateUsername(proc, pid, offset, pl->usersTable);
|
PCPProcessList_updateUsername(proc, pid, offset, pl->usersTable);
|
||||||
|
@ -538,7 +541,7 @@ static void PCPProcessList_updateAllCPUTime(PCPProcessList* this, Metric metric,
|
||||||
|
|
||||||
static void PCPProcessList_updatePerCPUTime(PCPProcessList* this, Metric metric, CPUMetric cpumetric)
|
static void PCPProcessList_updatePerCPUTime(PCPProcessList* this, Metric metric, CPUMetric cpumetric)
|
||||||
{
|
{
|
||||||
int cpus = this->super.cpuCount;
|
int cpus = this->super.existingCPUs;
|
||||||
if (Metric_values(metric, this->values, cpus, PM_TYPE_U64) == NULL)
|
if (Metric_values(metric, this->values, cpus, PM_TYPE_U64) == NULL)
|
||||||
memset(this->values, 0, cpus * sizeof(pmAtomValue));
|
memset(this->values, 0, cpus * sizeof(pmAtomValue));
|
||||||
for (int i = 0; i < cpus; i++)
|
for (int i = 0; i < cpus; i++)
|
||||||
|
@ -547,7 +550,7 @@ static void PCPProcessList_updatePerCPUTime(PCPProcessList* this, Metric metric,
|
||||||
|
|
||||||
static void PCPProcessList_updatePerCPUReal(PCPProcessList* this, Metric metric, CPUMetric cpumetric)
|
static void PCPProcessList_updatePerCPUReal(PCPProcessList* this, Metric metric, CPUMetric cpumetric)
|
||||||
{
|
{
|
||||||
int cpus = this->super.cpuCount;
|
int cpus = this->super.existingCPUs;
|
||||||
if (Metric_values(metric, this->values, cpus, PM_TYPE_DOUBLE) == NULL)
|
if (Metric_values(metric, this->values, cpus, PM_TYPE_DOUBLE) == NULL)
|
||||||
memset(this->values, 0, cpus * sizeof(pmAtomValue));
|
memset(this->values, 0, cpus * sizeof(pmAtomValue));
|
||||||
for (int i = 0; i < cpus; i++)
|
for (int i = 0; i < cpus; i++)
|
||||||
|
@ -607,7 +610,7 @@ static void PCPProcessList_updateHeader(ProcessList* super, const Settings* sett
|
||||||
PCPProcessList_updateAllCPUTime(this, PCP_CPU_GUEST, CPU_GUEST_TIME);
|
PCPProcessList_updateAllCPUTime(this, PCP_CPU_GUEST, CPU_GUEST_TIME);
|
||||||
PCPProcessList_deriveCPUTime(this->cpu);
|
PCPProcessList_deriveCPUTime(this->cpu);
|
||||||
|
|
||||||
for (unsigned int i = 0; i < super->cpuCount; i++)
|
for (unsigned int i = 0; i < super->existingCPUs; i++)
|
||||||
PCPProcessList_backupCPUTime(this->percpu[i]);
|
PCPProcessList_backupCPUTime(this->percpu[i]);
|
||||||
PCPProcessList_updatePerCPUTime(this, PCP_PERCPU_USER, CPU_USER_TIME);
|
PCPProcessList_updatePerCPUTime(this, PCP_PERCPU_USER, CPU_USER_TIME);
|
||||||
PCPProcessList_updatePerCPUTime(this, PCP_PERCPU_NICE, CPU_NICE_TIME);
|
PCPProcessList_updatePerCPUTime(this, PCP_PERCPU_NICE, CPU_NICE_TIME);
|
||||||
|
@ -618,7 +621,7 @@ static void PCPProcessList_updateHeader(ProcessList* super, const Settings* sett
|
||||||
PCPProcessList_updatePerCPUTime(this, PCP_PERCPU_SOFTIRQ, CPU_SOFTIRQ_TIME);
|
PCPProcessList_updatePerCPUTime(this, PCP_PERCPU_SOFTIRQ, CPU_SOFTIRQ_TIME);
|
||||||
PCPProcessList_updatePerCPUTime(this, PCP_PERCPU_STEAL, CPU_STEAL_TIME);
|
PCPProcessList_updatePerCPUTime(this, PCP_PERCPU_STEAL, CPU_STEAL_TIME);
|
||||||
PCPProcessList_updatePerCPUTime(this, PCP_PERCPU_GUEST, CPU_GUEST_TIME);
|
PCPProcessList_updatePerCPUTime(this, PCP_PERCPU_GUEST, CPU_GUEST_TIME);
|
||||||
for (unsigned int i = 0; i < super->cpuCount; i++)
|
for (unsigned int i = 0; i < super->existingCPUs; i++)
|
||||||
PCPProcessList_deriveCPUTime(this->percpu[i]);
|
PCPProcessList_deriveCPUTime(this->percpu[i]);
|
||||||
|
|
||||||
if (settings->showCPUFrequency)
|
if (settings->showCPUFrequency)
|
||||||
|
@ -671,3 +674,12 @@ void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate) {
|
||||||
double period = (this->timestamp - sample) * 100;
|
double period = (this->timestamp - sample) * 100;
|
||||||
PCPProcessList_updateProcesses(this, period, ×tamp);
|
PCPProcessList_updateProcesses(this, period, ×tamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ProcessList_isCPUonline(const ProcessList* super, unsigned int id) {
|
||||||
|
assert(id < super->existingCPUs);
|
||||||
|
|
||||||
|
// TODO: support offline CPUs and hot swapping
|
||||||
|
(void) super; (void) id;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
|
@ -69,4 +69,6 @@ void ProcessList_delete(ProcessList* pl);
|
||||||
|
|
||||||
void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate);
|
void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate);
|
||||||
|
|
||||||
|
bool ProcessList_isCPUonline(const ProcessList* super, unsigned int id);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -184,7 +184,7 @@ int Platform_getMaxPid() {
|
||||||
|
|
||||||
double Platform_setCPUValues(Meter* this, unsigned int cpu) {
|
double Platform_setCPUValues(Meter* this, unsigned int cpu) {
|
||||||
const SolarisProcessList* spl = (const SolarisProcessList*) this->pl;
|
const SolarisProcessList* spl = (const SolarisProcessList*) this->pl;
|
||||||
unsigned int cpus = this->pl->cpuCount;
|
unsigned int cpus = this->pl->existingCPUs;
|
||||||
const CPUData* cpuData = NULL;
|
const CPUData* cpuData = NULL;
|
||||||
|
|
||||||
if (cpus == 1) {
|
if (cpus == 1) {
|
||||||
|
@ -194,6 +194,11 @@ double Platform_setCPUValues(Meter* this, unsigned int cpu) {
|
||||||
cpuData = &(spl->cpus[cpu]);
|
cpuData = &(spl->cpus[cpu]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!cpuData->online) {
|
||||||
|
this->curItems = 0;
|
||||||
|
return NAN;
|
||||||
|
}
|
||||||
|
|
||||||
double percent;
|
double percent;
|
||||||
double* v = this->values;
|
double* v = this->values;
|
||||||
|
|
||||||
|
|
|
@ -47,32 +47,70 @@ static char* SolarisProcessList_readZoneName(kstat_ctl_t* kd, SolarisProcess* sp
|
||||||
return zname;
|
return zname;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void SolarisProcessList_updateCPUcount(ProcessList* super) {
|
||||||
|
SolarisProcessList* spl = (SolarisProcessList*) super;
|
||||||
|
long int s;
|
||||||
|
bool change = false;
|
||||||
|
|
||||||
|
s = sysconf(_SC_NPROCESSORS_CONF);
|
||||||
|
if (s < 1)
|
||||||
|
CRT_fatalError("Cannot get exisitng CPU count by sysconf(_SC_NPROCESSORS_CONF)");
|
||||||
|
|
||||||
|
if (s != super->existingCPUs) {
|
||||||
|
if (s == 1) {
|
||||||
|
spl->cpus = xRealloc(spl->cpus, sizeof(CPUData));
|
||||||
|
spl->cpus[0].online = true;
|
||||||
|
} else {
|
||||||
|
spl->cpus = xReallocArray(spl->cpus, s + 1, sizeof(CPUData));
|
||||||
|
for (int i = 0; i < s + 1; i++) {
|
||||||
|
spl->cpus[i].online = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
change = true;
|
||||||
|
super->existingCPUs = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
s = sysconf(_SC_NPROCESSORS_ONLN);
|
||||||
|
if (s < 1)
|
||||||
|
CRT_fatalError("Cannot get active CPU count by sysconf(_SC_NPROCESSORS_ONLN)");
|
||||||
|
|
||||||
|
if (s != super->activeCPUs) {
|
||||||
|
change = true;
|
||||||
|
super->activeCPUs = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (change) {
|
||||||
|
kstat_close(spl->kd);
|
||||||
|
spl->kd = kstat_open();
|
||||||
|
if (!spl->kd)
|
||||||
|
CRT_fatalError("Cannot open kstat handle");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* dynamicMeters, Hashtable* pidMatchList, uid_t userId) {
|
ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* dynamicMeters, Hashtable* pidMatchList, uid_t userId) {
|
||||||
SolarisProcessList* spl = xCalloc(1, sizeof(SolarisProcessList));
|
SolarisProcessList* spl = xCalloc(1, sizeof(SolarisProcessList));
|
||||||
ProcessList* pl = (ProcessList*) spl;
|
ProcessList* pl = (ProcessList*) spl;
|
||||||
ProcessList_init(pl, Class(SolarisProcess), usersTable, dynamicMeters, pidMatchList, userId);
|
ProcessList_init(pl, Class(SolarisProcess), usersTable, dynamicMeters, pidMatchList, userId);
|
||||||
|
|
||||||
spl->kd = kstat_open();
|
spl->kd = kstat_open();
|
||||||
|
if (!spl->kd)
|
||||||
|
CRT_fatalError("Cannot open kstat handle");
|
||||||
|
|
||||||
pageSize = sysconf(_SC_PAGESIZE);
|
pageSize = sysconf(_SC_PAGESIZE);
|
||||||
if (pageSize == -1)
|
if (pageSize == -1)
|
||||||
CRT_fatalError("Cannot get pagesize by sysconf(_SC_PAGESIZE)");
|
CRT_fatalError("Cannot get pagesize by sysconf(_SC_PAGESIZE)");
|
||||||
pageSizeKB = pageSize / 1024;
|
pageSizeKB = pageSize / 1024;
|
||||||
|
|
||||||
pl->cpuCount = sysconf(_SC_NPROCESSORS_ONLN);
|
SolarisProcessList_updateCPUcount(pl);
|
||||||
if (pl->cpuCount == (unsigned int)-1)
|
|
||||||
CRT_fatalError("Cannot get CPU count by sysconf(_SC_NPROCESSORS_ONLN)");
|
|
||||||
else if (pl->cpuCount == 1)
|
|
||||||
spl->cpus = xRealloc(spl->cpus, sizeof(CPUData));
|
|
||||||
else
|
|
||||||
spl->cpus = xRealloc(spl->cpus, (pl->cpuCount + 1) * sizeof(CPUData));
|
|
||||||
|
|
||||||
return pl;
|
return pl;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void SolarisProcessList_scanCPUTime(ProcessList* pl) {
|
static inline void SolarisProcessList_scanCPUTime(ProcessList* pl) {
|
||||||
const SolarisProcessList* spl = (SolarisProcessList*) pl;
|
const SolarisProcessList* spl = (SolarisProcessList*) pl;
|
||||||
unsigned int cpus = pl->cpuCount;
|
unsigned int activeCPUs = pl->activeCPUs;
|
||||||
|
unsigned int existingCPUs = pl->existingCPUs;
|
||||||
kstat_t* cpuinfo = NULL;
|
kstat_t* cpuinfo = NULL;
|
||||||
kstat_named_t* idletime = NULL;
|
kstat_named_t* idletime = NULL;
|
||||||
kstat_named_t* intrtime = NULL;
|
kstat_named_t* intrtime = NULL;
|
||||||
|
@ -85,44 +123,45 @@ static inline void SolarisProcessList_scanCPUTime(ProcessList* pl) {
|
||||||
double userbuf = 0;
|
double userbuf = 0;
|
||||||
int arrskip = 0;
|
int arrskip = 0;
|
||||||
|
|
||||||
assert(cpus > 0);
|
assert(existingCPUs > 0);
|
||||||
|
assert(spl->kd);
|
||||||
|
|
||||||
if (cpus > 1) {
|
if (existingCPUs > 1) {
|
||||||
// Store values for the stats loop one extra element up in the array
|
// Store values for the stats loop one extra element up in the array
|
||||||
// to leave room for the average to be calculated afterwards
|
// to leave room for the average to be calculated afterwards
|
||||||
arrskip++;
|
arrskip++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate per-CPU statistics first
|
// Calculate per-CPU statistics first
|
||||||
for (unsigned int i = 0; i < cpus; i++) {
|
for (unsigned int i = 0; i < existingCPUs; i++) {
|
||||||
if (spl->kd != NULL) {
|
CPUData* cpuData = &(spl->cpus[i + arrskip]);
|
||||||
if ((cpuinfo = kstat_lookup_wrapper(spl->kd, "cpu", i, "sys")) != NULL) {
|
|
||||||
if (kstat_read(spl->kd, cpuinfo, NULL) != -1) {
|
if ((cpuinfo = kstat_lookup_wrapper(spl->kd, "cpu", i, "sys")) != NULL) {
|
||||||
idletime = kstat_data_lookup_wrapper(cpuinfo, "cpu_nsec_idle");
|
cpuData->online = true;
|
||||||
intrtime = kstat_data_lookup_wrapper(cpuinfo, "cpu_nsec_intr");
|
if (kstat_read(spl->kd, cpuinfo, NULL) != -1) {
|
||||||
krnltime = kstat_data_lookup_wrapper(cpuinfo, "cpu_nsec_kernel");
|
idletime = kstat_data_lookup_wrapper(cpuinfo, "cpu_nsec_idle");
|
||||||
usertime = kstat_data_lookup_wrapper(cpuinfo, "cpu_nsec_user");
|
intrtime = kstat_data_lookup_wrapper(cpuinfo, "cpu_nsec_intr");
|
||||||
}
|
krnltime = kstat_data_lookup_wrapper(cpuinfo, "cpu_nsec_kernel");
|
||||||
|
usertime = kstat_data_lookup_wrapper(cpuinfo, "cpu_nsec_user");
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
cpuData->online = false;
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert( (idletime != NULL) && (intrtime != NULL)
|
assert( (idletime != NULL) && (intrtime != NULL)
|
||||||
&& (krnltime != NULL) && (usertime != NULL) );
|
&& (krnltime != NULL) && (usertime != NULL) );
|
||||||
|
|
||||||
if (pl->settings->showCPUFrequency) {
|
if (pl->settings->showCPUFrequency) {
|
||||||
if (spl->kd != NULL) {
|
if ((cpuinfo = kstat_lookup_wrapper(spl->kd, "cpu_info", i, NULL)) != NULL) {
|
||||||
if ((cpuinfo = kstat_lookup_wrapper(spl->kd, "cpu_info", i, NULL)) != NULL) {
|
if (kstat_read(spl->kd, cpuinfo, NULL) != -1) {
|
||||||
if (kstat_read(spl->kd, cpuinfo, NULL) != -1) {
|
cpu_freq = kstat_data_lookup_wrapper(cpuinfo, "current_clock_Hz");
|
||||||
cpu_freq = kstat_data_lookup_wrapper(cpuinfo, "current_clock_Hz");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
assert( cpu_freq != NULL );
|
assert( cpu_freq != NULL );
|
||||||
}
|
}
|
||||||
|
|
||||||
CPUData* cpuData = &(spl->cpus[i + arrskip]);
|
|
||||||
|
|
||||||
uint64_t totaltime = (idletime->value.ui64 - cpuData->lidle)
|
uint64_t totaltime = (idletime->value.ui64 - cpuData->lidle)
|
||||||
+ (intrtime->value.ui64 - cpuData->lintr)
|
+ (intrtime->value.ui64 - cpuData->lintr)
|
||||||
+ (krnltime->value.ui64 - cpuData->lkrnl)
|
+ (krnltime->value.ui64 - cpuData->lkrnl)
|
||||||
|
@ -143,7 +182,7 @@ static inline void SolarisProcessList_scanCPUTime(ProcessList* pl) {
|
||||||
// Add frequency in MHz
|
// Add frequency in MHz
|
||||||
cpuData->frequency = pl->settings->showCPUFrequency ? (double)cpu_freq->value.ui64 / 1E6 : NAN;
|
cpuData->frequency = pl->settings->showCPUFrequency ? (double)cpu_freq->value.ui64 / 1E6 : NAN;
|
||||||
// Accumulate the current percentages into buffers for later average calculation
|
// Accumulate the current percentages into buffers for later average calculation
|
||||||
if (cpus > 1) {
|
if (existingCPUs > 1) {
|
||||||
userbuf += cpuData->userPercent;
|
userbuf += cpuData->userPercent;
|
||||||
krnlbuf += cpuData->systemPercent;
|
krnlbuf += cpuData->systemPercent;
|
||||||
intrbuf += cpuData->irqPercent;
|
intrbuf += cpuData->irqPercent;
|
||||||
|
@ -151,14 +190,14 @@ static inline void SolarisProcessList_scanCPUTime(ProcessList* pl) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cpus > 1) {
|
if (existingCPUs > 1) {
|
||||||
CPUData* cpuData = &(spl->cpus[0]);
|
CPUData* cpuData = &(spl->cpus[0]);
|
||||||
cpuData->userPercent = userbuf / cpus;
|
cpuData->userPercent = userbuf / activeCPUs;
|
||||||
cpuData->nicePercent = (double)0.0; // Not implemented on Solaris
|
cpuData->nicePercent = (double)0.0; // Not implemented on Solaris
|
||||||
cpuData->systemPercent = krnlbuf / cpus;
|
cpuData->systemPercent = krnlbuf / activeCPUs;
|
||||||
cpuData->irqPercent = intrbuf / cpus;
|
cpuData->irqPercent = intrbuf / activeCPUs;
|
||||||
cpuData->systemAllPercent = cpuData->systemPercent + cpuData->irqPercent;
|
cpuData->systemAllPercent = cpuData->systemPercent + cpuData->irqPercent;
|
||||||
cpuData->idlePercent = idlebuf / cpus;
|
cpuData->idlePercent = idlebuf / activeCPUs;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -479,6 +518,7 @@ static int SolarisProcessList_walkproc(psinfo_t* _psinfo, lwpsinfo_t* _lwpsinfo,
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate) {
|
void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate) {
|
||||||
|
SolarisProcessList_updateCPUcount(super);
|
||||||
SolarisProcessList_scanCPUTime(super);
|
SolarisProcessList_scanCPUTime(super);
|
||||||
SolarisProcessList_scanMemoryInfo(super);
|
SolarisProcessList_scanMemoryInfo(super);
|
||||||
SolarisProcessList_scanZfsArcstats(super);
|
SolarisProcessList_scanZfsArcstats(super);
|
||||||
|
@ -491,3 +531,11 @@ void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate) {
|
||||||
super->kernelThreads = 1;
|
super->kernelThreads = 1;
|
||||||
proc_walk(&SolarisProcessList_walkproc, super, PR_WALK_LWP);
|
proc_walk(&SolarisProcessList_walkproc, super, PR_WALK_LWP);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ProcessList_isCPUonline(const ProcessList* super, unsigned int id) {
|
||||||
|
assert(id < super->existingCPUs);
|
||||||
|
|
||||||
|
const SolarisProcessList* spl = (const SolarisProcessList*) super;
|
||||||
|
|
||||||
|
return (super->existingCPUs == 1) ? true : spl->cpus[id + 1].online;
|
||||||
|
}
|
||||||
|
|
|
@ -44,6 +44,7 @@ typedef struct CPUData_ {
|
||||||
uint64_t lkrnl;
|
uint64_t lkrnl;
|
||||||
uint64_t lintr;
|
uint64_t lintr;
|
||||||
uint64_t lidle;
|
uint64_t lidle;
|
||||||
|
bool online;
|
||||||
} CPUData;
|
} CPUData;
|
||||||
|
|
||||||
typedef struct SolarisProcessList_ {
|
typedef struct SolarisProcessList_ {
|
||||||
|
@ -59,4 +60,6 @@ void ProcessList_delete(ProcessList* pl);
|
||||||
|
|
||||||
void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate);
|
void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate);
|
||||||
|
|
||||||
|
bool ProcessList_isCPUonline(const ProcessList* super, unsigned int id);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -18,7 +18,8 @@ ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* dynamicMeters, H
|
||||||
ProcessList* this = xCalloc(1, sizeof(ProcessList));
|
ProcessList* this = xCalloc(1, sizeof(ProcessList));
|
||||||
ProcessList_init(this, Class(Process), usersTable, dynamicMeters, pidMatchList, userId);
|
ProcessList_init(this, Class(Process), usersTable, dynamicMeters, pidMatchList, userId);
|
||||||
|
|
||||||
this->cpuCount = 1;
|
this->existingCPUs = 1;
|
||||||
|
this->activeCPUs = 1;
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
@ -88,3 +89,11 @@ void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate) {
|
||||||
if (!preExisting)
|
if (!preExisting)
|
||||||
ProcessList_add(super, proc);
|
ProcessList_add(super, proc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ProcessList_isCPUonline(const ProcessList* super, unsigned int id) {
|
||||||
|
assert(id < super->existingCPUs);
|
||||||
|
|
||||||
|
(void) super; (void) id;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
|
@ -16,4 +16,6 @@ void ProcessList_delete(ProcessList* this);
|
||||||
|
|
||||||
void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate);
|
void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate);
|
||||||
|
|
||||||
|
bool ProcessList_isCPUonline(const ProcessList* super, unsigned int id);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue