Commit ec17b702 authored by Hisham Muhammad's avatar Hisham Muhammad
Browse files

Convert affinity control from the deprecated PLPA to HWLOC

parent d07b043e
Showing with 215 additions and 64 deletions
+215 -64
#include "config.h"
#include "Affinity.h"
#include <stdlib.h>
/*{
typedef struct Affinity_ {
int size;
int used;
int* cpus;
} Affinity;
}*/
Affinity* Affinity_new() {
Affinity* this = calloc(sizeof(Affinity), 1);
this->size = 8;
this->cpus = calloc(sizeof(int), this->size);
return this;
}
void Affinity_delete(Affinity* this) {
free(this->cpus);
free(this);
}
void Affinity_add(Affinity* this, int id) {
if (this->used == this->size) {
this->size *= 2;
this->cpus = realloc(this->cpus, sizeof(int) * this->size);
}
this->cpus[this->used] = id;
this->used++;
}
#include "ProcessList.h"
#include "AffinityPanel.h"
#include "Panel.h"
#include "CheckItem.h"
#include "ProcessList.h"
#include "debug.h"
#include <assert.h>
......@@ -26,25 +25,33 @@ static HandlerResult AffinityPanel_eventHandler(Panel* this, int ch) {
return result;
}
Panel* AffinityPanel_new(ProcessList* pl, unsigned long mask) {
Panel* AffinityPanel_new(ProcessList* pl, Affinity* affinity) {
Panel* this = Panel_new(1, 1, 1, 1, CHECKITEM_CLASS, true, ListItem_compare);
this->eventHandler = AffinityPanel_eventHandler;
Panel_setHeader(this, "Use CPUs:");
int curCpu = 0;
for (int i = 0; i < pl->cpuCount; i++) {
char number[10];
snprintf(number, 9, "%d", ProcessList_cpuId(pl, i));
Panel_add(this, (Object*) CheckItem_new(String_copy(number), NULL, mask & (1 << i)));
bool mode;
if (curCpu < affinity->used && affinity->cpus[curCpu] == i) {
mode = true;
curCpu++;
} else {
mode = false;
}
Panel_add(this, (Object*) CheckItem_new(String_copy(number), NULL, mode));
}
return this;
}
unsigned long AffinityPanel_getAffinity(Panel* this) {
Affinity* AffinityPanel_getAffinity(Panel* this) {
Affinity* affinity = Affinity_new();
int size = Panel_size(this);
unsigned long mask = 0;
for (int i = 0; i < size; i++) {
if (CheckItem_get((CheckItem*)Panel_get(this, i)))
mask = mask | (1 << i);
Affinity_add(affinity, i);
}
return mask;
return affinity;
}
......@@ -3,16 +3,15 @@
#ifndef HEADER_AffinityPanel
#define HEADER_AffinityPanel
#include "ProcessList.h"
#include "Panel.h"
#include "CheckItem.h"
#include "ProcessList.h"
#include "debug.h"
#include <assert.h>
Panel* AffinityPanel_new(ProcessList* pl, unsigned long mask);
Panel* AffinityPanel_new(ProcessList* pl, Affinity* affinity);
unsigned long AffinityPanel_getAffinity(Panel* this);
Affinity* AffinityPanel_getAffinity(Panel* this);
#endif
#define _GNU_SOURCE
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
......
......@@ -3,7 +3,6 @@
#ifndef HEADER_DebugMemory
#define HEADER_DebugMemory
#define _GNU_SOURCE
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
......
if HAVE_PLPA
SUBDIRS = plpa-1.3.2
if HAVE_HWLOC
SUBDIRS = hwloc-1.2.1
endif
ACLOCAL_AMFLAGS=-I m4
ACLOCAL_AMFLAGS = -I m4 -I hwloc-1.2.1/config
bin_PROGRAMS = htop
dist_man_MANS = htop.1
......@@ -15,6 +15,7 @@ pixmapdir = $(datadir)/pixmaps
pixmap_DATA = htop.png
htop_CFLAGS = -pedantic -Wall -std=c99 -rdynamic -D_XOPEN_SOURCE_EXTENDED
AM_CFLAGS =
AM_CPPFLAGS = -DSYSCONFDIR=\"$(sysconfdir)\"
myhtopsources = AvailableMetersPanel.c CategoriesPanel.c CheckItem.c \
......@@ -24,7 +25,7 @@ LoadAverageMeter.c MemoryMeter.c Meter.c MetersPanel.c Object.c Panel.c \
BatteryMeter.c Process.c ProcessList.c RichString.c ScreenManager.c Settings.c \
SignalItem.c SignalsPanel.c String.c SwapMeter.c TasksMeter.c TraceScreen.c \
UptimeMeter.c UsersTable.c Vector.c AvailableColumnsPanel.c AffinityPanel.c \
HostnameMeter.c OpenFilesScreen.c
HostnameMeter.c OpenFilesScreen.c Affinity.c
myhtopheaders = AvailableColumnsPanel.h AvailableMetersPanel.h \
CategoriesPanel.h CheckItem.h ClockMeter.h ColorsPanel.h ColumnsPanel.h \
......@@ -33,14 +34,17 @@ Hashtable.h Header.h htop.h ListItem.h LoadAverageMeter.h MemoryMeter.h \
BatteryMeter.h Meter.h MetersPanel.h Object.h Panel.h ProcessList.h RichString.h \
ScreenManager.h Settings.h SignalItem.h SignalsPanel.h String.h \
SwapMeter.h TasksMeter.h TraceScreen.h UptimeMeter.h UsersTable.h Vector.h \
Process.h AffinityPanel.h HostnameMeter.h OpenFilesScreen.h
Process.h AffinityPanel.h HostnameMeter.h OpenFilesScreen.h Affinity.h
SUFFIXES = .h
BUILT_SOURCES = $(myhtopheaders)
htop_SOURCES = $(myhtopheaders) $(myhtopsources) config.h debug.h
if HAVE_PLPA
htop_LDADD = $(top_builddir)/plpa-1.3.2/src/libplpa/libplpa_included.la
if HAVE_HWLOC
htop_LDADD = $(HWLOC_EMBEDDED_LDADD) $(HWLOC_EMBEDDED_LIBS)
AM_CFLAGS += $(HWLOC_EMBEDDED_CFLAGS)
AM_CPPFLAGS += $(HWLOC_EMBEDDED_CPPFLAGS)
endif
profile:
......
......@@ -9,7 +9,6 @@ Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
#define _GNU_SOURCE
#include "RichString.h"
#include "Object.h"
#include "CRT.h"
......
......@@ -5,13 +5,13 @@ Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
#define _GNU_SOURCE
#include "ProcessList.h"
#include "Object.h"
#include "CRT.h"
#include "String.h"
#include "Process.h"
#include "RichString.h"
#include "Affinity.h"
#include "debug.h"
......@@ -29,8 +29,8 @@ in the source distribution for its full text.
#include <sched.h>
#include <time.h>
#ifdef HAVE_PLPA
#include <plpa.h>
#ifdef HAVE_HWLOC
#include <hwloc/linux.h>
#endif
// This works only with glibc 2.1+. On earlier versions
......@@ -535,15 +535,36 @@ bool Process_setPriority(Process* this, int priority) {
return (err == 0);
}
#ifdef HAVE_PLPA
unsigned long Process_getAffinity(Process* this) {
unsigned long mask = 0;
plpa_sched_getaffinity(this->pid, sizeof(unsigned long), (plpa_cpu_set_t*) &mask);
return mask;
#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);
Affinity* affinity = NULL;
if (ok) {
affinity = Affinity_new();
if (hwloc_bitmap_last(cpuset) == -1) {
for (int i = 0; i < this->pl->cpuCount; i++) {
Affinity_add(affinity, i);
}
} else {
unsigned int id;
hwloc_bitmap_foreach_begin(id, cpuset);
Affinity_add(affinity, id);
hwloc_bitmap_foreach_end();
}
}
hwloc_bitmap_free(cpuset);
return affinity;
}
bool Process_setAffinity(Process* this, unsigned long mask) {
return (plpa_sched_setaffinity(this->pid, sizeof(unsigned long), (plpa_cpu_set_t*) &mask) == 0);
bool Process_setAffinity(Process* this, Affinity* affinity) {
hwloc_cpuset_t cpuset = hwloc_bitmap_alloc();
for (int i = 0; i < affinity->used; i++) {
hwloc_bitmap_set(cpuset, affinity->cpus[i]);
}
bool ok = (hwloc_linux_set_tid_cpubind(this->pl->topology, this->pid, cpuset) == 0);
hwloc_bitmap_free(cpuset);
return ok;
}
#endif
......
......@@ -9,12 +9,12 @@ Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
#define _GNU_SOURCE
#include "ProcessList.h"
#include "Object.h"
#include "CRT.h"
#include "String.h"
#include "RichString.h"
#include "Affinity.h"
#include "debug.h"
......@@ -32,8 +32,8 @@ in the source distribution for its full text.
#include <sched.h>
#include <time.h>
#ifdef HAVE_PLPA
#include <plpa.h>
#ifdef HAVE_HWLOC
#include <hwloc/linux.h>
#endif
// This works only with glibc 2.1+. On earlier versions
......@@ -193,10 +193,10 @@ void Process_toggleTag(Process* this);
bool Process_setPriority(Process* this, int priority);
#ifdef HAVE_PLPA
unsigned long Process_getAffinity(Process* this);
#ifdef HAVE_HWLOC
Affinity* Process_getAffinity(Process* this);
bool Process_setAffinity(Process* this, unsigned long mask);
bool Process_setAffinity(Process* this, Affinity* affinity);
#endif
void Process_sendSignal(Process* this, int sgn);
......
......@@ -101,6 +101,10 @@ typedef struct ProcessList_ {
int kernelThreads;
int runningTasks;
#ifdef HAVE_HWLOC
hwloc_topology_t topology;
bool topologyOk;
#endif
CPUData* cpus;
unsigned long long int totalMem;
......@@ -155,7 +159,15 @@ ProcessList* ProcessList_new(UsersTable* usersTable) {
} while (String_startsWith(buffer, "cpu"));
fclose(file);
this->cpuCount = cpus - 1;
#ifdef HAVE_HWLOC
this->topologyOk = false;
int topoErr = hwloc_topology_init(&this->topology);
if (topoErr == 0) {
topoErr = hwloc_topology_load(this->topology);
this->topologyOk = true;
}
#endif
this->cpus = calloc(sizeof(CPUData), cpus);
for (int i = 0; i < cpus; i++) {
......
......@@ -101,6 +101,10 @@ typedef struct ProcessList_ {
int kernelThreads;
int runningTasks;
#ifdef HAVE_HWLOC
hwloc_topology_t topology;
bool topologyOk;
#endif
CPUData* cpus;
unsigned long long int totalMem;
......
......@@ -9,7 +9,6 @@ Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
#define _GNU_SOURCE
#include <string.h>
#include <strings.h>
#include <stdlib.h>
......
......@@ -5,7 +5,7 @@ Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
#define _GNU_SOURCE
#include "config.h"
#include <stdio.h>
#include <unistd.h>
#include <stdbool.h>
......
......@@ -9,7 +9,7 @@ Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
#define _GNU_SOURCE
#include "config.h"
#include <stdio.h>
#include <unistd.h>
#include <stdbool.h>
......
m4_include(plpa-1.3.2/plpa.m4)
m4_include(hwloc-1.2.1/config/hwloc.m4)
m4_include(hwloc-1.2.1/config/hwloc_pkg.m4)
# -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.
AC_PREREQ(2.57)
AC_PREREQ(2.65)
AC_INIT([htop],[0.9.1],[loderunner@users.sourceforge.net])
AM_INIT_AUTOMAKE
# The following two lines are required by hwloc scripts
AC_USE_SYSTEM_EXTENSIONS
AC_CANONICAL_TARGET
AM_INIT_AUTOMAKE([1.11])
AC_CONFIG_SRCDIR([htop.c])
AC_CONFIG_HEADER([config.h])
AC_CONFIG_MACRO_DIR([m4])
......@@ -105,14 +110,19 @@ 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(plpa, [AC_HELP_STRING([--enable-plpa], [enable PLPA support for CPU affinity])], ,enable_plpa="yes")
PLPA_INCLUDED
PLPA_INIT([plpa-1.3.2], [plpa_happy=yes], [plpa_happy=no])
AM_CONDITIONAL([HAVE_PLPA], [test "$plpa_happy" = "yes" && test "$enable_plpa" = "yes"])
if test "$plpa_happy" = "yes" && test "$enable_plpa" = "yes"
##### hwloc
enable_xml=no
AC_ARG_ENABLE(hwloc, [AC_HELP_STRING([--enable-hwloc], [enable hwloc support for CPU affinity])],, enable_hwloc="yes")
if test "x$enable_hwloc" = xyes
then
AC_DEFINE([HAVE_PLPA], [1], [Have plpa])
HWLOC_SETUP_CORE([hwloc-1.2.1], [hwloc_happy=yes], [hwloc_happy=no])
fi
HWLOC_DO_AM_CONDITIONALS
AM_CONDITIONAL([HAVE_HWLOC], [test "x$hwloc_happy" = "xyes"])
if test "x$hwloc_happy" = "xyes"; then
AC_DEFINE([HAVE_HWLOC], 1, [Have hwloc])
fi
#####
AC_CONFIG_FILES([Makefile htop.1])
AC_OUTPUT
......@@ -124,7 +124,7 @@ static void showHelp(ProcessList* pl) {
mvaddstr(15, 0, " F9 k: kill process/tagged processes P: sort by CPU%");
mvaddstr(16, 0, " ] F7: higher priority (root only) M: sort by MEM%");
mvaddstr(17, 0, " [ F8: lower priority (+ nice) T: sort by TIME");
#ifdef HAVE_PLPA
#ifdef HAVE_HWLOC
if (pl->cpuCount > 1)
mvaddstr(18, 0, " a: set CPU affinity I: invert sort order");
else
......@@ -145,7 +145,7 @@ static void showHelp(ProcessList* pl) {
mvaddstr(16, 0, " ] F7"); mvaddstr(16,40, " M");
mvaddstr(17, 0, " [ F8"); mvaddstr(17,40, " T");
mvaddstr(18,40, " F4 I");
#if HAVE_PLPA
#if HAVE_HWLOC
if (pl->cpuCount > 1)
mvaddstr(18, 0, " a:");
#endif
......@@ -457,7 +457,8 @@ int main(int argc, char** argv) {
Panel_draw(panel, true);
int prev = ch;
move(LINES-1, CRT_cursorX);
if (incMode)
move(LINES-1, CRT_cursorX);
ch = getch();
if (ch == ERR) {
......@@ -748,35 +749,36 @@ int main(int argc, char** argv) {
refreshTimeout = 0;
break;
}
#ifdef HAVE_PLPA
#ifdef HAVE_HWLOC
case 'a':
{
if (pl->cpuCount == 1)
break;
unsigned long curr = Process_getAffinity((Process*) Panel_getSelected(panel));
Panel* affinityPanel = AffinityPanel_new(pl, curr);
Affinity* affinity = Process_getAffinity((Process*) Panel_getSelected(panel));
Panel* affinityPanel = AffinityPanel_new(pl, affinity);
Affinity_delete(affinity);
const char* fuFunctions[] = {"Set ", "Cancel ", NULL};
void* set = pickFromVector(panel, affinityPanel, 15, headerHeight, fuFunctions, defaultBar, header);
if (set) {
unsigned long new = AffinityPanel_getAffinity(affinityPanel);
Affinity* affinity = AffinityPanel_getAffinity(affinityPanel);
bool anyTagged = false;
bool ok = true;
for (int i = 0; i < Panel_size(panel); i++) {
Process* p = (Process*) Panel_get(panel, i);
if (p->tag) {
ok = Process_setAffinity(p, new) && ok;
ok = Process_setAffinity(p, affinity) && ok;
anyTagged = true;
}
}
if (!anyTagged) {
Process* p = (Process*) Panel_getSelected(panel);
ok = Process_setAffinity(p, new) && ok;
ok = Process_setAffinity(p, affinity) && ok;
}
if (!ok)
beep();
Affinity_delete(affinity);
}
Panel_delete((Object*)affinityPanel);
ProcessList_printHeader(pl, Panel_getHeader(panel));
......@@ -895,9 +897,6 @@ int main(int argc, char** argv) {
((Object*)killPanel)->delete((Object*)killPanel);
UsersTable_delete(ut);
Settings_delete(settings);
#ifdef HAVE_PLPA
plpa_finalize();
#endif
debug_done();
return 0;
}
Cédric Augonnet <Cedric.Augonnet@labri.fr>
Jérôme Clet-Ortega <Jerome.Clet-Ortega@labri.fr>
Ludovic Courtès <Ludovic.Courtes@inria.fr>
Brice Goglin <Brice.Goglin@inria.fr>
Nathalie Furmento <Nathalie.Furmento@labri.fr>
Samuel Thibault <Samuel.Thibault@labri.fr>
Jeff Squyres <jsquyres@cisco.com>
Alexey Kardashevskiy <aik@au1.ibm.com>
Copyright © 2009 CNRS
Copyright © 2009 INRIA. All rights reserved.
Copyright © 2009 Université Bordeaux 1
Copyright © 2009 Cisco Systems, Inc. All rights reserved.
See COPYING in top-level directory.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# Copyright © 2009 INRIA. All rights reserved.
# Copyright © 2009 Université Bordeaux 1
# Copyright © 2009-2010 Cisco Systems, Inc. All rights reserved.
# See COPYING in top-level directory.
# Note that the -I directory must *exactly* match what was specified
# via AC_CONFIG_MACRO_DIR in configure.ac.
ACLOCAL_AMFLAGS = -I ./config
SUBDIRS = src include
# Do not let automake automatically add the non-standalone dirs to the
# distribution tarball if we're building in embedded mode.
DIST_SUBDIRS = $(SUBDIRS)
#
# "make distcheck" requires that tarballs are able to be able to "make
# dist", so we have to include config/distscript.csh.
#
EXTRA_DIST = \
README VERSION COPYING AUTHORS \
config/hwloc_get_version.sh \
config/distscript.csh
#
# Build the top-level README file
#
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment