Commit 27d0fd410c3cee00ece2e55f4354a7a9ec1a6a6a
Committed by
Ingo Molnar
1 parent
60c1baf124
Exists in
master
and in
7 other branches
strlist: Introduce strlist__entry and strlist__nr_entries methods
The strlist__entry method allows accessing strlists like an array, will be used in the 'perf report' to access the first entry. We now keep the nr_entries so that we can check if we have just one entry, will be used in 'perf report' to improve the output by showing just at the top when we have just, say, one DSO. While at it use nr_entries to optimize strlist__is_empty by not using the far more costly rb_first based implementation. Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> LKML-Reference: <1247325517-12272-2-git-send-email-acme@redhat.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Showing 2 changed files with 27 additions and 4 deletions Inline Diff
tools/perf/util/strlist.c
1 | /* | 1 | /* |
2 | * (c) 2009 Arnaldo Carvalho de Melo <acme@redhat.com> | 2 | * (c) 2009 Arnaldo Carvalho de Melo <acme@redhat.com> |
3 | * | 3 | * |
4 | * Licensed under the GPLv2. | 4 | * Licensed under the GPLv2. |
5 | */ | 5 | */ |
6 | 6 | ||
7 | #include "strlist.h" | 7 | #include "strlist.h" |
8 | #include <errno.h> | 8 | #include <errno.h> |
9 | #include <stdio.h> | 9 | #include <stdio.h> |
10 | #include <stdlib.h> | 10 | #include <stdlib.h> |
11 | #include <string.h> | 11 | #include <string.h> |
12 | 12 | ||
13 | static struct str_node *str_node__new(const char *s, bool dupstr) | 13 | static struct str_node *str_node__new(const char *s, bool dupstr) |
14 | { | 14 | { |
15 | struct str_node *self = malloc(sizeof(*self)); | 15 | struct str_node *self = malloc(sizeof(*self)); |
16 | 16 | ||
17 | if (self != NULL) { | 17 | if (self != NULL) { |
18 | if (dupstr) { | 18 | if (dupstr) { |
19 | s = strdup(s); | 19 | s = strdup(s); |
20 | if (s == NULL) | 20 | if (s == NULL) |
21 | goto out_delete; | 21 | goto out_delete; |
22 | } | 22 | } |
23 | self->s = s; | 23 | self->s = s; |
24 | } | 24 | } |
25 | 25 | ||
26 | return self; | 26 | return self; |
27 | 27 | ||
28 | out_delete: | 28 | out_delete: |
29 | free(self); | 29 | free(self); |
30 | return NULL; | 30 | return NULL; |
31 | } | 31 | } |
32 | 32 | ||
33 | static void str_node__delete(struct str_node *self, bool dupstr) | 33 | static void str_node__delete(struct str_node *self, bool dupstr) |
34 | { | 34 | { |
35 | if (dupstr) | 35 | if (dupstr) |
36 | free((void *)self->s); | 36 | free((void *)self->s); |
37 | free(self); | 37 | free(self); |
38 | } | 38 | } |
39 | 39 | ||
40 | int strlist__add(struct strlist *self, const char *new_entry) | 40 | int strlist__add(struct strlist *self, const char *new_entry) |
41 | { | 41 | { |
42 | struct rb_node **p = &self->entries.rb_node; | 42 | struct rb_node **p = &self->entries.rb_node; |
43 | struct rb_node *parent = NULL; | 43 | struct rb_node *parent = NULL; |
44 | struct str_node *sn; | 44 | struct str_node *sn; |
45 | 45 | ||
46 | while (*p != NULL) { | 46 | while (*p != NULL) { |
47 | int rc; | 47 | int rc; |
48 | 48 | ||
49 | parent = *p; | 49 | parent = *p; |
50 | sn = rb_entry(parent, struct str_node, rb_node); | 50 | sn = rb_entry(parent, struct str_node, rb_node); |
51 | rc = strcmp(sn->s, new_entry); | 51 | rc = strcmp(sn->s, new_entry); |
52 | 52 | ||
53 | if (rc > 0) | 53 | if (rc > 0) |
54 | p = &(*p)->rb_left; | 54 | p = &(*p)->rb_left; |
55 | else if (rc < 0) | 55 | else if (rc < 0) |
56 | p = &(*p)->rb_right; | 56 | p = &(*p)->rb_right; |
57 | else | 57 | else |
58 | return -EEXIST; | 58 | return -EEXIST; |
59 | } | 59 | } |
60 | 60 | ||
61 | sn = str_node__new(new_entry, self->dupstr); | 61 | sn = str_node__new(new_entry, self->dupstr); |
62 | if (sn == NULL) | 62 | if (sn == NULL) |
63 | return -ENOMEM; | 63 | return -ENOMEM; |
64 | 64 | ||
65 | rb_link_node(&sn->rb_node, parent, p); | 65 | rb_link_node(&sn->rb_node, parent, p); |
66 | rb_insert_color(&sn->rb_node, &self->entries); | 66 | rb_insert_color(&sn->rb_node, &self->entries); |
67 | ++self->nr_entries; | ||
67 | 68 | ||
68 | return 0; | 69 | return 0; |
69 | } | 70 | } |
70 | 71 | ||
71 | int strlist__load(struct strlist *self, const char *filename) | 72 | int strlist__load(struct strlist *self, const char *filename) |
72 | { | 73 | { |
73 | char entry[1024]; | 74 | char entry[1024]; |
74 | int err; | 75 | int err; |
75 | FILE *fp = fopen(filename, "r"); | 76 | FILE *fp = fopen(filename, "r"); |
76 | 77 | ||
77 | if (fp == NULL) | 78 | if (fp == NULL) |
78 | return errno; | 79 | return errno; |
79 | 80 | ||
80 | while (fgets(entry, sizeof(entry), fp) != NULL) { | 81 | while (fgets(entry, sizeof(entry), fp) != NULL) { |
81 | const size_t len = strlen(entry); | 82 | const size_t len = strlen(entry); |
82 | 83 | ||
83 | if (len == 0) | 84 | if (len == 0) |
84 | continue; | 85 | continue; |
85 | entry[len - 1] = '\0'; | 86 | entry[len - 1] = '\0'; |
86 | 87 | ||
87 | err = strlist__add(self, entry); | 88 | err = strlist__add(self, entry); |
88 | if (err != 0) | 89 | if (err != 0) |
89 | goto out; | 90 | goto out; |
90 | } | 91 | } |
91 | 92 | ||
92 | err = 0; | 93 | err = 0; |
93 | out: | 94 | out: |
94 | fclose(fp); | 95 | fclose(fp); |
95 | return err; | 96 | return err; |
96 | } | 97 | } |
97 | 98 | ||
98 | void strlist__remove(struct strlist *self, struct str_node *sn) | 99 | void strlist__remove(struct strlist *self, struct str_node *sn) |
99 | { | 100 | { |
100 | rb_erase(&sn->rb_node, &self->entries); | 101 | rb_erase(&sn->rb_node, &self->entries); |
101 | str_node__delete(sn, self->dupstr); | 102 | str_node__delete(sn, self->dupstr); |
102 | } | 103 | } |
103 | 104 | ||
104 | bool strlist__has_entry(struct strlist *self, const char *entry) | 105 | bool strlist__has_entry(struct strlist *self, const char *entry) |
105 | { | 106 | { |
106 | struct rb_node **p = &self->entries.rb_node; | 107 | struct rb_node **p = &self->entries.rb_node; |
107 | struct rb_node *parent = NULL; | 108 | struct rb_node *parent = NULL; |
108 | 109 | ||
109 | while (*p != NULL) { | 110 | while (*p != NULL) { |
110 | struct str_node *sn; | 111 | struct str_node *sn; |
111 | int rc; | 112 | int rc; |
112 | 113 | ||
113 | parent = *p; | 114 | parent = *p; |
114 | sn = rb_entry(parent, struct str_node, rb_node); | 115 | sn = rb_entry(parent, struct str_node, rb_node); |
115 | rc = strcmp(sn->s, entry); | 116 | rc = strcmp(sn->s, entry); |
116 | 117 | ||
117 | if (rc > 0) | 118 | if (rc > 0) |
118 | p = &(*p)->rb_left; | 119 | p = &(*p)->rb_left; |
119 | else if (rc < 0) | 120 | else if (rc < 0) |
120 | p = &(*p)->rb_right; | 121 | p = &(*p)->rb_right; |
121 | else | 122 | else |
122 | return true; | 123 | return true; |
123 | } | 124 | } |
124 | 125 | ||
125 | return false; | 126 | return false; |
126 | } | 127 | } |
127 | 128 | ||
128 | static int strlist__parse_list_entry(struct strlist *self, const char *s) | 129 | static int strlist__parse_list_entry(struct strlist *self, const char *s) |
129 | { | 130 | { |
130 | if (strncmp(s, "file://", 7) == 0) | 131 | if (strncmp(s, "file://", 7) == 0) |
131 | return strlist__load(self, s + 7); | 132 | return strlist__load(self, s + 7); |
132 | 133 | ||
133 | return strlist__add(self, s); | 134 | return strlist__add(self, s); |
134 | } | 135 | } |
135 | 136 | ||
136 | int strlist__parse_list(struct strlist *self, const char *s) | 137 | int strlist__parse_list(struct strlist *self, const char *s) |
137 | { | 138 | { |
138 | char *sep; | 139 | char *sep; |
139 | int err; | 140 | int err; |
140 | 141 | ||
141 | while ((sep = strchr(s, ',')) != NULL) { | 142 | while ((sep = strchr(s, ',')) != NULL) { |
142 | *sep = '\0'; | 143 | *sep = '\0'; |
143 | err = strlist__parse_list_entry(self, s); | 144 | err = strlist__parse_list_entry(self, s); |
144 | *sep = ','; | 145 | *sep = ','; |
145 | if (err != 0) | 146 | if (err != 0) |
146 | return err; | 147 | return err; |
147 | s = sep + 1; | 148 | s = sep + 1; |
148 | } | 149 | } |
149 | 150 | ||
150 | return *s ? strlist__parse_list_entry(self, s) : 0; | 151 | return *s ? strlist__parse_list_entry(self, s) : 0; |
151 | } | 152 | } |
152 | 153 | ||
153 | struct strlist *strlist__new(bool dupstr, const char *slist) | 154 | struct strlist *strlist__new(bool dupstr, const char *slist) |
154 | { | 155 | { |
155 | struct strlist *self = malloc(sizeof(*self)); | 156 | struct strlist *self = malloc(sizeof(*self)); |
156 | 157 | ||
157 | if (self != NULL) { | 158 | if (self != NULL) { |
158 | self->entries = RB_ROOT; | 159 | self->entries = RB_ROOT; |
159 | self->dupstr = dupstr; | 160 | self->dupstr = dupstr; |
161 | self->nr_entries = 0; | ||
160 | if (slist && strlist__parse_list(self, slist) != 0) | 162 | if (slist && strlist__parse_list(self, slist) != 0) |
161 | goto out_error; | 163 | goto out_error; |
162 | } | 164 | } |
163 | 165 | ||
164 | return self; | 166 | return self; |
165 | out_error: | 167 | out_error: |
166 | free(self); | 168 | free(self); |
167 | return NULL; | 169 | return NULL; |
168 | } | 170 | } |
169 | 171 | ||
170 | void strlist__delete(struct strlist *self) | 172 | void strlist__delete(struct strlist *self) |
171 | { | 173 | { |
172 | if (self != NULL) { | 174 | if (self != NULL) { |
173 | struct str_node *pos; | 175 | struct str_node *pos; |
174 | struct rb_node *next = rb_first(&self->entries); | 176 | struct rb_node *next = rb_first(&self->entries); |
175 | 177 | ||
176 | while (next) { | 178 | while (next) { |
177 | pos = rb_entry(next, struct str_node, rb_node); | 179 | pos = rb_entry(next, struct str_node, rb_node); |
178 | next = rb_next(&pos->rb_node); | 180 | next = rb_next(&pos->rb_node); |
179 | strlist__remove(self, pos); | 181 | strlist__remove(self, pos); |
180 | } | 182 | } |
181 | self->entries = RB_ROOT; | 183 | self->entries = RB_ROOT; |
182 | free(self); | 184 | free(self); |
183 | } | 185 | } |
186 | } | ||
187 | |||
188 | struct str_node *strlist__entry(const struct strlist *self, unsigned int idx) | ||
189 | { | ||
190 | struct rb_node *nd; | ||
191 | |||
192 | for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) { | ||
193 | struct str_node *pos = rb_entry(nd, struct str_node, rb_node); | ||
194 | |||
195 | if (!idx--) | ||
196 | return pos; | ||
197 | } | ||
198 | |||
199 | return NULL; | ||
184 | } | 200 | } |
185 | 201 |
tools/perf/util/strlist.h
1 | #ifndef STRLIST_H_ | 1 | #ifndef STRLIST_H_ |
2 | #define STRLIST_H_ | 2 | #define STRLIST_H_ |
3 | 3 | ||
4 | #include <linux/rbtree.h> | 4 | #include <linux/rbtree.h> |
5 | #include <stdbool.h> | 5 | #include <stdbool.h> |
6 | 6 | ||
7 | struct str_node { | 7 | struct str_node { |
8 | struct rb_node rb_node; | 8 | struct rb_node rb_node; |
9 | const char *s; | 9 | const char *s; |
10 | }; | 10 | }; |
11 | 11 | ||
12 | struct strlist { | 12 | struct strlist { |
13 | struct rb_root entries; | 13 | struct rb_root entries; |
14 | bool dupstr; | 14 | unsigned int nr_entries; |
15 | bool dupstr; | ||
15 | }; | 16 | }; |
16 | 17 | ||
17 | struct strlist *strlist__new(bool dupstr, const char *slist); | 18 | struct strlist *strlist__new(bool dupstr, const char *slist); |
18 | void strlist__delete(struct strlist *self); | 19 | void strlist__delete(struct strlist *self); |
19 | 20 | ||
20 | void strlist__remove(struct strlist *self, struct str_node *sn); | 21 | void strlist__remove(struct strlist *self, struct str_node *sn); |
21 | int strlist__load(struct strlist *self, const char *filename); | 22 | int strlist__load(struct strlist *self, const char *filename); |
22 | int strlist__add(struct strlist *self, const char *str); | 23 | int strlist__add(struct strlist *self, const char *str); |
23 | 24 | ||
25 | struct str_node *strlist__entry(const struct strlist *self, unsigned int idx); | ||
24 | bool strlist__has_entry(struct strlist *self, const char *entry); | 26 | bool strlist__has_entry(struct strlist *self, const char *entry); |
25 | 27 | ||
26 | static inline bool strlist__empty(const struct strlist *self) | 28 | static inline bool strlist__empty(const struct strlist *self) |
27 | { | 29 | { |
28 | return rb_first(&self->entries) == NULL; | 30 | return self->nr_entries == 0; |
31 | } | ||
32 | |||
33 | static inline unsigned int strlist__nr_entries(const struct strlist *self) | ||
34 | { | ||
35 | return self->nr_entries; | ||
29 | } | 36 | } |
30 | 37 | ||
31 | int strlist__parse_list(struct strlist *self, const char *s); | 38 | int strlist__parse_list(struct strlist *self, const char *s); |
32 | #endif /* STRLIST_H_ */ | 39 | #endif /* STRLIST_H_ */ |
33 | 40 |