Skip to content

Commit ddc9d47

Browse files
authored
Optimize RmtCommand serialization (#74)
1 parent 77c00d1 commit ddc9d47

17 files changed

+618
-53
lines changed
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
using nanoFramework.Benchmark;
2+
using System;
3+
using System.Diagnostics;
4+
using System.Threading;
5+
6+
namespace nanoFramework.Hardware.Esp32.Rmt.Benchmarks
7+
{
8+
public class Program
9+
{
10+
public static void Main()
11+
{
12+
#if DEBUG
13+
Console.WriteLine("Benchmarks should be run in a release build.");
14+
Debugger.Break();
15+
return;
16+
#endif
17+
18+
BenchmarkRunner.RunClass(typeof(SerializeCommandsBenchmark));
19+
Thread.Sleep(Timeout.Infinite);
20+
}
21+
}
22+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
using System.Reflection;
2+
using System.Runtime.CompilerServices;
3+
using System.Runtime.InteropServices;
4+
5+
// General Information about an assembly is controlled through the following
6+
// set of attributes. Change these attribute values to modify the information
7+
// associated with an assembly.
8+
[assembly: AssemblyTitle("CSharp.BlankApplication")]
9+
[assembly: AssemblyDescription("")]
10+
[assembly: AssemblyConfiguration("")]
11+
[assembly: AssemblyCompany("")]
12+
[assembly: AssemblyProduct("CSharp.BlankApplication")]
13+
[assembly: AssemblyCopyright("Copyright © 2025")]
14+
[assembly: AssemblyTrademark("")]
15+
[assembly: AssemblyCulture("")]
16+
17+
// Setting ComVisible to false makes the types in this assembly not visible
18+
// to COM components. If you need to access a type in this assembly from
19+
// COM, set the ComVisible attribute to true on that type.
20+
[assembly: ComVisible(false)]
21+
22+
// Version information for an assembly consists of the following four values:
23+
//
24+
// Major Version
25+
// Minor Version
26+
// Build Number
27+
// Revision
28+
//
29+
// You can specify all the values or you can default the Build and Revision Numbers
30+
// by using the '*' as shown below:
31+
// [assembly: AssemblyVersion("1.0.*")]
32+
[assembly: AssemblyVersion("1.0.0.0")]
33+
[assembly: AssemblyFileVersion("1.0.0.0")]
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
using System.Collections;
2+
using nanoFramework.Benchmark;
3+
using nanoFramework.Benchmark.Attributes;
4+
5+
// ReSharper disable InconsistentNaming
6+
namespace nanoFramework.Hardware.Esp32.Rmt.Benchmarks
7+
{
8+
9+
[IterationCount(2000)]
10+
public class SerializeCommandsBenchmark
11+
{
12+
public static readonly RmtCommand Sk6812_OnePulse = new(14, true, 12, false);
13+
public static readonly RmtCommand Sk6812_ZeroPulse = new(7, true, 16, false);
14+
public static readonly RmtCommand Sk6812_ResetCommand = new(500, false, 520, false);
15+
16+
public static readonly RmtCommand Ws2808_OnePulse = new(52, true, 52, false);
17+
public static readonly RmtCommand Ws2808_ZeroPulse = new(14, true, 52, false);
18+
public static readonly RmtCommand Ws2808_ResetCommand = new(1400, false, 1400, false);
19+
20+
public static readonly RmtCommand Ws2812b_OnePulse = new(32, true, 18, false);
21+
public static readonly RmtCommand Ws2812b_ZeroPulse = new(16, true, 34, false);
22+
public static readonly RmtCommand Ws2812b_ResetCommand = new(2000, false, 2000, false);
23+
24+
public static readonly RmtCommand Ws2812c_OnePulse = new(52, true, 52, false);
25+
public static readonly RmtCommand Ws2812c_ZeroPulse = new(14, true, 52, false);
26+
public static readonly RmtCommand Ws2812c_ResetCommand = new(1400, false, 1400, false);
27+
28+
public static readonly RmtCommand Ws2815b_OnePulse = new(52, true, 52, false);
29+
public static readonly RmtCommand Ws2815b_ZeroPulse = new(14, true, 52, false);
30+
public static readonly RmtCommand Ws2815b_ResetCommand = new(1400, false, 1400, false);
31+
32+
public static readonly ArrayList RmtCommandsArrayList = new()
33+
{
34+
Sk6812_OnePulse,
35+
Sk6812_ZeroPulse,
36+
Sk6812_ResetCommand,
37+
38+
Ws2808_OnePulse,
39+
Ws2808_ZeroPulse,
40+
Ws2808_ResetCommand,
41+
42+
Ws2812b_OnePulse,
43+
Ws2812b_ZeroPulse,
44+
Ws2812b_ResetCommand,
45+
46+
Ws2812c_OnePulse,
47+
Ws2812c_ZeroPulse,
48+
Ws2812c_ResetCommand,
49+
50+
Ws2815b_OnePulse,
51+
Ws2815b_ZeroPulse,
52+
Ws2815b_ResetCommand
53+
};
54+
55+
[Benchmark]
56+
public void SerializeCommands_Current()
57+
{
58+
var serializedCommands = RmtCommandSerializer.SerializeCommands(RmtCommandsArrayList);
59+
}
60+
61+
[Benchmark]
62+
public void SerializeCommands_Original()
63+
{
64+
int i = 0;
65+
int remaining;
66+
byte[] binaryCommands = new byte[RmtCommandsArrayList.Count * 4];
67+
foreach (var cmd in RmtCommandsArrayList)
68+
{
69+
// First pair
70+
if ((cmd as RmtCommand).Duration0 <= 255)
71+
{
72+
binaryCommands[0 + i] = (byte)(cmd as RmtCommand).Duration0;
73+
binaryCommands[1 + i] = (byte)((cmd as RmtCommand).Level0 == true ? 128 : 0);
74+
}
75+
else
76+
{
77+
remaining = (cmd as RmtCommand).Duration0 % 256;
78+
binaryCommands[0 + i] = (byte)(remaining);
79+
binaryCommands[1 + i] = (byte)(((cmd as RmtCommand).Level0 ? 128 : 0) + (((cmd as RmtCommand).Duration0 - remaining) / 256));
80+
}
81+
82+
// Second pair
83+
if ((cmd as RmtCommand).Duration1 <= 255)
84+
{
85+
binaryCommands[2 + i] = (byte)(cmd as RmtCommand).Duration1;
86+
binaryCommands[3 + i] = (byte)((cmd as RmtCommand).Level1 ? 128 : 0);
87+
}
88+
else
89+
{
90+
remaining = (cmd as RmtCommand).Duration1 % 256;
91+
binaryCommands[2 + i] = (byte)(remaining);
92+
binaryCommands[3 + i] = (byte)(((cmd as RmtCommand).Level1 ? 128 : 0) + (((cmd as RmtCommand).Duration1 - remaining) / 256));
93+
}
94+
i += 4;
95+
}
96+
}
97+
}
98+
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<Project ToolsVersion="Current" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3+
<PropertyGroup Label="Globals">
4+
<NanoFrameworkProjectSystemPath>$(MSBuildExtensionsPath)\nanoFramework\v1.0\</NanoFrameworkProjectSystemPath>
5+
</PropertyGroup>
6+
<Import Project="$(NanoFrameworkProjectSystemPath)NFProjectSystem.Default.props" Condition="Exists('$(NanoFrameworkProjectSystemPath)NFProjectSystem.Default.props')" />
7+
<PropertyGroup>
8+
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
9+
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
10+
<ProjectTypeGuids>{11A8DD76-328B-46DF-9F39-F559912D0360};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
11+
<ProjectGuid>7c2bc423-f2d8-41dc-a5af-90cfd014ca07</ProjectGuid>
12+
<OutputType>Exe</OutputType>
13+
<AppDesignerFolder>Properties</AppDesignerFolder>
14+
<FileAlignment>512</FileAlignment>
15+
<RootNamespace>nanoFramework.Hardware.Esp32.Rmt.Benchmarks</RootNamespace>
16+
<AssemblyName>nanoFramework.Hardware.Esp32.Rmt.Benchmarks</AssemblyName>
17+
<TargetFrameworkVersion>v1.0</TargetFrameworkVersion>
18+
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
19+
</PropertyGroup>
20+
<PropertyGroup Label="nanoFramework">
21+
<SignAssembly>true</SignAssembly>
22+
</PropertyGroup>
23+
<PropertyGroup>
24+
<AssemblyOriginatorKeyFile>..\nanoFramework.Hardware.Esp32.Rmt\key.snk</AssemblyOriginatorKeyFile>
25+
</PropertyGroup>
26+
<PropertyGroup>
27+
<DelaySign>false</DelaySign>
28+
</PropertyGroup>
29+
<Import Project="$(NanoFrameworkProjectSystemPath)NFProjectSystem.props" Condition="Exists('$(NanoFrameworkProjectSystemPath)NFProjectSystem.props')" />
30+
<ItemGroup>
31+
<Compile Include="Program.cs" />
32+
<Compile Include="Properties\AssemblyInfo.cs" />
33+
<Compile Include="SerializeCommandsBenchmark.cs" />
34+
</ItemGroup>
35+
<ItemGroup>
36+
<Reference Include="mscorlib">
37+
<HintPath>..\packages\nanoFramework.CoreLibrary.1.17.1\lib\mscorlib.dll</HintPath>
38+
</Reference>
39+
<Reference Include="nanoFramework.Benchmark">
40+
<HintPath>..\packages\nanoFramework.Benchmark.1.0.102\lib\nanoFramework.Benchmark.dll</HintPath>
41+
</Reference>
42+
<Reference Include="nanoFramework.Logging">
43+
<HintPath>..\packages\nanoFramework.Logging.1.1.142\lib\nanoFramework.Logging.dll</HintPath>
44+
</Reference>
45+
<Reference Include="nanoFramework.Runtime.Native">
46+
<HintPath>..\packages\nanoFramework.Runtime.Native.1.7.9\lib\nanoFramework.Runtime.Native.dll</HintPath>
47+
</Reference>
48+
<Reference Include="nanoFramework.System.Collections">
49+
<HintPath>..\packages\nanoFramework.System.Collections.1.5.62\lib\nanoFramework.System.Collections.dll</HintPath>
50+
</Reference>
51+
<Reference Include="nanoFramework.System.Text">
52+
<HintPath>..\packages\nanoFramework.System.Text.1.3.29\lib\nanoFramework.System.Text.dll</HintPath>
53+
</Reference>
54+
<Reference Include="System.Diagnostics.Stopwatch">
55+
<HintPath>..\packages\nanoFramework.System.Diagnostics.Stopwatch.1.2.815\lib\System.Diagnostics.Stopwatch.dll</HintPath>
56+
</Reference>
57+
</ItemGroup>
58+
<ItemGroup>
59+
<None Include="packages.config" />
60+
</ItemGroup>
61+
<ItemGroup>
62+
<ProjectReference Include="..\nanoFramework.Hardware.Esp32.Rmt\nanoFramework.Hardware.Esp32.Rmt.nfproj" />
63+
</ItemGroup>
64+
<ItemGroup>
65+
<Content Include="packages.lock.json" />
66+
</ItemGroup>
67+
<Import Project="$(NanoFrameworkProjectSystemPath)NFProjectSystem.CSharp.targets" Condition="Exists('$(NanoFrameworkProjectSystemPath)NFProjectSystem.CSharp.targets')" />
68+
<ProjectExtensions>
69+
<ProjectCapabilities>
70+
<ProjectConfigurationsDeclaredAsItems />
71+
</ProjectCapabilities>
72+
</ProjectExtensions>
73+
</Project>
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<packages>
3+
<package id="nanoFramework.Benchmark" version="1.0.102" targetFramework="netnano1.0" />
4+
<package id="nanoFramework.CoreLibrary" version="1.17.1" targetFramework="netnano1.0" />
5+
<package id="nanoFramework.Logging" version="1.1.142" targetFramework="netnano1.0" />
6+
<package id="nanoFramework.Runtime.Native" version="1.7.9" targetFramework="netnano1.0" />
7+
<package id="nanoFramework.System.Collections" version="1.5.62" targetFramework="netnano1.0" />
8+
<package id="nanoFramework.System.Diagnostics.Stopwatch" version="1.2.815" targetFramework="netnano1.0" />
9+
<package id="nanoFramework.System.Text" version="1.3.29" targetFramework="netnano1.0" />
10+
</packages>
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
{
2+
"version": 1,
3+
"dependencies": {
4+
".NETnanoFramework,Version=v1.0": {
5+
"nanoFramework.Benchmark": {
6+
"type": "Direct",
7+
"requested": "[1.0.102, 1.0.102]",
8+
"resolved": "1.0.102",
9+
"contentHash": "J7G0Yq5Ms9Cms/ZZDcmRN/MnFiDs52vQvL7CVcJZ5BcpI9NwdNT/p2ymckkejMPu5bo7watVrcXM/ni3sblx6g=="
10+
},
11+
"nanoFramework.CoreLibrary": {
12+
"type": "Direct",
13+
"requested": "[1.17.1, 1.17.1]",
14+
"resolved": "1.17.1",
15+
"contentHash": "T/iPvP8AeZs/5UeZgVa2cZVbl79ioeRyBJLzx4qvKbE9RE+984AR5WPY4tjGIdXugs1AFUYYnydvuGCpy+P1ww=="
16+
},
17+
"nanoFramework.Logging": {
18+
"type": "Direct",
19+
"requested": "[1.1.142, 1.1.142]",
20+
"resolved": "1.1.142",
21+
"contentHash": "rHeUDLgtYN/PLsJg5kuQdCeT0gBAZRtJbopZvShlVHS88UGMYHjBmr8LvBAIJmq611wDTMqacqG3dxtfjiME3w=="
22+
},
23+
"nanoFramework.Runtime.Native": {
24+
"type": "Direct",
25+
"requested": "[1.7.9, 1.7.9]",
26+
"resolved": "1.7.9",
27+
"contentHash": "ekjQ4lTNVZ5FNrgry6XV0e7ydOSvcDGuAnSaNQewiBQAfSbpTZx3njCwU5SU5wcO+tBqT4wP7K1LNtw7unaUkg=="
28+
},
29+
"nanoFramework.System.Collections": {
30+
"type": "Direct",
31+
"requested": "[1.5.62, 1.5.62]",
32+
"resolved": "1.5.62",
33+
"contentHash": "tqYYxVHnfJU+v4aOwtW5u6oI3DWYx+njaTa2gY3LXkcltHlaNCXD4c5q314Zb17isZiizKXIB+X9vJnwxw1oLA=="
34+
},
35+
"nanoFramework.System.Diagnostics.Stopwatch": {
36+
"type": "Direct",
37+
"requested": "[1.2.815, 1.2.815]",
38+
"resolved": "1.2.815",
39+
"contentHash": "tzJyaSZZ6qrO6lVuo6XwZ8gao57IK3tsVoBlYFNGvTqwsn6CQQzGMBw4GkFbJv71ldFlwh0mGMic2fDvYDZRjA=="
40+
},
41+
"nanoFramework.System.Text": {
42+
"type": "Direct",
43+
"requested": "[1.3.29, 1.3.29]",
44+
"resolved": "1.3.29",
45+
"contentHash": "h7Jbjd8vmNrro/co6s+Zth+OvStgvOiT3RQtlaqa2t6FmnLZGXkF7LAykjLqWeNfHTafGbBLkSMqHw2VHo4Dmg=="
46+
}
47+
}
48+
}
49+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
using System.Reflection;
2+
using System.Runtime.CompilerServices;
3+
using System.Runtime.InteropServices;
4+
5+
// General Information about an assembly is controlled through the following
6+
// set of attributes. Change these attribute values to modify the information
7+
// associated with an assembly.
8+
[assembly: AssemblyDescription("")]
9+
[assembly: AssemblyConfiguration("")]
10+
[assembly: AssemblyCompany("")]
11+
[assembly: AssemblyCopyright("Copyright (c) 2021 nanoFramework contributors")]
12+
[assembly: AssemblyTrademark("")]
13+
[assembly: AssemblyCulture("")]
14+
15+
// Setting ComVisible to false makes the types in this assembly not visible
16+
// to COM components. If you need to access a type in this assembly from
17+
// COM, set the ComVisible attribute to true on that type.
18+
[assembly: ComVisible(false)]
19+
20+
// Version information for an assembly consists of the following four values:
21+
//
22+
// Major Version
23+
// Minor Version
24+
// Build Number
25+
// Revision
26+
//
27+
// You can specify all the values or you can default the Build and Revision Numbers
28+
// by using the '*' as shown below:
29+
// [assembly: AssemblyVersion("1.0.*")]
30+
[assembly: AssemblyVersion("1.0.0.0")]
31+
[assembly: AssemblyFileVersion("1.0.0.0")]

0 commit comments

Comments
 (0)