diff --git a/processcore/process.h b/processcore/process.h --- a/processcore/process.h +++ b/processcore/process.h @@ -212,6 +212,9 @@ QString schedulerAsString() const; ///< Returns a translated string of the scheduler class. e.g. "FIFO", "Round Robin", "Batch" + QString cGroup() const; + void setCGroup(const QString &cGroup); ///< Linux Control Group (cgroup) + /** This is the number of 1/1000ths of a second since this * particular process was last updated compared to when all the processes * were updated. The purpose is to allow a more fine tracking of the time diff --git a/processcore/process.cpp b/processcore/process.cpp --- a/processcore/process.cpp +++ b/processcore/process.cpp @@ -83,6 +83,7 @@ Process::Changes changes; int elapsedTimeMilliSeconds; int noNewPrivileges; + QString cGroup; }; Process::Process() @@ -487,6 +488,11 @@ return d->elapsedTimeMilliSeconds; } +QString Process::cGroup() const +{ + return d->cGroup; +} + void Process::setParentPid(long int parent_pid) { d->parent_pid = parent_pid; @@ -777,4 +783,10 @@ d->changes = changes; } +void Process::setCGroup(const QString &_cGroup) { + if(d->cGroup == _cGroup) return; + d->cGroup = _cGroup; + d->changes |= Process::Status; +} + } diff --git a/processcore/processes_linux_p.cpp b/processcore/processes_linux_p.cpp --- a/processcore/processes_linux_p.cpp +++ b/processcore/processes_linux_p.cpp @@ -112,6 +112,7 @@ inline bool readProcStat(const QString &dir, Process *process); inline bool readProcStatm(const QString &dir, Process *process); inline bool readProcCmdline(const QString &dir, Process *process); + inline bool readProcCGroup(const QString &dir, Process *process); inline bool getNiceness(long pid, Process *process); inline bool getIOStatistics(const QString &dir, Process *process); QFile mFile; @@ -200,6 +201,22 @@ return true; } +bool ProcessesLocal::Private::readProcCGroup(const QString &dir, Process *process) +{ + mFile.setFileName(dir + QStringLiteral("cgroup")); + if(!mFile.open(QIODevice::ReadOnly)) + return false; /* process has terminated in the meantime */ + + while( mFile.readLine( mBuffer, sizeof(mBuffer)) > 0) { //-1 indicates an error + if ( mBuffer[0] == '0' && mBuffer[1] == ':' && mBuffer[2] == ':' ) { + process->setCGroup(QString::fromLocal8Bit(&mBuffer[3]).trimmed()); + break; + } + } + mFile.close(); + return true; +} + long ProcessesLocal::getParentPid(long pid) { if (pid <= 0) return -1; @@ -524,6 +541,7 @@ if(!d->readProcStatus(dir, process)) success = false; if(!d->readProcStatm(dir, process)) success = false; if(!d->readProcCmdline(dir, process)) success = false; + if(!d->readProcCGroup(dir, process)) success = false; if(!d->getNiceness(pid, process)) success = false; if(mUpdateFlags.testFlag(Processes::IOStatistics) && !d->getIOStatistics(dir, process)) success = false; diff --git a/processcore/processes_remote_p.cpp b/processcore/processes_remote_p.cpp --- a/processcore/processes_remote_p.cpp +++ b/processcore/processes_remote_p.cpp @@ -42,7 +42,7 @@ statusColumn = userColumn = systemColumn = niceColumn = vmSizeColumn = vmRSSColumn = loginColumn = commandColumn = tracerPidColumn = ttyColumn = ioprioClassColumn = ioprioColumn = - vmURSSColumn = noNewPrivilegesColumn = -1; + vmURSSColumn = noNewPrivilegesColumn = cGroupColumn = -1; usedMemory = freeMemory;} ~Private() {} QString host; @@ -70,6 +70,7 @@ int ioprioColumn; int ttyColumn; int noNewPrivilegesColumn; + int cGroupColumn; int numColumns; @@ -139,6 +140,7 @@ if(d->ioprioColumn!= -1) process->setIoniceLevel(p.at(d->ioprioColumn).toInt()); if(d->ioprioClassColumn!= -1) process->setIoPriorityClass((KSysGuard::Process::IoPriorityClass)(p.at(d->ioprioClassColumn).toInt())); if(d->noNewPrivilegesColumn!= -1) process->setNoNewPrivileges(p.at(d->noNewPrivilegesColumn).toLong()); + if(d->cGroupColumn!= -1) process->setCGroup(QString::fromUtf8(p.at(d->cGroupColumn))); return true; } @@ -246,6 +248,8 @@ d->ioprioColumn = i; else if(info[i] == "NNP") d->noNewPrivilegesColumn = i; + else if(info[i] == "CGroup") + d->cGroupColumn = i; } d->havePsInfo = true; break; diff --git a/processui/ProcessModel.h b/processui/ProcessModel.h --- a/processui/ProcessModel.h +++ b/processui/ProcessModel.h @@ -138,7 +138,7 @@ * setup header function, and make sure you increase PROCESSHEADERVERSION. This will ensure * that old saved settings won't be used */ -#define PROCESSHEADERVERSION 7 +#define PROCESSHEADERVERSION 8 enum { HeadingName=0, HeadingUser, HeadingPid, @@ -155,7 +155,8 @@ HeadingNoNewPrivileges, HeadingCommand, HeadingXMemory, - HeadingXTitle + HeadingXTitle, + HeadingCGroup }; enum { UidRole = Qt::UserRole, SortingValueRole, WindowIdRole, PlainValueRole, PercentageRole, PercentageHistoryRole }; diff --git a/processui/ProcessModel.cpp b/processui/ProcessModel.cpp --- a/processui/ProcessModel.cpp +++ b/processui/ProcessModel.cpp @@ -759,9 +759,11 @@ emit q->dataChanged(index, index); } if(process->changes() & KSysGuard::Process::Status) { - totalUpdated++; + totalUpdated+=2; QModelIndex index = q->createIndex(row, ProcessModel::HeadingNoNewPrivileges, process); emit q->dataChanged(index, index); + index = q->createIndex(row, ProcessModel::HeadingCGroup, process); + emit q->dataChanged(index, index); } if(process->changes() & KSysGuard::Process::NiceLevels) { totalUpdated++; @@ -1029,6 +1031,8 @@ return i18n("The number of bytes read. See What's This for more information."); case HeadingIoWrite: return i18n("The number of bytes written. See What's This for more information."); + case HeadingCGroup: + return i18n("The control group (cgroup) where this process belongs."); default: return QVariant(); } @@ -1083,6 +1087,8 @@ "

