You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1123 lines
27 KiB
1123 lines
27 KiB
/*
|
|
* fm-search-uri.c
|
|
* This file is part of qps -- Qt-based visual process status monitor
|
|
*
|
|
* Copyright 2015 Hong Jen Yee (PCMan) <pcman.tw@gmail.com>
|
|
* Copyright 2012-2014 Andriy Grytsenko (LStranger) <andrej@rep.kiev.ua>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
* MA 02110-1301, USA.
|
|
*/
|
|
|
|
// for Non-ASCII locale
|
|
//#include <global.h>
|
|
|
|
//#include <qtextcodec.h>
|
|
// extern QTextCodec * codec ;
|
|
//#define UniString(str) codec->toUnicode(str)
|
|
|
|
int flag_24_ok; // we presume a kernel 2.4.x
|
|
|
|
#include <grp.h>
|
|
#include <pwd.h>
|
|
#include <sys/types.h>
|
|
#include <unistd.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
// COMMON
|
|
bool Procview::treeview = 0; // true
|
|
bool Procview::flag_show_file_path = false;
|
|
bool Procview::flag_cumulative = false; // times cumulative with children's
|
|
bool Procview::flag_pcpu_single = false; // %CPU= pcpu/num_cpus
|
|
|
|
// COMMON: basic field
|
|
int Procview::mini_fields[] = {F_PID, F_STAT, F_MEM, F_CPU, F_CMDLINE, F_END};
|
|
|
|
// COMMON?
|
|
// return username from /etc/passwd
|
|
char *userName(int uid, int euid)
|
|
{
|
|
char buff[128];
|
|
struct passwd *pw = getpwuid(uid);
|
|
if (!pw)
|
|
{
|
|
// dont have name !
|
|
sprintf(buff, "%d", uid);
|
|
}
|
|
else
|
|
strcpy(buff, pw->pw_name);
|
|
|
|
if (uid != euid)
|
|
strcat(buff, euid == 0 ? "*" : "+");
|
|
|
|
return strdup(buff);
|
|
}
|
|
|
|
// return group name (possibly numeric)
|
|
char *groupName(int gid, int egid)
|
|
{
|
|
char *p;
|
|
struct group *gr = getgrgid(gid);
|
|
if (!gr)
|
|
{
|
|
p = (char *)malloc(11);
|
|
sprintf(p, "%d", gid);
|
|
}
|
|
else
|
|
p = strdup(gr->gr_name);
|
|
// s.append("*");
|
|
return p;
|
|
}
|
|
|
|
Category::~Category() {}
|
|
|
|
int Category::compare(Procinfo *a, Procinfo *b)
|
|
{
|
|
return string(a).compare(string(b));
|
|
}
|
|
|
|
Cat_int::Cat_int(const char *heading, const char *explain, int w,
|
|
int Procinfo::*member)
|
|
: Category(heading, explain), int_member(member), field_width(w)
|
|
{
|
|
}
|
|
|
|
QString Cat_int::string(Procinfo *p)
|
|
{
|
|
QString s;
|
|
s.setNum(p->*int_member);
|
|
return s;
|
|
}
|
|
|
|
int Cat_int::compare(Procinfo *a, Procinfo *b)
|
|
{
|
|
// qsort() only cares about the sign of the number returned by the
|
|
// comparison function; only a subtraction is necessary
|
|
return a->*int_member - b->*int_member;
|
|
}
|
|
|
|
// COMMON
|
|
Cat_percent::Cat_percent(const char *heading, const char *explain, int w,
|
|
float Procinfo::*member)
|
|
: Category(heading, explain), float_member(member), field_width(w)
|
|
{
|
|
}
|
|
|
|
QString Cat_percent::string(Procinfo *p)
|
|
{
|
|
QString s;
|
|
s.sprintf("%01.2f", (double)(p->*float_member));
|
|
return s;
|
|
}
|
|
|
|
int Cat_percent::compare(Procinfo *a, Procinfo *b)
|
|
{
|
|
float at = a->*float_member, bt = b->*float_member;
|
|
return at < bt ? 1 : (at > bt ? -1 : 0);
|
|
}
|
|
// added 2006/05/07
|
|
Cat_memory::Cat_memory(const char *heading, const char *explain, int w,
|
|
unsigned long Procinfo::*member)
|
|
: Category(heading, explain), uintl_member(member), field_width(w)
|
|
{
|
|
}
|
|
|
|
QString Cat_memory::string(Procinfo *p)
|
|
{
|
|
QString s;
|
|
char buff[128];
|
|
|
|
long sizeK, sizeM;
|
|
sizeK = p->*uintl_member;
|
|
|
|
sizeM = sizeK / 1024;
|
|
/* if ( sizeM > 1024 )
|
|
{
|
|
sprintf(buff,"%dM",sizeM/1024);
|
|
}
|
|
else */
|
|
if (sizeM > 0)
|
|
{
|
|
sprintf(buff, "%ldM", sizeM);
|
|
}
|
|
else
|
|
sprintf(buff, "%ldK", sizeK);
|
|
|
|
if (sizeK == 0)
|
|
s = "0";
|
|
else
|
|
s = buff;
|
|
return s;
|
|
}
|
|
|
|
int Cat_memory::compare(Procinfo *a, Procinfo *b)
|
|
{
|
|
int bu = b->*uintl_member, au = a->*uintl_member;
|
|
return bu >= au ? (bu == au ? 0 : 1) : -1;
|
|
}
|
|
|
|
Cat_uintl::Cat_uintl(const char *heading, const char *explain, int w,
|
|
unsigned long Procinfo::*member)
|
|
: Category(heading, explain), uintl_member(member), field_width(w)
|
|
{
|
|
}
|
|
|
|
QString Cat_uintl::string(Procinfo *p)
|
|
{
|
|
QString s;
|
|
s.setNum(p->*uintl_member);
|
|
return s;
|
|
}
|
|
|
|
int Cat_uintl::compare(Procinfo *a, Procinfo *b)
|
|
{
|
|
int bu = b->*uintl_member, au = a->*uintl_member;
|
|
return bu >= au ? (bu == au ? 0 : 1) : -1;
|
|
}
|
|
|
|
Cat_hex::Cat_hex(const char *heading, const char *explain, int w,
|
|
unsigned long Procinfo::*member)
|
|
: Cat_uintl(heading, explain, w, member)
|
|
{
|
|
}
|
|
|
|
// QString.sprintf 2x speed than glibc.sprintf (by fasthyun@magicn.com)
|
|
// but QString structuring & destructring eat more time
|
|
QString Cat_hex::string(Procinfo *p)
|
|
{
|
|
QString s;
|
|
s.sprintf("%8x", (unsigned)(p->*uintl_member));
|
|
return s;
|
|
}
|
|
|
|
// COMMON,
|
|
Cat_swap::Cat_swap(const char *heading, const char *explain)
|
|
: Category(heading, explain)
|
|
{
|
|
}
|
|
|
|
QString Cat_swap::string(Procinfo *p)
|
|
{
|
|
QString s;
|
|
// It can actually happen that size < resident (Sun under Solaris 2.6)
|
|
// Possible with Linux ?
|
|
|
|
long sizeK, sizeM;
|
|
sizeK = p->size > p->resident ? p->size - p->resident : 0;
|
|
|
|
sizeM = sizeK / 1024;
|
|
|
|
if (sizeM > 0)
|
|
s = QString::number(sizeM) + "M";
|
|
else
|
|
s = QString::number(sizeK) + "K";
|
|
|
|
if (sizeK == 0)
|
|
s = "0";
|
|
return s;
|
|
}
|
|
|
|
int Cat_swap::compare(Procinfo *a, Procinfo *b)
|
|
{
|
|
return (b->size - b->resident) - (a->size - a->resident);
|
|
}
|
|
|
|
Cat_string::Cat_string(const char *heading, const char *explain,
|
|
QString Procinfo::*member)
|
|
: Category(heading, explain), str_member(member)
|
|
{
|
|
}
|
|
|
|
QString Cat_string::string(Procinfo *p) { return p->*str_member; }
|
|
|
|
Cat_user::Cat_user(const char *heading, const char *explain)
|
|
: Cat_string(heading, explain)
|
|
{
|
|
}
|
|
|
|
QString Cat_user::string(Procinfo *p)
|
|
{
|
|
if (p->uid == p->euid)
|
|
return Uidstr::userName(p->uid);
|
|
else
|
|
{
|
|
QString s = Uidstr::userName(p->uid);
|
|
s.append(p->euid == 0 ? "*" : "+");
|
|
return s;
|
|
}
|
|
}
|
|
|
|
Cat_group::Cat_group(const char *heading, const char *explain)
|
|
: Cat_string(heading, explain)
|
|
{
|
|
}
|
|
|
|
QString Cat_group::string(Procinfo *p)
|
|
{
|
|
if (p->gid == p->egid)
|
|
return Uidstr::groupName(p->gid);
|
|
else
|
|
{
|
|
QString s = Uidstr::groupName(p->gid);
|
|
s.append("*");
|
|
return s;
|
|
}
|
|
}
|
|
|
|
Cat_wchan::Cat_wchan(const char *heading, const char *explain)
|
|
: Cat_string(heading, explain)
|
|
{
|
|
}
|
|
|
|
QString Cat_wchan::string(Procinfo *p)
|
|
{
|
|
#ifdef LINUX
|
|
return p->wchan_str;
|
|
#else
|
|
return Wchan::name(p->wchan);
|
|
#endif
|
|
}
|
|
|
|
Cat_cmdline::Cat_cmdline(const char *heading, const char *explain)
|
|
: Cat_string(heading, explain)
|
|
{
|
|
}
|
|
|
|
QString Cat_cmdline::string(Procinfo *p)
|
|
{
|
|
if (p->cmdline.isEmpty())
|
|
{
|
|
QString s("(");
|
|
s.append(p->command);
|
|
s.append(")");
|
|
return s;
|
|
}
|
|
else
|
|
{
|
|
if (Procview::flag_show_file_path)
|
|
return p->cmdline;
|
|
else
|
|
{
|
|
QString s(p->cmdline);
|
|
|
|
int i = s.indexOf(' ');
|
|
if (i < 0)
|
|
i = s.length();
|
|
if (i > 0)
|
|
{
|
|
i = s.lastIndexOf('/', i - 1);
|
|
if (i >= 0)
|
|
s.remove(0, i + 1);
|
|
}
|
|
return s;
|
|
}
|
|
}
|
|
}
|
|
|
|
// hmm COMMON? almost same...but Solaris's zombie process...
|
|
Cat_start::Cat_start(const char *heading, const char *explain)
|
|
: Category(heading, explain)
|
|
{
|
|
}
|
|
// don't let your confidence be shaken, just learn what you can from this young
|
|
// master.
|
|
QString Cat_start::string(Procinfo *p)
|
|
{
|
|
#ifdef SOLARIS
|
|
if (p->state == 'Z')
|
|
return "-"; // Solaris zombies have no valid start time
|
|
#endif
|
|
Proc *proc = p->proc;
|
|
// time_t start = boot_time + p->starttime / (unsigned)HZ;
|
|
QString s;
|
|
// time_t start = proc->boot_time + p->starttime / proc->clk_tick;
|
|
time_t start = p->starttime;
|
|
char *ct = ctime(&start); // ctime(sec)
|
|
time_t sec = p->starttime - proc->boot_time; // secs
|
|
// if(p->tv.tv_sec - start < 86400) {
|
|
if (sec < 86400)
|
|
{ // 24hours
|
|
ct[16] = '\0';
|
|
s = ct + 11; // Hour:minu
|
|
}
|
|
else
|
|
{
|
|
ct[10] = '\0';
|
|
s = ct + 4; // Date
|
|
}
|
|
return s;
|
|
}
|
|
|
|
int Cat_start::compare(Procinfo *a, Procinfo *b)
|
|
{
|
|
unsigned long bs = b->starttime, as = a->starttime;
|
|
return bs >= as ? (bs == as ? 0 : 1) : -1;
|
|
}
|
|
|
|
/* ======================== Procview ============================ */
|
|
float Procview::avg_factor = 1.0;
|
|
|
|
Procview::Procview()
|
|
{
|
|
// Proc::Proc(); //call once more ?
|
|
cats.clear();
|
|
reversed = false;
|
|
viewproc = ALL;
|
|
treeview = true;
|
|
idxF_CMD = 0; // **** important ****
|
|
viewfields = USER;
|
|
set_fields();
|
|
|
|
sortcat = 0; // categories[F_PID];
|
|
sort_column = -1;
|
|
sortcat_linear = NULL;
|
|
enable = true;
|
|
maxSizeHistory = 1200;
|
|
refresh(); // before reading Watchdog list
|
|
}
|
|
|
|
// COMMON:
|
|
// Description :
|
|
// View mode : ALL , OWNER, NO-ROOOT , HIDDEN, NETWORK
|
|
bool Procview::accept_proc(Procinfo *p)
|
|
{
|
|
QString pid;
|
|
static int my_uid = getuid();
|
|
bool result;
|
|
|
|
result = true;
|
|
|
|
// BAD
|
|
if (false and viewproc == NETWORK)
|
|
{
|
|
/*
|
|
p->read_fds();
|
|
if(p->sock_inodes.size()==0)
|
|
result=false;
|
|
for(int i=0;i<p->sock_inodes.size();i++)
|
|
{
|
|
SockInode *sn=p->sock_inodes[i];
|
|
Sockinfo *si=Procinfo::socks.value(sn->inode,NULL);
|
|
if(si)
|
|
{
|
|
si->pid=p->pid;
|
|
linear_socks.append(si);
|
|
}
|
|
}
|
|
*/
|
|
}
|
|
else if (viewproc == ALL)
|
|
result = true;
|
|
else if (viewproc == OWNED)
|
|
result = (p->uid == my_uid);
|
|
else if (viewproc == NROOT)
|
|
result = (p->uid != 0);
|
|
else if (viewproc == RUNNING)
|
|
result = strchr("ORDW", p->state) != 0;
|
|
|
|
/*
|
|
if ( viewproc == HIDDEN)
|
|
{
|
|
result=false;
|
|
for(int j=0;j<hidden_process.size();j++)
|
|
if(hidden_process[j]==p->command)
|
|
result=true ;
|
|
}
|
|
else
|
|
{
|
|
for(int j=0;j<hidden_process.size();j++)
|
|
if(hidden_process[j]==p->command)
|
|
result=false;
|
|
} */
|
|
|
|
if (result == false)
|
|
return false; // dont go further !! for better speed
|
|
|
|
/// if(search_box==NULL) return result;
|
|
if (filterstr == "")
|
|
return result;
|
|
|
|
if (filterstr == "*")
|
|
return true;
|
|
|
|
// Notice:
|
|
// 1. some process name maybe different CMDLINE. ex) Xorg
|
|
if (p->cmdline.contains(filterstr,
|
|
Qt::CaseInsensitive)) // search_box->text()
|
|
return true;
|
|
if (p->command.contains(filterstr, Qt::CaseInsensitive))
|
|
return true;
|
|
if (p->username.contains(filterstr, Qt::CaseInsensitive))
|
|
return true;
|
|
|
|
pid = pid.setNum(p->pid); //=QString::number(p->pid);
|
|
if (pid.contains(filterstr, Qt::CaseInsensitive))
|
|
return true;
|
|
|
|
/// printf("search_Box =%s , %s
|
|
/// \n",search_box->text().toAscii().data(),p->command.toAscii().data());
|
|
|
|
return false;
|
|
}
|
|
|
|
extern "C" {
|
|
typedef int (*compare_func)(const void *, const void *);
|
|
}
|
|
|
|
/*
|
|
template<class T>
|
|
void Svec<T>::sort(int (*compare)(const T *a, const T *b))
|
|
{
|
|
qsort(vect, used, sizeof(T), (compare_func)compare);
|
|
}
|
|
*/
|
|
|
|
// table view - sort
|
|
void Procview::linearize_tree(QVector<Procinfo *> *ps, int level, int prow,
|
|
bool hide)
|
|
{
|
|
static_sortcat = sortcat;
|
|
// ps->sort(reversed ? compare_backwards : compare);
|
|
if (reversed)
|
|
qsort(ps->data(), ps->size(), sizeof(Procinfo *),
|
|
(compare_func)compare_backwards);
|
|
else
|
|
qsort(ps->data(), ps->size(), sizeof(Procinfo *),
|
|
(compare_func)compare);
|
|
|
|
int size = ps->size();
|
|
// printf("level=%d prow=%d size=%d\n",level,prow,size);
|
|
for (int i = 0; i < size; i++)
|
|
{
|
|
Procinfo *p = (*ps)[i];
|
|
// if (p->pid<6 ) printf("pid=%d level=%d
|
|
// parent_row=%d\n",p->pid,p->pid,p->parent_row);
|
|
p->level = level;
|
|
p->lastchild = false;
|
|
p->table_child_seq = i; // ************* where using ? -> sequence
|
|
p->parent_row = prow;
|
|
if (!hide)
|
|
linear_procs.append(p); // need !!
|
|
if (p->table_children.size()) // and !p->hidekids)
|
|
linearize_tree(&p->table_children, level + 1,
|
|
linear_procs.size() - 1, hide | p->hidekids);
|
|
}
|
|
|
|
if (size > 0)
|
|
(*ps)[size - 1]->lastchild = true;
|
|
}
|
|
|
|
/// basic,memory,job fields
|
|
void Procview::set_fields_list(int fields[])
|
|
{
|
|
cats.clear();
|
|
for (int i = 0; fields[i] != F_END; i++)
|
|
{
|
|
if (fields[i] == F_CPUNUM and Proc::num_cpus < 2)
|
|
continue; // not correctly work
|
|
|
|
Category *c = categories.value(fields[i], NULL);
|
|
if (c)
|
|
{
|
|
// printf("name=%s\n",c->name);
|
|
cats.append(c);
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
// return the column number of a field, or -1 if not displayed
|
|
int Procview::findCol(int field_id)
|
|
{
|
|
for (int i = 0; i < cats.size(); i++)
|
|
if (cats[i]->id == field_id)
|
|
return i;
|
|
return -1;
|
|
}
|
|
|
|
// basis
|
|
// called by
|
|
// void Procview::fieldArrange();
|
|
// qps();
|
|
//
|
|
void Procview::addField(int Fid, int where)
|
|
{
|
|
// where=-1;
|
|
// printf("Fid =%d where=%d\n",Fid,where);
|
|
// where=pstable->clickedColumn();
|
|
if (where == 0)
|
|
{
|
|
// if (pstable->treeMode()) where=1;
|
|
}
|
|
|
|
if (Fid == F_PROCESSNAME)
|
|
where = 0;
|
|
if (Fid == F_CMDLINE)
|
|
where = cats.size(); // always should be the last column
|
|
|
|
if (where < 0)
|
|
{
|
|
// this is default
|
|
where = cats.size();
|
|
}
|
|
|
|
if (where > cats.size()) // CMD_LINE ! ??????
|
|
where = 1;
|
|
|
|
Category *newcat = categories[Fid];
|
|
// printf("name =%s where=%d\n",newcat->name,where);
|
|
if (cats.indexOf(newcat) < 0) // if not in the list ****
|
|
cats.insert(where, newcat);
|
|
}
|
|
|
|
// add a category to last by name
|
|
void Procview::addField(char *name) // interface
|
|
{
|
|
// QString str=sl[i];
|
|
int id = field_id_by_name(name);
|
|
if (id >= 0)
|
|
addField(id); // add to last
|
|
|
|
return;
|
|
|
|
Category *cat = cat_by_name(name);
|
|
if (cat)
|
|
cats.append(cat);
|
|
}
|
|
|
|
void Procview::removeField(int field_id)
|
|
{
|
|
for (int i = 0; i < cats.size();)
|
|
{
|
|
// printf("Fid=%d cats[%d].id=%d
|
|
//\n",field_id,i,cats[i]->id);
|
|
if (true)
|
|
{
|
|
if (cats[i]->id == field_id)
|
|
{
|
|
// if(cats[i]->id==F_CMD and !treeview)
|
|
// idxF_CMD=-1;
|
|
cats.remove(i);
|
|
break;
|
|
}
|
|
else
|
|
i++;
|
|
}
|
|
}
|
|
// printf("Fid=%d cats.size=%d\n",field_id,cats.size());
|
|
}
|
|
|
|
// called by
|
|
// 1. write_settings()
|
|
// DEL? -> not yet
|
|
void Procview::update_customfield()
|
|
{
|
|
int i;
|
|
// printf("update custom_fields\n");
|
|
|
|
customfields.clear();
|
|
|
|
for (i = 0; i < cats.size(); i++)
|
|
customfields.append(cats[i]->name);
|
|
|
|
// DEL
|
|
if (false and treeview)
|
|
{
|
|
int idx = customfields.indexOf("COMMAND"); // == removeField(F_CMD);
|
|
if (idx >= 0)
|
|
customfields.removeAt(idx);
|
|
|
|
if (idxF_CMD >= 0)
|
|
{
|
|
/* if(customfields.size()<=idxF_CMD)
|
|
customfields.append(categories[F_CMD]->name);
|
|
else */
|
|
customfields.insert(idxF_CMD, categories[F_CMD]->name);
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
// Description : FIELD movement by mouse drag
|
|
// From col To place
|
|
void Procview::moveColumn(int col, int place)
|
|
{
|
|
int i;
|
|
|
|
int f_size = cats.size();
|
|
if (col < 0 or place < 0 or f_size <= col or f_size <= place)
|
|
{
|
|
printf("QPS code bugs!! : moveColumn() col=%d place=%d "
|
|
"cats.size=%d\n",
|
|
col, place, cats.size());
|
|
return;
|
|
}
|
|
|
|
if (treeview == true)
|
|
{
|
|
// *** important : F_PROCESSNAME field should be the first in
|
|
// TreeMode!
|
|
/// if(place==0) return;
|
|
if (cats[col]->index == F_PROCESSNAME)
|
|
place = 0;
|
|
}
|
|
|
|
// COMMAND_LINE field should always be the last field
|
|
// if(cats[place]->index==F_CMDLINE) return;
|
|
if (cats[col]->index == F_CMDLINE)
|
|
place = cats.size() - 1;
|
|
|
|
Category *cat = cats[col]; // SEGFAULT POSSIBLE!
|
|
cats.insert(place, cat); // insert
|
|
|
|
if (place < col)
|
|
col++;
|
|
|
|
cats.remove(col); // remove idx
|
|
// refresh();
|
|
/// update_customfield();
|
|
}
|
|
|
|
// always called when linear to tree
|
|
// DEL
|
|
void Procview::saveCOMMANDFIELD() {}
|
|
|
|
// call by
|
|
// void Pstable::moveCol(int col, int place)
|
|
// void Pstable::setTreeMode(bool treemode)
|
|
// void Procview::set_fields()
|
|
// TODO: checkField();
|
|
void Procview::fieldArrange()
|
|
{
|
|
|
|
if (treeview == true)
|
|
{
|
|
// Tree Mode
|
|
// If ProcessName isn't the leftmost column, move it to
|
|
// leftmost
|
|
// *** important : F_PROCESSNAME field should be the first in
|
|
// TreeMode!
|
|
if (cats[0]->index != F_PROCESSNAME)
|
|
{
|
|
// find F_PROCESSNAME
|
|
for (int i = 1; i < cats.size(); i++)
|
|
{
|
|
if (cats[i]->index == F_PROCESSNAME)
|
|
moveColumn(i, 0);
|
|
}
|
|
}
|
|
// PID sort for convenience (default)
|
|
/*
|
|
if(false and cats[i]->index == F_PID )
|
|
{
|
|
reversed = false;
|
|
sortcat = cats[i];
|
|
//// pstable->setSortedCol(i);
|
|
} */
|
|
// Linear_Mode:
|
|
}
|
|
|
|
if (true)
|
|
{
|
|
|
|
for (int i = 0; i < cats.size(); i++)
|
|
{
|
|
|
|
if (cats[i]->index == F_CMDLINE)
|
|
{
|
|
// COMMAND_LINE field should always be the last
|
|
// field
|
|
if (i == (cats.size() - 1))
|
|
moveColumn(i, 0);
|
|
else
|
|
{
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Procview::setTreeMode(bool b)
|
|
{
|
|
if (treeview == false)
|
|
{
|
|
if (sortcat_linear == NULL)
|
|
sortcat_linear = sortcat;
|
|
else
|
|
sortcat = sortcat_linear;
|
|
}
|
|
}
|
|
|
|
void Procview::setSortColumn(int col, bool r)
|
|
{
|
|
// qDebug("xxx error? col>=cats.size() %d",col);
|
|
if (col >= cats.size())
|
|
{
|
|
qDebug("hmmm error? col>=cats.size() %d", col);
|
|
return;
|
|
}
|
|
|
|
// if(!procview->treeview) just reverse the lines
|
|
if (col == sort_column)
|
|
reversed = !reversed;
|
|
else
|
|
reversed = false;
|
|
sortcat = cats[col];
|
|
sort_column = col;
|
|
}
|
|
|
|
Category *Procview::static_sortcat = 0;
|
|
int Procview::compare(Procinfo *const *a, Procinfo *const *b)
|
|
{
|
|
if (static_sortcat == 0)
|
|
return 0;
|
|
int r = static_sortcat->compare(*a, *b);
|
|
return (r == 0) ? ((*a)->pid > (*b)->pid ? 1 : -1) : r;
|
|
}
|
|
|
|
int Procview::compare_backwards(Procinfo *const *a, Procinfo *const *b)
|
|
{
|
|
if (static_sortcat == 0)
|
|
return 0;
|
|
int r = static_sortcat->compare(*b, *a);
|
|
return (r == 0) ? ((*b)->pid > (*a)->pid ? 1 : -1) : r;
|
|
}
|
|
|
|
// COMMON
|
|
Category *Proc::cat_by_name(const char *s)
|
|
{
|
|
|
|
if (s)
|
|
{
|
|
// java style
|
|
QHashIterator<int, Category *> i(categories);
|
|
while (i.hasNext())
|
|
{
|
|
const char *p;
|
|
i.next();
|
|
p = i.value()->name;
|
|
if (*p == ' ')
|
|
p++;
|
|
if (strcmp(p, s) == 0)
|
|
return i.value();
|
|
// cout << i.key() << ": " << i.value() << endl;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// COMMON
|
|
// call by
|
|
int Proc::field_id_by_name(const char *s)
|
|
{
|
|
if (s)
|
|
{
|
|
// STL style
|
|
QHash<int, Category *>::iterator i = categories.begin();
|
|
while (i != categories.end())
|
|
{
|
|
if (strcmp(i.value()->name, s) == 0)
|
|
return i.key(); // cout << i.key() << ": " <<
|
|
// i.value() << endl;
|
|
++i;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
// postInit
|
|
void Proc::commonPostInit()
|
|
{
|
|
// java style
|
|
/*
|
|
QHashIterator<int,Category *> i(categories); // a little suck!
|
|
while (i.hasNext()) {
|
|
i.next();
|
|
i.value()->index=i.key();
|
|
i.value()->id=i.key();
|
|
}*/
|
|
|
|
// STL style , set id
|
|
QHash<int, Category *>::iterator i = categories.begin();
|
|
while (i != categories.end())
|
|
{
|
|
i.value()->index = i.key();
|
|
i.value()->id = i.key();
|
|
// cout << i.key() << ": " << i.value() << endl;
|
|
++i;
|
|
}
|
|
|
|
num_opened_files = 0; // test
|
|
num_process = 0; // 64bit
|
|
num_network_process = 0; // 64bit
|
|
|
|
dt_total = 0; // diff system tick
|
|
dt_used = 0; // for infobar
|
|
|
|
loadavg[0] = loadavg[1] = loadavg[2] =
|
|
0.0; // CPU load avg 1min,5min,15minute
|
|
|
|
Proc::num_cpus = 0;
|
|
Proc::old_num_cpus = 0;
|
|
|
|
Proc::mem_total = 0;
|
|
Proc::mem_free = 0;
|
|
|
|
Proc::mem_buffers = 0;
|
|
Proc::mem_cached = 0;
|
|
// mem_shared = 0; // only linux kernel 2.4.x???
|
|
|
|
Proc::swap_total = 0;
|
|
Proc::swap_free = 0;
|
|
|
|
Proc::qps_pid = -1;
|
|
Proc::loadQps = 0.0;
|
|
|
|
Proc::cpu_times_vec = 0; // array.
|
|
Proc::old_cpu_times_vec = 0;
|
|
|
|
Proc::boot_time = 0;
|
|
Proc::clk_tick = 100; // for most system
|
|
|
|
current_gen = 0; // !
|
|
mprocs = NULL;
|
|
hprocs = NULL;
|
|
|
|
clk_tick =
|
|
sysconf(_SC_CLK_TCK); //****** The number of clock ticks per second.
|
|
//
|
|
// printf("Qps: hz=%d\n",clk_tick);
|
|
|
|
/// Procinfo::init_static();
|
|
}
|
|
|
|
// COMMON?
|
|
// called by Procview::rebuild()
|
|
// using procs, makes root_procs for TABLE_View
|
|
void Procview::build_tree(Proclist &procs)
|
|
{
|
|
Procinfo *p;
|
|
int proc_n = 0;
|
|
|
|
// children clear
|
|
root_procs.clear();
|
|
|
|
QHash<int, Procinfo *>::iterator i;
|
|
for (i = procs.begin(); i != procs.end();)
|
|
{
|
|
Procinfo *p = i.value();
|
|
p->table_children.clear();
|
|
if ((p->accepted = accept_proc(p)))
|
|
proc_n++;
|
|
++i;
|
|
}
|
|
|
|
Proc::num_process = proc_n; // count process
|
|
|
|
// find parent of a process
|
|
for (i = procs.begin(); i != procs.end(); ++i)
|
|
{
|
|
p = i.value(); // always not NULL
|
|
|
|
if (p->accepted)
|
|
{
|
|
Procinfo *parent = 0;
|
|
int virtual_parent_pid;
|
|
|
|
if (p->isThread())
|
|
virtual_parent_pid = p->tgid; // thread's leader ID.
|
|
else
|
|
virtual_parent_pid = p->ppid;
|
|
|
|
if (p->pid < p->ppid)
|
|
{
|
|
// this occurs !! a reporter mailed to me
|
|
}
|
|
|
|
parent = procs.value(virtual_parent_pid,
|
|
NULL); // if pid not found, then return NULL.
|
|
|
|
// printf("thread_leader=0 (%d)
|
|
//%s\n",p->tgid,p->command.ascii());
|
|
if (treeview and parent and parent->accepted)
|
|
{
|
|
// p->table_child_seq=parent->table_children.size();
|
|
parent->table_children.append(p);
|
|
}
|
|
else
|
|
{
|
|
// 1.init(pid=1) process
|
|
// 2.some process which parent not accepted
|
|
// 3.(null) thread has TGID=0,PPID=0
|
|
// 4.when not tree mode
|
|
root_procs.append(p);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// COMMON
|
|
// BOTTLENECK No.3 0.5%
|
|
// re-sort the process list , ::rebuild() for Table
|
|
// called by Pstable::refresh()
|
|
void Procview::rebuild()
|
|
{
|
|
linear_procs.clear(); // Svec<Procinfo *> procs in Proview
|
|
#ifdef LINUX
|
|
linear_socks.clear();
|
|
#endif
|
|
|
|
// Procinfo *pi = getProcinfoByPID(Procinfo::qps_pid);
|
|
// if(pi) Procinfo::loadQps=pi->pcpu;
|
|
// printf("rebuild\n");
|
|
|
|
/* if(mprocs)
|
|
{
|
|
build_tree(*mprocs);
|
|
}
|
|
else */
|
|
build_tree(Proc::procs);
|
|
|
|
linearize_tree(&root_procs, 0, -1);
|
|
}
|
|
|
|
#include <math.h> // log()
|
|
// COMMON: CORE
|
|
// Description: update the process list BottleNeck 1.5%
|
|
// read /proc/*
|
|
// called by Procview::refresh(), every UPDATE .
|
|
void Proc::refresh()
|
|
{
|
|
current_gen++;
|
|
|
|
// TEST for Process History
|
|
SysHistory *s = new SysHistory;
|
|
|
|
history.append(s);
|
|
hprocs = &(s->procs);
|
|
|
|
// init
|
|
/// num_opened_files=0;
|
|
Proc::num_process = 0;
|
|
Proc::num_network_process = 0;
|
|
|
|
Proc::read_loadavg();
|
|
Proc::read_system(); // **** should be every refresh !!
|
|
// s->load_cpu=(float)Proc::dt_used/Proc::dt_total; //after
|
|
// read_system();
|
|
|
|
s->load_cpu = load_cpu; // after read_system();
|
|
s->time = time(NULL); // save current time in seconds since epoch
|
|
|
|
// TODO: clean
|
|
// Procinfo::read_sockets(); // for future, BottleNect 2%
|
|
read_byte = 0;
|
|
write_byte = 0;
|
|
io_byte = 0; //!!!
|
|
/// Proc::read_sockets(); // test
|
|
|
|
read_proc_all(); // Linux, Solaris...
|
|
|
|
// s->load_io=(float)(read_byte + write_byte ); // (50*1024*1024);
|
|
// //dt_total;
|
|
if (io_byte != 0)
|
|
{
|
|
s->load_io = log10(io_byte) * 2; // 9000 -> 3point
|
|
// printf("DEBUG: rw=[%d,%d] %d, %f\n",read_byte,
|
|
// write_byte,io_byte,s->load_io);
|
|
}
|
|
else
|
|
s->load_io = 0;
|
|
|
|
// remove non-existing processes, remove Procinfos of nonexisting
|
|
// processes
|
|
QHash<int, Procinfo *>::iterator i;
|
|
for (i = procs.begin(); i != procs.end();)
|
|
{
|
|
Procinfo *p = i.value();
|
|
if (p->generation != current_gen)
|
|
{
|
|
// printf("delete %d\n",p->pid);
|
|
i = procs.erase(i);
|
|
delete p;
|
|
}
|
|
else
|
|
{
|
|
// p->table_children.clear(); // for rebuild()
|
|
// p->accepted=accept_proc(p);
|
|
++i;
|
|
}
|
|
}
|
|
|
|
// TESTING
|
|
while (history.size() >= maxSizeHistory)
|
|
{
|
|
// if(history.isEmpty()==false)
|
|
delete history.takeFirst();
|
|
}
|
|
}
|
|
|
|
// COMMON
|
|
// read new process info
|
|
void Procview::refresh()
|
|
{
|
|
/****************************************************************/
|
|
/* Procview.procs has the procinfo
|
|
*/
|
|
/****************************************************************/
|
|
if (enable)
|
|
{
|
|
// printf("Procview::refresh()\n");
|
|
Proc::refresh(); // read "/proc/*", then update the process list
|
|
}
|
|
}
|
|
|
|
SysHistory::~SysHistory()
|
|
{
|
|
for (const auto *p : qAsConst(procs))
|
|
{
|
|
delete p;
|
|
}
|
|
procs.clear(); // remove all (key,val)
|
|
}
|
|
|
|
/* check
|
|
Category *Proc::cat_by_name(const char *s)
|
|
{
|
|
if( s )
|
|
{
|
|
for( int i = 0; i < categories.size(); i++ )
|
|
if( strcmp(categories[i]->name, s) == 0 )
|
|
return categories[i];
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
int Proc::field_id_by_name(const char *s)
|
|
{
|
|
if( s )
|
|
{
|
|
for( int i = 0; i < categories.size(); i++ )
|
|
if( strcmp(categories[i]->name, s) == 0 )
|
|
return i;
|
|
}
|
|
return -1;
|
|
}
|
|
*/
|