### Example: Using tracecmd_get_traceid and tracecmd_get_guest_cpumap Source: https://www.trace-cmd.org/Documentation/libtracecmd/libtracecmd-peer.html Example showing how to open host and guest trace files, retrieve trace IDs, and get guest CPU mappings. The returned name, vcpu_count, and cpu_pid values must not be freed. ```c #include ... struct tracecmd_input *host = tracecmd_open("trace.dat"); if (!host) { /* Failed to open host trace file */ } struct tracecmd_input *guest1 = tracecmd_open_head("trace-Guest1.dat"); if (!guest1) { /* Failed to open guest1 trace file */ } struct tracecmd_input *guest2 = tracecmd_open_head("trace-Guest2.dat"); if (!guest2) { /* Failed to open guest2 trace file */ } unsigned long long guest_id_1 = tracecmd_get_traceid(guest1); unsigned long long guest_id_2 = tracecmd_get_traceid(guest2); int *cpu_pid_1, *cpu_pid_2; int vcount_1, vcount_2; char *name_1, *name_2; if (!tracecmd_get_guest_cpumap(host, guest_id_1, &name_1, &vcount_1, &cpu_pid_1)) { /* The Host and a guest1 with name_1 are part of the same trace session. * Got guest1 VCPU to host PID mapping. */ } if (!tracecmd_get_guest_cpumap(host, guest_id_2, &name_2, &vcount_2, &cpu_pid_2)) { /* The Host and a guest2 with name_2 are part of the same trace session. * Got guest2 VCPU to host PID mapping. */ } ... tracecmd_close(guest1); tracecmd_close(guest2); tracecmd_close(handle); ``` -------------------------------- ### Example usage of tracefs option functions Source: https://www.trace-cmd.org/Documentation/libtracefs/libtracefs-option-misc.html Example showing how to enable, disable, and get the name of ftrace options. Note that the returned name string must not be freed. ```c #include ... if (tracefs_option_enable(NULL, TRACEFS_OPTION_ANNOTATE)) { /* Failed to enable annotate option in top trace instance */ } ... if (tracefs_option_disable(NULL, TRACEFS_OPTION_CONTEXT_INFO)) { /* Failed to disable context info option in top trace instance */ } ... char *name = tracefs_option_name(TRACEFS_OPTION_FUNC_STACKTRACE); if (strcmp(name, "unknown")) { /* Cannot get the name of the option */ } ``` -------------------------------- ### Example: Using tracefs options API Source: https://www.trace-cmd.org/Documentation/libtracefs/libtracefs-option-get.html Example usage of the tracefs options API. It gets supported and enabled options for the top instance, checks if the latency format option is supported and if the stacktrace option is enabled. ```c #include ... const struct tracefs_options_mask *options; ... options = tracefs_options_get_supported(NULL); if (!options) { /* Failed to get supported options */ } else { ... } ... options = tracefs_options_get_enabled(NULL); if (!options) { /* Failed to get options, enabled in the top instance */ } else { ... } if (tracefs_options_mask_is_set(options, TRACEFS_OPTION_LATENCY_FORMAT)) { ... } ... if (tracefs_option_is_supported(NULL, TRACEFS_OPTION_LATENCY_FORMAT)) { /* Latency format option is supprted */ } ... if (tracefs_option_is_enabled(NULL, TRACEFS_OPTION_STACKTRACE)) { /* Stacktrace option is enabled in the top instance */ } ``` -------------------------------- ### Example usage of tracefs_binary_init, tracefs_binary_write, tracefs_binary_close Source: https://www.trace-cmd.org/Documentation/libtracefs/libtracefs-marker_raw.html Example C code showing initialization, writing a 32-bit value, and closing the library. The example uses NULL for the top trace instance and checks return values for errors. ```c #include if (tracefs_binary_init(NULL) < 0) { /* Failed to initialize the library for writing in the trace buffer of the top trace instance */ } unsigned int data = 0xdeadbeef; if (tracefs_binary_write(NULL, &data, sizeof(data)) < 0) { /* Failed to write in the trace buffer */ } tracefs_binary_close(); ``` -------------------------------- ### tracefs_hist_* command-line example Source: https://www.trace-cmd.org/Documentation/libtracefs/libtracefs-hist-cont.html This example creates a 2D histogram for the kmem/kmalloc event, adds values and sort keys, and then executes a command (start, pause, cont, reset, delete, show) based on the first argument. It demonstrates the use of tracefs_hist_alloc_2d, tracefs_hist_add_value, tracefs_hist_add_sort_key, tracefs_hist_sort_key_direction, and the control functions. The program returns 0 on success or -1 on error. ```c #include #include enum commands { START, PAUSE, CONT, RESET, DELETE, SHOW, }; int main (int argc, char **argv, char **env) { struct tracefs_instance *instance; struct tracefs_hist *hist; struct tep_handle *tep; enum commands cmd; char *cmd_str; int ret; if (argc < 2) { fprintf(stderr, "usage: %s command\n", argv[0]); exit(-1); } cmd_str = argv[1]; if (!strcmp(cmd_str, "start")) cmd = START; else if (!strcmp(cmd_str, "pause")) cmd = PAUSE; else if (!strcmp(cmd_str, "cont")) cmd = CONT; else if (!strcmp(cmd_str, "reset")) cmd = RESET; else if (!strcmp(cmd_str, "delete")) cmd = DELETE; else if (!strcmp(cmd_str, "show")) cmd = SHOW; else { fprintf(stderr, "Unknown command %s\n", cmd_str); exit(-1); } tep = tracefs_local_events(NULL); if (!tep) { perror("Reading tracefs"); exit(-1); } instance = tracefs_instance_create("hist_test"); if (!instance) { fprintf(stderr, "Failed instance create\n"); exit(-1); } hist = tracefs_hist_alloc_2d(tep, "kmem", "kmalloc", "call_site",TRACEFS_HIST_KEY_SYM, "bytes_req", 0); if (!hist) { fprintf(stderr, "Failed hist create\n"); exit(-1); } ret = tracefs_hist_add_value(hist, "bytes_alloc"); ret |= tracefs_hist_add_sort_key(hist, "bytes_req"); ret |= tracefs_hist_add_sort_key(hist, "bytes_alloc"); ret |= tracefs_hist_sort_key_direction(hist, "bytes_alloc", TRACEFS_HIST_SORT_DESCENDING); if (ret) { fprintf(stderr, "Failed modifying histogram\n"); exit(-1); } tracefs_error_clear(instance); switch (cmd) { case START: ret = tracefs_hist_start(instance, hist); if (ret) { char *err = tracefs_error_last(instance); if (err) fprintf(stderr, "\n%s\n", err); } break; case PAUSE: ret = tracefs_hist_pause(instance, hist); break; case CONT: ret = tracefs_hist_continue(instance, hist); break; case RESET: ret = tracefs_hist_reset(instance, hist); break; case DELETE: ret = tracefs_hist_destroy(instance, hist); break; case SHOW: { char *content; content = tracefs_event_file_read(instance, "kmem", "kmalloc", "hist", NULL); ret = content ? 0 : -1; if (content) { printf("%s\n", content); free(content); } break; } } if (ret) fprintf(stderr, "Failed: command\n"); exit(ret); } ``` -------------------------------- ### Example usage of trace_seq functions Source: https://www.trace-cmd.org/Documentation/libtraceevent/libtraceevent-tseq.html Complete example showing initialization, writing with puts/putc/printf/vprintf, termination, and output to stdout and a file. Includes error checks for each operation. ```c #include #include ... struct trace_seq seq; trace_seq_init(&seq); ... void foo_seq_print(struct trace_seq *tseq, char *format, ...) { va_list ap; va_start(ap, format); if (trace_seq_vprintf(tseq, format, ap) <= 0) { /* Failed to print in the trace sequence */ } va_end(ap); } trace_seq_reset(&seq); char *str = " MAN page example"; if (trace_seq_puts(&seq, str) != strlen(str)) { /* Failed to put str in the trace sequence */ } if (trace_seq_putc(&seq, ':') != 1) { /* Failed to put ':' in the trace sequence */ } if (trace_seq_printf(&seq, " trace sequence: %d", 1) <= 0) { /* Failed to print in the trace sequence */ } foo_seq_print( &seq, " %d\n", 2); trace_seq_terminate(&seq); ... if (trace_seq_do_printf(&seq) < 0 ) { /* Failed to print the sequence buffer to the standard output */ } FILE *fp = fopen("trace.txt", "w"); if (trace_seq_do_fprintf(&seq, fp) < 0 ) [ /* Failed to print the sequence buffer to the trace.txt file */ } trace_seq_destroy(&seq); ... ``` -------------------------------- ### Example usage of tracefs instance utility functions Source: https://www.trace-cmd.org/Documentation/libtracefs/libtracefs-instances-utils.html This example demonstrates how to use tracefs_instance_get_name, tracefs_instance_get_trace_dir, tracefs_instances_walk, and tracefs_instance_exists. It includes a callback function for tracefs_instances_walk and checks for errors and existence. The example is incomplete, as indicated by the ellipsis, and assumes an existing tracefs_instance pointer. ```c #include struct tracefs_instance *inst; .... char *name = tracefs_instance_get_name(inst); if(name) { /* Got name of the instance */ } char *dir = tracefs_instance_get_trace_dir(inst); if(dir) { /* Got tracing directory of the instance */ } ... static int instance_walk(char *name, void *context) { /* Got instance with name */ return 0; } ... if (tracefs_instances_walk(instance_walk, NULL) < 0) { /* Error walking through the instances */ } ... if (tracefs_instance_exists("foo")) { /* There is instance with name foo in the system */ } else { /* There is no instance with name foo in the system */ } ``` -------------------------------- ### Example: redirect trace data to a file with tracefs_trace_pipe_stream Source: https://www.trace-cmd.org/Documentation/libtracefs/libtracefs-stream.html Complete example program that creates an output file, installs a SIGINT handler to stop the trace pipe, and calls tracefs_trace_pipe_stream with SPLICE_F_NONBLOCK. Returns the number of bytes transferred or -1 on error. ```c #include #include #include #include #include #include void stop(int sig) { tracefs_trace_pipe_stop(NULL); } int main(int argc, char **argv) { mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; const char *filename; int fd; int ret; if (argc < 2) { fprintf(stderr, "usage: %s output_file\n", argv[0]); exit(-1); } filename = argv[1]; fd = creat(filename, mode); if (fd < 0) { perror(filename); exit(-1); } signal(SIGINT, stop); ret = tracefs_trace_pipe_stream(fd, NULL, SPLICE_F_NONBLOCK); close(fd); return ret; } ``` -------------------------------- ### libtracefs histogram API usage example Source: https://www.trace-cmd.org/Documentation/libtracefs/libtracefs-hist.html C example showing how to allocate histograms (1D, 2D, or N-dimensional with buckets), add values and sort keys, set sort direction, and run commands (START, PAUSE, CONT, RESET, DELETE, SHOW) on a trace instance. Includes error handling and usage message. ```c /* buckets require the nd_cnt function */ switch (cnt) { case 2: if (axes[1].type == TRACEFS_HIST_KEY_BUCKETS) cnt = -1; /* fall through */ case 1: if (axes[0].type == TRACEFS_HIST_KEY_BUCKETS) cnt = -1; } /* Show examples of hist1d and hist2d */ switch (cnt) { case 1: hist = tracefs_hist_alloc(tep, system, event, axes[0].key, axes[0].type); break; case 2: hist = tracefs_hist_alloc_2d(tep, system, event, axes[0].key, axes[0].type, axes[1].key, axes[1].type); break; default: /* Really, 1 and 2 could use this too */ hist = tracefs_hist_alloc_nd_cnt(tep, system, event, axes); } if (!hist) { fprintf(stderr, "Failed hist create\n"); exit(-1); } if (vals) { sav = NULL; for (val = strtok_r(vals, ",", &sav); val; val = strtok_r(NULL, ",", &sav)) { ret = tracefs_hist_add_value(hist, val); if (ret) { fprintf(stderr, "Failed to add value %s\n", val); exit(-1); } } } if (sort) { sav = NULL; for (val = strtok_r(sort, ",", &sav); val; val = strtok_r(NULL, ",", &sav)) { ret = tracefs_hist_add_sort_key(hist, val); if (ret) { fprintf(stderr, "Failed to add sort key/val %s\n", val); exit(-1); } } } if (ascend) { sav = NULL; for (val = strtok_r(ascend, ",", &sav); val; val = strtok_r(NULL, ",", &sav)) { ret = tracefs_hist_sort_key_direction(hist, val, TRACEFS_HIST_SORT_ASCENDING); if (ret) { fprintf(stderr, "Failed to add ascending key/val %s\n", val); exit(-1); } } } if (desc) { sav = NULL; for (val = strtok_r(desc, ",", &sav); val; val = strtok_r(NULL, ",", &sav)) { ret = tracefs_hist_sort_key_direction(hist, val, TRACEFS_HIST_SORT_DESCENDING); if (ret) { fprintf(stderr, "Failed to add descending key/val %s\n", val); exit(-1); } } } tracefs_error_clear(instance); switch (cmd) { case START: ret = tracefs_hist_start(instance, hist); if (ret) { char *err = tracefs_error_last(instance); if (err) fprintf(stderr, "\n%s\n", err); } break; case PAUSE: ret = tracefs_hist_pause(instance, hist); break; case CONT: ret = tracefs_hist_continue(instance, hist); break; case RESET: ret = tracefs_hist_reset(instance, hist); break; case DELETE: ret = tracefs_hist_destroy(instance, hist); break; case SHOW: /* Show was already done */ break; } if (ret) fprintf(stderr, "Failed: command\n"); exit(ret); } int main (int argc, char **argv, char **env) { enum commands cmd; char *instance = NULL; char *cmd_str; char *event = NULL; char *keys = NULL; char *vals = NULL; char *sort = NULL; char *desc = NULL; char *ascend = NULL; if (argc < 2) { fprintf(stderr, "usage: %s command [-B instance][-e [system/]event][-k keys][-v vals][-s sort]\n", argv[0]); fprintf(stderr, " [-a ascending][-d descending]\n"); exit(-1); } cmd_str = argv[1]; ``` -------------------------------- ### Example: reading tracing instances from trace.dat Source: https://www.trace-cmd.org/Documentation/libtracecmd/libtracecmd-instances.html Shows how to open a trace file, iterate over instances, get names and handles, and close them. The returned name must not be freed; the instance handle must be closed with tracecmd_close(). ```c #include ... struct tracecmd_input *handle = tracecmd_open_head("trace.dat"); if (!handle) { /* Failed to open trace.dat file */ } ... int num = tracecmd_buffer_instances(handle); while(num) { struct tracecmd_input *h; char *name; name = tracecmd_buffer_instance_name(handle, num); if (!name) { /* Failed to get name of instance num */ } h = tracecmd_buffer_instance_handle(handle, num); if (!h) { /* Failed to initialize handler for instance num */ } ... tracecmd_close(h); num--; } ... tracecmd_close(handle); ``` -------------------------------- ### Example usage of header page functions Source: https://www.trace-cmd.org/Documentation/libtraceevent/libtraceevent-header_page.html Example showing how to call the three functions and print the results. Assumes a valid tep handle from tep_alloc(). ```c #include ... struct tep_handle *tep = tep_alloc(); ... int longsize; int timesize; bool old; longsize = tep_get_header_page_size(tep); timesize = tep_get_header_timestamp_size(tep); old = tep_is_old_format(tep); printf ("%s kernel is used to generate the tracing data.\n", old?"Old":"New"); printf("The size of a long integer is %d bytes.\n", longsize); printf("The timestamps size is %d bytes.\n", timesize); ... ``` -------------------------------- ### Example: Creating a Synthetic Event Source: https://www.trace-cmd.org/Documentation/libtracefs/libtracefs-synth2.html This example demonstrates how to use the tracefs_synth API to create a synthetic event that measures wakeup latency. ```APIDOC ## Example: Creating a Synthetic Event ### Description This example demonstrates how to use the tracefs_synth API to create a synthetic event that measures wakeup latency. ### Code ```c #include #include #define start_event "sched_waking" #define start_field "pid" #define end_event "sched_switch" #define end_field "next_pid" #define match_name "pid" static struct tracefs_synth *synth; static void make_event(void) { struct tep_handle *tep; /* Load all events from the system */ tep = tracefs_local_events(NULL); /* Initialize the synthetic event */ synth = tracefs_synth_alloc(tep, "wakeup_lat", NULL, start_event, NULL, end_event, start_field, end_field, match_name); /* The tep is no longer needed */ tep_free(tep); /* Save the "prio" field as "prio" from the start event */ tracefs_synth_add_start_field(synth, "prio", NULL); /* Save the "next_comm" as "comm" from the end event */ tracefs_synth_add_end_field(synth, "next_comm", "comm"); /* Save the "prev_prio" as "prev_prio" from the end event */ tracefs_synth_add_end_field(synth, "prev_prio", NULL); /* * Take a microsecond time difference between end and start * and record as "delta" */ tracefs_synth_add_compare_field(synth, TRACEFS_TIMESTAMP_USECS, TRACEFS_TIMESTAMP_USECS, TRACEFS_SYNTH_DELTA_END, "delta"); /* Only record if start event "prio" is less than 100 */ tracefs_synth_append_start_filter(synth, TRACEFS_FILTER_COMPARE, "prio", TRACEFS_COMPARE_LT, "100"); /* * Only record if end event "next_prio" is less than 50 * or the previous task's prio was not greater than or equal to 100. * next_prio < 50 || !(prev_prio >= 100) */ tracefs_synth_append_end_filter(synth, TRACEFS_FILTER_COMPARE, "next_prio", TRACEFS_COMPARE_LT, "50"); tracefs_synth_append_end_filter(synth, TRACEFS_FILTER_OR, NULL, 0, NULL); tracefs_synth_append_end_filter(synth, TRACEFS_FILTER_NOT, NULL, 0, NULL); tracefs_synth_append_end_filter(synth, TRACEFS_FILTER_OPEN_PAREN, NULL, 0, NULL); tracefs_synth_append_end_filter(synth, TRACEFS_FILTER_COMPARE, "prev_prio", TRACEFS_COMPARE_GE, "100"); /* * Note, the above only added: "next_prio < 50 || !(prev_prio >= 100" * That's because, when the synth is executed, the remaining close parenthesis * will be added. That is, the string will end up being: * "next_prio < 50 || !(prev_prio >= 100)" when one of tracefs_sync_create() * or tracefs_sync_echo_cmd() is run. */ } /* Display how to create the synthetic event */ static void show_event(void) { struct trace_seq s; trace_seq_init(&s); tracefs_synth_echo_cmd(&s, synth); trace_seq_terminate(&s); trace_seq_do_printf(&s); trace_seq_destroy(&s); } int main (int argc, char **argv) { make_event(); if (argc > 1) { if (!strcmp(argv[1], "create")) { /* Create the synthetic event */ tracefs_synth_create(synth); } else if (!strcmp(argv[1], "delete")) { /* Delete the synthetic event */ tracefs_synth_destroy(synth); } else { printf("usage: %s [create|delete]\n", argv[0]); exit(-1); } } else show_event(); tracefs_synth_free(synth); return 0; } ``` ``` -------------------------------- ### Example: Using tracefs instance file functions Source: https://www.trace-cmd.org/Documentation/libtracefs/libtracefs-instances-file-manip.html This example shows how to create a trace instance, check for files and directories, read and write trace_clock, read tracing_on, and open a file descriptor. It includes error handling and cleanup. ```c #include struct tracefs_instance *inst = tracefs_instance_create("foo"); if (!inst) { /* Error creating a new trace instance */ ... } if (tracefs_file_exists(inst,"trace_clock")) { /* The instance foo supports trace clock */ char *path, *clock; int size; path = = tracefs_instance_get_file(inst, "trace_clock") if (!path) { /* Error getting the path to trace_clock file in instance foo */ ... } ... tracefs_put_tracing_file(path); clock = tracefs_instance_file_read(inst, "trace_clock", &size); if (!clock) { /* Failed to read trace_clock file in instance foo */ ... } ... free(clock); if (tracefs_instance_file_write(inst, "trace_clock", "global") != strlen("global")) { /* Failed to set gloabl trace clock in instance foo */ ... } } else { /* The instance foo does not support trace clock */ } if (tracefs_dir_exists(inst,"options")) { /* The instance foo supports trace options */ char *path = tracefs_instance_get_file(inst, "options"); if (!path) { /* Error getting the path to options directory in instance foo */ ... } tracefs_put_tracing_file(path); } else { /* The instance foo does not support trace options */ } ... if (tracefs_instance_is_new(inst)) tracefs_instance_destroy(inst); else tracefs_instance_free(inst); ... long long int res; if (tracefs_instance_file_read_number(NULL, "tracing_on", &res) == 0) { if (res == 0) { /* tracing is disabled in the top instance */ } else if (res == 1) { /* tracing is enabled in the top instance */ } else { /* Unknown tracing state of the top instance */ } } else { /* Failed to read integer from tracing_on file */ } ... int fd; fd = tracefs_instance_file_open(NULL, "tracing_on", O_WRONLY); if (fd >= 0) { /* Got file descriptor to the tracing_on file from the top instance for writing */ ... close(fd); } ``` -------------------------------- ### Example: set and get page size Source: https://www.trace-cmd.org/Documentation/libtraceevent/libtraceevent-page_size.html Example usage of tep_set_page_size() and tep_get_page_size(). It allocates a tep handle, sets the page size to the system's page size, and prints it. ```c #include #include ... struct tep_handle *tep = tep_alloc(); ... int page_size = getpagesize(); tep_set_page_size(tep, page_size); printf("The page size for this machine is %d\n", tep_get_page_size(tep)); ``` -------------------------------- ### tracefs_synth_get_start_hist Source: https://www.trace-cmd.org/Documentation/libtracefs/ Gets the start histogram of a synthetic event. Returns a tracefs_hist pointer or NULL on error. ```APIDOC ## tracefs_synth_get_start_hist ### Description Gets the start histogram of a synthetic event. Returns a tracefs_hist pointer or NULL on error. ### Function Signature ```c struct tracefs_hist *tracefs_synth_get_start_hist(struct tracefs_synth *synth); ``` ### Parameters - **synth** (struct tracefs_synth*) - Required - The synthetic event. ### Return Value - **struct tracefs_hist*** - The start histogram, or NULL on error. ``` -------------------------------- ### Sample output with callbacks Source: https://www.trace-cmd.org/Documentation/libtraceevent/libtraceevent-kvm-plugin.html Example output when the program is run against a trace.dat file with kvm_exit and kvm_entry events and the guest's /proc/kallsyms file is passed as the second parameter. Shows resolved function names like native_apic_mem_write+0x2. ```text CPU 0/KVM-20407 83156.177626 [000] kvm_exit reason APIC_ACCESS rip 0xffffffffb0056ee2 exit native_apic_mem_write+0x2 info 10b0 0 CPU 0/KVM-20407 83156.177632 [000] kvm_entry vcpu 0 rip 0xffffffffb0056ee8 enter native_apic_mem_write+0x8 ``` -------------------------------- ### Example of loading plugins and adding a plugin path Source: https://www.trace-cmd.org/Documentation/libtraceevent/libtraceevent-plugins.html This example demonstrates how to use tep_add_plugin_path() to add a directory for plugins and tep_load_plugins() to load them. It also shows a callback function that is called for each loaded plugin. ```c #include ... struct tep_handle *tep = tep_alloc(); ... tep_add_plugin_path(tep, "~/dev_plugins", TEP_PLUGIN_LAST); ... struct tep_plugin_list *plugins = tep_load_plugins(tep); if (plugins == NULL) { /* no plugins are loaded */ } ... tep_unload_plugins(plugins, tep); ... void print_plugin(struct tep_handle *tep, const char *path, const char *name, void *data) { pritnf("Found libtraceevent plugin %s/%s\n", path, name); } ... tep_load_plugins_hook(tep, ".so", print_plugin, NULL); ... ``` -------------------------------- ### Example usage of tep_get_events_count, tep_get_first_event, and tep_get_event Source: https://www.trace-cmd.org/Documentation/libtraceevent/libtraceevent-event_get.html Shows how to iterate over events and get the last event. Assumes tep is allocated with tep_alloc(). The example checks for NULL from tep_get_first_event() to handle the no-events case. ```c #include ... struct tep_handle *tep = tep_alloc(); ... int i,count = tep_get_events_count(tep); struct tep_event *event, *events = tep_get_first_event(tep); if (events == NULL) { /* There are no events */ } else { for (i = 0; i < count; i++) { event = (events+i); /* process events[i] */ } /* Get the last event */ event = tep_get_event(tep, count-1); } ``` -------------------------------- ### Example program using tep_load_btf and tep_btf_print_args Source: https://www.trace-cmd.org/Documentation/libtraceevent/libtraceevent-btf.html This example program demonstrates how to load the BTF file from /sys/kernel/btf/vmlinux and use tep_btf_print_args to print function arguments. It includes error handling for file operations and memory mapping. The main function calls print_args with a sample args array and the function name 'getname_flags'. The output shows either the pretty-printed arguments or a hex fallback if BTF is not loaded or the function is not found. ```c #include #include #include #include #include #include #include #include int print_args(const char *func, unsigned long *args, int nr) { struct tep_handle *tep = tep_alloc(); struct trace_seq s; struct stat st; void *buf; int fd; int ret; if (!tep) return -1; fd = open("/sys/kernel/btf/vmlinux", O_RDONLY); if (fd < 0) return -1; if (fstat(fd, &st) < 0) { close(fd); return -1; } buf = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); if (buf == MAP_FAILED) { close(fd); return -1; } ret = tep_load_btf(tep, buf, st.st_size); munmap(buf, st.st_size); close(fd); if (ret < 0) return -1; trace_seq_init(&s); trace_seq_printf(&s, "%s(", func); tep_btf_print_args(tep, &s, args, nr, sizeof(long), func); trace_seq_puts(&s, ")\n"); trace_seq_do_printf(&s); tep_free(tep); return 0; } int main(int argc, char **argv) { unsigned long args[] = {0x7ffe7d33f3d0, 0, 0, 0, 0, 0}; print_args("getname_flags", args, 6); return 0; } ``` -------------------------------- ### SQL example: using AS to alias events Source: https://www.trace-cmd.org/Documentation/libtracefs/libtracefs-sql.html Uses AS to alias events as start and end, simplifying the statement. ```sql SELECT start.fd, end.ret FROM sys_enter_read AS start JOIN sys_exit_read AS end ON start.common_pid = end.common_pid ``` -------------------------------- ### Example output of the program Source: https://www.trace-cmd.org/Documentation/libtraceevent/libtraceevent-btf.html This is the expected output from the example program. The first line shows the pretty-printed arguments when BTF is loaded and the function is found. The second line shows the fallback output when BTF is not loaded or the function is not found. ```text getname_flags(filename=0x7ffe7d33f3d0, flags=0) If BTF is loaded and the function was found, or it may show: getname_flags(7ffe7d33f3d0, 0, 0, 0, 0, 0) If it was not. ``` -------------------------------- ### Example usage of tep_get_common_field_val, tep_get_field_val, and tep_get_field_raw Source: https://www.trace-cmd.org/Documentation/libtraceevent/libtraceevent-field_get_val.html This example shows how to retrieve field values from a trace record. It uses tep_find_event_by_record to get the event, then calls tep_get_common_field_val for the common_type field, tep_get_field_val for the pid field, and tep_get_field_raw for the comm field. The example assumes a tep handle and event are already set up. ```c #include #include ... struct tep_handle *tep = tep_alloc(); ... struct tep_event *event = tep_find_event_by_name(tep, "kvm", "kvm_exit"); ... void process_record(struct tep_record *record) { int len; char *comm; struct tep_event *event; unsigned long long val; event = tep_find_event_by_record(tep, record); if (event != NULL) { if (tep_get_common_field_val(NULL, event, "common_type", record, &val, 0) == 0) { /* Got the value of common type field */ } if (tep_get_field_val(NULL, event, "pid", record, &val, 0) == 0) { /* Got the value of pid specific field */ } comm = tep_get_field_raw(NULL, event, "comm", record, &len, 0); if (comm != NULL) { /* Got a pointer to the comm event specific field */ } } } ``` -------------------------------- ### C example using tracefs_cpu_open, tracefs_cpu_write, tracefs_cpu_stop, and tracefs_cpu_flush_write Source: https://www.trace-cmd.org/Documentation/libtracefs/libtracefs-cpu.html Complete C program demonstrating the tracefs_cpu API. It creates an instance, opens a CPU, spawns a thread to write data from a file, stops the thread, and flushes remaining data. Requires _LARGEFILE64_SOURCE and includes tracefs.h. ```c #define _LARGEFILE64_SOURCE #include #include #include #include #include struct thread_data { struct tracefs_cpu *tcpu; int done; int fd; }; static void *thread_run(void *arg) { struct thread_data *data = arg; struct tracefs_cpu *tcpu = data->tcpu; int fd = data->fd; int ret; while (!data->done) { ret = tracefs_cpu_write(tcpu, fd, false); printf("wrote %d\n", ret); } return NULL; } int main (int argc, char **argv) { struct tracefs_instance *instance; struct thread_data data; pthread_t thread; char *file; int secs = 10; int cpu; int ret; if (argc < 3 || !isdigit(argv[1][0])) { printf("usage: %s cpu file_destination [sleep secs]\n\n", argv[0]); exit(-1); } cpu = atoi(argv[1]); file = argv[2]; if (argc > 3) secs = atoi(argv[3]); instance = tracefs_instance_create("cpu_write"); if (!instance) { perror("create instance"); exit(-1); } memset(&data, 0, sizeof(data)); data.tcpu = tracefs_cpu_open(instance, cpu, 0); if (!data.tcpu) { perror("Open instance"); exit(-1); } data.fd = open(file, O_WRONLY | O_CREAT | O_TRUNC | O_LARGEFILE, 0644); if (data.fd < 0) { perror(file); exit(-1); } pthread_create(&thread, NULL, thread_run, &data); sleep(secs); data.done = 1; printf("stopping\n"); ret = tracefs_cpu_stop(data.tcpu); printf("joining %d\n", ret); pthread_join(thread, NULL); tracefs_trace_off(instance); do { ret = tracefs_cpu_flush_write(data.tcpu, data.fd); printf("flushed %d\n", ret); } while (ret > 0); tracefs_trace_on(instance); tracefs_cpu_close(data.tcpu); close(data.fd); return 0; } ``` -------------------------------- ### Example: create, check, destroy, and free a trace instance Source: https://www.trace-cmd.org/Documentation/libtracefs/libtracefs-instances-manage.html Shows how to create a trace instance with tracefs_instance_create(), check if it was newly created with tracefs_instance_is_new(), destroy it if new, and free it. The example uses the instance name "foo". ```c #include struct tracefs_instance *inst = tracefs_instance_create("foo"); if (!inst) { /* Error creating a new trace instance */ ... } ... if (tracefs_instance_is_new(inst)) tracefs_instance_destroy(inst); tracefs_instance_free(inst); ... ``` -------------------------------- ### Example usage of tracefs_get_tracing_file and tracefs_tracing_dir Source: https://www.trace-cmd.org/Documentation/libtracefs/libtracefs-files.html Shows how to get the full path to a trace file (e.g., tracing_on) and free it with tracefs_put_tracing_file, and how to get the trace directory path. The returned string from tracefs_get_tracing_file must be freed; the one from tracefs_tracing_dir must not be freed. ```c #include ... char *trace_on = tracefs_get_tracing_file("tracing_on"); if (trace_on) { ... tracefs_put_tracing_file(trace_on); } ... const char *trace_dir = tracefs_tracing_dir(); ``` -------------------------------- ### Example: map vCPUs and print host PIDs Source: https://www.trace-cmd.org/Documentation/libtracecmd/libtracecmd-maps.html Complete C program that opens multiple trace files, maps guest vCPUs to host CPUs, and prints the host PID for each guest CPU. Requires trace-cmd.h and uses tracecmd_map_vcpus, tracecmd_get_cpu_map, and tracecmd_map_get_host_pid. The program expects at least one trace file argument and prints usage if none are provided. ```c #include #include #include int main(int argc, char **argv) { struct tracecmd_input **handles = NULL; int nr_handles; int i; if (argc < 2) { printf("usage: host_trace.dat guest1_trace.dat [guest2_trace.dat ...]\n"); exit(-1); } for (i = 1; i < argc; i++) { handles = realloc(handles, sizeof(*handles) * (nr_handles + 1)); if (!handles) exit(-1); handles[nr_handles] = tracecmd_open(argv[i], 0); if (!handles[nr_handles]) { perror(argv[1]); exit(-1); } tracecmd_set_private(handles[nr_handles], argv[i]); nr_handles++; } tracecmd_map_vcpus(handles, nr_handles); for (i = 1; i < nr_handles; i++) { struct tracecmd_cpu_map *map; struct tep_handle *tep; const char *file = tracecmd_get_private(handles[i]); int cpus, cpu; printf("Mappings for guest %s:\n", file); tep = tracecmd_get_tep(handles[i]); cpus = tep_get_cpus(tep); for (cpu = 0; cpu < cpus; cpu++) { printf(" [%03d] ", cpu); map = tracecmd_get_cpu_map(handles[i], cpu); if (!map) { printf("Has no mapping!\n"); continue; } printf("host_pid: %d\n", tracecmd_map_get_host_pid(map)); } } for (i = 0; i < nr_handles; i++) tracecmd_close(handles[i]); free(handles); exit(0); } ``` -------------------------------- ### Complete C example using tracefs_iterate_raw_events() Source: https://www.trace-cmd.org/Documentation/libtracefs/libtracefs-iterator.html This example shows how to set up a trace instance, enable events, register callbacks for sched_switch and missed events, and iterate raw events. It also demonstrates clearing followers with tracefs_follow_event_clear() and tracefs_follow_missed_events_clear(). The program stops on SIGINT or after MAX_COUNT events. ```c #include #include #include #include struct my_struct { bool stopped; }; #define MAX_COUNT 500000 static int counter; static int callback(struct tep_event *event, struct tep_record *record, int cpu, void *data) { struct my_struct *my_data = data; static struct trace_seq seq; if (counter++ > MAX_COUNT) { my_data->stopped = true; return 1; } if (!seq.buffer) trace_seq_init(&seq); tep_print_event(event->tep, &seq, record, "%16s-%-5d [%03d] %6.1000d %s: %s\n", TEP_PRINT_COMM, TEP_PRINT_PID, TEP_PRINT_CPU, TEP_PRINT_TIME, TEP_PRINT_NAME, TEP_PRINT_INFO); trace_seq_terminate(&seq); trace_seq_do_printf(&seq); trace_seq_reset(&seq); return 0; } static int sched_callback(struct tep_event *event, struct tep_record *record, int cpu, void *data) { static struct tep_format_field *prev_pid; static struct tep_format_field *next_pid; unsigned long long pid; int this_pid = *(int *)data; if (!prev_pid) { prev_pid = tep_find_field(event, "prev_pid"); next_pid = tep_find_field(event, "next_pid"); if (!prev_pid || !next_pid) { fprintf(stderr, "No pid fields??\n"); return -1; } } tep_read_number_field(prev_pid, record->data, &pid); if (pid == this_pid) printf("WE ARE LEAVING!\n"); tep_read_number_field(next_pid, record->data, &pid); if (pid == this_pid) printf("WE ARE ARRIVING!\n"); return 0; } static int missed_callback(struct tep_event *event, struct tep_record *record, int cpu, void *data) { printf("OOPS! cpu %d dropped ", cpu); if (record->missed_events > 0) printf("%lld ", record->missed_events); printf("events\n"); return 0; } static struct tracefs_instance *instance; static struct my_struct my_data; static void sig(int s) { tracefs_iterate_stop(instance); my_data.stopped = true; } int main (int argc, char **argv, char **env) { struct tep_handle *tep; int this_pid = getpid(); instance = tracefs_instance_create("my-buffer"); if (!instance) return -1; signal(SIGINT, sig); tracefs_event_enable(instance, NULL, NULL); sleep(1); tracefs_event_disable(instance, NULL, NULL); tep = tracefs_local_events(NULL); tep_load_plugins(tep); tracefs_follow_missed_events(instance, missed_callback, NULL); tracefs_follow_event(tep, instance, "sched", "sched_switch", sched_callback, &this_pid); tracefs_iterate_raw_events(tep, instance, NULL, 0, callback, &my_data); /* Note, the clear here is to show how to clear all followers * in case tracefs_iterate_raw_events() is called again, but * does not want to include the followers. It's not needed * here because tracefs_instance_free() will clean them up. */ tracefs_follow_event_clear(instance, NULL, NULL); tracefs_follow_missed_events_clear(instance); tracefs_instance_destroy(instance); tracefs_instance_free(instance); if (my_data.stopped) { if (counter > MAX_COUNT) printf("Finished max count\n"); else printf("Finished via signal\n"); } return 0; } ``` -------------------------------- ### Example: Using tep_find_common_field, tep_find_field, and tep_find_any_field Source: https://www.trace-cmd.org/Documentation/libtraceevent/libtraceevent-field_find.html Shows how to find and read fields from an event record. It uses tep_find_event_by_name() to get the event, then each search function to locate a field, and tep_read_number() to extract the value. The example includes error handling for NULL fields. ```c #include ... void get_htimer_info(struct tep_handle *tep, struct tep_record *record) { struct tep_format_field *field; struct tep_event *event; long long softexpires; int mode; int pid; event = tep_find_event_by_name(tep, "timer", "hrtimer_start"); field = tep_find_common_field(event, "common_pid"); if (field == NULL) { /* Cannot find "common_pid" field in the event */ } else { /* Get pid from the data record */ pid = tep_read_number(tep, record->data + field->offset, field->size); } field = tep_find_field(event, "softexpires"); if (field == NULL) { /* Cannot find "softexpires" event specific field in the event */ } else { /* Get softexpires parameter from the data record */ softexpires = tep_read_number(tep, record->data + field->offset, field->size); } field = tep_find_any_field(event, "mode"); if (field == NULL) { /* Cannot find "mode" field in the event */ } else { /* Get mode parameter from the data record */ mode = tep_read_number(tep, record->data + field->offset, field->size); } } ... ```