lockdep: Add nr_save_trace_invocations counter
PATCH 1/1 lockdep: Add nr_save_trace_invocations counter
NOT FOR INCLUSION
I created this patch as a result of Peter Zilstra's request to get more info from lockdep. This patch is not for inclusion, at least in its present form, because it adds some redunant info to /proc/lockdep_stats
However, some of the fields are new, and it is worth examining, and / or applying if you are looking at the MAX_STACK_TRACE_ENTRIES too big problem.
I generated this patch against a recent tip/master but it applies without conflicts to the latest rt kernel as well. Comments are welcome, in fact they are appreciated.
Quoted 1 line
From
5181c0296dd1549e4e706ff25a4cd81a1d90137dMon Sep 17 00:00:00 2001
From: John Kacur <[email protected]>
Date: Thu, 22 Apr 2010 17:02:42 +0200
Subject: [PATCH] lockdep: Add nr_save_trace_invocations counter
Add the nr_save_trace_invocations counter which counts the number of time save_trace() is invoked when relevant for trace enteries.
This means, those invocations from mark_lock() and add_lock_to_list()
When called from mark_lock() we break it down into LOCKSTATE categories.
--- kernel/lockdep.c | 20 ++++++++++++++++++++ kernel/lockdep_internals.h | 2 ++ kernel/lockdep_proc.c | 23 +++++++++++++++++++++++ 3 files changed, 45 insertions(+), 0 deletions(-)
kernel/lockdep.c +20 -0
@@ -371,6 +371,10 @@ static int verbose(struct lock_class *class)unsigned long nr_stack_trace_entries;static unsigned long stack_trace[MAX_STACK_TRACE_ENTRIES ]; +/* Calls to save_trace() from mark_lock() and add_lock_to_list() only*/ +unsigned long nr_save_trace_invocations; +unsigned long nr_save_trace_invocations_type[LOCK_USAGE_STATES ]; +static int save_trace (struct stack_trace *trace) { trace->nr_entries =0 ;
@@ -410,6 +414,19 @@ static int save_trace(struct stack_trace *trace)return 1 ; } +/* +* This function is only called from mark_lock() and add_lock_to_list() +* which are only called when holding the graph_lock. This counter +* piggybacks off of that lock +*/ +static void inc_save_trace_invocations (enum lock_usage_bit new_bit) +{ + nr_save_trace_invocations++; +if (WARN_ON (new_bit >=LOCK_USAGE_STATES )) +return ; + nr_save_trace_invocations_type[new_bit]++; +} +unsigned int nr_hardirq_chains;unsigned int nr_softirq_chains;unsigned int nr_process_chains;
@@ -449,6 +466,7 @@ static const char *usage_str[] =#define LOCKDEP_STATE (__STATE) __USAGE(__STATE)#include "lockdep_states.h" #undef LOCKDEP_STATE +#undef __USAGE [LOCK_USED] = "INITIAL USE", };
@@ -816,6 +834,7 @@ static int add_lock_to_list(struct lock_class *class, struct lock_class *this,if (!entry)return 0 ; + nr_save_trace_invocations++;if (!save_trace (&entry->trace))return 0 ;
@@ -2615,6 +2634,7 @@ static int mark_lock(struct task_struct *curr, struct held_lock *this,hlock_class (this)->usage_mask |= new_mask; +inc_save_trace_invocations (new_bit);if (!save_trace (hlock_class (this)->usage_traces + new_bit))return 0 ;
kernel/lockdep_internals.h +2 -0
@@ -84,6 +84,8 @@ extern unsigned long nr_list_entries;extern unsigned long nr_lock_chains;extern int nr_chain_hlocks;extern unsigned long nr_stack_trace_entries; +extern unsigned long nr_save_trace_invocations; +extern unsigned long nr_save_trace_invocations_type[LOCK_USAGE_STATES ];extern unsigned int nr_hardirq_chains;extern unsigned int nr_softirq_chains;
kernel/lockdep_proc.c +23 -0
@@ -215,8 +215,24 @@ static void lockdep_stats_debug_show(struct seq_file *m)#endif } +#define __USAGE (__STATE) \ +[LOCK_USED_IN_##__STATE] = "LOCK_USED_IN_"__stringify(__STATE), \ +[LOCK_ENABLED_##__STATE] = "LOCK_ENABLED_"__stringify(__STATE), \ +[LOCK_USED_IN_##__STATE##_READ] = "LOCK_USED_IN_"__stringify(__STATE)"_READ", \ +[LOCK_ENABLED_##__STATE##_READ] = "LOCK_ENABLED_"__stringify(__STATE)"_READ", + +static const char *lockstate_tostr[] = +{ +#define LOCKDEP_STATE(__STATE) __USAGE(__STATE) +#include "lockdep_states.h" +#undef LOCKDEP_STATE +#undef __USAGE + [LOCK_USED ] ="LOCK_USED" , +}; +static int lockdep_stats_show (struct seq_file *m,void *v) { +int bit;struct lock_class *class;unsigned long nr_unused =0 , nr_uncategorized =0 , nr_irq_safe = 0, nr_irq_unsafe = 0,
@@ -307,6 +323,13 @@ static int lockdep_stats_show(struct seq_file *m, void *v) nr_process_chains);seq_printf (m," stack-trace entries: %11lu [max: %lu]\n" , nr_stack_trace_entries,MAX_STACK_TRACE_ENTRIES ); +seq_printf (m," stack-trace invocations: %lu\n" , + nr_save_trace_invocations); + +for (bit=0 ; bit <LOCK_USAGE_STATES ; bit++) +seq_printf (m,"\t%s: %lu\n" , lockstate_tostr[bit], + nr_save_trace_invocations_type[bit]); + seq_printf(m, " combined max dependencies: %11u\n", (nr_hardirq_chains + 1) * (nr_softirq_chains + 1) *
Signature · 1 line
1.6.6.1
Quoted 19 lines · John Kacur
NOT FOR INCLUSION
I created this patch as a result of Peter Zilstra's request to get more info from lockdep. This patch is not for inclusion, at least in its present form, because it adds some redunant info to
/proc/lockdep_statsHowever, some of the fields are new, and it is worth examining, and / or applying if you are looking at the
MAX_STACK_TRACE_ENTRIEStoo big problem.I generated this patch against a recent tip/master but it applies without conflicts to the latest rt kernel as well. Comments are welcome, in fact they are appreciated.
Quoted 1 line
From
5181c0296dd1549e4e706ff25a4cd81a1d90137dMon Sep 17 00:00:00 2001From: John Kacur <[email protected]>
Date: Thu, 22 Apr 2010 17:02:42 +0200
Subject: [PATCH] lockdep: Addnr_save_trace_invocationscounter
Quoted 8 lines
Add the
nr_save_trace_invocationscounter which counts the number of timesave_trace()is invoked when relevant for trace enteries.This means, those invocations from
mark_lock()andadd_lock_to_list()When called from
mark_lock()we break it down into LOCKSTATE categories.Signed-off-by John Kacur <[email protected]>
Just take a rough look at it. I don't think this can give more info.
kernel/lockdep.c static int verbose(struct lock_class *class) · line 375
Quoted 2 lines
kernel/lockdep.c +2
-0+/* Calls to save_trace() from mark_lock() and add_lock_to_list() only*/ +unsigned long nr_save_trace_invocations;
It will equal to nr_list_entries.
Quoted 1 line
+unsigned long nr_save_trace_invocations_type[LOCK_USAGE_STATES];
And each item in this array will equal to nr_hardirq_[un]safe, nr_softirq_[un]safe and such things under lockdep_stats_show(). Right?
Thanks,
Yong
Quoted 112 lines
kernel/lockdep.c +17
-0+static int save_trace (struct stack_trace *trace) { trace->nr_entries =0 ;@@ -410,6 +414,19 @@ static int save_trace(struct stack_trace *trace)return 1 ; } +/* +* This function is only called from mark_lock() and add_lock_to_list() +* which are only called when holding the graph_lock. This counter +* piggybacks off of that lock +*/ +static void inc_save_trace_invocations (enum lock_usage_bit new_bit) +{ + nr_save_trace_invocations++; +if (WARN_ON (new_bit >=LOCK_USAGE_STATES )) +return ; + nr_save_trace_invocations_type[new_bit]++; +} +unsigned int nr_hardirq_chains;unsigned int nr_softirq_chains;unsigned int nr_process_chains;@@ -449,6 +466,7 @@ static const char *usage_str[] =#define LOCKDEP_STATE (__STATE) __USAGE(__STATE)#include "lockdep_states.h" #undef LOCKDEP_STATE +#undef __USAGE [LOCK_USED] = "INITIAL USE", };@@ -816,6 +834,7 @@ static int add_lock_to_list(struct lock_class *class, struct lock_class *this,if (!entry)return 0 ; + nr_save_trace_invocations++;if (!save_trace (&entry->trace))return 0 ;@@ -2615,6 +2634,7 @@ static int mark_lock(struct task_struct *curr, struct held_lock *this,hlock_class (this)->usage_mask |= new_mask; +inc_save_trace_invocations (new_bit);if (!save_trace (hlock_class (this)->usage_traces + new_bit))return 0 ;kernel/lockdep_internals.h +2
-0@@ -84,6 +84,8 @@ extern unsigned long nr_list_entries;extern unsigned long nr_lock_chains;extern int nr_chain_hlocks;extern unsigned long nr_stack_trace_entries; +extern unsigned long nr_save_trace_invocations; +extern unsigned long nr_save_trace_invocations_type[LOCK_USAGE_STATES ];extern unsigned int nr_hardirq_chains;extern unsigned int nr_softirq_chains;kernel/lockdep_proc.c +23
-0@@ -215,8 +215,24 @@ static void lockdep_stats_debug_show(struct seq_file *m)#endif } +#define __USAGE (__STATE) \ +[LOCK_USED_IN_##__STATE] = "LOCK_USED_IN_"__stringify(__STATE), \ +[LOCK_ENABLED_##__STATE] = "LOCK_ENABLED_"__stringify(__STATE), \ +[LOCK_USED_IN_##__STATE##_READ] = "LOCK_USED_IN_"__stringify(__STATE)"_READ", \ +[LOCK_ENABLED_##__STATE##_READ] = "LOCK_ENABLED_"__stringify(__STATE)"_READ", + +static const char *lockstate_tostr[] = +{ +#define LOCKDEP_STATE(__STATE) __USAGE(__STATE) +#include "lockdep_states.h" +#undef LOCKDEP_STATE +#undef __USAGE + [LOCK_USED ] ="LOCK_USED" , +}; +static int lockdep_stats_show (struct seq_file *m,void *v) { +int bit;struct lock_class *class;unsigned long nr_unused =0 , nr_uncategorized =0 , nr_irq_safe = 0, nr_irq_unsafe = 0,@@ -307,6 +323,13 @@ static int lockdep_stats_show(struct seq_file *m, void *v) nr_process_chains);seq_printf (m," stack-trace entries: %11lu [max: %lu]\n" , nr_stack_trace_entries,MAX_STACK_TRACE_ENTRIES ); +seq_printf (m," stack-trace invocations: %lu\n" , + nr_save_trace_invocations); + +for (bit=0 ; bit <LOCK_USAGE_STATES ; bit++) +seq_printf (m,"\t%s: %lu\n" , lockstate_tostr[bit], + nr_save_trace_invocations_type[bit]); + seq_printf(m, " combined max dependencies: %11u\n", (nr_hardirq_chains + 1) * (nr_softirq_chains + 1) *Signature · 7 lines
1.6.6.1 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Quoted 5 lines · Yong Zhang
Quoted 2 lines
+unsigned long nr_save_trace_invocations_type[LOCK_USAGE_STATES];
And each item in this array will equal to nr_hardirq_[un]safe, nr_softirq_[un]safe and such things under
lockdep_stats_show(). Right?
Well, the stats for RECLAIM_FS as missing, so at the very least we need to re-write lockdep_stats_show() to use the lockdep_states.h magic.
Quoted 36 lines · Yong Zhang
Quoted 19 lines · John Kacur
NOT FOR INCLUSION
I created this patch as a result of Peter Zilstra's request to get more info from lockdep. This patch is not for inclusion, at least in its present form, because it adds some redunant info to
/proc/lockdep_statsHowever, some of the fields are new, and it is worth examining, and / or applying if you are looking at the
MAX_STACK_TRACE_ENTRIEStoo big problem.I generated this patch against a recent tip/master but it applies without conflicts to the latest rt kernel as well. Comments are welcome, in fact they are appreciated.
Quoted 1 line
From
5181c0296dd1549e4e706ff25a4cd81a1d90137dMon Sep 17 00:00:00 2001From: John Kacur <[email protected]>
Date: Thu, 22 Apr 2010 17:02:42 +0200
Subject: [PATCH] lockdep: Addnr_save_trace_invocationscounterQuoted 8 lines
Add the
nr_save_trace_invocationscounter which counts the number of timesave_trace()is invoked when relevant for trace enteries.This means, those invocations from
mark_lock()andadd_lock_to_list()When called from
mark_lock()we break it down into LOCKSTATE categories.Signed-off-by John Kacur <[email protected]>Just take a rough look at it. I don't think this can give more info.
kernel/lockdep.c static int verbose(struct lock_class *class) · line 375
Quoted 2 lines
kernel/lockdep.c +2
-0+/* Calls to save_trace() from mark_lock() and add_lock_to_list() only*/ +unsigned long nr_save_trace_invocations;It will equal to
nr_list_entries.
Quoted 8 lines
Quoted 1 line
+unsigned long nr_save_trace_invocations_type[LOCK_USAGE_STATES];
And each item in this array will equal to nr_hardirq_[un]safe, nr_softirq_[un]safe and such things under
lockdep_stats_show(). Right?Thanks,
Yong
Hi Yong
Some context here - Peter asked me to see if we could get some more detailed stats on why some configurations reach the MAX_STACK_TRACE_ENTRIES limit - whether the limit was really too low for some circumstances, or whether we were counting somethings unnecessarily.
In any case, I stamped a big NOT FOR INCLUSION on my mail, because I noticed that somethings were redundant - albeit, obtained in a slightly different manner, however, not everything is redundant.
In particular, nr_save_trace_invocations is NOT equal to nr_list_entries. You will see that reported in /proc/lockdep_stats as
direct dependencies: 8752 [max: 16384]
I have
stack-trace invocations: 10888
from the same run.
Still trying to figure out what the meaning is of that though to be honest.
Here is a portion of the lockdep_stats, with all of the new fields and the redundant ones.
stack-trace invocations: 10888
LOCK_USED_IN_HARDIRQ: 15 LOCK_USED_IN_HARDIRQ_READ: 0 LOCK_ENABLED_HARDIRQ: 543 LOCK_ENABLED_HARDIRQ_READ: 28 LOCK_USED_IN_SOFTIRQ: 0 LOCK_USED_IN_SOFTIRQ_READ: 0 LOCK_ENABLED_SOFTIRQ: 543 LOCK_ENABLED_SOFTIRQ_READ: 28 LOCK_USED_IN_RECLAIM_FS: 5 LOCK_USED_IN_RECLAIM_FS_READ: 0 LOCK_ENABLED_RECLAIM_FS: 95 LOCK_ENABLED_RECLAIM_FS_READ: 8 LOCK_USED: 871
combined max dependencies: 139841
hardirq-safe locks: 15
hardirq-unsafe locks: 543
softirq-safe locks: 0
softirq-unsafe locks: 543
irq-safe locks: 15
irq-unsafe locks: 543
hardirq-read-safe locks: 0
hardirq-read-unsafe locks: 28
softirq-read-safe locks: 0
softirq-read-unsafe locks: 28
irq-read-safe locks: 0
irq-read-unsafe locks: 28
So, you see that all of the reclaim fields are new,
LOCK_USED_IN_RECLAIM_FS: 5 LOCK_USED_IN_RECLAIM_FS_READ: 0
LOCK_ENABLED_RECLAIM_FS: 95 LOCK_ENABLED_RECLAIM_FS_READ: 8
I can create a patch for inclusion that adds the reclaim fields, the question is, is the nr_save_trace_invocations a useful stat for us or not?
Thanks
Quoted 9 lines · John Kacur
Some context here - Peter asked me to see if we could get some more detailed stats on why some configurations reach the
MAX_STACK_TRACE_ENTRIESlimit - whether the limit was really too low for some circumstances, or whether we were counting somethings unnecessarily.In any case, I stamped a big NOT FOR INCLUSION on my mail, because I noticed that somethings were redundant - albeit, obtained in a slightly different manner, however, not everything is redundant.
Quoted 6 lines
In particular,
nr_save_trace_invocationsis NOT equal tonr_list_entries. You will see that reported in/proc/lockdep_statsas
direct dependencies: 8752 [max: 16384]
I have
stack-trace invocations: 10888
from the same run.
I missed that nr_save_trace_invocations is also increased in inc_save_trace_invocations().
So nr_save_trace_invocations = nr_list_entries + sum of nr_save_trace_invocations_type[].
Quoted 35 lines
Still trying to figure out what the meaning is of that though to be honest.
Here is a portion of the
lockdep_stats, with all of the new fields and the redundant ones.stack-trace invocations: 10888
LOCK_USED_IN_HARDIRQ: 15 LOCK_USED_IN_HARDIRQ_READ: 0 LOCK_ENABLED_HARDIRQ: 543 LOCK_ENABLED_HARDIRQ_READ: 28 LOCK_USED_IN_SOFTIRQ: 0 LOCK_USED_IN_SOFTIRQ_READ: 0 LOCK_ENABLED_SOFTIRQ: 543 LOCK_ENABLED_SOFTIRQ_READ: 28 LOCK_USED_IN_RECLAIM_FS: 5 LOCK_USED_IN_RECLAIM_FS_READ: 0 LOCK_ENABLED_RECLAIM_FS: 95 LOCK_ENABLED_RECLAIM_FS_READ: 8 LOCK_USED: 871combined max dependencies: 139841
hardirq-safe locks: 15
hardirq-unsafe locks: 543
softirq-safe locks: 0
softirq-unsafe locks: 543
irq-safe locks: 15
irq-unsafe locks: 543
hardirq-read-safe locks: 0
hardirq-read-unsafe locks: 28
softirq-read-safe locks: 0
softirq-read-unsafe locks: 28
irq-read-safe locks: 0
irq-read-unsafe locks: 28
Quoted 5 lines
So, you see that all of the reclaim fields are new,
LOCK_USED_IN_RECLAIM_FS: 5LOCK_USED_IN_RECLAIM_FS_READ: 0
LOCK_ENABLED_RECLAIM_FS: 95LOCK_ENABLED_RECLAIM_FS_READ: 8
Yes, indeed, data in lockdep_stats_show() is out of time.
So as Peter has said in another thread, we should add sample for RECLAIM_FS.
Quoted 3 lines
I can create a patch for inclusion that adds the reclaim fields, the question is, is the
nr_save_trace_invocationsa useful stat for us or not?
Actually it's just a summation of the samples.
I don't think it's necessary.
Thanks,
Yong
Quoted 9 lines · Peter Zijlstra
Quoted 5 lines · Yong Zhang
Quoted 2 lines
+unsigned long nr_save_trace_invocations_type[LOCK_USAGE_STATES];
And each item in this array will equal to nr_hardirq_[un]safe, nr_softirq_[un]safe and such things under
lockdep_stats_show(). Right?Well, the stats for
RECLAIM_FSas missing, so at the very least we need to re-writelockdep_stats_show()to use thelockdep_states.hmagic.
Yeah, it's a good start point and will keep thing unifying in the future.
Thanks,
Yong
Quoted 12 lines · John Kacur
direct dependencies: 8752 [max: 16384]
I have
stack-trace invocations: 10888
from the same run.Still trying to figure out what the meaning is of that though to be honest.
Here is a portion of the
lockdep_stats, with all of the new fields and the redundant ones.stack-trace invocations: 10888
Quoted 13 lines
LOCK_USED_IN_HARDIRQ: 15
LOCK_USED_IN_HARDIRQ_READ: 0
LOCK_ENABLED_HARDIRQ: 543
LOCK_ENABLED_HARDIRQ_READ: 28
LOCK_USED_IN_SOFTIRQ: 0
LOCK_USED_IN_SOFTIRQ_READ: 0
LOCK_ENABLED_SOFTIRQ: 543
LOCK_ENABLED_SOFTIRQ_READ: 28
LOCK_USED_IN_RECLAIM_FS: 5
LOCK_USED_IN_RECLAIM_FS_READ: 0
LOCK_ENABLED_RECLAIM_FS: 95
LOCK_ENABLED_RECLAIM_FS_READ: 8
LOCK_USED: 871 8752+871+8+95+5+28+543+28+543+15=10888
So you get a stack-trace for each direct-dependency, and you get a stack-trace for each LOCK_state, the sum seems to match the total invocations.
Non of these numbers look strange..
Quoted 27 lines · Peter Zijlstra
Quoted 11 lines · John Kacur
direct dependencies: 8752 [max: 16384] I have
stack-trace invocations: 10888
from the same run.Still trying to figure out what the meaning is of that though to be honest.
Here is a portion of the
lockdep_stats, with all of the new fields and the redundant ones.Quoted 14 lines
stack-trace invocations: 10888
LOCK_USED_IN_HARDIRQ: 15
LOCK_USED_IN_HARDIRQ_READ: 0
LOCK_ENABLED_HARDIRQ: 543
LOCK_ENABLED_HARDIRQ_READ: 28
LOCK_USED_IN_SOFTIRQ: 0
LOCK_USED_IN_SOFTIRQ_READ: 0
LOCK_ENABLED_SOFTIRQ: 543
LOCK_ENABLED_SOFTIRQ_READ: 28
LOCK_USED_IN_RECLAIM_FS: 5
LOCK_USED_IN_RECLAIM_FS_READ: 0
LOCK_ENABLED_RECLAIM_FS: 95
LOCK_ENABLED_RECLAIM_FS_READ: 8
LOCK_USED: 871
Quoted 8 lines
8752+871+8+95+5+28+543+28+543+15=10888
So you get a stack-trace for each direct-dependency, and you get a stack-trace for each
LOCK_state, the sum seems to match the total invocations.Non of these numbers look strange..
As I told Peter privately the laptop that triggered the MAX_STACK_TRACE_ENTRIES every time, has met an
unfortunate early demise. However, I think it was the config - not the hardware. On this machine where the above
numbers come from, I believe I have less debug options configured - but it is running the exact same kernel as
the laptop was. (2.6.33.2-rt13)
--
To unsubscribe from this list: send the line "unsubscribe linux-rt-users" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Quoted 9 lines · John Kacur
Quoted 8 lines
8752+871+8+95+5+28+543+28+543+15=10888
So you get a stack-trace for each direct-dependency, and you get a stack-trace for each
LOCK_state, the sum seems to match the total invocations.Non of these numbers look strange..
Quoted 7 lines
As I told Peter privately the laptop that triggered the
MAX_STACK_TRACE_ENTRIESevery time, has met an
unfortunate early demise. However, I think it was the config - not the hardware. On this machine where the above
numbers come from, I believe I have less debug options configured - but it is running the exact same kernel as
the laptop was. (2.6.33.2-rt13)
Through a rough computation:
MAX_STACK_TRACE_ENTRIES/10888 = 24
That means the average stack deepth is about 24.
So I'm thinking if we can take a check on the biggest deepth? Could this make sense?
Thanks,
Yong
Quoted 18 lines · Yong Zhang
Quoted 9 lines · John Kacur
Quoted 8 lines
8752+871+8+95+5+28+543+28+543+15=10888
So you get a stack-trace for each direct-dependency, and you get a stack-trace for each
LOCK_state, the sum seems to match the total invocations.Non of these numbers look strange..
Quoted 7 lines
As I told Peter privately the laptop that triggered the
MAX_STACK_TRACE_ENTRIESevery time, has met an
unfortunate early demise. However, I think it was the config - not the hardware. On this machine where the above
numbers come from, I believe I have less debug options configured - but it is running the exact same kernel as
the laptop was. (2.6.33.2-rt13)
Quoted 6 lines
Through a rough computation:
MAX_STACK_TRACE_ENTRIES/10888 = 24
That means the average stack deepth is about 24.
So I'm thinking if we can take a check on the biggest deepth? Could this make sense?
Hi Yong, yes that makes sense, I'll see if I can provide a patch for that too.
Thanks
PATCH 1/1 lockdep: reduce stack_trace usage
In reply to John KacurQuoted 10 lines · John Kacur
Quoted 2 lines
Non of these numbers look strange..
As I told Peter privately the laptop that triggered the
MAX_STACK_TRACE_ENTRIESevery time, has met an
unfortunate early demise. However, I think it was the config - not the hardware. On this machine where the above
numbers come from, I believe I have less debug options configured - but it is running the exact same kernel as
the laptop was. (2.6.33.2-rt13)
Hi John,
(checking mail at home).
I find some place which can be hacked. Below is the patch. But I don't even compile it. Can you test it to see if it can smooth your problem.
---cut here ---
Quoted 1 line
From
6b9d513b7c417c0805ef0acc1cb3227bddba0889Mon Sep 17 00:00:00 2001
From: Yong Zhang <[email protected]>
Date: Fri, 23 Apr 2010 21:13:54 +0800
Subject: [PATCH] lockdep: reduce stack_trace usage
When calling check_prevs_add(), if all validations passed add_lock_to_list() will add new lock to dependency tree and alloc stack_trace for each list_entry. But at this time, we are always on the same stack, so stack_trace for each list_entry has the same value. This is redundant and eats up lots of memory which could lead to warning on low MAX_STACK_TRACE_ENTRIES.
Using one copy of stack_trace instead.
--- kernel/lockdep.c | 20 ++++++++++++-------- 1 files changed, 12 insertions(+), 8 deletions(-)
kernel/lockdep.c +12 -8
@@ -818,7 +818,8 @@ static struct lock_list *alloc_list_entry(void)* Add a new dependency to the head of the list: */ static int add_lock_to_list (struct lock_class *class,struct lock_class *this, -struct list_head *head,unsigned long ip,int distance) +struct list_head *head,unsigned long ip, +int distance,struct stack_trace *trace) {struct lock_list *entry;/*
@@ -829,11 +830,9 @@ static int add_lock_to_list(struct lock_class *class, struct lock_class *this,if (!entry)return 0 ; -if (!save_trace (&entry->trace)) -return 0 ; - entry->class = this; entry->distance = distance; + entry->trace = *trace;/* * Since we never remove from the dependency list, the list can * be walked lockless by other CPUs, it's only allocation
@@ -1635,7 +1634,7 @@ check_deadlock(struct task_struct *curr, struct held_lock *next,*/ static int check_prev_add (struct task_struct *curr,struct held_lock *prev, -struct held_lock *next,int distance) +struct held_lock *next,int distance,struct stack_trace *trace) {struct lock_list *entry;int ret;
@@ -1694,14 +1693,14 @@ check_prev_add(struct task_struct *curr, struct held_lock *prev,*/ ret =add_lock_to_list (hlock_class (prev),hlock_class (next), &hlock_class (prev)->locks_after, - next->acquire_ip, distance); + next->acquire_ip, distance, trace);if (!ret)return 0 ; ret =add_lock_to_list (hlock_class (next),hlock_class (prev), &hlock_class (next)->locks_before, - next->acquire_ip, distance); + next->acquire_ip, distance, trace);if (!ret)return 0 ;
@@ -1732,6 +1731,7 @@ check_prevs_add(struct task_struct *curr, struct held_lock *next) {int depth = curr->lockdep_depth;struct held_lock *hlock; +struct stack_trace trace;/* * Debugging checks.
@@ -1748,6 +1748,9 @@ check_prevs_add(struct task_struct *curr, struct held_lock *next) curr->held_locks[depth-1].irq_context) goto out_bug; +if (!save_trace (&trace)) +return 0 ; +for (;;) {int distance = curr->lockdep_depth - depth +1 ; hlock = curr->held_locks + depth-1 ;
@@ -1756,7 +1759,8 @@ check_prevs_add(struct task_struct *curr, struct held_lock *next)* added: */ if (hlock->read !=2 ) { -if (!check_prev_add (curr, hlock, next, distance)) +if (!check_prev_add (curr, hlock, next, + distance, &trace))return 0 ;/* * Stop after the first non-trylock entry,
Signature · 1 line
1.6.3.3
Re: [PATCH] lockdep: reduce stack_trace usage
Quoted 13 lines · Yong Zhang
Hi John,
(checking mail at home).
I find some place which can be hacked. Below is the patch. But I don't even compile it. Can you test it to see if it can smooth your problem.---cut here ---
Quoted 1 line
From
6b9d513b7c417c0805ef0acc1cb3227bddba0889Mon Sep 17 00:00:00 2001From: Yong Zhang <[email protected]>
Date: Fri, 23 Apr 2010 21:13:54 +0800
Subject: [PATCH] lockdep: reducestack_traceusage
Quoted 8 lines
When calling
check_prevs_add(), if all validations passedadd_lock_to_list()will add new lock to dependency tree and allocstack_tracefor eachlist_entry. But at this time, we are always on the same stack, sostack_tracefor eachlist_entryhas the same value. This is redundant and eats up lots of memory which could lead to warning on lowMAX_STACK_TRACE_ENTRIES.
Using one copy ofstack_traceinstead.
With the following test patch running on my machine:
Quoted 1 line
cat
/proc/lockdep_stats
lock-classes: 564 [max: 8191]
direct dependencies: 2626 [max: 16384]
indirect dependencies: 5951
all direct dependencies: 48226
dependency chains: 2576 [max: 32768]
dependency chain hlocks: 6740 [max: 163840]
in-hardirq chains: 18
in-softirq chains: 163
in-process chains: 2395
stack-trace entries: 63076 [max: 262144]
duplicated stack-trace entries: 7592 <=========
combined max dependencies: 7465936
hardirq-safe locks: 30
hardirq-unsafe locks: 380
softirq-safe locks: 82
softirq-unsafe locks: 305
irq-safe locks: 90
irq-unsafe locks: 380
hardirq-read-safe locks: 0
hardirq-read-unsafe locks: 51 softirq-read-safe locks: 11 softirq-read-unsafe locks: 40 irq-read-safe locks: 11 irq-read-unsafe locks: 51
uncategorized locks: 112
unused locks: 1
max locking depth: 15
max bfs queue depth: 83
debug_locks: 1
We can see that about 12% stack_trace usage can be reduced.
Thanks,
Yong
------lockdep-duplicated-stack_trace-detect.patch------
kernel/lockdep.c +23 -3
@@ -369,6 +369,7 @@ static int verbose(struct lock_class *class)* addresses. Protected by the graph_lock. */ unsigned long nr_stack_trace_entries; +unsigned long nr_duplicated_stack_trace_entries;static unsigned long stack_trace[MAX_STACK_TRACE_ENTRIES ];static int save_trace (struct stack_trace *trace)
@@ -818,9 +819,14 @@ static struct lock_list *alloc_list_entry(void)* Add a new dependency to the head of the list: */ static int add_lock_to_list (struct lock_class *class,struct lock_class *this, -struct list_head *head,unsigned long ip,int distance) +struct list_head *head,unsigned long ip, +int distance,struct held_lock *next) {struct lock_list *entry; +static struct held_lock *hlock; +static struct stack_trace trace; +int i; +/* * Lock not present yet - get a new dependency struct and * add it to the list:
@@ -834,6 +840,20 @@ static int add_lock_to_list(struct lock_class *class, struct lock_class *this, entry->class = this; entry->distance = distance; + +if (hlock != next) { + hlock = next; + trace = entry->trace; + }else if (trace.nr_entries == entry->trace.nr_entries && + trace.max_entries == entry->trace.max_entries) { +/* start from 2 to skip the stack introduced by lockdep */ +for (i=2 ; i<trace.nr_entries; i++) { +if (trace.entries[i] != entry->trace.entries[i]) + goto no_duplicated; + } + nr_duplicated_stack_trace_entries += trace.nr_entries; + } +no_duplicated:/* * Since we never remove from the dependency list, the list can * be walked lockless by other CPUs, it's only allocation
@@ -1694,14 +1714,14 @@ check_prev_add(struct task_struct *curr, struct held_lock *prev,*/ ret =add_lock_to_list (hlock_class (prev),hlock_class (next), &hlock_class (prev)->locks_after, - next->acquire_ip, distance); + next->acquire_ip, distance, next);if (!ret)return 0 ; ret =add_lock_to_list (hlock_class (next),hlock_class (prev), &hlock_class (next)->locks_before, - next->acquire_ip, distance); + next->acquire_ip, distance, next);if (!ret)return 0 ;
kernel/lockdep_internals.h +1 -0
@@ -84,6 +84,7 @@ extern unsigned long nr_list_entries;extern unsigned long nr_lock_chains;extern int nr_chain_hlocks;extern unsigned long nr_stack_trace_entries; +extern unsigned long nr_duplicated_stack_trace_entries;extern unsigned int nr_hardirq_chains;extern unsigned int nr_softirq_chains;
kernel/lockdep_proc.c +2 -0
@@ -307,6 +307,8 @@ static int lockdep_stats_show(struct seq_file *m, void *v) nr_process_chains);seq_printf (m," stack-trace entries: %11lu [max: %lu]\n" , nr_stack_trace_entries,MAX_STACK_TRACE_ENTRIES ); +seq_printf (m," duplicated stack-trace entries:%11lu\n" , + nr_duplicated_stack_trace_entries); seq_printf(m, " combined max dependencies: %11u\n", (nr_hardirq_chains + 1) * (nr_softirq_chains + 1) *
Quoted 92 lines
Signed-off-by Yong Zhang <[email protected]>Cc Peter Zijlstra <[email protected]>Cc Ingo Molnar <[email protected]>Cc David S. Miller <[email protected]>--- kernel/lockdep.c | 20 ++++++++++++-------- 1 files changed, 12 insertions(+), 8 deletions(-)kernel/lockdep.c +12
-8@@ -818,7 +818,8 @@ static struct lock_list *alloc_list_entry(void)* Add a new dependency to the head of the list: */ static int add_lock_to_list (struct lock_class *class,struct lock_class *this, -struct list_head *head,unsigned long ip,int distance) +struct list_head *head,unsigned long ip, +int distance,struct stack_trace *trace) {struct lock_list *entry;/* @@ -829,11 +830,9 @@ static int add_lock_to_list(struct lock_class *class, struct lock_class *this,if (!entry)return 0 ; -if (!save_trace (&entry->trace)) -return 0 ; - entry->class = this; entry->distance = distance; + entry->trace = *trace;/* * Since we never remove from the dependency list, the list can * be walked lockless by other CPUs, it's only allocation @@ -1635,7 +1634,7 @@ check_deadlock(struct task_struct *curr, struct held_lock *next,*/ static int check_prev_add (struct task_struct *curr,struct held_lock *prev, -struct held_lock *next,int distance) +struct held_lock *next,int distance,struct stack_trace *trace) {struct lock_list *entry;int ret;@@ -1694,14 +1693,14 @@ check_prev_add(struct task_struct *curr, struct held_lock *prev,*/ ret =add_lock_to_list (hlock_class (prev),hlock_class (next), &hlock_class (prev)->locks_after, - next->acquire_ip, distance); + next->acquire_ip, distance, trace);if (!ret)return 0 ; ret =add_lock_to_list (hlock_class (next),hlock_class (prev), &hlock_class (next)->locks_before, - next->acquire_ip, distance); + next->acquire_ip, distance, trace);if (!ret)return 0 ;@@ -1732,6 +1731,7 @@ check_prevs_add(struct task_struct *curr, struct held_lock *next) {int depth = curr->lockdep_depth;struct held_lock *hlock; +struct stack_trace trace;/* * Debugging checks. @@ -1748,6 +1748,9 @@ check_prevs_add(struct task_struct *curr, struct held_lock *next) curr->held_locks[depth-1].irq_context) goto out_bug; +if (!save_trace (&trace)) +return 0 ; +for (;;) {int distance = curr->lockdep_depth - depth +1 ; hlock = curr->held_locks + depth-1 ;@@ -1756,7 +1759,8 @@ check_prevs_add(struct task_struct *curr, struct held_lock *next)* added: */ if (hlock->read !=2 ) { -if (!check_prev_add (curr, hlock, next, distance)) +if (!check_prev_add (curr, hlock, next, + distance, &trace))return 0 ;/* * Stop after the first non-trylock entry, Signature · 1 line
1.6.3.3
Re: [PATCH] lockdep: reduce stack_trace usage
In reply to Yong ZhangQuoted 5 lines · Yong Zhang
From
6b9d513b7c417c0805ef0acc1cb3227bddba0889Mon Sep 17 00:00:00 2001
From: Yong Zhang <[email protected]>
Date: Fri, 23 Apr 2010 21:13:54 +0800
Subject: [PATCH] lockdep: reducestack_traceusage
Quoted 8 lines
When calling
check_prevs_add(), if all validations passedadd_lock_to_list()will add new lock to dependency tree and allocstack_tracefor eachlist_entry. But at this time, we are always on the same stack, sostack_tracefor eachlist_entryhas the same value. This is redundant and eats up lots of memory which could lead to warning on lowMAX_STACK_TRACE_ENTRIES.
Using one copy ofstack_traceinstead.
OK, I like the idea, but I'm a little confused as to why you pull save_trace() up two functions, from what I can see we can now end up saving a trace where we previously would not have done one (the whole recursive lock mess.
So please respin this with save_trace() in check_prev_add() right before the first add_lock_to_list().
Quoted 89 lines
Signed-off-by Yong Zhang <[email protected]>Cc Peter Zijlstra <[email protected]>Cc Ingo Molnar <[email protected]>Cc David S. Miller <[email protected]>--- kernel/lockdep.c | 20 ++++++++++++-------- 1 files changed, 12 insertions(+), 8 deletions(-)kernel/lockdep.c +12
-8@@ -818,7 +818,8 @@ static struct lock_list *alloc_list_entry(void)* Add a new dependency to the head of the list: */ static int add_lock_to_list (struct lock_class *class,struct lock_class *this, -struct list_head *head,unsigned long ip,int distance) +struct list_head *head,unsigned long ip, +int distance,struct stack_trace *trace) {struct lock_list *entry;/* @@ -829,11 +830,9 @@ static int add_lock_to_list(struct lock_class *class, struct lock_class *this,if (!entry)return 0 ; -if (!save_trace (&entry->trace)) -return 0 ; - entry->class = this; entry->distance = distance; + entry->trace = *trace;/* * Since we never remove from the dependency list, the list can * be walked lockless by other CPUs, it's only allocation @@ -1635,7 +1634,7 @@ check_deadlock(struct task_struct *curr, struct held_lock *next,*/ static int check_prev_add (struct task_struct *curr,struct held_lock *prev, -struct held_lock *next,int distance) +struct held_lock *next,int distance,struct stack_trace *trace) {struct lock_list *entry;int ret;@@ -1694,14 +1693,14 @@ check_prev_add(struct task_struct *curr, struct held_lock *prev,*/ ret =add_lock_to_list (hlock_class (prev),hlock_class (next), &hlock_class (prev)->locks_after, - next->acquire_ip, distance); + next->acquire_ip, distance, trace);if (!ret)return 0 ; ret =add_lock_to_list (hlock_class (next),hlock_class (prev), &hlock_class (next)->locks_before, - next->acquire_ip, distance); + next->acquire_ip, distance, trace);if (!ret)return 0 ;@@ -1732,6 +1731,7 @@ check_prevs_add(struct task_struct *curr, struct held_lock *next) {int depth = curr->lockdep_depth;struct held_lock *hlock; +struct stack_trace trace;/* * Debugging checks. @@ -1748,6 +1748,9 @@ check_prevs_add(struct task_struct *curr, struct held_lock *next) curr->held_locks[depth-1].irq_context) goto out_bug; +if (!save_trace (&trace)) +return 0 ; +for (;;) {int distance = curr->lockdep_depth - depth +1 ; hlock = curr->held_locks + depth-1 ;@@ -1756,7 +1759,8 @@ check_prevs_add(struct task_struct *curr, struct held_lock *next)* added: */ if (hlock->read !=2 ) { -if (!check_prev_add (curr, hlock, next, distance)) +if (!check_prev_add (curr, hlock, next, + distance, &trace))return 0 ;/* * Stop after the first non-trylock entry,
Re: [PATCH] lockdep: reduce stack_trace usage
Quoted 2 lines · Peter Zijlstra
OK, I like the idea, but I'm a little confused as to why you pull
save_trace()up two functions,
I also want to avoid adding redundant trace in case of trylock. On my machine, I catched about 150 trylock dependences.
Quoted 3 lines
from what I can see we can now end up
saving a trace where we previously would not have done one (the whole recursive lock mess.
Oh, Yes, this patch will not give result as expected. Thank you for pointing it. I will respin it in V2.
Quoted 3 lines
So please respin this with
save_trace()incheck_prev_add()right before the firstadd_lock_to_list().
No problem.
BTW, in case of trylock dependence, I will let check_prevs_add() carry a flag to check_prev_add(). Thus, we can save more redundant trace. How do you think about it?
Thanks,
Yong
Quoted 90 lines
Quoted 90 lines
Signed-off-by Yong Zhang <[email protected]>Cc Peter Zijlstra <[email protected]>Cc Ingo Molnar <[email protected]>Cc David S. Miller <[email protected]>--- kernel/lockdep.c | 20 ++++++++++++-------- 1 files changed, 12 insertions(+), 8 deletions(-)kernel/lockdep.c +12
-8@@ -818,7 +818,8 @@ static struct lock_list *alloc_list_entry(void)* Add a new dependency to the head of the list: */ static int add_lock_to_list (struct lock_class *class,struct lock_class *this, -struct list_head *head,unsigned long ip,int distance) +struct list_head *head,unsigned long ip, +int distance,struct stack_trace *trace) {struct lock_list *entry;/* @@ -829,11 +830,9 @@ static int add_lock_to_list(struct lock_class *class, struct lock_class *this,if (!entry)return 0 ; -if (!save_trace (&entry->trace)) -return 0 ; - entry->class = this; entry->distance = distance; + entry->trace = *trace;/* * Since we never remove from the dependency list, the list can * be walked lockless by other CPUs, it's only allocation @@ -1635,7 +1634,7 @@ check_deadlock(struct task_struct *curr, struct held_lock *next,*/ static int check_prev_add (struct task_struct *curr,struct held_lock *prev, -struct held_lock *next,int distance) +struct held_lock *next,int distance,struct stack_trace *trace) {struct lock_list *entry;int ret;@@ -1694,14 +1693,14 @@ check_prev_add(struct task_struct *curr, struct held_lock *prev,*/ ret =add_lock_to_list (hlock_class (prev),hlock_class (next), &hlock_class (prev)->locks_after, - next->acquire_ip, distance); + next->acquire_ip, distance, trace);if (!ret)return 0 ; ret =add_lock_to_list (hlock_class (next),hlock_class (prev), &hlock_class (next)->locks_before, - next->acquire_ip, distance); + next->acquire_ip, distance, trace);if (!ret)return 0 ;@@ -1732,6 +1731,7 @@ check_prevs_add(struct task_struct *curr, struct held_lock *next) {int depth = curr->lockdep_depth;struct held_lock *hlock; +struct stack_trace trace;/* * Debugging checks. @@ -1748,6 +1748,9 @@ check_prevs_add(struct task_struct *curr, struct held_lock *next) curr->held_locks[depth-1].irq_context) goto out_bug; +if (!save_trace (&trace)) +return 0 ; +for (;;) {int distance = curr->lockdep_depth - depth +1 ; hlock = curr->held_locks + depth-1 ;@@ -1756,7 +1759,8 @@ check_prevs_add(struct task_struct *curr, struct held_lock *next)* added: */ if (hlock->read !=2 ) { -if (!check_prev_add (curr, hlock, next, distance)) +if (!check_prev_add (curr, hlock, next, + distance, &trace))return 0 ;/* * Stop after the first non-trylock entry,
PATCH v2 1/1 lockdep: reduce stack_trace usage
In reply to Yong ZhangQuoted 1 line
From
04395389820e89c0bd4bb57b939ec1882e0bb5daMon Sep 17 00:00:00 2001
From: Yong Zhang <[email protected]>
Date: Tue, 4 May 2010 14:16:48 +0800
Subject: [PATCH] lockdep: Reduce stack_trace usage
When calling check_prevs_add(), if all validations passed add_lock_to_list() will add new lock to dependency tree and alloc stack_trace for each list_entry. But at this time, we are always on the same stack, so stack_trace for each list_entry has the same value. This is redundant and eats up lots of memory which could lead to warning on low MAX_STACK_TRACE_ENTRIES.
Using one copy of stack_trace instead.
V2: As suggested by Peter Zijlstra, move save_trace() from
check_prevs_add() to check_prev_add().
Add tracking for trylock dependence which is also redundant.
--- kernel/lockdep.c | 22 ++++++++++++++-------- 1 files changed, 14 insertions(+), 8 deletions(-)
kernel/lockdep.c +14 -8
@@ -818,7 +818,8 @@ static struct lock_list *alloc_list_entry(void)* Add a new dependency to the head of the list: */ static int add_lock_to_list (struct lock_class *class,struct lock_class *this, -struct list_head *head,unsigned long ip,int distance) +struct list_head *head,unsigned long ip, +int distance,struct stack_trace *trace) {struct lock_list *entry;/*
@@ -829,11 +830,9 @@ static int add_lock_to_list(struct lock_class *class, struct lock_class *this,if (!entry)return 0 ; -if (!save_trace (&entry->trace)) -return 0 ; - entry->class = this; entry->distance = distance; + entry->trace = *trace;/* * Since we never remove from the dependency list, the list can * be walked lockless by other CPUs, it's only allocation
@@ -1635,12 +1634,13 @@ check_deadlock(struct task_struct *curr, struct held_lock *next,*/ static int check_prev_add (struct task_struct *curr,struct held_lock *prev, -struct held_lock *next,int distance) +struct held_lock *next,int distance,int trylock_loop) {struct lock_list *entry;int ret;struct lock_list this;struct lock_list *uninitialized_var (target_entry ); +static struct stack_trace trace;/* * Prove that the new <prev> -> <next> dependency would not
@@ -1688,20 +1688,23 @@ check_prev_add(struct task_struct *curr, struct held_lock *prev, } } +if (!trylock_loop && !save_trace (&trace)) +return 0 ; +/* * Ok, all validations passed, add the new lock * to the previous lock's dependency list: */ ret =add_lock_to_list (hlock_class (prev),hlock_class (next), &hlock_class (prev)->locks_after, - next->acquire_ip, distance); + next->acquire_ip, distance, &trace);if (!ret)return 0 ; ret =add_lock_to_list (hlock_class (next),hlock_class (prev), &hlock_class (next)->locks_before, - next->acquire_ip, distance); + next->acquire_ip, distance, &trace);if (!ret)return 0 ;
@@ -1731,6 +1734,7 @@ static int check_prevs_add(struct task_struct *curr, struct held_lock *next) { int depth = curr->lockdep_depth; +int trylock_loop =0 ;struct held_lock *hlock;/*
@@ -1756,7 +1760,8 @@ check_prevs_add(struct task_struct *curr, struct held_lock *next)* added: */ if (hlock->read !=2 ) { -if (!check_prev_add (curr, hlock, next, distance)) +if (!check_prev_add (curr, hlock, next, + distance, trylock_loop))return 0 ;/* * Stop after the first non-trylock entry,
@@ -1779,6 +1784,7 @@ check_prevs_add(struct task_struct *curr, struct held_lock *next)if (curr->held_locks[depth].irq_context != curr->held_locks[depth-1 ].irq_context)break ; + trylock_loop =1 ; }return 1 ; out_bug:
Signature · 1 line
1.6.3.3
Re: [PATCH V2] lockdep: reduce stack_trace usage
Quoted 5 lines · Yong Zhang
From
04395389820e89c0bd4bb57b939ec1882e0bb5daMon Sep 17 00:00:00 2001
From: Yong Zhang <[email protected]>
Date: Tue, 4 May 2010 14:16:48 +0800
Subject: [PATCH] lockdep: Reducestack_traceusage
Quoted 8 lines
When calling
check_prevs_add(), if all validations passedadd_lock_to_list()will add new lock to dependency tree and allocstack_tracefor eachlist_entry. But at this time, we are always on the same stack, sostack_tracefor eachlist_entryhas the same value. This is redundant and eats up lots of memory which could lead to warning on lowMAX_STACK_TRACE_ENTRIES.
Using one copy ofstack_traceinstead.
Right, this looks like it ought to do as intended.
I added the below snipped because I know I'll fail to remember and that 'static' qualifier is fairly easy to miss.
Thanks!
---
kernel/lockdep.c +7 -0
@@ -1627,6 +1627,13 @@ check_prev_add(struct task_struct *curr,int ret;struct lock_list this;struct lock_list *uninitialized_var (target_entry ); +/* +* Static variable, serialized by the graph_lock(). +* +* We use this static variable to save the stack trace in case +* we call into this function multiple times due to encountering +* trylocks in the held lock stack. +*/ static struct stack_trace trace;/*
Re: [PATCH V2] lockdep: reduce stack_trace usage
Quoted 4 lines · Peter Zijlstra
Right, this looks like it ought to do as intended.
I added the below snipped because I know I'll fail to remember and that 'static' qualifier is fairly easy to miss.
OK. Thanks for your comments.
BTW, do you need me resend the patch with your comments in?
Thanks,
Yong
Re: [PATCH V2] lockdep: reduce stack_trace usage
Quoted 9 lines · Yong Zhang
Quoted 4 lines · Peter Zijlstra
Right, this looks like it ought to do as intended.
I added the below snipped because I know I'll fail to remember and that 'static' qualifier is fairly easy to miss.
OK. Thanks for your comments.
BTW, do you need me resend the patch with your comments in?
No, I've got it.
Re: [PATCH V2] lockdep: reduce stack_trace usage
Quoted 3 lines · Peter Zijlstra
Quoted 1 line
BTW, do you need me resend the patch with your comments in?
No, I've got it.
That's great. Thank you. :)
[tip:core/locking] lockdep: Reduce stack_trace usage
In reply to Yong ZhangCommit-ID: 4726f2a617ebd868a4fdeb5679613b897e5f1676 Gitweb: http://git.kernel.org/tip/4726f2a617ebd868a4fdeb5679613b897e5f1676 Author: Yong Zhang <[email protected]> AuthorDate: Tue, 4 May 2010 14:16:48 +0800 Committer: Ingo Molnar <[email protected]> CommitDate: Fri, 7 May 2010 11:27:26 +0200
lockdep: Reduce stack_trace usage
When calling check_prevs_add(), if all validations passed add_lock_to_list() will add new lock to dependency tree and alloc stack_trace for each list_entry.
But at this time, we are always on the same stack, so stack_trace for each list_entry has the same value. This is redundant and eats up lots of memory which could lead to warning on low MAX_STACK_TRACE_ENTRIES.
Use one copy of stack_trace instead.
V2: As suggested by Peter Zijlstra, move save_trace() from
check_prevs_add() to check_prev_add().
Add tracking for trylock dependence which is also redundant.
LKML-Reference: <[email protected]>
--- kernel/lockdep.c | 29 +++++++++++++++++++++-------- 1 files changed, 21 insertions(+), 8 deletions(-)
kernel/lockdep.c +21 -8
@@ -805,7 +805,8 @@ static struct lock_list *alloc_list_entry(void)* Add a new dependency to the head of the list: */ static int add_lock_to_list (struct lock_class *class,struct lock_class *this, -struct list_head *head,unsigned long ip,int distance) +struct list_head *head,unsigned long ip, +int distance,struct stack_trace *trace) {struct lock_list *entry;/*
@@ -816,11 +817,9 @@ static int add_lock_to_list(struct lock_class *class, struct lock_class *this,if (!entry)return 0 ; -if (!save_trace (&entry->trace)) -return 0 ; - entry->class = this; entry->distance = distance; + entry->trace = *trace;/* * Since we never remove from the dependency list, the list can * be walked lockless by other CPUs, it's only allocation
@@ -1622,12 +1621,20 @@ check_deadlock(struct task_struct *curr, struct held_lock *next,*/ static int check_prev_add (struct task_struct *curr,struct held_lock *prev, -struct held_lock *next,int distance) +struct held_lock *next,int distance,int trylock_loop) {struct lock_list *entry;int ret;struct lock_list this;struct lock_list *uninitialized_var (target_entry ); +/* +* Static variable, serialized by the graph_lock(). +* +* We use this static variable to save the stack trace in case +* we call into this function multiple times due to encountering +* trylocks in the held lock stack. +*/ +static struct stack_trace trace;/* * Prove that the new <prev> -> <next> dependency would not
@@ -1675,20 +1682,23 @@ check_prev_add(struct task_struct *curr, struct held_lock *prev, } } +if (!trylock_loop && !save_trace (&trace)) +return 0 ; +/* * Ok, all validations passed, add the new lock * to the previous lock's dependency list: */ ret =add_lock_to_list (hlock_class (prev),hlock_class (next), &hlock_class (prev)->locks_after, - next->acquire_ip, distance); + next->acquire_ip, distance, &trace);if (!ret)return 0 ; ret =add_lock_to_list (hlock_class (next),hlock_class (prev), &hlock_class (next)->locks_before, - next->acquire_ip, distance); + next->acquire_ip, distance, &trace);if (!ret)return 0 ;
@@ -1718,6 +1728,7 @@ static int check_prevs_add(struct task_struct *curr, struct held_lock *next) { int depth = curr->lockdep_depth; +int trylock_loop =0 ;struct held_lock *hlock;/*
@@ -1743,7 +1754,8 @@ check_prevs_add(struct task_struct *curr, struct held_lock *next)* added: */ if (hlock->read !=2 ) { -if (!check_prev_add (curr, hlock, next, distance)) +if (!check_prev_add (curr, hlock, next, + distance, trylock_loop))return 0 ;/* * Stop after the first non-trylock entry,
@@ -1766,6 +1778,7 @@ check_prevs_add(struct task_struct *curr, struct held_lock *next)if (curr->held_locks[depth].irq_context != curr->held_locks[depth-1 ].irq_context)break ; + trylock_loop =1 ; }return 1 ; out_bug: