forked from marfrit/libva-v4l2-request-fourier
fresnel-fourier iter7 Phase 7 fix-forward: data links connect pads not entities directly
Empirical Phase 7 verification revealed the algorithm bug: data links in MEDIA_IOC_G_TOPOLOGY connect PAD IDs, not entity IDs directly. My iter7 Phase 6 commit compared link source_id/sink_id against the proc entity_id, never matched → io_entity_ids stayed empty → interface lookup never fired → returns -1 → falls back to legacy hardcoded path. Topology dump on fresnel /dev/media0 (rkvdec) confirmed: - Entity 3 (rkvdec-proc) has function=0x4008 (DECODER) ✓ - Data link src=16777218 sink=16777220 — these are PAD ids (0x01000002, 0x01000004), NOT entity 3. - Interface link src=50331660 (interface) sink=1 (entity) — for interface links source/sink ARE entity IDs. Fix: resolve pads → entities via the topo.pads[] array. 1. Collect pads belonging to proc entity (via pads[].entity_id). 2. For each data link touching those pads, the OTHER pad's entity_id is an IO neighbor. 3. Find interface link to those IO entities (unchanged from prev). Also allocate topo.pads[] in the 2-call ioctl pattern. Signed-off-by: claude-noether <claude-noether@reauktion.de>
This commit is contained in:
+46
-13
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user