我正在运行一个文件并处理30个左右的不同片段类型。因此,每次,我都会读取一个片段并将其类型(十六进制)与我知道的片段进行比较。这是快还是我可以用另一种方式更快地做到这一点?
以下是我正在使用的代码示例:
// Iterate through the fragments and address them individually
for(int i = 0; i < header.fragmentCount; i++)
{
// Read in memory for the current fragment
memcpy(&frag, (wld + file_pos), sizeof(struct_wld_basic_frag));
// Deal with each frag type
switch(frag.id)
{
// Texture Bitmap Name(s)
case 0x03:
errorLog.OutputSuccess("[%i] 0x03 - Texture Bitmap Name", i);
break;
// Texture Bitmap Info
case 0x04:
errorLog.OutputSuccess("[%i] 0x04 - Texture Bitmap Info", i);
break;
// Texture Bitmap Reference Info
case 0x05:
errorLog.OutputSuccess("[%i] 0x05 - Texture Bitmap Reference Info", i);
break;
// Two-dimensional Object
case 0x06:
errorLog.OutputSuccess("[%i] 0x06 - Two-dimensioanl object", i);
break;
它贯穿其中的大约30个,当有数千个碎片时,它可以突然显示。如何建议我加快这个过程?
谢谢!
答案 0 :(得分:4)
如果除了格式字符串之外所有这些情况都相同,请考虑使用格式字符串数组,而不是大小写,如:
const char *fmtStrings[] = {
NULL, NULL, NULL,
"[%i] 0x03 - Texture Bitmap Name",
"[%i] 0x04 - Texture Bitmap Info",
/* ... */
};
// ...
errorLog.OutputSuccess(fmtStrings[i], i);
// (range checks elided)
这应该比交换机便宜,因为它不会涉及分支错误预测惩罚。也就是说,这个开关的成本可能低于实际格式化输出字符串的成本,因此您的优化工作可能有点错位。
答案 1 :(得分:2)
case语句应该非常快,因为当你的代码被优化时(甚至有时候它不是),它被实现为一个跳转表。进入调试器并在交换机上放置一个断点并检查反汇编以确保是这种情况。
答案 2 :(得分:1)
如果您的片段标识符不是太稀疏,您可以创建一个片段类型名称数组并将其用作查找表。
static const char *FRAGMENT_NAMES[] = {
0,
0,
0,
"Texture Bitmap Name", // 0x03
"Texture Bitmap Info", // 0x04
// etc.
};
...
const char *name = FRAGMENT_NAMES[frag.id];
if (name) {
errorLog.OutputSuccess("[%i] %x - %s", i, frag.id, name);
} else {
// unknown name
}
答案 3 :(得分:1)
我认为执行memcpy可能会导致很多开销。也许在(wld + file_pos)直接访问数据时使用switch语句。
答案 4 :(得分:1)
我怀疑30个案例陈述是个问题。与memcpy和errorLog方法所做的相比,这只是代码不多。首先验证您的速度是否受CPU时间限制,而不受磁盘访问限制。如果您确实受CPU限制,请检查分析器中的代码。
答案 5 :(得分:0)
如果你的日志语句总是“[%i] 0xdd - message ...”形式的字符串,而且frag.id总是0到30之间的整数,你可以改为声明一个字符串数组:
std::string messagesArray[] = {"[%i] 0x00 - message one", "[%i] 0x01 - message two", ...}
然后用
替换switch语句errorLog.OutputSuccess(messagesArray[frag.id], i);
答案 6 :(得分:0)
如果可能的片段类型值都是连续的,并且您不想做任何比匹配时打印字符串更复杂的事情,那么您只需索引到一个数组,例如:
const char* typeNames[] = {"Texture Bitmap Name", "Texture Bitmap Info", ...}; /* for each frag.id: */ if (LOWER_LIMIT <= frag.id && frag.id < UPPER_LIMIT) { printf("[%i] %#02x - %s\n", i, frag.id, typeNames[frag.id-LOWER_LIMIT]); } else { /* complain about error */ }
答案 7 :(得分:0)
如果没有看到更多内容,就无法确定,但似乎可以避免使用memcpy
,而是使用指针来浏览数据。
struct_wld_basic_frag *frag = (struct_wld_basic_frag *)wld;
for (i=0; i<header.fragmentCount; i++)
errorlog.OutputSuccess(fragment_strings[frag[i].id], i);
目前,我假设了@Chris和@Ates推荐的不同片段类型的字符串数组。即使在最坏的情况下,这也会提高可读性和可维护性,而不会影响速度。充其量,它可能(例如)提高缓存使用率,并提高速度 - 一个代码副本调用errorlog.outputSuccess
而不是30个单独的副本可以为许多其他“东西”腾出空间缓存。
每次避免复制数据更有可能做到真正的好。同时,我应该添加它可能可能导致问题 - 如果数据未在原始缓冲区中正确对齐,则尝试使用指针将无法工作。