mirror of
https://github.com/levinsv/pgadmin3.git
synced 2026-05-15 14:15:49 -06:00
Added collection of waiting events.
В окне "Status server" при получении информации о процессах добавлен сбор событий ожидания. Должно быть установлено расширение pg_wait_sampling. И правильно настроены параметры. Для примера минимальный размер буфера: при частоте опроса 1 сек (1000мс), количестве процессов 100 (num_p), pg_wait_sampling.history_period=10 Значение pg_wait_sampling.history_size = 1000 /10 * 100 = 10000 для 3-х кратного запаса можно взять 30000. Ожидание ClientRead немного изменено и означает, ожидание данных от клиента в НАЧАТОЙ ТРАНЗАКЦИИ. События ожидания можно сохранить в текстовый файл. В настройках pgadmin3opt.json можно выбрать цвета для отдельных событий или отключить сбор.
This commit is contained in:
parent
1e121c1fa0
commit
450c00ea90
8 changed files with 5281 additions and 712 deletions
714
utils/WaitSample.cpp
Normal file
714
utils/WaitSample.cpp
Normal file
|
|
@ -0,0 +1,714 @@
|
|||
#include "pgAdmin3.h"
|
||||
#include "utils/WaitSample.h"
|
||||
#include "wx/stdpaths.h"
|
||||
#include "utils/utffile.h"
|
||||
#include "utils/json/jsonval.h"
|
||||
|
||||
void WaitSample::Init() {
|
||||
wxString clr = "h1 { \
|
||||
region: \"IO:DataFileRead\", #3644ff;\n\
|
||||
region: \"IO:DataFileWrite\", #790808;\n\
|
||||
region: \"IO:BufFileRead\", #16658d;\n\
|
||||
region: \"IO:BufFileWrite\", #d30a0a;\n\
|
||||
region: \"IO:DataFileExtend\", #9720ba;\n\
|
||||
region: \"IO:DataFilePrefetch\", #c03ae8;\n\
|
||||
region: \"IO:DataFileFlush\", #b609ea;\n\
|
||||
region: \"IO:DataFileSync\", #b609ea;\n\
|
||||
region: \"IO:ReplicationSlotSync\", #b609ea;\n\
|
||||
region: \"IO:WALSync\", #ff6a00;\n\
|
||||
region: \"IO:WALWrite\", #ff6a00;\n\
|
||||
region: \"IO:WALInitWrite\", #ff6a00;\n\
|
||||
region: \"IO:WALRead\", #ba550e;\n\
|
||||
region: \"IO\", #2132bd;\n\
|
||||
region: \"IPC\", #908b3b;\n\
|
||||
region: \"Lock\", #ff0000;\n\
|
||||
region: \"Client\", #0b6222;\n\
|
||||
region: \"BufferPin\", #a4a3a0;\n\
|
||||
region: \"Client:ClientWrite\", #76bb88;\n\
|
||||
region: \"IPC:ArchiveCommand\", #fff200;\n\
|
||||
region: \"IPC:MessageQueueReceive\", #aaae4f;\n\
|
||||
region: \"IPC:MessageQueueSend\", #aaae4f;\n\
|
||||
region: \"LWLock\", #87f566;\n\
|
||||
region: \"LWLock:WALWrite\", #3bf61e;\n\
|
||||
region: \"LWLock:WALInsert\", #3bf61e;\n\
|
||||
region: \"LWLock:Autovacuum\", #20bb08;\n\
|
||||
region: \"LWLock:BufferContent\", #98db19;\n\
|
||||
region: \"Timeout\", #6ce4c6;\n\
|
||||
region: \"Timeout:VacuumDelay\", #20bb08;\n\
|
||||
}";
|
||||
wxStringTokenizer tk(clr, "\n", wxTOKEN_DEFAULT);
|
||||
wxString cc;
|
||||
wxString cnt;
|
||||
wxString ee;
|
||||
wxString l;
|
||||
wxJSONValue events(wxJSONType::wxJSONTYPE_ARRAY);
|
||||
while (tk.HasMoreTokens())
|
||||
{
|
||||
wxString l = tk.GetNextToken();
|
||||
wxString w = l.AfterFirst('"').BeforeFirst('"');
|
||||
if (w.IsEmpty()) continue;
|
||||
wxString c = l.AfterFirst('#').BeforeFirst(';');
|
||||
unsigned long tmp;
|
||||
wxSscanf(c, "%lx", &tmp);
|
||||
wait_idx.emplace(w, tmp);
|
||||
wxJSONValue e(wxJSONType::wxJSONTYPE_OBJECT);
|
||||
wxColour cc3("#"+c);
|
||||
e["enable"] = true;
|
||||
e["color"] = "#" + c;
|
||||
e["name"] = w;
|
||||
events.Append(e);
|
||||
}
|
||||
wxJSONValue def(wxJSONType::wxJSONTYPE_OBJECT);
|
||||
def["events"] = events;
|
||||
//def["autoloadcache_sql"] = true;
|
||||
group.push_back("BufferPin");
|
||||
group.push_back("Client");
|
||||
group.push_back("IO");
|
||||
group.push_back("IPC");
|
||||
group.push_back("Lock");
|
||||
group.push_back("Activity");
|
||||
group.push_back("LWLock");
|
||||
group.push_back("Timeout");
|
||||
settings->ReloadJsonFileIfNeed();
|
||||
settings->ReadJsonObect("WaitEvents", opt, def);
|
||||
// settings->WriteJsonFile();
|
||||
if (!opt.IsNull()) {
|
||||
wait_idx.clear();
|
||||
wxJSONValue r = opt["events"];
|
||||
for (int j = 0; j < r.Size(); j++) {
|
||||
wxJSONValue e = r[j];
|
||||
bool enable = e["enable"].AsBool();
|
||||
wxString c= e["color"].AsString();
|
||||
unsigned long tmp;
|
||||
wxSscanf(c, "#%lx", &tmp);
|
||||
wxColour cc(tmp);
|
||||
if (!cc.IsOk()) cc = *wxBLACK;
|
||||
//wxSscanf(c, "%lx", &tmp);
|
||||
wxString w = e["name"].AsString();
|
||||
wait_idx.emplace(w, tmp);
|
||||
if (!enable) wait_disable.emplace(w,0);
|
||||
}
|
||||
}
|
||||
else opt = def;
|
||||
wxString tempDir = wxStandardPaths::Get().GetUserConfigDir() + wxFileName::GetPathSeparator() + "postgresql" + wxFileName::GetPathSeparator() + "cache_sql.txt";
|
||||
wxTextFile file(tempDir);
|
||||
if (file.Exists()) file.Open();
|
||||
if (file.IsOpened())
|
||||
{
|
||||
wxString str;
|
||||
wxString sql;
|
||||
long long qid;
|
||||
for (str = file.GetFirstLine(); !file.Eof(); str = file.GetNextLine())
|
||||
{
|
||||
if (str.length() == 16) {
|
||||
unsigned long long temp_qid = 0;
|
||||
int cntbits = 0;
|
||||
for (int i = str.length() - 1; i >= 0; i--, cntbits = cntbits + 4)
|
||||
{
|
||||
unsigned char h = str[i];
|
||||
unsigned char n09 = h - '0';
|
||||
unsigned char nAF = (h | 0x20) - 'a';
|
||||
if ((n09 <= (9 - 0)) || (nAF <= (0xf - 0xa))) {
|
||||
// is hex digits
|
||||
}
|
||||
else break;
|
||||
unsigned long long tetra = ((h & 0xf) + (h >> 6) * 9);
|
||||
temp_qid |= tetra << cntbits;
|
||||
}
|
||||
if (cntbits == 64) {
|
||||
//wxString tmp = sql.BeforeLast('\n');
|
||||
//if (tmp.IsEmpty()) tmp=sql;
|
||||
if (sql.length() > 0) AddQuery(qid, sql); // previos sql
|
||||
qid = temp_qid;
|
||||
sql = wxEmptyString;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (!sql.IsEmpty()) sql.Append('\n');
|
||||
sql.Append(str);
|
||||
}
|
||||
//file.ReadAll(&str);
|
||||
file.Close();
|
||||
if (sql.length() > 0)
|
||||
{
|
||||
//wxString tmp = sql.BeforeLast('\n');
|
||||
//if (tmp.IsEmpty()) tmp = sql;
|
||||
AddQuery(qid, sql); // previos sql
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
std::vector<Sample>* WaitSample::GetSamples() { return &smp; }
|
||||
std::vector<int> WaitSample::GetColors() { return colors; }
|
||||
|
||||
wxArrayString WaitSample::GetWaitIdNameArray(bool onlyGroup) {
|
||||
typedef std::pair<wxString, int> pair;
|
||||
// sort map by value;
|
||||
std::vector<pair> vec;
|
||||
std::copy(wait_id.begin(),
|
||||
wait_id.end(),
|
||||
std::back_inserter<std::vector<pair>>(vec));
|
||||
std::sort(vec.begin(), vec.end(),
|
||||
[](const pair& l, const pair& r)
|
||||
{
|
||||
if (l.second != r.second) {
|
||||
return l.second < r.second;
|
||||
}
|
||||
|
||||
return l.first < r.first;
|
||||
});
|
||||
wxArrayString a;
|
||||
for (auto const& pair : vec) {
|
||||
//std::cout << '{' << pair.first << "," << pair.second << '}' << std::endl;
|
||||
wxString n = pair.first;
|
||||
if (onlyGroup) {
|
||||
if (!n.BeforeFirst(':').IsEmpty()) n = n.BeforeFirst(':');
|
||||
}
|
||||
a.Add(n);
|
||||
|
||||
}
|
||||
return a;
|
||||
}
|
||||
// return position in smp vector
|
||||
int WaitSample::GetHomeInterval(int timeEnd, int AggrigateInterval) {
|
||||
Sample sa;
|
||||
if (timeEnd == -1) {
|
||||
// end smp
|
||||
sa = smp.back();
|
||||
timeEnd = sa.btime;
|
||||
}
|
||||
else {
|
||||
|
||||
}
|
||||
long long th = ((basetime + timeEnd) / AggrigateInterval) * AggrigateInterval;
|
||||
int home_int = th - basetime;
|
||||
if (th > (basetime + timeEnd)) {
|
||||
//long long te = th - AggrigateInterval;
|
||||
home_int = th - AggrigateInterval - basetime;
|
||||
}
|
||||
return home_int;
|
||||
|
||||
//wxLongLong l(((basetime + timeEnd)/AggrigateInterval)* AggrigateInterval);
|
||||
//wxDateTime t(l);
|
||||
}
|
||||
int WaitSample::getPositionByTime(int time) {
|
||||
|
||||
int max = smp.size() - 1;
|
||||
int min = 0;
|
||||
int i = (max - min) / 2;
|
||||
while (i != -1) {
|
||||
int t = smp[i].btime;
|
||||
if (t < time) {
|
||||
min = i;
|
||||
i = min + (max - min) / 2;
|
||||
}
|
||||
else if (t > time) {
|
||||
max = i;
|
||||
i = min + (max - min) / 2;
|
||||
}
|
||||
else {
|
||||
while (i > 0 && smp[i - 1].btime == t) {
|
||||
i--;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (max - min < 2) {
|
||||
i = max;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
|
||||
}
|
||||
|
||||
int WaitSample::wait_class(wxString wclass) {
|
||||
int i = 0;
|
||||
for (const auto& name : group) {
|
||||
if (name == wclass) return i;
|
||||
i++;
|
||||
}
|
||||
wxFAIL_MSG("Unknown wait class " + wclass);
|
||||
return -1000;
|
||||
}
|
||||
// return count group
|
||||
int WaitSample::GetGroupingData(int timeEnd, int needCountGroup, int groupInterval,
|
||||
wxString groupRule, wxArrayString& nameGroup,
|
||||
std::vector<wxDateTime>& xAxisValue,
|
||||
std::vector<wxTimeSpan>& yAxisValue,
|
||||
std::vector<vec_int>& Values, // ìàññèâ ñòîëáöîâ ñïðàâà íà ëåâî
|
||||
std::vector<long>& clr // öåòà ñëî¸â ðàçìåðíîñòüþ groupRule.Count()
|
||||
)
|
||||
{
|
||||
int idx_grp = wait_id.size();
|
||||
std::vector<int> filter_map(wait_id.size() + group.size());
|
||||
std::vector<int> summary(wait_id.size() + group.size());
|
||||
for (size_t i = 0; i < filter_map.size(); i++) filter_map[i] = -1;
|
||||
nameGroup.Clear();
|
||||
//std::map<int, wxString> wait_id_name;
|
||||
long long qidfilter = -1;
|
||||
for (const auto& kv : wait_id) {
|
||||
//std::cout << kv.first << " has value " << kv.second << std::endl;
|
||||
wxString w_name = kv.first;
|
||||
int w_id = kv.second;
|
||||
//wait_id_name.emplace(w_id, w_name);
|
||||
bool enable = true;
|
||||
wxString grp_name = w_name.BeforeFirst(':');
|
||||
if (grp_name.IsEmpty()) grp_name = w_name;
|
||||
int cl = wait_class(grp_name);
|
||||
bool isF = false;
|
||||
if (!groupRule.IsEmpty()) {
|
||||
wxStringTokenizer tk(groupRule, ";", wxTOKEN_DEFAULT);
|
||||
wxString l;
|
||||
bool isDis = true;
|
||||
bool isGrp = true;
|
||||
|
||||
while (tk.HasMoreTokens())
|
||||
{
|
||||
l = tk.GetNextToken();
|
||||
if (l[0] == '@') {
|
||||
if (qidfilter == -1) {
|
||||
int cntbits = 0;
|
||||
unsigned long long temp_qid = 0;
|
||||
for (int i = l.length() - 1; i > 0; i--, cntbits = cntbits + 4)
|
||||
{
|
||||
unsigned char h = l[i];
|
||||
unsigned char n09 = h - '0';
|
||||
unsigned char nAF = (h | 0x20) - 'a';
|
||||
if ((n09 <= (9 - 0)) || (nAF <= (0xf - 0xa))) {
|
||||
// is hex digits
|
||||
}
|
||||
else break;
|
||||
unsigned long long tetra = ((h & 0xf) + (h >> 6) * 9);
|
||||
temp_qid |= tetra << cntbits;
|
||||
}
|
||||
qidfilter = temp_qid;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
isDis = l[0] == '-';
|
||||
if (isDis) l = l.substr(1);
|
||||
isGrp = l.find(':') == -1;
|
||||
if (w_name == l) {
|
||||
if (isDis) {
|
||||
filter_map[w_id] = w_id; //disable in Grp
|
||||
if (filter_map[idx_grp + cl] < 0) filter_map[idx_grp + cl] = -2;
|
||||
}
|
||||
else {
|
||||
//filter_map[w_id] = w_id;
|
||||
isF = false; //default
|
||||
break;
|
||||
}
|
||||
isF = true;
|
||||
break;
|
||||
}
|
||||
if (isGrp) {
|
||||
|
||||
if (grp_name == l) {
|
||||
if (isDis) {
|
||||
// Groups equal and disable
|
||||
filter_map[w_id] = w_id; // disable w_id Grp ALL disable
|
||||
filter_map[idx_grp + cl] = -2; // disable group
|
||||
isF = true;
|
||||
break;
|
||||
}
|
||||
// default rule
|
||||
break;
|
||||
}
|
||||
continue; // next rule
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!isF) {
|
||||
// no found in Rule
|
||||
filter_map[w_id] = idx_grp + cl; // wait_id -> [idx_grp + cl]
|
||||
filter_map[idx_grp + cl] = 999; // visible
|
||||
//filter_map[idx_grp+cl]=
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
// nameGroup
|
||||
// begin Group
|
||||
wxString n, g;
|
||||
clr.clear();
|
||||
clr.resize(filter_map.size());
|
||||
for (size_t i = idx_grp; i < filter_map.size(); i++)
|
||||
{
|
||||
int wait_id = filter_map[i];
|
||||
if (wait_id == -1) continue;
|
||||
n = group[i - idx_grp];
|
||||
g = n;
|
||||
clr[i] = GetColorByWaitName(n);
|
||||
if (wait_id == -2) n = '-' + n;
|
||||
nameGroup.Add(n);
|
||||
// individual wait
|
||||
for (size_t j = 0; j < idx_grp; j++)
|
||||
{
|
||||
int wait_id = filter_map[j];
|
||||
n = wait_id_name[j];
|
||||
wxString grp_name = n.BeforeFirst(':');
|
||||
if (grp_name.IsEmpty()) grp_name = n;
|
||||
if (grp_name != g) continue;
|
||||
if (!n.AfterFirst(':').IsEmpty()) n = n.AfterFirst(':');
|
||||
if (wait_id == j) n = "--" + n; else n = " " + n;
|
||||
nameGroup.Add(n);
|
||||
clr[j] = GetColorByWaitName(wait_id_name[j]);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
int homeInt = GetHomeInterval(timeEnd, groupInterval);
|
||||
Sample sa;
|
||||
if (timeEnd == -1) {
|
||||
sa = smp.back();
|
||||
timeEnd = sa.btime;
|
||||
}
|
||||
int idx = getPositionByTime(timeEnd);
|
||||
for (size_t i = 0; i < summary.size(); i++) summary[i] = 0;
|
||||
Values.clear();
|
||||
xAxisValue.clear();
|
||||
//for (size_t i = 0; i < maxS.size(); i++) maxS[i] = 0;
|
||||
long long maxsum = 0;
|
||||
int minsum = 0;
|
||||
int nGrp = needCountGroup;
|
||||
while (idx >= 0) {
|
||||
sa = smp[idx--];
|
||||
if (sa.btime >= homeInt && idx >= 0) {
|
||||
}
|
||||
else {
|
||||
// new interval
|
||||
wxLongLong l(basetime + homeInt);
|
||||
wxDateTime t(l);
|
||||
xAxisValue.push_back(t);
|
||||
std::vector<int> itog(summary.size());
|
||||
int ni = idx_grp;
|
||||
int Ymax = 0;
|
||||
for (size_t i = 0; i < itog.size(); i++)
|
||||
{
|
||||
|
||||
int wait_id = filter_map[i];
|
||||
if (wait_id < 0) { itog[i] = wait_id; continue; }
|
||||
int a = summary[i];
|
||||
itog[i] = a;
|
||||
if (i >= idx_grp) Ymax += a;
|
||||
//if (minsum > a) minsum = a;
|
||||
}
|
||||
if (maxsum < Ymax) maxsum = Ymax;
|
||||
Values.push_back(itog);
|
||||
homeInt -= groupInterval;
|
||||
nGrp--;
|
||||
if (nGrp == 0) break;
|
||||
for (size_t i = 0; i < summary.size(); i++) summary[i] = 0;
|
||||
}
|
||||
if (qidfilter != -1 && sa.qid != qidfilter) continue;
|
||||
int w_id = sa.wait_id;
|
||||
if (filter_map[w_id] < 0) continue;
|
||||
int ii = filter_map[w_id];
|
||||
// grp
|
||||
int s = sa.samples * periodms;
|
||||
if (ii != w_id) summary[ii] += s;
|
||||
// details
|
||||
summary[w_id] += s;
|
||||
}
|
||||
yAxisValue.clear();
|
||||
yAxisValue.push_back(wxTimeSpan(0, 0, 0, maxsum));
|
||||
return Values.size();
|
||||
}
|
||||
int WaitSample::GetInterval(int posStart, int posEnd) {
|
||||
Sample sa1, sa2;
|
||||
if (smp.size() == 0) return 0;
|
||||
if (posEnd == -1) {
|
||||
sa2 = smp.back();
|
||||
}
|
||||
else sa2 = smp.at(posEnd);
|
||||
sa1 = smp.at(posStart);
|
||||
return sa2.btime - sa1.btime;
|
||||
}
|
||||
bool WaitSample::AddQuery(long long qid, wxString sql) {
|
||||
if (qid_sql.find(qid) == qid_sql.end()) {
|
||||
qid_sql.emplace(qid, sql);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
wxString WaitSample::GetQueryByQid(long long qid) {
|
||||
if (qid_sql.find(qid) != qid_sql.end()) {
|
||||
wxString sql = qid_sql[qid];
|
||||
return sql;
|
||||
}
|
||||
return wxEmptyString;
|
||||
|
||||
}
|
||||
void WaitSample::LoadFileSamples() {
|
||||
wxString tempDir = wxStandardPaths::Get().GetUserConfigDir() + wxFileName::GetPathSeparator() + "postgresql" + wxFileName::GetPathSeparator() + "sample.dat";
|
||||
wxTextFile file(tempDir);
|
||||
file.Open();
|
||||
if (file.IsOpened())
|
||||
{
|
||||
wxString str;
|
||||
for (str = file.GetFirstLine() + '\n'; !file.Eof(); str += file.GetNextLine() + '\n')
|
||||
{
|
||||
|
||||
}
|
||||
//file.ReadAll(&str);
|
||||
file.Close();
|
||||
|
||||
wxStringTokenizer tk(str, "\n", wxTOKEN_DEFAULT);
|
||||
wxString cc;
|
||||
wxString cnt;
|
||||
wxString ee;
|
||||
wxString l;
|
||||
int nl = 0;
|
||||
while (tk.HasMoreTokens())
|
||||
{
|
||||
wxString l = tk.GetNextToken();
|
||||
if (l.IsEmpty()) continue;
|
||||
if (nl == 0) {
|
||||
long long t;
|
||||
wxSscanf(l, "%lld", &basetime);
|
||||
nl++;
|
||||
continue;
|
||||
}
|
||||
if (nl == 4) {
|
||||
//smp
|
||||
//wxString w_name = tk.GetNextToken();
|
||||
//wxString w_id = tk2.GetNextToken();
|
||||
int tmp = 0;
|
||||
Sample sa;
|
||||
if (wxSscanf(l, "%d %d %d %d %lld %d %d", &sa.btime, &sa.etime, &sa.wait_id, &sa.pid, &sa.qid, &sa.btype, &sa.samples) != 7) {
|
||||
wxLogError("Invalid count parameters '%s'.", l);
|
||||
}
|
||||
/*wxSscanf(tk2.GetNextToken(), "%d", &sa.btime);
|
||||
wxSscanf(tk2.GetNextToken(), "%d", &sa.etime);
|
||||
wxSscanf(tk2.GetNextToken(), "%d", &sa.wait_id);
|
||||
wxSscanf(tk2.GetNextToken(), "%d", &sa.pid);
|
||||
wxSscanf(tk2.GetNextToken(), "%lld", &sa.qid);
|
||||
wxSscanf(tk2.GetNextToken(), "%d", &sa.btype);
|
||||
wxSscanf(tk2.GetNextToken(), "%d", &sa.samples);*/
|
||||
smp.push_back(sa);
|
||||
continue;
|
||||
}
|
||||
|
||||
wxStringTokenizer tk2(l, " ", wxTOKEN_DEFAULT);
|
||||
if (nl == 1) {
|
||||
//btype
|
||||
|
||||
while (tk2.HasMoreTokens())
|
||||
{
|
||||
wxString b_name, b_id;
|
||||
while (b_id.IsEmpty()) {
|
||||
wxString str = tk2.GetNextToken();
|
||||
if (!wxIsdigit(str[0]))
|
||||
b_name += b_name.IsEmpty() ? str : " " + str;
|
||||
else b_id = str;
|
||||
}
|
||||
unsigned long tmp;
|
||||
wxSscanf(b_id, "%ld", &tmp);
|
||||
int i = GetBackendTypeId(b_name);
|
||||
if (i != tmp) {
|
||||
|
||||
}
|
||||
}
|
||||
nl++;
|
||||
continue;
|
||||
}
|
||||
if (nl == 2) {
|
||||
//wait_id
|
||||
while (tk2.HasMoreTokens())
|
||||
{
|
||||
wxString w_name, w_id;
|
||||
while (w_id.IsEmpty()) {
|
||||
wxString str = tk2.GetNextToken();
|
||||
if (!wxIsdigit(str[0]))
|
||||
w_name += w_name.IsEmpty() ? str : " " + str;
|
||||
else w_id = str;
|
||||
}
|
||||
unsigned long tmp;
|
||||
wxSscanf(w_id, "%ld", &tmp);
|
||||
wait_id.emplace(w_name, tmp);
|
||||
wait_id_name.emplace(tmp, w_name);
|
||||
}
|
||||
nl++;
|
||||
continue;
|
||||
}
|
||||
if (nl == 3) {
|
||||
//colors
|
||||
int sz = wait_id.size();
|
||||
colors.resize(sz);
|
||||
int i = 0;
|
||||
while (tk2.HasMoreTokens())
|
||||
{
|
||||
wxString c = tk2.GetNextToken();
|
||||
unsigned long tmp;
|
||||
wxSscanf(c, "%ld", &tmp);
|
||||
colors[i++] = tmp;
|
||||
}
|
||||
nl++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
void WaitSample::SaveFileSamples() {
|
||||
wxString tempDir = wxStandardPaths::Get().GetUserConfigDir() + wxFileName::GetPathSeparator() + "postgresql" + wxFileName::GetPathSeparator() + "sample.dat";
|
||||
wxUtfFile file(tempDir, wxFile::write, wxFONTENCODING_UTF8);
|
||||
if (file.IsOpened())
|
||||
{
|
||||
wxString strnl;
|
||||
strnl = wxString::Format("%lld\n", basetime);
|
||||
file.Write(strnl);
|
||||
strnl.Clear();
|
||||
//btype
|
||||
int i = 0;
|
||||
for (const auto& e : btype) {
|
||||
if (!strnl.IsEmpty()) strnl += ' ';
|
||||
strnl += wxString::Format("%s %d", e, i);
|
||||
i++;
|
||||
}
|
||||
strnl += '\n';
|
||||
file.Write(strnl);
|
||||
// wait_id
|
||||
strnl.Clear();
|
||||
for (const auto& e : wait_id) {
|
||||
if (!strnl.IsEmpty()) strnl += ' ';
|
||||
strnl += wxString::Format("%s %d", e.first, e.second);
|
||||
}
|
||||
strnl += '\n';
|
||||
file.Write(strnl);
|
||||
strnl.Clear();
|
||||
for (const auto& e : colors) {
|
||||
if (!strnl.IsEmpty()) strnl += ' ';
|
||||
strnl += wxString::Format("%d", e);
|
||||
}
|
||||
strnl += '\n';
|
||||
file.Write(strnl);
|
||||
strnl.Clear();
|
||||
for (const auto& e : smp) {
|
||||
strnl.Append(wxString::Format("%d %d %d %d %lld %d %d\n", e.btime, e.etime, e.wait_id, e.pid, e.qid, e.btype, e.samples));
|
||||
}
|
||||
file.Write(strnl);
|
||||
file.Close();
|
||||
}
|
||||
tempDir = wxStandardPaths::Get().GetUserConfigDir() + wxFileName::GetPathSeparator() + "postgresql" + wxFileName::GetPathSeparator() + "cache_sql.txt";
|
||||
wxUtfFile file1(tempDir, wxFile::write, wxFONTENCODING_UTF8);
|
||||
if (file1.IsOpened())
|
||||
{
|
||||
wxString str;
|
||||
|
||||
for (const auto& e : qid_sql) {
|
||||
wxLongLong l(e.first);
|
||||
|
||||
str = wxString::Format("%0x%0x\n%s\n", l.GetHi(), l.GetLo(), e.second);
|
||||
file1.Write(str);
|
||||
}
|
||||
file1.Close();
|
||||
}
|
||||
}
|
||||
|
||||
void WaitSample::AddSample(int pid, bool isXidTransation, wxString& btype, const wxString& sample) {
|
||||
//PidWait pw(pid, basetime);;
|
||||
// ïîèñê
|
||||
int pw;
|
||||
auto iter = pids.find(pid);
|
||||
if (iter != pids.end()) {
|
||||
//std::cout << "Found the key " << iter->first << " with the value " << iter->second << "\n";
|
||||
pw = iter->second;
|
||||
}
|
||||
else {
|
||||
pids.emplace(pid, pw);
|
||||
}
|
||||
++chkpids[pid];
|
||||
int bt = GetBackendTypeId(btype);
|
||||
//pw.AddSample(sample, active, timebegiserios, timeendserios);
|
||||
wxStringTokenizer tk(sample, ";", wxTOKEN_DEFAULT);
|
||||
wxString cnt;
|
||||
wxString w;
|
||||
wxString et;
|
||||
while (tk.HasMoreTokens())
|
||||
{
|
||||
wxString et = tk.GetNextToken();
|
||||
wxString cnt = et.AfterLast(':');
|
||||
et = et.BeforeLast(':');
|
||||
wxString tqid = et.AfterLast(':');
|
||||
wxString w = et.BeforeLast(':');
|
||||
// ignore ClientRead out transaction
|
||||
if (w == "Client:ClientRead" && !isXidTransation)
|
||||
continue;
|
||||
int smp_cnt;
|
||||
long long qid;
|
||||
wxSscanf(cnt, "%d", &smp_cnt);
|
||||
wxSscanf(tqid, "%lld", &qid);
|
||||
auto dis_it = wait_disable.find(w);
|
||||
if (dis_it != wait_disable.end()) {
|
||||
continue;
|
||||
}
|
||||
auto iter = wait_id.find(w);
|
||||
int id;
|
||||
if (iter == wait_id.end()) {
|
||||
id = wait_id.size();
|
||||
wait_id.emplace(w, id);
|
||||
wait_id_name.emplace(id, w);
|
||||
//map color
|
||||
long c = 0;
|
||||
auto it2 = wait_idx.find(w);
|
||||
if (it2 == wait_idx.end()) {
|
||||
it2 = wait_idx.find(w.BeforeFirst(':'));
|
||||
if (it2 != wait_idx.end()) {
|
||||
c = it2->second;
|
||||
}
|
||||
}
|
||||
else c = it2->second;
|
||||
colors.push_back(c);
|
||||
//colors
|
||||
}
|
||||
else id = iter->second;
|
||||
|
||||
Sample sa;
|
||||
sa.btime = timebegiserios;
|
||||
sa.etime = timeendserios;
|
||||
sa.wait_id = id;
|
||||
sa.samples = smp_cnt;
|
||||
sa.pid = pid;
|
||||
sa.qid = qid;
|
||||
sa.btype = bt;
|
||||
smp.push_back(sa);
|
||||
//pw.AddSample();
|
||||
}
|
||||
|
||||
}
|
||||
int WaitSample::GetBackendTypeId(wxString backend_type) {
|
||||
int idx = 0;
|
||||
auto it = std::find_if(btype.begin(), btype.end(), [&](const wxString& s) {
|
||||
idx++;
|
||||
return s == backend_type;
|
||||
}
|
||||
);
|
||||
if (it != btype.end()) return idx - 1;
|
||||
btype.push_back(backend_type);
|
||||
return idx;
|
||||
}
|
||||
std::vector<int> tmp_idx_colors;
|
||||
bool compareBySample(const Sample& a, const Sample& b)
|
||||
{
|
||||
if (tmp_idx_colors[a.wait_id] < tmp_idx_colors[b.wait_id])
|
||||
return true;
|
||||
if (tmp_idx_colors[b.wait_id] < tmp_idx_colors[a.wait_id])
|
||||
return false;
|
||||
return a.samples < b.samples;
|
||||
}
|
||||
|
||||
void WaitSample::EndSeriosSample() {
|
||||
int end_index = smp.size();
|
||||
if ((end_index - start_index_serios) < 2) return;
|
||||
// sort
|
||||
//(std::list<int>::iterator it = C.begin(), end = C.end(); it != end; ++it)
|
||||
std::vector<Sample>::iterator it = smp.end();
|
||||
it = it - (end_index - start_index_serios);
|
||||
tmp_idx_colors = colors;
|
||||
std::sort(it, smp.end(), compareBySample);
|
||||
return;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue