Commit b1e5a9bee3c342dd3281aef76d1be1044dd8addf
Committed by
Arnaldo Carvalho de Melo
1 parent
e20960c027
Exists in
master
and in
6 other branches
perf tools: Use for_each_set_bit() to iterate over feature flags
This patch introduces the for_each_set_bit() macro and modifies feature implementation to use it. Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Ingo Molnar <mingo@elte.hu> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Stephane Eranian <eranian@google.com> Link: http://lkml.kernel.org/r/1323248577-11268-8-git-send-email-robert.richter@amd.com Signed-off-by: Robert Richter <robert.richter@amd.com> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Showing 3 changed files with 149 additions and 93 deletions Side-by-side Diff
tools/perf/util/header.c
... | ... | @@ -8,6 +8,7 @@ |
8 | 8 | #include <stdlib.h> |
9 | 9 | #include <linux/list.h> |
10 | 10 | #include <linux/kernel.h> |
11 | +#include <linux/bitops.h> | |
11 | 12 | #include <sys/utsname.h> |
12 | 13 | |
13 | 14 | #include "evlist.h" |
... | ... | @@ -1353,7 +1354,7 @@ |
1353 | 1354 | "%d, continuing...\n", section->offset, feat); |
1354 | 1355 | return 0; |
1355 | 1356 | } |
1356 | - if (feat < HEADER_TRACE_INFO || feat >= HEADER_LAST_FEATURE) { | |
1357 | + if (feat >= HEADER_LAST_FEATURE) { | |
1357 | 1358 | pr_warning("unknown feature %d\n", feat); |
1358 | 1359 | return 0; |
1359 | 1360 | } |
... | ... | @@ -1390,6 +1391,8 @@ |
1390 | 1391 | int ret = 0; |
1391 | 1392 | |
1392 | 1393 | if (perf_header__has_feat(h, type)) { |
1394 | + if (!feat_ops[type].write) | |
1395 | + return -1; | |
1393 | 1396 | |
1394 | 1397 | (*p)->offset = lseek(fd, 0, SEEK_CUR); |
1395 | 1398 | |
... | ... | @@ -1416,6 +1419,7 @@ |
1416 | 1419 | struct perf_file_section *feat_sec, *p; |
1417 | 1420 | int sec_size; |
1418 | 1421 | u64 sec_start; |
1422 | + int feat; | |
1419 | 1423 | int err; |
1420 | 1424 | |
1421 | 1425 | session = container_of(header, struct perf_session, header); |
1422 | 1426 | |
... | ... | @@ -1433,62 +1437,11 @@ |
1433 | 1437 | sec_start = header->data_offset + header->data_size; |
1434 | 1438 | lseek(fd, sec_start + sec_size, SEEK_SET); |
1435 | 1439 | |
1436 | - err = do_write_feat(fd, header, HEADER_TRACE_INFO, &p, evlist); | |
1437 | - if (err) | |
1438 | - perf_header__clear_feat(header, HEADER_TRACE_INFO); | |
1440 | + for_each_set_bit(feat, header->adds_features, HEADER_FEAT_BITS) { | |
1441 | + if (do_write_feat(fd, header, feat, &p, evlist)) | |
1442 | + perf_header__clear_feat(header, feat); | |
1443 | + } | |
1439 | 1444 | |
1440 | - err = do_write_feat(fd, header, HEADER_BUILD_ID, &p, evlist); | |
1441 | - if (err) | |
1442 | - perf_header__clear_feat(header, HEADER_BUILD_ID); | |
1443 | - | |
1444 | - err = do_write_feat(fd, header, HEADER_HOSTNAME, &p, evlist); | |
1445 | - if (err) | |
1446 | - perf_header__clear_feat(header, HEADER_HOSTNAME); | |
1447 | - | |
1448 | - err = do_write_feat(fd, header, HEADER_OSRELEASE, &p, evlist); | |
1449 | - if (err) | |
1450 | - perf_header__clear_feat(header, HEADER_OSRELEASE); | |
1451 | - | |
1452 | - err = do_write_feat(fd, header, HEADER_VERSION, &p, evlist); | |
1453 | - if (err) | |
1454 | - perf_header__clear_feat(header, HEADER_VERSION); | |
1455 | - | |
1456 | - err = do_write_feat(fd, header, HEADER_ARCH, &p, evlist); | |
1457 | - if (err) | |
1458 | - perf_header__clear_feat(header, HEADER_ARCH); | |
1459 | - | |
1460 | - err = do_write_feat(fd, header, HEADER_NRCPUS, &p, evlist); | |
1461 | - if (err) | |
1462 | - perf_header__clear_feat(header, HEADER_NRCPUS); | |
1463 | - | |
1464 | - err = do_write_feat(fd, header, HEADER_CPUDESC, &p, evlist); | |
1465 | - if (err) | |
1466 | - perf_header__clear_feat(header, HEADER_CPUDESC); | |
1467 | - | |
1468 | - err = do_write_feat(fd, header, HEADER_CPUID, &p, evlist); | |
1469 | - if (err) | |
1470 | - perf_header__clear_feat(header, HEADER_CPUID); | |
1471 | - | |
1472 | - err = do_write_feat(fd, header, HEADER_TOTAL_MEM, &p, evlist); | |
1473 | - if (err) | |
1474 | - perf_header__clear_feat(header, HEADER_TOTAL_MEM); | |
1475 | - | |
1476 | - err = do_write_feat(fd, header, HEADER_CMDLINE, &p, evlist); | |
1477 | - if (err) | |
1478 | - perf_header__clear_feat(header, HEADER_CMDLINE); | |
1479 | - | |
1480 | - err = do_write_feat(fd, header, HEADER_EVENT_DESC, &p, evlist); | |
1481 | - if (err) | |
1482 | - perf_header__clear_feat(header, HEADER_EVENT_DESC); | |
1483 | - | |
1484 | - err = do_write_feat(fd, header, HEADER_CPU_TOPOLOGY, &p, evlist); | |
1485 | - if (err) | |
1486 | - perf_header__clear_feat(header, HEADER_CPU_TOPOLOGY); | |
1487 | - | |
1488 | - err = do_write_feat(fd, header, HEADER_NUMA_TOPOLOGY, &p, evlist); | |
1489 | - if (err) | |
1490 | - perf_header__clear_feat(header, HEADER_NUMA_TOPOLOGY); | |
1491 | - | |
1492 | 1445 | lseek(fd, sec_start, SEEK_SET); |
1493 | 1446 | /* |
1494 | 1447 | * may write more than needed due to dropped feature, but |
1495 | 1448 | |
1496 | 1449 | |
1497 | 1450 | |
... | ... | @@ -1634,20 +1587,20 @@ |
1634 | 1587 | int perf_header__process_sections(struct perf_header *header, int fd, |
1635 | 1588 | void *data, |
1636 | 1589 | int (*process)(struct perf_file_section *section, |
1637 | - struct perf_header *ph, | |
1638 | - int feat, int fd, void *data)) | |
1590 | + struct perf_header *ph, | |
1591 | + int feat, int fd, void *data)) | |
1639 | 1592 | { |
1640 | - struct perf_file_section *feat_sec; | |
1593 | + struct perf_file_section *feat_sec, *sec; | |
1641 | 1594 | int nr_sections; |
1642 | 1595 | int sec_size; |
1643 | - int idx = 0; | |
1644 | - int err = -1, feat = 1; | |
1596 | + int feat; | |
1597 | + int err; | |
1645 | 1598 | |
1646 | 1599 | nr_sections = bitmap_weight(header->adds_features, HEADER_FEAT_BITS); |
1647 | 1600 | if (!nr_sections) |
1648 | 1601 | return 0; |
1649 | 1602 | |
1650 | - feat_sec = calloc(sizeof(*feat_sec), nr_sections); | |
1603 | + feat_sec = sec = calloc(sizeof(*feat_sec), nr_sections); | |
1651 | 1604 | if (!feat_sec) |
1652 | 1605 | return -1; |
1653 | 1606 | |
1654 | 1607 | |
1655 | 1608 | |
... | ... | @@ -1655,20 +1608,16 @@ |
1655 | 1608 | |
1656 | 1609 | lseek(fd, header->data_offset + header->data_size, SEEK_SET); |
1657 | 1610 | |
1658 | - if (perf_header__getbuffer64(header, fd, feat_sec, sec_size)) | |
1611 | + err = perf_header__getbuffer64(header, fd, feat_sec, sec_size); | |
1612 | + if (err < 0) | |
1659 | 1613 | goto out_free; |
1660 | 1614 | |
1661 | - err = 0; | |
1662 | - while (idx < nr_sections && feat < HEADER_LAST_FEATURE) { | |
1663 | - if (perf_header__has_feat(header, feat)) { | |
1664 | - struct perf_file_section *sec = &feat_sec[idx++]; | |
1665 | - | |
1666 | - err = process(sec, header, feat, fd, data); | |
1667 | - if (err < 0) | |
1668 | - break; | |
1669 | - } | |
1670 | - ++feat; | |
1615 | + for_each_set_bit(feat, header->adds_features, HEADER_LAST_FEATURE) { | |
1616 | + err = process(sec++, header, feat, fd, data); | |
1617 | + if (err < 0) | |
1618 | + goto out_free; | |
1671 | 1619 | } |
1620 | + err = 0; | |
1672 | 1621 | out_free: |
1673 | 1622 | free(feat_sec); |
1674 | 1623 | return err; |
1675 | 1624 | |
1676 | 1625 | |
1677 | 1626 | |
... | ... | @@ -1903,32 +1852,21 @@ |
1903 | 1852 | return 0; |
1904 | 1853 | } |
1905 | 1854 | |
1855 | + if (feat >= HEADER_LAST_FEATURE) { | |
1856 | + pr_debug("unknown feature %d, continuing...\n", feat); | |
1857 | + return 0; | |
1858 | + } | |
1859 | + | |
1906 | 1860 | switch (feat) { |
1907 | 1861 | case HEADER_TRACE_INFO: |
1908 | 1862 | trace_report(fd, false); |
1909 | 1863 | break; |
1910 | - | |
1911 | 1864 | case HEADER_BUILD_ID: |
1912 | 1865 | if (perf_header__read_build_ids(ph, fd, section->offset, section->size)) |
1913 | 1866 | pr_debug("Failed to read buildids, continuing...\n"); |
1914 | 1867 | break; |
1915 | - | |
1916 | - case HEADER_HOSTNAME: | |
1917 | - case HEADER_OSRELEASE: | |
1918 | - case HEADER_VERSION: | |
1919 | - case HEADER_ARCH: | |
1920 | - case HEADER_NRCPUS: | |
1921 | - case HEADER_CPUDESC: | |
1922 | - case HEADER_CPUID: | |
1923 | - case HEADER_TOTAL_MEM: | |
1924 | - case HEADER_CMDLINE: | |
1925 | - case HEADER_EVENT_DESC: | |
1926 | - case HEADER_CPU_TOPOLOGY: | |
1927 | - case HEADER_NUMA_TOPOLOGY: | |
1928 | - break; | |
1929 | - | |
1930 | 1868 | default: |
1931 | - pr_debug("unknown feature %d, continuing...\n", feat); | |
1869 | + break; | |
1932 | 1870 | } |
1933 | 1871 | |
1934 | 1872 | return 0; |
tools/perf/util/header.h
... | ... | @@ -10,7 +10,8 @@ |
10 | 10 | #include <linux/bitmap.h> |
11 | 11 | |
12 | 12 | enum { |
13 | - HEADER_TRACE_INFO = 1, | |
13 | + HEADER_RESERVED = 0, /* always cleared */ | |
14 | + HEADER_TRACE_INFO = 1, | |
14 | 15 | HEADER_BUILD_ID, |
15 | 16 | |
16 | 17 | HEADER_HOSTNAME, |
17 | 18 | |
... | ... | @@ -27,9 +28,8 @@ |
27 | 28 | HEADER_NUMA_TOPOLOGY, |
28 | 29 | |
29 | 30 | HEADER_LAST_FEATURE, |
31 | + HEADER_FEAT_BITS = 256, | |
30 | 32 | }; |
31 | - | |
32 | -#define HEADER_FEAT_BITS 256 | |
33 | 33 | |
34 | 34 | struct perf_file_section { |
35 | 35 | u64 offset; |
tools/perf/util/include/linux/bitops.h
... | ... | @@ -9,6 +9,17 @@ |
9 | 9 | #define BITS_PER_BYTE 8 |
10 | 10 | #define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long)) |
11 | 11 | |
12 | +#define for_each_set_bit(bit, addr, size) \ | |
13 | + for ((bit) = find_first_bit((addr), (size)); \ | |
14 | + (bit) < (size); \ | |
15 | + (bit) = find_next_bit((addr), (size), (bit) + 1)) | |
16 | + | |
17 | +/* same as for_each_set_bit() but use bit as value to start with */ | |
18 | +#define for_each_set_bit_cont(bit, addr, size) \ | |
19 | + for ((bit) = find_next_bit((addr), (size), (bit)); \ | |
20 | + (bit) < (size); \ | |
21 | + (bit) = find_next_bit((addr), (size), (bit) + 1)) | |
22 | + | |
12 | 23 | static inline void set_bit(int nr, unsigned long *addr) |
13 | 24 | { |
14 | 25 | addr[nr / BITS_PER_LONG] |= 1UL << (nr % BITS_PER_LONG); |
... | ... | @@ -28,6 +39,113 @@ |
28 | 39 | static inline unsigned long hweight_long(unsigned long w) |
29 | 40 | { |
30 | 41 | return sizeof(w) == 4 ? hweight32(w) : hweight64(w); |
42 | +} | |
43 | + | |
44 | +#define BITOP_WORD(nr) ((nr) / BITS_PER_LONG) | |
45 | + | |
46 | +/** | |
47 | + * __ffs - find first bit in word. | |
48 | + * @word: The word to search | |
49 | + * | |
50 | + * Undefined if no bit exists, so code should check against 0 first. | |
51 | + */ | |
52 | +static __always_inline unsigned long __ffs(unsigned long word) | |
53 | +{ | |
54 | + int num = 0; | |
55 | + | |
56 | +#if BITS_PER_LONG == 64 | |
57 | + if ((word & 0xffffffff) == 0) { | |
58 | + num += 32; | |
59 | + word >>= 32; | |
60 | + } | |
61 | +#endif | |
62 | + if ((word & 0xffff) == 0) { | |
63 | + num += 16; | |
64 | + word >>= 16; | |
65 | + } | |
66 | + if ((word & 0xff) == 0) { | |
67 | + num += 8; | |
68 | + word >>= 8; | |
69 | + } | |
70 | + if ((word & 0xf) == 0) { | |
71 | + num += 4; | |
72 | + word >>= 4; | |
73 | + } | |
74 | + if ((word & 0x3) == 0) { | |
75 | + num += 2; | |
76 | + word >>= 2; | |
77 | + } | |
78 | + if ((word & 0x1) == 0) | |
79 | + num += 1; | |
80 | + return num; | |
81 | +} | |
82 | + | |
83 | +/* | |
84 | + * Find the first set bit in a memory region. | |
85 | + */ | |
86 | +static inline unsigned long | |
87 | +find_first_bit(const unsigned long *addr, unsigned long size) | |
88 | +{ | |
89 | + const unsigned long *p = addr; | |
90 | + unsigned long result = 0; | |
91 | + unsigned long tmp; | |
92 | + | |
93 | + while (size & ~(BITS_PER_LONG-1)) { | |
94 | + if ((tmp = *(p++))) | |
95 | + goto found; | |
96 | + result += BITS_PER_LONG; | |
97 | + size -= BITS_PER_LONG; | |
98 | + } | |
99 | + if (!size) | |
100 | + return result; | |
101 | + | |
102 | + tmp = (*p) & (~0UL >> (BITS_PER_LONG - size)); | |
103 | + if (tmp == 0UL) /* Are any bits set? */ | |
104 | + return result + size; /* Nope. */ | |
105 | +found: | |
106 | + return result + __ffs(tmp); | |
107 | +} | |
108 | + | |
109 | +/* | |
110 | + * Find the next set bit in a memory region. | |
111 | + */ | |
112 | +static inline unsigned long | |
113 | +find_next_bit(const unsigned long *addr, unsigned long size, unsigned long offset) | |
114 | +{ | |
115 | + const unsigned long *p = addr + BITOP_WORD(offset); | |
116 | + unsigned long result = offset & ~(BITS_PER_LONG-1); | |
117 | + unsigned long tmp; | |
118 | + | |
119 | + if (offset >= size) | |
120 | + return size; | |
121 | + size -= result; | |
122 | + offset %= BITS_PER_LONG; | |
123 | + if (offset) { | |
124 | + tmp = *(p++); | |
125 | + tmp &= (~0UL << offset); | |
126 | + if (size < BITS_PER_LONG) | |
127 | + goto found_first; | |
128 | + if (tmp) | |
129 | + goto found_middle; | |
130 | + size -= BITS_PER_LONG; | |
131 | + result += BITS_PER_LONG; | |
132 | + } | |
133 | + while (size & ~(BITS_PER_LONG-1)) { | |
134 | + if ((tmp = *(p++))) | |
135 | + goto found_middle; | |
136 | + result += BITS_PER_LONG; | |
137 | + size -= BITS_PER_LONG; | |
138 | + } | |
139 | + if (!size) | |
140 | + return result; | |
141 | + tmp = *p; | |
142 | + | |
143 | +found_first: | |
144 | + tmp &= (~0UL >> (BITS_PER_LONG - size)); | |
145 | + if (tmp == 0UL) /* Are any bits set? */ | |
146 | + return result + size; /* Nope. */ | |
147 | +found_middle: | |
148 | + return result + __ffs(tmp); | |
31 | 149 | } |
32 | 150 | |
33 | 151 | #endif |