1 /* 2 * 3 * Copyright 2016 gRPC authors. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 */ 18 19 #ifndef GRPC_CORE_LIB_IOMGR_RESOURCE_QUOTA_H 20 #define GRPC_CORE_LIB_IOMGR_RESOURCE_QUOTA_H 21 22 #include <grpc/support/port_platform.h> 23 24 #include <grpc/grpc.h> 25 26 #include "src/core/lib/debug/trace.h" 27 #include "src/core/lib/iomgr/closure.h" 28 29 /** \file Tracks resource usage against a pool. 30 31 The current implementation tracks only memory usage, but in the future 32 this may be extended to (for example) threads and file descriptors. 33 34 A grpc_resource_quota represents the pooled resources, and 35 grpc_resource_user instances attach to the quota and consume those 36 resources. They also offer a vector for reclamation: if we become 37 resource constrained, grpc_resource_user instances are asked (in turn) to 38 free up whatever they can so that the system as a whole can make progress. 39 40 There are three kinds of reclamation that take place, in order of increasing 41 invasiveness: 42 - an internal reclamation, where cached resource at the resource user level 43 is returned to the quota 44 - a benign reclamation phase, whereby resources that are in use but are not 45 helping anything make progress are reclaimed 46 - a destructive reclamation, whereby resources that are helping something 47 make progress may be enacted so that at least one part of the system can 48 complete. 49 50 Only one reclamation will be outstanding for a given quota at a given time. 51 On each reclamation attempt, the kinds of reclamation are tried in order of 52 increasing invasiveness, stopping at the first one that succeeds. Thus, on a 53 given reclamation attempt, if internal and benign reclamation both fail, it 54 will wind up doing a destructive reclamation. However, the next reclamation 55 attempt may then be able to get what it needs via internal or benign 56 reclamation, due to resources that may have been freed up by the destructive 57 reclamation in the previous attempt. 58 59 Future work will be to expose the current resource pressure so that back 60 pressure can be applied to avoid reclamation phases starting. 61 62 Resource users own references to resource quotas, and resource quotas 63 maintain lists of users (which users arrange to leave before they are 64 destroyed) */ 65 66 extern grpc_core::TraceFlag grpc_resource_quota_trace; 67 68 grpc_resource_quota* grpc_resource_quota_ref_internal( 69 grpc_resource_quota* resource_quota); 70 void grpc_resource_quota_unref_internal(grpc_resource_quota* resource_quota); 71 grpc_resource_quota* grpc_resource_quota_from_channel_args( 72 const grpc_channel_args* channel_args); 73 74 /* Return a number indicating current memory pressure: 75 0.0 ==> no memory usage 76 1.0 ==> maximum memory usage */ 77 double grpc_resource_quota_get_memory_pressure( 78 grpc_resource_quota* resource_quota); 79 80 size_t grpc_resource_quota_peek_size(grpc_resource_quota* resource_quota); 81 82 typedef struct grpc_resource_user grpc_resource_user; 83 84 grpc_resource_user* grpc_resource_user_create( 85 grpc_resource_quota* resource_quota, const char* name); 86 87 /* Returns a borrowed reference to the underlying resource quota for this 88 resource user. */ 89 grpc_resource_quota* grpc_resource_user_quota( 90 grpc_resource_user* resource_user); 91 92 void grpc_resource_user_ref(grpc_resource_user* resource_user); 93 void grpc_resource_user_unref(grpc_resource_user* resource_user); 94 void grpc_resource_user_shutdown(grpc_resource_user* resource_user); 95 96 /* Attempts to get quota from the resource_user to create 'thread_count' number 97 * of threads. Returns true if successful (i.e the caller is now free to create 98 * 'thread_count' number of threads) or false if quota is not available */ 99 bool grpc_resource_user_allocate_threads(grpc_resource_user* resource_user, 100 int thread_count); 101 /* Releases 'thread_count' worth of quota back to the resource user. The quota 102 * should have been previously obtained successfully by calling 103 * grpc_resource_user_allocate_threads(). 104 * 105 * Note: There need not be an exact one-to-one correspondence between 106 * grpc_resource_user_allocate_threads() and grpc_resource_user_free_threads() 107 * calls. The only requirement is that the number of threads allocated should 108 * all be eventually released */ 109 void grpc_resource_user_free_threads(grpc_resource_user* resource_user, 110 int thread_count); 111 112 /* Allocate from the resource user (and its quota). 113 If optional_on_done is NULL, then allocate immediately. This may push the 114 quota over-limit, at which point reclamation will kick in. 115 If optional_on_done is non-NULL, it will be scheduled when the allocation has 116 been granted by the quota. */ 117 void grpc_resource_user_alloc(grpc_resource_user* resource_user, size_t size, 118 grpc_closure* optional_on_done); 119 /* Release memory back to the quota */ 120 void grpc_resource_user_free(grpc_resource_user* resource_user, size_t size); 121 /* Post a memory reclaimer to the resource user. Only one benign and one 122 destructive reclaimer can be posted at once. When executed, the reclaimer 123 MUST call grpc_resource_user_finish_reclamation before it completes, to 124 return control to the resource quota. */ 125 void grpc_resource_user_post_reclaimer(grpc_resource_user* resource_user, 126 bool destructive, grpc_closure* closure); 127 /* Finish a reclamation step */ 128 void grpc_resource_user_finish_reclamation(grpc_resource_user* resource_user); 129 130 /* Helper to allocate slices from a resource user */ 131 typedef struct grpc_resource_user_slice_allocator { 132 /* Closure for when a resource user allocation completes */ 133 grpc_closure on_allocated; 134 /* Closure to call when slices have been allocated */ 135 grpc_closure on_done; 136 /* Length of slices to allocate on the current request */ 137 size_t length; 138 /* Number of slices to allocate on the current request */ 139 size_t count; 140 /* Destination for slices to allocate on the current request */ 141 grpc_slice_buffer* dest; 142 /* Parent resource user */ 143 grpc_resource_user* resource_user; 144 } grpc_resource_user_slice_allocator; 145 146 /* Initialize a slice allocator. 147 When an allocation is completed, calls \a cb with arg \p. */ 148 void grpc_resource_user_slice_allocator_init( 149 grpc_resource_user_slice_allocator* slice_allocator, 150 grpc_resource_user* resource_user, grpc_iomgr_cb_func cb, void* p); 151 152 /* Allocate \a count slices of length \a length into \a dest. Only one request 153 can be outstanding at a time. */ 154 void grpc_resource_user_alloc_slices( 155 grpc_resource_user_slice_allocator* slice_allocator, size_t length, 156 size_t count, grpc_slice_buffer* dest); 157 158 #endif /* GRPC_CORE_LIB_IOMGR_RESOURCE_QUOTA_H */ 159