NodeMCU / Lua性能问题

时间:2015-12-26 13:51:24

标签: lua esp8266 nodemcu

我正在向ws2812模块添加一些代码,以便能够存储某种可重用的缓冲区,我们可以存储led值。

当前版本为there

我有两个问题。

首先,我想要一些“OO风格”的界面。所以我做了:

local buffer = ws2812.newBuffer(300);
for j = 0,299 do
   buffer:set(j, 255, 255, 255)
end
buffer:write(pin);

这里的问题是buffer:set在每次循环转换时被解析,这是昂贵的(这个循环需要大约20.2ms):

8       [2]     FORPREP         1 6     ; to 15
9       [3]     SELF            5 0 -7  ; "set"
10      [3]     MOVE            7 4
11      [3]     LOADK           8 -8    ; 255
12      [3]     LOADK           9 -8    ; 255
13      [3]     LOADK           10 -8   ; 255
14      [3]     CALL            5 6 1
15      [2]     FORLOOP         1 -7    ; to 9

我发现这个问题的解决方法看起来不太好看:

local buffer = ws2812.newBuffer(300);
local set = getmetatable(buffer).set;
for j = 0,299 do
   set(buffer, j, 255, 255, 255)
end
buffer:write(pin);

它运行良好(循环4.3ms,快4倍以上),但它更像是黑客。 :/有没有更好的方法来“缓存”缓冲区:设置分辨率?

第二个问题,在我的C代码中,我使用:

ws2812_buffer * buffer = (ws2812_buffer*)luaL_checkudata(L, 1, "ws2812.buffer");

返回我的缓冲区ptr并检查它是否真的是ws2812.buffer。但是这个叫做sloooooow:在我的ESP8266上,~50us。如果它在每次通话时完成(例如我的300次buffer:set),那就是〜15ms!

有没有更好的方法来获取一些用户数据并检查其类型,或者我应该在我的结构的开头添加一些“金丝雀”来做我自己的检查(与50us相比几乎是“免费的”.. 。)?

1 个答案:

答案 0 :(得分:3)

为了让它看起来不那么糟糕,你可以尝试使用

local set = buffer.set

这基本上是相同的代码,但没有getmetatable,因为metatable通过__index metamethod隐式使用。

在我们的项目中,我们自己实现了luaL_checkudata。 一个选项 - 正如您所建议的那样 - 是使用包含该类型的包装器对象。由于假定所有userdata都包装在包装器中,我们可以使用它来获取并确认userdata的类型。但是没有进行基准测试,而是使用了测试元数据。

我想说测试metatables比包装慢,因为luaL_checkudata做了很多工作来测试metatables并且通过包装我们可以直接访问这个类型。然而,基准测试肯定会证明。