summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHisham Muhammad <hisham@gobolinux.org>2011-11-18 06:08:56 +0000
committerHisham Muhammad <hisham@gobolinux.org>2011-11-18 06:08:56 +0000
commit7ca10817122d3b7b30fabb1cadb75e5ee14b364e (patch)
tree14fa282dcad8eac9401fa463484b0b1693f43e1f
parent38856488815711138aa9d0ba32cca66694717171 (diff)
Mega-commit with features and tweaks for 1.0:
* Performance improvements * Support for splitting CPU meters into two or four columns (thanks to Wim Heirman) * Switch from PLPA, which is now deprecated, to HWLOC. * Bring back support for native Linux sched_setaffinity, so we don't have to use HWLOC where we don't need to. * Support for typing in user names and column fields in selection panels.
-rw-r--r--AvailableColumnsPanel.c5
-rw-r--r--CPUMeter.c152
-rw-r--r--CPUMeter.h11
-rw-r--r--ChangeLog7
-rw-r--r--ColumnsPanel.c7
-rw-r--r--Header.c12
-rw-r--r--Header.h2
-rw-r--r--Meter.c9
-rw-r--r--OpenFilesScreen.c2
-rw-r--r--Panel.c37
-rw-r--r--Panel.h3
-rw-r--r--Process.c26
-rw-r--r--Process.h8
-rw-r--r--ProcessList.c50
-rw-r--r--Settings.c12
-rw-r--r--Settings.h2
-rw-r--r--Vector.c93
-rw-r--r--Vector.h19
-rw-r--r--configure.ac29
-rw-r--r--debug.h2
-rw-r--r--htop.c43
21 files changed, 429 insertions, 102 deletions
diff --git a/AvailableColumnsPanel.c b/AvailableColumnsPanel.c
index b21bd3c3..c0b6af14 100644
--- a/AvailableColumnsPanel.c
+++ b/AvailableColumnsPanel.c
@@ -46,6 +46,11 @@ static HandlerResult AvailableColumnsPanel_eventHandler(Panel* super, int ch) {
result = HANDLED;
break;
}
+ default:
+ {
+ result = Panel_selectByTyping(super, ch);
+ break;
+ }
}
return result;
}
diff --git a/CPUMeter.c b/CPUMeter.c
index 2c4c4dbc..f2a4fe34 100644
--- a/CPUMeter.c
+++ b/CPUMeter.c
@@ -122,38 +122,91 @@ static void CPUMeter_display(Object* cast, RichString* out) {
}
}
+static void AllCPUsMeter_getRange(Meter* this, int* start, int* count) {
+ int cpus = this->pl->cpuCount;
+ switch(this->type->name[0]) {
+ default:
+ case 'A': // All
+ *start = 0;
+ *count = cpus;
+ break;
+ case 'L': // First Half
+ *start = 0;
+ *count = (cpus+1) / 2;
+ break;
+ case 'R': // Second Half
+ *start = (cpus+1) / 2;
+ *count = cpus / 2;
+ break;
+ }
+}
+
static void AllCPUsMeter_init(Meter* this) {
int cpus = this->pl->cpuCount;
if (!this->drawData)
this->drawData = calloc(sizeof(Meter*), cpus);
Meter** meters = (Meter**) this->drawData;
- for (int i = 0; i < cpus; i++) {
+ int start, count;
+ AllCPUsMeter_getRange(this, &start, &count);
+ for (int i = 0; i < count; i++) {
if (!meters[i])
- meters[i] = Meter_new(this->pl, i+1, &CPUMeter);
+ meters[i] = Meter_new(this->pl, start+i+1, &CPUMeter);
meters[i]->type->init(meters[i]);
}
- this->h = Meter_modes[this->mode]->h * cpus;
+ if (this->mode == 0)
+ this->mode = BAR_METERMODE;
+ int h = Meter_modes[this->mode]->h;
+ if (strchr(this->type->name, '2'))
+ this->h = h * ((count+1) / 2);
+ else
+ this->h = h * count;
}
static void AllCPUsMeter_done(Meter* this) {
- int cpus = this->pl->cpuCount;
Meter** meters = (Meter**) this->drawData;
- for (int i = 0; i < cpus; i++)
+ int start, count;
+ AllCPUsMeter_getRange(this, &start, &count);
+ for (int i = 0; i < count; i++)
Meter_delete((Object*)meters[i]);
}
static void AllCPUsMeter_setMode(Meter* this, int mode) {
+ Meter** meters = (Meter**) this->drawData;
this->mode = mode;
- int cpus = this->pl->cpuCount;
- int h = Meter_modes[this->mode]->h;
- this->h = h * cpus;
+ int h = Meter_modes[mode]->h;
+ int start, count;
+ AllCPUsMeter_getRange(this, &start, &count);
+ for (int i = 0; i < count; i++) {
+ Meter_setMode(meters[i], mode);
+ }
+ if (strchr(this->type->name, '2'))
+ this->h = h * ((count+1) / 2);
+ else
+ this->h = h * count;
}
-static void AllCPUsMeter_draw(Meter* this, int x, int y, int w) {
- int cpus = this->pl->cpuCount;
+static void DualColCPUsMeter_draw(Meter* this, int x, int y, int w) {
+ Meter** meters = (Meter**) this->drawData;
+ int start, count;
+ AllCPUsMeter_getRange(this, &start, &count);
+ int height = (count+1)/2;
+ int startY = y;
+ for (int i = 0; i < height; i++) {
+ meters[i]->draw(meters[i], x, y, (w-2)/2);
+ y += meters[i]->h;
+ }
+ y = startY;
+ for (int i = height; i < count; i++) {
+ meters[i]->draw(meters[i], x+(w-1)/2+2, y, (w-2)/2);
+ y += meters[i]->h;
+ }
+}
+
+static void SingleColCPUsMeter_draw(Meter* this, int x, int y, int w) {
Meter** meters = (Meter**) this->drawData;
- for (int i = 0; i < cpus; i++) {
- Meter_setMode(meters[i], this->mode);
+ int start, count;
+ AllCPUsMeter_getRange(this, &start, &count);
+ for (int i = 0; i < count; i++) {
meters[i]->draw(meters[i], x, y, w);
y += meters[i]->h;
}
@@ -178,10 +231,81 @@ MeterType AllCPUsMeter = {
.total = 100.0,
.attributes = CPUMeter_attributes,
.name = "AllCPUs",
- .uiName = "All CPUs",
+ .uiName = "CPUs (1/1)",
.caption = "CPU",
- .draw = AllCPUsMeter_draw,
+ .draw = SingleColCPUsMeter_draw,
.init = AllCPUsMeter_init,
.setMode = AllCPUsMeter_setMode,
.done = AllCPUsMeter_done
};
+
+MeterType AllCPUs2Meter = {
+ .mode = 0,
+ .items = 1,
+ .total = 100.0,
+ .attributes = CPUMeter_attributes,
+ .name = "AllCPUs2",
+ .uiName = "CPUs (1&2/2)",
+ .caption = "CPU",
+ .draw = DualColCPUsMeter_draw,
+ .init = AllCPUsMeter_init,
+ .setMode = AllCPUsMeter_setMode,
+ .done = AllCPUsMeter_done
+};
+
+MeterType LeftCPUsMeter = {
+ .mode = 0,
+ .items = 1,
+ .total = 100.0,
+ .attributes = CPUMeter_attributes,
+ .name = "LeftCPUs",
+ .uiName = "CPUs (1/2)",
+ .caption = "CPU",
+ .draw = SingleColCPUsMeter_draw,
+ .init = AllCPUsMeter_init,
+ .setMode = AllCPUsMeter_setMode,
+ .done = AllCPUsMeter_done
+};
+
+MeterType RightCPUsMeter = {
+ .mode = 0,
+ .items = 1,
+ .total = 100.0,
+ .attributes = CPUMeter_attributes,
+ .name = "RightCPUs",
+ .uiName = "CPUs (2/2)",
+ .caption = "CPU",
+ .draw = SingleColCPUsMeter_draw,
+ .init = AllCPUsMeter_init,
+ .setMode = AllCPUsMeter_setMode,
+ .done = AllCPUsMeter_done
+};
+
+MeterType LeftCPUs2Meter = {
+ .mode = 0,
+ .items = 1,
+ .total = 100.0,
+ .attributes = CPUMeter_attributes,
+ .name = "LeftCPUs2",
+ .uiName = "CPUs (1&2/4)",
+ .caption = "CPU",
+ .draw = DualColCPUsMeter_draw,
+ .init = AllCPUsMeter_init,
+ .setMode = AllCPUsMeter_setMode,
+ .done = AllCPUsMeter_done
+};
+
+MeterType RightCPUs2Meter = {
+ .mode = 0,
+ .items = 1,
+ .total = 100.0,
+ .attributes = CPUMeter_attributes,
+ .name = "RightCPUs2",
+ .uiName = "CPUs (3&4/4)",
+ .caption = "CPU",
+ .draw = DualColCPUsMeter_draw,
+ .init = AllCPUsMeter_init,
+ .setMode = AllCPUsMeter_setMode,
+ .done = AllCPUsMeter_done
+};
+
diff --git a/CPUMeter.h b/CPUMeter.h
index 37f7b431..47ef8882 100644
--- a/CPUMeter.h
+++ b/CPUMeter.h
@@ -34,4 +34,15 @@ extern MeterType CPUMeter;
extern MeterType AllCPUsMeter;
+extern MeterType AllCPUs2Meter;
+
+extern MeterType LeftCPUsMeter;
+
+extern MeterType RightCPUsMeter;
+
+extern MeterType LeftCPUs2Meter;
+
+extern MeterType RightCPUs2Meter;
+
+
#endif
diff --git a/ChangeLog b/ChangeLog
index ae9b57d6..724aaa77 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,7 +1,12 @@
-What's new in version 0.9.1
+What's new in version 1.0
+* Performance improvements
+* Support for splitting CPU meters into two or four columns
+ (thanks to Wim Heirman)
* Switch from PLPA, which is now deprecated, to HWLOC.
+* Bring back support for native Linux sched_setaffinity,
+ so we don't have to use HWLOC where we don't need to.
* Support for typing in user names and column fields in selection panels.
* Support for UTF-8 tree drawing
(thanks to Bin Guo)
diff --git a/ColumnsPanel.c b/ColumnsPanel.c
index 94a21232..5c630749 100644
--- a/ColumnsPanel.c
+++ b/ColumnsPanel.c
@@ -60,6 +60,13 @@ static HandlerResult ColumnsPanel_eventHandler(Panel* super, int ch) {
result = HANDLED;
break;
}
+ default:
+ {
+ result = Panel_selectByTyping(super, ch);
+ if (result == BREAK_LOOP)
+ result = IGNORED;
+ break;
+ }
}
if (result == HANDLED)
ColumnsPanel_update(super);
diff --git a/Header.c b/Header.c
index a30c834b..9a14b156 100644
--- a/Header.c
+++ b/Header.c
@@ -124,8 +124,16 @@ MeterModeId Header_readMeterMode(Header* this, int i, HeaderSide side) {
return meter->mode;
}
-void Header_defaultMeters(Header* this) {
- Vector_add(this->leftMeters, Meter_new(this->pl, 0, &AllCPUsMeter));
+void Header_defaultMeters(Header* this, int cpuCount) {
+ if (cpuCount > 8) {
+ Vector_add(this->leftMeters, Meter_new(this->pl, 0, &LeftCPUs2Meter));
+ Vector_add(this->rightMeters, Meter_new(this->pl, 0, &RightCPUs2Meter));
+ } else if (cpuCount > 4) {
+ Vector_add(this->leftMeters, Meter_new(this->pl, 0, &LeftCPUsMeter));
+ Vector_add(this->rightMeters, Meter_new(this->pl, 0, &RightCPUsMeter));
+ } else {
+ Vector_add(this->leftMeters, Meter_new(this->pl, 0, &AllCPUsMeter));
+ }
Vector_add(this->leftMeters, Meter_new(this->pl, 0, &MemoryMeter));
Vector_add(this->leftMeters, Meter_new(this->pl, 0, &SwapMeter));
Vector_add(this->rightMeters, Meter_new(this->pl, 0, &TasksMeter));
diff --git a/Header.h b/Header.h
index a74e8579..0fb5a735 100644
--- a/Header.h
+++ b/Header.h
@@ -51,7 +51,7 @@ char* Header_readMeterName(Header* this, int i, HeaderSide side);
MeterModeId Header_readMeterMode(Header* this, int i, HeaderSide side);
-void Header_defaultMeters(Header* this);
+void Header_defaultMeters(Header* this, int cpuCount);
void Header_reinit(Header* this);
diff --git a/Meter.c b/Meter.c
index 8c3cc50f..97b1dc4e 100644
--- a/Meter.c
+++ b/Meter.c
@@ -130,8 +130,13 @@ MeterType* Meter_types[] = {
&TasksMeter,
&UptimeMeter,
&BatteryMeter,
- &AllCPUsMeter,
&HostnameMeter,
+ &AllCPUsMeter,
+ &AllCPUs2Meter,
+ &LeftCPUsMeter,
+ &RightCPUsMeter,
+ &LeftCPUs2Meter,
+ &RightCPUs2Meter,
NULL
};
@@ -147,9 +152,9 @@ Meter* Meter_new(ProcessList* pl, int param, MeterType* type) {
this->values = calloc(sizeof(double), type->items);
this->total = type->total;
this->caption = strdup(type->caption);
- Meter_setMode(this, type->mode);
if (this->type->init)
this->type->init(this);
+ Meter_setMode(this, type->mode);
return this;
}
diff --git a/OpenFilesScreen.c b/OpenFilesScreen.c
index 46ecb6d9..b4ec11ae 100644
--- a/OpenFilesScreen.c
+++ b/OpenFilesScreen.c
@@ -151,7 +151,7 @@ static void OpenFilesScreen_scan(OpenFilesScreen* this) {
free(process->data[i]);
}
free(process);
- Vector_sort(panel->items);
+ Vector_insertionSort(panel->items);
Panel_setSelected(panel, idx);
}
diff --git a/Panel.c b/Panel.c
index 43432602..56e19488 100644
--- a/Panel.c
+++ b/Panel.c
@@ -93,6 +93,7 @@ void Panel_init(Panel* this, int x, int y, int w, int h, char* type, bool owner)
this->w = w;
this->h = h;
this->eventHandler = NULL;
+ this->eventHandlerBuffer = NULL;
this->items = Vector_new(type, owner, DEFAULT_SIZE, ListItem_compare);
this->scrollV = 0;
this->scrollH = 0;
@@ -108,6 +109,7 @@ void Panel_init(Panel* this, int x, int y, int w, int h, char* type, bool owner)
void Panel_done(Panel* this) {
assert (this != NULL);
+ free(this->eventHandlerBuffer);
Vector_delete(this->items);
RichString_end(this->header);
}
@@ -405,3 +407,38 @@ bool Panel_onKey(Panel* this, int key) {
}
return false;
}
+
+
+HandlerResult Panel_selectByTyping(Panel* this, int ch) {
+ int size = Panel_size(this);
+ if (!this->eventHandlerBuffer)
+ this->eventHandlerBuffer = calloc(100, 1);
+
+ if (isalnum(ch)) {
+ int len = strlen(this->eventHandlerBuffer);
+ if (len < 99) {
+ this->eventHandlerBuffer[len] = ch;
+ this->eventHandlerBuffer[len+1] = '\0';
+ }
+ for (int try = 0; try < 2; try++) {
+ len = strlen(this->eventHandlerBuffer);
+ for (int i = 0; i < size; i++) {
+ char* cur = ((ListItem*) Panel_get(this, i))->value;
+ while (*cur == ' ') cur++;
+ if (strncasecmp(cur, this->eventHandlerBuffer, len) == 0) {
+ Panel_setSelected(this, i);
+ return HANDLED;
+ }
+ }
+ this->eventHandlerBuffer[0] = ch;
+ this->eventHandlerBuffer[1] = '\0';
+ }
+ return HANDLED;
+ } else if (ch != ERR) {
+ this->eventHandlerBuffer[0] = '\0';
+ }
+ if (ch == 13) {
+ return BREAK_LOOP;
+ }
+ return IGNORED;
+}
diff --git a/Panel.h b/Panel.h
index fb588789..bc838105 100644
--- a/Panel.h
+++ b/Panel.h
@@ -117,4 +117,7 @@ void Panel_draw(Panel* this, bool focus);
bool Panel_onKey(Panel* this, int key);
+
+HandlerResult Panel_selectByTyping(Panel* this, int ch);
+
#endif
diff --git a/Process.c b/Process.c
index 31c87406..02d13966 100644
--- a/Process.c
+++ b/Process.c
@@ -567,6 +567,7 @@ bool Process_setPriority(Process* this, int priority) {
}
#ifdef HAVE_HWLOC
+
Affinity* Process_getAffinity(Process* this) {
hwloc_cpuset_t cpuset = hwloc_bitmap_alloc();
bool ok = (hwloc_linux_get_tid_cpubind(this->pl->topology, this->pid, cpuset) == 0);
@@ -597,6 +598,31 @@ bool Process_setAffinity(Process* this, Affinity* affinity) {
hwloc_bitmap_free(cpuset);
return ok;
}
+
+#elif HAVE_NATIVE_AFFINITY
+
+Affinity* Process_getAffinity(Process* this) {
+ cpu_set_t cpuset;
+ bool ok = (sched_getaffinity(this->pid, sizeof(cpu_set_t), &cpuset) == 0);
+ if (!ok) return NULL;
+ Affinity* affinity = Affinity_new();
+ for (int i = 0; i < this->pl->cpuCount; i++) {
+ if (CPU_ISSET(i, &cpuset))
+ Affinity_add(affinity, i);
+ }
+ return affinity;
+}
+
+bool Process_setAffinity(Process* this, Affinity* affinity) {
+ cpu_set_t cpuset;
+ CPU_ZERO(&cpuset);
+ for (int i = 0; i < affinity->used; i++) {
+ CPU_SET(affinity->cpus[i], &cpuset);
+ }
+ bool ok = (sched_setaffinity(this->pid, sizeof(unsigned long), &cpuset) == 0);
+ return ok;
+}
+
#endif
void Process_sendSignal(Process* this, int sgn) {
diff --git a/Process.h b/Process.h
index 403c2aff..c49e0b79 100644
--- a/Process.h
+++ b/Process.h
@@ -197,9 +197,17 @@ void Process_toggleTag(Process* this);
bool Process_setPriority(Process* this, int priority);
#ifdef HAVE_HWLOC
+
Affinity* Process_getAffinity(Process* this);
bool Process_setAffinity(Process* this, Affinity* affinity);
+
+#elif HAVE_NATIVE_AFFINITY
+
+Affinity* Process_getAffinity(Process* this);
+
+bool Process_setAffinity(Process* this, Affinity* affinity);
+
#endif
void Process_sendSignal(Process* this, int sgn);
diff --git a/ProcessList.c b/ProcessList.c
index b681fede..0ba17980 100644
--- a/ProcessList.c
+++ b/ProcessList.c
@@ -178,8 +178,7 @@ ProcessList* ProcessList_new(UsersTable* usersTable) {
ProcessList* this;
this = calloc(sizeof(ProcessList), 1);
this->processes = Vector_new(PROCESS_CLASS, true, DEFAULT_SIZE, Process_compare);
- this->processTable = Hashtable_new(70, false);
- assert(Hashtable_count(this->processTable) == Vector_count(this->processes));
+ this->processTable = Hashtable_new(140, false);
this->usersTable = usersTable;
/* tree-view auxiliary buffers */
@@ -329,7 +328,7 @@ static void ProcessList_buildTree(ProcessList* this, pid_t pid, int level, int i
void ProcessList_sort(ProcessList* this) {
if (!this->treeView) {
- Vector_sort(this->processes);
+ Vector_insertionSort(this->processes);
} else {
// Save settings
int direction = this->direction;
@@ -337,7 +336,7 @@ void ProcessList_sort(ProcessList* this) {
// Sort by PID
this->sortKey = PID;
this->direction = 1;
- Vector_sort(this->processes);
+ Vector_quickSort(this->processes);
// Restore settings
this->sortKey = sortKey;
this->direction = direction;
@@ -448,23 +447,34 @@ static void ProcessList_readIoFile(Process* process, const char* dirname, char*
unsigned long long last_read = process->io_read_bytes;
unsigned long long last_write = process->io_write_bytes;
while (fgets(buffer, 255, file)) {
- if (sscanf(buffer, "rchar: %llu", &process->io_rchar)) continue;
- if (sscanf(buffer, "wchar: %llu", &process->io_wchar)) continue;
- if (sscanf(buffer, "syscr: %llu", &process->io_syscr)) continue;
- if (sscanf(buffer, "syscw: %llu", &process->io_syscw)) continue;
- if (sscanf(buffer, "read_bytes: %llu", &process->io_read_bytes)) {
- process->io_rate_read_bps =
- ((double)(process->io_read_bytes - last_read))/(((double)(now - process->io_rate_read_time))/1000);
- process->io_rate_read_time = now;
- continue;
- }
- if (sscanf(buffer, "write_bytes: %llu", &process->io_write_bytes)) {
- process->io_rate_write_bps =
- ((double)(process->io_write_bytes - last_write))/(((double)(now - process->io_rate_write_time))/1000);
- process->io_rate_write_time = now;
- continue;
+ switch (buffer[0]) {
+ case 'r':
+ if (buffer[1] == 'c')
+ sscanf(buffer, "rchar: %llu", &process->io_rchar);
+ else if (sscanf(buffer, "read_bytes: %llu", &process->io_read_bytes)) {
+ process->io_rate_read_bps =
+ ((double)(process->io_read_bytes - last_read))/(((double)(now - process->io_rate_read_time))/1000);
+ process->io_rate_read_time = now;
+ }
+ break;
+ case 'w':
+ if (buffer[1] == 'c')
+ sscanf(buffer, "wchar: %llu", &process->io_wchar);
+ else if (sscanf(buffer, "write_bytes: %llu", &process->io_write_bytes)) {
+ process->io_rate_write_bps =
+ ((double)(process->io_write_bytes - last_write))/(((double)(now - process->io_rate_write_time))/1000);
+ process->io_rate_write_time = now;
+ }
+ break;
+ case 's':
+ if (buffer[5] == 'r')
+ sscanf(buffer, "syscr: %llu", &process->io_syscr);
+ else
+ sscanf(buffer, "syscw: %llu", &process->io_syscw);
+ break;
+ case 'c':
+ sscanf(buffer, "cancelled_write_bytes: %llu", &process->io_cancelled_write_bytes);
}
- sscanf(buffer, "cancelled_write_bytes: %llu", &process->io_cancelled_write_bytes);
}
fclose(file);
}
diff --git a/Settings.c b/Settings.c
index 3daf3c11..816a7ecb 100644
--- a/Settings.c
+++ b/Settings.c
@@ -55,7 +55,7 @@ static void Settings_readMeterModes(Settings* this, char* line, HeaderSide side)
String_freeArray(ids);
}
-static bool Settings_read(Settings* this, char* fileName) {
+static bool Settings_read(Settings* this, char* fileName, int cpuCount) {
// TODO: implement File object and make
// file I/O object-oriented.
FILE* fd;
@@ -144,7 +144,7 @@ static bool Settings_read(Settings* this, char* fileName) {
}
fclose(fd);
if (!readMeters) {
- Header_defaultMeters(this->header);
+ Header_defaultMeters(this->header, cpuCount);
}
return true;
}
@@ -208,7 +208,7 @@ bool Settings_write(Settings* this) {
return true;
}
-Settings* Settings_new(ProcessList* pl, Header* header) {
+Settings* Settings_new(ProcessList* pl, Header* header, int cpuCount) {
Settings* this = malloc(sizeof(Settings));
this->pl = pl;
this->header = header;
@@ -225,15 +225,15 @@ Settings* Settings_new(ProcessList* pl, Header* header) {
this->colorScheme = 0;
this->changed = false;
this->delay = DEFAULT_DELAY;
- bool ok = Settings_read(this, this->userSettings);
+ bool ok = Settings_read(this, this->userSettings, cpuCount);
if (!ok) {
this->changed = true;
// TODO: how to get SYSCONFDIR correctly through Autoconf?
char* systemSettings = String_cat(SYSCONFDIR, "/htoprc");
- ok = Settings_read(this, systemSettings);
+ ok = Settings_read(this, systemSettings, cpuCount);
free(systemSettings);
if (!ok) {
- Header_defaultMeters(this->header);
+ Header_defaultMeters(this->header, cpuCount);
pl->hideKernelThreads = true;
pl->highlightMegabytes = true;
pl->highlightThreads = false;
diff --git a/Settings.h b/Settings.h
index db3a6469..b75364e3 100644
--- a/Settings.h
+++ b/Settings.h
@@ -32,6 +32,6 @@ void Settings_delete(Settings* this);
bool Settings_write(Settings* this);
-Settings* Settings_new(ProcessList* pl, Header* header);
+Settings* Settings_new(ProcessList* pl, Header* header, int cpuCount);
#endif
diff --git a/Vector.c b/Vector.c
index e66e7232..e4d5d5c5 100644
--- a/Vector.c
+++ b/Vector.c
@@ -16,6 +16,8 @@ in the source distribution for its full text.
/*{
+#define swap(a_,x_,y_) do{ void* tmp_ = a_[x_]; a_[x_] = a_[y_]; a_[y_] = tmp_; }while(0)
+
#ifndef DEFAULT_SIZE
#define DEFAULT_SIZE -1
#endif
@@ -97,18 +99,83 @@ void Vector_prune(Vector* this) {
this->items = 0;
}
-void Vector_sort(Vector* this) {
+static int comparisons = 0;
+
+static int partition(Object** array, int left, int right, int pivotIndex, Object_Compare compare) {
+ void* pivotValue = array[pivotIndex];
+ swap(array, pivotIndex, right);
+ int storeIndex = left;
+ for (int i = left; i < right; i++) {
+ comparisons++;
+ if (compare(array[i], pivotValue) <= 0) {
+ swap(array, i, storeIndex);
+ storeIndex++;
+ }
+ }
+ swap(array, storeIndex, right);
+ return storeIndex;
+}
+
+static void quickSort(Object** array, int left, int right, Object_Compare compare) {
+ if (left >= right)
+ return;
+ int pivotIndex = (left+right) / 2;
+ int pivotNewIndex = partition(array, left, right, pivotIndex, compare);
+ quickSort(array, left, pivotNewIndex - 1, compare);
+ quickSort(array, pivotNewIndex + 1, right, compare);
+}
+
+// If I were to use only one sorting algorithm for both cases, it would probably be this one:
+/*
+
+static void combSort(Object** array, int left, int right, Object_Compare compare) {
+ int gap = right - left;
+ bool swapped = true;
+ while ((gap > 1) || swapped) {
+ if (gap > 1) {
+ gap = (int)((double)gap / 1.247330950103979);
+ }
+ swapped = false;
+ for (int i = left; gap + i <= right; i++) {
+ comparisons++;
+ if (compare(array[i], array[i+gap]) > 0) {
+ swap(array, i, i+gap);
+ swapped = true;
+ }
+ }
+ }
+}
+
+*/
+
+static void insertionSort(Object** array, int left, int right, Object_Compare compare) {
+ for (int i = left+1; i <= right; i++) {
+ void* t = array[i];
+ int j = i - 1;
+ while (j >= left) {
+ comparisons++;
+ if (compare(array[j], t) <= 0)
+ break;
+ array[j+1] = array[j];
+ j--;
+ }
+ array[j+1] = t;
+ }
+}
+
+void Vector_quickSort(Vector* this) {
assert(this->compare);
assert(Vector_isConsistent(this));
Object_Compare compare = this->compare;
- /* Insertion sort works best on mostly-sorted arrays. */
- for (int i = 1; i < this->items; i++) {
- int j;
- void* t = this->array[i];
- for (j = i-1; j >= 0 && compare(this->array[j], t) > 0; j--)
- this->array[j+1] = this->array[j];
- this->array[j+1] = t;
- }
+ quickSort(this->array, 0, this->items - 1, compare);
+ assert(Vector_isConsistent(this));
+}
+
+void Vector_insertionSort(Vector* this) {
+ assert(this->compare);
+ assert(Vector_isConsistent(this));
+ Object_Compare compare = this->compare;
+ insertionSort(this->array, 0, this->items - 1, compare);
assert(Vector_isConsistent(this));
}
@@ -205,12 +272,20 @@ void Vector_set(Vector* this, int idx, void* data_) {
assert(Vector_isConsistent(this));
}
+#ifdef DEBUG
+
inline Object* Vector_get(Vector* this, int idx) {
assert(idx < this->items);
assert(Vector_isConsistent(this));
return this->array[idx];
}
+#else
+
+#define Vector_get(v_, idx_) ((v_)->array[idx_])
+
+#endif
+
inline int Vector_size(Vector* this) {
assert(Vector_isConsistent(this));
return this->items;
diff --git a/Vector.h b/Vector.h
index fc189bfa..20c0036c 100644
--- a/Vector.h
+++ b/Vector.h
@@ -18,6 +18,8 @@ in the source distribution for its full text.
#include <assert.h>
+#define swap(a_,x_,y_) do{ void* tmp_ = a_[x_]; a_[x_] = a_[y_]; a_[y_] = tmp_; }while(0)
+
#ifndef DEFAULT_SIZE
#define DEFAULT_SIZE -1
#endif
@@ -45,7 +47,14 @@ int Vector_count(Vector* this);
void Vector_prune(Vector* this);
-void Vector_sort(Vector* this);
+// If I were to use only one sorting algorithm for both cases, it would probably be this one:
+/*
+
+*/
+
+void Vector_quickSort(Vector* this);
+
+void Vector_insertionSort(Vector* this);
void Vector_insert(Vector* this, int idx, void* data_);
@@ -59,8 +68,16 @@ void Vector_moveDown(Vector* this, int idx);
void Vector_set(Vector* this, int idx, void* data_);
+#ifdef DEBUG
+
extern Object* Vector_get(Vector* this, int idx);
+#else
+
+#define Vector_get(v_, idx_) ((v_)->array[idx_])
+
+#endif
+
extern int Vector_size(Vector* this);
/*
diff --git a/configure.ac b/configure.ac
index b049215b..514c458d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2,7 +2,7 @@
# Process this file with autoconf to produce a configure script.
AC_PREREQ(2.65)
-AC_INIT([htop],[0.9.1],[loderunner@users.sourceforge.net])
+AC_INIT([htop],[1.0],[loderunner@users.sourceforge.net])
# The following two lines are required by hwloc scripts
AC_USE_SYSTEM_EXTENSIONS
@@ -87,9 +87,12 @@ if test "x$enable_taskstats" = xyes; then
AC_DEFINE(HAVE_TASKSTATS, 1, [Define if taskstats support enabled.])
fi
-AC_ARG_ENABLE(unicode, [AC_HELP_STRING([--enable-unicode], [enable Unicode support])], ,enable_unicode="no")
+AC_ARG_ENABLE(unicode, [AC_HELP_STRING([--enable-unicode], [enable Unicode support])], ,enable_unicode="yes")
if test "x$enable_unicode" = xyes; then
- AC_CHECK_LIB([ncursesw], [refresh], [], [missing_libraries="$missing_libraries libncursesw"])
+ AC_CHECK_LIB([ncursesw], [refresh], [], [
+ missing_libraries="$missing_libraries libncursesw"
+ AC_MSG_ERROR([You may want to use --disable-unicode or install libncursesw.])
+ ])
AC_CHECK_HEADERS([ncursesw/curses.h],[:],
[AC_CHECK_HEADERS([ncurses/ncurses.h],[:],
[AC_CHECK_HEADERS([ncurses.h],[:],[missing_headers="$missing_headers $ac_header"])])])
@@ -110,10 +113,28 @@ AC_CHECK_FILE($PROCDIR/stat,,AC_MSG_ERROR(Cannot find /proc/stat. Make sure you
AC_CHECK_FILE($PROCDIR/meminfo,,AC_MSG_ERROR(Cannot find /proc/meminfo. Make sure you have a Linux-compatible /proc filesystem mounted. See the file README for help.))
fi
+AC_ARG_ENABLE(native_affinity, [AC_HELP_STRING([--enable-native-affinity], [enable native sched_setaffinity and sched_getaffinity for affinity support, disables hwloc])], ,enable_native_affinity="yes")
+if test "x$enable_native_affinity" = xyes; then
+ 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;
+ ]])],
+ [AC_DEFINE(HAVE_NATIVE_AFFINITY, 1, [Define if native sched_setaffinity and sched_getaffinity are to be used.])
+ AC_MSG_RESULT([yes])],
+ [AC_MSG_RESULT([no])])
+fi
+
##### hwloc
AC_ARG_ENABLE(system-hwloc, [AC_HELP_STRING([--enable-system-hwloc], [use the copy of hwloc from your system and not the one bundled with the htop sources. (hwloc required)])], ,enable_system_hwloc="no")
enable_xml=no
-AC_ARG_ENABLE(hwloc, [AC_HELP_STRING([--enable-hwloc], [enable hwloc support for CPU affinity])],, enable_hwloc="yes")
+AC_ARG_ENABLE(hwloc, [AC_HELP_STRING([--enable-hwloc], [enable hwloc support for CPU affinity])],, test "x$enable_native_affinity" = xno && enable_hwloc="yes")
if test "x$enable_hwloc" = xyes
then
if test "x$enable_system_hwloc" = xyes
diff --git a/debug.h b/debug.h
index 1dedb708..ec2f883e 100644
--- a/debug.h
+++ b/debug.h
@@ -8,7 +8,7 @@
#define realloc(x,s) DebugMemory_realloc(x, s, __FILE__, __LINE__, #x)
#define strdup(x) DebugMemory_strdup(x, __FILE__, __LINE__)
#define free(x) DebugMemory_free(x, __FILE__, __LINE__)
- #define debug_done() DebugMemory_report(); _nc_free_and_exit()
+ #define debug_done() DebugMemory_report(); _nc_freeall()
#elif defined(DEBUGLITE)
diff --git a/htop.c b/htop.c
index 6ceabb25..3fedd126 100644
--- a/htop.c
+++ b/htop.c
@@ -193,44 +193,11 @@ static bool changePriority(Panel* panel, int delta) {
return anyTagged;
}
-static HandlerResult pickWithEnter(Panel* panel, int ch) {
- int size = Panel_size(panel);
-
- if (isalnum(ch)) {
- int len = strlen(panel->eventHandlerBuffer);
- if (len < 99) {
- panel->eventHandlerBuffer[len] = ch;
- panel->eventHandlerBuffer[len+1] = '\0';
- }
- for (int try = 0; try < 2; try++) {
- len = strlen(panel->eventHandlerBuffer);
- for (int i = 0; i < size; i++) {
- char* cur = ((ListItem*) Panel_get(panel, i))->value;
- while (*cur == ' ') cur++;
- if (strncasecmp(cur, panel->eventHandlerBuffer, len) == 0) {
- Panel_setSelected(panel, i);
- return HANDLED;
- }
- }
- panel->eventHandlerBuffer[0] = ch;
- panel->eventHandlerBuffer[1] = '\0';
- }
- return HANDLED;
- } else if (ch != ERR) {
- panel->eventHandlerBuffer[0] = '\0';
- }
- if (ch == 13) {
- return BREAK_LOOP;
- }
- return IGNORED;
-}
-
static Object* pickFromVector(Panel* panel, Panel* list, int x, int y, const char** keyLabels, FunctionBar* prevBar, Header* header) {
const char* fuKeys[] = {"Enter", "Esc", NULL};
int fuEvents[] = {13, 27};
- list->eventHandlerBuffer = calloc(100, 1);
if (!list->eventHandler)
- Panel_setEventHandler(list, pickWithEnter);
+ Panel_setEventHandler(list, Panel_selectByTyping);
ScreenManager* scr = ScreenManager_new(0, y, 0, -1, HORIZONTAL, header, false);
ScreenManager_add(scr, list, FunctionBar_new(keyLabels, fuKeys, fuEvents), x - 1);
ScreenManager_add(scr, panel, NULL, -1);
@@ -238,8 +205,6 @@ static Object* pickFromVector(Panel* panel, Panel* list, int x, int y, const cha
int ch;
ScreenManager_run(scr, &panelFocus, &ch);
ScreenManager_delete(scr);
- free(list->eventHandlerBuffer);
- list->eventHandlerBuffer = NULL;
Panel_move(panel, 0, y);
Panel_resize(panel, COLS, LINES-y-1);
FunctionBar_draw(prevBar, NULL);
@@ -383,7 +348,7 @@ int main(int argc, char** argv) {
Process_getMaxPid();
Header* header = Header_new(pl);
- settings = Settings_new(pl, header);
+ settings = Settings_new(pl, header, pl->cpuCount);
int headerHeight = Header_calculateHeight(header);
// FIXME: move delay code to settings
@@ -750,7 +715,7 @@ int main(int argc, char** argv) {
Panel* usersPanel = Panel_new(0, 0, 0, 0, LISTITEM_CLASS, true, ListItem_compare);
Panel_setHeader(usersPanel, "Show processes of:");
UsersTable_foreach(ut, addUserToVector, usersPanel);
- Vector_sort(usersPanel->items);
+ Vector_insertionSort(usersPanel->items);
ListItem* allUsers = ListItem_new("All users", -1);
Panel_insert(usersPanel, 0, (Object*) allUsers);
const char* fuFunctions[] = {"Show ", "Cancel ", NULL};
@@ -808,7 +773,7 @@ int main(int argc, char** argv) {
refreshTimeout = 0;
break;
}
-#ifdef HAVE_HWLOC
+#if (HAVE_HWLOC || HAVE_NATIVE_AFFINITY)
case 'a':
{
if (pl->cpuCount == 1)

© 2014-2024 Faster IT GmbH | imprint | privacy policy