printf()调试库使用字符串表“解码器环” [英] printf() debugging library using string table "decoder ring"

查看:168
本文介绍了printf()调试库使用字符串表“解码器环”的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在写信,看看有没有人见过或听说过我将要描述的想法的实现。



我有兴趣在为嵌入式目标开发一个printf风格的调试库。目标是非常遥远的,我和目标之间的通信带宽预算非常紧张,所以我想能够以非常有效的格式获取调试消息。



经常,调试语句看起来像以下内容:

  myDebugLibraryPrintf(内部循环,处理项%d从% d.\\\
,i,numItems);

当然,当扩展为文本时,打印的字符串类似于内循环,处理项目5中的10.\\\
,共约〜42个字节。该语句打印出来的数据超过90%是静态的,在编译时是已知的。当然,在编译时只有5和10是不知道的。



我想做的是只能发回这两个整数(8字节而不是42)。收到这些数据后,我会有一些解码器铃声,让我重建接收到的数据,并在我的位置打印出完整的调试信息。我将自动生成解码器环(作为构建过程的一部分),在编译时给每个myDebugLibraryPrintf()语句提供唯一的ID,并生成一个将这些唯一ID映射到原始格式字符串的表。然后,任何时候在目标上调用myDebugLibraryPrintf(),它会传输唯一的ID和任何%d%f 等在格式字符串中看到的varargs值,但格式字符串本身不被传输。 (我现在可能不允许%s项目...)回到我的位置,我们将有一个程序来查找唯一ID表,找到适当的格式字符串,并使用它来重建原始的调试消息。



我觉得有人以前有这个想法,我想也许有人在社区会看到类似的东西(甚至知道这样做的开源图书馆)。



限制:




  • 为了澄清,我在这里处理C / C ++,对于printf()的100%完全替换实现我并不感兴趣 - 像非或者更高级的格式说明符,例如将宽度或精度放在带有%*的varargs列表中的文件格式字符串%s (string) 。* d 不需要被支持。


  • 我希望自动生成字符串表作为构建的一部分进程,以便添加调试不包括添加传统的printf()的工作。如果不需要最少的努力,我的项目中没有人会使用它。


  • 作为构建过程的一部分进行额外的工作以生成字符串表几乎被假定。幸运的是,我控制了我有兴趣使用这个库的所有源代码,我在构建过程中有很多灵活性。




谢谢!

解决方案

我只看过这个想法,一组字符串代码看起来像 debug_print(INSIDE_LOOP_MSG_ID,i,n)。当开发人员想要添加新消息时,他们必须将新文本放在一个特定的头文件中,并给它一个新的ID。



我认为生成它的想法来自正常的打印声明的飞是一个有趣的挑战。我没有遇到任何现有的实现。



一个想法可能是一个宏/模板,将第一个字符串参数转换为一个编译时的哈希值。因此,开发人员将 debug_print(test%d,i)编译成 debug_port_send(0x1d3s,i)。编写一个后处理脚本来提取字符串,并在接收方使用哈希应该很简单。 (解决哈希冲突的最简单的方法是给出错误消息,并强制用户稍稍更改措辞)。



编辑:

所以我试着用上面的链接的编译时哈希。

  #define QQuot_(x)# x 
#define QQuote(x)QQuot_(x)
#define Debug_Print(s,v)(发送(CONSTHASH(QQuote(__ LINE __)## s))*((long *)& )$)

void发送(long hash,long value)
{
printf(发送%x%x\\\
,hash,value); //替换为COMMS
}


int main()
{
int i = 1;
float f = 3.14f;
Debug_Print(这是一个测试%d,i);
i ++;
Debug_Print(这是一个测试%d,i);
Debug_Print(这是测试%f,f);
}

有一点更聪明,你可以支持多个参数。
检查拆分表明,所有的哈希确实是在编译时计算的。输出是预期的,没有相同字符串的冲突。 (此页面确认十六进制对于3.14)是正确的:

 发送94b7555c 1 
发送62fce13e 2
发送506e9a0c 4048f5c3

现在您需要的是一个文本处理脚本,可以在从Debug_Print中提取字符串的代码上运行,计算散列并填充表接收方。接收器从发送调用中获取一个哈希值,查找与之一起的字符串,并将该参数与参数一起传递到正常的printf调用。



我看到的唯一问题是编译时哈希中的嵌套宏是使我的重构插件变得混乱,并杀死我的IDE响应性。禁用加载项删除该问题。


I'm writing to see if any of you have ever seen or heard of an implementation of the idea I'm about to describe.

I'm interested in developing a printf-style debugging library for an embedded target. The target is extremely remote, and the comms bandwidth budget between me and the target is extremely tight, so I want to be able to get the debugging messages in a very efficient format.

Quite often, debug statements look something like the following:

myDebugLibraryPrintf("Inside loop, processing item %d out of %d.\n", i, numItems);

Of course, when this is expanded into text, the string printed is something like "Inside loop, processing item 5 out of 10.\n", a total of ~42 bytes or so. Over 90% of the data printed out by this statement is static, literal -- known at compile-time. Of course, only the "5" and "10" aren't known at compile-time.

What I'd like to do is be able to send back only those two integers (8 bytes instead of 42). Once I've received that data, I'd have some kind of "decoder ring" that lets me "reconstitute" the received data and print out the full debug message here at my location.

I'd generate the "decoder ring" by automatically (as part of the build process) giving every myDebugLibraryPrintf() statement a unique ID at compile time, and generating a table that maps those unique IDs to the original format strings. Then, any time myDebugLibraryPrintf() is called on the target, it transmits the unique ID and any of the "%d", "%f", etc. varargs values seen in the format string, but the format string itself is NOT transmitted. (I'll probably just disallow "%s" items for now...) Back at my location, we'll have a program that looks up the unique IDs in the table, finds the appropriate format string, and uses it to reconstruct the original debug message.

I feel like someone has probably had this idea before and I figured maybe someone in the community would have seen something like it (or even know of an open-source library that does this).

Constraints:

  • To clarify, I'm dealing with C/C++ here, and I'm not interested in a 100%-complete replacement implementation of printf() -- things like non-literal format strings, %s (string) format specifiers, or more advanced format specifiers like putting the width or precision in the varargs list with %*.*d don't need to be supported.

  • I want the string table to be generated automatically as part of the build process so that adding debug involves no more work than adding a traditional printf(). If any more than the minimum amount of effort is required, nobody on my project will use it.

  • Doing extra work as part of the build process to generate the string table is pretty much assumed. Fortunately, I have control of all the source code that I'm interested in using this library with, and I have a lot of flexibility within the build process.

Thanks!

解决方案

I've only seen this idea implemented with a pre-defined set of strings. The code would look like debug_print(INSIDE_LOOP_MSG_ID, i, n). When developers wanted to add new messages they would have to put the new text in a specific header file and give it a new ID.

I think the idea of generating it on the fly from a normal-looking print statement is a interesting challenge. I haven't come across any existing implementations.

One idea might be a macro/template which turns the first string argument into a hash value at compile time. So the developer writes debug_print("test %d",i), which gets compiled to debug_port_send(0x1d3s, i). Writing a post-processing script to extract the strings and hashes for use on the recieving side should be simple. (simplest way to resolve hash collisions would be to give error message and force user to alter the wording slightly).

edit:
So I tried this with the compile-time hash at the link above.

#define QQuot_(x) #x
#define QQuote(x) QQuot_(x)
#define Debug_Print(s, v) (Send( CONSTHASH(QQuote(__LINE__)##s), *((long*)&(v))))

void Send(long hash, long value)
{
   printf("Sending %x %x\n", hash, value); //replace with COMMS
}


int main()
{
   int i = 1;
   float f= 3.14f;
   Debug_Print("This is a test %d", i);
   i++;
   Debug_Print("This is a test %d", i);
   Debug_Print("This was test %f", f);
}

With a little more cleverness you could support multiple arguments. Examining dissasembly shows that all the hashes are indeed computed at compile time. Output is as expected, no collisions from identical strings. (This page confirms the hex is correct for 3.14):

Sending 94b7555c 1
Sending 62fce13e 2
Sending 506e9a0c 4048f5c3

All you need now is a text-processing script that can be run on the code which extracts the strings from Debug_Print, calculates the hashes and populates a table your reciever side. The reciever gets a hash value from the Send call, looks up the string that goes with it, and passes that, along with the argument(s) to a normal printf call.

The only problem I see is that the nested macros in the compile time hash are confusing my refactoring plug-in and killing my IDE responsiveness. Disabling the add-in removed that issue.

这篇关于printf()调试库使用字符串表“解码器环”的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