File: benchmark_encrypt_sign.rb

package info (click to toggle)
ruby-gpgme 2.0.26-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 3,644 kB
  • sloc: ruby: 3,683; ansic: 3,111; sh: 7; makefile: 5
file content (122 lines) | stat: -rw-r--r-- 4,103 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# -*- encoding: utf-8 -*-
# Benchmark to investigate encryption vs encryption+signing performance
require_relative '../test/test_helper'

# Simple timing helper since benchmark is no longer in stdlib
def measure(label, n = 5)
  start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
  n.times { yield }
  elapsed = Process.clock_gettime(Process::CLOCK_MONOTONIC) - start
  puts "#{label.ljust(30)} #{elapsed.round(4)}s total, #{(elapsed / n).round(4)}s per iteration"
  elapsed
end

# Profiling helper to trace where time is spent
def profile_encrypt_sign
  plain_text = "Hello, World! " * 100
  crypto = GPGME::Crypto.new(always_trust: true)
  key = KEYS.first[:sha]

  puts "\n=== Profiling encrypt only ==="
  t0 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
  keys = GPGME::Key.find(:public, key)
  t1 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
  puts "Key.find for recipients: #{((t1 - t0) * 1000).round(2)}ms"

  GPGME::Ctx.new(always_trust: true) do |ctx|
    t2 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
    puts "Ctx.new: #{((t2 - t1) * 1000).round(2)}ms"

    plain_data = GPGME::Data.new(plain_text)
    cipher_data = GPGME::Data.new
    ctx.encrypt(keys, plain_data, cipher_data, GPGME::ENCRYPT_ALWAYS_TRUST)
    t3 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
    puts "encrypt: #{((t3 - t2) * 1000).round(2)}ms"
  end

  puts "\n=== Profiling encrypt + sign (no explicit signer) ==="
  t0 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
  keys = GPGME::Key.find(:public, key)
  t1 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
  puts "Key.find for recipients: #{((t1 - t0) * 1000).round(2)}ms"

  GPGME::Ctx.new(always_trust: true) do |ctx|
    t2 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
    puts "Ctx.new: #{((t2 - t1) * 1000).round(2)}ms"

    plain_data = GPGME::Data.new(plain_text)
    cipher_data = GPGME::Data.new
    ctx.encrypt_sign(keys, plain_data, cipher_data, GPGME::ENCRYPT_ALWAYS_TRUST)
    t3 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
    puts "encrypt_sign: #{((t3 - t2) * 1000).round(2)}ms"
  end

  puts "\n=== Profiling encrypt + sign (with explicit signer - current code) ==="
  t0 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
  keys = GPGME::Key.find(:public, key)
  t1 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
  puts "Key.find for recipients: #{((t1 - t0) * 1000).round(2)}ms"

  signers = GPGME::Key.find(:public, key, :sign)
  t2 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
  puts "Key.find for signers: #{((t2 - t1) * 1000).round(2)}ms"

  GPGME::Ctx.new(always_trust: true) do |ctx|
    t3 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
    puts "Ctx.new: #{((t3 - t2) * 1000).round(2)}ms"

    ctx.add_signer(*signers)
    t4 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
    puts "add_signer: #{((t4 - t3) * 1000).round(2)}ms"

    plain_data = GPGME::Data.new(plain_text)
    cipher_data = GPGME::Data.new
    ctx.encrypt_sign(keys, plain_data, cipher_data, GPGME::ENCRYPT_ALWAYS_TRUST)
    t5 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
    puts "encrypt_sign: #{((t5 - t4) * 1000).round(2)}ms"
  end

  puts "\n=== Key.find cost breakdown ==="
  10.times do |i|
    t0 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
    GPGME::Key.find(:public, key)
    t1 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
    puts "Key.find iteration #{i + 1}: #{((t1 - t0) * 1000).round(2)}ms"
  end
end

# Ensure keys are imported
import_keys

plain_text = "Hello, World! " * 1000  # ~14KB of data

crypto = GPGME::Crypto.new(always_trust: true)
key = KEYS.first[:sha]

puts "Data size: #{plain_text.bytesize} bytes"
puts

n = 50

measure("encrypt only:", n) do
  crypto.encrypt(plain_text, recipients: key)
end

measure("encrypt + sign:", n) do
  crypto.encrypt(plain_text, recipients: key, sign: true)
end

measure("sign only:", n) do
  crypto.sign(plain_text)
end

puts
puts "Running with explicit signer..."
puts

measure("encrypt + sign (explicit):", n) do
  crypto.encrypt(plain_text, recipients: key, sign: true, signers: key)
end

# Run detailed profiling
profile_encrypt_sign