使用日志记录跟踪重要事件

通常,仅通过触发事件、微型驱动程序的处理和缓冲区完成来移动下游数据。 若要隔离挂起或停止的原因:

  • 检查不匹配的 KsGateXxx 调用。

  • 检查省略的 KsXxxAttemptProcessing 调用。

  • 查找与触发事件相关的代码中的问题,包括引用问题流的固定标志或调用 KsPinAttemptProcessing 的代码。

  • 在代码中查找与处理调度相关的问题,尤其是将队列排到硬件的位置以及创建克隆指针的位置。

  • 查找代码中与驱动程序延迟过程调用相关的问题, (DPC) ,尤其是在缓冲区完成或对 KsStreamPointerDelete 进行任何调用的情况下。

  • 在流的启动代码中查找问题。

收集此信息的最有效方法是记录受影响区域中的所有内容,包括处理、缓冲区获取 ((如克隆和编程硬件) 、缓冲区释放 ((例如删除克隆) )和任何门操作。 大部分信息依赖于高度计时,需要基于内存的日志记录或 ETW。

若要维护基于内存的滚动日志,请使用以下代码:

typedef struct _LOGENTRY {
    ULONG Tag;
    ULONG Arg[3];
} LOGENTRY, *PLOGENTRY;
#define LOGSIZE 2048
LONG g_LogCount;
LOGENTRY g_Log [LOGSIZE];
#define LOG(tag,arg1,arg2,arg3) do { \
    LONG i = InterlockedIncrement (&g_LogCount) % LOGSIZE; \
    g_Log [i].Tag = tag; \
    g_Log [i].Arg [0] = (ULONG)(arg1); \
    g_Log [i].Arg [1] = (ULONG)(arg2); \
    g_Log [i].Arg [2] = (ULONG)(arg3); \
} while (0)

然后,使用简单的“dc g_Log”查看调试器中 g_Log 数组的内容。

以下示例使用上述基于内存的方案来确定处理停止的原因。 输出来自 graphedt 中的 AVStream 流式处理方案。 记录了以下微型驱动程序事件:

缩写 说明

Strt

当微型驱动程序首先从微型驱动程序的 “开始 ”调度中为设备排队缓冲区时,会发生此事件。

中国<

此事件发生在微型驱动程序 的进程 调度开始时。

AddB

当微型驱动程序从其 进程 调度中将缓冲区排队到设备时,会发生此事件。

DPC<

此事件发生在微型驱动程序的 CallOnDPC 的开头。 它指示缓冲区完成。

Atmp

当微型驱动程序从 DPC 内部调用 KsPinAttemptProcessing 时发生此事件。

Dele

当微型驱动程序从 DPC 内部调用以删除克隆流指针时发生此事件。

日志摘录如下所示:

f9494b80  3c435044 816e2c90 00000000 00000000  DPC<.,n.........
f9494b90  656c6544 816e2c90 81750260 00000000  Dele.,n.`.u.....
f9494ba0  706d7441 816e2c90 ffa4d418 00000000  Atmp.,n.........
f9494bb0  3c637250 819c1f00 00000000 00000000  Prc<............
f9494bc0  42646441 819c1f00 ffa2eb08 00000000  AddB............
f9494bd0  3c435044 816e2c90 00000000 00000000  DPC<.,n.........
f9494be0  656c6544 816e2c90 ffa80348 00000000  Dele.,n.H.......
f9494bf0  706d7441 816e2c90 ffa4d418 00000000  Atmp.,n.........
f9494c00  3c637250 819c1f00 00000000 00000000  Prc<............
f9494c10  42646441 819c1f00 ffa3d9b8 00000000  AddB............

第一个日志摘录代表正常的流式处理状态。 在第一行中,将调用微型驱动程序的 CallOnDPC 来完成缓冲区 (DPC<) 。 (Dele) 删除缓冲区,并且调用 KsPinAttemptProcessing 以向前移动前边缘,如果队列中有任何未处理的缓冲区 (Atmp) 。 在这种情况下, (中国<) 调用进程调度可以看到这一点。 将更多缓冲区添加到队列 (AddB) ,整个方案重复。

下一个摘录包括日志中最后一个条目,然后再发生停止。

f949b430  3c435044 816e2c90 00000000 00000000  DPC<.,n.........
f949b440  656c6544 816e2c90 ffac4de8 00000000  Dele.,n..M......
f949b450  706d7441 816e2c90 ffa4d418 00000000  Atmp.,n.........
f949b460  3c435044 816e2c90 00000000 00000000  DPC<.,n.........
f949b470  656c6544 816e2c90 816ffc80 00000000  Dele.,n...o.....
f949b480  706d7441 816e2c90 ffa4d418 00000000  Atmp.,n.........
f949b490  3c435044 816e2c90 00000000 00000000  DPC<.,n.........
f949b4a0  656c6544 816e2c90 ffa80348 00000000  Dele.,n.H.......
f949b4b0  706d7441 816e2c90 ffa4d418 00000000  Atmp.,n.........
f949b4c0  3c435044 816e2c90 00000000 00000000  DPC<.,n.........
f949b4d0  656c6544 816e2c90 8174e1c0 00000000  Dele.,n...t.....
f949b4e0  706d7441 816e2c90 ffa4d418 00000000  Atmp.,n.........

在此示例中,) 重复实例<指示 (完成多个缓冲区,但队列中没有未处理的缓冲区,因此进程调度不是由中国<) (指示的。 事实上,队列中的所有已处理缓冲区都已完成,显然在可以添加任何新的未处理的缓冲区之前。 由于应用程序已在运行 (,因此不会) 调用 Start ,并且没有调用 CallOnDPC (,因为没有任何已处理缓冲区可供完成) ,因此任何新缓冲区显然都在领先边缘之前累积,等待处理,没有任何启动处理。

问题是已设置KSPIN_FLAG_DO_NOT_INITIATE_PROCESSING标志。 设置此标志时,仅通过调用 StartCallOnDPC 进行处理。 如果未设置此标志,每当将新缓冲区添加到队列时,就会启动处理。