" "The number in brackets shows the rate at which each value is changing, determined from taking the difference between the previous value and the new value, and dividing by the update interval.

" "Technical information: This data is collected from /proc/*/io and is documented further in Documentation/accounting and Documentation/filesystems/proc.txt in the kernel source."); + case HeadingCGroup: + return i18n("Technical information: This shows Linux Control Group (cgroup) membership, retrieved from /proc/[pid]/cgroup. Control groups are used by Systemd and containers for limiting process group's usage of resources and to monitor them."); default: return QVariant(); } @@ -1405,6 +1411,8 @@ return w->name; } #endif + case HeadingCGroup: + return process->cGroup(); default: return QVariant(); } @@ -1784,6 +1792,8 @@ return w->name; } #endif + case HeadingCGroup: + return process->cGroup(); default: return QVariant(); } @@ -1967,6 +1977,7 @@ headings << i18nc("process heading", "Window Title"); } #endif + headings << i18nc("process heading", "CGroup"); if(d->mHeadings.isEmpty()) { // If it's empty, this is the first time this has been called, so insert the headings beginInsertColumns(QModelIndex(), 0, headings.count()-1); diff --git a/processui/ksysguardprocesslist.cpp b/processui/ksysguardprocesslist.cpp --- a/processui/ksysguardprocesslist.cpp +++ b/processui/ksysguardprocesslist.cpp @@ -340,6 +340,7 @@ d->mUi->treeView->header()->hideSection(ProcessModel::HeadingIoRead); d->mUi->treeView->header()->hideSection(ProcessModel::HeadingIoWrite); d->mUi->treeView->header()->hideSection(ProcessModel::HeadingXMemory); + d->mUi->treeView->header()->hideSection(ProcessModel::HeadingCGroup); // NOTE! After this is all setup, the settings for the header are restored // from the user's last run. (in restoreHeaderState) // So making changes here only affects the default settings. To