diff options
author | Ingo Molnar <mingo@kernel.org> | 2016-01-13 04:36:03 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2016-01-13 04:36:03 -0500 |
commit | c36608843adf4674c462e49f63b64b2987d0ba0b (patch) | |
tree | 065cfa3b53e86cd17ba2b4b13fc0179e58bd9fe4 /tools/perf | |
parent | 0bd106d26dbe444160104b3153ca1652d2ab913b (diff) | |
parent | 34b7b0f95d41d2351a080e774d71085171db90e6 (diff) |
Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/urgent
Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo:
New, user visible features:
- Add --buildid-all option to 'perf record' to avoid processing
samples, just collecting build-ids for _all_ the DSOs that appears
in PERF_RECORD_MMAP records (Namhyung Kim)
- Add some more usage tips to appear in the hists browser
(top & report) (Namhyung Kim, Andi Kleen)
- Fix mmap2 event allocation in synthesize code, where we were
allocating space just for PERF_RECORD_MMAP, the older variant,
which could lead to corner case problems (Wang Nan)
Infrastructure fixes:
- Make list.h self-sufficient, removing one more reference to
kernel headers that lead to recent breakage when some rculist
change was made in the kernel sources. (Josh Poimboeuf)
Add missing NORETURN define for parse-options.h in
tools/lib/subcmd (Josh Poimboeuf)
- Fallback to srcdir/Documentation/ when not finding tips.txt
elsewhere (Namhyung Kim)
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'tools/perf')
-rw-r--r-- | tools/perf/Build | 1 | ||||
-rw-r--r-- | tools/perf/Documentation/perf-record.txt | 3 | ||||
-rw-r--r-- | tools/perf/Documentation/tips.txt | 15 | ||||
-rw-r--r-- | tools/perf/builtin-record.c | 26 | ||||
-rw-r--r-- | tools/perf/builtin-report.c | 10 | ||||
-rw-r--r-- | tools/perf/builtin-stat.c | 8 | ||||
-rw-r--r-- | tools/perf/config/Makefile | 3 | ||||
-rw-r--r-- | tools/perf/ui/browsers/hists.c | 2 | ||||
-rw-r--r-- | tools/perf/util/event.c | 4 | ||||
-rw-r--r-- | tools/perf/util/strlist.c | 8 | ||||
-rw-r--r-- | tools/perf/util/strlist.h | 9 | ||||
-rw-r--r-- | tools/perf/util/util.c | 11 |
12 files changed, 80 insertions, 20 deletions
diff --git a/tools/perf/Build b/tools/perf/Build index 6b67e6f4179f..a43fae7f439a 100644 --- a/tools/perf/Build +++ b/tools/perf/Build | |||
@@ -42,6 +42,7 @@ CFLAGS_perf.o += -DPERF_HTML_PATH="BUILD_STR($(htmldir_SQ))" \ | |||
42 | -include $(OUTPUT)PERF-VERSION-FILE | 42 | -include $(OUTPUT)PERF-VERSION-FILE |
43 | CFLAGS_builtin-trace.o += -DSTRACE_GROUPS_DIR="BUILD_STR($(STRACE_GROUPS_DIR_SQ))" | 43 | CFLAGS_builtin-trace.o += -DSTRACE_GROUPS_DIR="BUILD_STR($(STRACE_GROUPS_DIR_SQ))" |
44 | CFLAGS_builtin-report.o += -DTIPDIR="BUILD_STR($(tipdir_SQ))" | 44 | CFLAGS_builtin-report.o += -DTIPDIR="BUILD_STR($(tipdir_SQ))" |
45 | CFLAGS_builtin-report.o += -DDOCDIR="BUILD_STR($(srcdir_SQ)/Documentation)" | ||
45 | 46 | ||
46 | libperf-y += util/ | 47 | libperf-y += util/ |
47 | libperf-y += arch/ | 48 | libperf-y += arch/ |
diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt index 3a1a32f5479f..fbceb631387c 100644 --- a/tools/perf/Documentation/perf-record.txt +++ b/tools/perf/Documentation/perf-record.txt | |||
@@ -338,6 +338,9 @@ Options passed to clang when compiling BPF scriptlets. | |||
338 | Specify vmlinux path which has debuginfo. | 338 | Specify vmlinux path which has debuginfo. |
339 | (enabled when BPF prologue is on) | 339 | (enabled when BPF prologue is on) |
340 | 340 | ||
341 | --buildid-all:: | ||
342 | Record build-id of all DSOs regardless whether it's actually hit or not. | ||
343 | |||
341 | SEE ALSO | 344 | SEE ALSO |
342 | -------- | 345 | -------- |
343 | linkperf:perf-stat[1], linkperf:perf-list[1] | 346 | linkperf:perf-stat[1], linkperf:perf-list[1] |
diff --git a/tools/perf/Documentation/tips.txt b/tools/perf/Documentation/tips.txt index a1c10e360db5..e0ce9573b79b 100644 --- a/tools/perf/Documentation/tips.txt +++ b/tools/perf/Documentation/tips.txt | |||
@@ -12,3 +12,18 @@ List events using substring match: perf list <keyword> | |||
12 | To see list of saved events and attributes: perf evlist -v | 12 | To see list of saved events and attributes: perf evlist -v |
13 | Use --symfs <dir> if your symbol files are in non-standard locations | 13 | Use --symfs <dir> if your symbol files are in non-standard locations |
14 | To see callchains in a more compact form: perf report -g folded | 14 | To see callchains in a more compact form: perf report -g folded |
15 | Show individual samples with: perf script | ||
16 | Limit to show entries above 5% only: perf report --percent-limit 5 | ||
17 | Profiling branch (mis)predictions with: perf record -b / perf report | ||
18 | Treat branches as callchains: perf report --branch-history | ||
19 | To count events in every 1000 msec: perf stat -I 1000 | ||
20 | Print event counts in CSV format with: perf stat -x, | ||
21 | If you have debuginfo enabled, try: perf report -s sym,srcline | ||
22 | For memory address profiling, try: perf mem record / perf mem report | ||
23 | For tracepoint events, try: perf report -s trace_fields | ||
24 | To record callchains for each sample: perf record -g | ||
25 | To record every process run by an user: perf record -u <user> | ||
26 | Skip collecing build-id when recording: perf record -B | ||
27 | To change sampling frequency to 100 Hz: perf record -F 100 | ||
28 | See assembly instructions with percentage: perf annotate <symbol> | ||
29 | If you prefer Intel style assembly, try: perf annotate -M intel | ||
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index dc4e0adf5c5b..319712a4e02b 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c | |||
@@ -50,6 +50,7 @@ struct record { | |||
50 | int realtime_prio; | 50 | int realtime_prio; |
51 | bool no_buildid; | 51 | bool no_buildid; |
52 | bool no_buildid_cache; | 52 | bool no_buildid_cache; |
53 | bool buildid_all; | ||
53 | unsigned long long samples; | 54 | unsigned long long samples; |
54 | }; | 55 | }; |
55 | 56 | ||
@@ -362,6 +363,13 @@ static int process_buildids(struct record *rec) | |||
362 | */ | 363 | */ |
363 | symbol_conf.ignore_vmlinux_buildid = true; | 364 | symbol_conf.ignore_vmlinux_buildid = true; |
364 | 365 | ||
366 | /* | ||
367 | * If --buildid-all is given, it marks all DSO regardless of hits, | ||
368 | * so no need to process samples. | ||
369 | */ | ||
370 | if (rec->buildid_all) | ||
371 | rec->tool.sample = NULL; | ||
372 | |||
365 | return perf_session__process_events(session); | 373 | return perf_session__process_events(session); |
366 | } | 374 | } |
367 | 375 | ||
@@ -756,12 +764,8 @@ out_child: | |||
756 | 764 | ||
757 | if (!rec->no_buildid) { | 765 | if (!rec->no_buildid) { |
758 | process_buildids(rec); | 766 | process_buildids(rec); |
759 | /* | 767 | |
760 | * We take all buildids when the file contains | 768 | if (rec->buildid_all) |
761 | * AUX area tracing data because we do not decode the | ||
762 | * trace because it would take too long. | ||
763 | */ | ||
764 | if (rec->opts.full_auxtrace) | ||
765 | dsos__hit_all(rec->session); | 769 | dsos__hit_all(rec->session); |
766 | } | 770 | } |
767 | perf_session__write_header(rec->session, rec->evlist, fd, true); | 771 | perf_session__write_header(rec->session, rec->evlist, fd, true); |
@@ -1138,6 +1142,8 @@ struct option __record_options[] = { | |||
1138 | "options passed to clang when compiling BPF scriptlets"), | 1142 | "options passed to clang when compiling BPF scriptlets"), |
1139 | OPT_STRING(0, "vmlinux", &symbol_conf.vmlinux_name, | 1143 | OPT_STRING(0, "vmlinux", &symbol_conf.vmlinux_name, |
1140 | "file", "vmlinux pathname"), | 1144 | "file", "vmlinux pathname"), |
1145 | OPT_BOOLEAN(0, "buildid-all", &record.buildid_all, | ||
1146 | "Record build-id of all DSOs regardless of hits"), | ||
1141 | OPT_END() | 1147 | OPT_END() |
1142 | }; | 1148 | }; |
1143 | 1149 | ||
@@ -1255,6 +1261,14 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1255 | if (err) | 1261 | if (err) |
1256 | goto out_symbol_exit; | 1262 | goto out_symbol_exit; |
1257 | 1263 | ||
1264 | /* | ||
1265 | * We take all buildids when the file contains | ||
1266 | * AUX area tracing data because we do not decode the | ||
1267 | * trace because it would take too long. | ||
1268 | */ | ||
1269 | if (rec->opts.full_auxtrace) | ||
1270 | rec->buildid_all = true; | ||
1271 | |||
1258 | if (record_opts__config(&rec->opts)) { | 1272 | if (record_opts__config(&rec->opts)) { |
1259 | err = -EINVAL; | 1273 | err = -EINVAL; |
1260 | goto out_symbol_exit; | 1274 | goto out_symbol_exit; |
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index d5a42ee12529..2bf537f190a0 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include "util/tool.h" | 28 | #include "util/tool.h" |
29 | 29 | ||
30 | #include <subcmd/parse-options.h> | 30 | #include <subcmd/parse-options.h> |
31 | #include <subcmd/exec-cmd.h> | ||
31 | #include "util/parse-events.h" | 32 | #include "util/parse-events.h" |
32 | 33 | ||
33 | #include "util/thread.h" | 34 | #include "util/thread.h" |
@@ -433,7 +434,14 @@ static int report__browse_hists(struct report *rep) | |||
433 | int ret; | 434 | int ret; |
434 | struct perf_session *session = rep->session; | 435 | struct perf_session *session = rep->session; |
435 | struct perf_evlist *evlist = session->evlist; | 436 | struct perf_evlist *evlist = session->evlist; |
436 | const char *help = perf_tip(TIPDIR); | 437 | const char *help = perf_tip(system_path(TIPDIR)); |
438 | |||
439 | if (help == NULL) { | ||
440 | /* fallback for people who don't install perf ;-) */ | ||
441 | help = perf_tip(DOCDIR); | ||
442 | if (help == NULL) | ||
443 | help = "Cannot load tips.txt file, please install perf!"; | ||
444 | } | ||
437 | 445 | ||
438 | switch (use_browser) { | 446 | switch (use_browser) { |
439 | case 1: | 447 | case 1: |
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 7f568244662b..038e877081b6 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c | |||
@@ -1588,7 +1588,7 @@ static int add_default_attributes(void) | |||
1588 | return perf_evlist__add_default_attrs(evsel_list, very_very_detailed_attrs); | 1588 | return perf_evlist__add_default_attrs(evsel_list, very_very_detailed_attrs); |
1589 | } | 1589 | } |
1590 | 1590 | ||
1591 | static const char * const recort_usage[] = { | 1591 | static const char * const stat_record_usage[] = { |
1592 | "perf stat record [<options>]", | 1592 | "perf stat record [<options>]", |
1593 | NULL, | 1593 | NULL, |
1594 | }; | 1594 | }; |
@@ -1611,7 +1611,7 @@ static int __cmd_record(int argc, const char **argv) | |||
1611 | struct perf_session *session; | 1611 | struct perf_session *session; |
1612 | struct perf_data_file *file = &perf_stat.file; | 1612 | struct perf_data_file *file = &perf_stat.file; |
1613 | 1613 | ||
1614 | argc = parse_options(argc, argv, stat_options, record_usage, | 1614 | argc = parse_options(argc, argv, stat_options, stat_record_usage, |
1615 | PARSE_OPT_STOP_AT_NON_OPTION); | 1615 | PARSE_OPT_STOP_AT_NON_OPTION); |
1616 | 1616 | ||
1617 | if (output_name) | 1617 | if (output_name) |
@@ -1745,7 +1745,7 @@ int process_cpu_map_event(struct perf_tool *tool __maybe_unused, | |||
1745 | return set_maps(st); | 1745 | return set_maps(st); |
1746 | } | 1746 | } |
1747 | 1747 | ||
1748 | static const char * const report_usage[] = { | 1748 | static const char * const stat_report_usage[] = { |
1749 | "perf stat report [<options>]", | 1749 | "perf stat report [<options>]", |
1750 | NULL, | 1750 | NULL, |
1751 | }; | 1751 | }; |
@@ -1779,7 +1779,7 @@ static int __cmd_report(int argc, const char **argv) | |||
1779 | struct stat st; | 1779 | struct stat st; |
1780 | int ret; | 1780 | int ret; |
1781 | 1781 | ||
1782 | argc = parse_options(argc, argv, options, report_usage, 0); | 1782 | argc = parse_options(argc, argv, options, stat_report_usage, 0); |
1783 | 1783 | ||
1784 | if (!input_name || !strlen(input_name)) { | 1784 | if (!input_name || !strlen(input_name)) { |
1785 | if (!fstat(STDIN_FILENO, &st) && S_ISFIFO(st.st_mode)) | 1785 | if (!fstat(STDIN_FILENO, &st) && S_ISFIFO(st.st_mode)) |
diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile index 7545ba60053e..e5959c136a19 100644 --- a/tools/perf/config/Makefile +++ b/tools/perf/config/Makefile | |||
@@ -692,6 +692,7 @@ template_dir = share/perf-core/templates | |||
692 | STRACE_GROUPS_DIR = share/perf-core/strace/groups | 692 | STRACE_GROUPS_DIR = share/perf-core/strace/groups |
693 | htmldir = share/doc/perf-doc | 693 | htmldir = share/doc/perf-doc |
694 | tipdir = share/doc/perf-tip | 694 | tipdir = share/doc/perf-tip |
695 | srcdir = $(srctree)/tools/perf | ||
695 | ifeq ($(prefix),/usr) | 696 | ifeq ($(prefix),/usr) |
696 | sysconfdir = /etc | 697 | sysconfdir = /etc |
697 | ETC_PERFCONFIG = $(sysconfdir)/perfconfig | 698 | ETC_PERFCONFIG = $(sysconfdir)/perfconfig |
@@ -722,6 +723,7 @@ tipdir_SQ = $(subst ','\'',$(tipdir)) | |||
722 | prefix_SQ = $(subst ','\'',$(prefix)) | 723 | prefix_SQ = $(subst ','\'',$(prefix)) |
723 | sysconfdir_SQ = $(subst ','\'',$(sysconfdir)) | 724 | sysconfdir_SQ = $(subst ','\'',$(sysconfdir)) |
724 | libdir_SQ = $(subst ','\'',$(libdir)) | 725 | libdir_SQ = $(subst ','\'',$(libdir)) |
726 | srcdir_SQ = $(subst ','\'',$(srcdir)) | ||
725 | 727 | ||
726 | ifneq ($(filter /%,$(firstword $(perfexecdir))),) | 728 | ifneq ($(filter /%,$(firstword $(perfexecdir))),) |
727 | perfexec_instdir = $(perfexecdir) | 729 | perfexec_instdir = $(perfexecdir) |
@@ -776,6 +778,7 @@ $(call detected_var,STRACE_GROUPS_DIR_SQ) | |||
776 | $(call detected_var,prefix_SQ) | 778 | $(call detected_var,prefix_SQ) |
777 | $(call detected_var,perfexecdir_SQ) | 779 | $(call detected_var,perfexecdir_SQ) |
778 | $(call detected_var,tipdir_SQ) | 780 | $(call detected_var,tipdir_SQ) |
781 | $(call detected_var,srcdir_SQ) | ||
779 | $(call detected_var,LIBDIR) | 782 | $(call detected_var,LIBDIR) |
780 | $(call detected_var,GTK_CFLAGS) | 783 | $(call detected_var,GTK_CFLAGS) |
781 | $(call detected_var,PERL_EMBED_CCOPTS) | 784 | $(call detected_var,PERL_EMBED_CCOPTS) |
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index 901d481e6cea..08c09ad755d2 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c | |||
@@ -480,7 +480,7 @@ static int hist_browser__run(struct hist_browser *browser, const char *help) | |||
480 | 480 | ||
481 | hists__browser_title(browser->hists, hbt, title, sizeof(title)); | 481 | hists__browser_title(browser->hists, hbt, title, sizeof(title)); |
482 | 482 | ||
483 | if (ui_browser__show(&browser->b, title, help) < 0) | 483 | if (ui_browser__show(&browser->b, title, "%s", help) < 0) |
484 | return -1; | 484 | return -1; |
485 | 485 | ||
486 | while (1) { | 486 | while (1) { |
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index cd61bb1f3917..85155e91b61b 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c | |||
@@ -503,7 +503,7 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool, | |||
503 | if (comm_event == NULL) | 503 | if (comm_event == NULL) |
504 | goto out; | 504 | goto out; |
505 | 505 | ||
506 | mmap_event = malloc(sizeof(mmap_event->mmap) + machine->id_hdr_size); | 506 | mmap_event = malloc(sizeof(mmap_event->mmap2) + machine->id_hdr_size); |
507 | if (mmap_event == NULL) | 507 | if (mmap_event == NULL) |
508 | goto out_free_comm; | 508 | goto out_free_comm; |
509 | 509 | ||
@@ -577,7 +577,7 @@ int perf_event__synthesize_threads(struct perf_tool *tool, | |||
577 | if (comm_event == NULL) | 577 | if (comm_event == NULL) |
578 | goto out; | 578 | goto out; |
579 | 579 | ||
580 | mmap_event = malloc(sizeof(mmap_event->mmap) + machine->id_hdr_size); | 580 | mmap_event = malloc(sizeof(mmap_event->mmap2) + machine->id_hdr_size); |
581 | if (mmap_event == NULL) | 581 | if (mmap_event == NULL) |
582 | goto out_free_comm; | 582 | goto out_free_comm; |
583 | 583 | ||
diff --git a/tools/perf/util/strlist.c b/tools/perf/util/strlist.c index bdf98f6f27bb..0d3dfcb919b4 100644 --- a/tools/perf/util/strlist.c +++ b/tools/perf/util/strlist.c | |||
@@ -126,6 +126,11 @@ static int strlist__parse_list_entry(struct strlist *slist, const char *s, | |||
126 | err = strlist__load(slist, subst); | 126 | err = strlist__load(slist, subst); |
127 | goto out; | 127 | goto out; |
128 | } | 128 | } |
129 | |||
130 | if (slist->file_only) { | ||
131 | err = -ENOENT; | ||
132 | goto out; | ||
133 | } | ||
129 | } | 134 | } |
130 | 135 | ||
131 | err = strlist__add(slist, s); | 136 | err = strlist__add(slist, s); |
@@ -157,11 +162,13 @@ struct strlist *strlist__new(const char *list, const struct strlist_config *conf | |||
157 | 162 | ||
158 | if (slist != NULL) { | 163 | if (slist != NULL) { |
159 | bool dupstr = true; | 164 | bool dupstr = true; |
165 | bool file_only = false; | ||
160 | const char *dirname = NULL; | 166 | const char *dirname = NULL; |
161 | 167 | ||
162 | if (config) { | 168 | if (config) { |
163 | dupstr = !config->dont_dupstr; | 169 | dupstr = !config->dont_dupstr; |
164 | dirname = config->dirname; | 170 | dirname = config->dirname; |
171 | file_only = config->file_only; | ||
165 | } | 172 | } |
166 | 173 | ||
167 | rblist__init(&slist->rblist); | 174 | rblist__init(&slist->rblist); |
@@ -170,6 +177,7 @@ struct strlist *strlist__new(const char *list, const struct strlist_config *conf | |||
170 | slist->rblist.node_delete = strlist__node_delete; | 177 | slist->rblist.node_delete = strlist__node_delete; |
171 | 178 | ||
172 | slist->dupstr = dupstr; | 179 | slist->dupstr = dupstr; |
180 | slist->file_only = file_only; | ||
173 | 181 | ||
174 | if (list && strlist__parse_list(slist, list, dirname) != 0) | 182 | if (list && strlist__parse_list(slist, list, dirname) != 0) |
175 | goto out_error; | 183 | goto out_error; |
diff --git a/tools/perf/util/strlist.h b/tools/perf/util/strlist.h index 297565aa7535..ca990029e243 100644 --- a/tools/perf/util/strlist.h +++ b/tools/perf/util/strlist.h | |||
@@ -13,11 +13,18 @@ struct str_node { | |||
13 | 13 | ||
14 | struct strlist { | 14 | struct strlist { |
15 | struct rblist rblist; | 15 | struct rblist rblist; |
16 | bool dupstr; | 16 | bool dupstr; |
17 | bool file_only; | ||
17 | }; | 18 | }; |
18 | 19 | ||
20 | /* | ||
21 | * @file_only: When dirname is present, only consider entries as filenames, | ||
22 | * that should not be added to the list if dirname/entry is not | ||
23 | * found | ||
24 | */ | ||
19 | struct strlist_config { | 25 | struct strlist_config { |
20 | bool dont_dupstr; | 26 | bool dont_dupstr; |
27 | bool file_only; | ||
21 | const char *dirname; | 28 | const char *dirname; |
22 | }; | 29 | }; |
23 | 30 | ||
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c index 88b8f8d21f58..ead9509835d2 100644 --- a/tools/perf/util/util.c +++ b/tools/perf/util/util.c | |||
@@ -17,7 +17,6 @@ | |||
17 | #include <unistd.h> | 17 | #include <unistd.h> |
18 | #include "callchain.h" | 18 | #include "callchain.h" |
19 | #include "strlist.h" | 19 | #include "strlist.h" |
20 | #include <subcmd/exec-cmd.h> | ||
21 | 20 | ||
22 | struct callchain_param callchain_param = { | 21 | struct callchain_param callchain_param = { |
23 | .mode = CHAIN_GRAPH_ABS, | 22 | .mode = CHAIN_GRAPH_ABS, |
@@ -672,14 +671,16 @@ const char *perf_tip(const char *dirpath) | |||
672 | struct str_node *node; | 671 | struct str_node *node; |
673 | char *tip = NULL; | 672 | char *tip = NULL; |
674 | struct strlist_config conf = { | 673 | struct strlist_config conf = { |
675 | .dirname = system_path(dirpath) , | 674 | .dirname = dirpath, |
675 | .file_only = true, | ||
676 | }; | 676 | }; |
677 | 677 | ||
678 | tips = strlist__new("tips.txt", &conf); | 678 | tips = strlist__new("tips.txt", &conf); |
679 | if (tips == NULL || strlist__nr_entries(tips) == 1) { | 679 | if (tips == NULL) |
680 | tip = (char *)"Cannot find tips.txt file"; | 680 | return errno == ENOENT ? NULL : "Tip: get more memory! ;-p"; |
681 | |||
682 | if (strlist__nr_entries(tips) == 0) | ||
681 | goto out; | 683 | goto out; |
682 | } | ||
683 | 684 | ||
684 | node = strlist__entry(tips, random() % strlist__nr_entries(tips)); | 685 | node = strlist__entry(tips, random() % strlist__nr_entries(tips)); |
685 | if (asprintf(&tip, "Tip: %s", node->s) < 0) | 686 | if (asprintf(&tip, "Tip: %s", node->s) < 0) |