prog.c (9f0ca0c1a50a7de5c71970aa452941199ed210d9) | prog.c (47c09d6a9f6794caface4ad50930460b82d7c670) |
---|---|
1// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 2/* Copyright (C) 2017-2018 Netronome Systems, Inc. */ 3 4#define _GNU_SOURCE 5#include <errno.h> 6#include <fcntl.h> | 1// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 2/* Copyright (C) 2017-2018 Netronome Systems, Inc. */ 3 4#define _GNU_SOURCE 5#include <errno.h> 6#include <fcntl.h> |
7#include <signal.h> |
|
7#include <stdarg.h> 8#include <stdio.h> 9#include <stdlib.h> 10#include <string.h> 11#include <time.h> 12#include <unistd.h> 13#include <net/if.h> | 8#include <stdarg.h> 9#include <stdio.h> 10#include <stdlib.h> 11#include <string.h> 12#include <time.h> 13#include <unistd.h> 14#include <net/if.h> |
15#include <sys/ioctl.h> |
|
14#include <sys/types.h> 15#include <sys/stat.h> | 16#include <sys/types.h> 17#include <sys/stat.h> |
18#include <sys/syscall.h> |
|
16 17#include <linux/err.h> | 19 20#include <linux/err.h> |
21#include <linux/perf_event.h> |
|
18#include <linux/sizes.h> 19 20#include <bpf/bpf.h> 21#include <bpf/btf.h> 22#include <bpf/libbpf.h> 23 24#include "cfg.h" 25#include "main.h" --- 1506 unchanged lines hidden (view full) --- 1532 return load_with_options(argc, argv, true); 1533} 1534 1535static int do_loadall(int argc, char **argv) 1536{ 1537 return load_with_options(argc, argv, false); 1538} 1539 | 22#include <linux/sizes.h> 23 24#include <bpf/bpf.h> 25#include <bpf/btf.h> 26#include <bpf/libbpf.h> 27 28#include "cfg.h" 29#include "main.h" --- 1506 unchanged lines hidden (view full) --- 1536 return load_with_options(argc, argv, true); 1537} 1538 1539static int do_loadall(int argc, char **argv) 1540{ 1541 return load_with_options(argc, argv, false); 1542} 1543 |
1544#ifdef BPFTOOL_WITHOUT_SKELETONS 1545 1546static int do_profile(int argc, char **argv) 1547{ 1548 return 0; 1549} 1550 1551#else /* BPFTOOL_WITHOUT_SKELETONS */ 1552 1553#include "profiler.skel.h" 1554 1555struct profile_metric { 1556 const char *name; 1557 struct bpf_perf_event_value val; 1558 struct perf_event_attr attr; 1559 bool selected; 1560 1561 /* calculate ratios like instructions per cycle */ 1562 const int ratio_metric; /* 0 for N/A, 1 for index 0 (cycles) */ 1563 const char *ratio_desc; 1564 const float ratio_mul; 1565} metrics[] = { 1566 { 1567 .name = "cycles", 1568 .attr = { 1569 .type = PERF_TYPE_HARDWARE, 1570 .config = PERF_COUNT_HW_CPU_CYCLES, 1571 .exclude_user = 1, 1572 }, 1573 }, 1574 { 1575 .name = "instructions", 1576 .attr = { 1577 .type = PERF_TYPE_HARDWARE, 1578 .config = PERF_COUNT_HW_INSTRUCTIONS, 1579 .exclude_user = 1, 1580 }, 1581 .ratio_metric = 1, 1582 .ratio_desc = "insns per cycle", 1583 .ratio_mul = 1.0, 1584 }, 1585 { 1586 .name = "l1d_loads", 1587 .attr = { 1588 .type = PERF_TYPE_HW_CACHE, 1589 .config = 1590 PERF_COUNT_HW_CACHE_L1D | 1591 (PERF_COUNT_HW_CACHE_OP_READ << 8) | 1592 (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16), 1593 .exclude_user = 1, 1594 }, 1595 }, 1596 { 1597 .name = "llc_misses", 1598 .attr = { 1599 .type = PERF_TYPE_HW_CACHE, 1600 .config = 1601 PERF_COUNT_HW_CACHE_LL | 1602 (PERF_COUNT_HW_CACHE_OP_READ << 8) | 1603 (PERF_COUNT_HW_CACHE_RESULT_MISS << 16), 1604 .exclude_user = 1 1605 }, 1606 .ratio_metric = 2, 1607 .ratio_desc = "LLC misses per million insns", 1608 .ratio_mul = 1e6, 1609 }, 1610}; 1611 1612static __u64 profile_total_count; 1613 1614#define MAX_NUM_PROFILE_METRICS 4 1615 1616static int profile_parse_metrics(int argc, char **argv) 1617{ 1618 unsigned int metric_cnt; 1619 int selected_cnt = 0; 1620 unsigned int i; 1621 1622 metric_cnt = sizeof(metrics) / sizeof(struct profile_metric); 1623 1624 while (argc > 0) { 1625 for (i = 0; i < metric_cnt; i++) { 1626 if (is_prefix(argv[0], metrics[i].name)) { 1627 if (!metrics[i].selected) 1628 selected_cnt++; 1629 metrics[i].selected = true; 1630 break; 1631 } 1632 } 1633 if (i == metric_cnt) { 1634 p_err("unknown metric %s", argv[0]); 1635 return -1; 1636 } 1637 NEXT_ARG(); 1638 } 1639 if (selected_cnt > MAX_NUM_PROFILE_METRICS) { 1640 p_err("too many (%d) metrics, please specify no more than %d metrics at at time", 1641 selected_cnt, MAX_NUM_PROFILE_METRICS); 1642 return -1; 1643 } 1644 return selected_cnt; 1645} 1646 1647static void profile_read_values(struct profiler_bpf *obj) 1648{ 1649 __u32 m, cpu, num_cpu = obj->rodata->num_cpu; 1650 int reading_map_fd, count_map_fd; 1651 __u64 counts[num_cpu]; 1652 __u32 key = 0; 1653 int err; 1654 1655 reading_map_fd = bpf_map__fd(obj->maps.accum_readings); 1656 count_map_fd = bpf_map__fd(obj->maps.counts); 1657 if (reading_map_fd < 0 || count_map_fd < 0) { 1658 p_err("failed to get fd for map"); 1659 return; 1660 } 1661 1662 err = bpf_map_lookup_elem(count_map_fd, &key, counts); 1663 if (err) { 1664 p_err("failed to read count_map: %s", strerror(errno)); 1665 return; 1666 } 1667 1668 profile_total_count = 0; 1669 for (cpu = 0; cpu < num_cpu; cpu++) 1670 profile_total_count += counts[cpu]; 1671 1672 for (m = 0; m < ARRAY_SIZE(metrics); m++) { 1673 struct bpf_perf_event_value values[num_cpu]; 1674 1675 if (!metrics[m].selected) 1676 continue; 1677 1678 err = bpf_map_lookup_elem(reading_map_fd, &key, values); 1679 if (err) { 1680 p_err("failed to read reading_map: %s", 1681 strerror(errno)); 1682 return; 1683 } 1684 for (cpu = 0; cpu < num_cpu; cpu++) { 1685 metrics[m].val.counter += values[cpu].counter; 1686 metrics[m].val.enabled += values[cpu].enabled; 1687 metrics[m].val.running += values[cpu].running; 1688 } 1689 key++; 1690 } 1691} 1692 1693static void profile_print_readings_json(void) 1694{ 1695 __u32 m; 1696 1697 jsonw_start_array(json_wtr); 1698 for (m = 0; m < ARRAY_SIZE(metrics); m++) { 1699 if (!metrics[m].selected) 1700 continue; 1701 jsonw_start_object(json_wtr); 1702 jsonw_string_field(json_wtr, "metric", metrics[m].name); 1703 jsonw_lluint_field(json_wtr, "run_cnt", profile_total_count); 1704 jsonw_lluint_field(json_wtr, "value", metrics[m].val.counter); 1705 jsonw_lluint_field(json_wtr, "enabled", metrics[m].val.enabled); 1706 jsonw_lluint_field(json_wtr, "running", metrics[m].val.running); 1707 1708 jsonw_end_object(json_wtr); 1709 } 1710 jsonw_end_array(json_wtr); 1711} 1712 1713static void profile_print_readings_plain(void) 1714{ 1715 __u32 m; 1716 1717 printf("\n%18llu %-20s\n", profile_total_count, "run_cnt"); 1718 for (m = 0; m < ARRAY_SIZE(metrics); m++) { 1719 struct bpf_perf_event_value *val = &metrics[m].val; 1720 int r; 1721 1722 if (!metrics[m].selected) 1723 continue; 1724 printf("%18llu %-20s", val->counter, metrics[m].name); 1725 1726 r = metrics[m].ratio_metric - 1; 1727 if (r >= 0 && metrics[r].selected && 1728 metrics[r].val.counter > 0) { 1729 printf("# %8.2f %-30s", 1730 val->counter * metrics[m].ratio_mul / 1731 metrics[r].val.counter, 1732 metrics[m].ratio_desc); 1733 } else { 1734 printf("%-41s", ""); 1735 } 1736 1737 if (val->enabled > val->running) 1738 printf("(%4.2f%%)", 1739 val->running * 100.0 / val->enabled); 1740 printf("\n"); 1741 } 1742} 1743 1744static void profile_print_readings(void) 1745{ 1746 if (json_output) 1747 profile_print_readings_json(); 1748 else 1749 profile_print_readings_plain(); 1750} 1751 1752static char *profile_target_name(int tgt_fd) 1753{ 1754 struct bpf_prog_info_linear *info_linear; 1755 struct bpf_func_info *func_info; 1756 const struct btf_type *t; 1757 char *name = NULL; 1758 struct btf *btf; 1759 1760 info_linear = bpf_program__get_prog_info_linear( 1761 tgt_fd, 1UL << BPF_PROG_INFO_FUNC_INFO); 1762 if (IS_ERR_OR_NULL(info_linear)) { 1763 p_err("failed to get info_linear for prog FD %d", tgt_fd); 1764 return NULL; 1765 } 1766 1767 if (info_linear->info.btf_id == 0 || 1768 btf__get_from_id(info_linear->info.btf_id, &btf)) { 1769 p_err("prog FD %d doesn't have valid btf", tgt_fd); 1770 goto out; 1771 } 1772 1773 func_info = (struct bpf_func_info *)(info_linear->info.func_info); 1774 t = btf__type_by_id(btf, func_info[0].type_id); 1775 if (!t) { 1776 p_err("btf %d doesn't have type %d", 1777 info_linear->info.btf_id, func_info[0].type_id); 1778 goto out; 1779 } 1780 name = strdup(btf__name_by_offset(btf, t->name_off)); 1781out: 1782 free(info_linear); 1783 return name; 1784} 1785 1786static struct profiler_bpf *profile_obj; 1787static int profile_tgt_fd = -1; 1788static char *profile_tgt_name; 1789static int *profile_perf_events; 1790static int profile_perf_event_cnt; 1791 1792static void profile_close_perf_events(struct profiler_bpf *obj) 1793{ 1794 int i; 1795 1796 for (i = profile_perf_event_cnt - 1; i >= 0; i--) 1797 close(profile_perf_events[i]); 1798 1799 free(profile_perf_events); 1800 profile_perf_event_cnt = 0; 1801} 1802 1803static int profile_open_perf_events(struct profiler_bpf *obj) 1804{ 1805 unsigned int cpu, m; 1806 int map_fd, pmu_fd; 1807 1808 profile_perf_events = calloc( 1809 sizeof(int), obj->rodata->num_cpu * obj->rodata->num_metric); 1810 if (!profile_perf_events) { 1811 p_err("failed to allocate memory for perf_event array: %s", 1812 strerror(errno)); 1813 return -1; 1814 } 1815 map_fd = bpf_map__fd(obj->maps.events); 1816 if (map_fd < 0) { 1817 p_err("failed to get fd for events map"); 1818 return -1; 1819 } 1820 1821 for (m = 0; m < ARRAY_SIZE(metrics); m++) { 1822 if (!metrics[m].selected) 1823 continue; 1824 for (cpu = 0; cpu < obj->rodata->num_cpu; cpu++) { 1825 pmu_fd = syscall(__NR_perf_event_open, &metrics[m].attr, 1826 -1/*pid*/, cpu, -1/*group_fd*/, 0); 1827 if (pmu_fd < 0 || 1828 bpf_map_update_elem(map_fd, &profile_perf_event_cnt, 1829 &pmu_fd, BPF_ANY) || 1830 ioctl(pmu_fd, PERF_EVENT_IOC_ENABLE, 0)) { 1831 p_err("failed to create event %s on cpu %d", 1832 metrics[m].name, cpu); 1833 return -1; 1834 } 1835 profile_perf_events[profile_perf_event_cnt++] = pmu_fd; 1836 } 1837 } 1838 return 0; 1839} 1840 1841static void profile_print_and_cleanup(void) 1842{ 1843 profile_close_perf_events(profile_obj); 1844 profile_read_values(profile_obj); 1845 profile_print_readings(); 1846 profiler_bpf__destroy(profile_obj); 1847 1848 close(profile_tgt_fd); 1849 free(profile_tgt_name); 1850} 1851 1852static void int_exit(int signo) 1853{ 1854 profile_print_and_cleanup(); 1855 exit(0); 1856} 1857 1858static int do_profile(int argc, char **argv) 1859{ 1860 int num_metric, num_cpu, err = -1; 1861 struct bpf_program *prog; 1862 unsigned long duration; 1863 char *endptr; 1864 1865 /* we at least need two args for the prog and one metric */ 1866 if (!REQ_ARGS(3)) 1867 return -EINVAL; 1868 1869 /* parse target fd */ 1870 profile_tgt_fd = prog_parse_fd(&argc, &argv); 1871 if (profile_tgt_fd < 0) { 1872 p_err("failed to parse fd"); 1873 return -1; 1874 } 1875 1876 /* parse profiling optional duration */ 1877 if (argc > 2 && is_prefix(argv[0], "duration")) { 1878 NEXT_ARG(); 1879 duration = strtoul(*argv, &endptr, 0); 1880 if (*endptr) 1881 usage(); 1882 NEXT_ARG(); 1883 } else { 1884 duration = UINT_MAX; 1885 } 1886 1887 num_metric = profile_parse_metrics(argc, argv); 1888 if (num_metric <= 0) 1889 goto out; 1890 1891 num_cpu = libbpf_num_possible_cpus(); 1892 if (num_cpu <= 0) { 1893 p_err("failed to identify number of CPUs"); 1894 goto out; 1895 } 1896 1897 profile_obj = profiler_bpf__open(); 1898 if (!profile_obj) { 1899 p_err("failed to open and/or load BPF object"); 1900 goto out; 1901 } 1902 1903 profile_obj->rodata->num_cpu = num_cpu; 1904 profile_obj->rodata->num_metric = num_metric; 1905 1906 /* adjust map sizes */ 1907 bpf_map__resize(profile_obj->maps.events, num_metric * num_cpu); 1908 bpf_map__resize(profile_obj->maps.fentry_readings, num_metric); 1909 bpf_map__resize(profile_obj->maps.accum_readings, num_metric); 1910 bpf_map__resize(profile_obj->maps.counts, 1); 1911 1912 /* change target name */ 1913 profile_tgt_name = profile_target_name(profile_tgt_fd); 1914 if (!profile_tgt_name) 1915 goto out; 1916 1917 bpf_object__for_each_program(prog, profile_obj->obj) { 1918 err = bpf_program__set_attach_target(prog, profile_tgt_fd, 1919 profile_tgt_name); 1920 if (err) { 1921 p_err("failed to set attach target\n"); 1922 goto out; 1923 } 1924 } 1925 1926 set_max_rlimit(); 1927 err = profiler_bpf__load(profile_obj); 1928 if (err) { 1929 p_err("failed to load profile_obj"); 1930 goto out; 1931 } 1932 1933 err = profile_open_perf_events(profile_obj); 1934 if (err) 1935 goto out; 1936 1937 err = profiler_bpf__attach(profile_obj); 1938 if (err) { 1939 p_err("failed to attach profile_obj"); 1940 goto out; 1941 } 1942 signal(SIGINT, int_exit); 1943 1944 sleep(duration); 1945 profile_print_and_cleanup(); 1946 return 0; 1947 1948out: 1949 profile_close_perf_events(profile_obj); 1950 if (profile_obj) 1951 profiler_bpf__destroy(profile_obj); 1952 close(profile_tgt_fd); 1953 free(profile_tgt_name); 1954 return err; 1955} 1956 1957#endif /* BPFTOOL_WITHOUT_SKELETONS */ 1958 |
|
1540static int do_help(int argc, char **argv) 1541{ 1542 if (json_output) { 1543 jsonw_null(json_wtr); 1544 return 0; 1545 } 1546 1547 fprintf(stderr, --- 7 unchanged lines hidden (view full) --- 1555 " [pinmaps MAP_DIR]\n" 1556 " %s %s attach PROG ATTACH_TYPE [MAP]\n" 1557 " %s %s detach PROG ATTACH_TYPE [MAP]\n" 1558 " %s %s run PROG \\\n" 1559 " data_in FILE \\\n" 1560 " [data_out FILE [data_size_out L]] \\\n" 1561 " [ctx_in FILE [ctx_out FILE [ctx_size_out M]]] \\\n" 1562 " [repeat N]\n" | 1959static int do_help(int argc, char **argv) 1960{ 1961 if (json_output) { 1962 jsonw_null(json_wtr); 1963 return 0; 1964 } 1965 1966 fprintf(stderr, --- 7 unchanged lines hidden (view full) --- 1974 " [pinmaps MAP_DIR]\n" 1975 " %s %s attach PROG ATTACH_TYPE [MAP]\n" 1976 " %s %s detach PROG ATTACH_TYPE [MAP]\n" 1977 " %s %s run PROG \\\n" 1978 " data_in FILE \\\n" 1979 " [data_out FILE [data_size_out L]] \\\n" 1980 " [ctx_in FILE [ctx_out FILE [ctx_size_out M]]] \\\n" 1981 " [repeat N]\n" |
1982 " %s %s profile PROG [duration DURATION] METRICs\n" |
|
1563 " %s %s tracelog\n" 1564 " %s %s help\n" 1565 "\n" 1566 " " HELP_SPEC_MAP "\n" 1567 " " HELP_SPEC_PROGRAM "\n" 1568 " TYPE := { socket | kprobe | kretprobe | classifier | action |\n" 1569 " tracepoint | raw_tracepoint | xdp | perf_event | cgroup/skb |\n" 1570 " cgroup/sock | cgroup/dev | lwt_in | lwt_out | lwt_xmit |\n" 1571 " lwt_seg6local | sockops | sk_skb | sk_msg | lirc_mode2 |\n" 1572 " sk_reuseport | flow_dissector | cgroup/sysctl |\n" 1573 " cgroup/bind4 | cgroup/bind6 | cgroup/post_bind4 |\n" 1574 " cgroup/post_bind6 | cgroup/connect4 | cgroup/connect6 |\n" 1575 " cgroup/sendmsg4 | cgroup/sendmsg6 | cgroup/recvmsg4 |\n" 1576 " cgroup/recvmsg6 | cgroup/getsockopt | cgroup/setsockopt |\n" 1577 " struct_ops | fentry | fexit | freplace }\n" 1578 " ATTACH_TYPE := { msg_verdict | stream_verdict | stream_parser |\n" 1579 " flow_dissector }\n" | 1983 " %s %s tracelog\n" 1984 " %s %s help\n" 1985 "\n" 1986 " " HELP_SPEC_MAP "\n" 1987 " " HELP_SPEC_PROGRAM "\n" 1988 " TYPE := { socket | kprobe | kretprobe | classifier | action |\n" 1989 " tracepoint | raw_tracepoint | xdp | perf_event | cgroup/skb |\n" 1990 " cgroup/sock | cgroup/dev | lwt_in | lwt_out | lwt_xmit |\n" 1991 " lwt_seg6local | sockops | sk_skb | sk_msg | lirc_mode2 |\n" 1992 " sk_reuseport | flow_dissector | cgroup/sysctl |\n" 1993 " cgroup/bind4 | cgroup/bind6 | cgroup/post_bind4 |\n" 1994 " cgroup/post_bind6 | cgroup/connect4 | cgroup/connect6 |\n" 1995 " cgroup/sendmsg4 | cgroup/sendmsg6 | cgroup/recvmsg4 |\n" 1996 " cgroup/recvmsg6 | cgroup/getsockopt | cgroup/setsockopt |\n" 1997 " struct_ops | fentry | fexit | freplace }\n" 1998 " ATTACH_TYPE := { msg_verdict | stream_verdict | stream_parser |\n" 1999 " flow_dissector }\n" |
2000 " METRIC := { cycles | instructions | l1d_loads | llc_misses }\n" |
|
1580 " " HELP_SPEC_OPTIONS "\n" 1581 "", 1582 bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], 1583 bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], 1584 bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], | 2001 " " HELP_SPEC_OPTIONS "\n" 2002 "", 2003 bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], 2004 bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], 2005 bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], |
1585 bin_name, argv[-2]); | 2006 bin_name, argv[-2], bin_name, argv[-2]); |
1586 1587 return 0; 1588} 1589 1590static const struct cmd cmds[] = { 1591 { "show", do_show }, 1592 { "list", do_show }, 1593 { "help", do_help }, 1594 { "dump", do_dump }, 1595 { "pin", do_pin }, 1596 { "load", do_load }, 1597 { "loadall", do_loadall }, 1598 { "attach", do_attach }, 1599 { "detach", do_detach }, 1600 { "tracelog", do_tracelog }, 1601 { "run", do_run }, | 2007 2008 return 0; 2009} 2010 2011static const struct cmd cmds[] = { 2012 { "show", do_show }, 2013 { "list", do_show }, 2014 { "help", do_help }, 2015 { "dump", do_dump }, 2016 { "pin", do_pin }, 2017 { "load", do_load }, 2018 { "loadall", do_loadall }, 2019 { "attach", do_attach }, 2020 { "detach", do_detach }, 2021 { "tracelog", do_tracelog }, 2022 { "run", do_run }, |
2023 { "profile", do_profile }, |
|
1602 { 0 } 1603}; 1604 1605int do_prog(int argc, char **argv) 1606{ 1607 return cmd_select(cmds, argc, argv, do_help); 1608} | 2024 { 0 } 2025}; 2026 2027int do_prog(int argc, char **argv) 2028{ 2029 return cmd_select(cmds, argc, argv, do_help); 2030} |