Jiri Simsa | d7616c9 | 2015-03-24 23:44:30 -0700 | [diff] [blame] | 1 | // Copyright 2015 The Vanadium Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style |
| 3 | // license that can be found in the LICENSE file. |
| 4 | |
Matt Rosencrantz | 94502cf | 2015-03-18 09:43:44 -0700 | [diff] [blame] | 5 | package rpc |
Robin Thellend | 8eb7752 | 2014-08-28 14:12:01 -0700 | [diff] [blame] | 6 | |
| 7 | import ( |
| 8 | "sync" |
| 9 | "time" |
| 10 | |
Jiri Simsa | ffceefa | 2015-02-28 11:03:34 -0800 | [diff] [blame] | 11 | "v.io/x/ref/lib/stats" |
| 12 | "v.io/x/ref/lib/stats/counter" |
| 13 | "v.io/x/ref/lib/stats/histogram" |
Robin Thellend | 8eb7752 | 2014-08-28 14:12:01 -0700 | [diff] [blame] | 14 | |
Jiri Simsa | 6ac9522 | 2015-02-23 16:11:49 -0800 | [diff] [blame] | 15 | "v.io/v23/naming" |
Robin Thellend | 8eb7752 | 2014-08-28 14:12:01 -0700 | [diff] [blame] | 16 | ) |
| 17 | |
Matt Rosencrantz | 94502cf | 2015-03-18 09:43:44 -0700 | [diff] [blame] | 18 | type rpcStats struct { |
Suharsh Sivakumar | 720b704 | 2014-12-22 17:33:23 -0800 | [diff] [blame] | 19 | mu sync.RWMutex |
| 20 | prefix string |
| 21 | methods map[string]*perMethodStats |
| 22 | blessingsCacheStats *blessingsCacheStats |
Robin Thellend | 8eb7752 | 2014-08-28 14:12:01 -0700 | [diff] [blame] | 23 | } |
| 24 | |
Matt Rosencrantz | 94502cf | 2015-03-18 09:43:44 -0700 | [diff] [blame] | 25 | func newRPCStats(prefix string) *rpcStats { |
| 26 | return &rpcStats{ |
Suharsh Sivakumar | 720b704 | 2014-12-22 17:33:23 -0800 | [diff] [blame] | 27 | prefix: prefix, |
| 28 | methods: make(map[string]*perMethodStats), |
| 29 | blessingsCacheStats: newBlessingsCacheStats(prefix), |
| 30 | } |
Robin Thellend | 8eb7752 | 2014-08-28 14:12:01 -0700 | [diff] [blame] | 31 | } |
| 32 | |
| 33 | type perMethodStats struct { |
| 34 | latency *histogram.Histogram |
| 35 | } |
| 36 | |
Matt Rosencrantz | 94502cf | 2015-03-18 09:43:44 -0700 | [diff] [blame] | 37 | func (s *rpcStats) stop() { |
Robin Thellend | df42823 | 2014-10-06 12:50:44 -0700 | [diff] [blame] | 38 | stats.Delete(s.prefix) |
| 39 | } |
| 40 | |
Matt Rosencrantz | 94502cf | 2015-03-18 09:43:44 -0700 | [diff] [blame] | 41 | func (s *rpcStats) record(method string, latency time.Duration) { |
Robin Thellend | 8eb7752 | 2014-08-28 14:12:01 -0700 | [diff] [blame] | 42 | // Try first with a read lock. This will succeed in the most common |
| 43 | // case. If it fails, try again with a write lock and create the stats |
| 44 | // objects if they are still not there. |
| 45 | s.mu.RLock() |
| 46 | m, ok := s.methods[method] |
| 47 | s.mu.RUnlock() |
| 48 | if !ok { |
| 49 | m = s.newPerMethodStats(method) |
| 50 | } |
| 51 | m.latency.Add(int64(latency / time.Millisecond)) |
| 52 | } |
| 53 | |
Matt Rosencrantz | 94502cf | 2015-03-18 09:43:44 -0700 | [diff] [blame] | 54 | func (s *rpcStats) recordBlessingCache(hit bool) { |
Suharsh Sivakumar | 720b704 | 2014-12-22 17:33:23 -0800 | [diff] [blame] | 55 | s.blessingsCacheStats.incr(hit) |
| 56 | } |
| 57 | |
Robin Thellend | 8eb7752 | 2014-08-28 14:12:01 -0700 | [diff] [blame] | 58 | // newPerMethodStats creates a new perMethodStats object if one doesn't exist |
| 59 | // already. It returns the newly created object, or the already existing one. |
Matt Rosencrantz | 94502cf | 2015-03-18 09:43:44 -0700 | [diff] [blame] | 60 | func (s *rpcStats) newPerMethodStats(method string) *perMethodStats { |
Robin Thellend | 8eb7752 | 2014-08-28 14:12:01 -0700 | [diff] [blame] | 61 | s.mu.Lock() |
| 62 | defer s.mu.Unlock() |
| 63 | m, ok := s.methods[method] |
| 64 | if !ok { |
Bogdan Caprita | e737631 | 2014-11-10 13:13:17 -0800 | [diff] [blame] | 65 | name := naming.Join(s.prefix, "methods", method, "latency-ms") |
Robin Thellend | 8eb7752 | 2014-08-28 14:12:01 -0700 | [diff] [blame] | 66 | s.methods[method] = &perMethodStats{ |
| 67 | latency: stats.NewHistogram(name, histogram.Options{ |
| 68 | NumBuckets: 25, |
| 69 | GrowthFactor: 1, |
| 70 | SmallestBucketSize: 1, |
| 71 | MinValue: 0, |
| 72 | }), |
| 73 | } |
| 74 | m = s.methods[method] |
| 75 | } |
| 76 | return m |
| 77 | } |
Suharsh Sivakumar | 720b704 | 2014-12-22 17:33:23 -0800 | [diff] [blame] | 78 | |
| 79 | // blessingsCacheStats keeps blessing cache hits and total calls received to determine |
| 80 | // how often the blessingCache is being used. |
| 81 | type blessingsCacheStats struct { |
| 82 | callsReceived, cacheHits *counter.Counter |
| 83 | } |
| 84 | |
| 85 | func newBlessingsCacheStats(prefix string) *blessingsCacheStats { |
| 86 | cachePrefix := naming.Join(prefix, "security", "blessings", "cache") |
| 87 | return &blessingsCacheStats{ |
| 88 | callsReceived: stats.NewCounter(naming.Join(cachePrefix, "attempts")), |
| 89 | cacheHits: stats.NewCounter(naming.Join(cachePrefix, "hits")), |
| 90 | } |
| 91 | } |
| 92 | |
| 93 | // Incr increments the cache attempt counter and the cache hit counter if hit is true. |
| 94 | func (s *blessingsCacheStats) incr(hit bool) { |
| 95 | s.callsReceived.Incr(1) |
| 96 | if hit { |
| 97 | s.cacheHits.Incr(1) |
| 98 | } |
| 99 | } |