[Devel] [PATCH RHEL7 COMMIT] /proc/<pid>/vz_latency: Show maximal allocation latency in the last second.
Konstantin Khorenko
khorenko at virtuozzo.com
Fri Aug 31 13:30:00 MSK 2018
The commit is pushed to "branch-rh7-3.10.0-862.11.6.vz7.71.x-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git
after rh7-3.10.0-862.11.6.vz7.71.6
------>
commit 1914c29eb8754d0d8303ca73298ba6717fba42fe
Author: Andrey Ryabinin <aryabinin at virtuozzo.com>
Date: Fri Aug 31 13:30:00 2018 +0300
/proc/<pid>/vz_latency: Show maximal allocation latency in the last second.
Add to '/proc/<pid>/vz_latency' column with maximal latency task have seen
in the last 2 minutes.
E.g.:
cat /proc/1/vz_latency
Type Total_lat Calls Max (2min)
allocatomic: 0 294 0
alloc: 3000000 43394 0
allocmp: 0 1018 0
AFAICS this changes output format but shouldn't break our the only user of
this interface - pstorage. Accordind to the pstorage code it reads this
file line by line, reads 'Total_lat' and 'Calls' fields and skips to the next
line. Thus adding new field shouldn't break it.
https://jira.sw.ru/browse/PSBM-87797
Signed-off-by: Andrey Ryabinin <aryabinin at virtuozzo.com>
Cc: Pavel Borzenkov <Pavel.Borzenkov at acronis.com>
Reviewed-by: Denis V. Lunev <den at openvz.org>
---
fs/proc/base.c | 28 ++++++++++++++++++++--------
include/linux/kstat.h | 3 ++-
include/linux/vzstat.h | 15 +++++++++++++++
kernel/exit.c | 13 +++++++++++++
kernel/ve/vzstat.c | 2 +-
kernel/ve/vzstat_core.c | 6 +++---
mm/page_alloc.c | 35 +++++++++++++++++++++++++++++++++++
7 files changed, 89 insertions(+), 13 deletions(-)
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 64bbbc387afc..222b4cfeed8e 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -80,6 +80,7 @@
#include <linux/audit.h>
#include <linux/poll.h>
#include <linux/nsproxy.h>
+#include <linux/vzstat.h>
#include <linux/oom.h>
#include <linux/elf.h>
#include <linux/pid_namespace.h>
@@ -580,8 +581,8 @@ static void lastlat_seq_show(struct seq_file *m,
const char *name,
struct kstat_lat_snap_struct *snap)
{
- seq_printf(m, "%-12s %20Lu %20lu\n", name,
- snap->totlat, snap->count);
+ seq_printf(m, "%-12s %20Lu %20lu %20Lu\n", name,
+ snap->totlat, snap->count, get_max_lat(snap));
}
static const char *alloc_descr[] = {
"allocatomic:",
@@ -599,8 +600,8 @@ static int proc_tid_vz_lat(struct seq_file *m, struct pid_namespace *ns,
{
int i;
- seq_printf(m, "%-12s %20s %20s\n",
- "Type", "Total_lat", "Calls");
+ seq_printf(m, "%-12s %20s %20s %20s\n",
+ "Type", "Total_lat", "Calls", "Max (2min)");
for (i = 0; i < ARRAY_SIZE(alloc_types); i++)
lastlat_seq_show(m, alloc_descr[i],
@@ -615,33 +616,44 @@ static int proc_tgid_vz_lat(struct seq_file *m, struct pid_namespace *ns,
unsigned long flags;
u64 lat[ARRAY_SIZE(alloc_types)];
u64 count[ARRAY_SIZE(alloc_types)];
+ u64 maxlats[ARRAY_SIZE(alloc_types)];
for (i = 0; i < ARRAY_SIZE(alloc_types); i++) {
lat[i] = task->alloc_lat[alloc_types[i]].totlat;
count[i] = task->alloc_lat[alloc_types[i]].count;
+ maxlats[i] = get_max_lat(&task->alloc_lat[alloc_types[i]]);
}
if (lock_task_sighand(task, &flags)) {
struct task_struct *t = task;
+ u64 maxlat;
+
while_each_thread(task, t) {
for (i = 0; i < ARRAY_SIZE(alloc_types); i++) {
lat[i] += t->alloc_lat[alloc_types[i]].totlat;
count[i] += t->alloc_lat[alloc_types[i]].count;
+ maxlat = get_max_lat(&t->alloc_lat[alloc_types[i]]);
+ if (maxlats[i] < maxlat)
+ maxlats[i] = maxlat;
}
}
for (i = 0; i < ARRAY_SIZE(alloc_types); i++) {
lat[i] += t->signal->alloc_lat[alloc_types[i]].totlat;
count[i] += t->signal->alloc_lat[alloc_types[i]].count;
+ maxlat = get_max_lat(&t->signal->alloc_lat[alloc_types[i]]);
+ if (maxlats[i] < maxlat)
+ maxlats[i] = maxlat;
+
}
unlock_task_sighand(task, &flags);
}
- seq_printf(m, "%-12s %20s %20s\n",
- "Type", "Total_lat", "Calls");
+ seq_printf(m, "%-12s %20s %20s %20s\n",
+ "Type", "Total_lat", "Calls", "Max (2min)");
for (i = 0; i < ARRAY_SIZE(alloc_types); i++)
- seq_printf(m, "%-12s %20Lu %20Lu\n", alloc_descr[i],
- lat[i], count[i]);
+ seq_printf(m, "%-12s %20Lu %20Lu %20Lu\n", alloc_descr[i],
+ lat[i], count[i], maxlats[i]);
return 0;
}
diff --git a/include/linux/kstat.h b/include/linux/kstat.h
index b268752f2e15..1e42c0317e6e 100644
--- a/include/linux/kstat.h
+++ b/include/linux/kstat.h
@@ -30,8 +30,9 @@ struct kstat_perf_pcpu_struct {
};
struct kstat_lat_snap_struct {
- u64 maxlat, totlat;
+ u64 maxlat[2], totlat;
unsigned long count;
+ unsigned long time[2];
};
struct kstat_lat_pcpu_snap_struct {
diff --git a/include/linux/vzstat.h b/include/linux/vzstat.h
index f1475b2b763a..bfd3b461cb4c 100644
--- a/include/linux/vzstat.h
+++ b/include/linux/vzstat.h
@@ -9,6 +9,7 @@
#ifndef __VZSTAT_H__
#define __VZSTAT_H__
+#include <linux/jiffies.h>
#include <linux/mmzone.h>
#include <linux/kstat.h>
@@ -64,6 +65,20 @@ extern void KSTAT_PERF_ADD(struct kstat_perf_pcpu_struct *ptr, u64 real_time,
sleep_time = current->se.statistics->sum_sleep_runtime - sleep_time; \
KSTAT_PERF_ADD(&kstat_glob.name, start, start - sleep_time);
+#define KSTAT_ALLOC_MAX_LAT_PERIOD (120*HZ)
+
+static inline u64 get_max_lat(struct kstat_lat_snap_struct *snap)
+{
+ int i;
+ u64 max = 0;
+
+ for (i = 0; i < 2; i++) {
+ if (time_before(jiffies, snap->time[i] + KSTAT_ALLOC_MAX_LAT_PERIOD))
+ max = max > snap->maxlat[i] ? max : snap->maxlat[i];
+ }
+ return max;
+}
+
extern void KSTAT_LAT_PCPU_ADD(struct kstat_lat_pcpu_struct *p, u64 dur);
extern void KSTAT_LAT_PCPU_UPDATE(struct kstat_lat_pcpu_struct *p);
diff --git a/kernel/exit.c b/kernel/exit.c
index bf68b87a4d60..c926cca30df3 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -735,6 +735,9 @@ static void check_stack_usage(void)
static inline void check_stack_usage(void) {}
#endif
+void update_maxlat(struct kstat_lat_snap_struct *alloc_lat,
+ u64 lat, unsigned long time);
+
void kstat_add_dying(struct task_struct *tsk)
{
#ifdef CONFIG_VE
@@ -742,8 +745,18 @@ void kstat_add_dying(struct task_struct *tsk)
spin_lock_irq(&tsk->sighand->siglock);
for (i = 0; i < KSTAT_ALLOCSTAT_NR; i++) {
+ int j;
+
tsk->signal->alloc_lat[i].totlat += tsk->alloc_lat[i].totlat;
tsk->signal->alloc_lat[i].count += tsk->alloc_lat[i].count;
+ for (j = 0; j < 2; j++) {
+ if (time_after(tsk->signal->alloc_lat[i].time[j],
+ tsk->alloc_lat[i].time[0])) {
+ update_maxlat(&tsk->alloc_lat[i],
+ tsk->signal->alloc_lat[i].maxlat[j],
+ tsk->signal->alloc_lat[i].time[j]);
+ }
+ }
}
spin_unlock_irq(&tsk->sighand->siglock);
#endif
diff --git a/kernel/ve/vzstat.c b/kernel/ve/vzstat.c
index c8cb0b525aae..370098da3250 100644
--- a/kernel/ve/vzstat.c
+++ b/kernel/ve/vzstat.c
@@ -163,7 +163,7 @@ static void lastlat_seq_show(struct seq_file *m,
struct kstat_lat_snap_struct *snap)
{
seq_printf(m, "%-11s %20Lu %20Lu %20lu\n", name,
- snap->maxlat, snap->totlat, snap->count);
+ snap->maxlat[0], snap->totlat, snap->count);
}
static void avglat_seq_show(struct seq_file *m,
diff --git a/kernel/ve/vzstat_core.c b/kernel/ve/vzstat_core.c
index 2501422d146b..4370c4b5c504 100644
--- a/kernel/ve/vzstat_core.c
+++ b/kernel/ve/vzstat_core.c
@@ -87,11 +87,11 @@ void KSTAT_LAT_PCPU_UPDATE(struct kstat_lat_pcpu_struct *p)
p->last.count += snap.count;
p->last.totlat += snap.totlat;
- if (p->last.maxlat < snap.maxlat)
- p->last.maxlat = snap.maxlat;
+ if (p->last.maxlat[0] < snap.maxlat)
+ p->last.maxlat[0] = snap.maxlat;
}
- m = (p->last.maxlat > p->max_snap ? p->last.maxlat : p->max_snap);
+ m = (p->last.maxlat[0] > p->max_snap ? p->last.maxlat[0] : p->max_snap);
CALC_LOAD(p->avg[0], EXP_1, m);
CALC_LOAD(p->avg[1], EXP_5, m);
CALC_LOAD(p->avg[2], EXP_15, m);
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 9d8c9e4eb970..3d22c4301dc9 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -3214,6 +3214,40 @@ __alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order,
return page;
}
+void update_maxlat(struct kstat_lat_snap_struct *alloc_lat,
+ u64 lat, unsigned long time)
+{
+ if (time_before(time, alloc_lat->time[0] +
+ KSTAT_ALLOC_MAX_LAT_PERIOD/2)) {
+ if (alloc_lat->maxlat[0] < lat) {
+ alloc_lat->maxlat[0] = lat;
+ alloc_lat->time[0] = time;
+ }
+ } else if (time_before(time, alloc_lat->time[0] +
+ KSTAT_ALLOC_MAX_LAT_PERIOD)) {
+ if (alloc_lat->maxlat[1] < lat) {
+ alloc_lat->maxlat[1] = lat;
+ alloc_lat->time[1] = time;
+ }
+ } else if (time_before(time, alloc_lat->time[0] +
+ KSTAT_ALLOC_MAX_LAT_PERIOD*3/2)) {
+ if (alloc_lat->maxlat[1] < lat) {
+ alloc_lat->maxlat[0] = lat;
+ alloc_lat->time[0] = time;
+ } else {
+ alloc_lat->maxlat[0] = alloc_lat->maxlat[1];
+ alloc_lat->time[0] = alloc_lat->time[1];
+ }
+ alloc_lat->maxlat[1] = 0;
+ alloc_lat->time[1] = 0;
+ } else {
+ alloc_lat->maxlat[0] = lat;
+ alloc_lat->time[0] = time;
+ alloc_lat->maxlat[1] = 0;
+ alloc_lat->time[1] = 0;
+ }
+}
+
static void __alloc_collect_stats(gfp_t gfp_mask, unsigned int order,
struct page *page, u64 time)
{
@@ -3241,6 +3275,7 @@ static void __alloc_collect_stats(gfp_t gfp_mask, unsigned int order,
if (in_task()) {
current->alloc_lat[ind].totlat += time;
current->alloc_lat[ind].count++;
+ update_maxlat(¤t->alloc_lat[ind], time, jiffies);
}
if (!page)
More information about the Devel
mailing list