Skip to content

Instantly share code, notes, and snippets.

@skippy
Created January 31, 2015 21:53
Show Gist options
  • Save skippy/50ff331b78f2e60ae014 to your computer and use it in GitHub Desktop.
Save skippy/50ff331b78f2e60ae014 to your computer and use it in GitHub Desktop.
localshred/protobuf vs protobuf-ruby/beefcake

Overview:

  • speed 'champ': protobuf
  • namespacing: protobuf (beefcake doesn't support it 'out of the box')
  • rubyness: beefcake by a nose

notes:

  • performance isn't everything, though I was surprised how much protobuf seemed to be ahead. These are very basic benchmarks, and your milage may, and probably will (!), vary. I noticed without strings protobuf was about 1/2 faster, but when including strings, that dropped to about 1/3 faster.
  • I like namespacing. If I'm going to go through the 'hassle' of putting a schema and DSL onto my wire definitions, then namespacing is more than a nice-to-have. Beefcake has a way to add it during build-time via the shell ENV, but protobuf wins a bit by just getting 'er done.
  • rubyness: beefcake strikes me as a tad cleaner in its auto-generated classes. Plus it just does one thing, but does it well... protobuf tries to include encoding/decoding, json, as well as RPC mechanisms. I don't mind that, but it does add a bit of extra 'heft' to the protobuf gem.

I ended up going with protobuf for its better documentation, slight ease-of-use, and project activity. But it is nice to know that switching between the two is pretty simple!

user system total real
setter_to_hash: 0.090000 0.000000 0.090000 ( 0.095632)
setter_enocode_s: 0.300000 0.000000 0.300000 ( 0.318015)
new_encode_s: 0.330000 0.010000 0.340000 ( 0.344149)
new_encode: 0.300000 0.000000 0.300000 ( 0.310616)
setter_enocode_s: 0.290000 0.000000 0.290000 ( 0.295217)
new_encode_s: 0.320000 0.010000 0.330000 ( 0.322100)
new_encode: 0.330000 0.000000 0.330000 ( 0.337682)
require "benchmark"
require 'beefcake'
require_relative 'lib/error_beefcake.pb'
Benchmark.bm(16) do |x|
x.report("setter_to_hash:") do
(1..10000).each do
e = Error.new
e.type = Error::ErrorType::API
e.status = Error::StatusType::BAD_REQUEST
e.message = 'and my name is adam'
e.to_hash
end
end
x.report("setter_enocode_s:") do
(1..10000).each do
e = Error.new
e.type = Error::ErrorType::API
e.status = Error::StatusType::BAD_REQUEST
e.message = 'and my name is adam'
e.encode.to_s
end
end
x.report("new_encode_s:") do
(1..10000).each do
e = Error.new type: Error::ErrorType::API, status: Error::StatusType::BAD_REQUEST, message: 'and my name is adam'
e.encode.to_s
end
end
x.report("new_encode:") do
(1..10000).each do
e = Error.new type: Error::ErrorType::API, status: Error::StatusType::BAD_REQUEST, message: 'and my name is adam'
e.encode
end
end
x.report("setter_enocode_s:") do
(1..10000).each do
e = Error.new
e.type = Error::ErrorType::API
e.status = Error::StatusType::BAD_REQUEST
e.message = 'and my name is adam'
e.encode.to_s
end
end
x.report("new_encode_s:") do
(1..10000).each do
e = Error.new type: Error::ErrorType::API, status: Error::StatusType::BAD_REQUEST, message: 'and my name is adam'
e.encode.to_s
end
end
x.report("new_encode:") do
(1..10000).each do
e = Error.new type: Error::ErrorType::API, status: Error::StatusType::BAD_REQUEST, message: 'and my name is adam'
e.encode
end
end
end
## Generated from capsci/error.proto for capsci
require "beefcake"
class Error
include Beefcake::Message
module ErrorType
NONE = 0
API = 1
INVALID_REQUEST = 2
WORK = 3
end
module StatusType
OK = 0
CREATED = 1
BAD_REQUEST = 5
UNAUTHORIZED = 6
REQUEST_FAILED = 7
NOT_FOUND = 8
INTERNAL_SERVER_ERROR = 10
BAD_GATEWAY = 11
SERVICE_UNAVAILABLE = 12
GATEWAY_TIMEOUT = 13
end
end
class Error
required :type, Error::ErrorType, 1, :default => Error::ErrorType::API
required :status, Error::StatusType, 2, :default => Error::StatusType::BAD_REQUEST
optional :request_id, :string, 5
optional :message, :string, 6
end
# encoding: utf-8
##
# This file is auto-generated. DO NOT EDIT!
#
require 'protobuf/message'
module Capsci
##
# Message Classes
#
class Error < ::Protobuf::Message
class ErrorType < ::Protobuf::Enum
define :NONE, 0
define :API, 1
define :INVALID_REQUEST, 2
define :WORK, 3
end
class StatusType < ::Protobuf::Enum
define :OK, 0
define :CREATED, 1
define :BAD_REQUEST, 5
define :UNAUTHORIZED, 6
define :REQUEST_FAILED, 7
define :NOT_FOUND, 8
define :INTERNAL_SERVER_ERROR, 10
define :BAD_GATEWAY, 11
define :SERVICE_UNAVAILABLE, 12
define :GATEWAY_TIMEOUT, 13
end
end
##
# Message Fields
#
class Error
required ::Capsci::Error::ErrorType, :type, 1, :default => ::Capsci::Error::ErrorType::API
required ::Capsci::Error::StatusType, :status, 2, :default => ::Capsci::Error::StatusType::BAD_REQUEST
optional :string, :request_id, 5
optional :string, :message, 6
end
end
user system total real
setter_to_hash: 0.090000 0.000000 0.090000 ( 0.092572)
setter_enocode_s: 0.210000 0.000000 0.210000 ( 0.220693)
new_encode_s: 0.240000 0.010000 0.250000 ( 0.257145)
new_encode: 0.240000 0.000000 0.240000 ( 0.249320)
setter_enocode_s: 0.220000 0.000000 0.220000 ( 0.244635)
new_encode_s: 0.270000 0.010000 0.280000 ( 0.275617)
new_encode: 0.250000 0.000000 0.250000 ( 0.263240)
setter_json: 0.340000 0.000000 0.340000 ( 0.347016)
new_json: 0.380000 0.010000 0.390000 ( 0.398045)
require "benchmark"
require 'protobuf'
require_relative 'lib/capsci/error_protobuf.pb'
Benchmark.bm(16) do |x|
x.report("setter_to_hash:") do
(1..10000).each do
e = Capsci::Error.new
e.type = Capsci::Error::ErrorType::API
e.status = Capsci::Error::StatusType::BAD_REQUEST
e.message = 'and my name is adam'
e.to_hash
end
end
x.report("setter_enocode_s:") do
(1..10000).each do
e = Capsci::Error.new
e.type = Capsci::Error::ErrorType::API
e.status = Capsci::Error::StatusType::BAD_REQUEST
e.message = 'and my name is adam'
e.encode.to_s
end
end
x.report("new_encode_s:") do
(1..10000).each do
e = Capsci::Error.new type: Capsci::Error::ErrorType::API, status: Capsci::Error::StatusType::BAD_REQUEST, message: 'and my name is adam'
e.encode.to_s
end
end
x.report("new_encode:") do
(1..10000).each do
e = Capsci::Error.new type: Capsci::Error::ErrorType::API, status: Capsci::Error::StatusType::BAD_REQUEST, message: 'and my name is adam'
e.encode
end
end
x.report("setter_enocode_s:") do
(1..10000).each do
e = Capsci::Error.new
e.type = Capsci::Error::ErrorType::API
e.status = Capsci::Error::StatusType::BAD_REQUEST
e.message = 'and my name is adam'
e.encode.to_s
end
end
x.report("new_encode_s:") do
(1..10000).each do
e = Capsci::Error.new type: Capsci::Error::ErrorType::API, status: Capsci::Error::StatusType::BAD_REQUEST, message: 'and my name is adam'
e.encode.to_s
end
end
x.report("new_encode:") do
(1..10000).each do
e = Capsci::Error.new type: Capsci::Error::ErrorType::API, status: Capsci::Error::StatusType::BAD_REQUEST, message: 'and my name is adam'
e.encode
end
end
x.report("setter_json:") do
(1..10000).each do
e = Capsci::Error.new
e.type = Capsci::Error::ErrorType::API
e.status = Capsci::Error::StatusType::BAD_REQUEST
e.message = 'and my name is adam'
e.to_json
end
end
x.report("new_json:") do
(1..10000).each do
e = Capsci::Error.new type: Capsci::Error::ErrorType::API, status: Capsci::Error::StatusType::BAD_REQUEST, message: 'and my name is adam'
e.to_json
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment