Re: [PATCH 06/14] perf tools: Cache dso data file descriptor
On Thu, May 29, 2014 at 09:02:36AM +0900, Namhyung Kim wrote: > On Tue, 27 May 2014 09:37:38 +0200, Jiri Olsa wrote: > > On Tue, May 27, 2014 at 10:05:28AM +0900, Namhyung Kim wrote: > >> Hi Jiri, > >> > >> On Thu, 15 May 2014 19:23:27 +0200, Jiri Olsa wrote: > >> > >> [SNIP] > >> > +static void data_close(void) > >> > +{ > >> > +bool cache_fd = may_cache_fd(); > >> > + > >> > +if (!cache_fd) > >> > +close_first_dso(); > >> > +} > >> > >> Why do you do this at close()? As long as there's no attempt to open a > >> new file, we can keep existing fd, no? > > > > so the way it works now is: > > > > - we keep up to the 'RLIMIT_NOFILE / 2' of open dso objects > > - if we try to open dso and it fails, because we are out of > >file descriptors, we close dso objects and try to reopen > >(check do_open function) > > - when we close the dso object we check if number of opened > >dso objects is below 'RLIMIT_NOFILE / 2'.. if it is, we keep > >the dso opened, if not we close first dso in the list > > > > util/dso.h tries to describe that > > Yes, I know. But my question is why do this at close()? Isn't it > sufficient to check the file limit at open() and close previous one if > necessary? hm, it's still the same operation to be done either in open or in close.. but we would not need dso__data_close then.. ok, I'll make the change ;-) thanks, jirka -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH 06/14] perf tools: Cache dso data file descriptor
On Thu, May 29, 2014 at 09:02:36AM +0900, Namhyung Kim wrote: On Tue, 27 May 2014 09:37:38 +0200, Jiri Olsa wrote: On Tue, May 27, 2014 at 10:05:28AM +0900, Namhyung Kim wrote: Hi Jiri, On Thu, 15 May 2014 19:23:27 +0200, Jiri Olsa wrote: [SNIP] +static void data_close(void) +{ +bool cache_fd = may_cache_fd(); + +if (!cache_fd) +close_first_dso(); +} Why do you do this at close()? As long as there's no attempt to open a new file, we can keep existing fd, no? so the way it works now is: - we keep up to the 'RLIMIT_NOFILE / 2' of open dso objects - if we try to open dso and it fails, because we are out of file descriptors, we close dso objects and try to reopen (check do_open function) - when we close the dso object we check if number of opened dso objects is below 'RLIMIT_NOFILE / 2'.. if it is, we keep the dso opened, if not we close first dso in the list util/dso.h tries to describe that Yes, I know. But my question is why do this at close()? Isn't it sufficient to check the file limit at open() and close previous one if necessary? hm, it's still the same operation to be done either in open or in close.. but we would not need dso__data_close then.. ok, I'll make the change ;-) thanks, jirka -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH 06/14] perf tools: Cache dso data file descriptor
On Tue, 27 May 2014 09:37:38 +0200, Jiri Olsa wrote: > On Tue, May 27, 2014 at 10:05:28AM +0900, Namhyung Kim wrote: >> Hi Jiri, >> >> On Thu, 15 May 2014 19:23:27 +0200, Jiri Olsa wrote: >> >> [SNIP] >> > +static void data_close(void) >> > +{ >> > + bool cache_fd = may_cache_fd(); >> > + >> > + if (!cache_fd) >> > + close_first_dso(); >> > +} >> >> Why do you do this at close()? As long as there's no attempt to open a >> new file, we can keep existing fd, no? > > so the way it works now is: > > - we keep up to the 'RLIMIT_NOFILE / 2' of open dso objects > - if we try to open dso and it fails, because we are out of >file descriptors, we close dso objects and try to reopen >(check do_open function) > - when we close the dso object we check if number of opened >dso objects is below 'RLIMIT_NOFILE / 2'.. if it is, we keep >the dso opened, if not we close first dso in the list > > util/dso.h tries to describe that Yes, I know. But my question is why do this at close()? Isn't it sufficient to check the file limit at open() and close previous one if necessary? > >> >> > + >> > +void dso__data_close(struct dso *dso) >> > +{ >> > + if (dso->data.fd >= 0) >> > + data_close(); >> > +} >> >> Hmm.. it's confusing dso__data_close(dso) closes an other dso rather >> than the given dso. And this dso__data_close() is not paired with any >> _open() also these close calls make me confusing which one to use. ;-p > > thats due to the caching.. as explained above > > About the pairing.. originally the interface was only dso__data_fd > that opened and returned fd, which the caller needed to close. > > I added dso__data_close so we could keep track of file descriptors. > > I could add dso__data_open I guess, but it is dso__data_fd which is > needed for elf interface anyway. I'd rather suggest dropping the open/close idiom for this case since it's confusing. What about get/put or get_fd/put_fd? Thanks, Namhyung -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH 06/14] perf tools: Cache dso data file descriptor
On Tue, 27 May 2014 09:37:38 +0200, Jiri Olsa wrote: On Tue, May 27, 2014 at 10:05:28AM +0900, Namhyung Kim wrote: Hi Jiri, On Thu, 15 May 2014 19:23:27 +0200, Jiri Olsa wrote: [SNIP] +static void data_close(void) +{ + bool cache_fd = may_cache_fd(); + + if (!cache_fd) + close_first_dso(); +} Why do you do this at close()? As long as there's no attempt to open a new file, we can keep existing fd, no? so the way it works now is: - we keep up to the 'RLIMIT_NOFILE / 2' of open dso objects - if we try to open dso and it fails, because we are out of file descriptors, we close dso objects and try to reopen (check do_open function) - when we close the dso object we check if number of opened dso objects is below 'RLIMIT_NOFILE / 2'.. if it is, we keep the dso opened, if not we close first dso in the list util/dso.h tries to describe that Yes, I know. But my question is why do this at close()? Isn't it sufficient to check the file limit at open() and close previous one if necessary? + +void dso__data_close(struct dso *dso) +{ + if (dso-data.fd = 0) + data_close(); +} Hmm.. it's confusing dso__data_close(dso) closes an other dso rather than the given dso. And this dso__data_close() is not paired with any _open() also these close calls make me confusing which one to use. ;-p thats due to the caching.. as explained above About the pairing.. originally the interface was only dso__data_fd that opened and returned fd, which the caller needed to close. I added dso__data_close so we could keep track of file descriptors. I could add dso__data_open I guess, but it is dso__data_fd which is needed for elf interface anyway. I'd rather suggest dropping the open/close idiom for this case since it's confusing. What about get/put or get_fd/put_fd? Thanks, Namhyung -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH 06/14] perf tools: Cache dso data file descriptor
On Tue, May 27, 2014 at 10:05:28AM +0900, Namhyung Kim wrote: > Hi Jiri, > > On Thu, 15 May 2014 19:23:27 +0200, Jiri Olsa wrote: > > [SNIP] > > +static void data_close(void) > > +{ > > + bool cache_fd = may_cache_fd(); > > + > > + if (!cache_fd) > > + close_first_dso(); > > +} > > Why do you do this at close()? As long as there's no attempt to open a > new file, we can keep existing fd, no? so the way it works now is: - we keep up to the 'RLIMIT_NOFILE / 2' of open dso objects - if we try to open dso and it fails, because we are out of file descriptors, we close dso objects and try to reopen (check do_open function) - when we close the dso object we check if number of opened dso objects is below 'RLIMIT_NOFILE / 2'.. if it is, we keep the dso opened, if not we close first dso in the list util/dso.h tries to describe that > > > + > > +void dso__data_close(struct dso *dso) > > +{ > > + if (dso->data.fd >= 0) > > + data_close(); > > +} > > Hmm.. it's confusing dso__data_close(dso) closes an other dso rather > than the given dso. And this dso__data_close() is not paired with any > _open() also these close calls make me confusing which one to use. ;-p thats due to the caching.. as explained above About the pairing.. originally the interface was only dso__data_fd that opened and returned fd, which the caller needed to close. I added dso__data_close so we could keep track of file descriptors. I could add dso__data_open I guess, but it is dso__data_fd which is needed for elf interface anyway. thanks, jirka -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH 06/14] perf tools: Cache dso data file descriptor
On Tue, May 27, 2014 at 10:05:28AM +0900, Namhyung Kim wrote: Hi Jiri, On Thu, 15 May 2014 19:23:27 +0200, Jiri Olsa wrote: [SNIP] +static void data_close(void) +{ + bool cache_fd = may_cache_fd(); + + if (!cache_fd) + close_first_dso(); +} Why do you do this at close()? As long as there's no attempt to open a new file, we can keep existing fd, no? so the way it works now is: - we keep up to the 'RLIMIT_NOFILE / 2' of open dso objects - if we try to open dso and it fails, because we are out of file descriptors, we close dso objects and try to reopen (check do_open function) - when we close the dso object we check if number of opened dso objects is below 'RLIMIT_NOFILE / 2'.. if it is, we keep the dso opened, if not we close first dso in the list util/dso.h tries to describe that + +void dso__data_close(struct dso *dso) +{ + if (dso-data.fd = 0) + data_close(); +} Hmm.. it's confusing dso__data_close(dso) closes an other dso rather than the given dso. And this dso__data_close() is not paired with any _open() also these close calls make me confusing which one to use. ;-p thats due to the caching.. as explained above About the pairing.. originally the interface was only dso__data_fd that opened and returned fd, which the caller needed to close. I added dso__data_close so we could keep track of file descriptors. I could add dso__data_open I guess, but it is dso__data_fd which is needed for elf interface anyway. thanks, jirka -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH 06/14] perf tools: Cache dso data file descriptor
Hi Jiri, On Thu, 15 May 2014 19:23:27 +0200, Jiri Olsa wrote: [SNIP] > +static void data_close(void) > +{ > + bool cache_fd = may_cache_fd(); > + > + if (!cache_fd) > + close_first_dso(); > +} Why do you do this at close()? As long as there's no attempt to open a new file, we can keep existing fd, no? > + > +void dso__data_close(struct dso *dso) > +{ > + if (dso->data.fd >= 0) > + data_close(); > +} Hmm.. it's confusing dso__data_close(dso) closes an other dso rather than the given dso. And this dso__data_close() is not paired with any _open() also these close calls make me confusing which one to use. ;-p Thanks Namhyung -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH 06/14] perf tools: Cache dso data file descriptor
Hi Jiri, On Thu, 15 May 2014 19:23:27 +0200, Jiri Olsa wrote: [SNIP] +static void data_close(void) +{ + bool cache_fd = may_cache_fd(); + + if (!cache_fd) + close_first_dso(); +} Why do you do this at close()? As long as there's no attempt to open a new file, we can keep existing fd, no? + +void dso__data_close(struct dso *dso) +{ + if (dso-data.fd = 0) + data_close(); +} Hmm.. it's confusing dso__data_close(dso) closes an other dso rather than the given dso. And this dso__data_close() is not paired with any _open() also these close calls make me confusing which one to use. ;-p Thanks Namhyung -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH 06/14] perf tools: Cache dso data file descriptor
Changing the dso__data_close to keep the dso data file descriptor open if possible. We keep dsos data file descriptors open until their count reaches the half of the current fd open limit (RLIMIT_NOFILE). In this case we close file descriptor of the first opened dso object. We've got speed up in dso__data_fd function. Output from report over 10 GB data with DWARF unwind stacks: (TODO fix perf diff) current code: 0.16% perf perf [.] dso__data_fd change: no record of dso__data_fd And we got some noticable overall speed up: (perf perf stat -e '{cycles,instructions}:u' ...) current code: 291,315,329,878 cycles ( +- 0.22% ) 391,763,485,304 instructions ( +- 0.03% ) 180.742249687 seconds time elapsed( +- 0.64% ) change: 228,948,088,958 cycles ( +- 0.20% ) 324,936,504,336 instructions ( +- 0.02% ) 133.789677792 seconds time elapsed( +- 0.76% ) Cc: Arnaldo Carvalho de Melo Cc: Corey Ashford Cc: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Jean Pihet Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Signed-off-by: Jiri Olsa --- tools/perf/util/dso.c | 62 --- 1 file changed, 59 insertions(+), 3 deletions(-) diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c index 76e5c13..316e087 100644 --- a/tools/perf/util/dso.c +++ b/tools/perf/util/dso.c @@ -1,4 +1,6 @@ #include +#include +#include #include "symbol.h" #include "dso.h" #include "machine.h" @@ -204,11 +206,60 @@ static void close_dso(struct dso *dso) close_data_fd(dso); } -void dso__data_close(struct dso *dso) +static void close_first_dso(void) { + struct dso *dso; + + dso = list_first_entry(__data_open, struct dso, data.open_entry); close_dso(dso); } +static rlim_t get_fd_limit(void) +{ + struct rlimit l; + rlim_t limit = 0; + + /* Allow half of the current open fd limit. */ + if (getrlimit(RLIMIT_NOFILE, ) == 0) { + if (l.rlim_cur == RLIM_INFINITY) + limit = l.rlim_cur; + else + limit = l.rlim_cur / 2; + } else { + pr_err("failed to get fd limit\n"); + limit = 1; + } + + return limit; +} + +static bool may_cache_fd(void) +{ + static rlim_t limit; + + if (!limit) + limit = get_fd_limit(); + + if (limit == RLIM_INFINITY) + return true; + + return limit > (rlim_t) dso__data_open_cnt; +} + +static void data_close(void) +{ + bool cache_fd = may_cache_fd(); + + if (!cache_fd) + close_first_dso(); +} + +void dso__data_close(struct dso *dso) +{ + if (dso->data.fd >= 0) + data_close(); +} + int dso__data_fd(struct dso *dso, struct machine *machine) { enum dso_binary_type binary_type_data[] = { @@ -318,6 +369,7 @@ static ssize_t dso_cache__read(struct dso *dso, struct machine *machine, u64 offset, u8 *data, ssize_t size) { + bool new_fd = dso->data.fd == -1; struct dso_cache *cache; ssize_t ret; int fd; @@ -356,7 +408,10 @@ dso_cache__read(struct dso *dso, struct machine *machine, if (ret <= 0) free(cache); - dso__data_close(dso); + /* Check the cache only if we just added new fd. */ + if (new_fd) + data_close(); + return ret; } @@ -563,7 +618,8 @@ void dso__delete(struct dso *dso) dso->long_name_allocated = false; } - dso__data_close(dso); + if (dso->data.fd != -1) + close_dso(dso); dso_cache__free(>data.cache); dso__free_a2l(dso); zfree(>symsrc_filename); -- 1.8.3.1 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH 06/14] perf tools: Cache dso data file descriptor
Changing the dso__data_close to keep the dso data file descriptor open if possible. We keep dsos data file descriptors open until their count reaches the half of the current fd open limit (RLIMIT_NOFILE). In this case we close file descriptor of the first opened dso object. We've got speed up in dso__data_fd function. Output from report over 10 GB data with DWARF unwind stacks: (TODO fix perf diff) current code: 0.16% perf perf [.] dso__data_fd change: no record of dso__data_fd And we got some noticable overall speed up: (perf perf stat -e '{cycles,instructions}:u' ...) current code: 291,315,329,878 cycles ( +- 0.22% ) 391,763,485,304 instructions ( +- 0.03% ) 180.742249687 seconds time elapsed( +- 0.64% ) change: 228,948,088,958 cycles ( +- 0.20% ) 324,936,504,336 instructions ( +- 0.02% ) 133.789677792 seconds time elapsed( +- 0.76% ) Cc: Arnaldo Carvalho de Melo a...@kernel.org Cc: Corey Ashford cjash...@linux.vnet.ibm.com Cc: David Ahern dsah...@gmail.com Cc: Frederic Weisbecker fweis...@gmail.com Cc: Ingo Molnar mi...@kernel.org Cc: Jean Pihet jean.pi...@linaro.org Cc: Namhyung Kim namhy...@kernel.org Cc: Paul Mackerras pau...@samba.org Cc: Peter Zijlstra a.p.zijls...@chello.nl Signed-off-by: Jiri Olsa jo...@kernel.org --- tools/perf/util/dso.c | 62 --- 1 file changed, 59 insertions(+), 3 deletions(-) diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c index 76e5c13..316e087 100644 --- a/tools/perf/util/dso.c +++ b/tools/perf/util/dso.c @@ -1,4 +1,6 @@ #include asm/bug.h +#include sys/time.h +#include sys/resource.h #include symbol.h #include dso.h #include machine.h @@ -204,11 +206,60 @@ static void close_dso(struct dso *dso) close_data_fd(dso); } -void dso__data_close(struct dso *dso) +static void close_first_dso(void) { + struct dso *dso; + + dso = list_first_entry(dso__data_open, struct dso, data.open_entry); close_dso(dso); } +static rlim_t get_fd_limit(void) +{ + struct rlimit l; + rlim_t limit = 0; + + /* Allow half of the current open fd limit. */ + if (getrlimit(RLIMIT_NOFILE, l) == 0) { + if (l.rlim_cur == RLIM_INFINITY) + limit = l.rlim_cur; + else + limit = l.rlim_cur / 2; + } else { + pr_err(failed to get fd limit\n); + limit = 1; + } + + return limit; +} + +static bool may_cache_fd(void) +{ + static rlim_t limit; + + if (!limit) + limit = get_fd_limit(); + + if (limit == RLIM_INFINITY) + return true; + + return limit (rlim_t) dso__data_open_cnt; +} + +static void data_close(void) +{ + bool cache_fd = may_cache_fd(); + + if (!cache_fd) + close_first_dso(); +} + +void dso__data_close(struct dso *dso) +{ + if (dso-data.fd = 0) + data_close(); +} + int dso__data_fd(struct dso *dso, struct machine *machine) { enum dso_binary_type binary_type_data[] = { @@ -318,6 +369,7 @@ static ssize_t dso_cache__read(struct dso *dso, struct machine *machine, u64 offset, u8 *data, ssize_t size) { + bool new_fd = dso-data.fd == -1; struct dso_cache *cache; ssize_t ret; int fd; @@ -356,7 +408,10 @@ dso_cache__read(struct dso *dso, struct machine *machine, if (ret = 0) free(cache); - dso__data_close(dso); + /* Check the cache only if we just added new fd. */ + if (new_fd) + data_close(); + return ret; } @@ -563,7 +618,8 @@ void dso__delete(struct dso *dso) dso-long_name_allocated = false; } - dso__data_close(dso); + if (dso-data.fd != -1) + close_dso(dso); dso_cache__free(dso-data.cache); dso__free_a2l(dso); zfree(dso-symsrc_filename); -- 1.8.3.1 -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/