Skip to content

Commit

Permalink
Rework CPU counting
Browse files Browse the repository at this point in the history
Currently htop does not support offline CPUs and hot-swapping, e.g. via
    echo 0 > /sys/devices/system/cpu/cpu2/online

Split the current single cpuCount variable into activeCPUs and
existingCPUs.

Supersedes: #650
Related: #580
  • Loading branch information
cgzones committed Jun 12, 2021
1 parent df752dd commit f26c27f
Show file tree
Hide file tree
Showing 28 changed files with 264 additions and 144 deletions.
2 changes: 1 addition & 1 deletion Action.c
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,7 @@ static Htop_Reaction actionSetAffinity(State* st) {
if (Settings_isReadonly())
return HTOP_OK;

if (st->pl->cpuCount == 1)
if (st->pl->activeCPUs == 1)
return HTOP_OK;

#if (defined(HAVE_LIBHWLOC) || defined(HAVE_LINUX_AFFINITY))
Expand Down
4 changes: 2 additions & 2 deletions Affinity.c
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ Affinity* Affinity_get(const Process* proc, ProcessList* pl) {
if (ok) {
affinity = Affinity_new(pl);
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);
}
} else {
Expand Down Expand Up @@ -93,7 +93,7 @@ Affinity* Affinity_get(const Process* proc, ProcessList* pl) {
return NULL;

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)) {
Affinity_add(affinity, i);
}
Expand Down
6 changes: 4 additions & 2 deletions AffinityPanel.c
Original file line number Diff line number Diff line change
Expand Up @@ -383,7 +383,8 @@ Panel* AffinityPanel_new(ProcessList* pl, const Affinity* affinity, int* width)
Panel_setHeader(super, "Use CPUs:");

unsigned int curCpu = 0;
for (unsigned int i = 0; i < pl->cpuCount; i++) {
for (unsigned int i = 0; i < pl->existingCPUs; i++) {
/* TODO: skip offline CPUs */
char number[16];
xSnprintf(number, 9, "CPU %d", Settings_cpuId(pl->settings, i));
unsigned cpu_width = 4 + strlen(number);
Expand Down Expand Up @@ -427,7 +428,8 @@ Affinity* AffinityPanel_getAffinity(Panel* super, ProcessList* pl) {
Affinity_add(affinity, i);
hwloc_bitmap_foreach_end();
#else
for (unsigned int i = 0; i < this->pl->cpuCount; i++) {
for (unsigned int i = 0; i < this->pl->existingCPUs; i++) {
/* TODO: skip offline CPUs */
const MaskItem* item = (const MaskItem*)Vector_get(this->cpuids, i);
if (item->value) {
Affinity_add(affinity, item->cpu);
Expand Down
2 changes: 1 addition & 1 deletion AvailableMetersPanel.c
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ AvailableMetersPanel* AvailableMetersPanel_new(Settings* settings, Header* heade
}
// Handle (&CPUMeter_class)
const MeterClass* type = &CPUMeter_class;
unsigned int cpus = pl->cpuCount;
unsigned int cpus = pl->existingCPUs;
if (cpus > 1) {
Panel_add(super, (Object*) ListItem_new("CPU average", 0));
for (unsigned int i = 1; i <= cpus; i++) {
Expand Down
21 changes: 12 additions & 9 deletions CPUMeter.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,29 +43,32 @@ static void CPUMeter_init(Meter* this) {
unsigned int cpu = this->param;
if (cpu == 0) {
Meter_setCaption(this, "Avg");
} else if (this->pl->cpuCount > 1) {
} else if (this->pl->activeCPUs > 1) {
char caption[10];
xSnprintf(caption, sizeof(caption), "%3u", Settings_cpuId(this->pl->settings, cpu - 1));
Meter_setCaption(this, caption);
}
}

static void CPUMeter_updateValues(Meter* this) {
memset(this->values, 0, sizeof(double) * CPU_METER_ITEMCOUNT);

unsigned int cpu = this->param;
if (cpu > this->pl->cpuCount) {
if (cpu > this->pl->existingCPUs) {
xSnprintf(this->txtBuffer, sizeof(this->txtBuffer), "absent");
for (uint8_t i = 0; i < this->curItems; i++)
this->values[i] = 0;
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 cpuFrequencyBuffer[16] = { 0 };
char cpuTemperatureBuffer[16] = { 0 };

double percent = Platform_setCPUValues(this, cpu);

if (this->pl->settings->showCPUUsage) {
xSnprintf(cpuUsageBuffer, sizeof(cpuUsageBuffer), "%.1f%%", percent);
}
Expand Down Expand Up @@ -104,7 +107,7 @@ static void CPUMeter_display(const Object* cast, RichString* out) {
int len;
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");
return;
}
Expand Down Expand Up @@ -198,7 +201,7 @@ static void AllCPUsMeter_updateValues(Meter* this) {
}

static void CPUMeterCommonInit(Meter* this, int ncol) {
unsigned int cpus = this->pl->cpuCount;
unsigned int cpus = this->pl->existingCPUs;
CPUMeterData* data = this->meterData;
if (!data) {
data = this->meterData = xMalloc(sizeof(CPUMeterData));
Expand Down
2 changes: 1 addition & 1 deletion CommandLine.c
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@ int CommandLine_run(const char* name, int argc, char** argv) {
UsersTable* ut = UsersTable_new();
ProcessList* pl = ProcessList_new(ut, flags.pidMatchList, flags.userId);

Settings* settings = Settings_new(pl->cpuCount);
Settings* settings = Settings_new(pl->activeCPUs);
pl->settings = settings;

Header* header = Header_new(pl, settings, 2);
Expand Down
12 changes: 6 additions & 6 deletions LoadAverageMeter.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,12 @@ static void LoadAverageMeter_updateValues(Meter* this) {
if (this->values[0] < 1.0) {
this->curAttributes = OK_attributes;
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->total = this->pl->cpuCount;
this->total = this->pl->activeCPUs;
} else {
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]);
Expand All @@ -79,12 +79,12 @@ static void LoadMeter_updateValues(Meter* this) {
if (this->values[0] < 1.0) {
this->curAttributes = OK_attributes;
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->total = this->pl->cpuCount;
this->total = this->pl->activeCPUs;
} else {
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]);
Expand Down
2 changes: 1 addition & 1 deletion Process.c
Original file line number Diff line number Diff line change
Expand Up @@ -821,7 +821,7 @@ void Process_writeField(const Process* this, RichString* str, ProcessField field
case PERCENT_NORM_CPU: {
float cpuPercentage = this->percent_cpu;
if (field == PERCENT_NORM_CPU) {
cpuPercentage /= this->processList->cpuCount;
cpuPercentage /= this->processList->activeCPUs;
}
if (cpuPercentage > 999.9F) {
xSnprintf(buffer, n, "%4u ", (unsigned int)cpuPercentage);
Expand Down
3 changes: 2 additions & 1 deletion ProcessList.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ ProcessList* ProcessList_init(ProcessList* this, const ObjectClass* klass, Users
this->userId = userId;

// set later by platform-specific code
this->cpuCount = 0;
this->activeCPUs = 0;
this->existingCPUs = 0;
this->monotonicMs = 0;

// always maintain valid realtime timestamps
Expand Down
3 changes: 2 additions & 1 deletion ProcessList.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,8 @@ typedef struct ProcessList_ {
memory_t usedSwap;
memory_t cachedSwap;

unsigned int cpuCount;
unsigned int activeCPUs;
unsigned int existingCPUs;
} ProcessList;

ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidMatchList, uid_t userId);
Expand Down
2 changes: 1 addition & 1 deletion TasksMeter.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ static void TasksMeter_updateValues(Meter* this) {
this->values[0] = pl->kernelThreads;
this->values[1] = 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;

xSnprintf(this->txtBuffer, sizeof(this->txtBuffer), "%d/%d", (int) this->values[3], (int) this->total);
Expand Down
8 changes: 5 additions & 3 deletions darwin/DarwinProcessList.c
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,9 @@ ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidMatchList, ui
ProcessList_init(&this->super, Class(DarwinProcess), usersTable, pidMatchList, userId);

/* 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_allocateCPULoadInfo(&this->curr_load);

Expand Down Expand Up @@ -184,13 +186,13 @@ void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate) {

/* Get the time difference */
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) {
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 */
super->kernelThreads = 0;
Expand Down
12 changes: 6 additions & 6 deletions darwin/Platform.c
Original file line number Diff line number Diff line change
Expand Up @@ -186,21 +186,21 @@ int Platform_getMaxPid() {

static double Platform_setCPUAverageValues(Meter* mtr) {
const ProcessList* dpl = mtr->pl;
unsigned int cpus = dpl->cpuCount;
unsigned int activeCPUs = dpl->activeCPUs;
double sumNice = 0.0;
double sumNormal = 0.0;
double sumKernel = 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);
sumNice += mtr->values[CPU_METER_NICE];
sumNormal += mtr->values[CPU_METER_NORMAL];
sumKernel += mtr->values[CPU_METER_KERNEL];
}
mtr->values[CPU_METER_NICE] = sumNice / cpus;
mtr->values[CPU_METER_NORMAL] = sumNormal / cpus;
mtr->values[CPU_METER_KERNEL] = sumKernel / cpus;
return sumPercent / cpus;
mtr->values[CPU_METER_NICE] = sumNice / activeCPUs;
mtr->values[CPU_METER_NORMAL] = sumNormal / activeCPUs;
mtr->values[CPU_METER_KERNEL] = sumKernel / activeCPUs;
return sumPercent / activeCPUs;
}

double Platform_setCPUValues(Meter* mtr, unsigned int cpu) {
Expand Down
10 changes: 6 additions & 4 deletions dragonflybsd/DragonFlyBSDProcessList.c
Original file line number Diff line number Diff line change
Expand Up @@ -95,13 +95,15 @@ ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidMatchList, ui
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 ) {
dfpl->cpus = xRealloc(dfpl->cpus, sizeof(CPUData));
} else {
// 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);
Expand Down Expand Up @@ -140,8 +142,8 @@ void ProcessList_delete(ProcessList* this) {
static inline void DragonFlyBSDProcessList_scanCPUTime(ProcessList* pl) {
const DragonFlyBSDProcessList* dfpl = (DragonFlyBSDProcessList*) pl;

unsigned int cpus = pl->cpuCount; // actual CPU count
unsigned int maxcpu = cpus; // max iteration (in case we have average + smp)
unsigned int cpus = pl->existingCPUs; // actual CPU count
unsigned int maxcpu = cpus; // max iteration (in case we have average + smp)
int cp_times_offset;

assert(cpus > 0);
Expand Down
2 changes: 1 addition & 1 deletion dragonflybsd/Platform.c
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ int Platform_getMaxPid() {

double Platform_setCPUValues(Meter* this, unsigned int cpu) {
const DragonFlyBSDProcessList* fpl = (const DragonFlyBSDProcessList*) this->pl;
unsigned int cpus = this->pl->cpuCount;
unsigned int cpus = this->pl->activeCPUs;
const CPUData* cpuData;

if (cpus == 1) {
Expand Down
10 changes: 6 additions & 4 deletions freebsd/FreeBSDProcessList.c
Original file line number Diff line number Diff line change
Expand Up @@ -125,13 +125,15 @@ ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidMatchList, ui
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 ) {
fpl->cpus = xRealloc(fpl->cpus, sizeof(CPUData));
} else {
// 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));
}


Expand Down Expand Up @@ -169,8 +171,8 @@ void ProcessList_delete(ProcessList* this) {
static inline void FreeBSDProcessList_scanCPU(ProcessList* pl) {
const FreeBSDProcessList* fpl = (FreeBSDProcessList*) pl;

unsigned int cpus = pl->cpuCount; // actual CPU count
unsigned int maxcpu = cpus; // max iteration (in case we have average + smp)
unsigned int cpus = pl->existingCPUs; // actual CPU count
unsigned int maxcpu = cpus; // max iteration (in case we have average + smp)
int cp_times_offset;

assert(cpus > 0);
Expand Down
2 changes: 1 addition & 1 deletion freebsd/Platform.c
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ int Platform_getMaxPid() {

double Platform_setCPUValues(Meter* this, unsigned int cpu) {
const FreeBSDProcessList* fpl = (const FreeBSDProcessList*) this->pl;
unsigned int cpus = this->pl->cpuCount;
unsigned int cpus = this->pl->activeCPUs;
const CPUData* cpuData;

if (cpus == 1) {
Expand Down
Loading

0 comments on commit f26c27f

Please sign in to comment.