Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove slice! from fixed_protocol #1207

Merged
merged 2 commits into from
Apr 29, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions openc3/lib/openc3/interfaces/protocols/fixed_protocol.rb
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ def identify_and_finish_packet
end

if unique_id_mode
target_packets.each do |packet_name, packet|
target_packets.each do |_packet_name, packet|
if packet.identify?(@data[@discard_leading_bytes..-1])
identified_packet = packet
break
Expand Down Expand Up @@ -136,7 +136,13 @@ def identify_and_finish_packet
@packet_name = identified_packet.packet_name

# Get the data from this packet
packet_data = @data.slice!(0, identified_packet.defined_length + @discard_leading_bytes)
# Previous implementation looked like the following:
# packet_data = @data.slice!(0, identified_packet.defined_length + @discard_leading_bytes)
# But slice! is 6x slower at small packets (1024)
# and 1000x slower at large packets (1Mb)
# Run test/benchmarks/string_mod_benchmark.rb for details
packet_data = @data[0...identified_packet.defined_length + @discard_leading_bytes]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this intentionally ... and shouldn't there be parens around the + expression?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Order of operations applies plus before range but it's clearer with parens

@data = @data[(identified_packet.defined_length + @discard_leading_bytes)..-1]
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is equivalent functionality. I tried to add a new test case to the spec but not sure if I fully covered the case because if you change ..-1 to ..-2 it still passes

break
end
end
Expand All @@ -152,7 +158,7 @@ def identify_and_finish_packet
@data.replace('')
end

return packet_data
return packet_data, @extra
end

def reduce_to_single_packet
Expand Down
41 changes: 41 additions & 0 deletions openc3/spec/interfaces/protocols/fixed_protocol_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,47 @@ def read
expect(packet.buffer).to eql $buffer
target.cmd_unique_id_mode = false
end

it "breaks apart telemetry data from the stream" do
packet = System.telemetry.packet("SYSTEM", "META")
packet.write('PKTID', 1)
packet.write('OPERATOR_NAME', 'RYAN')
$buffer1 = packet.buffer.clone
packet.write('OPERATOR_NAME', 'JASON')
$buffer2 = packet.buffer.clone
$buffer = "\x1A\xCF\xFC\x1D" + $buffer1 + "\x1A\xCF\xFC\x1D" + $buffer2
$index = 0

class FixedStream3 < Stream
def connect; end

def connected?; true; end

def read
# Send a byte a time
$index += 1
$buffer[$index - 1]
end
end
# Require 5 bytes, discard 4 leading bytes, use 0x1ACFFC1D sync, telemetry = true
@interface.add_protocol(FixedProtocol, [5, 4, '0x1ACFFC1D', true], :READ_WRITE)
@interface.instance_variable_set(:@stream, FixedStream3.new)
@interface.target_names = ['SYSTEM']
@interface.cmd_target_names = ['SYSTEM']
@interface.tlm_target_names = ['SYSTEM']
packet = @interface.read
expect(packet.received_time.to_f).to be_within(0.01).of(Time.now.to_f)
expect(packet.target_name).to eql 'SYSTEM'
expect(packet.packet_name).to eql 'META'
expect(packet.buffer).to include('RYAN')
packet = @interface.read
expect(packet.received_time.to_f).to be_within(0.01).of(Time.now.to_f)
expect(packet.target_name).to eql 'SYSTEM'
expect(packet.packet_name).to eql 'META'
expect(packet.buffer).to include('JASON')
packet = @interface.read
expect(packet).to be_nil
end
end
end
end
50 changes: 50 additions & 0 deletions openc3/test/benchmarks/string_mod_benchmark.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# encoding: ascii-8bit

# Copyright 2023 OpenC3, Inc.
# All Rights Reserved.
#
# This program is free software; you can modify and/or redistribute it
# under the terms of the GNU Affero General Public License
# as published by the Free Software Foundation; version 3 with
# attribution addendums as found in the LICENSE.txt
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# This file may also be used under the terms of a commercial license
# if purchased from OpenC3, Inc.

require 'securerandom'
require 'benchmark'

Benchmark.bm do |x|
data = SecureRandom.random_bytes(1024)
x.report("slice!") do
1000.times.each { data.slice!(0, 1) }
end
data = SecureRandom.random_bytes(1024)
x.report("assign") do
1000.times.each { data = data[1..-1] }
end
data = SecureRandom.random_bytes(1024)
x.report("replace") do
1000.times.each { data.replace(data[1..-1]) }
end
end

Benchmark.bm do |x|
data = SecureRandom.random_bytes(1024*1024)
x.report("slice!") do
1000.times.each { data.slice!(0, 1) }
end
data = SecureRandom.random_bytes(1024*1024)
x.report("assign") do
1000.times.each { data = data[1..-1] }
end
data = SecureRandom.random_bytes(1024*1024)
x.report("replace") do
1000.times.each { data.replace(data[1..-1]) }
end
end
18 changes: 18 additions & 0 deletions openc3/test/benchmarks/system_benchmark.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,21 @@
# encoding: ascii-8bit

# Copyright 2023 OpenC3, Inc.
# All Rights Reserved.
#
# This program is free software; you can modify and/or redistribute it
# under the terms of the GNU Affero General Public License
# as published by the Free Software Foundation; version 3 with
# attribution addendums as found in the LICENSE.txt
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# This file may also be used under the terms of a commercial license
# if purchased from OpenC3, Inc.

require 'openc3'
require 'benchmark'
ENV['OPENC3_NO_STORE'] = 'true'
Expand Down
Loading