diff --git a/src/request.c b/src/request.c index f7b5154..d8f26d5 100644 --- a/src/request.c +++ b/src/request.c @@ -140,6 +140,7 @@ static int find_decoder_video_node_via_topology(int media_fd, struct media_v2_entity *entities = NULL; struct media_v2_interface *interfaces = NULL; struct media_v2_link *links = NULL; + struct media_v2_pad *pads = NULL; int ret = -1; unsigned int i, j; @@ -147,50 +148,81 @@ static int find_decoder_video_node_via_topology(int media_fd, if (ioctl(media_fd, MEDIA_IOC_G_TOPOLOGY, &topo) < 0) return -1; if (topo.num_entities == 0 || topo.num_interfaces == 0 || - topo.num_links == 0) + topo.num_links == 0 || topo.num_pads == 0) return -1; entities = calloc(topo.num_entities, sizeof *entities); interfaces = calloc(topo.num_interfaces, sizeof *interfaces); links = calloc(topo.num_links, sizeof *links); - if (!entities || !interfaces || !links) + pads = calloc(topo.num_pads, sizeof *pads); + if (!entities || !interfaces || !links || !pads) goto out; topo.ptr_entities = (uintptr_t)entities; topo.ptr_interfaces = (uintptr_t)interfaces; topo.ptr_links = (uintptr_t)links; + topo.ptr_pads = (uintptr_t)pads; if (ioctl(media_fd, MEDIA_IOC_G_TOPOLOGY, &topo) < 0) goto out; for (i = 0; i < topo.num_entities; i++) { uint32_t proc_id; + uint32_t proc_pad_ids[16]; uint32_t io_entity_ids[16]; + unsigned int proc_pad_count = 0; unsigned int io_count = 0; if (entities[i].function != MEDIA_ENT_F_PROC_VIDEO_DECODER) continue; proc_id = entities[i].id; - /* Step 2: collect data-link neighbors of the proc entity. */ + /* Step 2a: collect pads belonging to the proc entity. Data + * links connect PADs, not entities directly. */ + for (j = 0; j < topo.num_pads; j++) { + if (pads[j].entity_id != proc_id) + continue; + if (proc_pad_count < (sizeof proc_pad_ids / + sizeof proc_pad_ids[0])) + proc_pad_ids[proc_pad_count++] = pads[j].id; + } + + /* Step 2b: walk data links. For each link with either endpoint + * in proc_pad_ids[], the other endpoint is a pad belonging to + * an IO neighbor. Resolve that pad's entity_id via pads[]. */ for (j = 0; j < topo.num_links; j++) { - uint32_t other; + uint32_t other_pad = 0; + unsigned int k; if (links[j].flags & MEDIA_LNK_FL_INTERFACE_LINK) continue; - if (links[j].source_id == proc_id) - other = links[j].sink_id; - else if (links[j].sink_id == proc_id) - other = links[j].source_id; - else + for (k = 0; k < proc_pad_count; k++) { + if (links[j].source_id == proc_pad_ids[k]) + other_pad = links[j].sink_id; + else if (links[j].sink_id == proc_pad_ids[k]) + other_pad = links[j].source_id; + if (other_pad != 0) + break; + } + if (other_pad == 0) continue; - if (io_count < (sizeof io_entity_ids / - sizeof io_entity_ids[0])) - io_entity_ids[io_count++] = other; + /* Resolve other_pad to its entity_id. */ + for (k = 0; k < topo.num_pads; k++) { + if (pads[k].id != other_pad) + continue; + if (io_count < (sizeof io_entity_ids / + sizeof io_entity_ids[0])) + io_entity_ids[io_count++] = + pads[k].entity_id; + break; + } } /* Step 3-4: find an interface link from any IO entity neighbor; - * resolve devnode for the linked V4L_VIDEO interface. */ + * resolve devnode for the linked V4L_VIDEO interface. + * Interface links connect interfaces↔entities directly (not + * via pads), so source_id/sink_id is an entity ID on one side + * and an interface ID on the other. */ for (j = 0; j < topo.num_links; j++) { uint32_t intf_id = 0; unsigned int k; @@ -230,6 +262,7 @@ out: free(entities); free(interfaces); free(links); + free(pads); return ret; } diff --git a/tests/run_perf_binding_cell.sh b/tests/run_perf_binding_cell.sh index 683233a..d618311 100755 --- a/tests/run_perf_binding_cell.sh +++ b/tests/run_perf_binding_cell.sh @@ -171,17 +171,19 @@ run_consumer() { sleep 1 # Parse pidstat by header: locate the %CPU column index from the - # column-name row, then apply it to data rows. Robust across - # sysstat 12.x point releases (where column positions shift). + # column-name row (where any field equals "%CPU"), then apply it + # to data rows. Robust across sysstat 12.x point releases. + # pidstat default output has no '#' header marker — the header is + # the first row containing "%CPU" as a field. awk ' - # Header row: find which field is %CPU. - $1 == "#" { - for (i = 1; i <= NF; i++) if ($i == "%CPU") col = i - next + # Header row: any line where some field equals "%CPU". + !col { + for (i = 1; i <= NF; i++) if ($i == "%CPU") { col = i; next } } - # Data row: skip the average summary at end + blank lines. - col && NF >= col && $1 ~ /^[0-9]/ { - if ($col ~ /^[0-9]+(\.[0-9]+)?$/) print $col + # Data row: lines whose value at $col is numeric. Skip the + # trailing "Average" summary by requiring $col to parse cleanly. + col && NF >= col && $col ~ /^[0-9]+(\.[0-9]+)?$/ { + print $col } ' "$logdir/pidstat.log" >"$logdir/cpu_pct.log" || true