"op read" is pretty slow, ~700ms per invocation

ddribin
ddribin
Community Member
in CLI

Hi all,

I've noticed that op read is pretty slow, taking on the order of 700ms per invocation. Here's a benchmark using the hyerfine tool:

% hyperfine --warmup 3 "op read op://private/op-test/password"
Benchmark 1: op read op://private/op-test/password
  Time (mean ± σ):     717.2 ms ±  46.6 ms    [User: 118.7 ms, System: 39.6 ms]
  Range (min … max):   640.8 ms … 782.3 ms    10 runs

Reading a non-password field is about the same:

% hyperfine --warmup 3 "op read op://private/op-test/username"
Benchmark 1: op read op://private/op-test/username
  Time (mean ± σ):     733.2 ms ±  52.1 ms    [User: 124.0 ms, System: 41.4 ms]
  Range (min … max):   680.8 ms … 815.0 ms    10 runs

And using --cache does not seem to change anything:

% hyperfine --warmup 3 "op --cache read op://private/op-test/password"
Benchmark 1: op --cache read op://private/op-test/password
  Time (mean ± σ):     718.8 ms ±  50.3 ms    [User: 119.6 ms, System: 39.6 ms]
  Range (min … max):   653.7 ms … 806.7 ms    10 runs

This is on a 16-inch MacBook Pro with an M3 Max on Sonoma 14.4.1. I've installed op via Homebrew.

I'm not sure what the expectation is, but this seems much slower than I expected.


1Password Version: 8.10.30
Extension Version: Not Provided
OS Version: macOS 14.4.1
Browser: Not Provided

Comments

  • Hi @ddribin!

    I appreciate your feedback! I tested this myself and came up with similar results, I tried using UUIDs instead of the vault and item names in the secret reference, and was able to marginally improve the performance. Out of curiosity, were you expecting a faster response time? If so, what are some specific reasons why you were expecting that over what you encountered?

    • Andy
  • ddribin
    ddribin
    Community Member

    Hi @AndyW1P! Thank you for the reply!

    It's not so much that I was expecting faster times, but I didn't expect it to be so slow. Two places where I've used op recently that highlight the issue:

    First, I've been playing around with Ansible to setup a new server. I figured I'd put all the secrets, such as the sudo password, in 1Password and then use the community.general.onepassword lookup to set playbook variables.

    It turns out this lookup is extremely slow. It can slow down running playbooks by ~10x! A very simple playbook takes ~13s with the onepassword lookup. Switching it out to Ansible Vault, Ansible's own secret manager, the same playbook runs in ~1s.

    The onepassword lookup uses op under the hood. Apparently it runs it at least once for each task, due partially to Ansible’s lazy variable evaluation, so it adds up quickly.

    Second, I use Restic to backup some Linux servers to Backblaze B2. Again, I wanted to put all the secrets into 1Password, so I wrote this wrapper script:

    #!/bin/sh
    # shellcheck disable=SC2155
    
    RESTIC_BUCKET="$(op read "op://$OP_ITEM/bucket")"
    RESTIC_PATH="$(op read "op://$OP_ITEM/path")"
    export RESTIC_REPOSITORY="b2:$RESTIC_BUCKET:/$RESTIC_PATH"
    export RESTIC_PASSWORD="$(op read "op://$OP_ITEM/password")"
    
    export B2_ACCOUNT_ID="$(op read "op://$OP_ITEM/keyId")"
    export B2_ACCOUNT_KEY="$(op read "op://$OP_ITEM/applicationKey")"
    
    exec "$@"
    

    Now I can run restic-wrapper restic snapshots and it all "just works". But, again, I noticed this running very slowly. It takes 4 to 5 seconds just to get to the exec line, because there are five invocations of op.

    But, yes, both of these cases where unexpected slow, ultimately due to op taking ~700ms per invocation.

  • ddribin
    ddribin
    Community Member

    One other odd thing is that running this on an Intel CPU is a fair bit faster. On my 2017 iMac Pro, also running Sonoma 14.4.1, I get a benchmark of ~465ms:

    % hyperfine --warmup 3 "op read op://private/op-test/password"
    Benchmark 1: op read op://private/op-test/password
      Time (mean ± σ):     463.9 ms ±  13.0 ms    [User: 126.3 ms, System: 52.9 ms]
      Range (min … max):   441.7 ms … 485.8 ms    10 runs
    

    This is a good 235ms faster than the 700ms on my 2023 MacBook Pro with an M3 Max, which is very surprising. I thought maybe it was running through emulation, but it's a native ARM binary:

    % file =op
    /opt/homebrew/bin/op: Mach-O 64-bit executable arm64
    
  • jhogendorn
    jhogendorn
    Community Member

    I also find the op read function to be excruciatingly slow, averaging 2.5-3s per invocation. Its so slow it I would assume that it is doing multiple round trips to the internet vault to resolve. the cache flag makes no difference. I'm actually physically faster hitting cmd+shift+space, typing a search, cmd+shift+c, cmd+v, which is honestly kind of nuts. This cmd should be reading from a local vault if available and bound purely by I/O speed. for my use case i've been considering using the security cmd to cache credentials into the macos keychain, which is a silly workaround.

  • jhogendorn
    jhogendorn
    Community Member
    hyperfine --warmup 3 "op read 'op://private/test/password'"
    Benchmark 1: op read 'op://private/test/password'
      Time (mean ± σ):      2.695 s ±  0.051 s    [User: 0.051 s, System: 0.032 s]
      Range (min … max):    2.618 s …  2.775 s    10 runs
    
  • reps
    reps
    Community Member
    hyperfine --warmup 3  'op run -- echo'
    Benchmark 1: op run -- echo
      Time (mean ± σ):      2.131 s ±  0.066 s    [User: 0.063 s, System: 0.020 s]
      Range (min … max):    2.012 s …  2.208 s    10 runs
    

    op run is also very slow

  • thecurseofrng
    thecurseofrng
    Community Member

    Just to add further feedback on the subject, op read takes about 1s here.

    ❯ hyperfine "op read op://vault/test/credential"
    Benchmark 1: op read op://vault/test/credential
      Time (mean ± σ):     961.6 ms ±  27.6 ms    [User: 101.2 ms, System: 44.4 ms]
      Range (min … max):   919.1 ms … 1007.0 ms    10 runs
    

    On top of the Ansible use-case described earlier, this is also an issue for direnv variables, used to populate the shell env automatically on directory traversal. It kind of works with 1-2 secrets, but gets more and more obnoxious once you use more than that.