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; - for (int i = 0; i < cpus; i++) { - Meter_setMode(meters[i], this->mode); + 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; + 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; + 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); } - 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; - } - 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 +#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 + #include + 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)