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

Post: digging into struct initialization performance #827

Merged

Conversation

ysbaddaden
Copy link
Contributor

@ysbaddaden ysbaddaden commented Sep 5, 2024

Issue: the kramdown gfm doesn't support the > [!TIP] annotation for callouts. I'm not sure how to replace these?

@ysbaddaden ysbaddaden self-assigned this Sep 5, 2024
Copy link

netlify bot commented Sep 5, 2024

Deploy Preview for crystal-website ready!

Name Link
🔨 Latest commit 3ef748d
🔍 Latest deploy log https://app.netlify.com/sites/crystal-website/deploys/66e04389df644b0008c2c417
😎 Deploy Preview https://deploy-preview-827--crystal-website.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify site configuration.

Copy link
Member

@beta-ziliani beta-ziliani left a comment

Choose a reason for hiding this comment

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

Nice! I left a few tips to improve it.

@HertzDevil
Copy link
Contributor

IIRC this was first posted before ReferenceStorage was a thing, so I did my own benchmark:

class Digest
  module ClassMethods
    def digest(& : self ->) : Bytes
      context_buf = uninitialized ReferenceStorage(self)
      context = unsafe_construct(pointerof(context_buf))
      begin
        yield context
        context.final
      ensure
        context.finalize if context.responds_to?(:finalize)
      end
    end
  end
end

class Digest::Blake3 < ::Digest
  extend ::Digest::ClassMethods
end

struct Blake3Hasher
  # ditto
end

def blake3_hexstring(data)
  hasher = Blake3Hasher.new
  # ...
end

def blake3_hexstring_init(data)
  hasher = uninitialized Blake3Hasher
  hasher.init
  # ...
end

Benchmark.ips do |x|
  bytes = Random::Secure.random_bytes(32)
  x.report("SHA256") { Digest::SHA256.hexdigest(bytes) }
  x.report("Blake3 Digest") { Digest::Blake3.hexdigest(bytes) }
  x.report("Blake3 new") { blake3_hexstring(bytes) }
  x.report("Blake3 init") { blake3_hexstring_init(bytes) }
end
       SHA256   2.89M (346.37ns) (± 0.34%)   128B/op   2.54× slower
Blake3 Digest   6.41M (156.08ns) (± 0.48%)   128B/op   1.15× slower
   Blake3 new   3.48M (287.00ns) (± 0.30%)  80.0B/op   2.11× slower
  Blake3 init   7.34M (136.28ns) (± 0.26%)  80.0B/op        fastest

The remaining overhead most likely came from the mandatory memory zeroing for reference types.

Without redefining Digest::ClassMethods#digest:

       SHA256   2.44M (410.30ns) (± 0.48%)    224B/op   3.08× slower
Blake3 Digest   2.85M (351.27ns) (± 0.97%)  2.13kB/op   2.64× slower
   Blake3 new   3.53M (282.93ns) (± 0.43%)   80.0B/op   2.12× slower
  Blake3 init   7.50M (133.25ns) (± 0.40%)   80.0B/op        fastest

@ysbaddaden
Copy link
Contributor Author

@HertzDevil Nice! I was thinking about this. A good demonstration of the experimental methods, and that RFC 4 could significantly improve performance!

Co-authored-by: Johannes Müller <[email protected]>
@ysbaddaden
Copy link
Contributor Author

@beta-ziliani I let you decide when to publish :)

@beta-ziliani beta-ziliani merged commit 26ee9f0 into master Sep 10, 2024
6 checks passed
@straight-shoota straight-shoota deleted the posts/ysbaddaden/struct-initialization-performance branch September 10, 2024 14:35
@kostya
Copy link

kostya commented Sep 11, 2024

I also have slow structs and fast tuples here crystal-lang/crystal#14225 (comment),
probably if you use tuples instead of struct it would be fast.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants