mirror of
https://github.com/matrix-construct/construct
synced 2024-11-25 16:22:35 +01:00
ircd::prof: Add interface to pressure stall information on linux platforms.
This commit is contained in:
parent
8d1f10f8b4
commit
c0fc0a1cad
4 changed files with 236 additions and 0 deletions
|
@ -41,6 +41,7 @@ namespace ircd::prof
|
|||
#include "resource.h"
|
||||
#include "times.h"
|
||||
#include "system.h"
|
||||
#include "psi.h"
|
||||
|
||||
// Exports to ircd::
|
||||
namespace ircd
|
||||
|
|
52
include/ircd/prof/psi.h
Normal file
52
include/ircd/prof/psi.h
Normal file
|
@ -0,0 +1,52 @@
|
|||
// Matrix Construct
|
||||
//
|
||||
// Copyright (C) Matrix Construct Developers, Authors & Contributors
|
||||
// Copyright (C) 2016-2019 Jason Volk <jason@zemos.net>
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
// copyright notice and this permission notice is present in all copies. The
|
||||
// full license for this software is available in the LICENSE file.
|
||||
|
||||
#pragma once
|
||||
#define HAVE_IRCD_PROF_PSI_H
|
||||
|
||||
namespace ircd::prof::psi
|
||||
{
|
||||
struct file;
|
||||
struct metric;
|
||||
struct refresh;
|
||||
|
||||
bool refresh(file &) noexcept;
|
||||
|
||||
extern const bool supported;
|
||||
extern file cpu, mem, io;
|
||||
}
|
||||
|
||||
struct ircd::prof::psi::metric
|
||||
{
|
||||
struct avg
|
||||
{
|
||||
seconds window;
|
||||
float pct;
|
||||
};
|
||||
|
||||
std::array<struct avg, 3> avg;
|
||||
microseconds stall;
|
||||
};
|
||||
|
||||
struct ircd::prof::psi::file
|
||||
{
|
||||
string_view name;
|
||||
system_point sampled;
|
||||
metric some, full;
|
||||
};
|
||||
|
||||
#ifndef __linux__
|
||||
inline bool
|
||||
ircd::prof::psi::refresh(metric &)
|
||||
noexcept
|
||||
{
|
||||
return false; // unsupported platform
|
||||
}
|
||||
#endif
|
|
@ -154,6 +154,131 @@ catch(const std::exception &e)
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// prof/psi.h
|
||||
//
|
||||
|
||||
decltype(ircd::prof::psi::supported)
|
||||
ircd::prof::psi::supported
|
||||
{
|
||||
info::kernel_version[0] > 4 ||
|
||||
(info::kernel_version[0] >= 4 && info::kernel_version[1] >= 20)
|
||||
};
|
||||
|
||||
decltype(ircd::prof::psi::cpu)
|
||||
ircd::prof::psi::cpu
|
||||
{
|
||||
"cpu"
|
||||
};
|
||||
|
||||
decltype(ircd::prof::psi::mem)
|
||||
ircd::prof::psi::mem
|
||||
{
|
||||
"memory"
|
||||
};
|
||||
|
||||
decltype(ircd::prof::psi::io)
|
||||
ircd::prof::psi::io
|
||||
{
|
||||
"io"
|
||||
};
|
||||
|
||||
//
|
||||
// prof::psi::metric::refresh
|
||||
//
|
||||
|
||||
bool
|
||||
ircd::prof::psi::refresh(file &file)
|
||||
noexcept try
|
||||
{
|
||||
if(!supported)
|
||||
return false;
|
||||
|
||||
if(unlikely(!file.name))
|
||||
return false;
|
||||
|
||||
thread_local unique_mutable_buffer path_buf
|
||||
{
|
||||
fs::PATH_MAX_LEN
|
||||
};
|
||||
|
||||
const auto &path
|
||||
{
|
||||
fs::path(path_buf, vector_view<const string_view>
|
||||
{
|
||||
"/proc/pressure"_sv, file.name
|
||||
})
|
||||
};
|
||||
|
||||
// Copy value into userspace
|
||||
char buf[256];
|
||||
fs::read_opts opts;
|
||||
opts.aio = false; // can't read /proc through AIO
|
||||
opts.all = false; // don't need posix read-loop; make one read(2) only.
|
||||
const auto &result
|
||||
{
|
||||
fs::read(path, buf, opts)
|
||||
};
|
||||
|
||||
tokens(result, '\n', [&file] // Read each line
|
||||
(const string_view &line)
|
||||
{
|
||||
const auto &[type, vals]
|
||||
{
|
||||
split(line, ' ')
|
||||
};
|
||||
|
||||
// The first token tells us what the metric is; we have allocated
|
||||
// results for the following
|
||||
if(type != "full" && type != "some")
|
||||
return;
|
||||
|
||||
auto &metric
|
||||
{
|
||||
type == "full"?
|
||||
file.full:
|
||||
file.some
|
||||
};
|
||||
|
||||
size_t i(0);
|
||||
tokens(vals, ' ', [&metric, &i] // Read each key=value pair
|
||||
(const string_view &key_val)
|
||||
{
|
||||
const auto &[key, val]
|
||||
{
|
||||
split(key_val, '=')
|
||||
};
|
||||
|
||||
if(key == "total")
|
||||
{
|
||||
metric.stall = lex_cast<microseconds>(val);
|
||||
return;
|
||||
}
|
||||
else if(startswith(key, "avg") && i < metric.avg.size())
|
||||
{
|
||||
metric.avg.at(i).window = lex_cast<seconds>(lstrip(key, "avg"));
|
||||
metric.avg.at(i).pct = lex_cast<float>(val);
|
||||
++i;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
file.sampled = ircd::now<system_point>();
|
||||
return true;
|
||||
}
|
||||
catch(const std::exception &e)
|
||||
{
|
||||
log::error
|
||||
{
|
||||
"Failed to refresh pressure stall information '%s' :%s",
|
||||
file.name,
|
||||
e.what(),
|
||||
};
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// prof/instructions.h
|
||||
|
|
|
@ -1194,6 +1194,64 @@ console_cmd__vg(opt &out, const string_view &line)
|
|||
// prof
|
||||
//
|
||||
|
||||
bool
|
||||
console_cmd__prof__psi(opt &out, const string_view &line)
|
||||
{
|
||||
const auto show_file{[&out]
|
||||
(const string_view &name, prof::psi::file &file)
|
||||
{
|
||||
if(!refresh(file))
|
||||
return;
|
||||
|
||||
char pbuf[48];
|
||||
out
|
||||
<< std::left << name
|
||||
<< " some stall "
|
||||
<< pretty(pbuf, file.some.stall)
|
||||
<< " ("
|
||||
<< file.some.stall.count()
|
||||
<< ')'
|
||||
<< std::endl
|
||||
;
|
||||
for(size_t i(0); i < file.some.avg.size(); i++)
|
||||
out
|
||||
<< std::left << name
|
||||
<< " some "
|
||||
<< std::right << std::setw(3) << file.some.avg.at(i).window.count()
|
||||
<< "s "
|
||||
<< std::right << std::setw(4) << file.some.avg.at(i).pct << '%'
|
||||
<< std::endl
|
||||
;
|
||||
|
||||
out
|
||||
<< std::endl
|
||||
<< std::left << name
|
||||
<< " full stall "
|
||||
<< pretty(pbuf, file.full.stall)
|
||||
<< " ("
|
||||
<< file.full.stall.count()
|
||||
<< ')'
|
||||
<< std::endl
|
||||
;
|
||||
for(size_t i(0); i < file.full.avg.size(); i++)
|
||||
out
|
||||
<< std::left << name
|
||||
<< " full "
|
||||
<< std::right << std::setw(3) << file.full.avg.at(i).window.count()
|
||||
<< "s "
|
||||
<< std::right << std::setw(4) << file.full.avg.at(i).pct << '%'
|
||||
<< std::endl
|
||||
;
|
||||
|
||||
out << std::endl;
|
||||
}};
|
||||
|
||||
show_file("cpu", prof::psi::cpu);
|
||||
show_file("mem", prof::psi::mem);
|
||||
show_file("io ", prof::psi::io);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
console_cmd__prof__vg__start(opt &out, const string_view &line)
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue