0
0
Fork 0
mirror of https://github.com/matrix-construct/construct synced 2024-11-29 02:02:38 +01:00

ircd::prof: Add interface to pressure stall information on linux platforms.

This commit is contained in:
Jason Volk 2019-10-08 17:01:48 -07:00
parent 8d1f10f8b4
commit c0fc0a1cad
4 changed files with 236 additions and 0 deletions

View file

@ -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
View 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

View file

@ -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

View file

@ -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)
{