162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci#include "util/bpf_counter.h" 362306a36Sopenharmony_ci#include "util/debug.h" 462306a36Sopenharmony_ci#include "util/evsel.h" 562306a36Sopenharmony_ci#include "util/evlist.h" 662306a36Sopenharmony_ci#include "util/off_cpu.h" 762306a36Sopenharmony_ci#include "util/perf-hooks.h" 862306a36Sopenharmony_ci#include "util/record.h" 962306a36Sopenharmony_ci#include "util/session.h" 1062306a36Sopenharmony_ci#include "util/target.h" 1162306a36Sopenharmony_ci#include "util/cpumap.h" 1262306a36Sopenharmony_ci#include "util/thread_map.h" 1362306a36Sopenharmony_ci#include "util/cgroup.h" 1462306a36Sopenharmony_ci#include "util/strlist.h" 1562306a36Sopenharmony_ci#include <bpf/bpf.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include "bpf_skel/off_cpu.skel.h" 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#define MAX_STACKS 32 2062306a36Sopenharmony_ci#define MAX_PROC 4096 2162306a36Sopenharmony_ci/* we don't need actual timestamp, just want to put the samples at last */ 2262306a36Sopenharmony_ci#define OFF_CPU_TIMESTAMP (~0ull << 32) 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_cistatic struct off_cpu_bpf *skel; 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_cistruct off_cpu_key { 2762306a36Sopenharmony_ci u32 pid; 2862306a36Sopenharmony_ci u32 tgid; 2962306a36Sopenharmony_ci u32 stack_id; 3062306a36Sopenharmony_ci u32 state; 3162306a36Sopenharmony_ci u64 cgroup_id; 3262306a36Sopenharmony_ci}; 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ciunion off_cpu_data { 3562306a36Sopenharmony_ci struct perf_event_header hdr; 3662306a36Sopenharmony_ci u64 array[1024 / sizeof(u64)]; 3762306a36Sopenharmony_ci}; 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_cistatic int off_cpu_config(struct evlist *evlist) 4062306a36Sopenharmony_ci{ 4162306a36Sopenharmony_ci struct evsel *evsel; 4262306a36Sopenharmony_ci struct perf_event_attr attr = { 4362306a36Sopenharmony_ci .type = PERF_TYPE_SOFTWARE, 4462306a36Sopenharmony_ci .config = PERF_COUNT_SW_BPF_OUTPUT, 4562306a36Sopenharmony_ci .size = sizeof(attr), /* to capture ABI version */ 4662306a36Sopenharmony_ci }; 4762306a36Sopenharmony_ci char *evname = strdup(OFFCPU_EVENT); 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci if (evname == NULL) 5062306a36Sopenharmony_ci return -ENOMEM; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci evsel = evsel__new(&attr); 5362306a36Sopenharmony_ci if (!evsel) { 5462306a36Sopenharmony_ci free(evname); 5562306a36Sopenharmony_ci return -ENOMEM; 5662306a36Sopenharmony_ci } 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci evsel->core.attr.freq = 1; 5962306a36Sopenharmony_ci evsel->core.attr.sample_period = 1; 6062306a36Sopenharmony_ci /* off-cpu analysis depends on stack trace */ 6162306a36Sopenharmony_ci evsel->core.attr.sample_type = PERF_SAMPLE_CALLCHAIN; 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci evlist__add(evlist, evsel); 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci free(evsel->name); 6662306a36Sopenharmony_ci evsel->name = evname; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci return 0; 6962306a36Sopenharmony_ci} 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_cistatic void off_cpu_start(void *arg) 7262306a36Sopenharmony_ci{ 7362306a36Sopenharmony_ci struct evlist *evlist = arg; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci /* update task filter for the given workload */ 7662306a36Sopenharmony_ci if (!skel->bss->has_cpu && !skel->bss->has_task && 7762306a36Sopenharmony_ci perf_thread_map__pid(evlist->core.threads, 0) != -1) { 7862306a36Sopenharmony_ci int fd; 7962306a36Sopenharmony_ci u32 pid; 8062306a36Sopenharmony_ci u8 val = 1; 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci skel->bss->has_task = 1; 8362306a36Sopenharmony_ci skel->bss->uses_tgid = 1; 8462306a36Sopenharmony_ci fd = bpf_map__fd(skel->maps.task_filter); 8562306a36Sopenharmony_ci pid = perf_thread_map__pid(evlist->core.threads, 0); 8662306a36Sopenharmony_ci bpf_map_update_elem(fd, &pid, &val, BPF_ANY); 8762306a36Sopenharmony_ci } 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci skel->bss->enabled = 1; 9062306a36Sopenharmony_ci} 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_cistatic void off_cpu_finish(void *arg __maybe_unused) 9362306a36Sopenharmony_ci{ 9462306a36Sopenharmony_ci skel->bss->enabled = 0; 9562306a36Sopenharmony_ci off_cpu_bpf__destroy(skel); 9662306a36Sopenharmony_ci} 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci/* v5.18 kernel added prev_state arg, so it needs to check the signature */ 9962306a36Sopenharmony_cistatic void check_sched_switch_args(void) 10062306a36Sopenharmony_ci{ 10162306a36Sopenharmony_ci const struct btf *btf = btf__load_vmlinux_btf(); 10262306a36Sopenharmony_ci const struct btf_type *t1, *t2, *t3; 10362306a36Sopenharmony_ci u32 type_id; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci type_id = btf__find_by_name_kind(btf, "btf_trace_sched_switch", 10662306a36Sopenharmony_ci BTF_KIND_TYPEDEF); 10762306a36Sopenharmony_ci if ((s32)type_id < 0) 10862306a36Sopenharmony_ci return; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci t1 = btf__type_by_id(btf, type_id); 11162306a36Sopenharmony_ci if (t1 == NULL) 11262306a36Sopenharmony_ci return; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci t2 = btf__type_by_id(btf, t1->type); 11562306a36Sopenharmony_ci if (t2 == NULL || !btf_is_ptr(t2)) 11662306a36Sopenharmony_ci return; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci t3 = btf__type_by_id(btf, t2->type); 11962306a36Sopenharmony_ci /* btf_trace func proto has one more argument for the context */ 12062306a36Sopenharmony_ci if (t3 && btf_is_func_proto(t3) && btf_vlen(t3) == 5) { 12162306a36Sopenharmony_ci /* new format: pass prev_state as 4th arg */ 12262306a36Sopenharmony_ci skel->rodata->has_prev_state = true; 12362306a36Sopenharmony_ci } 12462306a36Sopenharmony_ci} 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ciint off_cpu_prepare(struct evlist *evlist, struct target *target, 12762306a36Sopenharmony_ci struct record_opts *opts) 12862306a36Sopenharmony_ci{ 12962306a36Sopenharmony_ci int err, fd, i; 13062306a36Sopenharmony_ci int ncpus = 1, ntasks = 1, ncgrps = 1; 13162306a36Sopenharmony_ci struct strlist *pid_slist = NULL; 13262306a36Sopenharmony_ci struct str_node *pos; 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci if (off_cpu_config(evlist) < 0) { 13562306a36Sopenharmony_ci pr_err("Failed to config off-cpu BPF event\n"); 13662306a36Sopenharmony_ci return -1; 13762306a36Sopenharmony_ci } 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci skel = off_cpu_bpf__open(); 14062306a36Sopenharmony_ci if (!skel) { 14162306a36Sopenharmony_ci pr_err("Failed to open off-cpu BPF skeleton\n"); 14262306a36Sopenharmony_ci return -1; 14362306a36Sopenharmony_ci } 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci /* don't need to set cpu filter for system-wide mode */ 14662306a36Sopenharmony_ci if (target->cpu_list) { 14762306a36Sopenharmony_ci ncpus = perf_cpu_map__nr(evlist->core.user_requested_cpus); 14862306a36Sopenharmony_ci bpf_map__set_max_entries(skel->maps.cpu_filter, ncpus); 14962306a36Sopenharmony_ci } 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci if (target->pid) { 15262306a36Sopenharmony_ci pid_slist = strlist__new(target->pid, NULL); 15362306a36Sopenharmony_ci if (!pid_slist) { 15462306a36Sopenharmony_ci pr_err("Failed to create a strlist for pid\n"); 15562306a36Sopenharmony_ci return -1; 15662306a36Sopenharmony_ci } 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci ntasks = 0; 15962306a36Sopenharmony_ci strlist__for_each_entry(pos, pid_slist) { 16062306a36Sopenharmony_ci char *end_ptr; 16162306a36Sopenharmony_ci int pid = strtol(pos->s, &end_ptr, 10); 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci if (pid == INT_MIN || pid == INT_MAX || 16462306a36Sopenharmony_ci (*end_ptr != '\0' && *end_ptr != ',')) 16562306a36Sopenharmony_ci continue; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci ntasks++; 16862306a36Sopenharmony_ci } 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci if (ntasks < MAX_PROC) 17162306a36Sopenharmony_ci ntasks = MAX_PROC; 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci bpf_map__set_max_entries(skel->maps.task_filter, ntasks); 17462306a36Sopenharmony_ci } else if (target__has_task(target)) { 17562306a36Sopenharmony_ci ntasks = perf_thread_map__nr(evlist->core.threads); 17662306a36Sopenharmony_ci bpf_map__set_max_entries(skel->maps.task_filter, ntasks); 17762306a36Sopenharmony_ci } else if (target__none(target)) { 17862306a36Sopenharmony_ci bpf_map__set_max_entries(skel->maps.task_filter, MAX_PROC); 17962306a36Sopenharmony_ci } 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci if (evlist__first(evlist)->cgrp) { 18262306a36Sopenharmony_ci ncgrps = evlist->core.nr_entries - 1; /* excluding a dummy */ 18362306a36Sopenharmony_ci bpf_map__set_max_entries(skel->maps.cgroup_filter, ncgrps); 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci if (!cgroup_is_v2("perf_event")) 18662306a36Sopenharmony_ci skel->rodata->uses_cgroup_v1 = true; 18762306a36Sopenharmony_ci } 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci if (opts->record_cgroup) { 19062306a36Sopenharmony_ci skel->rodata->needs_cgroup = true; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci if (!cgroup_is_v2("perf_event")) 19362306a36Sopenharmony_ci skel->rodata->uses_cgroup_v1 = true; 19462306a36Sopenharmony_ci } 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci set_max_rlimit(); 19762306a36Sopenharmony_ci check_sched_switch_args(); 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci err = off_cpu_bpf__load(skel); 20062306a36Sopenharmony_ci if (err) { 20162306a36Sopenharmony_ci pr_err("Failed to load off-cpu skeleton\n"); 20262306a36Sopenharmony_ci goto out; 20362306a36Sopenharmony_ci } 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci if (target->cpu_list) { 20662306a36Sopenharmony_ci u32 cpu; 20762306a36Sopenharmony_ci u8 val = 1; 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci skel->bss->has_cpu = 1; 21062306a36Sopenharmony_ci fd = bpf_map__fd(skel->maps.cpu_filter); 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci for (i = 0; i < ncpus; i++) { 21362306a36Sopenharmony_ci cpu = perf_cpu_map__cpu(evlist->core.user_requested_cpus, i).cpu; 21462306a36Sopenharmony_ci bpf_map_update_elem(fd, &cpu, &val, BPF_ANY); 21562306a36Sopenharmony_ci } 21662306a36Sopenharmony_ci } 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci if (target->pid) { 21962306a36Sopenharmony_ci u8 val = 1; 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci skel->bss->has_task = 1; 22262306a36Sopenharmony_ci skel->bss->uses_tgid = 1; 22362306a36Sopenharmony_ci fd = bpf_map__fd(skel->maps.task_filter); 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci strlist__for_each_entry(pos, pid_slist) { 22662306a36Sopenharmony_ci char *end_ptr; 22762306a36Sopenharmony_ci u32 tgid; 22862306a36Sopenharmony_ci int pid = strtol(pos->s, &end_ptr, 10); 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci if (pid == INT_MIN || pid == INT_MAX || 23162306a36Sopenharmony_ci (*end_ptr != '\0' && *end_ptr != ',')) 23262306a36Sopenharmony_ci continue; 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci tgid = pid; 23562306a36Sopenharmony_ci bpf_map_update_elem(fd, &tgid, &val, BPF_ANY); 23662306a36Sopenharmony_ci } 23762306a36Sopenharmony_ci } else if (target__has_task(target)) { 23862306a36Sopenharmony_ci u32 pid; 23962306a36Sopenharmony_ci u8 val = 1; 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci skel->bss->has_task = 1; 24262306a36Sopenharmony_ci fd = bpf_map__fd(skel->maps.task_filter); 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci for (i = 0; i < ntasks; i++) { 24562306a36Sopenharmony_ci pid = perf_thread_map__pid(evlist->core.threads, i); 24662306a36Sopenharmony_ci bpf_map_update_elem(fd, &pid, &val, BPF_ANY); 24762306a36Sopenharmony_ci } 24862306a36Sopenharmony_ci } 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci if (evlist__first(evlist)->cgrp) { 25162306a36Sopenharmony_ci struct evsel *evsel; 25262306a36Sopenharmony_ci u8 val = 1; 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci skel->bss->has_cgroup = 1; 25562306a36Sopenharmony_ci fd = bpf_map__fd(skel->maps.cgroup_filter); 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci evlist__for_each_entry(evlist, evsel) { 25862306a36Sopenharmony_ci struct cgroup *cgrp = evsel->cgrp; 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci if (cgrp == NULL) 26162306a36Sopenharmony_ci continue; 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci if (!cgrp->id && read_cgroup_id(cgrp) < 0) { 26462306a36Sopenharmony_ci pr_err("Failed to read cgroup id of %s\n", 26562306a36Sopenharmony_ci cgrp->name); 26662306a36Sopenharmony_ci goto out; 26762306a36Sopenharmony_ci } 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci bpf_map_update_elem(fd, &cgrp->id, &val, BPF_ANY); 27062306a36Sopenharmony_ci } 27162306a36Sopenharmony_ci } 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci err = off_cpu_bpf__attach(skel); 27462306a36Sopenharmony_ci if (err) { 27562306a36Sopenharmony_ci pr_err("Failed to attach off-cpu BPF skeleton\n"); 27662306a36Sopenharmony_ci goto out; 27762306a36Sopenharmony_ci } 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci if (perf_hooks__set_hook("record_start", off_cpu_start, evlist) || 28062306a36Sopenharmony_ci perf_hooks__set_hook("record_end", off_cpu_finish, evlist)) { 28162306a36Sopenharmony_ci pr_err("Failed to attach off-cpu skeleton\n"); 28262306a36Sopenharmony_ci goto out; 28362306a36Sopenharmony_ci } 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci return 0; 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ciout: 28862306a36Sopenharmony_ci off_cpu_bpf__destroy(skel); 28962306a36Sopenharmony_ci return -1; 29062306a36Sopenharmony_ci} 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ciint off_cpu_write(struct perf_session *session) 29362306a36Sopenharmony_ci{ 29462306a36Sopenharmony_ci int bytes = 0, size; 29562306a36Sopenharmony_ci int fd, stack; 29662306a36Sopenharmony_ci u64 sample_type, val, sid = 0; 29762306a36Sopenharmony_ci struct evsel *evsel; 29862306a36Sopenharmony_ci struct perf_data_file *file = &session->data->file; 29962306a36Sopenharmony_ci struct off_cpu_key prev, key; 30062306a36Sopenharmony_ci union off_cpu_data data = { 30162306a36Sopenharmony_ci .hdr = { 30262306a36Sopenharmony_ci .type = PERF_RECORD_SAMPLE, 30362306a36Sopenharmony_ci .misc = PERF_RECORD_MISC_USER, 30462306a36Sopenharmony_ci }, 30562306a36Sopenharmony_ci }; 30662306a36Sopenharmony_ci u64 tstamp = OFF_CPU_TIMESTAMP; 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci skel->bss->enabled = 0; 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci evsel = evlist__find_evsel_by_str(session->evlist, OFFCPU_EVENT); 31162306a36Sopenharmony_ci if (evsel == NULL) { 31262306a36Sopenharmony_ci pr_err("%s evsel not found\n", OFFCPU_EVENT); 31362306a36Sopenharmony_ci return 0; 31462306a36Sopenharmony_ci } 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci sample_type = evsel->core.attr.sample_type; 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci if (sample_type & ~OFFCPU_SAMPLE_TYPES) { 31962306a36Sopenharmony_ci pr_err("not supported sample type: %llx\n", 32062306a36Sopenharmony_ci (unsigned long long)sample_type); 32162306a36Sopenharmony_ci return -1; 32262306a36Sopenharmony_ci } 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci if (sample_type & (PERF_SAMPLE_ID | PERF_SAMPLE_IDENTIFIER)) { 32562306a36Sopenharmony_ci if (evsel->core.id) 32662306a36Sopenharmony_ci sid = evsel->core.id[0]; 32762306a36Sopenharmony_ci } 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci fd = bpf_map__fd(skel->maps.off_cpu); 33062306a36Sopenharmony_ci stack = bpf_map__fd(skel->maps.stacks); 33162306a36Sopenharmony_ci memset(&prev, 0, sizeof(prev)); 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci while (!bpf_map_get_next_key(fd, &prev, &key)) { 33462306a36Sopenharmony_ci int n = 1; /* start from perf_event_header */ 33562306a36Sopenharmony_ci int ip_pos = -1; 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci bpf_map_lookup_elem(fd, &key, &val); 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci if (sample_type & PERF_SAMPLE_IDENTIFIER) 34062306a36Sopenharmony_ci data.array[n++] = sid; 34162306a36Sopenharmony_ci if (sample_type & PERF_SAMPLE_IP) { 34262306a36Sopenharmony_ci ip_pos = n; 34362306a36Sopenharmony_ci data.array[n++] = 0; /* will be updated */ 34462306a36Sopenharmony_ci } 34562306a36Sopenharmony_ci if (sample_type & PERF_SAMPLE_TID) 34662306a36Sopenharmony_ci data.array[n++] = (u64)key.pid << 32 | key.tgid; 34762306a36Sopenharmony_ci if (sample_type & PERF_SAMPLE_TIME) 34862306a36Sopenharmony_ci data.array[n++] = tstamp; 34962306a36Sopenharmony_ci if (sample_type & PERF_SAMPLE_ID) 35062306a36Sopenharmony_ci data.array[n++] = sid; 35162306a36Sopenharmony_ci if (sample_type & PERF_SAMPLE_CPU) 35262306a36Sopenharmony_ci data.array[n++] = 0; 35362306a36Sopenharmony_ci if (sample_type & PERF_SAMPLE_PERIOD) 35462306a36Sopenharmony_ci data.array[n++] = val; 35562306a36Sopenharmony_ci if (sample_type & PERF_SAMPLE_CALLCHAIN) { 35662306a36Sopenharmony_ci int len = 0; 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci /* data.array[n] is callchain->nr (updated later) */ 35962306a36Sopenharmony_ci data.array[n + 1] = PERF_CONTEXT_USER; 36062306a36Sopenharmony_ci data.array[n + 2] = 0; 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci bpf_map_lookup_elem(stack, &key.stack_id, &data.array[n + 2]); 36362306a36Sopenharmony_ci while (data.array[n + 2 + len]) 36462306a36Sopenharmony_ci len++; 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci /* update length of callchain */ 36762306a36Sopenharmony_ci data.array[n] = len + 1; 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci /* update sample ip with the first callchain entry */ 37062306a36Sopenharmony_ci if (ip_pos >= 0) 37162306a36Sopenharmony_ci data.array[ip_pos] = data.array[n + 2]; 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci /* calculate sample callchain data array length */ 37462306a36Sopenharmony_ci n += len + 2; 37562306a36Sopenharmony_ci } 37662306a36Sopenharmony_ci if (sample_type & PERF_SAMPLE_CGROUP) 37762306a36Sopenharmony_ci data.array[n++] = key.cgroup_id; 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci size = n * sizeof(u64); 38062306a36Sopenharmony_ci data.hdr.size = size; 38162306a36Sopenharmony_ci bytes += size; 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci if (perf_data_file__write(file, &data, size) < 0) { 38462306a36Sopenharmony_ci pr_err("failed to write perf data, error: %m\n"); 38562306a36Sopenharmony_ci return bytes; 38662306a36Sopenharmony_ci } 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci prev = key; 38962306a36Sopenharmony_ci /* increase dummy timestamp to sort later samples */ 39062306a36Sopenharmony_ci tstamp++; 39162306a36Sopenharmony_ci } 39262306a36Sopenharmony_ci return bytes; 39362306a36Sopenharmony_ci} 394